@nymbalhq/sdk 1.4.0 → 1.6.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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -0
  3. package/dist/chunk-2EEZZXZX.js +601 -0
  4. package/dist/chunk-2EEZZXZX.js.map +1 -0
  5. package/dist/chunk-4GP43MKT.js +19 -0
  6. package/dist/chunk-4GP43MKT.js.map +1 -0
  7. package/dist/chunk-7LQGOJIT.js +133 -0
  8. package/dist/chunk-7LQGOJIT.js.map +1 -0
  9. package/dist/chunk-CJVA46FR.js +52 -0
  10. package/dist/chunk-CJVA46FR.js.map +1 -0
  11. package/dist/chunk-PDZKR65O.js +148 -0
  12. package/dist/chunk-PDZKR65O.js.map +1 -0
  13. package/dist/chunk-U6QF2DRY.js +30 -0
  14. package/dist/chunk-U6QF2DRY.js.map +1 -0
  15. package/dist/chunk-VYX72KGY.js +116 -0
  16. package/dist/chunk-VYX72KGY.js.map +1 -0
  17. package/dist/chunk-XS7RNJSY.js +118 -0
  18. package/dist/chunk-XS7RNJSY.js.map +1 -0
  19. package/dist/chunk-YHXC7DS5.js +92 -0
  20. package/dist/chunk-YHXC7DS5.js.map +1 -0
  21. package/dist/core-BviXjOsX.d.ts +560 -0
  22. package/dist/core.d.ts +2 -0
  23. package/dist/core.js +21 -0
  24. package/dist/core.js.map +1 -0
  25. package/dist/index.d.ts +4 -483
  26. package/dist/index.js +33 -1048
  27. package/dist/index.js.map +1 -1
  28. package/dist/ns/auth.d.ts +2 -0
  29. package/dist/ns/auth.js +4 -0
  30. package/dist/ns/auth.js.map +1 -0
  31. package/dist/ns/cart.d.ts +2 -0
  32. package/dist/ns/cart.js +4 -0
  33. package/dist/ns/cart.js.map +1 -0
  34. package/dist/ns/checkout.d.ts +2 -0
  35. package/dist/ns/checkout.js +5 -0
  36. package/dist/ns/checkout.js.map +1 -0
  37. package/dist/ns/product-list.d.ts +2 -0
  38. package/dist/ns/product-list.js +4 -0
  39. package/dist/ns/product-list.js.map +1 -0
  40. package/dist/ns/product.d.ts +2 -0
  41. package/dist/ns/product.js +4 -0
  42. package/dist/ns/product.js.map +1 -0
  43. package/dist/ns/search.d.ts +2 -0
  44. package/dist/ns/search.js +4 -0
  45. package/dist/ns/search.js.map +1 -0
  46. package/package.json +17 -2
