@nymbalhq/sdk 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Customer, CartItem, Address, PaymentIntent, OrderStatus, CheckoutPayment, VariantOption, ProductSortKey, Facet, Order, StoreCapabilities, Cart, CustomerAddress, ReviewsResult, ReviewResult } from '@nymbalhq/types';
2
- export { PaymentClient, ProductSortKey, ReviewResult as ReviewSubmitResult, ReviewsResult as ReviewsListResult, StoreCapabilities } from '@nymbalhq/types';
1
+ import { Customer, CartItem, Address, PaymentIntent, OrderStatus, CheckoutPayment, VariantOption, ProductSortKey, Facet, Order, StoreCapabilities, Cart, CustomerAddress, ShopperOrder, ReviewsResult, ReviewResult, AlertKind } from '@nymbalhq/types';
2
+ export { AlertKind, PaymentClient, ProductSortKey, ReviewResult as ReviewSubmitResult, ReviewsResult as ReviewsListResult, StoreCapabilities } from '@nymbalhq/types';
3
3
 
4
4
  interface DenormalisedVariant {
5
5
  id: string;
@@ -100,6 +100,8 @@ interface CheckoutState {
100
100
  } | null;
101
101
  /** The order this cart already became, when the server refused a resubmit and named it. */
102
102
  placedOrderNumber: string | null;
103
+ /** That order's key, when the refusal carried one. */
104
+ placedOrderKey: string | null;
103
105
  }
