@owlmeans/payment 0.1.18-rc.9 → 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 (366) 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 +7 -55
  134. package/build/entitlement.d.ts.map +1 -1
  135. package/build/entitlement.js +55 -86
  136. package/build/entitlement.js.map +1 -1
  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 +18 -1
  169. package/build/index.d.ts.map +1 -1
  170. package/build/index.js +11 -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 +67 -103
  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 +18 -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 +38 -25
  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/view.spec.ts +130 -0
  359. package/build/.gitkeep +0 -0
  360. package/src/model/subscription.ts +0 -63
  361. package/src/model/utils.ts +0 -32
  362. package/src/modules.ts +0 -43
  363. package/tests/entitlement.spec.d.ts +0 -2
  364. package/tests/entitlement.spec.d.ts.map +0 -1
  365. package/tests/entitlement.spec.js +0 -72
  366. package/tests/entitlement.spec.js.map +0 -1
package/src/limit.ts ADDED
@@ -0,0 +1,132 @@
1
+ import { LimitKind, LimitWindow, CAPABILITY_LIMIT_SCOPE, LIFETIME_WINDOW, OCCUPANCY_WINDOW, SUBSCRIPTION_WEEK_MS, SUBSCRIPTION_WEEK_PREFIX } from './consts.js'
2
+ import { entitlementParamHelper } from './entitlement.js'
3
+ import { LimitMisdeclared } from './errors.js'
4
+ import type { EntitlementView, LimitView, LimitParam } from './types.js'
5
+ import type { PermissionSet } from '@owlmeans/auth'
6
+ import type { PlanLimitHelper } from './limit/types.js'
7
+
8
+ const pad = (value: number): string => String(value).padStart(2, '0')
9
+
10
+ export const createPlanLimitHelper = (): PlanLimitHelper => {
11
+ const windowKeyOf = (
12
+ kind: LimitKind, window?: LimitWindow | null, at: Date = new Date(), anchor?: Date,
13
+ ): string => {
14
+ switch (kind) {
15
+ case LimitKind.Lifetime:
16
+ return LIFETIME_WINDOW
17
+ case LimitKind.Occupancy:
18
+ return OCCUPANCY_WINDOW
19
+ case LimitKind.Window: {
20
+ const month = `${at.getUTCFullYear()}-${pad(at.getUTCMonth() + 1)}`
21
+ switch (window) {
22
+ case LimitWindow.SubscriptionWeek:
23
+ return `${SUBSCRIPTION_WEEK_PREFIX}${windowBoundsOf(window, at, anchor).start.toISOString()}`
24
+ case LimitWindow.Month:
25
+ return month
26
+ case LimitWindow.Day:
27
+ return `${month}-${pad(at.getUTCDate())}`
28
+ }
29
+ throw new LimitMisdeclared(`window:${window ?? 'missing'}`)
30
+ }
31
+ }
32
+ throw new LimitMisdeclared(`kind:${kind}`)
33
+ }
34
+
35
+ const windowBoundsOf = (
36
+ window: LimitWindow, at: Date = new Date(), anchor?: Date,
37
+ ): { start: Date, resetsAt: Date } => {
38
+ const year = at.getUTCFullYear()
39
+ const month = at.getUTCMonth()
40
+ switch (window) {
41
+ case LimitWindow.SubscriptionWeek: {
42
+ const origin = anchor?.getTime()
43
+ if (origin == null || !Number.isFinite(origin) || !Number.isFinite(at.getTime())) {
44
+ throw new LimitMisdeclared('subscription-week:anchor')
45
+ }
46
+ const start = new Date(origin + Math.floor((at.getTime() - origin) / SUBSCRIPTION_WEEK_MS) * SUBSCRIPTION_WEEK_MS)
47
+ return { start, resetsAt: new Date(start.getTime() + SUBSCRIPTION_WEEK_MS) }
48
+ }
49
+ case LimitWindow.Month:
50
+ return { start: new Date(Date.UTC(year, month, 1)), resetsAt: new Date(Date.UTC(year, month + 1, 1)) }
51
+ case LimitWindow.Day: {
52
+ const day = at.getUTCDate()
53
+ return {
54
+ start: new Date(Date.UTC(year, month, day)), resetsAt: new Date(Date.UTC(year, month, day + 1)),
55
+ }
56
+ }
57
+ }
58
+ throw new LimitMisdeclared(`window:${window}`)
59
+ }
60
+
61
+ const formatLimitParam = (key: string, atLeast?: number): string =>
62
+ entitlementParamHelper.formatEntitlementParam({ scope: CAPABILITY_LIMIT_SCOPE, permission: key, atLeast })
63
+
64
+ const parseLimitParam = (param: string): LimitParam | null => {
65
+ if (typeof param !== 'string') {
66
+ return null
67
+ }
68
+ const parsed = entitlementParamHelper.parseEntitlementParam(param)
69
+ if (parsed.scope !== CAPABILITY_LIMIT_SCOPE || parsed.permission === '') {
70
+ return null
71
+ }
72
+ const atLeast = parsed.atLeast ?? 1
73
+ if (!Number.isFinite(atLeast) || atLeast <= 0) {
74
+ return null
75
+ }
76
+
77
+ return { key: parsed.permission, atLeast }
78
+ }
79
+
80
+ const hasLimitRoom = (limit: LimitView | null | undefined, atLeast: number = 1): boolean =>
81
+ limit != null && limit.remaining >= atLeast
82
+
83
+ const limitOf = (
84
+ view: EntitlementView | null | undefined, key: string,
85
+ ): LimitView | null => view?.limits.find(limit => limit.key === key) ?? null
86
+
87
+ const capabilityOf = (view: EntitlementView | null | undefined, param: string): boolean => {
88
+ if (view == null) {
89
+ return false
90
+ }
91
+ // One set per row, so two grants of one permission are two chances — exactly as the declared
92
+ // sets they were built from.
93
+ const sets: PermissionSet[] = view.capabilities
94
+ .filter(capability => capability.granted)
95
+ .map(capability => ({
96
+ scope: capability.scope, permissions: { [capability.permission]: capability.value },
97
+ }))
98
+
99
+ return entitlementParamHelper.hasEntitlement(sets, param)
100
+ }
101
+
102
+ return { windowKeyOf, windowBoundsOf, formatLimitParam, parseLimitParam, hasLimitRoom, limitOf, capabilityOf }
103
+ }
104
+
105
+ export const planLimitHelper = createPlanLimitHelper()
106
+
107
+ /** @deprecated compat:factory-refactor — use `planLimitHelper.windowKeyOf(…)` */
108
+ export const windowKeyOf = (kind: LimitKind, window?: LimitWindow | null, at?: Date, anchor?: Date): string =>
109
+ planLimitHelper.windowKeyOf(kind, window, at, anchor)
110
+
111
+ /** @deprecated compat:factory-refactor — use `planLimitHelper.windowBoundsOf(…)` */
112
+ export const windowBoundsOf = (window: LimitWindow, at?: Date, anchor?: Date): { start: Date, resetsAt: Date } =>
113
+ planLimitHelper.windowBoundsOf(window, at, anchor)
114
+
115
+ /** @deprecated compat:factory-refactor — use `planLimitHelper.formatLimitParam(…)` */
116
+ export const formatLimitParam = (key: string, atLeast?: number): string =>
117
+ planLimitHelper.formatLimitParam(key, atLeast)
118
+
119
+ /** @deprecated compat:factory-refactor — use `planLimitHelper.parseLimitParam(…)` */
120
+ export const parseLimitParam = (param: string): LimitParam | null => planLimitHelper.parseLimitParam(param)
121
+
122
+ /** @deprecated compat:factory-refactor — use `planLimitHelper.hasLimitRoom(…)` */
123
+ export const hasLimitRoom = (limit: LimitView | null | undefined, atLeast?: number): boolean =>
124
+ planLimitHelper.hasLimitRoom(limit, atLeast)
125
+
126
+ /** @deprecated compat:factory-refactor — use `planLimitHelper.limitOf(…)` */
127
+ export const limitOf = (view: EntitlementView | null | undefined, key: string): LimitView | null =>
128
+ planLimitHelper.limitOf(view, key)
129
+
130
+ /** @deprecated compat:factory-refactor — use `planLimitHelper.capabilityOf(…)` */
131
+ export const capabilityOf = (view: EntitlementView | null | undefined, param: string): boolean =>
132
+ planLimitHelper.capabilityOf(view, param)
@@ -1,27 +1,32 @@
1
1
  import type { JSONSchemaType } from 'ajv'
