@chipmobilesdk/rn-payment 0.6.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 (295) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/README.md +1 -1
  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
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createSync = createSync;
7
+ exports.toPersistedRecord = toPersistedRecord;
8
+ var _errors = require("../diagnostics/errors.js");
9
+ var _mapping = require("../entitlements/mapping.js");
10
+ var _mutex = require("../core/mutex.js");
11
+ var _snapshot = require("../persistence/snapshot.js");
12
+ /**
13
+ * Syncing with the store, and the one translation from a store purchase to a
14
+ * persisted record (PAY-10).
15
+ *
16
+ * The purchase flow and sync both build records here, so they cannot disagree
17
+ * about what a transaction still owes: a disagreement is how a paid purchase
18
+ * goes unacknowledged and is refunded three days later.
19
+ */
20
+
21
+ /** The persisted record for one store purchase, keeping what we already knew about it. */
22
+ function toPersistedRecord(resolved, purchase, productKey, existing) {
23
+ return {
24
+ transactionId: purchase.transactionId,
25
+ productKey,
26
+ productType: resolved.entries.get(productKey)?.productType ?? 'one_time_permanent',
27
+ token: purchase.token,
28
+ state: purchase.state === 'pending' ? 'pending' : 'purchased',
29
+ purchasedAt: purchase.purchasedAt,
30
+ // Finalize progress survives: a sync must never reset a queued
31
+ // acknowledgement and lose the paid transaction.
32
+ finalizeState: (0, _snapshot.resolveFinalizeState)(purchase, existing),
33
+ attempts: existing?.attempts ?? 0,
34
+ validationState: existing?.validationState ?? 'not_required',
35
+ expiresAt: purchase.expiresAt,
36
+ willAutoRenew: purchase.willAutoRenew
37
+ };
38
+ }
39
+
40
+ /** Store purchases as records, dropping products this catalog does not know. */
41
+ function toPersisted(resolved, purchases, known) {
42
+ const records = [];
43
+ for (const purchase of purchases) {
44
+ // Legitimately possible: a user owns something from a build whose catalog
45
+ // has since changed. Ignored rather than treated as impossible.
46
+ const productKey = (0, _mapping.productKeyForStoreId)(resolved, purchase.storeProductId);
47
+ if (!productKey || !resolved.entries.has(productKey)) {
48
+ continue;
49
+ }
50
+ const existing = known.find(p => p.transactionId === purchase.transactionId);
51
+ if (purchase.state === 'unspecified') {
52
+ // No basis for granting, finalizing or ending anything: a new transaction
53
+ // waits until the store says what it is, a known one keeps what we knew.
54
+ if (existing) {
55
+ records.push(existing);
56
+ }
57
+ continue;
58
+ }
59
+ records.push(toPersistedRecord(resolved, purchase, productKey, existing));
60
+ }
61
+ return records;
62
+ }
63
+ function purchasedIds(records) {
64
+ return new Set(records.filter(p => p.state === 'purchased').map(p => p.transactionId));
65
+ }
66
+ /**
67
+ * `settle` runs after every successful sync, outside the sync flight: the finalize
68
+ * drain and backend revalidation (FR-039, FR-042, FR-072a). Inside the flight, one
69
+ * store call or hook that never answered held it, and every later sync joined
70
+ * that stuck promise for the rest of the session.
71
+ */
72
+ function createSync(state, settle) {
73
+ const {
74
+ resolved,
75
+ provider,
76
+ now
77
+ } = state;
78
+ const syncFlight = (0, _mutex.createSingleFlight)();
79
+ const settleFlight = (0, _mutex.createSingleFlight)();
80
+ const foregroundLimiter = (0, _mutex.createRateLimiter)(resolved.foregroundSyncMinIntervalMs, now);
81
+ async function querySnapshot(trigger) {
82
+ try {
83
+ const owned = await (0, _mutex.withTimeout)(provider.queryOwned(), resolved.timeouts.syncMs, () => new _errors.PaymentError({
84
+ code: 'PAYMENT_TIMEOUT',
85
+ message: 'Syncing entitlements timed out',
86
+ operation: 'sync',
87
+ retryable: true
88
+ }));
89
+ const before = purchasedIds(state.snapshot.purchases);
90
+ const records = toPersisted(resolved, owned, state.snapshot.purchases);
91
+ const after = purchasedIds(records);
92
+ // A transaction the store no longer reports is revoked — a refund. The
93
+ // cache must not resurrect it (FR-064, FR-055).
94
+ const revokedCount = [...before].filter(id => !after.has(id)).length;
95
+ const restoredCount = [...after].filter(id => !before.has(id)).length;
96
+ state.hasSynced = true;
97
+ state.commit({
98
+ ...state.snapshot,
99
+ purchases: records,
100
+ lastSyncedAt: now()
101
+ });
102
+ state.emit({
103
+ type: 'sync_completed',
104
+ restoredCount,
105
+ revokedCount,
106
+ trigger
107
+ });
108
+ return {
109
+ ok: true,
110
+ restoredCount,
111
+ revokedCount
112
+ };
113
+ } catch (error) {
114
+ const paymentError = error instanceof _errors.PaymentError ? error : new _errors.PaymentError({
115
+ code: 'PAYMENT_STORE_ERROR',
116
+ message: 'Sync failed',
117
+ operation: 'sync',
118
+ retryable: true
119
+ });
120
+ // A failed sync leaves the previous snapshot in place, so offline
121
+ // entitlements survive rather than being wiped (FR-053).
122
+ state.emit({
123
+ type: 'internal_error',
124
+ code: paymentError.code,
125
+ operation: 'sync'
126
+ });
127
+ return {
128
+ ok: false,
129
+ error: paymentError
130
+ };
131
+ }
132
+ }
133
+ return {
134
+ async sync(trigger = 'manual') {
135
+ if (state.disposed || !resolved.enabled) {
136
+ return {
137
+ ok: false,
138
+ error: new _errors.PaymentError({
139
+ code: 'PAYMENT_DISABLED',
140
+ message: 'Payments are disabled',
141
+ operation: 'sync'
142
+ })
143
+ };
144
+ }
145
+ // Rejected rather than deferred: the next foreground event tries again,
146
+ // whereas queueing would fire a burst once the interval elapsed (PERF-002).
147
+ if (trigger === 'foreground' && !foregroundLimiter.tryAcquire()) {
148
+ return {
149
+ ok: true,
150
+ restoredCount: 0,
151
+ revokedCount: 0
152
+ };
153
+ }
154
+ // Concurrent callers join one flight: one store request (FR-063).
155
+ const outcome = await syncFlight.run(() => querySnapshot(trigger));
156
+ if (outcome.ok) {
157
+ await settleFlight.run(settle);
158
+ }
159
+ return outcome;
160
+ }
161
+ };
162
+ }
163
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_errors","require","_mapping","_mutex","_snapshot","toPersistedRecord","resolved","purchase","productKey","existing","transactionId","productType","entries","get","token","state","purchasedAt","finalizeState","resolveFinalizeState","attempts","validationState","expiresAt","willAutoRenew","toPersisted","purchases","known","records","productKeyForStoreId","storeProductId","has","find","p","push","purchasedIds","Set","filter","map","createSync","settle","provider","now","syncFlight","createSingleFlight","settleFlight","foregroundLimiter","createRateLimiter","foregroundSyncMinIntervalMs","querySnapshot","trigger","owned","withTimeout","queryOwned","timeouts","syncMs","PaymentError","code","message","operation","retryable","before","snapshot","after","revokedCount","id","length","restoredCount","hasSynced","commit","lastSyncedAt","emit","type","ok","error","paymentError","sync","disposed","enabled","tryAcquire","outcome","run"],"sourceRoot":"../../../src","sources":["engine/sync.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.aggregate = aggregate;
7
+ exports.diffEntitlements = diffEntitlements;
8
+ exports.initialEntitlements = initialEntitlements;
9
+ exports.shareUnchanged = shareUnchanged;
10
+ exports.snapshotCertainty = snapshotCertainty;
11
+ var _rnCore = require("@chipmobilesdk/rn-core");
12
+ var _mapping = require("./mapping.js");
13
+ var _policy = require("./policy.js");
14
+ /**
15
+ * Entitlement aggregation — the package's primary output.
16
+ *
17
+ * Everything else exists to make this one answer correct. The most damaging
18
+ * defect class in a payment SDK lives here: collapsing "not yet synced" into "not
19
+ * entitled" makes a paying user watch ads flash on cold start or see a purchased
20
+ * feature sit locked.
21
+ *
22
+ * Two rules do most of the work:
23
+ *
24
+ * - **A pending purchase is never a source** (FR-037). Enforced here, in
25
+ * aggregation, rather than at each call site, so no future code path can grant
26
+ * on money that has not arrived.
27
+ * - **Uncertainty resolves to `unknown`, never `not_entitled`** (FR-047,
28
+ * FR-055a). Never synced, stale, or scope-changed all mean "we do not know",
29
+ * and the package says so rather than asserting the user did not pay.
30
+ */
31
+
32
+ /** A purchase that currently confers its entitlements. */
33
+ function isValidSource(purchase, input) {
34
+ // Only a purchase the store confirmed grants. Pending money is not money, and a
35
+ // state this version does not know is no basis for a grant either (PAY-13).
36
+ if (purchase.state !== 'purchased') {
37
+ return false;
38
+ }
39
+ // A backend that said no is final (FR-071). A queued re-validation still
40
+ // grants, which is the documented `grant_and_queue` fallback (FR-072).
41
+ if (purchase.validationState === 'rejected') {
42
+ return false;
43
+ }
44
+ if (purchase.productType === 'subscription') {
45
+ if ((0, _policy.hasExpired)(purchase.expiresAt, input.now)) {
46
+ return false;
47
+ }
48
+ const renewalState = (0, _policy.deriveRenewalState)({
49
+ expiresAt: purchase.expiresAt,
50
+ willAutoRenew: purchase.willAutoRenew,
51
+ reportsGraceAndHoldDistinctly: input.reportsGraceAndHoldDistinctly
52
+ });
53
+ return (0, _policy.grantsUnderPolicy)(renewalState, {
54
+ gracePolicy: input.config.gracePolicy,
55
+ holdPolicy: input.config.holdPolicy
56
+ });
57
+ }
58
+
59
+ // A consumable that has not been consumed yet is owned, but it must never
60
+ // become a permanent entitlement — consumption flips it to `consumed` above.
61
+ return true;
62
+ }
63
+ function subscriptionDetailFor(purchases, input) {
64
+ const subs = purchases.filter(p => p.productType === 'subscription');
65
+ if (subs.length === 0) {
66
+ return undefined;
67
+ }
68
+
69
+ // Where several subscriptions grant one entitlement, the one running longest
70
+ // is what the user experiences, so report that one.
71
+ const furthest = subs.reduce((best, candidate) => {
72
+ const bestAt = best.expiresAt ?? Number.MAX_SAFE_INTEGER;
73
+ const candidateAt = candidate.expiresAt ?? Number.MAX_SAFE_INTEGER;
74
+ return candidateAt > bestAt ? candidate : best;
75
+ });
76
+ const renewalState = (0, _policy.deriveRenewalState)({
77
+ expiresAt: furthest.expiresAt,
78
+ willAutoRenew: furthest.willAutoRenew,
79
+ reportsGraceAndHoldDistinctly: input.reportsGraceAndHoldDistinctly
80
+ });
81
+ return {
82
+ expiresAt: furthest.expiresAt,
83
+ willAutoRenew: furthest.willAutoRenew === true,
84
+ isCancelledButValid: renewalState === 'cancelled_valid',
85
+ renewalState
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Computes the full entitlement map.
91
+ *
92
+ * Pure and synchronous by design: it runs on render paths, so it must never
93
+ * touch I/O (PERF-001). The engine calls it after any state change and caches the
94
+ * result.
95
+ */
96
+ /**
97
+ * How far the snapshot can be trusted right now.
98
+ *
99
+ * Shared by entitlements and the pending set (FR-103) so the two can never
100
+ * disagree about whether the package knows anything — a paywall that showed
101
+ * "not entitled" next to "nothing pending" from one stale snapshot would offer
102
+ * Buy to a user whose payment is in flight.
103
+ */
104
+ function snapshotCertainty(input) {
105
+ const {
106
+ config,
107
+ snapshot,
108
+ hasSynced,
109
+ now
110
+ } = input;
111
+ const isStale = snapshot.lastSyncedAt !== undefined && now - snapshot.lastSyncedAt > config.staleAfterMs;
112
+
113
+ // Both roads lead to `unknown`, never to a confident "no". Never having synced
114
+ // and having synced too long ago are the same epistemic state: we cannot
115
+ // currently support a claim either way.
116
+ return {
117
+ isStale,
118
+ undetermined: !hasSynced || isStale
119
+ };
120
+ }
121
+ function aggregate(input) {
122
+ const {
123
+ config,
124
+ snapshot
125
+ } = input;
126
+ const {
127
+ isStale,
128
+ undetermined
129
+ } = snapshotCertainty(input);
130
+ const valid = snapshot.purchases.filter(p => isValidSource(p, input));
131
+ const result = {};
132
+ for (const key of config.entitlementKeys) {
133
+ const granting = valid.filter(p => (0, _mapping.entitlementsFor)(config, p.productKey).includes(key));
134
+ const sources = [...new Set(granting.map(p => p.productKey))];
135
+ result[key] = {
136
+ key,
137
+ // An entitlement stays valid while at least one source remains (FR-052).
138
+ status: undetermined ? 'unknown' : sources.length > 0 ? 'entitled' : 'not_entitled',
139
+ sources,
140
+ subscription: subscriptionDetailFor(granting, input),
141
+ lastSyncedAt: snapshot.lastSyncedAt,
142
+ isStale
143
+ };
144
+ }
145
+ return result;
146
+ }
147
+
148
+ /** The initial map, before anything is known. Every key starts at `unknown` (FR-047). */
149
+ function initialEntitlements(config) {
150
+ const result = {};
151
+ for (const key of config.entitlementKeys) {
152
+ result[key] = {
153
+ key,
154
+ status: 'unknown',
155
+ sources: [],
156
+ lastSyncedAt: undefined,
157
+ isStale: false
158
+ };
159
+ }
160
+ return result;
161
+ }
162
+ /**
163
+ * Diffs two maps to produce change signals.
164
+ *
165
+ * Emitting from a diff rather than from grant call sites is what makes the
166
+ * exactly-once guarantees structural (FR-079): a successful subscription renewal
167
+ * changes no status, so it produces no event and cannot double-signal (FR-068);
168
+ * and an entitlement with three sources fires once on transition, not once per
169
+ * source.
170
+ */
171
+ function diffEntitlements(previous, next) {
172
+ const changes = [];
173
+ for (const key of Object.keys(next)) {
174
+ const before = previous[key]?.status ?? 'unknown';
175
+ const after = next[key].status;
176
+ if (before !== after) {
177
+ changes.push({
178
+ key,
179
+ previous: before,
180
+ next: after,
181
+ sources: next[key].sources
182
+ });
183
+ }
184
+ }
185
+ return changes;
186
+ }
187
+ function sameEntitlement(a, b) {
188
+ return a.status === b.status && a.isStale === b.isStale && a.lastSyncedAt === b.lastSyncedAt && a.sources.length === b.sources.length && a.sources.every((source, index) => source === b.sources[index]) && (0, _rnCore.shallowEqual)(a.subscription, b.subscription);
189
+ }
190
+
191
+ /**
192
+ * `next`, with every entitlement that did not change replaced by the object it
193
+ * replaces, and `previous` itself when nothing changed (PERF-03, PAY-08). A hook
194
+ * selecting one entitlement then sees the same object and does not re-render.
195
+ */
196
+ function shareUnchanged(previous, next) {
197
+ const keys = Object.keys(next);
198
+ let changed = keys.length !== Object.keys(previous).length;
199
+ const shared = {};
200
+ for (const key of keys) {
201
+ const before = previous[key];
202
+ const after = next[key];
203
+ if (before && sameEntitlement(before, after)) {
204
+ shared[key] = before;
205
+ } else {
206
+ shared[key] = after;
207
+ changed = true;
208
+ }
209
+ }
210
+ return changed ? shared : previous;
211
+ }
212
+ //# sourceMappingURL=aggregate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_rnCore","require","_mapping","_policy","isValidSource","purchase","input","state","validationState","productType","hasExpired","expiresAt","now","renewalState","deriveRenewalState","willAutoRenew","reportsGraceAndHoldDistinctly","grantsUnderPolicy","gracePolicy","config","holdPolicy","subscriptionDetailFor","purchases","subs","filter","p","length","undefined","furthest","reduce","best","candidate","bestAt","Number","MAX_SAFE_INTEGER","candidateAt","isCancelledButValid","snapshotCertainty","snapshot","hasSynced","isStale","lastSyncedAt","staleAfterMs","undetermined","aggregate","valid","result","key","entitlementKeys","granting","entitlementsFor","productKey","includes","sources","Set","map","status","subscription","initialEntitlements","diffEntitlements","previous","next","changes","Object","keys","before","after","push","sameEntitlement","a","b","every","source","index","shallowEqual","shareUnchanged","changed","shared"],"sourceRoot":"../../../src","sources":["entitlements/aggregate.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.entitlementsFor = entitlementsFor;
7
+ exports.productKeyForStoreId = productKeyForStoreId;
8
+ exports.storeIdForProductKey = storeIdForProductKey;
9
+ /**
10
+ * Product ↔ entitlement indexing.
11
+ *
12
+ * The relation is many-to-many (FR-010): monthly, yearly, and lifetime products
13
+ * may all grant `no_ads`, and one bundle product may grant several entitlements.
14
+ *
15
+ * Both directions are indexed once at configure time. The reverse direction is
16
+ * what makes two requirements cheap on hot paths: naming which product currently
17
+ * grants an entitlement (FR-051), and keeping an entitlement valid while *any*
18
+ * source remains (FR-052).
19
+ */
20
+
21
+ /** Entitlements a product confers. Empty for an unknown key rather than throwing. */
22
+ function entitlementsFor(config, productKey) {
23
+ return config.grants.get(productKey) ?? [];
24
+ }
25
+
26
+ /**
27
+ * Translates a store product id back to the app's own product key.
28
+ *
29
+ * Needed because store callbacks and `queryOwned` speak in store ids, while
30
+ * everything above the adapter speaks in product keys (FR-003). Returns
31
+ * `undefined` for an id absent from the catalog — which happens legitimately when
32
+ * a user owns something from a build whose catalog has since changed, so it must
33
+ * be handled rather than treated as impossible.
34
+ */
35
+ function productKeyForStoreId(config, storeProductId) {
36
+ return config.byStoreId.get(storeProductId);
37
+ }
38
+ function storeIdForProductKey(config, productKey) {
39
+ return config.entries.get(productKey)?.storeProductIds[config.platform];
40
+ }
41
+ //# sourceMappingURL=mapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["entitlementsFor","config","productKey","grants","get","productKeyForStoreId","storeProductId","byStoreId","storeIdForProductKey","entries","storeProductIds","platform"],"sourceRoot":"../../../src","sources":["entitlements/mapping.ts"],"mappings":";;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKA;AACO,SAASA,eAAeA,CAC9BC,MAAsB,EACtBC,UAAsB,EACM;EAC5B,OAAOD,MAAM,CAACE,MAAM,CAACC,GAAG,CAACF,UAAU,CAAC,IAAI,EAAE;AAC3C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,oBAAoBA,CACnCJ,MAAsB,EACtBK,cAAsB,EACG;EACzB,OAAOL,MAAM,CAACM,SAAS,CAACH,GAAG,CAACE,cAAc,CAAC;AAC5C;AAEO,SAASE,oBAAoBA,CACnCP,MAAsB,EACtBC,UAAsB,EACD;EACrB,OAAOD,MAAM,CAACQ,OAAO,CAACL,GAAG,CAACF,UAAU,CAAC,EAAEQ,eAAe,CAACT,MAAM,CAACU,QAAQ,CAAC;AACxE","ignoreList":[]}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.deriveRenewalState = deriveRenewalState;
7
+ exports.grantsUnderPolicy = grantsUnderPolicy;
8
+ exports.hasExpired = hasExpired;
9
+ /**
10
+ * Grace and hold entitlement policy.
11
+ *
12
+ * This is a **business decision, not a technical constant** (FR-049), so it is
13
+ * configurable with documented defaults.
14
+ *
15
+ * ## The defaults, and why
16
+ *
17
+ * `gracePolicy: 'grant'` — a grace period means the store is still retrying a
18
+ * payment method that failed for reasons usually outside the user's control: an
19
+ * expired card, a bank decline, a temporary hold. Revoking immediately punishes a
20
+ * paying customer for a billing hiccup they may not know about yet.
21
+ *
22
+ * `holdPolicy: 'withhold'` — account hold means the store has given up retrying.
23
+ * The subscription is effectively unpaid, and continuing to serve paid features
24
+ * indefinitely is giving away the product.
25
+ *
26
+ * ## What Android can actually tell us
27
+ *
28
+ * Client-side Play Billing **cannot** separate grace from hold: a grace-period
29
+ * subscription is still returned as active, and one in account hold stops being
30
+ * returned at all — indistinguishable from expired, cancelled, or refunded.
31
+ *
32
+ * Fortunately the platform's own behavior matches the defaults above. Play keeps
33
+ * returning a grace-period purchase, so the entitlement holds. Play stops
34
+ * returning a held one, so it lapses at the next sync. **The default policy is
35
+ * therefore correct with no backend at all.**
36
+ *
37
+ * What is *not* achievable client-side is a non-default policy — withholding
38
+ * during grace, or granting during hold — because that needs the state the client
39
+ * cannot see. Such an app supplies it through the validation hook (FR-069). This
40
+ * limitation is documented rather than papered over (FR-058).
41
+ */
42
+
43
+ /**
44
+ * A subscription's renewal state as far as the package can honestly tell.
45
+ *
46
+ * `indeterminate` is not a failure — it is the truthful answer when the platform
47
+ * reports a subscription as active but cannot say whether that is a healthy
48
+ * renewal, a cancelled-but-still-paid period, or a grace period.
49
+ */
50
+
51
+ /**
52
+ * Derives the renewal state without inventing information.
53
+ *
54
+ * The temptation is to read `willAutoRenew === false` as "grace period", but that
55
+ * same value is what a deliberate cancellation looks like. Guessing would mean
56
+ * showing "there's a problem with your payment method" to someone who simply
57
+ * chose not to renew — so when the provider cannot distinguish, neither do we.
58
+ */
59
+ function deriveRenewalState(facts) {
60
+ if (facts.reportsGraceAndHoldDistinctly && facts.providerRenewalState) {
61
+ switch (facts.providerRenewalState) {
62
+ case 'grace':
63
+ return 'grace';
64
+ case 'hold':
65
+ return 'hold';
66
+ case 'active':
67
+ return facts.willAutoRenew === false ? 'cancelled_valid' : 'active';
68
+ }
69
+ }
70
+ if (facts.willAutoRenew === false) {
71
+ // Still inside a paid period with auto-renew off. Genuinely ambiguous
72
+ // between "cancelled" and "in grace", so report the one that is certainly
73
+ // true — the period is paid for — and let the app decide how to present it.
74
+ return 'cancelled_valid';
75
+ }
76
+ if (facts.willAutoRenew === true) {
77
+ return 'active';
78
+ }
79
+ return 'indeterminate';
80
+ }
81
+
82
+ /**
83
+ * Whether a subscription in this state should confer its entitlement.
84
+ *
85
+ * `hold` reaching this function at all requires a provider that reports it,
86
+ * which Android does not. On Android a held subscription simply stops being
87
+ * returned, so it never becomes a source and the entitlement lapses — the same
88
+ * result the `withhold` default expresses.
89
+ */
90
+ function grantsUnderPolicy(state, policy) {
91
+ switch (state) {
92
+ case 'active':
93
+ case 'cancelled_valid':
94
+ return true;
95
+ case 'grace':
96
+ return policy.gracePolicy === 'grant';
97
+ case 'hold':
98
+ return policy.holdPolicy === 'grant';
99
+ case 'indeterminate':
100
+ // The store is still reporting the purchase as owned. Withholding here
101
+ // would revoke from a paying user because of our own uncertainty.
102
+ return true;
103
+ }
104
+ }
105
+
106
+ /** True once a subscription's paid period has genuinely elapsed (FR-048). */
107
+ function hasExpired(expiresAt, now) {
108
+ return expiresAt !== undefined && expiresAt <= now;
109
+ }
110
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["deriveRenewalState","facts","reportsGraceAndHoldDistinctly","providerRenewalState","willAutoRenew","grantsUnderPolicy","state","policy","gracePolicy","holdPolicy","hasExpired","expiresAt","now","undefined"],"sourceRoot":"../../../src","sources":["entitlements/policy.ts"],"mappings":";;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;AAiBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,kBAAkBA,CAACC,KAAwB,EAAgB;EAC1E,IAAIA,KAAK,CAACC,6BAA6B,IAAID,KAAK,CAACE,oBAAoB,EAAE;IACtE,QAAQF,KAAK,CAACE,oBAAoB;MACjC,KAAK,OAAO;QACX,OAAO,OAAO;MACf,KAAK,MAAM;QACV,OAAO,MAAM;MACd,KAAK,QAAQ;QACZ,OAAOF,KAAK,CAACG,aAAa,KAAK,KAAK,GAAG,iBAAiB,GAAG,QAAQ;IACrE;EACD;EAEA,IAAIH,KAAK,CAACG,aAAa,KAAK,KAAK,EAAE;IAClC;IACA;IACA;IACA,OAAO,iBAAiB;EACzB;EAEA,IAAIH,KAAK,CAACG,aAAa,KAAK,IAAI,EAAE;IACjC,OAAO,QAAQ;EAChB;EAEA,OAAO,eAAe;AACvB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,iBAAiBA,CAACC,KAAmB,EAAEC,MAAyB,EAAW;EAC1F,QAAQD,KAAK;IACZ,KAAK,QAAQ;IACb,KAAK,iBAAiB;MACrB,OAAO,IAAI;IACZ,KAAK,OAAO;MACX,OAAOC,MAAM,CAACC,WAAW,KAAK,OAAO;IACtC,KAAK,MAAM;MACV,OAAOD,MAAM,CAACE,UAAU,KAAK,OAAO;IACrC,KAAK,eAAe;MACnB;MACA;MACA,OAAO,IAAI;EACb;AACD;;AAEA;AACO,SAASC,UAAUA,CAACC,SAA6B,EAAEC,GAAW,EAAW;EAC/E,OAAOD,SAAS,KAAKE,SAAS,IAAIF,SAAS,IAAIC,GAAG;AACnD","ignoreList":[]}