@softure-ai/billing 0.0.0-stage → 0.1.5

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 (294) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +699 -2
  3. package/dist/calendar.d.ts +26 -0
  4. package/dist/calendar.d.ts.map +1 -0
  5. package/dist/calendar.js +81 -0
  6. package/dist/calendar.js.map +1 -0
  7. package/dist/contract.d.ts +187 -0
  8. package/dist/contract.d.ts.map +1 -0
  9. package/dist/contract.js +6 -0
  10. package/dist/contract.js.map +1 -0
  11. package/dist/currency-digits.d.ts +3 -0
  12. package/dist/currency-digits.d.ts.map +1 -0
  13. package/dist/currency-digits.js +32 -0
  14. package/dist/currency-digits.js.map +1 -0
  15. package/dist/entitlement.d.ts +25 -0
  16. package/dist/entitlement.d.ts.map +1 -0
  17. package/dist/entitlement.js +75 -0
  18. package/dist/entitlement.js.map +1 -0
  19. package/dist/fields.d.ts +25 -0
  20. package/dist/fields.d.ts.map +1 -0
  21. package/dist/fields.js +27 -0
  22. package/dist/fields.js.map +1 -0
  23. package/dist/index.d.ts +274 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +73 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/invoice.d.ts +29 -0
  28. package/dist/invoice.d.ts.map +1 -0
  29. package/dist/invoice.js +35 -0
  30. package/dist/invoice.js.map +1 -0
  31. package/dist/mailing/index.d.ts +2 -0
  32. package/dist/mailing/index.d.ts.map +1 -0
  33. package/dist/mailing/index.js +4 -0
  34. package/dist/mailing/index.js.map +1 -0
  35. package/dist/mailing/reminder-mail.d.ts +50 -0
  36. package/dist/mailing/reminder-mail.d.ts.map +1 -0
  37. package/dist/mailing/reminder-mail.js +71 -0
  38. package/dist/mailing/reminder-mail.js.map +1 -0
  39. package/dist/manual.d.ts +12 -0
  40. package/dist/manual.d.ts.map +1 -0
  41. package/dist/manual.js +22 -0
  42. package/dist/manual.js.map +1 -0
  43. package/dist/messages/en.d.ts +176 -0
  44. package/dist/messages/en.d.ts.map +1 -0
  45. package/dist/messages/en.js +151 -0
  46. package/dist/messages/en.js.map +1 -0
  47. package/dist/messages/index.d.ts +359 -0
  48. package/dist/messages/index.d.ts.map +1 -0
  49. package/dist/messages/index.js +14 -0
  50. package/dist/messages/index.js.map +1 -0
  51. package/dist/messages/pl.d.ts +3 -0
  52. package/dist/messages/pl.d.ts.map +1 -0
  53. package/dist/messages/pl.js +151 -0
  54. package/dist/messages/pl.js.map +1 -0
  55. package/dist/next/access.d.ts +16 -0
  56. package/dist/next/access.d.ts.map +1 -0
  57. package/dist/next/access.js +24 -0
  58. package/dist/next/access.js.map +1 -0
  59. package/dist/next/actions.d.ts +24 -0
  60. package/dist/next/actions.d.ts.map +1 -0
  61. package/dist/next/actions.js +158 -0
  62. package/dist/next/actions.js.map +1 -0
  63. package/dist/next/context.d.ts +4 -0
  64. package/dist/next/context.d.ts.map +1 -0
  65. package/dist/next/context.js +17 -0
  66. package/dist/next/context.js.map +1 -0
  67. package/dist/next/current-entitlement.d.ts +18 -0
  68. package/dist/next/current-entitlement.d.ts.map +1 -0
  69. package/dist/next/current-entitlement.js +26 -0
  70. package/dist/next/current-entitlement.js.map +1 -0
  71. package/dist/next/index.d.ts +8 -0
  72. package/dist/next/index.d.ts.map +1 -0
  73. package/dist/next/index.js +12 -0
  74. package/dist/next/index.js.map +1 -0
  75. package/dist/next/pages.d.ts +24 -0
  76. package/dist/next/pages.d.ts.map +1 -0
  77. package/dist/next/pages.js +166 -0
  78. package/dist/next/pages.js.map +1 -0
  79. package/dist/next/pricing.d.ts +12 -0
  80. package/dist/next/pricing.d.ts.map +1 -0
  81. package/dist/next/pricing.js +20 -0
  82. package/dist/next/pricing.js.map +1 -0
  83. package/dist/next/route.d.ts +11 -0
  84. package/dist/next/route.d.ts.map +1 -0
  85. package/dist/next/route.js +56 -0
  86. package/dist/next/route.js.map +1 -0
  87. package/dist/options.d.ts +85 -0
  88. package/dist/options.d.ts.map +1 -0
  89. package/dist/options.js +121 -0
  90. package/dist/options.js.map +1 -0
  91. package/dist/payment.d.ts +61 -0
  92. package/dist/payment.d.ts.map +1 -0
  93. package/dist/payment.js +12 -0
  94. package/dist/payment.js.map +1 -0
  95. package/dist/plans.d.ts +20 -0
  96. package/dist/plans.d.ts.map +1 -0
  97. package/dist/plans.js +53 -0
  98. package/dist/plans.js.map +1 -0
  99. package/dist/price.d.ts +12 -0
  100. package/dist/price.d.ts.map +1 -0
  101. package/dist/price.js +37 -0
  102. package/dist/price.js.map +1 -0
  103. package/dist/refund.d.ts +70 -0
  104. package/dist/refund.d.ts.map +1 -0
  105. package/dist/refund.js +109 -0
  106. package/dist/refund.js.map +1 -0
  107. package/dist/reminder.d.ts +30 -0
  108. package/dist/reminder.d.ts.map +1 -0
  109. package/dist/reminder.js +34 -0
  110. package/dist/reminder.js.map +1 -0
  111. package/dist/schema.d.ts +1023 -0
  112. package/dist/schema.d.ts.map +1 -0
  113. package/dist/schema.js +77 -0
  114. package/dist/schema.js.map +1 -0
  115. package/dist/scripts/entitlement-scripts.d.ts +17 -0
  116. package/dist/scripts/entitlement-scripts.d.ts.map +1 -0
  117. package/dist/scripts/entitlement-scripts.js +167 -0
  118. package/dist/scripts/entitlement-scripts.js.map +1 -0
  119. package/dist/scripts/index.d.ts +3 -0
  120. package/dist/scripts/index.d.ts.map +1 -0
  121. package/dist/scripts/index.js +5 -0
  122. package/dist/scripts/index.js.map +1 -0
  123. package/dist/scripts/plan-scripts.d.ts +19 -0
  124. package/dist/scripts/plan-scripts.d.ts.map +1 -0
  125. package/dist/scripts/plan-scripts.js +106 -0
  126. package/dist/scripts/plan-scripts.js.map +1 -0
  127. package/dist/server/entitlements.d.ts +69 -0
  128. package/dist/server/entitlements.d.ts.map +1 -0
  129. package/dist/server/entitlements.js +202 -0
  130. package/dist/server/entitlements.js.map +1 -0
  131. package/dist/server/grants.d.ts +74 -0
  132. package/dist/server/grants.d.ts.map +1 -0
  133. package/dist/server/grants.js +174 -0
  134. package/dist/server/grants.js.map +1 -0
  135. package/dist/server/health.d.ts +3 -0
  136. package/dist/server/health.d.ts.map +1 -0
  137. package/dist/server/health.js +17 -0
  138. package/dist/server/health.js.map +1 -0
  139. package/dist/server/index.d.ts +12 -0
  140. package/dist/server/index.d.ts.map +1 -0
  141. package/dist/server/index.js +14 -0
  142. package/dist/server/index.js.map +1 -0
  143. package/dist/server/options.d.ts +20 -0
  144. package/dist/server/options.d.ts.map +1 -0
  145. package/dist/server/options.js +38 -0
  146. package/dist/server/options.js.map +1 -0
  147. package/dist/server/payments.d.ts +140 -0
  148. package/dist/server/payments.d.ts.map +1 -0
  149. package/dist/server/payments.js +339 -0
  150. package/dist/server/payments.js.map +1 -0
  151. package/dist/server/plans.d.ts +50 -0
  152. package/dist/server/plans.d.ts.map +1 -0
  153. package/dist/server/plans.js +129 -0
  154. package/dist/server/plans.js.map +1 -0
  155. package/dist/server/privacy.d.ts +77 -0
  156. package/dist/server/privacy.d.ts.map +1 -0
  157. package/dist/server/privacy.js +110 -0
  158. package/dist/server/privacy.js.map +1 -0
  159. package/dist/server/reminders.d.ts +20 -0
  160. package/dist/server/reminders.d.ts.map +1 -0
  161. package/dist/server/reminders.js +85 -0
  162. package/dist/server/reminders.js.map +1 -0
  163. package/dist/server/requests.d.ts +80 -0
  164. package/dist/server/requests.d.ts.map +1 -0
  165. package/dist/server/requests.js +155 -0
  166. package/dist/server/requests.js.map +1 -0
  167. package/dist/server/setup.d.ts +9 -0
  168. package/dist/server/setup.d.ts.map +1 -0
  169. package/dist/server/setup.js +34 -0
  170. package/dist/server/setup.js.map +1 -0
  171. package/dist/server/take-back.d.ts +80 -0
  172. package/dist/server/take-back.d.ts.map +1 -0
  173. package/dist/server/take-back.js +138 -0
  174. package/dist/server/take-back.js.map +1 -0
  175. package/dist/server/user-id.d.ts +4 -0
  176. package/dist/server/user-id.d.ts.map +1 -0
  177. package/dist/server/user-id.js +11 -0
  178. package/dist/server/user-id.js.map +1 -0
  179. package/dist/stripe-currency.d.ts +27 -0
  180. package/dist/stripe-currency.d.ts.map +1 -0
  181. package/dist/stripe-currency.js +57 -0
  182. package/dist/stripe-currency.js.map +1 -0
  183. package/dist/stripe-webhook.d.ts +101 -0
  184. package/dist/stripe-webhook.d.ts.map +1 -0
  185. package/dist/stripe-webhook.js +209 -0
  186. package/dist/stripe-webhook.js.map +1 -0
  187. package/dist/stripe.d.ts +25 -0
  188. package/dist/stripe.d.ts.map +1 -0
  189. package/dist/stripe.js +116 -0
  190. package/dist/stripe.js.map +1 -0
  191. package/dist/ui/access-badge.d.ts +16 -0
  192. package/dist/ui/access-badge.d.ts.map +1 -0
  193. package/dist/ui/access-badge.js +43 -0
  194. package/dist/ui/access-badge.js.map +1 -0
  195. package/dist/ui/access-notice.d.ts +20 -0
  196. package/dist/ui/access-notice.d.ts.map +1 -0
  197. package/dist/ui/access-notice.js +41 -0
  198. package/dist/ui/access-notice.js.map +1 -0
  199. package/dist/ui/format.d.ts +11 -0
  200. package/dist/ui/format.d.ts.map +1 -0
  201. package/dist/ui/format.js +21 -0
  202. package/dist/ui/format.js.map +1 -0
  203. package/dist/ui/grant-form.d.ts +18 -0
  204. package/dist/ui/grant-form.d.ts.map +1 -0
  205. package/dist/ui/grant-form.js +23 -0
  206. package/dist/ui/grant-form.js.map +1 -0
  207. package/dist/ui/grant-history.d.ts +39 -0
  208. package/dist/ui/grant-history.d.ts.map +1 -0
  209. package/dist/ui/grant-history.js +36 -0
  210. package/dist/ui/grant-history.js.map +1 -0
  211. package/dist/ui/index.d.ts +9 -0
  212. package/dist/ui/index.d.ts.map +1 -0
  213. package/dist/ui/index.js +12 -0
  214. package/dist/ui/index.js.map +1 -0
  215. package/dist/ui/payment-form.d.ts +23 -0
  216. package/dist/ui/payment-form.d.ts.map +1 -0
  217. package/dist/ui/payment-form.js +34 -0
  218. package/dist/ui/payment-form.js.map +1 -0
  219. package/dist/ui/payment-requests.d.ts +30 -0
  220. package/dist/ui/payment-requests.d.ts.map +1 -0
  221. package/dist/ui/payment-requests.js +31 -0
  222. package/dist/ui/payment-requests.js.map +1 -0
  223. package/dist/ui/pricing-tiles.d.ts +22 -0
  224. package/dist/ui/pricing-tiles.d.ts.map +1 -0
  225. package/dist/ui/pricing-tiles.js +40 -0
  226. package/dist/ui/pricing-tiles.js.map +1 -0
  227. package/migrations/0001_create_entitlements.sql +16 -0
  228. package/migrations/0002_create_payments.sql +30 -0
  229. package/migrations/0003_record_payment_grants.sql +25 -0
  230. package/migrations/0004_create_requests_and_grants.sql +58 -0
  231. package/migrations/0005_record_refunded_amounts.sql +18 -0
  232. package/migrations/0006_record_request_handover_and_prices.sql +38 -0
  233. package/migrations/0007_record_failed_refunds.sql +27 -0
  234. package/migrations/0008_record_request_handover_claims.sql +9 -0
  235. package/migrations/0009_record_pending_charge_states.sql +16 -0
  236. package/module.json +23 -0
  237. package/package.json +81 -4
  238. package/src/calendar.ts +90 -0
  239. package/src/contract.ts +181 -0
  240. package/src/currency-digits.ts +37 -0
  241. package/src/entitlement.ts +84 -0
  242. package/src/fields.ts +37 -0
  243. package/src/index.ts +163 -0
  244. package/src/invoice.ts +58 -0
  245. package/src/mailing/index.ts +11 -0
  246. package/src/mailing/reminder-mail.ts +108 -0
  247. package/src/manual.ts +31 -0
  248. package/src/messages/en.ts +150 -0
  249. package/src/messages/index.ts +18 -0
  250. package/src/messages/pl.ts +152 -0
  251. package/src/next/access.tsx +55 -0
  252. package/src/next/actions.ts +176 -0
  253. package/src/next/context.ts +18 -0
  254. package/src/next/current-entitlement.ts +36 -0
  255. package/src/next/index.ts +11 -0
  256. package/src/next/next-modules.d.ts +21 -0
  257. package/src/next/pages.tsx +267 -0
  258. package/src/next/pricing.tsx +39 -0
  259. package/src/next/route.ts +57 -0
  260. package/src/options.ts +128 -0
  261. package/src/payment.ts +77 -0
  262. package/src/plans.ts +63 -0
  263. package/src/price.ts +50 -0
  264. package/src/refund.ts +135 -0
  265. package/src/reminder.ts +52 -0
  266. package/src/schema.ts +86 -0
  267. package/src/scripts/entitlement-scripts.ts +188 -0
  268. package/src/scripts/index.ts +11 -0
  269. package/src/scripts/plan-scripts.ts +143 -0
  270. package/src/server/entitlements.ts +227 -0
  271. package/src/server/grants.ts +227 -0
  272. package/src/server/health.ts +18 -0
  273. package/src/server/index.ts +83 -0
  274. package/src/server/options.ts +52 -0
  275. package/src/server/payments.ts +434 -0
  276. package/src/server/plans.ts +143 -0
  277. package/src/server/privacy.ts +189 -0
  278. package/src/server/reminders.ts +113 -0
  279. package/src/server/requests.ts +201 -0
  280. package/src/server/setup.ts +37 -0
  281. package/src/server/take-back.ts +190 -0
  282. package/src/server/user-id.ts +12 -0
  283. package/src/stripe-currency.ts +65 -0
  284. package/src/stripe-webhook.ts +278 -0
  285. package/src/stripe.ts +130 -0
  286. package/src/ui/access-badge.tsx +64 -0
  287. package/src/ui/access-notice.tsx +73 -0
  288. package/src/ui/format.ts +25 -0
  289. package/src/ui/grant-form.tsx +69 -0
  290. package/src/ui/grant-history.tsx +127 -0
  291. package/src/ui/index.ts +25 -0
  292. package/src/ui/payment-form.tsx +111 -0
  293. package/src/ui/payment-requests.tsx +126 -0
  294. package/src/ui/pricing-tiles.tsx +105 -0
