@owlmeans/payment 0.1.18-rc.8 → 0.1.18

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 (364) hide show
  1. package/README.md +95 -57
  2. package/agent-meta/manifest.json +10 -3
  3. package/agent-meta/skills/entitlements/SKILL.md +159 -0
  4. package/agent-meta/skills/payment/SKILL.md +491 -28
  5. package/build/advertise.d.ts +2 -0
  6. package/build/advertise.d.ts.map +1 -0
  7. package/build/advertise.js +10 -0
  8. package/build/advertise.js.map +1 -0
  9. package/build/checkout/consts.d.ts +2 -0
  10. package/build/checkout/consts.d.ts.map +1 -0
  11. package/build/checkout/consts.js +2 -0
  12. package/build/checkout/consts.js.map +1 -0
  13. package/build/checkout/index.d.ts +6 -0
  14. package/build/checkout/index.d.ts.map +1 -0
  15. package/build/checkout/index.js +4 -0
  16. package/build/checkout/index.js.map +1 -0
  17. package/build/checkout/narrow/types.d.ts +25 -0
  18. package/build/checkout/narrow/types.d.ts.map +1 -0
  19. package/build/checkout/narrow/types.js +2 -0
  20. package/build/checkout/narrow/types.js.map +1 -0
  21. package/build/checkout/narrow.d.ts +8 -0
  22. package/build/checkout/narrow.d.ts.map +1 -0
  23. package/build/checkout/narrow.js +47 -0
  24. package/build/checkout/narrow.js.map +1 -0
  25. package/build/checkout/protocols.d.ts +8 -0
  26. package/build/checkout/protocols.d.ts.map +1 -0
  27. package/build/checkout/protocols.js +28 -0
  28. package/build/checkout/protocols.js.map +1 -0
  29. package/build/checkout/types.d.ts +29 -0
  30. package/build/checkout/types.d.ts.map +1 -0
  31. package/build/checkout/types.js +2 -0
  32. package/build/checkout/types.js.map +1 -0
  33. package/build/consts.d.ts +242 -25
  34. package/build/consts.d.ts.map +1 -1
  35. package/build/consts.js +377 -24
  36. package/build/consts.js.map +1 -1
  37. package/build/consts.local.d.ts +20 -0
  38. package/build/consts.local.d.ts.map +1 -0
  39. package/build/consts.local.js +23 -0
  40. package/build/consts.local.js.map +1 -0
  41. package/build/consumer/cancel.d.ts +11 -0
  42. package/build/consumer/cancel.d.ts.map +1 -0
  43. package/build/consumer/cancel.js +33 -0
  44. package/build/consumer/cancel.js.map +1 -0
  45. package/build/consumer/consts.d.ts +20 -0
  46. package/build/consumer/consts.d.ts.map +1 -0
  47. package/build/consumer/consts.js +39 -0
  48. package/build/consumer/consts.js.map +1 -0
  49. package/build/consumer/consts.local.d.ts +7 -0
  50. package/build/consumer/consts.local.d.ts.map +1 -0
  51. package/build/consumer/consts.local.js +13 -0
  52. package/build/consumer/consts.local.js.map +1 -0
  53. package/build/consumer/copy/types.d.ts +56 -0
  54. package/build/consumer/copy/types.d.ts.map +1 -0
  55. package/build/consumer/copy/types.js +2 -0
  56. package/build/consumer/copy/types.js.map +1 -0
  57. package/build/consumer/copy.d.ts +22 -0
  58. package/build/consumer/copy.d.ts.map +1 -0
  59. package/build/consumer/copy.js +87 -0
  60. package/build/consumer/copy.js.map +1 -0
  61. package/build/consumer/deadline/types.d.ts +30 -0
  62. package/build/consumer/deadline/types.d.ts.map +1 -0
  63. package/build/consumer/deadline/types.js +2 -0
  64. package/build/consumer/deadline/types.js.map +1 -0
  65. package/build/consumer/deadline.d.ts +12 -0
  66. package/build/consumer/deadline.d.ts.map +1 -0
  67. package/build/consumer/deadline.js +44 -0
  68. package/build/consumer/deadline.js.map +1 -0
  69. package/build/consumer/fifo/types.d.ts +17 -0
  70. package/build/consumer/fifo/types.d.ts.map +1 -0
  71. package/build/consumer/fifo/types.js +2 -0
  72. package/build/consumer/fifo/types.js.map +1 -0
  73. package/build/consumer/fifo.d.ts +4 -0
  74. package/build/consumer/fifo.d.ts.map +1 -0
  75. package/build/consumer/fifo.js +34 -0
  76. package/build/consumer/fifo.js.map +1 -0
  77. package/build/consumer/index.d.ts +18 -0
  78. package/build/consumer/index.d.ts.map +1 -0
  79. package/build/consumer/index.js +11 -0
  80. package/build/consumer/index.js.map +1 -0
  81. package/build/consumer/policy/types.d.ts +20 -0
  82. package/build/consumer/policy/types.d.ts.map +1 -0
  83. package/build/consumer/policy/types.js +2 -0
  84. package/build/consumer/policy/types.js.map +1 -0
  85. package/build/consumer/policy.d.ts +17 -0
  86. package/build/consumer/policy.d.ts.map +1 -0
  87. package/build/consumer/policy.js +91 -0
  88. package/build/consumer/policy.js.map +1 -0
  89. package/build/consumer/protocols.d.ts +20 -0
  90. package/build/consumer/protocols.d.ts.map +1 -0
  91. package/build/consumer/protocols.js +70 -0
  92. package/build/consumer/protocols.js.map +1 -0
  93. package/build/consumer/refund/types.d.ts +27 -0
  94. package/build/consumer/refund/types.d.ts.map +1 -0
  95. package/build/consumer/refund/types.js +2 -0
  96. package/build/consumer/refund/types.js.map +1 -0
  97. package/build/consumer/refund.d.ts +9 -0
  98. package/build/consumer/refund.d.ts.map +1 -0
  99. package/build/consumer/refund.js +112 -0
  100. package/build/consumer/refund.js.map +1 -0
  101. package/build/consumer/refusal.d.ts +10 -0
  102. package/build/consumer/refusal.d.ts.map +1 -0
  103. package/build/consumer/refusal.js +35 -0
  104. package/build/consumer/refusal.js.map +1 -0
  105. package/build/consumer/revive/types.d.ts +19 -0
  106. package/build/consumer/revive/types.d.ts.map +1 -0
  107. package/build/consumer/revive/types.js +2 -0
  108. package/build/consumer/revive/types.js.map +1 -0
  109. package/build/consumer/revive.d.ts +13 -0
  110. package/build/consumer/revive.d.ts.map +1 -0
  111. package/build/consumer/revive.js +43 -0
  112. package/build/consumer/revive.js.map +1 -0
  113. package/build/consumer/types.d.ts +196 -0
  114. package/build/consumer/types.d.ts.map +1 -0
  115. package/build/consumer/types.js +2 -0
  116. package/build/consumer/types.js.map +1 -0
  117. package/build/consumer/types.local.d.ts +11 -0
  118. package/build/consumer/types.local.d.ts.map +1 -0
  119. package/build/consumer/types.local.js +2 -0
  120. package/build/consumer/types.local.js.map +1 -0
  121. package/build/countries.d.ts +3 -0
  122. package/build/countries.d.ts.map +1 -0
  123. package/build/countries.js +4 -0
  124. package/build/countries.js.map +1 -0
  125. package/build/entitled.d.ts +14 -0
  126. package/build/entitled.d.ts.map +1 -0
  127. package/build/entitled.js +17 -0
  128. package/build/entitled.js.map +1 -0
  129. package/build/entitlement/types.d.ts +29 -0
  130. package/build/entitlement/types.d.ts.map +1 -0
  131. package/build/entitlement/types.js +2 -0
  132. package/build/entitlement/types.js.map +1 -0
  133. package/build/entitlement.d.ts +12 -0
  134. package/build/entitlement.d.ts.map +1 -0
  135. package/build/entitlement.js +64 -0
  136. package/build/entitlement.js.map +1 -0
  137. package/build/errors.d.ts +189 -0
  138. package/build/errors.d.ts.map +1 -1
  139. package/build/errors.js +361 -0
  140. package/build/errors.js.map +1 -1
  141. package/build/estimate/types.d.ts +34 -0
  142. package/build/estimate/types.d.ts.map +1 -0
  143. package/build/estimate/types.js +2 -0
  144. package/build/estimate/types.js.map +1 -0
  145. package/build/estimate.d.ts +11 -0
  146. package/build/estimate.d.ts.map +1 -0
  147. package/build/estimate.js +76 -0
  148. package/build/estimate.js.map +1 -0
  149. package/build/i18n/consumer-rights/be.json +131 -0
  150. package/build/i18n/consumer-rights/de.json +131 -0
  151. package/build/i18n/consumer-rights/en.json +131 -0
  152. package/build/i18n/consumer-rights/es.json +131 -0
  153. package/build/i18n/consumer-rights/fr.json +131 -0
  154. package/build/i18n/consumer-rights/pl.json +131 -0
  155. package/build/i18n/consumer-rights/ru.json +131 -0
  156. package/build/i18n/consumer-rights/uk.json +131 -0
  157. package/build/i18n/errors/be.json +30 -0
  158. package/build/i18n/errors/de.json +30 -0
  159. package/build/i18n/errors/en.json +30 -0
  160. package/build/i18n/errors/es.json +30 -0
  161. package/build/i18n/errors/fr.json +30 -0
  162. package/build/i18n/errors/pl.json +30 -0
  163. package/build/i18n/errors/ru.json +30 -0
  164. package/build/i18n/errors/uk.json +30 -0
  165. package/build/i18n/fr.json +39 -0
  166. package/build/i18n.js +53 -8
  167. package/build/i18n.js.map +1 -1
  168. package/build/index.d.ts +19 -1
  169. package/build/index.d.ts.map +1 -1
  170. package/build/index.js +12 -1
  171. package/build/index.js.map +1 -1
  172. package/build/limit/types.d.ts +44 -0
  173. package/build/limit/types.d.ts.map +1 -0
  174. package/build/limit/types.js +2 -0
  175. package/build/limit/types.js.map +1 -0
  176. package/build/limit.d.ts +23 -0
  177. package/build/limit.d.ts.map +1 -0
  178. package/build/limit.js +97 -0
  179. package/build/limit.js.map +1 -0
  180. package/build/model/checkout.d.ts +2 -3
  181. package/build/model/checkout.d.ts.map +1 -1
  182. package/build/model/checkout.js +12 -7
  183. package/build/model/checkout.js.map +1 -1
  184. package/build/model/consts.d.ts +15 -0
  185. package/build/model/consts.d.ts.map +1 -0
  186. package/build/model/consts.js +193 -0
  187. package/build/model/consts.js.map +1 -0
  188. package/build/model/consts.local.d.ts +35 -0
  189. package/build/model/consts.local.d.ts.map +1 -0
  190. package/build/model/consts.local.js +65 -0
  191. package/build/model/consts.local.js.map +1 -0
  192. package/build/model/consumer.d.ts +23 -0
  193. package/build/model/consumer.d.ts.map +1 -0
  194. package/build/model/consumer.js +272 -0
  195. package/build/model/consumer.js.map +1 -0
  196. package/build/model/estimate.d.ts +5 -0
  197. package/build/model/estimate.d.ts.map +1 -0
  198. package/build/model/estimate.js +69 -0
  199. package/build/model/estimate.js.map +1 -0
  200. package/build/model/index.d.ts +7 -2
  201. package/build/model/index.d.ts.map +1 -1
  202. package/build/model/index.js +7 -2
  203. package/build/model/index.js.map +1 -1
  204. package/build/model/limit.d.ts +7 -0
  205. package/build/model/limit.d.ts.map +1 -0
  206. package/build/model/limit.js +32 -0
  207. package/build/model/limit.js.map +1 -0
  208. package/build/model/plan.d.ts.map +1 -1
  209. package/build/model/plan.js +24 -11
  210. package/build/model/plan.js.map +1 -1
  211. package/build/model/portal.d.ts +4 -0
  212. package/build/model/portal.d.ts.map +1 -0
  213. package/build/model/portal.js +22 -0
  214. package/build/model/portal.js.map +1 -0
  215. package/build/model/pricing.d.ts +4 -0
  216. package/build/model/pricing.d.ts.map +1 -0
  217. package/build/model/pricing.js +31 -0
  218. package/build/model/pricing.js.map +1 -0
  219. package/build/model/view.d.ts +3 -0
  220. package/build/model/view.d.ts.map +1 -0
  221. package/build/model/view.js +15 -0
  222. package/build/model/view.js.map +1 -0
  223. package/build/pricing/types.d.ts +13 -0
  224. package/build/pricing/types.d.ts.map +1 -0
  225. package/build/pricing/types.js +2 -0
  226. package/build/pricing/types.js.map +1 -0
  227. package/build/pricing.d.ts +13 -0
  228. package/build/pricing.d.ts.map +1 -0
  229. package/build/pricing.js +74 -0
  230. package/build/pricing.js.map +1 -0
  231. package/build/promo/types.d.ts +14 -0
  232. package/build/promo/types.d.ts.map +1 -0
  233. package/build/promo/types.js +2 -0
  234. package/build/promo/types.js.map +1 -0
  235. package/build/promo.d.ts +7 -0
  236. package/build/promo.d.ts.map +1 -0
  237. package/build/promo.js +25 -0
  238. package/build/promo.js.map +1 -0
  239. package/build/regions/types.d.ts +32 -0
  240. package/build/regions/types.d.ts.map +1 -0
  241. package/build/regions/types.js +2 -0
  242. package/build/regions/types.js.map +1 -0
  243. package/build/regions.d.ts +15 -0
  244. package/build/regions.d.ts.map +1 -0
  245. package/build/regions.js +43 -0
  246. package/build/regions.js.map +1 -0
  247. package/build/service.d.ts.map +1 -1
  248. package/build/service.js +24 -9
  249. package/build/service.js.map +1 -1
  250. package/build/types.d.ts +619 -52
  251. package/build/types.d.ts.map +1 -1
  252. package/build/types.local.d.ts +4 -0
  253. package/build/types.local.d.ts.map +1 -0
  254. package/build/types.local.js +2 -0
  255. package/build/types.local.js.map +1 -0
  256. package/build/view/types.d.ts +33 -0
  257. package/build/view/types.d.ts.map +1 -0
  258. package/build/view/types.js +2 -0
  259. package/build/view/types.js.map +1 -0
  260. package/build/view.d.ts +13 -0
  261. package/build/view.d.ts.map +1 -0
  262. package/build/view.js +78 -0
  263. package/build/view.js.map +1 -0
  264. package/package.json +14 -12
  265. package/src/advertise.ts +13 -0
  266. package/src/checkout/consts.ts +1 -0
  267. package/src/checkout/index.ts +5 -0
  268. package/src/checkout/narrow/types.ts +27 -0
  269. package/src/checkout/narrow.ts +63 -0
  270. package/src/checkout/protocols.ts +39 -0
  271. package/src/checkout/types.ts +27 -0
  272. package/src/consts.local.ts +34 -0
  273. package/src/consts.ts +417 -24
  274. package/src/consumer/cancel.ts +40 -0
  275. package/src/consumer/consts.local.ts +16 -0
  276. package/src/consumer/consts.ts +46 -0
  277. package/src/consumer/copy/types.ts +54 -0
  278. package/src/consumer/copy.ts +121 -0
  279. package/src/consumer/deadline/types.ts +30 -0
  280. package/src/consumer/deadline.ts +61 -0
  281. package/src/consumer/fifo/types.ts +17 -0
  282. package/src/consumer/fifo.ts +42 -0
  283. package/src/consumer/index.ts +17 -0
  284. package/src/consumer/policy/types.ts +20 -0
  285. package/src/consumer/policy.ts +101 -0
  286. package/src/consumer/protocols.ts +116 -0
  287. package/src/consumer/refund/types.ts +27 -0
  288. package/src/consumer/refund.ts +136 -0
  289. package/src/consumer/refusal.ts +35 -0
  290. package/src/consumer/revive/types.ts +23 -0
  291. package/src/consumer/revive.ts +82 -0
  292. package/src/consumer/types.local.ts +10 -0
  293. package/src/consumer/types.ts +189 -0
  294. package/src/countries.ts +5 -0
  295. package/src/entitled.ts +20 -0
  296. package/src/entitlement/types.ts +29 -0
  297. package/src/entitlement.ts +86 -0
  298. package/src/errors.ts +445 -0
  299. package/src/estimate/types.ts +34 -0
  300. package/src/estimate.ts +90 -0
  301. package/src/i18n/consumer-rights/be.json +131 -0
  302. package/src/i18n/consumer-rights/de.json +131 -0
  303. package/src/i18n/consumer-rights/en.json +131 -0
  304. package/src/i18n/consumer-rights/es.json +131 -0
  305. package/src/i18n/consumer-rights/fr.json +131 -0
  306. package/src/i18n/consumer-rights/pl.json +131 -0
  307. package/src/i18n/consumer-rights/ru.json +131 -0
  308. package/src/i18n/consumer-rights/uk.json +131 -0
  309. package/src/i18n/errors/be.json +30 -0
  310. package/src/i18n/errors/de.json +30 -0
  311. package/src/i18n/errors/en.json +30 -0
  312. package/src/i18n/errors/es.json +30 -0
  313. package/src/i18n/errors/fr.json +30 -0
  314. package/src/i18n/errors/pl.json +30 -0
  315. package/src/i18n/errors/ru.json +30 -0
  316. package/src/i18n/errors/uk.json +30 -0
  317. package/src/i18n/fr.json +39 -0
  318. package/src/i18n.ts +58 -8
  319. package/src/index.ts +19 -2
  320. package/src/limit/types.ts +41 -0
  321. package/src/limit.ts +132 -0
  322. package/src/model/checkout.ts +12 -7
  323. package/src/model/consts.local.ts +83 -0
  324. package/src/model/consts.ts +206 -0
  325. package/src/model/consumer.ts +294 -0
  326. package/src/model/estimate.ts +73 -0
  327. package/src/model/index.ts +7 -2
  328. package/src/model/limit.ts +36 -0
  329. package/src/model/plan.ts +25 -12
  330. package/src/model/portal.ts +25 -0
  331. package/src/model/pricing.ts +34 -0
  332. package/src/model/view.ts +17 -0
  333. package/src/pricing/types.ts +13 -0
  334. package/src/pricing.ts +110 -0
  335. package/src/promo/types.ts +18 -0
  336. package/src/promo.ts +46 -0
  337. package/src/regions/types.ts +42 -0
  338. package/src/regions.ts +85 -0
  339. package/src/service.ts +32 -15
  340. package/src/types.local.ts +5 -0
  341. package/src/types.ts +669 -49
  342. package/src/view/types.ts +39 -0
  343. package/src/view.ts +119 -0
  344. package/tests/checkout-narrow.spec.ts +75 -0
  345. package/tests/consumer-copy.spec.ts +378 -0
  346. package/tests/consumer-deadline.spec.ts +85 -0
  347. package/tests/consumer-fifo.spec.ts +61 -0
  348. package/tests/consumer-protocols.spec.ts +103 -0
  349. package/tests/consumer-refund.spec.ts +134 -0
  350. package/tests/consumer-regions.spec.ts +140 -0
  351. package/tests/consumer-wire.spec.ts +170 -0
  352. package/tests/contract.spec.ts +183 -0
  353. package/tests/entitlement.spec.ts +103 -0
  354. package/tests/errors.spec.ts +168 -0
  355. package/tests/estimate.spec.ts +139 -0
  356. package/tests/limit.spec.ts +117 -0
  357. package/tests/pricing.spec.ts +30 -0
  358. package/tests/tsconfig.json +11 -0
  359. package/tests/view.spec.ts +130 -0
  360. package/tsconfig.json +6 -1
  361. package/build/.gitkeep +0 -0
  362. package/src/model/subscription.ts +0 -63
  363. package/src/model/utils.ts +0 -32
  364. package/src/modules.ts +0 -43
