@brytdesigns/shopify-utils 1.2.22 → 3.1.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 (125) hide show
  1. package/dist/effect/Actions/bridge.js +71 -0
  2. package/dist/effect/Actions/bridge.js.map +1 -0
  3. package/dist/effect/Actions/errors.js +46 -0
  4. package/dist/effect/Actions/errors.js.map +1 -0
  5. package/dist/effect/Actions/index.js +23 -0
  6. package/dist/effect/Actions/index.js.map +1 -0
  7. package/dist/effect/Actions/service.js +127 -0
  8. package/dist/effect/Actions/service.js.map +1 -0
  9. package/dist/effect/Actions/trampoline.js +26 -0
  10. package/dist/effect/Actions/trampoline.js.map +1 -0
  11. package/dist/effect/Ajax/Sections/index.js +2 -4
  12. package/dist/effect/Ajax/Sections/schema.js +28 -39
  13. package/dist/effect/Ajax/Sections/schema.js.map +1 -1
  14. package/dist/effect/Ajax/Window/data/AllowedRouteOrigins.js +75 -0
  15. package/dist/effect/Ajax/Window/data/AllowedRouteOrigins.js.map +1 -0
  16. package/dist/effect/Ajax/Window/data/ShopifyRoutes.js +86 -37
  17. package/dist/effect/Ajax/Window/data/ShopifyRoutes.js.map +1 -1
  18. package/dist/effect/Ajax/Window/data/StorefrontClientConfig.js +14 -13
  19. package/dist/effect/Ajax/Window/data/StorefrontClientConfig.js.map +1 -1
  20. package/dist/effect/Ajax/Window/data/StorefrontOrigin.js +32 -0
  21. package/dist/effect/Ajax/Window/data/StorefrontOrigin.js.map +1 -0
  22. package/dist/effect/Ajax/Window/data/index.js +15 -5
  23. package/dist/effect/Ajax/Window/data/index.js.map +1 -1
  24. package/dist/effect/Ajax/Window/index.js +2 -4
  25. package/dist/effect/Ajax/index.js +13 -3
  26. package/dist/effect/Ajax/index.js.map +1 -1
  27. package/dist/effect/Logging/index.js +13 -10
  28. package/dist/effect/Logging/index.js.map +1 -1
  29. package/dist/effect/Resource/data.js +20 -30
  30. package/dist/effect/Resource/data.js.map +1 -1
  31. package/dist/effect/Resource/index.js +14 -3
  32. package/dist/effect/Resource/index.js.map +1 -1
  33. package/dist/effect/Resource/schema.js +46 -45
  34. package/dist/effect/Resource/schema.js.map +1 -1
  35. package/dist/effect/Schemas/index.js +75 -0
  36. package/dist/effect/Schemas/index.js.map +1 -0
  37. package/dist/effect/_virtual/_rolldown/runtime.js +13 -0
  38. package/dist/effect/index.d.ts +396 -62
  39. package/dist/effect/index.js +6 -8
  40. package/dist/main/_virtual/_rolldown/runtime.js +13 -0
  41. package/dist/main/actions.js +78 -0
  42. package/dist/main/actions.js.map +1 -0
  43. package/dist/main/effect/Actions/bridge.js +65 -0
  44. package/dist/main/effect/Actions/bridge.js.map +1 -0
  45. package/dist/main/effect/Actions/errors.js +46 -0
  46. package/dist/main/effect/Actions/errors.js.map +1 -0
  47. package/dist/main/effect/Actions/index.js +4 -0
  48. package/dist/main/effect/Actions/service.js +127 -0
  49. package/dist/main/effect/Actions/service.js.map +1 -0
  50. package/dist/main/effect/Actions/trampoline.js +26 -0
  51. package/dist/main/effect/Actions/trampoline.js.map +1 -0
  52. package/dist/main/effect/Ajax/Sections/index.js +1 -4
  53. package/dist/main/effect/Ajax/Sections/schema.js +11 -41
  54. package/dist/main/effect/Ajax/Sections/schema.js.map +1 -1
  55. package/dist/main/effect/Ajax/Window/data/AllowedRouteOrigins.js +18 -0
  56. package/dist/main/effect/Ajax/Window/data/AllowedRouteOrigins.js.map +1 -0
  57. package/dist/main/effect/Ajax/Window/data/ShopifyRoutes.js +37 -37
  58. package/dist/main/effect/Ajax/Window/data/ShopifyRoutes.js.map +1 -1
  59. package/dist/main/effect/Ajax/Window/data/StorefrontClientConfig.js +3 -14
  60. package/dist/main/effect/Ajax/Window/data/StorefrontClientConfig.js.map +1 -1
  61. package/dist/main/effect/Ajax/Window/data/StorefrontOrigin.js +6 -0
  62. package/dist/main/effect/Ajax/Window/data/StorefrontOrigin.js.map +1 -0
  63. package/dist/main/effect/Ajax/Window/data/index.js +4 -6
  64. package/dist/main/effect/Ajax/Window/index.js +1 -4
  65. package/dist/main/effect/Ajax/index.js +2 -4
  66. package/dist/main/effect/Logging/index.js +2 -13
  67. package/dist/main/effect/Resource/data.js +20 -30
  68. package/dist/main/effect/Resource/data.js.map +1 -1
  69. package/dist/main/effect/Resource/index.js +3 -4
  70. package/dist/main/effect/Resource/schema.js +46 -45
  71. package/dist/main/effect/Resource/schema.js.map +1 -1
  72. package/dist/main/effect/Schemas/index.js +28 -0
  73. package/dist/main/effect/Schemas/index.js.map +1 -0
  74. package/dist/main/effect/index.js +5 -8
  75. package/dist/main/index.d.ts +359 -11
  76. package/dist/main/index.js +3 -3
  77. package/dist/main/resources/index.js +8 -7
  78. package/dist/main/resources/index.js.map +1 -1
  79. package/package.json +9 -9
  80. package/dist/effect/Ajax/Sections/index.js.map +0 -1
  81. package/dist/effect/Ajax/Window/data/types.js +0 -3
  82. package/dist/effect/Ajax/Window/data/types.js.map +0 -1
  83. package/dist/effect/Ajax/Window/index.js.map +0 -1
  84. package/dist/effect/index.js.map +0 -1
  85. package/dist/index.d.ts +0 -77
  86. package/dist/jsdelivr/effect/Ajax/Sections/index.js +0 -4
  87. package/dist/jsdelivr/effect/Ajax/Sections/index.js.map +0 -1
  88. package/dist/jsdelivr/effect/Ajax/Sections/schema.js +0 -20
  89. package/dist/jsdelivr/effect/Ajax/Sections/schema.js.map +0 -1
  90. package/dist/jsdelivr/effect/Ajax/Window/data/ShopifyRoutes.js +0 -38
  91. package/dist/jsdelivr/effect/Ajax/Window/data/ShopifyRoutes.js.map +0 -1
  92. package/dist/jsdelivr/effect/Ajax/Window/data/StorefrontClientConfig.js +0 -16
  93. package/dist/jsdelivr/effect/Ajax/Window/data/StorefrontClientConfig.js.map +0 -1
  94. package/dist/jsdelivr/effect/Ajax/Window/data/index.js +0 -6
  95. package/dist/jsdelivr/effect/Ajax/Window/data/index.js.map +0 -1
  96. package/dist/jsdelivr/effect/Ajax/Window/data/types.js +0 -3
  97. package/dist/jsdelivr/effect/Ajax/Window/data/types.js.map +0 -1
  98. package/dist/jsdelivr/effect/Ajax/Window/index.js +0 -4
  99. package/dist/jsdelivr/effect/Ajax/Window/index.js.map +0 -1
  100. package/dist/jsdelivr/effect/Ajax/index.js +0 -4
  101. package/dist/jsdelivr/effect/Ajax/index.js.map +0 -1
  102. package/dist/jsdelivr/effect/Logging/index.js +0 -13
  103. package/dist/jsdelivr/effect/Logging/index.js.map +0 -1
  104. package/dist/jsdelivr/effect/Resource/data.js +0 -17
  105. package/dist/jsdelivr/effect/Resource/data.js.map +0 -1
  106. package/dist/jsdelivr/effect/Resource/index.js +0 -4
  107. package/dist/jsdelivr/effect/Resource/index.js.map +0 -1
  108. package/dist/jsdelivr/effect/Resource/schema.js +0 -47
  109. package/dist/jsdelivr/effect/Resource/schema.js.map +0 -1
  110. package/dist/jsdelivr/effect/index.js +0 -8
  111. package/dist/jsdelivr/effect/index.js.map +0 -1
  112. package/dist/jsdelivr/index.js +0 -3
  113. package/dist/jsdelivr/index.js.map +0 -1
  114. package/dist/jsdelivr/resources/index.js +0 -9
  115. package/dist/jsdelivr/resources/index.js.map +0 -1
  116. package/dist/main/effect/Ajax/Sections/index.js.map +0 -1
  117. package/dist/main/effect/Ajax/Window/data/index.js.map +0 -1
  118. package/dist/main/effect/Ajax/Window/data/types.js +0 -3
  119. package/dist/main/effect/Ajax/Window/data/types.js.map +0 -1
  120. package/dist/main/effect/Ajax/Window/index.js.map +0 -1
  121. package/dist/main/effect/Ajax/index.js.map +0 -1
  122. package/dist/main/effect/Logging/index.js.map +0 -1
  123. package/dist/main/effect/Resource/index.js.map +0 -1
  124. package/dist/main/effect/index.js.map +0 -1
  125. package/dist/main/index.js.map +0 -1
