{"_id":"@dszp/autoelevate-lib","_rev":"3-e5d68e96ca82b8a619e43a4bfc325bf0","name":"@dszp/autoelevate-lib","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@dszp/autoelevate-lib","version":"0.1.0","keywords":["autoelevate","cyberfox","privilege-management","msp","integration","cloudflare-workers"],"author":{"url":"https://david.szpunar.com","name":"David Szpunar"},"license":"MIT","_id":"@dszp/autoelevate-lib@0.1.0","maintainers":[{"name":"dszp","email":"davidszp@gmail.com"}],"homepage":"https://github.com/dszp/autoelevate-lib#readme","bugs":{"url":"https://github.com/dszp/autoelevate-lib/issues"},"dist":{"shasum":"c98bce076af62625f284c4c3f0b2be115766f5b5","tarball":"https://registry.npmjs.org/@dszp/autoelevate-lib/-/autoelevate-lib-0.1.0.tgz","fileCount":33,"integrity":"sha512-RW3ga4UzS+tOMJafMt94HXjIIiN2Jd1o3EqOC/p/3EWQMG4LjJVp9EmW9xb0wpk61OVB72B0Jn6qs1ArM3Mwtw==","signatures":[{"sig":"MEQCIBF6XQZjriyVB4yfoVzyOZgH5vuMUEM0uy70A8VsRxvCAiBAUOnc82Yb/3UcrR11Xo6fPrqcYH+CDHJpM53kKK3/zQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":114560},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","//files":"The maps and `src` ship together on purpose: tsc writes a sourceMappingURL pointer into every dist file and the .d.ts.map references ../src/*.ts, so a Worker stack trace names a real .ts line and Go-to-Definition opens actual source. Tests and the mock-fetch harness are excluded by negation so they stay beside the code they test without shipping.","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js","//require":"ESM-only package. This `require` condition lets Node >=22.12 load it via require(esm); older Node still gets an accurate ERR_REQUIRE_ESM here instead of the confusing ERR_PACKAGE_PATH_NOT_EXPORTED the bare export map produced."},"./package.json":"./package.json"},"scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","verify":"pnpm build && node --input-type=module -e \"import('./dist/index.js').then(m => { if (!Object.keys(m).length) { throw new Error('dist/index.js exported nothing'); } console.log('verify: dist imports cleanly,', Object.keys(m).length, 'exports'); })\"","//verify":"Build, then actually IMPORT the built entry point with Node. `pnpm build` and `vitest run` both pass on a dist that cannot be loaded (tsc emits relative specifiers verbatim; vitest resolves extensionless ones). This checks the artefact a consumer actually gets.","typecheck":"tsc -p tsconfig.test.json --noEmit","test:watch":"vitest","build:watch":"tsc -p tsconfig.json --watch"},"_npmUser":{"name":"dszp","email":"davidszp@gmail.com"},"repository":{"url":"git+https://github.com/dszp/autoelevate-lib.git","type":"git"},"description":"Portable, Node-free client for the AutoElevate Partner API (beta): read-only typed client, Bearer and HMAC signing, and a per-company active-agent count helper for billing reconciliation. Runs unchanged in a Cloudflare Worker, Node, or the browser.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"//publishConfig":"No `provenance: true` here on purpose: it would force provenance on EVERY publish, including the manual first one that a brand-new package requires (npm can only configure trusted publishing on a package that already exists). Provenance comes from the workflow's explicit `npm publish --provenance` in CI.","devDependencies":{"vitest":"^3","typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/autoelevate-lib_0.1.0_1788901279065_0.6852479672221403","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@dszp/autoelevate-lib","version":"0.1.1","keywords":["autoelevate","cyberfox","privilege-management","msp","integration","cloudflare-workers"],"author":{"url":"https://david.szpunar.com","name":"David Szpunar"},"license":"MIT","_id":"@dszp/autoelevate-lib@0.1.1","maintainers":[{"name":"dszp","email":"davidszp@gmail.com"}],"homepage":"https://github.com/dszp/autoelevate-lib#readme","bugs":{"url":"https://github.com/dszp/autoelevate-lib/issues"},"dist":{"shasum":"034921df957dca2395ae24ee1592515314ab299c","tarball":"https://registry.npmjs.org/@dszp/autoelevate-lib/-/autoelevate-lib-0.1.1.tgz","fileCount":33,"integrity":"sha512-J1an4280rDxYpKV6HV5IlJqEtCqqP9bjc5T5Eg2UhWieAXkxmSkCJPQ9U9RRWQ2a3PJqmzezWn/5IIHyq82SDg==","signatures":[{"sig":"MEQCIGEIyplvrkzHw7IxlKXXDPoO44wKL4QJVq0wZ990joF2AiBoFwUhSr3QH+NZb/Nh4l7yVqiGVy0nC4nXLlf0439TOQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dszp%2fautoelevate-lib@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":114597},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","//files":"The maps and `src` ship together on purpose: tsc writes a sourceMappingURL pointer into every dist file and the .d.ts.map references ../src/*.ts, so a Worker stack trace names a real .ts line and Go-to-Definition opens actual source. Tests and the mock-fetch harness are excluded by negation so they stay beside the code they test without shipping.","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js","//require":"ESM-only package. This `require` condition lets Node >=22.12 load it via require(esm); older Node still gets an accurate ERR_REQUIRE_ESM here instead of the confusing ERR_PACKAGE_PATH_NOT_EXPORTED the bare export map produced."},"./package.json":"./package.json"},"gitHead":"545e54c0c38b6a6ad416c2fd455f0a5760d68087","scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","verify":"pnpm build && node --input-type=module -e \"import('./dist/index.js').then(m => { if (!Object.keys(m).length) { throw new Error('dist/index.js exported nothing'); } console.log('verify: dist imports cleanly,', Object.keys(m).length, 'exports'); })\"","//verify":"Build, then actually IMPORT the built entry point with Node. `pnpm build` and `vitest run` both pass on a dist that cannot be loaded (tsc emits relative specifiers verbatim; vitest resolves extensionless ones). This checks the artefact a consumer actually gets.","typecheck":"tsc -p tsconfig.test.json --noEmit","test:watch":"vitest","build:watch":"tsc -p tsconfig.json --watch"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8d37e9d3-e4d6-45aa-aeb4-380ef0ea8438"}},"repository":{"url":"git+https://github.com/dszp/autoelevate-lib.git","type":"git"},"_npmVersion":"12.0.2","description":"Portable, Node-free client for the AutoElevate Partner API (beta): read-only typed client, Bearer and HMAC signing, and a per-company active-agent count helper for billing reconciliation. Runs unchanged in a Cloudflare Worker, Node, or the browser.","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.11.0","//publishConfig":"No `provenance: true` here on purpose: it would force provenance on EVERY publish, including the manual first one that a brand-new package requires (npm can only configure trusted publishing on a package that already exists). Provenance comes from the workflow's explicit `npm publish --provenance` in CI.","devDependencies":{"vitest":"^3","typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/autoelevate-lib_0.1.1_1788901572967_0.16353447765129658","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@dszp/autoelevate-lib","version":"0.2.0","description":"Portable, Node-free client for the AutoElevate Partner API (beta): a read client plus an explicit write client, Bearer and HMAC signing, and a per-company active-agent count helper for billing reconciliation. Runs unchanged in a Cloudflare Worker, Node, o","type":"module","license":"MIT","author":{"name":"David Szpunar","url":"https://david.szpunar.com"},"repository":{"type":"git","url":"git+https://github.com/dszp/autoelevate-lib.git"},"bugs":{"url":"https://github.com/dszp/autoelevate-lib/issues"},"homepage":"https://github.com/dszp/autoelevate-lib#readme","//publishConfig":"No `provenance: true` here on purpose: it would force provenance on EVERY publish, including the manual first one that a brand-new package requires (npm can only configure trusted publishing on a package that already exists). Provenance comes from the workflow's explicit `npm publish --provenance` in CI.","publishConfig":{"access":"public"},"engines":{"node":">=20"},"keywords":["autoelevate","cyberfox","privilege-management","msp","integration","cloudflare-workers"],"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","//require":"ESM-only package. This `require` condition lets Node >=22.12 load it via require(esm); older Node still gets an accurate ERR_REQUIRE_ESM here instead of the confusing ERR_PACKAGE_PATH_NOT_EXPORTED the bare export map produced.","require":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"types":"./dist/index.d.ts","module":"./dist/index.js","main":"./dist/index.js","sideEffects":false,"//files":"The maps and `src` ship together on purpose: tsc writes a sourceMappingURL pointer into every dist file and the .d.ts.map references ../src/*.ts, so a Worker stack trace names a real .ts line and Go-to-Definition opens actual source. Tests and the mock-fetch harness are excluded by negation so they stay beside the code they test without shipping.","scripts":{"build":"tsc -p tsconfig.json","build:watch":"tsc -p tsconfig.json --watch","typecheck":"tsc -p tsconfig.test.json --noEmit","//verify":"Build, then actually IMPORT the built entry point with Node. `pnpm build` and `vitest run` both pass on a dist that cannot be loaded (tsc emits relative specifiers verbatim; vitest resolves extensionless ones). This checks the artefact a consumer actually gets.","verify":"pnpm build && node --input-type=module -e \"import('./dist/index.js').then(m => { if (!Object.keys(m).length) { throw new Error('dist/index.js exported nothing'); } console.log('verify: dist imports cleanly,', Object.keys(m).length, 'exports'); })\"","test":"vitest run","test:watch":"vitest"},"devDependencies":{"typescript":"^5","vitest":"^3"},"packageManager":"pnpm@11.11.0","gitHead":"62bac887a5a492b9ce4557d2dfc0c2d192810053","_id":"@dszp/autoelevate-lib@0.2.0","_nodeVersion":"24.20.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-PdGwQDwHd5mBh02QdV/Sk7c8L+V6HP+g9TCU0OX8UpLDmRrUq2ZSJDC0AuZyrHlCIJyXRJqRz4IQ27j0TmQxJA==","shasum":"e269a0954104c5e840e59be9155a3f66b6c9a311","tarball":"https://registry.npmjs.org/@dszp/autoelevate-lib/-/autoelevate-lib-0.2.0.tgz","fileCount":38,"unpackedSize":135233,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dszp%2fautoelevate-lib@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCtpM7d6m3i6MAUkmVJUvBN1muH8x5iMYN1D4Wf/SxN0gIhALfiVYlMtedi+bAuzDCn8mz/8cjDaDayMZByQ54x+xQ9"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8d37e9d3-e4d6-45aa-aeb4-380ef0ea8438"}},"directories":{},"maintainers":[{"name":"dszp","email":"davidszp@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/autoelevate-lib_0.2.0_1789070112343_0.9857388166033001"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-08T21:01:18.845Z","modified":"2026-09-10T19:55:12.819Z","0.1.0":"2026-09-08T21:01:19.255Z","0.1.1":"2026-09-08T21:06:13.114Z","0.2.0":"2026-09-10T19:55:12.487Z"},"bugs":{"url":"https://github.com/dszp/autoelevate-lib/issues"},"author":{"name":"David Szpunar","url":"https://david.szpunar.com"},"license":"MIT","homepage":"https://github.com/dszp/autoelevate-lib#readme","keywords":["autoelevate","cyberfox","privilege-management","msp","integration","cloudflare-workers"],"repository":{"type":"git","url":"git+https://github.com/dszp/autoelevate-lib.git"},"description":"Portable, Node-free client for the AutoElevate Partner API (beta): a read client plus an explicit write client, Bearer and HMAC signing, and a per-company active-agent count helper for billing reconciliation. Runs unchanged in a Cloudflare Worker, Node, o","maintainers":[{"name":"dszp","email":"davidszp@gmail.com"}],"readme":"# @dszp/autoelevate-lib\n\nTypeScript client for the [AutoElevate Partner API (beta)](https://partner-api-docs.autoelevate.com/).\nIt runs unchanged in a Cloudflare Worker, Node 20+, or the browser: no Node built-ins, only\n`fetch` and WebCrypto.\n\nWhat you get:\n\n- `AutoElevateReadClient`: one typed method per GET endpoint, plus `listAll*` walkers that\n  page at the API's maximum and verify the row count against the server's `totalCount`.\n- `gatherAgentCounts()`: per-company active-agent counts for billing reconciliation, with an\n  MSP-total cross-check against `/usage`.\n- `signRequest()`: builds the `Authorization` header for both key schemes (HMAC-SHA256 and\n  Bearer), usable on its own from a script.\n- `AutoElevateWriteClient`: approve or deny a pending elevation request. Needs a key with the\n  `requestEdit` scope, and lives on a separate class from the read client so a read-only\n  integration can't grow a write by accident.\n\nThis package splits reads from writes: `AutoElevateReadClient` covers every GET endpoint, and\na separate `AutoElevateWriteClient` covers the two POST endpoints that approve or deny an\nelevation request. The write client needs an API key with the `requestEdit` scope — a key\nwithout it is refused by the API itself; the library does not inspect scopes.\n\n> The Partner API is in beta and can change without notice. Every request carries the\n> required `X-Acknowledgment: i-understand-this-is-beta-and-may-change` header. The library\n> pins `/api/v1/` paths and surfaces `Deprecation` and `Sunset` headers when the API sends them.\n\n## Install\n\n```bash\npnpm add @dszp/autoelevate-lib\n```\n\n## Create an API key\n\n1. In the AutoElevate admin portal, open **Users** and create a **service user** for the\n   integration. Do not attach keys to a person's account.\n2. In that user's **API Keys** section, add a key. Prefer **HMAC (AE-HMAC-SHA256)**: it shows\n   two values, a wire `token` (`aeh_…`) and a separate `hmacKey`, and every request is signed\n   so a captured request can't be replayed elsewhere or after five minutes. **API Token\n   (AE-BEARER)** gives one `aeb_…` secret and works with any HTTP client.\n3. Grant only the scopes you need (table below). Set the shortest expiry that fits.\n4. Copy the secret immediately. It is shown once.\n\nStore the value in a secrets manager (Worker secret, 1Password, etc.), never in source.\n\n| Method | Scope |\n|---|---|\n| `getUsage`, `listComputers`, `getComputer` | `computerView` |\n| `listCompanies`, `getCompany` | `companyView` |\n| `listLocations`, `getLocation` | `locationView` |\n| `listElevationRequests`, `getElevationRequest` | `requestView` |\n| `listElevationEvents` | `eventView` |\n| `listElevatedSessions`, `getElevatedSession` | `elevatedSessionView` |\n| `listElevationRules` | `ruleView` |\n| `listAuditLogs` | `auditLogView` (may also require Early Access enrolment) |\n| `gatherAgentCounts` | `computerView` + `companyView` |\n| `approveElevationRequest`, `denyElevationRequest` | `requestEdit` |\n\n## Use it in a Worker\n\n```ts\nimport { AutoElevateReadClient, gatherAgentCounts } from '@dszp/autoelevate-lib';\n\nexport default {\n  async fetch(_req: Request, env: { AUTOELEVATE_TOKEN: string; AUTOELEVATE_HMAC_KEY?: string }) {\n    const client = new AutoElevateReadClient({\n      // HMAC when hmacKey is present, Bearer when it is not.\n      credential: { token: env.AUTOELEVATE_TOKEN, hmacKey: env.AUTOELEVATE_HMAC_KEY },\n    });\n    const report = await gatherAgentCounts(client);\n    return Response.json(report);\n  },\n};\n```\n\nPass `hmacKey` exactly as the portal showed it. The scheme is inferred from its presence, and a\ntoken prefix that contradicts it (`aeb_` with a key, `aeh_` without) is rejected before any\nrequest is made; set `scheme` explicitly only if you want to be verbose. The signature covers the method, the request-target (path and query\nstring, without the host), a SHA-256 of the body, and a millisecond timestamp. The server\nrejects timestamps more than five minutes from its own clock. Verified against the live API\non 2026-09-08: signing the absolute URL is rejected with `Invalid signature`.\n\n## Billing counts\n\n`gatherAgentCounts(client)` returns:\n\n```ts\n{\n  gatheredAt: 1757360000000,\n  msp: { partnerId, partnerName, fromUsage: 142, fromComputers: 142, agree: true },\n  companies: [\n    {\n      companyId, companyName, managementSystemCompanyId,  // PSA-side key when a PSA created it\n      activeAgents: 37,\n      byElevationMode: { audit: 2, live: 35, policy: 0, technicianBypass: 0, unknown: 0 },\n    },\n    // ...sorted by company name; companies with zero agents are present with 0\n  ],\n}\n```\n\nHow it works, and why:\n\n- `/computers` returns only computers that checked in within the **last 30 days**. That\n  window is what AutoElevate calls the active fleet, so its `totalCount` is the billable\n  figure, not the inventory.\n- There is no per-company count endpoint. The helper walks `/computers` once, unfiltered, at\n  200 rows per page and buckets by `companyId` in memory. For N computers and C companies\n  that costs `ceil(N/200) + ceil(C/200) + 1` requests. Filtering by company would cost one\n  request per client.\n- `/usage` reports `totalActiveAgents` from a periodically refreshed snapshot. `agree` is\n  `false` when it differs from the live walk. A difference of a few units is snapshot lag;\n  a large one is worth investigating.\n- A computer whose company the key cannot see (restricted-company keys) still counts, in a\n  row with `companyName: null`.\n\n`bucketAgents(companies, computers)` is exported separately if you already have the rows.\n\n## Approving or denying elevation requests\n\nWrites live in a separate class so a read-only integration cannot grow a write by accident.\nThe key needs the `requestEdit` scope; the request must be `PENDING`, otherwise the API\nanswers `409` and nothing changes.\n\n```ts\nimport { AutoElevateWriteClient } from '@dszp/autoelevate-lib';\n\nconst writer = new AutoElevateWriteClient({ credential: { token, hmacKey } });\nawait writer.approveElevationRequest(requestId, { elevationType: 'admin', durationInMinutes: 30 });\nawait writer.denyElevationRequest(requestId, { denialReason: 'Not on the approved software list.' });\n```\n\nOptions: `createRule: true` with a `ruleLevel` (`computer`, `location`, `company`, `msp`) also\ncreates an auto-approve or auto-deny rule from the request. Payloads are validated before the\nrequest is sent (`AutoElevateValidationError` names the field), so a malformed call never spends\na request from the hourly bucket.\n\n## Pagination and completeness\n\nOffset lists (`take`/`skip`) return `{ items, totalCount }`. The API reports `totalCount: 0`\nonce `skip` is past the end, so a zero on a later page does not mean the collection is empty.\nThe `listAll*` walkers trust only the first page's `totalCount`, stop on a short page, and\nthrow `IncompleteListError` if the rows collected differ from that total. A runaway guard\n(200 pages by default, `maxPages` to override) stops a walk against a server that ignores\n`skip`.\n\n`/audit-logs` uses a cursor instead; `listAllAuditLogs` follows `nextCursor` until\n`hasMore` is false and applies the same completeness check.\n\n## Rate limits and errors\n\nLimits are **100 requests per hour per HTTP method and route**, in one sliding window. A\n429 arrives as `AutoElevateApiError` with `isRateLimited === true` and `retryAfterSeconds`\nset from the `Retry-After` header. The library does not retry on its own: with a budget that\nsmall, a retry loop spends what the caller needs. Decide in your scheduler.\n\nEvery failure is an `AutoElevateApiError` with `status`, `method`, `path`, and the parsed\nerror body. Messages for 400, 401, 403, and 429 add a one-line hint about the likely cause\n(missing acknowledgment header, expired key, missing scope or Early Access, rate limit).\n\n## Timestamps\n\nEvery time field is epoch **milliseconds**. `ElevatedSession.endedAt` is the scheduled end,\nset at creation and not updated if the session ends early.\n\n## Development\n\n```bash\npnpm install\npnpm test          # offline suite (mock fetch)\npnpm typecheck\npnpm verify        # build, then import dist/index.js under Node\n```\n\nRun the live smoke test against your own tenant with a short-lived read-only key. It costs a\nhandful of requests from the hourly buckets:\n\n```bash\nAUTOELEVATE_TOKEN=aeb_... pnpm test\n# HMAC instead:\nAUTOELEVATE_TOKEN=aeh_... AUTOELEVATE_HMAC_KEY=... pnpm test\n```\n\nThe write live smoke test self-skips unless both `AUTOELEVATE_TOKEN` and\n`AUTOELEVATE_LIVE_DECIDED_REQUEST_ID` are set, and needs a `requestEdit`-scoped key:\n\n```bash\nAUTOELEVATE_TOKEN=... AUTOELEVATE_HMAC_KEY=... AUTOELEVATE_LIVE_DECIDED_REQUEST_ID=<id> pnpm test\n```\n\nThe OpenAPI document this library was written against is vendored in\n`reference/AutoElevate Partner API Beta.json` (downloaded 2026-09-08 from the\n[Partner API reference](https://partner-api-docs.autoelevate.com/)). Types are hand-written\nfrom it, not generated.\n\n## Resources\n\n- [AutoElevate Partner API reference](https://partner-api-docs.autoelevate.com/): endpoints,\n  versioning, rate limits, and the OpenAPI document.\n- [CyberFOX support: AutoElevate Partner API (Beta)](https://support.cyberfox.com/360000239832-General-Troubleshooting/autoelevate-partner-api-beta):\n  creating service users and API keys, and troubleshooting 401/403 responses.\n- [Cloudflare Workers documentation](https://developers.cloudflare.com/workers/) for the\n  runtime this library targets first.\n- [`n8n-nodes-autoelevate`](https://github.com/dszp/n8n-nodes-autoelevate): the same surface as\n  an n8n community node. It vendors its own copy of the transport because verified community\n  nodes cannot carry runtime dependencies; this repository's `src/auth.ts` is the reference\n  implementation of the signing algorithm.\n- [ARCHITECTURE.md](ARCHITECTURE.md) for why the library is shaped this way, and\n  [CONTRIBUTING.md](CONTRIBUTING.md) for the rules.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md).\n\n## Attribution\n\nAutoElevate is a product of CyberFOX, which owns the AutoElevate trademarks. This library is not\naffiliated with or endorsed by CyberFOX.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}