@final-commerce/command-frame 0.1.73 → 0.1.75

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 (100) hide show
  1. package/README.md +50 -28
  2. package/dist/CommonTypes.d.ts +124 -7
  3. package/dist/CommonTypes.js +112 -0
  4. package/dist/actions/add-cart-discount/mock.js +6 -3
  5. package/dist/actions/add-cart-fee/mock.js +6 -6
  6. package/dist/actions/add-custom-sale/mock.js +7 -2
  7. package/dist/actions/add-order-note/mock.js +3 -1
  8. package/dist/actions/add-product-discount/mock.js +10 -3
  9. package/dist/actions/add-product-fee/mock.js +10 -1
  10. package/dist/actions/apply-transition/action.d.ts +2 -0
  11. package/dist/actions/apply-transition/action.js +4 -0
  12. package/dist/actions/apply-transition/mock.d.ts +6 -0
  13. package/dist/actions/apply-transition/mock.js +33 -0
  14. package/dist/actions/apply-transition/types.d.ts +17 -0
  15. package/dist/actions/apply-transition/types.js +1 -0
  16. package/dist/actions/can-transition/action.d.ts +2 -0
  17. package/dist/actions/can-transition/action.js +4 -0
  18. package/dist/actions/can-transition/mock.d.ts +6 -0
  19. package/dist/actions/can-transition/mock.js +28 -0
  20. package/dist/actions/can-transition/types.d.ts +11 -0
  21. package/dist/actions/can-transition/types.js +1 -0
  22. package/dist/actions/cash-payment/mock.js +12 -18
  23. package/dist/actions/cash-payment/types.d.ts +5 -0
  24. package/dist/actions/delete-parked-order/mock.js +3 -1
  25. package/dist/actions/delete-parked-order/types.d.ts +3 -0
  26. package/dist/actions/extension-payment/types.d.ts +5 -0
  27. package/dist/actions/get-available-transitions/action.d.ts +2 -0
  28. package/dist/actions/get-available-transitions/action.js +4 -0
  29. package/dist/actions/get-available-transitions/mock.d.ts +6 -0
  30. package/dist/actions/get-available-transitions/mock.js +26 -0
  31. package/dist/actions/get-available-transitions/types.d.ts +9 -0
  32. package/dist/actions/get-available-transitions/types.js +1 -0
  33. package/dist/actions/get-context/mock.js +1 -1
  34. package/dist/actions/get-orders/mock.js +3 -3
  35. package/dist/actions/initiate-refund/types.d.ts +3 -0
  36. package/dist/actions/open-extension-overlay/mock.d.ts +2 -0
  37. package/dist/actions/open-extension-overlay/mock.js +1 -0
  38. package/dist/actions/open-extension-overlay/types.d.ts +9 -0
  39. package/dist/actions/open-extension-overlay/types.js +1 -0
  40. package/dist/actions/park-order/mock.js +4 -1
  41. package/dist/actions/park-order/types.d.ts +3 -0
  42. package/dist/actions/partial-payment/mock.js +21 -3
  43. package/dist/actions/partial-payment/types.d.ts +5 -0
  44. package/dist/actions/process-partial-refund/types.d.ts +3 -0
  45. package/dist/actions/remove-custom-sale/mock.d.ts +2 -0
  46. package/dist/actions/remove-custom-sale/mock.js +29 -0
  47. package/dist/actions/remove-customer-from-cart/mock.js +3 -1
  48. package/dist/actions/remove-order-note/mock.d.ts +2 -0
  49. package/dist/actions/remove-order-note/mock.js +12 -0
  50. package/dist/actions/remove-product-discount/mock.d.ts +2 -0
  51. package/dist/actions/remove-product-discount/mock.js +17 -0
  52. package/dist/actions/remove-product-fee/mock.d.ts +2 -0
  53. package/dist/actions/remove-product-fee/mock.js +17 -0
  54. package/dist/actions/remove-product-from-cart/mock.js +5 -5
  55. package/dist/actions/resolve-extension-overlay/mock.d.ts +2 -0
  56. package/dist/actions/resolve-extension-overlay/mock.js +1 -0
  57. package/dist/actions/resolve-extension-overlay/types.d.ts +9 -0
  58. package/dist/actions/resolve-extension-overlay/types.js +1 -0
  59. package/dist/actions/resume-parked-order/mock.js +4 -1
  60. package/dist/actions/resume-parked-order/types.d.ts +3 -0
  61. package/dist/actions/tap-to-pay-payment/mock.js +5 -3
  62. package/dist/actions/tap-to-pay-payment/types.d.ts +5 -0
  63. package/dist/actions/terminal-payment/mock.js +4 -5
  64. package/dist/actions/terminal-payment/types.d.ts +5 -0
  65. package/dist/actions/update-cart-item-quantity/mock.js +9 -9
  66. package/dist/actions/vendara-payment/types.d.ts +5 -0
  67. package/dist/common-types/index.d.ts +1 -0
  68. package/dist/common-types/index.js +1 -0
  69. package/dist/common-types/order-state.d.ts +32 -0
  70. package/dist/common-types/order-state.js +6 -0
  71. package/dist/common-types/state-fragment.d.ts +77 -0
  72. package/dist/common-types/state-fragment.js +10 -0
  73. package/dist/demo/database.d.ts +10 -0
  74. package/dist/demo/database.js +169 -3
  75. package/dist/fragments/index.d.ts +1 -0
  76. package/dist/fragments/index.js +1 -0
  77. package/dist/fragments/preorder-no-deposit.d.ts +26 -0
  78. package/dist/fragments/preorder-no-deposit.js +166 -0
  79. package/dist/index.d.ts +14 -4
  80. package/dist/index.js +13 -3
  81. package/dist/interceptors/index.d.ts +21 -0
  82. package/dist/interceptors/index.js +53 -0
  83. package/dist/interceptors/types.d.ts +26 -0
  84. package/dist/interceptors/types.js +1 -0
  85. package/dist/projects/render/mocks.js +16 -4
  86. package/dist/projects/render/types.d.ts +7 -1
  87. package/dist/pubsub/topics/orders/index.js +10 -0
  88. package/dist/pubsub/topics/orders/state-transition-blocked/types.d.ts +16 -0
  89. package/dist/pubsub/topics/orders/state-transition-blocked/types.js +1 -0
  90. package/dist/pubsub/topics/orders/state-transition-completed/types.d.ts +15 -0
  91. package/dist/pubsub/topics/orders/state-transition-completed/types.js +1 -0
  92. package/dist/pubsub/topics/orders/types.d.ts +6 -2
  93. package/dist/pubsub/topics/orders/types.js +2 -0
  94. package/package.json +1 -1
  95. package/dist/actions/extension-refund/constants.d.ts +0 -2
  96. package/dist/actions/extension-refund/constants.js +0 -2
  97. package/dist/actions/extension-refund/extension-refund-listener.d.ts +0 -11
  98. package/dist/actions/extension-refund/extension-refund-listener.js +0 -60
  99. package/dist/actions/extension-refund/types.d.ts +0 -32
  100. package/dist/actions/extension-refund/types.js +0 -5
