@juo/blocks 1.12.1 → 1.13.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/{ExtensionRoot-9XfhG8YM.js → ExtensionRoot-peABLAZZ.js} +15 -3
  2. package/dist/block-B6s9jL7l.js +966 -0
  3. package/dist/block.d.ts +50 -0
  4. package/dist/block.d.ts.map +1 -1
  5. package/dist/block.devtools.test.d.ts +2 -0
  6. package/dist/block.devtools.test.d.ts.map +1 -0
  7. package/dist/{bridge-w5KQ-czl.js → bridge-r7Yk8fjY.js} +34 -25
  8. package/dist/context.d.ts.map +1 -1
  9. package/dist/context.devtools.test.d.ts +2 -0
  10. package/dist/context.devtools.test.d.ts.map +1 -0
  11. package/dist/core.js +1910 -362
  12. package/dist/devtools/env.d.ts +3 -0
  13. package/dist/devtools/env.d.ts.map +1 -0
  14. package/dist/devtools/hook.d.ts +35 -0
  15. package/dist/devtools/hook.d.ts.map +1 -0
  16. package/dist/devtools/index.d.ts +4 -0
  17. package/dist/devtools/index.d.ts.map +1 -0
  18. package/dist/devtools/protocol.d.ts +91 -0
  19. package/dist/devtools/protocol.d.ts.map +1 -0
  20. package/dist/devtools.js +44 -0
  21. package/dist/editor/bridge.d.ts +7 -0
  22. package/dist/editor/bridge.d.ts.map +1 -1
  23. package/dist/editor/components.d.ts.map +1 -1
  24. package/dist/editor/main.d.ts +2 -1
  25. package/dist/editor/main.d.ts.map +1 -1
  26. package/dist/editor/messages.d.ts +13 -2
  27. package/dist/editor/messages.d.ts.map +1 -1
  28. package/dist/editor/messages.test.d.ts +2 -0
  29. package/dist/editor/messages.test.d.ts.map +1 -0
  30. package/dist/editor/overlays.d.ts +14 -0
  31. package/dist/editor/overlays.d.ts.map +1 -0
  32. package/dist/editor/overlays.test.d.ts +2 -0
  33. package/dist/editor/overlays.test.d.ts.map +1 -0
  34. package/dist/editor.js +64 -45
  35. package/dist/{juo-workflow-CkyZRq60.js → juo-workflow-DY4rd256.js} +74 -873
  36. package/dist/main.d.ts +3 -1
  37. package/dist/main.d.ts.map +1 -1
  38. package/dist/overlay-wrapper.d.ts +69 -0
  39. package/dist/overlay-wrapper.d.ts.map +1 -0
  40. package/dist/overlay-wrapper.test.d.ts +2 -0
  41. package/dist/overlay-wrapper.test.d.ts.map +1 -0
  42. package/dist/overlays/OverlayService.d.ts +34 -0
  43. package/dist/overlays/OverlayService.d.ts.map +1 -0
  44. package/dist/overlays/OverlayService.test.d.ts +2 -0
  45. package/dist/overlays/OverlayService.test.d.ts.map +1 -0
  46. package/dist/preact.js +1 -1
  47. package/dist/react.js +1 -1
  48. package/dist/registry.devtools.test.d.ts +2 -0
  49. package/dist/registry.devtools.test.d.ts.map +1 -0
  50. package/dist/services/customer/adapter.d.ts +8 -0
  51. package/dist/services/customer/adapter.d.ts.map +1 -0
  52. package/dist/services/customer/customerService.d.ts +3 -2
  53. package/dist/services/customer/customerService.d.ts.map +1 -1
  54. package/dist/services/customer/index.d.ts +1 -0
  55. package/dist/services/customer/index.d.ts.map +1 -1
  56. package/dist/services/customer/types.d.ts +4 -1
  57. package/dist/services/customer/types.d.ts.map +1 -1
  58. package/dist/services/index.d.ts +3 -0
  59. package/dist/services/index.d.ts.map +1 -1
  60. package/dist/services/login/adapter.d.ts +32 -0
  61. package/dist/services/login/adapter.d.ts.map +1 -0
  62. package/dist/services/login/index.d.ts +3 -1
  63. package/dist/services/login/index.d.ts.map +1 -1
  64. package/dist/services/login/loginService.d.ts +6 -2
  65. package/dist/services/login/loginService.d.ts.map +1 -1
  66. package/dist/services/order/adapter.d.ts +9 -0
  67. package/dist/services/order/adapter.d.ts.map +1 -0
  68. package/dist/services/order/index.d.ts +5 -0
  69. package/dist/services/order/index.d.ts.map +1 -0
  70. package/dist/services/order/orderService.d.ts +7 -0
  71. package/dist/services/order/orderService.d.ts.map +1 -0
  72. package/dist/services/order/types.d.ts +21 -0
  73. package/dist/services/order/types.d.ts.map +1 -0
  74. package/dist/services/orders/adapter.d.ts +2 -0
  75. package/dist/services/orders/adapter.d.ts.map +1 -1
  76. package/dist/services/orders/index.d.ts +1 -1
  77. package/dist/services/orders/index.d.ts.map +1 -1
  78. package/dist/services/product/adapter.d.ts +27 -2
  79. package/dist/services/product/adapter.d.ts.map +1 -1
  80. package/dist/services/product/adapter.test.d.ts +2 -0
  81. package/dist/services/product/adapter.test.d.ts.map +1 -0
  82. package/dist/services/product/index.d.ts +1 -1
  83. package/dist/services/product/index.d.ts.map +1 -1
  84. package/dist/services/product/productService.d.ts.map +1 -1
  85. package/dist/services/product/types.d.ts +68 -0
  86. package/dist/services/product/types.d.ts.map +1 -1
  87. package/dist/services/schedules/adapter.d.ts +47 -0
  88. package/dist/services/schedules/adapter.d.ts.map +1 -0
  89. package/dist/services/schedules/adapter.test.d.ts +2 -0
  90. package/dist/services/schedules/adapter.test.d.ts.map +1 -0
  91. package/dist/services/schedules/index.d.ts +5 -0
  92. package/dist/services/schedules/index.d.ts.map +1 -0
  93. package/dist/services/schedules/schedulesService.d.ts +11 -0
  94. package/dist/services/schedules/schedulesService.d.ts.map +1 -0
  95. package/dist/services/schedules/schedulesService.test.d.ts +2 -0
  96. package/dist/services/schedules/schedulesService.test.d.ts.map +1 -0
  97. package/dist/services/schedules/types.d.ts +101 -0
  98. package/dist/services/schedules/types.d.ts.map +1 -0
  99. package/dist/services/settings/index.d.ts +3 -0
  100. package/dist/services/settings/index.d.ts.map +1 -0
  101. package/dist/services/settings/settingsService.d.ts +7 -0
  102. package/dist/services/settings/settingsService.d.ts.map +1 -0
  103. package/dist/services/settings/settingsService.test.d.ts +2 -0
  104. package/dist/services/settings/settingsService.test.d.ts.map +1 -0
  105. package/dist/services/settings/types.d.ts +35 -0
  106. package/dist/services/settings/types.d.ts.map +1 -0
  107. package/dist/services/shop/index.d.ts +3 -0
  108. package/dist/services/shop/index.d.ts.map +1 -0
  109. package/dist/services/shop/shopService.d.ts +12 -0
  110. package/dist/services/shop/shopService.d.ts.map +1 -0
  111. package/dist/services/shop/shopService.test.d.ts +2 -0
  112. package/dist/services/shop/shopService.test.d.ts.map +1 -0
  113. package/dist/services/shop/types.d.ts +7 -0
  114. package/dist/services/shop/types.d.ts.map +1 -0
  115. package/dist/services/subscription/adapter.d.ts +58 -2
  116. package/dist/services/subscription/adapter.d.ts.map +1 -1
  117. package/dist/services/subscription/adapter.test.d.ts +2 -0
  118. package/dist/services/subscription/adapter.test.d.ts.map +1 -0
  119. package/dist/services/subscription/index.d.ts +1 -1
  120. package/dist/services/subscription/index.d.ts.map +1 -1
  121. package/dist/services/subscription/subscriptionService.d.ts +1 -6
  122. package/dist/services/subscription/subscriptionService.d.ts.map +1 -1
  123. package/dist/services/subscription/types.d.ts +212 -9
  124. package/dist/services/subscription/types.d.ts.map +1 -1
  125. package/dist/services/subscription/types.test.d.ts +2 -0
  126. package/dist/services/subscription/types.test.d.ts.map +1 -0
  127. package/dist/theme-state.d.ts +2 -1
  128. package/dist/theme-state.d.ts.map +1 -1
  129. package/dist/theme-state.params.test.d.ts +2 -0
  130. package/dist/theme-state.params.test.d.ts.map +1 -0
  131. package/dist/theme-state.translations.test.d.ts +2 -0
  132. package/dist/theme-state.translations.test.d.ts.map +1 -0
  133. package/dist/utils/index.d.ts +6 -0
  134. package/dist/utils/index.d.ts.map +1 -1
  135. package/dist/vue/block.d.ts.map +1 -1
  136. package/dist/vue.js +25 -4
  137. package/dist/web-components/ExtensionRoot.d.ts +1 -0
  138. package/dist/web-components/ExtensionRoot.d.ts.map +1 -1
  139. package/dist/web-components-editor.js +4 -3
  140. package/dist/web-components-runtime.js +3 -2
  141. package/package.json +1 -1
package/dist/core.js CHANGED
@@ -1,8 +1,9 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { c as createContext, d, w, r as registerBlock, E, u } from "./juo-workflow-CkyZRq60.js";
5
- import { B, C, a, D, S, T, b, W, e, f, g, h, i, j, k, l, m, n, o, p, q, s, t, v, x, y, z, A, F, G, H, I, J, K, L } from "./juo-workflow-CkyZRq60.js";
4
+ import { e as createContext, d, k as w, l as defineBlock, g as createBlockInstance, h as getDefinedBlocks, r as registerBlock, E, u } from "./block-B6s9jL7l.js";
5
+ import { B, m, p, S, q, _, t, b, v, f, x, y, z, A, D, i, F, a, o, G, j, H, s, n, w as w2 } from "./block-B6s9jL7l.js";
6
+ import { D as D2, a as a2, T, W, c, b as b2, d as d2, e, g, h, i as i2 } from "./juo-workflow-DY4rd256.js";
6
7
  import { reportBlockWarning, reportBlockError } from "./observability.js";
7
8
  function createState() {
8
9
  const discountCode = d(null);
@@ -72,6 +73,111 @@ function createState() {
72
73
  };
73
74
  }
74
75
  const StateContext = createContext("state");
