@juo/blocks 2.0.0-alpha.4 → 2.0.0-alpha.6

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 (54) hide show
  1. package/dist/{ExtensionRoot-DRpD5EcC.js → ExtensionRoot-CG9dH98z.js} +1 -1
  2. package/dist/core.js +428 -11
  3. package/dist/{css-runtime-B7tZrBIp.js → css-runtime-CjZl0K48.js} +23 -17
  4. package/dist/editor/handler.d.ts.map +1 -1
  5. package/dist/editor.js +4 -1
  6. package/dist/{gridstack-adapter-BGKGC-eO.js → gridstack-adapter-C1Q8gbsH.js} +2 -2
  7. package/dist/languages.d.ts +51 -0
  8. package/dist/languages.d.ts.map +1 -0
  9. package/dist/main.d.ts +1 -0
  10. package/dist/main.d.ts.map +1 -1
  11. package/dist/{project-gridstack-PxN_DIfP.js → project-gridstack-CRZ_7HoT.js} +1 -1
  12. package/dist/services/customer/adapter.d.ts +12 -0
  13. package/dist/services/customer/adapter.d.ts.map +1 -1
  14. package/dist/services/customer/adapter.test.d.ts +2 -0
  15. package/dist/services/customer/adapter.test.d.ts.map +1 -0
  16. package/dist/services/customer/customerService.d.ts.map +1 -1
  17. package/dist/services/customer/index.d.ts +1 -1
  18. package/dist/services/customer/index.d.ts.map +1 -1
  19. package/dist/services/customer/types.d.ts +13 -0
  20. package/dist/services/customer/types.d.ts.map +1 -1
  21. package/dist/services/login/adapter.d.ts.map +1 -1
  22. package/dist/services/login/loginService.d.ts +1 -0
  23. package/dist/services/login/loginService.d.ts.map +1 -1
  24. package/dist/services/login/loginService.test.d.ts +2 -0
  25. package/dist/services/login/loginService.test.d.ts.map +1 -0
  26. package/dist/services/subscription/adapter.d.ts +56 -1
  27. package/dist/services/subscription/adapter.d.ts.map +1 -1
  28. package/dist/services/subscription/index.d.ts +3 -1
  29. package/dist/services/subscription/index.d.ts.map +1 -1
  30. package/dist/services/subscription/instantOrderErrors.d.ts +66 -0
  31. package/dist/services/subscription/instantOrderErrors.d.ts.map +1 -0
  32. package/dist/services/subscription/lineRemoval.d.ts +56 -0
  33. package/dist/services/subscription/lineRemoval.d.ts.map +1 -0
  34. package/dist/services/subscription/lineRemoval.test.d.ts +2 -0
  35. package/dist/services/subscription/lineRemoval.test.d.ts.map +1 -0
  36. package/dist/services/subscription/paymentInstrument.d.ts +8 -1
  37. package/dist/services/subscription/paymentInstrument.d.ts.map +1 -1
  38. package/dist/services/subscription/subscriptionService.d.ts.map +1 -1
  39. package/dist/services/subscription/types.d.ts +205 -1
  40. package/dist/services/subscription/types.d.ts.map +1 -1
  41. package/dist/theme-state.d.ts +10 -1
  42. package/dist/theme-state.d.ts.map +1 -1
  43. package/dist/utils/index.d.ts +7 -0
  44. package/dist/utils/index.d.ts.map +1 -1
  45. package/dist/vue/context.d.ts +25 -1
  46. package/dist/vue/context.d.ts.map +1 -1
  47. package/dist/vue/useTranslatedProp.test.d.ts +2 -0
  48. package/dist/vue/useTranslatedProp.test.d.ts.map +1 -0
  49. package/dist/vue.js +36 -2
  50. package/dist/web-components/editor/InlineText.d.ts +1 -0
  51. package/dist/web-components/editor/InlineText.d.ts.map +1 -1
  52. package/dist/web-components-editor.js +13 -5
  53. package/dist/web-components-runtime.js +2 -2
  54. package/package.json +1 -1
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4
4
  import { signal, effect, createBlockInstance, layoutSystemEnabled, untracked } from "@juo/blocks";
5
5
  import { reportBlockWarning, reportBlockError } from "./observability.js";
6
6
  import { b as isStubDefinition, w as withWrapper, s as subscribeContext, c as backfillInstanceDefaults, d as __clearDevtoolsBlockState, o as onRegisterBlock } from "./block-BjJztStr.js";
7
- import { L as LAYOUT_SCOPE_ATTR, b as buildGridLayout, a as ThemeStateContext } from "./css-runtime-B7tZrBIp.js";
7
+ import { L as LAYOUT_SCOPE_ATTR, b as buildGridLayout, a as ThemeStateContext } from "./css-runtime-CjZl0K48.js";
8
8
  import { getHook } from "./devtools.js";