package/README.md CHANGED
@@ -10,11 +10,12 @@ Command Frame provides a structured way to build integrations that run inside Fi
10
10
 
11
11
  The library provides three main capabilities:
12
12
 
13
- | Capability | Purpose | Scope |
14
- |-----------|---------|-------|
15
- | **Commands** | Call host functions from the iframe (e.g. get products, open cash drawer) | Request/response per call |
16
- | **Pub/Sub** | Subscribe to real-time events from the host (e.g. cart changes, payments) | Page-scoped (while iframe is mounted) |
17
- | **Hooks** | Register business-logic callbacks that persist across all pages | Session-scoped (survives page navigation) |
13
+ | Capability | Purpose | Scope |
14
+ | ------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------- |
15
+ | **Commands** | Call host functions from the iframe (e.g. get products, open cash drawer) | Request/response per call |
16
+ | **Pub/Sub** | Subscribe to real-time events from the host (e.g. cart changes, payments) | Page-scoped (while iframe is mounted) |
17
+ | **Hooks** | Register business-logic callbacks that persist across all pages | Session-scoped (survives page navigation) |
18
+ | **Interceptors** | Gate POS flows (approve / modify / block) at named points | Blocking; host waits for your response |
18
19
  | **Host → iframe refunds** | Render asks the extension to reverse redeem / gift-card payments before completing a POS refund | Parent `postMessage` + `requestId` (see below) |
19
20
 
20
21
  Domain models (orders, cart, customers, products, and related types) are documented in **[Types reference](./src/types/README.md)**.
@@ -54,7 +55,7 @@ For building applications that run inside the Render Point of Sale interface.
54
55
  - **Features:** Order management, Product catalog, Customer management, Payments, Hardware integration (Cash drawer, Printer), Custom tables, Secrets storage.
55
56
 
56
57
  ```typescript
57
- import { RenderClient } from '@final-commerce/command-frame';
58
+ import { RenderClient } from "@final-commerce/command-frame";
58
59
 
59
60
  const client = new RenderClient();
60
61
  const products = await client.getProducts();
@@ -68,7 +69,7 @@ For building applications that run inside the Final Commerce Management Dashboar
68
69
  - **Features:** Context, catalog, entities, custom tables, secrets, and optional host-specific commands (navigation, media, tax, branding, notifications) when the dashboard implements them.
69
70
 
70
71
  ```typescript
71
- import { ManageClient } from '@final-commerce/command-frame';
72
+ import { ManageClient } from "@final-commerce/command-frame";
72
73
 
73
74
  const client = new ManageClient();
74
75
  const context = await client.getContext();
@@ -82,14 +83,14 @@ The pub/sub system allows iframe extensions to subscribe to topics and receive r
82
83
  - **Topics:** Cart (16), Customers (8), Orders (4), Payments (2), Products (4), Refunds (4), Print (3), Custom Tables (3), Outlet (2), Station (2), Session (2), Users (2).
83
84
 