2
2
  import type { CreateCheckoutBody, CreateCheckoutResponse } from '../types.js'
3
3
  import { ResourceValueSchema, EntityValueSchema, IdValueSchema } from '@owlmeans/auth'
4
+ import { schema } from '@owlmeans/entrypoint'
5
+ import { CountrySchema } from '../consts.js'
4
6
 
5
- export const CreateCheckoutBodySchema: JSONSchemaType<CreateCheckoutBody> = {
7
+ export const CreateCheckoutBodySchema = schema<CreateCheckoutBody>({
6
8
  type: 'object',
7
9
  properties: {
8
10
  productSku: ResourceValueSchema,
9
- sku: { ...ResourceValueSchema, nullable: true },
10
- entityId: EntityValueSchema,
11
+ planSku: { ...ResourceValueSchema, nullable: true },
12
+ entitySlug: EntityValueSchema,
11
13
  service: { ...ResourceValueSchema, minLength: 2 },
14
+ amountMinor: { type: 'number', minimum: 0, multipleOf: 1, nullable: true },
12
15
  subscriptionId: { ...IdValueSchema, nullable: true },
13
16
  successUrl: { ...ResourceValueSchema, minLength: 1, nullable: true },
14
17
  cancelUrl: { ...ResourceValueSchema, minLength: 1, nullable: true },
18
+ country: { ...CountrySchema, nullable: true },
19
+ startRequestId: { ...IdValueSchema, nullable: true },
15
20
  },
16
- required: ['productSku', 'entityId', 'service'],
21
+ required: ['productSku', 'entitySlug', 'service'],
17
22
  additionalProperties: false,
18
- }
23
+ } as JSONSchemaType<CreateCheckoutBody>)
19
24
 
