@ledewire/browser 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/index.d.ts +1038 -33
- package/dist/index.js +125 -16
- package/dist/index.js.map +1 -1
- package/dist/ledewire.min.js +1 -1
- package/dist/ledewire.min.js.map +1 -1
- package/llms.txt +41 -3
- package/package.json +6 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../core/src/base64.ts","../../core/src/errors.ts","../../core/src/spend-cap.ts","../../core/src/http-client.ts","../../core/src/token-manager.ts","../src/resources/auth.ts","../src/resources/config.ts","../src/resources/content.ts","../src/resources/purchases.ts","../src/resources/seller/content.ts","../src/resources/seller/index.ts","../src/resources/wallet.ts","../src/resources/checkout.ts","../src/resources/user/api-keys.ts","../src/resources/user/spend-cap.ts","../src/resources/user/mcp-keys.ts","../src/resources/user/index.ts","../src/client.ts","../src/web-storage-adapter.ts","../src/local-storage-adapter.ts","../src/session-storage-adapter.ts"],"sourcesContent":["/**\n * Decode a base64-encoded string to plain UTF-8 text.\n *\n * Used internally by SDK response handlers to transparently decode\n * `content_body` and `teaser` fields from the API wire format.\n *\n * @internal\n */\nexport function decodeBase64(value: string): string {\n return atob(value)\n}\n\n/**\n * Encode a plain UTF-8 string to base64.\n *\n * Used internally by SDK request handlers to re-encode plain-text\n * `content_body` and `teaser` fields before they are sent to the API.\n *\n * @internal\n */\nexport function encodeBase64(value: string): string {\n return btoa(value)\n}\n\n/**\n * Decode base64-encoded `content_body` and `teaser` fields on a content\n * response object. Works with both `ContentResponse` (which may carry\n * `content_body`) and `ContentListItem` (which only carries `teaser`).\n * Null and absent fields are left untouched.\n *\n * @internal\n */\nexport function decodeContentFields<\n T extends { content_body?: string | null; teaser?: string | null },\n>(item: T): T {\n return {\n ...item,\n ...(typeof item.content_body === 'string' && {\n content_body: decodeBase64(item.content_body),\n }),\n ...(typeof item.teaser === 'string' && { teaser: decodeBase64(item.teaser) }),\n } as T\n}\n\n/**\n * Encode plain-text `content_body` and `teaser` fields to base64 before\n * they are sent to the API. Absent and undefined fields are left untouched.\n *\n * @internal\n */\nexport function encodeContentFields<\n T extends {\n content_body?: string | undefined\n teaser?: string | undefined\n [key: string]: unknown\n },\n>(body: T): T {\n const out = { ...body } as Record<string, unknown>\n if (typeof out['content_body'] === 'string')\n out['content_body'] = encodeBase64(out['content_body'])\n if (typeof out['teaser'] === 'string') out['teaser'] = encodeBase64(out['teaser'])\n return out as T\n}\n","import type { ErrorType } from './types.js'\n\n/**\n * Known {@link ErrorType} values, widened to accept any other string the API\n * may introduce. `ErrorType` still drives editor autocomplete; a value the API\n * emits that isn't (yet) in the spec's enum — e.g. `selection_too_large` on\n * `POST /v1/acquisitions` — still type-checks and survives on {@link\n * LedewireError.type} instead of being narrowed away.\n */\nexport type ErrorTypeValue = ErrorType | (string & {})\n\n/**\n * Global-symbol-registry key for the non-enumerable class-brand list every\n * `LedewireError` instance carries. See {@link LedewireError[Symbol.hasInstance]}.\n *\n * `@ledewire/core` is private and bundled separately into every published\n * package (via tsup), so `SpendCapReachedError` — and every other class in\n * this file — exists as a *distinct* class object in `@ledewire/node`,\n * `@ledewire/browser`, and `@ledewire/x402-client`. `Symbol.for` (the global\n * symbol registry, keyed by string and shared process-wide) rather than\n * `Symbol()` means every one of those bundle copies resolves this constant to\n * the *same* symbol, so a brand list written by one copy's constructor is\n * still readable by another copy's `hasInstance` check.\n */\nconst ERROR_BRAND = Symbol.for('@ledewire/error-brands')\n\n/**\n * Base error class for all LedeWire SDK errors.\n * All errors thrown by the SDK are instances of this class,\n * making it safe to use `err instanceof LedewireError` as a type guard.\n *\n * `instanceof` works even when `err` was constructed by a different bundled\n * copy of this class — e.g. an error thrown by `@ledewire/x402-client`\n * checked with the `SpendCapReachedError` bundled into `@ledewire/node`. See\n * {@link LedewireError[Symbol.hasInstance]}.\n *\n * @example\n * ```ts\n * try {\n * await client.purchases.create({ contentId: '...' })\n * } catch (err) {\n * if (err instanceof LedewireError) {\n * console.error(err.statusCode, err.message)\n * }\n * }\n * ```\n */\nexport class LedewireError extends Error {\n /**\n * Class-identity brand used for cross-bundle `instanceof` (see {@link\n * LedewireError[Symbol.hasInstance]}). Hardcoded per class — never derived\n * from `constructor.name` or `this.name`, either of which a minifier can\n * rewrite, silently breaking the brand match.\n */\n static readonly brand: string = 'LedewireError'\n\n /** HTTP status code returned by the API (e.g. 400, 401, 404, 422). */\n public readonly statusCode: number\n\n /** Machine-readable error code from the API error body, if present. */\n public readonly code: number | undefined\n\n /**\n * Machine-readable reason from the API error body's `error.type`, if present.\n * See {@link ErrorType} for the documented values and how to branch on them —\n * the API may emit other values it hasn't documented yet, which still land\n * here as a plain string rather than being dropped.\n */\n public readonly type: ErrorTypeValue | undefined\n\n /**\n * Extra top-level fields from the API error response body, excluding\n * `error` itself. For example, a `selection_too_large` refusal from `POST\n * /v1/acquisitions` (422) carries `maximum` and `submitted` alongside\n * `error`. `undefined` when the body carried no other top-level fields,\n * which is the common case.\n */\n public readonly details: Readonly<Record<string, unknown>> | undefined\n\n constructor(\n message: string,\n statusCode: number,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'LedewireError'\n this.statusCode = statusCode\n this.code = code\n this.type = type\n this.details = details\n // Restore prototype chain (required for extending built-in Error in TS)\n Object.setPrototypeOf(this, new.target.prototype)\n\n // Collect this instance's class brands by walking new.target's own\n // prototype (constructor) chain, so hasInstance can fall back to a\n // brand check when the normal prototype check fails across bundles.\n const brands: string[] = []\n let ctor: unknown = new.target\n while (typeof ctor === 'function') {\n const ownBrand = (ctor as { brand?: unknown }).brand\n if (typeof ownBrand === 'string' && Object.prototype.hasOwnProperty.call(ctor, 'brand')) {\n brands.push(ownBrand)\n }\n ctor = Object.getPrototypeOf(ctor)\n }\n Object.defineProperty(this, ERROR_BRAND, {\n value: brands,\n enumerable: false,\n configurable: true,\n })\n }\n\n /**\n * Makes `err instanceof LedewireError` (and every subclass below) true even\n * when `err` was constructed by a *different* bundled copy of this module.\n * Each published package (`@ledewire/node`, `@ledewire/browser`,\n * `@ledewire/x402-client`) bundles its own copy of `@ledewire/core` via\n * tsup, so the classes are distinct objects with unrelated prototypes —\n * the plain prototype-chain check `instanceof` normally does would fail.\n *\n * Falls back to the brand list every instance carries under a\n * `Symbol.for('@ledewire/error-brands')` key (collected from the `brand`\n * static along the constructing class's prototype chain): true when the\n * ordinary check passes, OR the instance's brand list includes this\n * class's own `brand`.\n */\n static override [Symbol.hasInstance](instance: unknown): boolean {\n if (Function.prototype[Symbol.hasInstance].call(this, instance)) {\n return true\n }\n if (!instance || (typeof instance !== 'object' && typeof instance !== 'function')) {\n return false\n }\n const brands = (instance as Record<PropertyKey, unknown>)[ERROR_BRAND]\n return Array.isArray(brands) && brands.includes(this.brand)\n }\n}\n\n/**\n * Thrown when the request lacks valid authentication credentials,\n * or when a token refresh fails and re-authentication is required.\n */\nexport class AuthError extends LedewireError {\n static override readonly brand: string = 'AuthError'\n\n constructor(\n message: string,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, 401, code, type, details)\n this.name = 'AuthError'\n }\n}\n\n/**\n * Thrown when the authenticated user does not have permission\n * to perform the requested operation.\n *\n * **Common cause — merchant login with the wrong account role:**\n * `POST /v1/auth/merchant/login/email` and `POST /v1/auth/merchant/login/google`\n * return `403 Forbidden` (not `401`) when the credentials are valid but the\n * account has no merchant store associations (e.g. a buyer account used on the\n * merchant endpoint). The `err.message` will be:\n * `\"This account does not have merchant access. Use a merchant or owner account.\"`\n *\n * Use a different account or ask a store owner to add your account as a member.\n *\n * @example\n * ```ts\n * // Browser\n * import { ForbiddenError, AuthError } from '@ledewire/browser'\n *\n * try {\n * await lw.auth.loginWithGoogle({ id_token })\n * } catch (err) {\n * if (err instanceof ForbiddenError) {\n * // Credentials were valid but account lacks the required role.\n * console.error('Access denied:', err.message)\n * } else if (err instanceof AuthError) {\n * // Bad credentials or expired token — re-authenticate.\n * console.error('Authentication failed:', err.message)\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // Node\n * import { ForbiddenError, AuthError } from '@ledewire/node'\n *\n * try {\n * await client.merchant.auth.loginWithGoogle({ id_token })\n * } catch (err) {\n * if (err instanceof ForbiddenError) {\n * // Credentials were valid but account has no merchant store access.\n * // err.message → \"This account does not have merchant access. Use a merchant or owner account.\"\n * console.error('Wrong account role:', err.message)\n * } else if (err instanceof AuthError) {\n * // Bad credentials or expired token — re-authenticate.\n * console.error('Authentication failed:', err.message)\n * }\n * }\n * ```\n */\nexport class ForbiddenError extends LedewireError {\n static override readonly brand: string = 'ForbiddenError'\n\n constructor(\n message: string,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, 403, code, type, details)\n this.name = 'ForbiddenError'\n }\n}\n\n/**\n * Thrown when the requested resource does not exist.\n */\nexport class NotFoundError extends LedewireError {\n static override readonly brand: string = 'NotFoundError'\n\n constructor(\n message: string,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, 404, code, type, details)\n this.name = 'NotFoundError'\n }\n}\n\n/**\n * Thrown when the purchase cannot be completed due to a validation\n * failure, such as a price mismatch or a duplicate purchase.\n */\nexport class PurchaseError extends LedewireError {\n static override readonly brand: string = 'PurchaseError'\n\n constructor(\n message: string,\n statusCode: number,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, statusCode, code, type, details)\n this.name = 'PurchaseError'\n }\n}\n\n/**\n * Thrown when the buyer's daily spend cap has been reached. Returned as HTTP `402`\n * by `POST /v1/purchases`, `GET /v1/x402/contents/{id}`, and acquisition\n * authorization, whenever the API error body's `error.type` is\n * `'daily_spend_cap_reached'`.\n *\n * **Funding the wallet does not clear this.** Unlike a plain `insufficient_funds`\n * 402 — where adding money to the wallet is enough to retry — a spend cap refusal\n * is a daily policy limit on the buyer's account (every new buyer starts with a\n * default cap). It clears only when the spend window rolls over at {@link\n * SpendCapReachedError.resetsAt}, or when the buyer raises or removes the cap via\n * `user.spendCap.update()`.\n *\n * @example\n * ```ts\n * try {\n * await client.purchases.create({ content_id })\n * } catch (err) {\n * if (err instanceof SpendCapReachedError) {\n * // Do NOT prompt the buyer to fund their wallet — that won't help.\n * console.error(\n * `Spend cap reached: spent ${err.spentCents} of ${err.capCents} cents. ` +\n * `Resets at ${err.resetsAt}.`,\n * )\n * }\n * }\n * ```\n */\nexport class SpendCapReachedError extends LedewireError {\n static override readonly brand: string = 'SpendCapReachedError'\n\n /** The buyer's daily spend cap in cents. */\n public readonly capCents: number\n\n /** Total spent so far in the current spend window. */\n public readonly spentCents: number\n\n /** Cap minus spend so far, floored at zero — what the buyer may still spend in this window. */\n public readonly remainingCents: number\n\n /** ISO 8601 timestamp (UTC) of the instant the current spend window rolls. */\n public readonly resetsAt: string\n\n /**\n * Whether this buyer's bulk acquisitions are exempt from the cap. When `true`,\n * `spentCents` and `remainingCents` describe ordinary spend only — an authorized\n * bulk acquisition does not consume them.\n */\n public readonly bulkExempt: boolean\n\n constructor(\n message: string,\n capInfo: {\n capCents: number\n spentCents: number\n remainingCents: number\n resetsAt: string\n bulkExempt: boolean\n },\n code?: number,\n ) {\n super(message, 402, code, 'daily_spend_cap_reached')\n this.name = 'SpendCapReachedError'\n this.capCents = capInfo.capCents\n this.spentCents = capInfo.spentCents\n this.remainingCents = capInfo.remainingCents\n this.resetsAt = capInfo.resetsAt\n this.bulkExempt = capInfo.bulkExempt\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import { SpendCapReachedError } from './errors.js'\n\n/**\n * Builds a {@link SpendCapReachedError} from a parsed `402` response body, or\n * `null` when the body isn't a well-formed daily-spend-cap-reached refusal.\n *\n * Shared by {@link HttpClient}'s error mapping (`POST /v1/purchases`,\n * acquisition authorization) and the `@ledewire/x402-client` fetch/Axios\n * adapters, which see the same body shape on a bare `GET /v1/x402/contents/{id}`\n * `402` — one with **no** `PAYMENT-REQUIRED` header, so there is nothing to\n * challenge and retrying or funding the wallet cannot clear it.\n *\n * Requires `error.type === 'daily_spend_cap_reached'` and `cap_cents`,\n * `spent_cents`, `remaining_cents` to be numbers, `resets_at` to be a string,\n * and `bulk_exempt` to be a boolean. A body with the right `error.type` but a\n * missing or mistyped field returns `null` — never `NaN`/`'undefined'` fields\n * on a shape that's merely close — so the caller falls back to its generic\n * error path.\n *\n * @param body - The parsed JSON body of a `402` response, or `undefined`/`null`\n * if it couldn't be parsed.\n */\nexport function spendCapErrorFromBody(body: unknown): SpendCapReachedError | null {\n if (!body || typeof body !== 'object') return null\n const record = body as Record<string, unknown>\n\n const error = record['error']\n if (!error || typeof error !== 'object') return null\n const errorRecord = error as Record<string, unknown>\n if (errorRecord['type'] !== 'daily_spend_cap_reached') return null\n\n const capCents = record['cap_cents']\n const spentCents = record['spent_cents']\n const remainingCents = record['remaining_cents']\n const resetsAt = record['resets_at']\n const bulkExempt = record['bulk_exempt']\n\n if (\n typeof capCents !== 'number' ||\n typeof spentCents !== 'number' ||\n typeof remainingCents !== 'number' ||\n typeof resetsAt !== 'string' ||\n typeof bulkExempt !== 'boolean'\n ) {\n return null\n }\n\n const message =\n typeof errorRecord['message'] === 'string' ? errorRecord['message'] : 'Daily spend cap reached.'\n const code = typeof errorRecord['code'] === 'number' ? errorRecord['code'] : undefined\n\n return new SpendCapReachedError(\n message,\n { capCents, spentCents, remainingCents, resetsAt, bulkExempt },\n code,\n )\n}\n","import { AuthError, ForbiddenError, LedewireError, NotFoundError } from './errors.js'\nimport type { ErrorTypeValue } from './errors.js'\nimport { spendCapErrorFromBody } from './spend-cap.js'\n\n/**\n * Configuration options for `HttpClient`.\n */\nexport interface HttpClientConfig {\n /** API base URL. Defaults to the production API. */\n baseUrl?: string\n /**\n * Returns the current access token (or null) before each request.\n * If null, requests are sent without an Authorization header.\n */\n getAccessToken?: () => string | null | Promise<string | null>\n /**\n * Called when a 401 is received on the first attempt.\n * Should refresh and return the new access token, or null to propagate\n * an `AuthError` to the caller.\n */\n onUnauthorized?: () => string | null | Promise<string | null>\n}\n\n/**\n * Per-request overrides accepted by {@link HttpClient} methods.\n */\nexport interface RequestOptions {\n /**\n * Whether to attach authentication to this request. Defaults to `true`.\n * Pass `false` for public endpoints: skips `getAccessToken`, sends no\n * `Authorization` header, and maps a `401` straight to an {@link AuthError}\n * without invoking `onUnauthorized`.\n */\n auth?: boolean\n}\n\n/** The default LedeWire API base URL used by all SDK packages. */\nexport const DEFAULT_BASE_URL = 'https://api.ledewire.com'\n\n/**\n * Extracts `{ message, code, type, details }` from a parsed API error body,\n * tolerating shapes that don't match the documented `ErrorResponse` envelope:\n * an empty object, a body with no `error` field at all, `error` as a bare\n * string (e.g. the spec's `{ \"error\": \"Content ... not found\" }` 404 purchase\n * example), `null`, or non-object JSON. Never throws; falls back to\n * `fallbackMessage` (the response's `statusText`) whenever the body doesn't\n * carry a usable message.\n */\nfunction extractErrorInfo(\n body: unknown,\n fallbackMessage: string,\n): {\n message: string\n code: number | undefined\n type: ErrorTypeValue | undefined\n details: Record<string, unknown> | undefined\n} {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n return { message: fallbackMessage, code: undefined, type: undefined, details: undefined }\n }\n\n const record = body as Record<string, unknown>\n const { error, ...rest } = record\n const details = Object.keys(rest).length > 0 ? rest : undefined\n\n if (typeof error === 'string') {\n return { message: error, code: undefined, type: undefined, details }\n }\n\n if (!error || typeof error !== 'object' || Array.isArray(error)) {\n return { message: fallbackMessage, code: undefined, type: undefined, details }\n }\n\n const errorRecord = error as Record<string, unknown>\n const message =\n typeof errorRecord['message'] === 'string' ? errorRecord['message'] : fallbackMessage\n const code = typeof errorRecord['code'] === 'number' ? errorRecord['code'] : undefined\n const type = typeof errorRecord['type'] === 'string' ? errorRecord['type'] : undefined\n\n return { message, code, type, details }\n}\n\n/**\n * Core HTTP client used by all SDK packages.\n *\n * Features:\n * - Injects `Authorization: Bearer <token>` headers automatically\n * - Maps HTTP error responses to typed `LedewireError` subclasses\n * - On receiving a 401, calls `onUnauthorized` once and retries the request\n * - Per-request `{ auth: false }` (see {@link RequestOptions}) skips all of\n * the above for public endpoints\n *\n * This is an internal class - consumers should use the\n * package-level client factories (`init` / `createClient`) instead.\n */\nexport class HttpClient {\n private readonly baseUrl: string\n private readonly getAccessToken: NonNullable<HttpClientConfig['getAccessToken']>\n private readonly onUnauthorized: NonNullable<HttpClientConfig['onUnauthorized']>\n\n constructor(config: HttpClientConfig = {}) {\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.getAccessToken = config.getAccessToken ?? (() => null)\n this.onUnauthorized = config.onUnauthorized ?? (() => null)\n }\n\n /**\n * GET request with optional query parameters.\n * @param path - API path (e.g. `/v1/wallet/balance`)\n * @param params - Query string parameters. `undefined` values are omitted; numbers are coerced to strings.\n * @param options - Per-request overrides. Pass `{ auth: false }` for public endpoints.\n */\n async get<T>(\n path: string,\n params?: Record<string, string | number | undefined>,\n options?: RequestOptions,\n ): Promise<T> {\n return this.request<T>('GET', this.buildUrl(path, params), undefined, options)\n }\n\n /**\n * POST request.\n * @param path - API path\n * @param body - Request body (JSON-serialized)\n * @param params - Optional query string parameters. `undefined` values are omitted; numbers are coerced to strings.\n */\n async post<T>(\n path: string,\n body?: unknown,\n params?: Record<string, string | number | undefined>,\n ): Promise<T> {\n return this.request<T>('POST', this.buildUrl(path, params), body)\n }\n\n /**\n * PUT request.\n * @param path - API path\n * @param body - Request body (JSON-serialized)\n */\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PUT', this.buildUrl(path), body)\n }\n\n /**\n * PATCH request.\n * @param path - API path\n * @param body - Partial update body (JSON-serialized)\n */\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PATCH', this.buildUrl(path), body)\n }\n\n /**\n * DELETE request.\n * @param path - API path\n */\n async delete<T = void>(path: string): Promise<T> {\n return this.request<T>('DELETE', this.buildUrl(path))\n }\n\n /**\n * GET request that returns the raw, unparsed `Response` instead of decoded JSON.\n * Used for binary downloads (e.g. `GET /v1/acquisitions/{id}/corpus/download`,\n * which streams a gzip archive when the corpus is ready, or a JSON\n * `CorpusResponse` body otherwise).\n *\n * Applies the same `Authorization` header injection and single-retry-on-401\n * behaviour as {@link HttpClient.get}, and maps a non-2xx response to the same\n * typed errors — it just skips the `response.json()` decode step so the caller\n * can read the body as a stream, blob, or array buffer.\n *\n * @param path - API path (e.g. `/v1/acquisitions/{id}/corpus/download`)\n * @returns The raw `Response`. Callers are responsible for reading its body.\n */\n async getRaw(path: string): Promise<Response> {\n return this.performRequest('GET', this.buildUrl(path), {\n Accept: 'application/gzip, application/json',\n })\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, params?: Record<string, string | number | undefined>): string {\n const url = `${this.baseUrl}${path}`\n if (!params) return url\n const filtered = Object.entries(params).filter(\n (entry): entry is [string, string | number] => entry[1] !== undefined,\n )\n if (filtered.length === 0) return url\n const qs = new URLSearchParams(filtered.map(([k, v]) => [k, String(v)]))\n return `${url}?${qs.toString()}`\n }\n\n private async request<T>(\n method: string,\n url: string,\n body?: unknown,\n options?: RequestOptions,\n ): Promise<T> {\n const response = await this.performRequest(\n method,\n url,\n { 'Content-Type': 'application/json', Accept: 'application/json' },\n body,\n false,\n options,\n )\n\n if (response.status === 204) {\n return undefined as T\n }\n\n return response.json() as Promise<T>\n }\n\n /**\n * Shared auth-injection, single-401-retry, and error-mapping logic behind both\n * `request()` (JSON in, JSON out) and `getRaw()` (JSON in, raw `Response` out).\n */\n private async performRequest(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: unknown,\n isRetry = false,\n options?: RequestOptions,\n ): Promise<Response> {\n const useAuth = options?.auth !== false\n const token = useAuth ? await this.getAccessToken() : null\n const finalHeaders: Record<string, string> = { ...headers }\n if (token) finalHeaders['Authorization'] = `Bearer ${token}`\n\n const response = await fetch(url, {\n method,\n headers: finalHeaders,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n\n if (response.status === 401 && !isRetry) {\n if (useAuth) {\n const newToken = await this.onUnauthorized()\n if (newToken) {\n return this.performRequest(method, url, headers, body, true, options)\n }\n }\n throw new AuthError('Session expired. Please re-authenticate.')\n }\n\n if (!response.ok) {\n await this.throwApiError(response)\n }\n\n return response\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let body: unknown\n try {\n body = await response.json()\n } catch {\n // Non-JSON body - fall through to use statusText\n }\n\n const spendCapError = spendCapErrorFromBody(body)\n if (spendCapError) {\n throw spendCapError\n }\n\n const { message, code, type, details } = extractErrorInfo(body, response.statusText)\n\n switch (response.status) {\n case 401:\n throw new AuthError(message, code, type, details)\n case 403:\n throw new ForbiddenError(message, code, type, details)\n case 404:\n throw new NotFoundError(message, code, type, details)\n default:\n throw new LedewireError(message, response.status, code, type, details)\n }\n }\n}\n","import type { StoredTokens, TokenStorage } from './types.js'\nimport { AuthError } from './errors.js'\n\n/** How many milliseconds before expiry to proactively refresh the token. */\nconst REFRESH_THRESHOLD_MS = 60_000 // 60 seconds\n\n/**\n * Options for constructing a `TokenManager`.\n */\nexport interface TokenManagerOptions {\n storage: TokenStorage\n /**\n * Exchanges a refresh token for a new token pair.\n * Implemented by each package's client factory using the\n * `/v1/auth/token/refresh` endpoint.\n */\n refreshFn: (refreshToken: string) => Promise<StoredTokens>\n /**\n * Called after a successful background token refresh (not on initial login).\n * Use for side-effects only — e.g. audit logging, cache invalidation, or\n * notifying a secondary system when tokens rotate.\n *\n * **Do not use this for token persistence.** The `storage` adapter's\n * `setTokens` is the canonical persistence hook and is already called on\n * every refresh. Providing both will result in double-writes.\n *\n * @example\n * ```ts\n * onTokenRefreshed: async (tokens) => {\n * await auditLog.record('token_refreshed', { expiresAt: tokens.expiresAt })\n * }\n * ```\n */\n onTokenRefreshed?: (tokens: StoredTokens) => void | Promise<void>\n /**\n * Called when a refresh attempt fails and the user must re-authenticate.\n * Typically used to redirect to login or emit a UI event.\n *\n * @example\n * ```ts\n * onAuthExpired: () => { window.location.href = '/login' }\n * ```\n */\n onAuthExpired?: () => void | Promise<void>\n}\n\n/**\n * Manages the JWT token lifecycle transparently.\n *\n * - Proactively refreshes the access token when it expires within 60 seconds\n * - Handles reactive refresh on 401 responses from the HTTP client\n * - Deduplicates concurrent refresh calls (only one in-flight refresh at a time)\n * - Fires `onAuthExpired` when refresh fails so the UI can prompt re-login\n *\n * This is an internal class - use the package-level client factories instead.\n */\nexport class TokenManager {\n private readonly storage: TokenStorage\n private readonly refreshFn: TokenManagerOptions['refreshFn']\n private readonly onTokenRefreshed: TokenManagerOptions['onTokenRefreshed']\n private readonly onAuthExpired: TokenManagerOptions['onAuthExpired']\n private refreshPromise: Promise<StoredTokens | null> | null = null\n\n constructor(options: TokenManagerOptions) {\n this.storage = options.storage\n this.refreshFn = options.refreshFn\n this.onTokenRefreshed = options.onTokenRefreshed\n this.onAuthExpired = options.onAuthExpired\n }\n\n /**\n * Returns a valid access token, refreshing proactively if needed.\n * Returns `null` if no tokens are stored (user not authenticated).\n */\n async getAccessToken(): Promise<string | null> {\n const stored = await this.storage.getTokens()\n if (!stored) return null\n\n const expiresInMs = stored.expiresAt - Date.now()\n if (expiresInMs < REFRESH_THRESHOLD_MS) {\n const refreshed = await this.performRefresh(stored.refreshToken)\n return refreshed?.accessToken ?? null\n }\n\n return stored.accessToken\n }\n\n /**\n * Called by `HttpClient` when a 401 is received.\n * Attempts one refresh; returns the new access token or null.\n */\n async handleUnauthorized(): Promise<string | null> {\n const stored = await this.storage.getTokens()\n if (!stored) {\n await this.onAuthExpired?.()\n return null\n }\n const refreshed = await this.performRefresh(stored.refreshToken)\n if (!refreshed) await this.onAuthExpired?.()\n return refreshed?.accessToken ?? null\n }\n\n /** Store new tokens after a successful login or signup. */\n async setTokens(tokens: StoredTokens): Promise<void> {\n await this.storage.setTokens(tokens)\n }\n\n /** Clear all stored tokens (call on logout). */\n async clearTokens(): Promise<void> {\n await this.storage.clearTokens()\n }\n\n // ---------------------------------------------------------------------------\n // Private\n // ---------------------------------------------------------------------------\n\n private performRefresh(refreshToken: string): Promise<StoredTokens | null> {\n if (this.refreshPromise) return this.refreshPromise\n\n this.refreshPromise = this.refreshFn(refreshToken)\n .then(async (tokens) => {\n await this.storage.setTokens(tokens)\n await this.onTokenRefreshed?.(tokens)\n return tokens\n })\n .catch((_err: unknown) => {\n void this.storage.clearTokens()\n throw new AuthError('Token refresh failed. Please re-authenticate.')\n })\n .finally(() => {\n this.refreshPromise = null\n })\n\n return this.refreshPromise\n }\n}\n\n// ---------------------------------------------------------------------------\n// Built-in storage adapters\n// ---------------------------------------------------------------------------\n\n/**\n * In-memory token storage (default for both packages).\n * Tokens are cleared when the page unloads or the process exits.\n * This is the most secure default for browser environments.\n */\nexport class MemoryTokenStorage implements TokenStorage {\n private tokens: StoredTokens | null = null\n\n getTokens(): StoredTokens | null {\n return this.tokens\n }\n\n setTokens(tokens: StoredTokens): void {\n this.tokens = tokens\n }\n\n clearTokens(): void {\n this.tokens = null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts an `expires_at` ISO 8601 string from an API auth response\n * into a Unix timestamp (milliseconds) for use in `StoredTokens.expiresAt`.\n *\n * @param expiresAt - ISO 8601 datetime string, e.g. `\"2026-01-01T12:00:00Z\"`\n * @returns Unix timestamp in milliseconds\n */\nexport function parseExpiresAt(expiresAt: string): number {\n return new Date(expiresAt).getTime()\n}\n\n/**\n * Creates the standard LedeWire token refresh function for use with `TokenManager`.\n *\n * Encapsulates the `/v1/auth/token/refresh` fetch call, response mapping, and\n * error handling so both `createClient` (node) and `init` (browser) share a\n * single implementation.\n *\n * @param baseUrl - The resolved API base URL (e.g. `'https://api.ledewire.com'`)\n * @returns A `refreshFn` compatible with `TokenManagerOptions['refreshFn']`\n */\nexport function createRefreshFn(baseUrl: string): TokenManagerOptions['refreshFn'] {\n return async (refreshToken: string): Promise<StoredTokens> => {\n const res = await fetch(`${baseUrl}/v1/auth/token/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refresh_token: refreshToken }),\n })\n if (!res.ok) throw new Error('Token refresh failed')\n const data = (await res.json()) as {\n access_token: string\n refresh_token: string\n expires_at: string\n }\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: parseExpiresAt(data.expires_at),\n }\n }\n}\n","/**\n * Buyer authentication namespace for browser environments.\n *\n * Handles buyer signup, email/password login, Google OAuth, and password reset.\n * Tokens are stored automatically in the `TokenManager` after every\n * successful call — callers never need to manage tokens directly.\n *\n * For seller/API key authentication, use {@link BrowserSellerNamespace.loginWithApiKey}\n * via `lw.seller.loginWithApiKey()`.\n *\n * @module\n */\nimport { parseExpiresAt } from '@ledewire/core'\nimport type { HttpClient, TokenManager } from '@ledewire/core'\nimport type {\n AuthLoginEmailRequest,\n AuthLoginBuyerApiKeyRequest,\n AuthLoginOAuthRequest,\n AuthPasswordResetBody,\n AuthPasswordResetRequestBody,\n AuthPasswordResetResponse,\n AuthSignupRequest,\n AuthenticationResponse,\n} from '@ledewire/core'\n\n/**\n * Buyer authentication: signup, email/password login, Google OAuth, password reset.\n *\n * Obtain via `lw.auth` — do not construct directly.\n *\n * @example\n * ```ts\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n * await lw.auth.loginWithEmail({ email: 'u@example.com', password: 'pw' })\n * ```\n */\nexport class BrowserAuthNamespace {\n /** @internal */\n constructor(\n private readonly http: HttpClient,\n private readonly tokenManager: TokenManager,\n ) {}\n\n /**\n * Register a new buyer account with email and password.\n * Tokens are stored automatically after successful signup.\n *\n * @param body - Signup credentials and display name.\n * @returns The authentication token response.\n */\n async signup(body: AuthSignupRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/signup', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Log in with email and password.\n * Tokens are stored automatically after successful login.\n *\n * @param body - Email and password credentials.\n * @returns The authentication token response.\n */\n async loginWithEmail(body: AuthLoginEmailRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/email', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Log in with a Google ID token obtained from the Google OAuth flow.\n * Tokens are stored automatically after successful login.\n *\n * @param body - The Google ID token.\n * @returns The authentication token response.\n */\n async loginWithGoogle(body: AuthLoginOAuthRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/google', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Log in using a buyer API key and secret.\n * Returns a buyer-scoped JWT, stored automatically after successful authentication.\n *\n * Primarily useful when building buyer-facing dashboards where the user\n * has created a named API key and wishes to authenticate with it programmatically,\n * or for agent workflows running inside a browser context.\n *\n * @param body - The buyer API key and secret.\n * @returns The authentication token response.\n *\n * @example\n * ```ts\n * await lw.auth.loginWithBuyerApiKey({\n * key: 'bktst_abc123',\n * secret: 'deadbeef...',\n * })\n * ```\n */\n async loginWithBuyerApiKey(body: AuthLoginBuyerApiKeyRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/buyer-api-key', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Request a password reset code to be sent to the buyer's email address.\n *\n * The response is intentionally ambiguous — if the email does not exist,\n * the API returns the same success message to prevent account enumeration.\n *\n * @param body - The buyer's email address.\n * @returns A response with a confirmation message.\n *\n * @example\n * ```ts\n * await lw.auth.requestPasswordReset({ email: 'buyer@example.com' })\n * // → { data: { message: 'If an account with this email exists, a reset code has been sent.' } }\n * ```\n */\n async requestPasswordReset(\n body: AuthPasswordResetRequestBody,\n ): Promise<AuthPasswordResetResponse> {\n return this.http.post<AuthPasswordResetResponse>('/v1/auth/password/reset-request', body)\n }\n\n /**\n * Reset a buyer's password using the code delivered to their email.\n *\n * Obtain the reset code first by calling `requestPasswordReset()`.\n *\n * @param body - Email address, 6-digit reset code, and the new password.\n * @returns A response with a confirmation message.\n *\n * @example\n * ```ts\n * await lw.auth.resetPassword({\n * email: 'buyer@example.com',\n * reset_code: '123456',\n * password: 'new-secure-password',\n * })\n * ```\n */\n async resetPassword(body: AuthPasswordResetBody): Promise<AuthPasswordResetResponse> {\n return this.http.post<AuthPasswordResetResponse>('/v1/auth/password/reset', body)\n }\n\n private async storeTokens(res: AuthenticationResponse): Promise<void> {\n await this.tokenManager.setTokens({\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n expiresAt: parseExpiresAt(res.expires_at),\n })\n }\n}\n","/**\n * Platform configuration namespace (browser).\n *\n * Provides access to public (unauthenticated) platform-level configuration.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { PublicConfigResponse } from '@ledewire/core'\n\n/**\n * Platform-level configuration for browser clients.\n *\n * Obtain via `client.config` — do not construct directly.\n */\nexport class BrowserConfigNamespace {\n /** @internal */\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns platform-level public configuration.\n * No authentication required — safe to call before the user has signed in.\n *\n * Use `google_client_id` to initialise the Google Identity Services library\n * on the storefront login page without requiring a prior authenticated call.\n *\n * @example\n * ```ts\n * const lw = init({ apiKey: 'your_api_key' })\n * const { google_client_id } = await lw.config.getPublic()\n * google.accounts.id.initialize({ client_id: google_client_id, callback })\n * ```\n */\n async getPublic(): Promise<PublicConfigResponse> {\n return this.http.get<PublicConfigResponse>('/v1/config/public')\n }\n}\n","import { decodeContentFields } from '@ledewire/core'\nimport type { HttpClient } from '@ledewire/core'\nimport type { ContentWithAccessResponse } from '@ledewire/core'\n\n/**\n * Buyer content namespace — fetch content with real-time access information.\n *\n * Obtain via `lw.content` — do not construct directly.\n *\n * @example\n * ```ts\n * const result = await lw.content.getWithAccess('content-id')\n * if (result.access_info.has_purchased) {\n * // Note: single-use — a past purchase does not imply access. Buy again\n * // via lw.purchases.create() to receive the content; the delivery comes\n * // back directly in that response, not from this endpoint.\n * }\n * ```\n */\nexport class BrowserContentNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns a content item together with access information for the\n * authenticated buyer (or a generic access response when unauthenticated).\n *\n * @param id - The content ID.\n * @returns The content item with access information. `content_body` and\n * `teaser` are returned as plain UTF-8 text — the SDK decodes base64\n * transparently so you can render them directly.\n *\n * @example\n * ```ts\n * const result = await lw.content.getWithAccess('article-123')\n * if (result.access_info.next_required_action === 'purchase') {\n * // Buy (or re-buy) via lw.purchases.create() — the response carries\n * // content_body / content_uri directly. has_purchased means only\n * // \"has ever bought\" and does not by itself grant access.\n * }\n * ```\n */\n async getWithAccess(id: string): Promise<ContentWithAccessResponse> {\n const res = await this.http.get<ContentWithAccessResponse>(\n `/v1/content/${encodeURIComponent(id)}/with-access`,\n )\n return decodeContentFields(res)\n }\n}\n","import type { HttpClient } from '@ledewire/core'\nimport type { PurchaseCreateRequest, PurchaseResponse } from '@ledewire/core'\n\n/**\n * Buyer purchases namespace — create and retrieve content purchases.\n *\n * **Single-use purchase model:** a completed purchase does not imply\n * standing access. `has_purchased` on other endpoints means only \"has ever\n * bought\" — it is not a re-access grant. Buying again is how the buyer\n * receives the content a second time; see {@link BrowserPurchasesNamespace.create}.\n *\n * Obtain via `lw.purchases` — do not construct directly.\n *\n * @example\n * ```ts\n * await lw.purchases.create({ content_id: 'content-id' })\n * const all = await lw.purchases.list()\n * ```\n */\nexport class BrowserPurchasesNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Completes a content purchase using the buyer's wallet balance and\n * delivers the content in the same response.\n *\n * **This response is the only place the delivered content ever arrives.**\n * For a deliverable LedeWire holds, `content_body` carries the full body as\n * plain UTF-8 text — it is never base64-encoded on the wire, so no\n * `atob()` or decoding step is needed. For a deliverable hosted elsewhere,\n * `content_uri` carries its URL instead. Neither field is present on\n * {@link BrowserPurchasesNamespace.get} or {@link BrowserPurchasesNamespace.list}\n * — there is no route that serves the same content a second time — so\n * persist `content_body` / `content_uri` immediately if you need it later.\n * A past purchase does not grant re-access: buying the same content again\n * is a new charge that delivers it again.\n *\n * @param body - The content ID and expected price in cents.\n * @returns The completed purchase record, including the delivered content.\n * @throws {SpendCapReachedError} `402` — the buyer's daily spend cap has\n * been reached. There is no funding URL for this refusal: adding money\n * to the wallet does not clear it. It clears only when the spend window\n * rolls over at `resetsAt`, or when the cap is raised via\n * `lw.user.spendCap.update()`.\n * @throws {NotFoundError} `404` — the content does not exist, or its\n * visibility is `unlisted` (non-public) and this buyer has no standing\n * grant to see it. Non-public content is not purchasable through this\n * endpoint.\n *\n * @example\n * ```ts\n * const purchase = await lw.purchases.create({ content_id: 'content-id' })\n * await saveDeliveredContent(purchase) // persist now — one-time delivery\n *\n * if (purchase.content_body && purchase.content.content_type === 'markdown') {\n * renderMarkdown(purchase.content_body)\n * } else if (purchase.content_body && purchase.content.content_type === 'html') {\n * // Inline HTML is seller-supplied — sanitise before inserting it.\n * container.innerHTML = DOMPurify.sanitize(purchase.content_body)\n * } else if (purchase.content_uri) {\n * // Seller-supplied URI — check the scheme before navigating to it.\n * const uri = new URL(purchase.content_uri)\n * if (['https:', 'http:'].includes(uri.protocol)) {\n * window.location.href = purchase.content_uri\n * }\n * }\n * ```\n */\n async create(body: PurchaseCreateRequest): Promise<PurchaseResponse> {\n return this.http.post<PurchaseResponse>('/v1/purchases', body)\n }\n\n /**\n * Returns all purchases made by the authenticated buyer.\n *\n * @returns A list of purchase records, newest first.\n */\n async list(): Promise<PurchaseResponse[]> {\n return this.http.get<PurchaseResponse[]>('/v1/purchases')\n }\n\n /**\n * Returns a single purchase by ID.\n *\n * @param id - The purchase ID.\n * @returns The purchase record.\n */\n async get(id: string): Promise<PurchaseResponse> {\n return this.http.get<PurchaseResponse>(`/v1/purchases/${encodeURIComponent(id)}`)\n }\n}\n","/**\n * Seller content namespace for browser environments.\n *\n * Read-only operations using a view-permission API key token.\n * Hits the `/v1/seller/content` family of endpoints — store identity is\n * derived server-side from the token, so no `store_id` is required.\n *\n * @module\n */\nimport { decodeContentFields } from '@ledewire/core'\nimport type { HttpClient } from '@ledewire/core'\nimport type { ContentResponse } from '@ledewire/core'\n\n/**\n * Search criteria for seller content search.\n * At least one field must be supplied. All supplied fields must match (AND logic).\n */\nexport interface SellerContentSearchRequest {\n /** Case-insensitive partial match against the content title. */\n title?: string\n /** Case-insensitive partial match against the content URI (`external_ref` content only). */\n uri?: string\n /**\n * Exact match against the content's external identifier.\n * Use the full formatted value as it appears in `ContentResponse.external_identifier`,\n * e.g. `'vimeo:123456789'`.\n */\n external_identifier?: string\n /** Exact key/value pairs to AND-match against content metadata. */\n metadata?: Record<string, unknown>\n}\n\n/**\n * Seller content namespace — list, search, and fetch store content by API key.\n *\n * Obtain via `lw.seller.content` — do not construct directly.\n *\n * @example\n * ```ts\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n * await lw.seller.loginWithApiKey({ key: 'your_api_key' })\n *\n * const items = await lw.seller.content.list()\n * const results = await lw.seller.content.search({ title: 'intro' })\n * const item = await lw.seller.content.get('content-id')\n * ```\n */\nexport class BrowserSellerContentNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all content for the authenticated seller's store.\n * Requires a token with at least `view` permission.\n *\n * @returns Array of content items. `teaser` is returned as plain text —\n * the SDK decodes base64 automatically.\n *\n * @example\n * ```ts\n * const items = await lw.seller.content.list()\n * ```\n */\n async list(): Promise<ContentResponse[]> {\n const res = await this.http.get<ContentResponse[]>('/v1/seller/content')\n return res.map(decodeContentFields)\n }\n\n /**\n * Search content by title, URI, and/or metadata (AND logic).\n * At least one criterion must be supplied.\n * Requires a token with at least `view` permission.\n *\n * @param body - Search criteria (title, uri, and/or metadata).\n * @returns Array of matching content items. `teaser` is returned as plain\n * text — the SDK decodes base64 automatically.\n *\n * @example\n * ```ts\n * const results = await lw.seller.content.search({ title: 'intro' })\n * const byUri = await lw.seller.content.search({ uri: 'vimeo.com' })\n * const byId = await lw.seller.content.search({ external_identifier: 'vimeo:123456789' })\n * const byMeta = await lw.seller.content.search({ metadata: { author: 'Alice' } })\n * ```\n */\n async search(body: SellerContentSearchRequest): Promise<ContentResponse[]> {\n const res = await this.http.post<ContentResponse[]>('/v1/seller/content/search', body)\n return res.map(decodeContentFields)\n }\n\n /**\n * Get a single content item by ID.\n * Requires a token with at least `view` permission.\n *\n * @param id - The content ID.\n * @returns The content item. `content_body` and `teaser` are returned as\n * plain UTF-8 text — the SDK decodes base64 automatically so you can render\n * them directly without calling `atob()`.\n *\n * @example\n * ```ts\n * const item = await lw.seller.content.get('content-id')\n * // item.content_body is plain markdown — no atob() needed\n * ```\n */\n async get(id: string): Promise<ContentResponse> {\n const res = await this.http.get<ContentResponse>(`/v1/seller/content/${encodeURIComponent(id)}`)\n return decodeContentFields(res)\n }\n}\n","/**\n * Browser seller namespace — API-key-authenticated read operations.\n *\n * @module\n */\nimport { parseExpiresAt } from '@ledewire/core'\nimport type { HttpClient, TokenManager } from '@ledewire/core'\nimport type { AuthLoginApiKeyRequest, AuthenticationResponse } from '@ledewire/core'\nimport { BrowserSellerContentNamespace } from './content.js'\n\n/**\n * Seller operations accessible with a view-permission API key token.\n *\n * Obtain via `lw.seller` — do not construct directly.\n *\n * @example\n * ```ts\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n *\n * // Authenticate as a seller (key-only = view; key+secret = full)\n * await lw.seller.loginWithApiKey({ key: 'your_api_key' })\n * const items = await lw.seller.content.list()\n * ```\n */\nexport class BrowserSellerNamespace {\n /** Seller content: list, search, and get by API key. */\n readonly content: BrowserSellerContentNamespace\n\n /** @internal */\n constructor(\n private readonly http: HttpClient,\n private readonly tokenManager: TokenManager,\n ) {\n this.content = new BrowserSellerContentNamespace(http)\n }\n\n /**\n * Log in using an API key to obtain a seller token.\n * Provide only `key` for read-only (`view`) access.\n * Provide both `key` and `secret` for read/write (`full`) access.\n * Tokens are stored automatically after successful authentication.\n *\n * Use this before calling `lw.seller.content.*` methods.\n *\n * @param body - API key credentials.\n * @returns The authentication token response.\n *\n * @example\n * ```ts\n * // View access (read-only) — sufficient for seller.content.list/search/get\n * await lw.seller.loginWithApiKey({ key: 'your_api_key' })\n *\n * // Full access (read/write)\n * await lw.seller.loginWithApiKey({ key: 'your_api_key', secret: 'your_secret' })\n * ```\n */\n async loginWithApiKey(body: AuthLoginApiKeyRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/api-key', body)\n await this.tokenManager.setTokens({\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n expiresAt: parseExpiresAt(res.expires_at),\n })\n return res\n }\n}\n","import type { HttpClient } from '@ledewire/core'\nimport type {\n WalletBalanceResponse,\n WalletPaymentSessionRequest,\n WalletPaymentSessionResponse,\n WalletPaymentStatusResponse,\n WalletTransactionItem,\n} from '@ledewire/core'\n\n/**\n * Buyer wallet namespace — balance, transactions, and payment session management.\n *\n * Obtain via `lw.wallet` — do not construct directly.\n *\n * @example\n * ```ts\n * const { balance_cents } = await lw.wallet.balance()\n * const session = await lw.wallet.createPaymentSession({ amount_cents: 500 })\n * ```\n */\nexport class BrowserWalletNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns the authenticated buyer's current wallet balance.\n *\n * `balance_cents` and `spendable_cents` are always the same number —\n * `balance_cents` has always meant \"what you can spend,\" and money committed to\n * a bulk acquisition is a hold, which moves it out of the wallet rather than\n * annotating it. `held_cents` is the total currently committed to active bulk\n * acquisitions and not yet spent or released, and `holds` lists one entry per\n * such acquisition (`acquisition_id`, `held_cents`, `authorized_at`) so a buyer\n * mid-acquisition can see why their balance is lower than their purchase\n * history explains.\n *\n * @returns The current wallet balance in cents, including held funds detail.\n */\n async balance(): Promise<WalletBalanceResponse> {\n return this.http.get<WalletBalanceResponse>('/v1/wallet/balance')\n }\n\n /**\n * Returns the authenticated buyer's wallet transaction history, newest first.\n *\n * `bulk_acquisition` and `bulk_hold` are each a single entry for a whole bulk\n * acquisition — its per-work purchases are deliberately not listed here,\n * because one acquisition can hold tens of thousands of them and they describe\n * one decision. A `bulk_hold` entry is an acquisition still holding funds (money\n * left the wallet but has not been spent); it becomes a `bulk_acquisition` entry\n * for the amount actually captured once the acquisition ends, and an\n * acquisition never produces both. Note that a bulk acquisition's per-work\n * purchases each carry a display `price_cents` that is **not summable** — bulk\n * prices at micro precision and rounds to cents once, on the acquisition total,\n * so `amount_cents` on the `bulk_acquisition` / `bulk_hold` entry is the figure\n * to read.\n *\n * @returns A list of completed wallet transaction entries.\n */\n async transactions(): Promise<WalletTransactionItem[]> {\n return this.http.get<WalletTransactionItem[]>('/v1/wallet/transactions')\n }\n\n /**\n * Creates a payment session for funding the buyer's wallet.\n *\n * @param body - The amount and currency to fund.\n * @returns Payment session details for use with the payment provider widget.\n */\n async createPaymentSession(\n body: WalletPaymentSessionRequest,\n ): Promise<WalletPaymentSessionResponse> {\n return this.http.post<WalletPaymentSessionResponse>('/v1/wallet/payment-session', body)\n }\n\n /**\n * Polls the status of a wallet funding payment session.\n *\n * @param sessionId - The session ID returned by `createPaymentSession`.\n * @returns The current payment status.\n */\n async getPaymentStatus(sessionId: string): Promise<WalletPaymentStatusResponse> {\n return this.http.get<WalletPaymentStatusResponse>(\n `/v1/wallet/payment-status/${encodeURIComponent(sessionId)}`,\n )\n }\n}\n","import type { HttpClient } from '@ledewire/core'\nimport type { CheckoutStateResponse } from '@ledewire/core'\n\n/**\n * Checkout namespace — buyer checkout state for a specific content item.\n *\n * Obtain via `lw.checkout` — do not construct directly.\n *\n * @example\n * ```ts\n * const state = await lw.checkout.state('content-id')\n * // state.checkout_state.next_required_action:\n * // 'authenticate' | 'fund_wallet' | 'purchase'\n * //\n * // Single-use model: a completed purchase does not imply access, so\n * // 'purchase' can still be the next action even when has_purchased is\n * // true. Buying delivers the content directly in the POST /v1/purchases\n * // response — there is no separate \"view content\" step.\n * ```\n */\nexport class CheckoutNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns the authenticated buyer's checkout readiness for a given piece of\n * content. Indicates whether the buyer needs to authenticate, fund their\n * wallet, or purchase before accessing the content.\n *\n * Works without authentication — returns anonymous checkout state when the\n * buyer is not logged in.\n *\n * @param contentId - The content item ID.\n * @returns The checkout state, including what action is required next.\n */\n async state(contentId: string): Promise<CheckoutStateResponse> {\n return this.http.get<CheckoutStateResponse>(\n `/v1/checkout/state/${encodeURIComponent(contentId)}`,\n )\n }\n}\n","/**\n * Buyer API key management namespace.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { UserApiKey, UserApiKeyCreateRequest, UserApiKeyCreateResponse } from '@ledewire/core'\n\n/**\n * Manage buyer API keys for the authenticated user.\n *\n * Buyer API keys are the authentication credential for autonomous agents — they\n * allow an agent to obtain a buyer JWT via `auth.loginWithBuyerApiKey()` without\n * requiring a username and password. Each key is named, independently revocable,\n * and can carry an optional `spending_limit_cents` ceiling.\n *\n * **Secret handling:** `create()` returns the `secret` exactly once. It is never\n * retrievable again after the response is received — store it immediately in a\n * secrets manager (e.g. environment variable, Vault, AWS Secrets Manager).\n *\n * Obtain via `client.user.apiKeys` — do not construct directly.\n *\n * @example\n * ```ts\n * // Create a key for an agent, with a $10 spend ceiling\n * const { key, secret } = await client.user.apiKeys.create({\n * name: 'my-rag-agent',\n * spending_limit_cents: 1000,\n * })\n * // Store secret immediately — it cannot be retrieved again\n * await secretsManager.put('LEDEWIRE_BUYER_SECRET', secret)\n *\n * // List all keys (secrets never included)\n * const keys = await client.user.apiKeys.list()\n *\n * // Revoke a compromised key\n * await client.user.apiKeys.revoke(keys[0].id)\n * ```\n */\nexport class UserApiKeysNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns all buyer API keys for the authenticated user.\n * The `secret` is never included in list responses.\n *\n * @returns Array of API key records.\n */\n async list(): Promise<UserApiKey[]> {\n return this.http.get<UserApiKey[]>('/v1/user/api-keys')\n }\n\n /**\n * Creates a new buyer API key.\n *\n * The `secret` in the response is shown exactly once and cannot be retrieved\n * again. Store it immediately in a secrets manager before discarding the\n * response object.\n *\n * @param body - Name and optional spend ceiling for the new key.\n * @returns The new key's public identifier and one-time secret.\n *\n * @example\n * ```ts\n * const { key, secret } = await client.user.apiKeys.create({\n * name: 'production-agent',\n * spending_limit_cents: 5000, // $50 cap\n * })\n * // ⚠️ Store secret NOW — it is shown once only\n * process.env.LEDEWIRE_BUYER_SECRET = secret\n * ```\n */\n async create(body: UserApiKeyCreateRequest): Promise<UserApiKeyCreateResponse> {\n return this.http.post<UserApiKeyCreateResponse>('/v1/user/api-keys', body)\n }\n\n /**\n * Revokes (permanently deletes) a buyer API key by ID.\n *\n * Any agent currently using this key will receive `401` on its next\n * token refresh. Revocation takes effect immediately.\n *\n * @param id - UUID of the API key to revoke.\n */\n async revoke(id: string): Promise<void> {\n return this.http.delete(`/v1/user/api-keys/${encodeURIComponent(id)}`)\n }\n}\n","/**\n * Buyer daily spend cap namespace.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { UserSpendCap, UserSpendCapUpdateRequest } from '@ledewire/core'\n\n/**\n * Manage the authenticated buyer's daily spend cap.\n *\n * Every new buyer starts with a default cap, so `null` on {@link\n * UserSpendCapNamespace.update} is the only way to become uncapped — there is no\n * separate \"remove the cap\" call. While capped, `cap_cents` and `remaining_cents`\n * are numbers; once uncapped, both read back as `null` because there is no ceiling\n * to report or subtract from.\n *\n * The cap governs every wallet debit the buyer makes — MCP, REST, or the web\n * payment gate — over a rolling window bounded by `spend_window_timezone` (an IANA\n * zone, UTC by default) and reset at `resets_at`. `bulk_exempt` says whether this\n * buyer's bulk acquisitions are excluded from that spend, in which case\n * `spent_cents` / `remaining_cents` describe ordinary purchases only.\n *\n * **Exceeding the cap throws {@link SpendCapReachedError}** (HTTP 402) from\n * `client.purchases.create()` and the x402 content gate. Funding the wallet does not\n * clear it — the buyer must wait for the window to roll at `resets_at`, or the cap\n * must be raised or cleared here.\n *\n * Obtain via `client.user.spendCap` — do not construct directly.\n *\n * @example\n * ```ts\n * const cap = await client.user.spendCap.get()\n * if (cap.remaining_cents !== null && cap.remaining_cents < 500) {\n * console.warn(`Only ${cap.remaining_cents}c left before the cap resets at ${cap.resets_at}`)\n * }\n *\n * // Raise the cap to $20/day\n * await client.user.spendCap.update({ daily_spend_limit_cents: 2000 })\n *\n * // Remove the cap entirely (become uncapped)\n * await client.user.spendCap.update({ daily_spend_limit_cents: null })\n * ```\n */\nexport class UserSpendCapNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns the authenticated buyer's spend cap, read against the current spend\n * window.\n *\n * @returns The current spend cap, spend-to-date, and reset time.\n */\n async get(): Promise<UserSpendCap> {\n return this.http.get<UserSpendCap>('/v1/user/spend-cap')\n }\n\n /**\n * Sets or clears the authenticated buyer's daily spend cap.\n *\n * `daily_spend_limit_cents` is required and nullable: pass a number to set the\n * cap, or `null` to remove it (the only way to become uncapped). A cap set below\n * spend already made in the current window is accepted — it just leaves\n * `remaining_cents` at zero until the window rolls.\n *\n * @param body - The new cap in whole cents, or `null` to remove it.\n * @returns The updated spend cap.\n */\n async update(body: UserSpendCapUpdateRequest): Promise<UserSpendCap> {\n return this.http.patch<UserSpendCap>('/v1/user/spend-cap', body)\n }\n}\n","/**\n * MCP API key management namespace.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { McpApiKey, McpApiKeyCreateRequest, McpApiKeyCreateResponse } from '@ledewire/core'\n\n/**\n * Manage the authenticated buyer's MCP API keys.\n *\n * MCP API keys authenticate agent requests against the Ledewire MCP server, sent\n * as `Authorization: Bearer <key>:<secret>`. Each key carries an explicit set of\n * scopes — `can_search` (default `true`), `can_purchase` (default `false`), and\n * the seller-tier `can_manage_content` / `can_read_analytics`, which additionally\n * require `store_id` to be set to a store the user owns or authors.\n *\n * **Secret handling:** `create()` returns the `secret` exactly once. It is never\n * retrievable again — store it immediately, alongside the `key`, in a secrets\n * manager.\n *\n * **Changing permissions:** scopes are fixed at creation. To change what a key\n * can do, revoke it and create a replacement with the desired scopes.\n *\n * Obtain via `client.user.mcpKeys` — do not construct directly.\n *\n * @example\n * ```ts\n * // Create a search+purchase key for an autonomous agent\n * const { key, secret } = await client.user.mcpKeys.create({\n * label: 'my-rag-agent',\n * can_search: true,\n * can_purchase: true,\n * })\n * // Store immediately — the secret cannot be retrieved again\n * await secretsManager.put('LEDEWIRE_MCP_CREDENTIAL', `${key}:${secret}`)\n *\n * // List all keys (secrets never included)\n * const keys = await client.user.mcpKeys.list()\n *\n * // To change permissions: revoke and recreate\n * await client.user.mcpKeys.revoke(keys[0].id)\n * ```\n */\nexport class UserMcpKeysNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns all MCP API keys for the authenticated user.\n * The `secret` is never included in list responses.\n *\n * @returns Array of MCP API key records.\n */\n async list(): Promise<McpApiKey[]> {\n return this.http.get<McpApiKey[]>('/v1/mcp/keys')\n }\n\n /**\n * Creates a new MCP API key.\n *\n * The `secret` in the response is shown exactly once and cannot be retrieved\n * again. Store it immediately alongside `key` — the pair is used together as\n * `Authorization: Bearer <key>:<secret>` against the Ledewire MCP server.\n *\n * @param body - Label and scopes for the new key.\n * @returns The new key's public identifier, scopes, and one-time secret.\n *\n * @example\n * ```ts\n * const { key, secret } = await client.user.mcpKeys.create({\n * label: 'production-agent',\n * can_search: true,\n * can_purchase: true,\n * })\n * ```\n */\n async create(body: McpApiKeyCreateRequest): Promise<McpApiKeyCreateResponse> {\n return this.http.post<McpApiKeyCreateResponse>('/v1/mcp/keys', body)\n }\n\n /**\n * Revokes (permanently deletes) an MCP API key by ID.\n *\n * To change a key's permissions, revoke it and create a replacement with the\n * desired scopes — scopes cannot be edited in place.\n *\n * @param id - UUID of the MCP API key to revoke.\n */\n async revoke(id: string): Promise<void> {\n return this.http.delete(`/v1/mcp/keys/${encodeURIComponent(id)}`)\n }\n}\n","/**\n * User namespace — authenticated buyer account operations.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport { UserApiKeysNamespace } from './api-keys.js'\nimport { UserSpendCapNamespace } from './spend-cap.js'\nimport { UserMcpKeysNamespace } from './mcp-keys.js'\n\n/**\n * Authenticated buyer account operations.\n *\n * Obtain via `client.user` — do not construct directly.\n */\nexport class UserNamespace {\n /**\n * Buyer API key management: create, list, and revoke named API keys.\n * Keys are used by autonomous agents to authenticate without a username/password.\n */\n readonly apiKeys: UserApiKeysNamespace\n\n /**\n * The authenticated buyer's daily spend cap: read and update the ceiling that\n * governs every wallet debit (MCP, REST, and the web payment gate).\n */\n readonly spendCap: UserSpendCapNamespace\n\n /**\n * MCP API key management: create, list, and revoke keys scoped for use against\n * the Ledewire MCP server.\n */\n readonly mcpKeys: UserMcpKeysNamespace\n\n /** @internal */\n constructor(http: HttpClient) {\n this.apiKeys = new UserApiKeysNamespace(http)\n this.spendCap = new UserSpendCapNamespace(http)\n this.mcpKeys = new UserMcpKeysNamespace(http)\n }\n}\n","import {\n DEFAULT_BASE_URL,\n HttpClient,\n MemoryTokenStorage,\n TokenManager,\n createRefreshFn,\n} from '@ledewire/core'\nimport type { TokenStorage } from '@ledewire/core'\nimport { BrowserAuthNamespace } from './resources/auth.js'\nimport { BrowserConfigNamespace } from './resources/config.js'\nimport { BrowserContentNamespace } from './resources/content.js'\nimport { BrowserPurchasesNamespace } from './resources/purchases.js'\nimport { BrowserSellerNamespace } from './resources/seller/index.js'\nimport { BrowserWalletNamespace } from './resources/wallet.js'\nimport { CheckoutNamespace } from './resources/checkout.js'\nimport { UserNamespace } from './resources/user/index.js'\n\n/**\n * Configuration options for the LedeWire browser client.\n */\nexport interface BrowserClientConfig {\n /**\n * LedeWire API key that identifies the store.\n * Obtained from the LedeWire merchant dashboard.\n */\n apiKey: string\n /**\n * Override the API base URL.\n * Defaults to `https://api.ledewire.com`.\n */\n baseUrl?: string\n /**\n * Token storage adapter.\n * Defaults to {@link MemoryTokenStorage} (in-memory, most secure).\n *\n * To persist sessions across page reloads, use the built-in\n * `localStorageAdapter`:\n * ```ts\n * import { init, localStorageAdapter } from '@ledewire/browser'\n * const lw = init({ apiKey: '...', storage: localStorageAdapter() })\n * ```\n */\n storage?: TokenStorage\n /**\n * Called when the user's session expires and cannot be refreshed.\n * Use this to show a re-authentication prompt.\n *\n * @example\n * ```ts\n * onAuthExpired: () => showLoginModal()\n * ```\n */\n onAuthExpired?: () => void\n}\n\n/**\n * Initialises a LedeWire browser client.\n * This is the primary entry point for the browser SDK.\n *\n * @example CDN usage:\n * ```html\n * <script src=\"https://cdn.jsdelivr.net/npm/@ledewire/browser@1/dist/ledewire.min.js\"></script>\n * <script>\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n * const state = await lw.checkout.state('content-id')\n * </script>\n * ```\n *\n * @example npm usage:\n * ```ts\n * import { init } from '@ledewire/browser'\n * const lw = init({ apiKey: 'your_api_key' })\n * ```\n */\nexport function init(config: BrowserClientConfig): BrowserClient {\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL\n const storage = config.storage ?? new MemoryTokenStorage()\n\n const tokenManager = new TokenManager({\n storage,\n refreshFn: createRefreshFn(baseUrl),\n ...(config.onAuthExpired !== undefined && { onAuthExpired: config.onAuthExpired }),\n })\n\n const http = new HttpClient({\n baseUrl,\n getAccessToken: () => tokenManager.getAccessToken(),\n onUnauthorized: () => tokenManager.handleUnauthorized(),\n })\n\n return new BrowserClient(http, tokenManager, config)\n}\n\n/**\n * The LedeWire browser client.\n * Access buyer flows through the namespaced properties.\n *\n * @remarks\n * Instantiate with {@link init} rather than constructing directly.\n */\nexport class BrowserClient {\n /** Platform-level public configuration (no auth required) */\n readonly config: BrowserConfigNamespace\n\n /** Buyer authentication: email/password signup/login, Google OAuth, password reset */\n readonly auth: BrowserAuthNamespace\n\n /** Checkout state machine: determines next action for a piece of content */\n readonly checkout: CheckoutNamespace\n\n /** Wallet: balance, fund via payment session, transaction history */\n readonly wallet: BrowserWalletNamespace\n\n /** Content purchases for the authenticated buyer */\n readonly purchases: BrowserPurchasesNamespace\n\n /** Public content with per-user access information */\n readonly content: BrowserContentNamespace\n\n /** Seller operations: API key login, content list/search/get */\n readonly seller: BrowserSellerNamespace\n\n /** Authenticated buyer account: API key management */\n readonly user: UserNamespace\n\n /** @internal */\n constructor(\n private readonly _http: HttpClient,\n private readonly _tokenManager: TokenManager,\n private readonly _config: BrowserClientConfig,\n ) {\n this.config = new BrowserConfigNamespace(_http)\n this.auth = new BrowserAuthNamespace(_http, _tokenManager)\n this.checkout = new CheckoutNamespace(_http)\n this.wallet = new BrowserWalletNamespace(_http)\n this.purchases = new BrowserPurchasesNamespace(_http)\n this.content = new BrowserContentNamespace(_http)\n this.seller = new BrowserSellerNamespace(_http, _tokenManager)\n this.user = new UserNamespace(_http)\n }\n}\n","import type { TokenStorage, StoredTokens } from '@ledewire/core'\n\nconst DEFAULT_STORAGE_KEY = 'lw:tokens'\n\n/**\n * Shared implementation for `localStorage` and `sessionStorage` adapters.\n * Not exported from the public API — use {@link localStorageAdapter} or\n * {@link sessionStorageAdapter} instead.\n *\n * @internal\n */\nexport function webStorageAdapter(backend: Storage, key = DEFAULT_STORAGE_KEY): TokenStorage {\n return {\n getTokens(): StoredTokens | null {\n const raw = backend.getItem(key)\n if (!raw) return null\n try {\n return JSON.parse(raw) as StoredTokens\n } catch {\n // Corrupted value — treat as empty\n return null\n }\n },\n setTokens(tokens: StoredTokens): void {\n backend.setItem(key, JSON.stringify(tokens))\n },\n clearTokens(): void {\n backend.removeItem(key)\n },\n }\n}\n","import type { TokenStorage } from '@ledewire/core'\nimport { webStorageAdapter } from './web-storage-adapter.js'\n\n/**\n * A {@link TokenStorage} adapter that persists tokens in `localStorage`.\n *\n * Tokens survive page reloads and browser restarts, which is convenient\n * for sites where users expect persistent sessions.\n *\n * **Security note:** `localStorage` is accessible to any JavaScript on the\n * same origin. Only use this adapter on sites you fully control and trust.\n * The default in-memory storage is safer for high-security use cases.\n *\n * @param key - The `localStorage` key used to store tokens.\n * Defaults to `'lw:tokens'`. Override this if you have multiple\n * LedeWire integrations on the same origin.\n *\n * @example\n * ```ts\n * import { init, localStorageAdapter } from '@ledewire/browser'\n *\n * const lw = init({\n * apiKey: 'your_api_key',\n * storage: localStorageAdapter(),\n * })\n * ```\n */\nexport function localStorageAdapter(key?: string): TokenStorage {\n return webStorageAdapter(localStorage, key)\n}\n","import type { TokenStorage } from '@ledewire/core'\nimport { webStorageAdapter } from './web-storage-adapter.js'\n\n/**\n * A {@link TokenStorage} adapter that persists tokens in `sessionStorage`.\n *\n * Tokens survive page reloads within the same tab but are cleared when the\n * tab is closed or the session ends. This prevents token leakage across\n * tabs and is a good default for sites where users do not expect persistent\n * sessions (e.g. embedded checkout widgets, kiosk-mode UIs).\n *\n * **Security note:** `sessionStorage` is accessible to any JavaScript on the\n * same origin and tab. It is more isolated than `localStorage` (no\n * cross-tab sharing), but the default in-memory storage is still safer for\n * high-security use cases.\n *\n * @param key - The `sessionStorage` key used to store tokens.\n * Defaults to `'lw:tokens'`. Override this if you have multiple\n * LedeWire integrations on the same origin.\n *\n * @example\n * ```ts\n * import { init, sessionStorageAdapter } from '@ledewire/browser'\n *\n * const lw = init({\n * apiKey: 'your_api_key',\n * storage: sessionStorageAdapter(),\n * })\n * ```\n */\nexport function sessionStorageAdapter(key?: string): TokenStorage {\n return webStorageAdapter(sessionStorage, key)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../core/src/base64.ts","../../core/src/errors.ts","../../core/src/spend-cap.ts","../../core/src/http-client.ts","../../core/src/token-manager.ts","../src/resources/auth.ts","../src/resources/config.ts","../src/resources/content.ts","../src/resources/purchases.ts","../src/resources/seller/content.ts","../src/resources/seller/index.ts","../src/resources/wallet.ts","../src/resources/checkout.ts","../src/resources/company/invitations.ts","../src/resources/company/machine-users.ts","../src/resources/company/members.ts","../src/resources/company/membership.ts","../src/resources/company/reports.ts","../src/resources/company/wallet.ts","../src/resources/company/index.ts","../src/resources/user/api-keys.ts","../src/resources/user/spend-cap.ts","../src/resources/user/mcp-keys.ts","../src/resources/user/index.ts","../src/client.ts","../src/web-storage-adapter.ts","../src/local-storage-adapter.ts","../src/session-storage-adapter.ts"],"sourcesContent":["/**\n * Decode a base64-encoded string to plain UTF-8 text.\n *\n * Used internally by SDK response handlers to transparently decode\n * `content_body` and `teaser` fields from the API wire format.\n *\n * @internal\n */\nexport function decodeBase64(value: string): string {\n return atob(value)\n}\n\n/**\n * Encode a plain UTF-8 string to base64.\n *\n * Used internally by SDK request handlers to re-encode plain-text\n * `content_body` and `teaser` fields before they are sent to the API.\n *\n * @internal\n */\nexport function encodeBase64(value: string): string {\n return btoa(value)\n}\n\n/**\n * Decode base64-encoded `content_body` and `teaser` fields on a content\n * response object. Works with both `ContentResponse` (which may carry\n * `content_body`) and `ContentListItem` (which only carries `teaser`).\n * Null and absent fields are left untouched.\n *\n * @internal\n */\nexport function decodeContentFields<\n T extends { content_body?: string | null; teaser?: string | null },\n>(item: T): T {\n return {\n ...item,\n ...(typeof item.content_body === 'string' && {\n content_body: decodeBase64(item.content_body),\n }),\n ...(typeof item.teaser === 'string' && { teaser: decodeBase64(item.teaser) }),\n } as T\n}\n\n/**\n * Encode plain-text `content_body` and `teaser` fields to base64 before\n * they are sent to the API. Absent and undefined fields are left untouched.\n *\n * @internal\n */\nexport function encodeContentFields<\n T extends {\n content_body?: string | undefined\n teaser?: string | undefined\n [key: string]: unknown\n },\n>(body: T): T {\n const out = { ...body } as Record<string, unknown>\n if (typeof out['content_body'] === 'string')\n out['content_body'] = encodeBase64(out['content_body'])\n if (typeof out['teaser'] === 'string') out['teaser'] = encodeBase64(out['teaser'])\n return out as T\n}\n","import type { ErrorType } from './types.js'\n\n/**\n * Known {@link ErrorType} values, widened to accept any other string the API\n * may introduce. `ErrorType` still drives editor autocomplete; a value the API\n * emits that isn't (yet) in the spec's enum — e.g. `selection_too_large` on\n * `POST /v1/acquisitions` — still type-checks and survives on {@link\n * LedewireError.type} instead of being narrowed away.\n */\nexport type ErrorTypeValue = ErrorType | (string & {})\n\n/**\n * Global-symbol-registry key for the non-enumerable class-brand list every\n * `LedewireError` instance carries. See {@link LedewireError[Symbol.hasInstance]}.\n *\n * `@ledewire/core` is private and bundled separately into every published\n * package (via tsup), so `SpendCapReachedError` — and every other class in\n * this file — exists as a *distinct* class object in `@ledewire/node`,\n * `@ledewire/browser`, and `@ledewire/x402-client`. `Symbol.for` (the global\n * symbol registry, keyed by string and shared process-wide) rather than\n * `Symbol()` means every one of those bundle copies resolves this constant to\n * the *same* symbol, so a brand list written by one copy's constructor is\n * still readable by another copy's `hasInstance` check.\n */\nconst ERROR_BRAND = Symbol.for('@ledewire/error-brands')\n\n/**\n * Base error class for all LedeWire SDK errors.\n * All errors thrown by the SDK are instances of this class,\n * making it safe to use `err instanceof LedewireError` as a type guard.\n *\n * `instanceof` works even when `err` was constructed by a different bundled\n * copy of this class — e.g. an error thrown by `@ledewire/x402-client`\n * checked with the `SpendCapReachedError` bundled into `@ledewire/node`. See\n * {@link LedewireError[Symbol.hasInstance]}.\n *\n * @example\n * ```ts\n * try {\n * await client.purchases.create({ contentId: '...' })\n * } catch (err) {\n * if (err instanceof LedewireError) {\n * console.error(err.statusCode, err.message)\n * }\n * }\n * ```\n */\nexport class LedewireError extends Error {\n /**\n * Class-identity brand used for cross-bundle `instanceof` (see {@link\n * LedewireError[Symbol.hasInstance]}). Hardcoded per class — never derived\n * from `constructor.name` or `this.name`, either of which a minifier can\n * rewrite, silently breaking the brand match.\n */\n static readonly brand: string = 'LedewireError'\n\n /** HTTP status code returned by the API (e.g. 400, 401, 404, 422). */\n public readonly statusCode: number\n\n /** Machine-readable error code from the API error body, if present. */\n public readonly code: number | undefined\n\n /**\n * Machine-readable reason from the API error body's `error.type`, if present.\n * See {@link ErrorType} for the documented values and how to branch on them —\n * the API may emit other values it hasn't documented yet, which still land\n * here as a plain string rather than being dropped.\n */\n public readonly type: ErrorTypeValue | undefined\n\n /**\n * Extra top-level fields from the API error response body, excluding\n * `error` itself. For example, a `selection_too_large` refusal from `POST\n * /v1/acquisitions` (422) carries `maximum` and `submitted` alongside\n * `error`. `undefined` when the body carried no other top-level fields,\n * which is the common case.\n */\n public readonly details: Readonly<Record<string, unknown>> | undefined\n\n constructor(\n message: string,\n statusCode: number,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'LedewireError'\n this.statusCode = statusCode\n this.code = code\n this.type = type\n this.details = details\n // Restore prototype chain (required for extending built-in Error in TS)\n Object.setPrototypeOf(this, new.target.prototype)\n\n // Collect this instance's class brands by walking new.target's own\n // prototype (constructor) chain, so hasInstance can fall back to a\n // brand check when the normal prototype check fails across bundles.\n const brands: string[] = []\n let ctor: unknown = new.target\n while (typeof ctor === 'function') {\n const ownBrand = (ctor as { brand?: unknown }).brand\n if (typeof ownBrand === 'string' && Object.prototype.hasOwnProperty.call(ctor, 'brand')) {\n brands.push(ownBrand)\n }\n ctor = Object.getPrototypeOf(ctor)\n }\n Object.defineProperty(this, ERROR_BRAND, {\n value: brands,\n enumerable: false,\n configurable: true,\n })\n }\n\n /**\n * Makes `err instanceof LedewireError` (and every subclass below) true even\n * when `err` was constructed by a *different* bundled copy of this module.\n * Each published package (`@ledewire/node`, `@ledewire/browser`,\n * `@ledewire/x402-client`) bundles its own copy of `@ledewire/core` via\n * tsup, so the classes are distinct objects with unrelated prototypes —\n * the plain prototype-chain check `instanceof` normally does would fail.\n *\n * Falls back to the brand list every instance carries under a\n * `Symbol.for('@ledewire/error-brands')` key (collected from the `brand`\n * static along the constructing class's prototype chain): true when the\n * ordinary check passes, OR the instance's brand list includes this\n * class's own `brand`.\n */\n static override [Symbol.hasInstance](instance: unknown): boolean {\n if (Function.prototype[Symbol.hasInstance].call(this, instance)) {\n return true\n }\n if (!instance || (typeof instance !== 'object' && typeof instance !== 'function')) {\n return false\n }\n const brands = (instance as Record<PropertyKey, unknown>)[ERROR_BRAND]\n return Array.isArray(brands) && brands.includes(this.brand)\n }\n}\n\n/**\n * Thrown when the request lacks valid authentication credentials,\n * or when a token refresh fails and re-authentication is required.\n */\nexport class AuthError extends LedewireError {\n static override readonly brand: string = 'AuthError'\n\n constructor(\n message: string,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, 401, code, type, details)\n this.name = 'AuthError'\n }\n}\n\n/**\n * Thrown when the authenticated user does not have permission\n * to perform the requested operation.\n *\n * **Common cause — merchant login with the wrong account role:**\n * `POST /v1/auth/merchant/login/email` and `POST /v1/auth/merchant/login/google`\n * return `403 Forbidden` (not `401`) when the credentials are valid but the\n * account has no merchant store associations (e.g. a buyer account used on the\n * merchant endpoint). The `err.message` will be:\n * `\"This account does not have merchant access. Use a merchant or owner account.\"`\n *\n * Use a different account or ask a store owner to add your account as a member.\n *\n * @example\n * ```ts\n * // Browser\n * import { ForbiddenError, AuthError } from '@ledewire/browser'\n *\n * try {\n * await lw.auth.loginWithGoogle({ id_token })\n * } catch (err) {\n * if (err instanceof ForbiddenError) {\n * // Credentials were valid but account lacks the required role.\n * console.error('Access denied:', err.message)\n * } else if (err instanceof AuthError) {\n * // Bad credentials or expired token — re-authenticate.\n * console.error('Authentication failed:', err.message)\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // Node\n * import { ForbiddenError, AuthError } from '@ledewire/node'\n *\n * try {\n * await client.merchant.auth.loginWithGoogle({ id_token })\n * } catch (err) {\n * if (err instanceof ForbiddenError) {\n * // Credentials were valid but account has no merchant store access.\n * // err.message → \"This account does not have merchant access. Use a merchant or owner account.\"\n * console.error('Wrong account role:', err.message)\n * } else if (err instanceof AuthError) {\n * // Bad credentials or expired token — re-authenticate.\n * console.error('Authentication failed:', err.message)\n * }\n * }\n * ```\n */\nexport class ForbiddenError extends LedewireError {\n static override readonly brand: string = 'ForbiddenError'\n\n constructor(\n message: string,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, 403, code, type, details)\n this.name = 'ForbiddenError'\n }\n}\n\n/**\n * Thrown when the requested resource does not exist.\n */\nexport class NotFoundError extends LedewireError {\n static override readonly brand: string = 'NotFoundError'\n\n constructor(\n message: string,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, 404, code, type, details)\n this.name = 'NotFoundError'\n }\n}\n\n/**\n * Thrown when the purchase cannot be completed due to a validation\n * failure, such as a price mismatch or a duplicate purchase.\n */\nexport class PurchaseError extends LedewireError {\n static override readonly brand: string = 'PurchaseError'\n\n constructor(\n message: string,\n statusCode: number,\n code?: number,\n type?: ErrorTypeValue,\n details?: Record<string, unknown>,\n ) {\n super(message, statusCode, code, type, details)\n this.name = 'PurchaseError'\n }\n}\n\n/**\n * Thrown when the buyer's daily spend cap has been reached. Returned as HTTP `402`\n * by `POST /v1/purchases`, `GET /v1/x402/contents/{id}`, and acquisition\n * authorization, whenever the API error body's `error.type` is\n * `'daily_spend_cap_reached'`.\n *\n * **Funding the wallet does not clear this.** Unlike a plain `insufficient_funds`\n * 402 — where adding money to the wallet is enough to retry — a spend cap refusal\n * is a daily policy limit on the buyer's account (every new buyer starts with a\n * default cap). It clears only when the spend window rolls over at {@link\n * SpendCapReachedError.resetsAt}, or when the buyer raises or removes the cap via\n * `user.spendCap.update()`.\n *\n * @example\n * ```ts\n * try {\n * await client.purchases.create({ content_id })\n * } catch (err) {\n * if (err instanceof SpendCapReachedError) {\n * // Do NOT prompt the buyer to fund their wallet — that won't help.\n * console.error(\n * `Spend cap reached: spent ${err.spentCents} of ${err.capCents} cents. ` +\n * `Resets at ${err.resetsAt}.`,\n * )\n * }\n * }\n * ```\n */\nexport class SpendCapReachedError extends LedewireError {\n static override readonly brand: string = 'SpendCapReachedError'\n\n /** The buyer's daily spend cap in cents. */\n public readonly capCents: number\n\n /** Total spent so far in the current spend window. */\n public readonly spentCents: number\n\n /** Cap minus spend so far, floored at zero — what the buyer may still spend in this window. */\n public readonly remainingCents: number\n\n /** ISO 8601 timestamp (UTC) of the instant the current spend window rolls. */\n public readonly resetsAt: string\n\n /**\n * Whether this buyer's bulk acquisitions are exempt from the cap. When `true`,\n * `spentCents` and `remainingCents` describe ordinary spend only — an authorized\n * bulk acquisition does not consume them.\n */\n public readonly bulkExempt: boolean\n\n constructor(\n message: string,\n capInfo: {\n capCents: number\n spentCents: number\n remainingCents: number\n resetsAt: string\n bulkExempt: boolean\n },\n code?: number,\n ) {\n super(message, 402, code, 'daily_spend_cap_reached')\n this.name = 'SpendCapReachedError'\n this.capCents = capInfo.capCents\n this.spentCents = capInfo.spentCents\n this.remainingCents = capInfo.remainingCents\n this.resetsAt = capInfo.resetsAt\n this.bulkExempt = capInfo.bulkExempt\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","import { SpendCapReachedError } from './errors.js'\n\n/**\n * Builds a {@link SpendCapReachedError} from a parsed `402` response body, or\n * `null` when the body isn't a well-formed daily-spend-cap-reached refusal.\n *\n * Shared by {@link HttpClient}'s error mapping (`POST /v1/purchases`,\n * acquisition authorization) and the `@ledewire/x402-client` fetch/Axios\n * adapters, which see the same body shape on a bare `GET /v1/x402/contents/{id}`\n * `402` — one with **no** `PAYMENT-REQUIRED` header, so there is nothing to\n * challenge and retrying or funding the wallet cannot clear it.\n *\n * Requires `error.type === 'daily_spend_cap_reached'` and `cap_cents`,\n * `spent_cents`, `remaining_cents` to be numbers, `resets_at` to be a string,\n * and `bulk_exempt` to be a boolean. A body with the right `error.type` but a\n * missing or mistyped field returns `null` — never `NaN`/`'undefined'` fields\n * on a shape that's merely close — so the caller falls back to its generic\n * error path.\n *\n * @param body - The parsed JSON body of a `402` response, or `undefined`/`null`\n * if it couldn't be parsed.\n */\nexport function spendCapErrorFromBody(body: unknown): SpendCapReachedError | null {\n if (!body || typeof body !== 'object') return null\n const record = body as Record<string, unknown>\n\n const error = record['error']\n if (!error || typeof error !== 'object') return null\n const errorRecord = error as Record<string, unknown>\n if (errorRecord['type'] !== 'daily_spend_cap_reached') return null\n\n const capCents = record['cap_cents']\n const spentCents = record['spent_cents']\n const remainingCents = record['remaining_cents']\n const resetsAt = record['resets_at']\n const bulkExempt = record['bulk_exempt']\n\n if (\n typeof capCents !== 'number' ||\n typeof spentCents !== 'number' ||\n typeof remainingCents !== 'number' ||\n typeof resetsAt !== 'string' ||\n typeof bulkExempt !== 'boolean'\n ) {\n return null\n }\n\n // The body also carries the remedy at the top level (`message`) — for a\n // Company member, \"ask a Company admin\" — which is what MCP clients see in\n // place of the envelope. Prefer the envelope's, fall back to it.\n const message =\n typeof errorRecord['message'] === 'string'\n ? errorRecord['message']\n : typeof record['message'] === 'string'\n ? record['message']\n : 'Daily spend cap reached.'\n const code = typeof errorRecord['code'] === 'number' ? errorRecord['code'] : undefined\n\n return new SpendCapReachedError(\n message,\n { capCents, spentCents, remainingCents, resetsAt, bulkExempt },\n code,\n )\n}\n","import { AuthError, ForbiddenError, LedewireError, NotFoundError } from './errors.js'\nimport type { ErrorTypeValue } from './errors.js'\nimport { spendCapErrorFromBody } from './spend-cap.js'\n\n/**\n * Configuration options for `HttpClient`.\n */\nexport interface HttpClientConfig {\n /** API base URL. Defaults to the production API. */\n baseUrl?: string\n /**\n * Returns the current access token (or null) before each request.\n * If null, requests are sent without an Authorization header.\n */\n getAccessToken?: () => string | null | Promise<string | null>\n /**\n * Called when a 401 is received on the first attempt.\n * Should refresh and return the new access token, or null to propagate\n * an `AuthError` to the caller.\n */\n onUnauthorized?: () => string | null | Promise<string | null>\n}\n\n/**\n * Per-request overrides accepted by {@link HttpClient} methods.\n */\nexport interface RequestOptions {\n /**\n * Whether to attach authentication to this request. Defaults to `true`.\n * Pass `false` for public endpoints: skips `getAccessToken`, sends no\n * `Authorization` header, and maps a `401` straight to an {@link AuthError}\n * without invoking `onUnauthorized`.\n */\n auth?: boolean\n}\n\n/** The default LedeWire API base URL used by all SDK packages. */\nexport const DEFAULT_BASE_URL = 'https://api.ledewire.com'\n\n/**\n * Extracts `{ message, code, type, details }` from a parsed API error body,\n * tolerating shapes that don't match the documented `ErrorResponse` envelope:\n * an empty object, a body with no `error` field at all, `error` as a bare\n * string (e.g. the spec's `{ \"error\": \"Content ... not found\" }` 404 purchase\n * example), `null`, or non-object JSON. Never throws; falls back to\n * `fallbackMessage` (the response's `statusText`) whenever the body doesn't\n * carry a usable message.\n */\nfunction extractErrorInfo(\n body: unknown,\n fallbackMessage: string,\n): {\n message: string\n code: number | undefined\n type: ErrorTypeValue | undefined\n details: Record<string, unknown> | undefined\n} {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n return { message: fallbackMessage, code: undefined, type: undefined, details: undefined }\n }\n\n const record = body as Record<string, unknown>\n const { error, ...rest } = record\n const details = Object.keys(rest).length > 0 ? rest : undefined\n\n if (typeof error === 'string') {\n return { message: error, code: undefined, type: undefined, details }\n }\n\n if (!error || typeof error !== 'object' || Array.isArray(error)) {\n return { message: fallbackMessage, code: undefined, type: undefined, details }\n }\n\n const errorRecord = error as Record<string, unknown>\n const message =\n typeof errorRecord['message'] === 'string' ? errorRecord['message'] : fallbackMessage\n const code = typeof errorRecord['code'] === 'number' ? errorRecord['code'] : undefined\n const type = typeof errorRecord['type'] === 'string' ? errorRecord['type'] : undefined\n\n return { message, code, type, details }\n}\n\n/**\n * Core HTTP client used by all SDK packages.\n *\n * Features:\n * - Injects `Authorization: Bearer <token>` headers automatically\n * - Maps HTTP error responses to typed `LedewireError` subclasses\n * - On receiving a 401, calls `onUnauthorized` once and retries the request\n * - Per-request `{ auth: false }` (see {@link RequestOptions}) skips all of\n * the above for public endpoints\n *\n * This is an internal class - consumers should use the\n * package-level client factories (`init` / `createClient`) instead.\n */\nexport class HttpClient {\n private readonly baseUrl: string\n private readonly getAccessToken: NonNullable<HttpClientConfig['getAccessToken']>\n private readonly onUnauthorized: NonNullable<HttpClientConfig['onUnauthorized']>\n\n constructor(config: HttpClientConfig = {}) {\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.getAccessToken = config.getAccessToken ?? (() => null)\n this.onUnauthorized = config.onUnauthorized ?? (() => null)\n }\n\n /**\n * GET request with optional query parameters.\n * @param path - API path (e.g. `/v1/wallet/balance`)\n * @param params - Query string parameters. `undefined` values are omitted; numbers are coerced to strings.\n * @param options - Per-request overrides. Pass `{ auth: false }` for public endpoints.\n */\n async get<T>(\n path: string,\n params?: Record<string, string | number | undefined>,\n options?: RequestOptions,\n ): Promise<T> {\n return this.request<T>('GET', this.buildUrl(path, params), undefined, options)\n }\n\n /**\n * POST request.\n * @param path - API path\n * @param body - Request body (JSON-serialized)\n * @param params - Optional query string parameters. `undefined` values are omitted; numbers are coerced to strings.\n */\n async post<T>(\n path: string,\n body?: unknown,\n params?: Record<string, string | number | undefined>,\n ): Promise<T> {\n return this.request<T>('POST', this.buildUrl(path, params), body)\n }\n\n /**\n * PUT request.\n * @param path - API path\n * @param body - Request body (JSON-serialized)\n */\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PUT', this.buildUrl(path), body)\n }\n\n /**\n * PATCH request.\n * @param path - API path\n * @param body - Partial update body (JSON-serialized)\n */\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PATCH', this.buildUrl(path), body)\n }\n\n /**\n * DELETE request.\n * @param path - API path\n */\n async delete<T = void>(path: string): Promise<T> {\n return this.request<T>('DELETE', this.buildUrl(path))\n }\n\n /**\n * GET request that returns the raw, unparsed `Response` instead of decoded JSON.\n * Used for binary downloads (e.g. `GET /v1/acquisitions/{id}/corpus/download`,\n * which streams a gzip archive when the corpus is ready, or a JSON\n * `CorpusResponse` body otherwise).\n *\n * Applies the same `Authorization` header injection and single-retry-on-401\n * behaviour as {@link HttpClient.get}, and maps a non-2xx response to the same\n * typed errors — it just skips the `response.json()` decode step so the caller\n * can read the body as a stream, blob, or array buffer.\n *\n * @param path - API path (e.g. `/v1/acquisitions/{id}/corpus/download`)\n * @returns The raw `Response`. Callers are responsible for reading its body.\n */\n async getRaw(path: string): Promise<Response> {\n return this.performRequest('GET', this.buildUrl(path), {\n Accept: 'application/gzip, application/json',\n })\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, params?: Record<string, string | number | undefined>): string {\n const url = `${this.baseUrl}${path}`\n if (!params) return url\n const filtered = Object.entries(params).filter(\n (entry): entry is [string, string | number] => entry[1] !== undefined,\n )\n if (filtered.length === 0) return url\n const qs = new URLSearchParams(filtered.map(([k, v]) => [k, String(v)]))\n return `${url}?${qs.toString()}`\n }\n\n private async request<T>(\n method: string,\n url: string,\n body?: unknown,\n options?: RequestOptions,\n ): Promise<T> {\n const response = await this.performRequest(\n method,\n url,\n { 'Content-Type': 'application/json', Accept: 'application/json' },\n body,\n false,\n options,\n )\n\n if (response.status === 204) {\n return undefined as T\n }\n\n return response.json() as Promise<T>\n }\n\n /**\n * Shared auth-injection, single-401-retry, and error-mapping logic behind both\n * `request()` (JSON in, JSON out) and `getRaw()` (JSON in, raw `Response` out).\n */\n private async performRequest(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: unknown,\n isRetry = false,\n options?: RequestOptions,\n ): Promise<Response> {\n const useAuth = options?.auth !== false\n const token = useAuth ? await this.getAccessToken() : null\n const finalHeaders: Record<string, string> = { ...headers }\n if (token) finalHeaders['Authorization'] = `Bearer ${token}`\n\n const response = await fetch(url, {\n method,\n headers: finalHeaders,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n\n if (response.status === 401 && !isRetry) {\n if (useAuth) {\n const newToken = await this.onUnauthorized()\n if (newToken) {\n return this.performRequest(method, url, headers, body, true, options)\n }\n }\n throw new AuthError('Session expired. Please re-authenticate.')\n }\n\n if (!response.ok) {\n await this.throwApiError(response)\n }\n\n return response\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let body: unknown\n try {\n body = await response.json()\n } catch {\n // Non-JSON body - fall through to use statusText\n }\n\n const spendCapError = spendCapErrorFromBody(body)\n if (spendCapError) {\n throw spendCapError\n }\n\n const { message, code, type, details } = extractErrorInfo(body, response.statusText)\n\n switch (response.status) {\n case 401:\n throw new AuthError(message, code, type, details)\n case 403:\n throw new ForbiddenError(message, code, type, details)\n case 404:\n throw new NotFoundError(message, code, type, details)\n default:\n throw new LedewireError(message, response.status, code, type, details)\n }\n }\n}\n","import type { StoredTokens, TokenStorage } from './types.js'\nimport { AuthError } from './errors.js'\n\n/** How many milliseconds before expiry to proactively refresh the token. */\nconst REFRESH_THRESHOLD_MS = 60_000 // 60 seconds\n\n/**\n * Options for constructing a `TokenManager`.\n */\nexport interface TokenManagerOptions {\n storage: TokenStorage\n /**\n * Exchanges a refresh token for a new token pair.\n * Implemented by each package's client factory using the\n * `/v1/auth/token/refresh` endpoint.\n */\n refreshFn: (refreshToken: string) => Promise<StoredTokens>\n /**\n * Called after a successful background token refresh (not on initial login).\n * Use for side-effects only — e.g. audit logging, cache invalidation, or\n * notifying a secondary system when tokens rotate.\n *\n * **Do not use this for token persistence.** The `storage` adapter's\n * `setTokens` is the canonical persistence hook and is already called on\n * every refresh. Providing both will result in double-writes.\n *\n * @example\n * ```ts\n * onTokenRefreshed: async (tokens) => {\n * await auditLog.record('token_refreshed', { expiresAt: tokens.expiresAt })\n * }\n * ```\n */\n onTokenRefreshed?: (tokens: StoredTokens) => void | Promise<void>\n /**\n * Called when a refresh attempt fails and the user must re-authenticate.\n * Typically used to redirect to login or emit a UI event.\n *\n * @example\n * ```ts\n * onAuthExpired: () => { window.location.href = '/login' }\n * ```\n */\n onAuthExpired?: () => void | Promise<void>\n}\n\n/**\n * Manages the JWT token lifecycle transparently.\n *\n * - Proactively refreshes the access token when it expires within 60 seconds\n * - Handles reactive refresh on 401 responses from the HTTP client\n * - Deduplicates concurrent refresh calls (only one in-flight refresh at a time)\n * - Fires `onAuthExpired` when refresh fails so the UI can prompt re-login\n *\n * This is an internal class - use the package-level client factories instead.\n */\nexport class TokenManager {\n private readonly storage: TokenStorage\n private readonly refreshFn: TokenManagerOptions['refreshFn']\n private readonly onTokenRefreshed: TokenManagerOptions['onTokenRefreshed']\n private readonly onAuthExpired: TokenManagerOptions['onAuthExpired']\n private refreshPromise: Promise<StoredTokens | null> | null = null\n\n constructor(options: TokenManagerOptions) {\n this.storage = options.storage\n this.refreshFn = options.refreshFn\n this.onTokenRefreshed = options.onTokenRefreshed\n this.onAuthExpired = options.onAuthExpired\n }\n\n /**\n * Returns a valid access token, refreshing proactively if needed.\n * Returns `null` if no tokens are stored (user not authenticated).\n */\n async getAccessToken(): Promise<string | null> {\n const stored = await this.storage.getTokens()\n if (!stored) return null\n\n const expiresInMs = stored.expiresAt - Date.now()\n if (expiresInMs < REFRESH_THRESHOLD_MS) {\n const refreshed = await this.performRefresh(stored.refreshToken)\n return refreshed?.accessToken ?? null\n }\n\n return stored.accessToken\n }\n\n /**\n * Called by `HttpClient` when a 401 is received.\n * Attempts one refresh; returns the new access token or null.\n */\n async handleUnauthorized(): Promise<string | null> {\n const stored = await this.storage.getTokens()\n if (!stored) {\n await this.onAuthExpired?.()\n return null\n }\n const refreshed = await this.performRefresh(stored.refreshToken)\n if (!refreshed) await this.onAuthExpired?.()\n return refreshed?.accessToken ?? null\n }\n\n /** Store new tokens after a successful login or signup. */\n async setTokens(tokens: StoredTokens): Promise<void> {\n await this.storage.setTokens(tokens)\n }\n\n /** Clear all stored tokens (call on logout). */\n async clearTokens(): Promise<void> {\n await this.storage.clearTokens()\n }\n\n // ---------------------------------------------------------------------------\n // Private\n // ---------------------------------------------------------------------------\n\n private performRefresh(refreshToken: string): Promise<StoredTokens | null> {\n if (this.refreshPromise) return this.refreshPromise\n\n this.refreshPromise = this.refreshFn(refreshToken)\n .then(async (tokens) => {\n await this.storage.setTokens(tokens)\n await this.onTokenRefreshed?.(tokens)\n return tokens\n })\n .catch((_err: unknown) => {\n void this.storage.clearTokens()\n throw new AuthError('Token refresh failed. Please re-authenticate.')\n })\n .finally(() => {\n this.refreshPromise = null\n })\n\n return this.refreshPromise\n }\n}\n\n// ---------------------------------------------------------------------------\n// Built-in storage adapters\n// ---------------------------------------------------------------------------\n\n/**\n * In-memory token storage (default for both packages).\n * Tokens are cleared when the page unloads or the process exits.\n * This is the most secure default for browser environments.\n */\nexport class MemoryTokenStorage implements TokenStorage {\n private tokens: StoredTokens | null = null\n\n getTokens(): StoredTokens | null {\n return this.tokens\n }\n\n setTokens(tokens: StoredTokens): void {\n this.tokens = tokens\n }\n\n clearTokens(): void {\n this.tokens = null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts an `expires_at` ISO 8601 string from an API auth response\n * into a Unix timestamp (milliseconds) for use in `StoredTokens.expiresAt`.\n *\n * @param expiresAt - ISO 8601 datetime string, e.g. `\"2026-01-01T12:00:00Z\"`\n * @returns Unix timestamp in milliseconds\n */\nexport function parseExpiresAt(expiresAt: string): number {\n return new Date(expiresAt).getTime()\n}\n\n/**\n * Creates the standard LedeWire token refresh function for use with `TokenManager`.\n *\n * Encapsulates the `/v1/auth/token/refresh` fetch call, response mapping, and\n * error handling so both `createClient` (node) and `init` (browser) share a\n * single implementation.\n *\n * @param baseUrl - The resolved API base URL (e.g. `'https://api.ledewire.com'`)\n * @returns A `refreshFn` compatible with `TokenManagerOptions['refreshFn']`\n */\nexport function createRefreshFn(baseUrl: string): TokenManagerOptions['refreshFn'] {\n return async (refreshToken: string): Promise<StoredTokens> => {\n const res = await fetch(`${baseUrl}/v1/auth/token/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refresh_token: refreshToken }),\n })\n if (!res.ok) throw new Error('Token refresh failed')\n const data = (await res.json()) as {\n access_token: string\n refresh_token: string\n expires_at: string\n }\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: parseExpiresAt(data.expires_at),\n }\n }\n}\n","/**\n * Buyer authentication namespace for browser environments.\n *\n * Handles buyer signup, email/password login, Google OAuth, and password reset.\n * Tokens are stored automatically in the `TokenManager` after every\n * successful call — callers never need to manage tokens directly.\n *\n * For seller/API key authentication, use {@link BrowserSellerNamespace.loginWithApiKey}\n * via `lw.seller.loginWithApiKey()`.\n *\n * @module\n */\nimport { parseExpiresAt } from '@ledewire/core'\nimport type { HttpClient, TokenManager } from '@ledewire/core'\nimport type {\n AuthLoginEmailRequest,\n AuthLoginBuyerApiKeyRequest,\n AuthLoginOAuthRequest,\n AuthPasswordResetBody,\n AuthPasswordResetRequestBody,\n AuthPasswordResetResponse,\n AuthSignupRequest,\n AuthenticationResponse,\n} from '@ledewire/core'\n\n/**\n * Buyer authentication: signup, email/password login, Google OAuth, password reset.\n *\n * Obtain via `lw.auth` — do not construct directly.\n *\n * @example\n * ```ts\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n * await lw.auth.loginWithEmail({ email: 'u@example.com', password: 'pw' })\n * ```\n */\nexport class BrowserAuthNamespace {\n /** @internal */\n constructor(\n private readonly http: HttpClient,\n private readonly tokenManager: TokenManager,\n ) {}\n\n /**\n * Register a new buyer account with email and password.\n * Tokens are stored automatically after successful signup.\n *\n * Pass `company_invitation_token` (from a Company invitation email) to sign\n * up and join the Company in one step. If the token does not name a pending\n * invitation addressed to this email, the account is still created, without\n * a membership.\n *\n * @param body - Signup credentials and display name.\n * @returns The authentication token response.\n */\n async signup(body: AuthSignupRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/signup', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Log in with email and password.\n * Tokens are stored automatically after successful login.\n *\n * @param body - Email and password credentials.\n * @returns The authentication token response.\n */\n async loginWithEmail(body: AuthLoginEmailRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/email', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Log in with a Google ID token obtained from the Google OAuth flow.\n * Tokens are stored automatically after successful login.\n *\n * @param body - The Google ID token.\n * @returns The authentication token response.\n */\n async loginWithGoogle(body: AuthLoginOAuthRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/google', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Log in using a buyer API key and secret.\n * Returns a buyer-scoped JWT, stored automatically after successful authentication.\n *\n * Primarily useful when building buyer-facing dashboards where the user\n * has created a named API key and wishes to authenticate with it programmatically,\n * or for agent workflows running inside a browser context.\n *\n * @param body - The buyer API key and secret.\n * @returns The authentication token response.\n *\n * @example\n * ```ts\n * await lw.auth.loginWithBuyerApiKey({\n * key: 'bktst_abc123',\n * secret: 'deadbeef...',\n * })\n * ```\n */\n async loginWithBuyerApiKey(body: AuthLoginBuyerApiKeyRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/buyer-api-key', body)\n await this.storeTokens(res)\n return res\n }\n\n /**\n * Request a password reset code to be sent to the buyer's email address.\n *\n * The response is intentionally ambiguous — if the email does not exist,\n * the API returns the same success message to prevent account enumeration.\n *\n * @param body - The buyer's email address.\n * @returns A response with a confirmation message.\n *\n * @example\n * ```ts\n * await lw.auth.requestPasswordReset({ email: 'buyer@example.com' })\n * // → { data: { message: 'If an account with this email exists, a reset code has been sent.' } }\n * ```\n */\n async requestPasswordReset(\n body: AuthPasswordResetRequestBody,\n ): Promise<AuthPasswordResetResponse> {\n return this.http.post<AuthPasswordResetResponse>('/v1/auth/password/reset-request', body)\n }\n\n /**\n * Reset a buyer's password using the code delivered to their email.\n *\n * Obtain the reset code first by calling `requestPasswordReset()`.\n *\n * @param body - Email address, 6-digit reset code, and the new password.\n * @returns A response with a confirmation message.\n *\n * @example\n * ```ts\n * await lw.auth.resetPassword({\n * email: 'buyer@example.com',\n * reset_code: '123456',\n * password: 'new-secure-password',\n * })\n * ```\n */\n async resetPassword(body: AuthPasswordResetBody): Promise<AuthPasswordResetResponse> {\n return this.http.post<AuthPasswordResetResponse>('/v1/auth/password/reset', body)\n }\n\n private async storeTokens(res: AuthenticationResponse): Promise<void> {\n await this.tokenManager.setTokens({\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n expiresAt: parseExpiresAt(res.expires_at),\n })\n }\n}\n","/**\n * Platform configuration namespace (browser).\n *\n * Provides access to public (unauthenticated) platform-level configuration.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { PublicConfigResponse } from '@ledewire/core'\n\n/**\n * Platform-level configuration for browser clients.\n *\n * Obtain via `client.config` — do not construct directly.\n */\nexport class BrowserConfigNamespace {\n /** @internal */\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns platform-level public configuration.\n * No authentication required — safe to call before the user has signed in.\n *\n * Use `google_client_id` to initialise the Google Identity Services library\n * on the storefront login page without requiring a prior authenticated call.\n *\n * @example\n * ```ts\n * const lw = init({ apiKey: 'your_api_key' })\n * const { google_client_id } = await lw.config.getPublic()\n * google.accounts.id.initialize({ client_id: google_client_id, callback })\n * ```\n */\n async getPublic(): Promise<PublicConfigResponse> {\n return this.http.get<PublicConfigResponse>('/v1/config/public')\n }\n}\n","import { decodeContentFields } from '@ledewire/core'\nimport type { HttpClient } from '@ledewire/core'\nimport type { ContentWithAccessResponse } from '@ledewire/core'\n\n/**\n * Buyer content namespace — fetch content with real-time access information.\n *\n * Obtain via `lw.content` — do not construct directly.\n *\n * @example\n * ```ts\n * const result = await lw.content.getWithAccess('content-id')\n * if (result.access_info.has_purchased) {\n * // Note: single-use — a past purchase does not imply access. Buy again\n * // via lw.purchases.create() to receive the content; the delivery comes\n * // back directly in that response, not from this endpoint.\n * }\n * ```\n */\nexport class BrowserContentNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns a content item together with access information for the\n * authenticated buyer (or a generic access response when unauthenticated).\n *\n * @param id - The content ID.\n * @returns The content item with access information. `content_body` and\n * `teaser` are returned as plain UTF-8 text — the SDK decodes base64\n * transparently so you can render them directly.\n *\n * @example\n * ```ts\n * const result = await lw.content.getWithAccess('article-123')\n * if (result.access_info.next_required_action === 'purchase') {\n * // Buy (or re-buy) via lw.purchases.create() — the response carries\n * // content_body / content_uri directly. has_purchased means only\n * // \"has ever bought\" and does not by itself grant access.\n * }\n * ```\n */\n async getWithAccess(id: string): Promise<ContentWithAccessResponse> {\n const res = await this.http.get<ContentWithAccessResponse>(\n `/v1/content/${encodeURIComponent(id)}/with-access`,\n )\n return decodeContentFields(res)\n }\n}\n","import type { HttpClient } from '@ledewire/core'\nimport type { PurchaseCreateRequest, PurchaseResponse } from '@ledewire/core'\n\n/**\n * Buyer purchases namespace — create and retrieve content purchases.\n *\n * **Single-use purchase model:** a completed purchase does not imply\n * standing access. `has_purchased` on other endpoints means only \"has ever\n * bought\" — it is not a re-access grant. Buying again is how the buyer\n * receives the content a second time; see {@link BrowserPurchasesNamespace.create}.\n *\n * Obtain via `lw.purchases` — do not construct directly.\n *\n * @example\n * ```ts\n * await lw.purchases.create({ content_id: 'content-id' })\n * const all = await lw.purchases.list()\n * ```\n */\nexport class BrowserPurchasesNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Completes a content purchase using the buyer's wallet balance and\n * delivers the content in the same response.\n *\n * **This response is the only place the delivered content ever arrives.**\n * For a deliverable LedeWire holds, `content_body` carries the full body as\n * plain UTF-8 text — it is never base64-encoded on the wire, so no\n * `atob()` or decoding step is needed. For a deliverable hosted elsewhere,\n * `content_uri` carries its URL instead. Neither field is present on\n * {@link BrowserPurchasesNamespace.get} or {@link BrowserPurchasesNamespace.list}\n * — there is no route that serves the same content a second time — so\n * persist `content_body` / `content_uri` immediately if you need it later.\n * A past purchase does not grant re-access: buying the same content again\n * is a new charge that delivers it again.\n *\n * @param body - The content ID and expected price in cents.\n * @returns The completed purchase record, including the delivered content.\n * @throws {SpendCapReachedError} `402` — the buyer's daily spend cap has\n * been reached. There is no funding URL for this refusal: adding money\n * to the wallet does not clear it. It clears only when the spend window\n * rolls over at `resetsAt`, or when the cap is raised via\n * `lw.user.spendCap.update()`.\n * @throws {NotFoundError} `404` — the content does not exist, or its\n * visibility is `unlisted` (non-public) and this buyer has no standing\n * grant to see it. Non-public content is not purchasable through this\n * endpoint.\n *\n * @example\n * ```ts\n * const purchase = await lw.purchases.create({ content_id: 'content-id' })\n * await saveDeliveredContent(purchase) // persist now — one-time delivery\n *\n * if (purchase.content_body && purchase.content.content_type === 'markdown') {\n * renderMarkdown(purchase.content_body)\n * } else if (purchase.content_body && purchase.content.content_type === 'html') {\n * // Inline HTML is seller-supplied — sanitise before inserting it.\n * container.innerHTML = DOMPurify.sanitize(purchase.content_body)\n * } else if (purchase.content_uri) {\n * // Seller-supplied URI — check the scheme before navigating to it.\n * const uri = new URL(purchase.content_uri)\n * if (['https:', 'http:'].includes(uri.protocol)) {\n * window.location.href = purchase.content_uri\n * }\n * }\n * ```\n */\n async create(body: PurchaseCreateRequest): Promise<PurchaseResponse> {\n return this.http.post<PurchaseResponse>('/v1/purchases', body)\n }\n\n /**\n * Returns all purchases made by the authenticated buyer.\n *\n * @returns A list of purchase records, newest first.\n */\n async list(): Promise<PurchaseResponse[]> {\n return this.http.get<PurchaseResponse[]>('/v1/purchases')\n }\n\n /**\n * Returns a single purchase by ID.\n *\n * @param id - The purchase ID.\n * @returns The purchase record.\n */\n async get(id: string): Promise<PurchaseResponse> {\n return this.http.get<PurchaseResponse>(`/v1/purchases/${encodeURIComponent(id)}`)\n }\n}\n","/**\n * Seller content namespace for browser environments.\n *\n * Read-only operations using a view-permission API key token.\n * Hits the `/v1/seller/content` family of endpoints — store identity is\n * derived server-side from the token, so no `store_id` is required.\n *\n * @module\n */\nimport { decodeContentFields } from '@ledewire/core'\nimport type { HttpClient } from '@ledewire/core'\nimport type { ContentResponse } from '@ledewire/core'\n\n/**\n * Search criteria for seller content search.\n * At least one field must be supplied. All supplied fields must match (AND logic).\n */\nexport interface SellerContentSearchRequest {\n /** Case-insensitive partial match against the content title. */\n title?: string\n /** Case-insensitive partial match against the content URI (`external_ref` content only). */\n uri?: string\n /**\n * Exact match against the content's external identifier.\n * Use the full formatted value as it appears in `ContentResponse.external_identifier`,\n * e.g. `'vimeo:123456789'`.\n */\n external_identifier?: string\n /** Exact key/value pairs to AND-match against content metadata. */\n metadata?: Record<string, unknown>\n}\n\n/**\n * Seller content namespace — list, search, and fetch store content by API key.\n *\n * Obtain via `lw.seller.content` — do not construct directly.\n *\n * @example\n * ```ts\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n * await lw.seller.loginWithApiKey({ key: 'your_api_key' })\n *\n * const items = await lw.seller.content.list()\n * const results = await lw.seller.content.search({ title: 'intro' })\n * const item = await lw.seller.content.get('content-id')\n * ```\n */\nexport class BrowserSellerContentNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all content for the authenticated seller's store.\n * Requires a token with at least `view` permission.\n *\n * @returns Array of content items. `teaser` is returned as plain text —\n * the SDK decodes base64 automatically.\n *\n * @example\n * ```ts\n * const items = await lw.seller.content.list()\n * ```\n */\n async list(): Promise<ContentResponse[]> {\n const res = await this.http.get<ContentResponse[]>('/v1/seller/content')\n return res.map(decodeContentFields)\n }\n\n /**\n * Search content by title, URI, and/or metadata (AND logic).\n * At least one criterion must be supplied.\n * Requires a token with at least `view` permission.\n *\n * @param body - Search criteria (title, uri, and/or metadata).\n * @returns Array of matching content items. `teaser` is returned as plain\n * text — the SDK decodes base64 automatically.\n *\n * @example\n * ```ts\n * const results = await lw.seller.content.search({ title: 'intro' })\n * const byUri = await lw.seller.content.search({ uri: 'vimeo.com' })\n * const byId = await lw.seller.content.search({ external_identifier: 'vimeo:123456789' })\n * const byMeta = await lw.seller.content.search({ metadata: { author: 'Alice' } })\n * ```\n */\n async search(body: SellerContentSearchRequest): Promise<ContentResponse[]> {\n const res = await this.http.post<ContentResponse[]>('/v1/seller/content/search', body)\n return res.map(decodeContentFields)\n }\n\n /**\n * Get a single content item by ID.\n * Requires a token with at least `view` permission.\n *\n * @param id - The content ID.\n * @returns The content item. `content_body` and `teaser` are returned as\n * plain UTF-8 text — the SDK decodes base64 automatically so you can render\n * them directly without calling `atob()`.\n *\n * @example\n * ```ts\n * const item = await lw.seller.content.get('content-id')\n * // item.content_body is plain markdown — no atob() needed\n * ```\n */\n async get(id: string): Promise<ContentResponse> {\n const res = await this.http.get<ContentResponse>(`/v1/seller/content/${encodeURIComponent(id)}`)\n return decodeContentFields(res)\n }\n}\n","/**\n * Browser seller namespace — API-key-authenticated read operations.\n *\n * @module\n */\nimport { parseExpiresAt } from '@ledewire/core'\nimport type { HttpClient, TokenManager } from '@ledewire/core'\nimport type { AuthLoginApiKeyRequest, AuthenticationResponse } from '@ledewire/core'\nimport { BrowserSellerContentNamespace } from './content.js'\n\n/**\n * Seller operations accessible with a view-permission API key token.\n *\n * Obtain via `lw.seller` — do not construct directly.\n *\n * @example\n * ```ts\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n *\n * // Authenticate as a seller (key-only = view; key+secret = full)\n * await lw.seller.loginWithApiKey({ key: 'your_api_key' })\n * const items = await lw.seller.content.list()\n * ```\n */\nexport class BrowserSellerNamespace {\n /** Seller content: list, search, and get by API key. */\n readonly content: BrowserSellerContentNamespace\n\n /** @internal */\n constructor(\n private readonly http: HttpClient,\n private readonly tokenManager: TokenManager,\n ) {\n this.content = new BrowserSellerContentNamespace(http)\n }\n\n /**\n * Log in using an API key to obtain a seller token.\n * Provide only `key` for read-only (`view`) access.\n * Provide both `key` and `secret` for read/write (`full`) access.\n * Tokens are stored automatically after successful authentication.\n *\n * Use this before calling `lw.seller.content.*` methods.\n *\n * @param body - API key credentials.\n * @returns The authentication token response.\n *\n * @example\n * ```ts\n * // View access (read-only) — sufficient for seller.content.list/search/get\n * await lw.seller.loginWithApiKey({ key: 'your_api_key' })\n *\n * // Full access (read/write)\n * await lw.seller.loginWithApiKey({ key: 'your_api_key', secret: 'your_secret' })\n * ```\n */\n async loginWithApiKey(body: AuthLoginApiKeyRequest): Promise<AuthenticationResponse> {\n const res = await this.http.post<AuthenticationResponse>('/v1/auth/login/api-key', body)\n await this.tokenManager.setTokens({\n accessToken: res.access_token,\n refreshToken: res.refresh_token,\n expiresAt: parseExpiresAt(res.expires_at),\n })\n return res\n }\n}\n","import type { HttpClient } from '@ledewire/core'\nimport type {\n WalletBalanceResponse,\n WalletPaymentSessionRequest,\n WalletPaymentSessionResponse,\n WalletPaymentStatusResponse,\n WalletTransactionItem,\n} from '@ledewire/core'\n\n/**\n * Buyer wallet namespace — balance, transactions, and payment session management.\n *\n * Obtain via `lw.wallet` — do not construct directly.\n *\n * @example\n * ```ts\n * const { balance_cents } = await lw.wallet.balance()\n * const session = await lw.wallet.createPaymentSession({ amount_cents: 500 })\n * ```\n */\nexport class BrowserWalletNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns the authenticated buyer's current wallet balance.\n *\n * `balance_cents` and `spendable_cents` are always the same number —\n * `balance_cents` has always meant \"what you can spend,\" and money committed to\n * a bulk acquisition is a hold, which moves it out of the wallet rather than\n * annotating it. `held_cents` is the total currently committed to active bulk\n * acquisitions and not yet spent or released, and `holds` lists one entry per\n * such acquisition (`acquisition_id`, `held_cents`, `authorized_at`) so a buyer\n * mid-acquisition can see why their balance is lower than their purchase\n * history explains.\n *\n * **Company members:** a buyer with an open Company membership spends from the\n * Company wallet and never sees its balance, so `balance_cents` and\n * `spendable_cents` are `null`. `company_name` names the Company whose wallet\n * pays, and `remaining_cents` is what the member may still spend today under\n * their membership Spend cap. For anyone else, `company_name` is `null` and\n * `remaining_cents` is their own cap's headroom (`null` when uncapped).\n *\n * @returns The current wallet balance in cents, including held funds detail.\n *\n * @example\n * ```ts\n * const wallet = await lw.wallet.balance()\n * if (wallet.company_name !== null) {\n * console.log(`${wallet.company_name} pays; ${wallet.remaining_cents}c left today`)\n * } else {\n * console.log(`Balance: ${wallet.balance_cents}c`)\n * }\n * ```\n */\n async balance(): Promise<WalletBalanceResponse> {\n return this.http.get<WalletBalanceResponse>('/v1/wallet/balance')\n }\n\n /**\n * Returns the authenticated buyer's wallet transaction history, newest first.\n *\n * `bulk_acquisition` and `bulk_hold` are each a single entry for a whole bulk\n * acquisition — its per-work purchases are deliberately not listed here,\n * because one acquisition can hold tens of thousands of them and they describe\n * one decision. A `bulk_hold` entry is an acquisition still holding funds (money\n * left the wallet but has not been spent); it becomes a `bulk_acquisition` entry\n * for the amount actually captured once the acquisition ends, and an\n * acquisition never produces both. Note that a bulk acquisition's per-work\n * purchases each carry a display `price_cents` that is **not summable** — bulk\n * prices at micro precision and rounds to cents once, on the acquisition total,\n * so `amount_cents` on the `bulk_acquisition` / `bulk_hold` entry is the figure\n * to read.\n *\n * @returns A list of completed wallet transaction entries.\n */\n async transactions(): Promise<WalletTransactionItem[]> {\n return this.http.get<WalletTransactionItem[]>('/v1/wallet/transactions')\n }\n\n /**\n * Creates a payment session for funding the buyer's personal wallet. A\n * Company admin funds the Company wallet with\n * `company.wallet.createPaymentSession()` instead.\n *\n * @param body - The amount and currency to fund.\n * @returns Payment session details for use with the payment provider widget.\n */\n async createPaymentSession(\n body: WalletPaymentSessionRequest,\n ): Promise<WalletPaymentSessionResponse> {\n return this.http.post<WalletPaymentSessionResponse>('/v1/wallet/payment-session', body)\n }\n\n /**\n * Polls the status of a personal wallet funding payment session.\n *\n * `completed`, `failed` and `cancelled` are terminal. An ACH top-up can sit\n * in `awaiting_verification` (bank microdeposits not yet confirmed) and then\n * `processing` (the debit under way) for days before it completes.\n * `balance_cents` is `null` for a Company member.\n *\n * @param sessionId - The session ID returned by `createPaymentSession`.\n * @returns The current payment status.\n */\n async getPaymentStatus(sessionId: string): Promise<WalletPaymentStatusResponse> {\n return this.http.get<WalletPaymentStatusResponse>(\n `/v1/wallet/payment-status/${encodeURIComponent(sessionId)}`,\n )\n }\n}\n","import type { HttpClient } from '@ledewire/core'\nimport type { CheckoutStateResponse } from '@ledewire/core'\n\n/**\n * Checkout namespace — buyer checkout state for a specific content item.\n *\n * Obtain via `lw.checkout` — do not construct directly.\n *\n * @example\n * ```ts\n * const state = await lw.checkout.state('content-id')\n * // state.checkout_state.next_required_action:\n * // 'authenticate' | 'fund_wallet' | 'purchase'\n * //\n * // Single-use model: a completed purchase does not imply access, so\n * // 'purchase' can still be the next action even when has_purchased is\n * // true. Buying delivers the content directly in the POST /v1/purchases\n * // response — there is no separate \"view content\" step.\n * ```\n */\nexport class CheckoutNamespace {\n constructor(protected readonly http: HttpClient) {}\n\n /**\n * Returns the authenticated buyer's checkout readiness for a given piece of\n * content. Indicates whether the buyer needs to authenticate, fund their\n * wallet, or purchase before accessing the content.\n *\n * Works without authentication — returns anonymous checkout state when the\n * buyer is not logged in.\n *\n * @param contentId - The content item ID.\n * @returns The checkout state, including what action is required next.\n */\n async state(contentId: string): Promise<CheckoutStateResponse> {\n return this.http.get<CheckoutStateResponse>(\n `/v1/checkout/state/${encodeURIComponent(contentId)}`,\n )\n }\n}\n","/**\n * Company invitations.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type {\n CompanyInvitation,\n CompanyInvitationAcceptRequest,\n CompanyInvitationList,\n CompanyInvitationRequest,\n CompanyMembership,\n} from '@ledewire/core'\n\n/**\n * Invite people to a Company, and accept an invitation.\n *\n * Nobody joins until they accept, because joining moves their spending onto\n * the Company wallet. Every invitation emails a token that accepting requires,\n * even for a buyer already signed in as the invited address. An existing buyer\n * passes it to {@link accept}; a new address passes it to `auth.signup()` as\n * `company_invitation_token`, which signs up and joins in one step.\n *\n * `list()` and `create()` are Company-admin only; `accept()` is for the invitee.\n *\n * Obtain via `client.company.invitations` — do not construct directly.\n *\n * @example\n * ```ts\n * // Admin: invite an analyst\n * await client.company.invitations.create({ email: 'analyst@example.com' })\n *\n * // Invitee (already has an account): accept with the emailed token\n * const membership = await client.company.invitations.accept({ token })\n * ```\n */\nexport class CompanyInvitationsNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Lists the Company's pending invitations. Company admins only.\n *\n * @returns The pending invitations.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n * @throws {NotFoundError} When the caller belongs to no Company.\n */\n async list(): Promise<CompanyInvitationList> {\n return this.http.get<CompanyInvitationList>('/v1/company/invitations')\n }\n\n /**\n * Invites someone to the Company and emails them the acceptance token.\n * Company admins only. Inviting someone who belongs to another Company\n * succeeds; their accept is refused until they leave it.\n *\n * @param body - The invitee's email, and their role (default `'member'`).\n * @returns The invitation. It expires seven days after it is sent.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n * @throws {LedewireError} With `statusCode === 409` when the address is\n * already a member or already has a pending invitation.\n */\n async create(body: CompanyInvitationRequest): Promise<CompanyInvitation> {\n return this.http.post<CompanyInvitation>('/v1/company/invitations', body)\n }\n\n /**\n * Accepts an invitation, opening a membership with the invited role. The\n * token must belong to an invitation addressed to one of the buyer's\n * addresses.\n *\n * @param body - The token from the invitation email.\n * @returns The new membership.\n * @throws {NotFoundError} When no invitation with this token is addressed to\n * this buyer.\n * @throws {LedewireError} With `statusCode === 409` when already accepted, or\n * when the buyer already belongs to a Company (leave it first); with\n * `statusCode === 410` when the invitation has expired or was withdrawn.\n */\n async accept(body: CompanyInvitationAcceptRequest): Promise<CompanyMembership> {\n return this.http.post<CompanyMembership>('/v1/company/invitations/accept', body)\n }\n}\n","/**\n * Company Machine users and their keys.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type {\n CompanyMachineUser,\n CompanyMachineUserBuyerKeyCreateRequest,\n CompanyMachineUserBuyerKeyCreateResponse,\n CompanyMachineUserBuyerKeyList,\n CompanyMachineUserCreateRequest,\n CompanyMachineUserList,\n CompanyMachineUserMcpKeyCreateRequest,\n CompanyMachineUserMcpKeyCreateResponse,\n CompanyMachineUserMcpKeyList,\n} from '@ledewire/core'\n\nfunction machineUserPath(machineUserId: string): string {\n return `/v1/company/machine-users/${encodeURIComponent(machineUserId)}`\n}\n\n/**\n * Issue and revoke a Machine user's Buyer keys. Company admins only.\n *\n * A Machine user's Buyer key logs in through `auth.loginWithBuyerApiKey()` (or\n * `createAgentClient()`), exactly like a buyer's own key. Its spending limit is\n * the Machine user's membership Spend cap, so a key carries no\n * `spending_limit_cents` of its own.\n *\n * **Secret handling:** `create()` returns the `secret` exactly once.\n *\n * Obtain via `client.company.machineUsers.buyerKeys` — do not construct directly.\n */\nexport class CompanyMachineUserBuyerKeysNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Lists a Machine user's Buyer keys, oldest first. Secrets are never included.\n *\n * @param machineUserId - The Machine user id (`CompanyMachineUser.id`).\n * @returns The keys.\n * @throws {NotFoundError} When the Machine user is not in the caller's Company.\n */\n async list(machineUserId: string): Promise<CompanyMachineUserBuyerKeyList> {\n return this.http.get<CompanyMachineUserBuyerKeyList>(\n `${machineUserPath(machineUserId)}/buyer-keys`,\n )\n }\n\n /**\n * Creates a Buyer key for a Machine user.\n *\n * @param machineUserId - The Machine user id (`CompanyMachineUser.id`).\n * @param body - The key's name, unique among this Machine user's Buyer keys.\n * @returns The key with its one-time `secret` — store it immediately.\n * @throws {LedewireError} With `statusCode === 409` when the Machine user is\n * deactivated; with `statusCode === 422` for a duplicate name.\n */\n async create(\n machineUserId: string,\n body: CompanyMachineUserBuyerKeyCreateRequest,\n ): Promise<CompanyMachineUserBuyerKeyCreateResponse> {\n return this.http.post<CompanyMachineUserBuyerKeyCreateResponse>(\n `${machineUserPath(machineUserId)}/buyer-keys`,\n body,\n )\n }\n\n /**\n * Revokes a Machine user's Buyer key.\n *\n * @param machineUserId - The Machine user id (`CompanyMachineUser.id`).\n * @param id - The key id.\n * @throws {NotFoundError} When there is no such Machine user in the caller's\n * Company, or no such active key.\n */\n async revoke(machineUserId: string, id: string): Promise<void> {\n return this.http.delete(\n `${machineUserPath(machineUserId)}/buyer-keys/${encodeURIComponent(id)}`,\n )\n }\n}\n\n/**\n * Issue and revoke a Machine user's MCP API keys. Company admins only.\n *\n * A Machine user's MCP key carries buyer scopes only — `mcp:search` and\n * `mcp:purchase` — never a store, and does not expire; revoke it instead. It is\n * presented to the Ledewire MCP server as `Authorization: Bearer <key>:<secret>`.\n *\n * **Secret handling:** `create()` returns the `secret` exactly once.\n *\n * Obtain via `client.company.machineUsers.mcpKeys` — do not construct directly.\n */\nexport class CompanyMachineUserMcpKeysNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Lists a Machine user's active MCP API keys, oldest first. Secrets are never\n * included.\n *\n * @param machineUserId - The Machine user id (`CompanyMachineUser.id`).\n * @returns The keys.\n * @throws {NotFoundError} When the Machine user is not in the caller's Company.\n */\n async list(machineUserId: string): Promise<CompanyMachineUserMcpKeyList> {\n return this.http.get<CompanyMachineUserMcpKeyList>(`${machineUserPath(machineUserId)}/mcp-keys`)\n }\n\n /**\n * Creates an MCP API key for a Machine user.\n *\n * @param machineUserId - The Machine user id (`CompanyMachineUser.id`).\n * @param body - A label and at least one of `'mcp:search'`, `'mcp:purchase'`.\n * Any other scope, or a `store_id`, is refused with `400`.\n * @returns The key with its one-time `secret` — store it immediately.\n * @throws {LedewireError} With `statusCode === 409` when the Machine user is\n * deactivated; with `statusCode === 422` for a duplicate label.\n */\n async create(\n machineUserId: string,\n body: CompanyMachineUserMcpKeyCreateRequest,\n ): Promise<CompanyMachineUserMcpKeyCreateResponse> {\n return this.http.post<CompanyMachineUserMcpKeyCreateResponse>(\n `${machineUserPath(machineUserId)}/mcp-keys`,\n body,\n )\n }\n\n /**\n * Revokes a Machine user's MCP API key.\n *\n * @param machineUserId - The Machine user id (`CompanyMachineUser.id`).\n * @param id - The key id.\n * @throws {NotFoundError} When there is no such Machine user in the caller's\n * Company, or no such active key.\n */\n async revoke(machineUserId: string, id: string): Promise<void> {\n return this.http.delete(`${machineUserPath(machineUserId)}/mcp-keys/${encodeURIComponent(id)}`)\n }\n}\n\n/**\n * Manage the Company's Machine users. Company admins only.\n *\n * A Machine user is a Buyer with a name and no email, password or login — an\n * identity for an autonomous agent that spends the Company's money. It joins at\n * once as a non-admin member with the default daily Spend cap (change it with\n * `company.members.update()`), and authenticates only with the keys an admin\n * issues it through {@link buyerKeys} and {@link mcpKeys}. Every human-only flow\n * (login, Google sign-in, password reset, accepting or leaving a membership)\n * refuses it.\n *\n * Obtain via `client.company.machineUsers` — do not construct directly.\n *\n * @example\n * ```ts\n * const agentUser = await client.company.machineUsers.create({ name: 'research-agent' })\n * const { key, secret } = await client.company.machineUsers.buyerKeys.create(agentUser.id, {\n * name: 'production',\n * })\n * // Store immediately — the secret cannot be retrieved again\n * await secretsManager.put('LEDEWIRE_AGENT_KEY', `${key}:${secret}`)\n *\n * // The agent then authenticates as the Machine user (server-side, @ledewire/node)\n * const agent = createAgentClient({ key, secret })\n * ```\n */\nexport class CompanyMachineUsersNamespace {\n /** A Machine user's Buyer keys: list, create, revoke. */\n readonly buyerKeys: CompanyMachineUserBuyerKeysNamespace\n\n /** A Machine user's MCP API keys: list, create, revoke. */\n readonly mcpKeys: CompanyMachineUserMcpKeysNamespace\n\n /** @internal */\n constructor(private readonly http: HttpClient) {\n this.buyerKeys = new CompanyMachineUserBuyerKeysNamespace(http)\n this.mcpKeys = new CompanyMachineUserMcpKeysNamespace(http)\n }\n\n /**\n * Lists the Company's Machine users, deactivated ones included\n * (`deactivated_at` set).\n *\n * @returns The Machine users.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n * @throws {NotFoundError} When the caller belongs to no Company.\n */\n async list(): Promise<CompanyMachineUserList> {\n return this.http.get<CompanyMachineUserList>('/v1/company/machine-users')\n }\n\n /**\n * Creates a Machine user, joined at once as an active non-admin member.\n *\n * @param body - A name (at most 100 characters, unique among the Company's\n * active Machine users) and an optional description.\n * @returns The Machine user.\n * @throws {LedewireError} With `statusCode === 409` when an active Machine\n * user already has this name; with `statusCode === 422` when the name is\n * blank or too long.\n */\n async create(body: CompanyMachineUserCreateRequest): Promise<CompanyMachineUser> {\n return this.http.post<CompanyMachineUser>('/v1/company/machine-users', body)\n }\n\n /**\n * Deactivates a Machine user, **permanently**. In one step this closes its\n * membership, revokes every key it holds, and ends its sessions. It cannot be\n * reactivated; create a new one, which may reuse the name.\n *\n * @param id - The Machine user id (`CompanyMachineUser.id`).\n * @returns The deactivated Machine user.\n * @throws {NotFoundError} When the Machine user is not in the caller's Company.\n * @throws {LedewireError} With `statusCode === 409` when already deactivated.\n */\n async deactivate(id: string): Promise<CompanyMachineUser> {\n return this.http.delete<CompanyMachineUser>(machineUserPath(id))\n }\n}\n","/**\n * Company member management.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { CompanyMember, CompanyMemberList, CompanyMemberUpdateRequest } from '@ledewire/core'\n\n/**\n * Manage the Company's open memberships: list them, change a member's role or\n * daily Spend cap, and remove a member. Company admins only.\n *\n * Every method takes the **membership id** (`CompanyMember.id`), not the\n * member's `user_id`.\n *\n * A member's daily Spend cap is never `null` — Company members are never\n * uncapped. It defaults to 1000 cents ($10) on joining, is read in the\n * Company's timezone, and also binds bulk acquisitions.\n *\n * Obtain via `client.company.members` — do not construct directly.\n *\n * @example\n * ```ts\n * const { data: members } = await client.company.members.list()\n * const analyst = members.find((m) => m.email === 'analyst@example.com')\n * if (analyst) {\n * await client.company.members.update(analyst.id, { daily_spend_limit_cents: 5000 })\n * }\n * ```\n */\nexport class CompanyMembersNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Lists the Company's open memberships, Machine users included\n * (`kind: 'machine'`, `email: null`).\n *\n * @returns The members.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n * @throws {NotFoundError} When the caller belongs to no Company.\n */\n async list(): Promise<CompanyMemberList> {\n return this.http.get<CompanyMemberList>('/v1/company/members')\n }\n\n /**\n * Changes a member's role, daily Spend cap, or both. Any admin may set any\n * member's cap, their own included.\n *\n * @param id - The membership id (`CompanyMember.id`).\n * @param body - At least one of `role` and `daily_spend_limit_cents`.\n * @returns The updated member.\n * @throws {LedewireError} With `statusCode === 400` when neither field is\n * given or the cap is `null`/negative; with `statusCode === 422` for an\n * unknown role, or a change that would leave the Company with no admin.\n */\n async update(id: string, body: CompanyMemberUpdateRequest): Promise<CompanyMember> {\n return this.http.patch<CompanyMember>(`/v1/company/members/${encodeURIComponent(id)}`, body)\n }\n\n /**\n * Removes a member, closing their membership. Their ledger accounts stay\n * with the Company. Removing a Machine user deactivates it permanently.\n *\n * @param id - The membership id (`CompanyMember.id`).\n * @throws {LedewireError} With `statusCode === 422` when it would leave the\n * Company with no admin.\n */\n async remove(id: string): Promise<void> {\n return this.http.delete(`/v1/company/members/${encodeURIComponent(id)}`)\n }\n}\n","/**\n * The authenticated buyer's own Company membership.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { CompanyMembership } from '@ledewire/core'\n\n/**\n * Read or close the authenticated buyer's own Company membership.\n *\n * While a buyer holds an open membership, the Company wallet pays for their\n * purchases and their own membership Spend cap limits them. They never see the\n * Company balance: `wallet.balance()` reports `balance_cents: null` and a\n * `remaining_cents` allowance instead, with `company_name` naming whose wallet\n * pays.\n *\n * Obtain via `client.company.membership` — do not construct directly.\n *\n * @example\n * ```ts\n * try {\n * const { company_name, role } = await client.company.membership.get()\n * console.log(`Purchases are paid by ${company_name} (${role})`)\n * } catch (err) {\n * if (err instanceof NotFoundError) console.log('Not in a Company')\n * else throw err\n * }\n * ```\n */\nexport class CompanyMembershipNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns the authenticated buyer's open Company membership. Names the\n * Company, never its balance.\n *\n * @returns The membership.\n * @throws {NotFoundError} When the buyer belongs to no Company.\n */\n async get(): Promise<CompanyMembership> {\n return this.http.get<CompanyMembership>('/v1/company/membership')\n }\n\n /**\n * Leaves the Company. The buyer's purchases are paid from their personal\n * wallet again afterwards.\n *\n * @throws {NotFoundError} When the buyer belongs to no Company.\n * @throws {ForbiddenError} For a Machine user, which cannot leave — an admin\n * deactivates it instead.\n * @throws {LedewireError} With `statusCode === 422` when the buyer is the\n * Company's last admin.\n */\n async leave(): Promise<void> {\n return this.http.delete('/v1/company/membership')\n }\n}\n","/**\n * Company purchase and spend reports.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type {\n CompanyPurchaseList,\n CompanyPurchasesParams,\n CompanySpendList,\n CompanySpendParams,\n} from '@ledewire/core'\n\n/**\n * Everything the Company paid for. Company admins only.\n *\n * Obtain via `client.company.purchases` — do not construct directly.\n *\n * @example\n * ```ts\n * const { data, pagination } = await client.company.purchases.list({\n * kind: 'bulk_acquisition',\n * from: '2026-09-01',\n * to: '2026-09-30',\n * })\n * ```\n */\nexport class CompanyPurchasesNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Lists every purchase and Bulk acquisition drawn on the Company wallet,\n * newest first, each attributed to the membership that bought it — including\n * members who have since left. A Bulk acquisition's per-work purchases are\n * not listed separately, and a failed purchase is not listed.\n *\n * A Bulk acquisition's corpus and manifest are reachable by a Company admin\n * through `acquisitions.getCorpus()` / `downloadCorpus()` / `getManifest()`\n * with its `id`.\n *\n * @param params - Optional filters (`member`, `from`, `to`, `kind`) and pagination.\n * @returns A paginated list of Company purchases.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n * @throws {LedewireError} With `statusCode === 400` for an invalid filter.\n */\n async list(params?: CompanyPurchasesParams): Promise<CompanyPurchaseList> {\n return this.http.get<CompanyPurchaseList>('/v1/company/purchases', params)\n }\n}\n\n/**\n * What each member has spent of the Company's money. Company admins only.\n *\n * Obtain via `client.company.spend` — do not construct directly.\n *\n * @example\n * ```ts\n * const { data } = await client.company.spend.list({ from: '2026-09-01' })\n * for (const { member, spend_cents } of data) console.log(member.name, spend_cents)\n * ```\n */\nexport class CompanySpendNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns one row per membership the Company has had, open or closed, oldest\n * first, with what each spent in the range — lifetime when neither `from`\n * nor `to` is given.\n *\n * `spend_cents` is net of refunds and counts what a Bulk acquisition\n * captured; a live hold does not count until it captures, so it can be lower\n * than the same member's `amount_cents` in `company.purchases.list()`.\n *\n * @param params - Optional `member`, `from`, and `to` filters.\n * @returns Spend per membership.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n * @throws {LedewireError} With `statusCode === 400` for an invalid filter.\n */\n async list(params?: CompanySpendParams): Promise<CompanySpendList> {\n return this.http.get<CompanySpendList>('/v1/company/spend', params)\n }\n}\n","/**\n * Company wallet funding.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type {\n CompanyPendingTopUpList,\n WalletPaymentSessionRequest,\n WalletPaymentSessionResponse,\n} from '@ledewire/core'\n\n/**\n * Fund the Company wallet and track top-ups that have not settled. Company\n * admins only.\n *\n * Members never see the Company balance and cannot fund the Company wallet; a\n * member who runs short is refused at purchase and must ask an admin.\n *\n * Obtain via `client.company.wallet` — do not construct directly.\n *\n * @example\n * ```ts\n * const session = await client.company.wallet.createPaymentSession({ amount_cents: 50000 })\n * // Confirm with session.client_secret in the payment widget, as for a personal top-up.\n *\n * const { data: pending } = await client.company.wallet.listPendingTopUps()\n * ```\n */\nexport class CompanyWalletNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Starts a Company wallet top-up, by card or ACH (`us_bank_account`). Confirm\n * it client-side with the returned `client_secret`, as for a personal top-up.\n *\n * The top-up is spendable only once it settles: a card usually settles at\n * once, an ACH debit after about four business days. Starting another top-up\n * never cancels an ACH debit already processing. Track it with\n * {@link listPendingTopUps}: a top-up drops off that list once it settles.\n * (`wallet.getPaymentStatus()` covers personal top-ups only and does not\n * find a Company session.)\n *\n * @param body - The amount to fund.\n * @returns Payment session details for the payment provider widget.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n * @throws {LedewireError} With `statusCode === 402` when the payment provider\n * refused to create the session.\n */\n async createPaymentSession(\n body: WalletPaymentSessionRequest,\n ): Promise<WalletPaymentSessionResponse> {\n return this.http.post<WalletPaymentSessionResponse>('/v1/company/wallet/payment-session', body)\n }\n\n /**\n * Lists the Company's top-ups that are not yet spendable, newest first:\n * `pending` (a session not yet paid), `awaiting_verification` (a bank account\n * whose microdeposits are not yet confirmed, up to ten days), and\n * `processing` (an ACH debit under way).\n *\n * @returns The pending top-ups.\n * @throws {ForbiddenError} When the caller is not a Company admin.\n */\n async listPendingTopUps(): Promise<CompanyPendingTopUpList> {\n return this.http.get<CompanyPendingTopUpList>('/v1/company/wallet/pending-top-ups')\n }\n}\n","/**\n * Company namespace — shared Company wallets, their members, and Machine users.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport { CompanyInvitationsNamespace } from './invitations.js'\nimport { CompanyMachineUsersNamespace } from './machine-users.js'\nimport { CompanyMembersNamespace } from './members.js'\nimport { CompanyMembershipNamespace } from './membership.js'\nimport { CompanyPurchasesNamespace, CompanySpendNamespace } from './reports.js'\nimport { CompanyWalletNamespace } from './wallet.js'\n\n/**\n * Company operations for the authenticated buyer.\n *\n * A Company is a shared wallet that pays for its members' purchases. Each\n * member spends under their own daily Spend cap, set by a Company admin, and\n * never sees the Company balance. Admins fund the wallet, manage members and\n * Machine users (agent identities with no login), and report on spend.\n *\n * `membership` and `invitations.accept()` are for any buyer; everything else is\n * Company-admin only and throws {@link ForbiddenError} for a plain member.\n *\n * Obtain via `client.company` — do not construct directly.\n */\nexport class CompanyNamespace {\n /** The authenticated buyer's own membership: read it, or leave the Company. */\n readonly membership: CompanyMembershipNamespace\n\n /** Invite people to the Company (admin), and accept an invitation (invitee). */\n readonly invitations: CompanyInvitationsNamespace\n\n /** List members, change a member's role or daily Spend cap, remove a member (admin). */\n readonly members: CompanyMembersNamespace\n\n /** Machine users and their Buyer keys and MCP API keys (admin). */\n readonly machineUsers: CompanyMachineUsersNamespace\n\n /** Fund the Company wallet and list unsettled top-ups (admin). */\n readonly wallet: CompanyWalletNamespace\n\n /** Everything the Company paid for, attributed to its members (admin). */\n readonly purchases: CompanyPurchasesNamespace\n\n /** What each member has spent of the Company's money (admin). */\n readonly spend: CompanySpendNamespace\n\n /** @internal */\n constructor(http: HttpClient) {\n this.membership = new CompanyMembershipNamespace(http)\n this.invitations = new CompanyInvitationsNamespace(http)\n this.members = new CompanyMembersNamespace(http)\n this.machineUsers = new CompanyMachineUsersNamespace(http)\n this.wallet = new CompanyWalletNamespace(http)\n this.purchases = new CompanyPurchasesNamespace(http)\n this.spend = new CompanySpendNamespace(http)\n }\n}\n","/**\n * Buyer API key management namespace.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { UserApiKey, UserApiKeyCreateRequest, UserApiKeyCreateResponse } from '@ledewire/core'\n\n/**\n * Manage buyer API keys for the authenticated user.\n *\n * Buyer API keys are the authentication credential for autonomous agents — they\n * allow an agent to obtain a buyer JWT via `auth.loginWithBuyerApiKey()` without\n * requiring a username and password. Each key is named, independently revocable,\n * and can carry an optional `spending_limit_cents` ceiling.\n *\n * **Secret handling:** `create()` returns the `secret` exactly once. It is never\n * retrievable again after the response is received — store it immediately in a\n * secrets manager (e.g. environment variable, Vault, AWS Secrets Manager).\n *\n * Obtain via `client.user.apiKeys` — do not construct directly.\n *\n * @example\n * ```ts\n * // Create a key for an agent, with a $10 spend ceiling\n * const { key, secret } = await client.user.apiKeys.create({\n * name: 'my-rag-agent',\n * spending_limit_cents: 1000,\n * })\n * // Store secret immediately — it cannot be retrieved again\n * await secretsManager.put('LEDEWIRE_BUYER_SECRET', secret)\n *\n * // List all keys (secrets never included)\n * const keys = await client.user.apiKeys.list()\n *\n * // Revoke a compromised key\n * await client.user.apiKeys.revoke(keys[0].id)\n * ```\n */\nexport class UserApiKeysNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns all buyer API keys for the authenticated user.\n * The `secret` is never included in list responses.\n *\n * @returns Array of API key records.\n */\n async list(): Promise<UserApiKey[]> {\n return this.http.get<UserApiKey[]>('/v1/user/api-keys')\n }\n\n /**\n * Creates a new buyer API key.\n *\n * The `secret` in the response is shown exactly once and cannot be retrieved\n * again. Store it immediately in a secrets manager before discarding the\n * response object.\n *\n * @param body - Name and optional spend ceiling for the new key.\n * @returns The new key's public identifier and one-time secret.\n * @throws {ForbiddenError} When the caller is a Machine user, whose keys its\n * Company's admins manage through `company.machineUsers.buyerKeys`.\n *\n * @example\n * ```ts\n * const { key, secret } = await client.user.apiKeys.create({\n * name: 'production-agent',\n * spending_limit_cents: 5000, // $50 cap\n * })\n * // ⚠️ Store secret NOW — it is shown once only\n * process.env.LEDEWIRE_BUYER_SECRET = secret\n * ```\n */\n async create(body: UserApiKeyCreateRequest): Promise<UserApiKeyCreateResponse> {\n return this.http.post<UserApiKeyCreateResponse>('/v1/user/api-keys', body)\n }\n\n /**\n * Revokes (permanently deletes) a buyer API key by ID.\n *\n * Any agent currently using this key will receive `401` on its next\n * token refresh. Revocation takes effect immediately.\n *\n * @param id - UUID of the API key to revoke.\n * @throws {ForbiddenError} When the caller is a Machine user.\n */\n async revoke(id: string): Promise<void> {\n return this.http.delete(`/v1/user/api-keys/${encodeURIComponent(id)}`)\n }\n}\n","/**\n * Buyer daily spend cap namespace.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { UserSpendCap, UserSpendCapUpdateRequest } from '@ledewire/core'\n\n/**\n * Manage the authenticated buyer's daily spend cap.\n *\n * Every new buyer starts with a default cap, so `null` on {@link\n * UserSpendCapNamespace.update} is the only way to become uncapped — there is no\n * separate \"remove the cap\" call. While capped, `cap_cents` and `remaining_cents`\n * are numbers; once uncapped, both read back as `null` because there is no ceiling\n * to report or subtract from.\n *\n * The cap governs every wallet debit the buyer makes — MCP, REST, or the web\n * payment gate — over a rolling window bounded by `spend_window_timezone` (an IANA\n * zone, UTC by default) and reset at `resets_at`. `bulk_exempt` says whether this\n * buyer's bulk acquisitions are excluded from that spend, in which case\n * `spent_cents` / `remaining_cents` describe ordinary purchases only.\n *\n * **Exceeding the cap throws {@link SpendCapReachedError}** (HTTP 402) from\n * `client.purchases.create()` and the x402 content gate. Funding the wallet does not\n * clear it — the buyer must wait for the window to roll at `resets_at`, or the cap\n * must be raised or cleared here.\n *\n * Obtain via `client.user.spendCap` — do not construct directly.\n *\n * @example\n * ```ts\n * const cap = await client.user.spendCap.get()\n * if (cap.remaining_cents !== null && cap.remaining_cents < 500) {\n * console.warn(`Only ${cap.remaining_cents}c left before the cap resets at ${cap.resets_at}`)\n * }\n *\n * // Raise the cap to $20/day\n * await client.user.spendCap.update({ daily_spend_limit_cents: 2000 })\n *\n * // Remove the cap entirely (become uncapped)\n * await client.user.spendCap.update({ daily_spend_limit_cents: null })\n * ```\n */\nexport class UserSpendCapNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns the authenticated buyer's spend cap, read against the current spend\n * window.\n *\n * For a buyer with an open Company membership this is the membership's cap —\n * read in the Company's timezone, counting only spend paid through the\n * membership, never uncapped, and always binding bulk acquisitions\n * (`bulk_exempt: false`). `company_name` names the Company; it is `null` for\n * anyone else.\n *\n * @returns The current spend cap, spend-to-date, and reset time.\n */\n async get(): Promise<UserSpendCap> {\n return this.http.get<UserSpendCap>('/v1/user/spend-cap')\n }\n\n /**\n * Sets or clears the authenticated buyer's daily spend cap.\n *\n * `daily_spend_limit_cents` is required and nullable: pass a number to set the\n * cap, or `null` to remove it (the only way to become uncapped). A cap set below\n * spend already made in the current window is accepted — it just leaves\n * `remaining_cents` at zero until the window rolls.\n *\n * @param body - The new cap in whole cents, or `null` to remove it.\n * @returns The updated spend cap.\n * @throws {ForbiddenError} When the buyer holds an open Company membership. A\n * member's cap — an admin's own included — is set by a Company admin through\n * `company.members.update()`.\n */\n async update(body: UserSpendCapUpdateRequest): Promise<UserSpendCap> {\n return this.http.patch<UserSpendCap>('/v1/user/spend-cap', body)\n }\n}\n","/**\n * MCP API key management namespace.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport type { McpApiKey, McpApiKeyCreateRequest, McpApiKeyCreateResponse } from '@ledewire/core'\n\n/**\n * Manage the authenticated buyer's MCP API keys.\n *\n * MCP API keys authenticate agent requests against the Ledewire MCP server, sent\n * as `Authorization: Bearer <key>:<secret>`. Each key carries an explicit set of\n * scopes — `can_search` (default `true`), `can_purchase` (default `false`), and\n * the seller-tier `can_manage_content` / `can_read_analytics`, which additionally\n * require `store_id` to be set to a store the user owns or authors.\n *\n * **Secret handling:** `create()` returns the `secret` exactly once. It is never\n * retrievable again — store it immediately, alongside the `key`, in a secrets\n * manager.\n *\n * **Changing permissions:** scopes are fixed at creation. To change what a key\n * can do, revoke it and create a replacement with the desired scopes.\n *\n * Obtain via `client.user.mcpKeys` — do not construct directly.\n *\n * @example\n * ```ts\n * // Create a search+purchase key for an autonomous agent\n * const { key, secret } = await client.user.mcpKeys.create({\n * label: 'my-rag-agent',\n * can_search: true,\n * can_purchase: true,\n * })\n * // Store immediately — the secret cannot be retrieved again\n * await secretsManager.put('LEDEWIRE_MCP_CREDENTIAL', `${key}:${secret}`)\n *\n * // List all keys (secrets never included)\n * const keys = await client.user.mcpKeys.list()\n *\n * // To change permissions: revoke and recreate\n * await client.user.mcpKeys.revoke(keys[0].id)\n * ```\n */\nexport class UserMcpKeysNamespace {\n /** @internal */\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Returns all MCP API keys for the authenticated user.\n * The `secret` is never included in list responses.\n *\n * @returns Array of MCP API key records.\n */\n async list(): Promise<McpApiKey[]> {\n return this.http.get<McpApiKey[]>('/v1/mcp/keys')\n }\n\n /**\n * Creates a new MCP API key.\n *\n * The `secret` in the response is shown exactly once and cannot be retrieved\n * again. Store it immediately alongside `key` — the pair is used together as\n * `Authorization: Bearer <key>:<secret>` against the Ledewire MCP server.\n *\n * @param body - Label and scopes for the new key.\n * @returns The new key's public identifier, scopes, and one-time secret.\n * @throws {ForbiddenError} When a seller-tier scope or `store_id` names a store\n * the user is not an owner or author of (plain store members cannot hold a\n * store-scoped key), or when the caller is a Machine user, whose keys its\n * Company's admins manage through `company.machineUsers.mcpKeys`. Seller-tier\n * scopes are re-checked on every use, so a key stops working if its holder\n * loses the role.\n *\n * @example\n * ```ts\n * const { key, secret } = await client.user.mcpKeys.create({\n * label: 'production-agent',\n * can_search: true,\n * can_purchase: true,\n * })\n * ```\n */\n async create(body: McpApiKeyCreateRequest): Promise<McpApiKeyCreateResponse> {\n return this.http.post<McpApiKeyCreateResponse>('/v1/mcp/keys', body)\n }\n\n /**\n * Revokes (permanently deletes) an MCP API key by ID.\n *\n * To change a key's permissions, revoke it and create a replacement with the\n * desired scopes — scopes cannot be edited in place.\n *\n * @param id - UUID of the MCP API key to revoke.\n * @throws {ForbiddenError} When the caller is a Machine user.\n */\n async revoke(id: string): Promise<void> {\n return this.http.delete(`/v1/mcp/keys/${encodeURIComponent(id)}`)\n }\n}\n","/**\n * User namespace — authenticated buyer account operations.\n *\n * @module\n */\nimport type { HttpClient } from '@ledewire/core'\nimport { UserApiKeysNamespace } from './api-keys.js'\nimport { UserSpendCapNamespace } from './spend-cap.js'\nimport { UserMcpKeysNamespace } from './mcp-keys.js'\n\n/**\n * Authenticated buyer account operations.\n *\n * Obtain via `client.user` — do not construct directly.\n */\nexport class UserNamespace {\n /**\n * Buyer API key management: create, list, and revoke named API keys.\n * Keys are used by autonomous agents to authenticate without a username/password.\n */\n readonly apiKeys: UserApiKeysNamespace\n\n /**\n * The authenticated buyer's daily spend cap: read and update the ceiling that\n * governs every wallet debit (MCP, REST, and the web payment gate).\n */\n readonly spendCap: UserSpendCapNamespace\n\n /**\n * MCP API key management: create, list, and revoke keys scoped for use against\n * the Ledewire MCP server.\n */\n readonly mcpKeys: UserMcpKeysNamespace\n\n /** @internal */\n constructor(http: HttpClient) {\n this.apiKeys = new UserApiKeysNamespace(http)\n this.spendCap = new UserSpendCapNamespace(http)\n this.mcpKeys = new UserMcpKeysNamespace(http)\n }\n}\n","import {\n DEFAULT_BASE_URL,\n HttpClient,\n MemoryTokenStorage,\n TokenManager,\n createRefreshFn,\n} from '@ledewire/core'\nimport type { TokenStorage } from '@ledewire/core'\nimport { BrowserAuthNamespace } from './resources/auth.js'\nimport { BrowserConfigNamespace } from './resources/config.js'\nimport { BrowserContentNamespace } from './resources/content.js'\nimport { BrowserPurchasesNamespace } from './resources/purchases.js'\nimport { BrowserSellerNamespace } from './resources/seller/index.js'\nimport { BrowserWalletNamespace } from './resources/wallet.js'\nimport { CheckoutNamespace } from './resources/checkout.js'\nimport { CompanyNamespace } from './resources/company/index.js'\nimport { UserNamespace } from './resources/user/index.js'\n\n/**\n * Configuration options for the LedeWire browser client.\n */\nexport interface BrowserClientConfig {\n /**\n * LedeWire API key that identifies the store.\n * Obtained from the LedeWire merchant dashboard.\n */\n apiKey: string\n /**\n * Override the API base URL.\n * Defaults to `https://api.ledewire.com`.\n */\n baseUrl?: string\n /**\n * Token storage adapter.\n * Defaults to {@link MemoryTokenStorage} (in-memory, most secure).\n *\n * To persist sessions across page reloads, use the built-in\n * `localStorageAdapter`:\n * ```ts\n * import { init, localStorageAdapter } from '@ledewire/browser'\n * const lw = init({ apiKey: '...', storage: localStorageAdapter() })\n * ```\n */\n storage?: TokenStorage\n /**\n * Called when the user's session expires and cannot be refreshed.\n * Use this to show a re-authentication prompt.\n *\n * @example\n * ```ts\n * onAuthExpired: () => showLoginModal()\n * ```\n */\n onAuthExpired?: () => void\n}\n\n/**\n * Initialises a LedeWire browser client.\n * This is the primary entry point for the browser SDK.\n *\n * @example CDN usage:\n * ```html\n * <script src=\"https://cdn.jsdelivr.net/npm/@ledewire/browser@1/dist/ledewire.min.js\"></script>\n * <script>\n * const lw = Ledewire.init({ apiKey: 'your_api_key' })\n * const state = await lw.checkout.state('content-id')\n * </script>\n * ```\n *\n * @example npm usage:\n * ```ts\n * import { init } from '@ledewire/browser'\n * const lw = init({ apiKey: 'your_api_key' })\n * ```\n */\nexport function init(config: BrowserClientConfig): BrowserClient {\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL\n const storage = config.storage ?? new MemoryTokenStorage()\n\n const tokenManager = new TokenManager({\n storage,\n refreshFn: createRefreshFn(baseUrl),\n ...(config.onAuthExpired !== undefined && { onAuthExpired: config.onAuthExpired }),\n })\n\n const http = new HttpClient({\n baseUrl,\n getAccessToken: () => tokenManager.getAccessToken(),\n onUnauthorized: () => tokenManager.handleUnauthorized(),\n })\n\n return new BrowserClient(http, tokenManager, config)\n}\n\n/**\n * The LedeWire browser client.\n * Access buyer flows through the namespaced properties.\n *\n * @remarks\n * Instantiate with {@link init} rather than constructing directly.\n */\nexport class BrowserClient {\n /** Platform-level public configuration (no auth required) */\n readonly config: BrowserConfigNamespace\n\n /** Buyer authentication: email/password signup/login, Google OAuth, password reset */\n readonly auth: BrowserAuthNamespace\n\n /** Checkout state machine: determines next action for a piece of content */\n readonly checkout: CheckoutNamespace\n\n /** Wallet: balance, fund via payment session, transaction history */\n readonly wallet: BrowserWalletNamespace\n\n /** Content purchases for the authenticated buyer */\n readonly purchases: BrowserPurchasesNamespace\n\n /** Public content with per-user access information */\n readonly content: BrowserContentNamespace\n\n /** Seller operations: API key login, content list/search/get */\n readonly seller: BrowserSellerNamespace\n\n /** Authenticated buyer account: API keys, MCP keys, and the daily spend cap */\n readonly user: UserNamespace\n\n /** Company membership, and Company administration: members, Machine users, wallet, reports */\n readonly company: CompanyNamespace\n\n /** @internal */\n constructor(\n private readonly _http: HttpClient,\n private readonly _tokenManager: TokenManager,\n private readonly _config: BrowserClientConfig,\n ) {\n this.config = new BrowserConfigNamespace(_http)\n this.auth = new BrowserAuthNamespace(_http, _tokenManager)\n this.checkout = new CheckoutNamespace(_http)\n this.wallet = new BrowserWalletNamespace(_http)\n this.purchases = new BrowserPurchasesNamespace(_http)\n this.content = new BrowserContentNamespace(_http)\n this.seller = new BrowserSellerNamespace(_http, _tokenManager)\n this.user = new UserNamespace(_http)\n this.company = new CompanyNamespace(_http)\n }\n}\n","import type { TokenStorage, StoredTokens } from '@ledewire/core'\n\nconst DEFAULT_STORAGE_KEY = 'lw:tokens'\n\n/**\n * Shared implementation for `localStorage` and `sessionStorage` adapters.\n * Not exported from the public API — use {@link localStorageAdapter} or\n * {@link sessionStorageAdapter} instead.\n *\n * @internal\n */\nexport function webStorageAdapter(backend: Storage, key = DEFAULT_STORAGE_KEY): TokenStorage {\n return {\n getTokens(): StoredTokens | null {\n const raw = backend.getItem(key)\n if (!raw) return null\n try {\n return JSON.parse(raw) as StoredTokens\n } catch {\n // Corrupted value — treat as empty\n return null\n }\n },\n setTokens(tokens: StoredTokens): void {\n backend.setItem(key, JSON.stringify(tokens))\n },\n clearTokens(): void {\n backend.removeItem(key)\n },\n }\n}\n","import type { TokenStorage } from '@ledewire/core'\nimport { webStorageAdapter } from './web-storage-adapter.js'\n\n/**\n * A {@link TokenStorage} adapter that persists tokens in `localStorage`.\n *\n * Tokens survive page reloads and browser restarts, which is convenient\n * for sites where users expect persistent sessions.\n *\n * **Security note:** `localStorage` is accessible to any JavaScript on the\n * same origin. Only use this adapter on sites you fully control and trust.\n * The default in-memory storage is safer for high-security use cases.\n *\n * @param key - The `localStorage` key used to store tokens.\n * Defaults to `'lw:tokens'`. Override this if you have multiple\n * LedeWire integrations on the same origin.\n *\n * @example\n * ```ts\n * import { init, localStorageAdapter } from '@ledewire/browser'\n *\n * const lw = init({\n * apiKey: 'your_api_key',\n * storage: localStorageAdapter(),\n * })\n * ```\n */\nexport function localStorageAdapter(key?: string): TokenStorage {\n return webStorageAdapter(localStorage, key)\n}\n","import type { TokenStorage } from '@ledewire/core'\nimport { webStorageAdapter } from './web-storage-adapter.js'\n\n/**\n * A {@link TokenStorage} adapter that persists tokens in `sessionStorage`.\n *\n * Tokens survive page reloads within the same tab but are cleared when the\n * tab is closed or the session ends. This prevents token leakage across\n * tabs and is a good default for sites where users do not expect persistent\n * sessions (e.g. embedded checkout widgets, kiosk-mode UIs).\n *\n * **Security note:** `sessionStorage` is accessible to any JavaScript on the\n * same origin and tab. It is more isolated than `localStorage` (no\n * cross-tab sharing), but the default in-memory storage is still safer for\n * high-security use cases.\n *\n * @param key - The `sessionStorage` key used to store tokens.\n * Defaults to `'lw:tokens'`. Override this if you have multiple\n * LedeWire integrations on the same origin.\n *\n * @example\n * ```ts\n * import { init, sessionStorageAdapter } from '@ledewire/browser'\n *\n * const lw = init({\n * apiKey: 'your_api_key',\n * storage: sessionStorageAdapter(),\n * })\n * ```\n */\nexport function sessionStorageAdapter(key?: string): TokenStorage {\n return webStorageAdapter(sessionStorage, key)\n}\n"],"mappings":"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"}
|
package/dist/ledewire.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var Ledewire=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){return atob(e)}function n(e){return{...e,...typeof e.content_body==`string`&&{content_body:t(e.content_body)},...typeof e.teaser==`string`&&{teaser:t(e.teaser)}}}function r(e){"@babel/helpers - typeof";return r=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},r(e)}function i(e,t){if(r(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var i=n.call(e,t||`default`);if(r(i)!=`object`)return i;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function a(e){var t=i(e,`string`);return r(t)==`symbol`?t:t+``}function o(e,t,n){return(t=a(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var s,c=Symbol.for(`@ledewire/error-brands`);s=Symbol.hasInstance;var l=class extends Error{constructor(e,t,n,r,i){super(e),o(this,`statusCode`,void 0),o(this,`code`,void 0),o(this,`type`,void 0),o(this,`details`,void 0),this.name=`LedewireError`,this.statusCode=t,this.code=n,this.type=r,this.details=i,Object.setPrototypeOf(this,new.target.prototype);let a=[],s=new.target;for(;typeof s==`function`;){let e=s.brand;typeof e==`string`&&Object.prototype.hasOwnProperty.call(s,`brand`)&&a.push(e),s=Object.getPrototypeOf(s)}Object.defineProperty(this,c,{value:a,enumerable:!1,configurable:!0})}static[s](e){if(Function.prototype[Symbol.hasInstance].call(this,e))return!0;if(!e||typeof e!=`object`&&typeof e!=`function`)return!1;let t=e[c];return Array.isArray(t)&&t.includes(this.brand)}};o(l,`brand`,`LedewireError`);var u=class extends l{constructor(e,t,n,r){super(e,401,t,n,r),this.name=`AuthError`}};o(u,`brand`,`AuthError`);var d=class extends l{constructor(e,t,n,r){super(e,403,t,n,r),this.name=`ForbiddenError`}};o(d,`brand`,`ForbiddenError`);var f=class extends l{constructor(e,t,n,r){super(e,404,t,n,r),this.name=`NotFoundError`}};o(f,`brand`,`NotFoundError`);var p=class extends l{constructor(e,t,n,r,i){super(e,t,n,r,i),this.name=`PurchaseError`}};o(p,`brand`,`PurchaseError`);var m=class extends l{constructor(e,t,n){super(e,402,n,`daily_spend_cap_reached`),o(this,`capCents`,void 0),o(this,`spentCents`,void 0),o(this,`remainingCents`,void 0),o(this,`resetsAt`,void 0),o(this,`bulkExempt`,void 0),this.name=`SpendCapReachedError`,this.capCents=t.capCents,this.spentCents=t.spentCents,this.remainingCents=t.remainingCents,this.resetsAt=t.resetsAt,this.bulkExempt=t.bulkExempt,Object.setPrototypeOf(this,new.target.prototype)}};o(m,`brand`,`SpendCapReachedError`);function h(e){if(!e||typeof e!=`object`)return null;let t=e,n=t.error;if(!n||typeof n!=`object`)return null;let r=n;if(r.type!==`daily_spend_cap_reached`)return null;let i=t.cap_cents,a=t.spent_cents,o=t.remaining_cents,s=t.resets_at,c=t.bulk_exempt;if(typeof i!=`number`||typeof a!=`number`||typeof o!=`number`||typeof s!=`string`||typeof c!=`boolean`)return null;let l=typeof r.message==`string`?r.message:`Daily spend cap reached.`,u=typeof r.code==`number`?r.code:void 0;return new m(l,{capCents:i,spentCents:a,remainingCents:o,resetsAt:s,bulkExempt:c},u)}function g(e,t){if(!e||typeof e!=`object`||Array.isArray(e))return{message:t,code:void 0,type:void 0,details:void 0};let{error:n,...r}=e,i=Object.keys(r).length>0?r:void 0;if(typeof n==`string`)return{message:n,code:void 0,type:void 0,details:i};if(!n||typeof n!=`object`||Array.isArray(n))return{message:t,code:void 0,type:void 0,details:i};let a=n;return{message:typeof a.message==`string`?a.message:t,code:typeof a.code==`number`?a.code:void 0,type:typeof a.type==`string`?a.type:void 0,details:i}}var _=class{constructor(e={}){o(this,`baseUrl`,void 0),o(this,`getAccessToken`,void 0),o(this,`onUnauthorized`,void 0),this.baseUrl=(e.baseUrl??`https://api.ledewire.com`).replace(/\/$/,``),this.getAccessToken=e.getAccessToken??(()=>null),this.onUnauthorized=e.onUnauthorized??(()=>null)}async get(e,t,n){return this.request(`GET`,this.buildUrl(e,t),void 0,n)}async post(e,t,n){return this.request(`POST`,this.buildUrl(e,n),t)}async put(e,t){return this.request(`PUT`,this.buildUrl(e),t)}async patch(e,t){return this.request(`PATCH`,this.buildUrl(e),t)}async delete(e){return this.request(`DELETE`,this.buildUrl(e))}async getRaw(e){return this.performRequest(`GET`,this.buildUrl(e),{Accept:`application/gzip, application/json`})}buildUrl(e,t){let n=`${this.baseUrl}${e}`;if(!t)return n;let r=Object.entries(t).filter(e=>e[1]!==void 0);return r.length===0?n:`${n}?${new URLSearchParams(r.map(([e,t])=>[e,String(t)])).toString()}`}async request(e,t,n,r){let i=await this.performRequest(e,t,{"Content-Type":`application/json`,Accept:`application/json`},n,!1,r);if(i.status!==204)return i.json()}async performRequest(e,t,n,r,i=!1,a){let o=a?.auth!==!1,s=o?await this.getAccessToken():null,c={...n};s&&(c.Authorization=`Bearer ${s}`);let l=await fetch(t,{method:e,headers:c,...r!==void 0&&{body:JSON.stringify(r)}});if(l.status===401&&!i){if(o&&await this.onUnauthorized())return this.performRequest(e,t,n,r,!0,a);throw new u(`Session expired. Please re-authenticate.`)}return l.ok||await this.throwApiError(l),l}async throwApiError(e){let t;try{t=await e.json()}catch{}let n=h(t);if(n)throw n;let{message:r,code:i,type:a,details:o}=g(t,e.statusText);switch(e.status){case 401:throw new u(r,i,a,o);case 403:throw new d(r,i,a,o);case 404:throw new f(r,i,a,o);default:throw new l(r,e.status,i,a,o)}}},v=6e4,y=class{constructor(e){o(this,`storage`,void 0),o(this,`refreshFn`,void 0),o(this,`onTokenRefreshed`,void 0),o(this,`onAuthExpired`,void 0),o(this,`refreshPromise`,null),this.storage=e.storage,this.refreshFn=e.refreshFn,this.onTokenRefreshed=e.onTokenRefreshed,this.onAuthExpired=e.onAuthExpired}async getAccessToken(){let e=await this.storage.getTokens();return e?e.expiresAt-Date.now()<v?(await this.performRefresh(e.refreshToken))?.accessToken??null:e.accessToken:null}async handleUnauthorized(){let e=await this.storage.getTokens();if(!e)return await this.onAuthExpired?.(),null;let t=await this.performRefresh(e.refreshToken);return t||await this.onAuthExpired?.(),t?.accessToken??null}async setTokens(e){await this.storage.setTokens(e)}async clearTokens(){await this.storage.clearTokens()}performRefresh(e){return this.refreshPromise||(this.refreshPromise=this.refreshFn(e).then(async e=>(await this.storage.setTokens(e),await this.onTokenRefreshed?.(e),e)).catch(e=>{throw this.storage.clearTokens(),new u(`Token refresh failed. Please re-authenticate.`)}).finally(()=>{this.refreshPromise=null})),this.refreshPromise}},b=class{constructor(){o(this,`tokens`,null)}getTokens(){return this.tokens}setTokens(e){this.tokens=e}clearTokens(){this.tokens=null}};function x(e){return new Date(e).getTime()}function S(e){return async t=>{let n=await fetch(`${e}/v1/auth/token/refresh`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({refresh_token:t})});if(!n.ok)throw Error(`Token refresh failed`);let r=await n.json();return{accessToken:r.access_token,refreshToken:r.refresh_token,expiresAt:x(r.expires_at)}}}var C=class{constructor(e,t){o(this,`http`,void 0),o(this,`tokenManager`,void 0),this.http=e,this.tokenManager=t}async signup(e){let t=await this.http.post(`/v1/auth/signup`,e);return await this.storeTokens(t),t}async loginWithEmail(e){let t=await this.http.post(`/v1/auth/login/email`,e);return await this.storeTokens(t),t}async loginWithGoogle(e){let t=await this.http.post(`/v1/auth/login/google`,e);return await this.storeTokens(t),t}async loginWithBuyerApiKey(e){let t=await this.http.post(`/v1/auth/login/buyer-api-key`,e);return await this.storeTokens(t),t}async requestPasswordReset(e){return this.http.post(`/v1/auth/password/reset-request`,e)}async resetPassword(e){return this.http.post(`/v1/auth/password/reset`,e)}async storeTokens(e){await this.tokenManager.setTokens({accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:x(e.expires_at)})}},w=class{constructor(e){o(this,`http`,void 0),this.http=e}async getPublic(){return this.http.get(`/v1/config/public`)}},T=class{constructor(e){o(this,`http`,void 0),this.http=e}async getWithAccess(e){return n(await this.http.get(`/v1/content/${encodeURIComponent(e)}/with-access`))}},E=class{constructor(e){o(this,`http`,void 0),this.http=e}async create(e){return this.http.post(`/v1/purchases`,e)}async list(){return this.http.get(`/v1/purchases`)}async get(e){return this.http.get(`/v1/purchases/${encodeURIComponent(e)}`)}},D=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return(await this.http.get(`/v1/seller/content`)).map(n)}async search(e){return(await this.http.post(`/v1/seller/content/search`,e)).map(n)}async get(e){return n(await this.http.get(`/v1/seller/content/${encodeURIComponent(e)}`))}},O=class{constructor(e,t){o(this,`http`,void 0),o(this,`tokenManager`,void 0),o(this,`content`,void 0),this.http=e,this.tokenManager=t,this.content=new D(e)}async loginWithApiKey(e){let t=await this.http.post(`/v1/auth/login/api-key`,e);return await this.tokenManager.setTokens({accessToken:t.access_token,refreshToken:t.refresh_token,expiresAt:x(t.expires_at)}),t}},k=class{constructor(e){o(this,`http`,void 0),this.http=e}async balance(){return this.http.get(`/v1/wallet/balance`)}async transactions(){return this.http.get(`/v1/wallet/transactions`)}async createPaymentSession(e){return this.http.post(`/v1/wallet/payment-session`,e)}async getPaymentStatus(e){return this.http.get(`/v1/wallet/payment-status/${encodeURIComponent(e)}`)}},A=class{constructor(e){o(this,`http`,void 0),this.http=e}async state(e){return this.http.get(`/v1/checkout/state/${encodeURIComponent(e)}`)}},j=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return this.http.get(`/v1/user/api-keys`)}async create(e){return this.http.post(`/v1/user/api-keys`,e)}async revoke(e){return this.http.delete(`/v1/user/api-keys/${encodeURIComponent(e)}`)}},M=class{constructor(e){o(this,`http`,void 0),this.http=e}async get(){return this.http.get(`/v1/user/spend-cap`)}async update(e){return this.http.patch(`/v1/user/spend-cap`,e)}},N=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return this.http.get(`/v1/mcp/keys`)}async create(e){return this.http.post(`/v1/mcp/keys`,e)}async revoke(e){return this.http.delete(`/v1/mcp/keys/${encodeURIComponent(e)}`)}},P=class{constructor(e){o(this,`apiKeys`,void 0),o(this,`spendCap`,void 0),o(this,`mcpKeys`,void 0),this.apiKeys=new j(e),this.spendCap=new M(e),this.mcpKeys=new N(e)}};function F(e){let t=e.baseUrl??`https://api.ledewire.com`,n=new y({storage:e.storage??new b,refreshFn:S(t),...e.onAuthExpired!==void 0&&{onAuthExpired:e.onAuthExpired}});return new I(new _({baseUrl:t,getAccessToken:()=>n.getAccessToken(),onUnauthorized:()=>n.handleUnauthorized()}),n,e)}var I=class{constructor(e,t,n){o(this,`_http`,void 0),o(this,`_tokenManager`,void 0),o(this,`_config`,void 0),o(this,`config`,void 0),o(this,`auth`,void 0),o(this,`checkout`,void 0),o(this,`wallet`,void 0),o(this,`purchases`,void 0),o(this,`content`,void 0),o(this,`seller`,void 0),o(this,`user`,void 0),this._http=e,this._tokenManager=t,this._config=n,this.config=new w(e),this.auth=new C(e,t),this.checkout=new A(e),this.wallet=new k(e),this.purchases=new E(e),this.content=new T(e),this.seller=new O(e,t),this.user=new P(e)}},L=`lw:tokens`;function R(e,t=L){return{getTokens(){let n=e.getItem(t);if(!n)return null;try{return JSON.parse(n)}catch{return null}},setTokens(n){e.setItem(t,JSON.stringify(n))},clearTokens(){e.removeItem(t)}}}function z(e){return R(localStorage,e)}function B(e){return R(sessionStorage,e)}return e.AuthError=u,e.ForbiddenError=d,e.LedewireError=l,e.MemoryTokenStorage=b,e.NotFoundError=f,e.PurchaseError=p,e.SpendCapReachedError=m,e.init=F,e.localStorageAdapter=z,e.parseExpiresAt=x,e.sessionStorageAdapter=B,e})({});
|
|
1
|
+
var Ledewire=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){return atob(e)}function n(e){return{...e,...typeof e.content_body==`string`&&{content_body:t(e.content_body)},...typeof e.teaser==`string`&&{teaser:t(e.teaser)}}}function r(e){"@babel/helpers - typeof";return r=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},r(e)}function i(e,t){if(r(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var i=n.call(e,t||`default`);if(r(i)!=`object`)return i;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function a(e){var t=i(e,`string`);return r(t)==`symbol`?t:t+``}function o(e,t,n){return(t=a(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var s,c=Symbol.for(`@ledewire/error-brands`);s=Symbol.hasInstance;var l=class extends Error{constructor(e,t,n,r,i){super(e),o(this,`statusCode`,void 0),o(this,`code`,void 0),o(this,`type`,void 0),o(this,`details`,void 0),this.name=`LedewireError`,this.statusCode=t,this.code=n,this.type=r,this.details=i,Object.setPrototypeOf(this,new.target.prototype);let a=[],s=new.target;for(;typeof s==`function`;){let e=s.brand;typeof e==`string`&&Object.prototype.hasOwnProperty.call(s,`brand`)&&a.push(e),s=Object.getPrototypeOf(s)}Object.defineProperty(this,c,{value:a,enumerable:!1,configurable:!0})}static[s](e){if(Function.prototype[Symbol.hasInstance].call(this,e))return!0;if(!e||typeof e!=`object`&&typeof e!=`function`)return!1;let t=e[c];return Array.isArray(t)&&t.includes(this.brand)}};o(l,`brand`,`LedewireError`);var u=class extends l{constructor(e,t,n,r){super(e,401,t,n,r),this.name=`AuthError`}};o(u,`brand`,`AuthError`);var d=class extends l{constructor(e,t,n,r){super(e,403,t,n,r),this.name=`ForbiddenError`}};o(d,`brand`,`ForbiddenError`);var f=class extends l{constructor(e,t,n,r){super(e,404,t,n,r),this.name=`NotFoundError`}};o(f,`brand`,`NotFoundError`);var p=class extends l{constructor(e,t,n,r,i){super(e,t,n,r,i),this.name=`PurchaseError`}};o(p,`brand`,`PurchaseError`);var m=class extends l{constructor(e,t,n){super(e,402,n,`daily_spend_cap_reached`),o(this,`capCents`,void 0),o(this,`spentCents`,void 0),o(this,`remainingCents`,void 0),o(this,`resetsAt`,void 0),o(this,`bulkExempt`,void 0),this.name=`SpendCapReachedError`,this.capCents=t.capCents,this.spentCents=t.spentCents,this.remainingCents=t.remainingCents,this.resetsAt=t.resetsAt,this.bulkExempt=t.bulkExempt,Object.setPrototypeOf(this,new.target.prototype)}};o(m,`brand`,`SpendCapReachedError`);function h(e){if(!e||typeof e!=`object`)return null;let t=e,n=t.error;if(!n||typeof n!=`object`)return null;let r=n;if(r.type!==`daily_spend_cap_reached`)return null;let i=t.cap_cents,a=t.spent_cents,o=t.remaining_cents,s=t.resets_at,c=t.bulk_exempt;if(typeof i!=`number`||typeof a!=`number`||typeof o!=`number`||typeof s!=`string`||typeof c!=`boolean`)return null;let l=typeof r.message==`string`?r.message:typeof t.message==`string`?t.message:`Daily spend cap reached.`,u=typeof r.code==`number`?r.code:void 0;return new m(l,{capCents:i,spentCents:a,remainingCents:o,resetsAt:s,bulkExempt:c},u)}function g(e,t){if(!e||typeof e!=`object`||Array.isArray(e))return{message:t,code:void 0,type:void 0,details:void 0};let{error:n,...r}=e,i=Object.keys(r).length>0?r:void 0;if(typeof n==`string`)return{message:n,code:void 0,type:void 0,details:i};if(!n||typeof n!=`object`||Array.isArray(n))return{message:t,code:void 0,type:void 0,details:i};let a=n;return{message:typeof a.message==`string`?a.message:t,code:typeof a.code==`number`?a.code:void 0,type:typeof a.type==`string`?a.type:void 0,details:i}}var _=class{constructor(e={}){o(this,`baseUrl`,void 0),o(this,`getAccessToken`,void 0),o(this,`onUnauthorized`,void 0),this.baseUrl=(e.baseUrl??`https://api.ledewire.com`).replace(/\/$/,``),this.getAccessToken=e.getAccessToken??(()=>null),this.onUnauthorized=e.onUnauthorized??(()=>null)}async get(e,t,n){return this.request(`GET`,this.buildUrl(e,t),void 0,n)}async post(e,t,n){return this.request(`POST`,this.buildUrl(e,n),t)}async put(e,t){return this.request(`PUT`,this.buildUrl(e),t)}async patch(e,t){return this.request(`PATCH`,this.buildUrl(e),t)}async delete(e){return this.request(`DELETE`,this.buildUrl(e))}async getRaw(e){return this.performRequest(`GET`,this.buildUrl(e),{Accept:`application/gzip, application/json`})}buildUrl(e,t){let n=`${this.baseUrl}${e}`;if(!t)return n;let r=Object.entries(t).filter(e=>e[1]!==void 0);return r.length===0?n:`${n}?${new URLSearchParams(r.map(([e,t])=>[e,String(t)])).toString()}`}async request(e,t,n,r){let i=await this.performRequest(e,t,{"Content-Type":`application/json`,Accept:`application/json`},n,!1,r);if(i.status!==204)return i.json()}async performRequest(e,t,n,r,i=!1,a){let o=a?.auth!==!1,s=o?await this.getAccessToken():null,c={...n};s&&(c.Authorization=`Bearer ${s}`);let l=await fetch(t,{method:e,headers:c,...r!==void 0&&{body:JSON.stringify(r)}});if(l.status===401&&!i){if(o&&await this.onUnauthorized())return this.performRequest(e,t,n,r,!0,a);throw new u(`Session expired. Please re-authenticate.`)}return l.ok||await this.throwApiError(l),l}async throwApiError(e){let t;try{t=await e.json()}catch{}let n=h(t);if(n)throw n;let{message:r,code:i,type:a,details:o}=g(t,e.statusText);switch(e.status){case 401:throw new u(r,i,a,o);case 403:throw new d(r,i,a,o);case 404:throw new f(r,i,a,o);default:throw new l(r,e.status,i,a,o)}}},v=6e4,y=class{constructor(e){o(this,`storage`,void 0),o(this,`refreshFn`,void 0),o(this,`onTokenRefreshed`,void 0),o(this,`onAuthExpired`,void 0),o(this,`refreshPromise`,null),this.storage=e.storage,this.refreshFn=e.refreshFn,this.onTokenRefreshed=e.onTokenRefreshed,this.onAuthExpired=e.onAuthExpired}async getAccessToken(){let e=await this.storage.getTokens();return e?e.expiresAt-Date.now()<v?(await this.performRefresh(e.refreshToken))?.accessToken??null:e.accessToken:null}async handleUnauthorized(){let e=await this.storage.getTokens();if(!e)return await this.onAuthExpired?.(),null;let t=await this.performRefresh(e.refreshToken);return t||await this.onAuthExpired?.(),t?.accessToken??null}async setTokens(e){await this.storage.setTokens(e)}async clearTokens(){await this.storage.clearTokens()}performRefresh(e){return this.refreshPromise||(this.refreshPromise=this.refreshFn(e).then(async e=>(await this.storage.setTokens(e),await this.onTokenRefreshed?.(e),e)).catch(e=>{throw this.storage.clearTokens(),new u(`Token refresh failed. Please re-authenticate.`)}).finally(()=>{this.refreshPromise=null})),this.refreshPromise}},b=class{constructor(){o(this,`tokens`,null)}getTokens(){return this.tokens}setTokens(e){this.tokens=e}clearTokens(){this.tokens=null}};function x(e){return new Date(e).getTime()}function S(e){return async t=>{let n=await fetch(`${e}/v1/auth/token/refresh`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({refresh_token:t})});if(!n.ok)throw Error(`Token refresh failed`);let r=await n.json();return{accessToken:r.access_token,refreshToken:r.refresh_token,expiresAt:x(r.expires_at)}}}var C=class{constructor(e,t){o(this,`http`,void 0),o(this,`tokenManager`,void 0),this.http=e,this.tokenManager=t}async signup(e){let t=await this.http.post(`/v1/auth/signup`,e);return await this.storeTokens(t),t}async loginWithEmail(e){let t=await this.http.post(`/v1/auth/login/email`,e);return await this.storeTokens(t),t}async loginWithGoogle(e){let t=await this.http.post(`/v1/auth/login/google`,e);return await this.storeTokens(t),t}async loginWithBuyerApiKey(e){let t=await this.http.post(`/v1/auth/login/buyer-api-key`,e);return await this.storeTokens(t),t}async requestPasswordReset(e){return this.http.post(`/v1/auth/password/reset-request`,e)}async resetPassword(e){return this.http.post(`/v1/auth/password/reset`,e)}async storeTokens(e){await this.tokenManager.setTokens({accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:x(e.expires_at)})}},w=class{constructor(e){o(this,`http`,void 0),this.http=e}async getPublic(){return this.http.get(`/v1/config/public`)}},T=class{constructor(e){o(this,`http`,void 0),this.http=e}async getWithAccess(e){return n(await this.http.get(`/v1/content/${encodeURIComponent(e)}/with-access`))}},E=class{constructor(e){o(this,`http`,void 0),this.http=e}async create(e){return this.http.post(`/v1/purchases`,e)}async list(){return this.http.get(`/v1/purchases`)}async get(e){return this.http.get(`/v1/purchases/${encodeURIComponent(e)}`)}},D=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return(await this.http.get(`/v1/seller/content`)).map(n)}async search(e){return(await this.http.post(`/v1/seller/content/search`,e)).map(n)}async get(e){return n(await this.http.get(`/v1/seller/content/${encodeURIComponent(e)}`))}},O=class{constructor(e,t){o(this,`http`,void 0),o(this,`tokenManager`,void 0),o(this,`content`,void 0),this.http=e,this.tokenManager=t,this.content=new D(e)}async loginWithApiKey(e){let t=await this.http.post(`/v1/auth/login/api-key`,e);return await this.tokenManager.setTokens({accessToken:t.access_token,refreshToken:t.refresh_token,expiresAt:x(t.expires_at)}),t}},k=class{constructor(e){o(this,`http`,void 0),this.http=e}async balance(){return this.http.get(`/v1/wallet/balance`)}async transactions(){return this.http.get(`/v1/wallet/transactions`)}async createPaymentSession(e){return this.http.post(`/v1/wallet/payment-session`,e)}async getPaymentStatus(e){return this.http.get(`/v1/wallet/payment-status/${encodeURIComponent(e)}`)}},A=class{constructor(e){o(this,`http`,void 0),this.http=e}async state(e){return this.http.get(`/v1/checkout/state/${encodeURIComponent(e)}`)}},j=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return this.http.get(`/v1/company/invitations`)}async create(e){return this.http.post(`/v1/company/invitations`,e)}async accept(e){return this.http.post(`/v1/company/invitations/accept`,e)}};function M(e){return`/v1/company/machine-users/${encodeURIComponent(e)}`}var N=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(e){return this.http.get(`${M(e)}/buyer-keys`)}async create(e,t){return this.http.post(`${M(e)}/buyer-keys`,t)}async revoke(e,t){return this.http.delete(`${M(e)}/buyer-keys/${encodeURIComponent(t)}`)}},P=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(e){return this.http.get(`${M(e)}/mcp-keys`)}async create(e,t){return this.http.post(`${M(e)}/mcp-keys`,t)}async revoke(e,t){return this.http.delete(`${M(e)}/mcp-keys/${encodeURIComponent(t)}`)}},F=class{constructor(e){o(this,`http`,void 0),o(this,`buyerKeys`,void 0),o(this,`mcpKeys`,void 0),this.http=e,this.buyerKeys=new N(e),this.mcpKeys=new P(e)}async list(){return this.http.get(`/v1/company/machine-users`)}async create(e){return this.http.post(`/v1/company/machine-users`,e)}async deactivate(e){return this.http.delete(M(e))}},I=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return this.http.get(`/v1/company/members`)}async update(e,t){return this.http.patch(`/v1/company/members/${encodeURIComponent(e)}`,t)}async remove(e){return this.http.delete(`/v1/company/members/${encodeURIComponent(e)}`)}},L=class{constructor(e){o(this,`http`,void 0),this.http=e}async get(){return this.http.get(`/v1/company/membership`)}async leave(){return this.http.delete(`/v1/company/membership`)}},R=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(e){return this.http.get(`/v1/company/purchases`,e)}},z=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(e){return this.http.get(`/v1/company/spend`,e)}},B=class{constructor(e){o(this,`http`,void 0),this.http=e}async createPaymentSession(e){return this.http.post(`/v1/company/wallet/payment-session`,e)}async listPendingTopUps(){return this.http.get(`/v1/company/wallet/pending-top-ups`)}},V=class{constructor(e){o(this,`membership`,void 0),o(this,`invitations`,void 0),o(this,`members`,void 0),o(this,`machineUsers`,void 0),o(this,`wallet`,void 0),o(this,`purchases`,void 0),o(this,`spend`,void 0),this.membership=new L(e),this.invitations=new j(e),this.members=new I(e),this.machineUsers=new F(e),this.wallet=new B(e),this.purchases=new R(e),this.spend=new z(e)}},H=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return this.http.get(`/v1/user/api-keys`)}async create(e){return this.http.post(`/v1/user/api-keys`,e)}async revoke(e){return this.http.delete(`/v1/user/api-keys/${encodeURIComponent(e)}`)}},U=class{constructor(e){o(this,`http`,void 0),this.http=e}async get(){return this.http.get(`/v1/user/spend-cap`)}async update(e){return this.http.patch(`/v1/user/spend-cap`,e)}},W=class{constructor(e){o(this,`http`,void 0),this.http=e}async list(){return this.http.get(`/v1/mcp/keys`)}async create(e){return this.http.post(`/v1/mcp/keys`,e)}async revoke(e){return this.http.delete(`/v1/mcp/keys/${encodeURIComponent(e)}`)}},G=class{constructor(e){o(this,`apiKeys`,void 0),o(this,`spendCap`,void 0),o(this,`mcpKeys`,void 0),this.apiKeys=new H(e),this.spendCap=new U(e),this.mcpKeys=new W(e)}};function K(e){let t=e.baseUrl??`https://api.ledewire.com`,n=new y({storage:e.storage??new b,refreshFn:S(t),...e.onAuthExpired!==void 0&&{onAuthExpired:e.onAuthExpired}});return new q(new _({baseUrl:t,getAccessToken:()=>n.getAccessToken(),onUnauthorized:()=>n.handleUnauthorized()}),n,e)}var q=class{constructor(e,t,n){o(this,`_http`,void 0),o(this,`_tokenManager`,void 0),o(this,`_config`,void 0),o(this,`config`,void 0),o(this,`auth`,void 0),o(this,`checkout`,void 0),o(this,`wallet`,void 0),o(this,`purchases`,void 0),o(this,`content`,void 0),o(this,`seller`,void 0),o(this,`user`,void 0),o(this,`company`,void 0),this._http=e,this._tokenManager=t,this._config=n,this.config=new w(e),this.auth=new C(e,t),this.checkout=new A(e),this.wallet=new k(e),this.purchases=new E(e),this.content=new T(e),this.seller=new O(e,t),this.user=new G(e),this.company=new V(e)}},J=`lw:tokens`;function Y(e,t=J){return{getTokens(){let n=e.getItem(t);if(!n)return null;try{return JSON.parse(n)}catch{return null}},setTokens(n){e.setItem(t,JSON.stringify(n))},clearTokens(){e.removeItem(t)}}}function X(e){return Y(localStorage,e)}function Z(e){return Y(sessionStorage,e)}return e.AuthError=u,e.ForbiddenError=d,e.LedewireError=l,e.MemoryTokenStorage=b,e.NotFoundError=f,e.PurchaseError=p,e.SpendCapReachedError=m,e.init=K,e.localStorageAdapter=X,e.parseExpiresAt=x,e.sessionStorageAdapter=Z,e})({});
|
|
2
2
|
//# sourceMappingURL=ledewire.min.js.map
|