@cosmicdrift/kumiko-bundled-features 0.392.2 → 0.394.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/dist/account-security/feature.d.ts +2 -0
  2. package/dist/account-security/feature.js +3 -1
  3. package/dist/audit/event-classification.js +1 -0
  4. package/dist/auth-email-password/handlers/change-password.write.d.ts +1 -1
  5. package/dist/auth-email-password/handlers/confirm-account-unlock.write.d.ts +1 -1
  6. package/dist/auth-email-password/handlers/invite-accept-with-login.write.d.ts +1 -1
  7. package/dist/auth-email-password/handlers/invite-accept.write.d.ts +1 -1
  8. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  9. package/dist/auth-email-password/handlers/invite-signup-complete.write.d.ts +1 -1
  10. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  11. package/dist/auth-email-password/handlers/logout.write.d.ts +1 -1
  12. package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -1
  13. package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -1
  14. package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -1
  15. package/dist/auth-email-password/handlers/reset-password.write.d.ts +1 -1
  16. package/dist/auth-email-password/handlers/signup-confirm.write.d.ts +1 -1
  17. package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -1
  18. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  19. package/dist/auth-email-password/handlers/token-request-handler.d.ts +1 -1
  20. package/dist/auth-email-password/handlers/verify-email.write.d.ts +1 -1
  21. package/dist/auth-email-password/web/auth-client.d.ts +3 -7
  22. package/dist/auth-email-password/web/auth-client.js +3 -24
  23. package/dist/auth-email-password/web/auth-gate.d.ts +2 -4
  24. package/dist/auth-email-password/web/auth-redirect.d.ts +2 -2
  25. package/dist/auth-email-password/web/auth-redirect.js +3 -12
  26. package/dist/auth-email-password/web/index.d.ts +2 -1
  27. package/dist/auth-email-password/web/index.js +1 -0
  28. package/dist/auth-email-password/web/login-failure.d.ts +9 -0
  29. package/dist/auth-email-password/web/login-failure.js +32 -0
  30. package/dist/auth-email-password/web/login-url.d.ts +5 -0
  31. package/dist/auth-email-password/web/login-url.js +13 -0
  32. package/dist/auth-email-password/web/static-login.d.ts +42 -0
  33. package/dist/auth-email-password/web/static-login.js +122 -0
  34. package/dist/auth-mfa/handlers/disable.write.d.ts +1 -1
  35. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.d.ts +1 -1
  36. package/dist/auth-mfa/handlers/enable-confirm.write.d.ts +1 -1
  37. package/dist/auth-mfa/handlers/enable-start-preauth.write.d.ts +1 -1
  38. package/dist/auth-mfa/handlers/enable-start.write.d.ts +1 -1
  39. package/dist/auth-mfa/handlers/regenerate-recovery.write.d.ts +1 -1
  40. package/dist/auth-mfa/handlers/verify.write.d.ts +1 -1
  41. package/dist/auth-mfa/web/mfa-client.js +4 -43
  42. package/dist/billing-foundation/checkout-core.d.ts +2 -1
  43. package/dist/billing-foundation/checkout-core.js +2 -11
  44. package/dist/billing-foundation/events.d.ts +1 -0
  45. package/dist/billing-foundation/events.js +2 -0
  46. package/dist/billing-foundation/feature.js +1 -1
  47. package/dist/billing-foundation/handlers/create-checkout-session.write.js +9 -2
  48. package/dist/billing-foundation/handlers/process-payment-event.write.d.ts +1 -0
  49. package/dist/billing-foundation/handlers/process-payment-event.write.js +2 -0
  50. package/dist/billing-foundation/index.d.ts +1 -1
  51. package/dist/billing-foundation/one-off-checkout-gate.d.ts +9 -0
  52. package/dist/billing-foundation/one-off-checkout-gate.js +30 -0
  53. package/dist/billing-foundation/one-off-customer.d.ts +6 -0
  54. package/dist/billing-foundation/one-off-customer.js +12 -0
  55. package/dist/billing-foundation/plan-catalog.js +1 -0
  56. package/dist/billing-foundation/types.d.ts +25 -0
  57. package/dist/billing-foundation/web/billing-plans-panel.js +1 -0
  58. package/dist/billing-foundation/web/plan-switch-confirm-dialog.js +7 -3
  59. package/dist/billing-foundation/web/plan-switch-recurring.d.ts +16 -0
  60. package/dist/billing-foundation/web/plan-switch-recurring.js +10 -0
  61. package/dist/billing-foundation/webhook-handler.js +1 -0
  62. package/dist/cap-overview/handlers/caps-usage.query.js +3 -3
  63. package/dist/cap-overview/types.d.ts +2 -0
  64. package/dist/channel-in-app/handlers/mark-all-read.write.d.ts +1 -1
  65. package/dist/channel-in-app/handlers/mark-read.write.d.ts +1 -1
  66. package/dist/compliance-profiles/handlers/set-profile.write.d.ts +1 -1
  67. package/dist/compliance-profiles/web/compliance-profile-catalog.js +8 -1
  68. package/dist/config/handlers/reset.write.d.ts +1 -1
  69. package/dist/config/handlers/set.write.d.ts +1 -1
  70. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +1 -1
  71. package/dist/delivery/handlers/resubscribe-address.write.d.ts +1 -1
  72. package/dist/delivery/handlers/resubscribe-user.write.d.ts +1 -1
  73. package/dist/delivery/handlers/set-preference.write.d.ts +1 -1
  74. package/dist/delivery/handlers/unsubscribe-address.write.d.ts +1 -1
  75. package/dist/delivery/handlers/unsubscribe-user.write.d.ts +1 -1
  76. package/dist/feature-toggles/handlers/set.write.d.ts +1 -1
  77. package/dist/file-foundation/read-file-ref-content.d.ts +2 -0
  78. package/dist/file-foundation/read-file-ref-content.js +9 -3
  79. package/dist/form-draft/handlers/discard.write.d.ts +1 -1
  80. package/dist/form-draft/handlers/save.write.d.ts +1 -1
  81. package/dist/inbound-mail-foundation/account-health.d.ts +17 -0
  82. package/dist/inbound-mail-foundation/account-health.js +101 -0
  83. package/dist/inbound-mail-foundation/account-poll-schedule.d.ts +19 -0
  84. package/dist/inbound-mail-foundation/account-poll-schedule.js +44 -0
  85. package/dist/inbound-mail-foundation/account-poll.d.ts +24 -0
  86. package/dist/inbound-mail-foundation/account-poll.js +157 -0
  87. package/dist/inbound-mail-foundation/account-record.d.ts +1 -0
  88. package/dist/inbound-mail-foundation/account-record.js +1 -0
  89. package/dist/inbound-mail-foundation/account-wake.d.ts +3 -0
  90. package/dist/inbound-mail-foundation/account-wake.js +17 -0
  91. package/dist/inbound-mail-foundation/connect-callback-verify.d.ts +10 -0
  92. package/dist/inbound-mail-foundation/connect-callback-verify.js +31 -0
  93. package/dist/inbound-mail-foundation/connect-route-responses.d.ts +13 -0
  94. package/dist/inbound-mail-foundation/connect-route-responses.js +16 -0
  95. package/dist/inbound-mail-foundation/connect-routes.js +52 -33
  96. package/dist/inbound-mail-foundation/constants.d.ts +50 -2
  97. package/dist/inbound-mail-foundation/constants.js +53 -3
  98. package/dist/inbound-mail-foundation/content-refetch.d.ts +14 -0
  99. package/dist/inbound-mail-foundation/content-refetch.js +93 -0
  100. package/dist/inbound-mail-foundation/describe-error.d.ts +1 -0
  101. package/dist/inbound-mail-foundation/describe-error.js +5 -0
  102. package/dist/inbound-mail-foundation/entities.d.ts +26 -0
  103. package/dist/inbound-mail-foundation/entities.js +43 -3
  104. package/dist/inbound-mail-foundation/events.d.ts +97 -0
  105. package/dist/inbound-mail-foundation/events.js +57 -2
  106. package/dist/inbound-mail-foundation/feature.d.ts +5 -2
  107. package/dist/inbound-mail-foundation/feature.js +122 -106
  108. package/dist/inbound-mail-foundation/file-storage-failure.d.ts +8 -0
  109. package/dist/inbound-mail-foundation/file-storage-failure.js +19 -0
  110. package/dist/inbound-mail-foundation/handlers/account-address.d.ts +16 -0
  111. package/dist/inbound-mail-foundation/handlers/account-address.js +51 -0
  112. package/dist/inbound-mail-foundation/handlers/acknowledge-quarantine.write.d.ts +8 -0
  113. package/dist/inbound-mail-foundation/handlers/acknowledge-quarantine.write.js +39 -0
  114. package/dist/inbound-mail-foundation/handlers/attach-message-content.write.d.ts +60 -0
  115. package/dist/inbound-mail-foundation/handlers/attach-message-content.write.js +128 -0
  116. package/dist/inbound-mail-foundation/handlers/connect-account.write.d.ts +3 -2
  117. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +97 -56
  118. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.d.ts +2 -1
  119. package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +55 -42
  120. package/dist/inbound-mail-foundation/handlers/ingest-message-prepare.d.ts +26 -0
  121. package/dist/inbound-mail-foundation/handlers/ingest-message-prepare.js +131 -0
  122. package/dist/inbound-mail-foundation/handlers/ingest-message-schema.d.ts +64 -0
  123. package/dist/inbound-mail-foundation/handlers/ingest-message-schema.js +39 -0
  124. package/dist/inbound-mail-foundation/handlers/ingest-message.write.d.ts +74 -21
  125. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +57 -134
  126. package/dist/inbound-mail-foundation/handlers/list-accounts.query.d.ts +2 -1
  127. package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +60 -26
  128. package/dist/inbound-mail-foundation/handlers/list-messages.query.d.ts +2 -1
  129. package/dist/inbound-mail-foundation/handlers/list-messages.query.js +43 -29
  130. package/dist/inbound-mail-foundation/handlers/list-quarantine.query.d.ts +3 -0
  131. package/dist/inbound-mail-foundation/handlers/list-quarantine.query.js +75 -0
  132. package/dist/inbound-mail-foundation/handlers/mark-credential-stored.write.d.ts +7 -0
  133. package/dist/inbound-mail-foundation/handlers/mark-credential-stored.write.js +38 -0
  134. package/dist/inbound-mail-foundation/handlers/message-content.d.ts +70 -0
  135. package/dist/inbound-mail-foundation/handlers/message-content.js +137 -0
  136. package/dist/inbound-mail-foundation/handlers/message-content.query.d.ts +19 -0
  137. package/dist/inbound-mail-foundation/handlers/message-content.query.js +59 -0
  138. package/dist/inbound-mail-foundation/handlers/message-detail.query.d.ts +3 -0
  139. package/dist/inbound-mail-foundation/handlers/message-detail.query.js +23 -0
  140. package/dist/inbound-mail-foundation/handlers/reactivate-account.write.d.ts +8 -0
  141. package/dist/inbound-mail-foundation/handlers/reactivate-account.write.js +84 -0
  142. package/dist/inbound-mail-foundation/handlers/retry-quarantined-message.write.d.ts +8 -0
  143. package/dist/inbound-mail-foundation/handlers/retry-quarantined-message.write.js +34 -0
  144. package/dist/inbound-mail-foundation/handlers/scope-visibility.d.ts +10 -2
  145. package/dist/inbound-mail-foundation/handlers/scope-visibility.js +27 -8
  146. package/dist/inbound-mail-foundation/handlers/set-trusted-authserv-id.write.d.ts +13 -0
  147. package/dist/inbound-mail-foundation/handlers/set-trusted-authserv-id.write.js +54 -0
  148. package/dist/inbound-mail-foundation/handlers/thread-rollup.d.ts +24 -0
  149. package/dist/inbound-mail-foundation/handlers/thread-rollup.js +98 -0
  150. package/dist/inbound-mail-foundation/handlers/trusted-authserv-id.d.ts +3 -0
  151. package/dist/inbound-mail-foundation/handlers/trusted-authserv-id.js +3 -0
  152. package/dist/inbound-mail-foundation/handlers/update-account.write.d.ts +13 -3
  153. package/dist/inbound-mail-foundation/handlers/update-account.write.js +62 -46
  154. package/dist/inbound-mail-foundation/i18n.js +72 -2
  155. package/dist/inbound-mail-foundation/inbound-oauth-flow.d.ts +43 -0
  156. package/dist/inbound-mail-foundation/inbound-oauth-flow.js +1 -0
  157. package/dist/inbound-mail-foundation/index.d.ts +19 -6
  158. package/dist/inbound-mail-foundation/index.js +17 -6
  159. package/dist/inbound-mail-foundation/ingest-failures.d.ts +77 -0
  160. package/dist/inbound-mail-foundation/ingest-failures.js +79 -0
  161. package/dist/inbound-mail-foundation/ingest-payload.d.ts +7 -0
  162. package/dist/inbound-mail-foundation/ingest-payload.js +34 -0
  163. package/dist/inbound-mail-foundation/mail-roles.d.ts +21 -0
  164. package/dist/inbound-mail-foundation/mail-roles.js +83 -0
  165. package/dist/inbound-mail-foundation/normalize-inbound-message.d.ts +17 -0
  166. package/dist/inbound-mail-foundation/normalize-inbound-message.js +90 -0
  167. package/dist/inbound-mail-foundation/oauth-access-token.d.ts +3 -1
  168. package/dist/inbound-mail-foundation/oauth-access-token.js +13 -2
  169. package/dist/inbound-mail-foundation/outbound-attachment-access.d.ts +5 -0
  170. package/dist/inbound-mail-foundation/outbound-attachment-access.js +16 -0
  171. package/dist/inbound-mail-foundation/outbound-attachments.d.ts +18 -0
  172. package/dist/inbound-mail-foundation/outbound-attachments.js +77 -0
  173. package/dist/inbound-mail-foundation/outbound-mail.d.ts +15 -1
  174. package/dist/inbound-mail-foundation/outbound-mail.js +4 -0
  175. package/dist/inbound-mail-foundation/probe.js +1 -1
  176. package/dist/inbound-mail-foundation/projection.d.ts +28 -0
  177. package/dist/inbound-mail-foundation/projection.js +25 -3
  178. package/dist/inbound-mail-foundation/provider-errors.d.ts +28 -0
  179. package/dist/inbound-mail-foundation/provider-errors.js +66 -0
  180. package/dist/inbound-mail-foundation/quarantine-entities.d.ts +61 -0
  181. package/dist/inbound-mail-foundation/quarantine-entities.js +47 -0
  182. package/dist/inbound-mail-foundation/quarantine-header-import.d.ts +9 -0
  183. package/dist/inbound-mail-foundation/quarantine-header-import.js +53 -0
  184. package/dist/inbound-mail-foundation/quarantine-retry.d.ts +13 -0
  185. package/dist/inbound-mail-foundation/quarantine-retry.js +97 -0
  186. package/dist/inbound-mail-foundation/quarantine-screens.d.ts +4 -0
  187. package/dist/inbound-mail-foundation/quarantine-screens.js +57 -0
  188. package/dist/inbound-mail-foundation/quarantine.d.ts +13 -0
  189. package/dist/inbound-mail-foundation/quarantine.js +46 -0
  190. package/dist/inbound-mail-foundation/retention-job.d.ts +2 -0
  191. package/dist/inbound-mail-foundation/retention-job.js +62 -0
  192. package/dist/inbound-mail-foundation/retention-sweep.d.ts +4 -0
  193. package/dist/inbound-mail-foundation/retention-sweep.js +35 -8
  194. package/dist/inbound-mail-foundation/screens.d.ts +14 -2
  195. package/dist/inbound-mail-foundation/screens.js +217 -79
  196. package/dist/inbound-mail-foundation/send-from-account.d.ts +11 -1
  197. package/dist/inbound-mail-foundation/send-from-account.js +19 -2
  198. package/dist/inbound-mail-foundation/sender-auth.d.ts +63 -0
  199. package/dist/inbound-mail-foundation/sender-auth.js +198 -0
  200. package/dist/inbound-mail-foundation/supervisor-ingest.d.ts +43 -0
  201. package/dist/inbound-mail-foundation/supervisor-ingest.js +195 -0
  202. package/dist/inbound-mail-foundation/sync-account-now.d.ts +22 -0
  203. package/dist/inbound-mail-foundation/sync-account-now.js +29 -0
  204. package/dist/inbound-mail-foundation/sync-cursor-store.d.ts +9 -0
  205. package/dist/inbound-mail-foundation/sync-cursor-store.js +54 -0
  206. package/dist/inbound-mail-foundation/syncable-accounts.d.ts +16 -0
  207. package/dist/inbound-mail-foundation/syncable-accounts.js +79 -0
  208. package/dist/inbound-mail-foundation/tenant-destroy-hook.js +5 -1
  209. package/dist/inbound-mail-foundation/types.d.ts +61 -62
  210. package/dist/inbound-mail-foundation/types.js +0 -54
  211. package/dist/inbound-mail-foundation/wake-consumer.d.ts +2 -0
  212. package/dist/inbound-mail-foundation/wake-consumer.js +30 -0
  213. package/dist/inbound-mail-foundation/watch-catch-up.d.ts +19 -0
  214. package/dist/inbound-mail-foundation/watch-catch-up.js +33 -0
  215. package/dist/inbound-mail-foundation/watch-lease.d.ts +15 -0
  216. package/dist/inbound-mail-foundation/watch-lease.js +81 -0
  217. package/dist/inbound-mail-foundation/watch-supervisor-types.d.ts +83 -0
  218. package/dist/inbound-mail-foundation/watch-supervisor-types.js +1 -0
  219. package/dist/inbound-mail-foundation/watch-supervisor.d.ts +1 -53
  220. package/dist/inbound-mail-foundation/watch-supervisor.js +123 -290
  221. package/dist/inbound-mail-foundation/web/client-plugin.d.ts +14 -0
  222. package/dist/inbound-mail-foundation/web/client-plugin.js +40 -0
  223. package/dist/inbound-mail-foundation/web/constants.d.ts +5 -0
  224. package/dist/inbound-mail-foundation/web/constants.js +6 -0
  225. package/dist/inbound-mail-foundation/web/index.d.ts +1 -0
  226. package/dist/inbound-mail-foundation/web/index.js +1 -0
  227. package/dist/inbound-provider-imap/connect-mailbox.d.ts +28 -5
  228. package/dist/inbound-provider-imap/connect-mailbox.js +91 -41
  229. package/dist/inbound-provider-imap/connect-my-mailbox.d.ts +13 -0
  230. package/dist/inbound-provider-imap/connect-my-mailbox.js +25 -0
  231. package/dist/inbound-provider-imap/constants.d.ts +12 -1
  232. package/dist/inbound-provider-imap/constants.js +12 -1
  233. package/dist/inbound-provider-imap/credential-document.js +2 -2
  234. package/dist/inbound-provider-imap/download-batch.d.ts +6 -0
  235. package/dist/inbound-provider-imap/download-batch.js +24 -0
  236. package/dist/inbound-provider-imap/feature.d.ts +2 -2
  237. package/dist/inbound-provider-imap/feature.js +49 -32
  238. package/dist/inbound-provider-imap/fetch-content.d.ts +4 -0
  239. package/dist/inbound-provider-imap/fetch-content.js +68 -0
  240. package/dist/inbound-provider-imap/i18n.js +18 -2
  241. package/dist/inbound-provider-imap/imap-client.d.ts +27 -23
  242. package/dist/inbound-provider-imap/imap-client.js +30 -68
  243. package/dist/inbound-provider-imap/index.d.ts +2 -1
  244. package/dist/inbound-provider-imap/index.js +2 -1
  245. package/dist/inbound-provider-imap/mime-content.d.ts +11 -0
  246. package/dist/inbound-provider-imap/mime-content.js +66 -0
  247. package/dist/inbound-provider-imap/parse-message.d.ts +35 -0
  248. package/dist/inbound-provider-imap/parse-message.js +113 -0
  249. package/dist/inbound-provider-imap/reconnect-account.d.ts +17 -0
  250. package/dist/inbound-provider-imap/reconnect-account.js +18 -0
  251. package/dist/inbound-provider-imap/reconnect-mailbox.d.ts +14 -0
  252. package/dist/inbound-provider-imap/reconnect-mailbox.js +71 -0
  253. package/dist/inbound-provider-imap/reconnect-prefill.query.d.ts +3 -0
  254. package/dist/inbound-provider-imap/reconnect-prefill.query.js +34 -0
  255. package/dist/inbound-provider-imap/screens.d.ts +6 -1
  256. package/dist/inbound-provider-imap/screens.js +174 -41
  257. package/dist/inbound-provider-imap/send-mail.d.ts +2 -2
  258. package/dist/inbound-provider-imap/send-mail.js +8 -1
  259. package/dist/inbound-provider-imap/sender-auth-headers.d.ts +3 -0
  260. package/dist/inbound-provider-imap/sender-auth-headers.js +18 -0
  261. package/dist/inbound-provider-inmemory/feature.d.ts +15 -0
  262. package/dist/inbound-provider-inmemory/feature.js +57 -2
  263. package/dist/inbound-provider-inmemory/index.d.ts +1 -1
  264. package/dist/inbound-provider-inmemory/index.js +1 -1
  265. package/dist/jobs/handlers/consumer.write.d.ts +4 -4
  266. package/dist/jobs/handlers/retry.write.d.ts +1 -1
  267. package/dist/jobs/handlers/trigger.write.d.ts +1 -1
  268. package/dist/managed-pages/handlers/set.write.d.ts +1 -1
  269. package/dist/managed-pages/web/i18n.js +1 -0
  270. package/dist/personal-access-tokens/handlers/create.write.d.ts +1 -1
  271. package/dist/personal-access-tokens/handlers/revoke.write.d.ts +1 -1
  272. package/dist/readiness/handlers/run-probes.write.d.ts +1 -1
  273. package/dist/secrets/handlers/delete.write.d.ts +1 -1
  274. package/dist/secrets/handlers/set.write.d.ts +1 -1
  275. package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -1
  276. package/dist/sessions/handlers/revoke-all-others.write.d.ts +1 -1
  277. package/dist/sessions/handlers/revoke.write.d.ts +1 -1
  278. package/dist/subscription-paddle/checkout-config.query.d.ts +3 -0
  279. package/dist/subscription-paddle/checkout-config.query.js +14 -0
  280. package/dist/subscription-paddle/checkout-methods.d.ts +6 -0
  281. package/dist/subscription-paddle/checkout-methods.js +85 -0
  282. package/dist/subscription-paddle/checkout-page.d.ts +19 -0
  283. package/dist/subscription-paddle/checkout-page.js +126 -0
  284. package/dist/subscription-paddle/client.d.ts +24 -0
  285. package/dist/subscription-paddle/client.js +60 -0
  286. package/dist/subscription-paddle/constants.d.ts +16 -0
  287. package/dist/subscription-paddle/constants.js +25 -0
  288. package/dist/subscription-paddle/feature.d.ts +49 -0
  289. package/dist/subscription-paddle/feature.js +192 -0
  290. package/dist/subscription-paddle/index.d.ts +2 -0
  291. package/dist/subscription-paddle/index.js +4 -0
  292. package/dist/subscription-paddle/plan-switch-methods.d.ts +6 -0
  293. package/dist/subscription-paddle/plan-switch-methods.js +114 -0
  294. package/dist/subscription-paddle/price-methods.d.ts +15 -0
  295. package/dist/subscription-paddle/price-methods.js +105 -0
  296. package/dist/subscription-paddle/runtime.d.ts +42 -0
  297. package/dist/subscription-paddle/runtime.js +109 -0
  298. package/dist/subscription-paddle/subscription-state.d.ts +34 -0
  299. package/dist/subscription-paddle/subscription-state.js +48 -0
  300. package/dist/subscription-paddle/tenant-binding.d.ts +8 -0
  301. package/dist/subscription-paddle/tenant-binding.js +26 -0
  302. package/dist/subscription-paddle/verify-webhook.d.ts +4 -0
  303. package/dist/subscription-paddle/verify-webhook.js +55 -0
  304. package/dist/subscription-paddle/webhook-events.d.ts +9 -0
  305. package/dist/subscription-paddle/webhook-events.js +124 -0
  306. package/dist/template-resolver/handlers/collection-item.query.js +2 -2
  307. package/dist/template-resolver/handlers/collection-list.query.js +4 -2
  308. package/dist/template-resolver/handlers/collection-set.write.d.ts +1 -1
  309. package/dist/template-resolver/handlers/collection-shared.d.ts +11 -0
  310. package/dist/template-resolver/handlers/collection-shared.js +16 -0
  311. package/dist/template-resolver/handlers/copy-locale.write.d.ts +1 -1
  312. package/dist/template-resolver/handlers/discard-draft.write.d.ts +2 -2
  313. package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +1 -1
  314. package/dist/template-resolver/handlers/import-bundle.write.d.ts +1 -1
  315. package/dist/template-resolver/handlers/patch-draft.write.d.ts +1 -1
  316. package/dist/template-resolver/handlers/reset-to-system.write.d.ts +1 -1
  317. package/dist/template-resolver/handlers/resource-link-pdf.write.d.ts +1 -1
  318. package/dist/template-resolver/handlers/resource-remove.write.d.ts +1 -1
  319. package/dist/template-resolver/handlers/resource-upload.write.d.ts +1 -1
  320. package/dist/template-resolver/handlers/send-test.write.d.ts +1 -1
  321. package/dist/template-resolver/handlers/set.write.d.ts +1 -1
  322. package/dist/template-resolver/handlers/toggle-status.write.d.ts +4 -4
  323. package/dist/template-resolver/handlers/upsert-system.write.d.ts +1 -1
  324. package/dist/template-resolver/handlers/upsert-tenant.write.d.ts +1 -1
  325. package/dist/template-resolver/web/client-plugin.d.ts +4 -0
  326. package/dist/template-resolver/web/client-plugin.js +134 -52
  327. package/dist/template-resolver/web/i18n.js +1 -1
  328. package/dist/tenant/handlers/add-member.write.d.ts +1 -1
  329. package/dist/tenant/handlers/cancel-invitation.write.d.ts +1 -1
  330. package/dist/tenant/handlers/create.write.d.ts +1 -1
  331. package/dist/tenant/handlers/remove-member.write.d.ts +1 -1
  332. package/dist/tenant/handlers/toggle-enabled.write.d.ts +2 -2
  333. package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
  334. package/dist/tenant/handlers/update.write.d.ts +1 -1
  335. package/dist/tenant-handover/handlers/claim.write.d.ts +1 -1
  336. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.d.ts +1 -1
  337. package/dist/tenant-lifecycle/handlers/request-destruction.write.d.ts +1 -1
  338. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +1 -1
  339. package/dist/user/handlers/create.write.d.ts +1 -1
  340. package/dist/user/handlers/update.write.d.ts +1 -1
  341. package/dist/user-data-rights/handlers/cancel-deletion.write.d.ts +1 -1
  342. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.d.ts +1 -1
  343. package/dist/user-data-rights/handlers/lift-restriction.write.d.ts +1 -1
  344. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +1 -1
  345. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +1 -1
  346. package/dist/user-data-rights/handlers/request-export.write.d.ts +1 -1
  347. package/dist/user-data-rights/handlers/restrict-account.write.d.ts +1 -1
  348. package/dist/user-data-rights/handlers/run-forget-cleanup.write.d.ts +1 -1
  349. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +2 -1
  350. package/dist/user-profile/handlers/change-email.write.d.ts +1 -1
  351. package/dist/waitlist/handlers/export-purge.write.d.ts +2 -2
  352. package/dist/waitlist/handlers/invite.write.d.ts +1 -1
  353. package/dist/waitlist/handlers/reject.write.d.ts +1 -1
  354. package/dist/waitlist/handlers/submit.write.d.ts +1 -1
  355. package/package.json +33 -17
  356. package/src/account-security/changes.json +6 -0
  357. package/src/auth-email-password/changes.json +6 -0
  358. package/src/billing-foundation/changes.json +30 -0
  359. package/src/cap-overview/changes.json +6 -0
  360. package/src/files/changes.json +18 -0
  361. package/src/inbound-mail-foundation/changes.json +155 -0
  362. package/src/inbound-provider-imap/changes.json +42 -0
  363. package/src/jobs/changes.json +18 -0
  364. package/src/subscription-paddle/changes.json +15 -0
  365. package/src/template-resolver/changes.json +12 -0
  366. package/dist/subscription-dodo/client.d.ts +0 -17
  367. package/dist/subscription-dodo/client.js +0 -31
  368. package/dist/subscription-dodo/constants.d.ts +0 -12
  369. package/dist/subscription-dodo/constants.js +0 -19
  370. package/dist/subscription-dodo/feature.d.ts +0 -37
  371. package/dist/subscription-dodo/feature.js +0 -144
  372. package/dist/subscription-dodo/index.d.ts +0 -2
  373. package/dist/subscription-dodo/index.js +0 -4
  374. package/dist/subscription-dodo/plugin-methods.d.ts +0 -23
  375. package/dist/subscription-dodo/plugin-methods.js +0 -260
  376. package/dist/subscription-dodo/runtime.d.ts +0 -27
  377. package/dist/subscription-dodo/runtime.js +0 -89
  378. package/dist/subscription-dodo/verify-webhook.d.ts +0 -37
  379. package/dist/subscription-dodo/verify-webhook.js +0 -189
  380. package/src/subscription-dodo/changes.json +0 -14
