@juo/blocks 1.13.0-alpha.2 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/dist/ExtensionRoot-CRJx0Dtr.js +378 -0
  2. package/dist/block.d.ts +0 -50
  3. package/dist/block.d.ts.map +1 -1
  4. package/dist/{bridge-r7Yk8fjY.js → bridge-D838SWmN.js} +147 -42
  5. package/dist/context.d.ts.map +1 -1
  6. package/dist/core.js +1120 -2157
  7. package/dist/css-runtime-DWytAzZ5.js +1532 -0
  8. package/dist/editor/bridge.d.ts +8 -7
  9. package/dist/editor/bridge.d.ts.map +1 -1
  10. package/dist/editor/canvas-mode-signal.d.ts +22 -0
  11. package/dist/editor/canvas-mode-signal.d.ts.map +1 -0
  12. package/dist/editor/canvas-mode.d.ts +15 -0
  13. package/dist/editor/canvas-mode.d.ts.map +1 -0
  14. package/dist/editor/canvas-mode.test.d.ts +2 -0
  15. package/dist/editor/canvas-mode.test.d.ts.map +1 -0
  16. package/dist/editor/components.d.ts +113 -0
  17. package/dist/editor/components.d.ts.map +1 -1
  18. package/dist/editor/components.test.d.ts.map +1 -1
  19. package/dist/editor/handler.d.ts.map +1 -1
  20. package/dist/editor/handler.test.d.ts +2 -0
  21. package/dist/editor/handler.test.d.ts.map +1 -0
  22. package/dist/editor/layout-command-emitter.d.ts +31 -0
  23. package/dist/editor/layout-command-emitter.d.ts.map +1 -0
  24. package/dist/editor/layout-command-emitter.test.d.ts +2 -0
  25. package/dist/editor/layout-command-emitter.test.d.ts.map +1 -0
  26. package/dist/editor/layout-system-signal.d.ts +21 -0
  27. package/dist/editor/layout-system-signal.d.ts.map +1 -0
  28. package/dist/editor/main.d.ts +2 -2
  29. package/dist/editor/main.d.ts.map +1 -1
  30. package/dist/editor/messages.d.ts +90 -14
  31. package/dist/editor/messages.d.ts.map +1 -1
  32. package/dist/editor/surface-context.d.ts +7 -0
  33. package/dist/editor/surface-context.d.ts.map +1 -0
  34. package/dist/editor/surface-context.test.d.ts +2 -0
  35. package/dist/editor/surface-context.test.d.ts.map +1 -0
  36. package/dist/editor/wrapper-shared.d.ts +31 -0
  37. package/dist/editor/wrapper-shared.d.ts.map +1 -0
  38. package/dist/editor.js +887 -88
  39. package/dist/flows/WorkflowService.d.ts +2 -0
  40. package/dist/flows/WorkflowService.d.ts.map +1 -1
  41. package/dist/gridstack-adapter-DreG3XnB.js +5490 -0
  42. package/dist/layout/css-runtime.d.ts +41 -0
  43. package/dist/layout/css-runtime.d.ts.map +1 -0
  44. package/dist/layout/css-runtime.test.d.ts +2 -0
  45. package/dist/layout/css-runtime.test.d.ts.map +1 -0
  46. package/dist/layout/derive.d.ts +4 -0
  47. package/dist/layout/derive.d.ts.map +1 -0
  48. package/dist/layout/derive.test.d.ts +2 -0
  49. package/dist/layout/derive.test.d.ts.map +1 -0
  50. package/dist/layout/dividers.d.ts +34 -0
  51. package/dist/layout/dividers.d.ts.map +1 -0
  52. package/dist/layout/dividers.test.d.ts +2 -0
  53. package/dist/layout/dividers.test.d.ts.map +1 -0
  54. package/dist/layout/engine.d.ts +3 -0
  55. package/dist/layout/engine.d.ts.map +1 -0
  56. package/dist/layout/engine.test.d.ts +2 -0
  57. package/dist/layout/engine.test.d.ts.map +1 -0
  58. package/dist/layout/grid-utils.d.ts +57 -0
  59. package/dist/layout/grid-utils.d.ts.map +1 -0
  60. package/dist/layout/grid-utils.test.d.ts +2 -0
  61. package/dist/layout/grid-utils.test.d.ts.map +1 -0
  62. package/dist/layout/index.d.ts +12 -0
  63. package/dist/layout/index.d.ts.map +1 -0
  64. package/dist/layout/index.test.d.ts +2 -0
  65. package/dist/layout/index.test.d.ts.map +1 -0
  66. package/dist/layout/insert.d.ts +31 -0
  67. package/dist/layout/insert.d.ts.map +1 -0
  68. package/dist/layout/insert.test.d.ts +2 -0
  69. package/dist/layout/insert.test.d.ts.map +1 -0
  70. package/dist/layout/project-css.d.ts +6 -0
  71. package/dist/layout/project-css.d.ts.map +1 -0
  72. package/dist/layout/project-css.test.d.ts +2 -0
  73. package/dist/layout/project-css.test.d.ts.map +1 -0
  74. package/dist/layout/project-gridstack.d.ts +50 -0
  75. package/dist/layout/project-gridstack.d.ts.map +1 -0
  76. package/dist/layout/project-gridstack.test.d.ts +2 -0
  77. package/dist/layout/project-gridstack.test.d.ts.map +1 -0
  78. package/dist/layout/reconcile.d.ts +22 -0
  79. package/dist/layout/reconcile.d.ts.map +1 -0
  80. package/dist/layout/reconcile.test.d.ts +2 -0
  81. package/dist/layout/reconcile.test.d.ts.map +1 -0
  82. package/dist/layout/types.d.ts +118 -0
  83. package/dist/layout/types.d.ts.map +1 -0
  84. package/dist/layout-mode-adapter-BBd4JRQd.js +21 -0
  85. package/dist/main.d.ts +8 -4
  86. package/dist/main.d.ts.map +1 -1
  87. package/dist/morph-Dj-xvrwt.js +182 -0
  88. package/dist/preact.js +1 -1
  89. package/dist/project-gridstack-DYLMKSH1.js +52 -0
  90. package/dist/react.js +1 -1
  91. package/dist/services/customer/customerService.d.ts +2 -3
  92. package/dist/services/customer/customerService.d.ts.map +1 -1
  93. package/dist/services/customer/index.d.ts +0 -1
  94. package/dist/services/customer/index.d.ts.map +1 -1
  95. package/dist/services/customer/types.d.ts +1 -4
  96. package/dist/services/customer/types.d.ts.map +1 -1
  97. package/dist/services/index.d.ts +0 -3
  98. package/dist/services/index.d.ts.map +1 -1
  99. package/dist/services/login/index.d.ts +1 -3
  100. package/dist/services/login/index.d.ts.map +1 -1
  101. package/dist/services/login/loginService.d.ts +2 -6
  102. package/dist/services/login/loginService.d.ts.map +1 -1
  103. package/dist/services/orders/adapter.d.ts +0 -2
  104. package/dist/services/orders/adapter.d.ts.map +1 -1
  105. package/dist/services/orders/index.d.ts +1 -1
  106. package/dist/services/orders/index.d.ts.map +1 -1
  107. package/dist/services/product/adapter.d.ts +2 -27
  108. package/dist/services/product/adapter.d.ts.map +1 -1
  109. package/dist/services/product/index.d.ts +1 -1
  110. package/dist/services/product/index.d.ts.map +1 -1
  111. package/dist/services/product/productService.d.ts.map +1 -1
  112. package/dist/services/product/types.d.ts +0 -68
  113. package/dist/services/product/types.d.ts.map +1 -1
  114. package/dist/services/subscription/adapter.d.ts +2 -77
  115. package/dist/services/subscription/adapter.d.ts.map +1 -1
  116. package/dist/services/subscription/index.d.ts +1 -1
  117. package/dist/services/subscription/index.d.ts.map +1 -1
  118. package/dist/services/subscription/subscriptionService.d.ts +6 -1
  119. package/dist/services/subscription/subscriptionService.d.ts.map +1 -1
  120. package/dist/services/subscription/types.d.ts +9 -220
  121. package/dist/services/subscription/types.d.ts.map +1 -1
  122. package/dist/theme-state.d.ts +17 -2
  123. package/dist/theme-state.d.ts.map +1 -1
  124. package/dist/theme-state.layout.test.d.ts +2 -0
  125. package/dist/theme-state.layout.test.d.ts.map +1 -0
  126. package/dist/theme-state.test.d.ts +2 -0
  127. package/dist/theme-state.test.d.ts.map +1 -0
  128. package/dist/utils/index.d.ts +0 -6
  129. package/dist/utils/index.d.ts.map +1 -1
  130. package/dist/vue/block.d.ts.map +1 -1
  131. package/dist/vue.js +4 -25
  132. package/dist/web-components/ExtensionRoot.d.ts +50 -3
  133. package/dist/web-components/ExtensionRoot.d.ts.map +1 -1
  134. package/dist/web-components/editor/ExtensionRoot.d.ts +11 -0
  135. package/dist/web-components/editor/ExtensionRoot.d.ts.map +1 -0
  136. package/dist/web-components/editor/ExtensionRoot.test.d.ts +2 -0
  137. package/dist/web-components/editor/ExtensionRoot.test.d.ts.map +1 -0
  138. package/dist/web-components/editor/InlineText.d.ts +1 -0
  139. package/dist/web-components/editor/InlineText.d.ts.map +1 -1
  140. package/dist/web-components/editor/editor-layout-controller.d.ts +28 -0
  141. package/dist/web-components/editor/editor-layout-controller.d.ts.map +1 -0
  142. package/dist/web-components/editor/gridstack-adapter.d.ts +3 -0
  143. package/dist/web-components/editor/gridstack-adapter.d.ts.map +1 -0
  144. package/dist/web-components/editor/gridstack-adapter.test.d.ts +2 -0
  145. package/dist/web-components/editor/gridstack-adapter.test.d.ts.map +1 -0
  146. package/dist/web-components/editor/morph.d.ts +32 -0
  147. package/dist/web-components/editor/morph.d.ts.map +1 -0
  148. package/dist/web-components/editor/morph.test.d.ts +2 -0
  149. package/dist/web-components/editor/morph.test.d.ts.map +1 -0
  150. package/dist/web-components/layout/layout-controller.d.ts +55 -0
  151. package/dist/web-components/layout/layout-controller.d.ts.map +1 -0
  152. package/dist/web-components/layout/view-layout-controller.d.ts +17 -0
  153. package/dist/web-components/layout/view-layout-controller.d.ts.map +1 -0
  154. package/dist/web-components/layout/view-layout-controller.test.d.ts +2 -0
  155. package/dist/web-components/layout/view-layout-controller.test.d.ts.map +1 -0
  156. package/dist/web-components/layout-grid.d.ts +47 -0
  157. package/dist/web-components/layout-grid.d.ts.map +1 -0
  158. package/dist/web-components/layout-grid.test.d.ts +2 -0
  159. package/dist/web-components/layout-grid.test.d.ts.map +1 -0
  160. package/dist/web-components/layout-mode-adapter.d.ts +51 -0
  161. package/dist/web-components/layout-mode-adapter.d.ts.map +1 -0
  162. package/dist/web-components/layout-mode-adapter.test.d.ts +2 -0
  163. package/dist/web-components/layout-mode-adapter.test.d.ts.map +1 -0
  164. package/dist/web-components-editor.js +125 -18
  165. package/dist/web-components-runtime.js +4 -4
  166. package/package.json +3 -2
  167. package/dist/ExtensionRoot-peABLAZZ.js +0 -231
  168. package/dist/block-B6s9jL7l.js +0 -966
  169. package/dist/block.devtools.test.d.ts +0 -2
  170. package/dist/block.devtools.test.d.ts.map +0 -1
  171. package/dist/context.devtools.test.d.ts +0 -2
  172. package/dist/context.devtools.test.d.ts.map +0 -1
  173. package/dist/devtools/env.d.ts +0 -3
  174. package/dist/devtools/env.d.ts.map +0 -1
  175. package/dist/devtools/hook.d.ts +0 -35
  176. package/dist/devtools/hook.d.ts.map +0 -1
  177. package/dist/devtools/index.d.ts +0 -4
  178. package/dist/devtools/index.d.ts.map +0 -1
  179. package/dist/devtools/protocol.d.ts +0 -91
  180. package/dist/devtools/protocol.d.ts.map +0 -1
  181. package/dist/devtools.js +0 -44
  182. package/dist/editor/overlays.d.ts +0 -14
  183. package/dist/editor/overlays.d.ts.map +0 -1
  184. package/dist/editor/overlays.test.d.ts +0 -2
  185. package/dist/editor/overlays.test.d.ts.map +0 -1
  186. package/dist/juo-workflow-DY4rd256.js +0 -868
  187. package/dist/overlay-wrapper.d.ts +0 -69
  188. package/dist/overlay-wrapper.d.ts.map +0 -1
  189. package/dist/overlay-wrapper.test.d.ts +0 -2
  190. package/dist/overlay-wrapper.test.d.ts.map +0 -1
  191. package/dist/overlays/OverlayService.d.ts +0 -34
  192. package/dist/overlays/OverlayService.d.ts.map +0 -1
  193. package/dist/overlays/OverlayService.test.d.ts +0 -2
  194. package/dist/overlays/OverlayService.test.d.ts.map +0 -1
  195. package/dist/registry.devtools.test.d.ts +0 -2
  196. package/dist/registry.devtools.test.d.ts.map +0 -1
  197. package/dist/services/customer/adapter.d.ts +0 -8
  198. package/dist/services/customer/adapter.d.ts.map +0 -1
  199. package/dist/services/login/adapter.d.ts +0 -32
  200. package/dist/services/login/adapter.d.ts.map +0 -1
  201. package/dist/services/order/adapter.d.ts +0 -9
  202. package/dist/services/order/adapter.d.ts.map +0 -1
  203. package/dist/services/order/index.d.ts +0 -5
  204. package/dist/services/order/index.d.ts.map +0 -1
  205. package/dist/services/order/orderService.d.ts +0 -7
  206. package/dist/services/order/orderService.d.ts.map +0 -1
  207. package/dist/services/order/types.d.ts +0 -21
  208. package/dist/services/order/types.d.ts.map +0 -1
  209. package/dist/services/product/adapter.test.d.ts +0 -2
  210. package/dist/services/product/adapter.test.d.ts.map +0 -1
  211. package/dist/services/schedules/adapter.d.ts +0 -71
  212. package/dist/services/schedules/adapter.d.ts.map +0 -1
  213. package/dist/services/schedules/adapter.test.d.ts +0 -2
  214. package/dist/services/schedules/adapter.test.d.ts.map +0 -1
  215. package/dist/services/schedules/index.d.ts +0 -5
  216. package/dist/services/schedules/index.d.ts.map +0 -1
  217. package/dist/services/schedules/schedulesService.d.ts +0 -11
  218. package/dist/services/schedules/schedulesService.d.ts.map +0 -1
  219. package/dist/services/schedules/schedulesService.test.d.ts +0 -2
  220. package/dist/services/schedules/schedulesService.test.d.ts.map +0 -1
  221. package/dist/services/schedules/types.d.ts +0 -226
  222. package/dist/services/schedules/types.d.ts.map +0 -1
  223. package/dist/services/settings/index.d.ts +0 -3
  224. package/dist/services/settings/index.d.ts.map +0 -1
  225. package/dist/services/settings/settingsService.d.ts +0 -7
  226. package/dist/services/settings/settingsService.d.ts.map +0 -1
  227. package/dist/services/settings/settingsService.test.d.ts +0 -2
  228. package/dist/services/settings/settingsService.test.d.ts.map +0 -1
  229. package/dist/services/settings/types.d.ts +0 -35
  230. package/dist/services/settings/types.d.ts.map +0 -1
  231. package/dist/services/shop/index.d.ts +0 -3
  232. package/dist/services/shop/index.d.ts.map +0 -1
  233. package/dist/services/shop/shopService.d.ts +0 -12
  234. package/dist/services/shop/shopService.d.ts.map +0 -1
  235. package/dist/services/shop/shopService.test.d.ts +0 -2
  236. package/dist/services/shop/shopService.test.d.ts.map +0 -1
  237. package/dist/services/shop/types.d.ts +0 -7
  238. package/dist/services/shop/types.d.ts.map +0 -1
  239. package/dist/services/subscription/adapter.test.d.ts +0 -2
  240. package/dist/services/subscription/adapter.test.d.ts.map +0 -1
  241. package/dist/services/subscription/types.test.d.ts +0 -2
  242. package/dist/services/subscription/types.test.d.ts.map +0 -1
  243. package/dist/theme-state.params.test.d.ts +0 -2
  244. package/dist/theme-state.params.test.d.ts.map +0 -1
  245. package/dist/theme-state.translations.test.d.ts +0 -2
  246. package/dist/theme-state.translations.test.d.ts.map +0 -1