84
85
  ```typescript
85
- import { topics } from '@final-commerce/command-frame';
86
+ import { topics } from "@final-commerce/command-frame";
86
87
 
87
- const subscriptionId = topics.subscribe('cart', (event) => {
88
- console.log('Cart event:', event.type, event.data);
88
+ const subscriptionId = topics.subscribe("cart", event => {
89
+ console.log("Cart event:", event.type, event.data);
89
90
  });
90
91
 
91
92
  // Unsubscribe when done
92
- topics.unsubscribe('cart', subscriptionId);
93
+ topics.unsubscribe("cart", subscriptionId);
93
94
  ```
94
95
 
95
96
  ## Hooks
@@ -101,17 +102,44 @@ Hooks are **session-scoped** event callbacks that run in the host (Render) conte
101
102
  - A stable `hookId` is required for deduplication (safe on iframe reload).
102
103
 
103
104
  ```typescript
104
- import { hooks } from '@final-commerce/command-frame';
105
-
106
- hooks.register('cart', async (event, hostCommands) => {
107
- await hostCommands.upsertCustomTableData({
108
- tableName: 'cart-events-log',
109
- data: { eventType: event.type, payload: event.data, timestamp: event.timestamp },
110
- });
111
- }, { hookId: 'my-extension:cart-log' });
105
+ import { hooks } from "@final-commerce/command-frame";
106
+
107
+ hooks.register(
108
+ "cart",
109
+ async (event, hostCommands) => {
110
+ await hostCommands.upsertCustomTableData({
111
+ tableName: "cart-events-log",
112
+ data: { eventType: event.type, payload: event.data, timestamp: event.timestamp }
113
+ });
114
+ },
115
+ { hookId: "my-extension:cart-log" }
116
+ );
112
117
 
113
118
  // Unregister when no longer needed
114
- hooks.unregister('my-extension:cart-log');
119
+ hooks.unregister("my-extension:cart-log");
120
+ ```
121
+
122
+ ## Interceptors
123
+
124
+ Interceptors let an extension **gate a POS flow** (approve / modify / block) at a named point — the host waits for your interceptor and acts on what it returns. Unlike hooks, interceptors are **blocking**.
125
+
126
+ - **[Interceptors Documentation](./src/interceptors/README.md)**
127
+ - The callback is serialized and reconstructed on the host; it must be **self-contained** (no closures, no imports).
128
+ - A stable `interceptorId` is required for deduplication (safe on iframe reload).
129
+
130
+ ```typescript
131
+ import { interceptors } from '@final-commerce/command-frame';
132
+
133
+ interceptors.register(
134
+ 'refund_start',
135
+ async (payload, cmds) => {
136
+ if (payload.paymentTypes.includes('redeem')) {
137
+ return cmds.openExtensionOverlay({ point: 'refund_start', payload });
138
+ }
139
+ return true; // nothing for us to do
140
+ },
141
+ { interceptorId: 'my-extension:refund-guard' }
142
+ );
115
143
  ```
116
144
 
117
145
  ## Host-initiated extension refunds (redeem / gift card)
@@ -127,18 +155,12 @@ hooks.unregister('my-extension:cart-log');
127
155
  Exported APIs: `installExtensionRefundListener`, `EXTENSION_REFUND_REQUEST_ACTION`, types **`ExtensionRefundParams`** / **`ExtensionRefundResponse`**.
128
156
 