@@ -0,0 +1,85 @@
1
+ // Paddle plugin methods for checkout, portal, cancel and resume. Every response
2
+ // is validated with Zod; every non-2xx throws a PaddleHttpError.
3
+ import { SubscriptionCancelTimings } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
4
+ import * as z from "zod";
5
+ import { signTenantBinding } from "./tenant-binding.js";
6
+ export function paddleSubscriptionPath(providerSubscriptionId) {
7
+ return `/subscriptions/${encodeURIComponent(providerSubscriptionId)}`;
8
+ }
9
+ function relativeTarget(url) {
10
+ const parsed = new URL(url);
11
+ return `${parsed.pathname}${parsed.search}${parsed.hash}`;
12
+ }
13
+ const checkoutResponseSchema = z.object({
14
+ data: z.object({
15
+ id: z.string(),
16
+ checkout: z.object({ url: z.string().nullable() }).nullish(),
17
+ }),
18
+ });
19
+ export function createPaddleCheckoutSession(runtime) {
20
+ return async (ctx, options) => {
21
+ // No Paddle transaction may be created while billing is not live.
22
+ await runtime.assertBillingLive(ctx);
23
+ const bindingKey = await runtime.tenantBindingKey(ctx);
24
+ // No `checkout.url` in the body: Paddle rejects unapproved domains and otherwise
25
+ // answers with the dashboard's Default Payment Link plus `?_ptxn=`.
26
+ const { data } = checkoutResponseSchema.parse(await runtime.call(ctx, {
27
+ method: "POST",
28
+ path: "/transactions",
29
+ body: {
30
+ items: [{ price_id: options.priceId, quantity: 1 }],
31
+ ...(options.providerCustomerId && { customer_id: options.providerCustomerId }),
32
+ custom_data: {
33
+ tenantId: options.tenantId,
34
+ tenantBinding: signTenantBinding(bindingKey, options.tenantId),
35
+ ...(options.consentId && { consentId: options.consentId }),
36
+ },
37
+ },
38
+ }));
39
+ if (!data.checkout?.url) {
40
+ throw new Error("subscription-paddle: transaction was created without a checkout url");
41
+ }
42
+ const url = new URL(data.checkout.url);
43
+ url.searchParams.set("success", relativeTarget(options.successUrl));
44
+ url.searchParams.set("cancel", relativeTarget(options.cancelUrl));
45
+ if (options.locale)
46
+ url.searchParams.set("locale", options.locale);
47
+ return { url: url.href };
48
+ };
49
+ }
50
+ const portalResponseSchema = z.object({
51
+ data: z.object({ urls: z.object({ general: z.object({ overview: z.string() }) }) }),
52
+ });
53
+ // Paddle's portal has no return url, so options.returnUrl is not used.
54
+ export function createPaddlePortalSession(runtime) {
55
+ return async (ctx, options) => {
56
+ const response = portalResponseSchema.parse(await runtime.call(ctx, {
57
+ method: "POST",
58
+ path: `/customers/${encodeURIComponent(options.providerCustomerId)}/portal-sessions`,
59
+ body: {},
60
+ }));
61
+ return { url: response.data.urls.general.overview };
62
+ };
63
+ }
64
+ export function createPaddleCancelSubscription(runtime) {
65
+ return async (ctx, options) => {
66
+ await runtime.call(ctx, {
67
+ method: "POST",
68
+ path: `${paddleSubscriptionPath(options.providerSubscriptionId)}/cancel`,
69
+ body: {
70
+ effective_from: options.when === SubscriptionCancelTimings.periodEnd
71
+ ? "next_billing_period"
72
+ : "immediately",
73
+ },
74
+ });
75
+ };
76
+ }
77
+ export function createPaddleResumeSubscription(runtime) {
78
+ return async (ctx, options) => {
79
+ await runtime.call(ctx, {
80
+ method: "PATCH",
81
+ path: paddleSubscriptionPath(options.providerSubscriptionId),
82
+ body: { scheduled_change: null },
83
+ });
84
+ };
85
+ }
@@ -0,0 +1,19 @@
1
+ import type { Context } from "hono";
2
+ import type { SystemQueryFn } from "../shared/index.ts";
3
+ export declare const PADDLE_INIT_SCRIPT = "(function () {\n var data = document.getElementById(\"kumiko-paddle-checkout\").dataset;\n var completed = false;\n if (data.environment === \"sandbox\") Paddle.Environment.set(\"sandbox\");\n var settings = { displayMode: \"overlay\", successUrl: new URL(data.successUrl, location.origin).href };\n if (data.locale) settings.locale = data.locale;\n Paddle.Initialize({\n token: data.clientToken,\n checkout: { settings: settings },\n eventCallback: function (event) {\n if (event.name === \"checkout.completed\") completed = true;\n if (event.name === \"checkout.closed\" && !completed) {\n location.assign(new URL(data.cancelUrl, location.origin).href);\n }\n }\n });\n})();";
4
+ export declare const PADDLE_CHECKOUT_CSP: string;
5
+ /** Same-origin path only: anything else would make the page an open redirector. */
6
+ export declare function safeRedirectPath(raw: string | undefined): string;
7
+ export declare function safeLocale(raw: string | undefined): string | undefined;
8
+ type CheckoutPageValues = {
9
+ readonly clientToken: string;
10
+ readonly environment: string;
11
+ readonly successUrl: string;
12
+ readonly cancelUrl: string;
13
+ readonly locale: string | undefined;
14
+ };
15
+ export declare function renderCheckoutPage(values: CheckoutPageValues): string;
16
+ export declare function servePaddleCheckoutPage(c: Context, { systemQuery }: {
17
+ readonly systemQuery: SystemQueryFn;
18
+ }): Promise<Response>;
19
+ export {};
@@ -0,0 +1,126 @@
1
+ // The Default Payment Link page. Paddle has no hosted checkout, so Paddle.js
2
+ // runs on this page and opens the overlay for the `?_ptxn=` transaction by
3
+ // itself. The page never reflects `_ptxn`.
4
+ import { createHash } from "node:crypto";
5
+ import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
6
+ import { escapeHtml } from "@cosmicdrift/kumiko-renderer/headless";
7
+ import * as z from "zod";
8
+ import { PADDLE_CHECKOUT_CONFIG_QUERY, PaddleEnvironments } from "./constants.js";
9
+ const PADDLE_JS_URL = "https://cdn.paddle.com/paddle/v2/paddle.js";
10
+ const MAX_REDIRECT_LENGTH = 2048;
11
+ const FALLBACK_REDIRECT = "/";
12
+ const LOCALE_PATTERN = /^[a-z]{2}(-[A-Z]{2})?$/;
13
+ // Control characters, which browsers strip or reinterpret inside URLs.
14
+ const CONTROL_CHARACTERS = /\p{Cc}/u;
15
+ // Static on purpose: its sha256 goes into the CSP, so nothing may be interpolated.
16
+ export const PADDLE_INIT_SCRIPT = `(function () {
17
+ var data = document.getElementById("kumiko-paddle-checkout").dataset;
18
+ var completed = false;
19
+ if (data.environment === "sandbox") Paddle.Environment.set("sandbox");
20
+ var settings = { displayMode: "overlay", successUrl: new URL(data.successUrl, location.origin).href };
21
+ if (data.locale) settings.locale = data.locale;
22
+ Paddle.Initialize({
23
+ token: data.clientToken,
24
+ checkout: { settings: settings },
25
+ eventCallback: function (event) {
26
+ if (event.name === "checkout.completed") completed = true;
27
+ if (event.name === "checkout.closed" && !completed) {
28
+ location.assign(new URL(data.cancelUrl, location.origin).href);
29
+ }
30
+ }
31
+ });
32
+ })();`;
33
+ const INIT_SCRIPT_HASH = createHash("sha256").update(PADDLE_INIT_SCRIPT).digest("base64");
34
+ export const PADDLE_CHECKOUT_CSP = [
35
+ "default-src 'none'",
36
+ `script-src 'sha256-${INIT_SCRIPT_HASH}' https://cdn.paddle.com`,
37
+ "style-src 'unsafe-inline' https://cdn.paddle.com",
38
+ "img-src data: https://*.paddle.com",
39
+ "connect-src https://*.paddle.com",
40
+ "frame-src https://buy.paddle.com https://sandbox-buy.paddle.com",
41
+ "frame-ancestors 'none'",
42
+ "base-uri 'none'",
43
+ "form-action 'none'",
44
+ "object-src 'none'",
45
+ ].join("; ");
46
+ // Own header set: `securePageHeaders` pins `script-src 'none'`. The global
47
+ // wrapper only fills headers that are absent, so these win.
48
+ function pageHeaders() {
49
+ return {
50
+ "content-type": "text/html; charset=utf-8",
51
+ "cache-control": "no-store",
52
+ "referrer-policy": "no-referrer",
53
+ "x-frame-options": "DENY",
54
+ "x-content-type-options": "nosniff",
55
+ "content-security-policy": PADDLE_CHECKOUT_CSP,
56
+ };
57
+ }
58
+ /** Same-origin path only: anything else would make the page an open redirector. */
59
+ export function safeRedirectPath(raw) {
60
+ if (raw === undefined ||
61
+ raw.length > MAX_REDIRECT_LENGTH ||
62
+ !raw.startsWith("/") ||
63
+ raw.startsWith("//") ||
64
+ raw.startsWith("/\\") ||
65
+ CONTROL_CHARACTERS.test(raw)) {
66
+ return FALLBACK_REDIRECT;
67
+ }
68
+ return raw;
69
+ }
70
+ export function safeLocale(raw) {
71
+ return raw !== undefined && LOCALE_PATTERN.test(raw) ? raw : undefined;
72
+ }
73
+ export function renderCheckoutPage(values) {
74
+ const attributesHtml = [
75
+ ["data-client-token", values.clientToken],
76
+ ["data-environment", values.environment],
77
+ ["data-success-url", values.successUrl],
78
+ ["data-cancel-url", values.cancelUrl],
79
+ ...(values.locale ? [["data-locale", values.locale]] : []),
80
+ ]
81
+ .map(([name, value]) => `${name}="${escapeHtml(value ?? "")}"`)
82
+ .join(" ");
83
+ return `<!doctype html>
84
+ <html lang="en">
85
+ <head>
86
+ <meta charset="utf-8">
87
+ <meta name="viewport" content="width=device-width, initial-scale=1">
88
+ <title>Checkout</title>
89
+ </head>
90
+ <body>
91
+ <div id="kumiko-paddle-checkout" ${attributesHtml}></div>
92
+ <noscript>JavaScript is required to complete the checkout.</noscript>
93
+ <script src="${PADDLE_JS_URL}"></script>
94
+ <script>${PADDLE_INIT_SCRIPT}</script>
95
+ </body>
96
+ </html>
97
+ `;
98
+ }
99
+ const checkoutConfigSchema = z.object({
100
+ clientToken: z.string().nullable(),
101
+ environment: z.string(),
102
+ });
103
+ export async function servePaddleCheckoutPage(c, { systemQuery }) {
104
+ let config;
105
+ try {
106
+ config = checkoutConfigSchema.parse(await systemQuery(PADDLE_CHECKOUT_CONFIG_QUERY, {}, SYSTEM_TENANT_ID));
107
+ }
108
+ catch {
109
+ return unavailable(c);
110
+ }
111
+ if (!config.clientToken)
112
+ return unavailable(c);
113
+ const html = renderCheckoutPage({
114
+ clientToken: config.clientToken,
115
+ environment: config.environment === PaddleEnvironments.live
116
+ ? PaddleEnvironments.live
117
+ : PaddleEnvironments.sandbox,
118
+ successUrl: safeRedirectPath(c.req.query("success")),
119
+ cancelUrl: safeRedirectPath(c.req.query("cancel")),
120
+ locale: safeLocale(c.req.query("locale")),
121
+ });
122
+ return new Response(html, { status: 200, headers: pageHeaders() });
123
+ }
124
+ function unavailable(c) {
125
+ return c.text("checkout unavailable", 503, { "cache-control": "no-store" });
126
+ }
@@ -0,0 +1,24 @@
1
+ export type PaddleSend = (url: string, init?: RequestInit) => Promise<Response>;
2
+ export type PaddleRequest = {
3
+ readonly method: "GET" | "POST" | "PATCH";
4
+ /** Path segments interpolated into it must already be encodeURIComponent'ed. */
5
+ readonly path: string;
6
+ readonly query?: Readonly<Record<string, string>>;
7
+ readonly body?: unknown;
8
+ };
9
+ export type PaddleTarget = {
10
+ readonly baseUrl: string;
11
+ readonly apiKey: string;
12
+ };
13
+ type PaddleErrorDetails = {
14
+ readonly type?: string;
15
+ readonly code?: string;
16
+ };
17
+ export declare class PaddleHttpError extends Error {
18
+ readonly status: number;
19
+ readonly paddleErrorType?: string;
20
+ readonly paddleErrorCode?: string;
21
+ constructor(request: PaddleRequest, status: number, details?: PaddleErrorDetails);
22
+ }
23
+ export declare function createPaddleHttp(send: PaddleSend): (target: PaddleTarget, request: PaddleRequest) => Promise<unknown>;
24
+ export {};
@@ -0,0 +1,60 @@
1
+ // Thin JSON-over-fetch client for the Paddle Billing REST API. All traffic goes
2
+ // through the injected `send`, which defaults to the SSRF-safe egress in
3
+ // feature.ts and is replaced by a mock in tests.
4
+ import { parseJsonOrThrow, parseJsonSafe } from "@cosmicdrift/kumiko-framework/utils";
5
+ import * as z from "zod";
6
+ const PADDLE_API_VERSION = "1";
7
+ const paddleErrorBodySchema = z.object({ error: z.object({ type: z.string(), code: z.string() }) });
8
+ // Both values come from outside; anything beyond a plain identifier is dropped so
9
+ // no customer text reaches the logs.
10
+ const ERROR_IDENTIFIER = /^[a-z0-9_]{1,100}$/;
11
+ function paddleErrorDetails(bodyText) {
12
+ const parsed = paddleErrorBodySchema.safeParse(parseJsonSafe(bodyText, undefined));
13
+ if (!parsed.success)
14
+ return {};
15
+ const { type, code } = parsed.data.error;
16
+ return {
17
+ ...(ERROR_IDENTIFIER.test(type) && { type }),
18
+ ...(ERROR_IDENTIFIER.test(code) && { code }),
19
+ };
20
+ }
21
+ // Carries only the status and Paddle's error type and code, never `detail`, the
22
+ // rest of the body or the key: they can hold customer data or secrets.
23
+ export class PaddleHttpError extends Error {
24
+ status;
25
+ paddleErrorType;
26
+ paddleErrorCode;
27
+ constructor(request, status, details = {}) {
28
+ const suffix = [details.type && `type ${details.type}`, details.code && `code ${details.code}`]
29
+ .filter(Boolean)
30
+ .join(", ");
31
+ super(`subscription-paddle: ${request.method} ${request.path} failed with status ${status}${suffix ? ` (${suffix})` : ""}`);
32
+ this.name = "PaddleHttpError";
33
+ this.status = status;
34
+ if (details.type)
35
+ this.paddleErrorType = details.type;
36
+ if (details.code)
37
+ this.paddleErrorCode = details.code;
38
+ }
39
+ }
40
+ export function createPaddleHttp(send) {
41
+ return async (target, request) => {
42
+ const query = request.query ? `?${new URLSearchParams(request.query).toString()}` : "";
43
+ const response = await send(`${target.baseUrl}${request.path}${query}`, {
44
+ method: request.method,
45
+ headers: {
46
+ Authorization: `Bearer ${target.apiKey}`,
47
+ Accept: "application/json",
48
+ "Content-Type": "application/json",
49
+ "Paddle-Version": PADDLE_API_VERSION,
50
+ },
51
+ ...(request.body !== undefined && { body: JSON.stringify(request.body) }),
52
+ });
53
+ const text = await response.text();
54
+ if (!response.ok)
55
+ throw new PaddleHttpError(request, response.status, paddleErrorDetails(text));
56
+ return text.length === 0
57
+ ? null
58
+ : parseJsonOrThrow(text, "subscription-paddle response");
59
+ };
60
+ }
@@ -0,0 +1,16 @@
1
+ export declare const SUBSCRIPTION_PADDLE_FEATURE: "subscription-paddle";
2
+ export declare const PADDLE_PROVIDER_NAME: "paddle";
3
+ export declare const PADDLE_CHECKOUT_PATH: "/billing/paddle-checkout";
4
+ export declare const PADDLE_API_KEY_CONFIG: "api-key";
5
+ export declare const PADDLE_WEBHOOK_SECRET_CONFIG: "webhook-secret";
6
+ export declare const PADDLE_TENANT_BINDING_KEY_CONFIG: "tenant-binding-key";
7
+ export declare const PADDLE_CLIENT_TOKEN_CONFIG: "client-token";
8
+ export declare const PADDLE_ENVIRONMENT_CONFIG: "environment";
9
+ export declare const PADDLE_BILLING_LIVE_CONFIG: "billingLive";
10
+ export declare const PADDLE_CHECKOUT_CONFIG_QUERY: string;
11
+ export declare const PaddleEnvironments: {
12
+ readonly sandbox: "sandbox";
13
+ readonly live: "live";
14
+ };
15
+ export type PaddleEnvironment = (typeof PaddleEnvironments)[keyof typeof PaddleEnvironments];
16
+ export declare const PADDLE_BASE_URLS: Readonly<Record<PaddleEnvironment, string>>;
@@ -0,0 +1,25 @@
1
+ export const SUBSCRIPTION_PADDLE_FEATURE = "subscription-paddle";
2
+ // Must match the last path segment of the webhook URL (`/webhooks/subscription/paddle` via the boot option).
3
+ export const PADDLE_PROVIDER_NAME = "paddle";
4
+ // Paddle has no hosted checkout page, so the feature serves the Default Payment
5
+ // Link itself; the same path goes into the Paddle dashboard.
6
+ export const PADDLE_CHECKOUT_PATH = "/billing/paddle-checkout";
7
+ // Config-key short-names, qualified to `subscription-paddle:config:<name>` at
8
+ // registry-build. api-key, webhook-secret and tenant-binding-key are backing:"secrets".
9
+ export const PADDLE_API_KEY_CONFIG = "api-key";
10
+ export const PADDLE_WEBHOOK_SECRET_CONFIG = "webhook-secret";
11
+ export const PADDLE_TENANT_BINDING_KEY_CONFIG = "tenant-binding-key";
12
+ export const PADDLE_CLIENT_TOKEN_CONFIG = "client-token";
13
+ export const PADDLE_ENVIRONMENT_CONFIG = "environment";
14
+ export const PADDLE_BILLING_LIVE_CONFIG = "billingLive";
15
+ export const PADDLE_CHECKOUT_CONFIG_QUERY = `${SUBSCRIPTION_PADDLE_FEATURE}:query:checkout-config`;
16
+ // Separate from billingLive on purpose: staging runs Paddle's sandbox with
17
+ // billingLive on, production flips both.
18
+ export const PaddleEnvironments = {
19
+ sandbox: "sandbox",
20
+ live: "live",
21
+ };
22
+ export const PADDLE_BASE_URLS = {
23
+ sandbox: "https://sandbox-api.paddle.com",
24
+ live: "https://api.paddle.com",
25
+ };
@@ -0,0 +1,49 @@
1
+ import { type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { type FeatureWithEnvSchema } from "@cosmicdrift/kumiko-framework/env";
3
+ import * as z from "zod";
4
+ import type { PaddleSend } from "./client.ts";
5
+ /** Bridge contract: all fields are optional fallbacks for the config store. */
6
+ export declare const subscriptionPaddleEnvSchema: z.ZodObject<{
7
+ PADDLE_API_KEY: z.ZodOptional<z.ZodString>;
8
+ PADDLE_WEBHOOK_SECRET: z.ZodOptional<z.ZodString>;
9
+ PADDLE_TENANT_BINDING_KEY: z.ZodOptional<z.ZodString>;
10
+ PADDLE_CLIENT_TOKEN: z.ZodOptional<z.ZodString>;
11
+ }, z.core.$strip>;
12
+ type PaddlePriceEnvShape<TPrice extends string> = {
13
+ [Key in `PADDLE_PRICE_${TPrice}`]: z.ZodOptional<z.ZodString>;
14
+ };
15
+ /** Paddle env block plus one `PADDLE_PRICE_<NAME>` slot per plan price the app
16
+ * maps to a tier, e.g. `paddleEnvSchema({ prices: ["PRO", "TEAM"] })`.
17
+ * Shares its bridge fields with `subscriptionPaddleEnvSchema`, so spreading
18
+ * it into `composeEnvSchema({ extend })` next to the mounted feature is no
19
+ * key clash. */
20
+ export declare function paddleEnvSchema<const TPrice extends string>(options: {
21
+ readonly prices: readonly TPrice[];
22
+ }): z.ZodObject<{
23
+ PADDLE_API_KEY: z.ZodOptional<z.ZodString>;
24
+ PADDLE_WEBHOOK_SECRET: z.ZodOptional<z.ZodString>;
25
+ PADDLE_TENANT_BINDING_KEY: z.ZodOptional<z.ZodString>;
26
+ PADDLE_CLIENT_TOKEN: z.ZodOptional<z.ZodString>;
27
+ } & PaddlePriceEnvShape<TPrice> extends infer T ? { -readonly [P in keyof T]: T[P]; } : never, z.core.$strip>;
28
+ export type SubscriptionPaddleOptions = {
29
+ /** Bridge-fallback API key; the `api-key` config key wins when set. */
30
+ readonly apiKey?: string;
31
+ /** Bridge-fallback webhook secret; the `webhook-secret` config key wins when set. */
32
+ readonly webhookSecret?: string;
33
+ /** Bridge-fallback tenant binding key; the `tenant-binding-key` config key wins when set. */
34
+ readonly tenantBindingKey?: string;
35
+ /** Bridge-fallback Paddle.js client token; the `client-token` config key wins when set. */
36
+ readonly clientToken?: string;
37
+ /** Paddle price id → app tier name. Prices absent here drop the event. */
38
+ readonly priceToTier?: Readonly<Record<string, string>>;
39
+ /** Price ids a mode:"payment" checkout may target; empty = one-off checkouts closed. */
40
+ readonly oneOffPriceIds?: readonly string[];
41
+ /** HTTP transport; defaults to the SSRF-safe external egress. Test seam. */
42
+ readonly send?: PaddleSend;
43
+ /** Epoch milliseconds for the plan-switch preview timestamp. Test seam. */
44
+ readonly now?: () => number;
45
+ /** Unix seconds for the webhook tolerance window. Test seam. */
46
+ readonly nowSeconds?: () => number;
47
+ };
48
+ export declare function createSubscriptionPaddleFeature(options?: SubscriptionPaddleOptions): FeatureWithEnvSchema<FeatureDefinition, typeof subscriptionPaddleEnvSchema.shape>;
49
+ export {};
@@ -0,0 +1,192 @@
1
+ // kumiko-feature-version: 1
2
+ //
3
+ // subscription-paddle — Paddle Billing (merchant of record) plugin for the
4
+ // billing-foundation plugin API. Credentials, the billing-live master switch and
5
+ // the API environment (sandbox | live) are config keys resolved at call time, like
6
+ // subscription-stripe. The `apiKey` / `webhookSecret` / `tenantBindingKey` /
7
+ // `clientToken` options are env→config bridge fallbacks.
8
+ import { access, createSystemConfig, defineFeature, } from "@cosmicdrift/kumiko-framework/engine";
9
+ import { featureWithEnvSchema } from "@cosmicdrift/kumiko-framework/env";
10
+ import { egress } from "@cosmicdrift/kumiko-framework/http";
11
+ import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
12
+ import * as z from "zod";
13
+ import { makeCheckoutConfigQuery } from "./checkout-config.query.js";
14
+ import { createPaddleCancelSubscription, createPaddleCheckoutSession, createPaddlePortalSession, createPaddleResumeSubscription, } from "./checkout-methods.js";
15
+ import { servePaddleCheckoutPage } from "./checkout-page.js";
16
+ import { PADDLE_API_KEY_CONFIG, PADDLE_BILLING_LIVE_CONFIG, PADDLE_CLIENT_TOKEN_CONFIG, PADDLE_ENVIRONMENT_CONFIG, PADDLE_PROVIDER_NAME, PADDLE_TENANT_BINDING_KEY_CONFIG, PADDLE_WEBHOOK_SECRET_CONFIG, PaddleEnvironments, SUBSCRIPTION_PADDLE_FEATURE, } from "./constants.js";
17
+ import { createPaddleApplyPlanSwitch, createPaddlePreviewPlanSwitch, createPaddleRetrieveSubscription, } from "./plan-switch-methods.js";
18
+ import { createPaddlePriceCache, createPaddleRetrievePrices } from "./price-methods.js";
19
+ import { createPaddleRuntimes } from "./runtime.js";
20
+ import { verifyAndParsePaddleWebhook } from "./webhook-events.js";
21
+ /** Bridge contract: all fields are optional fallbacks for the config store. */
22
+ export const subscriptionPaddleEnvSchema = z.object({
23
+ PADDLE_API_KEY: z
24
+ .string()
25
+ .min(1)
26
+ .describe("Paddle API key. Bridge-fallback — prefer the secret.")
27
+ .meta({ kumiko: { pulumi: { secret: true } } })
28
+ .optional(),
29
+ PADDLE_WEBHOOK_SECRET: z
30
+ .string()
31
+ .min(1)
32
+ .describe("Paddle notification secret (`pdl_ntfset_...`). Bridge-fallback — prefer the secret.")
33
+ .meta({ kumiko: { pulumi: { secret: true } } })
34
+ .optional(),
35
+ PADDLE_TENANT_BINDING_KEY: z
36
+ .string()
37
+ .min(1)
38
+ .describe("Server-only HMAC key binding a Paddle checkout to its tenant. Bridge-fallback — prefer the secret.")
39
+ .meta({ kumiko: { pulumi: { secret: true } } })
40
+ .optional(),
41
+ PADDLE_CLIENT_TOKEN: z
42
+ .string()
43
+ .regex(/^(test|live)_/, "PADDLE_CLIENT_TOKEN must start with 'test_' or 'live_'")
44
+ .describe("Paddle.js client-side token (public). Bridge-fallback for the config key.")
45
+ .optional(),
46
+ });
47
+ /** Paddle env block plus one `PADDLE_PRICE_<NAME>` slot per plan price the app
48
+ * maps to a tier, e.g. `paddleEnvSchema({ prices: ["PRO", "TEAM"] })`.
49
+ * Shares its bridge fields with `subscriptionPaddleEnvSchema`, so spreading
50
+ * it into `composeEnvSchema({ extend })` next to the mounted feature is no
51
+ * key clash. */
52
+ export function paddleEnvSchema(options) {
53
+ const priceShape = Object.fromEntries(options.prices.map((price) => [
54
+ `PADDLE_PRICE_${price}`,
55
+ z
56
+ .string()
57
+ .regex(/^pri_/, `PADDLE_PRICE_${price} must start with 'pri_'`)
58
+ .optional()
59
+ .describe(`Paddle price id (\`pri_...\`) of the ${price} plan.`),
60
+ ]));
61
+ return z.object({ ...subscriptionPaddleEnvSchema.shape, ...priceShape });
62
+ }
63
+ // Validated once at feature-build time so a typo fails app startup instead of
64
+ // silently widening or narrowing the one-off allowlist at request time.
65
+ function validateOneOffPriceIds(priceIds) {
66
+ const seen = new Set();
67
+ for (const priceId of priceIds) {
68
+ if (priceId.length === 0) {
69
+ throw new Error("subscription-paddle: oneOffPriceIds must not contain an empty string");
70
+ }
71
+ if (seen.has(priceId)) {
72
+ throw new Error(`subscription-paddle: duplicate oneOffPriceIds entry "${priceId}"`);
73
+ }
74
+ seen.add(priceId);
75
+ }
76
+ }
77
+ export function createSubscriptionPaddleFeature(options = {}) {
78
+ validateOneOffPriceIds(options.oneOffPriceIds ?? []);
79
+ const now = options.now ?? (() => Temporal.Now.instant().epochMilliseconds);
80
+ const feature = defineFeature(SUBSCRIPTION_PADDLE_FEATURE, (r) => {
81
+ r.describe('Paddle Billing provider plugin for `billing-foundation`. Paddle acts as merchant of record: it sells to the customer and issues invoice and VAT, so the consumer-protection texts for this provider come from `consumerProtection.providerTexts`. Reads its API key, webhook secret and tenant binding key from system config keys with `backing:"secrets"` (envelope-encrypted in the secrets store under the system tenant), the public Paddle.js `client-token`, a `billingLive` master switch and an `environment` key (sandbox | live). `environment` is its own key because Paddle serves sandbox and live from different API hosts and a live key must never hit the sandbox host or the other way round; `billingLive` only decides whether checkouts are offered at all. All of them are runtime config, so keys rotate and prod goes live without a redeploy, and the `mask` on each derives the sysadmin settings screen and nav. Mount via `createSubscriptionPaddleFeature({ priceToTier })`; the optional `apiKey`/`webhookSecret`/`tenantBindingKey`/`clientToken` options are env to config bridge fallbacks (`PADDLE_API_KEY`, `PADDLE_WEBHOOK_SECRET`, `PADDLE_TENANT_BINDING_KEY`, `PADDLE_CLIENT_TOKEN`). The plugin always mounts; `createCheckoutSession` throws `feature_disabled` unless `billingLive` is true, and billing counts as enabled only with API key and binding key present. Webhooks arrive at `/webhooks/subscription/paddle` when mounted through the server-runtime `billing.paddle` boot option, or at `/api/subscription/webhook/paddle` when `createSubscriptionWebhookRoute` is mounted by hand and are verified with the `Paddle-Signature` header (HMAC-SHA256 over `ts:rawBody` keyed with the raw secret, any `h1` may match, 5 minute tolerance). Paddle.js can open checkouts with arbitrary `customData` from the browser, so `custom_data.tenantId` is only trusted together with `tenantBinding`, an HMAC of the tenant id under the binding key; events without a valid binding, for prices outside `priceToTier` or without a tenant are dropped. Rotating the binding key makes the webhooks of existing subscriptions fail that check until they are re-bound. Paddle has no hosted checkout page, so the feature serves the Default Payment Link itself at `/billing/paddle-checkout` (the Default Payment Link in the Paddle dashboard must point to `<APP_BASE_URL>/billing/paddle-checkout`; it is the only source, because checkouts are created without a `checkout.url`). Create subscription prices in the Paddle catalog with quantity minimum and maximum 1; for one-off packs set the quantity limits on purpose, because the payment event carries `quantity` and the app has to multiply its credits by it: an anonymous page with its own CSP that loads Paddle.js from cdn.paddle.com, the one external script this framework allows, and opens the overlay for the transaction. Implements checkout, customer portal, cancel and resume, `retrievePrices` (batched, 10-minute TTL cache), `retrieveSubscription` for the sync job, and an in-app plan switch: `previewPlanSwitch` shows the proration before the customer confirms, `applyPlanSwitch` changes the plan without a hosted page and waits for the `subscription.updated` webhook to move the tier.');
82
+ r.uiHints({
83
+ displayLabel: "Billing · Paddle",
84
+ category: "billing",
85
+ recommended: false,
86
+ });
87
+ r.requires({ features: ["billing-foundation"] });
88
+ r.requires({ features: ["config"] });
89
+ r.requires({ features: ["secrets"] });
90
+ r.envSchema(subscriptionPaddleEnvSchema);
91
+ const configKeys = r.config({
92
+ keys: {
93
+ [PADDLE_API_KEY_CONFIG]: createSystemConfig("text", {
94
+ backing: "secrets",
95
+ write: access.systemAdmin,
96
+ read: access.admin,
97
+ mask: { title: "subscription-paddle.api-key", icon: "key", order: 1 },
98
+ }),
99
+ [PADDLE_WEBHOOK_SECRET_CONFIG]: createSystemConfig("text", {
100
+ backing: "secrets",
101
+ write: access.systemAdmin,
102
+ read: access.admin,
103
+ mask: { title: "subscription-paddle.webhook-secret", icon: "shield", order: 2 },
104
+ }),
105
+ [PADDLE_TENANT_BINDING_KEY_CONFIG]: createSystemConfig("text", {
106
+ backing: "secrets",
107
+ write: access.systemAdmin,
108
+ read: access.admin,
109
+ mask: { title: "subscription-paddle.tenant-binding-key", icon: "lock", order: 3 },
110
+ }),
111
+ [PADDLE_CLIENT_TOKEN_CONFIG]: createSystemConfig("text", {
112
+ write: access.systemAdmin,
113
+ read: access.admin,
114
+ mask: { title: "subscription-paddle.client-token", icon: "settings", order: 4 },
115
+ }),
116
+ [PADDLE_ENVIRONMENT_CONFIG]: createSystemConfig("select", {
117
+ default: PaddleEnvironments.sandbox,
118
+ options: [PaddleEnvironments.sandbox, PaddleEnvironments.live],
119
+ write: access.systemAdmin,
120
+ read: access.admin,
121
+ mask: { title: "subscription-paddle.environment", icon: "server", order: 5 },
122
+ }),
123
+ [PADDLE_BILLING_LIVE_CONFIG]: createSystemConfig("boolean", {
124
+ default: false,
125
+ write: access.privileged,
126
+ read: access.admin,
127
+ mask: { title: "subscription-paddle.billing-live", icon: "rocket", order: 6 },
128
+ }),
129
+ },
130
+ });
131
+ r.translations({
132
+ keys: {
133
+ "subscription-paddle.api-key": { en: "Paddle API key" },
134
+ "subscription-paddle.webhook-secret": { en: "Paddle webhook secret" },
135
+ "subscription-paddle.tenant-binding-key": { en: "Paddle tenant binding key" },
136
+ "subscription-paddle.client-token": { en: "Paddle client-side token" },
137
+ "subscription-paddle.environment": { en: "Paddle environment" },
138
+ "subscription-paddle.billing-live": { en: "Live billing" },
139
+ "subscription-paddle.settings": { en: "Paddle" },
140
+ "screen:subscription-paddle-system.title": { en: "Paddle" },
141
+ },
142
+ });
143
+ const priceToTier = options.priceToTier ?? {};
144
+ const runtimes = createPaddleRuntimes({
145
+ apiKeyHandle: configKeys[PADDLE_API_KEY_CONFIG],
146
+ webhookSecretHandle: configKeys[PADDLE_WEBHOOK_SECRET_CONFIG],
147
+ tenantBindingKeyHandle: configKeys[PADDLE_TENANT_BINDING_KEY_CONFIG],
148
+ clientTokenHandle: configKeys[PADDLE_CLIENT_TOKEN_CONFIG],
149
+ billingLiveHandle: configKeys[PADDLE_BILLING_LIVE_CONFIG],
150
+ environmentHandle: configKeys[PADDLE_ENVIRONMENT_CONFIG],
151
+ send: options.send ?? egress({ kind: "external" }),
152
+ fallback: {
153
+ ...(options.apiKey !== undefined && { apiKey: options.apiKey }),
154
+ ...(options.webhookSecret !== undefined && { webhookSecret: options.webhookSecret }),
155
+ ...(options.tenantBindingKey !== undefined && {
156
+ tenantBindingKey: options.tenantBindingKey,
157
+ }),
158
+ ...(options.clientToken !== undefined && { clientToken: options.clientToken }),
159
+ },
160
+ });
161
+ r.queryHandler(makeCheckoutConfigQuery(runtimes.readCheckoutConfig));
162
+ r.httpRoute({
163
+ method: "GET",
164
+ // Literal for the feature-AST extractor; must equal PADDLE_CHECKOUT_PATH (integration test).
165
+ path: "/billing/paddle-checkout",
166
+ anonymous: true,
167
+ rateLimit: { per: "ip+handler", limit: 60, windowSeconds: 60 },
168
+ handler: (c, deps) => servePaddleCheckoutPage(c, deps),
169
+ });
170
+ const plugin = {
171
+ displayName: "Paddle",
172
+ verifyAndParseWebhook: verifyAndParsePaddleWebhook(runtimes.webhook, {
173
+ priceToTier,
174
+ ...(options.nowSeconds && { nowSeconds: options.nowSeconds }),
175
+ }),
176
+ createCheckoutSession: createPaddleCheckoutSession(runtimes.ctx),
177
+ createPortalSession: createPaddlePortalSession(runtimes.ctx),
178
+ cancelSubscription: createPaddleCancelSubscription(runtimes.ctx),
179
+ resumeSubscription: createPaddleResumeSubscription(runtimes.ctx),
180
+ priceToTier,
181
+ oneOffPriceIds: options.oneOffPriceIds ?? [],
182
+ isBillingEnabled: runtimes.ctx.isBillingEnabled,
183
+ retrievePrices: createPaddleRetrievePrices(runtimes.ctx, createPaddlePriceCache({ now })),
184
+ retrieveSubscription: createPaddleRetrieveSubscription(runtimes.ctx, { priceToTier }),
185
+ previewPlanSwitch: createPaddlePreviewPlanSwitch(runtimes.ctx, now),
186
+ applyPlanSwitch: createPaddleApplyPlanSwitch(runtimes.ctx),
187
+ };
188
+ r.useExtension("subscriptionProvider", PADDLE_PROVIDER_NAME, plugin);
189
+ return { configKeys };
190
+ });
191
+ return featureWithEnvSchema(feature, subscriptionPaddleEnvSchema);
192
+ }
@@ -0,0 +1,2 @@
1
+ export { PADDLE_BASE_URLS, PADDLE_CHECKOUT_PATH, PADDLE_PROVIDER_NAME, type PaddleEnvironment, PaddleEnvironments, SUBSCRIPTION_PADDLE_FEATURE, } from "./constants.ts";
2
+ export { createSubscriptionPaddleFeature, paddleEnvSchema, type SubscriptionPaddleOptions, subscriptionPaddleEnvSchema, } from "./feature.ts";
@@ -0,0 +1,4 @@
1
+ // Public API of the subscription-paddle bundled feature. The webhook verifier,
2
+ // client and plugin methods are internal to feature.ts.
3
+ export { PADDLE_BASE_URLS, PADDLE_CHECKOUT_PATH, PADDLE_PROVIDER_NAME, PaddleEnvironments, SUBSCRIPTION_PADDLE_FEATURE, } from "./constants.js";
4
+ export { createSubscriptionPaddleFeature, paddleEnvSchema, subscriptionPaddleEnvSchema, } from "./feature.js";
@@ -0,0 +1,6 @@
1
+ import type { PaddleCtxRuntime, PaddlePluginMethod } from "./runtime.ts";
2
+ export declare function createPaddlePreviewPlanSwitch(runtime: PaddleCtxRuntime, now: () => number): PaddlePluginMethod<"previewPlanSwitch">;
3
+ export declare function createPaddleApplyPlanSwitch(runtime: PaddleCtxRuntime): PaddlePluginMethod<"applyPlanSwitch">;
4
+ export declare function createPaddleRetrieveSubscription(runtime: PaddleCtxRuntime, options: {
5
+ readonly priceToTier: Readonly<Record<string, string>>;
6
+ }): PaddlePluginMethod<"retrieveSubscription">;