package/dist/core.js CHANGED
@@ -1,10 +1,12 @@
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 { 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";
4
+ import { c as createContext, d, w, r as registerBlock, E, u, g as getDefinedBlocks, a as createBlockInstance, b as defineBlock, s as subscribeContext, G as GRID_V1_ENGINE_ID, e as clampRect, f as applyFillExpansion, h as compactItems, i as findFreeRect, D as DEFAULT_GRID } from "./css-runtime-DWytAzZ5.js";
5
+ import { B, C, j, k, l, L, P, S, T, m, n, o, p, q, t, v, x, y, z, A, F, H, I, J, K, M, N, O, Q, R, U, V, W, X, Y, Z, _, $, a0, a1, a2, a3, a4, a5 } from "./css-runtime-DWytAzZ5.js";
7
6
  import { reportBlockWarning, reportBlockError } from "./observability.js";
7
+ import { c as createEditorBridge, a as createSelectBlockMessage } from "./bridge-D838SWmN.js";
8
+ import { p as p2 } from "./project-gridstack-DYLMKSH1.js";
9
+ import { clearLayoutModeAdapter, getLayoutModeAdapter, registerLayoutModeAdapter } from "./layout-mode-adapter-BBd4JRQd.js";
8
10
  function createState() {
9
11
  const discountCode = d(null);
10
12
  const products = d([]);
@@ -73,111 +75,6 @@ function createState() {
73
75
  };
74
76
  }
75
77
  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
- }
181
78
  function isLocalhostOrigin(origin) {
182
79
  try {
183
80
  const url = new URL(origin);
@@ -262,43 +159,13 @@ async function loadBlockRegistry(options = {}) {
262
159
  function createCustomerService(options) {
263
160
  const current = d(null);
264
161
  const accountOrdersUrl = d(options.getAccountOrdersUrl());
265
- return {
162
+ const service = {
266
163
  current,
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
- }
164
+ accountOrdersUrl
273
165
  };
166
+ return service;
274
167
  }
275
168
  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
- }
302
169
  const PARAMS = {
303
170
  DELETGATED_TOKEN: "delegated-token",
304
171
  REDIRECT_TO: "redirect-to",
@@ -312,125 +179,9 @@ const PARAMS = {
312
179
  function uuid() {
313
180
  return ("10000000-1000-4000-8000" + -1e11).replace(
314
181
  /[018]/g,
315
- (c2) => (c2 ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c2 / 4).toString(16)
182
+ (c) => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
316
183
  );
317
184
  }
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__ = {};
434
185
  var AuthenticationErrorReason = /* @__PURE__ */ ((AuthenticationErrorReason2) => {
435
186
  AuthenticationErrorReason2["Expired"] = "expired";
436
187
  AuthenticationErrorReason2["IncorrectCode"] = "wrong-code";
@@ -449,9 +200,6 @@ class AuthenticationError extends Error {
449
200
  this.data = data ?? {};
450
201
  }
451
202
  }
452
- const STORAGE_DELEGATED_TOKEN = "delegated-token";
453
- const STORAGE_REFRESH_TOKEN_KEY = "refresh-token";
454
- const STORAGE_STATE_KEY = "state";
455
203
  function storage(key, value) {
456
204
  const storageKey = `auth:${key}`;
457
205
  try {
@@ -467,33 +215,83 @@ function storage(key, value) {
467
215
  }
468
216
  return null;
469
217
  }
218
+ const STORAGE_DELEGATED_TOKEN = "delegated-token";
219
+ const STORAGE_REFRESH_TOKEN_KEY = "refresh-token";
220
+ const STORAGE_STATE_KEY = "state";
221
+ function createAuthFunctions(basePath, shop) {
222
+ async function start(email, lang) {
223
+ const response = await fetch(
224
+ `${basePath}/auth/customer/passwordless/start?lang=${lang}`,
225
+ {
226
+ method: "POST",
227
+ headers: {
228
+ Accept: "application/json",
229
+ "Content-Type": "application/json",
230
+ "X-Shopify-Shop-Domain": shop
231
+ },
232
+ body: JSON.stringify({ email })
233
+ }
234
+ );
235
+ if (response.status !== 200) {
236
+ throw new Error(`Unexpected response: ${response.statusText}`);
237
+ }
238
+ }
239
+ async function authenticate(data) {
240
+ const response = await fetch(`${basePath}/auth/customer/token`, {
241
+ method: "POST",
242
+ headers: {
243
+ Accept: "application/json",
244
+ "Content-Type": "application/json",
245
+ "X-Shopify-Shop-Domain": shop
246
+ },
247
+ body: JSON.stringify(data)
248
+ });
249
+ if (response.status === 403) {
250
+ const data2 = await response.json();
251
+ if ("error_description" in data2) {
252
+ if (data2.error_description === "Wrong email or verification code.") {
253
+ throw new AuthenticationError(
254
+ "wrong-code"
255
+ /* IncorrectCode */
256
+ );
257
+ } else if (data2.error_description === "You've reached the maximum number of attempts. Please try to login again.") {
258
+ throw new AuthenticationError(
259
+ "too-many-tries"
260
+ /* TooManyTries */
261
+ );
262
+ } else if (data2.error_description === "The verification code has expired. Please try to login again.") {
263
+ throw new AuthenticationError(
264
+ "expired"
265
+ /* Expired */
266
+ );
267
+ }
268
+ } else if ("code" in data2) {
269
+ if (data2.code === "AUTH_ERROR") {
270
+ throw new AuthenticationError("no-email", {
271
+ connection: data2.connection
272
+ });
273
+ }
274
+ }
275
+ }
276
+ if (response.status !== 200) {
277
+ throw new Error(`Unexpected response: ${response.statusText}`);
278
+ }
279
+ return await response.json();
280
+ }
281
+ return { start, authenticate };
282
+ }
470
283
  function nonce(len = 10) {
471
284
  return uuid().replace(/-/g, "").slice(0, len);
472
285
  }
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;
286
+ function createAuthService(apiUrl, shopDomain) {
287
+ const { start: authStart, authenticate: authAuthenticate } = createAuthFunctions(apiUrl, shopDomain);
494
288
  const accessToken = d(null);
495
- const delegatedToken = d(storage(STORAGE_DELEGATED_TOKEN));
496
- const refreshToken = d(storage(STORAGE_REFRESH_TOKEN_KEY));
289
+ const delegatedToken = d(
290
+ storage(STORAGE_DELEGATED_TOKEN)
291
+ );
292
+ const refreshToken = d(
293
+ storage(STORAGE_REFRESH_TOKEN_KEY)
294
+ );
497
295
  const expires = d(null);
498
296
  const state = d(storage(STORAGE_STATE_KEY));
499
297
  E(() => {
@@ -505,28 +303,67 @@ function createLoginService(init) {
505
303
  E(() => {
506
304
  storage(STORAGE_STATE_KEY, state.value);
507
305
  });
508
- function storeTokens(data) {
306
+ function store(data) {
509
307
  const { access_token, refresh_token, expires_in } = data;
510
308
  accessToken.value = access_token;
511
309
  refreshToken.value = refresh_token;
512
310
  expires.value = new Date(Date.now() + expires_in);
513
311
  }
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);
312
+ return {
313
+ state,
314
+ async start(email, lang) {
315
+ await authStart(email, lang);
316
+ },
317
+ async authenticate(data) {
318
+ store(await authAuthenticate(data));
319
+ },
320
+ getDelegatedToken() {
321
+ return delegatedToken.value;
322
+ },
323
+ setDelegatedToken(token) {
324
+ delegatedToken.value = token;
325
+ },
326
+ async getToken() {
327
+ if (refreshToken.value == null) {
328
+ return null;
329
+ }
330
+ if (accessToken.value == null || typeof accessToken.value === "string" && (expires.value == null || expires.value < /* @__PURE__ */ new Date())) {
331
+ accessToken.value = new Promise(
332
+ (resolve, reject) => authAuthenticate({ refreshToken: refreshToken.value }).then((data) => data).then((data) => {
333
+ store(data);
334
+ resolve(data.access_token);
521
335
  return;
522
- }
523
- storeTokens(result.data);
524
- resolve(result.data.access_token);
525
- }).catch(reject)
526
- );
527
- }
528
- return Promise.resolve(accessToken.value);
529
- }
336
+ }).catch(reject)
337
+ );
338
+ }
339
+ return Promise.resolve(accessToken.value);
340
+ },
341
+ logout() {
342
+ accessToken.value = null;
343
+ delegatedToken.value = null;
344
+ refreshToken.value = null;
345
+ expires.value = null;
346
+ },
347
+ isAuthenticated: w(
348
+ () => delegatedToken.value != null || refreshToken.value != null
349
+ )
350
+ };
351
+ }
352
+ function loginService(deps) {
353
+ return createLoginService({
354
+ apiUrl: `${deps.shop.rootUrl.replace(/\/$/, "")}/api`,
355
+ router: deps.router,
356
+ formatError: deps.formatError,
357
+ shop: {
358
+ domain: deps.shop.domain,
359
+ locale: w(() => deps.getLocale())
360
+ },
361
+ onLoginSuccess: deps.onLoginSuccess
362
+ });
363
+ }
364
+ function createLoginService(init) {
365
+ const { formatError, router, shop, onLoginSuccess } = init;
366
+ const auth = createAuthService(init.apiUrl.replace(/\/$/, ""), shop.domain);
530
367
  const userEmail = d(null);
531
368
  async function onSuccess(query) {
532
369
  await (onLoginSuccess == null ? void 0 : onLoginSuccess());
@@ -539,9 +376,13 @@ function createLoginService(init) {
539
376
  queryParams[key] = value;
540
377
  }
541
378
  });
542
- router.push({ path: decodeURIComponent(redirect), query: queryParams });
379
+ router.push({
380
+ path: decodeURIComponent(redirect),
381
+ query: queryParams
382
+ });
543
383
  } else {
544
- router.replace(decodeURIComponent(query.get(PARAMS.REDIRECT_TO)));
384
+ const redirect = query.get(PARAMS.REDIRECT_TO);
385
+ router.replace(decodeURIComponent(redirect));
545
386
  }
546
387
  } else {
547
388
  router.replace("/");
@@ -553,17 +394,16 @@ function createLoginService(init) {
553
394
  async start(email) {
554
395
  try {
555
396
  userEmail.value = email;
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
- }
397
+ await auth.start(
398
+ userEmail.value,
399
+ shop.locale instanceof u ? shop.locale.value : shop.locale
400
+ );
564
401
  return { _tag: "Success", data: void 0 };
565
402
  } catch (error) {
566
- return { _tag: "Failure", error: formatError(error) };
403
+ return {
404
+ _tag: "Failure",
405
+ error: formatError(error)
406
+ };
567
407
  }
568
408
  },
569
409
  async verify(email, code) {
@@ -574,61 +414,63 @@ function createLoginService(init) {
574
414
  };
575
415
  }
576
416
  try {
577
- const result = await adapter.authenticate({
417
+ const result = await auth.authenticate({
578
418
  email: userEmail.value,
579
419
  code
580
420
  });
581
- if (result._tag === "Failure") {
582
- return { _tag: "Failure", error: formatError(result.error) };
583
- }
584
- storeTokens(result.data);
585
421
  await onSuccess();
586
- return { _tag: "Success", data: void 0 };
422
+ return { _tag: "Success", data: result };
587
423
  } catch (error) {
588
- return { _tag: "Failure", error: formatError(error) };
424
+ return {
425
+ _tag: "Failure",
426
+ error: formatError(error)
427
+ };
589
428
  }
590
429
  }
591
430
  }
592
431
  },
593
432
  social: {
594
433
  async start(provider) {
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 };
434
+ function socialUrl(key, shop2) {
435
+ auth.state.value = nonce();
436
+ const url = new URL(
437
+ // TODO: double check admin url
438
+ `${"https://admin.juo.io"}/auth/customer/authorize`
439
+ );
440
+ url.searchParams.append("connection", key);
441
+ url.searchParams.append("state", auth.state.value ?? "");
442
+ url.searchParams.append("shop", shop2);
443
+ return url.toString();
444
+ }
445
+ window.location.href = socialUrl(
446
+ provider === "Facebook" ? "facebook" : "google-oauth2",
447
+ shop.domain
448
+ );
449
+ return {
450
+ _tag: "Success",
451
+ data: void 0
452
+ };
607
453
  },
608
454
  async verify(code) {
609
455
  try {
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);
456
+ const result = await auth.authenticate({ code });
615
457
  await onSuccess();
616
- return { _tag: "Success", data: void 0 };
458
+ return { _tag: "Success", data: result };
617
459
  } catch (error) {
618
- return { _tag: "Failure", error: formatError(error) };
460
+ return {
461
+ _tag: "Failure",
462
+ error: formatError(error)
463
+ };
619
464
  }
620
465
  }
621
466
  },
622
467
  async logout() {
623
- accessToken.value = null;
624
- delegatedToken.value = null;
625
- refreshToken.value = null;
626
- expires.value = null;
468
+ await auth.logout();
627
469
  return { _tag: "Success", data: void 0 };
628
470
  },
629
471
  async handleQueryParams(query) {
630
472
  if (query.has(PARAMS.DELETGATED_TOKEN)) {
631
- delegatedToken.value = query.get(PARAMS.DELETGATED_TOKEN);
473
+ auth.setDelegatedToken(query.get(PARAMS.DELETGATED_TOKEN));
632
474
  await onSuccess(query);
633
475
  return { _tag: "Success", data: void 0 };
634
476
  }
@@ -640,13 +482,16 @@ function createLoginService(init) {
640
482
  }
641
483
  const code = query.get(PARAMS.CODE);
642
484
  if (code != null) {
643
- if (query.get(PARAMS.STATE) !== state.value) {
644
- return { _tag: "Failure", error: formatError("Invalid state") };
485
+ if (query.get(PARAMS.STATE) !== auth.state.value) {
486
+ return {
487
+ _tag: "Failure",
488
+ error: formatError("Invalid state")
489
+ };
645
490
  } else {
646
491
  return service.social.verify(code);
647
492
  }
648
493
  }
649
- if (query.get(PARAMS.REFRESH) === "1" && await getToken() != null) {
494
+ if (query.get(PARAMS.REFRESH) === "1" && await auth.getToken() != null) {
650
495
  await onSuccess();
651
496
  return { _tag: "Success", data: void 0 };
652
497
  }
@@ -663,20 +508,8 @@ function createLoginService(init) {
663
508
  }
664
509
  return { _tag: "Success", data: void 0 };
665
510
  },
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
- }
511
+ isAuthenticated: auth.isAuthenticated,
512
+ getToken: () => auth.getToken()
680
513
  };
681
514
  return service;
682
515
  }
@@ -742,55 +575,6 @@ function createMockOrdersAdapter() {
742
575
  }
743
576
  };