@@ -0,0 +1,274 @@
1
+ export declare const MODULE_ID = "billing";
2
+ /**
3
+ * The rate limit bucket payments consume, with its default to spread into `security({ buckets })`:
4
+ * `billing-payment` per account (a payment page sent again and again).
5
+ */
6
+ export declare const BILLING_RATE_LIMIT_BUCKETS: {
7
+ readonly "billing-payment": {
8
+ readonly limit: 5;
9
+ readonly windowMinutes: 60;
10
+ };
11
+ };
12
+ /**
13
+ * Enables entitlements, plans and payments in `softure.config.ts` (after `security` and `auth`):
14
+ * `billing({ trial: { days: 14 }, plans: [{ id: "monthly", name: { en: "Monthly" }, price: { amount: 2900, currency: "PLN" }, period: "month" }], payment: stripe() })`
15
+ * (or `manual({ onRequest })` for invoices).
16
+ */
17
+ export declare const billing: import("@softure-ai/core").ModuleFactory<{
18
+ payment: string;
19
+ admin: string;
20
+ webhook: string;
21
+ }, {
22
+ badge: {
23
+ trial: string;
24
+ paid: string;
25
+ lifetime: string;
26
+ readOnly: string;
27
+ daysLeft: {
28
+ one: string;
29
+ few: string;
30
+ many: string;
31
+ other: string;
32
+ };
33
+ until: string;
34
+ };
35
+ notice: {
36
+ trialEnding: string;
37
+ paidEnding: string;
38
+ trialEnded: string;
39
+ paidEnded: string;
40
+ choosePlan: string;
41
+ renew: string;
42
+ };
43
+ reminderMail: {
44
+ trialEnding: {
45
+ subject: string;
46
+ body: string;
47
+ };
48
+ paidEnding: {
49
+ subject: string;
50
+ body: string;
51
+ };
52
+ trialEnded: {
53
+ subject: string;
54
+ body: string;
55
+ };
56
+ paidEnded: {
57
+ subject: string;
58
+ body: string;
59
+ };
60
+ };
61
+ pricing: {
62
+ period: {
63
+ day: {
64
+ one: string;
65
+ few: string;
66
+ many: string;
67
+ other: string;
68
+ };
69
+ week: {
70
+ one: string;
71
+ few: string;
72
+ many: string;
73
+ other: string;
74
+ };
75
+ month: {
76
+ one: string;
77
+ few: string;
78
+ many: string;
79
+ other: string;
80
+ };
81
+ year: {
82
+ one: string;
83
+ few: string;
84
+ many: string;
85
+ other: string;
86
+ };
87
+ lifetime: string;
88
+ };
89
+ featured: string;
90
+ choose: string;
91
+ empty: string;
92
+ };
93
+ payment: {
94
+ title: string;
95
+ lead: string;
96
+ plansLabel: string;
97
+ orderTitle: string;
98
+ orderLead: string;
99
+ changePlan: string;
100
+ invoiceLead: string;
101
+ fields: {
102
+ name: string;
103
+ taxId: string;
104
+ address: string;
105
+ };
106
+ requestInvoice: string;
107
+ checkout: string;
108
+ pending: string;
109
+ requested: string;
110
+ checkoutSuccess: string;
111
+ checkoutCancelled: string;
112
+ lifetime: string;
113
+ };
114
+ admin: {
115
+ title: string;
116
+ lead: string;
117
+ email: string;
118
+ plan: string;
119
+ submit: string;
120
+ pending: string;
121
+ granted: string;
122
+ grantedUntil: string;
123
+ noPlans: string;
124
+ requests: {
125
+ title: string;
126
+ lead: string;
127
+ empty: string;
128
+ line: string;
129
+ requestedOn: string;
130
+ price: string;
131
+ invoice: string;
132
+ taxId: string;
133
+ noInvoice: string;
134
+ grant: string;
135
+ granting: string;
136
+ dismiss: string;
137
+ dismissing: string;
138
+ history: string;
139
+ grantLabel: string;
140
+ dismissLabel: string;
141
+ };
142
+ history: {
143
+ title: string;
144
+ lead: string;
145
+ email: string;
146
+ submit: string;
147
+ pending: string;
148
+ accountTitle: string;
149
+ empty: string;
150
+ manual: string;
151
+ fromRequest: string;
152
+ provider: string;
153
+ grantedOn: string;
154
+ grantedFor: string;
155
+ paidOn: string;
156
+ period: string;
157
+ lifetime: string;
158
+ noGrant: string;
159
+ active: string;
160
+ revokedOn: string;
161
+ paid: string;
162
+ refundedOn: string;
163
+ partlyRefunded: string;
164
+ revoke: string;
165
+ revoking: string;
166
+ revokeLabel: string;
167
+ };
168
+ };
169
+ errors: {
170
+ billing: {
171
+ read_only: string;
172
+ account_unknown: string;
173
+ end_not_in_future: string;
174
+ plan_unknown: string;
175
+ invoice_details_invalid: string;
176
+ invoice_field_required: string;
177
+ invoice_field_too_long: string;
178
+ invoice_field_control_characters: string;
179
+ payment_failed: string;
180
+ lifetime_active: string;
181
+ request_closed: string;
182
+ grant_revoked: string;
183
+ };
184
+ security: {
185
+ rate_limited: string;
186
+ };
187
+ auth: {
188
+ forbidden: string;
189
+ };
190
+ core: {
191
+ database_failed: string;
192
+ unexpected: string;
193
+ };
194
+ };
195
+ }, import("zod").ZodObject<{
196
+ trial: import("zod").ZodPrefault<import("zod").ZodObject<{
197
+ days: import("zod").ZodDefault<import("zod").ZodNumber>;
198
+ reminderDays: import("zod").ZodDefault<import("zod").ZodNumber>;
199
+ startsAt: import("zod").ZodOptional<import("zod").ZodString>;
200
+ }, import("zod/v4/core").$strict>>;
201
+ paid: import("zod").ZodPrefault<import("zod").ZodObject<{
202
+ reminderDays: import("zod").ZodDefault<import("zod").ZodNumber>;
203
+ }, import("zod/v4/core").$strict>>;
204
+ requests: import("zod").ZodPrefault<import("zod").ZodObject<{
205
+ expireAfterDays: import("zod").ZodDefault<import("zod").ZodNumber>;
206
+ }, import("zod/v4/core").$strict>>;
207
+ plans: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodObject<{
208
+ id: import("zod").ZodString;
209
+ name: import("zod").ZodRecord<import("zod").ZodEnum<{
210
+ en: "en";
211
+ pl: "pl";
212
+ }> & import("zod/v4/core").$partial, import("zod").ZodString>;
213
+ description: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodEnum<{
214
+ en: "en";
215
+ pl: "pl";
216
+ }> & import("zod/v4/core").$partial, import("zod").ZodString>>;
217
+ price: import("zod").ZodObject<{
218
+ amount: import("zod").ZodNumber;
219
+ currency: import("zod").ZodString;
220
+ }, import("zod/v4/core").$strict>;
221
+ period: import("zod").ZodUnion<readonly [import("zod").ZodPipe<import("zod").ZodEnum<{
222
+ year: "year";
223
+ month: "month";
224
+ day: "day";
225
+ lifetime: "lifetime";
226
+ week: "week";
227
+ }>, import("zod").ZodTransform<{
228
+ readonly unit: import("./contract.js").PeriodUnit;
229
+ readonly count: number;
230
+ } | {
231
+ readonly unit: "lifetime";
232
+ }, "year" | "month" | "day" | "lifetime" | "week">>, import("zod").ZodObject<{
233
+ unit: import("zod").ZodEnum<{
234
+ year: "year";
235
+ month: "month";
236
+ day: "day";
237
+ week: "week";
238
+ }>;
239
+ count: import("zod").ZodDefault<import("zod").ZodNumber>;
240
+ }, import("zod/v4/core").$strict>, import("zod").ZodObject<{
241
+ unit: import("zod").ZodLiteral<"lifetime">;
242
+ }, import("zod/v4/core").$strict>]>;
243
+ features: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodRecord<import("zod").ZodEnum<{
244
+ en: "en";
245
+ pl: "pl";
246
+ }> & import("zod/v4/core").$partial, import("zod").ZodString>>>;
247
+ isFeatured: import("zod").ZodDefault<import("zod").ZodBoolean>;
248
+ }, import("zod/v4/core").$strict>>>;
249
+ payment: import("zod").ZodOptional<import("zod").ZodCustom<import("./payment.js").PaymentProvider, import("./payment.js").PaymentProvider>>;
250
+ partialRefunds: import("zod").ZodDefault<import("zod").ZodEnum<{
251
+ pro_rata: "pro_rata";
252
+ keep_access: "keep_access";
253
+ }>>;
254
+ adminRole: import("zod").ZodDefault<import("zod").ZodString>;
255
+ }, import("zod/v4/core").$strict>>;
256
+ export { getDayNumber, getDaysLeft, getStartOfDay, getTrialEnd, parseDay } from "./calendar.js";
257
+ export { ENTITLEMENT_STATUSES, INITIAL_ADMIN_ACTION_STATE, INITIAL_GRANT_FORM_STATE, INITIAL_PAYMENT_FORM_STATE, PERIOD_UNITS, type AdminActionErrorCode, type AdminActionState, type AdminErrorCode, type BillingErrorCode, type BillingFormErrorCode, type Entitlement, type EntitlementEvent, type EntitlementRecord, type EntitlementStatus, type GrantFormErrorCode, type GrantFormState, type LocalizedText, type PaymentErrorCode, type PaymentFormErrorCode, type PaymentFormState, type PaymentGrant, type PeriodUnit, type Plan, type PlanPeriod, type PlanPrice, } from "./contract.js";
258
+ export { applyEntitlementEvent, hasWriteAccess, resolveEntitlement, type EntitlementPolicy } from "./entitlement.js";
259
+ export { CHECKOUT_PARAM, CHECKOUT_RESULTS, type CheckoutResult } from "./fields.js";
260
+ export { invoiceDetailsSchema, type InvoiceFieldErrorCode } from "./invoice.js";
261
+ export { manual, type ManualPaymentOptions } from "./manual.js";
262
+ export { billingMessages, getBillingErrorMessage, type BillingMessages } from "./messages/index.js";
263
+ export { DEFAULT_REQUEST_EXPIRY_DAYS, MAX_DAYS, MAX_FEATURES, MAX_PERIOD_COUNT, MAX_PLANS, MAX_PRICE_AMOUNT, PARTIAL_REFUND_POLICIES, type PartialRefundPolicy, type BillingOptions, type BillingOptionsInput, } from "./options.js";
264
+ export { isPaymentProvider, type InvoiceDetails, type PaymentAccount, type PaymentContext, type PaymentProvider, type PaymentRequest, type PaymentStart, } from "./payment.js";
265
+ export { findPlan, getLocalizedText, getPeriodEnd, getPlanGrant } from "./plans.js";
266
+ export { getPaymentGrant, getRefundEvent, getRestoredDays, getTakenBackDays, getUnusedDays, isFullShare, moveBackByDays, moveForwardByDays, type RefundShare, type RefundTiming, type RestoredDaysInput, } from "./refund.js";
267
+ export { ACCESS_REMINDER_KINDS, DEFAULT_CATCH_UP_DAYS, getAccessReminder, getAccessReminderScope, MAX_CATCH_UP_DAYS, type AccessReminder, type AccessReminderInput, type AccessReminderKind, } from "./reminder.js";
268
+ export { CURRENCY_MINOR_UNIT_DIGITS } from "./currency-digits.js";
269
+ export { formatPrice, getMinorUnitDigits, isSupportedCurrency } from "./price.js";
270
+ export { billingSchema, entitlements, manualGrants, paymentRequests, payments } from "./schema.js";
271
+ export { getCheckoutSessionParams, stripe, STRIPE_API_BASE, STRIPE_SECRET_KEY_ENV, STRIPE_TIMEOUT_MS, type StripeOptions } from "./stripe.js";
272
+ export { describeStripePriceProblem, fromStripeAmount, getStripeMinorUnitDigits, STRIPE_THREE_DECIMAL_CURRENCIES, STRIPE_ZERO_DECIMAL_CURRENCIES, toStripeAmount, } from "./stripe-currency.js";
273
+ export { parseStripeEvent, readStripeWebhook, signStripePayload, STRIPE_METADATA, STRIPE_SIGNATURE_HEADER, STRIPE_SIGNATURE_TOLERANCE_SECONDS, verifyStripeSignature, type FailedRefund, type PaidCheckout, type SignStripePayloadInput, type StripeWebhookError, type StripeWebhookEvent, type VerifyStripeSignatureInput, } from "./stripe-webhook.js";
274
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,SAAS,YAAY,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;CAE7B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCA6BlB,CAAC;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,wBAAwB,EACxB,0BAA0B,EAC1B,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EACL,2BAA2B,EAC3B,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACpF,OAAO,EACL,eAAe,EACf,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,wBAAwB,EAAE,MAAM,EAAE,eAAe,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9I,OAAO,EACL,0BAA0B,EAC1B,gBAAgB,EAChB,wBAAwB,EACxB,+BAA+B,EAC/B,8BAA8B,EAC9B,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,kCAAkC,EAClC,qBAAqB,EACrB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,73 @@
1
+ // Public API of @softure-ai/billing: the module factory for softure.config.ts, its rate limit bucket,
2
+ // the manual and Stripe payment adapters, Stripe's webhook signature, the pure entitlement state
3
+ // machine and plan periods, prices, types, messages and the tables. Reading and changing
4
+ // entitlements, granting plans, starting payments and recording provider payments is in
5
+ // `@softure-ai/billing/server`, the Next.js adapter (write guard, payment and admin pages, actions,
6
+ // the Stripe webhook route, current badge and notice) in `/next`, the components in `/ui`.
7
+ import { defineModule, resolveMigrationsDir } from "@softure-ai/core";
8
+ import { billingMessages } from "./messages/index.js";
9
+ import { billingOptionsSchema } from "./options.js";
10
+ import { checkBillingTables } from "./server/health.js";
11
+ import { billingPrivacyContributor } from "./server/privacy.js";
12
+ export const MODULE_ID = "billing";
13
+ /**
14
+ * The rate limit bucket payments consume, with its default to spread into `security({ buckets })`:
15
+ * `billing-payment` per account (a payment page sent again and again).
16
+ */
17
+ export const BILLING_RATE_LIMIT_BUCKETS = {
18
+ "billing-payment": { limit: 5, windowMinutes: 60 },
19
+ };
20
+ /**
21
+ * Enables entitlements, plans and payments in `softure.config.ts` (after `security` and `auth`):
22
+ * `billing({ trial: { days: 14 }, plans: [{ id: "monthly", name: { en: "Monthly" }, price: { amount: 2900, currency: "PLN" }, period: "month" }], payment: stripe() })`
23
+ * (or `manual({ onRequest })` for invoices).
24
+ */
25
+ export const billing = defineModule({
26
+ manifest: {
27
+ id: MODULE_ID,
28
+ version: "0.1.5",
29
+ dependsOn: { security: "^0.1.0", auth: "^0.1.0" },
30
+ dbSchema: "billing",
31
+ tables: ["entitlements", "payments", "payment_requests", "manual_grants"],
32
+ env: [
33
+ {
34
+ name: "STRIPE_SECRET_KEY",
35
+ required: false,
36
+ description: "Secret API key of the stripe() payment adapter (sk_test_... in the sandbox), read on every payment; not needed with stripe({ secretKey }) or another adapter.",
37
+ },
38
+ {
39
+ name: "STRIPE_WEBHOOK_SECRET",
40
+ required: false,
41
+ description: "Signing secret (whsec_...) of the Stripe webhook endpoint that points at stripeWebhookRoute; required when that route is mounted.",
42
+ },
43
+ ],
44
+ switches: [],
45
+ routes: { payment: "/payment", admin: "/admin/billing", webhook: "/api/billing/webhook" },
46
+ mount: [{ kind: "route-handler", path: "app/api/billing/webhook/route.ts", export: "stripeWebhookRoute" }],
47
+ privacy: { exports: true, deletes: true },
48
+ },
49
+ messages: billingMessages,
50
+ options: billingOptionsSchema,
51
+ migrations: { dir: resolveMigrationsDir(import.meta.url, "../migrations/") },
52
+ privacy: billingPrivacyContributor,
53
+ health: checkBillingTables,
54
+ });
55
+ export { getDayNumber, getDaysLeft, getStartOfDay, getTrialEnd, parseDay } from "./calendar.js";
56
+ export { ENTITLEMENT_STATUSES, INITIAL_ADMIN_ACTION_STATE, INITIAL_GRANT_FORM_STATE, INITIAL_PAYMENT_FORM_STATE, PERIOD_UNITS, } from "./contract.js";
57
+ export { applyEntitlementEvent, hasWriteAccess, resolveEntitlement } from "./entitlement.js";
58
+ export { CHECKOUT_PARAM, CHECKOUT_RESULTS } from "./fields.js";
59
+ export { invoiceDetailsSchema } from "./invoice.js";
60
+ export { manual } from "./manual.js";
61
+ export { billingMessages, getBillingErrorMessage } from "./messages/index.js";
62
+ export { DEFAULT_REQUEST_EXPIRY_DAYS, MAX_DAYS, MAX_FEATURES, MAX_PERIOD_COUNT, MAX_PLANS, MAX_PRICE_AMOUNT, PARTIAL_REFUND_POLICIES, } from "./options.js";
63
+ export { isPaymentProvider, } from "./payment.js";
64
+ export { findPlan, getLocalizedText, getPeriodEnd, getPlanGrant } from "./plans.js";
65
+ export { getPaymentGrant, getRefundEvent, getRestoredDays, getTakenBackDays, getUnusedDays, isFullShare, moveBackByDays, moveForwardByDays, } from "./refund.js";
66
+ export { ACCESS_REMINDER_KINDS, DEFAULT_CATCH_UP_DAYS, getAccessReminder, getAccessReminderScope, MAX_CATCH_UP_DAYS, } from "./reminder.js";
67
+ export { CURRENCY_MINOR_UNIT_DIGITS } from "./currency-digits.js";
68
+ export { formatPrice, getMinorUnitDigits, isSupportedCurrency } from "./price.js";
69
+ export { billingSchema, entitlements, manualGrants, paymentRequests, payments } from "./schema.js";
70
+ export { getCheckoutSessionParams, stripe, STRIPE_API_BASE, STRIPE_SECRET_KEY_ENV, STRIPE_TIMEOUT_MS } from "./stripe.js";
71
+ export { describeStripePriceProblem, fromStripeAmount, getStripeMinorUnitDigits, STRIPE_THREE_DECIMAL_CURRENCIES, STRIPE_ZERO_DECIMAL_CURRENCIES, toStripeAmount, } from "./stripe-currency.js";
72
+ export { parseStripeEvent, readStripeWebhook, signStripePayload, STRIPE_METADATA, STRIPE_SIGNATURE_HEADER, STRIPE_SIGNATURE_TOLERANCE_SECONDS, verifyStripeSignature, } from "./stripe-webhook.js";
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { type Err, type Ok } from "@softure-ai/core";
2
+ import { z } from "zod";
3
+ import { type InvoiceField } from "./fields.js";
4
+ import type { InvoiceDetails } from "./payment.js";
5
+ /** Invoice details as the form sent them, untrimmed. */
6
+ export interface InvoiceInput {
7
+ readonly name: string;
8
+ readonly taxId: string;
9
+ readonly address: string;
10
+ }
11
+ /** Why one invoice field was refused. */
12
+ export type InvoiceFieldErrorCode =
13
+ /** The name or the address is empty. */
14
+ "billing.invoice_field_required"
15
+ /** Longer than `INVOICE_LIMITS` allows the field. */
16
+ | "billing.invoice_field_too_long"
17
+ /** A line break, a tab or another control character. */
18
+ | "billing.invoice_field_control_characters";
19
+ export type InvoiceDetailsError = Err<"billing.invoice_details_invalid"> & {
20
+ readonly fieldErrors: Readonly<Partial<Record<InvoiceField, InvoiceFieldErrorCode>>>;
21
+ };
22
+ export declare const invoiceDetailsSchema: z.ZodObject<{
23
+ name: z.ZodString;
24
+ taxId: z.ZodPipe<z.ZodString, z.ZodTransform<string | null, string>>;
25
+ address: z.ZodString;
26
+ }, z.core.$strict>;
27
+ /** Trimmed invoice details, or the first problem of each field that has one. */
28
+ export declare function parseInvoiceDetails(input: InvoiceInput): Ok<InvoiceDetails> | InvoiceDetailsError;
29
+ //# sourceMappingURL=invoice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoice.d.ts","sourceRoot":"","sources":["../src/invoice.ts"],"names":[],"mappings":"AAIA,OAAO,EAAW,KAAK,GAAG,EAAE,KAAK,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,yCAAyC;AACzC,MAAM,MAAM,qBAAqB;AAC/B,wCAAwC;AACtC,gCAAgC;AAClC,qDAAqD;GACnD,gCAAgC;AAClC,wDAAwD;GACtD,0CAA0C,CAAC;AAE/C,MAAM,MAAM,mBAAmB,GAAG,GAAG,CAAC,iCAAiC,CAAC,GAAG;IACzE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;CACtF,CAAC;AAaF,eAAO,MAAM,oBAAoB;;;;kBAI/B,CAAC;AAEH,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,mBAAmB,CAUjG"}
@@ -0,0 +1,35 @@
1
+ // Invoice details as the payment form sends them, parsed at the boundary by a zod schema: each
2
+ // field trimmed, the name and the address required, each within its limit, and no control
3
+ // characters (Unicode Cc: line breaks, tabs, escapes) anywhere, so a name cannot add lines to the
4
+ // owner's mail. Every field problem has its own code, so the form says what to fix.
5
+ import { err, ok } from "@softure-ai/core";
6
+ import { z } from "zod";
7
+ import { INVOICE_FIELDS, INVOICE_LIMITS } from "./fields.js";
8
+ const CONTROL_CHARACTER = /\p{Cc}/u;
9
+ function createFieldSchema(limit, isRequired) {
10
+ return z
11
+ .string()
12
+ .trim()
13
+ .refine((value) => !CONTROL_CHARACTER.test(value), { message: "billing.invoice_field_control_characters", abort: true })
14
+ .refine((value) => !isRequired || value !== "", { message: "billing.invoice_field_required", abort: true })
15
+ .refine((value) => value.length <= limit, { message: "billing.invoice_field_too_long", abort: true });
16
+ }
17
+ export const invoiceDetailsSchema = z.strictObject({
18
+ name: createFieldSchema(INVOICE_LIMITS.name, true),
19
+ taxId: createFieldSchema(INVOICE_LIMITS.taxId, false).transform((taxId) => (taxId === "" ? null : taxId)),
20
+ address: createFieldSchema(INVOICE_LIMITS.address, true),
21
+ });
22
+ /** Trimmed invoice details, or the first problem of each field that has one. */
23
+ export function parseInvoiceDetails(input) {
24
+ const parsed = invoiceDetailsSchema.safeParse({ name: input.name, taxId: input.taxId, address: input.address });
25
+ if (parsed.success)
26
+ return ok(parsed.data);
27
+ const fieldErrors = {};
28
+ for (const issue of parsed.error.issues) {
29
+ const key = issue.path[0];
30
+ // Each refinement's message is one of the codes above; the first problem of a field wins.
31
+ fieldErrors[INVOICE_FIELDS[key]] ??= issue.message;
32
+ }
33
+ return { ...err("billing.invoice_details_invalid"), fieldErrors };
34
+ }
35
+ //# sourceMappingURL=invoice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoice.js","sourceRoot":"","sources":["../src/invoice.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,0FAA0F;AAC1F,kGAAkG;AAClG,oFAAoF;AACpF,OAAO,EAAE,GAAG,EAAE,EAAE,EAAqB,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAqB,MAAM,aAAa,CAAC;AAuBhF,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAEpC,SAAS,iBAAiB,CAAC,KAAa,EAAE,UAAmB;IAC3D,OAAO,CAAC;SACL,MAAM,EAAE;SACR,IAAI,EAAE;SACN,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,0CAA0C,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;SACvH,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,UAAU,IAAI,KAAK,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,gCAAgC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;SAC1G,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,EAAE,EAAE,OAAO,EAAE,gCAAgC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1G,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,YAAY,CAAC;IACjD,IAAI,EAAE,iBAAiB,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC;IAClD,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACzG,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC;CACzD,CAAC,CAAC;AAEH,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CAAC,KAAmB;IACrD,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAChH,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,WAAW,GAAyD,EAAE,CAAC;IAC7E,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAgC,CAAC;QACzD,0FAA0F;QAC1F,WAAW,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,OAAgC,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,GAAG,GAAG,CAAC,iCAAiC,CAAC,EAAE,WAAW,EAAE,CAAC;AACpE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { DEFAULT_REMINDER_PAUSE_MS, renderAccessReminderMail, sendAccessReminders, type AccessReminderMail, type AccessReminderMailInput, type AccessReminderSummary, type SendAccessRemindersOptions, } from "./reminder-mail.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mailing/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,GAChC,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,4 @@
1
+ // The mailing adapter of @softure-ai/billing: reminder mail before and after access ends, through
2
+ // `@softure-ai/mailing` (an optional peer dependency; only apps that import this entry need it).
3
+ export { DEFAULT_REMINDER_PAUSE_MS, renderAccessReminderMail, sendAccessReminders, } from "./reminder-mail.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mailing/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,iGAAiG;AACjG,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,mBAAmB,GAKpB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { type ModuleContext } from "@softure-ai/core";
2
+ import type { Queryable } from "@softure-ai/db";
3
+ import type { OutgoingMail } from "@softure-ai/mailing";
4
+ import type { BillingMessages } from "../messages/index.js";
5
+ import { type AccessReminderKind } from "../reminder.js";
6
+ import { type FindAccessRemindersOptions } from "../server/reminders.js";
7
+ /** Pause between two mails a provider was called for: Resend allows two requests per second. */
8
+ export declare const DEFAULT_REMINDER_PAUSE_MS = 500;
9
+ export interface AccessReminderMailInput {
10
+ readonly kind: AccessReminderKind;
11
+ /** The last day with access, as the app's locale writes it (`formatLastDay`). */
12
+ readonly lastDay: string;
13
+ /** The payment page's absolute URL. */
14
+ readonly link: string;
15
+ }
16
+ /** The subject and bodies of a reminder mail, without the recipient. */
17
+ export type AccessReminderMail = Pick<OutgoingMail, "subject" | "text"> & {
18
+ readonly html: string;
19
+ };
20
+ export interface SendAccessRemindersOptions extends FindAccessRemindersOptions {
21
+ /** Milliseconds to wait after each mail a provider was called for. Default 500; 0 never waits. */
22
+ readonly pauseMs?: number;
23
+ /** How to wait; tests pass their own. */
24
+ readonly sleep?: (ms: number) => Promise<void>;
25
+ }
26
+ export interface AccessReminderSummary {
27
+ /** Accounts due a reminder this run. */
28
+ readonly due: number;
29
+ /** Mails sent now. */
30
+ readonly sent: number;
31
+ /** Mails an earlier run sent (or refused), or another run is sending right now. */
32
+ readonly skipped: number;
33
+ /** Mails refused for good (an invalid address, the provider rejected it). */
34
+ readonly rejected: number;
35
+ /** Mails the provider could not take now; the next run sends them. */
36
+ readonly retryLater: number;
37
+ }
38
+ /**
39
+ * Renders a reminder from `messages` (one locale's dictionary, overrides applied): a plain-text body
40
+ * with the notice's link text and the bare link, and an HTML body with the link as an anchor.
41
+ */
42
+ export declare function renderAccessReminderMail(messages: BillingMessages, input: AccessReminderMailInput): AccessReminderMail;
43
+ /**
44
+ * Mails every account due a reminder (`findAccessReminders`) through mailing's delivery ledger, so
45
+ * each account gets one mail per kind and end however often the run repeats or overlaps. Call it
46
+ * on a schedule (a daily cron job running a script). Needs `mailing({ ... })` in the config; a
47
+ * database failure propagates (the next run resumes, and the ledger keeps it from mailing twice).
48
+ */
49
+ export declare function sendAccessReminders(ctx: ModuleContext<Queryable>, options?: SendAccessRemindersOptions): Promise<AccessReminderSummary>;
50
+ //# sourceMappingURL=reminder-mail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reminder-mail.d.ts","sourceRoot":"","sources":["../../src/mailing/reminder-mail.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAA0B,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEjF,OAAO,EAAuB,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAG9F,gGAAgG;AAChG,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wEAAwE;AACxE,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,MAAM,CAAC,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpG,MAAM,WAAW,0BAA2B,SAAQ,0BAA0B;IAC5E,kGAAkG;IAClG,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAeD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,uBAAuB,GAAG,kBAAkB,CAStH;AAMD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAqBjJ"}
@@ -0,0 +1,71 @@
1
+ // The reminder mail: the in-app notice's four states as a mail, sent once per account, kind and
2
+ // end through `@softure-ai/mailing`'s delivery ledger. A transactional mail (an account notice): no
3
+ // unsubscribe link, never suppressed. The copy comes from billing's dictionary in the app's locale;
4
+ // the link to the payment page is placed by the code, so a copy override cannot drop it.
5
+ import { formatMessage } from "@softure-ai/core";
6
+ import { deliverOnce } from "@softure-ai/mailing/server";
7
+ import { getAccessReminderScope } from "../reminder.js";
8
+ import { getBillingMessages, getBillingRoutes } from "../server/options.js";
9
+ import { findAccessReminders } from "../server/reminders.js";
10
+ import { formatLastDay } from "../ui/format.js";
11
+ /** Pause between two mails a provider was called for: Resend allows two requests per second. */
12
+ export const DEFAULT_REMINDER_PAUSE_MS = 500;
13
+ const COPY_KEYS = {
14
+ "trial-ending": "trialEnding",
15
+ "paid-ending": "paidEnding",
16
+ "trial-ended": "trialEnded",
17
+ "paid-ended": "paidEnded",
18
+ };
19
+ const HTML_ESCAPES = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
20
+ function escapeHtml(value) {
21
+ return value.replace(/[&<>"']/g, (character) => HTML_ESCAPES[character] ?? character);
22
+ }
23
+ /**
24
+ * Renders a reminder from `messages` (one locale's dictionary, overrides applied): a plain-text body
25
+ * with the notice's link text and the bare link, and an HTML body with the link as an anchor.
26
+ */
27
+ export function renderAccessReminderMail(messages, input) {
28
+ const copy = messages.reminderMail[COPY_KEYS[input.kind]];
29
+ const action = input.kind.startsWith("trial-") ? messages.notice.choosePlan : messages.notice.renew;
30
+ const values = { date: input.lastDay };
31
+ const subject = formatMessage(copy.subject, values);
32
+ const body = formatMessage(copy.body, values);
33
+ const text = [body, `${action}: ${input.link}`].join("\n\n");
34
+ const html = [`<p>${escapeHtml(body)}</p>`, `<p><a href="${escapeHtml(input.link)}">${escapeHtml(action)}</a></p>`].join("\n");
35
+ return { subject, text, html };
36
+ }
37
+ function wait(ms) {
38
+ return new Promise((resolve) => setTimeout(resolve, ms));
39
+ }
40
+ /**
41
+ * Mails every account due a reminder (`findAccessReminders`) through mailing's delivery ledger, so
42
+ * each account gets one mail per kind and end however often the run repeats or overlaps. Call it
43
+ * on a schedule (a daily cron job running a script). Needs `mailing({ ... })` in the config; a
44
+ * database failure propagates (the next run resumes, and the ledger keeps it from mailing twice).
45
+ */
46
+ export async function sendAccessReminders(ctx, options = {}) {
47
+ const { pauseMs = DEFAULT_REMINDER_PAUSE_MS, sleep = wait, ...findOptions } = options;
48
+ const due = await findAccessReminders(ctx, findOptions);
49
+ const messages = getBillingMessages(ctx.config);
50
+ const link = new URL(getBillingRoutes(ctx.config).payment, ctx.config.appOrigin).href;
51
+ const counts = { sent: 0, skipped: 0, rejected: 0, retryLater: 0 };
52
+ for (const reminder of due) {
53
+ const lastDay = formatLastDay(reminder.endsAt, ctx.config.locale, ctx.config.timezone);
54
+ const mail = renderAccessReminderMail(messages, { kind: reminder.kind, lastDay, link });
55
+ const outcome = await deliverOnce(ctx, { scope: getAccessReminderScope(reminder.kind, reminder.userId, reminder.endsAt), mail: { to: reminder.email, ...mail } });
56
+ if (outcome.status === "done" || outcome.status === "in-flight") {
57
+ counts.skipped += 1;
58
+ continue;
59
+ }
60
+ if (outcome.status === "sent")
61
+ counts.sent += 1;
62
+ else if (outcome.status === "rejected")
63
+ counts.rejected += 1;
64
+ else
65
+ counts.retryLater += 1;
66
+ if (pauseMs > 0)
67
+ await sleep(pauseMs);
68
+ }
69
+ return { due: due.length, ...counts };
70
+ }
71
+ //# sourceMappingURL=reminder-mail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reminder-mail.js","sourceRoot":"","sources":["../../src/mailing/reminder-mail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type Err, type ErrorCode, type Ok } from "@softure-ai/core";
2
+ import type { PaymentContext, PaymentProvider, PaymentRequest } from "./payment.js";
3
+ export interface ManualPaymentOptions {
4
+ /**
5
+ * Hands a request to the owner. An `Err` tells the buyer the request did not go through
6
+ * (`billing.payment_failed`, its code is logged); a throw is reported as an unexpected failure.
7
+ */
8
+ readonly onRequest: (request: PaymentRequest, ctx: PaymentContext) => Promise<Ok<undefined> | Err<ErrorCode>>;
9
+ }
10
+ /** `billing({ payment: manual({ onRequest }) })`: invoices requested by the buyer, access granted by an admin. */
11
+ export declare function manual(options: ManualPaymentOptions): PaymentProvider;
12
+ //# sourceMappingURL=manual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.d.ts","sourceRoot":"","sources":["../src/manual.ts"],"names":[],"mappings":"AAIA,OAAO,EAAW,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,KAAK,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEpF,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;CAC/G;AAED,kHAAkH;AAClH,wBAAgB,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,eAAe,CAcrE"}
package/dist/manual.js ADDED
@@ -0,0 +1,22 @@
1
+ // The manual payment adapter: the buyer asks for an invoice on the payment page, the app hands the
2
+ // request to its owner (`onRequest`: a mail, a ticket), and the owner grants the plan in the admin
3
+ // page once the invoice is paid. Nothing is charged here; `startPayment` stores the request before
4
+ // it is handed over, so the admin page lists it, and hands an open request over once.
5
+ import { err, ok } from "@softure-ai/core";
6
+ /** `billing({ payment: manual({ onRequest }) })`: invoices requested by the buyer, access granted by an admin. */
7
+ export function manual(options) {
8
+ return {
9
+ name: "manual",
10
+ collectsInvoiceDetails: true,
11
+ handsOverRequests: true,
12
+ async startPayment(ctx, request) {
13
+ const handed = await options.onRequest(request, ctx);
14
+ if (!handed.ok) {
15
+ console.error(`@softure-ai/billing: the manual payment request for plan "${request.plan.id}" was not handed over: ${handed.error}`);
16
+ return err("billing.payment_failed");
17
+ }
18
+ return ok({ type: "requested" });
19
+ },
20
+ };
21
+ }
22
+ //# sourceMappingURL=manual.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.js","sourceRoot":"","sources":["../src/manual.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,mGAAmG;AACnG,mGAAmG;AACnG,sFAAsF;AACtF,OAAO,EAAE,GAAG,EAAE,EAAE,EAAqC,MAAM,kBAAkB,CAAC;AAW9E,kHAAkH;AAClH,MAAM,UAAU,MAAM,CAAC,OAA6B;IAClD,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,sBAAsB,EAAE,IAAI;QAC5B,iBAAiB,EAAE,IAAI;QACvB,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO;YAC7B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,6DAA6D,OAAO,CAAC,IAAI,CAAC,EAAE,0BAA0B,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;gBACpI,OAAO,GAAG,CAAC,wBAAwB,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACnC,CAAC;KACF,CAAC;AACJ,CAAC"}