@chipmobilesdk/rn-payment 0.5.0 → 0.7.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 (317) hide show
  1. package/CHANGELOG.md +172 -0
  2. package/README.md +47 -16
  3. package/lib/commonjs/adapter/createStoreProvider.js +110 -0
  4. package/lib/commonjs/adapter/createStoreProvider.js.map +1 -0
  5. package/lib/commonjs/adapter/iap-adapter.js +393 -0
  6. package/lib/commonjs/adapter/iap-adapter.js.map +1 -0
  7. package/lib/commonjs/adapter/iapShapes.js +169 -0
  8. package/lib/commonjs/adapter/iapShapes.js.map +1 -0
  9. package/lib/commonjs/adapter/port.js +6 -0
  10. package/lib/commonjs/adapter/port.js.map +1 -0
  11. package/lib/commonjs/config/types.js +2 -0
  12. package/lib/commonjs/config/types.js.map +1 -0
  13. package/lib/commonjs/config/validate.js +181 -0
  14. package/lib/commonjs/config/validate.js.map +1 -0
  15. package/lib/commonjs/core/mutex.js +31 -0
  16. package/lib/commonjs/core/mutex.js.map +1 -0
  17. package/lib/commonjs/core/retry.js +37 -0
  18. package/lib/commonjs/core/retry.js.map +1 -0
  19. package/lib/commonjs/core/timers.js +207 -0
  20. package/lib/commonjs/core/timers.js.map +1 -0
  21. package/lib/commonjs/diagnostics/errors.js +83 -0
  22. package/lib/commonjs/diagnostics/errors.js.map +1 -0
  23. package/lib/commonjs/diagnostics/events.js +126 -0
  24. package/lib/commonjs/diagnostics/events.js.map +1 -0
  25. package/lib/commonjs/diagnostics/messageKeys.js +70 -0
  26. package/lib/commonjs/diagnostics/messageKeys.js.map +1 -0
  27. package/lib/commonjs/engine/connection.js +189 -0
  28. package/lib/commonjs/engine/connection.js.map +1 -0
  29. package/lib/commonjs/engine/engine.js +279 -0
  30. package/lib/commonjs/engine/engine.js.map +1 -0
  31. package/lib/commonjs/engine/finalize.js +325 -0
  32. package/lib/commonjs/engine/finalize.js.map +1 -0
  33. package/lib/commonjs/engine/foreground.js +26 -0
  34. package/lib/commonjs/engine/foreground.js.map +1 -0
  35. package/lib/commonjs/engine/internals.js +31 -0
  36. package/lib/commonjs/engine/internals.js.map +1 -0
  37. package/lib/commonjs/engine/pending.js +102 -0
  38. package/lib/commonjs/engine/pending.js.map +1 -0
  39. package/lib/commonjs/engine/products.js +198 -0
  40. package/lib/commonjs/engine/products.js.map +1 -0
  41. package/lib/commonjs/engine/purchase.js +395 -0
  42. package/lib/commonjs/engine/purchase.js.map +1 -0
  43. package/lib/commonjs/engine/purchaseFailure.js +77 -0
  44. package/lib/commonjs/engine/purchaseFailure.js.map +1 -0
  45. package/lib/commonjs/engine/receiptValidation.js +90 -0
  46. package/lib/commonjs/engine/receiptValidation.js.map +1 -0
  47. package/lib/commonjs/engine/state.js +201 -0
  48. package/lib/commonjs/engine/state.js.map +1 -0
  49. package/lib/commonjs/engine/subscriptions.js +122 -0
  50. package/lib/commonjs/engine/subscriptions.js.map +1 -0
  51. package/lib/commonjs/engine/sync.js +163 -0
  52. package/lib/commonjs/engine/sync.js.map +1 -0
  53. package/lib/commonjs/entitlements/aggregate.js +212 -0
  54. package/lib/commonjs/entitlements/aggregate.js.map +1 -0
  55. package/lib/commonjs/entitlements/mapping.js +41 -0
  56. package/lib/commonjs/entitlements/mapping.js.map +1 -0
  57. package/lib/commonjs/entitlements/policy.js +110 -0
  58. package/lib/commonjs/entitlements/policy.js.map +1 -0
  59. package/lib/commonjs/index.js +266 -0
  60. package/lib/commonjs/index.js.map +1 -0
  61. package/lib/commonjs/package.json +1 -0
  62. package/lib/commonjs/persistence/mmkv-store.js +149 -0
  63. package/lib/commonjs/persistence/mmkv-store.js.map +1 -0
  64. package/lib/commonjs/persistence/snapshot.js +229 -0
  65. package/lib/commonjs/persistence/snapshot.js.map +1 -0
  66. package/lib/commonjs/react/PaymentProvider.js +96 -0
  67. package/lib/commonjs/react/PaymentProvider.js.map +1 -0
  68. package/lib/commonjs/react/hooks.js +202 -0
  69. package/lib/commonjs/react/hooks.js.map +1 -0
  70. package/lib/commonjs/testing/conformance.js +136 -0
  71. package/lib/commonjs/testing/conformance.js.map +1 -0
  72. package/lib/commonjs/testing/fakeStore.js +281 -0
  73. package/lib/commonjs/testing/fakeStore.js.map +1 -0
  74. package/lib/commonjs/testing/index.js +45 -0
  75. package/lib/commonjs/testing/index.js.map +1 -0
  76. package/lib/module/adapter/createStoreProvider.js +106 -0
  77. package/lib/module/adapter/createStoreProvider.js.map +1 -0
  78. package/lib/module/adapter/iap-adapter.js +383 -0
  79. package/lib/module/adapter/iap-adapter.js.map +1 -0
  80. package/lib/module/adapter/iapShapes.js +160 -0
  81. package/lib/module/adapter/iapShapes.js.map +1 -0
  82. package/lib/module/adapter/port.js +4 -0
  83. package/lib/module/adapter/port.js.map +1 -0
  84. package/lib/module/config/types.js +2 -0
  85. package/lib/module/config/types.js.map +1 -0
  86. package/lib/module/config/validate.js +175 -0
  87. package/lib/module/config/validate.js.map +1 -0
  88. package/lib/module/core/mutex.js +22 -0
  89. package/lib/module/core/mutex.js.map +1 -0
  90. package/lib/module/core/retry.js +33 -0
  91. package/lib/module/core/retry.js.map +1 -0
  92. package/lib/module/core/timers.js +198 -0
  93. package/lib/module/core/timers.js.map +1 -0
  94. package/lib/module/diagnostics/errors.js +76 -0
  95. package/lib/module/diagnostics/errors.js.map +1 -0
  96. package/lib/module/diagnostics/events.js +117 -0
  97. package/lib/module/diagnostics/events.js.map +1 -0
  98. package/lib/module/diagnostics/messageKeys.js +64 -0
  99. package/lib/module/diagnostics/messageKeys.js.map +1 -0
  100. package/lib/module/engine/connection.js +185 -0
  101. package/lib/module/engine/connection.js.map +1 -0
  102. package/lib/module/engine/engine.js +274 -0
  103. package/lib/module/engine/engine.js.map +1 -0
  104. package/lib/module/engine/finalize.js +322 -0
  105. package/lib/module/engine/finalize.js.map +1 -0
  106. package/lib/module/engine/foreground.js +21 -0
  107. package/lib/module/engine/foreground.js.map +1 -0
  108. package/lib/module/engine/internals.js +26 -0
  109. package/lib/module/engine/internals.js.map +1 -0
  110. package/lib/module/engine/pending.js +95 -0
  111. package/lib/module/engine/pending.js.map +1 -0
  112. package/lib/module/engine/products.js +195 -0
  113. package/lib/module/engine/products.js.map +1 -0
  114. package/lib/module/engine/purchase.js +390 -0
  115. package/lib/module/engine/purchase.js.map +1 -0
  116. package/lib/module/engine/purchaseFailure.js +72 -0
  117. package/lib/module/engine/purchaseFailure.js.map +1 -0
  118. package/lib/module/engine/receiptValidation.js +87 -0
  119. package/lib/module/engine/receiptValidation.js.map +1 -0
  120. package/lib/module/engine/state.js +196 -0
  121. package/lib/module/engine/state.js.map +1 -0
  122. package/lib/module/engine/subscriptions.js +119 -0
  123. package/lib/module/engine/subscriptions.js.map +1 -0
  124. package/lib/module/engine/sync.js +158 -0
  125. package/lib/module/engine/sync.js.map +1 -0
  126. package/lib/module/entitlements/aggregate.js +204 -0
  127. package/lib/module/entitlements/aggregate.js.map +1 -0
  128. package/lib/module/entitlements/mapping.js +35 -0
  129. package/lib/module/entitlements/mapping.js.map +1 -0
  130. package/lib/module/entitlements/policy.js +104 -0
  131. package/lib/module/entitlements/policy.js.map +1 -0
  132. package/lib/module/index.js +59 -0
  133. package/lib/module/index.js.map +1 -0
  134. package/lib/module/package.json +1 -0
  135. package/lib/module/persistence/mmkv-store.js +144 -0
  136. package/lib/module/persistence/mmkv-store.js.map +1 -0
  137. package/lib/module/persistence/snapshot.js +221 -0
  138. package/lib/module/persistence/snapshot.js.map +1 -0
  139. package/lib/module/react/PaymentProvider.js +90 -0
  140. package/lib/module/react/PaymentProvider.js.map +1 -0
  141. package/lib/module/react/hooks.js +192 -0
  142. package/lib/module/react/hooks.js.map +1 -0
  143. package/lib/module/testing/conformance.js +130 -0
  144. package/lib/module/testing/conformance.js.map +1 -0
  145. package/lib/module/testing/fakeStore.js +276 -0
  146. package/lib/module/testing/fakeStore.js.map +1 -0
  147. package/lib/module/testing/index.js +13 -0
  148. package/lib/module/testing/index.js.map +1 -0
  149. package/lib/typescript/commonjs/adapter/createStoreProvider.d.ts +45 -0
  150. package/lib/typescript/commonjs/adapter/createStoreProvider.d.ts.map +1 -0
  151. package/lib/typescript/commonjs/adapter/iap-adapter.d.ts +80 -0
  152. package/lib/typescript/commonjs/adapter/iap-adapter.d.ts.map +1 -0
  153. package/lib/typescript/commonjs/adapter/iapShapes.d.ts +94 -0
  154. package/lib/typescript/commonjs/adapter/iapShapes.d.ts.map +1 -0
  155. package/lib/typescript/commonjs/adapter/port.d.ts +184 -0
  156. package/lib/typescript/commonjs/adapter/port.d.ts.map +1 -0
  157. package/lib/typescript/commonjs/config/types.d.ts +326 -0
  158. package/lib/typescript/commonjs/config/types.d.ts.map +1 -0
  159. package/lib/typescript/commonjs/config/validate.d.ts +63 -0
  160. package/lib/typescript/commonjs/config/validate.d.ts.map +1 -0
  161. package/lib/typescript/commonjs/core/mutex.d.ts +17 -0
  162. package/lib/typescript/commonjs/core/mutex.d.ts.map +1 -0
  163. package/lib/typescript/commonjs/core/retry.d.ts +19 -0
  164. package/lib/typescript/commonjs/core/retry.d.ts.map +1 -0
  165. package/lib/typescript/commonjs/core/timers.d.ts +142 -0
  166. package/lib/typescript/commonjs/core/timers.d.ts.map +1 -0
  167. package/lib/typescript/commonjs/diagnostics/errors.d.ts +55 -0
  168. package/lib/typescript/commonjs/diagnostics/errors.d.ts.map +1 -0
  169. package/lib/typescript/commonjs/diagnostics/events.d.ts +158 -0
  170. package/lib/typescript/commonjs/diagnostics/events.d.ts.map +1 -0
  171. package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts +54 -0
  172. package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts.map +1 -0
  173. package/lib/typescript/commonjs/engine/connection.d.ts +30 -0
  174. package/lib/typescript/commonjs/engine/connection.d.ts.map +1 -0
  175. package/lib/typescript/commonjs/engine/engine.d.ts +93 -0
  176. package/lib/typescript/commonjs/engine/engine.d.ts.map +1 -0
  177. package/lib/typescript/commonjs/engine/finalize.d.ts +53 -0
  178. package/lib/typescript/commonjs/engine/finalize.d.ts.map +1 -0
  179. package/lib/typescript/commonjs/engine/foreground.d.ts +15 -0
  180. package/lib/typescript/commonjs/engine/foreground.d.ts.map +1 -0
  181. package/lib/typescript/commonjs/engine/internals.d.ts +28 -0
  182. package/lib/typescript/commonjs/engine/internals.d.ts.map +1 -0
  183. package/lib/typescript/commonjs/engine/pending.d.ts +51 -0
  184. package/lib/typescript/commonjs/engine/pending.d.ts.map +1 -0
  185. package/lib/typescript/commonjs/engine/products.d.ts +82 -0
  186. package/lib/typescript/commonjs/engine/products.d.ts.map +1 -0
  187. package/lib/typescript/commonjs/engine/purchase.d.ts +61 -0
  188. package/lib/typescript/commonjs/engine/purchase.d.ts.map +1 -0
  189. package/lib/typescript/commonjs/engine/purchaseFailure.d.ts +15 -0
  190. package/lib/typescript/commonjs/engine/purchaseFailure.d.ts.map +1 -0
  191. package/lib/typescript/commonjs/engine/receiptValidation.d.ts +42 -0
  192. package/lib/typescript/commonjs/engine/receiptValidation.d.ts.map +1 -0
  193. package/lib/typescript/commonjs/engine/state.d.ts +46 -0
  194. package/lib/typescript/commonjs/engine/state.d.ts.map +1 -0
  195. package/lib/typescript/commonjs/engine/subscriptions.d.ts +61 -0
  196. package/lib/typescript/commonjs/engine/subscriptions.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/engine/sync.d.ts +36 -0
  198. package/lib/typescript/commonjs/engine/sync.d.ts.map +1 -0
  199. package/lib/typescript/commonjs/entitlements/aggregate.d.ts +97 -0
  200. package/lib/typescript/commonjs/entitlements/aggregate.d.ts.map +1 -0
  201. package/lib/typescript/commonjs/entitlements/mapping.d.ts +27 -0
  202. package/lib/typescript/commonjs/entitlements/mapping.d.ts.map +1 -0
  203. package/lib/typescript/commonjs/entitlements/policy.d.ts +75 -0
  204. package/lib/typescript/commonjs/entitlements/policy.d.ts.map +1 -0
  205. package/lib/typescript/commonjs/index.d.ts +44 -0
  206. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  207. package/lib/typescript/commonjs/package.json +1 -0
  208. package/lib/typescript/commonjs/persistence/mmkv-store.d.ts +45 -0
  209. package/lib/typescript/commonjs/persistence/mmkv-store.d.ts.map +1 -0
  210. package/lib/typescript/commonjs/persistence/snapshot.d.ts +106 -0
  211. package/lib/typescript/commonjs/persistence/snapshot.d.ts.map +1 -0
  212. package/lib/typescript/commonjs/react/PaymentProvider.d.ts +57 -0
  213. package/lib/typescript/commonjs/react/PaymentProvider.d.ts.map +1 -0
  214. package/lib/typescript/commonjs/react/hooks.d.ts +80 -0
  215. package/lib/typescript/commonjs/react/hooks.d.ts.map +1 -0
  216. package/lib/typescript/commonjs/testing/conformance.d.ts +41 -0
  217. package/lib/typescript/commonjs/testing/conformance.d.ts.map +1 -0
  218. package/lib/typescript/commonjs/testing/fakeStore.d.ts +69 -0
  219. package/lib/typescript/commonjs/testing/fakeStore.d.ts.map +1 -0
  220. package/lib/typescript/commonjs/testing/index.d.ts +12 -0
  221. package/lib/typescript/commonjs/testing/index.d.ts.map +1 -0
  222. package/lib/typescript/module/adapter/createStoreProvider.d.ts +45 -0
  223. package/lib/typescript/module/adapter/createStoreProvider.d.ts.map +1 -0
  224. package/lib/typescript/module/adapter/iap-adapter.d.ts +80 -0
  225. package/lib/typescript/module/adapter/iap-adapter.d.ts.map +1 -0
  226. package/lib/typescript/module/adapter/iapShapes.d.ts +94 -0
  227. package/lib/typescript/module/adapter/iapShapes.d.ts.map +1 -0
  228. package/lib/typescript/module/adapter/port.d.ts +184 -0
  229. package/lib/typescript/module/adapter/port.d.ts.map +1 -0
  230. package/lib/typescript/module/config/types.d.ts +326 -0
  231. package/lib/typescript/module/config/types.d.ts.map +1 -0
  232. package/lib/typescript/module/config/validate.d.ts +63 -0
  233. package/lib/typescript/module/config/validate.d.ts.map +1 -0
  234. package/lib/typescript/module/core/mutex.d.ts +17 -0
  235. package/lib/typescript/module/core/mutex.d.ts.map +1 -0
  236. package/lib/typescript/module/core/retry.d.ts +19 -0
  237. package/lib/typescript/module/core/retry.d.ts.map +1 -0
  238. package/lib/typescript/module/core/timers.d.ts +142 -0
  239. package/lib/typescript/module/core/timers.d.ts.map +1 -0
  240. package/lib/typescript/module/diagnostics/errors.d.ts +55 -0
  241. package/lib/typescript/module/diagnostics/errors.d.ts.map +1 -0
  242. package/lib/typescript/module/diagnostics/events.d.ts +158 -0
  243. package/lib/typescript/module/diagnostics/events.d.ts.map +1 -0
  244. package/lib/typescript/module/diagnostics/messageKeys.d.ts +54 -0
  245. package/lib/typescript/module/diagnostics/messageKeys.d.ts.map +1 -0
  246. package/lib/typescript/module/engine/connection.d.ts +30 -0
  247. package/lib/typescript/module/engine/connection.d.ts.map +1 -0
  248. package/lib/typescript/module/engine/engine.d.ts +93 -0
  249. package/lib/typescript/module/engine/engine.d.ts.map +1 -0
  250. package/lib/typescript/module/engine/finalize.d.ts +53 -0
  251. package/lib/typescript/module/engine/finalize.d.ts.map +1 -0
  252. package/lib/typescript/module/engine/foreground.d.ts +15 -0
  253. package/lib/typescript/module/engine/foreground.d.ts.map +1 -0
  254. package/lib/typescript/module/engine/internals.d.ts +28 -0
  255. package/lib/typescript/module/engine/internals.d.ts.map +1 -0
  256. package/lib/typescript/module/engine/pending.d.ts +51 -0
  257. package/lib/typescript/module/engine/pending.d.ts.map +1 -0
  258. package/lib/typescript/module/engine/products.d.ts +82 -0
  259. package/lib/typescript/module/engine/products.d.ts.map +1 -0
  260. package/lib/typescript/module/engine/purchase.d.ts +61 -0
  261. package/lib/typescript/module/engine/purchase.d.ts.map +1 -0
  262. package/lib/typescript/module/engine/purchaseFailure.d.ts +15 -0
  263. package/lib/typescript/module/engine/purchaseFailure.d.ts.map +1 -0
  264. package/lib/typescript/module/engine/receiptValidation.d.ts +42 -0
  265. package/lib/typescript/module/engine/receiptValidation.d.ts.map +1 -0
  266. package/lib/typescript/module/engine/state.d.ts +46 -0
  267. package/lib/typescript/module/engine/state.d.ts.map +1 -0
  268. package/lib/typescript/module/engine/subscriptions.d.ts +61 -0
  269. package/lib/typescript/module/engine/subscriptions.d.ts.map +1 -0
  270. package/lib/typescript/module/engine/sync.d.ts +36 -0
  271. package/lib/typescript/module/engine/sync.d.ts.map +1 -0
  272. package/lib/typescript/module/entitlements/aggregate.d.ts +97 -0
  273. package/lib/typescript/module/entitlements/aggregate.d.ts.map +1 -0
  274. package/lib/typescript/module/entitlements/mapping.d.ts +27 -0
  275. package/lib/typescript/module/entitlements/mapping.d.ts.map +1 -0
  276. package/lib/typescript/module/entitlements/policy.d.ts +75 -0
  277. package/lib/typescript/module/entitlements/policy.d.ts.map +1 -0
  278. package/lib/typescript/module/index.d.ts +44 -0
  279. package/lib/typescript/module/index.d.ts.map +1 -0
  280. package/lib/typescript/module/package.json +1 -0
  281. package/lib/typescript/module/persistence/mmkv-store.d.ts +45 -0
  282. package/lib/typescript/module/persistence/mmkv-store.d.ts.map +1 -0
  283. package/lib/typescript/module/persistence/snapshot.d.ts +106 -0
  284. package/lib/typescript/module/persistence/snapshot.d.ts.map +1 -0
  285. package/lib/typescript/module/react/PaymentProvider.d.ts +57 -0
  286. package/lib/typescript/module/react/PaymentProvider.d.ts.map +1 -0
  287. package/lib/typescript/module/react/hooks.d.ts +80 -0
  288. package/lib/typescript/module/react/hooks.d.ts.map +1 -0
  289. package/lib/typescript/module/testing/conformance.d.ts +41 -0
  290. package/lib/typescript/module/testing/conformance.d.ts.map +1 -0
  291. package/lib/typescript/module/testing/fakeStore.d.ts +69 -0
  292. package/lib/typescript/module/testing/fakeStore.d.ts.map +1 -0
  293. package/lib/typescript/module/testing/index.d.ts +12 -0
  294. package/lib/typescript/module/testing/index.d.ts.map +1 -0
  295. package/package.json +49 -13
  296. package/skills/sdk-rn-payment/SKILL.md +4 -4
  297. package/src/adapter/iap-adapter.ts +12 -216
  298. package/src/adapter/iapShapes.ts +232 -0
  299. package/src/config/types.ts +8 -0
  300. package/src/config/validate.ts +19 -4
  301. package/src/core/retry.ts +1 -58
  302. package/src/diagnostics/events.ts +1 -1
  303. package/src/engine/connection.ts +194 -0
  304. package/src/engine/engine.ts +140 -700
  305. package/src/engine/internals.ts +40 -0
  306. package/src/engine/products.ts +39 -17
  307. package/src/engine/purchase.ts +22 -130
  308. package/src/engine/purchaseFailure.ts +48 -0
  309. package/src/engine/receiptValidation.ts +101 -0
  310. package/src/engine/state.ts +253 -0
  311. package/src/engine/sync.ts +161 -0
  312. package/src/entitlements/aggregate.ts +3 -5
  313. package/src/entitlements/mapping.ts +0 -22
  314. package/src/persistence/mmkv-store.ts +10 -3
  315. package/src/persistence/snapshot.ts +102 -27
  316. package/src/react/PaymentProvider.tsx +73 -24
  317. package/src/react/hooks.ts +13 -3
