@voltro/plugin-economy 0.0.0-stage → 0.87.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 (177) hide show
  1. package/CHANGELOG.md +24329 -0
  2. package/LICENSE +61 -0
  3. package/README.md +2719 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +9189 -0
  6. package/dist/amount.js +21 -0
  7. package/dist/appleIap.server.js +263 -0
  8. package/dist/appleIapNotifications.server.js +163 -0
  9. package/dist/appleIapTrust.server.js +31 -0
  10. package/dist/bundleValue.server.js +113 -0
  11. package/dist/canonicalDataJson.js +11 -0
  12. package/dist/capture.js +54 -0
  13. package/dist/codePort.fixture.js +124 -0
  14. package/dist/codeStore.server.js +440 -0
  15. package/dist/codeTables.entity.js +44 -0
  16. package/dist/codes.d.ts +150 -0
  17. package/dist/codes.js +83 -0
  18. package/dist/components.d.ts +397 -0
  19. package/dist/components.js +284 -0
  20. package/dist/consistency.server.js +116 -0
  21. package/dist/containerStore.server.js +688 -0
  22. package/dist/containerStore.testFixtures.js +76 -0
  23. package/dist/containerTables.entity.js +46 -0
  24. package/dist/containers.d.ts +311 -0
  25. package/dist/containers.fixture.js +129 -0
  26. package/dist/containers.js +215 -0
  27. package/dist/containers.server.js +40 -0
  28. package/dist/containersPort.fixture.js +75 -0
  29. package/dist/currency.js +33 -0
  30. package/dist/declarationFixtures.js +62 -0
  31. package/dist/economy-app/events/economy.refundReversed.event.ts +1 -0
  32. package/dist/economy-app/events/economy.refunded.event.ts +1 -0
  33. package/dist/economyPort.fixture.js +125 -0
  34. package/dist/errors.d.ts +14 -0
  35. package/dist/errors.js +22 -0
  36. package/dist/events.d.ts +46 -0
  37. package/dist/events.js +1 -0
  38. package/dist/googleIap.server.js +392 -0
  39. package/dist/googleIapNotifications.server.js +131 -0
  40. package/dist/googleIapSubscription.server.js +184 -0
  41. package/dist/iap.d.ts +309 -0
  42. package/dist/iap.js +304 -0
  43. package/dist/iap.testFixtures.js +145 -0
  44. package/dist/iapAccountTables.entity.js +40 -0
  45. package/dist/iapAccounts.server.js +201 -0
  46. package/dist/iapBinding.server.js +524 -0
  47. package/dist/iapCheckout.server.js +98 -0
  48. package/dist/iapCompletion.server.js +56 -0
  49. package/dist/iapCurrentState.server.js +108 -0
  50. package/dist/iapCurrentState.testFixtures.js +23 -0
  51. package/dist/iapCurrentStatePort.fixture.js +64 -0
  52. package/dist/iapEntitlements.d.ts +79 -0
  53. package/dist/iapEntitlements.js +58 -0
  54. package/dist/iapEntitlements.server.js +49 -0
  55. package/dist/iapEntitlementsBinding.server.js +106 -0
  56. package/dist/iapEntitlementsPort.fixture.js +81 -0
  57. package/dist/iapInstalledEntitlements.testFixtures.js +76 -0
  58. package/dist/iapInstalledNotifications.testFixtures.js +94 -0
  59. package/dist/iapInventoryRefunds.server.js +262 -0
  60. package/dist/iapNotificationCustodyPort.fixture.js +68 -0
  61. package/dist/iapNotificationPort.fixture.js +74 -0
  62. package/dist/iapNotificationProcessor.server.js +135 -0
  63. package/dist/iapNotificationProcessor.testFixtures.js +64 -0
  64. package/dist/iapNotificationProcessorPort.fixture.js +56 -0
  65. package/dist/iapNotificationSchedule.server.js +70 -0
  66. package/dist/iapNotificationStore.server.js +353 -0
  67. package/dist/iapNotificationStore.testFixtures.js +32 -0
  68. package/dist/iapNotificationTables.entity.js +49 -0
  69. package/dist/iapNotificationTarget.server.js +37 -0
  70. package/dist/iapNotificationTarget.testFixtures.js +30 -0
  71. package/dist/iapNotifications.d.ts +644 -0
  72. package/dist/iapNotifications.js +6 -0
  73. package/dist/iapNotifications.server.js +96 -0
  74. package/dist/iapNotificationsBinding.server.js +233 -0
  75. package/dist/iapNotificationsSystemPort.fixture.js +51 -0
  76. package/dist/iapPlugin.testFixtures.js +60 -0
  77. package/dist/iapPort.fixture.js +75 -0
  78. package/dist/iapProviderCapture.server.js +18 -0
  79. package/dist/iapRecovery.d.ts +146 -0
  80. package/dist/iapRecovery.js +90 -0
  81. package/dist/iapRefundEventDelivery.server.js +83 -0
  82. package/dist/iapRefundEvents.js +45 -0
  83. package/dist/iapRefundEventsPort.fixture.js +60 -0
  84. package/dist/iapRefundPort.fixture.js +55 -0
  85. package/dist/iapRefundTables.entity.js +56 -0
  86. package/dist/iapRefunds.d.ts +755 -0
  87. package/dist/iapRefunds.js +6 -0
  88. package/dist/iapRefunds.server.js +554 -0
  89. package/dist/iapRefunds.testFixtures.js +65 -0
  90. package/dist/iapSpendAdmission.server.js +99 -0
  91. package/dist/iapStore.server.js +741 -0
  92. package/dist/iapStore.testFixtures.js +128 -0
  93. package/dist/iapTables.entity.js +81 -0
  94. package/dist/iapVerification.server.js +121 -0
  95. package/dist/index.d.ts +2984 -0
  96. package/dist/index.js +15 -0
  97. package/dist/intentionRecovery.js +134 -0
  98. package/dist/ledger.js +78 -0
  99. package/dist/loyalty.d.ts +274 -0
  100. package/dist/loyalty.fixture.js +93 -0
  101. package/dist/loyalty.js +312 -0
  102. package/dist/loyaltyBinding.server.js +204 -0
  103. package/dist/loyaltyPort.fixture.js +87 -0
  104. package/dist/loyaltyShopSource.server.js +91 -0
  105. package/dist/loyaltyStore.server.js +553 -0
  106. package/dist/loyaltyStore.testFixtures.js +83 -0
  107. package/dist/loyaltyTables.entity.js +50 -0
  108. package/dist/offerMerchandising.fixture.js +115 -0
  109. package/dist/offerMerchandising.js +283 -0
  110. package/dist/offerPolicies.d.ts +441 -0
  111. package/dist/offerPolicies.fixture.js +54 -0
  112. package/dist/offerPolicies.js +268 -0
  113. package/dist/piggyBanks.d.ts +272 -0
  114. package/dist/piggyBanks.fixture.js +71 -0
  115. package/dist/piggyBanks.js +201 -0
  116. package/dist/piggyBinding.server.js +205 -0
  117. package/dist/piggyPort.fixture.js +73 -0
  118. package/dist/piggyStore.server.js +611 -0
  119. package/dist/piggyStore.testFixtures.js +98 -0
  120. package/dist/piggyTables.entity.js +41 -0
  121. package/dist/plugin.js +1048 -0
  122. package/dist/port.js +13 -0
  123. package/dist/price.d.ts +99 -0
  124. package/dist/price.js +144 -0
  125. package/dist/purchaseRecovery.js +56 -0
  126. package/dist/reports.server.js +115 -0
  127. package/dist/rpc.d.ts +3201 -0
  128. package/dist/rpc.js +1201 -0
  129. package/dist/sanctionsTradeAuthority.server.js +80 -0
  130. package/dist/server.d.ts +3856 -0
  131. package/dist/server.js +43 -0
  132. package/dist/shop.d.ts +279 -0
  133. package/dist/shop.js +196 -0
  134. package/dist/shop.testFixtures.js +114 -0
  135. package/dist/shopPort.fixture.js +72 -0
  136. package/dist/shopPresentation.js +68 -0
  137. package/dist/shopStore.server.js +624 -0
  138. package/dist/shopTables.entity.js +63 -0
  139. package/dist/shopUiCopy.js +57 -0
  140. package/dist/spendLimits.d.ts +140 -0
  141. package/dist/spendLimits.fixture.js +53 -0
  142. package/dist/spendLimits.js +155 -0
  143. package/dist/spendLimitsPort.fixture.js +120 -0
  144. package/dist/subscriptionBinding.server.js +211 -0
  145. package/dist/subscriptionStore.server.js +643 -0
  146. package/dist/subscriptionStore.testFixtures.js +72 -0
  147. package/dist/subscriptionTables.entity.js +37 -0
  148. package/dist/subscriptions.d.ts +394 -0
  149. package/dist/subscriptions.fixture.js +97 -0
  150. package/dist/subscriptions.js +213 -0
  151. package/dist/subscriptionsPort.fixture.js +76 -0
  152. package/dist/systemFixtures.js +89 -0
  153. package/dist/tables.entity.js +83 -0
  154. package/dist/testing.d.ts +4615 -0
  155. package/dist/testing.js +29 -0
  156. package/dist/tradeAuthority.server.js +172 -0
  157. package/dist/tradeBinding.server.js +201 -0
  158. package/dist/tradeComponents.js +342 -0
  159. package/dist/tradeEscrow.server.js +232 -0
  160. package/dist/tradeEscrow.testFixtures.js +133 -0
  161. package/dist/tradeExpiry.server.js +43 -0
  162. package/dist/tradeRecovery.js +48 -0
  163. package/dist/tradeStore.server.js +750 -0
  164. package/dist/tradeStore.testFixtures.js +73 -0
  165. package/dist/tradeTables.entity.js +66 -0
  166. package/dist/tradeUiCopy.js +79 -0
  167. package/dist/trades.d.ts +246 -0
  168. package/dist/trades.fixture.js +103 -0
  169. package/dist/trades.js +289 -0
  170. package/dist/tradesPort.fixture.js +94 -0
  171. package/dist/walletEscrow.js +106 -0
  172. package/dist/walletEscrow.server.js +376 -0
  173. package/dist/walletKeys.server.js +5 -0
  174. package/dist/walletStore.js +571 -0
  175. package/dist/web.d.ts +2257 -0
  176. package/dist/web.js +9 -0
  177. package/package.json +161 -4