129
157
  ```typescript
130
- import {
131
- installExtensionRefundListener,
132
- type ExtensionRefundParams,
133
- type ExtensionRefundResponse
134
- } from '@final-commerce/command-frame';
158
+ import { installExtensionRefundListener, type ExtensionRefundParams, type ExtensionRefundResponse } from "@final-commerce/command-frame";
135
159
 
136
160
  const unsubscribe = installExtensionRefundListener(async (params: ExtensionRefundParams): Promise<ExtensionRefundResponse> => {
137
161
  // params.paymentType === "redeem", params.amount in major currency units, params.saleId, params.processor, etc.
138
162
  const ok = await myGiftCardProvider.refund(params);
139
- return ok
140
- ? { success: true, extensionTransactionId: ok.providerRefundId }
141
- : { success: false, error: 'Refund declined' };
163
+ return ok ? { success: true, extensionTransactionId: ok.providerRefundId } : { success: false, error: "Refund declined" };
142
164
  });
143
165
 
144
166
  // on teardown (optional)
@@ -27,6 +27,107 @@ export declare enum CurrencyCode {
27
27
  ILS = "ILS",
28
28
  TRY = "TRY",
29
29
  RUB = "RUB",
30
+ HTG = "HTG",
31
+ BND = "BND",
32
+ CRC = "CRC",
33
+ BDT = "BDT",
34
+ UAH = "UAH",
35
+ NGN = "NGN",
36
+ AFN = "AFN",
37
+ ALL = "ALL",
38
+ AMD = "AMD",
39
+ ANG = "ANG",
40
+ AOA = "AOA",
41
+ ARS = "ARS",
42
+ AWG = "AWG",
43
+ AZN = "AZN",
44
+ BAM = "BAM",
45
+ BBD = "BBD",
46
+ BGN = "BGN",
47
+ BMD = "BMD",
48
+ BOB = "BOB",
49
+ BSD = "BSD",
50
+ BTN = "BTN",
51
+ BWP = "BWP",
52
+ BYN = "BYN",
53
+ BZD = "BZD",
54
+ COP = "COP",
55
+ CZK = "CZK",
56
+ DOP = "DOP",
57
+ DZD = "DZD",
58
+ EGP = "EGP",
59
+ ETB = "ETB",
60
+ FJD = "FJD",
61
+ GEL = "GEL",
62
+ GHS = "GHS",
63
+ GTQ = "GTQ",
64
+ GYD = "GYD",
65
+ HNL = "HNL",
66
+ IRR = "IRR",
67
+ JMD = "JMD",
68
+ KES = "KES",
69
+ KGS = "KGS",
70
+ KHR = "KHR",
71
+ KYD = "KYD",
72
+ KZT = "KZT",
73
+ LAK = "LAK",
74
+ LBP = "LBP",
75
+ LKR = "LKR",
76
+ MAD = "MAD",
77
+ MDL = "MDL",
78
+ MKD = "MKD",
79
+ MMK = "MMK",
80
+ MNT = "MNT",
81
+ MOP = "MOP",
82
+ MUR = "MUR",
83
+ MVR = "MVR",
84
+ MZN = "MZN",
85
+ NAD = "NAD",
86
+ NIO = "NIO",
87
+ NPR = "NPR",
88
+ PAB = "PAB",
89
+ PEN = "PEN",
90
+ PGK = "PGK",
91
+ PKR = "PKR",
92
+ QAR = "QAR",
93
+ RON = "RON",
94
+ RSD = "RSD",
95
+ SBD = "SBD",
96
+ SRD = "SRD",
97
+ SYP = "SYP",
98
+ TJS = "TJS",
99
+ TMT = "TMT",
100
+ TOP = "TOP",
101
+ TTD = "TTD",
102
+ TZS = "TZS",
103
+ UYU = "UYU",
104
+ UZS = "UZS",
105
+ VES = "VES",
106
+ WST = "WST",
107
+ XCD = "XCD",
108
+ YER = "YER",
109
+ ZMW = "ZMW",
110
+ CDF = "CDF",
111
+ CUP = "CUP",
112
+ ERN = "ERN",
113
+ FKP = "FKP",
114
+ GIP = "GIP",
115
+ GMD = "GMD",
116
+ KPW = "KPW",
117
+ LRD = "LRD",
118
+ LSL = "LSL",
119
+ MGA = "MGA",
120
+ MWK = "MWK",
121
+ SCR = "SCR",
122
+ SDG = "SDG",
123
+ SHP = "SHP",
124
+ SLE = "SLE",
125
+ SOS = "SOS",
126
+ SSP = "SSP",
127
+ STN = "STN",
128
+ SZL = "SZL",
129
+ VED = "VED",
130
+ XCG = "XCG",
30
131
  JPY = "JPY",
31
132
  KRW = "KRW",
32
133
  VND = "VND",
@@ -34,6 +135,17 @@ export declare enum CurrencyCode {
34
135
  ISK = "ISK",
35
136
  HUF = "HUF",
36
137
  TWD = "TWD",
138
+ GNF = "GNF",
139
+ BIF = "BIF",
140
+ DJF = "DJF",
141
+ KMF = "KMF",
142
+ PYG = "PYG",
143
+ RWF = "RWF",
144
+ UGX = "UGX",
145
+ VUV = "VUV",
146
+ XAF = "XAF",
147
+ XOF = "XOF",
148
+ XPF = "XPF",
37
149
  KWD = "KWD",
38
150
  BHD = "BHD",
39
151
  OMR = "OMR",
@@ -255,7 +367,7 @@ export interface CFActiveProduct extends CFActiveEntity {
255
367
  }
256
368
  export interface CFCustomer {
257
369
  _id: string;
258
- companyId: any;
370
+ companyId: string;
259
371
  externalId?: string;
260
372
  email: string;
261
373
  firstName: string;
@@ -440,8 +552,7 @@ export interface CFRefundedLineItem {
440
552
  images?: string[];
441
553
  fee: CFFeeLineItem;
442
554
  }
443
- export interface CFRefundedCustomSale extends CFCustomSale {
444
- }
555
+ export type CFRefundedCustomSale = CFCustomSale;
445
556
  export interface CFRefundItem {
446
557
  lineItems: CFRefundedLineItem[];
447
558
  customSales: CFRefundedCustomSale[];
@@ -464,6 +575,12 @@ export interface CFOrder {
464
575
  companyId: string;
465
576
  externalId: string | null;
466
577
  status: string;
578
+ /** Financial state (state machine). Undefined on legacy orders pre-backfill. */
579
+ paymentState?: string;
580
+ /** Operational state (state machine). Undefined on legacy orders pre-backfill. */
581
+ fulfillmentState?: string;
582
+ /** Computed display label from paymentState + fulfillmentState matrix. */
583
+ displayState?: string;
467
584
  customer: Partial<CFActiveCustomer | null>;
468
585
  customerNote?: string;
469
586
  summary: CFSummary;
@@ -521,7 +638,7 @@ export interface CFActiveUser extends CFActiveEntity {
521
638
  _id: string;
522
639
  }[];
523
640
  type?: CFUserTypes;
524
- companies?: any;
641
+ companies?: unknown;
525
642
  }
526
643
  export interface CFActiveOutlet extends CFActiveEntity {
527
644
  address: string;
@@ -607,8 +724,8 @@ export interface CFActiveCustomSales {
607
724
  taxTableId?: string;
608
725
  quantity: number;
609
726
  price: number;
610
- discount?: any;
611
- fee?: any;
727
+ discount?: Record<string, unknown>;
728
+ fee?: Record<string, unknown>;
612
729
  }
613
730
  /** Non-revenue cart line (e.g. gift card load) — aligned with Render `NonRevenueItem.externalId` (order line id). */
614
731
  export interface CFNonRevenueItem {
@@ -660,7 +777,7 @@ export interface CFActiveCompany extends CFActiveEntity {
660
777
  id?: string;
661
778
  name?: string;
662
779
  logo?: string;
663
- settings?: any;
780
+ settings?: Record<string, unknown>;
664
781
  }
665
782
  export type CFProjectName = "Render" | "Manage";
666
783
  export interface CFContextRender {
@@ -28,6 +28,107 @@ export var CurrencyCode;
28
28
  CurrencyCode["ILS"] = "ILS";
29
29
  CurrencyCode["TRY"] = "TRY";
30
30
  CurrencyCode["RUB"] = "RUB";
31
+ CurrencyCode["HTG"] = "HTG";
32
+ CurrencyCode["BND"] = "BND";
33
+ CurrencyCode["CRC"] = "CRC";
34
+ CurrencyCode["BDT"] = "BDT";
35
+ CurrencyCode["UAH"] = "UAH";
36
+ CurrencyCode["NGN"] = "NGN";
37
+ CurrencyCode["AFN"] = "AFN";
38
+ CurrencyCode["ALL"] = "ALL";
39
+ CurrencyCode["AMD"] = "AMD";
40
+ CurrencyCode["ANG"] = "ANG";
41
+ CurrencyCode["AOA"] = "AOA";
42
+ CurrencyCode["ARS"] = "ARS";
43
+ CurrencyCode["AWG"] = "AWG";
44
+ CurrencyCode["AZN"] = "AZN";
45
+ CurrencyCode["BAM"] = "BAM";
46
+ CurrencyCode["BBD"] = "BBD";
47
+ CurrencyCode["BGN"] = "BGN";
48
+ CurrencyCode["BMD"] = "BMD";
49
+ CurrencyCode["BOB"] = "BOB";
50
+ CurrencyCode["BSD"] = "BSD";
51
+ CurrencyCode["BTN"] = "BTN";
52
+ CurrencyCode["BWP"] = "BWP";
53
+ CurrencyCode["BYN"] = "BYN";
54
+ CurrencyCode["BZD"] = "BZD";
55
+ CurrencyCode["COP"] = "COP";
56
+ CurrencyCode["CZK"] = "CZK";
57
+ CurrencyCode["DOP"] = "DOP";
58
+ CurrencyCode["DZD"] = "DZD";
59
+ CurrencyCode["EGP"] = "EGP";
60
+ CurrencyCode["ETB"] = "ETB";
61
+ CurrencyCode["FJD"] = "FJD";
62
+ CurrencyCode["GEL"] = "GEL";
63
+ CurrencyCode["GHS"] = "GHS";
64
+ CurrencyCode["GTQ"] = "GTQ";
65
+ CurrencyCode["GYD"] = "GYD";
66
+ CurrencyCode["HNL"] = "HNL";
67
+ CurrencyCode["IRR"] = "IRR";
68
+ CurrencyCode["JMD"] = "JMD";
69
+ CurrencyCode["KES"] = "KES";
70
+ CurrencyCode["KGS"] = "KGS";
71
+ CurrencyCode["KHR"] = "KHR";
72
+ CurrencyCode["KYD"] = "KYD";
73
+ CurrencyCode["KZT"] = "KZT";
74
+ CurrencyCode["LAK"] = "LAK";
75
+ CurrencyCode["LBP"] = "LBP";
76
+ CurrencyCode["LKR"] = "LKR";
77
+ CurrencyCode["MAD"] = "MAD";
78
+ CurrencyCode["MDL"] = "MDL";
79
+ CurrencyCode["MKD"] = "MKD";
80
+ CurrencyCode["MMK"] = "MMK";
81
+ CurrencyCode["MNT"] = "MNT";
82
+ CurrencyCode["MOP"] = "MOP";
83
+ CurrencyCode["MUR"] = "MUR";
84
+ CurrencyCode["MVR"] = "MVR";
85
+ CurrencyCode["MZN"] = "MZN";
86
+ CurrencyCode["NAD"] = "NAD";
87
+ CurrencyCode["NIO"] = "NIO";
88
+ CurrencyCode["NPR"] = "NPR";
89
+ CurrencyCode["PAB"] = "PAB";
90
+ CurrencyCode["PEN"] = "PEN";
91
+ CurrencyCode["PGK"] = "PGK";
92
+ CurrencyCode["PKR"] = "PKR";
93
+ CurrencyCode["QAR"] = "QAR";
94
+ CurrencyCode["RON"] = "RON";
95
+ CurrencyCode["RSD"] = "RSD";
96
+ CurrencyCode["SBD"] = "SBD";
97
+ CurrencyCode["SRD"] = "SRD";
98
+ CurrencyCode["SYP"] = "SYP";
99
+ CurrencyCode["TJS"] = "TJS";
100
+ CurrencyCode["TMT"] = "TMT";
101
+ CurrencyCode["TOP"] = "TOP";
102
+ CurrencyCode["TTD"] = "TTD";
103
+ CurrencyCode["TZS"] = "TZS";
104
+ CurrencyCode["UYU"] = "UYU";
105
+ CurrencyCode["UZS"] = "UZS";
106
+ CurrencyCode["VES"] = "VES";
107
+ CurrencyCode["WST"] = "WST";
108
+ CurrencyCode["XCD"] = "XCD";
109
+ CurrencyCode["YER"] = "YER";
110
+ CurrencyCode["ZMW"] = "ZMW";
111
+ CurrencyCode["CDF"] = "CDF";
112
+ CurrencyCode["CUP"] = "CUP";
113
+ CurrencyCode["ERN"] = "ERN";
114
+ CurrencyCode["FKP"] = "FKP";
115
+ CurrencyCode["GIP"] = "GIP";
116
+ CurrencyCode["GMD"] = "GMD";
117
+ CurrencyCode["KPW"] = "KPW";
118
+ CurrencyCode["LRD"] = "LRD";
119
+ CurrencyCode["LSL"] = "LSL";
120
+ CurrencyCode["MGA"] = "MGA";
121
+ CurrencyCode["MWK"] = "MWK";
122
+ CurrencyCode["SCR"] = "SCR";
123
+ CurrencyCode["SDG"] = "SDG";
124
+ CurrencyCode["SHP"] = "SHP";
125
+ CurrencyCode["SLE"] = "SLE";
126
+ CurrencyCode["SOS"] = "SOS";
127
+ CurrencyCode["SSP"] = "SSP";
128
+ CurrencyCode["STN"] = "STN";
129
+ CurrencyCode["SZL"] = "SZL";
130
+ CurrencyCode["VED"] = "VED";
131
+ CurrencyCode["XCG"] = "XCG";
31
132
  CurrencyCode["JPY"] = "JPY";
32
133
  CurrencyCode["KRW"] = "KRW";
33
134
  CurrencyCode["VND"] = "VND";
@@ -35,6 +136,17 @@ export var CurrencyCode;
35
136
  CurrencyCode["ISK"] = "ISK";
36
137
  CurrencyCode["HUF"] = "HUF";
37
138
  CurrencyCode["TWD"] = "TWD";
139
+ CurrencyCode["GNF"] = "GNF";
140
+ CurrencyCode["BIF"] = "BIF";
141
+ CurrencyCode["DJF"] = "DJF";
142
+ CurrencyCode["KMF"] = "KMF";
143
+ CurrencyCode["PYG"] = "PYG";
144
+ CurrencyCode["RWF"] = "RWF";
145
+ CurrencyCode["UGX"] = "UGX";
146
+ CurrencyCode["VUV"] = "VUV";
147
+ CurrencyCode["XAF"] = "XAF";
148
+ CurrencyCode["XOF"] = "XOF";
149
+ CurrencyCode["XPF"] = "XPF";
38
150
  CurrencyCode["KWD"] = "KWD";
39
151
  CurrencyCode["BHD"] = "BHD";
40
152
  CurrencyCode["OMR"] = "OMR";
@@ -2,17 +2,20 @@ import { MOCK_CART, mockPublishEvent } from "../../demo/database";
2
2
  export const mockAddCartDiscount = async (params) => {
3
3
  console.log("[Mock] addCartDiscount called", params);
4
4
  if (params) {
5
+ // Mirror render: input is raw (50 = 50%, 5 = $5). Store percent as a
6
+ // fraction (0.5) and fixed as minor units (500), like the real handler.
7
+ const minorFactor = 10 ** (MOCK_CART.minorUnits ?? 2);
8
+ const value = params.isPercent ? params.amount / 100 : Math.round(params.amount * minorFactor);
5
9
  MOCK_CART.discount = {
6
- value: params.amount,
10
+ value,
7
11
  isPercent: params.isPercent,
8
12
  label: params.label
9
13
  };
10
- // Simple mock calc (not real logic)
11
14
  if (params.isPercent) {
12
15
  MOCK_CART.total = MOCK_CART.subtotal * (1 - params.amount / 100);
13
16
  }
14
17
  else {
15
- MOCK_CART.total = MOCK_CART.subtotal - params.amount;
18
+ MOCK_CART.total = MOCK_CART.subtotal - value;
16
19
  }
17
20
  MOCK_CART.amountToBeCharged = MOCK_CART.total;
18
21
  MOCK_CART.remainingBalance = MOCK_CART.total;
@@ -4,18 +4,18 @@ export const mockAddCartFee = async (params) => {
4
4
  if (params) {
5
5
  if (!MOCK_CART.customFee)
6
6
  MOCK_CART.customFee = [];
7
+ // Mirror render: input is raw (50 = 50%, 5 = $5). Store percent as a
8
+ // fraction (0.5) and fixed as minor units (500), like the real handler.
9
+ const minorFactor = 10 ** (MOCK_CART.minorUnits ?? 2);
10
+ const storedAmount = params.isPercent ? params.amount / 100 : Math.round(params.amount * minorFactor);
7
11
  MOCK_CART.customFee.push({
8
12
  label: params.label || "Fee",
9
- amount: params.amount,
13
+ amount: storedAmount,
10
14
  isPercent: params.isPercent || false,
11
15
  applyTaxes: params.applyTaxes || false,
12
16
  taxTableId: params.taxTableId
13
17
  });
14
- // Simple calc
15
- let feeAmount = params.amount;
16
- if (params.isPercent) {
17
- feeAmount = MOCK_CART.subtotal * (params.amount / 100);
18
- }
18
+ const feeAmount = params.isPercent ? MOCK_CART.subtotal * (params.amount / 100) : storedAmount;
19
19
  MOCK_CART.total += feeAmount;
20
20
  MOCK_CART.amountToBeCharged = MOCK_CART.total;
21
21
  MOCK_CART.remainingBalance = MOCK_CART.total;
@@ -1,11 +1,14 @@
1
- import { MOCK_CART } from "../../demo/database";
1
+ import { MOCK_CART, mockPublishEvent } from "../../demo/database";
2
2
  export const mockAddCustomSale = async (params) => {
3
3
  console.log("[Mock] addCustomSale called", params);
4
4
  if (!params)
5
5
  throw new Error("Params required");
6
6
  // Simple mock ID generation
7
7
  const mockId = 'sale_' + Math.random().toString(36).substr(2, 9);
8
- const price = Number(params.price);
8
+ // Mirror render: the flow sends raw dollars ($4); render does toMinorUnits.
9
+ // MOCK_CART tracks minor units, so convert here too.
10
+ const minorFactor = 10 ** (MOCK_CART.minorUnits ?? 2);
11
+ const price = Math.round(Number(params.price) * minorFactor);
9
12
  const quantity = 1; // Default to 1 for custom sale usually
10
13
  const customSale = {
11
14
  id: mockId,
@@ -24,6 +27,8 @@ export const mockAddCustomSale = async (params) => {
24
27
  MOCK_CART.total += price * quantity;
25
28
  MOCK_CART.amountToBeCharged = MOCK_CART.total;
26
29
  MOCK_CART.remainingBalance = MOCK_CART.total;
30
+ // Publish custom-sale-added event so cart subscribers refresh
31
+ mockPublishEvent('cart', 'custom-sale-added', { customSale });
27
32
  return {
28
33
  success: true,
29
34
  customSaleId: mockId,
@@ -1,4 +1,4 @@
1
- import { MOCK_CART } from "../../demo/database";
1
+ import { MOCK_CART, mockPublishEvent } from "../../demo/database";
2
2
  export const mockAddOrderNote = async (params) => {
3
3
  console.log("[Mock] addOrderNote called", params);
4
4
  // In Render, AddOrderNote usually adds a note to the active cart if it's not checked out yet.
@@ -9,6 +9,8 @@ export const mockAddOrderNote = async (params) => {
9
9
  else {
10
10
  MOCK_CART.orderNotes = params.note;
11
11
  }
12
+ // Publish order-note-added event so cart subscribers refresh.
13
+ mockPublishEvent("cart", "order-note-added", { note: params.note });
12
14
  }
13
15
  return {
14
16
  success: true,
@@ -1,4 +1,4 @@
1
- import { MOCK_CART } from "../../demo/database";
1
+ import { MOCK_CART, mockPublishEvent } from "../../demo/database";
2
2
  export const mockAddProductDiscount = async (params) => {
3
3
  console.log("[Mock] addProductDiscount called", params);
4
4
  if (params && (params.amount > 0 || params.amount < 0)) { // Allow 0 to clear discount if logic permits
@@ -10,13 +10,20 @@ export const mockAddProductDiscount = async (params) => {
10
10
  item = MOCK_CART.products[MOCK_CART.products.length - 1];
11
11
  }
12
12
  if (item) {
13
+ // Mirror render's product handler: it stores `amount` AS-IS — the flow
14
+ // already sends a fraction (0.5 = 50%) for percent and minor units (500 = $5)
15
+ // for fixed. tax.ts then uses value as the fraction / minor amount directly.
13
16
  item.discount = {
14
17
  value: params.amount,
15
18
  isPercent: params.isPercent || false,
16
19
  label: params.label
17
20
  };
18
- // Recalculate cart totals (simplified)
19
- // Ideally, this should trigger a full recalculation function
21
+ const linePrice = (item.price || 0) * (item.quantity || 1);
22
+ const discountMinor = params.isPercent ? Math.round(linePrice * params.amount) : params.amount;
23
+ MOCK_CART.total = Math.max(0, MOCK_CART.total - discountMinor);
24
+ MOCK_CART.amountToBeCharged = MOCK_CART.total;
25
+ MOCK_CART.remainingBalance = MOCK_CART.total;
26
+ mockPublishEvent("cart", "product-discount-added", { internalId: params.internalId });
20
27
  }
21
28
  }
22
29
  return {
@@ -1,4 +1,4 @@
1
- import { MOCK_CART } from "../../demo/database";
1
+ import { MOCK_CART, mockPublishEvent } from "../../demo/database";
2
2
  export const mockAddProductFee = async (params) => {
3
3
  console.log("[Mock] addProductFee called", params);
4
4
  if (params) {
@@ -10,12 +10,21 @@ export const mockAddProductFee = async (params) => {
10
10
  item = MOCK_CART.products[MOCK_CART.products.length - 1];
11
11
  }
12
12
  if (item) {
13
+ // Mirror render's product handler: it stores `amount` AS-IS — the flow
14
+ // already sends a fraction (0.5 = 50%) for percent and minor units (500 = $5)
15
+ // for fixed. tax.ts then uses amount as the fraction / minor amount directly.
13
16
  item.fee = {
14
17
  label: params.label || "Fee",
15
18
  amount: params.amount,
16
19
  isPercent: params.isPercent || false,
17
20
  applyTaxes: params.applyTaxes || false
18
21
  };
22
+ const linePrice = (item.price || 0) * (item.quantity || 1);
23
+ const feeMinor = params.isPercent ? Math.round(linePrice * params.amount) : params.amount;
24
+ MOCK_CART.total += feeMinor;
25
+ MOCK_CART.amountToBeCharged = MOCK_CART.total;
26
+ MOCK_CART.remainingBalance = MOCK_CART.total;
27
+ mockPublishEvent("cart", "product-fee-added", { internalId: params.internalId });
19
28
  }
20
29
  }
21
30
  return {
@@ -0,0 +1,2 @@
1
+ import type { ApplyTransition } from "./types";
2
+ export declare const applyTransition: ApplyTransition;
@@ -0,0 +1,4 @@
1
+ import { commandFrameClient } from "../../client";
2
+ export const applyTransition = async (params) => {
3
+ return await commandFrameClient.call("applyTransition", params);
4
+ };
@@ -0,0 +1,6 @@
1
+ import type { ApplyTransitionParams, ApplyTransitionResponse } from "./types";
2
+ /**
3
+ * Mock implementation: applies all transitions except a few known-invalid ones
4
+ * so the demo app can show both successful and blocked responses.
5
+ */
6
+ export declare const applyTransitionMock: (params: ApplyTransitionParams) => Promise<ApplyTransitionResponse>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Mock implementation: applies all transitions except a few known-invalid ones
3
+ * so the demo app can show both successful and blocked responses.
4
+ */
5
+ export const applyTransitionMock = (params) => {
6
+ const { to } = params;
7
+ if (to.payment === "refunded" && to.fulfillment === "draft") {
8
+ return Promise.resolve({
9
+ result: {
10
+ allowed: false,
11
+ blockedBy: "financial_invariant",
12
+ guard: "no-refund-in-draft",
13
+ reason: "Cannot refund an order that is still in draft"
14
+ }
15
+ });
16
+ }
17
+ if (to.payment === "paid" && to.fulfillment === "cancelled") {
18
+ return Promise.resolve({
19
+ result: {
20
+ allowed: false,
21
+ blockedBy: "cross_axis_rule",
22
+ guard: "no-pay-cancelled",
23
+ reason: "Cannot mark a cancelled order as paid"
24
+ }
25
+ });
26
+ }
27
+ return Promise.resolve({
28
+ result: { allowed: true },
29
+ from: { payment: "unpaid", fulfillment: "draft" },
30
+ to,
31
+ displayState: `${to.payment} / ${to.fulfillment}`
32
+ });
33
+ };
@@ -0,0 +1,17 @@
1
+ import type { CFStatePair, CFTransitionResult } from "../../common-types/order-state";
2
+ export interface ApplyTransitionParams {
3
+ /** Order to transition. */
4
+ orderId: string;
5
+ /** Target state pair. */
6
+ to: CFStatePair;
7
+ }
8
+ export interface ApplyTransitionResponse {
9
+ result: CFTransitionResult;
10
+ /** Previous state — present only when the transition was applied. */
11
+ from?: CFStatePair;
12
+ /** New state — present only when the transition was applied. */
13
+ to?: CFStatePair;
14
+ /** Computed display label — present only when the transition was applied. */
15
+ displayState?: string;
16
+ }
17
+ export type ApplyTransition = (params: ApplyTransitionParams) => Promise<ApplyTransitionResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { CanTransition } from "./types";
2
+ export declare const canTransition: CanTransition;