package/src/consts.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { JSONSchemaType } from 'ajv'
2
+ import type { PricingPolicy } from './types.js'
2
3
 
3
4
  export enum ProductType {
4
5
  Simple = 'simple',
@@ -6,6 +7,11 @@ export enum ProductType {
6
7
  Consumable = 'consumable'
7
8
  }
8
9
 
10
+ export enum CheckoutPricingMode {
11
+ Quantity = 'quantity',
12
+ Amount = 'amount',
13
+ }
14
+
9
15
  export enum PaymentEntityType {
10
16
  Product = 'product',
11
17
  Plan = 'plan',
@@ -38,12 +44,212 @@ export enum SubscriptionStatus {
38
44
  Trial = 'trial',
39
45
  Canceled = 'canceled',
40
46
  Expired = 'expired',
47
+ /** Revoked until resumed: unpaid, paused, or collection paused. */
41
48
  Suspended = 'suspended',
42
49
  Blocked = 'blocked',
43
50
  Ended = 'ended',
44
- Free = 'free',
45
51
  Active = 'active',
46
- Consumable = 'consumable'
52
+ /** Payment failed and is being retried: still entitled, flagged. */
53
+ PastDue = 'past-due',
54
+ }
55
+
56
+ /** The statuses that grant a plan's capabilities and limits. */
57
+ export const ENTITLING_STATUSES: readonly SubscriptionStatus[] = Object.freeze([
58
+ SubscriptionStatus.Active, SubscriptionStatus.Trial, SubscriptionStatus.PastDue,
59
+ ])
60
+
61
+ /** The statuses a subscription never leaves on its own. */
62
+ export const TERMINAL_STATUSES: readonly SubscriptionStatus[] = Object.freeze([
63
+ SubscriptionStatus.Canceled, SubscriptionStatus.Expired, SubscriptionStatus.Ended,
64
+ SubscriptionStatus.Blocked,
65
+ ])
66
+
67
+ /** How a limit's counter renews. */
68
+ export enum LimitKind {
69
+ /** Renews on the calendar UTC or subscription-anchored `LimitWindow`. */
70
+ Window = 'window',
71
+ /** Never renews: the counter belongs to the entity and survives plan changes. */
72
+ Lifetime = 'lifetime',
73
+ /** A held count (`+1` on acquire, `-1` on release), reconciled against reality. */
74
+ Occupancy = 'occupancy',
75
+ }
76
+
77
+ /** Calendar UTC windows, or a seven-day window anchored at subscription creation. */
78
+ export enum LimitWindow {
79
+ Day = 'day',
80
+ Month = 'month',
81
+ SubscriptionWeek = 'subscription-week',
82
+ }
83
+
84
+ export const SUBSCRIPTION_WEEK_MS = 7 * 24 * 60 * 60 * 1000
85
+ export const SUBSCRIPTION_WEEK_PREFIX = 'subscription-week:'
86
+
87
+ /** Which paygate portal flow a portal link opens. */
88
+ export enum PortalFlow {
89
+ Manage = 'manage',
90
+ Cancel = 'cancel',
91
+ Update = 'update',
92
+ Change = 'change',
93
+ PaymentMethod = 'payment-method',
94
+ }
95
+
96
+ /** Whether a price's amount includes tax, or tax is added on top — never inferred, always declared. */
97
+ export enum TaxBehavior {
98
+ Exclusive = 'exclusive',
99
+ Inclusive = 'inclusive',
100
+ }
101
+
102
+ /** What a price estimate says about tax at one billing country. */
103
+ export enum TaxEstimateStatus {
104
+ /** Tax is due and its rate(s) are in `TaxEstimate.rates`. */
105
+ Taxed = 'taxed',
106
+ /** No tax because the buyer's tax id shifts liability to them (EU/GB reverse charge). */
107
+ ReverseCharge = 'reverse-charge',
108
+ /** No tax for any other reason (not registered there, exempt, zero-rated). */
109
+ None = 'none',
110
+ /** The gateway could not resolve a rate from what it was given; the real total shows at checkout. */
111
+ AtCheckout = 'at-checkout',
112
+ /** No country was given and none could be inferred from the entity's paygate customer. */
113
+ LocationRequired = 'location-required',
114
+ }
115
+
116
+ /** A tax type a rate carries, collapsed from Stripe's finer `tax_type` for display. */
117
+ export enum TaxType {
118
+ Vat = 'vat',
119
+ Gst = 'gst',
120
+ SalesTax = 'sales-tax',
121
+ /** Any other Stripe `tax_type` (excise, lease, tourism, …). */
122
+ Tax = 'tax',
123
+ }
124
+
125
+ /** The paygate alias of subscriptions the application grants itself (a free plan, a comp). */
126
+ export const INTERNAL_PAYGATE = 'internal'
127
+
128
+ /**
129
+ * Where a billing country sits for consumer rights and the charge currency: inside the declared
130
+ * consumer-rights territories (`ConsumerRightsPolicy.countries`) or outside them.
131
+ */
132
+ export enum ConsumerRegion {
133
+ Eu = 'eu',
134
+ Other = 'other',
135
+ }
136
+
137
+ /** What a purchase — a window of the right of withdrawal — was. */
138
+ export enum PurchaseKind {
139
+ /** A paid one-time checkout of an amount or quantity plan (prepaid credits). */
140
+ TopUp = 'top-up',
141
+ /** The FIRST invoice of a subscription. Renewals are not purchases. */
142
+ Subscription = 'subscription',
143
+ }
144
+
145
+ /** What a consumer expressly requested. */
146
+ export enum ConsentKind {
147
+ /** Start performing now, before the withdrawal period of a credit purchase ends. */
148
+ Performance = 'performance',
149
+ /** Start a subscription's services now — given before its checkout. */
150
+ SubscriptionStart = 'subscription-start',
151
+ }
152
+
153
+ /** What a consumer declared through a statutory function. */
154
+ export enum DeclarationKind {
155
+ Withdrawal = 'withdrawal',
156
+ Cancellation = 'cancellation',
157
+ }
158
+
159
+ /** Where a declaration was made: signed in, or through the public page without a login. */
160
+ export enum DeclarationChannel {
161
+ InApp = 'in-app',
162
+ Public = 'public',
163
+ }
164
+
165
+ export enum CancellationKind {
166
+ Ordinary = 'ordinary',
167
+ /** For cause; carries a reason. */
168
+ Extraordinary = 'extraordinary',
169
+ }
170
+
171
+ export enum WithdrawalStatus {
172
+ /** Recorded; nothing is disclosed yet (a public declaration always answers this). */
173
+ Received = 'received',
174
+ Processing = 'processing',
175
+ Refunded = 'refunded',
176
+ /** Recorded, and left to an operator: no usage meter, or automatic refunds are off. */
177
+ Review = 'review',
178
+ Failed = 'failed',
179
+ /** Received after the withdrawal period ended; recorded, not executed. */
180
+ Expired = 'expired',
181
+ }
182
+
183
+ export enum CancellationStatus {
184
+ Received = 'received',
185
+ Scheduled = 'scheduled',
186
+ AlreadyScheduled = 'already-scheduled',
187
+ /** Recorded and left to an operator — an extraordinary cancellation (for cause). */
188
+ Review = 'review',
189
+ }
190
+
191
+ export enum WithdrawalUnavailableReason {
192
+ NotInScope = 'not-in-scope',
193
+ Expired = 'expired',
194
+ Withdrawn = 'withdrawn',
195
+ /** Fully performed after consent: the right of withdrawal has expired, nothing would be reimbursed. */
196
+ Performed = 'performed',
197
+ Unknown = 'unknown',
198
+ }
199
+
200
+ export enum CancellationUnavailableReason {
201
+ NoSubscription = 'no-subscription',
202
+ Ended = 'ended',
203
+ }
204
+
205
+ export const ConsumerRegionSchema: JSONSchemaType<ConsumerRegion> = {
206
+ type: 'string',
207
+ enum: Object.values(ConsumerRegion),
208
+ }
209
+
210
+ export const PurchaseKindSchema: JSONSchemaType<PurchaseKind> = {
211
+ type: 'string',
212
+ enum: Object.values(PurchaseKind),
213
+ }
214
+
215
+ export const ConsentKindSchema: JSONSchemaType<ConsentKind> = {
216
+ type: 'string',
217
+ enum: Object.values(ConsentKind),
218
+ }
219
+
220
+ export const DeclarationKindSchema: JSONSchemaType<DeclarationKind> = {
221
+ type: 'string',
222
+ enum: Object.values(DeclarationKind),
223
+ }
224
+
225
+ export const DeclarationChannelSchema: JSONSchemaType<DeclarationChannel> = {
226
+ type: 'string',
227
+ enum: Object.values(DeclarationChannel),
228
+ }
229
+
230
+ export const CancellationKindSchema: JSONSchemaType<CancellationKind> = {
231
+ type: 'string',
232
+ enum: Object.values(CancellationKind),
233
+ }
234
+
235
+ export const WithdrawalStatusSchema: JSONSchemaType<WithdrawalStatus> = {
236
+ type: 'string',
237
+ enum: Object.values(WithdrawalStatus),
238
+ }
239
+
240
+ export const CancellationStatusSchema: JSONSchemaType<CancellationStatus> = {
241
+ type: 'string',
242
+ enum: Object.values(CancellationStatus),
243
+ }
244
+
245
+ export const WithdrawalUnavailableReasonSchema: JSONSchemaType<WithdrawalUnavailableReason> = {
246
+ type: 'string',
247
+ enum: Object.values(WithdrawalUnavailableReason),
248
+ }
249
+
250
+ export const CancellationUnavailableReasonSchema: JSONSchemaType<CancellationUnavailableReason> = {
251
+ type: 'string',
252
+ enum: Object.values(CancellationUnavailableReason),
47
253
  }
48
254
 
49
255
  export const ProductTypeSchema: JSONSchemaType<ProductType> = {
@@ -51,6 +257,11 @@ export const ProductTypeSchema: JSONSchemaType<ProductType> = {
51
257
  enum: Object.values(ProductType)
52
258
  }
53
259
 
260
+ export const CheckoutPricingModeSchema: JSONSchemaType<CheckoutPricingMode> = {
261
+ type: 'string',
262
+ enum: Object.values(CheckoutPricingMode),
263
+ }
264
+
54
265
  export const PaymentEntityTypeSchema: JSONSchemaType<PaymentEntityType> = {
55
266
  type: 'string',
56
267
  enum: Object.values(PaymentEntityType)
@@ -71,6 +282,36 @@ export const SubscriptionStatusSchema: JSONSchemaType<SubscriptionStatus> = {
71
282
  enum: Object.values(SubscriptionStatus)
72
283
  }
73
284
 
285
+ export const LimitKindSchema: JSONSchemaType<LimitKind> = {
286
+ type: 'string',
287
+ enum: Object.values(LimitKind)
288
+ }
289
+
290
+ export const LimitWindowSchema: JSONSchemaType<LimitWindow> = {
291
+ type: 'string',
292
+ enum: Object.values(LimitWindow)
293
+ }
294
+
295
+ export const PortalFlowSchema: JSONSchemaType<PortalFlow> = {
296
+ type: 'string',
297
+ enum: Object.values(PortalFlow)
298
+ }
299
+
300
+ export const TaxBehaviorSchema: JSONSchemaType<TaxBehavior> = {
301
+ type: 'string',
302
+ enum: Object.values(TaxBehavior)
303
+ }
304
+
305
+ export const TaxEstimateStatusSchema: JSONSchemaType<TaxEstimateStatus> = {
306
+ type: 'string',
307
+ enum: Object.values(TaxEstimateStatus)
308
+ }
309
+
310
+ export const TaxTypeSchema: JSONSchemaType<TaxType> = {
311
+ type: 'string',
312
+ enum: Object.values(TaxType)
313
+ }
314
+
74
315
  export const ProductTitleSchema: JSONSchemaType<string> = {
75
316
  type: 'string', minLength: 1, maxLength: 128
76
317
  }
@@ -92,30 +333,182 @@ export const PLAN_RECORD_PREFIX = PLAN_RECORD_TYPE
92
333
  export const L10N_RECORD_TYPE = 'l10n'
93
334
  export const L10N_RECORD_PREFIX = L10N_RECORD_TYPE
94
335
 
336
+ /** A singleton record: at most one per configuration, at this fixed id. */
337
+ export const PRICING_POLICY_RECORD_TYPE = 'pricing-policy'
338
+ export const PRICING_POLICY_RECORD_ID = PRICING_POLICY_RECORD_TYPE
339
+
340
+ /** A singleton record: the declared `ConsumerRightsPolicy`, at this fixed id. */
341
+ export const CONSUMER_RIGHTS_RECORD_TYPE = 'consumer-rights-policy'
342
+ export const CONSUMER_RIGHTS_RECORD_ID = CONSUMER_RIGHTS_RECORD_TYPE
343
+
344
+ /** The i18n resource (library tier, `lib` namespace) holding the consumer-rights legal copy. */
345
+ export const CONSUMER_RIGHTS_RESOURCE = 'payment-consumer-rights'
346
+
347
+ /**
348
+ * The version of the legal copy this package ships. Bumped on ANY change to a
349
+ * `payment-consumer-rights` bundle, so a consent recorded against an older wording is told apart.
350
+ */
351
+ export const CONSUMER_RIGHTS_COPY_VERSION = '2026-10-04.2'
352
+
95
353
  export const DEFAULT_ALIAS = 'payment'
96
354
 
97
355
  export const PAYMENT_SERVICE = DEFAULT_ALIAS
98
356
 
99
- export const paymentApi = {
100
- subscription: {
101
- base: 'payment-api:subscription',
102
- /**
103
- * @deprecated Use propagate instead
104
- */
105
- propogate: 'payment-api:subscription:propogate',
106
- propagate: 'payment-api:subscription:propagate',
107
- },
108
- service: {
109
- base: 'payment-service:base',
110
- checkout: {
111
- base: 'payment-service:checkout',
112
- session: {
113
- base: 'payment-service:checkout:session',
114
- external: {
115
- base: 'payment-service:checkout:session:external',
116
- create: 'payment-service:checkout:session:external:create',
117
- }
118
- }
119
- }
120
- }
357
+ /**
358
+ * ISO 3166-1 alpha-2 country code → lowercase ISO 4217 currency code — the currency circulating in
359
+ * that country, for the "≈ local total" line of a price estimate. Not a Stripe list: Stripe Tax can
360
+ * compute a rate for a country this map has no entry for (or none at all, `location-required`), and
361
+ * `currencyOfCountry` returning `null` just means the estimate carries no local-currency line, never
362
+ * a rejected request.
363
+ *
364
+ * A territory that circulates another country's currency (Ecuador, Kosovo, Puerto Rico, …) is
365
+ * mapped to that currency, not left out.
366
+ */
367
+ export const COUNTRY_CURRENCIES: Readonly<Record<string, string>> = Object.freeze({
368
+ AD: 'eur', AE: 'aed', AF: 'afn', AG: 'xcd', AI: 'xcd', AL: 'all', AM: 'amd', AO: 'aoa',
369
+ AR: 'ars', AS: 'usd', AT: 'eur', AU: 'aud', AW: 'awg', AX: 'eur', AZ: 'azn',
370
+ BA: 'bam', BB: 'bbd', BD: 'bdt', BE: 'eur', BF: 'xof', BG: 'bgn', BH: 'bhd', BI: 'bif',
371
+ BJ: 'xof', BL: 'eur', BM: 'bmd', BN: 'bnd', BO: 'bob', BQ: 'usd', BR: 'brl', BS: 'bsd',
372
+ BT: 'btn', BW: 'bwp', BY: 'byn', BZ: 'bzd',
373
+ CA: 'cad', CD: 'cdf', CF: 'xaf', CG: 'xaf', CH: 'chf', CI: 'xof', CK: 'nzd', CL: 'clp',
374
+ CM: 'xaf', CN: 'cny', CO: 'cop', CR: 'crc', CU: 'cup', CV: 'cve', CW: 'ang', CY: 'eur',
375
+ CZ: 'czk',
376
+ DE: 'eur', DJ: 'djf', DK: 'dkk', DM: 'xcd', DO: 'dop', DZ: 'dzd',
377
+ EC: 'usd', EE: 'eur', EG: 'egp', EH: 'mad', ER: 'ern', ES: 'eur', ET: 'etb',
378
+ FI: 'eur', FJ: 'fjd', FK: 'fkp', FM: 'usd', FO: 'dkk', FR: 'eur',
379
+ GA: 'xaf', GB: 'gbp', GD: 'xcd', GE: 'gel', GF: 'eur', GG: 'gbp', GH: 'ghs', GI: 'gip',
380
+ GL: 'dkk', GM: 'gmd', GN: 'gnf', GP: 'eur', GQ: 'xaf', GR: 'eur', GT: 'gtq', GU: 'usd',
381
+ GW: 'xof', GY: 'gyd',
382
+ HK: 'hkd', HN: 'hnl', HR: 'eur', HT: 'htg', HU: 'huf',
383
+ ID: 'idr', IE: 'eur', IL: 'ils', IM: 'gbp', IN: 'inr', IQ: 'iqd', IR: 'irr', IS: 'isk',
384
+ IT: 'eur',
385
+ JE: 'gbp', JM: 'jmd', JO: 'jod', JP: 'jpy',
386
+ KE: 'kes', KG: 'kgs', KH: 'khr', KI: 'aud', KM: 'kmf', KN: 'xcd', KP: 'kpw', KR: 'krw',
387
+ KW: 'kwd', KY: 'kyd', KZ: 'kzt',
388
+ LA: 'lak', LB: 'lbp', LC: 'xcd', LI: 'chf', LK: 'lkr', LR: 'lrd', LS: 'lsl', LT: 'eur',
389
+ LU: 'eur', LV: 'eur', LY: 'lyd',
390
+ MA: 'mad', MC: 'eur', MD: 'mdl', ME: 'eur', MF: 'eur', MG: 'mga', MH: 'usd', MK: 'mkd',
391
+ ML: 'xof', MM: 'mmk', MN: 'mnt', MO: 'mop', MQ: 'eur', MR: 'mru', MS: 'xcd', MT: 'eur',
392
+ MU: 'mur', MV: 'mvr', MW: 'mwk', MX: 'mxn', MY: 'myr', MZ: 'mzn',
393
+ NA: 'nad', NC: 'xpf', NE: 'xof', NG: 'ngn', NI: 'nio', NL: 'eur', NO: 'nok', NP: 'npr',
394
+ NR: 'aud', NU: 'nzd', NZ: 'nzd',
395
+ OM: 'omr',
396
+ PA: 'pab', PE: 'pen', PF: 'xpf', PG: 'pgk', PH: 'php', PK: 'pkr', PL: 'pln', PR: 'usd',
397
+ PS: 'ils', PT: 'eur', PW: 'usd', PY: 'pyg',
398
+ QA: 'qar',
399
+ RE: 'eur', RO: 'ron', RS: 'rsd', RU: 'rub', RW: 'rwf',
400
+ SA: 'sar', SB: 'sbd', SC: 'scr', SD: 'sdg', SE: 'sek', SG: 'sgd', SH: 'shp', SI: 'eur',
401
+ SK: 'eur', SL: 'sle', SM: 'eur', SN: 'xof', SO: 'sos', SR: 'srd', SS: 'ssp', ST: 'stn',
402
+ SV: 'usd', SX: 'ang', SY: 'syp', SZ: 'szl',
403
+ TC: 'usd', TD: 'xaf', TG: 'xof', TH: 'thb', TJ: 'tjs', TK: 'nzd', TL: 'usd', TM: 'tmt',
404
+ TN: 'tnd', TO: 'top', TR: 'try', TT: 'ttd', TV: 'aud', TW: 'twd', TZ: 'tzs',
405
+ UA: 'uah', UG: 'ugx', US: 'usd', UY: 'uyu', UZ: 'uzs',
406
+ VA: 'eur', VC: 'xcd', VE: 'ves', VG: 'usd', VI: 'usd', VN: 'vnd', VU: 'vuv',
407
+ WF: 'xpf', WS: 'wst',
408
+ YE: 'yer', YT: 'eur',
409
+ ZA: 'zar', ZM: 'zmw', ZW: 'zwl',
410
+ })
411
+
412
+ /** Every country code `COUNTRY_CURRENCIES` names, sorted. */
413
+ export const COUNTRY_CODES: readonly string[] = Object.freeze(Object.keys(COUNTRY_CURRENCIES).sort())
414
+
415
+ /**
416
+ * A permissive ISO 3166-1 alpha-2 shape (two uppercase letters) — not restricted to
417
+ * `COUNTRY_CURRENCIES`, so a country this map cannot name a currency for is still a valid request;
418
+ * it only loses the local-currency line of its estimate.
419
+ */
420
+ export const CountrySchema: JSONSchemaType<string> = {
421
+ type: 'string', pattern: '^[A-Z]{2}$',
121
422
  }
423
+
424
+ /**
425
+ * The gate alias a paid capability is asserted under.
426
+ *
427
+ * Distinct from `paymentGate.base` (a ROUTE id) and from the gateway service alias — three
428
+ * different things that would otherwise all be called "payment gate".
429
+ */
430
+ export const ENTITLEMENT_GATE = 'entitlement-gate'
431
+
432
+ /**
433
+ * The gate alias a plan limit is asserted under (`limit:<key>[>=n]`).
434
+ *
435
+ * A separate alias from `ENTITLEMENT_GATE` because the framework collects an entrypoint's gates
436
+ * per gate SERVICE: a capability requirement and a limit requirement under one alias would hide
437
+ * each other.
438
+ */
439
+ export const LIMIT_GATE = 'limit-gate'
440
+
441
+ /**
442
+ * The capability scope that carries FEATURE flags.
443
+ *
444
+ * Kept apart from `renewable`, which carries numeric quotas that are consumed or counted. Merging
445
+ * them would make "has one production slot left" and "may remove the platform credit" the same
446
+ * number, and the first purchase that spent the quota would take the feature with it.
447
+ */
448
+ export const CAPABILITY_FEATURE_SCOPE = 'feature'
449
+
450
+ /**
451
+ * The scope RESERVED for limit parameters (`limit:<key>[>=n]`).
452
+ *
453
+ * Never a declarable capability scope: a plan's limits live in `ProductPlan.limits`, and a
454
+ * capability predicate refuses any parameter under this scope, so a limit requirement can never be
455
+ * satisfied by a capability grant.
456
+ */
457
+ export const CAPABILITY_LIMIT_SCOPE = 'limit'
458
+
459
+ /**
460
+ * Preserves today's fixed behavior for every consumer that declares no policy: automatic tax and
461
+ * tax-id collection stay on for every checkout (`taxOptions` before this policy existed), no
462
+ * `behavior` is forced onto a synced price, no Adaptive Pricing, and the estimate endpoints are off
463
+ * (a new capability, opt-in only).
464
+ */
465
+ export const DEFAULT_PRICING_POLICY: PricingPolicy = Object.freeze({
466
+ tax: Object.freeze({ automatic: true, collectTaxId: true, estimate: false }),
467
+ currency: Object.freeze({ estimate: false }),
468
+ }) as PricingPolicy
469
+
470
+ /** The window key a lifetime limit's counter lives under. */
471
+ export const LIFETIME_WINDOW = 'lifetime'
472
+
473
+ /** The window key an occupancy limit's counter lives under. */
474
+ export const OCCUPANCY_WINDOW = 'occupancy'
475
+
476
+ /** The 27 EU member states (ISO 3166-1 alpha-2; Greece is `GR`, as Stripe reports it). */
477
+ export const EU_COUNTRIES: readonly string[] = Object.freeze([
478
+ 'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HR', 'HU',
479
+ 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK',
480
+ ])
481
+
482
+ /**
483
+ * The member states plus the parts of them that carry their own ISO code — Åland (FI) and the
484
+ * French outermost regions (French Guiana, Guadeloupe, Martinique, Réunion, Mayotte, Saint-Martin).
485
+ * EU consumer law applies there even where EU VAT does not; the Canary Islands, Azores and Madeira
486
+ * share their state's code. Scope beyond the member states is a question for the lawyer.
487
+ */
488
+ export const EU_CONSUMER_TERRITORIES: readonly string[] = Object.freeze([
489
+ ...EU_COUNTRIES, 'AX', 'GF', 'GP', 'MQ', 'RE', 'YT', 'MF',
490
+ ])
491
+
492
+ /** The EEA members outside the EU. */
493
+ export const EEA_EXTRA: readonly string[] = Object.freeze(['IS', 'LI', 'NO'])
494
+
495
+ /** The territories whose consumers have the right of withdrawal by default: the EU's and the EEA's. */
496
+ export const CONSUMER_RIGHTS_TERRITORIES: readonly string[] = Object.freeze([
497
+ ...EU_CONSUMER_TERRITORIES, ...EEA_EXTRA,
498
+ ])
499
+
500
+ /**
501
+ * Country → the language of its legal copy, only where that is unambiguous (Belgium, Luxembourg,
502
+ * Switzerland, Canada … are absent and fall back to the policy's default). An application widens
503
+ * or overrides it with `ConsumerRightsPolicy.languages`.
504
+ */
505
+ export const COUNTRY_LANGUAGES: Readonly<Record<string, string>> = Object.freeze({
506
+ DE: 'de', AT: 'de', LI: 'de',
507
+ FR: 'fr', GF: 'fr', GP: 'fr', MQ: 'fr', RE: 'fr', YT: 'fr', MF: 'fr', MC: 'fr',
508
+ PL: 'pl',
509
+ ES: 'es',
510
+ IE: 'en', MT: 'en', GB: 'en', US: 'en', AU: 'en', NZ: 'en',
511
+ UA: 'uk',
512
+ BY: 'be',
513
+ RU: 'ru',
514
+ })
@@ -0,0 +1,40 @@
1
+ import { ConsumerRightsError } from '../errors.js'
2
+ import type { BillingInterval } from './types.js'
3
+
4
+ /** `anchor` moved by `months` calendar months (UTC), its day clamped to the target month's end. */
5
+ const addMonths = (anchor: Date, months: number): Date => {
6
+ const year = anchor.getUTCFullYear()
7
+ const month = anchor.getUTCMonth() + months
8
+ const lastDay = new Date(Date.UTC(year, month + 1, 0)).getUTCDate()
9
+
10
+ return new Date(Date.UTC(
11
+ year, month, Math.min(anchor.getUTCDate(), lastDay),
12
+ anchor.getUTCHours(), anchor.getUTCMinutes(), anchor.getUTCSeconds(), anchor.getUTCMilliseconds(),
13
+ ))
14
+ }
15
+
16
+ /**
17
+ * When an ordinary cancellation takes effect. No requested date, or one on or before the current
18
+ * period's end, ends the contract at `periodEnd`; a later date ends it at the first period
19
+ * boundary on or after that date — whole intervals stepped from `periodEnd`, each step measured
20
+ * from `periodEnd` itself so a 31st stays the 31st where the month has one.
21
+ *
22
+ * @throws ConsumerRightsError (`cancellation:date`) for an invalid date.
23
+ */
24
+ export const cancellationEffectiveAt = (periodEnd: Date, interval: BillingInterval, requested?: Date | null): Date => {
25
+ if (Number.isNaN(periodEnd.getTime()) || (requested != null && Number.isNaN(requested.getTime()))) {
26
+ throw new ConsumerRightsError('cancellation:date')
27
+ }
28
+ if (requested == null || requested.getTime() <= periodEnd.getTime()) {
29
+ return periodEnd
30
+ }
31
+ const step = interval === 'year' ? 12 : 1
32
+ let count = 1
33
+ let candidate = addMonths(periodEnd, step)
34
+ while (candidate.getTime() < requested.getTime()) {
35
+ count += 1
36
+ candidate = addMonths(periodEnd, step * count)
37
+ }
38
+
39
+ return candidate
40
+ }
@@ -0,0 +1,16 @@
1
+ import { ConsentKind } from '../consts.js'
2
+ import { PerformanceConsentRequired, SubscriptionStartRequired } from '../errors.js'
3
+
4
+ export const COUNTRY = /^[A-Z]{2}$/
5
+
6
+ export const CURRENCY = /^[a-z]{3}$/
7
+
8
+ export const CONSENT_CONTEXT = /^[a-z][a-z0-9-]{0,63}$/
9
+
10
+ /** The marker or type name a refusal of each express request carries in its message or type. */
11
+ export const CONSENT_REFUSAL_MARKERS: Array<[string, ConsentKind]> = [
12
+ ['performance-consent-required', ConsentKind.Performance],
13
+ [PerformanceConsentRequired.typeName, ConsentKind.Performance],
14
+ ['subscription-start-required', ConsentKind.SubscriptionStart],
15
+ [SubscriptionStartRequired.typeName, ConsentKind.SubscriptionStart],
16
+ ]
@@ -0,0 +1,46 @@
1
+ import type { ConsumerRightsMechanisms, ConsumerRightsPolicy } from '../types.js'
2
+ import { CONSUMER_RIGHTS_TERRITORIES } from '../consts.js'
3
+
4
+ export const DAY_MS = 86_400_000
5
+
6
+ /** Every mechanism off: declaring a policy changes nothing until the application switches one on. */
7
+ export const NO_CONSUMER_RIGHTS_MECHANISMS: ConsumerRightsMechanisms = Object.freeze({
8
+ countryLock: false,
9
+ checkoutTerms: false,
10
+ performanceConsent: false,
11
+ subscriptionStart: false,
12
+ withdrawal: false,
13
+ automaticRefunds: false,
14
+ cancellation: false,
15
+ purchaseConfirmation: false,
16
+ })
17
+
18
+ /**
19
+ * What a declaration leaves out: the EU and EEA territories, an unknown country protected, 14 days
20
+ * ending at the end of a UTC day, a weekend end moved to Monday, five margin days, every mechanism
21
+ * off, English as the default language, start requests usable for an hour.
22
+ *
23
+ * Five margin days because a period ending on a public holiday runs to the next working day (EU
24
+ * Reg. 1182/71 art. 3(4)) and holiday clusters (24–26 December plus a weekend, Maundy Thursday to
25
+ * Easter Monday) need up to five; no per-country holiday calendar is kept, so a generous margin
26
+ * keeps the withdrawal function open for the whole statutory period everywhere.
27
+ */
28
+ export const DEFAULT_CONSUMER_RIGHTS: Readonly<Omit<ConsumerRightsPolicy, 'textVersion' | 'links'>> = Object.freeze({
29
+ countries: [...CONSUMER_RIGHTS_TERRITORIES],
30
+ unknownCountry: 'protect',
31
+ withdrawalDays: 14,
32
+ deadline: Object.freeze({ weekendRollover: true, marginDays: 5 }),
33
+ mechanisms: NO_CONSUMER_RIGHTS_MECHANISMS,
34
+ defaultLanguage: 'en',
35
+ renewalOpensWindow: false,
36
+ startRequestTtlSeconds: 3600,
37
+ exemptBusinesses: false,
38
+ })
39
+
40
+ export const CONSUMER_RIGHTS_API_PATH = '/consumer-rights'
41
+
42
+ export const CONSUMER_RIGHTS_PUBLIC_PATH = '/public/consumer-rights'
43
+
44
+ export const CONSUMER_RIGHTS_WITHDRAWAL_SCREEN_PATH = '/legal/withdraw'
45
+
46
+ export const CONSUMER_RIGHTS_CANCELLATION_SCREEN_PATH = '/legal/cancel'
@@ -0,0 +1,54 @@
1
+ import type { ConsentKind } from '../../consts.js'
2
+ import type { ProductPlan } from '../../types.js'
3
+ import type { ConsentStatement, CopyTree, CopyValues, LegalLabels } from '../types.js'
4
+
5
+ /** The consumer-rights legal copy of any language, and the texts rendered from it. */
6
+ export interface ConsumerCopyHelper {
7
+ /**
8
+ * The consumer-rights copy of one language — the `payment-consumer-rights` bundles as registered
9
+ * (the package's own, merged under any application override made with
10
+ * `addI18nApp(lng, 'payment-consumer-rights', data, { ns: LIB_NAMESPACE })`), key by key over the
11
+ * English ones so a missing key still reads. Any language, independent of the active i18next
12
+ * language and without draining a bundle: this is what a server renders e-mails and paygate
13
+ * texts from, and what a dialog shows in the billing country's language.
14
+ */
15
+ consumerRightsCopy: (lng: string) => CopyTree
16
+ /**
17
+ * One text of the copy at a dot path (`withdrawal.function`), its `{{name}}` placeholders filled.
18
+ * Values are inserted as given — escape them for the medium (HTML) before passing them in.
19
+ *
20
+ * With a `context`, the variant `<path>_<context>` is read first and the base `path` only where the
21
+ * copy has no such variant — the i18next context suffix (`performance-consent.request_included`).
22
+ *
23
+ * @throws ConsumerRightsError `copy:<path>` when the path is not a text, `copy:<path>:<name>` when a
24
+ * placeholder has no value — a legal text is never sent with a hole in it.
25
+ */
26
+ consumerText: (lng: string, path: string, vars?: CopyValues, context?: string) => string
27
+ /** The placeholders a text of the copy expects, in order of first appearance. */
28
+ placeholdersOf: (text: string) => string[]
29
+ /**
30
+ * The statutory button labels of one language — the withdrawal function (CRD Art. 11a; § 356a
31
+ * BGB; L221-21) and the cancellation function (§ 312k BGB; L215-1-1). Shown in the language of the
32
+ * billing country, whatever the interface language.
33
+ */
34
+ legalLabelsOf: (lng: string) => LegalLabels
35
+ /**
36
+ * The copy variant of a plan's subscription start statement — the one place it is decided.
37
+ *
38
+ * `'units'` exactly when the plan's `withdrawal.components` declare a `units` part: the statement
39
+ * then names the split (the services pro rata by time, the right of withdrawal expiring for the
40
+ * included units used) — the `_units` texts. Otherwise (no components, or `time` parts only: the
41
+ * whole price pro rata by the days elapsed) `undefined`, the base texts.
42
+ */
43
+ startContextOf: (plan: Pick<ProductPlan, 'withdrawal'> | null | undefined) => 'units' | undefined
44
+ /**
45
+ * The express request of one consent kind in one language, rendered — what the dialog shows, the
46
+ * server records and the confirmation e-mail repeats verbatim. `trader` names the business;
47
+ * `plan` (the plan's title) is required for a subscription start; `context` picks the
48
+ * `_<context>` variant of each text that has one — the policy's `consentContext` for the
49
+ * performance consent, `startContextOf(plan)` for a subscription start.
50
+ */
51
+ consentStatementOf: (
52
+ lng: string, kind: ConsentKind, vars: { trader: string, plan?: string, context?: string },
53
+ ) => ConsentStatement
54
+ }