744
577
  }
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
- }
794
578
  function createOrdersService(adapter) {
795
579
  return {
796
580
  async getOrders(params) {
@@ -810,7 +594,7 @@ function createMockProductAdapter() {
810
594
  id: "sample-1",
811
595
  title: "Hydrating Gel Cleanser for Face and Eye Area",
812
596
  featuredImage: {
813
- url: "https://placehold.co/400x400?text=Product+1"
597
+ url: "https://via.placeholder.com/400x400?text=Product+1"
814
598
  },
815
599
  hasOnlyDefaultVariant: true,
816
600
  variants: [
@@ -818,7 +602,7 @@ function createMockProductAdapter() {
818
602
  id: "sample-1-1",
819
603
  title: "150 ml bottle",
820
604
  image: {
821
- url: "https://placehold.co/400x400?text=Product+1"
605
+ url: "https://via.placeholder.com/400x400?text=Product+1"
822
606
  },
823
607
  price: {
824
608
  amount: "12.49",
@@ -844,7 +628,7 @@ function createMockProductAdapter() {
844
628
  id: "sample-2",
845
629
  title: "More COLLAGEN",
846
630
  featuredImage: {
847
- url: "https://placehold.co/400x400?text=Product+2"
631
+ url: "https://via.placeholder.com/400x400?text=Product+2"
848
632
  },
849
633
  hasOnlyDefaultVariant: true,
850
634
  variants: [
@@ -852,7 +636,7 @@ function createMockProductAdapter() {
852
636
  id: "sample-2-1",
853
637
  title: "blackcurrant",
854
638
  image: {
855
- url: "https://placehold.co/400x400?text=Product+2"
639
+ url: "https://via.placeholder.com/400x400?text=Product+2"
856
640
  },
857
641
  price: {
858
642
  amount: "12.49",
@@ -873,7 +657,7 @@ function createMockProductAdapter() {
873
657
  id: "sample-3",
874
658
  title: "Gentle deodorant for underarms and bust",
875
659
  featuredImage: {
876
- url: "https://placehold.co/400x400?text=Product+3"
660
+ url: "https://via.placeholder.com/400x400?text=Product+3"
877
661
  },
878
662
  hasOnlyDefaultVariant: false,
879
663
  variants: [
@@ -881,7 +665,7 @@ function createMockProductAdapter() {
881
665
  id: "sample-3-1",
882
666
  title: "Green tea and jasmine",
883
667
  image: {
884
- url: "https://placehold.co/400x400?text=Product+3a"
668
+ url: "https://via.placeholder.com/400x400?text=Product+3a"
885
669
  },
886
670
  price: {
887
671
  amount: "6.7",
@@ -899,7 +683,7 @@ function createMockProductAdapter() {
899
683
  id: "sample-3-2",
900
684
  title: "Lavender and mint",
901
685
  image: {
902
- url: "https://placehold.co/400x400?text=Product+3b"
686
+ url: "https://via.placeholder.com/400x400?text=Product+3b"
903
687
  },
904
688
  price: {
905
689
  amount: "7.5",
@@ -931,48 +715,6 @@ function createMockProductAdapter() {
931
715
  }
932
716
  };
933
717
  }
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
- };
976
718
  return {
977
719
  async getById(id) {
978
720
  await new Promise((resolve) => setTimeout(resolve, 100));
@@ -986,27 +728,6 @@ function createMockProductAdapter() {
986
728
  );
987
729
  return product == null ? null : processProduct(product);
988
730
  },
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
- },
1010
731
  async search(opts) {
1011
732
  await new Promise((resolve) => setTimeout(resolve, 100));
1012
733
  let filteredProducts = [...products];
@@ -1047,201 +768,18 @@ function createMockProductAdapter() {
1047
768
  }
1048
769
  };
1049
770
  }
1050
- function mapVariant(variant, currencyCode) {
1051
- var _a;
1052
- return {
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
- }
1080
- },
1081
- collections: product.collections
1082
- };
1083
- }
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();
1091
- }
771
+ const ProductServiceContext = createContext("services/product");
772
+ function createProductService(adapter) {
1092
773
  return {
1093
774
  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
- }
775
+ return adapter.getById(id);
1101
776
  },
1102
777
  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);
778
+ return adapter.getByVariantId(variantId);
1237
779
  },
1238
780
  async search(opts) {
1239
781
  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 })
782
+ }
1245
783
  };
1246
784
  }
1247
785
  function routeNameTableFromPages(pages) {
@@ -1258,7 +796,7 @@ function routeNameTableFromPages(pages) {
1258
796
  function createRouterService(options) {
1259
797
  const { pages, pushImplementation } = options;
1260
798
  const routeNameToPagePath = routeNameTableFromPages(pages);
1261
- const pathSet = new Set(pages.map((p2) => p2.path));
799
+ const pathSet = new Set(pages.map((p3) => p3.path));
1262
800
  const navigationSubscribers = [];
1263
801
  function notifySubscribers(logicalPath) {
1264
802
  for (const cb of navigationSubscribers) cb({ path: logicalPath });
@@ -1295,74 +833,7 @@ function createMockRouterService() {
1295
833
  }
1296
834
  }).routerService;
1297
835
  }
1298
- function toAttributeArray(next) {
1299
- return Object.entries(next).map(([key, value]) => ({ key, value }));
1300
- }
1301
836
  function createMockSubscriptionAdapter(options = {}) {
1302
- const richBase = (id, itemId, renewalId) => ({
1303
- id,
1304
- customerId: "customer_1",
1305
- items: [
1306
- {
1307
- id: itemId,
1308
- // Aligned with the mock product catalog (createMockProductAdapter):
1309
- // sample-3 "Gentle deodorant", variant sample-3-1 "Green tea and jasmine",
1310
- // recurring price 5.36 EUR (10% off → 4.82 with SAVE10).
1311
- productId: "sample-3",
1312
- variantId: "sample-3-1",
1313
- quantity: 2,
1314
- price: { amount: "5.36", currencyCode: "EUR" },
1315
- nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-15"),
1316
- isUpsell: false,
1317
- isVirtual: false,
1318
- nextBillingDate: "2025-11-15T00:00:00Z",
1319
- currentPrice: { amount: "5.36", currencyCode: "EUR" },
1320
- lineDiscountedPrice: { amount: "4.82", currencyCode: "EUR" },
1321
- variantAvailableForSale: true,
1322
- title: "Gentle deodorant for underarms and bust",
1323
- variantTitle: "Green tea and jasmine",
1324
- variantImage: { url: "https://placehold.co/400x400?text=Product+3a" },
1325
- billingPolicy: { intervalCount: 1, interval: "MONTH" },
1326
- deliveryPolicy: { intervalCount: 1, interval: "MONTH" }
1327
- }
1328
- ],
1329
- discounts: [
1330
- {
1331
- id: "discount_1",
1332
- type: "percentage",
1333
- value: 10,
1334
- code: "SAVE10",
1335
- description: "10% off subscription"
1336
- }
1337
- ],
1338
- status: "active",
1339
- nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-15"),
1340
- frequency: "1 MONTH",
1341
- createdAt: "2024-10-01T00:00:00Z",
1342
- updatedAt: "2024-10-14T00:00:00Z",
1343
- billingPolicy: { intervalCount: 1, interval: "MONTH", minCycles: 6 },
1344
- deliveryPolicy: {
1345
- intervalCount: 1,
1346
- interval: "MONTH",
1347
- anchors: [{ day: 15, type: "MONTHDAY" }]
1348
- },
1349
- nextBillingDate: "2025-11-15T00:00:00Z",
1350
- nextBillingAttempt: { date: "2025-11-15T00:00:00Z", attempt: 1, ready: true },
1351
- lastBillingAttempt: { date: "2025-10-15T00:00:00Z", ready: true },
1352
- nextFulfillment: "2025-11-17T00:00:00Z",
1353
- estimatedOrderDate: "2025-11-13T00:00:00Z",
1354
- customerPaymentMethod: {
1355
- id: "pm_1",
1356
- instrument: { type: "credit_card", brand: "visa", maskedNumber: "************4242" },
1357
- active: true,
1358
- isRecurring: true
1359
- },
1360
- requiredBillingCyclesLeft: 3,
1361
- renewal: { id: renewalId, isInActiveProcessState: false },
1362
- lastPaymentStatus: "succeeded",
1363
- pausePeriod: null,
1364
- isEditable: true
1365
- });
1366
837
  const mockSubscriptions = [
1367
838
  {
1368
839
  id: "sub_1",
@@ -1370,27 +841,14 @@ function createMockSubscriptionAdapter(options = {}) {
1370
841
  items: [
1371
842
  {
1372
843
  id: "item_1",
1373
- // Aligned with the mock product catalog (createMockProductAdapter):
1374
- // sample-1 "Hydrating Gel Cleanser" (default variant), recurring price
1375
- // 9.99 EUR (10% off → 8.99 with SAVE10).
1376
- productId: "sample-1",
1377
- variantId: "sample-1-1",
844
+ productId: "product_1",
845
+ variantId: "variant_1",
1378
846
  quantity: 2,
1379
- price: { amount: "9.99", currencyCode: "EUR" },
847
+ price: { amount: "29.99", currencyCode: "USD" },
1380
848
  nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-15"),
1381
- isUpsell: false,
1382
- isVirtual: false,
1383
- nextBillingDate: "2025-11-15T00:00:00Z",
1384
- currentPrice: { amount: "9.99", currencyCode: "EUR" },
1385
- lineDiscountedPrice: { amount: "8.99", currencyCode: "EUR" },
1386
- variantAvailableForSale: true,
1387
- title: "Hydrating Gel Cleanser for Face and Eye Area",
1388
- variantImage: { url: "https://placehold.co/400x400?text=Product+1" },
1389
- billingPolicy: { intervalCount: 1, interval: "MONTH" },
1390
- deliveryPolicy: { intervalCount: 1, interval: "MONTH" },
1391
849
  customAttributes: [
1392
- { key: "skin_type", value: "combination" },
1393
- { key: "fragrance", value: "fragrance_free" }
850
+ { key: "roast_level", value: "medium" },
851
+ { key: "grind_type", value: "whole_bean" }
1394
852
  ]
1395
853
  }
1396
854
  ],
@@ -1408,31 +866,9 @@ function createMockSubscriptionAdapter(options = {}) {
1408
866
  frequency: "1 MONTH",
1409
867
  createdAt: "2024-10-01T00:00:00Z",
1410
868
  updatedAt: "2024-10-14T00:00:00Z",
1411
- billingPolicy: { intervalCount: 1, interval: "MONTH", minCycles: 6 },
1412
- deliveryPolicy: {
1413
- intervalCount: 1,
1414
- interval: "MONTH",
1415
- anchors: [{ day: 15, type: "MONTHDAY" }]
1416
- },
1417
- nextBillingDate: "2025-11-15T00:00:00Z",
1418
- nextBillingAttempt: { date: "2025-11-15T00:00:00Z", attempt: 1, ready: true },
1419
- lastBillingAttempt: { date: "2025-10-15T00:00:00Z", ready: true },
1420
- nextFulfillment: "2025-11-17T00:00:00Z",
1421
- estimatedOrderDate: "2025-11-13T00:00:00Z",
1422
- customerPaymentMethod: {
1423
- id: "pm_1",
1424
- instrument: { type: "credit_card", brand: "visa", maskedNumber: "************4242" },
1425
- active: true,
1426
- isRecurring: true
1427
- },
1428
- requiredBillingCyclesLeft: 3,
1429
- renewal: { id: "ren_1", isInActiveProcessState: false },
1430
- lastPaymentStatus: "succeeded",
1431
- pausePeriod: null,
1432
- isEditable: true,
1433
869
  customAttributes: [
1434
870
  { key: "subscription_tier", value: "premium" },
1435
- { key: "gift_message", value: "Enjoy your skincare routine!" }
871
+ { key: "gift_message", value: "Enjoy your coffee!" }
1436
872
  ]
1437
873
  },
1438
874
  {
@@ -1441,17 +877,11 @@ function createMockSubscriptionAdapter(options = {}) {
1441
877
  items: [
1442
878
  {
1443
879
  id: "item_2",
1444
- // Aligned with the mock product catalog (createMockProductAdapter):
1445
- // sample-2 "More COLLAGEN" (default variant), recurring price 10.99 EUR.
1446
- productId: "sample-2",
1447
- variantId: "sample-2-1",
880
+ productId: "product_2",
881
+ variantId: "variant_2",
1448
882
  quantity: 1,
1449
- price: { amount: "10.99", currencyCode: "EUR" },
883
+ price: { amount: "49.99", currencyCode: "USD" },
1450
884
  nextDeliveryDate: /* @__PURE__ */ new Date("2025-11-20"),
1451
- title: "More COLLAGEN",
1452
- variantImage: { url: "https://placehold.co/400x400?text=Product+2" },
1453
- billingPolicy: { intervalCount: 2, interval: "WEEK" },
1454
- deliveryPolicy: { intervalCount: 2, interval: "WEEK" },
1455
885
  customAttributes: []
1456
886
  }
1457
887
  ],
@@ -1462,66 +892,17 @@ function createMockSubscriptionAdapter(options = {}) {
1462
892
  createdAt: "2024-09-15T00:00:00Z",
1463
893
  updatedAt: "2024-10-10T00:00:00Z",
1464
894
  customAttributes: []
1465
- },
1466
- // Per-status fixtures: groundwork for the deferred editor preview picker
1467
- // (docs/superpowers/specs/2026-06-17-renewalsummary-parity-and-mock-groundwork-design.md §9).
1468
- // Not consumed yet — the editor still seeds the active sub_1 via getDefaultSubscriptionId().
1469
- {
1470
- ...richBase("sub_paused", "item_paused", "ren_paused"),
1471
- status: "paused",
1472
- pausePeriod: { start: "2025-11-01T00:00:00Z", end: "2026-01-01T00:00:00Z" }
1473
- },
1474
- {
1475
- ...richBase("sub_canceled", "item_canceled", "ren_canceled"),
1476
- status: "canceled",
1477
- pausePeriod: null
1478
- },
1479
- {
1480
- ...richBase("sub_failed", "item_failed", "ren_failed"),
1481
- status: "failed",
1482
- lastPaymentStatus: "failed",
1483
- pausePeriod: null
1484
- },
1485
- {
1486
- ...richBase("sub_expired", "item_expired", "ren_expired"),
1487
- status: "expired",
1488
- pausePeriod: null
1489
- }
1490
- ];
1491
- const mockUpsellProducts = [
1492
- {
1493
- id: "upsell-1",
1494
- variantId: "upsell-v-1",
1495
- title: "Retinol Night Cream",
1496
- imageUrl: "https://images.unsplash.com/photo-1617897903246-719242758050?w=200",
1497
- price: { amount: "38.00", currencyCode: "USD" },
1498
- description: "Anti-aging night treatment"
1499
- },
1500
- {
1501
- id: "upsell-2",
1502
- variantId: "upsell-v-2",
1503
- title: "SPF 50 Day Shield",
1504
- imageUrl: "https://images.unsplash.com/photo-1556228578-8c89e6adf883?w=200",
1505
- price: { amount: "24.00", currencyCode: "USD" },
1506
- description: "Lightweight daily sun protection"
1507
895
  }
1508
896
  ];
1509
897
  return {
1510
898
  async getById(id) {
1511
899
  await new Promise((resolve) => setTimeout(resolve, 300));
1512
- const subscription = mockSubscriptions.find((sub) => sub.id === id);
1513
- return {
1514
- _tag: "Success",
1515
- data: subscription ? {
1516
- ...subscription,
1517
- items: subscription.items.map((item) => ({ ...item })),
1518
- discounts: subscription.discounts.map((d3) => ({ ...d3 }))
1519
- } : null
1520
- };
900
+ const subscription = mockSubscriptions.find((sub) => sub.id === id) || null;
901
+ return { _tag: "Success", data: subscription };
1521
902
  },
1522
903
  async search(options2 = {}) {
1523
904
  await new Promise((resolve) => setTimeout(resolve, 300));
1524
- const pageSize = 2;
905
+ const pageSize = 1;
1525
906
  const allItems = mockSubscriptions;
1526
907
  let startIndex = 0;
1527
908
  let endIndex = pageSize;
@@ -1537,108 +918,29 @@ function createMockSubscriptionAdapter(options = {}) {
1537
918
  }
1538
919
  }
1539
920
  const pageItems = allItems.slice(startIndex, endIndex);
1540
- return {
1541
- _tag: "Success",
1542
- data: {
1543
- items: pageItems.map((sub) => ({
1544
- ...sub,
1545
- items: sub.items.map((item) => ({ ...item })),
1546
- discounts: sub.discounts.map((discount) => ({ ...discount }))
1547
- })),
1548
- pageInfo: {
1549
- hasNextPage: endIndex < allItems.length,
1550
- hasPrevPage: startIndex > 0,
1551
- startCursor: pageItems.length > 0 ? startIndex.toString() : null,
1552
- endCursor: pageItems.length > 0 ? (endIndex - 1).toString() : null
1553
- }
921
+ const paginatedList = {
922
+ items: pageItems.map((sub) => ({
923
+ ...sub,
924
+ items: sub.items.map((item) => ({ ...item })),
925
+ discounts: sub.discounts.map((discount) => ({ ...discount }))
926
+ })),
927
+ pageInfo: {
928
+ hasNextPage: endIndex < allItems.length,
929
+ hasPrevPage: startIndex > 0,
930
+ startCursor: pageItems.length > 0 ? startIndex.toString() : null,
931
+ endCursor: pageItems.length > 0 ? (endIndex - 1).toString() : null
1554
932
  }
1555
933
  };
934
+ return { _tag: "Success", data: paginatedList };
1556
935
  },
1557
- async addItem({ subscriptionId, item }) {
1558
- var _a, _b, _c, _d, _e, _f, _g;
1559
- await new Promise((resolve) => setTimeout(resolve, 300));
1560
- const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1561
- if (!subscription) {
1562
- return { _tag: "Failure", error: "Subscription not found" };
1563
- }
1564
- const currencyCode = ((_a = subscription.items[0]) == null ? void 0 : _a.price.currencyCode) ?? "USD";
1565
- 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;
1566
- const variant = (product == null ? void 0 : product.variants.items.find((v2) => v2.id === item.variantId)) ?? (product == null ? void 0 : product.variants.items[0]);
1567
- 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);
1568
- subscription.items.push({
1569
- id: `item_${Date.now()}_${subscription.items.length}`,
1570
- productId: (product == null ? void 0 : product.id) ?? "",
1571
- variantId: item.variantId,
1572
- quantity: item.quantity,
1573
- price: linePrice ? { ...linePrice } : { amount: "0.00", currencyCode },
1574
- ...linePrice ? { currentPrice: { ...linePrice } } : {},
1575
- title: (product == null ? void 0 : product.title) ?? `Product ${item.variantId}`,
1576
- ...variant && product && !product.hasOnlyDefaultVariant ? { variantTitle: variant.title } : {},
1577
- ...(variant == null ? void 0 : variant.image) ? { variantImage: variant.image } : {},
1578
- variantAvailableForSale: true,
1579
- billingPolicy: ((_f = subscription.items[0]) == null ? void 0 : _f.billingPolicy) ?? subscription.billingPolicy ?? null,
1580
- deliveryPolicy: ((_g = subscription.items[0]) == null ? void 0 : _g.deliveryPolicy) ?? subscription.deliveryPolicy ?? null
1581
- });
1582
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1583
- return { _tag: "Success", data: void 0 };
1584
- },
1585
- async removeItem({ subscriptionId, itemId }) {
1586
- await new Promise((resolve) => setTimeout(resolve, 300));
1587
- const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1588
- if (!subscription) {
1589
- return { _tag: "Failure", error: "Subscription not found" };
1590
- }
1591
- subscription.items = subscription.items.filter((i3) => i3.id !== itemId);
1592
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1593
- return { _tag: "Success", data: void 0 };
1594
- },
1595
- async updateItem({ subscriptionId, lineId, update }) {
1596
- await new Promise((resolve) => setTimeout(resolve, 300));
1597
- const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1598
- if (!subscription) {
1599
- return { _tag: "Failure", error: "Subscription not found" };
1600
- }
1601
- const item = subscription.items.find((i3) => i3.id === lineId);
1602
- if (!item) {
1603
- return { _tag: "Failure", error: "Line item not found" };
1604
- }
1605
- if (update.variantId !== void 0) item.variantId = update.variantId;
1606
- if (update.quantity !== void 0) item.quantity = update.quantity;
1607
- if (update.billingPolicy !== void 0) item.billingPolicy = update.billingPolicy;
1608
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1609
- return { _tag: "Success", data: void 0 };
1610
- },
1611
- async updateItemAttributes({ subscriptionId, lineId, customAttributes }) {
1612
- await new Promise((resolve) => setTimeout(resolve, 300));
1613
- const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1614
- if (!subscription) {
1615
- return { _tag: "Failure", error: "Subscription not found" };
1616
- }
1617
- const item = subscription.items.find((i3) => i3.id === lineId);
1618
- if (!item) {
1619
- return { _tag: "Failure", error: "Line item not found" };
1620
- }
1621
- item.customAttributes = toAttributeArray(customAttributes);
1622
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1623
- return { _tag: "Success", data: void 0 };
1624
- },
1625
- async updateAttributes({ subscriptionId, customAttributes }) {
936
+ async addItem() {
1626
937
  await new Promise((resolve) => setTimeout(resolve, 300));
1627
- const subscription = mockSubscriptions.find((sub) => sub.id === subscriptionId);
1628
- if (!subscription) {
1629
- return { _tag: "Failure", error: "Subscription not found" };
1630
- }
1631
- subscription.customAttributes = toAttributeArray(customAttributes);
1632
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1633
938
  return { _tag: "Success", data: void 0 };
1634
939
  },
1635
- async skipLineItem() {
940
+ async removeItem() {
1636
941
  await new Promise((resolve) => setTimeout(resolve, 300));
1637
942
  return { _tag: "Success", data: void 0 };
1638
943
  },
1639
- async updateBoxItems() {
1640
- return { _tag: "Success", data: void 0 };
1641
- },
1642
944
  async addDiscount() {
1643
945
  await new Promise((resolve) => setTimeout(resolve, 300));
1644
946
  const behavior = options.addDiscountBehavior ?? { kind: "success" };
@@ -1667,29 +969,24 @@ function createMockSubscriptionAdapter(options = {}) {
1667
969
  (sub) => sub.id === params.subscriptionId
1668
970
  );
1669
971
  if (!subscription) {
1670
- return { _tag: "Failure", error: "Subscription not found" };
972
+ return {
973
+ _tag: "Failure",
974
+ error: "Subscription not found"
975
+ };
1671
976
  }
1672
977
  subscription.nextDeliveryDate = new Date(params.newDate);
1673
978
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1674
- return { _tag: "Success", data: { ...subscription } };
1675
- },
1676
- async updateCustomAttributes(params) {
1677
- await new Promise((resolve) => setTimeout(resolve, 300));
1678
- const subscription = mockSubscriptions.find(
1679
- (sub) => sub.id === params.subscriptionId
1680
- );
1681
- if (!subscription) {
1682
- return { _tag: "Failure", error: "Subscription not found" };
1683
- }
1684
- const preserved = (subscription.customAttributes ?? []).filter(
1685
- (attr) => attr.key.startsWith("_")
1686
- );
1687
- const next = Object.entries(params.customAttributes).map(
1688
- ([key, value]) => ({ key, value })
1689
- );
1690
- subscription.customAttributes = [...preserved, ...next];
1691
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1692
- return { _tag: "Success", data: { ...subscription } };
979
+ subscription.items.forEach((item) => {
980
+ item.nextDeliveryDate = new Date(params.newDate);
981
+ });
982
+ return {
983
+ _tag: "Success",
984
+ data: {
985
+ ...subscription,
986
+ items: subscription.items.map((item) => ({ ...item })),
987
+ discounts: subscription.discounts.map((discount) => ({ ...discount }))
988
+ }
989
+ };
1693
990
  },
1694
991
  async resume(params) {
1695
992
  await new Promise((resolve) => setTimeout(resolve, 300));
@@ -1697,1110 +994,121 @@ function createMockSubscriptionAdapter(options = {}) {
1697
994
  (sub) => sub.id === params.subscriptionId
1698
995
  );
1699
996
  if (!subscription) {
1700
- return { _tag: "Failure", error: "Subscription not found" };
1701
- }
1702
- subscription.status = "active";
1703
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1704
- return { _tag: "Success", data: { ...subscription } };
1705
- },
1706
- async pause(params) {
1707
- await new Promise((resolve) => setTimeout(resolve, 300));
1708
- const subscription = mockSubscriptions.find(
1709
- (sub) => sub.id === params.subscriptionId
1710
- );
1711
- if (!subscription) {
1712
- return { _tag: "Failure", error: "Subscription not found" };
1713
- }
1714
- subscription.status = "paused";
1715
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1716
- return { _tag: "Success", data: { ...subscription } };
1717
- },
1718
- async reactivate(params) {
1719
- await new Promise((resolve) => setTimeout(resolve, 300));
1720
- const subscription = mockSubscriptions.find(
1721
- (sub) => sub.id === params.subscriptionId
1722
- );
1723
- if (!subscription) {
1724
- return { _tag: "Failure", error: "Subscription not found" };
997
+ return {
998
+ _tag: "Failure",
999
+ error: "Subscription not found"
1000
+ };
1725
1001
  }
1726
1002
  subscription.status = "active";
1727
1003
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1728
- return { _tag: "Success", data: { ...subscription } };
1729
- },
1730
- async cancel(params) {
1731
- await new Promise((resolve) => setTimeout(resolve, 300));
1732
- const subscription = mockSubscriptions.find(
1733
- (sub) => sub.id === params.subscriptionId
1734
- );
1735
- if (!subscription) {
1736
- return { _tag: "Failure", error: "Subscription not found" };
1737
- }
1738
- subscription.status = "canceled";
1739
- subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1740
- return { _tag: "Success", data: { ...subscription } };
1741
- },
1742
- async getAvailablePlans() {
1743
- await new Promise((resolve) => setTimeout(resolve, 300));
1744
- return {
1745
- _tag: "Success",
1746
- data: [
1747
- {
1748
- id: "plan_1",
1749
- name: "Monthly",
1750
- billingPolicy: { intervalCount: 1, interval: "MONTH" },
1751
- deliveryPolicy: { intervalCount: 1, interval: "MONTH" }
1752
- },
1753
- {
1754
- id: "plan_2",
1755
- name: "Every 2 months",
1756
- billingPolicy: { intervalCount: 2, interval: "MONTH" },
1757
- deliveryPolicy: { intervalCount: 2, interval: "MONTH" }
1758
- },
1759
- {
1760
- id: "plan_3",
1761
- name: "Every 3 months",
1762
- billingPolicy: { intervalCount: 3, interval: "MONTH" },
1763
- deliveryPolicy: { intervalCount: 3, interval: "MONTH" }
1764
- }
1765
- ]
1766
- };
1767
- },
1768
- async getLastOrder(params) {
1769
- await new Promise((resolve) => setTimeout(resolve, 200));
1770
- const subscription = mockSubscriptions.find((sub) => sub.id === params.subscriptionId);
1771
- if (!subscription) return { _tag: "Success", data: null };
1772
1004
  return {
1773
1005
  _tag: "Success",
1774
1006
  data: {
1775
- id: `mock_last_order_${params.subscriptionId}`,
1776
- createdAt: "2026-04-22T12:00:00Z"
1007
+ ...subscription,
1008
+ items: subscription.items.map((item) => ({ ...item })),
1009
+ discounts: subscription.discounts.map((discount) => ({ ...discount }))
1777
1010
  }
1778
1011
  };
1779
1012
  },
1780
- async renewNow(_params) {
1781
- await new Promise((resolve) => setTimeout(resolve, 300));
1782
- return { _tag: "Success", data: { result: "success" } };
1783
- },
1784
- async changeFrequency(params) {
1013
+ async pause(params) {
1785
1014
  await new Promise((resolve) => setTimeout(resolve, 300));
1786
- const subscription = mockSubscriptions.find((sub) => sub.id === params.subscriptionId);
1015
+ const subscription = mockSubscriptions.find(
1016
+ (sub) => sub.id === params.subscriptionId
1017
+ );
1787
1018
  if (!subscription) {
1788
- return { _tag: "Failure", error: "Subscription not found" };
1789
- }
1790
- if (typeof params.plan === "string") {
1791
- subscription.frequency = `1 ${params.plan}`;
1792
- } else {
1793
- subscription.frequency = `${params.plan.intervalCount} ${params.plan.interval}`;
1794
- if (subscription.billingPolicy) {
1795
- subscription.billingPolicy = { ...subscription.billingPolicy, ...params.plan };
1796
- }
1797
- if (subscription.deliveryPolicy) {
1798
- subscription.deliveryPolicy = { ...subscription.deliveryPolicy, ...params.plan };
1799
- }
1019
+ return {
1020
+ _tag: "Failure",
1021
+ error: "Subscription not found"
1022
+ };
1800
1023
  }
1024
+ subscription.status = "paused";
1801
1025
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1802
1026
  return {
1803
1027
  _tag: "Success",
1804
1028
  data: {
1805
1029
  ...subscription,
1806
1030
  items: subscription.items.map((item) => ({ ...item })),
1807
- discounts: subscription.discounts.map((d3) => ({ ...d3 }))
1031
+ discounts: subscription.discounts.map((discount) => ({ ...discount }))
1808
1032
  }
1809
1033
  };
1810
1034
  },
1811
- async getDefaultSubscriptionId() {
1812
- var _a;
1813
- await new Promise((resolve) => setTimeout(resolve, 300));
1814
- return { _tag: "Success", data: ((_a = mockSubscriptions[0]) == null ? void 0 : _a.id) ?? null };
1815
- },
1816
- async getUpsellProducts() {
1817
- await new Promise((resolve) => setTimeout(resolve, 300));
1818
- return { _tag: "Success", data: [...mockUpsellProducts] };
1819
- },
1820
- async addUpsellProduct() {
1821
- await new Promise((resolve) => setTimeout(resolve, 400));
1822
- return { _tag: "Success", data: void 0 };
1823
- }
1824
- };
1825
- }
1826
- function normalizeInstrumentType(type) {
1827
- return type.replace(/-/g, "_");
1828
- }
1829
- function mapPaymentMethod(rawPm) {
1830
- if (!rawPm) return null;
1831
- if (typeof rawPm === "string") {
1832
- return { id: rawPm };
1833
- }
1834
- return {
1835
- id: rawPm.id ?? "",
1836
- ...rawPm.instrument != null ? {
1837
- instrument: {
1838
- ...rawPm.instrument,
1839
- type: normalizeInstrumentType(rawPm.instrument.type)
1840
- }
1841
- } : {},
1842
- ...rawPm.active != null ? { active: rawPm.active } : {},
1843
- ...rawPm.isRecurring != null ? { isRecurring: rawPm.isRecurring } : {}
1844
- };
1845
- }
1846
- function mapSubscription(raw) {
1847
- var _a, _b;
1848
- const status = raw.status === "merged" ? "canceled" : raw.status;
1849
- const deliveryPolicy = raw.deliveryPolicy ?? ((_b = (_a = raw.items) == null ? void 0 : _a[0]) == null ? void 0 : _b.deliveryPolicy);
1850
- const frequency = deliveryPolicy ? `${deliveryPolicy.intervalCount} ${deliveryPolicy.interval}` : "";
1851
- return {
1852
- id: raw.id,
1853
- customerId: "",
1854
- serial: raw.serial,
1855
- items: (raw.items ?? []).map(
1856
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1857
- (item) => ({
1858
- id: item.id,
1859
- productId: item.productId ?? item.product ?? "",
1860
- variantId: item.variantId ?? item.variant ?? "",
1861
- quantity: item.quantity,
1862
- price: item.price ?? {
1863
- amount: String(item.totalPrice ?? 0),
1864
- currencyCode: raw.currencyCode ?? ""
1865
- },
1866
- nextDeliveryDate: item.nextDeliveryDate ? new Date(item.nextDeliveryDate) : null,
1867
- billingPolicy: item.billingPolicy ?? raw.billingPolicy ?? null,
1868
- deliveryPolicy: item.deliveryPolicy ?? raw.deliveryPolicy ?? null,
1869
- // Map human-readable titles from the v1 SubscriptionItemResource
1870
- title: item.title,
1871
- variantTitle: item.subtitle ?? void 0,
1872
- // recurringCycleLimit === 1 means the item charges exactly once (one-time upsell)
1873
- recurringCycleLimit: item.recurringCycleLimit ?? null,
1874
- customAttributes: Array.isArray(item.customAttributes) ? item.customAttributes : []
1875
- })
1876
- ),
1877
- discounts: (raw.discounts ?? []).map(
1878
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1879
- (d3) => {
1880
- var _a2, _b2, _c;
1881
- return {
1882
- id: d3.id,
1883
- type: ((_a2 = d3.value) == null ? void 0 : _a2.type) === "fixed-amount" || d3.type === "fixed_amount" ? "fixed_amount" : "percentage",
1884
- value: ((_b2 = d3.value) == null ? void 0 : _b2.amount) ?? ((_c = d3.value) == null ? void 0 : _c.percentage) ?? d3.value ?? 0,
1885
- code: d3.title ?? d3.code ?? "",
1886
- description: d3.description ?? ""
1887
- };
1888
- }
1889
- ),
1890
- status,
1891
- nextDeliveryDate: raw.nextBillingDate ? new Date(raw.nextBillingDate) : raw.nextDeliveryDate ? new Date(raw.nextDeliveryDate) : null,
1892
- // Map nextBillingDate as the raw ISO string for ProductSelect skip() and other consumers
1893
- nextBillingDate: raw.nextBillingDate ?? null,
1894
- // Map customerPaymentMethod — note: arrives as bare id (not expanded) since the
1895
- // subscriptions endpoint does not support ?expand=paymentMethod; instrument digits
1896
- // remain a data gap pending backend API extension.
1897
- customerPaymentMethod: mapPaymentMethod(raw.paymentMethod),
1898
- frequency,
1899
- createdAt: raw.createdAt,
1900
- updatedAt: raw.updatedAt,
1901
- billingPolicy: raw.billingPolicy ?? null,
1902
- deliveryPolicy: raw.deliveryPolicy ?? null,
1903
- customAttributes: Array.isArray(raw.customAttributes) ? raw.customAttributes : []
1904
- };
1905
- }
1906
- function createApiSubscriptionAdapter(fetcher) {
1907
- const adapter = {
1908
- async search(options) {
1909
- var _a;
1910
- try {
1911
- const params = new URLSearchParams();
1912
- if ((_a = options == null ? void 0 : options.filters) == null ? void 0 : _a.length) {
1913
- 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 ");
1914
- if (q2) params.set("query", q2);
1915
- }
1916
- if (options == null ? void 0 : options.pagination) {
1917
- if ("after" in options.pagination)
1918
- params.set("after", options.pagination.after);
1919
- else if ("before" in options.pagination)
1920
- params.set("before", options.pagination.before);
1921
- }
1922
- const query = params.toString() ? `?${params.toString()}` : "";
1923
- const res = await fetcher(`/customer/v1/subscriptions${query}`);
1924
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1925
- const body = await res.json();
1926
- return {
1927
- _tag: "Success",
1928
- data: {
1929
- items: body.data.map(mapSubscription),
1930
- pageInfo: {
1931
- hasNextPage: body.hasNextPage,
1932
- hasPrevPage: body.hasPrevPage,
1933
- startCursor: body.startCursor,
1934
- endCursor: body.endCursor
1935
- }
1936
- }
1937
- };
1938
- } catch (e2) {
1939
- return { _tag: "Failure", error: e2 };
1940
- }
1941
- },
1942
- async getById(id) {
1943
- try {
1944
- const res = await fetcher(
1945
- `/customer/v1/subscriptions?query=id:"${id}"&limit=1`
1946
- );
1947
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1948
- const body = await res.json();
1949
- const raw = body.data[0];
1950
- return { _tag: "Success", data: raw ? mapSubscription(raw) : null };
1951
- } catch (e2) {
1952
- return { _tag: "Failure", error: e2 };
1953
- }
1954
- },
1955
- async addItem({ subscriptionId, item }) {
1956
- try {
1957
- const res = await fetcher(
1958
- `/customer/v1/subscriptions/${subscriptionId}/items`,
1959
- {
1960
- method: "POST",
1961
- headers: { "Content-Type": "application/json" },
1962
- body: JSON.stringify(item)
1963
- }
1964
- );
1965
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1966
- return { _tag: "Success", data: void 0 };
1967
- } catch (e2) {
1968
- return { _tag: "Failure", error: e2 };
1969
- }
1970
- },
1971
- async removeItem({ subscriptionId, itemId }) {
1972
- try {
1973
- const res = await fetcher(
1974
- `/customer/v1/subscriptions/${subscriptionId}/items/${itemId}`,
1975
- { method: "DELETE" }
1976
- );
1977
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
1978
- return { _tag: "Success", data: void 0 };
1979
- } catch (e2) {
1980
- return { _tag: "Failure", error: e2 };
1981
- }
1982
- },
1983
- async updateItem({ subscriptionId, lineId, update }) {
1984
- try {
1985
- const body = {
1986
- ...update.variantId !== void 0 ? { productVariantId: update.variantId } : {},
1987
- ...update.quantity !== void 0 ? { quantity: update.quantity } : {},
1988
- ...update.billingPolicy !== void 0 ? { billingPolicy: update.billingPolicy } : {},
1989
- ...update.shippingMethodHandle !== void 0 ? { shippingMethodHandle: update.shippingMethodHandle } : {}
1990
- };
1991
- const res = await fetcher(
1992
- `/customer/subscriptions/${subscriptionId}/lines/${lineId}`,
1993
- {
1994
- method: "PUT",
1995
- headers: { "Content-Type": "application/json" },
1996
- body: JSON.stringify(body)
1997
- }
1998
- );
1999
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2000
- return { _tag: "Success", data: void 0 };
2001
- } catch (e2) {
2002
- return { _tag: "Failure", error: e2 };
2003
- }
2004
- },
2005
- async updateItemAttributes({ subscriptionId, lineId, customAttributes }) {
2006
- try {
2007
- const res = await fetcher(
2008
- `/customer/v1/subscriptions/${subscriptionId}/items/${lineId}`,
2009
- {
2010
- method: "PATCH",
2011
- headers: { "Content-Type": "application/json" },
2012
- body: JSON.stringify({ customAttributes })
2013
- }
2014
- );
2015
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2016
- return { _tag: "Success", data: void 0 };
2017
- } catch (e2) {
2018
- return { _tag: "Failure", error: e2 };
2019
- }
2020
- },
2021
- async updateAttributes({ subscriptionId, customAttributes }) {
2022
- try {
2023
- const res = await fetcher(
2024
- `/customer/v1/subscriptions/${subscriptionId}`,
2025
- {
2026
- method: "PATCH",
2027
- headers: { "Content-Type": "application/json" },
2028
- body: JSON.stringify({ customAttributes })
2029
- }
2030
- );
2031
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2032
- return { _tag: "Success", data: void 0 };
2033
- } catch (e2) {
2034
- return { _tag: "Failure", error: e2 };
2035
- }
2036
- },
2037
- async skipLineItem({ subscriptionId, lineId, nextBillingDate }) {
2038
- try {
2039
- const res = await fetcher(
2040
- `/customer/subscriptions/${subscriptionId}/lines/${lineId}`,
2041
- {
2042
- method: "PUT",
2043
- headers: { "Content-Type": "application/json" },
2044
- body: JSON.stringify({ nextBillingDate })
2045
- }
2046
- );
2047
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2048
- return { _tag: "Success", data: void 0 };
2049
- } catch (e2) {
2050
- return { _tag: "Failure", error: e2 };
2051
- }
2052
- },
2053
- async updateBoxItems({ subscriptionId, parentId, items, shippingMethodHandle }) {
2054
- try {
2055
- const res = await fetcher(
2056
- `/customer/subscriptions/${subscriptionId}/update-box-products`,
2057
- {
2058
- method: "POST",
2059
- headers: { "Content-Type": "application/json" },
2060
- body: JSON.stringify({ parentId, items, shippingMethodHandle })
2061
- }
2062
- );
2063
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2064
- return { _tag: "Success", data: void 0 };
2065
- } catch (e2) {
2066
- return { _tag: "Failure", error: e2 };
2067
- }
2068
- },
2069
- async addDiscount({ subscriptionId, code }) {
2070
- try {
2071
- const res = await fetcher(
2072
- `/customer/v1/subscriptions/${subscriptionId}/discounts`,
2073
- {
2074
- method: "POST",
2075
- headers: { "Content-Type": "application/json" },
2076
- body: JSON.stringify({ code })
2077
- }
2078
- );
2079
- if (!res.ok) return { _tag: "Failure", error: { kind: "NETWORK", message: `HTTP ${res.status}` } };
2080
- return { _tag: "Success", data: void 0 };
2081
- } catch (e2) {
2082
- return { _tag: "Failure", error: { kind: "UNKNOWN", message: e2 instanceof Error ? e2.message : void 0 } };
2083
- }
2084
- },
2085
- async removeDiscount({ subscriptionId, discountId }) {
2086
- try {
2087
- const res = await fetcher(
2088
- `/customer/v1/subscriptions/${subscriptionId}/discounts/${discountId}`,
2089
- { method: "DELETE" }
2090
- );
2091
- if (!res.ok) return { _tag: "Failure", error: { kind: "NETWORK", message: `HTTP ${res.status}` } };
2092
- return { _tag: "Success", data: void 0 };
2093
- } catch (e2) {
2094
- return { _tag: "Failure", error: { kind: "UNKNOWN", message: e2 instanceof Error ? e2.message : void 0 } };
2095
- }
2096
- },
2097
- // Uses PATCH /customer/v1/subscriptions/{id} — the dedicated /reschedule route does not exist.
2098
- async reschedule({ subscriptionId, newDate }) {
2099
- try {
2100
- const res = await fetcher(
2101
- `/customer/v1/subscriptions/${subscriptionId}`,
2102
- {
2103
- method: "PATCH",
2104
- headers: { "Content-Type": "application/json" },
2105
- body: JSON.stringify({ nextBillingDate: newDate })
2106
- }
2107
- );
2108
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2109
- const data = await res.json();
2110
- return { _tag: "Success", data: mapSubscription(data) };
2111
- } catch (e2) {
2112
- return { _tag: "Failure", error: e2 };
2113
- }
2114
- },
2115
- // PATCH /customer/v1/subscriptions/{id} with the full customer-visible set.
2116
- async updateCustomAttributes({ subscriptionId, customAttributes }) {
2117
- try {
2118
- const res = await fetcher(
2119
- `/customer/v1/subscriptions/${subscriptionId}`,
2120
- {
2121
- method: "PATCH",
2122
- headers: { "Content-Type": "application/json" },
2123
- body: JSON.stringify({ customAttributes })
2124
- }
2125
- );
2126
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2127
- const data = await res.json();
2128
- return { _tag: "Success", data: mapSubscription(data) };
2129
- } catch (e2) {
2130
- return { _tag: "Failure", error: e2 };
2131
- }
2132
- },
2133
- async resume({ subscriptionId }) {
2134
- try {
2135
- const res = await fetcher(
2136
- `/customer/v1/subscriptions/${subscriptionId}/resume`,
2137
- { method: "POST" }
2138
- );
2139
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2140
- const data = await res.json();
2141
- return { _tag: "Success", data: mapSubscription(data) };
2142
- } catch (e2) {
2143
- return { _tag: "Failure", error: e2 };
2144
- }
2145
- },
2146
- async pause({ subscriptionId }) {
2147
- try {
2148
- const res = await fetcher(
2149
- `/customer/v1/subscriptions/${subscriptionId}/pause`,
2150
- { method: "POST" }
2151
- );
2152
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2153
- const data = await res.json();
2154
- return { _tag: "Success", data: mapSubscription(data) };
2155
- } catch (e2) {
2156
- return { _tag: "Failure", error: e2 };
2157
- }
2158
- },
2159
- async reactivate({ subscriptionId }) {
2160
- try {
2161
- const res = await fetcher(
2162
- `/customer/v1/subscriptions/${subscriptionId}/reactivate`,
2163
- { method: "POST" }
2164
- );
2165
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2166
- const data = await res.json();
2167
- return { _tag: "Success", data: mapSubscription(data) };
2168
- } catch (e2) {
2169
- return { _tag: "Failure", error: e2 };
2170
- }
2171
- },
2172
- async cancel({ subscriptionId, reason }) {
2173
- try {
2174
- const res = await fetcher(
2175
- `/customer/v1/subscriptions/${subscriptionId}/cancel`,
2176
- {
2177
- method: "POST",
2178
- headers: { "Content-Type": "application/json" },
2179
- body: JSON.stringify({ cancellationReason: reason })
2180
- }
2181
- );
2182
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2183
- const data = await res.json();
2184
- return { _tag: "Success", data: mapSubscription(data) };
2185
- } catch (e2) {
2186
- return { _tag: "Failure", error: e2 };
2187
- }
2188
- },
2189
- // Legacy endpoint — no /customer/v1/subscriptions/{id}/plans exists yet.
2190
- async getAvailablePlans({ subscriptionId }) {
2191
- try {
2192
- const res = await fetcher(
2193
- `/customer/subscriptions/${subscriptionId}/plans`
2194
- );
2195
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2196
- const data = await res.json();
2197
- return { _tag: "Success", data };
2198
- } catch (e2) {
2199
- return { _tag: "Failure", error: e2 };
2200
- }
2201
- },
2202
- // Legacy endpoint — no /customer/v1 equivalent exists yet.
2203
- async getDefaultSubscriptionId() {
2204
- try {
2205
- const res = await fetcher(
2206
- `/customer/subscriptions/one-by-next-billing-date`
2207
- );
2208
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2209
- const data = await res.json();
2210
- return { _tag: "Success", data: (data == null ? void 0 : data.id) ?? null };
2211
- } catch (e2) {
2212
- return { _tag: "Failure", error: e2 };
2213
- }
2214
- },
2215
- // Legacy endpoint — no /customer/v1/subscriptions/{id}/upsells exists yet.
2216
- async getUpsellProducts({ subscriptionId }) {
2217
- try {
2218
- const res = await fetcher(
2219
- `/customer/subscriptions/${subscriptionId}/upsell-products`
2220
- );
2221
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2222
- const data = await res.json();
2223
- const products = data.map((p2) => {
2224
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2225
- return {
2226
- id: p2.id,
2227
- variantId: ((_b = (_a = p2.variants) == null ? void 0 : _a[0]) == null ? void 0 : _b.id) ?? "",
2228
- title: p2.title ?? "",
2229
- imageUrl: ((_c = p2.featuredImage) == null ? void 0 : _c.url) ?? void 0,
2230
- price: {
2231
- amount: String(((_f = (_e = (_d = p2.variants) == null ? void 0 : _d[0]) == null ? void 0 : _e.currentPrice) == null ? void 0 : _f.amount) ?? 0),
2232
- currencyCode: ((_i = (_h = (_g = p2.variants) == null ? void 0 : _g[0]) == null ? void 0 : _h.currentPrice) == null ? void 0 : _i.currencyCode) ?? ""
2233
- },
2234
- // recurring comes from the upsell rule on variants[0]; present in PreparedProductSchema
2235
- recurring: (_k = (_j = p2.variants) == null ? void 0 : _j[0]) == null ? void 0 : _k.recurring
2236
- };
2237
- });
2238
- return { _tag: "Success", data: products };
2239
- } catch (e2) {
2240
- return { _tag: "Failure", error: e2 };
2241
- }
2242
- },
2243
- // Legacy endpoint — no /customer/v1/subscriptions/{id}/upsells POST exists yet.
2244
- async addUpsellProduct({ subscriptionId, variantId, quantity, oneTime }) {
2245
- try {
2246
- const res = await fetcher(
2247
- `/customer/subscriptions/${subscriptionId}/upsell`,
2248
- {
2249
- method: "POST",
2250
- headers: { "Content-Type": "application/json" },
2251
- body: JSON.stringify({
2252
- productVariantId: variantId,
2253
- quantity,
2254
- ...oneTime ? { renewalLimit: 1 } : {}
2255
- })
2256
- }
2257
- );
2258
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2259
- return { _tag: "Success", data: void 0 };
2260
- } catch (e2) {
2261
- return { _tag: "Failure", error: e2 };
2262
- }
2263
- },
2264
- // Legacy endpoint — no /customer/v1 equivalent exists yet.
2265
- async getLastOrder({ subscriptionId }) {
2266
- try {
2267
- const res = await fetcher(
2268
- `/customer/subscriptions/${subscriptionId}/last-order`
2269
- );
2270
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2271
- const data = await res.json();
2272
- if (!data) return { _tag: "Success", data: null };
2273
- return {
2274
- _tag: "Success",
2275
- data: { id: data.id, createdAt: data.createdAt }
2276
- };
2277
- } catch (e2) {
2278
- return { _tag: "Failure", error: e2 };
2279
- }
2280
- },
2281
- // Legacy endpoints, split by stage (see SubscriptionService.renewNow docs):
2282
- // retry → POST /customer/subscriptions/{id}/retry
2283
- // renewalId → POST /customer/renewals/{renewalId}/renew
2284
- // default → POST /customer/subscriptions/{id}/order-now
2285
- async renewNow({ subscriptionId, renewalId, retry }) {
2286
- try {
2287
- const url = retry ? `/customer/subscriptions/${subscriptionId}/retry` : renewalId ? `/customer/renewals/${renewalId}/renew` : `/customer/subscriptions/${subscriptionId}/order-now`;
2288
- const res = await fetcher(url, { method: "POST" });
2289
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2290
- const body = res.status === 204 ? null : await res.json();
2291
- return {
2292
- _tag: "Success",
2293
- data: {
2294
- nextActionUrl: (body == null ? void 0 : body.nextActionUrl) ?? void 0,
2295
- result: (body == null ? void 0 : body.result) ?? "success"
2296
- }
2297
- };
2298
- } catch (e2) {
2299
- return { _tag: "Failure", error: e2 };
2300
- }
2301
- },
2302
- // Legacy endpoint — POST /plan returns 204; re-fetch to return the updated subscription.
2303
- async changeFrequency({ subscriptionId, plan }) {
2304
- try {
2305
- const res = await fetcher(
2306
- `/customer/subscriptions/${subscriptionId}/plan`,
2307
- {
2308
- method: "POST",
2309
- headers: { "Content-Type": "application/json" },
2310
- body: JSON.stringify({ plan })
2311
- }
2312
- );
2313
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2314
- const refreshed = await adapter.getById(subscriptionId);
2315
- if (refreshed._tag === "Failure") return refreshed;
2316
- if (refreshed.data) return { _tag: "Success", data: refreshed.data };
2317
- return {
2318
- _tag: "Failure",
2319
- error: "Subscription not found after frequency change"
2320
- };
2321
- } catch (e2) {
2322
- return { _tag: "Failure", error: e2 };
2323
- }
2324
- }
2325
- };
2326
- return adapter;
2327
- }
2328
- function toIsoOrNull(value) {
2329
- const date = new Date(value);
2330
- return Number.isNaN(date.getTime()) ? null : date.toISOString();
2331
- }
2332
- function buildMatcher(params) {
2333
- const { cycle, date } = params;
2334
- let iso;
2335
- if (date != null) {
2336
- const parsed = toIsoOrNull(date);
2337
- if (parsed == null) return { ok: false, error: "date must be a valid date" };
2338
- iso = parsed;
2339
- }
2340
- if (cycle != null && iso != null) {
2341
- return { ok: true, matcher: { type: "CYCLE_AND_DATE", input: { cycle, date: iso } } };
2342
- }
2343
- if (cycle != null) return { ok: true, matcher: { type: "CYCLE", input: { cycle } } };
2344
- if (iso != null) return { ok: true, matcher: { type: "DATE", input: { date: iso } } };
2345
- return { ok: false, error: "Either cycle or date is required" };
2346
- }
2347
- const DELIVERY_PRICE_CENTS = 500;
2348
- const DELIVERY_OFFSET_DAYS = 2;
2349
- function toCents(amount) {
2350
- const n2 = Number.parseFloat(amount ?? "0");
2351
- return Number.isFinite(n2) ? Math.round(n2 * 100) : 0;
2352
- }
2353
- function addInterval(date, interval, units) {
2354
- const d3 = new Date(date);
2355
- switch (interval) {
2356
- case "DAY":
2357
- d3.setDate(d3.getDate() + units);
2358
- break;
2359
- case "WEEK":
2360
- d3.setDate(d3.getDate() + units * 7);
2361
- break;
2362
- case "YEAR":
2363
- d3.setFullYear(d3.getFullYear() + units);
2364
- break;
2365
- default:
2366
- d3.setMonth(d3.getMonth() + units);
2367
- break;
2368
- }
2369
- return d3;
2370
- }
2371
- function mapItem(sub, item, cycle) {
2372
- var _a, _b;
2373
- const price = toCents(((_a = item.currentPrice) == null ? void 0 : _a.amount) ?? item.price.amount);
2374
- return {
2375
- id: `${sub.id}_cycle_${cycle}_${item.id}`,
2376
- title: item.title ?? `Product ${item.variantId}`,
2377
- subtitle: item.variantTitle ?? null,
2378
- imageUrl: (_b = item.variantImage) == null ? void 0 : _b.url,
2379
- variantId: item.variantId,
2380
- quantity: item.quantity,
2381
- price,
2382
- totalPrice: price * item.quantity,
2383
- variantImage: item.variantImage ?? null,
2384
- variantAvailableForSale: item.variantAvailableForSale ?? true,
2385
- subscriptionId: sub.id,
2386
- subscriptionLineId: item.id,
2387
- productId: item.productId,
2388
- parentProductId: item.parentProductId ?? null,
2389
- parentLineId: item.parentLineId ?? null,
2390
- isVirtual: item.isVirtual ?? false,
2391
- isUpsell: item.isUpsell ?? false,
2392
- recurringCycleLimit: item.recurringCycleLimit ?? null,
2393
- customAttributes: item.customAttributes ?? []
2394
- };
2395
- }
2396
- function projectUpcomingOrders(sub, count) {
2397
- var _a, _b;
2398
- if (sub.status !== "active") return [];
2399
- const billing = sub.billingPolicy ?? ((_a = sub.items[0]) == null ? void 0 : _a.billingPolicy) ?? { interval: "MONTH", intervalCount: 1 };
2400
- const baseStr = sub.nextBillingDate ?? (sub.nextDeliveryDate ? sub.nextDeliveryDate.toISOString() : null);
2401
- const base = baseStr ? new Date(baseStr) : /* @__PURE__ */ new Date();
2402
- const currencyCode = ((_b = sub.items[0]) == null ? void 0 : _b.price.currencyCode) ?? "USD";
2403
- const orders = [];
2404
- for (let cycle = 0; cycle < count; cycle++) {
2405
- const billingDate = addInterval(
2406
- base,
2407
- billing.interval,
2408
- cycle * billing.intervalCount
2409
- );
2410
- const deliveryDate = addInterval(billingDate, "DAY", DELIVERY_OFFSET_DAYS);
2411
- const items = sub.items.map((item) => mapItem(sub, item, cycle));
2412
- const subtotal = items.reduce((sum, it) => sum + it.totalPrice, 0);
2413
- orders.push({
2414
- id: `${sub.id}_cycle_${cycle}`,
2415
- customerId: sub.customerId,
2416
- subscriptionId: sub.id,
2417
- date: billingDate.toISOString(),
2418
- skipped: false,
2419
- currencyCode,
2420
- subtotal,
2421
- deliveryPrice: DELIVERY_PRICE_CENTS,
2422
- cycleIndex: cycle,
2423
- deliveryDate: deliveryDate.toISOString(),
2424
- status: "scheduled",
2425
- items,
2426
- discounts: sub.discounts.map((d3) => ({
2427
- id: d3.id,
2428
- title: d3.code,
2429
- type: d3.type,
2430
- value: d3.value
2431
- }))
2432
- });
2433
- }
2434
- return orders;
2435
- }
2436
- function applyAdjustments(orders, stored) {
2437
- return orders.map((order) => {
2438
- let next = order;
2439
- for (const { adjustment, subscriptionId, cycle } of stored) {
2440
- if (subscriptionId !== order.subscriptionId) continue;
2441
- if (cycle !== order.cycleIndex) continue;
2442
- const { action } = adjustment;
2443
- if (action.type === "SKIP_ORDER") {
2444
- next = { ...next, skipped: true, status: "skipped" };
2445
- } else if (action.type === "CHANGE_DATE") {
2446
- next = {
2447
- ...next,
2448
- date: action.input.newDate,
2449
- deliveryDate: action.input.newDate
2450
- };
2451
- }
2452
- }
2453
- return next;
2454
- });
2455
- }
2456
- function createMockSchedulesAdapter(subscriptions = createMockSubscriptionAdapter()) {
2457
- const RESOLVE_DEPTH = 12;
2458
- let stored = [];
2459
- let idSeq = 0;
2460
- async function subscriptionsToProject(subscriptionId) {
2461
- if (subscriptionId) {
2462
- const res = await subscriptions.getById(subscriptionId);
2463
- return res._tag === "Success" && res.data ? [res.data] : [];
2464
- }
2465
- const all = [];
2466
- let pagination;
2467
- for (let guard = 0; guard < 50; guard++) {
2468
- const res = await subscriptions.search(pagination ? { pagination } : {});
2469
- if (res._tag !== "Success") break;
2470
- all.push(...res.data.items);
2471
- const { hasNextPage, endCursor } = res.data.pageInfo;
2472
- if (!hasNextPage || !endCursor) break;
2473
- pagination = { after: endCursor };
2474
- }
2475
- return all;
2476
- }
2477
- function resolveCycle(orders, opts) {
2478
- if (opts.cycle != null) return opts.cycle;
2479
- if (opts.date) {
2480
- const iso = toIsoOrNull(opts.date);
2481
- const target = iso == null ? void 0 : iso.split("T")[0];
2482
- const match = target ? orders.find(
2483
- (o2) => o2.deliveryDate.split("T")[0] === target || o2.date.split("T")[0] === target
2484
- ) : void 0;
2485
- if (match) return match.cycleIndex;
2486
- }
2487
- const firstScheduled = orders.find((o2) => o2.status === "scheduled");
2488
- return (firstScheduled == null ? void 0 : firstScheduled.cycleIndex) ?? null;
2489
- }
2490
- async function recordAdjustment(subscriptionId, opts, buildAction) {
2491
- const res = await subscriptions.getById(subscriptionId);
2492
- const sub = res._tag === "Success" ? res.data : null;
2493
- if (!sub) return { _tag: "Failure", error: "No scheduled order found" };
2494
- const orders = applyAdjustments(
2495
- projectUpcomingOrders(sub, RESOLVE_DEPTH),
2496
- stored
2497
- );
2498
- const cycle = resolveCycle(orders, opts);
2499
- if (cycle == null) {
2500
- return { _tag: "Failure", error: "No scheduled order found" };
2501
- }
2502
- const built = buildMatcher({ cycle, date: opts.date });
2503
- const matcher = built.ok ? built.matcher : { type: "CYCLE", input: { cycle } };
2504
- stored = [
2505
- ...stored,
2506
- {
2507
- adjustment: { id: `adj-${idSeq++}`, matcher, action: buildAction() },
2508
- subscriptionId,
2509
- cycle
2510
- }
2511
- ];
2512
- return { _tag: "Success", data: void 0 };
2513
- }
2514
- return {
2515
- async getUpcomingOrders({ count, subscriptionId }) {
2516
- await new Promise((r) => setTimeout(r, 200));
2517
- const subs = await subscriptionsToProject(subscriptionId);
2518
- const orders = subs.flatMap(
2519
- (sub) => applyAdjustments(projectUpcomingOrders(sub, count), stored)
2520
- ).sort((a3, b3) => a3.date.localeCompare(b3.date));
2521
- return { _tag: "Success", data: orders.slice(0, count) };
2522
- },
2523
- async getAdjustments() {
2524
- await new Promise((r) => setTimeout(r, 200));
2525
- return { _tag: "Success", data: stored.map((s2) => s2.adjustment) };
2526
- },
2527
- async skipOrder({ subscriptionId, cycle, date }) {
2528
- await new Promise((r) => setTimeout(r, 300));
2529
- return recordAdjustment(subscriptionId, { cycle, date }, () => ({
2530
- type: "SKIP_ORDER",
2531
- input: { reason: "" }
2532
- }));
2533
- },
2534
- async changeDateAdjustment({ subscriptionId, newDate, cycle, currentDate }) {
2535
- await new Promise((r) => setTimeout(r, 300));
2536
- const newIso = toIsoOrNull(newDate);
2537
- if (newIso == null) {
2538
- return { _tag: "Failure", error: "newDate must be a valid date" };
2539
- }
2540
- return recordAdjustment(
2541
- subscriptionId,
2542
- { cycle, date: currentDate },
2543
- () => ({
2544
- type: "CHANGE_DATE",
2545
- input: { newDate: newIso }
2546
- })
2547
- );
2548
- },
2549
- async updateShippingAdjustment({ subscriptionId, address, cycle, date }) {
2550
- await new Promise((r) => setTimeout(r, 300));
2551
- return recordAdjustment(subscriptionId, { cycle, date }, () => ({
2552
- type: "UPDATE_SHIPPING",
2553
- input: { address }
2554
- }));
2555
- },
2556
- async updatePaymentMethodAdjustment({
2557
- subscriptionId,
2558
- paymentMethodId,
2559
- cycle,
2560
- date
2561
- }) {
2562
- await new Promise((r) => setTimeout(r, 300));
2563
- return recordAdjustment(subscriptionId, { cycle, date }, () => ({
2564
- type: "UPDATE_PAYMENT_METHOD",
2565
- input: { paymentMethodId }
2566
- }));
2567
- },
2568
- async updateProductsAdjustment({ subscriptionId, lines, cycle, date }) {
2569
- await new Promise((r) => setTimeout(r, 300));
2570
- return recordAdjustment(subscriptionId, { cycle, date }, () => ({
2571
- type: "UPDATE_PRODUCTS",
2572
- input: { lines }
2573
- }));
2574
- },
2575
- async applyDiscountAdjustment({ subscriptionId, discountCode, cycle }) {
2576
- await new Promise((r) => setTimeout(r, 300));
2577
- return recordAdjustment(subscriptionId, { cycle }, () => ({
2578
- type: "APPLY_DISCOUNT",
2579
- input: { discountSource: "code", discountCode }
2580
- }));
2581
- },
2582
- async removeAdjustment({ adjustmentId }) {
2583
- await new Promise((r) => setTimeout(r, 200));
2584
- stored = stored.filter((s2) => s2.adjustment.id !== adjustmentId);
2585
- return { _tag: "Success", data: void 0 };
2586
- }
2587
- };
2588
- }
2589
- function createApiSchedulesAdapter(fetcher) {
2590
- async function postAdjustment(matcher, action) {
2591
- try {
2592
- const res = await fetcher(`/customer/v1/schedules/adjustments`, {
2593
- method: "POST",
2594
- headers: { "Content-Type": "application/json" },
2595
- body: JSON.stringify({ matcher, action })
2596
- });
2597
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2598
- return { _tag: "Success", data: void 0 };
2599
- } catch (e2) {
2600
- return { _tag: "Failure", error: e2 };
2601
- }
2602
- }
2603
- return {
2604
- async getUpcomingOrders({ count, subscriptionId }) {
2605
- try {
2606
- const params = new URLSearchParams({ count: String(count) });
2607
- if (subscriptionId) params.set("query", `id:"${subscriptionId}"`);
2608
- const res = await fetcher(`/customer/v1/schedules/?${params.toString()}`);
2609
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2610
- const data = await res.json();
2611
- return { _tag: "Success", data: data.orders };
2612
- } catch (e2) {
2613
- return { _tag: "Failure", error: e2 };
2614
- }
2615
- },
2616
- async getAdjustments() {
2617
- try {
2618
- const res = await fetcher(`/customer/v1/schedules/adjustments`);
2619
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2620
- const data = await res.json();
2621
- const adjustments = data.data.map((a3) => ({
2622
- id: a3.id,
2623
- matcher: a3.matcher,
2624
- action: a3.action
2625
- }));
2626
- return { _tag: "Success", data: adjustments };
2627
- } catch (e2) {
2628
- return { _tag: "Failure", error: e2 };
2629
- }
2630
- },
2631
- async skipOrder({ cycle, date }) {
2632
- const built = buildMatcher({ cycle, date });
2633
- if (!built.ok) return { _tag: "Failure", error: built.error };
2634
- return postAdjustment(built.matcher, {
2635
- type: "SKIP_ORDER",
2636
- input: { reason: "" }
2637
- });
2638
- },
2639
- async changeDateAdjustment({ newDate, cycle }) {
2640
- if (cycle == null) {
2641
- return {
2642
- _tag: "Failure",
2643
- error: "cycle is required for changeDateAdjustment"
2644
- };
2645
- }
2646
- const newIso = toIsoOrNull(newDate);
2647
- if (newIso == null) {
2648
- return { _tag: "Failure", error: "newDate must be a valid date" };
2649
- }
2650
- return postAdjustment(
2651
- { type: "CYCLE", input: { cycle } },
2652
- { type: "CHANGE_DATE", input: { newDate: newIso } }
2653
- );
2654
- },
2655
- async updateShippingAdjustment({ address, cycle, date }) {
2656
- const built = buildMatcher({ cycle, date });
2657
- if (!built.ok) return { _tag: "Failure", error: built.error };
2658
- return postAdjustment(built.matcher, {
2659
- type: "UPDATE_SHIPPING",
2660
- input: { address }
2661
- });
2662
- },
2663
- async updatePaymentMethodAdjustment({ paymentMethodId, cycle, date }) {
2664
- const built = buildMatcher({ cycle, date });
2665
- if (!built.ok) return { _tag: "Failure", error: built.error };
2666
- return postAdjustment(built.matcher, {
2667
- type: "UPDATE_PAYMENT_METHOD",
2668
- input: { paymentMethodId }
2669
- });
2670
- },
2671
- async updateProductsAdjustment({ lines, cycle, date }) {
2672
- const built = buildMatcher({ cycle, date });
2673
- if (!built.ok) return { _tag: "Failure", error: built.error };
2674
- return postAdjustment(built.matcher, {
2675
- type: "UPDATE_PRODUCTS",
2676
- input: { lines }
2677
- });
2678
- },
2679
- async applyDiscountAdjustment({ discountCode, cycle }) {
2680
- return postAdjustment(
2681
- { type: "CYCLE", input: { cycle } },
2682
- {
2683
- type: "APPLY_DISCOUNT",
2684
- input: { discountSource: "code", discountCode }
2685
- }
2686
- );
2687
- },
2688
- async removeAdjustment({ adjustmentId }) {
2689
- try {
2690
- const res = await fetcher(
2691
- `/customer/v1/schedules/adjustments/${adjustmentId}`,
2692
- { method: "DELETE" }
2693
- );
2694
- if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2695
- return { _tag: "Success", data: void 0 };
2696
- } catch (e2) {
2697
- return { _tag: "Failure", error: e2 };
2698
- }
2699
- }
2700
- };
2701
- }
2702
- const SchedulesServiceContext = createContext("services/schedules");
2703
- function createSchedulesService(adapter, opts) {
2704
- const current = d(null);
2705
- const currentLoading = d(false);
2706
- const hasPendingBilling = (opts == null ? void 0 : opts.hasPendingBilling) ?? d(false);
2707
- let reloadToken = 0;
2708
- async function getUpcomingOrder() {
2709
- const result = await adapter.getUpcomingOrders({ count: 1 });
2710
- if (result._tag === "Failure") return result;
2711
- return { _tag: "Success", data: result.data[0] ?? null };
2712
- }
2713
- async function getUpcomingOrders(count) {
2714
- return adapter.getUpcomingOrders({ count });
2715
- }
2716
- async function reloadCurrent(subscriptionId) {
2717
- var _a;
2718
- const token = ++reloadToken;
2719
- currentLoading.value = true;
2720
- const count = Math.max(((_a = current.value) == null ? void 0 : _a.length) ?? 0, 3);
2721
- const result = await adapter.getUpcomingOrders({
2722
- count,
2723
- subscriptionId
2724
- });
2725
- if (token !== reloadToken) return;
2726
- currentLoading.value = false;
2727
- if (result._tag === "Success") {
2728
- current.value = result.data;
2729
- }
2730
- }
2731
- return {
2732
- current,
2733
- currentLoading,
2734
- hasPendingBilling,
2735
- getUpcomingOrder,
2736
- getUpcomingOrders,
2737
- async getAdjustments() {
2738
- return adapter.getAdjustments();
2739
- },
2740
- async skipOrder(params) {
2741
- const result = await adapter.skipOrder(params);
2742
- if (result._tag === "Success") {
2743
- await reloadCurrent(params.subscriptionId);
2744
- }
2745
- return result;
2746
- },
2747
- async changeDateAdjustment(params) {
2748
- const result = await adapter.changeDateAdjustment(params);
2749
- if (result._tag === "Success") {
2750
- await reloadCurrent(params.subscriptionId);
2751
- }
2752
- return result;
2753
- },
2754
- async updateShippingAdjustment(params) {
2755
- const result = await adapter.updateShippingAdjustment(params);
2756
- if (result._tag === "Success") {
2757
- await reloadCurrent(params.subscriptionId);
2758
- }
2759
- return result;
2760
- },
2761
- async updatePaymentMethodAdjustment(params) {
2762
- const result = await adapter.updatePaymentMethodAdjustment(params);
2763
- if (result._tag === "Success") {
2764
- await reloadCurrent(params.subscriptionId);
2765
- }
2766
- return result;
2767
- },
2768
- async updateProductsAdjustment(params) {
2769
- const result = await adapter.updateProductsAdjustment(params);
2770
- if (result._tag === "Success") {
2771
- await reloadCurrent(params.subscriptionId);
1035
+ async reactivate(params) {
1036
+ await new Promise((resolve) => setTimeout(resolve, 300));
1037
+ const subscription = mockSubscriptions.find(
1038
+ (sub) => sub.id === params.subscriptionId
1039
+ );
1040
+ if (!subscription) {
1041
+ return {
1042
+ _tag: "Failure",
1043
+ error: "Subscription not found"
1044
+ };
2772
1045
  }
2773
- return result;
1046
+ subscription.status = "active";
1047
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1048
+ return {
1049
+ _tag: "Success",
1050
+ data: {
1051
+ ...subscription,
1052
+ items: subscription.items.map((item) => ({ ...item })),
1053
+ discounts: subscription.discounts.map((discount) => ({ ...discount }))
1054
+ }
1055
+ };
2774
1056
  },
2775
- async applyDiscountAdjustment(params) {
2776
- const result = await adapter.applyDiscountAdjustment(params);
2777
- if (result._tag === "Success") {
2778
- await reloadCurrent(params.subscriptionId);
1057
+ async cancel(params) {
1058
+ await new Promise((resolve) => setTimeout(resolve, 300));
1059
+ const subscription = mockSubscriptions.find(
1060
+ (sub) => sub.id === params.subscriptionId
1061
+ );
1062
+ if (!subscription) {
1063
+ return {
1064
+ _tag: "Failure",
1065
+ error: "Subscription not found"
1066
+ };
2779
1067
  }
2780
- return result;
1068
+ subscription.status = "canceled";
1069
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1070
+ return {
1071
+ _tag: "Success",
1072
+ data: {
1073
+ ...subscription,
1074
+ items: subscription.items.map((item) => ({ ...item })),
1075
+ discounts: subscription.discounts.map((discount) => ({ ...discount }))
1076
+ }
1077
+ };
2781
1078
  },
2782
- async removeAdjustment(params) {
2783
- return adapter.removeAdjustment(params);
1079
+ async getAvailablePlans() {
1080
+ await new Promise((resolve) => setTimeout(resolve, 300));
1081
+ return {
1082
+ _tag: "Success",
1083
+ data: [
1084
+ {
1085
+ id: "plan_1",
1086
+ name: "Monthly",
1087
+ billingPolicy: { intervalCount: 1, interval: "MONTH" },
1088
+ deliveryPolicy: { intervalCount: 1, interval: "MONTH" }
1089
+ },
1090
+ {
1091
+ id: "plan_2",
1092
+ name: "Every 2 months",
1093
+ billingPolicy: { intervalCount: 2, interval: "MONTH" },
1094
+ deliveryPolicy: { intervalCount: 2, interval: "MONTH" }
1095
+ },
1096
+ {
1097
+ id: "plan_3",
1098
+ name: "Every 3 months",
1099
+ billingPolicy: { intervalCount: 3, interval: "MONTH" },
1100
+ deliveryPolicy: { intervalCount: 3, interval: "MONTH" }
1101
+ }
1102
+ ]
1103
+ };
2784
1104
  },
2785
- reloadCurrent
2786
- };
2787
- }
2788
- const SettingsServiceContext = createContext("services/settings");
2789
- function createSettingsService(initial = {}) {
2790
- const current = d(initial);
2791
- return {
2792
- current,
2793
- get(key) {
2794
- return current.value[key];
1105
+ async getDefaultSubscriptionId() {
1106
+ var _a;
1107
+ await new Promise((resolve) => setTimeout(resolve, 300));
1108
+ return { _tag: "Success", data: ((_a = mockSubscriptions[0]) == null ? void 0 : _a.id) ?? null };
2795
1109
  }
2796
1110
  };
2797
1111
  }
2798
- function createShopService(options) {
2799
- const contactEmail = d(options.getContactEmail());
2800
- const service = { contactEmail };
2801
- return service;
2802
- }
2803
- const ShopServiceContext = createContext("services/shop");
2804
1112
  const SubscriptionServiceContext = createContext("services/subscription");
2805
1113
  function getCurrentSubscriptionId() {
2806
1114
  if (typeof window === "undefined") {
@@ -2823,97 +1131,41 @@ function getCurrentSubscriptionId() {
2823
1131
  }
2824
1132
  function createSubscriptionService(adapter) {
2825
1133
  const current = d(null);
2826
- const hasPendingBilling = d(false);
2827
- const discountsChangedAt = d(0);
2828
- const itemsChangedAt = d(0);
2829
- const lastOrder = d(null);
2830
- async function refreshAfterDiscountChange() {
2831
- await reload();
2832
- discountsChangedAt.value = discountsChangedAt.value + 1;
1134
+ const discountsChangedAtSignal = d(0);
1135
+ const itemsChangedAtSignal = d(0);
1136
+ async function refreshCurrent(subscriptionId) {
1137
+ const result = await adapter.getById(subscriptionId);
1138
+ if (result._tag === "Success" && result.data != null) {
1139
+ current.value = result.data;
1140
+ }
1141
+ }
1142
+ async function refreshAfterDiscountChange(subscriptionId) {
1143
+ await refreshCurrent(subscriptionId);
1144
+ discountsChangedAtSignal.value = discountsChangedAtSignal.value + 1;
2833
1145
  }
2834
- async function refreshAfterItemChange() {
2835
- await reload();
2836
- itemsChangedAt.value = itemsChangedAt.value + 1;
1146
+ async function refreshAfterItemChange(subscriptionId) {
1147
+ await refreshCurrent(subscriptionId);
1148
+ itemsChangedAtSignal.value = itemsChangedAtSignal.value + 1;
2837
1149
  }
2838
1150
  function subscriptionIdFromCurrent() {
2839
1151
  var _a;
2840
1152
  return ((_a = current.value) == null ? void 0 : _a.id) ?? null;
2841
1153
  }
2842
- async function reload() {
2843
- var _a, _b;
2844
- const id = (_a = current.value) == null ? void 0 : _a.id;
2845
- if (!id) return;
2846
- const [subResult, lastOrderResult] = await Promise.all([
2847
- adapter.getById(id),
2848
- adapter.getLastOrder({ subscriptionId: id })
2849
- ]);
2850
- if (((_b = current.value) == null ? void 0 : _b.id) !== id) return;
2851
- if (subResult._tag === "Success") current.value = subResult.data;
2852
- if (lastOrderResult._tag === "Success") lastOrder.value = lastOrderResult.data;
2853
- }
2854
1154
  const service = {
2855
- current,
2856
- hasPendingBilling,
2857
- discountsChangedAt,
2858
- itemsChangedAt,
2859
- lastOrder,
2860
1155
  search: adapter.search,
2861
- // Prefer the adapter's rich cross-subscription list (legacy endpoint, active-first).
2862
- // Fall back to a single `search` page for adapters that don't implement it
2863
- // (e.g. the editor mock) so the cross-subscription views still render.
2864
- listAll: adapter.listAll ? adapter.listAll.bind(adapter) : async () => {
2865
- const result = await adapter.search();
2866
- if (result._tag !== "Success") return result;
2867
- return { _tag: "Success", data: result.data.items };
2868
- },
2869
1156
  getById: adapter.getById,
2870
1157
  getCurrentSubscriptionId,
2871
1158
  addItem: async (subscriptionId, item) => {
2872
1159
  const result = await adapter.addItem({ subscriptionId, item });
2873
1160
  if (result._tag === "Success") {
2874
- await refreshAfterItemChange();
1161
+ await refreshAfterItemChange(subscriptionId);
2875
1162
  }
2876
1163
  return result;
2877
1164
  },
2878
1165
  removeItem: async (subscriptionId, itemId) => {
2879
1166
  const result = await adapter.removeItem({ subscriptionId, itemId });
2880
1167
  if (result._tag === "Success") {
2881
- await refreshAfterItemChange();
2882
- }
2883
- return result;
2884
- },
2885
- updateItem: async (subscriptionId, lineId, update) => {
2886
- const result = await adapter.updateItem({ subscriptionId, lineId, update });
2887
- if (result._tag === "Success") {
2888
- await refreshAfterItemChange();
2889
- }
2890
- return result;
2891
- },
2892
- updateItemAttributes: async (subscriptionId, lineId, customAttributes) => {
2893
- const result = await adapter.updateItemAttributes({ subscriptionId, lineId, customAttributes });
2894
- if (result._tag === "Success") {
2895
- await refreshAfterItemChange();
2896
- }
2897
- return result;
2898
- },
2899
- updateAttributes: async (subscriptionId, customAttributes) => {
2900
- const result = await adapter.updateAttributes({ subscriptionId, customAttributes });
2901
- if (result._tag === "Success") {
2902
- await reload();
2903
- }
2904
- return result;
2905
- },
2906
- skipLineItem: async (subscriptionId, lineId, nextBillingDate) => {
2907
- const result = await adapter.skipLineItem({ subscriptionId, lineId, nextBillingDate });
2908
- if (result._tag === "Success") {
2909
- await refreshAfterItemChange();
2910
- }
2911
- return result;
2912
- },
2913
- updateBoxItems: async (subscriptionId, params) => {
2914
- const result = await adapter.updateBoxItems({ subscriptionId, ...params });
2915
- if (result._tag === "Success") {
2916
- await refreshAfterItemChange();
1168
+ await refreshAfterItemChange(subscriptionId);
2917
1169
  }
2918
1170
  return result;
2919
1171
  },
@@ -2927,7 +1179,7 @@ function createSubscriptionService(adapter) {
2927
1179
  }
2928
1180
  const result = await adapter.addDiscount({ subscriptionId: id, code });
2929
1181
  if (result._tag === "Success") {
2930
- await refreshAfterDiscountChange();
1182
+ await refreshAfterDiscountChange(id);
2931
1183
  }
2932
1184
  return result;
2933
1185
  },
@@ -2944,23 +1196,20 @@ function createSubscriptionService(adapter) {
2944
1196
  discountId
2945
1197
  });
2946
1198
  if (result._tag === "Success") {
2947
- await refreshAfterDiscountChange();
1199
+ await refreshAfterDiscountChange(id);
2948
1200
  }
2949
1201
  return result;
2950
1202
  },
2951
1203
  reschedule: (subscriptionId, newDate) => adapter.reschedule({ subscriptionId, newDate }),
2952
- updateCustomAttributes: (subscriptionId, customAttributes) => adapter.updateCustomAttributes({ subscriptionId, customAttributes }),
2953
1204
  resume: (subscriptionId) => adapter.resume({ subscriptionId }),
2954
1205
  pause: (subscriptionId) => adapter.pause({ subscriptionId }),
2955
1206
  reactivate: (subscriptionId) => adapter.reactivate({ subscriptionId }),
2956
1207
  cancel: (subscriptionId, reason) => adapter.cancel({ subscriptionId, reason }),
2957
- renewNow: (params) => adapter.renewNow(params),
2958
- changeFrequency: (subscriptionId, plan) => adapter.changeFrequency({ subscriptionId, plan }),
2959
- reload,
2960
1208
  getAvailablePlans: (subscriptionId) => adapter.getAvailablePlans({ subscriptionId }),
2961
1209
  getDefaultSubscriptionId: () => adapter.getDefaultSubscriptionId(),
2962
- getUpsellProducts: (params) => adapter.getUpsellProducts ? adapter.getUpsellProducts(params) : Promise.resolve({ _tag: "Success", data: [] }),
2963
- addUpsellProduct: (params) => adapter.addUpsellProduct ? adapter.addUpsellProduct(params) : Promise.resolve({ _tag: "Success", data: void 0 })
1210
+ current,
1211
+ discountsChangedAt: discountsChangedAtSignal,
1212
+ itemsChangedAt: itemsChangedAtSignal
2964
1213
  };
2965
1214
  return service;
2966
1215
  }
@@ -2975,6 +1224,487 @@ const DISCOUNT_REJECTION_REASONS = [
2975
1224
  "INVALID_COMBINATION",
2976
1225
  "QUANTITY_REQUIREMENT_NOT_MET"
2977
1226
  ];
1227
+ function getDefaultBlockForAction(actionType, actionConfig, blockId) {
1228
+ const blockName = `action:${actionType}`;
1229
+ const definedBlocks = getDefinedBlocks();
1230
+ const exists = definedBlocks.some((b) => b.name === blockName);
1231
+ if (!exists) {
1232
+ throw new Error(
1233
+ `No default block registered for action type "${actionType}". Expected a block named "${blockName}" to be registered in blocks-extensions.`
1234
+ );
1235
+ }
1236
+ return createBlockInstance(blockName, { props: actionConfig, id: blockId });
1237
+ }
1238
+ function hasDefaultBlockForAction(actionType) {
1239
+ const blockName = `action:${actionType}`;
1240
+ return getDefinedBlocks().some((b) => b.name === blockName);
1241
+ }
1242
+ const WorkflowServiceContext = createContext("services/workflow");
1243
+ const RUN_SCOPED_RESET = {
1244
+ firstPollReason: null,
1245
+ feedbackCollected: false
1246
+ };
1247
+ function createWorkflowApiAdapter(sdk) {
1248
+ return {
1249
+ async start(flowType, context, workflowId, dryRun) {
1250
+ const { data } = await sdk.post("/customer/v1/workflows/start", {
1251
+ flowType,
1252
+ context,
1253
+ ...workflowId ? { workflowId } : {},
1254
+ ...dryRun ? { dryRun: true } : {}
1255
+ });
1256
+ return data;
1257
+ },
1258
+ async respond(runId, interactionId, responseType, responseData, expectedRunVersion, eventId) {
1259
+ const { data } = await sdk.post(
1260
+ "/customer/v1/workflows/{runId}/respond",
1261
+ {
1262
+ runId,
1263
+ interactionId,
1264
+ responseType,
1265
+ responseData,
1266
+ expectedRunVersion,
1267
+ eventId
1268
+ }
1269
+ );
1270
+ return data;
1271
+ },
1272
+ async getState(runId) {
1273
+ const { data } = await sdk.get("/customer/v1/workflows/{runId}", {
1274
+ runId
1275
+ });
1276
+ return data;
1277
+ },
1278
+ async cancel(runId) {
1279
+ const { data } = await sdk.post("/customer/v1/workflows/{runId}/cancel", {
1280
+ runId
1281
+ });
1282
+ return data;
1283
+ }
1284
+ };
1285
+ }
1286
+ function createWorkflowService(deps) {
1287
+ const { api } = deps;
1288
+ const editor = createEditorBridge();
1289
+ const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
1290
+ const previewWorkflowTrigger = (urlParams == null ? void 0 : urlParams.get("trigger")) ?? null;
1291
+ const previewStepId = (urlParams == null ? void 0 : urlParams.get("step-id")) ?? null;
1292
+ const previewWorkflowId = (urlParams == null ? void 0 : urlParams.get("workflow-id")) ?? null;
1293
+ const isEditorMode = editor.isEditorMode || previewWorkflowTrigger !== null;
1294
+ const _state = d({
1295
+ status: "idle",
1296
+ flowType: null,
1297
+ workflowId: null,
1298
+ workflowVersion: null,
1299
+ runId: null,
1300
+ runVersion: null,
1301
+ currentStepId: null,
1302
+ currentInteraction: null,
1303
+ error: null,
1304
+ result: null,
1305
+ flowParams: null,
1306
+ invalidatedResources: [],
1307
+ outcome: null,
1308
+ completionData: null,
1309
+ dryRun: null,
1310
+ ...RUN_SCOPED_RESET
1311
+ });
1312
+ const _backendInteractionId = d(null);
1313
+ const _registeredRootBlocks = /* @__PURE__ */ new Set();
1314
+ const isActive = w(() => _state.value.status === "active");
1315
+ const isLoading = w(() => _state.value.status === "loading");
1316
+ const isCompleted = w(() => _state.value.status === "completed");
1317
+ const hasError = w(() => _state.value.status === "error");
1318
+ const currentInteraction = w(() => _state.value.currentInteraction);
1319
+ const canRespond = w(() => {
1320
+ const interaction = _state.value.currentInteraction;
1321
+ const backendId = _backendInteractionId.value;
1322
+ if (!interaction || !backendId) return false;
1323
+ return interaction.interactionId === backendId;
1324
+ });
1325
+ const currentStepInfo = w(() => {
1326
+ const interaction = _state.value.currentInteraction;
1327
+ if (!interaction) return null;
1328
+ const actionConfig = deps.shopCurrencyCode ? { ...interaction.actionConfig, currency: deps.shopCurrencyCode } : interaction.actionConfig;
1329
+ return {
1330
+ interactionId: interaction.interactionId,
1331
+ stepId: interaction.stepId,
1332
+ actionType: interaction.actionType,
1333
+ actionConfig,
1334
+ availableResponses: interaction.availableResponses
1335
+ };
1336
+ });
1337
+ function updateState(updates) {
1338
+ _state.value = { ..._state.value, ...updates };
1339
+ }
1340
+ function hashString(value) {
1341
+ let hash = 2166136261;
1342
+ for (let index = 0; index < value.length; index += 1) {
1343
+ hash ^= value.charCodeAt(index);
1344
+ hash = Math.imul(hash, 16777619);
1345
+ }
1346
+ return (hash >>> 0).toString(36);
1347
+ }
1348
+ function shortenId(value, slugLength = 6) {
1349
+ const compact = value.toLowerCase().replace(/[^a-z0-9]/g, "");
1350
+ const slug = (compact || "id").slice(0, slugLength);
1351
+ return `${slug}-${hashString(value)}`;
1352
+ }
1353
+ function createStableStepBlockId(workflowId, stepId) {
1354
+ return `wf-${shortenId(workflowId)}-${shortenId(stepId)}`;
1355
+ }
1356
+ function handleFlowResponse(data) {
1357
+ var _a, _b, _c, _d, _e, _f, _g;
1358
+ const mergedInvalidated = [
1359
+ ..._state.value.invalidatedResources,
1360
+ ...data.invalidatedResources ?? []
1361
+ ];
1362
+ if (data.status === "waiting_interaction") {
1363
+ const currentStepId = ((_a = data.pendingInteraction) == null ? void 0 : _a.stepId) ?? (isEditorMode ? (_c = (_b = data.interactiveSteps) == null ? void 0 : _b[0]) == null ? void 0 : _c.stepId : null);
1364
+ _backendInteractionId.value = ((_d = data.pendingInteraction) == null ? void 0 : _d.interactionId) ?? null;
1365
+ const isInitialResponse = _state.value.runId == null;
1366
+ updateState({
1367
+ status: "active",
1368
+ workflowId: data.workflowId,
1369
+ workflowVersion: data.workflowVersion,
1370
+ runId: data.runId,
1371
+ runVersion: data.runVersion,
1372
+ currentStepId,
1373
+ currentInteraction: data.pendingInteraction,
1374
+ invalidatedResources: mergedInvalidated,
1375
+ outcome: null
1376
+ });
1377
+ if (editor.isEditorMode) {
1378
+ const displayStepId = isInitialResponse && previewStepId && ((_e = data.interactiveSteps) == null ? void 0 : _e.some((s) => s.stepId === previewStepId)) ? previewStepId : currentStepId;
1379
+ const overlayBlocks = deps.themeState.overlay.blocks.value;
1380
+ const rootBlock = overlayBlocks[0];
1381
+ const stepSlot = displayStepId ? (_f = rootBlock == null ? void 0 : rootBlock.slots) == null ? void 0 : _f[displayStepId] : null;
1382
+ const stepBlock = Array.isArray(stepSlot) ? stepSlot[0] : null;
1383
+ const blockId = stepBlock && typeof stepBlock === "object" && "id" in stepBlock ? stepBlock.id : null;
1384
+ if (blockId) {
1385
+ editor.sendMessage(
1386
+ createSelectBlockMessage({ blockId }, blockId)
1387
+ );
1388
+ }
1389
+ }
1390
+ } else if (data.status === "completed") {
1391
+ _backendInteractionId.value = null;
1392
+ updateState({
1393
+ status: "completed",
1394
+ currentStepId: null,
1395
+ currentInteraction: null,
1396
+ runVersion: data.runVersion,
1397
+ result: data.result || null,
1398
+ invalidatedResources: mergedInvalidated,
1399
+ outcome: data.outcome || null,
1400
+ completionData: data.completionData || null
1401
+ });
1402
+ } else if (data.status === "failed") {
1403
+ _backendInteractionId.value = null;
1404
+ handleError(new Error(((_g = data.error) == null ? void 0 : _g.message) || "Flow failed"));
1405
+ } else if (data.status === "cancelled") {
1406
+ _backendInteractionId.value = null;
1407
+ updateState({
1408
+ status: "idle",
1409
+ flowType: null,
1410
+ workflowId: null,
1411
+ workflowVersion: null,
1412
+ runId: null,
1413
+ runVersion: null,
1414
+ currentStepId: null,
1415
+ currentInteraction: null,
1416
+ error: null,
1417
+ result: null,
1418
+ invalidatedResources: [],
1419
+ outcome: null,
1420
+ completionData: null,
1421
+ ...RUN_SCOPED_RESET
1422
+ });
1423
+ }
1424
+ }
1425
+ function handleError(error) {
1426
+ const message = error instanceof Error ? error.message : "Unknown error";
1427
+ updateState({
1428
+ status: "error",
1429
+ error: message
1430
+ });
1431
+ }
1432
+ function maybeApplyPreviewStep(flowType, data) {
1433
+ var _a;
1434
+ if (!previewWorkflowTrigger) return;
1435
+ if (flowType !== previewWorkflowTrigger) return;
1436
+ if (data.status !== "waiting_interaction") return;
1437
+ const step = (_a = data.interactiveSteps) == null ? void 0 : _a.find(
1438
+ (interactiveStep) => interactiveStep.stepId === previewStepId
1439
+ );
1440
+ if (!step) return;
1441
+ updateState({
1442
+ currentStepId: step.stepId,
1443
+ currentInteraction: {
1444
+ interactionId: `preview-${data.runId}-${step.stepId}`,
1445
+ stepId: step.stepId,
1446
+ actionType: step.actionType,
1447
+ actionBehavior: "input",
1448
+ actionConfig: step.actionConfig,
1449
+ availableResponses: step.availableResponses,
1450
+ presentedAt: /* @__PURE__ */ new Date()
1451
+ }
1452
+ });
1453
+ }
1454
+ function initWorkflowRootBlock(data) {
1455
+ if (_registeredRootBlocks.has(data.workflowId)) {
1456
+ return;
1457
+ }
1458
+ const allSteps = data.interactiveSteps ?? (data.pendingInteraction ? [
1459
+ {
1460
+ stepId: data.pendingInteraction.stepId,
1461
+ actionType: data.pendingInteraction.actionType,
1462
+ actionConfig: data.pendingInteraction.actionConfig,
1463
+ availableResponses: data.pendingInteraction.availableResponses
1464
+ }
1465
+ ] : []);
1466
+ const slotProperties = {};
1467
+ for (const step of allSteps) {
1468
+ slotProperties[step.stepId] = {};
1469
+ }
1470
+ const presets = {};
1471
+ const baseLabelFor = (step) => {
1472
+ var _a;
1473
+ return ((_a = getDefinedBlocks().find((b) => b.name === `action:${step.actionType}`)) == null ? void 0 : _a.displayName) ?? step.stepId;
1474
+ };
1475
+ const totalCounts = /* @__PURE__ */ new Map();
1476
+ for (const step of allSteps) {
1477
+ const baseLabel = baseLabelFor(step);
1478
+ totalCounts.set(baseLabel, (totalCounts.get(baseLabel) ?? 0) + 1);
1479
+ }
1480
+ const seenCounts = /* @__PURE__ */ new Map();
1481
+ for (const step of allSteps) {
1482
+ const baseLabel = baseLabelFor(step);
1483
+ const occurrence = (seenCounts.get(baseLabel) ?? 0) + 1;
1484
+ seenCounts.set(baseLabel, occurrence);
1485
+ const isDuplicated = (totalCounts.get(baseLabel) ?? 0) > 1;
1486
+ const label = isDuplicated ? `${baseLabel} (${occurrence})` : baseLabel;
1487
+ presets[step.stepId] = {
1488
+ label,
1489
+ description: step.actionType,
1490
+ state: step.stepId,
1491
+ // @ts-expect-error Untyped
1492
+ context: step
1493
+ };
1494
+ }
1495
+ registerBlock(
1496
+ defineBlock(`workflow:${data.workflowId}`, {
1497
+ group: "workflow",
1498
+ schema: {
1499
+ type: "object",
1500
+ properties: {
1501
+ props: { type: "object" },
1502
+ slots: {
1503
+ type: "object",
1504
+ properties: slotProperties
1505
+ }
1506
+ },
1507
+ required: ["props", "slots"],
1508
+ additionalProperties: true
1509
+ },
1510
+ initialValue: () => ({
1511
+ props: {},
1512
+ slots: Object.fromEntries(
1513
+ allSteps.map((step) => [
1514
+ step.stepId,
1515
+ [
1516
+ getDefaultBlockForAction(
1517
+ step.actionType,
1518
+ step.actionConfig,
1519
+ createStableStepBlockId(data.workflowId, step.stepId)
1520
+ )
1521
+ ]
1522
+ ])
1523
+ )
1524
+ }),
1525
+ presets,
1526
+ renderer() {
1527
+ return null;
1528
+ }
1529
+ })
1530
+ );
1531
+ _registeredRootBlocks.add(data.workflowId);
1532
+ }
1533
+ async function initWorkflowState(data) {
1534
+ const { blocks } = await deps.themeState.resolve(
1535
+ "overlay",
1536
+ `workflow:${data.workflowId}`
1537
+ );
1538
+ if (blocks.length === 0) return;
1539
+ editor.onBlockPresetChange(blocks[0].id, (preset) => {
1540
+ if (!preset) {
1541
+ return;
1542
+ }
1543
+ updateState({
1544
+ // @ts-expect-error Untyped
1545
+ currentStepId: preset.state,
1546
+ // @ts-expect-error Untyped
1547
+ currentInteraction: { ...preset == null ? void 0 : preset.context }
1548
+ });
1549
+ });
1550
+ }
1551
+ const service = {
1552
+ // State signals (readonly)
1553
+ state: _state,
1554
+ /** True when the portal is running inside the Blocks Editor (editorMode dep
1555
+ * or ?trigger=... URL param). Consumers use this to suppress auto-start. */
1556
+ isPreviewMode: isEditorMode,
1557
+ // Computed signals
1558
+ isActive,
1559
+ isLoading,
1560
+ isCompleted,
1561
+ hasError,
1562
+ canRespond,
1563
+ currentInteraction,
1564
+ currentStepInfo,
1565
+ // Methods
1566
+ async startFlow(flowType, context, workflowId) {
1567
+ const isDryRun = isEditorMode;
1568
+ updateState({
1569
+ status: "loading",
1570
+ error: null,
1571
+ flowParams: context,
1572
+ flowType,
1573
+ dryRun: isDryRun,
1574
+ ...RUN_SCOPED_RESET
1575
+ });
1576
+ try {
1577
+ const data = await api.start(
1578
+ flowType,
1579
+ context,
1580
+ workflowId,
1581
+ isDryRun || void 0
1582
+ );
1583
+ if (data.status === "no_workflow") {
1584
+ service.reset();
1585
+ return;
1586
+ }
1587
+ if (data.status === "completed_silently") {
1588
+ updateState({
1589
+ status: "completed",
1590
+ currentStepId: null,
1591
+ currentInteraction: null,
1592
+ result: null,
1593
+ invalidatedResources: data.invalidatedResources ?? [],
1594
+ outcome: data.outcome || null,
1595
+ completionData: data.completionData || null
1596
+ });
1597
+ return;
1598
+ }
1599
+ initWorkflowRootBlock(data);
1600
+ await initWorkflowState(data);
1601
+ handleFlowResponse(data);
1602
+ maybeApplyPreviewStep(flowType, data);
1603
+ } catch (error) {
1604
+ handleError(error);
1605
+ }
1606
+ },
1607
+ async respond(responseType, responseData) {
1608
+ const { runId, runVersion, currentInteraction: currentInteraction2 } = _state.value;
1609
+ if (!runId || !currentInteraction2) {
1610
+ throw new Error("No active interaction to respond to");
1611
+ }
1612
+ updateState({ status: "loading" });
1613
+ try {
1614
+ const data = await api.respond(
1615
+ runId,
1616
+ currentInteraction2.interactionId,
1617
+ responseType,
1618
+ responseData,
1619
+ runVersion ?? void 0
1620
+ );
1621
+ if (_state.value.firstPollReason == null && currentInteraction2.actionType === "poll") {
1622
+ const reason = responseData == null ? void 0 : responseData.reason;
1623
+ if (typeof reason === "string" && reason.length > 0) {
1624
+ updateState({ firstPollReason: reason });
1625
+ }
1626
+ }
1627
+ if (!_state.value.feedbackCollected && currentInteraction2.actionType === "collect_feedback" && responseType === "submitted") {
1628
+ const feedback = responseData == null ? void 0 : responseData.feedback;
1629
+ if (typeof feedback === "string" && feedback.trim().length > 0) {
1630
+ updateState({ feedbackCollected: true });
1631
+ }
1632
+ }
1633
+ handleFlowResponse(data);
1634
+ } catch (error) {
1635
+ handleError(error);
1636
+ }
1637
+ },
1638
+ async cancel() {
1639
+ const { runId, status } = _state.value;
1640
+ const isTerminal = status === "completed" || status === "error";
1641
+ if (runId && !isTerminal) {
1642
+ try {
1643
+ const data = await api.cancel(runId);
1644
+ if (data.outcome) {
1645
+ updateState({
1646
+ status: "completed",
1647
+ flowType: null,
1648
+ workflowId: null,
1649
+ workflowVersion: null,
1650
+ runId: null,
1651
+ runVersion: null,
1652
+ currentStepId: null,
1653
+ currentInteraction: null,
1654
+ error: null,
1655
+ result: null,
1656
+ flowParams: null,
1657
+ invalidatedResources: data.invalidatedResources ?? [],
1658
+ outcome: data.outcome || null,
1659
+ dryRun: null
1660
+ });
1661
+ return;
1662
+ }
1663
+ } catch {
1664
+ }
1665
+ }
1666
+ service.reset();
1667
+ },
1668
+ reset() {
1669
+ _backendInteractionId.value = null;
1670
+ updateState({
1671
+ status: "idle",
1672
+ flowType: null,
1673
+ workflowId: null,
1674
+ workflowVersion: null,
1675
+ runId: null,
1676
+ runVersion: null,
1677
+ currentStepId: null,
1678
+ currentInteraction: null,
1679
+ error: null,
1680
+ result: null,
1681
+ flowParams: null,
1682
+ invalidatedResources: [],
1683
+ outcome: null,
1684
+ completionData: null,
1685
+ ...RUN_SCOPED_RESET
1686
+ });
1687
+ },
1688
+ async refresh() {
1689
+ const { runId } = _state.value;
1690
+ if (!runId) return;
1691
+ try {
1692
+ const data = await api.getState(runId);
1693
+ handleFlowResponse(data);
1694
+ } catch (error) {
1695
+ handleError(error);
1696
+ }
1697
+ }
1698
+ };
1699
+ if (previewWorkflowTrigger) {
1700
+ void service.startFlow(
1701
+ previewWorkflowTrigger,
1702
+ {},
1703
+ previewWorkflowId ?? void 0
1704
+ );
1705
+ }
1706
+ return service;
1707
+ }
2978
1708
  const MOCK_FLOWS = {
2979
1709
  cancellation: [
2980
1710
  {
@@ -3225,93 +1955,326 @@ function createMockWorkflowApiAdapter() {
3225
1955
  }
3226
1956
  };
3227
1957
  }
1958
+ class JuoWorkflowElement extends HTMLElement {
1959
+ constructor() {
1960
+ super(...arguments);
1961
+ __publicField(this, "workflowService", null);
1962
+ __publicField(this, "unsubscribeContext", null);
1963
+ __publicField(this, "unsubscribeEffect", null);
1964
+ /** Tracks which step is currently mounted to avoid unnecessary DOM teardown. */
1965
+ __publicField(this, "renderedStepId", null);
1966
+ /**
1967
+ * Optional function to wrap rendered content (step blocks).
1968
+ * Must be set before workflow becomes active for correct behavior.
1969
+ */
1970
+ __publicField(this, "blockWrapper", null);
1971
+ }
1972
+ connectedCallback() {
1973
+ this.style.display = "contents";
1974
+ this.unsubscribeContext = subscribeContext(
1975
+ this,
1976
+ WorkflowServiceContext,
1977
+ (service) => {
1978
+ this.workflowService = service;
1979
+ this.setupSubscription();
1980
+ }
1981
+ );
1982
+ }
1983
+ disconnectedCallback() {
1984
+ var _a, _b;
1985
+ (_a = this.unsubscribeContext) == null ? void 0 : _a.call(this);
1986
+ (_b = this.unsubscribeEffect) == null ? void 0 : _b.call(this);
1987
+ this.unsubscribeContext = null;
1988
+ this.unsubscribeEffect = null;
1989
+ this.renderedStepId = null;
1990
+ }
1991
+ setupSubscription() {
1992
+ var _a;
1993
+ if (!this.workflowService) return;
1994
+ (_a = this.unsubscribeEffect) == null ? void 0 : _a.call(this);
1995
+ this.unsubscribeEffect = E(() => {
1996
+ var _a2, _b;
1997
+ const status = ((_a2 = this.workflowService) == null ? void 0 : _a2.state.value.status) ?? "idle";
1998
+ const stepInfo = (_b = this.workflowService) == null ? void 0 : _b.currentStepInfo.value;
1999
+ const stepId = (stepInfo == null ? void 0 : stepInfo.stepId) ?? null;
2000
+ queueMicrotask(() => {
2001
+ if (this.isConnected) {
2002
+ this.render(status, stepId);
2003
+ }
2004
+ });
2005
+ });
2006
+ }
2007
+ render(status, stepId) {
2008
+ var _a;
2009
+ if ((status === "active" || status === "loading") && stepId) {
2010
+ if (this.renderedStepId !== stepId) {
2011
+ this.innerHTML = "";
2012
+ this.renderedStepId = stepId;
2013
+ const extensionRoot = document.createElement(
2014
+ "juo-extension-root"
2015
+ );
2016
+ extensionRoot.setAttribute("surface", "overlay");
2017
+ extensionRoot.setAttribute("name", stepId);
2018
+ extensionRoot.blockWrapper = this.blockWrapper;
2019
+ this.appendChild(extensionRoot);
2020
+ }
2021
+ return;
2022
+ }
2023
+ this.innerHTML = "";
2024
+ this.renderedStepId = null;
2025
+ if (status === "error") {
2026
+ const error = ((_a = this.workflowService) == null ? void 0 : _a.state.value.error) ?? "Unknown error";
2027
+ this.dispatchEvent(
2028
+ new CustomEvent("juo-workflow-error", {
2029
+ bubbles: true,
2030
+ composed: true,
2031
+ detail: { error }
2032
+ })
2033
+ );
2034
+ }
2035
+ }
2036
+ }
2037
+ if (typeof customElements !== "undefined" && !customElements.get("juo-workflow")) {
2038
+ customElements.define("juo-workflow", JuoWorkflowElement);
2039
+ }
2040
+ const gridV1Engine = {
2041
+ id: GRID_V1_ENGINE_ID,
2042
+ applyCommand(doc, cmd, ctx2) {
2043
+ const next = structuredClone(doc);
2044
+ const existing = next.layouts[ctx2.breakpoint];
2045
+ const layout = existing ?? {
2046
+ grid: { cols: ctx2.cols, gap: ctx2.gap, rowUnit: ctx2.rowUnit },
2047
+ items: {}
2048
+ };
2049
+ layout.grid = { cols: ctx2.cols, gap: ctx2.gap, rowUnit: ctx2.rowUnit };
2050
+ switch (cmd.kind) {
2051
+ case "add": {
2052
+ layout.items[cmd.blockId] = cmd.rect ? clampRect(cmd.rect, ctx2.cols) : findFreeRect(layout.items, { w: ctx2.cols, h: 1 }, ctx2.cols);
2053
+ break;
2054
+ }
2055
+ case "move": {
2056
+ const current = layout.items[cmd.blockId];
2057
+ if (current) {
2058
+ layout.items[cmd.blockId] = clampRect(
2059
+ { ...current, c: cmd.to.c, r: cmd.to.r },
2060
+ ctx2.cols
2061
+ );
2062
+ }
2063
+ break;
2064
+ }
2065
+ case "resize": {
2066
+ const current = layout.items[cmd.blockId];
2067
+ if (current) {
2068
+ const w2 = Math.max(1, Math.min(cmd.size.w, ctx2.cols - current.c));
2069
+ const h = Math.max(1, cmd.size.h);
2070
+ layout.items[cmd.blockId] = { ...current, w: w2, h };
2071
+ }
2072
+ break;
2073
+ }
2074
+ case "remove": {
2075
+ delete layout.items[cmd.blockId];
2076
+ layout.items = compactItems(layout.items, ctx2.cols);
2077
+ break;
2078
+ }
2079
+ case "setRects": {
2080
+ for (const [blockId, rect] of Object.entries(cmd.rects)) {
2081
+ const prev = layout.items[blockId];
2082
+ const clamped = clampRect(rect, ctx2.cols);
2083
+ clamped.fill = (prev == null ? void 0 : prev.fill) === true && rect.w === prev.w;
2084
+ if (!clamped.fill) delete clamped.fill;
2085
+ layout.items[blockId] = clamped;
2086
+ }
2087
+ break;
2088
+ }
2089
+ case "fillWidth": {
2090
+ const current = layout.items[cmd.blockId];
2091
+ if (current) {
2092
+ const nextFill = current.fill !== true;
2093
+ layout.items[cmd.blockId] = nextFill ? { ...current, fill: true } : (() => {
2094
+ const { fill, ...rest } = current;
2095
+ return rest;
2096
+ })();
2097
+ }
2098
+ break;
2099
+ }
2100
+ }
2101
+ layout.items = applyFillExpansion(layout.items, ctx2.cols);
2102
+ next.layouts[ctx2.breakpoint] = layout;
2103
+ return next;
2104
+ },
2105
+ reflow(doc, ctx2) {
2106
+ const next = structuredClone(doc);
2107
+ const layout = next.layouts[ctx2.breakpoint];
2108
+ if (layout) {
2109
+ layout.grid = { cols: ctx2.cols, gap: ctx2.gap, rowUnit: ctx2.rowUnit };
2110
+ for (const id of Object.keys(layout.items)) {
2111
+ layout.items[id] = clampRect(layout.items[id], ctx2.cols);
2112
+ }
2113
+ layout.items = applyFillExpansion(layout.items, ctx2.cols);
2114
+ }
2115
+ return next;
2116
+ }
2117
+ };
2118
+ const DEFAULT_NEW_BLOCK_HEIGHT = 4;
2119
+ function insertRectRelative(doc, args) {
2120
+ var _a, _b;
2121
+ const baseId = (_a = doc.breakpoints[0]) == null ? void 0 : _a.id;
2122
+ if (!baseId) return doc;
2123
+ const baseLayout = doc.layouts[baseId];
2124
+ if (!baseLayout) return doc;
2125
+ const target = baseLayout.items[args.targetId];
2126
+ if (!target) return doc;
2127
+ const next = structuredClone(doc);
2128
+ const layout = next.layouts[baseId];
2129
+ if (!layout) return doc;
2130
+ const cols = ((_b = layout.grid) == null ? void 0 : _b.cols) ?? DEFAULT_GRID.cols;
2131
+ const newHeight = DEFAULT_NEW_BLOCK_HEIGHT;
2132
+ const insertRow = args.position === "before" ? target.r : target.r + target.h;
2133
+ for (const [id, rect] of Object.entries(layout.items)) {
2134
+ if (id === args.blockId) continue;
2135
+ if (rect.r >= insertRow) {
2136
+ layout.items[id] = { ...rect, r: rect.r + newHeight };
2137
+ }
2138
+ }
2139
+ layout.items[args.blockId] = clampRect(
2140
+ { c: target.c, r: insertRow, w: target.w, h: newHeight },
2141
+ cols
2142
+ );
2143
+ return next;
2144
+ }
2145
+ const canvasMode = d(false);
2146
+ const ctx = {};
2147
+ function setActiveSurfaceContext(surface, id) {
2148
+ if (id == null) {
2149
+ delete ctx[surface];
2150
+ return;
2151
+ }
2152
+ ctx[surface] = { id };
2153
+ }
2154
+ function getActiveSurfaceContext(surface) {
2155
+ return ctx[surface] ?? null;
2156
+ }
2157
+ function clearAllSurfaceContexts() {
2158
+ for (const key of Object.keys(ctx)) {
2159
+ delete ctx[key];
2160
+ }
2161
+ }
2162
+ let currentEmitter = null;
2163
+ function setLayoutCommandEmitter(emitter) {
2164
+ currentEmitter = emitter;
2165
+ }
2166
+ function emitLayoutSetRects(event) {
2167
+ currentEmitter == null ? void 0 : currentEmitter(event);
2168
+ }
2169
+ let currentDispatcher = null;
2170
+ function setLayoutCommandDispatcher(dispatcher) {
2171
+ currentDispatcher = dispatcher;
2172
+ }
2173
+ function emitLayoutCommand(event) {
2174
+ currentDispatcher == null ? void 0 : currentDispatcher(event);
2175
+ }
3228
2176
  export {
3229
2177
  AuthenticationError,
3230
2178
  AuthenticationErrorReason,
3231
2179
  B as BlockWrapperEvent,
3232
- m as ContextProvideEvent,
3233
- p as ContextRequestEvent,
2180
+ C as ContextProvideEvent,
2181
+ j as ContextRequestEvent,
3234
2182
  CustomerServiceContext,
3235
- D2 as DEFAULT_GLOBAL_STYLES,
2183
+ k as DEFAULT_BREAKPOINTS,
2184
+ l as DEFAULT_GLOBAL_STYLES,
2185
+ DEFAULT_GRID,
2186
+ DEFAULT_NEW_BLOCK_HEIGHT,
3236
2187
  DISCOUNT_REJECTION_REASONS,
2188
+ GRID_V1_ENGINE_ID,
2189
+ L as LAYOUT_SCOPE_ATTR,
3237
2190
  LoginServiceContext,
3238
2191
  OrdersServiceContext,
3239
- OverlayServiceContext,
2192
+ P as PAGE_ROOT_SLOT,
3240
2193
  ProductServiceContext,
3241
2194
  RouterServiceContext,
3242
- SchedulesServiceContext,
3243
2195
  S as SelectedBlockContext,
3244
- SettingsServiceContext,
3245
- ShopServiceContext,
3246
2196
  u as Signal,
3247
2197
  StateContext,
3248
2198
  SubscriptionServiceContext,
3249
- a2 as ThemeStateContext,
3250
- T as TranslationContext,
3251
- W as WorkflowServiceContext,
3252
- q as __recordDevtoolsInstance,
3253
- _ as __recordDevtoolsPropSetter,
3254
- t as attachEmptyTracking,
3255
- b as backfillInstanceDefaults,
2199
+ T as ThemeStateContext,
2200
+ m as TranslationContext,
2201
+ WorkflowServiceContext,
2202
+ n as attachEmptyTracking,
2203
+ o as backfillInstanceDefaults,
2204
+ p as buildGridLayout,
2205
+ q as buildLayoutCss,
2206
+ canvasMode,
2207
+ clampRect,
2208
+ t as classifyRowDividers,
2209
+ clearAllSurfaceContexts,
2210
+ clearLayoutModeAdapter,
2211
+ compactItems,
2212
+ v as compactLayoutDocument,
3256
2213
  w as computed,
3257
- createApiCustomerAdapter,
3258
- createApiLoginAdapter,
3259
- createApiOrdersAdapter,
3260
- createApiProductAdapter,
3261
- createApiSchedulesAdapter,
3262
- createApiSubscriptionAdapter,
3263
2214
  createBlockInstance,
3264
- v as createBlockInstanceFromJSON,
3265
- f as createBlockInstanceFromObject,
3266
- x as createCeRenderer,
2215
+ x as createBlockInstanceFromJSON,
2216
+ y as createBlockInstanceFromObject,
2217
+ z as createCeRenderer,
3267
2218
  createContext,
3268
2219
  createCustomerService,
3269
- createLoginService,
3270
- createMockCustomerAdapter,
3271
- createMockLoginAdapter,
2220
+ A as createDefaultLayoutDocument,
3272
2221
  createMockOrdersAdapter,
3273
2222
  createMockProductAdapter,
3274
2223
  createMockRouterService,
3275
- createMockSchedulesAdapter,
3276
2224
  createMockSubscriptionAdapter,
3277
2225
  createMockWorkflowApiAdapter,
3278
2226
  createOrdersService,
3279
- createOverlayService,
3280
2227
  createProductService,
3281
2228
  createRouterService,
3282
- createSchedulesService,
3283
- y as createSelectedBlock,
3284
- createSettingsService,
3285
- createShopService,
2229
+ F as createSelectedBlock,
3286
2230
  createState,
3287
2231
  createSubscriptionService,
3288
- c as createThemeState,
3289
- b2 as createTranslationService,
3290
- d2 as createWorkflowApiAdapter,
3291
- e as createWorkflowService,
2232
+ H as createThemeState,
2233
+ I as createTranslationService,
2234
+ createWorkflowApiAdapter,
2235
+ createWorkflowService,
3292
2236
  defineBlock,
3293
- z as defineBlockRuntime,
3294
- defineOverlayWrapper,
2237
+ J as defineBlockRuntime,
2238
+ K as deriveLayout,
3295
2239
  E as effect,
3296
- g as getDefaultBlockForAction,
2240
+ emitLayoutCommand,
2241
+ emitLayoutSetRects,
2242
+ M as expandFillLayoutDocument,
2243
+ findFreeRect,
2244
+ getActiveSurfaceContext,
2245
+ getDefaultBlockForAction,
3297
2246
  getDefinedBlocks,
3298
- A as getDevtoolsBlockState,
3299
- h as hasDefaultBlockForAction,
3300
- D as hasRenderedContent,
3301
- i2 as indexOverrides,
3302
- i as injectContext,
3303
- F as isEditorPreview,
3304
- a as isStubDefinition,
2247
+ getLayoutModeAdapter,
2248
+ gridV1Engine,
2249
+ hasDefaultBlockForAction,
2250
+ N as hasRenderedContent,
2251
+ O as indexOverrides,
2252
+ Q as injectContext,
2253
+ insertRectRelative,
2254
+ R as isEditorPreview,
2255
+ U as isStubDefinition,
2256
+ V as layoutScopeSelector,
2257
+ W as layoutSystemEnabled,
3305
2258
  loadBlockRegistry,
3306
2259
  loginService,
3307
- o as onRegisterBlock,
3308
- G as provideContext,
2260
+ X as onRegisterBlock,
2261
+ Y as projectToCss,
2262
+ p2 as projectToGridStack,
2263
+ Z as provideContext,
2264
+ _ as readingOrder,
2265
+ $ as reconcileLayout,
2266
+ a0 as rectsOverlap,
3309
2267
  registerBlock,
3310
- j as serializeBlocks,
3311
- H as setDevtoolsBlockProp,
2268
+ registerLayoutModeAdapter,
2269
+ a1 as resolveLayout,
2270
+ a2 as serializeBlocks,
2271
+ setActiveSurfaceContext,
2272
+ setLayoutCommandDispatcher,
2273
+ setLayoutCommandEmitter,
2274
+ a3 as setLayoutSystemEnabled,
3312
2275
  d as signal,
3313
- s as subscribeContext,
3314
- n as untracked,
2276
+ subscribeContext,
2277
+ a4 as untracked,
3315
2278
  waitForDevBlocksUrl,
3316
- w2 as withWrapper
2279
+ a5 as withWrapper
3317
2280
  };