20
- export const CreateCheckoutResponseSchema: JSONSchemaType<CreateCheckoutResponse> = {
25
+ export const CreateCheckoutResponseSchema = schema<CreateCheckoutResponse>({
21
26
  type: 'object',
22
27
  properties: {
23
28
  url: { type: 'string', minLength: 1 },
24
29
  },
25
30
  required: ['url'],
26
31
  additionalProperties: false,
27
- }
32
+ } as JSONSchemaType<CreateCheckoutResponse>)
@@ -0,0 +1,83 @@
1
+ import type { JSONSchemaType } from 'ajv'
2
+ import { IdValueSchema } from '@owlmeans/auth'
3
+ import type { TaxEstimate, TaxRateEstimate } from '../types.js'
4
+ import { TaxEstimateStatusSchema, TaxTypeSchema, CountrySchema, ConsumerRegion, ConsumerRegionSchema } from '../consts.js'
5
+
6
+ /**
7
+ * The consumer-rights schemas describe the WIRE: a date is an ISO string, exactly as in
8
+ * `model/view.ts` — a response serializer writes a `Date` through it as ISO. A browser revives the
9
+ * dates with the `revive*` helpers before touching one.
10
+ */
11
+ export const IsoDateSchema = { type: 'string', format: 'date-time' } as unknown as JSONSchemaType<Date>
12
+
13
+ export const MinorSchema: JSONSchemaType<number> = { type: 'number', minimum: 0, multipleOf: 1 }
14
+
15
+ export const CurrencySchema: JSONSchemaType<string> = { type: 'string', minLength: 3, maxLength: 3 }
16
+
17
+ export const VersionSchema: JSONSchemaType<string> = { type: 'string', minLength: 1, maxLength: 64 }
18
+
19
+ export const KeySchema: JSONSchemaType<string> = { type: 'string', minLength: 1, maxLength: 128 }
20
+
21
+ export const UrlSchema: JSONSchemaType<string> = { type: 'string', minLength: 1, maxLength: 2048 }
22
+
23
+ export const LanguageSchema: JSONSchemaType<string> = {
24
+ type: 'string', minLength: 2, maxLength: 16, pattern: '^[a-z]{2,3}([-_][A-Za-z0-9]{2,8})?$',
25
+ }
26
+
27
+ export const NameSchema: JSONSchemaType<string> = { type: 'string', minLength: 1, maxLength: 200 }
28
+
29
+ export const EmailSchema: JSONSchemaType<string> = {
30
+ type: 'string', minLength: 3, maxLength: 254, pattern: '^[^\\s@]+@[^\\s@]+$',
31
+ }
32
+
33
+ export const HoneypotSchema: JSONSchemaType<string> = { type: 'string', maxLength: 256 }
34
+
35
+ /** A copy variant suffix: `performance-consent.request_<context>`, `subscription-start.request_units`. */
36
+ export const ConsentContextSchema: JSONSchemaType<string> = {
37
+ type: 'string', minLength: 1, maxLength: 64, pattern: '^[a-z][a-z0-9-]*$',
38
+ }
39
+
40
+ export const AcknowledgedSchema = { type: 'boolean', const: true } as unknown as JSONSchemaType<true>
41
+
42
+ export const ReceiptContentSchema = {
43
+ type: 'object', required: [], additionalProperties: { type: 'string', maxLength: 4096 },
44
+ } as unknown as JSONSchemaType<Record<string, string>>
45
+
46
+ export const declarationReceiptProperties = {
47
+ declarationId: IdValueSchema,
48
+ receivedAt: IsoDateSchema,
49
+ content: ReceiptContentSchema,
50
+ mailed: { type: 'boolean' },
51
+ }
52
+
53
+ export const TaxRateEstimateSchema: JSONSchemaType<TaxRateEstimate> = {
54
+ type: 'object',
55
+ properties: {
56
+ type: TaxTypeSchema,
57
+ percentage: { type: 'string', minLength: 1, maxLength: 16 },
58
+ ratePpm: { type: 'number', minimum: 0, multipleOf: 1 },
59
+ country: { ...CountrySchema, nullable: true },
60
+ state: { type: 'string', minLength: 1, maxLength: 8, nullable: true },
61
+ },
62
+ required: ['type', 'percentage', 'ratePpm'],
63
+ additionalProperties: false,
64
+ }
65
+
66
+ export const TaxEstimateSchema: JSONSchemaType<TaxEstimate> = {
67
+ type: 'object',
68
+ properties: {
69
+ status: TaxEstimateStatusSchema,
70
+ subtotalMinor: { type: 'number', minimum: 0, multipleOf: 1 },
71
+ taxMinor: { type: 'number', minimum: 0, multipleOf: 1 },
72
+ totalMinor: { type: 'number', minimum: 0, multipleOf: 1 },
73
+ scalable: { type: 'boolean' },
74
+ rates: { type: 'array', items: TaxRateEstimateSchema },
75
+ },
76
+ required: ['status', 'subtotalMinor', 'taxMinor', 'totalMinor', 'scalable', 'rates'],
77
+ additionalProperties: false,
78
+ }
79
+
80
+ /** A region that may be `null` on the wire — an enum admits `null` only when it lists it. */
81
+ export const NullableRegionSchema = {
82
+ ...ConsumerRegionSchema, enum: [...ConsumerRegionSchema.enum, null], nullable: true,
83
+ } as unknown as JSONSchemaType<ConsumerRegion | null>
@@ -0,0 +1,206 @@
1
+ import type { JSONSchemaType } from 'ajv'
2
+ import type { CheckoutLimitView, ConsumerRightsLinks, ConsumerRightsMechanisms, PlanPriceView, PlanWithdrawalComponent, PurchaseView, WithdrawalCandidate, WithdrawalEstimate, CapabilityView, EntitlementPlanView, LimitView, PromoView } from '../types.js'
3
+ import { IdValueSchema } from '@owlmeans/auth'
4
+ import { PurchaseKindSchema, TaxBehaviorSchema, LimitKindSchema, LimitWindowSchema, SubscriptionStatusSchema } from '../consts.js'
5
+ import { CurrencySchema, IsoDateSchema, KeySchema, MinorSchema, UrlSchema } from './consts.local.js'
6
+
7
+ export const ConsumerRightsLinksSchema: JSONSchemaType<ConsumerRightsLinks> = {
8
+ type: 'object',
9
+ properties: {
10
+ billingTerms: UrlSchema,
11
+ withdrawalInformation: { ...UrlSchema, nullable: true },
12
+ withdrawalForm: { ...UrlSchema, nullable: true },
13
+ withdrawalFunction: { ...UrlSchema, nullable: true },
14
+ cancellation: { ...UrlSchema, nullable: true },
15
+ },
16
+ required: ['billingTerms'],
17
+ additionalProperties: false,
18
+ }
19
+
20
+ export const ConsumerRightsMechanismsSchema: JSONSchemaType<ConsumerRightsMechanisms> = {
21
+ type: 'object',
22
+ properties: {
23
+ countryLock: { type: 'boolean' },
24
+ checkoutTerms: { type: 'boolean' },
25
+ performanceConsent: { type: 'boolean' },
26
+ subscriptionStart: { type: 'boolean' },
27
+ withdrawal: { type: 'boolean' },
28
+ automaticRefunds: { type: 'boolean' },
29
+ cancellation: { type: 'boolean' },
30
+ purchaseConfirmation: { type: 'boolean' },
31
+ },
32
+ required: [
33
+ 'countryLock', 'checkoutTerms', 'performanceConsent', 'subscriptionStart', 'withdrawal', 'automaticRefunds',
34
+ 'cancellation', 'purchaseConfirmation',
35
+ ],
36
+ additionalProperties: false,
37
+ }
38
+
39
+ export const PlanWithdrawalComponentSchema: JSONSchemaType<PlanWithdrawalComponent> = {
40
+ type: 'object',
41
+ properties: {
42
+ key: KeySchema,
43
+ basis: { type: 'string', enum: ['time', 'units'] },
44
+ shareMinor: MinorSchema,
45
+ },
46
+ required: ['key', 'basis', 'shareMinor'],
47
+ additionalProperties: false,
48
+ }
49
+
50
+ export const PurchaseViewSchema: JSONSchemaType<PurchaseView> = {
51
+ type: 'object',
52
+ properties: {
53
+ purchaseId: IdValueSchema,
54
+ contractRef: IdValueSchema,
55
+ kind: PurchaseKindSchema,
56
+ purchasedAt: IsoDateSchema,
57
+ deadline: { ...IsoDateSchema, nullable: true },
58
+ productSku: KeySchema,
59
+ planSku: { ...KeySchema, nullable: true },
60
+ amountTotalMinor: MinorSchema,
61
+ currency: CurrencySchema,
62
+ consentedAt: { ...IsoDateSchema, nullable: true },
63
+ withdrawnAt: { ...IsoDateSchema, nullable: true },
64
+ withdrawable: { type: 'boolean' },
65
+ },
66
+ required: [
67
+ 'purchaseId', 'contractRef', 'kind', 'purchasedAt', 'productSku', 'amountTotalMinor', 'currency', 'withdrawable',
68
+ ],
69
+ additionalProperties: false,
70
+ }
71
+
72
+ export const WithdrawalEstimateSchema: JSONSchemaType<WithdrawalEstimate> = {
73
+ type: 'object',
74
+ properties: {
75
+ refundMinor: MinorSchema,
76
+ currency: CurrencySchema,
77
+ timeDeductionMinor: MinorSchema,
78
+ unitsDeductionMinor: MinorSchema,
79
+ elapsedDays: { ...MinorSchema, nullable: true },
80
+ periodDays: { ...MinorSchema, nullable: true },
81
+ unitsUsed: { type: 'number', minimum: 0, nullable: true },
82
+ unitsGranted: { type: 'number', minimum: 0, nullable: true },
83
+ },
84
+ required: ['refundMinor', 'currency', 'timeDeductionMinor', 'unitsDeductionMinor'],
85
+ additionalProperties: false,
86
+ }
87
+
88
+ export const WithdrawalCandidateSchema: JSONSchemaType<WithdrawalCandidate> = {
89
+ type: 'object',
90
+ properties: {
91
+ purchaseId: IdValueSchema,
92
+ contractRef: IdValueSchema,
93
+ kind: PurchaseKindSchema,
94
+ purchasedAt: IsoDateSchema,
95
+ deadline: IsoDateSchema,
96
+ amountTotalMinor: MinorSchema,
97
+ currency: CurrencySchema,
98
+ estimate: { ...WithdrawalEstimateSchema, nullable: true },
99
+ automatic: { type: 'boolean' },
100
+ },
101
+ required: [
102
+ 'purchaseId', 'contractRef', 'kind', 'purchasedAt', 'deadline', 'amountTotalMinor', 'currency', 'estimate',
103
+ 'automatic',
104
+ ],
105
+ additionalProperties: false,
106
+ } as unknown as JSONSchemaType<WithdrawalCandidate>
107
+
108
+ export const CheckoutLimitViewSchema: JSONSchemaType<CheckoutLimitView> = {
109
+ type: 'object',
110
+ properties: {
111
+ productSku: { type: 'string', maxLength: 128 },
112
+ planSku: { ...KeySchema, nullable: true },
113
+ currency: CurrencySchema,
114
+ minimumMinor: MinorSchema,
115
+ maximumMinor: MinorSchema,
116
+ narrowed: { type: 'boolean' },
117
+ blocked: { type: 'boolean' },
118
+ reason: { ...KeySchema, nullable: true },
119
+ resetsAt: { ...IsoDateSchema, nullable: true },
120
+ remainingMinor: { ...MinorSchema, nullable: true },
121
+ },
122
+ required: ['productSku', 'currency', 'minimumMinor', 'maximumMinor', 'narrowed', 'blocked'],
123
+ additionalProperties: false,
124
+ }
125
+
126
+ export const PlanPriceViewSchema: JSONSchemaType<PlanPriceView> = {
127
+ type: 'object',
128
+ properties: {
129
+ planSku: KeySchema,
130
+ currency: CurrencySchema,
131
+ unitAmountMinor: MinorSchema,
132
+ default: { type: 'boolean' },
133
+ taxBehavior: { ...TaxBehaviorSchema, nullable: true },
134
+ interval: { type: 'string', enum: ['month', 'year'], nullable: true },
135
+ },
136
+ required: ['planSku', 'currency', 'unitAmountMinor', 'default'],
137
+ additionalProperties: false,
138
+ } as JSONSchemaType<PlanPriceView>
139
+
140
+ export const PromoViewSchema: JSONSchemaType<PromoView> = {
141
+ type: 'object',
142
+ properties: {
143
+ until: IsoDateSchema,
144
+ grandfathered: { type: 'boolean' },
145
+ active: { type: 'boolean' },
146
+ },
147
+ required: ['until', 'grandfathered', 'active'],
148
+ additionalProperties: false,
149
+ }
150
+
151
+ export const CapabilityViewSchema: JSONSchemaType<CapabilityView> = {
152
+ type: 'object',
153
+ properties: {
154
+ param: KeySchema,
155
+ scope: KeySchema,
156
+ permission: KeySchema,
157
+ value: { type: ['boolean', 'number'] },
158
+ granted: { type: 'boolean' },
159
+ promo: { ...PromoViewSchema, nullable: true },
160
+ },
161
+ required: ['param', 'scope', 'permission', 'value', 'granted'],
162
+ additionalProperties: false,
163
+ } as unknown as JSONSchemaType<CapabilityView>
164
+
165
+ export const LimitViewSchema: JSONSchemaType<LimitView> = {
166
+ type: 'object',
167
+ properties: {
168
+ key: KeySchema,
169
+ param: KeySchema,
170
+ kind: LimitKindSchema,
171
+ window: { ...LimitWindowSchema, nullable: true },
172
+ limit: { type: 'number' },
173
+ used: { type: 'number' },
174
+ remaining: { type: 'number' },
175
+ windowStart: { ...IsoDateSchema, nullable: true },
176
+ resetsAt: { ...IsoDateSchema, nullable: true },
177
+ unit: { type: 'string', nullable: true },
178
+ promo: { ...PromoViewSchema, nullable: true },
179
+ },
180
+ required: ['key', 'param', 'kind', 'limit', 'used', 'remaining'],
181
+ additionalProperties: false,
182
+ } as JSONSchemaType<LimitView>
183
+
184
+ export const EntitlementPlanViewSchema: JSONSchemaType<EntitlementPlanView> = {
185
+ type: 'object',
186
+ properties: {
187
+ sku: KeySchema,
188
+ productSku: KeySchema,
189
+ title: { type: 'string' },
190
+ rank: { type: 'number' },
191
+ free: { type: 'boolean' },
192
+ status: SubscriptionStatusSchema,
193
+ paygate: KeySchema,
194
+ subscriptionId: { type: 'string', nullable: true },
195
+ subscribedAt: { ...IsoDateSchema, nullable: true },
196
+ periodStart: { ...IsoDateSchema, nullable: true },
197
+ periodEnd: { ...IsoDateSchema, nullable: true },
198
+ cancelAtPeriodEnd: { type: 'boolean', nullable: true },
199
+ trialEnd: { ...IsoDateSchema, nullable: true },
200
+ pausedAt: { ...IsoDateSchema, nullable: true },
201
+ pastDue: { type: 'boolean', nullable: true },
202
+ fallbackSku: { type: 'string', nullable: true },
203
+ },
204
+ required: ['sku', 'productSku', 'title', 'rank', 'free', 'status', 'paygate'],
205
+ additionalProperties: false,
206
+ } as JSONSchemaType<EntitlementPlanView>