@@ -0,0 +1,71 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
+ import * as Cause from "effect/Cause";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Exit from "effect/Exit";
5
+ //#region src/effect/Actions/bridge.ts
6
+ var bridge_exports = /* @__PURE__ */ __exportAll({
7
+ fromPromiseThunk: () => fromPromiseThunk,
8
+ toAsyncCallback: () => toAsyncCallback,
9
+ toSyncCallback: () => toSyncCallback
10
+ });
11
+ /**
12
+ * Discharges Effects across a callback boundary owned by foreign code.
13
+ *
14
+ * Shopify's `configure()` stores plain callbacks and invokes them later, at
15
+ * which point there is no fiber and no services. A `Context` captured while the
16
+ * caller's services were still in scope is the only thing that can carry them
17
+ * across that gap, so every helper here takes one.
18
+ *
19
+ * These helpers are deliberately free of Shopify specifics — they apply to any
20
+ * register-a-callback API.
21
+ *
22
+ * Note that a captured `Context` freezes references as well as services, so the
23
+ * log level, spans, and annotations in force at capture time are the ones the
24
+ * callbacks run under — changing them afterwards does not reach back into an
25
+ * already-registered callback.
26
+ */
27
+ /**
28
+ * Turn an Effect-returning function into the Promise-returning callback a
29
+ * foreign API expects.
30
+ *
31
+ * A failed Effect becomes a rejected Promise, which is the correct signal for
32
+ * an action handler: Shopify treats rejection as handler failure.
33
+ */
34
+ var toAsyncCallback = (services, f) => (...args) => Effect.runPromiseWith(services)(f(...args));
35
+ /**
36
+ * Turn an Effect-returning function into a *synchronous* callback.
37
+ *
38
+ * `Effect<A, E, R>` does not track sync-vs-async at the type level, so nothing
39
+ * stops a caller handing us an Effect that suspends. When that happens there is
40
+ * no value to return and no error channel to use — the foreign API demands a
41
+ * value right now. `onAbnormal` supplies it.
42
+ *
43
+ * Both failure shapes are covered: `runSyncExit` reports an async effect as a
44
+ * failed `Exit` in some paths and throws in others depending on where the
45
+ * suspension occurs, so we handle the thrown case too rather than letting a
46
+ * defect escape into third-party code.
47
+ */
48
+ var toSyncCallback = (services, f, onAbnormal) => (...args) => {
49
+ let exit;
50
+ try {
51
+ exit = Effect.runSyncExitWith(services)(f(...args));
52
+ } catch (defect) {
53
+ return onAbnormal(Cause.die(defect));
54
+ }
55
+ return Exit.isSuccess(exit) ? exit.value : onAbnormal(exit.cause);
56
+ };
57
+ /**
58
+ * Lift a foreign Promise thunk back into Effect-land.
59
+ *
60
+ * This is the opposite crossing from {@link toAsyncCallback}: Shopify hands our
61
+ * handler a `defaultHandler(): Promise<A>`, and the caller's handler is written
62
+ * in Effect, so the thunk has to become an Effect before it can be composed.
63
+ */
64
+ var fromPromiseThunk = (thunk, onReject) => Effect.tryPromise({
65
+ try: () => thunk(),
66
+ catch: onReject
67
+ });
68
+ //#endregion
69
+ export { bridge_exports, fromPromiseThunk, toAsyncCallback, toSyncCallback };
70
+
71
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","names":[],"sources":["../../../src/effect/Actions/bridge.ts"],"sourcesContent":["import * as Cause from \"effect/Cause\";\nimport type * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Exit from \"effect/Exit\";\n\n/**\n * Discharges Effects across a callback boundary owned by foreign code.\n *\n * Shopify's `configure()` stores plain callbacks and invokes them later, at\n * which point there is no fiber and no services. A `Context` captured while the\n * caller's services were still in scope is the only thing that can carry them\n * across that gap, so every helper here takes one.\n *\n * These helpers are deliberately free of Shopify specifics — they apply to any\n * register-a-callback API.\n *\n * Note that a captured `Context` freezes references as well as services, so the\n * log level, spans, and annotations in force at capture time are the ones the\n * callbacks run under — changing them afterwards does not reach back into an\n * already-registered callback.\n */\n\n/**\n * Turn an Effect-returning function into the Promise-returning callback a\n * foreign API expects.\n *\n * A failed Effect becomes a rejected Promise, which is the correct signal for\n * an action handler: Shopify treats rejection as handler failure.\n */\nexport const toAsyncCallback =\n\t<Args extends ReadonlyArray<unknown>, A, E, R>(\n\t\tservices: Context.Context<R>,\n\t\tf: (...args: Args) => Effect.Effect<A, E, R>,\n\t) =>\n\t(...args: Args): Promise<A> =>\n\t\tEffect.runPromiseWith(services)(f(...args));\n\n/**\n * Turn an Effect-returning function into a *synchronous* callback.\n *\n * `Effect<A, E, R>` does not track sync-vs-async at the type level, so nothing\n * stops a caller handing us an Effect that suspends. When that happens there is\n * no value to return and no error channel to use — the foreign API demands a\n * value right now. `onAbnormal` supplies it.\n *\n * Both failure shapes are covered: `runSyncExit` reports an async effect as a\n * failed `Exit` in some paths and throws in others depending on where the\n * suspension occurs, so we handle the thrown case too rather than letting a\n * defect escape into third-party code.\n */\nexport const toSyncCallback =\n\t<Args extends ReadonlyArray<unknown>, A, R>(\n\t\tservices: Context.Context<R>,\n\t\tf: (...args: Args) => Effect.Effect<A, never, R>,\n\t\tonAbnormal: (cause: Cause.Cause<never>) => A,\n\t) =>\n\t(...args: Args): A => {\n\t\tlet exit: Exit.Exit<A, never>;\n\n\t\ttry {\n\t\t\texit = Effect.runSyncExitWith(services)(f(...args));\n\t\t} catch (defect) {\n\t\t\treturn onAbnormal(Cause.die(defect));\n\t\t}\n\n\t\treturn Exit.isSuccess(exit) ? exit.value : onAbnormal(exit.cause);\n\t};\n\n/**\n * Lift a foreign Promise thunk back into Effect-land.\n *\n * This is the opposite crossing from {@link toAsyncCallback}: Shopify hands our\n * handler a `defaultHandler(): Promise<A>`, and the caller's handler is written\n * in Effect, so the thunk has to become an Effect before it can be composed.\n */\nexport const fromPromiseThunk = <A, E>(\n\tthunk: () => Promise<A>,\n\tonReject: (cause: unknown) => E,\n): Effect.Effect<A, E> =>\n\tEffect.tryPromise({ try: () => thunk(), catch: onReject });\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,mBAEX,UACA,OAEA,GAAG,SACH,OAAO,eAAe,QAAQ,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;;;;;;;;;;;;;;AAe5C,IAAa,kBAEX,UACA,GACA,gBAEA,GAAG,SAAkB;CACrB,IAAI;CAEJ,IAAI;EACH,OAAO,OAAO,gBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;CACnD,SAAS,QAAQ;EAChB,OAAO,WAAW,MAAM,IAAI,MAAM,CAAC;CACpC;CAEA,OAAO,KAAK,UAAU,IAAI,IAAI,KAAK,QAAQ,WAAW,KAAK,KAAK;AACjE;;;;;;;;AASD,IAAa,oBACZ,OACA,aAEA,OAAO,WAAW;CAAE,WAAW,MAAM;CAAG,OAAO;AAAS,CAAC"}
@@ -0,0 +1,46 @@
1
+ import * as Data from "effect/Data";
2
+ //#region src/effect/Actions/errors.ts
3
+ /**
4
+ * The storefront actions runtime was not present on `window`.
5
+ *
6
+ * Shopify injects it on Liquid storefronts only, so this is the expected
7
+ * failure in tests, in checkout extensions, and during SSR — not a defect.
8
+ */
9
+ var ActionsUnavailableError = class extends Data.TaggedError("@brytdesigns/shopify-utils/ActionsUnavailableError") {
10
+ constructor(options) {
11
+ super({
12
+ action: options.action,
13
+ message: `window.Shopify.actions.${options.action} is unavailable. The storefront standard actions runtime is only injected on Liquid storefronts.`
14
+ });
15
+ }
16
+ };
17
+ /**
18
+ * `configure()` returned `false`, meaning the action refused the registration
19
+ * (most commonly because something else already claimed it).
20
+ *
21
+ * Surfacing this as a typed failure is deliberate: a silently discarded
22
+ * `false` leaves the caller believing their handler is installed when it is
23
+ * not.
24
+ */
25
+ var ActionConfigurationRejectedError = class extends Data.TaggedError("@brytdesigns/shopify-utils/ActionConfigurationRejectedError") {
26
+ constructor(options) {
27
+ super({
28
+ action: options.action,
29
+ message: `window.Shopify.actions.${options.action}.configure() returned false. The action already has a configuration installed.`
30
+ });
31
+ }
32
+ };
33
+ /** The underlying action promise rejected. */
34
+ var ActionInvocationError = class extends Data.TaggedError("@brytdesigns/shopify-utils/ActionInvocationError") {
35
+ constructor(options) {
36
+ super({
37
+ action: options.action,
38
+ cause: options.cause,
39
+ message: `window.Shopify.actions.${options.action} rejected.`
40
+ });
41
+ }
42
+ };
43
+ //#endregion
44
+ export { ActionConfigurationRejectedError, ActionInvocationError, ActionsUnavailableError };
45
+
46
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../../../src/effect/Actions/errors.ts"],"sourcesContent":["import * as Data from \"effect/Data\";\n\n/** Every action exposed on `window.Shopify.actions`. */\nexport type ActionName = \"getCart\" | \"updateCart\" | \"openCart\";\n\n/**\n * Only `updateCart` and `openCart` are `ActionFunction`s — `getCart` is a bare\n * callable with no `configure()` / `isDefault()`.\n */\nexport type ConfigurableActionName = Exclude<ActionName, \"getCart\">;\n\n/**\n * The storefront actions runtime was not present on `window`.\n *\n * Shopify injects it on Liquid storefronts only, so this is the expected\n * failure in tests, in checkout extensions, and during SSR — not a defect.\n */\nexport class ActionsUnavailableError extends Data.TaggedError(\n\t\"@brytdesigns/shopify-utils/ActionsUnavailableError\",\n)<{\n\treadonly action: ActionName;\n\treadonly message: string;\n}> {\n\tconstructor(options: { readonly action: ActionName }) {\n\t\tsuper({\n\t\t\taction: options.action,\n\t\t\tmessage: `window.Shopify.actions.${options.action} is unavailable. The storefront standard actions runtime is only injected on Liquid storefronts.`,\n\t\t});\n\t}\n}\n\n/**\n * `configure()` returned `false`, meaning the action refused the registration\n * (most commonly because something else already claimed it).\n *\n * Surfacing this as a typed failure is deliberate: a silently discarded\n * `false` leaves the caller believing their handler is installed when it is\n * not.\n */\nexport class ActionConfigurationRejectedError extends Data.TaggedError(\n\t\"@brytdesigns/shopify-utils/ActionConfigurationRejectedError\",\n)<{\n\treadonly action: ConfigurableActionName;\n\treadonly message: string;\n}> {\n\tconstructor(options: { readonly action: ConfigurableActionName }) {\n\t\tsuper({\n\t\t\taction: options.action,\n\t\t\tmessage: `window.Shopify.actions.${options.action}.configure() returned false. The action already has a configuration installed.`,\n\t\t});\n\t}\n}\n\n/** The underlying action promise rejected. */\nexport class ActionInvocationError extends Data.TaggedError(\n\t\"@brytdesigns/shopify-utils/ActionInvocationError\",\n)<{\n\treadonly action: ActionName;\n\treadonly cause: unknown;\n\treadonly message: string;\n}> {\n\tconstructor(options: {\n\t\treadonly action: ActionName;\n\t\treadonly cause: unknown;\n\t}) {\n\t\tsuper({\n\t\t\taction: options.action,\n\t\t\tcause: options.cause,\n\t\t\tmessage: `window.Shopify.actions.${options.action} rejected.`,\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;AAiBA,IAAa,0BAAb,cAA6C,KAAK,YACjD,oDACD,CAAC,CAGE;CACF,YAAY,SAA0C;EACrD,MAAM;GACL,QAAQ,QAAQ;GAChB,SAAS,0BAA0B,QAAQ,OAAO;EACnD,CAAC;CACF;AACD;;;;;;;;;AAUA,IAAa,mCAAb,cAAsD,KAAK,YAC1D,6DACD,CAAC,CAGE;CACF,YAAY,SAAsD;EACjE,MAAM;GACL,QAAQ,QAAQ;GAChB,SAAS,0BAA0B,QAAQ,OAAO;EACnD,CAAC;CACF;AACD;;AAGA,IAAa,wBAAb,cAA2C,KAAK,YAC/C,kDACD,CAAC,CAIE;CACF,YAAY,SAGT;EACF,MAAM;GACL,QAAQ,QAAQ;GAChB,OAAO,QAAQ;GACf,SAAS,0BAA0B,QAAQ,OAAO;EACnD,CAAC;CACF;AACD"}
@@ -0,0 +1,23 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
+ import { bridge_exports } from "./bridge.js";
3
+ import { ActionConfigurationRejectedError, ActionInvocationError, ActionsUnavailableError } from "./errors.js";
4
+ import { ShopifyStorefrontActions, configureOpenCart, configureUpdateCart, getCart, isDefault, layer, openCart, updateCart } from "./service.js";
5
+ //#region src/effect/Actions/index.ts
6
+ var Actions_exports = /* @__PURE__ */ __exportAll({
7
+ ActionConfigurationRejectedError: () => ActionConfigurationRejectedError,
8
+ ActionInvocationError: () => ActionInvocationError,
9
+ ActionsUnavailableError: () => ActionsUnavailableError,
10
+ Bridge: () => bridge_exports,
11
+ ShopifyStorefrontActions: () => ShopifyStorefrontActions,
12
+ configureOpenCart: () => configureOpenCart,
13
+ configureUpdateCart: () => configureUpdateCart,
14
+ getCart: () => getCart,
15
+ isDefault: () => isDefault,
16
+ layer: () => layer,
17
+ openCart: () => openCart,
18
+ updateCart: () => updateCart
19
+ });
20
+ //#endregion
21
+ export { ActionConfigurationRejectedError, ActionInvocationError, ActionsUnavailableError, Actions_exports, bridge_exports as Bridge, ShopifyStorefrontActions, configureOpenCart, configureUpdateCart, getCart, isDefault, layer, openCart, updateCart };
22
+
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/effect/Actions/index.ts"],"sourcesContent":["export * as Bridge from \"./bridge.js\";\nexport * from \"./errors.js\";\nexport * from \"./service.js\";\nexport * from \"./types.js\";\n"],"mappings":""}
@@ -0,0 +1,127 @@
1
+ import { fromPromiseThunk, toAsyncCallback, toSyncCallback } from "./bridge.js";
2
+ import { ActionConfigurationRejectedError, ActionInvocationError, ActionsUnavailableError } from "./errors.js";
3
+ import { makeRegistry } from "./trampoline.js";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Context from "effect/Context";
6
+ import * as Layer from "effect/Layer";
7
+ //#region src/effect/Actions/service.ts
8
+ var updateCartRegistry = makeRegistry();
9
+ var openCartRegistry = makeRegistry();
10
+ var ShopifyStorefrontActions = class extends Context.Service()("@brytdesigns/shopify-utils/ShopifyStorefrontActions") {};
11
+ /**
12
+ * Resolve one action off `window` at call time.
13
+ *
14
+ * Deliberately not hoisted to layer construction: Shopify injects the runtime
15
+ * during page load, so a snapshot taken when the layer is built can be stale.
16
+ */
17
+ var requireAction = (action) => Effect.suspend(() => {
18
+ const target = globalThis.window?.Shopify?.actions?.[action];
19
+ return target === void 0 ? Effect.fail(new ActionsUnavailableError({ action })) : Effect.succeed(target);
20
+ });
21
+ /**
22
+ * Bind `bridged` for the lifetime of the enclosing scope.
23
+ *
24
+ * The finalizer only clears the cell if it still holds *our* configuration. A
25
+ * later `configure` supersedes an earlier one, and when the earlier one's scope
26
+ * closes it must not clobber the newer binding.
27
+ */
28
+ var bindForScope = (registration, bridged) => Effect.acquireRelease(Effect.sync(() => {
29
+ registration.active = bridged;
30
+ }), () => Effect.sync(() => {
31
+ if (registration.active === bridged) registration.active = null;
32
+ }));
33
+ var make = () => ({
34
+ getCart: (payload, options) => Effect.flatMap(requireAction("getCart"), (getCart) => Effect.tryPromise({
35
+ try: (signal) => getCart(payload, {
36
+ ...options,
37
+ signal: options?.signal ?? signal
38
+ }),
39
+ catch: (cause) => new ActionInvocationError({
40
+ action: "getCart",
41
+ cause
42
+ })
43
+ })),
44
+ updateCart: (payload, options) => Effect.flatMap(requireAction("updateCart"), (updateCart) => Effect.tryPromise({
45
+ try: (signal) => updateCart(payload, {
46
+ ...options,
47
+ signal: options?.signal ?? signal
48
+ }),
49
+ catch: (cause) => new ActionInvocationError({
50
+ action: "updateCart",
51
+ cause
52
+ })
53
+ })),
54
+ openCart: Effect.flatMap(requireAction("openCart"), (openCart) => Effect.tryPromise({
55
+ try: () => openCart(),
56
+ catch: (cause) => new ActionInvocationError({
57
+ action: "openCart",
58
+ cause
59
+ })
60
+ })),
61
+ configureUpdateCart: (config) => Effect.gen(function* () {
62
+ const action = yield* requireAction("updateCart");
63
+ const services = yield* Effect.context();
64
+ const registration = updateCartRegistry(action);
65
+ if (!registration.claimed) {
66
+ if (!action.configure({
67
+ eventTarget: (meta) => registration.active?.eventTarget(meta) ?? null,
68
+ handler: (defaultHandler, ...args) => {
69
+ const handler = registration.active?.handler;
70
+ return handler ? handler(defaultHandler, ...args) : defaultHandler();
71
+ }
72
+ })) return yield* new ActionConfigurationRejectedError({ action: "updateCart" });
73
+ registration.claimed = true;
74
+ }
75
+ const handler = config.handler;
76
+ yield* bindForScope(registration, {
77
+ eventTarget: toSyncCallback(services, config.eventTarget, (cause) => {
78
+ Effect.runSyncWith(services)(Effect.logError("updateCart eventTarget did not resolve synchronously; dispatching on document instead", cause));
79
+ return null;
80
+ }),
81
+ handler: handler === void 0 ? null : toAsyncCallback(services, (defaultHandler, ...args) => handler(fromPromiseThunk(defaultHandler, (cause) => new ActionInvocationError({
82
+ action: "updateCart",
83
+ cause
84
+ })), ...args))
85
+ });
86
+ }),
87
+ configureOpenCart: (config) => Effect.gen(function* () {
88
+ const action = yield* requireAction("openCart");
89
+ const services = yield* Effect.context();
90
+ const registration = openCartRegistry(action);
91
+ if (!registration.claimed) {
92
+ if (!action.configure({ handler: (defaultHandler, ...args) => {
93
+ const handler = registration.active?.handler;
94
+ return handler ? handler(defaultHandler, ...args) : defaultHandler();
95
+ } })) return yield* new ActionConfigurationRejectedError({ action: "openCart" });
96
+ registration.claimed = true;
97
+ }
98
+ const handler = config.handler;
99
+ yield* bindForScope(registration, { handler: toAsyncCallback(services, (defaultHandler, ...args) => handler(fromPromiseThunk(defaultHandler, (cause) => new ActionInvocationError({
100
+ action: "openCart",
101
+ cause
102
+ })), ...args)) });
103
+ }),
104
+ isDefault: (action) => Effect.map(requireAction(action), (target) => target.isDefault())
105
+ });
106
+ /**
107
+ * Live layer, backed by `window.Shopify.actions`.
108
+ *
109
+ * Named `layer` per the v4 convention, which replaces v3's `Default`/`Live`.
110
+ */
111
+ var layer = Layer.succeed(ShopifyStorefrontActions, make());
112
+ /**
113
+ * Accessors so consumers can compose without pulling the service out by hand.
114
+ *
115
+ * `yield* Actions.configureUpdateCart({ ... })` reads better than
116
+ * `yield* (yield* Actions.ShopifyStorefrontActions).configureUpdateCart({ ... })`.
117
+ */
118
+ var getCart = (payload, options) => Effect.flatMap(ShopifyStorefrontActions, (actions) => actions.getCart(payload, options));
119
+ var updateCart = (payload, options) => Effect.flatMap(ShopifyStorefrontActions, (actions) => actions.updateCart(payload, options));
120
+ var openCart = Effect.flatMap(ShopifyStorefrontActions, (actions) => actions.openCart);
121
+ var configureUpdateCart = (config) => Effect.flatMap(ShopifyStorefrontActions, (actions) => actions.configureUpdateCart(config));
122
+ var configureOpenCart = (config) => Effect.flatMap(ShopifyStorefrontActions, (actions) => actions.configureOpenCart(config));
123
+ var isDefault = (action) => Effect.flatMap(ShopifyStorefrontActions, (actions) => actions.isDefault(action));
124
+ //#endregion
125
+ export { ShopifyStorefrontActions, configureOpenCart, configureUpdateCart, getCart, isDefault, layer, openCart, updateCart };
126
+
127
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","names":[],"sources":["../../../src/effect/Actions/service.ts"],"sourcesContent":["import type {\n\tActionArgs,\n\tDefaultActionHandler,\n\tGetCartOptions,\n\tGetCartPayload,\n\tGetCartResult,\n\tUpdateCartEventTargetMeta,\n\tUpdateCartOptions,\n\tUpdateCartPayload,\n\tUpdateCartResult,\n} from \"@theme/standard-actions\";\n\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport type * as Scope from \"effect/Scope\";\n\nimport { fromPromiseThunk, toAsyncCallback, toSyncCallback } from \"./bridge.js\";\nimport {\n\tActionConfigurationRejectedError,\n\tActionInvocationError,\n\ttype ActionName,\n\tActionsUnavailableError,\n\ttype ConfigurableActionName,\n} from \"./errors.js\";\nimport { makeRegistry } from \"./trampoline.js\";\n\n/** The runtime object Shopify injects, as described by the vendored types. */\ntype StandardActions = NonNullable<Window[\"Shopify\"][\"actions\"]>;\n\n/**\n * The default handler, lifted into Effect-land.\n *\n * Handlers receive this rather than a pre-computed result so they keep the full\n * range of the upstream contract: run the default, wrap it, retry it, race it,\n * or skip it entirely and synthesise a result.\n */\nexport type DefaultHandler<A> = Effect.Effect<A, ActionInvocationError>;\n\n/**\n * An action handler written in Effect.\n *\n * The returned Effect's success value is what the action resolves with, and its\n * failure becomes a rejected promise for Shopify.\n *\n * Note that `E` is checked but never surfaces to the fiber that called\n * `configure` — the handler runs long afterwards, when a shopper triggers the\n * action, so its failure has nowhere to go but the promise Shopify awaits. If\n * you want handler failures observed, observe them inside the handler.\n */\nexport type Handler<P, A, O, E, R> = (\n\tdefaultHandler: DefaultHandler<A>,\n\t...args: ActionArgs<P, O>\n) => Effect.Effect<A, E, R>;\n\n/**\n * Resolves the element that `shopify:cart:*` events are dispatched from.\n *\n * The error channel is `never` on purpose. Shopify calls this synchronously and\n * uses the return value immediately, so there is nowhere for a failure to go —\n * handle errors inside the Effect and fall back to an element or `null`.\n *\n * For the same reason this Effect must complete synchronously. Anything that\n * suspends (`Effect.sleep`, an HTTP call, an async service) cannot produce a\n * value in time and is reported as `null` with a logged defect, which makes\n * Shopify dispatch on `document`. If you need async work, resolve it ahead of\n * time into a `Ref` and read the `Ref` here.\n */\nexport type EventTargetResolver<R> = (\n\tmeta: UpdateCartEventTargetMeta,\n) => Effect.Effect<EventTarget | null, never, R>;\n\nexport interface UpdateCartConfiguration<E, R> {\n\treadonly eventTarget: EventTargetResolver<R>;\n\t/** Optional: routing events without changing cart behaviour is valid. */\n\treadonly handler?: Handler<\n\t\tUpdateCartPayload,\n\t\tUpdateCartResult,\n\t\tUpdateCartOptions,\n\t\tE,\n\t\tR\n\t>;\n}\n\nexport interface OpenCartConfiguration<E, R> {\n\t/**\n\t * Required, unlike `updateCart`'s. `openCart` has no event target, so a\n\t * configuration without a handler would claim the one-shot upstream slot\n\t * while contributing nothing — locking everyone else out for the life of\n\t * the page in exchange for default behaviour.\n\t */\n\treadonly handler: Handler<void, void, void, E, R>;\n}\n\n/** The bridged (plain-callback) shape our trampoline reads. */\ninterface BridgedUpdateCart {\n\treadonly eventTarget: (meta: UpdateCartEventTargetMeta) => EventTarget | null;\n\treadonly handler:\n\t\t| ((\n\t\t\t\tdefaultHandler: DefaultActionHandler<UpdateCartResult>,\n\t\t\t\t...args: ActionArgs<UpdateCartPayload, UpdateCartOptions>\n\t\t ) => Promise<UpdateCartResult>)\n\t\t| null;\n}\n\ninterface BridgedOpenCart {\n\treadonly handler: (\n\t\tdefaultHandler: DefaultActionHandler<void>,\n\t\t...args: ActionArgs<void, void>\n\t) => Promise<void>;\n}\n\nconst updateCartRegistry = makeRegistry<BridgedUpdateCart>();\nconst openCartRegistry = makeRegistry<BridgedOpenCart>();\n\nexport interface ShopifyStorefrontActionsImpl {\n\t/**\n\t * Read the current cart. `getCart` is a bare callable upstream — it has no\n\t * `configure()`, so there is no `configureGetCart`.\n\t */\n\treadonly getCart: (\n\t\tpayload?: GetCartPayload,\n\t\toptions?: GetCartOptions,\n\t) => Effect.Effect<\n\t\tGetCartResult,\n\t\tActionsUnavailableError | ActionInvocationError\n\t>;\n\n\treadonly updateCart: (\n\t\tpayload: UpdateCartPayload,\n\t\toptions?: UpdateCartOptions,\n\t) => Effect.Effect<\n\t\tUpdateCartResult,\n\t\tActionsUnavailableError | ActionInvocationError\n\t>;\n\n\treadonly openCart: Effect.Effect<\n\t\tvoid,\n\t\tActionsUnavailableError | ActionInvocationError\n\t>;\n\n\t/**\n\t * Install an Effect-based `updateCart` configuration for the lifetime of the\n\t * enclosing `Scope`.\n\t *\n\t * The `R` of the supplied Effects flows out into the returned Effect's\n\t * requirements, so the services your handler needs stay explicit and must be\n\t * provided before this runs — they are captured, not smuggled.\n\t *\n\t * Calling this more than once rebinds rather than failing: we claim the\n\t * upstream slot once and swap our own configuration behind it. A\n\t * `ActionConfigurationRejectedError` therefore means one specific thing —\n\t * something outside this library claimed the action first.\n\t *\n\t * For page-lifetime registration, build it into a layer with\n\t * `Layer.effectDiscard(Actions.configureUpdateCart({ ... }))` so the\n\t * registration lives exactly as long as the runtime does.\n\t */\n\treadonly configureUpdateCart: <E, R>(\n\t\tconfig: UpdateCartConfiguration<E, R>,\n\t) => Effect.Effect<\n\t\tvoid,\n\t\tActionsUnavailableError | ActionConfigurationRejectedError,\n\t\tR | Scope.Scope\n\t>;\n\n\treadonly configureOpenCart: <E, R>(\n\t\tconfig: OpenCartConfiguration<E, R>,\n\t) => Effect.Effect<\n\t\tvoid,\n\t\tActionsUnavailableError | ActionConfigurationRejectedError,\n\t\tR | Scope.Scope\n\t>;\n\n\t/**\n\t * Upstream's own notion: `true` until the action's slot is claimed.\n\t *\n\t * Because the slot can never be released, this stays `false` once we have\n\t * claimed it, even after every configuration has been deactivated.\n\t */\n\treadonly isDefault: (\n\t\taction: ConfigurableActionName,\n\t) => Effect.Effect<boolean, ActionsUnavailableError>;\n}\n\nexport class ShopifyStorefrontActions extends Context.Service<\n\tShopifyStorefrontActions,\n\tShopifyStorefrontActionsImpl\n>()(\"@brytdesigns/shopify-utils/ShopifyStorefrontActions\") {}\n\n/**\n * Resolve one action off `window` at call time.\n *\n * Deliberately not hoisted to layer construction: Shopify injects the runtime\n * during page load, so a snapshot taken when the layer is built can be stale.\n */\nconst requireAction = <K extends ActionName>(\n\taction: K,\n): Effect.Effect<StandardActions[K], ActionsUnavailableError> =>\n\tEffect.suspend(() => {\n\t\tconst target = globalThis.window?.Shopify?.actions?.[action];\n\n\t\treturn target === undefined\n\t\t\t? Effect.fail(new ActionsUnavailableError({ action }))\n\t\t\t: Effect.succeed(target);\n\t});\n\n/**\n * Bind `bridged` for the lifetime of the enclosing scope.\n *\n * The finalizer only clears the cell if it still holds *our* configuration. A\n * later `configure` supersedes an earlier one, and when the earlier one's scope\n * closes it must not clobber the newer binding.\n */\nconst bindForScope = <Config>(\n\tregistration: { active: Config | null },\n\tbridged: Config,\n) =>\n\tEffect.acquireRelease(\n\t\tEffect.sync(() => {\n\t\t\tregistration.active = bridged;\n\t\t}),\n\t\t() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tif (registration.active === bridged) registration.active = null;\n\t\t\t}),\n\t);\n\nconst make = (): ShopifyStorefrontActionsImpl => ({\n\tgetCart: (payload, options) =>\n\t\tEffect.flatMap(requireAction(\"getCart\"), (getCart) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\t// Effect's interruption signal is forwarded when the caller has not\n\t\t\t\t// supplied one, so an interrupted fiber aborts the in-flight request.\n\t\t\t\ttry: (signal) =>\n\t\t\t\t\tgetCart(payload, { ...options, signal: options?.signal ?? signal }),\n\t\t\t\tcatch: (cause) =>\n\t\t\t\t\tnew ActionInvocationError({ action: \"getCart\", cause }),\n\t\t\t}),\n\t\t),\n\n\tupdateCart: (payload, options) =>\n\t\tEffect.flatMap(requireAction(\"updateCart\"), (updateCart) =>\n\t\t\tEffect.tryPromise({\n\t\t\t\ttry: (signal) =>\n\t\t\t\t\tupdateCart(payload, {\n\t\t\t\t\t\t...options,\n\t\t\t\t\t\tsignal: options?.signal ?? signal,\n\t\t\t\t\t}),\n\t\t\t\tcatch: (cause) =>\n\t\t\t\t\tnew ActionInvocationError({ action: \"updateCart\", cause }),\n\t\t\t}),\n\t\t),\n\n\topenCart: Effect.flatMap(requireAction(\"openCart\"), (openCart) =>\n\t\tEffect.tryPromise({\n\t\t\ttry: () => openCart(),\n\t\t\tcatch: (cause) =>\n\t\t\t\tnew ActionInvocationError({ action: \"openCart\", cause }),\n\t\t}),\n\t),\n\n\tconfigureUpdateCart: <E, R>(config: UpdateCartConfiguration<E, R>) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst action = yield* requireAction(\"updateCart\");\n\t\t\tconst services = yield* Effect.context<R>();\n\t\t\tconst registration = updateCartRegistry(action);\n\n\t\t\tif (!registration.claimed) {\n\t\t\t\t// One stable trampoline, installed once. Everything after this\n\t\t\t\t// rebinds `registration.active` instead of calling configure again.\n\t\t\t\tconst accepted = action.configure({\n\t\t\t\t\teventTarget: (meta) => registration.active?.eventTarget(meta) ?? null,\n\t\t\t\t\thandler: (defaultHandler, ...args) => {\n\t\t\t\t\t\tconst handler = registration.active?.handler;\n\n\t\t\t\t\t\treturn handler\n\t\t\t\t\t\t\t? handler(defaultHandler, ...args)\n\t\t\t\t\t\t\t: defaultHandler();\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tif (!accepted) {\n\t\t\t\t\treturn yield* new ActionConfigurationRejectedError({\n\t\t\t\t\t\taction: \"updateCart\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tregistration.claimed = true;\n\t\t\t}\n\n\t\t\tconst handler = config.handler;\n\n\t\t\tconst bridged: BridgedUpdateCart = {\n\t\t\t\teventTarget: toSyncCallback(services, config.eventTarget, (cause) => {\n\t\t\t\t\tEffect.runSyncWith(services)(\n\t\t\t\t\t\tEffect.logError(\n\t\t\t\t\t\t\t\"updateCart eventTarget did not resolve synchronously; dispatching on document instead\",\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn null;\n\t\t\t\t}),\n\t\t\t\thandler:\n\t\t\t\t\thandler === undefined\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: toAsyncCallback(\n\t\t\t\t\t\t\t\tservices,\n\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\tdefaultHandler: DefaultActionHandler<UpdateCartResult>,\n\t\t\t\t\t\t\t\t\t...args: ActionArgs<UpdateCartPayload, UpdateCartOptions>\n\t\t\t\t\t\t\t\t) =>\n\t\t\t\t\t\t\t\t\thandler(\n\t\t\t\t\t\t\t\t\t\tfromPromiseThunk(\n\t\t\t\t\t\t\t\t\t\t\tdefaultHandler,\n\t\t\t\t\t\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\t\t\t\t\t\tnew ActionInvocationError({\n\t\t\t\t\t\t\t\t\t\t\t\t\taction: \"updateCart\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t...args,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t};\n\n\t\t\tyield* bindForScope(registration, bridged);\n\t\t}),\n\n\tconfigureOpenCart: <E, R>(config: OpenCartConfiguration<E, R>) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst action = yield* requireAction(\"openCart\");\n\t\t\tconst services = yield* Effect.context<R>();\n\t\t\tconst registration = openCartRegistry(action);\n\n\t\t\tif (!registration.claimed) {\n\t\t\t\tconst accepted = action.configure({\n\t\t\t\t\thandler: (defaultHandler, ...args) => {\n\t\t\t\t\t\tconst handler = registration.active?.handler;\n\n\t\t\t\t\t\treturn handler\n\t\t\t\t\t\t\t? handler(defaultHandler, ...args)\n\t\t\t\t\t\t\t: defaultHandler();\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tif (!accepted) {\n\t\t\t\t\treturn yield* new ActionConfigurationRejectedError({\n\t\t\t\t\t\taction: \"openCart\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tregistration.claimed = true;\n\t\t\t}\n\n\t\t\tconst handler = config.handler;\n\n\t\t\tconst bridged: BridgedOpenCart = {\n\t\t\t\thandler: toAsyncCallback(\n\t\t\t\t\tservices,\n\t\t\t\t\t(\n\t\t\t\t\t\tdefaultHandler: DefaultActionHandler<void>,\n\t\t\t\t\t\t...args: ActionArgs<void, void>\n\t\t\t\t\t) =>\n\t\t\t\t\t\thandler(\n\t\t\t\t\t\t\tfromPromiseThunk(\n\t\t\t\t\t\t\t\tdefaultHandler,\n\t\t\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\t\t\tnew ActionInvocationError({ action: \"openCart\", cause }),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t...args,\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t};\n\n\t\t\tyield* bindForScope(registration, bridged);\n\t\t}),\n\n\tisDefault: (action) =>\n\t\tEffect.map(requireAction(action), (target) => target.isDefault()),\n});\n\n/**\n * Live layer, backed by `window.Shopify.actions`.\n *\n * Named `layer` per the v4 convention, which replaces v3's `Default`/`Live`.\n */\nexport const layer = Layer.succeed(ShopifyStorefrontActions, make());\n\n/**\n * Accessors so consumers can compose without pulling the service out by hand.\n *\n * `yield* Actions.configureUpdateCart({ ... })` reads better than\n * `yield* (yield* Actions.ShopifyStorefrontActions).configureUpdateCart({ ... })`.\n */\n\nexport const getCart = (payload?: GetCartPayload, options?: GetCartOptions) =>\n\tEffect.flatMap(ShopifyStorefrontActions, (actions) =>\n\t\tactions.getCart(payload, options),\n\t);\n\nexport const updateCart = (\n\tpayload: UpdateCartPayload,\n\toptions?: UpdateCartOptions,\n) =>\n\tEffect.flatMap(ShopifyStorefrontActions, (actions) =>\n\t\tactions.updateCart(payload, options),\n\t);\n\nexport const openCart = Effect.flatMap(\n\tShopifyStorefrontActions,\n\t(actions) => actions.openCart,\n);\n\nexport const configureUpdateCart = <E, R>(\n\tconfig: UpdateCartConfiguration<E, R>,\n) =>\n\tEffect.flatMap(ShopifyStorefrontActions, (actions) =>\n\t\tactions.configureUpdateCart(config),\n\t);\n\nexport const configureOpenCart = <E, R>(config: OpenCartConfiguration<E, R>) =>\n\tEffect.flatMap(ShopifyStorefrontActions, (actions) =>\n\t\tactions.configureOpenCart(config),\n\t);\n\nexport const isDefault = (action: ConfigurableActionName) =>\n\tEffect.flatMap(ShopifyStorefrontActions, (actions) =>\n\t\tactions.isDefault(action),\n\t);\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ //#region src/effect/Actions/trampoline.ts
2
+ /**
3
+ * A registry keyed on the action object itself rather than on the layer.
4
+ *
5
+ * Action identity is the correct key: the upstream slot belongs to that object,
6
+ * so two independently built layers on one page must share a registration,
7
+ * while a freshly stubbed action in a test must get a clean one. Keying on the
8
+ * layer would get both of those backwards.
9
+ */
10
+ var makeRegistry = () => {
11
+ const registrations = /* @__PURE__ */ new WeakMap();
12
+ return (action) => {
13
+ const existing = registrations.get(action);
14
+ if (existing !== void 0) return existing;
15
+ const created = {
16
+ claimed: false,
17
+ active: null
18
+ };
19
+ registrations.set(action, created);
20
+ return created;
21
+ };
22
+ };
23
+ //#endregion
24
+ export { makeRegistry };
25
+
26
+ //# sourceMappingURL=trampoline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trampoline.js","names":[],"sources":["../../../src/effect/Actions/trampoline.ts"],"sourcesContent":["/**\n * Registration bookkeeping that turns Shopify's one-shot `configure()` into\n * something re-bindable.\n *\n * The shipped runtime stores the configuration in a closure variable and\n * refuses every later call:\n *\n * ```js\n * configure(e) { return t || !e || typeof e !== \"object\" ? false : (t = e, true) }\n * ```\n *\n * There is no reset path, so the slot can never be released. What we *can* do\n * is claim it once with a stable trampoline that reads a mutable cell, then\n * rebind that cell as often as we like. Deactivating restores the runtime's\n * default behaviour exactly — the trampoline falls through to the default\n * handler, and a `null` event target makes Shopify dispatch on `document`,\n * which is what it does when unconfigured.\n *\n * The one residue we cannot undo is `isDefault()`, which reports `false` from\n * the moment we claim the slot, whether or not a configuration is active.\n */\nexport interface Registration<Config> {\n\t/** Whether our trampoline currently occupies the upstream slot. */\n\tclaimed: boolean;\n\t/** The live bridged configuration, or `null` when deactivated. */\n\tactive: Config | null;\n}\n\n/**\n * A registry keyed on the action object itself rather than on the layer.\n *\n * Action identity is the correct key: the upstream slot belongs to that object,\n * so two independently built layers on one page must share a registration,\n * while a freshly stubbed action in a test must get a clean one. Keying on the\n * layer would get both of those backwards.\n */\nexport const makeRegistry = <Config>() => {\n\tconst registrations = new WeakMap<object, Registration<Config>>();\n\n\treturn (action: object): Registration<Config> => {\n\t\tconst existing = registrations.get(action);\n\n\t\tif (existing !== undefined) return existing;\n\n\t\tconst created: Registration<Config> = { claimed: false, active: null };\n\t\tregistrations.set(action, created);\n\n\t\treturn created;\n\t};\n};\n"],"mappings":";;;;;;;;;AAoCA,IAAa,qBAA6B;CACzC,MAAM,gCAAgB,IAAI,QAAsC;CAEhE,QAAQ,WAAyC;EAChD,MAAM,WAAW,cAAc,IAAI,MAAM;EAEzC,IAAI,aAAa,KAAA,GAAW,OAAO;EAEnC,MAAM,UAAgC;GAAE,SAAS;GAAO,QAAQ;EAAK;EACrE,cAAc,IAAI,QAAQ,OAAO;EAEjC,OAAO;CACR;AACD"}
@@ -1,4 +1,2 @@
1
- import * as schema_js from './schema.js';
2
- export { schema_js as Sections };
3
- //# sourceMappingURL=index.js.map
4
- //# sourceMappingURL=index.js.map
1
+ import { schema_exports } from "./schema.js";
2
+ export { schema_exports as Sections };
@@ -1,44 +1,33 @@
1
- import * as Schema from 'effect/Schema';
2
- import * as ParseResult from 'effect/ParseResult';
3
- import 'effect/Function';
4
-
5
- const Input = Schema.Struct({
6
- sections: Schema.optional(
7
- Schema.transform(Schema.Array(Schema.String), Schema.String, {
8
- decode: (sections) => sections.join(","),
9
- encode: (str) => str.split(",")
10
- })
11
- ),
12
- sections_url: Schema.optional(Schema.String)
1
+ import { __exportAll } from "../../_virtual/_rolldown/runtime.js";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Schema from "effect/Schema";
4
+ import * as SchemaGetter from "effect/SchemaGetter";
5
+ import * as SchemaIssue from "effect/SchemaIssue";
6
+ //#region src/effect/Ajax/Sections/schema.ts
7
+ var schema_exports = /* @__PURE__ */ __exportAll({
8
+ Input: () => Input,
9
+ makeResponseSchema: () => makeResponseSchema
10
+ });
11
+ var Input = Schema.Struct({
12
+ sections: Schema.optional(Schema.Array(Schema.String).pipe(Schema.decodeTo(Schema.String, {
13
+ decode: SchemaGetter.transform((sections) => sections.join(",")),
14
+ encode: SchemaGetter.transform((str) => str.split(","))
15
+ }))),
16
+ sections_url: Schema.optional(Schema.String)
13
17
  });
14
- const parseKeys = (keys) => Array.from(
15
- new Set(keys.split(",").map((key) => key.trim()))
16
- );
18
+ var parseKeys = (keys) => Array.from(new Set(keys.split(",").map((key) => key.trim())));
17
19
  function makeResponseSchema(input) {
18
- const keys = parseKeys(input);
19
- return Schema.Record({
20
- key: Schema.Literal(...keys),
21
- value: Schema.transformOrFail(Schema.String, Schema.instanceOf(Element), {
22
- decode: (htmlString, _, ast) => {
23
- const parser = new DOMParser();
24
- const doc = parser.parseFromString(htmlString, "text/html");
25
- const root = doc.body.firstElementChild;
26
- if (!root) {
27
- return ParseResult.fail(
28
- new ParseResult.Type(
29
- ast,
30
- htmlString,
31
- "Failed to convert HTML string to Element"
32
- )
33
- );
34
- }
35
- return ParseResult.succeed(root);
36
- },
37
- encode: (element, options, ast) => ParseResult.succeed(element.outerHTML)
38
- }).pipe(Schema.NullOr)
39
- });
20
+ const keys = parseKeys(input);
21
+ return Schema.Record(Schema.Literals(keys), Schema.String.pipe(Schema.decodeTo(Schema.instanceOf(Element), {
22
+ decode: SchemaGetter.transformEffect((htmlString) => {
23
+ const root = new DOMParser().parseFromString(htmlString, "text/html").body.firstElementChild;
24
+ if (!root) return Effect.fail(new SchemaIssue.InvalidValue({ message: "Failed to convert HTML string to Element" }, htmlString));
25
+ return Effect.succeed(root);
26
+ }),
27
+ encode: SchemaGetter.transform((element) => element.outerHTML)
28
+ }), Schema.NullOr));
40
29
  }
30
+ //#endregion
31
+ export { Input, makeResponseSchema, schema_exports };
41
32
 
42
- export { Input, makeResponseSchema };
43
- //# sourceMappingURL=schema.js.map
44
33
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/effect/Ajax/Sections/schema.ts"],"names":[],"mappings":";;;;AAKa,MAAA,KAAA,GAAQ,OAAO,MAAO,CAAA;AAAA,EACjC,UAAU,MAAO,CAAA,QAAA;AAAA,IACf,MAAA,CAAO,UAAU,MAAO,CAAA,KAAA,CAAM,OAAO,MAAM,CAAA,EAAG,OAAO,MAAQ,EAAA;AAAA,MAC3D,MAAQ,EAAA,CAAC,QAAa,KAAA,QAAA,CAAS,KAAK,GAAG,CAAA;AAAA,MACvC,MAAQ,EAAA,CAAC,GAAQ,KAAA,GAAA,CAAI,MAAM,GAAG;AAAA,KAC/B;AAAA,GACH;AAAA,EACA,YAAc,EAAA,MAAA,CAAO,QAAS,CAAA,MAAA,CAAO,MAAM;AAC7C,CAAC;AAOD,MAAM,SAAA,GAAY,CAAyB,IAAA,KACzC,KAAM,CAAA,IAAA;AAAA,EACJ,IAAI,GAAA,CAAI,IAAK,CAAA,KAAA,CAAM,GAAG,CAAA,CAAE,GAAI,CAAA,CAAC,GAAQ,KAAA,GAAA,CAAI,IAAK,EAAC,CAAC;AAClD,CAAA;AAEK,SAAS,mBAA2C,KAAU,EAAA;AACnE,EAAM,MAAA,IAAA,GAAO,UAAU,KAAK,CAAA;AAC5B,EAAA,OAAO,OAAO,MAAO,CAAA;AAAA,IACnB,GAAK,EAAA,MAAA,CAAO,OAAQ,CAAA,GAAG,IAAI,CAAA;AAAA,IAC3B,KAAA,EAAO,OAAO,eAAgB,CAAA,MAAA,CAAO,QAAQ,MAAO,CAAA,UAAA,CAAW,OAAO,CAAG,EAAA;AAAA,MACvE,MAAQ,EAAA,CAAC,UAAY,EAAA,CAAA,EAAG,GAAQ,KAAA;AAC9B,QAAM,MAAA,MAAA,GAAS,IAAI,SAAU,EAAA;AAC7B,QAAA,MAAM,GAAM,GAAA,MAAA,CAAO,eAAgB,CAAA,UAAA,EAAY,WAAW,CAAA;AAC1D,QAAM,MAAA,IAAA,GAAO,IAAI,IAAK,CAAA,iBAAA;AACtB,QAAA,IAAI,CAAC,IAAM,EAAA;AACT,UAAA,OAAO,WAAY,CAAA,IAAA;AAAA,YACjB,IAAI,WAAY,CAAA,IAAA;AAAA,cACd,GAAA;AAAA,cACA,UAAA;AAAA,cACA;AAAA;AACF,WACF;AAAA;AAEF,QAAO,OAAA,WAAA,CAAY,QAAQ,IAAI,CAAA;AAAA,OACjC;AAAA,MACA,MAAA,EAAQ,CAAC,OAAS,EAAA,OAAA,EAAS,QAAQ,WAAY,CAAA,OAAA,CAAQ,QAAQ,SAAS;AAAA,KACzE,CAAA,CAAE,IAAK,CAAA,MAAA,CAAO,MAAM;AAAA,GACtB,CAAA;AACH","file":"schema.js","sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as ParseResult from \"effect/ParseResult\";\nimport * as Function from \"effect/Function\";\n\nexport type Input = typeof Input;\nexport const Input = Schema.Struct({\n sections: Schema.optional(\n Schema.transform(Schema.Array(Schema.String), Schema.String, {\n decode: (sections) => sections.join(\",\"),\n encode: (str) => str.split(\",\"),\n }),\n ),\n sections_url: Schema.optional(Schema.String),\n});\n\n// Helper type to convert a string to a tuple of unique literals\ntype UniqueKeys<T extends string> = T extends `${infer K},${infer Rest}`\n ? K | UniqueKeys<Rest>\n : T;\n\nconst parseKeys = <const T extends string>(keys: T) =>\n Array.from(\n new Set(keys.split(\",\").map((key) => key.trim())),\n ) as UniqueKeys<T>[];\n\nexport function makeResponseSchema<const T extends string>(input: T) {\n const keys = parseKeys(input);\n return Schema.Record({\n key: Schema.Literal(...keys),\n value: Schema.transformOrFail(Schema.String, Schema.instanceOf(Element), {\n decode: (htmlString, _, ast) => {\n const parser = new DOMParser();\n const doc = parser.parseFromString(htmlString, \"text/html\");\n const root = doc.body.firstElementChild;\n if (!root) {\n return ParseResult.fail(\n new ParseResult.Type(\n ast,\n htmlString,\n \"Failed to convert HTML string to Element\",\n ),\n );\n }\n return ParseResult.succeed(root);\n },\n encode: (element, options, ast) => ParseResult.succeed(element.outerHTML),\n }).pipe(Schema.NullOr),\n });\n}\n"]}
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../../../src/effect/Ajax/Sections/schema.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaGetter from \"effect/SchemaGetter\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\n\nexport type Input = typeof Input;\nexport const Input = Schema.Struct({\n\tsections: Schema.optional(\n\t\tSchema.Array(Schema.String).pipe(\n\t\t\tSchema.decodeTo(Schema.String, {\n\t\t\t\tdecode: SchemaGetter.transform((sections: ReadonlyArray<string>) =>\n\t\t\t\t\tsections.join(\",\"),\n\t\t\t\t),\n\t\t\t\tencode: SchemaGetter.transform((str: string) => str.split(\",\")),\n\t\t\t}),\n\t\t),\n\t),\n\tsections_url: Schema.optional(Schema.String),\n});\n\n// Helper type to convert a string to a tuple of unique literals\ntype UniqueKeys<T extends string> = T extends `${infer K},${infer Rest}`\n\t? K | UniqueKeys<Rest>\n\t: T;\n\nconst parseKeys = <const T extends string>(keys: T) =>\n\tArray.from(\n\t\tnew Set(keys.split(\",\").map((key) => key.trim())),\n\t) as UniqueKeys<T>[];\n\nexport function makeResponseSchema<const T extends string>(input: T) {\n\tconst keys = parseKeys(input);\n\treturn Schema.Record(\n\t\tSchema.Literals(keys),\n\t\tSchema.String.pipe(\n\t\t\tSchema.decodeTo(Schema.instanceOf(Element), {\n\t\t\t\tdecode: SchemaGetter.transformEffect((htmlString: string) => {\n\t\t\t\t\tconst parser = new DOMParser();\n\t\t\t\t\tconst doc = parser.parseFromString(htmlString, \"text/html\");\n\t\t\t\t\tconst root = doc.body.firstElementChild;\n\n\t\t\t\t\tif (!root) {\n\t\t\t\t\t\t// InvalidValue rather than InvalidType: the input really is a\n\t\t\t\t\t\t// string, it just does not parse to an Element. The v3 code used\n\t\t\t\t\t\t// the type-mismatch issue for this.\n\t\t\t\t\t\treturn Effect.fail(\n\t\t\t\t\t\t\tnew SchemaIssue.InvalidValue(\n\t\t\t\t\t\t\t\t{ message: \"Failed to convert HTML string to Element\" },\n\t\t\t\t\t\t\t\thtmlString,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Effect.succeed(root);\n\t\t\t\t}),\n\t\t\t\tencode: SchemaGetter.transform((element: Element) => element.outerHTML),\n\t\t\t}),\n\t\t\tSchema.NullOr,\n\t\t),\n\t);\n}\n"],"mappings":";;;;;;;;;;AAMA,IAAa,QAAQ,OAAO,OAAO;CAClC,UAAU,OAAO,SAChB,OAAO,MAAM,OAAO,MAAM,CAAC,CAAC,KAC3B,OAAO,SAAS,OAAO,QAAQ;EAC9B,QAAQ,aAAa,WAAW,aAC/B,SAAS,KAAK,GAAG,CAClB;EACA,QAAQ,aAAa,WAAW,QAAgB,IAAI,MAAM,GAAG,CAAC;CAC/D,CAAC,CACF,CACD;CACA,cAAc,OAAO,SAAS,OAAO,MAAM;AAC5C,CAAC;AAOD,IAAM,aAAqC,SAC1C,MAAM,KACL,IAAI,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CACjD;AAED,SAAgB,mBAA2C,OAAU;CACpE,MAAM,OAAO,UAAU,KAAK;CAC5B,OAAO,OAAO,OACb,OAAO,SAAS,IAAI,GACpB,OAAO,OAAO,KACb,OAAO,SAAS,OAAO,WAAW,OAAO,GAAG;EAC3C,QAAQ,aAAa,iBAAiB,eAAuB;GAG5D,MAAM,OADM,IADO,UACP,CAAA,CAAO,gBAAgB,YAAY,WAClC,CAAA,CAAI,KAAK;GAEtB,IAAI,CAAC,MAIJ,OAAO,OAAO,KACb,IAAI,YAAY,aACf,EAAE,SAAS,2CAA2C,GACtD,UACD,CACD;GAGD,OAAO,OAAO,QAAQ,IAAI;EAC3B,CAAC;EACD,QAAQ,aAAa,WAAW,YAAqB,QAAQ,SAAS;CACvE,CAAC,GACD,OAAO,MACR,CACD;AACD"}
@@ -0,0 +1,75 @@
1
+ import { __exportAll } from "../../../_virtual/_rolldown/runtime.js";
2
+ import * as Context from "effect/Context";
3
+ import * as Layer from "effect/Layer";
4
+ //#region src/effect/Ajax/Window/data/AllowedRouteOrigins.ts
5
+ var AllowedRouteOrigins_exports = /* @__PURE__ */ __exportAll({
6
+ Origins: () => Origins,
7
+ layer: () => layer
8
+ });
9
+ /**
10
+ * Origins, besides the storefront's own, that a route in the table may point
11
+ * at.
12
+ *
13
+ * ## Why this exists
14
+ *
15
+ * The route table is `{ ...Defaults, ...window.BrytDesigns.routes }`, and the
16
+ * URL used to be built by concatenating it onto the origin. A route of
17
+ * `"@evil.com/collect"` therefore produced
18
+ * `https://shop.myshopify.com@evil.com/collect`, which parses the storefront
19
+ * as *userinfo* and `evil.com` as the host — every cart request, with the
20
+ * shopper's session cookies, sent off-origin. Routes are resolved with `new
21
+ * URL` now and checked against the storefront origin.
22
+ *
23
+ * That check would otherwise make a *deliberate* off-origin route impossible,
24
+ * which is a real thing to want: a storefront fronting its cart endpoints
25
+ * through a proxy or an edge worker on another host. This reference is the
26
+ * seam for it.
27
+ *
28
+ * ## What it is and is not
29
+ *
30
+ * It is not a privilege boundary. Whoever can write `window.BrytDesigns` can
31
+ * write both the routes and this list — and could patch `fetch` besides. What
32
+ * the pair buys is that going off-origin has to be **stated**: a typo
33
+ * (`"cart.js"` without its leading slash) and a smuggled host both fail
34
+ * loudly, while the supported case is one explicit line that shows up in a
35
+ * code review and in the page source.
36
+ *
37
+ * Empty by default, so the storefront origin is the only one accepted.
38
+ *
39
+ * @example
40
+ * ```html
41
+ * <!-- In the theme, before the modules load. -->
42
+ * <script>
43
+ * window.BrytDesigns = window.BrytDesigns || {};
44
+ * window.BrytDesigns.allowedRouteOrigins = ["https://cart-proxy.example"];
45
+ * window.BrytDesigns.routes = { cart_url: "https://cart-proxy.example/cart.js" };
46
+ * <\/script>
47
+ * ```
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * // From Effect, without a DOM.
52
+ * Effect.provideService(effect, Ajax.Window.AllowedRouteOrigins.Origins, [
53
+ * "https://cart-proxy.example",
54
+ * ]);
55
+ * ```
56
+ */
57
+ var Origins = Context.Reference("@brytdesigns/shopify-utils/AllowedRouteOrigins", { defaultValue: () => {
58
+ if (typeof window === "undefined") return [];
59
+ const configured = window?.BrytDesigns?.allowedRouteOrigins;
60
+ if (!Array.isArray(configured)) return [];
61
+ return configured.flatMap((value) => {
62
+ try {
63
+ return [new URL(String(value)).origin];
64
+ } catch {
65
+ console.warn(`[brytdesigns] ignoring unparseable entry in window.BrytDesigns.allowedRouteOrigins: ${String(value)}`);
66
+ return [];
67
+ }
68
+ });
69
+ } });
70
+ /** Pins the allow-list for a whole program. */
71
+ var layer = (origins) => Layer.succeed(Origins, origins);
72
+ //#endregion
73
+ export { AllowedRouteOrigins_exports, Origins, layer };
74
+
75
+ //# sourceMappingURL=AllowedRouteOrigins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AllowedRouteOrigins.js","names":[],"sources":["../../../../../src/effect/Ajax/Window/data/AllowedRouteOrigins.ts"],"sourcesContent":["import * as Context from \"effect/Context\";\nimport * as Layer from \"effect/Layer\";\n\n/**\n * Origins, besides the storefront's own, that a route in the table may point\n * at.\n *\n * ## Why this exists\n *\n * The route table is `{ ...Defaults, ...window.BrytDesigns.routes }`, and the\n * URL used to be built by concatenating it onto the origin. A route of\n * `\"@evil.com/collect\"` therefore produced\n * `https://shop.myshopify.com@evil.com/collect`, which parses the storefront\n * as *userinfo* and `evil.com` as the host — every cart request, with the\n * shopper's session cookies, sent off-origin. Routes are resolved with `new\n * URL` now and checked against the storefront origin.\n *\n * That check would otherwise make a *deliberate* off-origin route impossible,\n * which is a real thing to want: a storefront fronting its cart endpoints\n * through a proxy or an edge worker on another host. This reference is the\n * seam for it.\n *\n * ## What it is and is not\n *\n * It is not a privilege boundary. Whoever can write `window.BrytDesigns` can\n * write both the routes and this list — and could patch `fetch` besides. What\n * the pair buys is that going off-origin has to be **stated**: a typo\n * (`\"cart.js\"` without its leading slash) and a smuggled host both fail\n * loudly, while the supported case is one explicit line that shows up in a\n * code review and in the page source.\n *\n * Empty by default, so the storefront origin is the only one accepted.\n *\n * @example\n * ```html\n * <!-- In the theme, before the modules load. -->\n * <script>\n * window.BrytDesigns = window.BrytDesigns || {};\n * window.BrytDesigns.allowedRouteOrigins = [\"https://cart-proxy.example\"];\n * window.BrytDesigns.routes = { cart_url: \"https://cart-proxy.example/cart.js\" };\n * </script>\n * ```\n *\n * @example\n * ```ts\n * // From Effect, without a DOM.\n * Effect.provideService(effect, Ajax.Window.AllowedRouteOrigins.Origins, [\n * \"https://cart-proxy.example\",\n * ]);\n * ```\n */\nexport const Origins: Context.Reference<readonly string[]> = Context.Reference<\n\treadonly string[]\n>(\"@brytdesigns/shopify-utils/AllowedRouteOrigins\", {\n\t// Read lazily and defensively, for the same reasons as the route table:\n\t// `window?.` does not protect against the identifier being undeclared, and\n\t// the default has to work from Node so `ajax-client`'s tests need no jsdom.\n\tdefaultValue: () => {\n\t\tif (typeof window === \"undefined\") return [];\n\t\tconst configured = window?.BrytDesigns?.allowedRouteOrigins;\n\t\tif (!Array.isArray(configured)) return [];\n\t\t// Normalised through `URL` so that a trailing slash or a different case\n\t\t// in the theme's string still matches what `URL.origin` reports.\n\t\treturn configured.flatMap((value) => {\n\t\t\ttry {\n\t\t\t\treturn [new URL(String(value)).origin];\n\t\t\t} catch {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[brytdesigns] ignoring unparseable entry in window.BrytDesigns.allowedRouteOrigins: ${String(value)}`,\n\t\t\t\t);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t});\n\t},\n});\n\n/** Pins the allow-list for a whole program. */\nexport const layer = (origins: readonly string[]): Layer.Layer<never> =>\n\tLayer.succeed(Origins, origins);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,IAAa,UAAgD,QAAQ,UAEnE,kDAAkD,EAInD,oBAAoB;CACnB,IAAI,OAAO,WAAW,aAAa,OAAO,CAAC;CAC3C,MAAM,aAAa,QAAQ,aAAa;CACxC,IAAI,CAAC,MAAM,QAAQ,UAAU,GAAG,OAAO,CAAC;CAGxC,OAAO,WAAW,SAAS,UAAU;EACpC,IAAI;GACH,OAAO,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM;EACtC,QAAQ;GACP,QAAQ,KACP,uFAAuF,OAAO,KAAK,GACpG;GACA,OAAO,CAAC;EACT;CACD,CAAC;AACF,EACD,CAAC;;AAGD,IAAa,SAAS,YACrB,MAAM,QAAQ,SAAS,OAAO"}