104
106
  interface AuthState {
105
107
  customer: Customer | null;
@@ -144,6 +146,8 @@ interface CheckoutResult {
144
146
  totalMinor: number;
145
147
  orderStatus: OrderStatus;
146
148
  payment: CheckoutPayment;
149
+ /** Reads the order with no session (`customer.orders.get(n, { key })`); absent from an API that mints none. */
150
+ orderKey?: string;
147
151
  }
148
152
  interface RegisterParams {
149
153
  email: string;
@@ -171,6 +175,13 @@ interface CommerceAdapter {
171
175
  capabilities?: {
172
176
  get(): Promise<StoreCapabilities>;
173
177
  };
178
+ /** The shopper's recently viewed products; an adapter without it shows none. */
179
+ recentlyViewed?: {
180
+ record(productId: string): Promise<void>;
181
+ list(): Promise<{
182
+ items: DenormalisedProduct[];
183
+ }>;
184
+ };
174
185
  cart: {
175
186
  get(): Promise<Cart>;
176
187
  addItem(variantId: string, qty: number): Promise<Cart>;
@@ -202,7 +213,10 @@ interface CommerceAdapter {
202
213
  listOrders(params?: {
203
214
  cursor?: string;
204
215
  }): Promise<OrderPage>;
205
- getOrder(orderNumber: string): Promise<Order>;
216
+ /** `key` is the order's key from its checkout, for a reader with no session. */
217
+ getOrder(orderNumber: string, options?: {
218
+ key?: string;
219
+ }): Promise<ShopperOrder>;
206
220
  };
207
221
  reviews: {
208
222
  getForProduct(productId: string, params?: {
@@ -216,6 +230,19 @@ interface CommerceAdapter {
216
230
  body: string;
217
231
  }): Promise<ReviewResult>;
218
232
  };
233
+ alerts: {
234
+ /**
235
+ * Asks to be emailed when a variant is back; the store mails a confirmation first. The answer is `pending` whether
236
+ * or not the address has an account or an alert already.
237
+ */
238
+ subscribe(request: {
239
+ email: string;
240
+ variantId: string;
241
+ kind: AlertKind;
242
+ }): Promise<{
243
+ status: 'pending';
244
+ }>;
245
+ };
219
246
  }
220
247
 
221
248
  interface CartStore {
@@ -334,15 +361,28 @@ interface CustomerAccount {
334
361
  list(opts?: {
335
362
  cursor?: string;
336
363
  }): Promise<OrderPage>;
337
- get(orderNumber: string): Promise<Order>;
364
+ /** `key`, the order's key from its checkout, reads it with no session; without one, only its owner can. */
365
+ get(orderNumber: string, options?: {
366
+ key?: string;
367
+ }): Promise<ShopperOrder>;
338
368
  };
339
369
  }
340
370
  /** The store's capabilities report, read once per client: what it can do does not change while it runs. */
341
371
  interface StoreCapabilitiesReader {
342
372
  get(): Promise<StoreCapabilities>;
343
373
  }
374
+ /** The shopper's recently viewed products, kept by the store under the signed-in customer or the browser's visitor. */
375
+ interface RecentlyViewed {
376
+ /** Records a view of the product; the store ignores a product that is not active. */
377
+ record(productId: string): Promise<void>;
378
+ /** The shopper's active products, newest first. */
379
+ list(): Promise<{
380
+ items: DenormalisedProduct[];
381
+ }>;
382
+ }
344
383
  interface NymbalClient {
345
384
  capabilities: StoreCapabilitiesReader;
385
+ recentlyViewed: RecentlyViewed;
346
386
  cart: CartStore;
347
387
  product: ProductStore;
348
388
  productList: ProductListStore;
@@ -403,22 +443,36 @@ interface FetchClientOptions {
403
443
  getCartToken?: () => string | null;
404
444
  onUnauthorized?: () => Promise<void>;
405
445
  }
446
+ /** Per request: headers sent beside the client's own. */
447
+ interface RequestOptions {
448
+ headers?: Record<string, string>;
449
+ /**
450
+ * The token refresh itself (what `onUnauthorized` sends through this client): its 401 is thrown, never waited on or
451
+ * sent again, so a refused refresh cannot wait on itself. An unmarked one that is refused is cut off after
452
+ * 10 s with the original 401.
453
+ */
454
+ authRefresh?: boolean;
455
+ }
406
456
  declare class FetchClient {
407
457
  private readonly baseUrl;
408
458
  private readonly credentials;
409
459
  private readonly getAccessToken;
410
460
  private readonly getCartToken;
411
461
  private readonly onUnauthorized;
412
- private handlingUnauthorized;
462
+ /** The refresh a refused request started, which every request refused meanwhile waits on rather than its own. */
463
+ private refreshing;
413
464
  /** The token `GET /api/csrf` answered: the API's `nymbal.csrf` cookie, which this origin may not be able to read. */
414
465
  private csrfToken;
415
466
  constructor(options: FetchClientOptions);
416
- request<T>(method: string, path: string, body?: unknown): Promise<T>;
467
+ request<T>(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<T>;
417
468
  /** Like `request`, keeping the envelope's `meta` (pagination cursors live there). */
418
- requestWithMeta<T>(method: string, path: string, body?: unknown): Promise<{
469
+ requestWithMeta<T>(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<{
419
470
  data: T;
420
471
  meta: Record<string, unknown>;
421
472
  }>;
473
+ /** Whether the refresh ended within `REFRESH_WAIT_MS`; a refresh that fails throws here, as it always has. */
474
+ private waitFor;
475
+ private refresh;
422
476
  private csrf;
423
477
  private fetchCsrfToken;
424
478
  private isCsrfRejection;
@@ -429,4 +483,4 @@ declare class FetchClient {
429
483
  declare function createNymbalApiAdapter(fetchClient: FetchClient): CommerceAdapter;
430
484
 
431
485
  export { FetchClient, NymbalApiError, createAuthStore, createCartStore, createCheckoutStore, createNymbalApiAdapter, createNymbalClient, createProductListStore, createProductStore, createSearchStore, createStore, createTokenManager, getPaymentDriver, registerPaymentDriver };
432
- export type { AuthResult, AuthState, AuthStore, CartState, CartStore, CheckoutDetails, CheckoutResult, CheckoutState, CheckoutStep, CheckoutStore, CommerceAdapter, CustomerAccount, DenormalisedProduct, DenormalisedVariant, FetchClientOptions, Listener, NewAddress, NymbalClient, NymbalClientOptions, OrderPage, PaymentConfirmContext, PaymentConfirmation, PaymentDriver, ProductListParams, ProductListResult, ProductListState, ProductListStore, ProductSearchParams, ProductSearchResult, ProductState, ProductStore, RegisterParams, SearchState, SearchStore, ShippingMethod, Store, StoreCapabilitiesReader, TokenManager, TokenManagerOptions };
486
+ export type { AuthResult, AuthState, AuthStore, CartState, CartStore, CheckoutDetails, CheckoutResult, CheckoutState, CheckoutStep, CheckoutStore, CommerceAdapter, CustomerAccount, DenormalisedProduct, DenormalisedVariant, FetchClientOptions, Listener, NewAddress, NymbalClient, NymbalClientOptions, OrderPage, PaymentConfirmContext, PaymentConfirmation, PaymentDriver, ProductListParams, ProductListResult, ProductListState, ProductListStore, ProductSearchParams, ProductSearchResult, ProductState, ProductStore, RecentlyViewed, RegisterParams, SearchState, SearchStore, ShippingMethod, Store, StoreCapabilitiesReader, TokenManager, TokenManagerOptions };
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ var NymbalApiError = class extends Error {
11
11
  status;
12
12
  context;
13
13
  };
14
+ var REFRESH_WAIT_MS = 1e4;
14
15
  var CSRF_HEADER = "x-csrf-token";
15
16
  var UNSAFE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
16
17
  var FetchClient = class {
@@ -19,7 +20,8 @@ var FetchClient = class {
19
20
  getAccessToken;
20
21
  getCartToken;
21
22
  onUnauthorized;
22
- handlingUnauthorized = false;
23
+ /** The refresh a refused request started, which every request refused meanwhile waits on rather than its own. */
24
+ refreshing = null;
23
25
  /** The token `GET /api/csrf` answered: the API's `nymbal.csrf` cookie, which this origin may not be able to read. */
24
26
  csrfToken = null;
25
27
  constructor(options) {
@@ -29,28 +31,50 @@ var FetchClient = class {
29
31
  this.getCartToken = options.getCartToken;
30
32
  this.onUnauthorized = options.onUnauthorized;
31
33
  }
32
- async request(method, path, body) {
33
- return (await this.requestWithMeta(method, path, body)).data;
34
+ async request(method, path, body, options = {}) {
35
+ return (await this.requestWithMeta(method, path, body, options)).data;
34
36
  }
35
37
  /** Like `request`, keeping the envelope's `meta` (pagination cursors live there). */
36
- async requestWithMeta(method, path, body) {
37
- let response = await this.doFetch(method, path, body);
38
+ async requestWithMeta(method, path, body, options = {}) {
39
+ const sentDuring = this.refreshing;
40
+ let { response, bearer } = await this.doFetch(method, path, body, options);
38
41
  if (await this.isCsrfRejection(response)) {
39
42
  this.csrfToken = null;
40
- response = await this.doFetch(method, path, body);
43
+ ({ response, bearer } = await this.doFetch(method, path, body, options));
41
44
  }
42
- if (response.status === 401 && this.onUnauthorized && !this.handlingUnauthorized) {
43
- this.handlingUnauthorized = true;
44
- try {
45
- await this.onUnauthorized();
46
- } finally {
47
- this.handlingUnauthorized = false;
45
+ if (response.status === 401 && this.onUnauthorized && options.authRefresh !== true) {
46
+ const pending = this.refreshing;
47
+ const retry = async () => this.parseResponse((await this.doFetch(method, path, body, options)).response);
48
+ if (pending === null && this.getAccessToken() !== bearer) {
49
+ return retry();
50
+ }
51
+ if (pending !== null && pending === sentDuring) {
52
+ if (await this.waitFor(pending) && this.getAccessToken() !== bearer) return retry();
53
+ } else if (await this.waitFor(pending ?? this.refresh(this.onUnauthorized))) {
54
+ return retry();
48
55
  }
49
- const retry = await this.doFetch(method, path, body);
50
- return this.parseResponse(retry);
51
56
  }
52
57
  return this.parseResponse(response);
53
58
  }
59
+ /** Whether the refresh ended within `REFRESH_WAIT_MS`; a refresh that fails throws here, as it always has. */
60
+ async waitFor(refresh) {
61
+ let timer;
62
+ const bound = new Promise((resolve) => {
63
+ timer = setTimeout(() => resolve(false), REFRESH_WAIT_MS);
64
+ });
65
+ try {
66
+ return await Promise.race([refresh.then(() => true), bound]);
67
+ } finally {
68
+ clearTimeout(timer);
69
+ }
70
+ }
71
+ refresh(onUnauthorized) {
72
+ const refresh = Promise.resolve().then(onUnauthorized).finally(() => {
73
+ this.refreshing = null;
74
+ });
75
+ this.refreshing = refresh;
76
+ return refresh;
77
+ }
54
78
  csrf() {
55
79
  this.csrfToken ??= this.fetchCsrfToken().catch((err) => {
56
80
  this.csrfToken = null;
@@ -75,8 +99,8 @@ var FetchClient = class {
75
99
  return false;
76
100
  }
77
101
  }
78
- async doFetch(method, path, body) {
79
- const headers = {};
102
+ async doFetch(method, path, body, options) {
103
+ const headers = { ...options.headers };
80
104
  const cookies = [];
81
105
  if (UNSAFE_METHODS.has(method.toUpperCase())) {
82
106
  const csrf = await this.csrf();
@@ -97,12 +121,13 @@ var FetchClient = class {
97
121
  if (cookies.length > 0) {
98
122
  headers["Cookie"] = cookies.join("; ");
99
123
  }
100
- return globalThis.fetch(`${this.baseUrl}${path}`, {
124
+ const response = await globalThis.fetch(`${this.baseUrl}${path}`, {
101
125
  method,
102
126
  headers,
103
127
  credentials: this.credentials,
104
128
  ...body !== void 0 && { body: JSON.stringify(body) }
105
129
  });
130
+ return { response, bearer: token };
106
131
  }
107
132
  async parseResponse(response) {
108
133
  const text = await response.text();
@@ -123,6 +148,9 @@ var FetchClient = class {
123
148
  };
124
149
 
125
150
  // src/adapter/nymbal-api-adapter.ts
151
+ import {
152
+ ORDER_KEY_HEADER
153
+ } from "@nymbalhq/types";
126
154
  function createNymbalApiAdapter(fetchClient) {
127
155
  return {
128
156
  capabilities: {
@@ -200,7 +228,9 @@ function createNymbalApiAdapter(fetchClient) {
200
228
  refresh() {
201
229
  return fetchClient.request(
202
230
  "POST",
203
- "/api/auth/refresh"
231
+ "/api/auth/refresh",
232
+ void 0,
233
+ { authRefresh: true }
204
234
  );
205
235
  },
206
236
  getProfile() {
@@ -227,8 +257,22 @@ function createNymbalApiAdapter(fetchClient) {
227
257
  const nextCursor = typeof meta.nextCursor === "string" ? meta.nextCursor : null;
228
258
  return { items: data ?? [], nextCursor };
229
259
  },
230
- getOrder(orderNumber) {
231
- return fetchClient.request("GET", `/api/orders/${encodeURIComponent(orderNumber)}`);
260
+ getOrder(orderNumber, options = {}) {
261
+ const { key } = options;
262
+ return fetchClient.request(
263
+ "GET",
264
+ `/api/orders/${encodeURIComponent(orderNumber)}`,
265
+ void 0,
266
+ key === void 0 ? {} : { headers: { [ORDER_KEY_HEADER]: key } }
267
+ );
268
+ }
269
+ },
270
+ recentlyViewed: {
271
+ async record(productId) {
272
+ await fetchClient.request("POST", "/api/recently-viewed", { productId });
273
+ },
274
+ list() {
275
+ return fetchClient.request("GET", "/api/recently-viewed");
232
276
  }
233
277
  },
234
278
  reviews: {
@@ -245,6 +289,11 @@ function createNymbalApiAdapter(fetchClient) {
245
289
  submit(review) {
246
290
  return fetchClient.request("POST", "/api/reviews", review);
247
291
  }
292
+ },
293
+ alerts: {
294
+ subscribe(request) {
295
+ return fetchClient.request("POST", "/api/alerts/subscribe", request);
296
+ }
248
297
  }
249
298
  };
250
299
  }
@@ -685,12 +734,17 @@ var INITIAL_STATE5 = {
685
734
  paymentStatus: "idle",
686
735
  error: null,
687
736
  order: null,
688
- placedOrderNumber: null
737
+ placedOrderNumber: null,
738
+ placedOrderKey: null
689
739
  };
690
740
  function namedOrder(err) {
691
- if (!(err instanceof NymbalApiError)) return null;
692
- const orderNumber = err.context?.["orderNumber"];
693
- return typeof orderNumber === "string" ? orderNumber : null;
741
+ const context = err instanceof NymbalApiError ? err.context : void 0;
742
+ const orderNumber = context?.["orderNumber"];
743
+ const orderKey = context?.["orderKey"];
744
+ return typeof orderNumber === "string" ? {
745
+ placedOrderNumber: orderNumber,
746
+ placedOrderKey: typeof orderKey === "string" ? orderKey : null
747
+ } : { placedOrderNumber: null, placedOrderKey: null };
694
748
  }
695
749
  function createCheckoutStore(adapter, cart) {
696
750
  const store = createStore(INITIAL_STATE5);
@@ -712,7 +766,12 @@ function createCheckoutStore(adapter, cart) {
712
766
  store.setState({ error: "Shipping and billing addresses are required" });
713
767
  return null;
714
768
  }
715
- store.setState({ paymentStatus: "processing", error: null, placedOrderNumber: null });
769
+ store.setState({
770
+ paymentStatus: "processing",
771
+ error: null,
772
+ placedOrderNumber: null,
773
+ placedOrderKey: null
774
+ });
716
775
  try {
717
776
  const result = await adapter.checkout.create({
718
777
  email: state.email,
@@ -733,13 +792,13 @@ function createCheckoutStore(adapter, cart) {
733
792
  await cart?.load();
734
793
  return result;
735
794
  } catch (err) {
736
- const placedOrderNumber = namedOrder(err);
795
+ const placed = namedOrder(err);
737
796
  store.setState({
738
797
  paymentStatus: "failed",
739
798
  error: err instanceof Error ? err.message : String(err),
740
- placedOrderNumber
799
+ ...placed
741
800
  });
742
- if (placedOrderNumber !== null) await cart?.load();
801
+ if (placed.placedOrderNumber !== null) await cart?.load();
743
802
  return null;
744
803
  }
745
804
  }
@@ -919,7 +978,7 @@ function createNymbalClient(options) {
919
978
  },
920
979
  orders: {
921
980
  list: (opts) => adapter.customers.listOrders(opts),
922
- get: (orderNumber) => adapter.customers.getOrder(orderNumber)
981
+ get: (orderNumber, options2) => adapter.customers.getOrder(orderNumber, options2)
923
982
  }
924
983
  };
925
984
  let report = null;
@@ -935,6 +994,21 @@ function createNymbalClient(options) {
935
994
  return report;
936
995
  }
937
996
  };
997
+ const recentlyViewedOf = () => {
998
+ const reader = adapter.recentlyViewed;
999
+ if (reader === void 0) {
1000
+ throw new Error("This client\u2019s adapter cannot record or list recently viewed products.");
1001
+ }
1002
+ return reader;
1003
+ };
1004
+ const recentlyViewed = {
1005
+ async record(productId) {
1006
+ await recentlyViewedOf().record(productId);
1007
+ },
1008
+ async list() {
1009
+ return recentlyViewedOf().list();
1010
+ }
1011
+ };
938
1012
  tokenManager.scheduleRefresh(() => adapter.customers.refresh());
939
1013
  function destroy() {
940
1014
  cart.destroy();
@@ -947,6 +1021,7 @@ function createNymbalClient(options) {
947
1021
  }
948
1022
  return {
949
1023
  capabilities,
1024
+ recentlyViewed,
950
1025
  cart,
951
1026
  product,
952
1027
  productList,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapter/fetch-client.ts","../src/adapter/nymbal-api-adapter.ts","../src/auth/token-manager.ts","../src/store/create-store.ts","../src/store/cart-store.ts","../src/store/product-store.ts","../src/store/product-list-store.ts","../src/store/search-store.ts","../src/store/checkout-store.ts","../src/store/auth-store.ts","../src/client.ts","../src/payment-drivers.ts"],"sourcesContent":["export class NymbalApiError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number,\n public readonly context?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'NymbalApiError'\n }\n}\n\nexport interface FetchClientOptions {\n baseUrl: string\n credentials?: RequestCredentials\n getAccessToken?: () => string | null\n getCartToken?: () => string | null\n onUnauthorized?: () => Promise<void>\n}\n\nconst CSRF_HEADER = 'x-csrf-token'\nconst UNSAFE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])\n\ninterface Envelope<T> {\n data?: T\n meta?: Record<string, unknown>\n error?: { code: string; message: string; context?: Record<string, unknown> }\n}\n\nexport class FetchClient {\n private readonly baseUrl: string\n private readonly credentials: RequestCredentials\n private readonly getAccessToken: () => string | null\n private readonly getCartToken: (() => string | null) | undefined\n private readonly onUnauthorized: (() => Promise<void>) | undefined\n private handlingUnauthorized = false\n /** The token `GET /api/csrf` answered: the API's `nymbal.csrf` cookie, which this origin may not be able to read. */\n private csrfToken: Promise<string> | null = null\n\n constructor(options: FetchClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.credentials = options.credentials ?? 'include'\n this.getAccessToken = options.getAccessToken ?? (() => null)\n this.getCartToken = options.getCartToken\n this.onUnauthorized = options.onUnauthorized\n }\n\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n return (await this.requestWithMeta<T>(method, path, body)).data\n }\n\n /** Like `request`, keeping the envelope's `meta` (pagination cursors live there). */\n async requestWithMeta<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<{ data: T; meta: Record<string, unknown> }> {\n let response = await this.doFetch(method, path, body)\n\n // A stale token (the cookie was replaced or expired) is fetched again once; a second refusal is thrown.\n if (await this.isCsrfRejection(response)) {\n this.csrfToken = null\n response = await this.doFetch(method, path, body)\n }\n\n if (response.status === 401 && this.onUnauthorized && !this.handlingUnauthorized) {\n this.handlingUnauthorized = true\n try {\n await this.onUnauthorized()\n } finally {\n this.handlingUnauthorized = false\n }\n const retry = await this.doFetch(method, path, body)\n return this.parseResponse<T>(retry)\n }\n\n return this.parseResponse<T>(response)\n }\n\n private csrf(): Promise<string> {\n this.csrfToken ??= this.fetchCsrfToken().catch((err: unknown) => {\n this.csrfToken = null\n throw err\n })\n return this.csrfToken\n }\n\n private async fetchCsrfToken(): Promise<string> {\n const response = await globalThis.fetch(`${this.baseUrl}/api/csrf`, {\n method: 'GET',\n credentials: this.credentials,\n })\n const { data } = await this.parseResponse<{ token: string }>(response)\n return data.token\n }\n\n private async isCsrfRejection(response: Response): Promise<boolean> {\n if (response.status !== 403) return false\n const text = await response.clone().text()\n try {\n return (JSON.parse(text) as Envelope<unknown>).error?.code === 'csrf.invalid'\n } catch {\n return false\n }\n }\n\n private async doFetch(method: string, path: string, body?: unknown): Promise<Response> {\n const headers: Record<string, string> = {}\n const cookies: string[] = []\n\n if (UNSAFE_METHODS.has(method.toUpperCase())) {\n const csrf = await this.csrf()\n headers[CSRF_HEADER] = csrf\n // Outside a browser there is no cookie jar to send the pair's cookie half; a browser drops this header.\n cookies.push(`nymbal.csrf=${csrf}`)\n }\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json'\n }\n\n const token = this.getAccessToken()\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n\n const cartToken = this.getCartToken?.()\n if (cartToken) {\n cookies.unshift(`nymbal.cart=${cartToken}`)\n }\n if (cookies.length > 0) {\n headers['Cookie'] = cookies.join('; ')\n }\n\n return globalThis.fetch(`${this.baseUrl}${path}`, {\n method,\n headers,\n credentials: this.credentials,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n }\n\n private async parseResponse<T>(\n response: Response,\n ): Promise<{ data: T; meta: Record<string, unknown> }> {\n const text = await response.text()\n if (!text) {\n return { data: undefined as T, meta: {} }\n }\n\n const envelope = JSON.parse(text) as Envelope<T>\n\n if (envelope.error) {\n throw new NymbalApiError(\n envelope.error.code,\n envelope.error.message,\n response.status,\n envelope.error.context,\n )\n }\n\n return { data: envelope.data as T, meta: envelope.meta ?? {} }\n }\n}\n","import type {\n Cart,\n Customer,\n CustomerAddress,\n Order,\n ReviewsResult,\n ReviewResult,\n StoreCapabilities,\n} from '@nymbalhq/types'\nimport type { CommerceAdapter } from './commerce-adapter.js'\nimport type { FetchClient } from './fetch-client.js'\nimport type {\n DenormalisedProduct,\n ProductListParams,\n ProductListResult,\n ProductSearchParams,\n ProductSearchResult,\n CheckoutDetails,\n CheckoutResult,\n RegisterParams,\n AuthResult,\n NewAddress,\n OrderPage,\n} from '../types.js'\n\nexport function createNymbalApiAdapter(fetchClient: FetchClient): CommerceAdapter {\n return {\n capabilities: {\n get() {\n return fetchClient.request<StoreCapabilities>('GET', '/api/capabilities')\n },\n },\n\n cart: {\n get() {\n return fetchClient.request<Cart>('GET', '/api/cart')\n },\n addItem(variantId: string, qty: number) {\n return fetchClient.request<Cart>('POST', '/api/cart/items', { variantId, qty })\n },\n removeItem(variantId: string) {\n return fetchClient.request<Cart>(\n 'DELETE',\n `/api/cart/items/${encodeURIComponent(variantId)}`,\n )\n },\n updateQuantity(variantId: string, qty: number) {\n return fetchClient.request<Cart>(\n 'PATCH',\n `/api/cart/items/${encodeURIComponent(variantId)}`,\n { qty },\n )\n },\n clear() {\n return fetchClient.request<Cart>('DELETE', '/api/cart')\n },\n },\n\n products: {\n getBySlug(slug: string) {\n return fetchClient.request<DenormalisedProduct>(\n 'GET',\n `/api/products/${encodeURIComponent(slug)}`,\n )\n },\n list(params?: ProductListParams) {\n const search = new URLSearchParams()\n if (params?.limit !== undefined) search.set('limit', String(params.limit))\n if (params?.cursor !== undefined) search.set('cursor', params.cursor)\n if (params?.category !== undefined) search.set('category', params.category)\n if (params?.sort !== undefined) search.set('sort', params.sort)\n const qs = search.toString()\n return fetchClient.request<ProductListResult>('GET', `/api/products${qs ? `?${qs}` : ''}`)\n },\n search(query: string, params?: ProductSearchParams) {\n const search = new URLSearchParams()\n search.set('q', query)\n if (params?.limit !== undefined) search.set('limit', String(params.limit))\n if (params?.cursor !== undefined) search.set('cursor', params.cursor)\n if (params?.category !== undefined) search.set('category', params.category)\n return fetchClient.request<ProductSearchResult>(\n 'GET',\n `/api/products/search?${search.toString()}`,\n )\n },\n },\n\n checkout: {\n create(details: CheckoutDetails) {\n return fetchClient.request<CheckoutResult>('POST', '/api/checkout', details)\n },\n },\n\n customers: {\n register(params: RegisterParams) {\n return fetchClient.request<AuthResult>('POST', '/api/auth/register', params)\n },\n login(email: string, password: string) {\n return fetchClient.request<AuthResult>('POST', '/api/auth/login', { email, password })\n },\n async logout() {\n await fetchClient.request<{ ok: boolean }>('POST', '/api/auth/logout')\n },\n refresh() {\n return fetchClient.request<{ accessToken: string; expiresIn: number }>(\n 'POST',\n '/api/auth/refresh',\n )\n },\n getProfile() {\n return fetchClient.request<Customer>('GET', '/api/customers/me')\n },\n updateProfile(updates: Partial<Pick<Customer, 'firstName' | 'lastName' | 'phone'>>) {\n return fetchClient.request<Customer>('PATCH', '/api/customers/me', updates)\n },\n listAddresses() {\n return fetchClient.request<CustomerAddress[]>('GET', '/api/customers/me/addresses')\n },\n addAddress(address: NewAddress) {\n return fetchClient.request<CustomerAddress>('POST', '/api/customers/me/addresses', address)\n },\n async removeAddress(id: string) {\n await fetchClient.request<{ ok: boolean }>(\n 'DELETE',\n `/api/customers/me/addresses/${encodeURIComponent(id)}`,\n )\n },\n async listOrders(params?: { cursor?: string }): Promise<OrderPage> {\n const qs =\n params?.cursor !== undefined ? `?cursor=${encodeURIComponent(params.cursor)}` : ''\n const { data, meta } = await fetchClient.requestWithMeta<Order[]>('GET', `/api/orders${qs}`)\n const nextCursor = typeof meta.nextCursor === 'string' ? meta.nextCursor : null\n return { items: data ?? [], nextCursor }\n },\n getOrder(orderNumber: string) {\n return fetchClient.request<Order>('GET', `/api/orders/${encodeURIComponent(orderNumber)}`)\n },\n },\n\n reviews: {\n getForProduct(productId: string, params?: { limit?: number; cursor?: string }) {\n const search = new URLSearchParams()\n if (params?.limit !== undefined) search.set('limit', String(params.limit))\n if (params?.cursor !== undefined) search.set('cursor', params.cursor)\n const qs = search.toString()\n return fetchClient.request<ReviewsResult>(\n 'GET',\n `/api/products/${encodeURIComponent(productId)}/reviews${qs ? `?${qs}` : ''}`,\n )\n },\n submit(review: { productId: string; rating: number; title: string; body: string }) {\n return fetchClient.request<ReviewResult>('POST', '/api/reviews', review)\n },\n },\n }\n}\n","export interface TokenManagerOptions {\n storage?: 'memory' | 'localStorage'\n storageKey?: string\n}\n\nexport interface TokenManager {\n getAccessToken(): string | null\n setTokens(accessToken: string, expiresIn: number): void\n clear(): void\n scheduleRefresh(refreshFn: () => Promise<{ accessToken: string; expiresIn: number }>): void\n destroy(): void\n}\n\nconst DEFAULT_STORAGE_KEY = 'nymbal.auth.accessToken'\n\nexport function createTokenManager(options?: TokenManagerOptions): TokenManager {\n const storageMode = options?.storage ?? 'memory'\n const storageKey = options?.storageKey ?? DEFAULT_STORAGE_KEY\n\n let memoryToken: string | null = null\n let refreshTimer: ReturnType<typeof setTimeout> | null = null\n let refreshFn: (() => Promise<{ accessToken: string; expiresIn: number }>) | null = null\n\n function getAccessToken(): string | null {\n if (storageMode === 'localStorage' && typeof globalThis.localStorage !== 'undefined') {\n return globalThis.localStorage.getItem(storageKey)\n }\n return memoryToken\n }\n\n function setAccessToken(token: string | null): void {\n memoryToken = token\n if (storageMode === 'localStorage' && typeof globalThis.localStorage !== 'undefined') {\n if (token) {\n globalThis.localStorage.setItem(storageKey, token)\n } else {\n globalThis.localStorage.removeItem(storageKey)\n }\n }\n }\n\n function setTokens(accessToken: string, expiresIn: number): void {\n setAccessToken(accessToken)\n scheduleAutoRefresh(expiresIn)\n }\n\n function clear(): void {\n setAccessToken(null)\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer)\n refreshTimer = null\n }\n }\n\n function scheduleAutoRefresh(expiresIn: number): void {\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer)\n }\n const delayMs = Math.max(1000, expiresIn * 0.8 * 1000)\n refreshTimer = setTimeout(async () => {\n if (!refreshFn) return\n try {\n const result = await refreshFn()\n setTokens(result.accessToken, result.expiresIn)\n } catch (err) {\n console.error('[TokenManager] auto-refresh failed, clearing session', err)\n clear()\n }\n }, delayMs)\n }\n\n function scheduleRefresh(\n fn: () => Promise<{ accessToken: string; expiresIn: number }>,\n ): void {\n refreshFn = fn\n }\n\n function destroy(): void {\n clear()\n refreshFn = null\n }\n\n return { getAccessToken, setTokens, clear, scheduleRefresh, destroy }\n}\n","export type Listener = () => void\n\nexport interface Store<TState> {\n getState(): TState\n setState(partial: Partial<TState> | ((prev: TState) => Partial<TState>)): void\n subscribe(listener: Listener): () => void\n destroy(): void\n}\n\nexport function createStore<TState extends object>(\n initialState: TState,\n): Store<TState> {\n let state = initialState\n const listeners = new Set<Listener>()\n\n function getState(): TState {\n return state\n }\n\n function setState(partial: Partial<TState> | ((prev: TState) => Partial<TState>)): void {\n const next = typeof partial === 'function' ? partial(state) : partial\n state = { ...state, ...next }\n for (const listener of listeners) {\n listener()\n }\n }\n\n function subscribe(listener: Listener): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n }\n\n function destroy(): void {\n listeners.clear()\n }\n\n return { getState, setState, subscribe, destroy }\n}\n","import type { CartItem } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { CartState } from '../types.js'\nimport { createStore } from './create-store.js'\n\nfunction deriveItemCount(items: CartItem[]): number {\n let count = 0\n for (const item of items) {\n count += item.qty\n }\n return count\n}\n\nconst INITIAL_STATE: CartState = {\n items: [],\n subtotalMinor: 0,\n currency: 'USD',\n itemCount: 0,\n loading: false,\n error: null,\n}\n\nexport interface CartStore {\n getState(): CartState\n subscribe(listener: () => void): () => void\n addItem(variantId: string, qty?: number): Promise<void>\n removeItem(variantId: string): Promise<void>\n updateQuantity(variantId: string, qty: number): Promise<void>\n clear(): Promise<void>\n load(): Promise<void>\n destroy(): void\n}\n\nexport function createCartStore(adapter: CommerceAdapter): CartStore {\n const store = createStore<CartState>(INITIAL_STATE)\n\n async function load(): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.get()\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function addItem(variantId: string, qty = 1): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.addItem(variantId, qty)\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function removeItem(variantId: string): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.removeItem(variantId)\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function updateQuantity(variantId: string, qty: number): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.updateQuantity(variantId, qty)\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function clear(): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n await adapter.cart.clear()\n store.setState({\n items: [],\n subtotalMinor: 0,\n itemCount: 0,\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n addItem,\n removeItem,\n updateQuantity,\n clear,\n load,\n destroy: store.destroy,\n }\n}\n","import type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { ProductState, DenormalisedVariant } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: ProductState = {\n product: null,\n selectedVariant: null,\n loading: false,\n error: null,\n}\n\nexport interface ProductStore {\n getState(): ProductState\n subscribe(listener: () => void): () => void\n loadBySlug(slug: string): Promise<void>\n selectVariant(variant: DenormalisedVariant | null): void\n destroy(): void\n}\n\nexport function createProductStore(adapter: CommerceAdapter): ProductStore {\n const store = createStore<ProductState>(INITIAL_STATE)\n\n async function loadBySlug(slug: string): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const product = await adapter.products.getBySlug(slug)\n const firstVariant = product.variants[0] ?? null\n store.setState({\n product,\n selectedVariant: firstVariant,\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n function selectVariant(variant: DenormalisedVariant | null): void {\n store.setState({ selectedVariant: variant })\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n loadBySlug,\n selectVariant,\n destroy: store.destroy,\n }\n}\n","import { DEFAULT_PRODUCT_SORT, type ProductSortKey } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { ProductListState, ProductListParams } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: ProductListState = {\n products: [],\n facets: [],\n filters: {},\n sort: DEFAULT_PRODUCT_SORT,\n pagination: { cursor: null, hasMore: false },\n loading: false,\n error: null,\n}\n\nexport interface ProductListStore {\n getState(): ProductListState\n subscribe(listener: () => void): () => void\n load(params?: ProductListParams): Promise<void>\n loadMore(): Promise<void>\n applyFilter(name: string, value: string | string[]): Promise<void>\n removeFilter(name: string): Promise<void>\n setSort(sort: ProductSortKey): Promise<void>\n destroy(): void\n}\n\nexport function createProductListStore(adapter: CommerceAdapter): ProductListStore {\n const store = createStore<ProductListState>(INITIAL_STATE)\n let lastLimit: number | undefined\n // Only the latest request's answer may reach the state: an older one carries another sort's items and cursor.\n let generation = 0\n\n function buildParams(): ProductListParams {\n const state = store.getState()\n const params: ProductListParams = { sort: state.sort }\n if (lastLimit !== undefined) params.limit = lastLimit\n const category = state.filters['category']\n if (typeof category === 'string') {\n params.category = category\n }\n return params\n }\n\n /** With params, they become the listing's category and sort, so `setSort` and `loadMore` keep them. */\n async function load(params?: ProductListParams): Promise<void> {\n if (params !== undefined) {\n if (params.limit !== undefined) lastLimit = params.limit\n const filters = { ...store.getState().filters }\n if (params.category !== undefined) filters['category'] = params.category\n else delete filters['category']\n // Loading from this update on: an update that is not loading is a settled answer, which a server-rendered\n // listing gives its cards way to.\n store.setState({ filters, sort: params.sort ?? DEFAULT_PRODUCT_SORT, loading: true })\n }\n const request = buildParams()\n if (params?.cursor !== undefined) request.cursor = params.cursor\n const current = ++generation\n store.setState({ loading: true })\n try {\n const result = await adapter.products.list(request)\n if (current !== generation) return\n store.setState({\n products: result.items,\n facets: result.facets ?? store.getState().facets,\n pagination: { cursor: result.nextCursor, hasMore: result.nextCursor !== null },\n loading: false,\n error: null,\n })\n } catch (err) {\n if (current !== generation) return\n console.error('[ProductListStore] load failed', err)\n store.setState({ loading: false, error: err instanceof Error ? err.message : String(err) })\n }\n }\n\n async function loadMore(): Promise<void> {\n const state = store.getState()\n if (!state.pagination.hasMore || state.loading) return\n const current = ++generation\n store.setState({ loading: true })\n try {\n const params = buildParams()\n if (state.pagination.cursor !== null) {\n params.cursor = state.pagination.cursor\n }\n const result = await adapter.products.list(params)\n if (current !== generation) return\n store.setState({\n products: [...state.products, ...result.items],\n pagination: { cursor: result.nextCursor, hasMore: result.nextCursor !== null },\n loading: false,\n error: null,\n })\n } catch (err) {\n if (current !== generation) return\n console.error('[ProductListStore] loadMore failed', err)\n store.setState({ loading: false, error: err instanceof Error ? err.message : String(err) })\n }\n }\n\n async function applyFilter(name: string, value: string | string[]): Promise<void> {\n const filters = { ...store.getState().filters, [name]: value }\n store.setState({ filters })\n await load()\n }\n\n async function removeFilter(name: string): Promise<void> {\n const filters = { ...store.getState().filters }\n delete filters[name]\n store.setState({ filters })\n await load()\n }\n\n async function setSort(sort: ProductSortKey): Promise<void> {\n store.setState({ sort })\n await load()\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n load,\n loadMore,\n applyFilter,\n removeFilter,\n setSort,\n destroy: store.destroy,\n }\n}\n","import type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { SearchState } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: SearchState = {\n query: '',\n category: null,\n results: [],\n total: 0,\n nextCursor: null,\n facets: [],\n loading: false,\n}\n\nexport interface SearchStore {\n getState(): SearchState\n subscribe(listener: () => void): () => void\n /** Page 1 of `query`, in `options.category` (a slug) when given, otherwise in every category. */\n search(query: string, options?: { category?: string | null }): Promise<void>\n /** Appends the next page; a no-op when every match is loaded or a page is loading. */\n loadMore(): Promise<void>\n /** Page 1 of the current query in `category` (a slug), or in every category when null. */\n setCategory(category: string | null): Promise<void>\n clearSearch(): void\n destroy(): void\n}\n\nexport function createSearchStore(adapter: CommerceAdapter): SearchStore {\n const store = createStore<SearchState>(INITIAL_STATE)\n // Each search supersedes the last: an answer for an older one is dropped.\n let generation = 0\n\n async function search(query: string, options?: { category?: string | null }): Promise<void> {\n const run = ++generation\n if (!query.trim()) {\n store.setState({ ...INITIAL_STATE })\n return\n }\n const category = options?.category ?? null\n store.setState({ query, category, loading: true })\n try {\n const result = await (category === null\n ? adapter.products.search(query)\n : adapter.products.search(query, { category }))\n if (run !== generation) return\n store.setState({\n results: result.items,\n total: result.total,\n nextCursor: result.nextCursor,\n facets: result.facets ?? [],\n loading: false,\n })\n } catch (err) {\n if (run !== generation) return\n console.error('[SearchStore] search failed', err)\n store.setState({ loading: false })\n }\n }\n\n async function loadMore(): Promise<void> {\n const { query, category, nextCursor, loading } = store.getState()\n if (nextCursor === null || loading) return\n const run = generation\n store.setState({ loading: true })\n try {\n const result = await adapter.products.search(query, {\n cursor: nextCursor,\n ...(category !== null && { category }),\n })\n if (run !== generation) return\n store.setState({\n results: [...store.getState().results, ...result.items],\n total: result.total,\n nextCursor: result.nextCursor,\n loading: false,\n })\n } catch (err) {\n if (run !== generation) return\n console.error('[SearchStore] load more failed', err)\n store.setState({ loading: false })\n }\n }\n\n function setCategory(category: string | null): Promise<void> {\n return search(store.getState().query, { category })\n }\n\n function clearSearch(): void {\n generation++\n store.setState({ ...INITIAL_STATE })\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n search,\n loadMore,\n setCategory,\n clearSearch,\n destroy: store.destroy,\n }\n}\n","import type { Address } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport { NymbalApiError } from '../adapter/fetch-client.js'\nimport type { CartStore } from './cart-store.js'\nimport type { CheckoutResult, CheckoutState, ShippingMethod } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: CheckoutState = {\n step: 'contact',\n email: '',\n shippingAddress: null,\n billingAddress: null,\n shippingMethod: null,\n paymentStatus: 'idle',\n error: null,\n order: null,\n placedOrderNumber: null,\n}\n\n/** The order a refused resubmit names (409 `checkout.cart_empty` or `checkout.payment_in_progress`), if any. */\nfunction namedOrder(err: unknown): string | null {\n if (!(err instanceof NymbalApiError)) return null\n const orderNumber = err.context?.['orderNumber']\n return typeof orderNumber === 'string' ? orderNumber : null\n}\n\nexport interface CheckoutStore {\n getState(): CheckoutState\n subscribe(listener: () => void): () => void\n setEmail(email: string): void\n setShippingAddress(address: Address): void\n setBillingAddress(address: Address): void\n setShippingMethod(method: ShippingMethod): void\n /** Places the order; resolves to the server's result, or null when there is none. */\n submitPayment(): Promise<CheckoutResult | null>\n /** The provider confirmed the payment on the client (Stripe's `confirmCardPayment`). */\n markConfirmed(): void\n reset(): void\n destroy(): void\n}\n\n/**\n * `cart`, when given, is loaded again once the server has answered a submit: placing an order changes the cart on the\n * server (emptied when confirmed, kept while awaiting payment), and whatever renders the cart store must show that.\n */\nexport function createCheckoutStore(adapter: CommerceAdapter, cart?: CartStore): CheckoutStore {\n const store = createStore<CheckoutState>(INITIAL_STATE)\n\n function setEmail(email: string): void {\n store.setState({ email, step: 'shipping' })\n }\n\n function setShippingAddress(address: Address): void {\n store.setState({ shippingAddress: address })\n }\n\n function setBillingAddress(address: Address): void {\n store.setState({ billingAddress: address })\n }\n\n function setShippingMethod(method: ShippingMethod): void {\n store.setState({ shippingMethod: method, step: 'payment' })\n }\n\n async function submitPayment(): Promise<CheckoutResult | null> {\n const state = store.getState()\n if (!state.shippingAddress || !state.billingAddress) {\n store.setState({ error: 'Shipping and billing addresses are required' })\n return null\n }\n store.setState({ paymentStatus: 'processing', error: null, placedOrderNumber: null })\n try {\n const result = await adapter.checkout.create({\n email: state.email,\n billingAddress: state.billingAddress,\n shippingAddress: state.shippingAddress,\n })\n const { status, reason } = result.payment\n store.setState({\n paymentStatus: status,\n order: {\n orderId: result.orderId,\n orderNumber: result.orderNumber,\n paymentIntent: result.paymentIntent,\n },\n error:\n status === 'failed'\n ? `Your payment did not go through${reason ? ` (${reason})` : ''}. Please try again.`\n : null,\n ...(status === 'succeeded' && { step: 'confirmation' as const }),\n })\n await cart?.load()\n return result\n } catch (err) {\n const placedOrderNumber = namedOrder(err)\n store.setState({\n paymentStatus: 'failed',\n error: err instanceof Error ? err.message : String(err),\n placedOrderNumber,\n })\n // A refusal naming an order: the cart became (or is becoming) that order on the server.\n if (placedOrderNumber !== null) await cart?.load()\n return null\n }\n }\n\n function markConfirmed(): void {\n store.setState({ paymentStatus: 'succeeded', step: 'confirmation' })\n }\n\n function reset(): void {\n store.setState(INITIAL_STATE)\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n setEmail,\n setShippingAddress,\n setBillingAddress,\n setShippingMethod,\n submitPayment,\n markConfirmed,\n reset,\n destroy: store.destroy,\n }\n}\n","import type { Customer } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { TokenManager } from '../auth/token-manager.js'\nimport type { AuthState, RegisterParams } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: AuthState = {\n customer: null,\n isAuthenticated: false,\n loading: false,\n error: null,\n}\n\nexport interface AuthStore {\n getState(): AuthState\n subscribe(listener: () => void): () => void\n login(email: string, password: string): Promise<void>\n register(params: RegisterParams): Promise<void>\n logout(): Promise<void>\n refreshToken(): Promise<void>\n updateProfile(updates: Partial<Pick<Customer, 'firstName' | 'lastName' | 'phone'>>): Promise<void>\n loadProfile(): Promise<void>\n destroy(): void\n}\n\nexport function createAuthStore(\n adapter: CommerceAdapter,\n tokenManager: TokenManager,\n): AuthStore {\n const store = createStore<AuthState>(INITIAL_STATE)\n\n async function login(email: string, password: string): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const result = await adapter.customers.login(email, password)\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n store.setState({\n customer: result.customer,\n isAuthenticated: true,\n loading: false,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n store.setState({ loading: false, error: message })\n throw err\n }\n }\n\n async function register(params: RegisterParams): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const result = await adapter.customers.register(params)\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n store.setState({\n customer: result.customer,\n isAuthenticated: true,\n loading: false,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n store.setState({ loading: false, error: message })\n throw err\n }\n }\n\n async function logout(): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n await adapter.customers.logout()\n tokenManager.clear()\n store.setState({\n customer: null,\n isAuthenticated: false,\n loading: false,\n })\n } catch (err) {\n tokenManager.clear()\n store.setState({\n customer: null,\n isAuthenticated: false,\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function refreshToken(): Promise<void> {\n try {\n const result = await adapter.customers.refresh()\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n } catch (err) {\n console.error('[AuthStore] token refresh failed, logging out', err)\n tokenManager.clear()\n store.setState({\n customer: null,\n isAuthenticated: false,\n })\n }\n }\n\n async function updateProfile(\n updates: Partial<Pick<Customer, 'firstName' | 'lastName' | 'phone'>>,\n ): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const customer = await adapter.customers.updateProfile(updates)\n store.setState({ customer, loading: false })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function loadProfile(): Promise<void> {\n if (!tokenManager.getAccessToken()) return\n store.setState({ loading: true, error: null })\n try {\n const customer = await adapter.customers.getProfile()\n store.setState({\n customer,\n isAuthenticated: true,\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n login,\n register,\n logout,\n refreshToken,\n updateProfile,\n loadProfile,\n destroy: store.destroy,\n }\n}\n","import type { CommerceAdapter } from './adapter/commerce-adapter.js'\nimport { FetchClient } from './adapter/fetch-client.js'\nimport { createNymbalApiAdapter } from './adapter/nymbal-api-adapter.js'\nimport { createTokenManager } from './auth/token-manager.js'\nimport { createCartStore, type CartStore } from './store/cart-store.js'\nimport { createProductStore, type ProductStore } from './store/product-store.js'\nimport { createProductListStore, type ProductListStore } from './store/product-list-store.js'\nimport { createSearchStore, type SearchStore } from './store/search-store.js'\nimport { createCheckoutStore, type CheckoutStore } from './store/checkout-store.js'\nimport { createAuthStore, type AuthStore } from './store/auth-store.js'\nimport type { CustomerAddress, Order, StoreCapabilities } from '@nymbalhq/types'\nimport type { NewAddress, OrderPage } from './types.js'\n\nexport interface NymbalClientOptions {\n baseUrl: string\n adapter?: CommerceAdapter\n tokenStorage?: 'memory' | 'localStorage'\n credentials?: RequestCredentials\n getCartToken?: () => string | null\n}\n\n/** The signed-in customer's own account; every call sends the session's bearer token. */\nexport interface CustomerAccount {\n addresses: {\n list(): Promise<CustomerAddress[]>\n create(address: NewAddress): Promise<CustomerAddress>\n remove(id: string): Promise<void>\n }\n orders: {\n list(opts?: { cursor?: string }): Promise<OrderPage>\n get(orderNumber: string): Promise<Order>\n }\n}\n\n/** The store's capabilities report, read once per client: what it can do does not change while it runs. */\nexport interface StoreCapabilitiesReader {\n get(): Promise<StoreCapabilities>\n}\n\nexport interface NymbalClient {\n capabilities: StoreCapabilitiesReader\n cart: CartStore\n product: ProductStore\n productList: ProductListStore\n search: SearchStore\n checkout: CheckoutStore\n auth: AuthStore\n customer: CustomerAccount\n adapter: CommerceAdapter\n destroy(): void\n}\n\nexport function createNymbalClient(options: NymbalClientOptions): NymbalClient {\n const tokenManager = createTokenManager({\n ...(options.tokenStorage !== undefined && { storage: options.tokenStorage }),\n })\n\n let adapter: CommerceAdapter\n\n if (options.adapter) {\n adapter = options.adapter\n } else {\n const fetchClient = new FetchClient({\n baseUrl: options.baseUrl,\n ...(options.credentials !== undefined && { credentials: options.credentials }),\n getAccessToken: () => tokenManager.getAccessToken(),\n ...(options.getCartToken !== undefined && { getCartToken: options.getCartToken }),\n onUnauthorized: async () => {\n try {\n const result = await adapter.customers.refresh()\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n } catch (err) {\n // Token refresh failure is expected when the user session has expired.\n console.warn('[NymbalClient] token refresh on unauthorized failed', err)\n tokenManager.clear()\n }\n },\n })\n adapter = createNymbalApiAdapter(fetchClient)\n }\n\n const cart = createCartStore(adapter)\n const product = createProductStore(adapter)\n const productList = createProductListStore(adapter)\n const search = createSearchStore(adapter)\n const checkout = createCheckoutStore(adapter, cart)\n const auth = createAuthStore(adapter, tokenManager)\n\n const customer: CustomerAccount = {\n addresses: {\n list: () => adapter.customers.listAddresses(),\n create: (address) => adapter.customers.addAddress(address),\n remove: (id) => adapter.customers.removeAddress(id),\n },\n orders: {\n list: (opts) => adapter.customers.listOrders(opts),\n get: (orderNumber) => adapter.customers.getOrder(orderNumber),\n },\n }\n\n // A failed read is not kept, so the next get() asks again.\n let report: Promise<StoreCapabilities> | null = null\n const capabilities: StoreCapabilitiesReader = {\n get() {\n if (report === null) {\n const reader = adapter.capabilities\n report =\n reader === undefined\n ? Promise.reject(new Error('This client’s adapter cannot read the store capabilities.'))\n : reader.get()\n report.catch(() => {\n report = null\n })\n }\n return report\n },\n }\n\n tokenManager.scheduleRefresh(() => adapter.customers.refresh())\n\n function destroy(): void {\n cart.destroy()\n product.destroy()\n productList.destroy()\n search.destroy()\n checkout.destroy()\n auth.destroy()\n tokenManager.destroy()\n }\n\n return {\n capabilities,\n cart,\n product,\n productList,\n search,\n checkout,\n auth,\n customer,\n adapter,\n destroy,\n }\n}\n","import type { Address } from '@nymbalhq/types'\n\n/** What a checkout already knows about the shopper, which a driver may hand its processor with the payment. */\nexport interface PaymentConfirmContext {\n email?: string\n billing?: Address\n}\n\n/** What a payment driver's `confirm` answers: paid now, accepted without a payment yet, or refused with a reason. */\nexport type PaymentConfirmation = { ok: true; confirmed: boolean } | { ok: false; error: string }\n\n/**\n * The browser half of a payments adapter, named by the `driver` of GET /api/capabilities' payments client. `mount`\n * renders whatever the shopper pays with inside `el`; `confirm` completes a payment the API left `requires_action`,\n * with the shopper's email and billing address when the checkout has them.\n */\nexport interface PaymentDriver {\n mount(el: HTMLElement, options: Record<string, string>): Promise<void> | void\n confirm(clientSecret: string, context?: PaymentConfirmContext): Promise<PaymentConfirmation>\n}\n\n// On globalThis, like the registered client: a page that loads two copies of the SDK still has one registry.\nconst DRIVERS_KEY = Symbol.for('nymbal.paymentDrivers')\n\nfunction drivers(): Map<string, PaymentDriver> {\n const holder = globalThis as Record<symbol, Map<string, PaymentDriver> | undefined>\n holder[DRIVERS_KEY] ??= new Map()\n return holder[DRIVERS_KEY]\n}\n\n/** Registers `driver` under `name`, replacing any driver of that name. */\nexport function registerPaymentDriver(name: string, driver: PaymentDriver): void {\n drivers().set(name, driver)\n}\n\nexport function getPaymentDriver(name: string): PaymentDriver | undefined {\n return drivers().get(name)\n}\n"],"mappings":"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","names":["INITIAL_STATE","INITIAL_STATE","INITIAL_STATE","INITIAL_STATE","INITIAL_STATE"]}
1
+ {"version":3,"sources":["../src/adapter/fetch-client.ts","../src/adapter/nymbal-api-adapter.ts","../src/auth/token-manager.ts","../src/store/create-store.ts","../src/store/cart-store.ts","../src/store/product-store.ts","../src/store/product-list-store.ts","../src/store/search-store.ts","../src/store/checkout-store.ts","../src/store/auth-store.ts","../src/client.ts","../src/payment-drivers.ts"],"sourcesContent":["export class NymbalApiError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n public readonly status: number,\n public readonly context?: Record<string, unknown>,\n ) {\n super(message)\n this.name = 'NymbalApiError'\n }\n}\n\nexport interface FetchClientOptions {\n baseUrl: string\n credentials?: RequestCredentials\n getAccessToken?: () => string | null\n getCartToken?: () => string | null\n onUnauthorized?: () => Promise<void>\n}\n\n/** Per request: headers sent beside the client's own. */\nexport interface RequestOptions {\n headers?: Record<string, string>\n /**\n * The token refresh itself (what `onUnauthorized` sends through this client): its 401 is thrown, never waited on or\n * sent again, so a refused refresh cannot wait on itself. An unmarked one that is refused is cut off after\n * 10 s with the original 401.\n */\n authRefresh?: boolean\n}\n\n/**\n * The longest a refused request waits on a refresh before its 401 is thrown: far beyond one healthy refresh round trip,\n * and the bound on a refresh that, unmarked, waits on itself.\n */\nconst REFRESH_WAIT_MS = 10_000\n\nconst CSRF_HEADER = 'x-csrf-token'\nconst UNSAFE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])\n\ninterface Envelope<T> {\n data?: T\n meta?: Record<string, unknown>\n error?: { code: string; message: string; context?: Record<string, unknown> }\n}\n\nexport class FetchClient {\n private readonly baseUrl: string\n private readonly credentials: RequestCredentials\n private readonly getAccessToken: () => string | null\n private readonly getCartToken: (() => string | null) | undefined\n private readonly onUnauthorized: (() => Promise<void>) | undefined\n /** The refresh a refused request started, which every request refused meanwhile waits on rather than its own. */\n private refreshing: Promise<void> | null = null\n /** The token `GET /api/csrf` answered: the API's `nymbal.csrf` cookie, which this origin may not be able to read. */\n private csrfToken: Promise<string> | null = null\n\n constructor(options: FetchClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.credentials = options.credentials ?? 'include'\n this.getAccessToken = options.getAccessToken ?? (() => null)\n this.getCartToken = options.getCartToken\n this.onUnauthorized = options.onUnauthorized\n }\n\n async request<T>(\n method: string,\n path: string,\n body?: unknown,\n options: RequestOptions = {},\n ): Promise<T> {\n return (await this.requestWithMeta<T>(method, path, body, options)).data\n }\n\n /** Like `request`, keeping the envelope's `meta` (pagination cursors live there). */\n async requestWithMeta<T>(\n method: string,\n path: string,\n body?: unknown,\n options: RequestOptions = {},\n ): Promise<{ data: T; meta: Record<string, unknown> }> {\n // Read before the first await: the refresh, if any, in flight when this request was sent.\n const sentDuring = this.refreshing\n let { response, bearer } = await this.doFetch(method, path, body, options)\n\n // A stale token (the cookie was replaced or expired) is fetched again once; a second refusal is thrown.\n if (await this.isCsrfRejection(response)) {\n this.csrfToken = null\n ;({ response, bearer } = await this.doFetch(method, path, body, options))\n }\n\n if (response.status === 401 && this.onUnauthorized && options.authRefresh !== true) {\n const pending = this.refreshing\n const retry = async () =>\n this.parseResponse<T>((await this.doFetch(method, path, body, options)).response)\n if (pending === null && this.getAccessToken() !== bearer) {\n // A refresh that ended after this was sent has replaced its token already.\n return retry()\n }\n if (pending !== null && pending === sentDuring) {\n // Sent during the refresh with the token it replaces: sent again once it has, and only if it did.\n if ((await this.waitFor(pending)) && this.getAccessToken() !== bearer) return retry()\n } else if (await this.waitFor(pending ?? this.refresh(this.onUnauthorized))) {\n // Every request refused with the old token waits on the one refresh and is sent again once.\n return retry()\n }\n }\n\n return this.parseResponse<T>(response)\n }\n\n /** Whether the refresh ended within `REFRESH_WAIT_MS`; a refresh that fails throws here, as it always has. */\n private async waitFor(refresh: Promise<void>): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined\n const bound = new Promise<false>((resolve) => {\n timer = setTimeout(() => resolve(false), REFRESH_WAIT_MS)\n })\n try {\n return await Promise.race([refresh.then(() => true as const), bound])\n } finally {\n clearTimeout(timer)\n }\n }\n\n private refresh(onUnauthorized: () => Promise<void>): Promise<void> {\n const refresh = Promise.resolve()\n .then(onUnauthorized)\n .finally(() => {\n this.refreshing = null\n })\n this.refreshing = refresh\n return refresh\n }\n\n private csrf(): Promise<string> {\n this.csrfToken ??= this.fetchCsrfToken().catch((err: unknown) => {\n this.csrfToken = null\n throw err\n })\n return this.csrfToken\n }\n\n private async fetchCsrfToken(): Promise<string> {\n const response = await globalThis.fetch(`${this.baseUrl}/api/csrf`, {\n method: 'GET',\n credentials: this.credentials,\n })\n const { data } = await this.parseResponse<{ token: string }>(response)\n return data.token\n }\n\n private async isCsrfRejection(response: Response): Promise<boolean> {\n if (response.status !== 403) return false\n const text = await response.clone().text()\n try {\n return (JSON.parse(text) as Envelope<unknown>).error?.code === 'csrf.invalid'\n } catch {\n return false\n }\n }\n\n private async doFetch(\n method: string,\n path: string,\n body: unknown,\n options: RequestOptions,\n ): Promise<{ response: Response; bearer: string | null }> {\n const headers: Record<string, string> = { ...options.headers }\n const cookies: string[] = []\n\n if (UNSAFE_METHODS.has(method.toUpperCase())) {\n const csrf = await this.csrf()\n headers[CSRF_HEADER] = csrf\n // Outside a browser there is no cookie jar to send the pair's cookie half; a browser drops this header.\n cookies.push(`nymbal.csrf=${csrf}`)\n }\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json'\n }\n\n const token = this.getAccessToken()\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n\n const cartToken = this.getCartToken?.()\n if (cartToken) {\n cookies.unshift(`nymbal.cart=${cartToken}`)\n }\n if (cookies.length > 0) {\n headers['Cookie'] = cookies.join('; ')\n }\n\n const response = await globalThis.fetch(`${this.baseUrl}${path}`, {\n method,\n headers,\n credentials: this.credentials,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n })\n return { response, bearer: token }\n }\n\n private async parseResponse<T>(\n response: Response,\n ): Promise<{ data: T; meta: Record<string, unknown> }> {\n const text = await response.text()\n if (!text) {\n return { data: undefined as T, meta: {} }\n }\n\n const envelope = JSON.parse(text) as Envelope<T>\n\n if (envelope.error) {\n throw new NymbalApiError(\n envelope.error.code,\n envelope.error.message,\n response.status,\n envelope.error.context,\n )\n }\n\n return { data: envelope.data as T, meta: envelope.meta ?? {} }\n }\n}\n","import {\n ORDER_KEY_HEADER,\n type AlertKind,\n type Cart,\n type Customer,\n type CustomerAddress,\n type Order,\n type ReviewsResult,\n type ReviewResult,\n type ShopperOrder,\n type StoreCapabilities,\n} from '@nymbalhq/types'\nimport type { CommerceAdapter } from './commerce-adapter.js'\nimport type { FetchClient } from './fetch-client.js'\nimport type {\n DenormalisedProduct,\n ProductListParams,\n ProductListResult,\n ProductSearchParams,\n ProductSearchResult,\n CheckoutDetails,\n CheckoutResult,\n RegisterParams,\n AuthResult,\n NewAddress,\n OrderPage,\n} from '../types.js'\n\nexport function createNymbalApiAdapter(fetchClient: FetchClient): CommerceAdapter {\n return {\n capabilities: {\n get() {\n return fetchClient.request<StoreCapabilities>('GET', '/api/capabilities')\n },\n },\n\n cart: {\n get() {\n return fetchClient.request<Cart>('GET', '/api/cart')\n },\n addItem(variantId: string, qty: number) {\n return fetchClient.request<Cart>('POST', '/api/cart/items', { variantId, qty })\n },\n removeItem(variantId: string) {\n return fetchClient.request<Cart>(\n 'DELETE',\n `/api/cart/items/${encodeURIComponent(variantId)}`,\n )\n },\n updateQuantity(variantId: string, qty: number) {\n return fetchClient.request<Cart>(\n 'PATCH',\n `/api/cart/items/${encodeURIComponent(variantId)}`,\n { qty },\n )\n },\n clear() {\n return fetchClient.request<Cart>('DELETE', '/api/cart')\n },\n },\n\n products: {\n getBySlug(slug: string) {\n return fetchClient.request<DenormalisedProduct>(\n 'GET',\n `/api/products/${encodeURIComponent(slug)}`,\n )\n },\n list(params?: ProductListParams) {\n const search = new URLSearchParams()\n if (params?.limit !== undefined) search.set('limit', String(params.limit))\n if (params?.cursor !== undefined) search.set('cursor', params.cursor)\n if (params?.category !== undefined) search.set('category', params.category)\n if (params?.sort !== undefined) search.set('sort', params.sort)\n const qs = search.toString()\n return fetchClient.request<ProductListResult>('GET', `/api/products${qs ? `?${qs}` : ''}`)\n },\n search(query: string, params?: ProductSearchParams) {\n const search = new URLSearchParams()\n search.set('q', query)\n if (params?.limit !== undefined) search.set('limit', String(params.limit))\n if (params?.cursor !== undefined) search.set('cursor', params.cursor)\n if (params?.category !== undefined) search.set('category', params.category)\n return fetchClient.request<ProductSearchResult>(\n 'GET',\n `/api/products/search?${search.toString()}`,\n )\n },\n },\n\n checkout: {\n create(details: CheckoutDetails) {\n return fetchClient.request<CheckoutResult>('POST', '/api/checkout', details)\n },\n },\n\n customers: {\n register(params: RegisterParams) {\n return fetchClient.request<AuthResult>('POST', '/api/auth/register', params)\n },\n login(email: string, password: string) {\n return fetchClient.request<AuthResult>('POST', '/api/auth/login', { email, password })\n },\n async logout() {\n await fetchClient.request<{ ok: boolean }>('POST', '/api/auth/logout')\n },\n refresh() {\n return fetchClient.request<{ accessToken: string; expiresIn: number }>(\n 'POST',\n '/api/auth/refresh',\n undefined,\n { authRefresh: true },\n )\n },\n getProfile() {\n return fetchClient.request<Customer>('GET', '/api/customers/me')\n },\n updateProfile(updates: Partial<Pick<Customer, 'firstName' | 'lastName' | 'phone'>>) {\n return fetchClient.request<Customer>('PATCH', '/api/customers/me', updates)\n },\n listAddresses() {\n return fetchClient.request<CustomerAddress[]>('GET', '/api/customers/me/addresses')\n },\n addAddress(address: NewAddress) {\n return fetchClient.request<CustomerAddress>('POST', '/api/customers/me/addresses', address)\n },\n async removeAddress(id: string) {\n await fetchClient.request<{ ok: boolean }>(\n 'DELETE',\n `/api/customers/me/addresses/${encodeURIComponent(id)}`,\n )\n },\n async listOrders(params?: { cursor?: string }): Promise<OrderPage> {\n const qs =\n params?.cursor !== undefined ? `?cursor=${encodeURIComponent(params.cursor)}` : ''\n const { data, meta } = await fetchClient.requestWithMeta<Order[]>('GET', `/api/orders${qs}`)\n const nextCursor = typeof meta.nextCursor === 'string' ? meta.nextCursor : null\n return { items: data ?? [], nextCursor }\n },\n getOrder(orderNumber: string, options: { key?: string } = {}) {\n const { key } = options\n return fetchClient.request<ShopperOrder>(\n 'GET',\n `/api/orders/${encodeURIComponent(orderNumber)}`,\n undefined,\n key === undefined ? {} : { headers: { [ORDER_KEY_HEADER]: key } },\n )\n },\n },\n\n recentlyViewed: {\n async record(productId: string) {\n await fetchClient.request<void>('POST', '/api/recently-viewed', { productId })\n },\n list() {\n return fetchClient.request<{ items: DenormalisedProduct[] }>('GET', '/api/recently-viewed')\n },\n },\n\n reviews: {\n getForProduct(productId: string, params?: { limit?: number; cursor?: string }) {\n const search = new URLSearchParams()\n if (params?.limit !== undefined) search.set('limit', String(params.limit))\n if (params?.cursor !== undefined) search.set('cursor', params.cursor)\n const qs = search.toString()\n return fetchClient.request<ReviewsResult>(\n 'GET',\n `/api/products/${encodeURIComponent(productId)}/reviews${qs ? `?${qs}` : ''}`,\n )\n },\n submit(review: { productId: string; rating: number; title: string; body: string }) {\n return fetchClient.request<ReviewResult>('POST', '/api/reviews', review)\n },\n },\n\n alerts: {\n subscribe(request: { email: string; variantId: string; kind: AlertKind }) {\n return fetchClient.request<{ status: 'pending' }>('POST', '/api/alerts/subscribe', request)\n },\n },\n }\n}\n","export interface TokenManagerOptions {\n storage?: 'memory' | 'localStorage'\n storageKey?: string\n}\n\nexport interface TokenManager {\n getAccessToken(): string | null\n setTokens(accessToken: string, expiresIn: number): void\n clear(): void\n scheduleRefresh(refreshFn: () => Promise<{ accessToken: string; expiresIn: number }>): void\n destroy(): void\n}\n\nconst DEFAULT_STORAGE_KEY = 'nymbal.auth.accessToken'\n\nexport function createTokenManager(options?: TokenManagerOptions): TokenManager {\n const storageMode = options?.storage ?? 'memory'\n const storageKey = options?.storageKey ?? DEFAULT_STORAGE_KEY\n\n let memoryToken: string | null = null\n let refreshTimer: ReturnType<typeof setTimeout> | null = null\n let refreshFn: (() => Promise<{ accessToken: string; expiresIn: number }>) | null = null\n\n function getAccessToken(): string | null {\n if (storageMode === 'localStorage' && typeof globalThis.localStorage !== 'undefined') {\n return globalThis.localStorage.getItem(storageKey)\n }\n return memoryToken\n }\n\n function setAccessToken(token: string | null): void {\n memoryToken = token\n if (storageMode === 'localStorage' && typeof globalThis.localStorage !== 'undefined') {\n if (token) {\n globalThis.localStorage.setItem(storageKey, token)\n } else {\n globalThis.localStorage.removeItem(storageKey)\n }\n }\n }\n\n function setTokens(accessToken: string, expiresIn: number): void {\n setAccessToken(accessToken)\n scheduleAutoRefresh(expiresIn)\n }\n\n function clear(): void {\n setAccessToken(null)\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer)\n refreshTimer = null\n }\n }\n\n function scheduleAutoRefresh(expiresIn: number): void {\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer)\n }\n const delayMs = Math.max(1000, expiresIn * 0.8 * 1000)\n refreshTimer = setTimeout(async () => {\n if (!refreshFn) return\n try {\n const result = await refreshFn()\n setTokens(result.accessToken, result.expiresIn)\n } catch (err) {\n console.error('[TokenManager] auto-refresh failed, clearing session', err)\n clear()\n }\n }, delayMs)\n }\n\n function scheduleRefresh(\n fn: () => Promise<{ accessToken: string; expiresIn: number }>,\n ): void {\n refreshFn = fn\n }\n\n function destroy(): void {\n clear()\n refreshFn = null\n }\n\n return { getAccessToken, setTokens, clear, scheduleRefresh, destroy }\n}\n","export type Listener = () => void\n\nexport interface Store<TState> {\n getState(): TState\n setState(partial: Partial<TState> | ((prev: TState) => Partial<TState>)): void\n subscribe(listener: Listener): () => void\n destroy(): void\n}\n\nexport function createStore<TState extends object>(\n initialState: TState,\n): Store<TState> {\n let state = initialState\n const listeners = new Set<Listener>()\n\n function getState(): TState {\n return state\n }\n\n function setState(partial: Partial<TState> | ((prev: TState) => Partial<TState>)): void {\n const next = typeof partial === 'function' ? partial(state) : partial\n state = { ...state, ...next }\n for (const listener of listeners) {\n listener()\n }\n }\n\n function subscribe(listener: Listener): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n }\n\n function destroy(): void {\n listeners.clear()\n }\n\n return { getState, setState, subscribe, destroy }\n}\n","import type { CartItem } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { CartState } from '../types.js'\nimport { createStore } from './create-store.js'\n\nfunction deriveItemCount(items: CartItem[]): number {\n let count = 0\n for (const item of items) {\n count += item.qty\n }\n return count\n}\n\nconst INITIAL_STATE: CartState = {\n items: [],\n subtotalMinor: 0,\n currency: 'USD',\n itemCount: 0,\n loading: false,\n error: null,\n}\n\nexport interface CartStore {\n getState(): CartState\n subscribe(listener: () => void): () => void\n addItem(variantId: string, qty?: number): Promise<void>\n removeItem(variantId: string): Promise<void>\n updateQuantity(variantId: string, qty: number): Promise<void>\n clear(): Promise<void>\n load(): Promise<void>\n destroy(): void\n}\n\nexport function createCartStore(adapter: CommerceAdapter): CartStore {\n const store = createStore<CartState>(INITIAL_STATE)\n\n async function load(): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.get()\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function addItem(variantId: string, qty = 1): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.addItem(variantId, qty)\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function removeItem(variantId: string): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.removeItem(variantId)\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function updateQuantity(variantId: string, qty: number): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const cart = await adapter.cart.updateQuantity(variantId, qty)\n store.setState({\n items: cart.items,\n subtotalMinor: cart.subtotalMinor,\n currency: cart.currency,\n itemCount: deriveItemCount(cart.items),\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function clear(): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n await adapter.cart.clear()\n store.setState({\n items: [],\n subtotalMinor: 0,\n itemCount: 0,\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n addItem,\n removeItem,\n updateQuantity,\n clear,\n load,\n destroy: store.destroy,\n }\n}\n","import type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { ProductState, DenormalisedVariant } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: ProductState = {\n product: null,\n selectedVariant: null,\n loading: false,\n error: null,\n}\n\nexport interface ProductStore {\n getState(): ProductState\n subscribe(listener: () => void): () => void\n loadBySlug(slug: string): Promise<void>\n selectVariant(variant: DenormalisedVariant | null): void\n destroy(): void\n}\n\nexport function createProductStore(adapter: CommerceAdapter): ProductStore {\n const store = createStore<ProductState>(INITIAL_STATE)\n\n async function loadBySlug(slug: string): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const product = await adapter.products.getBySlug(slug)\n const firstVariant = product.variants[0] ?? null\n store.setState({\n product,\n selectedVariant: firstVariant,\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n function selectVariant(variant: DenormalisedVariant | null): void {\n store.setState({ selectedVariant: variant })\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n loadBySlug,\n selectVariant,\n destroy: store.destroy,\n }\n}\n","import { DEFAULT_PRODUCT_SORT, type ProductSortKey } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { ProductListState, ProductListParams } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: ProductListState = {\n products: [],\n facets: [],\n filters: {},\n sort: DEFAULT_PRODUCT_SORT,\n pagination: { cursor: null, hasMore: false },\n loading: false,\n error: null,\n}\n\nexport interface ProductListStore {\n getState(): ProductListState\n subscribe(listener: () => void): () => void\n load(params?: ProductListParams): Promise<void>\n loadMore(): Promise<void>\n applyFilter(name: string, value: string | string[]): Promise<void>\n removeFilter(name: string): Promise<void>\n setSort(sort: ProductSortKey): Promise<void>\n destroy(): void\n}\n\nexport function createProductListStore(adapter: CommerceAdapter): ProductListStore {\n const store = createStore<ProductListState>(INITIAL_STATE)\n let lastLimit: number | undefined\n // Only the latest request's answer may reach the state: an older one carries another sort's items and cursor.\n let generation = 0\n\n function buildParams(): ProductListParams {\n const state = store.getState()\n const params: ProductListParams = { sort: state.sort }\n if (lastLimit !== undefined) params.limit = lastLimit\n const category = state.filters['category']\n if (typeof category === 'string') {\n params.category = category\n }\n return params\n }\n\n /** With params, they become the listing's category and sort, so `setSort` and `loadMore` keep them. */\n async function load(params?: ProductListParams): Promise<void> {\n if (params !== undefined) {\n if (params.limit !== undefined) lastLimit = params.limit\n const filters = { ...store.getState().filters }\n if (params.category !== undefined) filters['category'] = params.category\n else delete filters['category']\n // Loading from this update on: an update that is not loading is a settled answer, which a server-rendered\n // listing gives its cards way to.\n store.setState({ filters, sort: params.sort ?? DEFAULT_PRODUCT_SORT, loading: true })\n }\n const request = buildParams()\n if (params?.cursor !== undefined) request.cursor = params.cursor\n const current = ++generation\n store.setState({ loading: true })\n try {\n const result = await adapter.products.list(request)\n if (current !== generation) return\n store.setState({\n products: result.items,\n facets: result.facets ?? store.getState().facets,\n pagination: { cursor: result.nextCursor, hasMore: result.nextCursor !== null },\n loading: false,\n error: null,\n })\n } catch (err) {\n if (current !== generation) return\n console.error('[ProductListStore] load failed', err)\n store.setState({ loading: false, error: err instanceof Error ? err.message : String(err) })\n }\n }\n\n async function loadMore(): Promise<void> {\n const state = store.getState()\n if (!state.pagination.hasMore || state.loading) return\n const current = ++generation\n store.setState({ loading: true })\n try {\n const params = buildParams()\n if (state.pagination.cursor !== null) {\n params.cursor = state.pagination.cursor\n }\n const result = await adapter.products.list(params)\n if (current !== generation) return\n store.setState({\n products: [...state.products, ...result.items],\n pagination: { cursor: result.nextCursor, hasMore: result.nextCursor !== null },\n loading: false,\n error: null,\n })\n } catch (err) {\n if (current !== generation) return\n console.error('[ProductListStore] loadMore failed', err)\n store.setState({ loading: false, error: err instanceof Error ? err.message : String(err) })\n }\n }\n\n async function applyFilter(name: string, value: string | string[]): Promise<void> {\n const filters = { ...store.getState().filters, [name]: value }\n store.setState({ filters })\n await load()\n }\n\n async function removeFilter(name: string): Promise<void> {\n const filters = { ...store.getState().filters }\n delete filters[name]\n store.setState({ filters })\n await load()\n }\n\n async function setSort(sort: ProductSortKey): Promise<void> {\n store.setState({ sort })\n await load()\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n load,\n loadMore,\n applyFilter,\n removeFilter,\n setSort,\n destroy: store.destroy,\n }\n}\n","import type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { SearchState } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: SearchState = {\n query: '',\n category: null,\n results: [],\n total: 0,\n nextCursor: null,\n facets: [],\n loading: false,\n}\n\nexport interface SearchStore {\n getState(): SearchState\n subscribe(listener: () => void): () => void\n /** Page 1 of `query`, in `options.category` (a slug) when given, otherwise in every category. */\n search(query: string, options?: { category?: string | null }): Promise<void>\n /** Appends the next page; a no-op when every match is loaded or a page is loading. */\n loadMore(): Promise<void>\n /** Page 1 of the current query in `category` (a slug), or in every category when null. */\n setCategory(category: string | null): Promise<void>\n clearSearch(): void\n destroy(): void\n}\n\nexport function createSearchStore(adapter: CommerceAdapter): SearchStore {\n const store = createStore<SearchState>(INITIAL_STATE)\n // Each search supersedes the last: an answer for an older one is dropped.\n let generation = 0\n\n async function search(query: string, options?: { category?: string | null }): Promise<void> {\n const run = ++generation\n if (!query.trim()) {\n store.setState({ ...INITIAL_STATE })\n return\n }\n const category = options?.category ?? null\n store.setState({ query, category, loading: true })\n try {\n const result = await (category === null\n ? adapter.products.search(query)\n : adapter.products.search(query, { category }))\n if (run !== generation) return\n store.setState({\n results: result.items,\n total: result.total,\n nextCursor: result.nextCursor,\n facets: result.facets ?? [],\n loading: false,\n })\n } catch (err) {\n if (run !== generation) return\n console.error('[SearchStore] search failed', err)\n store.setState({ loading: false })\n }\n }\n\n async function loadMore(): Promise<void> {\n const { query, category, nextCursor, loading } = store.getState()\n if (nextCursor === null || loading) return\n const run = generation\n store.setState({ loading: true })\n try {\n const result = await adapter.products.search(query, {\n cursor: nextCursor,\n ...(category !== null && { category }),\n })\n if (run !== generation) return\n store.setState({\n results: [...store.getState().results, ...result.items],\n total: result.total,\n nextCursor: result.nextCursor,\n loading: false,\n })\n } catch (err) {\n if (run !== generation) return\n console.error('[SearchStore] load more failed', err)\n store.setState({ loading: false })\n }\n }\n\n function setCategory(category: string | null): Promise<void> {\n return search(store.getState().query, { category })\n }\n\n function clearSearch(): void {\n generation++\n store.setState({ ...INITIAL_STATE })\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n search,\n loadMore,\n setCategory,\n clearSearch,\n destroy: store.destroy,\n }\n}\n","import type { Address } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport { NymbalApiError } from '../adapter/fetch-client.js'\nimport type { CartStore } from './cart-store.js'\nimport type { CheckoutResult, CheckoutState, ShippingMethod } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: CheckoutState = {\n step: 'contact',\n email: '',\n shippingAddress: null,\n billingAddress: null,\n shippingMethod: null,\n paymentStatus: 'idle',\n error: null,\n order: null,\n placedOrderNumber: null,\n placedOrderKey: null,\n}\n\n/**\n * The order a refused resubmit names (409 `checkout.cart_empty` or `checkout.payment_in_progress`), if any, and the key\n * the refusal carries to read it.\n */\nfunction namedOrder(err: unknown): Pick<CheckoutState, 'placedOrderNumber' | 'placedOrderKey'> {\n const context = err instanceof NymbalApiError ? err.context : undefined\n const orderNumber = context?.['orderNumber']\n const orderKey = context?.['orderKey']\n return typeof orderNumber === 'string'\n ? {\n placedOrderNumber: orderNumber,\n placedOrderKey: typeof orderKey === 'string' ? orderKey : null,\n }\n : { placedOrderNumber: null, placedOrderKey: null }\n}\n\nexport interface CheckoutStore {\n getState(): CheckoutState\n subscribe(listener: () => void): () => void\n setEmail(email: string): void\n setShippingAddress(address: Address): void\n setBillingAddress(address: Address): void\n setShippingMethod(method: ShippingMethod): void\n /** Places the order; resolves to the server's result, or null when there is none. */\n submitPayment(): Promise<CheckoutResult | null>\n /** The provider confirmed the payment on the client (Stripe's `confirmCardPayment`). */\n markConfirmed(): void\n reset(): void\n destroy(): void\n}\n\n/**\n * `cart`, when given, is loaded again once the server has answered a submit: placing an order changes the cart on the\n * server (emptied when confirmed, kept while awaiting payment), and whatever renders the cart store must show that.\n */\nexport function createCheckoutStore(adapter: CommerceAdapter, cart?: CartStore): CheckoutStore {\n const store = createStore<CheckoutState>(INITIAL_STATE)\n\n function setEmail(email: string): void {\n store.setState({ email, step: 'shipping' })\n }\n\n function setShippingAddress(address: Address): void {\n store.setState({ shippingAddress: address })\n }\n\n function setBillingAddress(address: Address): void {\n store.setState({ billingAddress: address })\n }\n\n function setShippingMethod(method: ShippingMethod): void {\n store.setState({ shippingMethod: method, step: 'payment' })\n }\n\n async function submitPayment(): Promise<CheckoutResult | null> {\n const state = store.getState()\n if (!state.shippingAddress || !state.billingAddress) {\n store.setState({ error: 'Shipping and billing addresses are required' })\n return null\n }\n store.setState({\n paymentStatus: 'processing',\n error: null,\n placedOrderNumber: null,\n placedOrderKey: null,\n })\n try {\n const result = await adapter.checkout.create({\n email: state.email,\n billingAddress: state.billingAddress,\n shippingAddress: state.shippingAddress,\n })\n const { status, reason } = result.payment\n store.setState({\n paymentStatus: status,\n order: {\n orderId: result.orderId,\n orderNumber: result.orderNumber,\n paymentIntent: result.paymentIntent,\n },\n error:\n status === 'failed'\n ? `Your payment did not go through${reason ? ` (${reason})` : ''}. Please try again.`\n : null,\n ...(status === 'succeeded' && { step: 'confirmation' as const }),\n })\n await cart?.load()\n return result\n } catch (err) {\n const placed = namedOrder(err)\n store.setState({\n paymentStatus: 'failed',\n error: err instanceof Error ? err.message : String(err),\n ...placed,\n })\n // A refusal naming an order: the cart became (or is becoming) that order on the server.\n if (placed.placedOrderNumber !== null) await cart?.load()\n return null\n }\n }\n\n function markConfirmed(): void {\n store.setState({ paymentStatus: 'succeeded', step: 'confirmation' })\n }\n\n function reset(): void {\n store.setState(INITIAL_STATE)\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n setEmail,\n setShippingAddress,\n setBillingAddress,\n setShippingMethod,\n submitPayment,\n markConfirmed,\n reset,\n destroy: store.destroy,\n }\n}\n","import type { Customer } from '@nymbalhq/types'\nimport type { CommerceAdapter } from '../adapter/commerce-adapter.js'\nimport type { TokenManager } from '../auth/token-manager.js'\nimport type { AuthState, RegisterParams } from '../types.js'\nimport { createStore } from './create-store.js'\n\nconst INITIAL_STATE: AuthState = {\n customer: null,\n isAuthenticated: false,\n loading: false,\n error: null,\n}\n\nexport interface AuthStore {\n getState(): AuthState\n subscribe(listener: () => void): () => void\n login(email: string, password: string): Promise<void>\n register(params: RegisterParams): Promise<void>\n logout(): Promise<void>\n refreshToken(): Promise<void>\n updateProfile(updates: Partial<Pick<Customer, 'firstName' | 'lastName' | 'phone'>>): Promise<void>\n loadProfile(): Promise<void>\n destroy(): void\n}\n\nexport function createAuthStore(\n adapter: CommerceAdapter,\n tokenManager: TokenManager,\n): AuthStore {\n const store = createStore<AuthState>(INITIAL_STATE)\n\n async function login(email: string, password: string): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const result = await adapter.customers.login(email, password)\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n store.setState({\n customer: result.customer,\n isAuthenticated: true,\n loading: false,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n store.setState({ loading: false, error: message })\n throw err\n }\n }\n\n async function register(params: RegisterParams): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const result = await adapter.customers.register(params)\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n store.setState({\n customer: result.customer,\n isAuthenticated: true,\n loading: false,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n store.setState({ loading: false, error: message })\n throw err\n }\n }\n\n async function logout(): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n await adapter.customers.logout()\n tokenManager.clear()\n store.setState({\n customer: null,\n isAuthenticated: false,\n loading: false,\n })\n } catch (err) {\n tokenManager.clear()\n store.setState({\n customer: null,\n isAuthenticated: false,\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function refreshToken(): Promise<void> {\n try {\n const result = await adapter.customers.refresh()\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n } catch (err) {\n console.error('[AuthStore] token refresh failed, logging out', err)\n tokenManager.clear()\n store.setState({\n customer: null,\n isAuthenticated: false,\n })\n }\n }\n\n async function updateProfile(\n updates: Partial<Pick<Customer, 'firstName' | 'lastName' | 'phone'>>,\n ): Promise<void> {\n store.setState({ loading: true, error: null })\n try {\n const customer = await adapter.customers.updateProfile(updates)\n store.setState({ customer, loading: false })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n async function loadProfile(): Promise<void> {\n if (!tokenManager.getAccessToken()) return\n store.setState({ loading: true, error: null })\n try {\n const customer = await adapter.customers.getProfile()\n store.setState({\n customer,\n isAuthenticated: true,\n loading: false,\n })\n } catch (err) {\n store.setState({\n loading: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return {\n getState: store.getState,\n subscribe: store.subscribe,\n login,\n register,\n logout,\n refreshToken,\n updateProfile,\n loadProfile,\n destroy: store.destroy,\n }\n}\n","import type { CommerceAdapter } from './adapter/commerce-adapter.js'\nimport { FetchClient } from './adapter/fetch-client.js'\nimport { createNymbalApiAdapter } from './adapter/nymbal-api-adapter.js'\nimport { createTokenManager } from './auth/token-manager.js'\nimport { createCartStore, type CartStore } from './store/cart-store.js'\nimport { createProductStore, type ProductStore } from './store/product-store.js'\nimport { createProductListStore, type ProductListStore } from './store/product-list-store.js'\nimport { createSearchStore, type SearchStore } from './store/search-store.js'\nimport { createCheckoutStore, type CheckoutStore } from './store/checkout-store.js'\nimport { createAuthStore, type AuthStore } from './store/auth-store.js'\nimport type { CustomerAddress, ShopperOrder, StoreCapabilities } from '@nymbalhq/types'\nimport type { DenormalisedProduct, NewAddress, OrderPage } from './types.js'\n\nexport interface NymbalClientOptions {\n baseUrl: string\n adapter?: CommerceAdapter\n tokenStorage?: 'memory' | 'localStorage'\n credentials?: RequestCredentials\n getCartToken?: () => string | null\n}\n\n/** The signed-in customer's own account; every call sends the session's bearer token. */\nexport interface CustomerAccount {\n addresses: {\n list(): Promise<CustomerAddress[]>\n create(address: NewAddress): Promise<CustomerAddress>\n remove(id: string): Promise<void>\n }\n orders: {\n list(opts?: { cursor?: string }): Promise<OrderPage>\n /** `key`, the order's key from its checkout, reads it with no session; without one, only its owner can. */\n get(orderNumber: string, options?: { key?: string }): Promise<ShopperOrder>\n }\n}\n\n/** The store's capabilities report, read once per client: what it can do does not change while it runs. */\nexport interface StoreCapabilitiesReader {\n get(): Promise<StoreCapabilities>\n}\n\n/** The shopper's recently viewed products, kept by the store under the signed-in customer or the browser's visitor. */\nexport interface RecentlyViewed {\n /** Records a view of the product; the store ignores a product that is not active. */\n record(productId: string): Promise<void>\n /** The shopper's active products, newest first. */\n list(): Promise<{ items: DenormalisedProduct[] }>\n}\n\nexport interface NymbalClient {\n capabilities: StoreCapabilitiesReader\n recentlyViewed: RecentlyViewed\n cart: CartStore\n product: ProductStore\n productList: ProductListStore\n search: SearchStore\n checkout: CheckoutStore\n auth: AuthStore\n customer: CustomerAccount\n adapter: CommerceAdapter\n destroy(): void\n}\n\nexport function createNymbalClient(options: NymbalClientOptions): NymbalClient {\n const tokenManager = createTokenManager({\n ...(options.tokenStorage !== undefined && { storage: options.tokenStorage }),\n })\n\n let adapter: CommerceAdapter\n\n if (options.adapter) {\n adapter = options.adapter\n } else {\n const fetchClient = new FetchClient({\n baseUrl: options.baseUrl,\n ...(options.credentials !== undefined && { credentials: options.credentials }),\n getAccessToken: () => tokenManager.getAccessToken(),\n ...(options.getCartToken !== undefined && { getCartToken: options.getCartToken }),\n onUnauthorized: async () => {\n try {\n const result = await adapter.customers.refresh()\n tokenManager.setTokens(result.accessToken, result.expiresIn)\n } catch (err) {\n // Token refresh failure is expected when the user session has expired.\n console.warn('[NymbalClient] token refresh on unauthorized failed', err)\n tokenManager.clear()\n }\n },\n })\n adapter = createNymbalApiAdapter(fetchClient)\n }\n\n const cart = createCartStore(adapter)\n const product = createProductStore(adapter)\n const productList = createProductListStore(adapter)\n const search = createSearchStore(adapter)\n const checkout = createCheckoutStore(adapter, cart)\n const auth = createAuthStore(adapter, tokenManager)\n\n const customer: CustomerAccount = {\n addresses: {\n list: () => adapter.customers.listAddresses(),\n create: (address) => adapter.customers.addAddress(address),\n remove: (id) => adapter.customers.removeAddress(id),\n },\n orders: {\n list: (opts) => adapter.customers.listOrders(opts),\n get: (orderNumber, options) => adapter.customers.getOrder(orderNumber, options),\n },\n }\n\n // A failed read is not kept, so the next get() asks again.\n let report: Promise<StoreCapabilities> | null = null\n const capabilities: StoreCapabilitiesReader = {\n get() {\n if (report === null) {\n const reader = adapter.capabilities\n report =\n reader === undefined\n ? Promise.reject(new Error('This client’s adapter cannot read the store capabilities.'))\n : reader.get()\n report.catch(() => {\n report = null\n })\n }\n return report\n },\n }\n\n const recentlyViewedOf = (): NonNullable<CommerceAdapter['recentlyViewed']> => {\n const reader = adapter.recentlyViewed\n if (reader === undefined) {\n throw new Error('This client’s adapter cannot record or list recently viewed products.')\n }\n return reader\n }\n const recentlyViewed: RecentlyViewed = {\n async record(productId) {\n await recentlyViewedOf().record(productId)\n },\n async list() {\n return recentlyViewedOf().list()\n },\n }\n\n tokenManager.scheduleRefresh(() => adapter.customers.refresh())\n\n function destroy(): void {\n cart.destroy()\n product.destroy()\n productList.destroy()\n search.destroy()\n checkout.destroy()\n auth.destroy()\n tokenManager.destroy()\n }\n\n return {\n capabilities,\n recentlyViewed,\n cart,\n product,\n productList,\n search,\n checkout,\n auth,\n customer,\n adapter,\n destroy,\n }\n}\n","import type { Address } from '@nymbalhq/types'\n\n/** What a checkout already knows about the shopper, which a driver may hand its processor with the payment. */\nexport interface PaymentConfirmContext {\n email?: string\n billing?: Address\n}\n\n/** What a payment driver's `confirm` answers: paid now, accepted without a payment yet, or refused with a reason. */\nexport type PaymentConfirmation = { ok: true; confirmed: boolean } | { ok: false; error: string }\n\n/**\n * The browser half of a payments adapter, named by the `driver` of GET /api/capabilities' payments client. `mount`\n * renders whatever the shopper pays with inside `el`; `confirm` completes a payment the API left `requires_action`,\n * with the shopper's email and billing address when the checkout has them.\n */\nexport interface PaymentDriver {\n mount(el: HTMLElement, options: Record<string, string>): Promise<void> | void\n confirm(clientSecret: string, context?: PaymentConfirmContext): Promise<PaymentConfirmation>\n}\n\n// On globalThis, like the registered client: a page that loads two copies of the SDK still has one registry.\nconst DRIVERS_KEY = Symbol.for('nymbal.paymentDrivers')\n\nfunction drivers(): Map<string, PaymentDriver> {\n const holder = globalThis as Record<symbol, Map<string, PaymentDriver> | undefined>\n holder[DRIVERS_KEY] ??= new Map()\n return holder[DRIVERS_KEY]\n}\n\n/** Registers `driver` under `name`, replacing any driver of that name. */\nexport function registerPaymentDriver(name: string, driver: PaymentDriver): void {\n drivers().set(name, driver)\n}\n\nexport function getPaymentDriver(name: string): PaymentDriver | undefined {\n return drivers().get(name)\n}\n"],"mappings":"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","names":["INITIAL_STATE","INITIAL_STATE","INITIAL_STATE","INITIAL_STATE","INITIAL_STATE","options"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nymbalhq/sdk",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Framework-agnostic commerce SDK with pub/sub stores and adapter interface",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,7 +27,7 @@
27
27
  "dist"
28
28
  ],
29
29
  "dependencies": {
30
- "@nymbalhq/types": "1.2.0"
30
+ "@nymbalhq/types": "1.4.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@typescript/native": "npm:typescript@^7.0.2",