@@ -0,0 +1,116 @@
1
+ import {
2
+ createStore
3
+ } from "./chunk-U6QF2DRY.js";
4
+ import {
5
+ NymbalApiError,
6
+ defineNamespace
7
+ } from "./chunk-2EEZZXZX.js";
8
+
9
+ // src/store/checkout-store.ts
10
+ var INITIAL_STATE = {
11
+ step: "contact",
12
+ email: "",
13
+ shippingAddress: null,
14
+ billingAddress: null,
15
+ shippingMethod: null,
16
+ paymentStatus: "idle",
17
+ error: null,
18
+ errorCode: null,
19
+ order: null,
20
+ placedOrderNumber: null,
21
+ placedOrderKey: null
22
+ };
23
+ function namedOrder(err) {
24
+ const context = err instanceof NymbalApiError ? err.context : void 0;
25
+ const orderNumber = context?.["orderNumber"];
26
+ const orderKey = context?.["orderKey"];
27
+ return typeof orderNumber === "string" ? {
28
+ placedOrderNumber: orderNumber,
29
+ placedOrderKey: typeof orderKey === "string" ? orderKey : null
30
+ } : { placedOrderNumber: null, placedOrderKey: null };
31
+ }
32
+ function createCheckoutStore(adapter, cart) {
33
+ const store = createStore(INITIAL_STATE);
34
+ function setEmail(email) {
35
+ store.setState({ email, step: "shipping" });
36
+ }
37
+ function setShippingAddress(address) {
38
+ store.setState({ shippingAddress: address });
39
+ }
40
+ function setBillingAddress(address) {
41
+ store.setState({ billingAddress: address });
42
+ }
43
+ function setShippingMethod(method) {
44
+ store.setState({ shippingMethod: method, step: "payment" });
45
+ }
46
+ async function submitPayment() {
47
+ const state = store.getState();
48
+ if (!state.shippingAddress || !state.billingAddress) {
49
+ store.setState({ error: "Shipping and billing addresses are required", errorCode: null });
50
+ return null;
51
+ }
52
+ store.setState({
53
+ paymentStatus: "processing",
54
+ error: null,
55
+ errorCode: null,
56
+ placedOrderNumber: null,
57
+ placedOrderKey: null
58
+ });
59
+ try {
60
+ const result = await adapter.checkout.create({
61
+ email: state.email,
62
+ billingAddress: state.billingAddress,
63
+ shippingAddress: state.shippingAddress
64
+ });
65
+ const { status, reason } = result.payment;
66
+ store.setState({
67
+ paymentStatus: status,
68
+ order: {
69
+ orderId: result.orderId,
70
+ orderNumber: result.orderNumber,
71
+ paymentIntent: result.paymentIntent
72
+ },
73
+ error: status === "failed" ? `Your payment did not go through${reason ? ` (${reason})` : ""}. Please try again.` : null,
74
+ ...status === "succeeded" && { step: "confirmation" }
75
+ });
76
+ await cart?.load();
77
+ return result;
78
+ } catch (err) {
79
+ const placed = namedOrder(err);
80
+ store.setState({
81
+ paymentStatus: "failed",
82
+ error: err instanceof Error ? err.message : String(err),
83
+ errorCode: err instanceof NymbalApiError ? err.code : null,
84
+ ...placed
85
+ });
86
+ if (placed.placedOrderNumber !== null) await cart?.load();
87
+ return null;
88
+ }
89
+ }
90
+ function markConfirmed() {
91
+ store.setState({ paymentStatus: "succeeded", step: "confirmation" });
92
+ }
93
+ function reset() {
94
+ store.setState(INITIAL_STATE);
95
+ }
96
+ return {
97
+ getState: store.getState,
98
+ subscribe: store.subscribe,
99
+ setEmail,
100
+ setShippingAddress,
101
+ setBillingAddress,
102
+ setShippingMethod,
103
+ submitPayment,
104
+ markConfirmed,
105
+ reset,
106
+ destroy: store.destroy
107
+ };
108
+ }
109
+
110
+ // src/ns/checkout.ts
111
+ defineNamespace("checkout", ({ adapter, client }) => createCheckoutStore(adapter, client.cart));
112
+
113
+ export {
114
+ createCheckoutStore
115
+ };
116
+ //# sourceMappingURL=chunk-VYX72KGY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/store/checkout-store.ts","../src/ns/checkout.ts"],"sourcesContent":["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 errorCode: 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', errorCode: null })\n return null\n }\n store.setState({\n paymentStatus: 'processing',\n error: null,\n errorCode: 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 errorCode: err instanceof NymbalApiError ? err.code : null,\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 './cart.js'\nimport { defineNamespace } from '../client.js'\nimport { createCheckoutStore } from '../store/checkout-store.js'\n\n// The checkout places its order on the client's own cart, so one cart serves both.\ndefineNamespace('checkout', ({ adapter, client }) => createCheckoutStore(adapter, client.cart))\n"],"mappings":"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","names":[]}
@@ -0,0 +1,118 @@
1
+ import {
2
+ createStore
3
+ } from "./chunk-U6QF2DRY.js";
4
+ import {
5
+ defineNamespace
6
+ } from "./chunk-2EEZZXZX.js";
7
+
8
+ // src/store/product-list-store.ts
9
+ import { DEFAULT_PRODUCT_SORT } from "@nymbalhq/types";
10
+ var INITIAL_STATE = {
11
+ products: [],
12
+ facets: [],
13
+ filters: {},
14
+ sort: DEFAULT_PRODUCT_SORT,
15
+ pagination: { cursor: null, hasMore: false },
16
+ loading: false,
17
+ error: null
18
+ };
19
+ function createProductListStore(adapter) {
20
+ const store = createStore(INITIAL_STATE);
21
+ let lastLimit;
22
+ let generation = 0;
23
+ function buildParams() {
24
+ const state = store.getState();
25
+ const params = { sort: state.sort };
26
+ if (lastLimit !== void 0) params.limit = lastLimit;
27
+ const category = state.filters["category"];
28
+ if (typeof category === "string") {
29
+ params.category = category;
30
+ }
31
+ return params;
32
+ }
33
+ async function load(params) {
34
+ if (params !== void 0) {
35
+ if (params.limit !== void 0) lastLimit = params.limit;
36
+ const filters = { ...store.getState().filters };
37
+ if (params.category !== void 0) filters["category"] = params.category;
38
+ else delete filters["category"];
39
+ store.setState({ filters, sort: params.sort ?? DEFAULT_PRODUCT_SORT, loading: true });
40
+ }
41
+ const request = buildParams();
42
+ if (params?.cursor !== void 0) request.cursor = params.cursor;
43
+ const current = ++generation;
44
+ store.setState({ loading: true });
45
+ try {
46
+ const result = await adapter.products.list(request);
47
+ if (current !== generation) return;
48
+ store.setState({
49
+ products: result.items,
50
+ facets: result.facets ?? store.getState().facets,
51
+ pagination: { cursor: result.nextCursor, hasMore: result.nextCursor !== null },
52
+ loading: false,
53
+ error: null
54
+ });
55
+ } catch (err) {
56
+ if (current !== generation) return;
57
+ console.error("[ProductListStore] load failed", err);
58
+ store.setState({ loading: false, error: err instanceof Error ? err.message : String(err) });
59
+ }
60
+ }
61
+ async function loadMore() {
62
+ const state = store.getState();
63
+ if (!state.pagination.hasMore || state.loading) return;
64
+ const current = ++generation;
65
+ store.setState({ loading: true });
66
+ try {
67
+ const params = buildParams();
68
+ if (state.pagination.cursor !== null) {
69
+ params.cursor = state.pagination.cursor;
70
+ }
71
+ const result = await adapter.products.list(params);
72
+ if (current !== generation) return;
73
+ store.setState({
74
+ products: [...state.products, ...result.items],
75
+ pagination: { cursor: result.nextCursor, hasMore: result.nextCursor !== null },
76
+ loading: false,
77
+ error: null
78
+ });
79
+ } catch (err) {
80
+ if (current !== generation) return;
81
+ console.error("[ProductListStore] loadMore failed", err);
82
+ store.setState({ loading: false, error: err instanceof Error ? err.message : String(err) });
83
+ }
84
+ }
85
+ async function applyFilter(name, value) {
86
+ const filters = { ...store.getState().filters, [name]: value };
87
+ store.setState({ filters });
88
+ await load();
89
+ }
90
+ async function removeFilter(name) {
91
+ const filters = { ...store.getState().filters };
92
+ delete filters[name];
93
+ store.setState({ filters });
94
+ await load();
95
+ }
96
+ async function setSort(sort) {
97
+ store.setState({ sort });
98
+ await load();
99
+ }
100
+ return {
101
+ getState: store.getState,
102
+ subscribe: store.subscribe,
103
+ load,
104
+ loadMore,
105
+ applyFilter,
106
+ removeFilter,
107
+ setSort,
108
+ destroy: store.destroy
109
+ };
110
+ }
111
+
112
+ // src/ns/product-list.ts
113
+ defineNamespace("productList", ({ adapter }) => createProductListStore(adapter));
114
+
115
+ export {
116
+ createProductListStore
117
+ };
118
+ //# sourceMappingURL=chunk-XS7RNJSY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/store/product-list-store.ts","../src/ns/product-list.ts"],"sourcesContent":["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 { defineNamespace } from '../client.js'\nimport { createProductListStore } from '../store/product-list-store.js'\n\ndefineNamespace('productList', ({ adapter }) => createProductListStore(adapter))\n"],"mappings":"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","names":[]}
@@ -0,0 +1,92 @@
1
+ import {
2
+ createStore
3
+ } from "./chunk-U6QF2DRY.js";
4
+ import {
5
+ defineNamespace
6
+ } from "./chunk-2EEZZXZX.js";
7
+
8
+ // src/store/search-store.ts
9
+ var INITIAL_STATE = {
10
+ query: "",
11
+ category: null,
12
+ results: [],
13
+ total: 0,
14
+ nextCursor: null,
15
+ facets: [],
16
+ loading: false
17
+ };
18
+ function createSearchStore(adapter) {
19
+ const store = createStore(INITIAL_STATE);
20
+ let generation = 0;
21
+ async function search(query, options) {
22
+ const run = ++generation;
23
+ if (!query.trim()) {
24
+ store.setState({ ...INITIAL_STATE });
25
+ return;
26
+ }
27
+ const category = options?.category ?? null;
28
+ store.setState({ query, category, loading: true });
29
+ try {
30
+ const result = await (category === null ? adapter.products.search(query) : adapter.products.search(query, { category }));
31
+ if (run !== generation) return;
32
+ store.setState({
33
+ results: result.items,
34
+ total: result.total,
35
+ nextCursor: result.nextCursor,
36
+ facets: result.facets ?? [],
37
+ loading: false
38
+ });
39
+ } catch (err) {
40
+ if (run !== generation) return;
41
+ console.error("[SearchStore] search failed", err);
42
+ store.setState({ loading: false });
43
+ }
44
+ }
45
+ async function loadMore() {
46
+ const { query, category, nextCursor, loading } = store.getState();
47
+ if (nextCursor === null || loading) return;
48
+ const run = generation;
49
+ store.setState({ loading: true });
50
+ try {
51
+ const result = await adapter.products.search(query, {
52
+ cursor: nextCursor,
53
+ ...category !== null && { category }
54
+ });
55
+ if (run !== generation) return;
56
+ store.setState({
57
+ results: [...store.getState().results, ...result.items],
58
+ total: result.total,
59
+ nextCursor: result.nextCursor,
60
+ loading: false
61
+ });
62
+ } catch (err) {
63
+ if (run !== generation) return;
64
+ console.error("[SearchStore] load more failed", err);
65
+ store.setState({ loading: false });
66
+ }
67
+ }
68
+ function setCategory(category) {
69
+ return search(store.getState().query, { category });
70
+ }
71
+ function clearSearch() {
72
+ generation++;
73
+ store.setState({ ...INITIAL_STATE });
74
+ }
75
+ return {
76
+ getState: store.getState,
77
+ subscribe: store.subscribe,
78
+ search,
79
+ loadMore,
80
+ setCategory,
81
+ clearSearch,
82
+ destroy: store.destroy
83
+ };
84
+ }
85
+
86
+ // src/ns/search.ts
87
+ defineNamespace("search", ({ adapter }) => createSearchStore(adapter));
88
+
89
+ export {
90
+ createSearchStore
91
+ };
92
+ //# sourceMappingURL=chunk-YHXC7DS5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/store/search-store.ts","../src/ns/search.ts"],"sourcesContent":["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 { defineNamespace } from '../client.js'\nimport { createSearchStore } from '../store/search-store.js'\n\ndefineNamespace('search', ({ adapter }) => createSearchStore(adapter))\n"],"mappings":";;;;;;;;AAIA,IAAM,gBAA6B;AAAA,EACjC,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS,CAAC;AAAA,EACV,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,QAAQ,CAAC;AAAA,EACT,SAAS;AACX;AAeO,SAAS,kBAAkB,SAAuC;AACvE,QAAM,QAAQ,YAAyB,aAAa;AAEpD,MAAI,aAAa;AAEjB,iBAAe,OAAO,OAAe,SAAuD;AAC1F,UAAM,MAAM,EAAE;AACd,QAAI,CAAC,MAAM,KAAK,GAAG;AACjB,YAAM,SAAS,EAAE,GAAG,cAAc,CAAC;AACnC;AAAA,IACF;AACA,UAAM,WAAW,SAAS,YAAY;AACtC,UAAM,SAAS,EAAE,OAAO,UAAU,SAAS,KAAK,CAAC;AACjD,QAAI;AACF,YAAM,SAAS,OAAO,aAAa,OAC/B,QAAQ,SAAS,OAAO,KAAK,IAC7B,QAAQ,SAAS,OAAO,OAAO,EAAE,SAAS,CAAC;AAC/C,UAAI,QAAQ,WAAY;AACxB,YAAM,SAAS;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,OAAO,OAAO;AAAA,QACd,YAAY,OAAO;AAAA,QACnB,QAAQ,OAAO,UAAU,CAAC;AAAA,QAC1B,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,QAAQ,WAAY;AACxB,cAAQ,MAAM,+BAA+B,GAAG;AAChD,YAAM,SAAS,EAAE,SAAS,MAAM,CAAC;AAAA,IACnC;AAAA,EACF;AAEA,iBAAe,WAA0B;AACvC,UAAM,EAAE,OAAO,UAAU,YAAY,QAAQ,IAAI,MAAM,SAAS;AAChE,QAAI,eAAe,QAAQ,QAAS;AACpC,UAAM,MAAM;AACZ,UAAM,SAAS,EAAE,SAAS,KAAK,CAAC;AAChC,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,SAAS,OAAO,OAAO;AAAA,QAClD,QAAQ;AAAA,QACR,GAAI,aAAa,QAAQ,EAAE,SAAS;AAAA,MACtC,CAAC;AACD,UAAI,QAAQ,WAAY;AACxB,YAAM,SAAS;AAAA,QACb,SAAS,CAAC,GAAG,MAAM,SAAS,EAAE,SAAS,GAAG,OAAO,KAAK;AAAA,QACtD,OAAO,OAAO;AAAA,QACd,YAAY,OAAO;AAAA,QACnB,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,QAAQ,WAAY;AACxB,cAAQ,MAAM,kCAAkC,GAAG;AACnD,YAAM,SAAS,EAAE,SAAS,MAAM,CAAC;AAAA,IACnC;AAAA,EACF;AAEA,WAAS,YAAY,UAAwC;AAC3D,WAAO,OAAO,MAAM,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC;AAAA,EACpD;AAEA,WAAS,cAAoB;AAC3B;AACA,UAAM,SAAS,EAAE,GAAG,cAAc,CAAC;AAAA,EACrC;AAEA,SAAO;AAAA,IACL,UAAU,MAAM;AAAA,IAChB,WAAW,MAAM;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,MAAM;AAAA,EACjB;AACF;;;AClGA,gBAAgB,UAAU,CAAC,EAAE,QAAQ,MAAM,kBAAkB,OAAO,CAAC;","names":[]}