@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,158 @@
1
+ /**
2
+ * Typed events and the emitter.
3
+ *
4
+ * The bar is FR-077: the event stream **alone** must be enough to reconstruct a
5
+ * transaction's full lifecycle, so that "the user says they paid but has no
6
+ * entitlement" can be investigated from logs without a reproduction.
7
+ *
8
+ * Forbidden in every payload, without exception (FR-076, FR-074): store objects,
9
+ * raw receipts, verification payloads, backend tokens, payment details, the
10
+ * obfuscated account identifier, and the cache-scope token.
11
+ */
12
+ import { redact, type PaymentErrorCode, type PaymentOperation } from './errors.js';
13
+ import type { EntitlementKey, Environment, PendingResolution, ProductKey, Unsubscribe, UnavailableReason, PaymentStatusKind } from '../config/types.js';
14
+ export type PaymentEventType = 'initialization' | 'connection_changed' | 'products_queried' | 'purchase_started' | 'purchase_succeeded' | 'purchase_cancelled' | 'purchase_pending' | 'purchase_pending_resolved' | 'purchase_failed' | 'transaction_finalized' | 'transaction_consumed' | 'finalize_retry_scheduled' | 'sync_completed' | 'entitlement_granted' | 'entitlement_revoked' | 'validation_decided' | 'validation_unavailable' | 'environment_blocked' | 'config_warning' | 'internal_error';
15
+ interface BaseEvent {
16
+ timestamp: number;
17
+ /** Ties one purchase cycle together end to end. Absent for lifecycle events. */
18
+ correlationId?: string;
19
+ }
20
+ export type SyncTrigger = 'initialize' | 'foreground' | 'manual' | 'already_owned';
21
+ export type PaymentEvent = BaseEvent & ({
22
+ type: 'initialization';
23
+ status: PaymentStatusKind;
24
+ unavailableReason?: UnavailableReason;
25
+ retryable?: boolean;
26
+ } | {
27
+ type: 'connection_changed';
28
+ connected: boolean;
29
+ reason?: string;
30
+ attempt?: number;
31
+ } | {
32
+ type: 'products_queried';
33
+ productKeys: ProductKey[];
34
+ found: number;
35
+ missing: ProductKey[];
36
+ fromCache: boolean;
37
+ } | {
38
+ type: 'purchase_started';
39
+ productKey: ProductKey;
40
+ } | {
41
+ type: 'purchase_succeeded';
42
+ productKey: ProductKey;
43
+ } | {
44
+ type: 'purchase_cancelled';
45
+ productKey: ProductKey;
46
+ } | {
47
+ type: 'purchase_pending';
48
+ productKey: ProductKey;
49
+ } | {
50
+ type: 'purchase_pending_resolved';
51
+ productKey: ProductKey;
52
+ outcome: PendingResolution;
53
+ } | {
54
+ type: 'purchase_failed';
55
+ productKey: ProductKey;
56
+ code: PaymentErrorCode;
57
+ retryable: boolean;
58
+ } | {
59
+ type: 'transaction_finalized';
60
+ productKey: ProductKey;
61
+ attempts: number;
62
+ } | {
63
+ type: 'transaction_consumed';
64
+ productKey: ProductKey;
65
+ } | {
66
+ type: 'finalize_retry_scheduled';
67
+ productKey: ProductKey;
68
+ attempt: number;
69
+ delayMs: number;
70
+ } | {
71
+ type: 'sync_completed';
72
+ restoredCount: number;
73
+ revokedCount: number;
74
+ trigger: SyncTrigger;
75
+ } | {
76
+ type: 'entitlement_granted';
77
+ entitlementKey: EntitlementKey;
78
+ sources: ProductKey[];
79
+ } | {
80
+ type: 'entitlement_revoked';
81
+ entitlementKey: EntitlementKey;
82
+ reason: 'expired' | 'revoked_by_store' | 'validation_rejected' | 'consumed';
83
+ } | {
84
+ type: 'validation_decided';
85
+ productKey: ProductKey;
86
+ decision: 'approved' | 'rejected';
87
+ } | {
88
+ type: 'validation_unavailable';
89
+ productKey: ProductKey;
90
+ fallback: 'grant_and_queue' | 'withhold';
91
+ } | {
92
+ type: 'environment_blocked';
93
+ productKey: ProductKey;
94
+ environment: Environment;
95
+ } | {
96
+ type: 'config_warning';
97
+ detail: string;
98
+ } | {
99
+ type: 'internal_error';
100
+ code: PaymentErrorCode;
101
+ operation: PaymentOperation;
102
+ });
103
+ export type PaymentEventListener = (event: PaymentEvent) => void;
104
+ /**
105
+ * A `PaymentEvent` with the timestamp left to the emitter.
106
+ *
107
+ * Distributive on purpose: a plain `Omit<PaymentEvent, 'timestamp'>` collapses the
108
+ * discriminated union into one object type with only the shared keys, which would
109
+ * reject every variant-specific field. `T extends unknown` forces the mapping to
110
+ * apply per member and keeps the union discriminated.
111
+ */
112
+ type WithOptionalTimestamp<T> = T extends unknown ? Omit<T, 'timestamp'> & {
113
+ timestamp?: number;
114
+ } : never;
115
+ export type PaymentEventInput = WithOptionalTimestamp<PaymentEvent>;
116
+ export interface PaymentEmitter {
117
+ emit(event: PaymentEvent): void;
118
+ subscribe(listener: PaymentEventListener): Unsubscribe;
119
+ /** Disarms permanently. After this nothing is emitted (FR-082). */
120
+ dispose(): void;
121
+ listenerCount(): number;
122
+ disposed(): boolean;
123
+ }
124
+ /**
125
+ * Creates the emitter.
126
+ *
127
+ * Two properties are deliberate:
128
+ *
129
+ * 1. **A throwing listener cannot break anything** (FR-081). Each listener is
130
+ * invoked defensively, the throw is handed to `onListenerError`, and delivery
131
+ * continues to the remaining listeners. One app's broken analytics callback
132
+ * must not stop the package granting an entitlement or stop another listener
133
+ * hearing about it.
134
+ *
135
+ * The failure is **not** re-emitted as an event, deliberately. A consumer's own
136
+ * bug is not a payment-lifecycle event, and reporting it through the channel
137
+ * that just failed would both invite recursion and double event traffic for
138
+ * every event while that listener stays broken. It goes to the logger instead.
139
+ *
140
+ * 2. **After `dispose`, nothing is emitted** (FR-082). A store callback can
141
+ * arrive after cleanup; it must be dropped silently rather than reach a
142
+ * listener whose component is gone.
143
+ */
144
+ export declare function createEmitter(onListenerError?: (error: unknown, event: PaymentEvent) => void): PaymentEmitter;
145
+ /**
146
+ * Fields that must never appear in an event payload.
147
+ *
148
+ * Used by `__tests__/diagnostics.test.ts` to walk every emitted event across the
149
+ * whole suite. Enumerating the ban here rather than in the test keeps the rule
150
+ * next to the type it constrains.
151
+ */
152
+ export declare const FORBIDDEN_EVENT_FIELDS: readonly string[];
153
+ /** Correlation ids tie one purchase cycle together; no user data goes into them. */
154
+ export declare function createCorrelationId(counter: {
155
+ next: number;
156
+ }, prefix?: string): string;
157
+ export { redact };
158
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../../src/diagnostics/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Stable, localizable message keys with English default copy (FR-084, FR-085).
3
+ *
4
+ * The package takes no i18n runtime dependency: consuming apps map these keys to
5
+ * localized strings through whatever i18n system they already run. This is plain
6
+ * data, and the package never resolves or renders it.
7
+ *
8
+ * Message keys are **public API**: renaming one is a breaking change, on the
9
+ * same footing as an error code (FR-078).
10
+ *
11
+ * User-actionable copy and developer/configuration copy are kept in separate
12
+ * maps so an app cannot accidentally show "Payment catalog is invalid" to a
13
+ * customer — a configuration fault is a developer's problem, not a user's.
14
+ */
15
+ export interface PaymentUserMessageMap {
16
+ 'payment.state.pending': string;
17
+ 'payment.state.alreadyOwned': string;
18
+ 'payment.action.restore': string;
19
+ 'payment.restore.succeeded': string;
20
+ 'payment.restore.nothingFound': string;
21
+ 'payment.error.cancelled': string;
22
+ 'payment.error.network': string;
23
+ 'payment.error.unavailable': string;
24
+ 'payment.error.disabled': string;
25
+ 'payment.subscription.grace': string;
26
+ 'payment.subscription.hold': string;
27
+ }
28
+ /** Copy for developers and operators. **Never** surfaced to an end user. */
29
+ export interface PaymentDeveloperMessageMap {
30
+ 'payment.config.invalidCatalog': string;
31
+ 'payment.config.missingStoreId': string;
32
+ 'payment.config.productionInNonProductionBuild': string;
33
+ 'payment.config.storageUnavailable': string;
34
+ 'payment.config.environmentBlocked': string;
35
+ }
36
+ export type PaymentMessageMap = PaymentUserMessageMap & PaymentDeveloperMessageMap;
37
+ export type PaymentUserMessageKey = keyof PaymentUserMessageMap;
38
+ export type PaymentDeveloperMessageKey = keyof PaymentDeveloperMessageMap;
39
+ export type PaymentMessageKey = keyof PaymentMessageMap;
40
+ export declare const DEFAULT_USER_MESSAGES: PaymentUserMessageMap;
41
+ export declare const DEFAULT_DEVELOPER_MESSAGES: PaymentDeveloperMessageMap;
42
+ /**
43
+ * The catalog as an rn-core message set. Register `paymentMessages.user` with
44
+ * rn-i18n to translate it like app copy; the developer copy stays out of bundles.
45
+ */
46
+ export declare const paymentMessages: import("@chipmobilesdk/rn-core").MessageSet<PaymentUserMessageMap, PaymentDeveloperMessageMap>;
47
+ export declare const DEFAULT_MESSAGES: PaymentMessageMap;
48
+ /** Every user-actionable key, for an app building its translation resource. */
49
+ export declare const USER_MESSAGE_KEYS: PaymentUserMessageKey[];
50
+ /** Every developer-facing key, so an app can exclude them from user-visible bundles. */
51
+ export declare const DEVELOPER_MESSAGE_KEYS: PaymentDeveloperMessageKey[];
52
+ /** True for keys safe to show an end user. Lets an app assert that at its boundary. */
53
+ export declare function isUserMessageKey(key: PaymentMessageKey): key is PaymentUserMessageKey;
54
+ //# sourceMappingURL=messageKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messageKeys.d.ts","sourceRoot":"","sources":["../../../../src/diagnostics/messageKeys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,MAAM,WAAW,qBAAqB;IACrC,uBAAuB,EAAE,MAAM,CAAC;IAChC,4BAA4B,EAAE,MAAM,CAAC;IACrC,wBAAwB,EAAE,MAAM,CAAC;IACjC,2BAA2B,EAAE,MAAM,CAAC;IACpC,8BAA8B,EAAE,MAAM,CAAC;IACvC,yBAAyB,EAAE,MAAM,CAAC;IAClC,uBAAuB,EAAE,MAAM,CAAC;IAChC,2BAA2B,EAAE,MAAM,CAAC;IACpC,wBAAwB,EAAE,MAAM,CAAC;IACjC,4BAA4B,EAAE,MAAM,CAAC;IACrC,2BAA2B,EAAE,MAAM,CAAC;CACpC;AAED,4EAA4E;AAC5E,MAAM,WAAW,0BAA0B;IAC1C,+BAA+B,EAAE,MAAM,CAAC;IACxC,+BAA+B,EAAE,MAAM,CAAC;IACxC,+CAA+C,EAAE,MAAM,CAAC;IACxD,mCAAmC,EAAE,MAAM,CAAC;IAC5C,mCAAmC,EAAE,MAAM,CAAC;CAC5C;AAED,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG,0BAA0B,CAAC;AAEnF,MAAM,MAAM,qBAAqB,GAAG,MAAM,qBAAqB,CAAC;AAChE,MAAM,MAAM,0BAA0B,GAAG,MAAM,0BAA0B,CAAC;AAC1E,MAAM,MAAM,iBAAiB,GAAG,MAAM,iBAAiB,CAAC;AAExD,eAAO,MAAM,qBAAqB,EAAE,qBAYnC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,0BASxC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,gGAG1B,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,iBAA4C,CAAC;AAE5E,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,EAA+B,qBAAqB,EAAE,CAAC;AAErF,wFAAwF;AACxF,eAAO,MAAM,sBAAsB,EAAoC,0BAA0B,EAAE,CAAC;AAEpG,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,GAAG,GAAG,IAAI,qBAAqB,CAErF"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The billing connection: connecting, watching it, and reconnecting with bounded
3
+ * backoff (FR-018 – FR-024, PAY-10).
4
+ *
5
+ * A reconnect is always a full teardown-then-connect cycle. The upstream
6
+ * binding's own `reconnect()` has reported success without rebuilding anything
7
+ * (openiap#408), so no shortcut is trusted here.
8
+ */
9
+ import type { ProviderPurchase } from '../adapter/port.js';
10
+ import { PaymentError } from '../diagnostics/errors.js';
11
+ import type { EngineState } from './state.js';
12
+ export type InitOutcome = {
13
+ ok: true;
14
+ } | {
15
+ ok: false;
16
+ error: PaymentError;
17
+ };
18
+ export interface Connection {
19
+ /** Connects and attaches the watchers; status follows the outcome. */
20
+ connect(): Promise<InitOutcome>;
21
+ /**
22
+ * A fresh reconnect budget and one immediate attempt, when an earlier budget
23
+ * ran out: a foreground return is when the network the app lost is usually
24
+ * back.
25
+ */
26
+ recover(): Promise<void>;
27
+ dispose(): void;
28
+ }
29
+ export declare function createConnection(state: EngineState, onPurchase: (purchase: ProviderPurchase) => void): Connection;
30
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../src/engine/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAiB,CAAC;AAIxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAS,CAAC;AAE3C,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAE5E,MAAM,WAAW,UAAU;IAC1B,sEAAsE;IACtE,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAChC;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,GAC9C,UAAU,CAiKZ"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * The engine: status, initialization, entitlement reads, and sync.
3
+ *
4
+ * Owns the concurrency guarantees that make three requirements structurally true
5
+ * rather than hoped for — one connection under concurrent init (FR-018), one
6
+ * store request under concurrent sync (FR-063), and a rate-limited foreground
7
+ * sync (PERF-002).
8
+ *
9
+ * It never imports a store type. The only thing it talks to is `ProviderPort`,
10
+ * which is what keeps the binding replaceable and iOS additive (FR-002, FR-007).
11
+ *
12
+ * This file composes (PAY-10): state and its publication live in `state.ts`, the
13
+ * connection in `connection.ts`, sync in `sync.ts`, and the internals tests reach
14
+ * for in `internals.ts`, off the public type (PAY-11).
15
+ */
16
+ import type { ProviderPort } from '../adapter/port.js';
17
+ import { type TargetPlatform } from '../config/validate.js';
18
+ import type { EntitlementKey, FinalizeResult, PaymentConfig, PaymentStatus, PendingPurchasesState, ProductKey, PurchaseOptions, PurchaseResult, TransactionRef, UnfinalizedSummary, Unsubscribe } from '../config/types.js';
19
+ import { PaymentError } from '../diagnostics/errors.js';
20
+ import { type PaymentEventListener, type SyncTrigger } from '../diagnostics/events.js';
21
+ import type { EntitlementMap, EntitlementState } from '../entitlements/aggregate.js';
22
+ import { type SnapshotStore } from '../persistence/mmkv-store.js';
23
+ import { type InitOutcome } from './connection.js';
24
+ import { type ProductQueryResult } from './products.js';
25
+ import { type PriceChangeResult, type ProrationMode } from './subscriptions.js';
26
+ import { type SyncOutcome } from './sync.js';
27
+ export type { SyncOutcome } from './sync.js';
28
+ export type { InitOutcome } from './connection.js';
29
+ export type RestoreOutcome = {
30
+ ok: true;
31
+ restored: true;
32
+ entitlements: EntitlementKey[];
33
+ }
34
+ /** Distinct from a failure so an app never shows a false success (FR-061). */
35
+ | {
36
+ ok: true;
37
+ restored: false;
38
+ } | {
39
+ ok: false;
40
+ error: PaymentError;
41
+ };
42
+ export interface EngineDeps {
43
+ /** Injected so the fake store is a drop-in replacement (NFR-007). */
44
+ provider: ProviderPort;
45
+ snapshotStore?: SnapshotStore;
46
+ platform?: TargetPlatform;
47
+ now?: () => number;
48
+ }
49
+ export interface PaymentEngine {
50
+ initialize(): Promise<InitOutcome>;
51
+ cleanup(): void;
52
+ getStatus(): PaymentStatus;
53
+ subscribeStatus(listener: (status: PaymentStatus) => void): Unsubscribe;
54
+ getEntitlement(key: EntitlementKey): EntitlementState;
55
+ getAllEntitlements(): EntitlementMap;
56
+ subscribeEntitlements(listener: (entitlements: EntitlementMap) => void): Unsubscribe;
57
+ /**
58
+ * Purchases whose money has not arrived, in this session or an earlier one
59
+ * (FR-101). Synchronous and in-memory, like `getEntitlement`. Added in 0.2.0.
60
+ */
61
+ getPendingPurchases(): PendingPurchasesState;
62
+ /** Pushed only when the set, its status, or its staleness changes (FR-101). */
63
+ subscribePendingPurchases(listener: (pending: PendingPurchasesState) => void): Unsubscribe;
64
+ sync(trigger?: SyncTrigger): Promise<SyncOutcome>;
65
+ restore(): Promise<RestoreOutcome>;
66
+ getLastSyncedAt(): number | undefined;
67
+ clearLocalData(): Promise<void>;
68
+ subscribeEvents(listener: PaymentEventListener): Unsubscribe;
69
+ purchase(productKey: ProductKey, options?: PurchaseOptions): Promise<PurchaseResult>;
70
+ /** App-triggered consumption of a consumable (FR-043). */
71
+ consume(ref: TransactionRef): Promise<FinalizeResult>;
72
+ /** Paid-but-unsettled transactions, so the condition is observable (FR-045). */
73
+ getUnfinalized(): UnfinalizedSummary[];
74
+ getProducts(productKeys: ProductKey[]): Promise<ProductQueryResult>;
75
+ refreshProducts(productKeys: ProductKey[]): Promise<ProductQueryResult>;
76
+ changePlan(fromProductKey: ProductKey, toProductKey: ProductKey, mode: ProrationMode, options?: PurchaseOptions): Promise<PurchaseResult>;
77
+ /** Opens the **store's** management screen; never a self-built one (FR-066). */
78
+ openSubscriptionManagement(productKey?: ProductKey): Promise<void>;
79
+ confirmPriceChange(productKey: ProductKey): Promise<PriceChangeResult>;
80
+ /**
81
+ * Call when the app returns to the foreground (FR-059).
82
+ *
83
+ * Left to the app rather than subscribing to `AppState` internally: the package
84
+ * must not decide what "foreground" means for a host that may be backgrounded
85
+ * by its own modal, a biometric prompt, or the store's purchase sheet. The
86
+ * engine rate-limits it regardless (PERF-002).
87
+ */
88
+ handleForeground(): Promise<void>;
89
+ }
90
+ /** How many refused operations `status.blockedOperations` keeps. */
91
+ export declare const MAX_BLOCKED_OPERATIONS = 20;
92
+ export declare function createEngine(config: PaymentConfig, deps: EngineDeps): PaymentEngine;
93
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../src/engine/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The finalization queue — the package's hardest invariant (FR-041, FR-042).
3
+ *
4
+ * Google auto-refunds and revokes a purchase that is not acknowledged within
5
+ * **three days**. So finalization cannot be a step the app might forget, and it
6
+ * cannot live only in memory: the failure case FR-042 names is the app being
7
+ * force-killed in the instant between payment and acknowledgement.
8
+ *
9
+ * The ordering that makes this work is: **write the intent, then call the store.**
10
+ * A crash before the write means the purchase is still owned and the next sync
11
+ * re-queues it from `queryOwned`. A crash after the write means the queue has a
12
+ * record and the next startup drains it. There is no window where a paid
13
+ * transaction is forgotten.
14
+ *
15
+ * Consumption stays app-triggered (FR-043), because only the app knows whether
16
+ * the item was actually banked in its own data.
17
+ */
18
+ import type { FinalizeResult, TransactionRef, UnfinalizedSummary } from '../config/types.js';
19
+ import type { ProviderPort } from '../adapter/port.js';
20
+ import type { ResolvedRetry } from '../core/timers.js';
21
+ import { type PersistedSnapshot } from '../persistence/snapshot.js';
22
+ import type { PaymentEventInput } from '../diagnostics/events.js';
23
+ export interface FinalizerDeps {
24
+ provider: ProviderPort;
25
+ retry: ResolvedRetry;
26
+ /** `timeouts.finalizeAttemptMs`: one acknowledge or consume call may take no longer. */
27
+ attemptTimeoutMs: number;
28
+ snapshot: () => PersistedSnapshot;
29
+ commit: (next: PersistedSnapshot) => void;
30
+ emit: (event: PaymentEventInput) => void;
31
+ now: () => number;
32
+ disposed: () => boolean;
33
+ /** Injected so a test can run the retry schedule without waiting it out. */
34
+ setTimeoutFn?: (fn: () => void, ms: number) => FinalizeTimerHandle;
35
+ clearTimeoutFn?: (handle: FinalizeTimerHandle) => void;
36
+ }
37
+ /** A Node `Timeout` and a browser numeric id are both valid here. */
38
+ type FinalizeTimerHandle = ReturnType<typeof setTimeout> | number;
39
+ export interface Finalizer {
40
+ /** Records the intent to finalize, then attempts it. Safe to call repeatedly. */
41
+ enqueue(transactionId: string): Promise<FinalizeResult>;
42
+ /** Drains every outstanding finalization. Runs at startup and on foreground. */
43
+ drain(): Promise<void>;
44
+ /** App-triggered consumption of a consumable (FR-043). */
45
+ consume(ref: TransactionRef): Promise<FinalizeResult>;
46
+ /** Paid-but-unsettled transactions, so the condition is observable (FR-045). */
47
+ unfinalized(): UnfinalizedSummary[];
48
+ /** Cancels pending retries. Idempotent, called from cleanup. */
49
+ dispose(): void;
50
+ }
51
+ export declare function createFinalizer(deps: FinalizerDeps): Finalizer;
52
+ export {};
53
+ //# sourceMappingURL=finalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finalize.d.ts","sourceRoot":"","sources":["../../../../src/engine/finalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACX,cAAc,EAEd,cAAc,EACd,kBAAkB,EAClB,MAAM,oBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAgB,CAAC;AAIpD,OAAO,EAGN,KAAK,iBAAiB,EACtB,MAAM,4BAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAAuB,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB,wFAAwF;IACxF,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;IAClC,MAAM,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC1C,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACzC,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,mBAAmB,CAAC;IACnE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACvD;AAED,qEAAqE;AACrE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,SAAS;IACzB,iFAAiF;IACjF,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACxD,gFAAgF;IAChF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,0DAA0D;IAC1D,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACtD,gFAAgF;IAChF,WAAW,IAAI,kBAAkB,EAAE,CAAC;IACpC,gEAAgE;IAChE,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAmR9D"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Opt-in foreground sync over rn-core's shared lifecycle port (PERF-07, FR-059).
3
+ *
4
+ * `handleForeground()` stays the app's to call: the engine does not decide what a
5
+ * foreground return is. An app that is happy with "back from the background" calls
6
+ * this once instead of wiring `AppState` itself, and shares the one native
7
+ * subscription every package uses. A trip through `inactive` alone (a biometric
8
+ * prompt, iOS Control Center) is not a return. On Android the Play purchase sheet
9
+ * does send the app to the background, so a purchase is followed by a sync; the
10
+ * engine's foreground rate limit keeps that to one request per interval.
11
+ */
12
+ import { type AppLifecyclePort, type Unsubscribe } from '@chipmobilesdk/rn-core';
13
+ import type { PaymentEngine } from './engine.js';
14
+ export declare function syncOnForeground(engine: Pick<PaymentEngine, 'handleForeground'>, lifecycle?: AppLifecyclePort): Unsubscribe;
15
+ //# sourceMappingURL=foreground.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foreground.d.ts","sourceRoot":"","sources":["../../../../src/engine/foreground.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAGN,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAU,CAAC;AAE9C,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,kBAAkB,CAAC,EAC/C,SAAS,GAAE,gBAAiC,GAC1C,WAAW,CAKb"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What tests and diagnostics need from an engine, off its public type (PAY-11).
3
+ *
4
+ * Until 0.6.0 these were methods of `PaymentEngine`, so any consumer could commit
5
+ * a snapshot of its own and grant itself an entitlement the store never sold,
6
+ * and a hand-written engine double had to implement all of them. They live in a
7
+ * WeakMap keyed by the engine now, and this module is not exported from the
8
+ * package entrypoint.
9
+ */
10
+ import type { ProductKey } from '../config/types.js';
11
+ import type { ResolvedConfig } from '../config/validate.js';
12
+ import type { PaymentEmitter } from '../diagnostics/events.js';
13
+ import type { PersistedSnapshot } from '../persistence/snapshot.js';
14
+ import type { PaymentEngine } from './engine.js';
15
+ export interface EngineInternals {
16
+ resolvedConfig(): ResolvedConfig;
17
+ nextCorrelationId(): string;
18
+ emitter(): PaymentEmitter;
19
+ snapshot(): PersistedSnapshot;
20
+ commitSnapshot(next: PersistedSnapshot): void;
21
+ mayCreateRealTransaction(): boolean;
22
+ /** Records a purchase refused because this environment may not move real money (FR-014). */
23
+ recordBlockedOperation(productKey: ProductKey): void;
24
+ }
25
+ export declare function attachEngineInternals(engine: PaymentEngine, internals: EngineInternals): void;
26
+ /** The internals of an engine `createEngine` made. Throws for any other object. */
27
+ export declare function engineInternals(engine: PaymentEngine): EngineInternals;
28
+ //# sourceMappingURL=internals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internals.d.ts","sourceRoot":"","sources":["../../../../src/engine/internals.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAU,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC/B,cAAc,IAAI,cAAc,CAAC;IACjC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,OAAO,IAAI,cAAc,CAAC;IAC1B,QAAQ,IAAI,iBAAiB,CAAC;IAC9B,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9C,wBAAwB,IAAI,OAAO,CAAC;IACpC,4FAA4F;IAC5F,sBAAsB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;CACrD;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI,CAE7F;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,CAMtE"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The pending set, and how a pending purchase ends (FR-101 – FR-104), added in
3
+ * 0.2.0.
4
+ *
5
+ * 0.1.0 handled pending purchases correctly on the grant side — pending never
6
+ * grants, a settled one is granted at the next sync, an abandoned one is removed
7
+ * — but an app could only *see* one in the session it started in. The record
8
+ * was already persisted with a `pending` state; this module is the read side of
9
+ * it, and nothing more. It decides nothing about granting: that stays in
10
+ * `entitlements/aggregate.ts`, where pending is refused unconditionally.
11
+ *
12
+ * Pure: no provider, no I/O, no React. The engine calls it from `commit`.
13
+ */
14
+ import type { ResolvedConfig } from '../config/validate.js';
15
+ import type { PendingPurchasesState, PendingResolution, ProductKey } from '../config/types.js';
16
+ import type { PersistedSnapshot } from '../persistence/snapshot.js';
17
+ export declare const UNKNOWN_PENDING: PendingPurchasesState;
18
+ /**
19
+ * Derives the pending set from the snapshot.
20
+ *
21
+ * Read from the persisted record, so it survives an app kill and an offline
22
+ * restart, and judged by the very staleness rule entitlements use (FR-103).
23
+ * Products no longer in the catalog are left out: an app cannot render a row,
24
+ * or withhold a Buy button, for a product key it no longer has.
25
+ */
26
+ export declare function derivePending(input: {
27
+ config: ResolvedConfig;
28
+ snapshot: PersistedSnapshot;
29
+ hasSynced: boolean;
30
+ now: number;
31
+ }): PendingPurchasesState;
32
+ export interface PendingTransition {
33
+ readonly productKey: ProductKey;
34
+ readonly outcome: PendingResolution;
35
+ }
36
+ /**
37
+ * Every pending transaction that stopped being pending between two snapshots.
38
+ *
39
+ * Computed from the commit itself rather than at each call site that might end
40
+ * a pending purchase — sync, a store push, a purchase — which is what makes
41
+ * "exactly once" structural (FR-104, FR-079). A store push and a sync racing on
42
+ * one settling purchase both commit, but only the first commit sees it leave
43
+ * the pending set.
44
+ *
45
+ * A record that disappeared ended without payment. Why is the store's to say;
46
+ * when it says nothing, `cancelled` (see `PendingResolution`).
47
+ */
48
+ export declare function pendingTransitions(previous: PersistedSnapshot, next: PersistedSnapshot, config: ResolvedConfig, endReason: (transactionId: string) => 'cancelled' | 'expired' | undefined): PendingTransition[];
49
+ /** Whether a listener has anything new to hear. */
50
+ export declare function samePending(a: PendingPurchasesState, b: PendingPurchasesState): boolean;
51
+ //# sourceMappingURL=pending.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../../src/engine/pending.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,KAAK,EAEX,qBAAqB,EACrB,iBAAiB,EACjB,UAAU,EACV,MAAM,oBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAAyB,CAAC;AAGjE,eAAO,MAAM,eAAe,EAAE,qBAI7B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACpC,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACZ,GAAG,qBAAqB,CAoBxB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACpC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CACjC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GACvE,iBAAiB,EAAE,CAgBrB;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAWvF"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Product query, normalization, and the in-memory price cache (US11).
3
+ *
4
+ * Two rules shape this module:
5
+ *
6
+ * - **Prices come from the store, formatted.** An app must never build a price
7
+ * string (FR-028): only the store knows the right currency symbol, its
8
+ * placement, the decimal separator, and the grouping for the user's locale. A
9
+ * hand-built "$9.99" is wrong in most of the world.
10
+ * - **Offer eligibility is reported, never computed.** The store decides who
11
+ * qualifies for a trial or an introductory price (FR-026). Guessing locally
12
+ * would promise a trial the store then refuses at checkout.
13
+ *
14
+ * The cache is in **memory only** and short-lived. Persisting prices would risk
15
+ * showing a stale one as current in a later session, and a paywall is exactly
16
+ * where that matters.
17
+ */
18
+ import type { ProductKey, ProductType } from '../config/types.js';
19
+ import type { ResolvedConfig } from '../config/validate.js';
20
+ import type { ProviderPort } from '../adapter/port.js';
21
+ import { PaymentError } from '../diagnostics/errors.js';
22
+ import type { PaymentEventInput } from '../diagnostics/events.js';
23
+ export interface Offer {
24
+ offerKey: string;
25
+ billingPeriod: string;
26
+ formattedPrice: string;
27
+ priceAmountMicros: number;
28
+ currencyCode: string;
29
+ trialPeriod?: string;
30
+ introductoryPrice?: {
31
+ formattedPrice: string;
32
+ period: string;
33
+ cycles: number;
34
+ };
35
+ /** As the store determined it. Never computed here (FR-026). */
36
+ isEligible: boolean;
37
+ }
38
+ export interface ProductInfo {
39
+ productKey: ProductKey;
40
+ productType: ProductType;
41
+ title: string;
42
+ description: string;
43
+ /** Store-formatted and locale-correct. For display (FR-024). */
44
+ formattedPrice: string;
45
+ currencyCode: string;
46
+ /** For comparison and sorting only — never for display (FR-028). */
47
+ priceAmountMicros: number;
48
+ offers: Offer[];
49
+ }
50
+ /** Why a requested product produced nothing, kept distinct from a network error. */
51
+ export type MissingProductReason = 'not_in_catalog'
52
+ /** Does not exist, is unapproved, or is not sold in this country (FR-027). */
53
+ | 'not_available_from_store';
54
+ export interface MissingProduct {
55
+ productKey: ProductKey;
56
+ reason: MissingProductReason;
57
+ }
58
+ export type ProductQueryResult = {
59
+ ok: true;
60
+ products: ProductInfo[];
61
+ /** Reported separately so an app shows an explanation, not an empty row. */
62
+ missing: MissingProduct[];
63
+ fromCache: boolean;
64
+ } | {
65
+ ok: false;
66
+ error: PaymentError;
67
+ };
68
+ export interface ProductsDeps {
69
+ resolved: ResolvedConfig;
70
+ provider: ProviderPort;
71
+ emit: (event: PaymentEventInput) => void;
72
+ now: () => number;
73
+ }
74
+ export interface Products {
75
+ get(productKeys: ProductKey[]): Promise<ProductQueryResult>;
76
+ /** Bypasses the cache; for a pull-to-refresh on a paywall (FR-029). */
77
+ refresh(productKeys: ProductKey[]): Promise<ProductQueryResult>;
78
+ /** Drops the cache, e.g. after a locale or account change. */
79
+ invalidate(): void;
80
+ }
81
+ export declare function createProducts(deps: ProductsDeps): Products;
82
+ //# sourceMappingURL=products.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../../../src/engine/products.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,oBAAiB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAAuB,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAAuB,CAAC;AAG/D,MAAM,WAAW,KAAK;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KACf,CAAC;IACF,gEAAgE;IAChE,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED,oFAAoF;AACpF,MAAM,MAAM,oBAAoB,GAC7B,gBAAgB;AAClB,8EAA8E;GAC5E,0BAA0B,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,oBAAoB,CAAC;CAC7B;AAED,MAAM,MAAM,kBAAkB,GAC3B;IACA,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,4EAA4E;IAC5E,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CAClB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACzC,GAAG,EAAE,MAAM,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACxB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5D,uEAAuE;IACvE,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChE,8DAA8D;IAC9D,UAAU,IAAI,IAAI,CAAC;CACnB;AAiCD,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,QAAQ,CA8J3D"}