76
+ const OVERLAY_WRAPPER_SCHEMA = {
77
+ type: "object",
78
+ properties: {
79
+ props: {
80
+ type: "object",
81
+ properties: {
82
+ layout: {
83
+ type: "string",
84
+ enum: ["modal", "sidebar"]
85
+ },
86
+ canAbort: {
87
+ type: "boolean"
88
+ }
89
+ },
90
+ required: ["layout"],
91
+ additionalProperties: false
92
+ },
93
+ slots: {
94
+ type: "object",
95
+ properties: {
96
+ content: {}
97
+ },
98
+ additionalProperties: false
99
+ }
100
+ },
101
+ required: ["props", "slots"],
102
+ additionalProperties: false
103
+ };
104
+ function defineOverlayWrapper(opts) {
105
+ const layout = opts.layout ?? "sidebar";
106
+ const canAbort = opts.canAbort ?? true;
107
+ return defineBlock(opts.name, {
108
+ displayName: opts.title,
109
+ group: "internal",
110
+ schema: OVERLAY_WRAPPER_SCHEMA,
111
+ initialValue: () => ({
112
+ props: { layout, canAbort },
113
+ slots: {
114
+ content: [createBlockInstance(opts.content)]
115
+ }
116
+ }),
117
+ renderer: () => null
118
+ });
119
+ }
120
+ const OVERLAY_PREFIX$1 = "overlay:";
121
+ function callInitialValue(block) {
122
+ if (typeof block.initialValue !== "function") return block.initialValue;
123
+ try {
124
+ return block.initialValue();
125
+ } catch (error) {
126
+ console.warn(
127
+ `[overlays] initialValue() threw for "${block.name}"; its content block will not be hidden from the palette.`,
128
+ error
129
+ );
130
+ return void 0;
131
+ }
132
+ }
133
+ function buildOverlayRegistry(blocks) {
134
+ var _a, _b;
135
+ const registry = {};
136
+ for (const block of blocks) {
137
+ if (!block.name.startsWith(OVERLAY_PREFIX$1)) continue;
138
+ const id = block.name.slice(OVERLAY_PREFIX$1.length);
139
+ const initial = callInitialValue(block);
140
+ const first = (_b = (_a = initial == null ? void 0 : initial.slots) == null ? void 0 : _a.content) == null ? void 0 : _b[0];
141
+ const contentBlock = typeof (first == null ? void 0 : first.type) === "string" ? first.type : "";
142
+ registry[id] = {
143
+ block: block.name,
144
+ title: block.displayName ?? id,
145
+ contentBlock
146
+ };
147
+ }
148
+ return registry;
149
+ }
150
+ const OVERLAY_PREFIX = "overlay:";
151
+ const OverlayServiceContext = createContext("services/overlay");
152
+ function createOverlayService(themeState, options = {}) {
153
+ const getBlocks = options.getBlocks ?? getDefinedBlocks;
154
+ const current = w(() => {
155
+ const root = themeState.overlay.blocks.value[0];
156
+ const type = root == null ? void 0 : root.type;
157
+ if (typeof type !== "string" || !type.startsWith(OVERLAY_PREFIX)) {
158
+ return null;
159
+ }
160
+ const props = root.props ?? {};
161
+ return {
162
+ name: type,
163
+ // Defaults mirror defineOverlayWrapper's seeding in overlay-wrapper.ts — keep in sync.
164
+ layout: props.layout ?? "sidebar",
165
+ canAbort: Boolean(props.canAbort ?? true)
166
+ };
167
+ });
168
+ return {
169
+ getEditableOverlays() {
170
+ return buildOverlayRegistry(getBlocks());
171
+ },
172
+ open(name, params) {
173
+ void themeState.resolve("overlay", name, params);
174
+ },
175
+ close() {
176
+ themeState.overlay.blocks.value = [];
177
+ },
178
+ current
179
+ };
180
+ }
75
181
  function isLocalhostOrigin(origin) {
76
182
  try {
77
183
  const url = new URL(origin);
@@ -132,7 +238,7 @@ async function loadBlockRegistry(options = {}) {
132
238
  if ("registerBlocks" in module && typeof module.registerBlocks === "function") {
133
239
  module.registerBlocks();
134
240
  } else {
135
- Object.entries(module).forEach(([_, item]) => {
241
+ Object.entries(module).forEach(([_2, item]) => {
136
242
  if (typeof item === "object" && item != null) {
137
243
  registerBlock(item);
138
244
  }
@@ -156,13 +262,43 @@ async function loadBlockRegistry(options = {}) {
156
262
  function createCustomerService(options) {
157
263
  const current = d(null);
158
264
  const accountOrdersUrl = d(options.getAccountOrdersUrl());
159
- const service = {
265
+ return {
160
266
  current,
161
- accountOrdersUrl
267
+ accountOrdersUrl,
268
+ async getCurrent() {
269
+ const result = await options.adapter.getCurrent();
270
+ if (result._tag === "Success") current.value = result.data;
271
+ return result;
272
+ }
162
273
  };
163
- return service;
164
274
  }
165
275
  const CustomerServiceContext = createContext("services/customer");
276
+ function createMockCustomerAdapter() {
277
+ const customer = { id: "customer-1", name: "Customer 1" };
278
+ return {
279
+ async getCurrent() {
280
+ return { _tag: "Success", data: customer };
281
+ }
282
+ };
283
+ }
284
+ function createApiCustomerAdapter(fetcher) {
285
+ return {
286
+ async getCurrent() {
287
+ try {
288
+ const res = await fetcher("/customer/info");
289
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
290
+ const data = await res.json();
291
+ const name = [data.firstName, data.lastName].filter(Boolean).join(" ") || data.email || "";
292
+ return {
293
+ _tag: "Success",
294
+ data: { id: data.id, name, email: data.email }
295
+ };
296
+ } catch (e2) {
297
+ return { _tag: "Failure", error: e2 };
298
+ }
299
+ }
300
+ };
301
+ }
166
302
  const PARAMS = {
167
303
  DELETGATED_TOKEN: "delegated-token",
168
304
  REDIRECT_TO: "redirect-to",
@@ -176,9 +312,125 @@ const PARAMS = {
176
312
  function uuid() {
177
313
  return ("10000000-1000-4000-8000" + -1e11).replace(
178
314
  /[018]/g,
179
- (c) => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
315
+ (c2) => (c2 ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c2 / 4).toString(16)
180
316
  );
181
317
  }
318
+ function createMockLoginAdapter() {
319
+ return {
320
+ async passwordlessStart() {
321
+ return { _tag: "Success", data: void 0 };
322
+ },
323
+ async authenticate() {
324
+ return {
325
+ _tag: "Success",
326
+ data: {
327
+ access_token: "mock-access-token",
328
+ refresh_token: "mock-refresh-token",
329
+ expires_in: 3600
330
+ }
331
+ };
332
+ },
333
+ getAuthorizeUrl({ connection, state, shop, appUrl }) {
334
+ const url = new URL(`${appUrl}/auth/customer/authorize`);
335
+ url.searchParams.set("connection", connection);
336
+ url.searchParams.set("state", state);
337
+ url.searchParams.set("shop", shop);
338
+ return url.toString();
339
+ }
340
+ };
341
+ }
342
+ function createApiLoginAdapter(fetcher, opts) {
343
+ const { shopDomain, appUrl } = opts;
344
+ async function callAuthEndpoint(path, body, lang) {
345
+ const url = lang ? `${path}?lang=${lang}` : path;
346
+ const res = await fetcher(url, {
347
+ method: "POST",
348
+ headers: {
349
+ Accept: "application/json",
350
+ "Content-Type": "application/json",
351
+ "X-Shopify-Shop-Domain": shopDomain
352
+ },
353
+ body: JSON.stringify(body)
354
+ });
355
+ if (res.status === 403) {
356
+ const data = await res.json();
357
+ if ("error_description" in data) {
358
+ if (data.error_description === "Wrong email or verification code.") {
359
+ throw new AuthenticationError(AuthenticationErrorReason.IncorrectCode);
360
+ } else if (data.error_description === "You've reached the maximum number of attempts. Please try to login again.") {
361
+ throw new AuthenticationError(AuthenticationErrorReason.TooManyTries);
362
+ } else if (data.error_description === "The verification code has expired. Please try to login again.") {
363
+ throw new AuthenticationError(AuthenticationErrorReason.Expired);
364
+ }
365
+ } else if ("code" in data && data.code === "AUTH_ERROR") {
366
+ throw new AuthenticationError(AuthenticationErrorReason.NoEmail, {
367
+ connection: data.connection
368
+ });
369
+ }
370
+ }
371
+ if (!res.ok) {
372
+ throw new Error(`Unexpected response: ${res.statusText}`);
373
+ }
374
+ return { _tag: "Success", data: void 0 };
375
+ }
376
+ return {
377
+ async passwordlessStart({ email, lang }) {
378
+ try {
379
+ await callAuthEndpoint(
380
+ "/auth/customer/passwordless/start",
381
+ { email },
382
+ lang
383
+ );
384
+ return { _tag: "Success", data: void 0 };
385
+ } catch (e2) {
386
+ return { _tag: "Failure", error: e2 };
387
+ }
388
+ },
389
+ async authenticate(params) {
390
+ try {
391
+ const res = await fetcher("/auth/customer/token", {
392
+ method: "POST",
393
+ headers: {
394
+ Accept: "application/json",
395
+ "Content-Type": "application/json",
396
+ "X-Shopify-Shop-Domain": shopDomain
397
+ },
398
+ body: JSON.stringify(params)
399
+ });
400
+ if (res.status === 403) {
401
+ const data = await res.json();
402
+ if ("error_description" in data) {
403
+ if (data.error_description === "Wrong email or verification code.") {
404
+ throw new AuthenticationError(AuthenticationErrorReason.IncorrectCode);
405
+ } else if (data.error_description === "You've reached the maximum number of attempts. Please try to login again.") {
406
+ throw new AuthenticationError(AuthenticationErrorReason.TooManyTries);
407
+ } else if (data.error_description === "The verification code has expired. Please try to login again.") {
408
+ throw new AuthenticationError(AuthenticationErrorReason.Expired);
409
+ }
410
+ } else if ("code" in data && data.code === "AUTH_ERROR") {
411
+ throw new AuthenticationError(AuthenticationErrorReason.NoEmail, {
412
+ connection: data.connection
413
+ });
414
+ }
415
+ }
416
+ if (!res.ok) {
417
+ throw new Error(`Unexpected response: ${res.statusText}`);
418
+ }
419
+ return { _tag: "Success", data: await res.json() };
420
+ } catch (e2) {
421
+ return { _tag: "Failure", error: e2 };
422
+ }
423
+ },
424
+ getAuthorizeUrl({ connection, state, shop }) {
425
+ const url = new URL(`${appUrl}/auth/customer/authorize`);
426
+ url.searchParams.set("connection", connection);
427
+ url.searchParams.set("state", state);
428
+ url.searchParams.set("shop", shop);
429
+ return url.toString();
430
+ }
431
+ };
432
+ }
433
+ const __vite_import_meta_env__ = {};
182
434
  var AuthenticationErrorReason = /* @__PURE__ */ ((AuthenticationErrorReason2) => {
183
435
  AuthenticationErrorReason2["Expired"] = "expired";
184
436
  AuthenticationErrorReason2["IncorrectCode"] = "wrong-code";
@@ -197,6 +449,9 @@ class AuthenticationError extends Error {
197
449
  this.data = data ?? {};
198
450
  }
199
451
  }
452
+ const STORAGE_DELEGATED_TOKEN = "delegated-token";
453
+ const STORAGE_REFRESH_TOKEN_KEY = "refresh-token";
454
+ const STORAGE_STATE_KEY = "state";
200
455
  function storage(key, value) {
201
456
  const storageKey = `auth:${key}`;
202
457
  try {
@@ -212,83 +467,33 @@ function storage(key, value) {
212
467
  }
213
468
  return null;
214
469
  }
215
- const STORAGE_DELEGATED_TOKEN = "delegated-token";
216
- const STORAGE_REFRESH_TOKEN_KEY = "refresh-token";
217
- const STORAGE_STATE_KEY = "state";
218
- function createAuthFunctions(basePath, shop) {
219
- async function start(email, lang) {
220
- const response = await fetch(
221
- `${basePath}/auth/customer/passwordless/start?lang=${lang}`,
222
- {
223
- method: "POST",
224
- headers: {
225
- Accept: "application/json",
226
- "Content-Type": "application/json",
227
- "X-Shopify-Shop-Domain": shop
228
- },
229
- body: JSON.stringify({ email })
230
- }
231
- );
232
- if (response.status !== 200) {
233
- throw new Error(`Unexpected response: ${response.statusText}`);
234
- }
235
- }
236
- async function authenticate(data) {
237
- const response = await fetch(`${basePath}/auth/customer/token`, {
238
- method: "POST",
239
- headers: {
240
- Accept: "application/json",
241
- "Content-Type": "application/json",
242
- "X-Shopify-Shop-Domain": shop
243
- },
244
- body: JSON.stringify(data)
245
- });
246
- if (response.status === 403) {
247
- const data2 = await response.json();
248
- if ("error_description" in data2) {
249
- if (data2.error_description === "Wrong email or verification code.") {
250
- throw new AuthenticationError(
251
- "wrong-code"
252
- /* IncorrectCode */
253
- );
254
- } else if (data2.error_description === "You've reached the maximum number of attempts. Please try to login again.") {
255
- throw new AuthenticationError(
256
- "too-many-tries"
257
- /* TooManyTries */
258
- );
259
- } else if (data2.error_description === "The verification code has expired. Please try to login again.") {
260
- throw new AuthenticationError(
261
- "expired"
262
- /* Expired */
263
- );
264
- }
265
- } else if ("code" in data2) {
266
- if (data2.code === "AUTH_ERROR") {
267
- throw new AuthenticationError("no-email", {
268
- connection: data2.connection
269
- });
270
- }
271
- }
272
- }
273
- if (response.status !== 200) {
274
- throw new Error(`Unexpected response: ${response.statusText}`);
275
- }
276
- return await response.json();
277
- }
278
- return { start, authenticate };
279
- }
280
470
  function nonce(len = 10) {
281
471
  return uuid().replace(/-/g, "").slice(0, len);
282
472
  }
283
- function createAuthService(apiUrl, shopDomain) {
284
- const { start: authStart, authenticate: authAuthenticate } = createAuthFunctions(apiUrl, shopDomain);
473
+ function loginService(deps) {
474
+ const apiBase = deps.shop.rootUrl.replace(/\/$/, "") + "/api";
475
+ const appUrl = (typeof import.meta !== "undefined" ? __vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_APP_URL : void 0) ?? "https://admin.juo.io";
476
+ const fetcher = (path, init) => fetch(`${apiBase}${path}`, init);
477
+ const adapter = createApiLoginAdapter(fetcher, {
478
+ shopDomain: deps.shop.domain,
479
+ appUrl
480
+ });
481
+ return createLoginService({
482
+ adapter,
483
+ router: deps.router,
484
+ formatError: deps.formatError,
485
+ shop: {
486
+ domain: deps.shop.domain,
487
+ locale: w(() => deps.getLocale())
488
+ },
489
+ onLoginSuccess: deps.onLoginSuccess
490
+ });
491
+ }
492
+ function createLoginService(init) {
493
+ const { adapter, formatError, router, shop, onLoginSuccess } = init;
285
494
  const accessToken = d(null);
286
- const delegatedToken = d(
287
- storage(STORAGE_DELEGATED_TOKEN)
288
- );
289
- const refreshToken = d(
290
- storage(STORAGE_REFRESH_TOKEN_KEY)
291
- );
495
+ const delegatedToken = d(storage(STORAGE_DELEGATED_TOKEN));
496
+ const refreshToken = d(storage(STORAGE_REFRESH_TOKEN_KEY));
292
497
  const expires = d(null);
293
498
  const state = d(storage(STORAGE_STATE_KEY));
294
499
  E(() => {
@@ -300,67 +505,28 @@ function createAuthService(apiUrl, shopDomain) {
300
505
  E(() => {
301
506
  storage(STORAGE_STATE_KEY, state.value);
302
507
  });
303
- function store(data) {
508
+ function storeTokens(data) {
304
509
  const { access_token, refresh_token, expires_in } = data;
305
510
  accessToken.value = access_token;
306
511
  refreshToken.value = refresh_token;
307
512
  expires.value = new Date(Date.now() + expires_in);
308
513
  }
309
- return {
310
- state,
311
- async start(email, lang) {
312
- await authStart(email, lang);
313
- },
314
- async authenticate(data) {
315
- store(await authAuthenticate(data));
316
- },
317
- getDelegatedToken() {
318
- return delegatedToken.value;
319
- },
320
- setDelegatedToken(token) {
321
- delegatedToken.value = token;
322
- },
323
- async getToken() {
324
- if (refreshToken.value == null) {
325
- return null;
326
- }
327
- if (accessToken.value == null || typeof accessToken.value === "string" && (expires.value == null || expires.value < /* @__PURE__ */ new Date())) {
328
- accessToken.value = new Promise(
329
- (resolve, reject) => authAuthenticate({ refreshToken: refreshToken.value }).then((data) => data).then((data) => {
330
- store(data);
331
- resolve(data.access_token);
514
+ async function getToken() {
515
+ if (refreshToken.value == null) return null;
516
+ if (accessToken.value == null || typeof accessToken.value === "string" && (expires.value == null || expires.value < /* @__PURE__ */ new Date())) {
517
+ accessToken.value = new Promise(
518
+ (resolve, reject) => adapter.authenticate({ refreshToken: refreshToken.value }).then((result) => {
519
+ if (result._tag === "Failure") {
520
+ reject(result.error);
332
521
  return;
333
- }).catch(reject)
334
- );
335
- }
336
- return Promise.resolve(accessToken.value);
337
- },
338
- logout() {
339
- accessToken.value = null;
340
- delegatedToken.value = null;
341
- refreshToken.value = null;
342
- expires.value = null;
343
- },
344
- isAuthenticated: w(
345
- () => delegatedToken.value != null || refreshToken.value != null
346
- )
347
- };
348
- }
349
- function loginService(deps) {
350
- return createLoginService({
351
- apiUrl: `${deps.shop.rootUrl.replace(/\/$/, "")}/api`,
352
- router: deps.router,
353
- formatError: deps.formatError,
354
- shop: {
355
- domain: deps.shop.domain,
356
- locale: w(() => deps.getLocale())
357
- },
358
- onLoginSuccess: deps.onLoginSuccess
359
- });
360
- }
361
- function createLoginService(init) {
362
- const { formatError, router, shop, onLoginSuccess } = init;
363
- const auth = createAuthService(init.apiUrl.replace(/\/$/, ""), shop.domain);
522
+ }
523
+ storeTokens(result.data);
524
+ resolve(result.data.access_token);
525
+ }).catch(reject)
526
+ );
527
+ }
528
+ return Promise.resolve(accessToken.value);
529
+ }
364
530
  const userEmail = d(null);
365
531
  async function onSuccess(query) {
366
532
  await (onLoginSuccess == null ? void 0 : onLoginSuccess());
@@ -373,13 +539,9 @@ function createLoginService(init) {
373
539
  queryParams[key] = value;
374
540
  }
375
541
  });
376
- router.push({
377
- path: decodeURIComponent(redirect),
378
- query: queryParams
379
- });
542
+ router.push({ path: decodeURIComponent(redirect), query: queryParams });
380
543
  } else {
381
- const redirect = query.get(PARAMS.REDIRECT_TO);
382
- router.replace(decodeURIComponent(redirect));
544
+ router.replace(decodeURIComponent(query.get(PARAMS.REDIRECT_TO)));
383
545
  }
384
546
  } else {
385
547
  router.replace("/");
@@ -391,16 +553,17 @@ function createLoginService(init) {
391
553
  async start(email) {
392
554
  try {
393
555
  userEmail.value = email;
394
- await auth.start(
395
- userEmail.value,
396
- shop.locale instanceof u ? shop.locale.value : shop.locale
397
- );
556
+ const lang = shop.locale instanceof u ? shop.locale.value : shop.locale;
557
+ const result = await adapter.passwordlessStart({
558
+ email: userEmail.value,
559
+ lang
560
+ });
561
+ if (result._tag === "Failure") {
562
+ return { _tag: "Failure", error: formatError(result.error) };
563
+ }
398
564
  return { _tag: "Success", data: void 0 };
399
565
  } catch (error) {
400
- return {
401
- _tag: "Failure",
402
- error: formatError(error)
403
- };
566
+ return { _tag: "Failure", error: formatError(error) };
404
567
  }
405
568
  },
406
569
  async verify(email, code) {
@@ -411,63 +574,61 @@ function createLoginService(init) {
411
574
  };
412
575
  }
413
576
  try {
414
- const result = await auth.authenticate({
577
+ const result = await adapter.authenticate({
415
578
  email: userEmail.value,
416
579
  code
417
580
  });
581
+ if (result._tag === "Failure") {
582
+ return { _tag: "Failure", error: formatError(result.error) };
583
+ }
584
+ storeTokens(result.data);
418
585
  await onSuccess();
419
- return { _tag: "Success", data: result };
586
+ return { _tag: "Success", data: void 0 };
420
587
  } catch (error) {
421
- return {
422
- _tag: "Failure",
423
- error: formatError(error)
424
- };
588
+ return { _tag: "Failure", error: formatError(error) };
425
589
  }
426
590
  }
427
591
  }
428
592
  },
429
593
  social: {
430
594
  async start(provider) {
431
- function socialUrl(key, shop2) {
432
- auth.state.value = nonce();
433
- const url = new URL(
434
- // TODO: double check admin url
435
- `${"https://admin.juo.io"}/auth/customer/authorize`
436
- );
437
- url.searchParams.append("connection", key);
438
- url.searchParams.append("state", auth.state.value ?? "");
439
- url.searchParams.append("shop", shop2);
440
- return url.toString();
441
- }
442
- window.location.href = socialUrl(
443
- provider === "Facebook" ? "facebook" : "google-oauth2",
444
- shop.domain
445
- );
446
- return {
447
- _tag: "Success",
448
- data: void 0
449
- };
595
+ state.value = nonce();
596
+ const connection = provider === "Facebook" ? "facebook" : "google-oauth2";
597
+ window.location.href = adapter.getAuthorizeUrl({
598
+ connection,
599
+ state: state.value ?? "",
600
+ shop: shop.domain,
601
+ appUrl: (
602
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
603
+ (typeof import.meta !== "undefined" ? __vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_APP_URL : void 0) ?? "https://admin.juo.io"
604
+ )
605
+ });
606
+ return { _tag: "Success", data: void 0 };
450
607
  },
451
608
  async verify(code) {
452
609
  try {
453
- const result = await auth.authenticate({ code });
610
+ const result = await adapter.authenticate({ code });
611
+ if (result._tag === "Failure") {
612
+ return { _tag: "Failure", error: formatError(result.error) };
613
+ }
614
+ storeTokens(result.data);
454
615
  await onSuccess();
455
- return { _tag: "Success", data: result };
616
+ return { _tag: "Success", data: void 0 };
456
617
  } catch (error) {
457
- return {
458
- _tag: "Failure",
459
- error: formatError(error)
460
- };
618
+ return { _tag: "Failure", error: formatError(error) };
461
619
  }
462
620
  }
463
621
  },
464
622
  async logout() {
465
- await auth.logout();
623
+ accessToken.value = null;
624
+ delegatedToken.value = null;
625
+ refreshToken.value = null;
626
+ expires.value = null;
466
627
  return { _tag: "Success", data: void 0 };
467
628
  },
468
629
  async handleQueryParams(query) {
469
630
  if (query.has(PARAMS.DELETGATED_TOKEN)) {
470
- auth.setDelegatedToken(query.get(PARAMS.DELETGATED_TOKEN));
631
+ delegatedToken.value = query.get(PARAMS.DELETGATED_TOKEN);
471
632
  await onSuccess(query);
472
633
  return { _tag: "Success", data: void 0 };
473
634
  }
@@ -479,16 +640,13 @@ function createLoginService(init) {
479
640
  }
480
641
  const code = query.get(PARAMS.CODE);
481
642
  if (code != null) {
482
- if (query.get(PARAMS.STATE) !== auth.state.value) {
483
- return {
484
- _tag: "Failure",
485
- error: formatError("Invalid state")
486
- };
643
+ if (query.get(PARAMS.STATE) !== state.value) {
644
+ return { _tag: "Failure", error: formatError("Invalid state") };
487
645
  } else {
488
646
  return service.social.verify(code);
489
647
  }
490
648
  }
491
- if (query.get(PARAMS.REFRESH) === "1" && await auth.getToken() != null) {
649
+ if (query.get(PARAMS.REFRESH) === "1" && await getToken() != null) {
492
650
  await onSuccess();
493
651
  return { _tag: "Success", data: void 0 };
494
652
  }
@@ -505,8 +663,20 @@ function createLoginService(init) {
505
663
  }
506
664
  return { _tag: "Success", data: void 0 };
507
665
  },
508
- isAuthenticated: auth.isAuthenticated,
509
- getToken: () => auth.getToken()
666
+ isAuthenticated: w(
667
+ () => delegatedToken.value != null || refreshToken.value != null
668
+ ),
669
+ getToken,
670
+ async getAuthHeaders() {
671
+ if (delegatedToken.value) {
672
+ return { "X-Delegated-Token": delegatedToken.value };
673
+ }
674
+ const token = await getToken();
675
+ if (token) {
676
+ return { Authorization: `Bearer ${token}` };
677
+ }
678
+ return {};
679
+ }
510
680
  };
511
681
  return service;
512
682
  }
@@ -572,6 +742,55 @@ function createMockOrdersAdapter() {
572
742
  }
573
743
  };
574
744
  }
745
+ function mapOrderLine(item) {
746
+ var _a;
747
+ return {
748
+ id: item.id,
749
+ title: item.title,
750
+ quantity: item.quantity,
751
+ variantImage: ((_a = item.variantImage) == null ? void 0 : _a.url) ? { url: item.variantImage.url, altText: item.variantImage.altText ?? void 0 } : null,
752
+ customAttributes: item.customAttributes
753
+ };
754
+ }
755
+ function mapOrder(order) {
756
+ return {
757
+ id: order.id,
758
+ createdAt: order.createdAt,
759
+ placedAt: order.placedAt,
760
+ currencyCode: order.currencyCode,
761
+ totalPrice: order.totalPrice,
762
+ financialStatus: order.financialStatus,
763
+ fulfillmentStatus: order.fulfillmentStatus,
764
+ lines: order.items.map(mapOrderLine),
765
+ customAttributes: order.customAttributes
766
+ };
767
+ }
768
+ function createApiOrdersAdapter(fetcher) {
769
+ return {
770
+ async getOrders(params) {
771
+ const query = new URLSearchParams();
772
+ if ((params == null ? void 0 : params.limit) != null) query.set("limit", String(params.limit));
773
+ if ((params == null ? void 0 : params.after) != null) query.set("after", params.after);
774
+ if ((params == null ? void 0 : params.before) != null) query.set("before", params.before);
775
+ if ((params == null ? void 0 : params.query) != null) query.set("query", params.query);
776
+ if ((params == null ? void 0 : params.includeOneTime) != null) query.set("includeOneTime", String(params.includeOneTime));
777
+ if ((params == null ? void 0 : params.sort) != null) query.set("sort", params.sort);
778
+ const qs = query.toString();
779
+ const res = await fetcher(`/customer/v1/orders${qs ? `?${qs}` : ""}`);
780
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
781
+ const body = await res.json();
782
+ return {
783
+ items: body.data.map(mapOrder),
784
+ pageInfo: {
785
+ hasNextPage: body.hasNextPage,
786
+ hasPrevPage: body.hasPrevPage,
787
+ startCursor: body.startCursor,
788
+ endCursor: body.endCursor
789
+ }
790
+ };
791
+ }
792
+ };
793
+ }
575
794
  function createOrdersService(adapter) {
576
795
  return {
577
796
  async getOrders(params) {
@@ -591,7 +810,7 @@ function createMockProductAdapter() {
591
810
  id: "sample-1",
592
811
  title: "Hydrating Gel Cleanser for Face and Eye Area",
593
812
  featuredImage: {
594
- url: "https://via.placeholder.com/400x400?text=Product+1"
813
+ url: "https://placehold.co/400x400?text=Product+1"
595
814
  },
596
815
  hasOnlyDefaultVariant: true,
597
816
  variants: [
@@ -599,7 +818,7 @@ function createMockProductAdapter() {
599
818
  id: "sample-1-1",
600
819
  title: "150 ml bottle",
601
820
  image: {
602
- url: "https://via.placeholder.com/400x400?text=Product+1"
821
+ url: "https://placehold.co/400x400?text=Product+1"
603
822
  },
604
823
  price: {
605
824
  amount: "12.49",
@@ -625,7 +844,7 @@ function createMockProductAdapter() {
625
844
  id: "sample-2",
626
845
  title: "More COLLAGEN",
627
846
  featuredImage: {
628
- url: "https://via.placeholder.com/400x400?text=Product+2"
847
+ url: "https://placehold.co/400x400?text=Product+2"
629
848
  },
630
849
  hasOnlyDefaultVariant: true,
631
850
  variants: [
@@ -633,7 +852,7 @@ function createMockProductAdapter() {
633
852
  id: "sample-2-1",
634
853
  title: "blackcurrant",
635
854
  image: {
636
- url: "https://via.placeholder.com/400x400?text=Product+2"
855
+ url: "https://placehold.co/400x400?text=Product+2"
637
856
  },
638
857
  price: {
639
858
  amount: "12.49",
@@ -654,7 +873,7 @@ function createMockProductAdapter() {
654
873
  id: "sample-3",
655
874
  title: "Gentle deodorant for underarms and bust",
656
875
  featuredImage: {
657
- url: "https://via.placeholder.com/400x400?text=Product+3"
876
+ url: "https://placehold.co/400x400?text=Product+3"
658
877
  },
659
878
  hasOnlyDefaultVariant: false,
660
879
  variants: [
@@ -662,7 +881,7 @@ function createMockProductAdapter() {
662
881
  id: "sample-3-1",
663
882
  title: "Green tea and jasmine",
664
883
  image: {
665
- url: "https://via.placeholder.com/400x400?text=Product+3a"
884
+ url: "https://placehold.co/400x400?text=Product+3a"
666
885
  },
667
886
  price: {
668
887
  amount: "6.7",
@@ -680,7 +899,7 @@ function createMockProductAdapter() {
680
899
  id: "sample-3-2",
681
900
  title: "Lavender and mint",
682
901
  image: {
683
- url: "https://via.placeholder.com/400x400?text=Product+3b"
902
+ url: "https://placehold.co/400x400?text=Product+3b"
684
903
  },
685
904
  price: {
686
905
  amount: "7.5",
@@ -712,6 +931,48 @@ function createMockProductAdapter() {
712
931
  }
713
932
  };
714
933
  }
934
+ function toAvailableProduct(product) {
935
+ return {
936
+ id: product.id,
937
+ title: product.title,
938
+ description: `Sample description for ${product.title}.`,
939
+ featuredImage: product.featuredImage ?? void 0,
940
+ hasOnlyDefaultVariant: product.hasOnlyDefaultVariant,
941
+ variants: product.variants.map((variant) => {
942
+ var _a, _b, _c;
943
+ const base = Number.parseFloat(variant.price.amount);
944
+ const sub = (_b = (_a = variant.purchaseOptions) == null ? void 0 : _a[0]) == null ? void 0 : _b.price.amount;
945
+ const current = sub == null ? base : Number.parseFloat(sub);
946
+ return {
947
+ id: variant.id,
948
+ availableForSale: true,
949
+ title: variant.title,
950
+ currentPrice: { amount: current, currencyCode: variant.price.currencyCode },
951
+ basePrice: { amount: base, currencyCode: variant.price.currencyCode },
952
+ image: variant.image ?? void 0,
953
+ recurring: (((_c = variant.purchaseOptions) == null ? void 0 : _c.length) ?? 0) > 0
954
+ };
955
+ })
956
+ };
957
+ }
958
+ const sampleBox = {
959
+ id: "sample-box-1",
960
+ title: "Build Your Own Box",
961
+ minProductsCount: 3,
962
+ parentProduct: "sample-1",
963
+ tiers: [
964
+ { value: 5, threshold: 3 },
965
+ { value: 10, threshold: 5 }
966
+ ],
967
+ variants: products.map((product) => ({
968
+ id: product.id,
969
+ variants: product.variants.map((variant) => ({ id: variant.id }))
970
+ })),
971
+ freeVariants: [],
972
+ thresholdType: "LINES_COUNT",
973
+ type: "PERCENTAGE",
974
+ restrictQuantityToTiers: false
975
+ };
715
976
  return {
716
977
  async getById(id) {
717
978
  await new Promise((resolve) => setTimeout(resolve, 100));
@@ -725,6 +986,27 @@ function createMockProductAdapter() {
725
986
  );
726
987
  return product == null ? null : processProduct(product);
727
988
  },
989
+ async getProductsByIds({ ids }) {
990
+ await new Promise((resolve) => setTimeout(resolve, 100));
991
+ return products.filter((product) => ids.includes(product.id)).map(({ variants: _variants, ...product }) => product);
992
+ },
993
+ async getBoxVariants({ ids }) {
994
+ await new Promise((resolve) => setTimeout(resolve, 100));
995
+ return products.filter((product) => ids.includes(product.id)).map(toAvailableProduct);
996
+ },
997
+ async getAvailableProducts({ q: q2 }) {
998
+ await new Promise((resolve) => setTimeout(resolve, 100));
999
+ const queryLower = q2 == null ? void 0 : q2.toLowerCase();
1000
+ return products.filter(
1001
+ (product) => !queryLower || product.title.toLowerCase().includes(queryLower) || product.variants.some(
1002
+ (variant) => variant.title.toLowerCase().includes(queryLower)
1003
+ )
1004
+ ).map(toAvailableProduct);
1005
+ },
1006
+ async getBox({ id }) {
1007
+ await new Promise((resolve) => setTimeout(resolve, 100));
1008
+ return id === sampleBox.id ? sampleBox : null;
1009
+ },
728
1010
  async search(opts) {
729
1011
  await new Promise((resolve) => setTimeout(resolve, 100));
730
1012
  let filteredProducts = [...products];
@@ -765,34 +1047,217 @@ function createMockProductAdapter() {
765
1047
  }
766
1048
  };
767
1049
  }
768
- const ProductServiceContext = createContext("services/product");
769
- function createProductService(adapter) {
1050
+ function mapVariant(variant, currencyCode) {
1051
+ var _a;
770
1052
  return {
771
- async getById(id) {
772
- return adapter.getById(id);
773
- },
774
- async getByVariantId(variantId) {
775
- return adapter.getByVariantId(variantId);
1053
+ id: variant.id,
1054
+ title: variant.title,
1055
+ image: variant.image == null ? null : { url: variant.image.url, altText: variant.image.altText ?? void 0 },
1056
+ price: { amount: variant.price.toFixed(2), currencyCode },
1057
+ ...((_a = variant.purchaseOptions) == null ? void 0 : _a.length) ? {
1058
+ purchaseOptions: variant.purchaseOptions.map((opt) => ({
1059
+ name: opt.name,
1060
+ price: { amount: opt.price.toFixed(2), currencyCode },
1061
+ interval: opt.interval
1062
+ }))
1063
+ } : {}
1064
+ };
1065
+ }
1066
+ function mapProduct(product, currencyCode) {
1067
+ return {
1068
+ id: product.id,
1069
+ title: product.title,
1070
+ featuredImage: product.image == null ? null : { url: product.image.url, altText: product.image.altText ?? void 0 },
1071
+ hasOnlyDefaultVariant: product.variants.length <= 1,
1072
+ variants: {
1073
+ items: product.variants.map((v2) => mapVariant(v2, currencyCode)),
1074
+ pageInfo: {
1075
+ hasNextPage: false,
1076
+ hasPrevPage: false,
1077
+ startCursor: null,
1078
+ endCursor: null
1079
+ }
776
1080
  },
777
- async search(opts) {
778
- return adapter.search(opts);
779
- }
1081
+ collections: product.collections
780
1082
  };
781
1083
  }
782
- function routeNameTableFromPages(pages) {
783
- const table = {};
784
- for (const page of pages) {
785
- const names = page.routeNames;
786
- if (names.length === 0) continue;
787
- for (const name of names) {
788
- table[name] = page.path;
789
- }
1084
+ function createApiProductAdapter(fetcher, opts = { currencyCode: "USD" }) {
1085
+ const { currencyCode } = opts;
1086
+ async function fetchProducts(params) {
1087
+ const query = params.toString() ? `?${params.toString()}` : "";
1088
+ const res = await fetcher(`/customer/v1/products${query}`);
1089
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
1090
+ return res.json();
790
1091
  }
791
- return table;
792
- }
793
- function createRouterService(options) {
794
- const { pages, pushImplementation } = options;
795
- const routeNameToPagePath = routeNameTableFromPages(pages);
1092
+ return {
1093
+ async getById(id) {
1094
+ try {
1095
+ const params = new URLSearchParams({ query: `id:"${id}"`, limit: "1" });
1096
+ const body = await fetchProducts(params);
1097
+ return body.data.length > 0 ? mapProduct(body.data[0], currencyCode) : null;
1098
+ } catch {
1099
+ return null;
1100
+ }
1101
+ },
1102
+ async getByVariantId(variantId) {
1103
+ try {
1104
+ const params = new URLSearchParams({
1105
+ query: `variants.id:"${variantId}"`,
1106
+ limit: "1"
1107
+ });
1108
+ const body = await fetchProducts(params);
1109
+ return body.data.length > 0 ? mapProduct(body.data[0], currencyCode) : null;
1110
+ } catch {
1111
+ return null;
1112
+ }
1113
+ },
1114
+ async search(opts2) {
1115
+ try {
1116
+ const params = new URLSearchParams();
1117
+ if (opts2 == null ? void 0 : opts2.query) {
1118
+ params.set("query", `"${opts2.query.trim().replace(/"/g, '\\"')}"`);
1119
+ }
1120
+ if (opts2 == null ? void 0 : opts2.pagination) {
1121
+ if ("after" in opts2.pagination)
1122
+ params.set("after", opts2.pagination.after);
1123
+ else if ("before" in opts2.pagination)
1124
+ params.set("before", opts2.pagination.before);
1125
+ }
1126
+ const body = await fetchProducts(params);
1127
+ return {
1128
+ items: body.data.map((p2) => mapProduct(p2, currencyCode)),
1129
+ pageInfo: {
1130
+ hasNextPage: body.hasNextPage,
1131
+ hasPrevPage: body.hasPrevPage,
1132
+ startCursor: body.startCursor,
1133
+ endCursor: body.endCursor
1134
+ }
1135
+ };
1136
+ } catch {
1137
+ return {
1138
+ items: [],
1139
+ pageInfo: {
1140
+ hasNextPage: false,
1141
+ hasPrevPage: false,
1142
+ startCursor: null,
1143
+ endCursor: null
1144
+ }
1145
+ };
1146
+ }
1147
+ },
1148
+ async getProductsByIds({ ids }) {
1149
+ const params = new URLSearchParams();
1150
+ for (const id of ids) params.append("ids", id);
1151
+ const res = await fetcher(`/customer/products/by-ids?${params.toString()}`);
1152
+ if (!res.ok) return [];
1153
+ const data = await res.json();
1154
+ return (data ?? []).map((p2) => ({
1155
+ id: p2.id,
1156
+ title: p2.title ?? "",
1157
+ featuredImage: p2.featuredImage ? { url: p2.featuredImage.url, altText: p2.featuredImage.altText } : null,
1158
+ hasOnlyDefaultVariant: true,
1159
+ collections: []
1160
+ }));
1161
+ },
1162
+ async getBoxVariants({ ids, subscriptionId }) {
1163
+ const params = new URLSearchParams();
1164
+ for (const id of ids) params.append("ids", id);
1165
+ params.set("subscriptionId", subscriptionId);
1166
+ const res = await fetcher(`/customer/products/variants?${params.toString()}`);
1167
+ if (!res.ok) return [];
1168
+ const data = await res.json();
1169
+ return (data ?? []).map((p2) => {
1170
+ var _a;
1171
+ return {
1172
+ id: p2.id,
1173
+ title: p2.title,
1174
+ description: p2.description ?? "",
1175
+ featuredImage: p2.featuredImage,
1176
+ hasOnlyDefaultVariant: p2.hasOnlyDefaultVariant ?? (((_a = p2.variants) == null ? void 0 : _a.length) ?? 0) <= 1,
1177
+ variants: (p2.variants ?? []).map((v2) => ({
1178
+ id: v2.id,
1179
+ availableForSale: v2.availableForSale,
1180
+ title: v2.title,
1181
+ currentPrice: v2.currentPrice,
1182
+ basePrice: v2.basePrice,
1183
+ image: v2.image,
1184
+ recurring: v2.recurring
1185
+ }))
1186
+ };
1187
+ });
1188
+ },
1189
+ async getAvailableProducts({ subscriptionId, lineId, q: q2, mode, action, pagination }) {
1190
+ const params = new URLSearchParams();
1191
+ params.set("action", action);
1192
+ if (q2) params.set("q", q2);
1193
+ if (mode) params.set("mode", mode);
1194
+ if (pagination && "after" in pagination) params.set("after", pagination.after);
1195
+ if (pagination && "before" in pagination) params.set("before", pagination.before);
1196
+ const res = await fetcher(
1197
+ `/customer/subscriptions/${subscriptionId}/lines/${lineId}/available-products?${params.toString()}`
1198
+ );
1199
+ if (!res.ok) return [];
1200
+ const data = await res.json();
1201
+ return (data ?? []).map((p2) => {
1202
+ var _a;
1203
+ return {
1204
+ id: p2.id,
1205
+ title: p2.title,
1206
+ description: p2.description ?? "",
1207
+ featuredImage: p2.featuredImage,
1208
+ hasOnlyDefaultVariant: p2.hasOnlyDefaultVariant ?? (((_a = p2.variants) == null ? void 0 : _a.length) ?? 0) <= 1,
1209
+ variants: (p2.variants ?? []).map((v2) => ({
1210
+ id: v2.id,
1211
+ availableForSale: v2.availableForSale,
1212
+ title: v2.title,
1213
+ currentPrice: v2.currentPrice,
1214
+ basePrice: v2.basePrice,
1215
+ image: v2.image,
1216
+ recurring: v2.recurring
1217
+ }))
1218
+ };
1219
+ });
1220
+ },
1221
+ async getBox({ id }) {
1222
+ const res = await fetcher(`/customer/boxes/${id}`);
1223
+ if (!res.ok) return null;
1224
+ const data = await res.json();
1225
+ return { id, ...data };
1226
+ }
1227
+ };
1228
+ }
1229
+ const ProductServiceContext = createContext("services/product");
1230
+ function createProductService(adapter) {
1231
+ return {
1232
+ async getById(id) {
1233
+ return adapter.getById(id);
1234
+ },
1235
+ async getByVariantId(variantId) {
1236
+ return adapter.getByVariantId(variantId);
1237
+ },
1238
+ async search(opts) {
1239
+ return adapter.search(opts);
1240
+ },
1241
+ getProductsByIds: (ids) => adapter.getProductsByIds({ ids }),
1242
+ getBoxVariants: (ids, subscriptionId) => adapter.getBoxVariants({ ids, subscriptionId }),
1243
+ getAvailableProducts: (params) => adapter.getAvailableProducts(params),
1244
+ getBox: (id) => adapter.getBox({ id })
1245
+ };
1246
+ }
1247
+ function routeNameTableFromPages(pages) {
1248
+ const table = {};
1249
+ for (const page of pages) {
1250
+ const names = page.routeNames;
1251
+ if (names.length === 0) continue;
1252
+ for (const name of names) {
1253
+ table[name] = page.path;
1254
+ }
1255
+ }
1256
+ return table;
1257
+ }
1258
+ function createRouterService(options) {
1259
+ const { pages, pushImplementation } = options;
1260
+ const routeNameToPagePath = routeNameTableFromPages(pages);
796
1261
  const pathSet = new Set(pages.map((p2) => p2.path));
797
1262
  const navigationSubscribers = [];
798
1263
  function notifySubscribers(logicalPath) {
@@ -831,6 +1296,70 @@ function createMockRouterService() {
831
1296
  }).routerService;
832
1297
  }
833
1298
  function createMockSubscriptionAdapter(options = {}) {
1299
+ const richBase = (id, itemId, renewalId) => ({
1300
+ id,
1301
+ customerId: "customer_1",
1302
+ items: [
1303
+ {
1304
+ id: itemId,
1305
+ // Aligned with the mock product catalog (createMockProductAdapter):
1306
+ // sample-3 "Gentle deodorant", variant sample-3-1 "Green tea and jasmine",
1307
+ // recurring price 5.36 EUR (10% off → 4.82 with SAVE10).
1308
+ productId: "sample-3",
1309
+ variantId: "sample-3-1",
1310
+ quantity: 2,
1311
+ price: { amount: "5.36", currencyCode: "EUR" },
1312
+ nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-15"),
1313
+ isUpsell: false,
1314
+ isVirtual: false,
1315
+ nextBillingDate: "2025-11-15T00:00:00Z",
1316
+ currentPrice: { amount: "5.36", currencyCode: "EUR" },
1317
+ lineDiscountedPrice: { amount: "4.82", currencyCode: "EUR" },
1318
+ variantAvailableForSale: true,
1319
+ title: "Gentle deodorant for underarms and bust",
1320
+ variantTitle: "Green tea and jasmine",
1321
+ variantImage: { url: "https://placehold.co/400x400?text=Product+3a" },
1322
+ billingPolicy: { intervalCount: 1, interval: "MONTH" },
1323
+ deliveryPolicy: { intervalCount: 1, interval: "MONTH" }
1324
+ }
1325
+ ],
1326
+ discounts: [
1327
+ {
1328
+ id: "discount_1",
1329
+ type: "percentage",
1330
+ value: 10,
1331
+ code: "SAVE10",
1332
+ description: "10% off subscription"
1333
+ }
1334
+ ],
1335
+ status: "active",
1336
+ nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-15"),
1337
+ frequency: "1 MONTH",
1338
+ createdAt: "2024-10-01T00:00:00Z",
1339
+ updatedAt: "2024-10-14T00:00:00Z",
1340
+ billingPolicy: { intervalCount: 1, interval: "MONTH", minCycles: 6 },
1341
+ deliveryPolicy: {
1342
+ intervalCount: 1,
1343
+ interval: "MONTH",
1344
+ anchors: [{ day: 15, type: "MONTHDAY" }]
1345
+ },
1346
+ nextBillingDate: "2025-11-15T00:00:00Z",
1347
+ nextBillingAttempt: { date: "2025-11-15T00:00:00Z", attempt: 1, ready: true },
1348
+ lastBillingAttempt: { date: "2025-10-15T00:00:00Z", ready: true },
1349
+ nextFulfillment: "2025-11-17T00:00:00Z",
1350
+ estimatedOrderDate: "2025-11-13T00:00:00Z",
1351
+ customerPaymentMethod: {
1352
+ id: "pm_1",
1353
+ instrument: { type: "credit_card", brand: "visa", maskedNumber: "************4242" },
1354
+ active: true,
1355
+ isRecurring: true
1356
+ },
1357
+ requiredBillingCyclesLeft: 3,
1358
+ renewal: { id: renewalId, isInActiveProcessState: false },
1359
+ lastPaymentStatus: "succeeded",
1360
+ pausePeriod: null,
1361
+ isEditable: true
1362
+ });
834
1363
  const mockSubscriptions = [
835
1364
  {
836
1365
  id: "sub_1",
@@ -838,14 +1367,27 @@ function createMockSubscriptionAdapter(options = {}) {
838
1367
  items: [
839
1368
  {
840
1369
  id: "item_1",
841
- productId: "product_1",
842
- variantId: "variant_1",
1370
+ // Aligned with the mock product catalog (createMockProductAdapter):
1371
+ // sample-1 "Hydrating Gel Cleanser" (default variant), recurring price
1372
+ // 9.99 EUR (10% off → 8.99 with SAVE10).
1373
+ productId: "sample-1",
1374
+ variantId: "sample-1-1",
843
1375
  quantity: 2,
844
- price: { amount: "29.99", currencyCode: "USD" },
1376
+ price: { amount: "9.99", currencyCode: "EUR" },
845
1377
  nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-15"),
1378
+ isUpsell: false,
1379
+ isVirtual: false,
1380
+ nextBillingDate: "2025-11-15T00:00:00Z",
1381
+ currentPrice: { amount: "9.99", currencyCode: "EUR" },
1382
+ lineDiscountedPrice: { amount: "8.99", currencyCode: "EUR" },
1383
+ variantAvailableForSale: true,
1384
+ title: "Hydrating Gel Cleanser for Face and Eye Area",
1385
+ variantImage: { url: "https://placehold.co/400x400?text=Product+1" },
1386
+ billingPolicy: { intervalCount: 1, interval: "MONTH" },
1387
+ deliveryPolicy: { intervalCount: 1, interval: "MONTH" },
846
1388
  customAttributes: [
847
- { key: "roast_level", value: "medium" },
848
- { key: "grind_type", value: "whole_bean" }
1389
+ { key: "skin_type", value: "combination" },
1390
+ { key: "fragrance", value: "fragrance_free" }
849
1391
  ]
850
1392
  }
851
1393
  ],
@@ -863,9 +1405,31 @@ function createMockSubscriptionAdapter(options = {}) {
863
1405
  frequency: "1 MONTH",
864
1406
  createdAt: "2024-10-01T00:00:00Z",
865
1407
  updatedAt: "2024-10-14T00:00:00Z",
1408
+ billingPolicy: { intervalCount: 1, interval: "MONTH", minCycles: 6 },
1409
+ deliveryPolicy: {
1410
+ intervalCount: 1,
1411
+ interval: "MONTH",
1412
+ anchors: [{ day: 15, type: "MONTHDAY" }]
1413
+ },
1414
+ nextBillingDate: "2025-11-15T00:00:00Z",
1415
+ nextBillingAttempt: { date: "2025-11-15T00:00:00Z", attempt: 1, ready: true },
1416
+ lastBillingAttempt: { date: "2025-10-15T00:00:00Z", ready: true },
1417
+ nextFulfillment: "2025-11-17T00:00:00Z",
1418
+ estimatedOrderDate: "2025-11-13T00:00:00Z",
1419
+ customerPaymentMethod: {
1420
+ id: "pm_1",
1421
+ instrument: { type: "credit_card", brand: "visa", maskedNumber: "************4242" },
1422
+ active: true,
1423
+ isRecurring: true
1424
+ },
1425
+ requiredBillingCyclesLeft: 3,
1426
+ renewal: { id: "ren_1", isInActiveProcessState: false },
1427
+ lastPaymentStatus: "succeeded",
1428
+ pausePeriod: null,
1429
+ isEditable: true,
866
1430
  customAttributes: [
867
1431
  { key: "subscription_tier", value: "premium" },
868
- { key: "gift_message", value: "Enjoy your coffee!" }
1432
+ { key: "gift_message", value: "Enjoy your skincare routine!" }
869
1433
  ]
870
1434
  },
871
1435
  {
@@ -874,11 +1438,17 @@ function createMockSubscriptionAdapter(options = {}) {
874
1438
  items: [
875
1439
  {
876
1440
  id: "item_2",
877
- productId: "product_2",
878
- variantId: "variant_2",
1441
+ // Aligned with the mock product catalog (createMockProductAdapter):
1442
+ // sample-2 "More COLLAGEN" (default variant), recurring price 10.99 EUR.
1443
+ productId: "sample-2",
1444
+ variantId: "sample-2-1",
879
1445
  quantity: 1,
880
- price: { amount: "49.99", currencyCode: "USD" },
1446
+ price: { amount: "10.99", currencyCode: "EUR" },
881
1447
  nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-20"),
1448
+ title: "More COLLAGEN",
1449
+ variantImage: { url: "https://placehold.co/400x400?text=Product+2" },
1450
+ billingPolicy: { intervalCount: 2, interval: "WEEK" },
1451
+ deliveryPolicy: { intervalCount: 2, interval: "WEEK" },
882
1452
  customAttributes: []
883
1453
  }
884
1454
  ],
@@ -889,17 +1459,66 @@ function createMockSubscriptionAdapter(options = {}) {
889
1459
  createdAt: "2024-09-15T00:00:00Z",
890
1460
  updatedAt: "2024-10-10T00:00:00Z",
891
1461
  customAttributes: []
1462
+ },
1463
+ // Per-status fixtures: groundwork for the deferred editor preview picker
1464
+ // (docs/superpowers/specs/2026-06-17-renewalsummary-parity-and-mock-groundwork-design.md §9).
1465
+ // Not consumed yet — the editor still seeds the active sub_1 via getDefaultSubscriptionId().
1466
+ {
1467
+ ...richBase("sub_paused", "item_paused", "ren_paused"),
1468
+ status: "paused",
1469
+ pausePeriod: { start: "2025-11-01T00:00:00Z", end: "2026-01-01T00:00:00Z" }
1470
+ },
1471
+ {
1472
+ ...richBase("sub_canceled", "item_canceled", "ren_canceled"),
1473
+ status: "canceled",
1474
+ pausePeriod: null
1475
+ },
1476
+ {
1477
+ ...richBase("sub_failed", "item_failed", "ren_failed"),
1478
+ status: "failed",
1479
+ lastPaymentStatus: "failed",
1480
+ pausePeriod: null
1481
+ },
1482
+ {
1483
+ ...richBase("sub_expired", "item_expired", "ren_expired"),
1484
+ status: "expired",
1485
+ pausePeriod: null
1486
+ }
1487
+ ];
1488
+ const mockUpsellProducts = [
1489
+ {
1490
+ id: "upsell-1",
1491
+ variantId: "upsell-v-1",
1492
+ title: "Retinol Night Cream",
1493
+ imageUrl: "https://images.unsplash.com/photo-1617897903246-719242758050?w=200",
1494
+ price: { amount: "38.00", currencyCode: "USD" },
1495
+ description: "Anti-aging night treatment"
1496
+ },
1497
+ {
1498
+ id: "upsell-2",
1499
+ variantId: "upsell-v-2",
1500
+ title: "SPF 50 Day Shield",
1501
+ imageUrl: "https://images.unsplash.com/photo-1556228578-8c89e6adf883?w=200",
1502
+ price: { amount: "24.00", currencyCode: "USD" },
1503
+ description: "Lightweight daily sun protection"
892
1504
  }
893
1505
  ];
894
1506
  return {
895
1507
  async getById(id) {
896
1508
  await new Promise((resolve) => setTimeout(resolve, 300));
897
- const subscription = mockSubscriptions.find((sub) => sub.id === id) || null;
898
- return { _tag: "Success", data: subscription };
1509
+ const subscription = mockSubscriptions.find((sub) => sub.id === id);
1510
+ return {
1511
+ _tag: "Success",
1512
+ data: subscription ? {
1513
+ ...subscription,
1514
+ items: subscription.items.map((item) => ({ ...item })),
1515
+ discounts: subscription.discounts.map((d3) => ({ ...d3 }))
1516
+ } : null
1517
+ };
899
1518
  },
900
1519
  async search(options2 = {}) {
901
1520
  await new Promise((resolve) => setTimeout(resolve, 300));
902
- const pageSize = 1;
1521
+ const pageSize = 2;
903
1522
  const allItems = mockSubscriptions;
904
1523
  let startIndex = 0;
905
1524
  let endIndex = pageSize;
@@ -915,27 +1534,82 @@ function createMockSubscriptionAdapter(options = {}) {
915
1534
  }
916
1535
  }
917
1536
  const pageItems = allItems.slice(startIndex, endIndex);
918
- const paginatedList = {
919
- items: pageItems.map((sub) => ({
920
- ...sub,
921
- items: sub.items.map((item) => ({ ...item })),
922
- discounts: sub.discounts.map((discount) => ({ ...discount }))
923
- })),
924
- pageInfo: {
925
- hasNextPage: endIndex < allItems.length,
926
- hasPrevPage: startIndex > 0,
927
- startCursor: pageItems.length > 0 ? startIndex.toString() : null,
928
- endCursor: pageItems.length > 0 ? (endIndex - 1).toString() : null
1537
+ return {
1538
+ _tag: "Success",
1539
+ data: {
1540
+ items: pageItems.map((sub) => ({
1541
+ ...sub,
1542
+ items: sub.items.map((item) => ({ ...item })),
1543
+ discounts: sub.discounts.map((discount) => ({ ...discount }))
1544
+ })),
1545
+ pageInfo: {
1546
+ hasNextPage: endIndex < allItems.length,
1547
+ hasPrevPage: startIndex > 0,
1548
+ startCursor: pageItems.length > 0 ? startIndex.toString() : null,
1549
+ endCursor: pageItems.length > 0 ? (endIndex - 1).toString() : null
1550
+ }
929
1551
  }
930
1552
  };
931
- return { _tag: "Success", data: paginatedList };
932
1553
  },
933
- async addItem() {
1554
+ async addItem({ subscriptionId, item }) {
1555
+ var _a, _b, _c, _d, _e, _f, _g;
1556
+ await new Promise((resolve) => setTimeout(resolve, 300));
1557
+ const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1558
+ if (!subscription) {
1559
+ return { _tag: "Failure", error: "Subscription not found" };
1560
+ }
1561
+ const currencyCode = ((_a = subscription.items[0]) == null ? void 0 : _a.price.currencyCode) ?? "USD";
1562
+ const product = await ((_b = options.productAdapter) == null ? void 0 : _b.getByVariantId(item.variantId)) ?? await ((_c = options.productAdapter) == null ? void 0 : _c.getById(item.variantId)) ?? null;
1563
+ const variant = (product == null ? void 0 : product.variants.items.find((v2) => v2.id === item.variantId)) ?? (product == null ? void 0 : product.variants.items[0]);
1564
+ const linePrice = ((_e = (_d = variant == null ? void 0 : variant.purchaseOptions) == null ? void 0 : _d[0]) == null ? void 0 : _e.price) ?? (variant == null ? void 0 : variant.price);
1565
+ subscription.items.push({
1566
+ id: `item_${Date.now()}_${subscription.items.length}`,
1567
+ productId: (product == null ? void 0 : product.id) ?? "",
1568
+ variantId: item.variantId,
1569
+ quantity: item.quantity,
1570
+ price: linePrice ? { ...linePrice } : { amount: "0.00", currencyCode },
1571
+ ...linePrice ? { currentPrice: { ...linePrice } } : {},
1572
+ title: (product == null ? void 0 : product.title) ?? `Product ${item.variantId}`,
1573
+ ...variant && product && !product.hasOnlyDefaultVariant ? { variantTitle: variant.title } : {},
1574
+ ...(variant == null ? void 0 : variant.image) ? { variantImage: variant.image } : {},
1575
+ variantAvailableForSale: true,
1576
+ billingPolicy: ((_f = subscription.items[0]) == null ? void 0 : _f.billingPolicy) ?? subscription.billingPolicy ?? null,
1577
+ deliveryPolicy: ((_g = subscription.items[0]) == null ? void 0 : _g.deliveryPolicy) ?? subscription.deliveryPolicy ?? null
1578
+ });
1579
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1580
+ return { _tag: "Success", data: void 0 };
1581
+ },
1582
+ async removeItem({ subscriptionId, itemId }) {
934
1583
  await new Promise((resolve) => setTimeout(resolve, 300));
1584
+ const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1585
+ if (!subscription) {
1586
+ return { _tag: "Failure", error: "Subscription not found" };
1587
+ }
1588
+ subscription.items = subscription.items.filter((i3) => i3.id !== itemId);
1589
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
935
1590
  return { _tag: "Success", data: void 0 };
936
1591
  },
937
- async removeItem() {
1592
+ async updateItem({ subscriptionId, lineId, update }) {
938
1593
  await new Promise((resolve) => setTimeout(resolve, 300));
1594
+ const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1595
+ if (!subscription) {
1596
+ return { _tag: "Failure", error: "Subscription not found" };
1597
+ }
1598
+ const item = subscription.items.find((i3) => i3.id === lineId);
1599
+ if (!item) {
1600
+ return { _tag: "Failure", error: "Line item not found" };
1601
+ }
1602
+ if (update.variantId !== void 0) item.variantId = update.variantId;
1603
+ if (update.quantity !== void 0) item.quantity = update.quantity;
1604
+ if (update.billingPolicy !== void 0) item.billingPolicy = update.billingPolicy;
1605
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1606
+ return { _tag: "Success", data: void 0 };
1607
+ },
1608
+ async skipLineItem() {
1609
+ await new Promise((resolve) => setTimeout(resolve, 300));
1610
+ return { _tag: "Success", data: void 0 };
1611
+ },
1612
+ async updateBoxItems() {
939
1613
  return { _tag: "Success", data: void 0 };
940
1614
  },
941
1615
  async addDiscount() {
@@ -966,24 +1640,11 @@ function createMockSubscriptionAdapter(options = {}) {
966
1640
  (sub) => sub.id === params.subscriptionId
967
1641
  );
968
1642
  if (!subscription) {
969
- return {
970
- _tag: "Failure",
971
- error: "Subscription not found"
972
- };
1643
+ return { _tag: "Failure", error: "Subscription not found" };
973
1644
  }
974
1645
  subscription.nextDeliveryDate = new Date(params.newDate);
975
1646
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
976
- subscription.items.forEach((item) => {
977
- item.nextDeliveryDate = new Date(params.newDate);
978
- });
979
- return {
980
- _tag: "Success",
981
- data: {
982
- ...subscription,
983
- items: subscription.items.map((item) => ({ ...item })),
984
- discounts: subscription.discounts.map((discount) => ({ ...discount }))
985
- }
986
- };
1647
+ return { _tag: "Success", data: { ...subscription } };
987
1648
  },
988
1649
  async resume(params) {
989
1650
  await new Promise((resolve) => setTimeout(resolve, 300));
@@ -991,21 +1652,11 @@ function createMockSubscriptionAdapter(options = {}) {
991
1652
  (sub) => sub.id === params.subscriptionId
992
1653
  );
993
1654
  if (!subscription) {
994
- return {
995
- _tag: "Failure",
996
- error: "Subscription not found"
997
- };
1655
+ return { _tag: "Failure", error: "Subscription not found" };
998
1656
  }
999
1657
  subscription.status = "active";
1000
1658
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1001
- return {
1002
- _tag: "Success",
1003
- data: {
1004
- ...subscription,
1005
- items: subscription.items.map((item) => ({ ...item })),
1006
- discounts: subscription.discounts.map((discount) => ({ ...discount }))
1007
- }
1008
- };
1659
+ return { _tag: "Success", data: { ...subscription } };
1009
1660
  },
1010
1661
  async pause(params) {
1011
1662
  await new Promise((resolve) => setTimeout(resolve, 300));
@@ -1013,21 +1664,11 @@ function createMockSubscriptionAdapter(options = {}) {
1013
1664
  (sub) => sub.id === params.subscriptionId
1014
1665
  );
1015
1666
  if (!subscription) {
1016
- return {
1017
- _tag: "Failure",
1018
- error: "Subscription not found"
1019
- };
1667
+ return { _tag: "Failure", error: "Subscription not found" };
1020
1668
  }
1021
1669
  subscription.status = "paused";
1022
1670
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1023
- return {
1024
- _tag: "Success",
1025
- data: {
1026
- ...subscription,
1027
- items: subscription.items.map((item) => ({ ...item })),
1028
- discounts: subscription.discounts.map((discount) => ({ ...discount }))
1029
- }
1030
- };
1671
+ return { _tag: "Success", data: { ...subscription } };
1031
1672
  },
1032
1673
  async reactivate(params) {
1033
1674
  await new Promise((resolve) => setTimeout(resolve, 300));
@@ -1035,21 +1676,11 @@ function createMockSubscriptionAdapter(options = {}) {
1035
1676
  (sub) => sub.id === params.subscriptionId
1036
1677
  );
1037
1678
  if (!subscription) {
1038
- return {
1039
- _tag: "Failure",
1040
- error: "Subscription not found"
1041
- };
1679
+ return { _tag: "Failure", error: "Subscription not found" };
1042
1680
  }
1043
1681
  subscription.status = "active";
1044
1682
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1045
- return {
1046
- _tag: "Success",
1047
- data: {
1048
- ...subscription,
1049
- items: subscription.items.map((item) => ({ ...item })),
1050
- discounts: subscription.discounts.map((discount) => ({ ...discount }))
1051
- }
1052
- };
1683
+ return { _tag: "Success", data: { ...subscription } };
1053
1684
  },
1054
1685
  async cancel(params) {
1055
1686
  await new Promise((resolve) => setTimeout(resolve, 300));
@@ -1057,21 +1688,11 @@ function createMockSubscriptionAdapter(options = {}) {
1057
1688
  (sub) => sub.id === params.subscriptionId
1058
1689
  );
1059
1690
  if (!subscription) {
1060
- return {
1061
- _tag: "Failure",
1062
- error: "Subscription not found"
1063
- };
1691
+ return { _tag: "Failure", error: "Subscription not found" };
1064
1692
  }
1065
1693
  subscription.status = "canceled";
1066
1694
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1067
- return {
1068
- _tag: "Success",
1069
- data: {
1070
- ...subscription,
1071
- items: subscription.items.map((item) => ({ ...item })),
1072
- discounts: subscription.discounts.map((discount) => ({ ...discount }))
1073
- }
1074
- };
1695
+ return { _tag: "Success", data: { ...subscription } };
1075
1696
  },
1076
1697
  async getAvailablePlans() {
1077
1698
  await new Promise((resolve) => setTimeout(resolve, 300));
@@ -1099,13 +1720,873 @@ function createMockSubscriptionAdapter(options = {}) {
1099
1720
  ]
1100
1721
  };
1101
1722
  },
1723
+ async getLastOrder(params) {
1724
+ await new Promise((resolve) => setTimeout(resolve, 200));
1725
+ const subscription = mockSubscriptions.find((sub) => sub.id === params.subscriptionId);
1726
+ if (!subscription) return { _tag: "Success", data: null };
1727
+ return {
1728
+ _tag: "Success",
1729
+ data: {
1730
+ id: `mock_last_order_${params.subscriptionId}`,
1731
+ createdAt: "2026-04-22T12:00:00Z"
1732
+ }
1733
+ };
1734
+ },
1735
+ async renewNow(_params) {
1736
+ await new Promise((resolve) => setTimeout(resolve, 300));
1737
+ return { _tag: "Success", data: { result: "success" } };
1738
+ },
1739
+ async changeFrequency(params) {
1740
+ await new Promise((resolve) => setTimeout(resolve, 300));
1741
+ const subscription = mockSubscriptions.find((sub) => sub.id === params.subscriptionId);
1742
+ if (!subscription) {
1743
+ return { _tag: "Failure", error: "Subscription not found" };
1744
+ }
1745
+ if (typeof params.plan === "string") {
1746
+ subscription.frequency = `1 ${params.plan}`;
1747
+ } else {
1748
+ subscription.frequency = `${params.plan.intervalCount} ${params.plan.interval}`;
1749
+ if (subscription.billingPolicy) {
1750
+ subscription.billingPolicy = { ...subscription.billingPolicy, ...params.plan };
1751
+ }
1752
+ if (subscription.deliveryPolicy) {
1753
+ subscription.deliveryPolicy = { ...subscription.deliveryPolicy, ...params.plan };
1754
+ }
1755
+ }
1756
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1757
+ return {
1758
+ _tag: "Success",
1759
+ data: {
1760
+ ...subscription,
1761
+ items: subscription.items.map((item) => ({ ...item })),
1762
+ discounts: subscription.discounts.map((d3) => ({ ...d3 }))
1763
+ }
1764
+ };
1765
+ },
1102
1766
  async getDefaultSubscriptionId() {
1103
1767
  var _a;
1104
1768
  await new Promise((resolve) => setTimeout(resolve, 300));
1105
1769
  return { _tag: "Success", data: ((_a = mockSubscriptions[0]) == null ? void 0 : _a.id) ?? null };
1770
+ },
1771
+ async getUpsellProducts() {
1772
+ await new Promise((resolve) => setTimeout(resolve, 300));
1773
+ return { _tag: "Success", data: [...mockUpsellProducts] };
1774
+ },
1775
+ async addUpsellProduct() {
1776
+ await new Promise((resolve) => setTimeout(resolve, 400));
1777
+ return { _tag: "Success", data: void 0 };
1778
+ }
1779
+ };
1780
+ }
1781
+ function normalizeInstrumentType(type) {
1782
+ return type.replace(/-/g, "_");
1783
+ }
1784
+ function mapPaymentMethod(rawPm) {
1785
+ if (!rawPm) return null;
1786
+ if (typeof rawPm === "string") {
1787
+ return { id: rawPm };
1788
+ }
1789
+ return {
1790
+ id: rawPm.id ?? "",
1791
+ ...rawPm.instrument != null ? {
1792
+ instrument: {
1793
+ ...rawPm.instrument,
1794
+ type: normalizeInstrumentType(rawPm.instrument.type)
1795
+ }
1796
+ } : {},
1797
+ ...rawPm.active != null ? { active: rawPm.active } : {},
1798
+ ...rawPm.isRecurring != null ? { isRecurring: rawPm.isRecurring } : {}
1799
+ };
1800
+ }
1801
+ function mapSubscription(raw) {
1802
+ var _a, _b;
1803
+ const status = raw.status === "merged" ? "canceled" : raw.status;
1804
+ const deliveryPolicy = raw.deliveryPolicy ?? ((_b = (_a = raw.items) == null ? void 0 : _a[0]) == null ? void 0 : _b.deliveryPolicy);
1805
+ const frequency = deliveryPolicy ? `${deliveryPolicy.intervalCount} ${deliveryPolicy.interval}` : "";
1806
+ return {
1807
+ id: raw.id,
1808
+ customerId: "",
1809
+ serial: raw.serial,
1810
+ items: (raw.items ?? []).map(
1811
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1812
+ (item) => ({
1813
+ id: item.id,
1814
+ productId: item.productId ?? item.product ?? "",
1815
+ variantId: item.variantId ?? item.variant ?? "",
1816
+ quantity: item.quantity,
1817
+ price: item.price ?? {
1818
+ amount: String(item.totalPrice ?? 0),
1819
+ currencyCode: raw.currencyCode ?? ""
1820
+ },
1821
+ nextDeliveryDate: item.nextDeliveryDate ? new Date(item.nextDeliveryDate) : null,
1822
+ billingPolicy: item.billingPolicy ?? raw.billingPolicy ?? null,
1823
+ deliveryPolicy: item.deliveryPolicy ?? raw.deliveryPolicy ?? null,
1824
+ // Map human-readable titles from the v1 SubscriptionItemResource
1825
+ title: item.title,
1826
+ variantTitle: item.subtitle ?? void 0,
1827
+ // recurringCycleLimit === 1 means the item charges exactly once (one-time upsell)
1828
+ recurringCycleLimit: item.recurringCycleLimit ?? null,
1829
+ customAttributes: Array.isArray(item.customAttributes) ? item.customAttributes : []
1830
+ })
1831
+ ),
1832
+ discounts: (raw.discounts ?? []).map(
1833
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1834
+ (d3) => {
1835
+ var _a2, _b2, _c;
1836
+ return {
1837
+ id: d3.id,
1838
+ type: ((_a2 = d3.value) == null ? void 0 : _a2.type) === "fixed-amount" || d3.type === "fixed_amount" ? "fixed_amount" : "percentage",
1839
+ value: ((_b2 = d3.value) == null ? void 0 : _b2.amount) ?? ((_c = d3.value) == null ? void 0 : _c.percentage) ?? d3.value ?? 0,
1840
+ code: d3.title ?? d3.code ?? "",
1841
+ description: d3.description ?? ""
1842
+ };
1843
+ }
1844
+ ),
1845
+ status,
1846
+ nextDeliveryDate: raw.nextBillingDate ? new Date(raw.nextBillingDate) : raw.nextDeliveryDate ? new Date(raw.nextDeliveryDate) : null,
1847
+ // Map nextBillingDate as the raw ISO string for ProductSelect skip() and other consumers
1848
+ nextBillingDate: raw.nextBillingDate ?? null,
1849
+ // Map customerPaymentMethod — note: arrives as bare id (not expanded) since the
1850
+ // subscriptions endpoint does not support ?expand=paymentMethod; instrument digits
1851
+ // remain a data gap pending backend API extension.
1852
+ customerPaymentMethod: mapPaymentMethod(raw.paymentMethod),
1853
+ frequency,
1854
+ createdAt: raw.createdAt,
1855
+ updatedAt: raw.updatedAt,
1856
+ billingPolicy: raw.billingPolicy ?? null,
1857
+ deliveryPolicy: raw.deliveryPolicy ?? null
1858
+ };
1859
+ }
1860
+ function createApiSubscriptionAdapter(fetcher) {
1861
+ const adapter = {
1862
+ async search(options) {
1863
+ var _a;
1864
+ try {
1865
+ const params = new URLSearchParams();
1866
+ if ((_a = options == null ? void 0 : options.filters) == null ? void 0 : _a.length) {
1867
+ const q2 = options.filters.filter((f2) => Object.keys(f2).length > 0).flatMap((f2) => Object.entries(f2).filter(([, v2]) => Boolean(v2))).map(([k, v2]) => `${k}:'${v2}'`).join(" AND ");
1868
+ if (q2) params.set("query", q2);
1869
+ }
1870
+ if (options == null ? void 0 : options.pagination) {
1871
+ if ("after" in options.pagination)
1872
+ params.set("after", options.pagination.after);
1873
+ else if ("before" in options.pagination)
1874
+ params.set("before", options.pagination.before);
1875
+ }
1876
+ const query = params.toString() ? `?${params.toString()}` : "";
1877
+ const res = await fetcher(`/customer/v1/subscriptions${query}`);
1878
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1879
+ const body = await res.json();
1880
+ return {
1881
+ _tag: "Success",
1882
+ data: {
1883
+ items: body.data.map(mapSubscription),
1884
+ pageInfo: {
1885
+ hasNextPage: body.hasNextPage,
1886
+ hasPrevPage: body.hasPrevPage,
1887
+ startCursor: body.startCursor,
1888
+ endCursor: body.endCursor
1889
+ }
1890
+ }
1891
+ };
1892
+ } catch (e2) {
1893
+ return { _tag: "Failure", error: e2 };
1894
+ }
1895
+ },
1896
+ async getById(id) {
1897
+ try {
1898
+ const res = await fetcher(
1899
+ `/customer/v1/subscriptions?query=id:"${id}"&limit=1`
1900
+ );
1901
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1902
+ const body = await res.json();
1903
+ const raw = body.data[0];
1904
+ return { _tag: "Success", data: raw ? mapSubscription(raw) : null };
1905
+ } catch (e2) {
1906
+ return { _tag: "Failure", error: e2 };
1907
+ }
1908
+ },
1909
+ async addItem({ subscriptionId, item }) {
1910
+ try {
1911
+ const res = await fetcher(
1912
+ `/customer/v1/subscriptions/${subscriptionId}/items`,
1913
+ {
1914
+ method: "POST",
1915
+ headers: { "Content-Type": "application/json" },
1916
+ body: JSON.stringify(item)
1917
+ }
1918
+ );
1919
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1920
+ return { _tag: "Success", data: void 0 };
1921
+ } catch (e2) {
1922
+ return { _tag: "Failure", error: e2 };
1923
+ }
1924
+ },
1925
+ async removeItem({ subscriptionId, itemId }) {
1926
+ try {
1927
+ const res = await fetcher(
1928
+ `/customer/v1/subscriptions/${subscriptionId}/items/${itemId}`,
1929
+ { method: "DELETE" }
1930
+ );
1931
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1932
+ return { _tag: "Success", data: void 0 };
1933
+ } catch (e2) {
1934
+ return { _tag: "Failure", error: e2 };
1935
+ }
1936
+ },
1937
+ async updateItem({ subscriptionId, lineId, update }) {
1938
+ try {
1939
+ const body = {
1940
+ ...update.variantId !== void 0 ? { productVariantId: update.variantId } : {},
1941
+ ...update.quantity !== void 0 ? { quantity: update.quantity } : {},
1942
+ ...update.billingPolicy !== void 0 ? { billingPolicy: update.billingPolicy } : {},
1943
+ ...update.shippingMethodHandle !== void 0 ? { shippingMethodHandle: update.shippingMethodHandle } : {}
1944
+ };
1945
+ const res = await fetcher(
1946
+ `/customer/subscriptions/${subscriptionId}/lines/${lineId}`,
1947
+ {
1948
+ method: "PUT",
1949
+ headers: { "Content-Type": "application/json" },
1950
+ body: JSON.stringify(body)
1951
+ }
1952
+ );
1953
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1954
+ return { _tag: "Success", data: void 0 };
1955
+ } catch (e2) {
1956
+ return { _tag: "Failure", error: e2 };
1957
+ }
1958
+ },
1959
+ async skipLineItem({ subscriptionId, lineId, nextBillingDate }) {
1960
+ try {
1961
+ const res = await fetcher(
1962
+ `/customer/subscriptions/${subscriptionId}/lines/${lineId}`,
1963
+ {
1964
+ method: "PUT",
1965
+ headers: { "Content-Type": "application/json" },
1966
+ body: JSON.stringify({ nextBillingDate })
1967
+ }
1968
+ );
1969
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1970
+ return { _tag: "Success", data: void 0 };
1971
+ } catch (e2) {
1972
+ return { _tag: "Failure", error: e2 };
1973
+ }
1974
+ },
1975
+ async updateBoxItems({ subscriptionId, parentId, items, shippingMethodHandle }) {
1976
+ try {
1977
+ const res = await fetcher(
1978
+ `/customer/subscriptions/${subscriptionId}/update-box-products`,
1979
+ {
1980
+ method: "POST",
1981
+ headers: { "Content-Type": "application/json" },
1982
+ body: JSON.stringify({ parentId, items, shippingMethodHandle })
1983
+ }
1984
+ );
1985
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1986
+ return { _tag: "Success", data: void 0 };
1987
+ } catch (e2) {
1988
+ return { _tag: "Failure", error: e2 };
1989
+ }
1990
+ },
1991
+ async addDiscount({ subscriptionId, code }) {
1992
+ try {
1993
+ const res = await fetcher(
1994
+ `/customer/v1/subscriptions/${subscriptionId}/discounts`,
1995
+ {
1996
+ method: "POST",
1997
+ headers: { "Content-Type": "application/json" },
1998
+ body: JSON.stringify({ code })
1999
+ }
2000
+ );
2001
+ if (!res.ok) return { _tag: "Failure", error: { kind: "NETWORK", message: `HTTP ${res.status}` } };
2002
+ return { _tag: "Success", data: void 0 };
2003
+ } catch (e2) {
2004
+ return { _tag: "Failure", error: { kind: "UNKNOWN", message: e2 instanceof Error ? e2.message : void 0 } };
2005
+ }
2006
+ },
2007
+ async removeDiscount({ subscriptionId, discountId }) {
2008
+ try {
2009
+ const res = await fetcher(
2010
+ `/customer/v1/subscriptions/${subscriptionId}/discounts/${discountId}`,
2011
+ { method: "DELETE" }
2012
+ );
2013
+ if (!res.ok) return { _tag: "Failure", error: { kind: "NETWORK", message: `HTTP ${res.status}` } };
2014
+ return { _tag: "Success", data: void 0 };
2015
+ } catch (e2) {
2016
+ return { _tag: "Failure", error: { kind: "UNKNOWN", message: e2 instanceof Error ? e2.message : void 0 } };
2017
+ }
2018
+ },
2019
+ // Uses PATCH /customer/v1/subscriptions/{id} — the dedicated /reschedule route does not exist.
2020
+ async reschedule({ subscriptionId, newDate }) {
2021
+ try {
2022
+ const res = await fetcher(
2023
+ `/customer/v1/subscriptions/${subscriptionId}`,
2024
+ {
2025
+ method: "PATCH",
2026
+ headers: { "Content-Type": "application/json" },
2027
+ body: JSON.stringify({ nextBillingDate: newDate })
2028
+ }
2029
+ );
2030
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2031
+ const data = await res.json();
2032
+ return { _tag: "Success", data: mapSubscription(data) };
2033
+ } catch (e2) {
2034
+ return { _tag: "Failure", error: e2 };
2035
+ }
2036
+ },
2037
+ async resume({ subscriptionId }) {
2038
+ try {
2039
+ const res = await fetcher(
2040
+ `/customer/v1/subscriptions/${subscriptionId}/resume`,
2041
+ { method: "POST" }
2042
+ );
2043
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2044
+ const data = await res.json();
2045
+ return { _tag: "Success", data: mapSubscription(data) };
2046
+ } catch (e2) {
2047
+ return { _tag: "Failure", error: e2 };
2048
+ }
2049
+ },
2050
+ async pause({ subscriptionId }) {
2051
+ try {
2052
+ const res = await fetcher(
2053
+ `/customer/v1/subscriptions/${subscriptionId}/pause`,
2054
+ { method: "POST" }
2055
+ );
2056
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2057
+ const data = await res.json();
2058
+ return { _tag: "Success", data: mapSubscription(data) };
2059
+ } catch (e2) {
2060
+ return { _tag: "Failure", error: e2 };
2061
+ }
2062
+ },
2063
+ async reactivate({ subscriptionId }) {
2064
+ try {
2065
+ const res = await fetcher(
2066
+ `/customer/v1/subscriptions/${subscriptionId}/reactivate`,
2067
+ { method: "POST" }
2068
+ );
2069
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2070
+ const data = await res.json();
2071
+ return { _tag: "Success", data: mapSubscription(data) };
2072
+ } catch (e2) {
2073
+ return { _tag: "Failure", error: e2 };
2074
+ }
2075
+ },
2076
+ async cancel({ subscriptionId, reason }) {
2077
+ try {
2078
+ const res = await fetcher(
2079
+ `/customer/v1/subscriptions/${subscriptionId}/cancel`,
2080
+ {
2081
+ method: "POST",
2082
+ headers: { "Content-Type": "application/json" },
2083
+ body: JSON.stringify({ cancellationReason: reason })
2084
+ }
2085
+ );
2086
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2087
+ const data = await res.json();
2088
+ return { _tag: "Success", data: mapSubscription(data) };
2089
+ } catch (e2) {
2090
+ return { _tag: "Failure", error: e2 };
2091
+ }
2092
+ },
2093
+ // Legacy endpoint — no /customer/v1/subscriptions/{id}/plans exists yet.
2094
+ async getAvailablePlans({ subscriptionId }) {
2095
+ try {
2096
+ const res = await fetcher(
2097
+ `/customer/subscriptions/${subscriptionId}/plans`
2098
+ );
2099
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2100
+ const data = await res.json();
2101
+ return { _tag: "Success", data };
2102
+ } catch (e2) {
2103
+ return { _tag: "Failure", error: e2 };
2104
+ }
2105
+ },
2106
+ // Legacy endpoint — no /customer/v1 equivalent exists yet.
2107
+ async getDefaultSubscriptionId() {
2108
+ try {
2109
+ const res = await fetcher(
2110
+ `/customer/subscriptions/one-by-next-billing-date`
2111
+ );
2112
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2113
+ const data = await res.json();
2114
+ return { _tag: "Success", data: (data == null ? void 0 : data.id) ?? null };
2115
+ } catch (e2) {
2116
+ return { _tag: "Failure", error: e2 };
2117
+ }
2118
+ },
2119
+ // Legacy endpoint — no /customer/v1/subscriptions/{id}/upsells exists yet.
2120
+ async getUpsellProducts({ subscriptionId }) {
2121
+ try {
2122
+ const res = await fetcher(
2123
+ `/customer/subscriptions/${subscriptionId}/upsell-products`
2124
+ );
2125
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2126
+ const data = await res.json();
2127
+ const products = data.map((p2) => {
2128
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2129
+ return {
2130
+ id: p2.id,
2131
+ variantId: ((_b = (_a = p2.variants) == null ? void 0 : _a[0]) == null ? void 0 : _b.id) ?? "",
2132
+ title: p2.title ?? "",
2133
+ imageUrl: ((_c = p2.featuredImage) == null ? void 0 : _c.url) ?? void 0,
2134
+ price: {
2135
+ amount: String(((_f = (_e = (_d = p2.variants) == null ? void 0 : _d[0]) == null ? void 0 : _e.currentPrice) == null ? void 0 : _f.amount) ?? 0),
2136
+ currencyCode: ((_i = (_h = (_g = p2.variants) == null ? void 0 : _g[0]) == null ? void 0 : _h.currentPrice) == null ? void 0 : _i.currencyCode) ?? ""
2137
+ },
2138
+ // recurring comes from the upsell rule on variants[0]; present in PreparedProductSchema
2139
+ recurring: (_k = (_j = p2.variants) == null ? void 0 : _j[0]) == null ? void 0 : _k.recurring
2140
+ };
2141
+ });
2142
+ return { _tag: "Success", data: products };
2143
+ } catch (e2) {
2144
+ return { _tag: "Failure", error: e2 };
2145
+ }
2146
+ },
2147
+ // Legacy endpoint — no /customer/v1/subscriptions/{id}/upsells POST exists yet.
2148
+ async addUpsellProduct({ subscriptionId, variantId, quantity, oneTime }) {
2149
+ try {
2150
+ const res = await fetcher(
2151
+ `/customer/subscriptions/${subscriptionId}/upsell`,
2152
+ {
2153
+ method: "POST",
2154
+ headers: { "Content-Type": "application/json" },
2155
+ body: JSON.stringify({
2156
+ productVariantId: variantId,
2157
+ quantity,
2158
+ ...oneTime ? { renewalLimit: 1 } : {}
2159
+ })
2160
+ }
2161
+ );
2162
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2163
+ return { _tag: "Success", data: void 0 };
2164
+ } catch (e2) {
2165
+ return { _tag: "Failure", error: e2 };
2166
+ }
2167
+ },
2168
+ // Legacy endpoint — no /customer/v1 equivalent exists yet.
2169
+ async getLastOrder({ subscriptionId }) {
2170
+ try {
2171
+ const res = await fetcher(
2172
+ `/customer/subscriptions/${subscriptionId}/last-order`
2173
+ );
2174
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2175
+ const data = await res.json();
2176
+ if (!data) return { _tag: "Success", data: null };
2177
+ return {
2178
+ _tag: "Success",
2179
+ data: { id: data.id, createdAt: data.createdAt }
2180
+ };
2181
+ } catch (e2) {
2182
+ return { _tag: "Failure", error: e2 };
2183
+ }
2184
+ },
2185
+ // Legacy endpoints, split by stage (see SubscriptionService.renewNow docs):
2186
+ // retry → POST /customer/subscriptions/{id}/retry
2187
+ // renewalId → POST /customer/renewals/{renewalId}/renew
2188
+ // default → POST /customer/subscriptions/{id}/order-now
2189
+ async renewNow({ subscriptionId, renewalId, retry }) {
2190
+ try {
2191
+ const url = retry ? `/customer/subscriptions/${subscriptionId}/retry` : renewalId ? `/customer/renewals/${renewalId}/renew` : `/customer/subscriptions/${subscriptionId}/order-now`;
2192
+ const res = await fetcher(url, { method: "POST" });
2193
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2194
+ const body = res.status === 204 ? null : await res.json();
2195
+ return {
2196
+ _tag: "Success",
2197
+ data: {
2198
+ nextActionUrl: (body == null ? void 0 : body.nextActionUrl) ?? void 0,
2199
+ result: (body == null ? void 0 : body.result) ?? "success"
2200
+ }
2201
+ };
2202
+ } catch (e2) {
2203
+ return { _tag: "Failure", error: e2 };
2204
+ }
2205
+ },
2206
+ // Legacy endpoint — POST /plan returns 204; re-fetch to return the updated subscription.
2207
+ async changeFrequency({ subscriptionId, plan }) {
2208
+ try {
2209
+ const res = await fetcher(
2210
+ `/customer/subscriptions/${subscriptionId}/plan`,
2211
+ {
2212
+ method: "POST",
2213
+ headers: { "Content-Type": "application/json" },
2214
+ body: JSON.stringify({ plan })
2215
+ }
2216
+ );
2217
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2218
+ const refreshed = await adapter.getById(subscriptionId);
2219
+ if (refreshed._tag === "Failure") return refreshed;
2220
+ if (refreshed.data) return { _tag: "Success", data: refreshed.data };
2221
+ return {
2222
+ _tag: "Failure",
2223
+ error: "Subscription not found after frequency change"
2224
+ };
2225
+ } catch (e2) {
2226
+ return { _tag: "Failure", error: e2 };
2227
+ }
2228
+ }
2229
+ };
2230
+ return adapter;
2231
+ }
2232
+ const DELIVERY_PRICE_CENTS = 500;
2233
+ const DELIVERY_OFFSET_DAYS = 2;
2234
+ function toCents(amount) {
2235
+ const n2 = Number.parseFloat(amount ?? "0");
2236
+ return Number.isFinite(n2) ? Math.round(n2 * 100) : 0;
2237
+ }
2238
+ function addInterval(date, interval, units) {
2239
+ const d3 = new Date(date);
2240
+ switch (interval) {
2241
+ case "DAY":
2242
+ d3.setDate(d3.getDate() + units);
2243
+ break;
2244
+ case "WEEK":
2245
+ d3.setDate(d3.getDate() + units * 7);
2246
+ break;
2247
+ case "YEAR":
2248
+ d3.setFullYear(d3.getFullYear() + units);
2249
+ break;
2250
+ default:
2251
+ d3.setMonth(d3.getMonth() + units);
2252
+ break;
2253
+ }
2254
+ return d3;
2255
+ }
2256
+ function mapItem(sub, item, cycle) {
2257
+ var _a, _b;
2258
+ const price = toCents(((_a = item.currentPrice) == null ? void 0 : _a.amount) ?? item.price.amount);
2259
+ return {
2260
+ id: `${sub.id}_cycle_${cycle}_${item.id}`,
2261
+ title: item.title ?? `Product ${item.variantId}`,
2262
+ subtitle: item.variantTitle ?? null,
2263
+ imageUrl: (_b = item.variantImage) == null ? void 0 : _b.url,
2264
+ variantId: item.variantId,
2265
+ quantity: item.quantity,
2266
+ price,
2267
+ totalPrice: price * item.quantity,
2268
+ variantImage: item.variantImage ?? null,
2269
+ variantAvailableForSale: item.variantAvailableForSale ?? true,
2270
+ subscriptionId: sub.id,
2271
+ subscriptionLineId: item.id,
2272
+ productId: item.productId,
2273
+ parentProductId: item.parentProductId ?? null,
2274
+ parentLineId: item.parentLineId ?? null,
2275
+ isVirtual: item.isVirtual ?? false,
2276
+ isUpsell: item.isUpsell ?? false,
2277
+ recurringCycleLimit: item.recurringCycleLimit ?? null,
2278
+ customAttributes: item.customAttributes ?? []
2279
+ };
2280
+ }
2281
+ function projectUpcomingOrders(sub, count) {
2282
+ var _a, _b;
2283
+ if (sub.status !== "active") return [];
2284
+ const billing = sub.billingPolicy ?? ((_a = sub.items[0]) == null ? void 0 : _a.billingPolicy) ?? { interval: "MONTH", intervalCount: 1 };
2285
+ const baseStr = sub.nextBillingDate ?? (sub.nextDeliveryDate ? sub.nextDeliveryDate.toISOString() : null);
2286
+ const base = baseStr ? new Date(baseStr) : /* @__PURE__ */ new Date();
2287
+ const currencyCode = ((_b = sub.items[0]) == null ? void 0 : _b.price.currencyCode) ?? "USD";
2288
+ const orders = [];
2289
+ for (let cycle = 0; cycle < count; cycle++) {
2290
+ const billingDate = addInterval(
2291
+ base,
2292
+ billing.interval,
2293
+ cycle * billing.intervalCount
2294
+ );
2295
+ const deliveryDate = addInterval(billingDate, "DAY", DELIVERY_OFFSET_DAYS);
2296
+ const items = sub.items.map((item) => mapItem(sub, item, cycle));
2297
+ const subtotal = items.reduce((sum, it) => sum + it.totalPrice, 0);
2298
+ orders.push({
2299
+ id: `${sub.id}_cycle_${cycle}`,
2300
+ customerId: sub.customerId,
2301
+ subscriptionId: sub.id,
2302
+ date: billingDate.toISOString(),
2303
+ skipped: false,
2304
+ currencyCode,
2305
+ subtotal,
2306
+ deliveryPrice: DELIVERY_PRICE_CENTS,
2307
+ cycleIndex: cycle,
2308
+ deliveryDate: deliveryDate.toISOString(),
2309
+ status: "scheduled",
2310
+ items,
2311
+ discounts: sub.discounts.map((d3) => ({
2312
+ id: d3.id,
2313
+ title: d3.code,
2314
+ type: d3.type,
2315
+ value: d3.value
2316
+ }))
2317
+ });
2318
+ }
2319
+ return orders;
2320
+ }
2321
+ function applyAdjustments(orders, adjustments) {
2322
+ return orders.map((order) => {
2323
+ let next = order;
2324
+ for (const adj of adjustments) {
2325
+ if (adj.subscriptionId !== order.subscriptionId) continue;
2326
+ if (adj.cycle !== order.cycleIndex) continue;
2327
+ if (adj.type === "skip") {
2328
+ next = { ...next, skipped: true, status: "skipped" };
2329
+ } else if (adj.type === "date_change" && adj.newDate) {
2330
+ next = { ...next, date: adj.newDate, deliveryDate: adj.newDate };
2331
+ }
2332
+ }
2333
+ return next;
2334
+ });
2335
+ }
2336
+ function createMockSchedulesAdapter(subscriptions = createMockSubscriptionAdapter()) {
2337
+ const RESOLVE_DEPTH = 12;
2338
+ let adjustments = [];
2339
+ async function subscriptionsToProject(subscriptionId) {
2340
+ if (subscriptionId) {
2341
+ const res = await subscriptions.getById(subscriptionId);
2342
+ return res._tag === "Success" && res.data ? [res.data] : [];
2343
+ }
2344
+ const all = [];
2345
+ let pagination;
2346
+ for (let guard = 0; guard < 50; guard++) {
2347
+ const res = await subscriptions.search(pagination ? { pagination } : {});
2348
+ if (res._tag !== "Success") break;
2349
+ all.push(...res.data.items);
2350
+ const { hasNextPage, endCursor } = res.data.pageInfo;
2351
+ if (!hasNextPage || !endCursor) break;
2352
+ pagination = { after: endCursor };
2353
+ }
2354
+ return all;
2355
+ }
2356
+ function resolveCycle(orders, opts) {
2357
+ if (opts.cycle != null) return opts.cycle;
2358
+ if (opts.date) {
2359
+ const target = new Date(opts.date).toISOString().split("T")[0];
2360
+ const match = orders.find(
2361
+ (o2) => o2.deliveryDate.split("T")[0] === target || o2.date.split("T")[0] === target
2362
+ );
2363
+ if (match) return match.cycleIndex;
2364
+ }
2365
+ const firstScheduled = orders.find((o2) => o2.status === "scheduled");
2366
+ return (firstScheduled == null ? void 0 : firstScheduled.cycleIndex) ?? null;
2367
+ }
2368
+ async function recordAdjustment(subscriptionId, opts, build) {
2369
+ const res = await subscriptions.getById(subscriptionId);
2370
+ const sub = res._tag === "Success" ? res.data : null;
2371
+ if (!sub) return { _tag: "Failure", error: "No scheduled order found" };
2372
+ const orders = applyAdjustments(
2373
+ projectUpcomingOrders(sub, RESOLVE_DEPTH),
2374
+ adjustments
2375
+ );
2376
+ const cycle = resolveCycle(orders, opts);
2377
+ if (cycle == null) {
2378
+ return { _tag: "Failure", error: "No scheduled order found" };
2379
+ }
2380
+ adjustments = [...adjustments, build(cycle)];
2381
+ return { _tag: "Success", data: void 0 };
2382
+ }
2383
+ return {
2384
+ async getUpcomingOrders({ count, subscriptionId }) {
2385
+ await new Promise((r) => setTimeout(r, 200));
2386
+ const subs = await subscriptionsToProject(subscriptionId);
2387
+ const orders = subs.flatMap(
2388
+ (sub) => applyAdjustments(projectUpcomingOrders(sub, count), adjustments)
2389
+ ).sort((a3, b3) => a3.date.localeCompare(b3.date));
2390
+ return { _tag: "Success", data: orders.slice(0, count) };
2391
+ },
2392
+ async getAdjustments() {
2393
+ await new Promise((r) => setTimeout(r, 200));
2394
+ return { _tag: "Success", data: [...adjustments] };
2395
+ },
2396
+ async skipOrder({ subscriptionId, cycle, date }) {
2397
+ await new Promise((r) => setTimeout(r, 300));
2398
+ return recordAdjustment(subscriptionId, { cycle, date }, (resolved) => ({
2399
+ id: `adj-${Date.now()}`,
2400
+ subscriptionId,
2401
+ type: "skip",
2402
+ cycle: resolved
2403
+ }));
2404
+ },
2405
+ async changeDateAdjustment({ subscriptionId, newDate, currentDate }) {
2406
+ await new Promise((r) => setTimeout(r, 300));
2407
+ return recordAdjustment(
2408
+ subscriptionId,
2409
+ { date: currentDate },
2410
+ (resolved) => ({
2411
+ id: `adj-${Date.now()}`,
2412
+ subscriptionId,
2413
+ type: "date_change",
2414
+ cycle: resolved,
2415
+ newDate
2416
+ })
2417
+ );
2418
+ },
2419
+ async removeAdjustment({ adjustmentId }) {
2420
+ await new Promise((r) => setTimeout(r, 200));
2421
+ adjustments = adjustments.filter((a3) => a3.id !== adjustmentId);
2422
+ return { _tag: "Success", data: void 0 };
2423
+ }
2424
+ };
2425
+ }
2426
+ function createApiSchedulesAdapter(fetcher) {
2427
+ return {
2428
+ async getUpcomingOrders({ count, subscriptionId }) {
2429
+ try {
2430
+ const params = new URLSearchParams({ count: String(count) });
2431
+ if (subscriptionId) params.set("query", `id:"${subscriptionId}"`);
2432
+ const res = await fetcher(`/customer/v1/schedules/?${params.toString()}`);
2433
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2434
+ const data = await res.json();
2435
+ return { _tag: "Success", data: data.orders };
2436
+ } catch (e2) {
2437
+ return { _tag: "Failure", error: e2 };
2438
+ }
2439
+ },
2440
+ async getAdjustments() {
2441
+ try {
2442
+ const res = await fetcher(`/customer/v1/schedules/adjustments`);
2443
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2444
+ const data = await res.json();
2445
+ const adjustments = data.data.map((a3) => ({
2446
+ id: a3.id,
2447
+ subscriptionId: a3.subscriptionId ?? "",
2448
+ type: a3.type === "CHANGE_DATE" ? "date_change" : "skip",
2449
+ newDate: a3.newDate
2450
+ }));
2451
+ return { _tag: "Success", data: adjustments };
2452
+ } catch (e2) {
2453
+ return { _tag: "Failure", error: e2 };
2454
+ }
2455
+ },
2456
+ async skipOrder({ cycle, date }) {
2457
+ if (cycle == null && date == null) {
2458
+ return { _tag: "Failure", error: "Either cycle or date is required for skipOrder" };
2459
+ }
2460
+ try {
2461
+ const matcher = cycle != null ? { type: "CYCLE", input: { cycle } } : { type: "DATE", input: { date: new Date(date).toISOString() } };
2462
+ const res = await fetcher(`/customer/v1/schedules/adjustments`, {
2463
+ method: "POST",
2464
+ headers: { "Content-Type": "application/json" },
2465
+ body: JSON.stringify({
2466
+ matcher,
2467
+ action: { type: "SKIP_ORDER", input: { reason: "" } }
2468
+ })
2469
+ });
2470
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2471
+ return { _tag: "Success", data: void 0 };
2472
+ } catch (e2) {
2473
+ return { _tag: "Failure", error: e2 };
2474
+ }
2475
+ },
2476
+ async changeDateAdjustment({ newDate, currentDate }) {
2477
+ if (currentDate == null) {
2478
+ return {
2479
+ _tag: "Failure",
2480
+ error: "currentDate is required for changeDateAdjustment"
2481
+ };
2482
+ }
2483
+ try {
2484
+ const matcher = { type: "DATE", input: { date: new Date(currentDate).toISOString() } };
2485
+ const res = await fetcher(`/customer/v1/schedules/adjustments`, {
2486
+ method: "POST",
2487
+ headers: { "Content-Type": "application/json" },
2488
+ body: JSON.stringify({
2489
+ matcher,
2490
+ action: {
2491
+ type: "CHANGE_DATE",
2492
+ input: { newDate: new Date(newDate).toISOString() }
2493
+ }
2494
+ })
2495
+ });
2496
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2497
+ return { _tag: "Success", data: void 0 };
2498
+ } catch (e2) {
2499
+ return { _tag: "Failure", error: e2 };
2500
+ }
2501
+ },
2502
+ async removeAdjustment({ adjustmentId }) {
2503
+ try {
2504
+ const res = await fetcher(
2505
+ `/customer/v1/schedules/adjustments/${adjustmentId}`,
2506
+ { method: "DELETE" }
2507
+ );
2508
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2509
+ return { _tag: "Success", data: void 0 };
2510
+ } catch (e2) {
2511
+ return { _tag: "Failure", error: e2 };
2512
+ }
1106
2513
  }
1107
2514
  };
1108
2515
  }
2516
+ const SchedulesServiceContext = createContext("services/schedules");
2517
+ function createSchedulesService(adapter, opts) {
2518
+ const current = d(null);
2519
+ const currentLoading = d(false);
2520
+ const hasPendingBilling = (opts == null ? void 0 : opts.hasPendingBilling) ?? d(false);
2521
+ let reloadToken = 0;
2522
+ async function getUpcomingOrder() {
2523
+ const result = await adapter.getUpcomingOrders({ count: 1 });
2524
+ if (result._tag === "Failure") return result;
2525
+ return { _tag: "Success", data: result.data[0] ?? null };
2526
+ }
2527
+ async function getUpcomingOrders(count) {
2528
+ return adapter.getUpcomingOrders({ count });
2529
+ }
2530
+ async function reloadCurrent(subscriptionId) {
2531
+ var _a;
2532
+ const token = ++reloadToken;
2533
+ currentLoading.value = true;
2534
+ const count = Math.max(((_a = current.value) == null ? void 0 : _a.length) ?? 0, 3);
2535
+ const result = await adapter.getUpcomingOrders({
2536
+ count,
2537
+ subscriptionId
2538
+ });
2539
+ if (token !== reloadToken) return;
2540
+ currentLoading.value = false;
2541
+ if (result._tag === "Success") {
2542
+ current.value = result.data;
2543
+ }
2544
+ }
2545
+ return {
2546
+ current,
2547
+ currentLoading,
2548
+ hasPendingBilling,
2549
+ getUpcomingOrder,
2550
+ getUpcomingOrders,
2551
+ async getAdjustments() {
2552
+ return adapter.getAdjustments();
2553
+ },
2554
+ async skipOrder(params) {
2555
+ const result = await adapter.skipOrder(params);
2556
+ if (result._tag === "Success") {
2557
+ await reloadCurrent(params.subscriptionId);
2558
+ }
2559
+ return result;
2560
+ },
2561
+ async changeDateAdjustment(params) {
2562
+ const result = await adapter.changeDateAdjustment(params);
2563
+ if (result._tag === "Success") {
2564
+ await reloadCurrent(params.subscriptionId);
2565
+ }
2566
+ return result;
2567
+ },
2568
+ async removeAdjustment(params) {
2569
+ return adapter.removeAdjustment(params);
2570
+ },
2571
+ reloadCurrent
2572
+ };
2573
+ }
2574
+ const SettingsServiceContext = createContext("services/settings");
2575
+ function createSettingsService(initial = {}) {
2576
+ const current = d(initial);
2577
+ return {
2578
+ current,
2579
+ get(key) {
2580
+ return current.value[key];
2581
+ }
2582
+ };
2583
+ }
2584
+ function createShopService(options) {
2585
+ const contactEmail = d(options.getContactEmail());
2586
+ const service = { contactEmail };
2587
+ return service;
2588
+ }
2589
+ const ShopServiceContext = createContext("services/shop");
1109
2590
  const SubscriptionServiceContext = createContext("services/subscription");
1110
2591
  function getCurrentSubscriptionId() {
1111
2592
  if (typeof window === "undefined") {
@@ -1128,41 +2609,83 @@ function getCurrentSubscriptionId() {
1128
2609
  }
1129
2610
  function createSubscriptionService(adapter) {
1130
2611
  const current = d(null);
1131
- const discountsChangedAtSignal = d(0);
1132
- const itemsChangedAtSignal = d(0);
1133
- async function refreshCurrent(subscriptionId) {
1134
- const result = await adapter.getById(subscriptionId);
1135
- if (result._tag === "Success" && result.data != null) {
1136
- current.value = result.data;
1137
- }
2612
+ const hasPendingBilling = d(false);
2613
+ const discountsChangedAt = d(0);
2614
+ const itemsChangedAt = d(0);
2615
+ const lastOrder = d(null);
2616
+ async function refreshAfterDiscountChange() {
2617
+ await reload();
2618
+ discountsChangedAt.value = discountsChangedAt.value + 1;
1138
2619
  }
1139
- async function refreshAfterDiscountChange(subscriptionId) {
1140
- await refreshCurrent(subscriptionId);
1141
- discountsChangedAtSignal.value = discountsChangedAtSignal.value + 1;
1142
- }
1143
- async function refreshAfterItemChange(subscriptionId) {
1144
- await refreshCurrent(subscriptionId);
1145
- itemsChangedAtSignal.value = itemsChangedAtSignal.value + 1;
2620
+ async function refreshAfterItemChange() {
2621
+ await reload();
2622
+ itemsChangedAt.value = itemsChangedAt.value + 1;
1146
2623
  }
1147
2624
  function subscriptionIdFromCurrent() {
1148
2625
  var _a;
1149
2626
  return ((_a = current.value) == null ? void 0 : _a.id) ?? null;
1150
2627
  }
2628
+ async function reload() {
2629
+ var _a, _b;
2630
+ const id = (_a = current.value) == null ? void 0 : _a.id;
2631
+ if (!id) return;
2632
+ const [subResult, lastOrderResult] = await Promise.all([
2633
+ adapter.getById(id),
2634
+ adapter.getLastOrder({ subscriptionId: id })
2635
+ ]);
2636
+ if (((_b = current.value) == null ? void 0 : _b.id) !== id) return;
2637
+ if (subResult._tag === "Success") current.value = subResult.data;
2638
+ if (lastOrderResult._tag === "Success") lastOrder.value = lastOrderResult.data;
2639
+ }
1151
2640
  const service = {
2641
+ current,
2642
+ hasPendingBilling,
2643
+ discountsChangedAt,
2644
+ itemsChangedAt,
2645
+ lastOrder,
1152
2646
  search: adapter.search,
2647
+ // Prefer the adapter's rich cross-subscription list (legacy endpoint, active-first).
2648
+ // Fall back to a single `search` page for adapters that don't implement it
2649
+ // (e.g. the editor mock) so the cross-subscription views still render.
2650
+ listAll: adapter.listAll ? adapter.listAll.bind(adapter) : async () => {
2651
+ const result = await adapter.search();
2652
+ if (result._tag !== "Success") return result;
2653
+ return { _tag: "Success", data: result.data.items };
2654
+ },
1153
2655
  getById: adapter.getById,
1154
2656
  getCurrentSubscriptionId,
1155
2657
  addItem: async (subscriptionId, item) => {
1156
2658
  const result = await adapter.addItem({ subscriptionId, item });
1157
2659
  if (result._tag === "Success") {
1158
- await refreshAfterItemChange(subscriptionId);
2660
+ await refreshAfterItemChange();
1159
2661
  }
1160
2662
  return result;
1161
2663
  },
1162
2664
  removeItem: async (subscriptionId, itemId) => {
1163
2665
  const result = await adapter.removeItem({ subscriptionId, itemId });
1164
2666
  if (result._tag === "Success") {
1165
- await refreshAfterItemChange(subscriptionId);
2667
+ await refreshAfterItemChange();
2668
+ }
2669
+ return result;
2670
+ },
2671
+ updateItem: async (subscriptionId, lineId, update) => {
2672
+ const result = await adapter.updateItem({ subscriptionId, lineId, update });
2673
+ if (result._tag === "Success") {
2674
+ await refreshAfterItemChange();
2675
+ }
2676
+ return result;
2677
+ },
2678
+ skipLineItem: async (subscriptionId, lineId, nextBillingDate) => {
2679
+ const result = await adapter.skipLineItem({ subscriptionId, lineId, nextBillingDate });
2680
+ if (result._tag === "Success") {
2681
+ await refreshAfterItemChange();
2682
+ }
2683
+ return result;
2684
+ },
2685
+ updateBoxItems: async (subscriptionId, params) => {
2686
+ const result = await adapter.updateBoxItems({ subscriptionId, ...params });
2687
+ if (result._tag === "Success") {
2688
+ await refreshAfterItemChange();
1166
2689
  }
1167
2690
  return result;
1168
2691
  },
@@ -1176,7 +2699,7 @@ function createSubscriptionService(adapter) {
1176
2699
  }
1177
2700
  const result = await adapter.addDiscount({ subscriptionId: id, code });
1178
2701
  if (result._tag === "Success") {
1179
- await refreshAfterDiscountChange(id);
2702
+ await refreshAfterDiscountChange();
1180
2703
  }
1181
2704
  return result;
1182
2705
  },
@@ -1193,7 +2716,7 @@ function createSubscriptionService(adapter) {
1193
2716
  discountId
1194
2717
  });
1195
2718
  if (result._tag === "Success") {
1196
- await refreshAfterDiscountChange(id);
2719
+ await refreshAfterDiscountChange();
1197
2720
  }
1198
2721
  return result;
1199
2722
  },
@@ -1202,11 +2725,13 @@ function createSubscriptionService(adapter) {
1202
2725
  pause: (subscriptionId) => adapter.pause({ subscriptionId }),
1203
2726
  reactivate: (subscriptionId) => adapter.reactivate({ subscriptionId }),
1204
2727
  cancel: (subscriptionId, reason) => adapter.cancel({ subscriptionId, reason }),
2728
+ renewNow: (params) => adapter.renewNow(params),
2729
+ changeFrequency: (subscriptionId, plan) => adapter.changeFrequency({ subscriptionId, plan }),
2730
+ reload,
1205
2731
  getAvailablePlans: (subscriptionId) => adapter.getAvailablePlans({ subscriptionId }),
1206
2732
  getDefaultSubscriptionId: () => adapter.getDefaultSubscriptionId(),
1207
- current,
1208
- discountsChangedAt: discountsChangedAtSignal,
1209
- itemsChangedAt: itemsChangedAtSignal
2733
+ getUpsellProducts: (params) => adapter.getUpsellProducts ? adapter.getUpsellProducts(params) : Promise.resolve({ _tag: "Success", data: [] }),
2734
+ addUpsellProduct: (params) => adapter.addUpsellProduct ? adapter.addUpsellProduct(params) : Promise.resolve({ _tag: "Success", data: void 0 })
1210
2735
  };
1211
2736
  return service;
1212
2737
  }
@@ -1475,66 +3000,89 @@ export {
1475
3000
  AuthenticationError,
1476
3001
  AuthenticationErrorReason,
1477
3002
  B as BlockWrapperEvent,
1478
- C as ContextProvideEvent,
1479
- a as ContextRequestEvent,
3003
+ m as ContextProvideEvent,
3004
+ p as ContextRequestEvent,
1480
3005
  CustomerServiceContext,
1481
- D as DEFAULT_GLOBAL_STYLES,
3006
+ D2 as DEFAULT_GLOBAL_STYLES,
1482
3007
  DISCOUNT_REJECTION_REASONS,
1483
3008
  LoginServiceContext,
1484
3009
  OrdersServiceContext,
3010
+ OverlayServiceContext,
1485
3011
  ProductServiceContext,
1486
3012
  RouterServiceContext,
3013
+ SchedulesServiceContext,
1487
3014
  S as SelectedBlockContext,
3015
+ SettingsServiceContext,
3016
+ ShopServiceContext,
1488
3017
  u as Signal,
1489
3018
  StateContext,
1490
3019
  SubscriptionServiceContext,
1491
- T as ThemeStateContext,
1492
- b as TranslationContext,
3020
+ a2 as ThemeStateContext,
3021
+ T as TranslationContext,
1493
3022
  W as WorkflowServiceContext,
1494
- e as attachEmptyTracking,
1495
- f as backfillInstanceDefaults,
3023
+ q as __recordDevtoolsInstance,
3024
+ _ as __recordDevtoolsPropSetter,
3025
+ t as attachEmptyTracking,
3026
+ b as backfillInstanceDefaults,
1496
3027
  w as computed,
1497
- g as createBlockInstance,
1498
- h as createBlockInstanceFromJSON,
1499
- i as createBlockInstanceFromObject,
1500
- j as createCeRenderer,
3028
+ createApiCustomerAdapter,
3029
+ createApiLoginAdapter,
3030
+ createApiOrdersAdapter,
3031
+ createApiProductAdapter,
3032
+ createApiSchedulesAdapter,
3033
+ createApiSubscriptionAdapter,
3034
+ createBlockInstance,
3035
+ v as createBlockInstanceFromJSON,
3036
+ f as createBlockInstanceFromObject,
3037
+ x as createCeRenderer,
1501
3038
  createContext,
1502
3039
  createCustomerService,
3040
+ createLoginService,
3041
+ createMockCustomerAdapter,
3042
+ createMockLoginAdapter,
1503
3043
  createMockOrdersAdapter,
1504
3044
  createMockProductAdapter,
1505
3045
  createMockRouterService,
3046
+ createMockSchedulesAdapter,
1506
3047
  createMockSubscriptionAdapter,
1507
3048
  createMockWorkflowApiAdapter,
1508
3049
  createOrdersService,
3050
+ createOverlayService,
1509
3051
  createProductService,
1510
3052
  createRouterService,
1511
- k as createSelectedBlock,
3053
+ createSchedulesService,
3054
+ y as createSelectedBlock,
3055
+ createSettingsService,
3056
+ createShopService,
1512
3057
  createState,
1513
3058
  createSubscriptionService,
1514
- l as createThemeState,
1515
- m as createTranslationService,
1516
- n as createWorkflowApiAdapter,
1517
- o as createWorkflowService,
1518
- p as defineBlock,
1519
- q as defineBlockRuntime,
3059
+ c as createThemeState,
3060
+ b2 as createTranslationService,
3061
+ d2 as createWorkflowApiAdapter,
3062
+ e as createWorkflowService,
3063
+ defineBlock,
3064
+ z as defineBlockRuntime,
3065
+ defineOverlayWrapper,
1520
3066
  E as effect,
1521
- s as getDefaultBlockForAction,
1522
- t as getDefinedBlocks,
1523
- v as hasDefaultBlockForAction,
1524
- x as hasRenderedContent,
1525
- y as indexOverrides,
1526
- z as injectContext,
1527
- A as isEditorPreview,
1528
- F as isStubDefinition,
3067
+ g as getDefaultBlockForAction,
3068
+ getDefinedBlocks,
3069
+ A as getDevtoolsBlockState,
3070
+ h as hasDefaultBlockForAction,
3071
+ D as hasRenderedContent,
3072
+ i2 as indexOverrides,
3073
+ i as injectContext,
3074
+ F as isEditorPreview,
3075
+ a as isStubDefinition,
1529
3076
  loadBlockRegistry,
1530
3077
  loginService,
1531
- G as onRegisterBlock,
1532
- H as provideContext,
3078
+ o as onRegisterBlock,
3079
+ G as provideContext,
1533
3080
  registerBlock,
1534
- I as serializeBlocks,
3081
+ j as serializeBlocks,
3082
+ H as setDevtoolsBlockProp,
1535
3083
  d as signal,
1536
- J as subscribeContext,
1537
- K as untracked,
3084
+ s as subscribeContext,
3085
+ n as untracked,
1538
3086
  waitForDevBlocksUrl,
1539
- L as withWrapper
3087
+ w2 as withWrapper
1540
3088
  };