@ledewire/browser 0.6.0 → 0.6.1

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/dist/index.d.ts CHANGED
@@ -175,9 +175,9 @@ declare class BrowserAuthNamespace {
175
175
  * Instantiate with {@link init} rather than constructing directly.
176
176
  */
177
177
  declare class BrowserClient {
178
- readonly _http: HttpClient;
179
- readonly _tokenManager: TokenManager;
180
- readonly _config: BrowserClientConfig;
178
+ private readonly _http;
179
+ private readonly _tokenManager;
180
+ private readonly _config;
181
181
  /** Platform-level public configuration (no auth required) */
182
182
  readonly config: BrowserConfigNamespace;
183
183
  /** Buyer authentication: email/password signup/login, Google OAuth, password reset */
@@ -1419,15 +1419,16 @@ declare class HttpClient {
1419
1419
  /**
1420
1420
  * GET request with optional query parameters.
1421
1421
  * @param path - API path (e.g. `/v1/wallet/balance`)
1422
- * @param params - Query string parameters
1422
+ * @param params - Query string parameters. `undefined` values are omitted; numbers are coerced to strings.
1423
1423
  */
1424
- get<T>(path: string, params?: Record<string, string>): Promise<T>;
1424
+ get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T>;
1425
1425
  /**
1426
1426
  * POST request.
1427
1427
  * @param path - API path
1428
1428
  * @param body - Request body (JSON-serialized)
1429
+ * @param params - Optional query string parameters. `undefined` values are omitted; numbers are coerced to strings.
1429
1430
  */
1430
- post<T>(path: string, body?: unknown): Promise<T>;
1431
+ post<T>(path: string, body?: unknown, params?: Record<string, string | number | undefined>): Promise<T>;
1431
1432
  /**
1432
1433
  * PUT request.
1433
1434
  * @param path - API path
@@ -1562,6 +1563,21 @@ export declare class NotFoundError extends LedewireError {
1562
1563
  constructor(message: string, code?: number);
1563
1564
  }
1564
1565
 
1566
+ /**
1567
+ * Pagination parameters accepted by paginated list endpoints.
1568
+ *
1569
+ * Pass as the final argument to any `list()` or `search()` method that
1570
+ * accepts optional pagination. Omitting either field defers to the server
1571
+ * default (page 1, 25 items per page).
1572
+ */
1573
+ export declare interface PaginationParams {
1574
+ /** Page number (1-based). Defaults to 1. */
1575
+ page?: number;
1576
+ /** Items per page. Maximum 100. Defaults to 25. */
1577
+ per_page?: number;
1578
+ [key: string]: number | undefined;
1579
+ }
1580
+
1565
1581
  /**
1566
1582
  * Converts an `expires_at` ISO 8601 string from an API auth response
1567
1583
  * into a Unix timestamp (milliseconds) for use in `StoredTokens.expiresAt`.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- var d = Object.defineProperty;
2
- var g = (s, e, t) => e in s ? d(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
- var n = (s, e, t) => g(s, typeof e != "symbol" ? e + "" : e, t);
1
+ var g = Object.defineProperty;
2
+ var k = (s, e, t) => e in s ? g(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
+ var n = (s, e, t) => k(s, typeof e != "symbol" ? e + "" : e, t);
4
4
  function w(s) {
5
5
  return atob(s);
6
6
  }
@@ -28,33 +28,33 @@ class l extends c {
28
28
  super(e, 401, t), this.name = "AuthError";
29
29
  }
30
30
  }
31
- class k extends c {
31
+ class T extends c {
32
32
  constructor(e, t) {
33
33
  super(e, 403, t), this.name = "ForbiddenError";
34
34
  }
35
35
  }
36
- class f extends c {
36
+ class y extends c {
37
37
  constructor(e, t) {
38
38
  super(e, 404, t), this.name = "NotFoundError";
39
39
  }
40
40
  }
41
- class B extends c {
41
+ class q extends c {
42
42
  constructor(e, t, r) {
43
43
  super(e, t, r), this.name = "PurchaseError";
44
44
  }
45
45
  }
46
- const T = "https://api.ledewire.com";
47
- class y {
46
+ const d = "https://api.ledewire.com";
47
+ class A {
48
48
  constructor(e = {}) {
49
49
  n(this, "baseUrl");
50
50
  n(this, "getAccessToken");
51
51
  n(this, "onUnauthorized");
52
- this.baseUrl = (e.baseUrl ?? T).replace(/\/$/, ""), this.getAccessToken = e.getAccessToken ?? (() => null), this.onUnauthorized = e.onUnauthorized ?? (() => null);
52
+ this.baseUrl = (e.baseUrl ?? d).replace(/\/$/, ""), this.getAccessToken = e.getAccessToken ?? (() => null), this.onUnauthorized = e.onUnauthorized ?? (() => null);
53
53
  }
54
54
  /**
55
55
  * GET request with optional query parameters.
56
56
  * @param path - API path (e.g. `/v1/wallet/balance`)
57
- * @param params - Query string parameters
57
+ * @param params - Query string parameters. `undefined` values are omitted; numbers are coerced to strings.
58
58
  */
59
59
  async get(e, t) {
60
60
  return this.request("GET", this.buildUrl(e, t));
@@ -63,9 +63,10 @@ class y {
63
63
  * POST request.
64
64
  * @param path - API path
65
65
  * @param body - Request body (JSON-serialized)
66
+ * @param params - Optional query string parameters. `undefined` values are omitted; numbers are coerced to strings.
66
67
  */
67
- async post(e, t) {
68
- return this.request("POST", this.buildUrl(e), t);
68
+ async post(e, t, r) {
69
+ return this.request("POST", this.buildUrl(e, r), t);
69
70
  }
70
71
  /**
71
72
  * PUT request.
@@ -95,7 +96,13 @@ class y {
95
96
  // ---------------------------------------------------------------------------
96
97
  buildUrl(e, t) {
97
98
  const r = `${this.baseUrl}${e}`;
98
- return !t || Object.keys(t).length === 0 ? r : `${r}?${new URLSearchParams(t).toString()}`;
99
+ if (!t) return r;
100
+ const o = Object.entries(t).filter(
101
+ (i) => i[1] !== void 0
102
+ );
103
+ if (o.length === 0) return r;
104
+ const h = new URLSearchParams(o.map(([i, a]) => [i, String(a)]));
105
+ return `${r}?${h.toString()}`;
99
106
  }
100
107
  async request(e, t, r, o = !1) {
101
108
  const h = await this.getAccessToken(), i = {
@@ -127,9 +134,9 @@ class y {
127
134
  case 401:
128
135
  throw new l(r, o);
129
136
  case 403:
130
- throw new k(r, o);
137
+ throw new T(r, o);
131
138
  case 404:
132
- throw new f(r, o);
139
+ throw new y(r, o);
133
140
  default:
134
141
  throw new c(r, e.status, o);
135
142
  }
@@ -183,7 +190,7 @@ class E {
183
190
  }), this.refreshPromise);
184
191
  }
185
192
  }
186
- class A {
193
+ class v {
187
194
  constructor() {
188
195
  n(this, "tokens", null);
189
196
  }
@@ -200,6 +207,22 @@ class A {
200
207
  function p(s) {
201
208
  return new Date(s).getTime();
202
209
  }
210
+ function x(s) {
211
+ return async (e) => {
212
+ const t = await fetch(`${s}/v1/auth/token/refresh`, {
213
+ method: "POST",
214
+ headers: { "Content-Type": "application/json" },
215
+ body: JSON.stringify({ refresh_token: e })
216
+ });
217
+ if (!t.ok) throw new Error("Token refresh failed");
218
+ const r = await t.json();
219
+ return {
220
+ accessToken: r.access_token,
221
+ refreshToken: r.refresh_token,
222
+ expiresAt: p(r.expires_at)
223
+ };
224
+ };
225
+ }
203
226
  class S {
204
227
  /** @internal */
205
228
  constructor(e, t) {
@@ -284,7 +307,7 @@ class S {
284
307
  });
285
308
  }
286
309
  }
287
- class v {
310
+ class b {
288
311
  /** @internal */
289
312
  constructor(e) {
290
313
  this.http = e;
@@ -307,7 +330,7 @@ class v {
307
330
  return this.http.get("/v1/config/public");
308
331
  }
309
332
  }
310
- class x {
333
+ class U {
311
334
  constructor(e) {
312
335
  this.http = e;
313
336
  }
@@ -333,7 +356,7 @@ class x {
333
356
  return u(t);
334
357
  }
335
358
  }
336
- class b {
359
+ class P {
337
360
  constructor(e) {
338
361
  this.http = e;
339
362
  }
@@ -364,7 +387,7 @@ class b {
364
387
  return this.http.get(`/v1/purchases/${e}`);
365
388
  }
366
389
  }
367
- class U {
390
+ class R {
368
391
  /** @internal */
369
392
  constructor(e) {
370
393
  this.http = e;
@@ -424,12 +447,12 @@ class U {
424
447
  return u(t);
425
448
  }
426
449
  }
427
- class P {
450
+ class F {
428
451
  /** @internal */
429
452
  constructor(e, t) {
430
453
  /** Seller content: list, search, and get by API key. */
431
454
  n(this, "content");
432
- this.http = e, this.tokenManager = t, this.content = new U(e);
455
+ this.http = e, this.tokenManager = t, this.content = new R(e);
433
456
  }
434
457
  /**
435
458
  * Log in using an API key to obtain a seller token.
@@ -518,32 +541,19 @@ class _ {
518
541
  return this.http.get(`/v1/checkout/state/${e}`);
519
542
  }
520
543
  }
521
- function q(s) {
522
- const e = s.baseUrl ?? "https://api.ledewire.com", t = s.storage ?? new A(), r = new E({
544
+ function M(s) {
545
+ const e = s.baseUrl ?? d, t = s.storage ?? new v(), r = new E({
523
546
  storage: t,
524
- refreshFn: async (h) => {
525
- const i = await fetch(`${e}/v1/auth/token/refresh`, {
526
- method: "POST",
527
- headers: { "Content-Type": "application/json" },
528
- body: JSON.stringify({ refresh_token: h })
529
- });
530
- if (!i.ok) throw new Error("Token refresh failed");
531
- const a = await i.json();
532
- return {
533
- accessToken: a.access_token,
534
- refreshToken: a.refresh_token,
535
- expiresAt: p(a.expires_at)
536
- };
537
- },
547
+ refreshFn: x(e),
538
548
  ...s.onAuthExpired !== void 0 && { onAuthExpired: s.onAuthExpired }
539
- }), o = new y({
549
+ }), o = new A({
540
550
  baseUrl: e,
541
551
  getAccessToken: () => r.getAccessToken(),
542
552
  onUnauthorized: () => r.handleUnauthorized()
543
553
  });
544
- return new R(o, r, s);
554
+ return new C(o, r, s);
545
555
  }
546
- class R {
556
+ class C {
547
557
  /** @internal */
548
558
  constructor(e, t, r) {
549
559
  /** Platform-level public configuration (no auth required) */
@@ -560,59 +570,45 @@ class R {
560
570
  n(this, "content");
561
571
  /** Seller operations: API key login, content list/search/get */
562
572
  n(this, "seller");
563
- this._http = e, this._tokenManager = t, this._config = r, this.config = new v(e), this.auth = new S(e, t), this.checkout = new _(e), this.wallet = new N(e), this.purchases = new b(e), this.content = new x(e), this.seller = new P(e, t);
573
+ this._http = e, this._tokenManager = t, this._config = r, this.config = new b(e), this.auth = new S(e, t), this.checkout = new _(e), this.wallet = new N(e), this.purchases = new P(e), this.content = new U(e), this.seller = new F(e, t);
564
574
  }
565
575
  }
566
- const F = "lw:tokens";
567
- function L(s = F) {
576
+ const $ = "lw:tokens";
577
+ function f(s, e = $) {
568
578
  return {
569
579
  getTokens() {
570
- const e = localStorage.getItem(s);
571
- if (!e) return null;
580
+ const t = s.getItem(e);
581
+ if (!t) return null;
572
582
  try {
573
- return JSON.parse(e);
583
+ return JSON.parse(t);
574
584
  } catch {
575
585
  return null;
576
586
  }
577
587
  },
578
- setTokens(e) {
579
- localStorage.setItem(s, JSON.stringify(e));
588
+ setTokens(t) {
589
+ s.setItem(e, JSON.stringify(t));
580
590
  },
581
591
  clearTokens() {
582
- localStorage.removeItem(s);
592
+ s.removeItem(e);
583
593
  }
584
594
  };
585
595
  }
586
- const O = "lw:tokens";
587
- function M(s = O) {
588
- return {
589
- getTokens() {
590
- const e = sessionStorage.getItem(s);
591
- if (!e) return null;
592
- try {
593
- return JSON.parse(e);
594
- } catch {
595
- return null;
596
- }
597
- },
598
- setTokens(e) {
599
- sessionStorage.setItem(s, JSON.stringify(e));
600
- },
601
- clearTokens() {
602
- sessionStorage.removeItem(s);
603
- }
604
- };
596
+ function j(s) {
597
+ return f(localStorage, s);
598
+ }
599
+ function z(s) {
600
+ return f(sessionStorage, s);
605
601
  }
606
602
  export {
607
603
  l as AuthError,
608
- k as ForbiddenError,
604
+ T as ForbiddenError,
609
605
  c as LedewireError,
610
- A as MemoryTokenStorage,
611
- f as NotFoundError,
612
- B as PurchaseError,
613
- q as init,
614
- L as localStorageAdapter,
606
+ v as MemoryTokenStorage,
607
+ y as NotFoundError,
608
+ q as PurchaseError,
609
+ M as init,
610
+ j as localStorageAdapter,
615
611
  p as parseExpiresAt,
616
- M as sessionStorageAdapter
612
+ z as sessionStorageAdapter
617
613
  };
618
614
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../core/src/base64.ts","../../core/src/errors.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/client.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(body: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...body }\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\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 * @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 /** 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 constructor(message: string, statusCode: number, code?: number) {\n super(message)\n this.name = 'LedewireError'\n this.statusCode = statusCode\n this.code = code\n // Restore prototype chain (required for extending built-in Error in TS)\n Object.setPrototypeOf(this, new.target.prototype)\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 constructor(message: string, code?: number) {\n super(message, 401, code)\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 constructor(message: string, code?: number) {\n super(message, 403, code)\n this.name = 'ForbiddenError'\n }\n}\n\n/**\n * Thrown when the requested resource does not exist.\n */\nexport class NotFoundError extends LedewireError {\n constructor(message: string, code?: number) {\n super(message, 404, code)\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 constructor(message: string, statusCode: number, code?: number) {\n super(message, statusCode, code)\n this.name = 'PurchaseError'\n }\n}\n","import type { components } from './api.gen.js'\nimport { AuthError, ForbiddenError, LedewireError, NotFoundError } from './errors.js'\n\n/** @internal */\ntype ApiErrorBody = components['schemas']['ErrorResponse']\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\nconst DEFAULT_BASE_URL = 'https://api.ledewire.com'\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 *\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\n */\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>('GET', this.buildUrl(path, params))\n }\n\n /**\n * POST request.\n * @param path - API path\n * @param body - Request body (JSON-serialized)\n */\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('POST', this.buildUrl(path), 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 // Private helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, params?: Record<string, string>): string {\n const url = `${this.baseUrl}${path}`\n if (!params || Object.keys(params).length === 0) return url\n return `${url}?${new URLSearchParams(params).toString()}`\n }\n\n private async request<T>(\n method: string,\n url: string,\n body?: unknown,\n isRetry = false,\n ): Promise<T> {\n const token = await this.getAccessToken()\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n }\n if (token) headers['Authorization'] = `Bearer ${token}`\n\n const response = await fetch(url, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n\n if (response.status === 401 && !isRetry) {\n const newToken = await this.onUnauthorized()\n if (newToken) {\n return this.request<T>(method, url, body, true)\n }\n throw new AuthError('Session expired. Please re-authenticate.')\n }\n\n if (!response.ok) {\n await this.throwApiError(response)\n }\n\n if (response.status === 204) {\n return undefined as T\n }\n\n return response.json() as Promise<T>\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let body: ApiErrorBody | undefined\n try {\n body = (await response.json()) as ApiErrorBody\n } catch {\n // Non-JSON body - fall through to use statusText\n }\n\n const message = body?.error.message ?? response.statusText\n const code = body?.error.code\n\n switch (response.status) {\n case 401:\n throw new AuthError(message, code)\n case 403:\n throw new ForbiddenError(message, code)\n case 404:\n throw new NotFoundError(message, code)\n default:\n throw new LedewireError(message, response.status, code)\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 * 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 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 * 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.next_required_action === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\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 === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\n * }\n * ```\n */\n async getWithAccess(id: string): Promise<ContentWithAccessResponse> {\n const res = await this.http.get<ContentWithAccessResponse>(`/v1/content/${id}/with-access`)\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 * 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.\n *\n * @param body - The content ID and expected price in cents.\n * @returns The completed purchase record.\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/${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/${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 * @returns The current wallet balance in cents.\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 * @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>(`/v1/wallet/payment-status/${sessionId}`)\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' | 'view_content'\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>(`/v1/checkout/state/${contentId}`)\n }\n}\n","import { HttpClient, MemoryTokenStorage, TokenManager, parseExpiresAt } 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'\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 ?? 'https://api.ledewire.com'\n const storage = config.storage ?? new MemoryTokenStorage()\n\n const tokenManager = new TokenManager({\n storage,\n refreshFn: async (refreshToken) => {\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 ...(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 /** @internal */\n constructor(\n public readonly _http: HttpClient,\n public readonly _tokenManager: TokenManager,\n public 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 }\n}\n","import type { TokenStorage, StoredTokens } from '@ledewire/core'\n\nconst DEFAULT_STORAGE_KEY = 'lw:tokens'\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 = DEFAULT_STORAGE_KEY): TokenStorage {\n return {\n getTokens(): StoredTokens | null {\n const raw = localStorage.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 localStorage.setItem(key, JSON.stringify(tokens))\n },\n clearTokens(): void {\n localStorage.removeItem(key)\n },\n }\n}\n","import type { TokenStorage, StoredTokens } from '@ledewire/core'\n\nconst DEFAULT_STORAGE_KEY = 'lw:tokens'\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 = DEFAULT_STORAGE_KEY): TokenStorage {\n return {\n getTokens(): StoredTokens | null {\n const raw = sessionStorage.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 sessionStorage.setItem(key, JSON.stringify(tokens))\n },\n clearTokens(): void {\n sessionStorage.removeItem(key)\n },\n }\n}\n"],"names":["decodeBase64","value","decodeContentFields","item","LedewireError","message","statusCode","code","__publicField","AuthError","ForbiddenError","NotFoundError","PurchaseError","DEFAULT_BASE_URL","HttpClient","config","path","params","body","url","method","isRetry","token","headers","response","REFRESH_THRESHOLD_MS","TokenManager","options","stored","refreshed","tokens","refreshToken","_err","MemoryTokenStorage","parseExpiresAt","expiresAt","BrowserAuthNamespace","http","tokenManager","res","BrowserConfigNamespace","BrowserContentNamespace","id","BrowserPurchasesNamespace","BrowserSellerContentNamespace","BrowserSellerNamespace","BrowserWalletNamespace","sessionId","CheckoutNamespace","contentId","init","baseUrl","storage","data","BrowserClient","_http","_tokenManager","_config","DEFAULT_STORAGE_KEY","localStorageAdapter","key","raw","sessionStorageAdapter"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../core/src/base64.ts","../../core/src/errors.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/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","/**\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 * @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 /** 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 constructor(message: string, statusCode: number, code?: number) {\n super(message)\n this.name = 'LedewireError'\n this.statusCode = statusCode\n this.code = code\n // Restore prototype chain (required for extending built-in Error in TS)\n Object.setPrototypeOf(this, new.target.prototype)\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 constructor(message: string, code?: number) {\n super(message, 401, code)\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 constructor(message: string, code?: number) {\n super(message, 403, code)\n this.name = 'ForbiddenError'\n }\n}\n\n/**\n * Thrown when the requested resource does not exist.\n */\nexport class NotFoundError extends LedewireError {\n constructor(message: string, code?: number) {\n super(message, 404, code)\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 constructor(message: string, statusCode: number, code?: number) {\n super(message, statusCode, code)\n this.name = 'PurchaseError'\n }\n}\n","import type { components } from './api.gen.js'\nimport { AuthError, ForbiddenError, LedewireError, NotFoundError } from './errors.js'\n\n/** @internal */\ntype ApiErrorBody = components['schemas']['ErrorResponse']\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/** The default LedeWire API base URL used by all SDK packages. */\nexport const DEFAULT_BASE_URL = 'https://api.ledewire.com'\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 *\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 */\n async get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T> {\n return this.request<T>('GET', this.buildUrl(path, params))\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 // 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 isRetry = false,\n ): Promise<T> {\n const token = await this.getAccessToken()\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n }\n if (token) headers['Authorization'] = `Bearer ${token}`\n\n const response = await fetch(url, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n\n if (response.status === 401 && !isRetry) {\n const newToken = await this.onUnauthorized()\n if (newToken) {\n return this.request<T>(method, url, body, true)\n }\n throw new AuthError('Session expired. Please re-authenticate.')\n }\n\n if (!response.ok) {\n await this.throwApiError(response)\n }\n\n if (response.status === 204) {\n return undefined as T\n }\n\n return response.json() as Promise<T>\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let body: ApiErrorBody | undefined\n try {\n body = (await response.json()) as ApiErrorBody\n } catch {\n // Non-JSON body - fall through to use statusText\n }\n\n const message = body?.error.message ?? response.statusText\n const code = body?.error.code\n\n switch (response.status) {\n case 401:\n throw new AuthError(message, code)\n case 403:\n throw new ForbiddenError(message, code)\n case 404:\n throw new NotFoundError(message, code)\n default:\n throw new LedewireError(message, response.status, code)\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 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 * 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.next_required_action === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\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 === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\n * }\n * ```\n */\n async getWithAccess(id: string): Promise<ContentWithAccessResponse> {\n const res = await this.http.get<ContentWithAccessResponse>(`/v1/content/${id}/with-access`)\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 * 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.\n *\n * @param body - The content ID and expected price in cents.\n * @returns The completed purchase record.\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/${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/${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 * @returns The current wallet balance in cents.\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 * @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>(`/v1/wallet/payment-status/${sessionId}`)\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' | 'view_content'\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>(`/v1/checkout/state/${contentId}`)\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'\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 /** @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 }\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"],"names":["decodeBase64","value","decodeContentFields","item","LedewireError","message","statusCode","code","__publicField","AuthError","ForbiddenError","NotFoundError","PurchaseError","DEFAULT_BASE_URL","HttpClient","config","path","params","body","url","filtered","entry","qs","k","v","method","isRetry","token","headers","response","REFRESH_THRESHOLD_MS","TokenManager","options","stored","refreshed","tokens","refreshToken","_err","MemoryTokenStorage","parseExpiresAt","expiresAt","createRefreshFn","baseUrl","res","data","BrowserAuthNamespace","http","tokenManager","BrowserConfigNamespace","BrowserContentNamespace","id","BrowserPurchasesNamespace","BrowserSellerContentNamespace","BrowserSellerNamespace","BrowserWalletNamespace","sessionId","CheckoutNamespace","contentId","init","storage","BrowserClient","_http","_tokenManager","_config","DEFAULT_STORAGE_KEY","webStorageAdapter","backend","key","raw","localStorageAdapter","sessionStorageAdapter"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var Ledewire=(function(o){"use strict";var L=Object.defineProperty;var M=(o,a,c)=>a in o?L(o,a,{enumerable:!0,configurable:!0,writable:!0,value:c}):o[a]=c;var n=(o,a,c)=>M(o,typeof a!="symbol"?a+"":a,c);function a(s){return atob(s)}function c(s){return{...s,...typeof s.content_body=="string"&&{content_body:a(s.content_body)},...typeof s.teaser=="string"&&{teaser:a(s.teaser)}}}class u extends Error{constructor(t,r,i){super(t);n(this,"statusCode");n(this,"code");this.name="LedewireError",this.statusCode=r,this.code=i,Object.setPrototypeOf(this,new.target.prototype)}}class p extends u{constructor(e,t){super(e,401,t),this.name="AuthError"}}class g extends u{constructor(e,t){super(e,403,t),this.name="ForbiddenError"}}class k extends u{constructor(e,t){super(e,404,t),this.name="NotFoundError"}}class T extends u{constructor(e,t,r){super(e,t,r),this.name="PurchaseError"}}const y="https://api.ledewire.com";class E{constructor(e={}){n(this,"baseUrl");n(this,"getAccessToken");n(this,"onUnauthorized");this.baseUrl=(e.baseUrl??y).replace(/\/$/,""),this.getAccessToken=e.getAccessToken??(()=>null),this.onUnauthorized=e.onUnauthorized??(()=>null)}async get(e,t){return this.request("GET",this.buildUrl(e,t))}async post(e,t){return this.request("POST",this.buildUrl(e),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))}buildUrl(e,t){const r=`${this.baseUrl}${e}`;return!t||Object.keys(t).length===0?r:`${r}?${new URLSearchParams(t).toString()}`}async request(e,t,r,i=!1){const d=await this.getAccessToken(),l={"Content-Type":"application/json",Accept:"application/json"};d&&(l.Authorization=`Bearer ${d}`);const h=await fetch(t,{method:e,headers:l,...r!==void 0&&{body:JSON.stringify(r)}});if(h.status===401&&!i){if(await this.onUnauthorized())return this.request(e,t,r,!0);throw new p("Session expired. Please re-authenticate.")}if(h.ok||await this.throwApiError(h),h.status!==204)return h.json()}async throwApiError(e){let t;try{t=await e.json()}catch{}const r=t?.error.message??e.statusText,i=t?.error.code;switch(e.status){case 401:throw new p(r,i);case 403:throw new g(r,i);case 404:throw new k(r,i);default:throw new u(r,e.status,i)}}}const A=6e4;class m{constructor(e){n(this,"storage");n(this,"refreshFn");n(this,"onTokenRefreshed");n(this,"onAuthExpired");n(this,"refreshPromise",null);this.storage=e.storage,this.refreshFn=e.refreshFn,this.onTokenRefreshed=e.onTokenRefreshed,this.onAuthExpired=e.onAuthExpired}async getAccessToken(){const e=await this.storage.getTokens();return e?e.expiresAt-Date.now()<A?(await this.performRefresh(e.refreshToken))?.accessToken??null:e.accessToken:null}async handleUnauthorized(){const e=await this.storage.getTokens();if(!e)return await this.onAuthExpired?.(),null;const 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.refreshPromise=this.refreshFn(e).then(async t=>(await this.storage.setTokens(t),await this.onTokenRefreshed?.(t),t)).catch(t=>{throw this.storage.clearTokens(),new p("Token refresh failed. Please re-authenticate.")}).finally(()=>{this.refreshPromise=null}),this.refreshPromise)}}class f{constructor(){n(this,"tokens",null)}getTokens(){return this.tokens}setTokens(e){this.tokens=e}clearTokens(){this.tokens=null}}function w(s){return new Date(s).getTime()}class S{constructor(e,t){this.http=e,this.tokenManager=t}async signup(e){const t=await this.http.post("/v1/auth/signup",e);return await this.storeTokens(t),t}async loginWithEmail(e){const t=await this.http.post("/v1/auth/login/email",e);return await this.storeTokens(t),t}async loginWithGoogle(e){const t=await this.http.post("/v1/auth/login/google",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:w(e.expires_at)})}}class b{constructor(e){this.http=e}async getPublic(){return this.http.get("/v1/config/public")}}class v{constructor(e){this.http=e}async getWithAccess(e){const t=await this.http.get(`/v1/content/${e}/with-access`);return c(t)}}class U{constructor(e){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/${e}`)}}class P{constructor(e){this.http=e}async list(){return(await this.http.get("/v1/seller/content")).map(c)}async search(e){return(await this.http.post("/v1/seller/content/search",e)).map(c)}async get(e){const t=await this.http.get(`/v1/seller/content/${e}`);return c(t)}}class N{constructor(e,t){n(this,"content");this.http=e,this.tokenManager=t,this.content=new P(e)}async loginWithApiKey(e){const 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:w(t.expires_at)}),t}}class F{constructor(e){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/${e}`)}}class _{constructor(e){this.http=e}async state(e){return this.http.get(`/v1/checkout/state/${e}`)}}function x(s){const e=s.baseUrl??"https://api.ledewire.com",t=s.storage??new f,r=new m({storage:t,refreshFn:async d=>{const l=await fetch(`${e}/v1/auth/token/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:d})});if(!l.ok)throw new Error("Token refresh failed");const h=await l.json();return{accessToken:h.access_token,refreshToken:h.refresh_token,expiresAt:w(h.expires_at)}},...s.onAuthExpired!==void 0&&{onAuthExpired:s.onAuthExpired}}),i=new E({baseUrl:e,getAccessToken:()=>r.getAccessToken(),onUnauthorized:()=>r.handleUnauthorized()});return new O(i,r,s)}class O{constructor(e,t,r){n(this,"config");n(this,"auth");n(this,"checkout");n(this,"wallet");n(this,"purchases");n(this,"content");n(this,"seller");this._http=e,this._tokenManager=t,this._config=r,this.config=new b(e),this.auth=new S(e,t),this.checkout=new _(e),this.wallet=new F(e),this.purchases=new U(e),this.content=new v(e),this.seller=new N(e,t)}}const R="lw:tokens";function $(s=R){return{getTokens(){const e=localStorage.getItem(s);if(!e)return null;try{return JSON.parse(e)}catch{return null}},setTokens(e){localStorage.setItem(s,JSON.stringify(e))},clearTokens(){localStorage.removeItem(s)}}}const C="lw:tokens";function B(s=C){return{getTokens(){const e=sessionStorage.getItem(s);if(!e)return null;try{return JSON.parse(e)}catch{return null}},setTokens(e){sessionStorage.setItem(s,JSON.stringify(e))},clearTokens(){sessionStorage.removeItem(s)}}}return o.AuthError=p,o.ForbiddenError=g,o.LedewireError=u,o.MemoryTokenStorage=f,o.NotFoundError=k,o.PurchaseError=T,o.init=x,o.localStorageAdapter=$,o.parseExpiresAt=w,o.sessionStorageAdapter=B,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),o})({});
1
+ var Ledewire=(function(o){"use strict";var q=Object.defineProperty;var L=(o,i,c)=>i in o?q(o,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):o[i]=c;var n=(o,i,c)=>L(o,typeof i!="symbol"?i+"":i,c);function i(s){return atob(s)}function c(s){return{...s,...typeof s.content_body=="string"&&{content_body:i(s.content_body)},...typeof s.teaser=="string"&&{teaser:i(s.teaser)}}}class u extends Error{constructor(t,r,a){super(t);n(this,"statusCode");n(this,"code");this.name="LedewireError",this.statusCode=r,this.code=a,Object.setPrototypeOf(this,new.target.prototype)}}class p extends u{constructor(e,t){super(e,401,t),this.name="AuthError"}}class g extends u{constructor(e,t){super(e,403,t),this.name="ForbiddenError"}}class f extends u{constructor(e,t){super(e,404,t),this.name="NotFoundError"}}class E extends u{constructor(e,t,r){super(e,t,r),this.name="PurchaseError"}}const k="https://api.ledewire.com";class A{constructor(e={}){n(this,"baseUrl");n(this,"getAccessToken");n(this,"onUnauthorized");this.baseUrl=(e.baseUrl??k).replace(/\/$/,""),this.getAccessToken=e.getAccessToken??(()=>null),this.onUnauthorized=e.onUnauthorized??(()=>null)}async get(e,t){return this.request("GET",this.buildUrl(e,t))}async post(e,t,r){return this.request("POST",this.buildUrl(e,r),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))}buildUrl(e,t){const r=`${this.baseUrl}${e}`;if(!t)return r;const a=Object.entries(t).filter(l=>l[1]!==void 0);if(a.length===0)return r;const d=new URLSearchParams(a.map(([l,h])=>[l,String(h)]));return`${r}?${d.toString()}`}async request(e,t,r,a=!1){const d=await this.getAccessToken(),l={"Content-Type":"application/json",Accept:"application/json"};d&&(l.Authorization=`Bearer ${d}`);const h=await fetch(t,{method:e,headers:l,...r!==void 0&&{body:JSON.stringify(r)}});if(h.status===401&&!a){if(await this.onUnauthorized())return this.request(e,t,r,!0);throw new p("Session expired. Please re-authenticate.")}if(h.ok||await this.throwApiError(h),h.status!==204)return h.json()}async throwApiError(e){let t;try{t=await e.json()}catch{}const r=t?.error.message??e.statusText,a=t?.error.code;switch(e.status){case 401:throw new p(r,a);case 403:throw new g(r,a);case 404:throw new f(r,a);default:throw new u(r,e.status,a)}}}const m=6e4;class S{constructor(e){n(this,"storage");n(this,"refreshFn");n(this,"onTokenRefreshed");n(this,"onAuthExpired");n(this,"refreshPromise",null);this.storage=e.storage,this.refreshFn=e.refreshFn,this.onTokenRefreshed=e.onTokenRefreshed,this.onAuthExpired=e.onAuthExpired}async getAccessToken(){const e=await this.storage.getTokens();return e?e.expiresAt-Date.now()<m?(await this.performRefresh(e.refreshToken))?.accessToken??null:e.accessToken:null}async handleUnauthorized(){const e=await this.storage.getTokens();if(!e)return await this.onAuthExpired?.(),null;const 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.refreshPromise=this.refreshFn(e).then(async t=>(await this.storage.setTokens(t),await this.onTokenRefreshed?.(t),t)).catch(t=>{throw this.storage.clearTokens(),new p("Token refresh failed. Please re-authenticate.")}).finally(()=>{this.refreshPromise=null}),this.refreshPromise)}}class T{constructor(){n(this,"tokens",null)}getTokens(){return this.tokens}setTokens(e){this.tokens=e}clearTokens(){this.tokens=null}}function w(s){return new Date(s).getTime()}function v(s){return async e=>{const t=await fetch(`${s}/v1/auth/token/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:e})});if(!t.ok)throw new Error("Token refresh failed");const r=await t.json();return{accessToken:r.access_token,refreshToken:r.refresh_token,expiresAt:w(r.expires_at)}}}class b{constructor(e,t){this.http=e,this.tokenManager=t}async signup(e){const t=await this.http.post("/v1/auth/signup",e);return await this.storeTokens(t),t}async loginWithEmail(e){const t=await this.http.post("/v1/auth/login/email",e);return await this.storeTokens(t),t}async loginWithGoogle(e){const t=await this.http.post("/v1/auth/login/google",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:w(e.expires_at)})}}class P{constructor(e){this.http=e}async getPublic(){return this.http.get("/v1/config/public")}}class U{constructor(e){this.http=e}async getWithAccess(e){const t=await this.http.get(`/v1/content/${e}/with-access`);return c(t)}}class F{constructor(e){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/${e}`)}}class x{constructor(e){this.http=e}async list(){return(await this.http.get("/v1/seller/content")).map(c)}async search(e){return(await this.http.post("/v1/seller/content/search",e)).map(c)}async get(e){const t=await this.http.get(`/v1/seller/content/${e}`);return c(t)}}class N{constructor(e,t){n(this,"content");this.http=e,this.tokenManager=t,this.content=new x(e)}async loginWithApiKey(e){const 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:w(t.expires_at)}),t}}class R{constructor(e){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/${e}`)}}class _{constructor(e){this.http=e}async state(e){return this.http.get(`/v1/checkout/state/${e}`)}}function C(s){const e=s.baseUrl??k,t=s.storage??new T,r=new S({storage:t,refreshFn:v(e),...s.onAuthExpired!==void 0&&{onAuthExpired:s.onAuthExpired}}),a=new A({baseUrl:e,getAccessToken:()=>r.getAccessToken(),onUnauthorized:()=>r.handleUnauthorized()});return new O(a,r,s)}class O{constructor(e,t,r){n(this,"config");n(this,"auth");n(this,"checkout");n(this,"wallet");n(this,"purchases");n(this,"content");n(this,"seller");this._http=e,this._tokenManager=t,this._config=r,this.config=new P(e),this.auth=new b(e,t),this.checkout=new _(e),this.wallet=new R(e),this.purchases=new F(e),this.content=new U(e),this.seller=new N(e,t)}}const $="lw:tokens";function y(s,e=$){return{getTokens(){const t=s.getItem(e);if(!t)return null;try{return JSON.parse(t)}catch{return null}},setTokens(t){s.setItem(e,JSON.stringify(t))},clearTokens(){s.removeItem(e)}}}function B(s){return y(localStorage,s)}function M(s){return y(sessionStorage,s)}return o.AuthError=p,o.ForbiddenError=g,o.LedewireError=u,o.MemoryTokenStorage=T,o.NotFoundError=f,o.PurchaseError=E,o.init=C,o.localStorageAdapter=B,o.parseExpiresAt=w,o.sessionStorageAdapter=M,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),o})({});
2
2
  //# sourceMappingURL=ledewire.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ledewire.min.js","sources":["../../core/src/base64.ts","../../core/src/errors.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/client.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(body: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...body }\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\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 * @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 /** 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 constructor(message: string, statusCode: number, code?: number) {\n super(message)\n this.name = 'LedewireError'\n this.statusCode = statusCode\n this.code = code\n // Restore prototype chain (required for extending built-in Error in TS)\n Object.setPrototypeOf(this, new.target.prototype)\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 constructor(message: string, code?: number) {\n super(message, 401, code)\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 constructor(message: string, code?: number) {\n super(message, 403, code)\n this.name = 'ForbiddenError'\n }\n}\n\n/**\n * Thrown when the requested resource does not exist.\n */\nexport class NotFoundError extends LedewireError {\n constructor(message: string, code?: number) {\n super(message, 404, code)\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 constructor(message: string, statusCode: number, code?: number) {\n super(message, statusCode, code)\n this.name = 'PurchaseError'\n }\n}\n","import type { components } from './api.gen.js'\nimport { AuthError, ForbiddenError, LedewireError, NotFoundError } from './errors.js'\n\n/** @internal */\ntype ApiErrorBody = components['schemas']['ErrorResponse']\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\nconst DEFAULT_BASE_URL = 'https://api.ledewire.com'\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 *\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\n */\n async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>('GET', this.buildUrl(path, params))\n }\n\n /**\n * POST request.\n * @param path - API path\n * @param body - Request body (JSON-serialized)\n */\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('POST', this.buildUrl(path), 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 // Private helpers\n // ---------------------------------------------------------------------------\n\n private buildUrl(path: string, params?: Record<string, string>): string {\n const url = `${this.baseUrl}${path}`\n if (!params || Object.keys(params).length === 0) return url\n return `${url}?${new URLSearchParams(params).toString()}`\n }\n\n private async request<T>(\n method: string,\n url: string,\n body?: unknown,\n isRetry = false,\n ): Promise<T> {\n const token = await this.getAccessToken()\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n }\n if (token) headers['Authorization'] = `Bearer ${token}`\n\n const response = await fetch(url, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n\n if (response.status === 401 && !isRetry) {\n const newToken = await this.onUnauthorized()\n if (newToken) {\n return this.request<T>(method, url, body, true)\n }\n throw new AuthError('Session expired. Please re-authenticate.')\n }\n\n if (!response.ok) {\n await this.throwApiError(response)\n }\n\n if (response.status === 204) {\n return undefined as T\n }\n\n return response.json() as Promise<T>\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let body: ApiErrorBody | undefined\n try {\n body = (await response.json()) as ApiErrorBody\n } catch {\n // Non-JSON body - fall through to use statusText\n }\n\n const message = body?.error.message ?? response.statusText\n const code = body?.error.code\n\n switch (response.status) {\n case 401:\n throw new AuthError(message, code)\n case 403:\n throw new ForbiddenError(message, code)\n case 404:\n throw new NotFoundError(message, code)\n default:\n throw new LedewireError(message, response.status, code)\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 * 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 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 * 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.next_required_action === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\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 === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\n * }\n * ```\n */\n async getWithAccess(id: string): Promise<ContentWithAccessResponse> {\n const res = await this.http.get<ContentWithAccessResponse>(`/v1/content/${id}/with-access`)\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 * 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.\n *\n * @param body - The content ID and expected price in cents.\n * @returns The completed purchase record.\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/${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/${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 * @returns The current wallet balance in cents.\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 * @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>(`/v1/wallet/payment-status/${sessionId}`)\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' | 'view_content'\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>(`/v1/checkout/state/${contentId}`)\n }\n}\n","import { HttpClient, MemoryTokenStorage, TokenManager, parseExpiresAt } 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'\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 ?? 'https://api.ledewire.com'\n const storage = config.storage ?? new MemoryTokenStorage()\n\n const tokenManager = new TokenManager({\n storage,\n refreshFn: async (refreshToken) => {\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 ...(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 /** @internal */\n constructor(\n public readonly _http: HttpClient,\n public readonly _tokenManager: TokenManager,\n public 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 }\n}\n","import type { TokenStorage, StoredTokens } from '@ledewire/core'\n\nconst DEFAULT_STORAGE_KEY = 'lw:tokens'\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 = DEFAULT_STORAGE_KEY): TokenStorage {\n return {\n getTokens(): StoredTokens | null {\n const raw = localStorage.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 localStorage.setItem(key, JSON.stringify(tokens))\n },\n clearTokens(): void {\n localStorage.removeItem(key)\n },\n }\n}\n","import type { TokenStorage, StoredTokens } from '@ledewire/core'\n\nconst DEFAULT_STORAGE_KEY = 'lw:tokens'\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 = DEFAULT_STORAGE_KEY): TokenStorage {\n return {\n getTokens(): StoredTokens | null {\n const raw = sessionStorage.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 sessionStorage.setItem(key, JSON.stringify(tokens))\n },\n clearTokens(): void {\n sessionStorage.removeItem(key)\n },\n }\n}\n"],"names":["decodeBase64","value","decodeContentFields","item","LedewireError","message","statusCode","code","__publicField","AuthError","ForbiddenError","NotFoundError","PurchaseError","DEFAULT_BASE_URL","HttpClient","config","path","params","body","url","method","isRetry","token","headers","response","REFRESH_THRESHOLD_MS","TokenManager","options","stored","refreshed","tokens","refreshToken","_err","MemoryTokenStorage","parseExpiresAt","expiresAt","BrowserAuthNamespace","http","tokenManager","res","BrowserConfigNamespace","BrowserContentNamespace","id","BrowserPurchasesNamespace","BrowserSellerContentNamespace","BrowserSellerNamespace","BrowserWalletNamespace","sessionId","CheckoutNamespace","contentId","init","baseUrl","storage","data","BrowserClient","_http","_tokenManager","_config","DEFAULT_STORAGE_KEY","localStorageAdapter","key","raw","sessionStorageAdapter"],"mappings":"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"}
1
+ {"version":3,"file":"ledewire.min.js","sources":["../../core/src/base64.ts","../../core/src/errors.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/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","/**\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 * @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 /** 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 constructor(message: string, statusCode: number, code?: number) {\n super(message)\n this.name = 'LedewireError'\n this.statusCode = statusCode\n this.code = code\n // Restore prototype chain (required for extending built-in Error in TS)\n Object.setPrototypeOf(this, new.target.prototype)\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 constructor(message: string, code?: number) {\n super(message, 401, code)\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 constructor(message: string, code?: number) {\n super(message, 403, code)\n this.name = 'ForbiddenError'\n }\n}\n\n/**\n * Thrown when the requested resource does not exist.\n */\nexport class NotFoundError extends LedewireError {\n constructor(message: string, code?: number) {\n super(message, 404, code)\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 constructor(message: string, statusCode: number, code?: number) {\n super(message, statusCode, code)\n this.name = 'PurchaseError'\n }\n}\n","import type { components } from './api.gen.js'\nimport { AuthError, ForbiddenError, LedewireError, NotFoundError } from './errors.js'\n\n/** @internal */\ntype ApiErrorBody = components['schemas']['ErrorResponse']\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/** The default LedeWire API base URL used by all SDK packages. */\nexport const DEFAULT_BASE_URL = 'https://api.ledewire.com'\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 *\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 */\n async get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T> {\n return this.request<T>('GET', this.buildUrl(path, params))\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 // 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 isRetry = false,\n ): Promise<T> {\n const token = await this.getAccessToken()\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n }\n if (token) headers['Authorization'] = `Bearer ${token}`\n\n const response = await fetch(url, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n\n if (response.status === 401 && !isRetry) {\n const newToken = await this.onUnauthorized()\n if (newToken) {\n return this.request<T>(method, url, body, true)\n }\n throw new AuthError('Session expired. Please re-authenticate.')\n }\n\n if (!response.ok) {\n await this.throwApiError(response)\n }\n\n if (response.status === 204) {\n return undefined as T\n }\n\n return response.json() as Promise<T>\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let body: ApiErrorBody | undefined\n try {\n body = (await response.json()) as ApiErrorBody\n } catch {\n // Non-JSON body - fall through to use statusText\n }\n\n const message = body?.error.message ?? response.statusText\n const code = body?.error.code\n\n switch (response.status) {\n case 401:\n throw new AuthError(message, code)\n case 403:\n throw new ForbiddenError(message, code)\n case 404:\n throw new NotFoundError(message, code)\n default:\n throw new LedewireError(message, response.status, code)\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 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 * 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.next_required_action === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\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 === 'view_content') {\n * renderMarkdown(result.content_body ?? '')\n * }\n * ```\n */\n async getWithAccess(id: string): Promise<ContentWithAccessResponse> {\n const res = await this.http.get<ContentWithAccessResponse>(`/v1/content/${id}/with-access`)\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 * 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.\n *\n * @param body - The content ID and expected price in cents.\n * @returns The completed purchase record.\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/${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/${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 * @returns The current wallet balance in cents.\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 * @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>(`/v1/wallet/payment-status/${sessionId}`)\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' | 'view_content'\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>(`/v1/checkout/state/${contentId}`)\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'\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 /** @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 }\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"],"names":["decodeBase64","value","decodeContentFields","item","LedewireError","message","statusCode","code","__publicField","AuthError","ForbiddenError","NotFoundError","PurchaseError","DEFAULT_BASE_URL","HttpClient","config","path","params","body","url","filtered","entry","qs","k","v","method","isRetry","token","headers","response","REFRESH_THRESHOLD_MS","TokenManager","options","stored","refreshed","tokens","refreshToken","_err","MemoryTokenStorage","parseExpiresAt","expiresAt","createRefreshFn","baseUrl","res","data","BrowserAuthNamespace","http","tokenManager","BrowserConfigNamespace","BrowserContentNamespace","id","BrowserPurchasesNamespace","BrowserSellerContentNamespace","BrowserSellerNamespace","BrowserWalletNamespace","sessionId","CheckoutNamespace","contentId","init","storage","BrowserClient","_http","_tokenManager","_config","DEFAULT_STORAGE_KEY","webStorageAdapter","backend","key","raw","localStorageAdapter","sessionStorageAdapter"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledewire/browser",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "LedeWire SDK for browsers — embed a paywall with a single script tag",
5
5
  "type": "module",
6
6
  "exports": {