@@ -0,0 +1,342 @@
1
+ import { dataList as e, dataObject as t, identifier as n } from "./capture.js";
2
+ import { captureTradeProposeIntention as r, captureTradeReceipt as i, captureTradeView as a, tradeAcceptIntent as o } from "./trades.js";
3
+ import { captureTradeIntention as s } from "./tradeRecovery.js";
4
+ import { tradeUiCopy as c } from "./tradeUiCopy.js";
5
+ import { useEffect as l, useId as u, useRef as d } from "react";
6
+ import { Button as f, Dialog as p, DialogDescription as m, DialogFooter as h, DialogHeader as g, DialogTitle as _ } from "@voltro/ui-shadcn";
7
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
8
+ //#region src/tradeComponents.tsx
9
+ var b = (e) => e.copy ?? c[e.locale ?? "en"], x = (e) => Number.isSafeInteger(e) && e >= 0 && e <= 864e13, S = (e, t, n) => x(n) && e.state === "proposed" && n >= e.createdAt && n < e.expiresAt && t !== e.proposerId && (e.toId === null || e.toId === t), C = ({ leg: e, taxes: t, copy: n, ...r }) => /* @__PURE__ */ y("ul", {
10
+ className: "space-y-2 text-sm leading-relaxed",
11
+ children: [
12
+ !e.items.length && !e.currencies.length ? /* @__PURE__ */ v("li", {
13
+ className: "text-muted-foreground",
14
+ children: n.emptyLeg
15
+ }) : null,
16
+ e.items.map((e) => /* @__PURE__ */ y("li", {
17
+ className: "break-words",
18
+ children: [
19
+ /* @__PURE__ */ v("span", {
20
+ className: "tabular-nums",
21
+ children: e.qty
22
+ }),
23
+ " × ",
24
+ r.itemLabel?.(e.instanceId) ?? e.instanceId
25
+ ]
26
+ }, e.instanceId)),
27
+ e.currencies.map((e) => {
28
+ let i = t.find((t) => t.currency === e.currency);
29
+ return /* @__PURE__ */ v("li", {
30
+ className: "break-words tabular-nums",
31
+ children: i ? n.payment(i.gross, i.net, i.tax, r.currencyLabel?.(e.currency) ?? e.currency) : `${e.amount} ${r.currencyLabel?.(e.currency) ?? e.currency}`
32
+ }, e.currency);
33
+ })
34
+ ]
35
+ }), w = (e) => {
36
+ let t = b(e), n;
37
+ try {
38
+ n = a(e.view);
39
+ } catch {
40
+ return /* @__PURE__ */ v("p", {
41
+ role: "alert",
42
+ children: t.invalid
43
+ });
44
+ }
45
+ return /* @__PURE__ */ y("div", {
46
+ className: "grid min-w-0 gap-6 sm:grid-cols-2",
47
+ children: [/* @__PURE__ */ y("section", {
48
+ className: "min-w-0 space-y-3",
49
+ children: [/* @__PURE__ */ v("h3", {
50
+ className: "font-semibold",
51
+ children: t.offered
52
+ }), /* @__PURE__ */ v(C, {
53
+ leg: n.offered,
54
+ taxes: n.taxes.filter((e) => e.leg === "offered"),
55
+ copy: t,
56
+ itemLabel: e.itemLabel,
57
+ currencyLabel: e.currencyLabel
58
+ })]
59
+ }), /* @__PURE__ */ y("section", {
60
+ className: "min-w-0 space-y-3",
61
+ children: [/* @__PURE__ */ v("h3", {
62
+ className: "font-semibold",
63
+ children: t.requested
64
+ }), /* @__PURE__ */ v(C, {
65
+ leg: n.requested,
66
+ taxes: n.taxes.filter((e) => e.leg === "requested"),
67
+ copy: t,
68
+ itemLabel: e.itemLabel,
69
+ currencyLabel: e.currencyLabel
70
+ })]
71
+ })]
72
+ });
73
+ }, T = (t) => {
74
+ let r = b(t), i = u(), o, s = !1, c = "";
75
+ try {
76
+ if (c = n(t.actorId), !x(t.at)) throw Error("Invalid trade presentation time");
77
+ o = t.source.data === void 0 ? void 0 : e(t.source.data, 1e3).map(a), s = o !== void 0 && (new Set(o.map((e) => e.tradeId)).size !== o.length || o.some((e) => c !== e.proposerId && c !== e.toId && c !== e.accepterId));
78
+ } catch {
79
+ s = !0;
80
+ }
81
+ return /* @__PURE__ */ y("section", {
82
+ "aria-labelledby": i,
83
+ className: "min-w-0 space-y-5",
84
+ children: [/* @__PURE__ */ v("h2", {
85
+ id: i,
86
+ className: "text-2xl font-semibold",
87
+ children: r.title
88
+ }), s || t.source.error !== void 0 ? /* @__PURE__ */ v("p", {
89
+ role: "alert",
90
+ children: r.unavailable
91
+ }) : t.source.loading || o === void 0 ? /* @__PURE__ */ v("p", {
92
+ role: "status",
93
+ children: r.loading
94
+ }) : o.length === 0 ? /* @__PURE__ */ v("p", { children: r.empty }) : /* @__PURE__ */ v("ul", {
95
+ className: "divide-y divide-border",
96
+ children: o.map((e) => {
97
+ let n = S(e, c, t.at) && !t.busy, i = e.state === "proposed" && c === e.proposerId && !t.busy;
98
+ return /* @__PURE__ */ y("li", {
99
+ className: "min-w-0 space-y-5 py-6",
100
+ children: [
101
+ /* @__PURE__ */ y("div", {
102
+ className: "flex flex-wrap items-baseline justify-between gap-3",
103
+ children: [/* @__PURE__ */ v("p", {
104
+ className: "font-medium",
105
+ children: r.status[e.state]
106
+ }), /* @__PURE__ */ v("p", {
107
+ className: "text-sm text-muted-foreground",
108
+ children: /* @__PURE__ */ v("time", {
109
+ dateTime: new Date(e.expiresAt).toISOString(),
110
+ children: r.expires(new Date(e.expiresAt).toLocaleString(t.locale ?? "en"))
111
+ })
112
+ })]
113
+ }),
114
+ /* @__PURE__ */ v(w, {
115
+ view: e,
116
+ locale: t.locale,
117
+ copy: r,
118
+ itemLabel: t.itemLabel,
119
+ currencyLabel: t.currencyLabel
120
+ }),
121
+ e.state === "proposed" && t.at >= e.expiresAt ? /* @__PURE__ */ v("p", {
122
+ className: "text-sm",
123
+ children: r.expired
124
+ }) : null,
125
+ /* @__PURE__ */ y("div", {
126
+ className: "flex flex-wrap gap-3",
127
+ children: [c !== e.proposerId && (e.toId === null || c === e.toId) ? /* @__PURE__ */ v(f, {
128
+ type: "button",
129
+ "aria-disabled": !n,
130
+ className: "h-auto min-h-11 whitespace-normal",
131
+ onClick: () => {
132
+ n && t.onAccept(e);
133
+ },
134
+ children: r.accept
135
+ }) : null, c === e.proposerId ? /* @__PURE__ */ v(f, {
136
+ type: "button",
137
+ variant: "outline",
138
+ "aria-disabled": !i,
139
+ className: "h-auto min-h-11 whitespace-normal",
140
+ onClick: () => {
141
+ i && t.onCancel(e);
142
+ },
143
+ children: r.cancel
144
+ }) : null]
145
+ })
146
+ ]
147
+ }, e.tradeId);
148
+ })
149
+ })]
150
+ });
151
+ }, E = (e) => {
152
+ let t = b(e), r = d(null), s = u(), c = u();
153
+ l(() => {
154
+ let t = r.current;
155
+ t && (e.open && !t.open ? t.showModal() : !e.open && t.open && t.close());
156
+ }, [e.open]);
157
+ let x, C, T;
158
+ try {
159
+ let t = a(e.view), r = o(e.intention);
160
+ r.tradeId === t.tradeId && r.tradeDigest === t.tradeDigest && n(e.actorId) !== t.proposerId && (t.toId === null || t.toId === e.actorId) && (x = t, C = r);
161
+ } catch {
162
+ x = void 0;
163
+ }
164
+ if (e.receipt !== void 0) try {
165
+ let t = i(e.receipt);
166
+ C && t.requestId === C.requestId && t.trade.tradeId === C.tradeId && t.trade.tradeDigest === C.tradeDigest && t.trade.state === "accepted" && t.trade.accepterId === e.actorId && x && t.trade.proposerId === x.proposerId && t.trade.toId === x.toId && t.trade.createdAt === x.createdAt && t.trade.expiresAt === x.expiresAt && t.trade.rulesVersion === x.rulesVersion && JSON.stringify(t.trade.offered) === JSON.stringify(x.offered) && JSON.stringify(t.trade.requested) === JSON.stringify(x.requested) && JSON.stringify(t.trade.taxes) === JSON.stringify(x.taxes) && (T = t);
167
+ } catch {
168
+ T = void 0;
169
+ }
170
+ let E = x !== void 0 && C !== void 0 && S(x, e.actorId, e.at) && !e.busy && e.error === void 0 && e.receipt === void 0;
171
+ return /* @__PURE__ */ y(p, {
172
+ ref: r,
173
+ "aria-labelledby": s,
174
+ "aria-describedby": c,
175
+ className: "max-h-[calc(100dvh-2rem)] max-w-[min(40rem,calc(100vw-2rem))] overflow-y-auto motion-reduce:animate-none",
176
+ onCancel: (t) => {
177
+ t.preventDefault(), e.onClose();
178
+ },
179
+ children: [
180
+ /* @__PURE__ */ y(g, { children: [/* @__PURE__ */ v(_, {
181
+ id: s,
182
+ children: t.confirmation
183
+ }), /* @__PURE__ */ v(m, {
184
+ id: c,
185
+ children: t.confirmationHelp
186
+ })] }),
187
+ x ? /* @__PURE__ */ v(w, {
188
+ view: x,
189
+ locale: e.locale,
190
+ copy: t,
191
+ itemLabel: e.itemLabel,
192
+ currencyLabel: e.currencyLabel
193
+ }) : /* @__PURE__ */ v("p", {
194
+ role: "alert",
195
+ children: t.invalid
196
+ }),
197
+ e.busy ? /* @__PURE__ */ v("p", {
198
+ role: "status",
199
+ className: "mt-4 text-sm",
200
+ children: t.sending
201
+ }) : null,
202
+ e.error === void 0 ? null : /* @__PURE__ */ v("p", {
203
+ role: "alert",
204
+ className: "mt-4 text-sm",
205
+ children: t.uncertain
206
+ }),
207
+ T ? /* @__PURE__ */ v("p", {
208
+ role: "status",
209
+ className: "mt-4 font-medium",
210
+ children: t.complete
211
+ }) : e.receipt === void 0 ? null : /* @__PURE__ */ v("p", {
212
+ role: "alert",
213
+ className: "mt-4",
214
+ children: t.invalid
215
+ }),
216
+ /* @__PURE__ */ y(h, { children: [/* @__PURE__ */ v(f, {
217
+ type: "button",
218
+ variant: "outline",
219
+ className: "h-auto min-h-11 whitespace-normal",
220
+ onClick: e.onClose,
221
+ children: t.close
222
+ }), /* @__PURE__ */ v(f, {
223
+ type: "button",
224
+ "aria-disabled": !E,
225
+ className: "h-auto min-h-11 whitespace-normal",
226
+ onClick: () => {
227
+ E && C && e.onConfirm(C);
228
+ },
229
+ children: t.confirm
230
+ })] })
231
+ ]
232
+ });
233
+ }, D = (e) => {
234
+ let i = b(e);
235
+ if (e.reference === void 0 || e.scope === void 0) return null;
236
+ let a;
237
+ try {
238
+ let r = t(e.reference, [
239
+ "version",
240
+ "scope",
241
+ "request"
242
+ ]);
243
+ if (r.scope !== n(e.scope)) return null;
244
+ if (r.version !== 1) throw Error("Invalid trade recovery version");
245
+ a = {
246
+ version: 1,
247
+ scope: e.scope,
248
+ request: s(r.request)
249
+ };
250
+ } catch {
251
+ return /* @__PURE__ */ v("p", {
252
+ role: "alert",
253
+ children: i.invalid
254
+ });
255
+ }
256
+ let o = a.request, c = o.kind === "propose" ? r(o.input) : void 0;
257
+ return /* @__PURE__ */ y("section", {
258
+ "aria-label": i.recovery,
259
+ className: "min-w-0 space-y-4 border-y border-border py-5",
260
+ children: [
261
+ /* @__PURE__ */ v("h2", {
262
+ className: "text-lg font-semibold",
263
+ children: i.recovery
264
+ }),
265
+ /* @__PURE__ */ v("p", {
266
+ role: "status",
267
+ className: "max-w-prose text-sm leading-relaxed",
268
+ children: e.busy ? i.sending : i.uncertain
269
+ }),
270
+ /* @__PURE__ */ v("p", {
271
+ className: "font-medium",
272
+ children: i.operation[o.kind]
273
+ }),
274
+ c ? /* @__PURE__ */ y("div", {
275
+ className: "grid gap-6 sm:grid-cols-2",
276
+ children: [/* @__PURE__ */ y("section", {
277
+ className: "min-w-0 space-y-3",
278
+ children: [/* @__PURE__ */ v("h3", {
279
+ className: "font-semibold",
280
+ children: i.offered
281
+ }), /* @__PURE__ */ v(C, {
282
+ leg: c.offered,
283
+ taxes: [],
284
+ copy: i,
285
+ itemLabel: e.itemLabel,
286
+ currencyLabel: e.currencyLabel
287
+ })]
288
+ }), /* @__PURE__ */ y("section", {
289
+ className: "min-w-0 space-y-3",
290
+ children: [/* @__PURE__ */ v("h3", {
291
+ className: "font-semibold",
292
+ children: i.requested
293
+ }), /* @__PURE__ */ v(C, {
294
+ leg: c.requested,
295
+ taxes: [],
296
+ copy: i,
297
+ itemLabel: e.itemLabel,
298
+ currencyLabel: e.currencyLabel
299
+ })]
300
+ })]
301
+ }) : null,
302
+ /* @__PURE__ */ y("details", {
303
+ className: "text-sm",
304
+ children: [/* @__PURE__ */ v("summary", {
305
+ className: "cursor-pointer",
306
+ children: i.reference
307
+ }), /* @__PURE__ */ v("p", {
308
+ className: "mt-2 break-all font-mono",
309
+ children: o.input.requestId
310
+ })]
311
+ }),
312
+ e.error === void 0 ? null : /* @__PURE__ */ v("p", {
313
+ role: "alert",
314
+ className: "max-w-prose text-sm",
315
+ children: i.uncertain
316
+ }),
317
+ /* @__PURE__ */ y("div", {
318
+ className: "flex flex-wrap gap-3",
319
+ children: [/* @__PURE__ */ v(f, {
320
+ type: "button",
321
+ "aria-disabled": e.busy,
322
+ className: "h-auto min-h-11 whitespace-normal",
323
+ onClick: () => {
324
+ e.busy || e.onRetry(o);
325
+ },
326
+ children: i.retry
327
+ }), e.onCheckReceipt ? /* @__PURE__ */ v(f, {
328
+ type: "button",
329
+ variant: "outline",
330
+ "aria-disabled": e.busy,
331
+ className: "h-auto min-h-11 whitespace-normal",
332
+ onClick: () => {
333
+ e.busy || e.onCheckReceipt?.(o.input.requestId);
334
+ },
335
+ children: i.checkReceipt
336
+ }) : null]
337
+ })
338
+ ]
339
+ });
340
+ };
341
+ //#endregion
342
+ export { E as TradeAcceptDialog, D as TradeIntentionRecovery, T as TradeList, w as TradeTerms, c as tradeUiCopy };
@@ -0,0 +1,232 @@
1
+ import { EconomyError as e, economyError as t } from "./errors.js";
2
+ import { captureBoundMethods as n, dataList as r, dataObject as i, identifier as a } from "./capture.js";
3
+ import { captureCurrencies as o } from "./currency.js";
4
+ import { captureTradeLeg as s, defaultTradeTaxPolicy as c, defineTradeRules as l, resolveTradeTax as u } from "./trades.js";
5
+ import { Effect as d, Result as f } from "effect";
6
+ import { prepareSqlMutationGroup as p } from "@voltro/database/sql";
7
+ import { InventoryError as m } from "@voltro/plugin-inventory/errors";
8
+ //#region src/tradeEscrow.server.ts
9
+ var h = (n) => n instanceof e ? n : n instanceof m && [
10
+ "invalid_input",
11
+ "invalid_record",
12
+ "not_found",
13
+ "erased",
14
+ "forbidden",
15
+ "conflict",
16
+ "limit_exceeded"
17
+ ].includes(n.code) ? t(n.code) : t("unavailable"), g = async (e) => {
18
+ let t = await d.runPromise(d.result(e));
19
+ if (f.isFailure(t)) throw t.failure;
20
+ return t.success;
21
+ }, _ = (e) => d.tryPromise({
22
+ try: e,
23
+ catch: h
24
+ }), v = (e) => {
25
+ try {
26
+ return e();
27
+ } catch (e) {
28
+ return d.fail(h(e));
29
+ }
30
+ }, y = (e) => Object.freeze({
31
+ kind: "wallet",
32
+ ownerKind: "player",
33
+ ownerId: e
34
+ }), b = (e) => Object.freeze({
35
+ ownerKind: "player",
36
+ ownerId: e
37
+ }), x = (e, d) => {
38
+ let f = i(d, [
39
+ "currencies",
40
+ "rules",
41
+ "taxPolicy",
42
+ "economy",
43
+ "inventory",
44
+ "allowedServices"
45
+ ]), m = o(f.currencies), h = l(f.rules), x = f.taxPolicy ?? c;
46
+ if (typeof x != "function") throw t("invalid_input");
47
+ let S = n(f.economy, [
48
+ "prepareEscrowReserve",
49
+ "prepareEscrowRelease",
50
+ "prepareEscrowTaxSettle",
51
+ "prepareEscrowReserveTaxSettle",
52
+ "escrow"
53
+ ]), C = f.inventory === void 0 ? void 0 : n(f.inventory, [
54
+ "prepareReserve",
55
+ "prepareRelease",
56
+ "prepareReservationTransfer",
57
+ "prepareReserveTransfer",
58
+ "reservation"
59
+ ]), w = r(f.allowedServices ?? [], 256).map((e) => a(e)), T = new Set(w);
60
+ if (T.size !== w.length) throw t("invalid_input");
61
+ let E = (e) => {
62
+ let n = structuredClone(e);
63
+ if (n.type !== "system" && (n.type !== "service" || !T.has(n.service))) throw t("forbidden");
64
+ return n;
65
+ }, D = (e, n = !1) => {
66
+ let r = i(e, [
67
+ "tenantId",
68
+ "tradeId",
69
+ "proposerId",
70
+ "offered",
71
+ "requested",
72
+ ...n ? ["accepterId"] : []
73
+ ]), o = s(r.offered, m), c = s(r.requested, m);
74
+ if (!o.items.length && !o.currencies.length && !c.items.length && !c.currencies.length || o.items.some((e) => c.items.some((t) => e.instanceId === t.instanceId))) throw t("invalid_input");
75
+ let l = a(r.proposerId), u = n ? a(r.accepterId) : null;
76
+ if (u === l || !C && (o.items.length || c.items.length)) throw t("invalid_input");
77
+ return Object.freeze({
78
+ tenantId: a(r.tenantId),
79
+ tradeId: a(r.tradeId),
80
+ proposerId: l,
81
+ accepterId: u,
82
+ offered: o,
83
+ requested: c
84
+ });
85
+ }, O = async (e, n) => {
86
+ if (n.offered.items.length) {
87
+ let r = await g(C.reservation(e, {
88
+ tenantId: n.tenantId,
89
+ owner: b(n.proposerId),
90
+ reservationId: n.tradeId
91
+ }));
92
+ if (r.state !== "reserved" || r.reservationId !== n.tradeId || r.items.length !== n.offered.items.length || r.items.some((e, t) => e.instance.id !== n.offered.items[t].instanceId || e.qty !== n.offered.items[t].qty)) throw t("conflict");
93
+ }
94
+ let r = [];
95
+ for (let i of n.offered.currencies) {
96
+ let a = await g(S.escrow(e, {
97
+ tenantId: n.tenantId,
98
+ owner: y(n.proposerId),
99
+ reservationId: n.tradeId,
100
+ currency: i.currency
101
+ }));
102
+ if (a.state !== "held" || a.amount !== i.amount) throw t("conflict");
103
+ r.push(a.receipt);
104
+ }
105
+ return Object.freeze(r);
106
+ }, k = (t, n, r, i) => v(() => {
107
+ let a = E(t), o = D(n);
108
+ return _(async () => {
109
+ i && await O(a, o);
110
+ let t = [];
111
+ if (o.offered.items.length) {
112
+ let n = {
113
+ tenantId: o.tenantId,
114
+ owner: b(o.proposerId),
115
+ reservationId: o.tradeId
116
+ }, r = await g(i ? C.prepareRelease(a, n) : C.prepareReserve(a, {
117
+ ...n,
118
+ items: o.offered.items
119
+ }));
120
+ t.push(p(e, [r], async (e, [t]) => Object.freeze({
121
+ kind: "inventory",
122
+ receipt: t
123
+ })));
124
+ }
125
+ for (let n of o.offered.currencies) {
126
+ let r = {
127
+ tenantId: o.tenantId,
128
+ owner: y(o.proposerId),
129
+ reservationId: o.tradeId,
130
+ currency: n.currency
131
+ }, s = await g(i ? S.prepareEscrowRelease(a, r) : S.prepareEscrowReserve(a, {
132
+ ...r,
133
+ amount: n.amount
134
+ }));
135
+ t.push(p(e, [s], async (e, [t]) => Object.freeze({
136
+ kind: "currency",
137
+ receipt: t
138
+ })));
139
+ }
140
+ return p(e, [r, ...t], async (e, [, ...t]) => Object.freeze({
141
+ tradeId: o.tradeId,
142
+ inventory: t.find((e) => e.kind === "inventory")?.receipt ?? null,
143
+ currencies: Object.freeze(t.flatMap((e) => e.kind === "currency" ? [e.receipt] : []))
144
+ }));
145
+ });
146
+ });
147
+ return Object.freeze({
148
+ prepareReserve: (e, t, n) => k(e, t, n, !1),
149
+ prepareRelease: (e, t, n) => k(e, t, n, !0),
150
+ prepareExchange: (t, n, r) => v(() => {
151
+ let i = E(t), a = D(n, !0);
152
+ return _(async () => {
153
+ let t = await O(i, a), n = [], o = async (r, o, s, c) => {
154
+ if (o.items.length) {
155
+ let t = {
156
+ tenantId: a.tenantId,
157
+ from: b(s),
158
+ to: b(c),
159
+ reservationId: a.tradeId
160
+ };
161
+ if (r === "offered") {
162
+ let a = await g(C.prepareReservationTransfer(i, t));
163
+ n.push(p(e, [a], async (e, [t]) => Object.freeze({
164
+ leg: r,
165
+ kind: "inventory",
166
+ receipt: t
167
+ })));
168
+ } else {
169
+ let a = await g(C.prepareReserveTransfer(i, {
170
+ ...t,
171
+ items: o.items
172
+ }));
173
+ n.push(p(e, [a], async (e, [t]) => Object.freeze({
174
+ leg: r,
175
+ kind: "inventory",
176
+ receipt: t.transfer
177
+ })));
178
+ }
179
+ }
180
+ for (let [l, d] of o.currencies.entries()) {
181
+ let o = u({
182
+ currency: d.currency,
183
+ amount: d.amount,
184
+ rules: h
185
+ }, x), f = {
186
+ tenantId: a.tenantId,
187
+ owner: y(s),
188
+ to: y(c),
189
+ reservationId: a.tradeId,
190
+ currency: d.currency,
191
+ taxAmount: o.tax
192
+ };
193
+ if (r === "offered") {
194
+ let a = await g(S.prepareEscrowTaxSettle(i, f)), o = t[l];
195
+ n.push(p(e, [a], async (e, [t]) => Object.freeze({
196
+ leg: r,
197
+ kind: "currency",
198
+ receipt: Object.freeze({
199
+ reserve: o,
200
+ settlement: t
201
+ })
202
+ })));
203
+ } else {
204
+ let t = await g(S.prepareEscrowReserveTaxSettle(i, {
205
+ ...f,
206
+ amount: d.amount
207
+ }));
208
+ n.push(p(e, [t], async (e, [t]) => Object.freeze({
209
+ leg: r,
210
+ kind: "currency",
211
+ receipt: t
212
+ })));
213
+ }
214
+ }
215
+ };
216
+ return await o("offered", a.offered, a.proposerId, a.accepterId), await o("requested", a.requested, a.accepterId, a.proposerId), p(e, [r, ...n], async (e, [, ...t]) => {
217
+ let n = (e) => Object.freeze({
218
+ inventory: t.find((t) => t.leg === e && t.kind === "inventory")?.receipt ?? null,
219
+ currencies: Object.freeze(t.flatMap((t) => t.leg === e && t.kind === "currency" ? [t.receipt] : []))
220
+ });
221
+ return Object.freeze({
222
+ tradeId: a.tradeId,
223
+ offered: n("offered"),
224
+ requested: n("requested")
225
+ });
226
+ });
227
+ });
228
+ })
229
+ });
230
+ };
231
+ //#endregion
232
+ export { x as tradeEscrowParticipant };
@@ -0,0 +1,133 @@
1
+ import { economyTables as e } from "./tables.entity.js";
2
+ import { dataStoreEconomy as t } from "./walletStore.js";
3
+ import { tradeEscrowParticipant as n } from "./tradeEscrow.server.js";
4
+ import { Effect as r } from "effect";
5
+ import { systemSubject as i } from "@voltro/protocol";
6
+ import { and as a, ensureTableRegistered as o, eq as s } from "@voltro/database";
7
+ import { prepareSqlMutation as c } from "@voltro/database/sql";
8
+ import { InMemoryDataStore as l } from "@voltro/runtime";
9
+ import { dataStoreCatalog as u, dataStoreInventory as d, inventorySubjectsTable as f, inventoryTables as p } from "@voltro/plugin-inventory/server";
10
+ import { inventoryFixture as m } from "@voltro/plugin-inventory/testing";
11
+ import { defineItem as h, itemContent as g } from "@voltro/plugin-inventory";
12
+ //#region src/tradeEscrow.testFixtures.ts
13
+ var _ = [...e, ...p], v = Date.UTC(2026, 9, 10), y = i("trade.escrow.fixture"), b = async (e = new l(), i = "tenant") => {
14
+ _.forEach(o);
15
+ let p = h({
16
+ ...m().item,
17
+ tradable: !0,
18
+ maxStack: 100,
19
+ expiresAfter: 1e3
20
+ }), b = u(e, {
21
+ items: [p],
22
+ now: () => v
23
+ });
24
+ await r.runPromise(b.importSnapshot(y, {
25
+ tenantId: i,
26
+ channel: "live",
27
+ locale: "en",
28
+ revision: "trade.r1",
29
+ items: [g(p, { potency: 1 }, {})]
30
+ }));
31
+ let x = [{
32
+ id: "gold",
33
+ kind: "soft",
34
+ cap: "1000"
35
+ }], S = t(e, {
36
+ currencies: x,
37
+ now: () => v
38
+ }), C = d(e, {
39
+ items: [p],
40
+ catalogSource: b,
41
+ channel: "live",
42
+ locale: "en",
43
+ now: () => v
44
+ }), w = (e) => ({
45
+ type: "user",
46
+ id: e,
47
+ tenantId: i
48
+ });
49
+ for (let [e, t] of [["a", 5], ["b", 7]]) await r.runPromise(S.transfer(y, {
50
+ tenantId: i,
51
+ requestId: "fund." + e,
52
+ currency: "gold",
53
+ amount: "100",
54
+ reason: "fixture",
55
+ ref: {
56
+ kind: "fixture",
57
+ id: "fixture"
58
+ },
59
+ from: {
60
+ kind: "system",
61
+ id: "fixture"
62
+ },
63
+ to: {
64
+ kind: "wallet",
65
+ ownerKind: "player",
66
+ ownerId: e
67
+ }
68
+ })), await r.runPromise(C.grant(y, {
69
+ tenantId: i,
70
+ owner: {
71
+ ownerKind: "player",
72
+ ownerId: e
73
+ },
74
+ requestId: "stock." + e,
75
+ itemId: p.id,
76
+ qty: t,
77
+ reason: "fixture",
78
+ ref: {
79
+ kind: "fixture",
80
+ id: "stock." + e
81
+ }
82
+ }));
83
+ let T = (await r.runPromise(C.mine(w("a"))))[0], E = (await r.runPromise(C.mine(w("b"))))[0], D = {
84
+ tenantId: i,
85
+ tradeId: "trade.atomic",
86
+ proposerId: "a",
87
+ offered: {
88
+ items: [{
89
+ instanceId: T.id,
90
+ qty: 2
91
+ }],
92
+ currencies: [{
93
+ currency: "gold",
94
+ amount: "30"
95
+ }]
96
+ },
97
+ requested: {
98
+ items: [{
99
+ instanceId: E.id,
100
+ qty: 2
101
+ }],
102
+ currencies: [{
103
+ currency: "gold",
104
+ amount: "10"
105
+ }]
106
+ }
107
+ }, O = {
108
+ currencies: x,
109
+ rules: {
110
+ version: "trade.fixture.v1",
111
+ taxBps: 100
112
+ },
113
+ economy: S,
114
+ inventory: C
115
+ };
116
+ return {
117
+ store: e,
118
+ item: p,
119
+ economy: S,
120
+ inventory: C,
121
+ participant: n(e, O),
122
+ options: O,
123
+ terms: D,
124
+ user: w,
125
+ a: T,
126
+ b: E,
127
+ admission: () => c(e, async (e) => {
128
+ for (let t of ["a", "b"]) if (await e.updateMany(f.tableName, { admission: 0 }, { where: a(s("tenantId", i), s("ownerId", t), s("erased", !1)) }) !== 1) throw Error("Fixture owner admission refused");
129
+ })
130
+ };
131
+ };
132
+ //#endregion
133
+ export { v as tradeEscrowAt, b as tradeEscrowFixture, y as tradeEscrowMachine, _ as tradeEscrowTables };