9
9
  class Block extends HTMLElement {
10
10
  constructor() {
package/dist/core.js CHANGED
@@ -3,12 +3,33 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { e as createContext, f as d, m as w, n as defineBlock, h as createBlockInstance, j as getDefinedBlocks, p as registerBlock, E, u, s as subscribeContext } from "./block-BjJztStr.js";
5
5
  import { B, q, t, S, v, _, x, c, y, g, z, A, D, F, G, i, H, b, I, o, J, k, K, l, L, w as w2 } from "./block-BjJztStr.js";
6
- import { G as GRID_V1_ENGINE_ID, d as clampRect, e as applyFillExpansion, f as compactItems, g as findFreeRect, D as DEFAULT_GRID } from "./css-runtime-B7tZrBIp.js";
7
- import { h, i as i2, L as L2, P, a, T, b as b2, j, k as k2, l as l2, m, n, o as o2, p, q as q2, s, t as t2, u as u2, v as v2, c as c2, w as w3, r } from "./css-runtime-B7tZrBIp.js";
6
+ import { G as GRID_V1_ENGINE_ID, d as clampRect, e as applyFillExpansion, f as compactItems, g as findFreeRect, D as DEFAULT_GRID } from "./css-runtime-CjZl0K48.js";
7
+ import { h, i as i2, L as L2, P, a, T, b as b2, j, k as k2, l as l2, m, n, o as o2, p, q as q2, s, t as t2, u as u2, v as v2, c as c2, w as w3, r } from "./css-runtime-CjZl0K48.js";
8
8
  import { reportBlockWarning, reportBlockError } from "./observability.js";
9
9
  import { a as createEditorBridge, E as createSelectBlockMessage } from "./bridge-Mz0CqG6E.js";
10
- import { p as p2 } from "./project-gridstack-PxN_DIfP.js";
10
+ import { p as p2 } from "./project-gridstack-CRZ_7HoT.js";
11
11
  import { clearLayoutModeAdapter, getLayoutModeAdapter, registerLayoutModeAdapter } from "./layout-mode-adapter-BBd4JRQd.js";
12
+ const SUPPORTED_UI_LANGUAGES = [
13
+ { code: "cs", label: "Czech" },
14
+ { code: "da", label: "Danish" },
15
+ { code: "nl", label: "Dutch" },
16
+ { code: "en", label: "English" },
17
+ { code: "fr", label: "French" },
18
+ { code: "de", label: "German" },
19
+ { code: "el", label: "Greek" },
20
+ { code: "hu", label: "Hungarian" },
21
+ { code: "pl", label: "Polish" },
22
+ { code: "pt", label: "Portuguese" },
23
+ { code: "sk", label: "Slovak" },
24
+ { code: "sl", label: "Slovenian" },
25
+ { code: "es", label: "Spanish" }
26
+ ];
27
+ function toLanguageSelectOptions(languages) {
28
+ return languages.map(({ code, label }) => ({ label, value: code }));
29
+ }
30
+ const SUPPORTED_UI_LANGUAGE_OPTIONS = toLanguageSelectOptions(
31
+ SUPPORTED_UI_LANGUAGES
32
+ );
12
33
  function createState() {
13
34
  const discountCode = d(null);
14
35
  const products = d([]);
@@ -276,6 +297,13 @@ function createCustomerService(options) {
276
297
  },
277
298
  createPaymentMethod(params) {
278
299
  return options.adapter.createPaymentMethod(params);
300
+ },
301
+ async updateAttributes(attributes) {
302
+ var _a;
303
+ const merged = { ...(_a = current.value) == null ? void 0 : _a.attributes, ...attributes };
304
+ const result = await options.adapter.updateAttributes(merged);
305
+ if (result._tag === "Success") current.value = result.data;
306
+ return result;
279
307
  }
280
308
  };
281
309
  }
@@ -287,7 +315,8 @@ const PAYMENT_INSTRUMENT_TYPES = [
287
315
  "sepa_direct_debit",
288
316
  "blik",
289
317
  "mbway",
290
- "bacs"
318
+ "bacs",
319
+ "manual"
291
320
  ];
292
321
  const INSTRUMENT_TYPE_TO_NAME = {
293
322
  credit_card: null,
@@ -296,7 +325,8 @@ const INSTRUMENT_TYPE_TO_NAME = {
296
325
  sepa_direct_debit: "SEPA",
297
326
  mbway: "MB WAY",
298
327
  shop_pay: "Shop Pay",
299
- bacs: "Bacs"
328
+ bacs: "Bacs",
329
+ manual: "Shopify Checkout"
300
330
  };
301
331
  function getPaymentInstrumentName(instrument) {
302
332
  const name = INSTRUMENT_TYPE_TO_NAME[instrument.type] ?? null;
@@ -378,16 +408,23 @@ function serializeV1PaymentInstrument(raw) {
378
408
  return { type: "mbway", ...r2.phone != null ? { phone: r2.phone } : {} };
379
409
  case "bacs":
380
410
  return { type: "bacs", maskedNumber: r2.maskedNumber ?? "" };
411
+ case "manual":
412
+ return { type: "manual" };
381
413
  default:
382
414
  return null;
383
415
  }
384
416
  }
385
417
  function createMockCustomerAdapter() {
386
- const customer = { id: "customer-1", name: "Customer 1" };
418
+ let customer = { id: "customer-1", name: "Customer 1", attributes: {} };
387
419
  return {
388
420
  async getCurrent() {
389
421
  return { _tag: "Success", data: customer };
390
422
  },
423
+ async updateAttributes(attributes) {
424
+ await new Promise((resolve) => setTimeout(resolve, 300));
425
+ customer = { ...customer, attributes: { ...attributes } };
426
+ return { _tag: "Success", data: customer };
427
+ },
391
428
  async createPaymentMethod(params) {
392
429
  await new Promise((resolve) => setTimeout(resolve, 300));
393
430
  if (params.provider === "shopify") {
@@ -410,17 +447,41 @@ function createMockCustomerAdapter() {
410
447
  }
411
448
  };
412
449
  }
450
+ function fromV1Customer(body) {
451
+ return {
452
+ id: body.id,
453
+ name: body.displayName,
454
+ email: body.email ?? void 0,
455
+ attributes: Object.fromEntries(
456
+ body.customAttributes.map(({ key, value }) => [key, value])
457
+ )
458
+ };
459
+ }
413
460
  function createApiCustomerAdapter(fetcher) {
414
461
  return {
415
462
  async getCurrent() {
416
463
  try {
417
- const res = await fetcher("/customer/info");
464
+ const res = await fetcher("/customer/v1/customer");
418
465
  if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
419
- const data = await res.json();
420
- const name = [data.firstName, data.lastName].filter(Boolean).join(" ") || data.email || "";
421
466
  return {
422
467
  _tag: "Success",
423
- data: { id: data.id, name, email: data.email }
468
+ data: fromV1Customer(await res.json())
469
+ };
470
+ } catch (e) {
471
+ return { _tag: "Failure", error: e };
472
+ }
473
+ },
474
+ async updateAttributes(attributes) {
475
+ try {
476
+ const res = await fetcher("/customer/v1/customer", {
477
+ method: "PATCH",
478
+ headers: { "Content-Type": "application/json" },
479
+ body: JSON.stringify({ customAttributes: attributes })
480
+ });
481
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
482
+ return {
483
+ _tag: "Success",
484
+ data: fromV1Customer(await res.json())
424
485
  };
425
486
  } catch (e) {
426
487
  return { _tag: "Failure", error: e };
@@ -578,6 +639,12 @@ function createApiLoginAdapter(fetcher, opts) {
578
639
  });
579
640
  }
580
641
  }
642
+ if (res.status === 401) {
643
+ const data = await res.json().catch(() => null);
644
+ if (data != null && typeof data === "object" && "message" in data && data.message === "Customer not found") {
645
+ throw new AuthenticationError(AuthenticationErrorReason.Missing);
646
+ }
647
+ }
581
648
  if (!res.ok) {
582
649
  throw new Error(`Unexpected response: ${res.statusText}`);
583
650
  }
@@ -1481,6 +1548,39 @@ const DISCOUNT_REJECTION_REASONS = [
1481
1548
  function toAttributeArray(next) {
1482
1549
  return Object.entries(next).map(([key, value]) => ({ key, value }));
1483
1550
  }
1551
+ const MOCK_SHIPPING_METHODS = [
1552
+ {
1553
+ handle: "standard-shipping",
1554
+ title: "Standard shipping",
1555
+ price: { amount: "0.00", currencyCode: "EUR" }
1556
+ },
1557
+ {
1558
+ handle: "dhl-express",
1559
+ title: "DHL Express",
1560
+ price: { amount: "9.99", currencyCode: "EUR" }
1561
+ },
1562
+ {
1563
+ handle: "next-day",
1564
+ title: "Next day delivery",
1565
+ price: { amount: "14.99", currencyCode: "EUR" }
1566
+ }
1567
+ ];
1568
+ function toShippingAddressBody(address) {
1569
+ return {
1570
+ firstName: address.firstName,
1571
+ lastName: address.lastName,
1572
+ address1: address.address1,
1573
+ zip: address.zip,
1574
+ city: address.city,
1575
+ ...address.address2 ? { address2: address.address2 } : {},
1576
+ ...address.province ? { province: address.province } : {},
1577
+ ...address.phone ? { phone: address.phone } : {},
1578
+ ...address.company ? { company: address.company } : {}
1579
+ };
1580
+ }
1581
+ function isStaleSubscriptionMessage(message) {
1582
+ return message ? message.toLowerCase().includes("changed since last fetch") : false;
1583
+ }
1484
1584
  function toNonEmptyAttributeArray(next) {
1485
1585
  if (next == null) return [];
1486
1586
  return toAttributeArray(next).filter(
@@ -1962,6 +2062,92 @@ function createMockSubscriptionAdapter(options = {}) {
1962
2062
  subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1963
2063
  return { _tag: "Success", data: { ...subscription } };
1964
2064
  },
2065
+ async updateDeliveryAddress({
2066
+ subscriptionId,
2067
+ address
2068
+ }) {
2069
+ var _a;
2070
+ await new Promise((resolve) => setTimeout(resolve, 300));
2071
+ const subscription = mockSubscriptions.find(
2072
+ (sub) => sub.id === subscriptionId
2073
+ );
2074
+ if (!subscription) {
2075
+ return { _tag: "Failure", error: { kind: "SUBSCRIPTION_NOT_FOUND" } };
2076
+ }
2077
+ const previous = (_a = subscription.deliveryMethod) == null ? void 0 : _a.address;
2078
+ subscription.deliveryMethod = {
2079
+ ...subscription.deliveryMethod,
2080
+ address: {
2081
+ firstName: address.firstName,
2082
+ lastName: address.lastName,
2083
+ address1: address.address1,
2084
+ zip: address.zip,
2085
+ city: address.city,
2086
+ ...address.address2 ? { address2: address.address2 } : {},
2087
+ ...address.province ? { province: address.province } : {},
2088
+ ...address.phone ? { phone: address.phone } : {},
2089
+ ...address.company ? { company: address.company } : {},
2090
+ ...(previous == null ? void 0 : previous.country) != null ? { country: previous.country } : {},
2091
+ ...(previous == null ? void 0 : previous.countryCode) != null ? { countryCode: previous.countryCode } : {}
2092
+ }
2093
+ };
2094
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2095
+ return { _tag: "Success", data: void 0 };
2096
+ },
2097
+ async getAvailableShippingMethods({
2098
+ subscriptionId
2099
+ }) {
2100
+ var _a, _b, _c;
2101
+ await new Promise((resolve) => setTimeout(resolve, 300));
2102
+ const subscription = mockSubscriptions.find(
2103
+ (sub) => sub.id === subscriptionId
2104
+ );
2105
+ if (!subscription) {
2106
+ return { _tag: "Failure", error: "Subscription not found" };
2107
+ }
2108
+ const currentTitle = (_b = (_a = subscription.deliveryMethod) == null ? void 0 : _a.shippingOption) == null ? void 0 : _b.title;
2109
+ const currencyCode = ((_c = subscription.items[0]) == null ? void 0 : _c.price.currencyCode) ?? "EUR";
2110
+ return {
2111
+ _tag: "Success",
2112
+ data: MOCK_SHIPPING_METHODS.map((method) => ({
2113
+ ...method,
2114
+ price: { ...method.price, currencyCode },
2115
+ isActive: method.title === currentTitle
2116
+ }))
2117
+ };
2118
+ },
2119
+ async updateDeliveryMethod({
2120
+ subscriptionId,
2121
+ shippingMethodHandle
2122
+ }) {
2123
+ await new Promise((resolve) => setTimeout(resolve, 300));
2124
+ const subscription = mockSubscriptions.find(
2125
+ (sub) => sub.id === subscriptionId
2126
+ );
2127
+ if (!subscription) {
2128
+ return { _tag: "Failure", error: { kind: "SUBSCRIPTION_NOT_FOUND" } };
2129
+ }
2130
+ const method = MOCK_SHIPPING_METHODS.find(
2131
+ (m2) => m2.handle === shippingMethodHandle
2132
+ );
2133
+ if (!method) {
2134
+ return {
2135
+ _tag: "Failure",
2136
+ error: {
2137
+ kind: "UNKNOWN",
2138
+ message: `Provided shipping method handle "${shippingMethodHandle}" is not available`
2139
+ }
2140
+ };
2141
+ }
2142
+ subscription.deliveryMethod = {
2143
+ ...subscription.deliveryMethod,
2144
+ shippingOption: { title: method.title },
2145
+ pickupOption: null,
2146
+ localDeliveryOption: null
2147
+ };
2148
+ subscription.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2149
+ return { _tag: "Success", data: void 0 };
2150
+ },
1965
2151
  async resume(params) {
1966
2152
  await new Promise((resolve) => setTimeout(resolve, 300));
1967
2153
  const subscription = mockSubscriptions.find(
@@ -2516,6 +2702,121 @@ function createApiSubscriptionAdapter(fetcher) {
2516
2702
  return { _tag: "Failure", error: e };
2517
2703
  }
2518
2704
  },
2705
+ // Legacy endpoint on purpose — see SubscriptionAdapter.updateDeliveryAddress
2706
+ // for why the documented v1 `deliveryAddress` patch is not used here.
2707
+ async updateDeliveryAddress({ subscriptionId, address }) {
2708
+ try {
2709
+ const res = await fetcher(
2710
+ `/customer/subscriptions/${subscriptionId}/shipping-address`,
2711
+ {
2712
+ method: "PUT",
2713
+ headers: { "Content-Type": "application/json" },
2714
+ body: JSON.stringify(toShippingAddressBody(address))
2715
+ }
2716
+ );
2717
+ if (!res.ok) {
2718
+ if (res.status === 403) {
2719
+ return { _tag: "Failure", error: { kind: "NOT_ALLOWED" } };
2720
+ }
2721
+ if (res.status === 404) {
2722
+ return {
2723
+ _tag: "Failure",
2724
+ error: { kind: "SUBSCRIPTION_NOT_FOUND" }
2725
+ };
2726
+ }
2727
+ if (res.status === 400) {
2728
+ const body = await readErrorBody(res);
2729
+ const message = typeof body.message === "string" ? body.message : void 0;
2730
+ if (isStaleSubscriptionMessage(message)) {
2731
+ return { _tag: "Failure", error: { kind: "STALE" } };
2732
+ }
2733
+ return {
2734
+ _tag: "Failure",
2735
+ error: {
2736
+ kind: "INVALID_ADDRESS",
2737
+ ...message ? { message } : {}
2738
+ }
2739
+ };
2740
+ }
2741
+ return {
2742
+ _tag: "Failure",
2743
+ error: { kind: "UNKNOWN", message: `HTTP ${res.status}` }
2744
+ };
2745
+ }
2746
+ return { _tag: "Success", data: void 0 };
2747
+ } catch (e) {
2748
+ return {
2749
+ _tag: "Failure",
2750
+ error: {
2751
+ kind: "NETWORK",
2752
+ message: e instanceof Error ? e.message : void 0
2753
+ }
2754
+ };
2755
+ }
2756
+ },
2757
+ // Legacy endpoint — no /customer/v1 equivalent exists yet.
2758
+ async getAvailableShippingMethods({ subscriptionId }) {
2759
+ try {
2760
+ const res = await fetcher(
2761
+ `/customer/subscriptions/${subscriptionId}/available-shipping-methods`
2762
+ );
2763
+ if (!res.ok) return { _tag: "Failure", error: `HTTP ${res.status}` };
2764
+ const data = await res.json();
2765
+ return { _tag: "Success", data };
2766
+ } catch (e) {
2767
+ return { _tag: "Failure", error: e };
2768
+ }
2769
+ },
2770
+ // Legacy endpoint — no /customer/v1 equivalent exists yet. No `extra` is
2771
+ // sent: pickup points are out of scope, and omitting it is what tells the
2772
+ // endpoint to leave any existing parcel-locker attributes alone.
2773
+ async updateDeliveryMethod({ subscriptionId, shippingMethodHandle }) {
2774
+ try {
2775
+ const res = await fetcher(
2776
+ `/customer/subscriptions/${subscriptionId}/shipping-method`,
2777
+ {
2778
+ method: "POST",
2779
+ headers: { "Content-Type": "application/json" },
2780
+ body: JSON.stringify({ shippingMethodHandle })
2781
+ }
2782
+ );
2783
+ if (!res.ok) {
2784
+ if (res.status === 403) {
2785
+ return { _tag: "Failure", error: { kind: "NOT_ALLOWED" } };
2786
+ }
2787
+ if (res.status === 404) {
2788
+ return {
2789
+ _tag: "Failure",
2790
+ error: { kind: "SUBSCRIPTION_NOT_FOUND" }
2791
+ };
2792
+ }
2793
+ if (res.status === 400) {
2794
+ const body = await readErrorBody(res);
2795
+ const message = typeof body.message === "string" ? body.message : void 0;
2796
+ if (isStaleSubscriptionMessage(message)) {
2797
+ return { _tag: "Failure", error: { kind: "STALE" } };
2798
+ }
2799
+ return {
2800
+ _tag: "Failure",
2801
+ error: { kind: "UNKNOWN", ...message ? { message } : {} }
2802
+ };
2803
+ }
2804
+ return {
2805
+ _tag: "Failure",
2806
+ error: { kind: "UNKNOWN", message: `HTTP ${res.status}` }
2807
+ };
2808
+ }
2809
+ return { _tag: "Success", data: void 0 };
2810
+ } catch (e) {
2811
+ return {
2812
+ _tag: "Failure",
2813
+ error: {
2814
+ kind: "NETWORK",
2815
+ message: e instanceof Error ? e.message : void 0
2816
+ }
2817
+ };
2818
+ }
2819
+ },
2519
2820
  async resume({ subscriptionId }) {
2520
2821
  try {
2521
2822
  const res = await fetcher(
@@ -3551,6 +3852,27 @@ function createSubscriptionService(adapter) {
3551
3852
  },
3552
3853
  reschedule: (subscriptionId, newDate) => adapter.reschedule({ subscriptionId, newDate }),
3553
3854
  updateCustomAttributes: (subscriptionId, customAttributes) => adapter.updateCustomAttributes({ subscriptionId, customAttributes }),
3855
+ updateDeliveryAddress: async (subscriptionId, address) => {
3856
+ const result = await adapter.updateDeliveryAddress({
3857
+ subscriptionId,
3858
+ address
3859
+ });
3860
+ if (result._tag === "Success") {
3861
+ await reload();
3862
+ }
3863
+ return result;
3864
+ },
3865
+ getAvailableShippingMethods: (subscriptionId) => adapter.getAvailableShippingMethods({ subscriptionId }),
3866
+ updateDeliveryMethod: async (subscriptionId, shippingMethodHandle) => {
3867
+ const result = await adapter.updateDeliveryMethod({
3868
+ subscriptionId,
3869
+ shippingMethodHandle
3870
+ });
3871
+ if (result._tag === "Success") {
3872
+ await reload();
3873
+ }
3874
+ return result;
3875
+ },
3554
3876
  resume: (subscriptionId) => adapter.resume({ subscriptionId }),
3555
3877
  pause: (subscriptionId) => adapter.pause({ subscriptionId }),
3556
3878
  reactivate: (subscriptionId) => adapter.reactivate({ subscriptionId }),
@@ -3561,10 +3883,98 @@ function createSubscriptionService(adapter) {
3561
3883
  getAvailablePlans: (subscriptionId) => adapter.getAvailablePlans({ subscriptionId }),
3562
3884
  getDefaultSubscriptionId: () => adapter.getDefaultSubscriptionId(),
3563
3885
  getUpsellProducts: (params) => adapter.getUpsellProducts ? adapter.getUpsellProducts(params) : Promise.resolve({ _tag: "Success", data: [] }),
3564
- addUpsellProduct: (params) => adapter.addUpsellProduct ? adapter.addUpsellProduct(params) : Promise.resolve({ _tag: "Success", data: void 0 })
3886
+ addUpsellProduct: (params) => adapter.addUpsellProduct ? adapter.addUpsellProduct(params) : Promise.resolve({ _tag: "Success", data: void 0 }),
3887
+ getInstantOrderProducts: (subscriptionId, params) => adapter.getInstantOrderProducts ? adapter.getInstantOrderProducts({ subscriptionId, ...params }) : Promise.resolve({
3888
+ _tag: "Success",
3889
+ data: {
3890
+ available: false,
3891
+ requiresCheckout: false,
3892
+ products: [],
3893
+ hasNextPage: false,
3894
+ endCursor: null
3895
+ }
3896
+ }),
3897
+ placeInstantOrder: (subscriptionId, requestKey, items) => adapter.placeInstantOrder ? adapter.placeInstantOrder({ subscriptionId, requestKey, items }) : (
3898
+ // Distinguishable from every server-side refusal, so a consumer can
3899
+ // treat "this host cannot do instant orders" as a missing capability
3900
+ // rather than telling the customer their order was declined.
3901
+ Promise.resolve({
3902
+ _tag: "Failure",
3903
+ error: { kind: "UNSUPPORTED" }
3904
+ })
3905
+ )
3565
3906
  };
3566
3907
  return service;
3567
3908
  }
3909
+ function isOneTimeLine(line) {
3910
+ return line.isOneTime === true || line.recurringCycleLimit === 1;
3911
+ }
3912
+ function hasValue(value) {
3913
+ return typeof value === "string" && value.length > 0;
3914
+ }
3915
+ function hasIdentity(line) {
3916
+ return hasValue(line.subscriptionId) && hasValue(line.subscriptionLineId);
3917
+ }
3918
+ function isSameLine(a2, b3) {
3919
+ return hasValue(a2.subscriptionLineId) && a2.subscriptionLineId === b3.subscriptionLineId;
3920
+ }
3921
+ function belongsToSameSubscription(a2, b3) {
3922
+ return hasValue(a2.subscriptionId) && a2.subscriptionId === b3.subscriptionId;
3923
+ }
3924
+ function parentLineFor(child, lines) {
3925
+ if (!hasValue(child.parentLineId)) {
3926
+ return void 0;
3927
+ }
3928
+ return lines.find(
3929
+ (candidate) => belongsToSameSubscription(candidate, child) && (candidate.subscriptionLineId === child.parentLineId || candidate.id === child.parentLineId)
3930
+ );
3931
+ }
3932
+ function productKey(line, lines) {
3933
+ if (hasValue(line.parentProductId)) {
3934
+ return `product:${line.parentProductId}`;
3935
+ }
3936
+ if (hasValue(line.parentLineId)) {
3937
+ const parent = parentLineFor(line, lines);
3938
+ if (hasValue(parent == null ? void 0 : parent.productId)) {
3939
+ return `product:${parent.productId}`;
3940
+ }
3941
+ return `line:${line.parentLineId}`;
3942
+ }
3943
+ const lineIdentity = hasValue(line.subscriptionLineId) ? line.subscriptionLineId : line.id;
3944
+ if (!hasValue(lineIdentity)) {
3945
+ return null;
3946
+ }
3947
+ const isReferencedAsParent = lines.some(
3948
+ (candidate) => belongsToSameSubscription(candidate, line) && (hasValue(line.productId) && candidate.parentProductId === line.productId || hasValue(candidate.parentLineId) && (candidate.parentLineId === line.subscriptionLineId || candidate.parentLineId === line.id))
3949
+ );
3950
+ if (isReferencedAsParent && hasValue(line.productId)) {
3951
+ return `product:${line.productId}`;
3952
+ }
3953
+ return `line:${lineIdentity}`;
3954
+ }
3955
+ function remainingRecurringProductKeys(line, lines) {
3956
+ const removedProductKey = productKey(line, lines);
3957
+ return new Set(
3958
+ lines.filter(
3959
+ (item) => belongsToSameSubscription(item, line) && !isOneTimeLine(item)
3960
+ ).map((item) => productKey(item, lines)).filter((key) => key != null && key !== removedProductKey)
3961
+ );
3962
+ }
3963
+ function canRemoveLine(line, lines) {
3964
+ if (!hasIdentity(line)) {
3965
+ return false;
3966
+ }
3967
+ const targetExists = lines.some(
3968
+ (item) => belongsToSameSubscription(item, line) && isSameLine(item, line)
3969
+ );
3970
+ if (!targetExists) {
3971
+ return false;
3972
+ }
3973
+ if (isOneTimeLine(line)) {
3974
+ return true;
3975
+ }
3976
+ return remainingRecurringProductKeys(line, lines).size > 0;
3977
+ }
3568
3978
  function getDefaultBlockForAction(actionType, actionConfig, blockId) {
3569
3979
  const blockName = `action:${actionType}`;
3570
3980
  const definedBlocks = getDefinedBlocks();
@@ -4543,6 +4953,8 @@ export {
4543
4953
  PAYMENT_INSTRUMENT_TYPES,
4544
4954
  ProductServiceContext,
4545
4955
  RouterServiceContext,
4956
+ SUPPORTED_UI_LANGUAGES,
4957
+ SUPPORTED_UI_LANGUAGE_OPTIONS,
4546
4958
  SchedulesServiceContext,
4547
4959
  S as SelectedBlockContext,
4548
4960
  SettingsServiceContext,
@@ -4559,6 +4971,7 @@ export {
4559
4971
  c as backfillInstanceDefaults,
4560
4972
  b2 as buildGridLayout,
4561
4973
  j as buildLayoutCss,
4974
+ canRemoveLine,
4562
4975
  canvasMode,
4563
4976
  clampRect,
4564
4977
  k2 as classifyRowDividers,
@@ -4612,6 +5025,7 @@ export {
4612
5025
  emitLayoutSetRects,
4613
5026
  q2 as expandFillLayoutDocument,
4614
5027
  findFreeRect,
5028
+ fromV1Customer,
4615
5029
  getActiveSurfaceContext,
4616
5030
  getDefaultBlockForAction,
4617
5031
  getDefinedBlocks,
@@ -4629,6 +5043,8 @@ export {
4629
5043
  insertRectRelative,
4630
5044
  H as isEditorPreview,
4631
5045
  isFilterQuery,
5046
+ isOneTimeLine,
5047
+ isStaleSubscriptionMessage,
4632
5048
  b as isStubDefinition,
4633
5049
  t2 as layoutScopeSelector,
4634
5050
  I as layoutSystemEnabled,
@@ -4654,6 +5070,7 @@ export {
4654
5070
  l as setLayoutSystemEnabled,
4655
5071
  d as signal,
4656
5072
  subscribeContext,
5073
+ toLanguageSelectOptions,
4657
5074
  L as untracked,
4658
5075
  waitForDevBlocksUrl,
4659
5076
  w2 as withWrapper
@@ -51,12 +51,16 @@ function parseBlockLocaleFile(file) {
51
51
  }
52
52
  };
53
53
  }
54
- function indexOverrides(overrides) {
54
+ function indexOverrides(overrides, locale) {
55
55
  const indexed = {
56
56
  theme: {},
57
57
  blocks: {}
58
58
  };
59
+ const wanted = locale == null ? null : normalizeLocale(locale);
59
60
  for (const item of overrides) {
61
+ if (wanted != null && normalizeLocale(item.locale) !== wanted) {
62
+ continue;
63
+ }
60
64
  if (item.scope.kind === "theme") {
61
65
  indexed.theme[item.key] = item.value;
62
66
  continue;
@@ -122,29 +126,31 @@ function createThemeState(deps) {
122
126
  }
123
127
  return { defaults: nextDefaults, modes: nextModes };
124
128
  }
129
+ let localeVersion = 0;
125
130
  async function setLocale(nextLocaleRaw) {
126
131
  var _a2;
127
132
  const nextLocale = normalizeLocale(nextLocaleRaw);
133
+ const version = ++localeVersion;
128
134
  const [blockData, loadedOverrides] = await Promise.all([
129
135
  collectBlockDefaults(nextLocale),
130
136
  ((_a2 = deps.translations) == null ? void 0 : _a2.resolveTranslations(nextLocale).catch(() => [])) ?? Promise.resolve([])
131
137
  ]);
132
- const overrides = loadedOverrides.filter(
133
- (item) => normalizeLocale(item.locale) === nextLocale
134
- );
135
- const indexed = indexOverrides(overrides);
136
- catalogs.value = {
137
- theme: {
138
- defaults: {},
139
- overrides: indexed.theme
140
- },
141
- blocks: {
142
- defaults: blockData.defaults,
143
- modes: blockData.modes,
144
- overrides: indexed.blocks
145
- }
146
- };
147
- locale.value = nextLocale;
138
+ if (version !== localeVersion) return;
139
+ const indexed = indexOverrides(loadedOverrides, nextLocale);
140
+ r(() => {
141
+ catalogs.value = {
142
+ theme: {
143
+ defaults: {},
144
+ overrides: indexed.theme
145
+ },
146
+ blocks: {
147
+ defaults: blockData.defaults,
148
+ modes: blockData.modes,
149
+ overrides: indexed.blocks
150
+ }
151
+ };
152
+ locale.value = nextLocale;
153
+ });
148
154
  }
149
155
  async function resolve(surface, path, params) {
150
156
  var _a2, _b, _c, _d, _e, _f, _g, _h;
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/editor/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACrD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB;6BAsE/B,aAAa;EAgU9C"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/editor/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACrD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB;6BAsE/B,aAAa;EA0U9C"}
package/dist/editor.js CHANGED
@@ -82,7 +82,10 @@ function createEditorHandler(options) {
82
82
  const catalogs = themeState.locales.catalogs;
83
83
  const current = catalogs.value;
84
84
  if (current == null) return;
85
- const indexed = indexOverrides(message.payload.overrides);
85
+ const indexed = indexOverrides(
86
+ message.payload.overrides,
87
+ themeState.locales.locale.value
88
+ );
86
89
  catalogs.value = {
87
90
  ...current,
88
91
  theme: {
@@ -1,5 +1,5 @@
1
- import { c as reconcileLayout, L as LAYOUT_SCOPE_ATTR, M as MAX_BLOCKS_PER_ROW } from "./css-runtime-B7tZrBIp.js";
2
- import { r as resolveActiveBreakpoint, p as projectToGridStack, M as MIN_BLOCK_ROWS, a as MIN_BLOCK_PX } from "./project-gridstack-PxN_DIfP.js";
1
+ import { c as reconcileLayout, L as LAYOUT_SCOPE_ATTR, M as MAX_BLOCKS_PER_ROW } from "./css-runtime-CjZl0K48.js";
2
+ import { r as resolveActiveBreakpoint, p as projectToGridStack, M as MIN_BLOCK_ROWS, a as MIN_BLOCK_PX } from "./project-gridstack-CRZ_7HoT.js";
3
3
  import { LAYOUT_POP_CLASS, LAYOUT_INTERACTION_START, LAYOUT_INTERACTION_END } from "./layout-mode-adapter-BBd4JRQd.js";
4
4
  function obsolete(self, f, oldName, newName, rev) {
5
5
  const wrapper = (...args) => {