@@ -0,0 +1,395 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createPurchaseFlow = createPurchaseFlow;
7
+ var _mutex = require("../core/mutex.js");
8
+ var _timers = require("../core/timers.js");
9
+ var _errors = require("../diagnostics/errors.js");
10
+ var _mapping = require("../entitlements/mapping.js");
11
+ var _sync = require("./sync.js");
12
+ var _receiptValidation = require("./receiptValidation.js");
13
+ var _purchaseFailure = require("./purchaseFailure.js");
14
+ /**
15
+ * The purchase flow.
16
+ *
17
+ * Ordering here is deliberate and load-bearing:
18
+ *
19
+ * 1. Refuse early and cheaply — disabled, not ready, already busy, environment
20
+ * blocked, unknown product — so nothing reaches the store that should not.
21
+ * 2. Launch, and map every store outcome onto a typed result (FR-005).
22
+ * 3. Pending stops here: it is persisted and signalled, but **never granted**
23
+ * (FR-037).
24
+ * 4. Validate with the app's backend, if one is configured, and only for a
25
+ * **newly completed** purchase (FR-069a).
26
+ * 5. Grant the entitlement, then finalize. In that order — the user gets what
27
+ * they paid for before the bookkeeping completes, so a finalize failure never
28
+ * withholds a paid entitlement. Finalization is still guaranteed, by the
29
+ * persisted queue.
30
+ */
31
+
32
+ /** The error code each failed purchase kind is reported under (PAY-19). */
33
+
34
+ function createPurchaseFlow(deps) {
35
+ const {
36
+ resolved
37
+ } = deps;
38
+ // The backend check and what to do when it cannot answer (receiptValidation).
39
+ const {
40
+ askHook,
41
+ validate
42
+ } = (0, _receiptValidation.createReceiptValidation)({
43
+ config: deps.config,
44
+ platform: deps.platform,
45
+ resolved,
46
+ emit: deps.emit
47
+ });
48
+ const toRef = record => ({
49
+ transactionId: record.transactionId,
50
+ productKey: record.productKey
51
+ });
52
+
53
+ /** Writes or replaces the record for one transaction. */
54
+ const upsert = record => {
55
+ const snapshot = deps.snapshot();
56
+ const others = snapshot.purchases.filter(p => p.transactionId !== record.transactionId);
57
+ deps.commit({
58
+ ...snapshot,
59
+ purchases: [...others, record]
60
+ });
61
+ };
62
+ const recordFor = (purchase, productKey) => (0, _sync.toPersistedRecord)(resolved, purchase, productKey, deps.snapshot().purchases.find(p => p.transactionId === purchase.transactionId));
63
+
64
+ /**
65
+ * Calls the app's hook under `timeouts.validateMs`.
66
+ *
67
+ * Unbounded, a hook that never answers held the purchase lock and, through
68
+ * revalidation, the sync flight for the rest of the session. A timeout rejects,
69
+ * so callers treat it exactly like a hook that throws: unavailable (FR-072b).
70
+ */
71
+ /**
72
+ * Settlements in progress, by transaction.
73
+ *
74
+ * The Play binding delivers a launched purchase twice: to the launch and, at
75
+ * the same moment, to the session-long update listener. Both paths reach
76
+ * `settle`, and without this the hook ran twice and the purchase was settled
77
+ * twice. The second caller joins the first and gets the same result.
78
+ */
79
+ const inFlightSettle = new Map();
80
+ const settleOnce = (purchase, productKey, correlationId) => {
81
+ const running = inFlightSettle.get(purchase.transactionId);
82
+ if (running) {
83
+ return running;
84
+ }
85
+ const flight = settle(purchase, productKey, correlationId).finally(() => {
86
+ inFlightSettle.delete(purchase.transactionId);
87
+ });
88
+ inFlightSettle.set(purchase.transactionId, flight);
89
+ return flight;
90
+ };
91
+
92
+ /** Persists a completed purchase, grants it, then finalizes. */
93
+ const settle = async (purchase, productKey, correlationId) => {
94
+ const decision = await validate(purchase, productKey, correlationId);
95
+ if (decision.outcome === 'rejected') {
96
+ upsert({
97
+ ...recordFor(purchase, productKey),
98
+ validationState: 'rejected',
99
+ finalizeState: 'queued'
100
+ });
101
+ // Still finalized with the store: the money moved, so leaving it
102
+ // unacknowledged would have Google refund it while our backend has
103
+ // already decided the user is not entitled. Refunding is the app owner's
104
+ // call, not a side effect of a bookkeeping omission.
105
+ await deps.finalizer.enqueue(purchase.transactionId);
106
+ return {
107
+ kind: 'validation_rejected',
108
+ productKey,
109
+ reason: decision.reason
110
+ };
111
+ }
112
+ upsert({
113
+ ...recordFor(purchase, productKey),
114
+ validationState: decision.outcome === 'granted_pending_revalidation' ? 'queued_for_revalidation' : 'approved',
115
+ finalizeState: 'queued'
116
+ });
117
+
118
+ // Grant is already live at this point: `commit` recomputed entitlements.
119
+ // Finalize second, so a store hiccup cannot withhold what was paid for.
120
+ await deps.finalizer.enqueue(purchase.transactionId);
121
+ const record = deps.snapshot().purchases.find(p => p.transactionId === purchase.transactionId);
122
+ return {
123
+ kind: 'success',
124
+ productKey,
125
+ transaction: record ? toRef(record) : {
126
+ transactionId: purchase.transactionId,
127
+ productKey
128
+ }
129
+ };
130
+ };
131
+ const handlePending = (purchase, productKey) => {
132
+ // The same pending transaction arrives from the launch and from the update
133
+ // listener (see `inFlightSettle`). The signal is about a purchase becoming
134
+ // pending, so it fires once per transaction, not once per delivery.
135
+ const alreadyPending = deps.snapshot().purchases.some(p => p.transactionId === purchase.transactionId && p.state === 'pending');
136
+ upsert(recordFor(purchase, productKey));
137
+ if (!alreadyPending) {
138
+ deps.emit({
139
+ type: 'purchase_pending',
140
+ productKey
141
+ });
142
+ }
143
+ return {
144
+ kind: 'pending',
145
+ productKey,
146
+ transaction: {
147
+ transactionId: purchase.transactionId,
148
+ productKey
149
+ }
150
+ };
151
+ };
152
+
153
+ /**
154
+ * The store returned a purchase in a state it could not name — neither paid
155
+ * nor pending. Nothing is granted, persisted or acknowledged on it.
156
+ *
157
+ * Retrying is the repair path: if the money did move, the store answers
158
+ * `already_owned`, which re-syncs and grants (FR-033).
159
+ */
160
+ const handleUnspecified = (productKey, correlationId) => {
161
+ deps.emit({
162
+ type: 'purchase_failed',
163
+ productKey,
164
+ code: 'PAYMENT_STORE_ERROR',
165
+ retryable: true,
166
+ correlationId
167
+ });
168
+ return {
169
+ kind: 'store_error',
170
+ productKey,
171
+ code: 'PAYMENT_STORE_ERROR'
172
+ };
173
+ };
174
+
175
+ /** What the store is asked for: the product and, for a plan change, what it replaces. */
176
+ const launchRequest = (productKey, storeProductId, options) => {
177
+ const replaceKey = options?.replaceProductKey;
178
+ return {
179
+ storeProductId,
180
+ productType: resolved.entries.get(productKey)?.productType ?? 'one_time_permanent',
181
+ offerKey: options?.offerKey,
182
+ obfuscatedAccountId: options?.obfuscatedAccountId,
183
+ // Present only for a plan change. The store needs the token of the
184
+ // subscription being replaced so it migrates the existing purchase instead
185
+ // of creating a second one (FR-065), and its product id to apply the
186
+ // replacement mode.
187
+ replacePurchaseToken: replaceKey ? deps.snapshot().purchases.find(p => p.productKey === replaceKey && p.state === 'purchased')?.token : undefined,
188
+ replaceStoreProductId: replaceKey ? (0, _mapping.storeIdForProductKey)(resolved, replaceKey) : undefined,
189
+ prorationMode: options?.prorationMode
190
+ };
191
+ };
192
+
193
+ /**
194
+ * The launch timeout covers opening the store surface only; time the user
195
+ * spends inside it is the store's, not ours (FR-035). A provider that reports
196
+ * nothing until the flow ends gives no "opened" moment to time, so it gets only
197
+ * `PURCHASE_FLOW_CEILING_MS`: far beyond any real purchase, there so a binding
198
+ * that never answers cannot hold the purchase lock for the whole session.
199
+ */
200
+ const launch = request => {
201
+ const launched = deps.provider.launchPurchase(request);
202
+ const includesStoreTime = deps.provider.capabilities().purchaseOutcomeIncludesStoreTime;
203
+ return (0, _mutex.withTimeout)(launched, includesStoreTime ? _timers.PURCHASE_FLOW_CEILING_MS : resolved.timeouts.purchaseLaunchMs, () => new _errors.PaymentError({
204
+ code: 'PAYMENT_TIMEOUT',
205
+ message: 'Opening the purchase surface timed out',
206
+ operation: 'purchase',
207
+ retryable: true
208
+ }));
209
+ };
210
+ return {
211
+ async purchase(productKey, options) {
212
+ if (!resolved.enabled) {
213
+ return {
214
+ kind: 'disabled'
215
+ };
216
+ }
217
+ const status = deps.statusKind();
218
+ if (status !== 'ready') {
219
+ return {
220
+ kind: 'not_ready',
221
+ status
222
+ };
223
+ }
224
+ const storeProductId = (0, _mapping.storeIdForProductKey)(resolved, productKey);
225
+ if (!storeProductId) {
226
+ return {
227
+ kind: 'unknown_product',
228
+ productKey
229
+ };
230
+ }
231
+
232
+ // The block that makes a developer mistake unable to move real money.
233
+ // Gated on the provider actually being one that would: the fake store
234
+ // must still be able to complete a purchase in a test (FR-014).
235
+ if (deps.provider.capabilities().createsRealTransactions && !deps.mayCreateRealTransaction()) {
236
+ deps.recordBlockedOperation(productKey);
237
+ return {
238
+ kind: 'environment_blocked',
239
+ productKey,
240
+ environment: deps.config.environment
241
+ };
242
+ }
243
+ const correlationId = deps.nextCorrelationId();
244
+
245
+ // Exclusive, not single-flight: a second purchase is refused rather than
246
+ // joined or queued, so no second store surface opens (FR-031).
247
+ const attempt = await deps.runExclusive(async () => {
248
+ deps.emit({
249
+ type: 'purchase_started',
250
+ productKey,
251
+ correlationId
252
+ });
253
+ let outcome;
254
+ try {
255
+ outcome = await launch(launchRequest(productKey, storeProductId, options));
256
+ } catch {
257
+ deps.emit({
258
+ type: 'purchase_failed',
259
+ productKey,
260
+ code: 'PAYMENT_TIMEOUT',
261
+ retryable: true,
262
+ correlationId
263
+ });
264
+ return {
265
+ kind: 'timeout',
266
+ productKey
267
+ };
268
+ }
269
+ if (!outcome.ok) {
270
+ const mapped = (0, _purchaseFailure.mapFailure)(outcome.reason, productKey, deps.statusKind());
271
+ if (mapped.kind === 'user_cancelled') {
272
+ // A normal outcome. Reported on its own channel so it is never
273
+ // counted as a technical failure (FR-032).
274
+ deps.emit({
275
+ type: 'purchase_cancelled',
276
+ productKey,
277
+ correlationId
278
+ });
279
+ return mapped;
280
+ }
281
+ if (mapped.kind === 'already_owned') {
282
+ // How a reinstall or a new device repairs itself (FR-033).
283
+ deps.requestSync('already_owned');
284
+ return mapped;
285
+ }
286
+ deps.emit({
287
+ type: 'purchase_failed',
288
+ productKey,
289
+ code: _purchaseFailure.FAILURE_CODES[mapped.kind] ?? 'PAYMENT_STORE_ERROR',
290
+ retryable: mapped.kind === 'network_error',
291
+ correlationId
292
+ });
293
+ return mapped;
294
+ }
295
+ if (outcome.purchase.state === 'pending') {
296
+ return handlePending(outcome.purchase, productKey);
297
+ }
298
+ if (outcome.purchase.state === 'unspecified') {
299
+ return handleUnspecified(productKey, correlationId);
300
+ }
301
+ deps.emit({
302
+ type: 'purchase_succeeded',
303
+ productKey,
304
+ correlationId
305
+ });
306
+ return settleOnce(outcome.purchase, productKey, correlationId);
307
+ });
308
+ if (!attempt.acquired) {
309
+ return {
310
+ kind: 'purchase_in_progress'
311
+ };
312
+ }
313
+ return attempt.value;
314
+ },
315
+ /**
316
+ * A store-pushed update.
317
+ *
318
+ * This is how a pending purchase that settled between sessions is granted
319
+ * without the user buying again (FR-039). It runs outside the exclusive lock
320
+ * because it is not a user-initiated purchase and must not be refused just
321
+ * because one is open.
322
+ */
323
+ async ingest(purchase) {
324
+ const productKey = resolved.byStoreId.get(purchase.storeProductId);
325
+ if (!productKey) {
326
+ return;
327
+ }
328
+ if (purchase.state === 'pending') {
329
+ handlePending(purchase, productKey);
330
+ return;
331
+ }
332
+ if (purchase.state === 'unspecified') {
333
+ // No basis to grant or to end anything. The next sync reports what
334
+ // the store actually holds.
335
+ return;
336
+ }
337
+ const existing = deps.snapshot().purchases.find(p => p.transactionId === purchase.transactionId);
338
+
339
+ // Already settled and validated: nothing to redo, and re-running the hook
340
+ // here would break FR-069a's "new purchases only" rule.
341
+ if (existing && existing.state === 'purchased' && existing.validationState !== 'not_required') {
342
+ await deps.finalizer.enqueue(purchase.transactionId);
343
+ return;
344
+ }
345
+ await settleOnce(purchase, productKey, deps.nextCorrelationId());
346
+ },
347
+ async revalidate() {
348
+ const hook = deps.config.validateTransaction;
349
+ if (!hook) {
350
+ return;
351
+ }
352
+ const queued = deps.snapshot().purchases.filter(p => p.validationState === 'queued_for_revalidation');
353
+ for (const record of queued) {
354
+ const entry = resolved.entries.get(record.productKey);
355
+ let approved;
356
+ try {
357
+ const decision = await askHook(hook, {
358
+ productKey: record.productKey,
359
+ productType: entry?.productType ?? 'one_time_permanent',
360
+ // Re-validation deliberately carries no payload: the original
361
+ // verification material is not persisted (FR-056), so the backend
362
+ // re-checks by transaction against its own record of the purchase —
363
+ // which is why the transaction id has to travel with it.
364
+ verificationPayload: '',
365
+ correlationId: deps.nextCorrelationId(),
366
+ transactionId: record.transactionId,
367
+ platform: deps.platform
368
+ });
369
+ approved = decision.approved;
370
+ } catch {
371
+ // Still unreachable. Leave it queued and try again next sync rather
372
+ // than revoking from a paying user because our backend is down.
373
+ continue;
374
+ }
375
+ const snapshot = deps.snapshot();
376
+ deps.commit({
377
+ ...snapshot,
378
+ purchases: snapshot.purchases.map(p => p.transactionId === record.transactionId ? {
379
+ ...p,
380
+ validationState: approved ? 'approved' : 'rejected',
381
+ // A rejection on recovery revokes, which is the bound on the
382
+ // exposure `grant_and_queue` accepts (FR-072a).
383
+ state: approved ? p.state : 'revoked'
384
+ } : p)
385
+ });
386
+ deps.emit({
387
+ type: 'validation_decided',
388
+ productKey: record.productKey,
389
+ decision: approved ? 'approved' : 'rejected'
390
+ });
391
+ }
392
+ }
393
+ };
394
+ }
395
+ //# sourceMappingURL=purchase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_mutex","require","_timers","_errors","_mapping","_sync","_receiptValidation","_purchaseFailure","createPurchaseFlow","deps","resolved","askHook","validate","createReceiptValidation","config","platform","emit","toRef","record","transactionId","productKey","upsert","snapshot","others","purchases","filter","p","commit","recordFor","purchase","toPersistedRecord","find","inFlightSettle","Map","settleOnce","correlationId","running","get","flight","settle","finally","delete","set","decision","outcome","validationState","finalizeState","finalizer","enqueue","kind","reason","transaction","handlePending","alreadyPending","some","state","type","handleUnspecified","code","retryable","launchRequest","storeProductId","options","replaceKey","replaceProductKey","productType","entries","offerKey","obfuscatedAccountId","replacePurchaseToken","token","undefined","replaceStoreProductId","storeIdForProductKey","prorationMode","launch","request","launched","provider","launchPurchase","includesStoreTime","capabilities","purchaseOutcomeIncludesStoreTime","withTimeout","PURCHASE_FLOW_CEILING_MS","timeouts","purchaseLaunchMs","PaymentError","message","operation","enabled","status","statusKind","createsRealTransactions","mayCreateRealTransaction","recordBlockedOperation","environment","nextCorrelationId","attempt","runExclusive","ok","mapped","mapFailure","requestSync","FAILURE_CODES","acquired","value","ingest","byStoreId","existing","revalidate","hook","validateTransaction","queued","entry","approved","verificationPayload","map"],"sourceRoot":"../../../src","sources":["engine/purchase.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.FAILURE_CODES = void 0;
7
+ exports.mapFailure = mapFailure;
8
+ /**
9
+ * What a refused purchase means to the app (PAY-19).
10
+ *
11
+ * The store answers with a reason of its own; this turns it into the result the
12
+ * app sees, under the code it can branch on, so no store vocabulary leaks out.
13
+ * Split from the flow next door, which is about the sequence of calls.
14
+ */
15
+
16
+ const FAILURE_CODES = exports.FAILURE_CODES = {
17
+ network_error: 'PAYMENT_NETWORK_ERROR',
18
+ unknown_product: 'PAYMENT_UNKNOWN_PRODUCT',
19
+ ineligible: 'PAYMENT_INELIGIBLE',
20
+ product_unavailable_in_region: 'PAYMENT_PRODUCT_UNAVAILABLE_IN_REGION'
21
+ };
22
+
23
+ /** Maps a provider failure onto the public vocabulary, so no store code leaks out. */
24
+ function mapFailure(reason, productKey, status) {
25
+ switch (reason) {
26
+ case 'user_cancelled':
27
+ return {
28
+ kind: 'user_cancelled',
29
+ productKey
30
+ };
31
+ case 'already_owned':
32
+ return {
33
+ kind: 'already_owned',
34
+ productKey
35
+ };
36
+ case 'ineligible':
37
+ return {
38
+ kind: 'ineligible',
39
+ productKey
40
+ };
41
+ case 'unknown_product':
42
+ return {
43
+ kind: 'unknown_product',
44
+ productKey
45
+ };
46
+ case 'product_unavailable_in_region':
47
+ return {
48
+ kind: 'product_unavailable_in_region',
49
+ productKey
50
+ };
51
+ case 'not_ready':
52
+ // The engine's real status, not a guess (PAY-19).
53
+ return {
54
+ kind: 'not_ready',
55
+ status
56
+ };
57
+ case 'network_error':
58
+ return {
59
+ kind: 'network_error',
60
+ productKey
61
+ };
62
+ case 'timeout':
63
+ return {
64
+ kind: 'timeout',
65
+ productKey
66
+ };
67
+ case 'store_error':
68
+ return {
69
+ kind: 'store_error',
70
+ productKey,
71
+ code: 'PAYMENT_STORE_ERROR'
72
+ };
73
+ }
74
+ }
75
+
76
+ /** Plan-change parameters, which only `subscriptions.ts` supplies. */
77
+ //# sourceMappingURL=purchaseFailure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["FAILURE_CODES","exports","network_error","unknown_product","ineligible","product_unavailable_in_region","mapFailure","reason","productKey","status","kind","code"],"sourceRoot":"../../../src","sources":["engine/purchaseFailure.ts"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKO,MAAMA,aAAwE,GAAAC,OAAA,CAAAD,aAAA,GAAG;EACvFE,aAAa,EAAE,uBAAuB;EACtCC,eAAe,EAAE,yBAAyB;EAC1CC,UAAU,EAAE,oBAAoB;EAChCC,6BAA6B,EAAE;AAChC,CAAC;;AAED;AACO,SAASC,UAAUA,CACzBC,MAA6B,EAC7BC,UAAsB,EACtBC,MAAyB,EACR;EACjB,QAAQF,MAAM;IACb,KAAK,gBAAgB;MACpB,OAAO;QAAEG,IAAI,EAAE,gBAAgB;QAAEF;MAAW,CAAC;IAC9C,KAAK,eAAe;MACnB,OAAO;QAAEE,IAAI,EAAE,eAAe;QAAEF;MAAW,CAAC;IAC7C,KAAK,YAAY;MAChB,OAAO;QAAEE,IAAI,EAAE,YAAY;QAAEF;MAAW,CAAC;IAC1C,KAAK,iBAAiB;MACrB,OAAO;QAAEE,IAAI,EAAE,iBAAiB;QAAEF;MAAW,CAAC;IAC/C,KAAK,+BAA+B;MACnC,OAAO;QAAEE,IAAI,EAAE,+BAA+B;QAAEF;MAAW,CAAC;IAC7D,KAAK,WAAW;MACf;MACA,OAAO;QAAEE,IAAI,EAAE,WAAW;QAAED;MAAO,CAAC;IACrC,KAAK,eAAe;MACnB,OAAO;QAAEC,IAAI,EAAE,eAAe;QAAEF;MAAW,CAAC;IAC7C,KAAK,SAAS;MACb,OAAO;QAAEE,IAAI,EAAE,SAAS;QAAEF;MAAW,CAAC;IACvC,KAAK,aAAa;MACjB,OAAO;QAAEE,IAAI,EAAE,aAAa;QAAEF,UAAU;QAAEG,IAAI,EAAE;MAAsB,CAAC;EACzE;AACD;;AAEA","ignoreList":[]}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createReceiptValidation = createReceiptValidation;
7
+ var _mutex = require("../core/mutex.js");
8
+ var _errors = require("../diagnostics/errors.js");
9
+ /**
10
+ * Asking the app's backend whether a purchase is real (FR-069a, FR-072b).
11
+ *
12
+ * The hook is optional and bounded by a timeout, and its answer decides whether
13
+ * an entitlement is granted — so what happens when it throws, times out, or is
14
+ * absent is the whole point of this module. Split from the flow next door,
15
+ * which is about the sequence of store calls.
16
+ *
17
+ * A hook that could not answer is never an implicit approval: the configured
18
+ * `onValidationUnavailable` decides, and the default refuses.
19
+ */
20
+
21
+ /** What the backend decided about one purchase. */
22
+
23
+ function createReceiptValidation(deps) {
24
+ const {
25
+ resolved
26
+ } = deps;
27
+ const askHook = (hook, candidate) => (0, _mutex.withTimeout)(hook(candidate), resolved.timeouts.validateMs, () => new _errors.PaymentError({
28
+ code: 'PAYMENT_VALIDATION_UNAVAILABLE',
29
+ message: 'The validation hook did not answer in time',
30
+ operation: 'validate',
31
+ retryable: true
32
+ }));
33
+
34
+ /**
35
+ * Runs the app's backend check, if configured.
36
+ *
37
+ * Called for newly completed purchases only (FR-069a) — sync and restore trust
38
+ * a decision already made, which is what keeps restore working while the
39
+ * backend is unreachable.
40
+ */
41
+ const validate = async (purchase, productKey, correlationId) => {
42
+ const hook = deps.config.validateTransaction;
43
+ if (!hook) {
44
+ return {
45
+ outcome: 'approved'
46
+ };
47
+ }
48
+ const entry = resolved.entries.get(productKey);
49
+ try {
50
+ const decision = await askHook(hook, {
51
+ productKey,
52
+ productType: entry?.productType ?? 'one_time_permanent',
53
+ verificationPayload: purchase.verificationPayload ?? '',
54
+ correlationId,
55
+ transactionId: purchase.transactionId,
56
+ platform: deps.platform
57
+ });
58
+ deps.emit({
59
+ type: 'validation_decided',
60
+ productKey,
61
+ decision: decision.approved ? 'approved' : 'rejected'
62
+ });
63
+ return decision.approved ? {
64
+ outcome: 'approved'
65
+ } : {
66
+ outcome: 'rejected',
67
+ reason: decision.reason
68
+ };
69
+ } catch {
70
+ // A hook that throws is unavailable, never an implicit approval (FR-072b).
71
+ const fallback = resolved.onValidationUnavailable;
72
+ deps.emit({
73
+ type: 'validation_unavailable',
74
+ productKey,
75
+ fallback
76
+ });
77
+ return fallback === 'grant_and_queue' ? {
78
+ outcome: 'granted_pending_revalidation'
79
+ } : {
80
+ outcome: 'rejected',
81
+ reason: 'validation_unavailable'
82
+ };
83
+ }
84
+ };
85
+ return {
86
+ askHook,
87
+ validate
88
+ };
89
+ }
90
+ //# sourceMappingURL=receiptValidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_mutex","require","_errors","createReceiptValidation","deps","resolved","askHook","hook","candidate","withTimeout","timeouts","validateMs","PaymentError","code","message","operation","retryable","validate","purchase","productKey","correlationId","config","validateTransaction","outcome","entry","entries","get","decision","productType","verificationPayload","transactionId","platform","emit","type","approved","reason","fallback","onValidationUnavailable"],"sourceRoot":"../../../src","sources":["engine/receiptValidation.ts"],"mappings":";;;;;;AAeA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAhBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAeA;;AAMO,SAASE,uBAAuBA,CAACC,IAA2B,EAAE;EACpE,MAAM;IAAEC;EAAS,CAAC,GAAGD,IAAI;EAEzB,MAAME,OAAO,GAAGA,CACfC,IAAuD,EACvDC,SAA2E,KAE3E,IAAAC,kBAAW,EACVF,IAAI,CAACC,SAAS,CAAC,EACfH,QAAQ,CAACK,QAAQ,CAACC,UAAU,EAC5B,MACC,IAAIC,oBAAY,CAAC;IAChBC,IAAI,EAAE,gCAAgC;IACtCC,OAAO,EAAE,4CAA4C;IACrDC,SAAS,EAAE,UAAU;IACrBC,SAAS,EAAE;EACZ,CAAC,CACH,CAAC;;EAEF;AACD;AACA;AACA;AACA;AACA;AACA;EACC,MAAMC,QAAQ,GAAG,MAAAA,CAChBC,QAA0B,EAC1BC,UAAsB,EACtBC,aAAqB,KAKjB;IACJ,MAAMb,IAAI,GAAGH,IAAI,CAACiB,MAAM,CAACC,mBAAmB;IAC5C,IAAI,CAACf,IAAI,EAAE;MACV,OAAO;QAAEgB,OAAO,EAAE;MAAW,CAAC;IAC/B;IAEA,MAAMC,KAAK,GAAGnB,QAAQ,CAACoB,OAAO,CAACC,GAAG,CAACP,UAAU,CAAC;IAC9C,IAAI;MACH,MAAMQ,QAAQ,GAAG,MAAMrB,OAAO,CAACC,IAAI,EAAE;QACpCY,UAAU;QACVS,WAAW,EAAEJ,KAAK,EAAEI,WAAW,IAAI,oBAAoB;QACvDC,mBAAmB,EAAEX,QAAQ,CAACW,mBAAmB,IAAI,EAAE;QACvDT,aAAa;QACbU,aAAa,EAAEZ,QAAQ,CAACY,aAAa;QACrCC,QAAQ,EAAE3B,IAAI,CAAC2B;MAChB,CAAC,CAAC;MACF3B,IAAI,CAAC4B,IAAI,CAAC;QACTC,IAAI,EAAE,oBAAoB;QAC1Bd,UAAU;QACVQ,QAAQ,EAAEA,QAAQ,CAACO,QAAQ,GAAG,UAAU,GAAG;MAC5C,CAAC,CAAC;MACF,OAAOP,QAAQ,CAACO,QAAQ,GACrB;QAAEX,OAAO,EAAE;MAAW,CAAC,GACvB;QAAEA,OAAO,EAAE,UAAU;QAAEY,MAAM,EAAER,QAAQ,CAACQ;MAAO,CAAC;IACpD,CAAC,CAAC,MAAM;MACP;MACA,MAAMC,QAAQ,GAAG/B,QAAQ,CAACgC,uBAAuB;MACjDjC,IAAI,CAAC4B,IAAI,CAAC;QAAEC,IAAI,EAAE,wBAAwB;QAAEd,UAAU;QAAEiB;MAAS,CAAC,CAAC;MACnE,OAAOA,QAAQ,KAAK,iBAAiB,GAClC;QAAEb,OAAO,EAAE;MAA+B,CAAC,GAC3C;QAAEA,OAAO,EAAE,UAAU;QAAEY,MAAM,EAAE;MAAyB,CAAC;IAC7D;EACD,CAAC;EAED,OAAO;IAAE7B,OAAO;IAAEW;EAAS,CAAC;AAC7B","ignoreList":[]}