payment-kit 1.29.1 → 1.29.3

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 (343) hide show
  1. package/api/dev.ts +41 -2
  2. package/api/hono.d.ts +42 -0
  3. package/api/node-sqlite.d.ts +12 -0
  4. package/api/src/bootstrap.ts +47 -0
  5. package/api/src/crons/base.ts +3 -3
  6. package/api/src/crons/currency.ts +1 -1
  7. package/api/src/crons/index.ts +41 -37
  8. package/api/src/crons/metering-subscription-detection.ts +1 -1
  9. package/api/src/crons/overdue-detection.ts +2 -2
  10. package/api/src/crons/retry-pending-events.ts +6 -0
  11. package/api/src/crons/tenant-fanout.ts +82 -0
  12. package/api/src/host-node/did-connect-runtime-node.ts +33 -0
  13. package/api/src/host-node/serve-static-arc.ts +68 -0
  14. package/api/src/host-node/serve-static.ts +41 -0
  15. package/api/src/index.ts +22 -161
  16. package/api/src/integrations/app-store/client.ts +3 -4
  17. package/api/src/integrations/app-store/handlers/subscription.ts +7 -7
  18. package/api/src/integrations/app-store/signed-data-verifier.ts +3 -2
  19. package/api/src/integrations/arcblock/token.ts +21 -7
  20. package/api/src/integrations/google-play/handlers/subscription.ts +6 -6
  21. package/api/src/integrations/google-play/handlers/voided.ts +2 -2
  22. package/api/src/integrations/google-play/verify.ts +3 -2
  23. package/api/src/integrations/iap-reconcile.ts +3 -5
  24. package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
  25. package/api/src/integrations/stripe/handlers/subscription.ts +3 -3
  26. package/api/src/libs/archive/query.ts +19 -0
  27. package/api/src/libs/audit.ts +61 -4
  28. package/api/src/libs/auth.ts +247 -47
  29. package/api/src/libs/context.ts +89 -1
  30. package/api/src/libs/currency.ts +2 -2
  31. package/api/src/libs/dayjs.ts +8 -2
  32. package/api/src/libs/did-connect/runtime-did-connect-js.ts +88 -0
  33. package/api/src/libs/did-connect/tenant-identity.ts +221 -0
  34. package/api/src/libs/drivers/auth-storage.ts +118 -0
  35. package/api/src/libs/drivers/cron.ts +264 -0
  36. package/api/src/libs/drivers/db.ts +170 -0
  37. package/api/src/libs/drivers/identity.ts +142 -0
  38. package/api/src/libs/drivers/index.ts +40 -0
  39. package/api/src/libs/drivers/locks.ts +226 -0
  40. package/api/src/libs/drivers/migrate-runner.ts +70 -0
  41. package/api/src/libs/drivers/queue.ts +104 -0
  42. package/api/src/libs/drivers/secrets.ts +194 -0
  43. package/api/src/libs/env.ts +170 -54
  44. package/api/src/libs/exchange-rate/service.ts +7 -6
  45. package/api/src/libs/http-fetch-adapter.ts +60 -0
  46. package/api/src/libs/invoice.ts +1 -1
  47. package/api/src/libs/lock.ts +51 -47
  48. package/api/src/libs/logger.ts +48 -8
  49. package/api/src/libs/notification/index.ts +1 -1
  50. package/api/src/libs/notification/template/customer-credit-low-balance.ts +2 -1
  51. package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -1
  52. package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -1
  53. package/api/src/libs/overdraft-protection.ts +1 -1
  54. package/api/src/libs/payout.ts +1 -1
  55. package/api/src/libs/queue/index.ts +271 -52
  56. package/api/src/libs/queue/runtime.ts +175 -0
  57. package/api/src/libs/resource.ts +3 -3
  58. package/api/src/libs/secrets.ts +38 -0
  59. package/api/src/libs/session.ts +3 -2
  60. package/api/src/libs/subscription.ts +5 -5
  61. package/api/src/libs/tenant.ts +92 -0
  62. package/api/src/libs/url.ts +3 -3
  63. package/api/src/libs/util.ts +21 -13
  64. package/api/src/middlewares/hono/cdn.ts +63 -0
  65. package/api/src/middlewares/hono/context.ts +80 -0
  66. package/api/src/middlewares/hono/csrf.ts +83 -0
  67. package/api/src/middlewares/hono/fallback.ts +194 -0
  68. package/api/src/middlewares/hono/pipeline.ts +73 -0
  69. package/api/src/middlewares/hono/resource-mount.ts +42 -0
  70. package/api/src/middlewares/hono/resource.ts +63 -0
  71. package/api/src/middlewares/hono/security.ts +209 -0
  72. package/api/src/middlewares/hono/session.ts +114 -0
  73. package/api/src/middlewares/hono/xss.ts +61 -0
  74. package/api/src/queues/auto-recharge.ts +12 -10
  75. package/api/src/queues/checkout-session.ts +38 -21
  76. package/api/src/queues/credit-consume.ts +40 -36
  77. package/api/src/queues/credit-grant.ts +25 -18
  78. package/api/src/queues/credit-reconciliation.ts +7 -5
  79. package/api/src/queues/discount-status.ts +9 -6
  80. package/api/src/queues/event.ts +41 -11
  81. package/api/src/queues/exchange-rate-health.ts +49 -30
  82. package/api/src/queues/invoice.ts +18 -15
  83. package/api/src/queues/notification.ts +14 -7
  84. package/api/src/queues/payment.ts +64 -37
  85. package/api/src/queues/payout.ts +37 -21
  86. package/api/src/queues/refund.ts +36 -18
  87. package/api/src/queues/subscription.ts +83 -53
  88. package/api/src/queues/token-transfer.ts +15 -10
  89. package/api/src/queues/usage-record.ts +8 -5
  90. package/api/src/queues/vendors/commission.ts +7 -5
  91. package/api/src/queues/vendors/fulfillment-coordinator.ts +17 -13
  92. package/api/src/queues/vendors/fulfillment.ts +4 -2
  93. package/api/src/queues/vendors/return-processor.ts +5 -3
  94. package/api/src/queues/vendors/return-scanner.ts +5 -4
  95. package/api/src/queues/vendors/status-check.ts +10 -7
  96. package/api/src/queues/webhook.ts +60 -32
  97. package/api/src/routes/connect/shared.ts +1 -2
  98. package/api/src/routes/connect/subscribe.ts +3 -3
  99. package/api/src/routes/{archive.ts → hono/archive.ts} +69 -64
  100. package/api/src/routes/{auto-recharge-configs.ts → hono/auto-recharge-configs.ts} +39 -28
  101. package/api/src/routes/{checkout-sessions.ts → hono/checkout-sessions.ts} +790 -923
  102. package/api/src/routes/{coupons.ts → hono/coupons.ts} +93 -76
  103. package/api/src/routes/{credit-grants.ts → hono/credit-grants.ts} +140 -126
  104. package/api/src/routes/hono/credit-tokens.ts +43 -0
  105. package/api/src/routes/{credit-transactions.ts → hono/credit-transactions.ts} +37 -29
  106. package/api/src/routes/{customers.ts → hono/customers.ts} +199 -224
  107. package/api/src/routes/{donations.ts → hono/donations.ts} +41 -32
  108. package/api/src/routes/{entitlements.ts → hono/entitlements.ts} +28 -25
  109. package/api/src/routes/{events.ts → hono/events.ts} +107 -71
  110. package/api/src/routes/{exchange-rate-providers.ts → hono/exchange-rate-providers.ts} +138 -126
  111. package/api/src/routes/hono/exchange-rates.ts +77 -0
  112. package/api/src/routes/hono/index.ts +115 -0
  113. package/api/src/routes/{integrations → hono/integrations}/app-store.ts +68 -48
  114. package/api/src/routes/{integrations → hono/integrations}/google-play.ts +78 -58
  115. package/api/src/routes/hono/integrations/stripe.ts +74 -0
  116. package/api/src/routes/{invoices.ts → hono/invoices.ts} +253 -244
  117. package/api/src/routes/{meter-events.ts → hono/meter-events.ts} +120 -110
  118. package/api/src/routes/hono/meters.ts +288 -0
  119. package/api/src/routes/hono/passports.ts +73 -0
  120. package/api/src/routes/{payment-currencies.ts → hono/payment-currencies.ts} +219 -197
  121. package/api/src/routes/{payment-intents.ts → hono/payment-intents.ts} +136 -132
  122. package/api/src/routes/{payment-links.ts → hono/payment-links.ts} +145 -128
  123. package/api/src/routes/{payment-methods.ts → hono/payment-methods.ts} +125 -93
  124. package/api/src/routes/{payment-stats.ts → hono/payment-stats.ts} +30 -25
  125. package/api/src/routes/{payouts.ts → hono/payouts.ts} +55 -47
  126. package/api/src/routes/{prices.ts → hono/prices.ts} +265 -242
  127. package/api/src/routes/{pricing-table.ts → hono/pricing-table.ts} +94 -87
  128. package/api/src/routes/{products.ts → hono/products.ts} +172 -159
  129. package/api/src/routes/{promotion-codes.ts → hono/promotion-codes.ts} +207 -185
  130. package/api/src/routes/hono/redirect.ts +24 -0
  131. package/api/src/routes/{refunds.ts → hono/refunds.ts} +98 -83
  132. package/api/src/routes/{settings.ts → hono/settings.ts} +64 -55
  133. package/api/src/routes/{subscription-items.ts → hono/subscription-items.ts} +64 -57
  134. package/api/src/routes/{subscriptions.ts → hono/subscriptions.ts} +475 -528
  135. package/api/src/routes/{tax-rates.ts → hono/tax-rates.ts} +71 -70
  136. package/api/src/routes/hono/tool.ts +69 -0
  137. package/api/src/routes/{usage-records.ts → hono/usage-records.ts} +47 -42
  138. package/api/src/routes/{vendor.ts → hono/vendor.ts} +315 -167
  139. package/api/src/routes/{webhook-attempts.ts → hono/webhook-attempts.ts} +17 -13
  140. package/api/src/routes/hono/webhook-endpoints.ts +126 -0
  141. package/api/src/service.ts +814 -0
  142. package/api/src/store/migrations/20230911-seeding.ts +2 -1
  143. package/api/src/store/migrations/20260609-remove-did-space-jobs.ts +23 -0
  144. package/api/src/store/migrations/20260610-tenant-columns.ts +40 -0
  145. package/api/src/store/migrations/20260611-tenant-backfill.ts +33 -0
  146. package/api/src/store/models/auto-recharge-config.ts +22 -10
  147. package/api/src/store/models/checkout-session.ts +15 -14
  148. package/api/src/store/models/coupon.ts +29 -20
  149. package/api/src/store/models/credit-grant.ts +38 -29
  150. package/api/src/store/models/credit-transaction.ts +32 -21
  151. package/api/src/store/models/customer.ts +19 -17
  152. package/api/src/store/models/discount.ts +11 -2
  153. package/api/src/store/models/entitlement-grant.ts +21 -9
  154. package/api/src/store/models/entitlement-product.ts +21 -9
  155. package/api/src/store/models/entitlement.ts +19 -10
  156. package/api/src/store/models/event.ts +18 -9
  157. package/api/src/store/models/exchange-rate-provider.ts +17 -4
  158. package/api/src/store/models/invoice-item.ts +18 -9
  159. package/api/src/store/models/invoice.ts +16 -8
  160. package/api/src/store/models/meter-event.ts +27 -9
  161. package/api/src/store/models/meter.ts +31 -22
  162. package/api/src/store/models/payment-currency.ts +25 -8
  163. package/api/src/store/models/payment-intent.ts +15 -6
  164. package/api/src/store/models/payment-link.ts +15 -6
  165. package/api/src/store/models/payment-method.ts +38 -22
  166. package/api/src/store/models/payment-stat.ts +18 -9
  167. package/api/src/store/models/payout.ts +15 -6
  168. package/api/src/store/models/price-quote.ts +17 -8
  169. package/api/src/store/models/price.ts +24 -12
  170. package/api/src/store/models/pricing-table.ts +29 -20
  171. package/api/src/store/models/product-vendor.ts +20 -10
  172. package/api/src/store/models/product.ts +15 -6
  173. package/api/src/store/models/promotion-code.ts +14 -6
  174. package/api/src/store/models/refund.ts +15 -6
  175. package/api/src/store/models/revenue-snapshot.ts +21 -9
  176. package/api/src/store/models/setting.ts +18 -9
  177. package/api/src/store/models/setup-intent.ts +36 -27
  178. package/api/src/store/models/subscription-item.ts +21 -9
  179. package/api/src/store/models/subscription-schedule.ts +21 -9
  180. package/api/src/store/models/subscription.ts +21 -10
  181. package/api/src/store/models/tax-rate.ts +29 -21
  182. package/api/src/store/models/usage-record.ts +11 -2
  183. package/api/src/store/models/webhook-attempt.ts +18 -9
  184. package/api/src/store/models/webhook-endpoint.ts +18 -9
  185. package/api/src/store/scoped-core.ts +55 -0
  186. package/api/src/store/scoped.ts +247 -0
  187. package/api/src/store/sequelize.ts +82 -23
  188. package/api/src/store/sql-migrations.ts +20 -0
  189. package/api/src/store/tenant-backfill.ts +260 -0
  190. package/api/src/store/tenant-model.ts +124 -0
  191. package/api/src/store/tenant-tables.ts +50 -0
  192. package/api/tests/bootstrap/bootstrap.spec.ts +162 -0
  193. package/api/tests/crons/tenant-fanout.spec.ts +158 -0
  194. package/api/tests/embedded/embedded-multi-mode-d3.spec.ts +257 -0
  195. package/api/tests/fixtures/bare-query-violation.ts +13 -0
  196. package/api/tests/fixtures/core-env-violation.ts +10 -0
  197. package/api/tests/fixtures/host-read-violation.ts +19 -0
  198. package/api/tests/fixtures/tenants.ts +4 -0
  199. package/api/tests/integrations/iap-tenant.spec.ts +284 -0
  200. package/api/tests/libs/archive-query.spec.ts +26 -0
  201. package/api/tests/libs/audit-tenant.spec.ts +153 -0
  202. package/api/tests/libs/context.spec.ts +204 -0
  203. package/api/tests/libs/core-config.spec.ts +115 -0
  204. package/api/tests/libs/cron-driver-d2.spec.ts +237 -0
  205. package/api/tests/libs/crons-conservation-d2.spec.ts +52 -0
  206. package/api/tests/libs/did-connect-runtime-js.spec.ts +98 -0
  207. package/api/tests/libs/did-connect-tenant-identity.spec.ts +159 -0
  208. package/api/tests/libs/lock-tenant.spec.ts +66 -0
  209. package/api/tests/libs/scoped.spec.ts +222 -0
  210. package/api/tests/libs/secrets-facade.spec.ts +52 -0
  211. package/api/tests/libs/service-host.spec.ts +37 -0
  212. package/api/tests/libs/tenancy-slot-authority.spec.ts +209 -0
  213. package/api/tests/libs/tenant-middleware.spec.ts +42 -0
  214. package/api/tests/libs/tenant-scanner.spec.ts +120 -0
  215. package/api/tests/middlewares/hono/cdn.spec.ts +70 -0
  216. package/api/tests/middlewares/hono/context.spec.ts +113 -0
  217. package/api/tests/middlewares/hono/csrf.spec.ts +136 -0
  218. package/api/tests/middlewares/hono/fallback.spec.ts +67 -0
  219. package/api/tests/middlewares/hono/pipeline.spec.ts +47 -0
  220. package/api/tests/middlewares/hono/security.spec.ts +181 -0
  221. package/api/tests/middlewares/hono/session.spec.ts +42 -0
  222. package/api/tests/middlewares/hono/xss.spec.ts +81 -0
  223. package/api/tests/models/tenant-backfill.spec.ts +287 -0
  224. package/api/tests/models/tenant-columns-model.spec.ts +46 -0
  225. package/api/tests/models/tenant-columns.spec.ts +161 -0
  226. package/api/tests/queues/credit-consume-batch.spec.ts +8 -1
  227. package/api/tests/queues/credit-consume.spec.ts +8 -1
  228. package/api/tests/queues/event-tenant.spec.ts +292 -0
  229. package/api/tests/queues/exchange-rate-health-tenant-d6.spec.ts +62 -0
  230. package/api/tests/queues/queue-parity.spec.ts +249 -0
  231. package/api/tests/queues/queue-runtime-surface.spec.ts +277 -0
  232. package/api/tests/queues/queue-teardown-d2.spec.ts +127 -0
  233. package/api/tests/queues/tenant-matrix-a.spec.ts +245 -0
  234. package/api/tests/queues/tenant-matrix-b.spec.ts +168 -0
  235. package/api/tests/routes/connect/hono-attach.spec.ts +107 -0
  236. package/api/tests/service/collapse.spec.ts +96 -0
  237. package/api/tests/service/didconnect-storage-slot.spec.ts +60 -0
  238. package/api/tests/service/fail-closed-http.spec.ts +79 -0
  239. package/api/tests/service/static-arc-handler.spec.ts +101 -0
  240. package/api/tests/service/static-externalized.spec.ts +48 -0
  241. package/api/tests/store/tenant-crosscut.spec.ts +202 -0
  242. package/api/tests/store/tenant-model-spike.spec.ts +177 -0
  243. package/api/tests/store/tenant-model.spec.ts +162 -0
  244. package/api/tests/store/tenant-residual.spec.ts +196 -0
  245. package/api/third.d.ts +4 -0
  246. package/blocklet.yml +1 -1
  247. package/cloudflare/MIGRATION-RUNBOOK.md +3 -8
  248. package/cloudflare/README.md +34 -27
  249. package/cloudflare/STAGING-MIGRATION-GUIDE.md +3 -15
  250. package/cloudflare/build.ts +33 -13
  251. package/cloudflare/cf-adapter.ts +419 -0
  252. package/cloudflare/did-connect-runtime.ts +96 -0
  253. package/cloudflare/did-connect-token-storage.ts +151 -0
  254. package/cloudflare/esbuild-cf-config.cjs +407 -0
  255. package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
  256. package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
  257. package/cloudflare/migrations/0008_schema_parity.sql +16 -0
  258. package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
  259. package/cloudflare/queue-runtime-mode.ts +13 -0
  260. package/cloudflare/run-build.js +33 -403
  261. package/cloudflare/scripts/cf-package-import-probe.mjs +90 -0
  262. package/cloudflare/scripts/didconnect-mock-smoke.mjs +140 -0
  263. package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
  264. package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
  265. package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
  266. package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
  267. package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
  268. package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
  269. package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +16 -1
  270. package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +18 -3
  271. package/cloudflare/shims/cron.ts +38 -158
  272. package/cloudflare/shims/events.ts +124 -0
  273. package/cloudflare/shims/fastq.ts +15 -1
  274. package/cloudflare/shims/nedb-storage.ts +16 -8
  275. package/cloudflare/shims/xss.ts +8 -0
  276. package/cloudflare/tenant-middleware.ts +36 -0
  277. package/cloudflare/tests/cf-adapter.spec.ts +244 -0
  278. package/cloudflare/tests/did-connect-token-storage.spec.ts +105 -0
  279. package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
  280. package/cloudflare/tests/worker-handler-gate.spec.ts +69 -0
  281. package/cloudflare/vite.config.ts +53 -45
  282. package/cloudflare/worker.ts +261 -448
  283. package/cloudflare/wrangler.json +0 -6
  284. package/cloudflare/wrangler.jsonc +0 -6
  285. package/cloudflare/wrangler.local-e2e.jsonc +25 -0
  286. package/cloudflare/wrangler.staging.json +0 -6
  287. package/jest.config.js +3 -1
  288. package/package.json +33 -38
  289. package/scripts/bootstrap-inject.ts +166 -0
  290. package/scripts/core-env-whitelist.json +1 -0
  291. package/scripts/e2e-12b-runtime.ts +149 -0
  292. package/scripts/e2e-core-config.ts +125 -0
  293. package/scripts/e2e-d1-tenancy.ts +116 -0
  294. package/scripts/e2e-d2-cron-queue.ts +139 -0
  295. package/scripts/e2e-d3-embedded-multi.ts +171 -0
  296. package/scripts/e2e-hono-s2.ts +125 -0
  297. package/scripts/e2e-hono-s3e.ts +135 -0
  298. package/scripts/e2e-hono-s4.ts +114 -0
  299. package/scripts/e2e-migration-contract.ts +100 -0
  300. package/scripts/e2e-s0.ts +61 -0
  301. package/scripts/e2e-s1.ts +107 -0
  302. package/scripts/e2e-s2.ts +178 -0
  303. package/scripts/e2e-s3.ts +110 -0
  304. package/scripts/e2e-s4.ts +191 -0
  305. package/scripts/e2e-s5.ts +139 -0
  306. package/scripts/e2e-s6.ts +127 -0
  307. package/scripts/e2e-tenant-model.ts +119 -0
  308. package/scripts/e2e-tenant-worker.ts +199 -0
  309. package/scripts/gen-sql-migrations.js +46 -0
  310. package/scripts/phase8-codemod.js +219 -0
  311. package/scripts/phase9a-env-getters-codemod.js +82 -0
  312. package/scripts/scan-core-env.js +109 -0
  313. package/scripts/scan-tenant-queries.js +235 -0
  314. package/scripts/schema-drift-guard.ts +210 -0
  315. package/scripts/tenant-scan-whitelist.json +1 -0
  316. package/src/app.tsx +2 -1
  317. package/src/env.d.ts +13 -1
  318. package/src/libs/service-host.ts +13 -0
  319. package/tsconfig.json +1 -1
  320. package/vite.arc.config.ts +159 -0
  321. package/api/src/libs/did-space.ts +0 -235
  322. package/api/src/libs/middleware.ts +0 -50
  323. package/api/src/libs/security.ts +0 -192
  324. package/api/src/queues/space.ts +0 -662
  325. package/api/src/routes/credit-tokens.ts +0 -38
  326. package/api/src/routes/exchange-rates.ts +0 -87
  327. package/api/src/routes/index.ts +0 -142
  328. package/api/src/routes/integrations/stripe.ts +0 -61
  329. package/api/src/routes/meters.ts +0 -274
  330. package/api/src/routes/passports.ts +0 -68
  331. package/api/src/routes/redirect.ts +0 -20
  332. package/api/src/routes/tool.ts +0 -65
  333. package/api/src/routes/webhook-endpoints.ts +0 -126
  334. package/api/tests/routes/credit-grants.spec.ts +0 -1261
  335. package/cloudflare/did-connect-auth.ts +0 -527
  336. package/cloudflare/shims/did-space-js.ts +0 -17
  337. package/cloudflare/shims/did-space.ts +0 -11
  338. package/cloudflare/shims/express-compat/index.ts +0 -80
  339. package/cloudflare/shims/express-compat/types.ts +0 -41
  340. package/cloudflare/shims/lock.ts +0 -115
  341. package/cloudflare/shims/queue.ts +0 -611
  342. package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
  343. package/cloudflare/tests/shims/queue-scheduled.spec.ts +0 -186
@@ -0,0 +1,151 @@
1
+ // S3-CF (DID convergence) — the CF DID-Connect token store, tenant-aware.
2
+ //
3
+ // Carries forward the proven standalone-worker behavior (the `_did_connect_tokens`
4
+ // D1 table + first-primary read-your-writes + the `waitUntil` hack for the
5
+ // fire-and-forget `update` that did-connect-js's onProcessError performs) and ADDS
6
+ // per-tenant isolation: every record is stamped with the creating `instanceDid`
7
+ // (from the TenantContext), and read/update/delete/exist reject a token whose
8
+ // stored instanceDid != the current tenant's (treated as not-found). A token minted
9
+ // under tenant A can never be read/advanced under tenant B's host.
10
+ //
11
+ // Isolation lives in the record JSON (no schema migration): the existing `data`
12
+ // column already holds JSON, so we add an `instanceDid` field. Tokens are short-TTL
13
+ // ephemeral sessions, so older untagged rows simply read as not-found under a tenant
14
+ // once this ships — acceptable per the convergence plan (fail-closed, no migration).
15
+ import { EventEmitter } from 'events';
16
+
17
+ import { getInstanceDid } from '../api/src/libs/context';
18
+
19
+ interface TokenRecord {
20
+ token: string;
21
+ status?: string;
22
+ instanceDid?: string;
23
+ [key: string]: any;
24
+ }
25
+
26
+ export class CloudflareTenantTokenStorage extends EventEmitter {
27
+ private ttl: number;
28
+
29
+ constructor(options: { ttl?: number } = {}) {
30
+ super();
31
+ this.ttl = options.ttl ?? 300;
32
+ }
33
+
34
+ private _getDB() {
35
+ const env = (globalThis as any).__CF_ENV__;
36
+ const db = env?.DB;
37
+ if (!db) {
38
+ console.error('[D1TokenStore] DB not available — __CF_ENV__ missing or no DB binding');
39
+ return db;
40
+ }
41
+ return db.withSession('first-primary');
42
+ }
43
+
44
+ /** The tenant whose context this storage op runs under. Throws (fail-closed) in
45
+ * multi mode without an established context — the caller is misrouted. */
46
+ private _tenant(): string {
47
+ return getInstanceDid();
48
+ }
49
+
50
+ /** Read the raw row, enforcing tenant isolation: a record stamped with a
51
+ * different instanceDid is invisible (treated as not-found). */
52
+ private async _readScoped(token: string): Promise<TokenRecord | null> {
53
+ const db = this._getDB();
54
+ if (!db) return null;
55
+ const now = Math.floor(Date.now() / 1000);
56
+ const row = await db
57
+ .prepare('SELECT data FROM _did_connect_tokens WHERE token = ? AND expires_at > ?')
58
+ .bind(token, now)
59
+ .first();
60
+ if (!row) return null;
61
+ const record = JSON.parse(row.data as string) as TokenRecord;
62
+ // tenant isolation: untagged (legacy) or cross-tenant tokens are not-found.
63
+ if (record.instanceDid !== this._tenant()) return null;
64
+ return record;
65
+ }
66
+
67
+ async create(token: string, status = 'created') {
68
+ try {
69
+ const db = this._getDB();
70
+ if (!db) throw new Error('DB not available');
71
+ const record: TokenRecord = { token, status, instanceDid: this._tenant() };
72
+ const expiresAt = Math.floor(Date.now() / 1000) + this.ttl;
73
+ await db
74
+ .prepare('INSERT OR REPLACE INTO _did_connect_tokens (token, data, expires_at) VALUES (?, ?, ?)')
75
+ .bind(token, JSON.stringify(record), expiresAt)
76
+ .run();
77
+ this.emit('create', record);
78
+ return record;
79
+ } catch (err: any) {
80
+ console.error('[D1TokenStore] create failed:', token, err?.message || err);
81
+ throw err;
82
+ }
83
+ }
84
+
85
+ async read(token: string) {
86
+ try {
87
+ return await this._readScoped(token);
88
+ } catch (err: any) {
89
+ console.error('[D1TokenStore] read failed:', token, err?.message || err);
90
+ return null;
91
+ }
92
+ }
93
+
94
+ update(token: string, updates: Record<string, any>) {
95
+ // did-connect-js's onProcessError calls tokenStorage.update WITHOUT awaiting
96
+ // (fire-and-forget). On workerd a non-awaited Promise is killed when the handler
97
+ // returns, so the UPDATE never lands and the token sticks at "scanned" forever
98
+ // (wallet UI loops on "validating…"). Register the write via ctx.waitUntil
99
+ // (exposed as __cfWaitUntil__) so the isolate stays alive until D1 acks,
100
+ // regardless of whether the caller awaits us. (Carried forward verbatim.)
101
+ const promise = (async () => {
102
+ try {
103
+ const existing = await this._readScoped(token); // tenant-scoped read
104
+ if (!existing) return null;
105
+ delete updates.token;
106
+ delete updates.instanceDid; // never let an update rewrite the owning tenant
107
+ const merged = { ...existing, ...updates };
108
+ const expiresAt = Math.floor(Date.now() / 1000) + this.ttl;
109
+ const db = this._getDB();
110
+ if (!db) throw new Error('DB not available');
111
+ await db
112
+ .prepare('UPDATE _did_connect_tokens SET data = ?, expires_at = ? WHERE token = ?')
113
+ .bind(JSON.stringify(merged), expiresAt, token)
114
+ .run();
115
+ this.emit('update', merged);
116
+ return merged;
117
+ } catch (err: any) {
118
+ console.error('[D1TokenStore] update failed:', token, err?.message || err);
119
+ throw err;
120
+ }
121
+ })();
122
+
123
+ const waitUntil = (globalThis as any).__cfWaitUntil__ as ((p: Promise<any>) => void) | undefined;
124
+ if (typeof waitUntil === 'function') {
125
+ waitUntil(promise.catch(() => {}));
126
+ }
127
+ return promise;
128
+ }
129
+
130
+ async delete(token: string) {
131
+ try {
132
+ const existing = await this._readScoped(token); // tenant-scoped
133
+ if (!existing) return; // cross-tenant / missing → no-op
134
+ this.emit('destroy', existing);
135
+ const db = this._getDB();
136
+ if (!db) return;
137
+ await db.prepare('DELETE FROM _did_connect_tokens WHERE token = ?').bind(token).run();
138
+ } catch (err: any) {
139
+ console.error('[D1TokenStore] delete failed:', token, err?.message || err);
140
+ }
141
+ }
142
+
143
+ async exist(token: string, did?: string) {
144
+ const record = await this._readScoped(token);
145
+ if (!record) return false;
146
+ if (did) return record.did === did;
147
+ return true;
148
+ }
149
+ }
150
+
151
+ export default CloudflareTenantTokenStorage;
@@ -0,0 +1,407 @@
1
+ // Shared CF Workers esbuild config — the ONE worker-safe alias/shim/plugin/banner
2
+ // table for the payment graph. Both consumers reuse it so the two build outputs
3
+ // can never drift (S3-CF plan "从源头消除 drift"):
4
+ //
5
+ // - run-build.js → bundles cloudflare/worker.ts into dist/worker.js
6
+ // (the standalone Payment Kit Worker; default export).
7
+ // - packages/payment-core/build-cf.mjs
8
+ // → bundles the runtime-neutral http.fetch adapter into
9
+ // @arcblock/payment-service/dist/cf.js (a LIBRARY: no
10
+ // default export — the consumer, arc, provides it).
11
+ //
12
+ // The whole point of the `./cf` artifact (S3-CF Phase 2 命门) is that it is a
13
+ // SELF-CONTAINED RE-BUNDLEABLE artifact: every npm/server dependency is inlined
14
+ // here behind these shims, so a downstream consumer (arc's worker build)
15
+ // re-bundles dist/cf.js with ZERO alias / ZERO define / ZERO external of its own.
16
+ // Only `node:*` builtins (CF nodejs_compat) + `cloudflare:*` (worker runtime)
17
+ // remain as imports, which every Workers host already provides.
18
+
19
+ const path = require('path');
20
+
21
+ const cfDir = __dirname;
22
+ const s = (f) => path.resolve(cfDir, f);
23
+
24
+ // Plugin to neutralize rolldown-generated `__require(import.meta.url)` helpers
25
+ // that ship inside npm packages built with rolldown (e.g. @ocap/message,
26
+ // @arcblock/did-connect-js). These helpers use `createRequire(import.meta.url)`
27
+ // at module init to pull in CJS deps like `google-protobuf`, `debug`, etc. —
28
+ // which neither resolve nor work in the CF Workers runtime.
29
+ //
30
+ // The downstream patches/shims that use these require calls are all either:
31
+ // - monkey-patches for edge cases Payment Kit doesn't exercise, or
32
+ // - debug()/logger() factories that Payment Kit doesn't need on CF.
33
+ //
34
+ // Replace every `_virtual/rolldown_runtime.mjs` with a stub whose `__require`
35
+ // returns a Proxy that swallows further property accesses + function calls,
36
+ // and whose `__commonJSMin` returns an empty-module factory. This lets the
37
+ // importing modules finish loading without crashing the worker at startup.
38
+ const rolldownRuntimeStub = `
39
+ // After the Phase 2 CBOR switch (payment-method.ts + did-connect-auth.ts
40
+ // moved off @ocap/client/legacy), no codepath in the worker calls
41
+ // __require('google-protobuf') at runtime. The CBOR-only @ocap/client
42
+ // default entry + @ocap/client/encode use plain ESM imports for their
43
+ // deps. Any remaining __require calls in Rolldown-compiled packages
44
+ // (debug, @arcblock/event-hub, etc.) are handled by the __noop Proxy
45
+ // below — they don't need real modules for payment-kit's flows.
46
+ const __requireMap = {};
47
+ const __noopTarget = function(){};
48
+ const __noopHandler = {
49
+ get(t, p) {
50
+ if (p === Symbol.toPrimitive || p === 'toString') return () => '';
51
+ if (p === 'default') return new Proxy(__noopTarget, __noopHandler);
52
+ return new Proxy(__noopTarget, __noopHandler);
53
+ },
54
+ apply() { return new Proxy(__noopTarget, __noopHandler); },
55
+ construct() { return new Proxy(__noopTarget, __noopHandler); },
56
+ };
57
+ const __noop = new Proxy(__noopTarget, __noopHandler);
58
+ export const __commonJSMin = function(cb){
59
+ return function(){
60
+ var m = { exports: {} };
61
+ try { cb(m.exports, m); } catch (_) {}
62
+ return m.exports;
63
+ };
64
+ };
65
+ export const __require = function(id){
66
+ if (__requireMap[id]) return __requireMap[id];
67
+ return __noop;
68
+ };
69
+ export const __exportAll = function(target, source){
70
+ if (source) {
71
+ try {
72
+ for (var key in source) {
73
+ if (key !== 'default' && !Object.prototype.hasOwnProperty.call(target, key)) {
74
+ Object.defineProperty(target, key, {
75
+ get: function() { return source[key]; },
76
+ enumerable: true,
77
+ configurable: true,
78
+ });
79
+ }
80
+ }
81
+ } catch (_) {}
82
+ }
83
+ return target;
84
+ };
85
+ export const __toESM = function(mod){ return mod && mod.__esModule ? mod : { default: mod }; };
86
+ export const __toCommonJS = function(mod){ return mod; };
87
+ export const __copyProps = function(target){ return target; };
88
+ export default { __commonJSMin, __require, __exportAll, __toESM, __toCommonJS, __copyProps };
89
+ `;
90
+ const rolldownRuntimeNoopPlugin = {
91
+ name: 'rolldown-runtime-noop',
92
+ setup(build) {
93
+ // Catch any import that resolves to a `_virtual/rolldown_runtime.mjs`
94
+ // file, regardless of which package it comes from.
95
+ build.onResolve({ filter: /_virtual\/rolldown_runtime\.mjs$/ }, (args) => {
96
+ return { path: args.path, namespace: 'rolldown-runtime-noop' };
97
+ });
98
+ build.onLoad({ filter: /.*/, namespace: 'rolldown-runtime-noop' }, () => ({
99
+ contents: rolldownRuntimeStub,
100
+ loader: 'js',
101
+ // Need a resolveDir so the virtual stub's `import "google-protobuf"` resolves
102
+ // against the workspace's node_modules. Pointing at cfDir is sufficient since
103
+ // pnpm hoists google-protobuf up to the repo root node_modules.
104
+ resolveDir: cfDir,
105
+ }));
106
+ },
107
+ };
108
+
109
+ // Plugin: fix lodash sub-path CJS/ESM interop
110
+ // The "lodash" → "lodash-es" alias also redirects require('lodash/camelCase')
111
+ // to lodash-es/camelCase (ESM). CJS consumers get { __esModule, default: fn }
112
+ // instead of the function itself, causing "_m is not a function" at runtime.
113
+ // Fix: intercept lodash-es sub-path imports from CJS contexts and generate a
114
+ // virtual wrapper that re-exports the default as module.exports.
115
+ const lodashSubpathPlugin = {
116
+ name: 'lodash-subpath-interop',
117
+ setup(build) {
118
+ // Intercept resolved lodash-es sub-path imports that come from require() calls
119
+ // Intercept CJS require('lodash/xxx') — the alias hasn't applied yet at this stage
120
+ build.onResolve({ filter: /^lodash\/.+/ }, (args) => {
121
+ if (args.kind === 'require-call') {
122
+ // Convert lodash/xxx → lodash-es/xxx and wrap for CJS compat
123
+ const esPath = args.path.replace(/^lodash\//, 'lodash-es/');
124
+ return {
125
+ path: esPath,
126
+ namespace: 'lodash-cjs-compat',
127
+ };
128
+ }
129
+ });
130
+ build.onLoad({ filter: /.*/, namespace: 'lodash-cjs-compat' }, (args) => {
131
+ // Resolve the actual file path, then read and re-export as CJS.
132
+ // By loading the original ESM source as 'js' with CJS-style wrapping,
133
+ // esbuild treats the result as CJS, avoiding the __toModule interop.
134
+ const subPath = args.path.replace('lodash-es/', '');
135
+ const filePath = require.resolve(`lodash-es/${subPath}`);
136
+ const source = require('fs').readFileSync(filePath, 'utf8');
137
+ // Transform: replace ESM export default with module.exports
138
+ // lodash-es modules all follow: import deps... ; function fn(...){...}; export default fn;
139
+ const transformed = source
140
+ .replace(/^export default /m, 'module.exports = ')
141
+ .replace(/^export\s*\{[^}]*\}\s*;?\s*$/m, '');
142
+ return {
143
+ contents: transformed,
144
+ loader: 'js',
145
+ resolveDir: require('path').dirname(filePath),
146
+ };
147
+ });
148
+ },
149
+ };
150
+
151
+ // Plugin: redirect bare `@arcblock/did-util` and `@ocap/message` imports to their
152
+ // CBOR-only subpath entries, and noop `@arcblock/did-util/protobuf`. This strips
153
+ // the protobuf runtime (`@ocap/proto/runtime`, `google-protobuf`, `*_pb.js`) out
154
+ // of the CF Workers bundle. Only matches EXACT bare specifiers — subpath imports
155
+ // (e.g. `@arcblock/did-util/cbor`) pass through untouched.
156
+ const cborOnlyPlugin = {
157
+ name: 'cbor-only-redirect',
158
+ setup(build) {
159
+ build.onResolve({ filter: /^@arcblock\/did-util$/ }, () => ({
160
+ path: path.resolve(cfDir, '../../..', 'node_modules/@arcblock/did-util/esm/cbor.mjs'),
161
+ }));
162
+ build.onResolve({ filter: /^@ocap\/message$/ }, () => ({
163
+ path: path.resolve(cfDir, '../../..', 'node_modules/@ocap/message/esm/cbor.mjs'),
164
+ }));
165
+ build.onResolve({ filter: /^@arcblock\/did-util\/protobuf$/ }, () => ({
166
+ path: s('shims/noop.ts'),
167
+ }));
168
+ },
169
+ };
170
+
171
+ // Plugin: noop entire package trees that have sub-path imports (alias alone
172
+ // doesn't work because esbuild treats "axon" alias as prefix, breaking
173
+ // "axon/lib/plugins/queue"). This plugin intercepts bare + sub-path imports.
174
+ const noopPackagesPlugin = {
175
+ name: 'noop-packages',
176
+ setup(build) {
177
+ const packages = ['axon', '@arcblock/ws', '@arcblock/event-hub', 'graphql', 'follow-redirects', 'proxy-from-env'];
178
+ const filter = new RegExp('^(' + packages.join('|') + ')(\\/|$)');
179
+ build.onResolve({ filter }, () => ({ path: s('shims/noop.ts') }));
180
+ },
181
+ };
182
+
183
+ // Plugin: drop ethers' non-English BIP39 wordlists (~70K dead weight). The payment
184
+ // worker never uses Mnemonic/HD wallets (0 source refs to Mnemonic/HDNode/wordlist),
185
+ // so the 8 non-English word tables never execute. ethers' own /dist build strips
186
+ // these too (~80kb). Keep LangEn (Mnemonic default). Stub the rest with a static
187
+ // wordlist() returning null so wordlists.js's top-level LangXx.wordlist() calls
188
+ // (run at module init) don't crash.
189
+ const dropEthersWordlistsPlugin = {
190
+ name: 'drop-ethers-wordlists',
191
+ setup(build) {
192
+ build.onLoad({ filter: /ethers\/lib\.esm\/wordlists\/lang-(cz|es|fr|ja|ko|it|pt|zh)\.js$/ }, (args) => {
193
+ const lang = /lang-(\w+)\.js$/.exec(args.path)[1];
194
+ const cls = 'Lang' + lang.charAt(0).toUpperCase() + lang.slice(1);
195
+ return { contents: `export class ${cls} { static wordlist() { return null; } }`, loader: 'js' };
196
+ });
197
+ },
198
+ };
199
+
200
+ // The worker-safe alias table: every Node/server dependency the payment graph
201
+ // reaches is redirected to a CF Workers-safe shim or a tree-shakeable ESM build.
202
+ const alias = {
203
+ // axios → lightweight fetch-based shim (115KB → ~2KB)
204
+ axios: s('shims/axios-lite.ts'),
205
+
206
+ // node-fetch → native fetch (drops encoding/tr46/whatwg-url polyfill ~754KB
207
+ // pulled in by @apple/app-store-server-library; dead weight on CF Workers)
208
+ 'node-fetch': s('shims/node-fetch.ts'),
209
+
210
+ // Stripe — wrap constructor to use fetch HTTP client in CF Workers
211
+ stripe: s('shims/stripe-cf.ts'),
212
+ __real_stripe__: require.resolve('stripe'),
213
+
214
+ // @ocap/message ships a patch.mjs that monkey-patches google-protobuf at
215
+ // module init. google-protobuf isn't available in CF Workers (no filesystem
216
+ // for createRequire to resolve), and Payment Kit doesn't use the features
217
+ // that patch touches. Replace with a noop so the import chain stays alive
218
+ // but the patch is skipped. Same for the rolldown_runtime helper that
219
+ // relies on createRequire(import.meta.url).
220
+ '@ocap/message/esm/patch.mjs': s('shims/noop.ts'),
221
+ '@ocap/message/esm/_virtual/rolldown_runtime.mjs': s('shims/noop.ts'),
222
+
223
+ sequelize: s('shims/sequelize-d1/index.ts'),
224
+ sqlite3: s('shims/noop.ts'),
225
+ 'cls-hooked': s('shims/noop.ts'),
226
+ 'express-async-errors': s('shims/noop.ts'),
227
+ cors: s('shims/cors.ts'),
228
+ 'cookie-parser': s('shims/cookie-parser.ts'),
229
+ '@blocklet/sdk/lib/middlewares/fallback': s('shims/blocklet-sdk/fallback.ts'),
230
+ '@blocklet/sdk/lib/middlewares/cdn': s('shims/blocklet-sdk/cdn.ts'),
231
+ '@blocklet/sdk/lib/middlewares/session': s('shims/blocklet-sdk/session.ts'),
232
+ '@blocklet/sdk/lib/middlewares': s('shims/blocklet-sdk/middlewares.ts'),
233
+ '@blocklet/sdk/lib/env': s('shims/blocklet-sdk/env.ts'),
234
+ '@blocklet/sdk/lib/config': s('shims/blocklet-sdk/config.ts'),
235
+ '@blocklet/sdk/lib/component': s('shims/blocklet-sdk/component.ts'),
236
+ '@blocklet/sdk/lib/wallet': s('shims/blocklet-sdk/wallet.ts'),
237
+ '@blocklet/sdk/lib/wallet-authenticator': s('shims/blocklet-sdk/wallet-authenticator.ts'),
238
+ '@blocklet/sdk/lib/wallet-handler': s('shims/blocklet-sdk/wallet-handler.ts'),
239
+ '@blocklet/sdk/lib/security': s('shims/blocklet-sdk/security.ts'),
240
+ '@blocklet/sdk/lib/util/verify-sign': s('shims/blocklet-sdk/verify-sign.ts'),
241
+ '@blocklet/sdk/lib/util/verify-session': s('shims/blocklet-sdk/verify-session.ts'),
242
+ '@blocklet/sdk/lib/util/component-api': s('shims/blocklet-sdk/component-api.ts'),
243
+ // S3-CF Phase 1 ②: the broad "@blocklet/sdk" alias above also captures these
244
+ // util/* sub-paths (esbuild alias matches sub-paths), mangling them to
245
+ // ".../index.ts/lib/util/*". The hono app-shell pipeline (csrf/cdn) + the
246
+ // sessionMiddleware reach them, so the worker bundle must resolve each one:
247
+ // - csrf + wallet: pass through to the REAL worker-safe modules (util/csrf is
248
+ // crypto-only; util/wallet is zero-dep). The converged single http.fetch
249
+ // runs the full pipeline on the worker, so csrf must REALLY protect write
250
+ // routes — a dead stub would silently disable csrf (plan ② "直通真模块").
251
+ '@blocklet/sdk/lib/util/csrf': require.resolve('@blocklet/sdk/lib/util/csrf'),
252
+ '@blocklet/sdk/lib/util/wallet': require.resolve('@blocklet/sdk/lib/util/wallet'),
253
+ // - asset-host-transformer (cdn, inert on JSON), login (verbatim string
254
+ // checks), service-api (blacklist-off stub): existing worker-safe shims.
255
+ '@blocklet/sdk/lib/util/asset-host-transformer': s('shims/blocklet-sdk/asset-host-transformer.ts'),
256
+ '@blocklet/sdk/lib/util/login': s('shims/blocklet-sdk/login.ts'),
257
+ '@blocklet/sdk/lib/util/service-api': s('shims/blocklet-sdk/service-api.ts'),
258
+ '@blocklet/sdk/lib/error-handler': s('shims/noop.ts'),
259
+ '@blocklet/sdk/lib/did': s('shims/blocklet-sdk/did.ts'),
260
+ '@blocklet/sdk/lib/types/notification': s('shims/noop.ts'),
261
+ '@blocklet/sdk/service/notification': s('shims/blocklet-sdk/notification.ts'),
262
+ '@blocklet/sdk/service/eventbus': s('shims/blocklet-sdk/eventbus.ts'),
263
+ '@blocklet/sdk/service/auth': s('shims/blocklet-sdk/auth-service.ts'),
264
+ '@blocklet/sdk/service/blocklet': s('shims/blocklet-sdk/auth-service.ts'),
265
+ '@blocklet/sdk': s('shims/blocklet-sdk/index.ts'),
266
+ '@blocklet/xss': s('shims/xss.ts'),
267
+ '@blocklet/error': s('shims/error.ts'),
268
+ '@blocklet/logger': s('shims/blocklet-sdk/logger.ts'),
269
+ '@blocklet/payment-vendor': s('shims/payment-vendor.ts'),
270
+ '@arcblock/did-connect-storage-nedb': s('shims/nedb-storage.ts'),
271
+ '@abtnode/cron': s('shims/cron.ts'),
272
+ 'dotenv-flow': s('shims/noop.ts'),
273
+ fastq: s('shims/fastq.ts'),
274
+
275
+ // Bundle size optimizations — lodash base import aliased to lodash-es for tree-shaking.
276
+ // Sub-path imports (lodash/camelCase etc.) handled by lodashSubpathPlugin below.
277
+ lodash: 'lodash-es', // 357KB CJS → tree-shakeable ESM
278
+ esprima: s('shims/noop.ts'), // 215KB — only used by @ocap/contract, not called in payment-kit
279
+ mustache: s('shims/noop.ts'), // 16KB — template engine, not used in payment-kit
280
+ 'mime-types': s('shims/mime-types.ts'), // 150KB — lightweight shim with common MIME types
281
+ 'mime-db': s('shims/noop.ts'),
282
+ ws: s('shims/ws-lite.ts'), // 66KB — native WebSocket wrapper for CF Workers
283
+ 'crypto-js': s('shims/crypto-js-warn.ts'), // 115KB — AES legacy not used, warns if called
284
+ 'crypto-js/aes': s('shims/crypto-js-warn.ts'),
285
+ 'crypto-js/enc-base64': s('shims/noop.ts'),
286
+ 'crypto-js/enc-hex': s('shims/noop.ts'),
287
+ 'crypto-js/enc-latin1': s('shims/noop.ts'),
288
+ 'crypto-js/enc-utf8': s('shims/noop.ts'),
289
+ 'crypto-js/enc-utf16': s('shims/noop.ts'),
290
+
291
+ // Force ESM-only to avoid CJS+ESM double-bundling
292
+ valibot: path.resolve(cfDir, '../../..', 'node_modules/valibot/dist/index.mjs'), // 396KB → ~200KB
293
+ // CF Workers: noop modules not useful in Workers environment
294
+ phoenix: s('shims/noop.ts'), // 36KB — Phoenix channels, only used by @arcblock/ws
295
+ numbro: s('shims/noop.ts'), // 49KB — number formatting, replaced inline in util.ts
296
+
297
+ // Node built-in shims (not fully supported in CF Workers nodejs_compat)
298
+ os: s('shims/node-os.ts'),
299
+ 'node:os': s('shims/node-os.ts'),
300
+ tty: s('shims/node-tty.ts'),
301
+ 'node:tty': s('shims/node-tty.ts'),
302
+ http: s('shims/node-http.ts'),
303
+ 'node:http': s('shims/node-http.ts'),
304
+ https: s('shims/node-https.ts'),
305
+ 'node:https': s('shims/node-https.ts'),
306
+ http2: s('shims/node-http.ts'),
307
+ 'node:http2': s('shims/node-http.ts'),
308
+ net: s('shims/node-net.ts'),
309
+ 'node:net': s('shims/node-net.ts'),
310
+ tls: s('shims/node-misc.ts'),
311
+ 'node:tls': s('shims/node-misc.ts'),
312
+ fs: s('shims/node-fs.ts'),
313
+ 'node:fs': s('shims/node-fs.ts'),
314
+ cluster: s('shims/node-misc.ts'),
315
+ 'node:cluster': s('shims/node-misc.ts'),
316
+ zlib: s('shims/node-zlib.ts'),
317
+ 'node:zlib': s('shims/node-zlib.ts'),
318
+ child_process: s('shims/node-child-process.ts'),
319
+ 'node:child_process': s('shims/node-child-process.ts'),
320
+ bufferutil: s('shims/noop.ts'),
321
+ 'utf-8-validate': s('shims/noop.ts'),
322
+ dns: s('shims/noop.ts'),
323
+ 'node:dns': s('shims/noop.ts'),
324
+ pg: s('shims/noop.ts'),
325
+ postgres: s('shims/noop.ts'),
326
+ };
327
+
328
+ // The require()-polyfill + timer-deferral banner. Every CF bundle (worker OR the
329
+ // re-bundleable ./cf library) needs these globals installed before the payment
330
+ // graph's module-init code runs, so the banner is shared. When the ./cf artifact
331
+ // is re-bundled by arc, this banner code is already inlined into dist/cf.js and
332
+ // runs at import — no consumer banner needed.
333
+ const banner = {
334
+ js: [
335
+ '// Polyfill require() for CJS modules that dynamically require Node builtins',
336
+ 'import __nodeCrypto from "node:crypto";',
337
+ 'import __nodeBuffer from "node:buffer";',
338
+ 'import __nodeEvents from "node:events";',
339
+ 'import __nodeStream from "node:stream";',
340
+ 'import __nodeUtil from "node:util";',
341
+ 'import __nodeAssert from "node:assert";',
342
+ 'import __nodePath from "node:path";',
343
+ 'import __nodeUrl from "node:url";',
344
+ 'import __nodeProcess from "node:process";',
345
+ 'const __qsShim = { stringify: function(o) { return new URLSearchParams(o).toString(); }, parse: function(s) { return Object.fromEntries(new URLSearchParams(s).entries()); } };',
346
+ 'const __nodeModules = { crypto: __nodeCrypto, buffer: __nodeBuffer, events: __nodeEvents, stream: __nodeStream, util: __nodeUtil, assert: __nodeAssert, path: __nodePath, url: __nodeUrl, process: __nodeProcess, querystring: __qsShim };',
347
+ '// Accept both "xxx" and "node:xxx" specifier forms; return empty stub for unknown modules',
348
+ '// (some deps tree-shake to nothing but still call require() at init — a hard throw crashes the worker).',
349
+ 'globalThis.require = globalThis.require || function(m) { var key = typeof m === "string" && m.indexOf("node:") === 0 ? m.slice(5) : m; if (__nodeModules[key]) return __nodeModules[key]; console.warn("[require shim] unknown module: " + m); return {}; };',
350
+ '// Ensure process.stderr.fd exists for debug/supports-color',
351
+ 'if (typeof process !== "undefined") { if (!process.stderr) process.stderr = { fd: 2, write: function(){} }; else if (process.stderr.fd === undefined) process.stderr.fd = 2; if (!process.stdout) process.stdout = { fd: 1, write: function(){} }; else if (process.stdout.fd === undefined) process.stdout.fd = 1; }',
352
+ '// Polyfill process.on/process.exit for modules that use them at init',
353
+ 'if (typeof process !== "undefined" && !process.on) { process.on = function(){}; process.once = function(){}; process.off = function(){}; process.removeListener = function(){}; process.emit = function(){}; process.exit = function(){}; }',
354
+ '// CF Workers: defer timers called during global scope init until first request',
355
+ 'var __deferredTimers = []; var __timersReady = false;',
356
+ 'globalThis.__flushDeferredTimers = function() { if (__timersReady) return; __timersReady = true; var q = __deferredTimers; __deferredTimers = []; q.forEach(function(entry) { try { entry.fn.apply(null, entry.args); } catch(e) { console.error("deferred timer error:", e); } }); };',
357
+ 'var _origSetTimeout = globalThis.setTimeout; globalThis.setTimeout = function() { if (!__timersReady) { var args = arguments; var fn = args[0]; __deferredTimers.push({fn: function(){ _origSetTimeout.apply(globalThis, args); }, args: []}); return { unref: function(){}, ref: function(){}, [Symbol.toPrimitive]: function(){ return 0; } }; } var id = _origSetTimeout.apply(this, arguments); if (typeof id === "number") { return { unref: function(){}, ref: function(){}, [Symbol.toPrimitive]: function(){ return id; } }; } if (id && !id.unref) id.unref = function(){}; return id; };',
358
+ 'var _origSetInterval = globalThis.setInterval; globalThis.setInterval = function() { if (!__timersReady) { var args = arguments; __deferredTimers.push({fn: function(){ _origSetInterval.apply(globalThis, args); }, args: []}); return { unref: function(){}, ref: function(){}, [Symbol.toPrimitive]: function(){ return 0; } }; } var id = _origSetInterval.apply(this, arguments); if (typeof id === "number") { return { unref: function(){}, ref: function(){}, [Symbol.toPrimitive]: function(){ return id; } }; } if (id && !id.unref) id.unref = function(){}; return id; };',
359
+ 'var _origSetImmediate = globalThis.setImmediate; if (_origSetImmediate) { globalThis.setImmediate = function() { if (!__timersReady) { var args = arguments; __deferredTimers.push({fn: function(){ _origSetImmediate.apply(globalThis, args); }, args: []}); return { unref: function(){}, ref: function(){} }; } return _origSetImmediate.apply(this, arguments); }; } else { globalThis.setImmediate = function(fn) { if (!__timersReady) { __deferredTimers.push({fn: function(){ _origSetTimeout(fn, 0); }, args: []}); return { unref: function(){}, ref: function(){} }; } return _origSetTimeout(fn, 0); }; }',
360
+ 'if (typeof process !== "undefined") { var _origNextTick = process.nextTick; if (_origNextTick) { process.nextTick = function() { if (!__timersReady) { var args = Array.prototype.slice.call(arguments); var fn = args.shift(); __deferredTimers.push({fn: function(){ _origNextTick.apply(process, [fn].concat(args)); }, args: []}); return; } return _origNextTick.apply(process, arguments); }; } else { process.nextTick = function(fn) { if (!__timersReady) { __deferredTimers.push({fn: function(){ _origSetTimeout(fn, 0); }, args: []}); return; } _origSetTimeout(fn, 0); }; } }',
361
+ ].join('\n'),
362
+ };
363
+
364
+ /**
365
+ * Build the shared esbuild options object for a CF payment bundle.
366
+ *
367
+ * @param {object} opts
368
+ * @param {string[]|Record<string,string>} opts.entryPoints
369
+ * @param {string} opts.outdir
370
+ * @param {string} [opts.outExtension] — e.g. { '.js': '.js' }
371
+ * @param {boolean} [opts.metafile=true]
372
+ * @returns esbuild build options
373
+ */
374
+ function buildCfEsbuildOptions({ entryPoints, outdir, metafile = true }) {
375
+ return {
376
+ entryPoints,
377
+ bundle: true,
378
+ format: 'esm',
379
+ platform: 'node',
380
+ target: 'esnext',
381
+ outdir,
382
+ minify: true,
383
+ sourcemap: true,
384
+ metafile,
385
+ mainFields: ['module', 'main'],
386
+ plugins: [noopPackagesPlugin, rolldownRuntimeNoopPlugin, lodashSubpathPlugin, dropEthersWordlistsPlugin],
387
+ external: ['cloudflare:*', '__STATIC_CONTENT_MANIFEST'],
388
+ // Give import.meta.url a stable fallback so bundled deps that call
389
+ // createRequire(import.meta.url) at module init don't throw at worker
390
+ // startup. The polyfill in banner handles any legitimate require() lookups.
391
+ define: {
392
+ 'import.meta.url': '"file:///worker.js"',
393
+ },
394
+ banner,
395
+ alias,
396
+ logLevel: 'warning',
397
+ };
398
+ }
399
+
400
+ module.exports = {
401
+ cfDir,
402
+ alias,
403
+ banner,
404
+ buildCfEsbuildOptions,
405
+ // exported for completeness / potential reuse; not all consumers need them
406
+ plugins: { rolldownRuntimeNoopPlugin, lodashSubpathPlugin, cborOnlyPlugin, noopPackagesPlugin, dropEthersWordlistsPlugin },
407
+ };
@@ -0,0 +1,46 @@
1
+ -- Payment Kit: tenant columns (Phase 1, W1-1a)
2
+ -- Adds a nullable instance_did column to all 38 tenant tables.
3
+ -- Mirrors blocklets/core/api/src/store/migrations/20260610-tenant-columns.ts.
4
+ -- No constraints / indexes / backfill here — those land in 0007 (Phase 2).
5
+ --
6
+ -- NOTE: wrangler tracks applied migrations in `d1_migrations` by filename,
7
+ -- so this file is applied exactly once via `wrangler d1 migrations apply`.
8
+
9
+ ALTER TABLE customers ADD COLUMN instance_did VARCHAR(64);
10
+ ALTER TABLE products ADD COLUMN instance_did VARCHAR(64);
11
+ ALTER TABLE prices ADD COLUMN instance_did VARCHAR(64);
12
+ ALTER TABLE pricing_tables ADD COLUMN instance_did VARCHAR(64);
13
+ ALTER TABLE payment_methods ADD COLUMN instance_did VARCHAR(64);
14
+ ALTER TABLE checkout_sessions ADD COLUMN instance_did VARCHAR(64);
15
+ ALTER TABLE payment_intents ADD COLUMN instance_did VARCHAR(64);
16
+ ALTER TABLE payment_links ADD COLUMN instance_did VARCHAR(64);
17
+ ALTER TABLE setup_intents ADD COLUMN instance_did VARCHAR(64);
18
+ ALTER TABLE price_quotes ADD COLUMN instance_did VARCHAR(64);
19
+ ALTER TABLE subscriptions ADD COLUMN instance_did VARCHAR(64);
20
+ ALTER TABLE subscription_items ADD COLUMN instance_did VARCHAR(64);
21
+ ALTER TABLE subscription_schedules ADD COLUMN instance_did VARCHAR(64);
22
+ ALTER TABLE invoices ADD COLUMN instance_did VARCHAR(64);
23
+ ALTER TABLE invoice_items ADD COLUMN instance_did VARCHAR(64);
24
+ ALTER TABLE refunds ADD COLUMN instance_did VARCHAR(64);
25
+ ALTER TABLE credit_grants ADD COLUMN instance_did VARCHAR(64);
26
+ ALTER TABLE credit_transactions ADD COLUMN instance_did VARCHAR(64);
27
+ ALTER TABLE meters ADD COLUMN instance_did VARCHAR(64);
28
+ ALTER TABLE meter_events ADD COLUMN instance_did VARCHAR(64);
29
+ ALTER TABLE usage_records ADD COLUMN instance_did VARCHAR(64);
30
+ ALTER TABLE coupons ADD COLUMN instance_did VARCHAR(64);
31
+ ALTER TABLE promotion_codes ADD COLUMN instance_did VARCHAR(64);
32
+ ALTER TABLE discounts ADD COLUMN instance_did VARCHAR(64);
33
+ ALTER TABLE entitlements ADD COLUMN instance_did VARCHAR(64);
34
+ ALTER TABLE entitlement_grants ADD COLUMN instance_did VARCHAR(64);
35
+ ALTER TABLE entitlement_products ADD COLUMN instance_did VARCHAR(64);
36
+ ALTER TABLE events ADD COLUMN instance_did VARCHAR(64);
37
+ ALTER TABLE webhook_endpoints ADD COLUMN instance_did VARCHAR(64);
38
+ ALTER TABLE webhook_attempts ADD COLUMN instance_did VARCHAR(64);
39
+ ALTER TABLE payouts ADD COLUMN instance_did VARCHAR(64);
40
+ ALTER TABLE payment_stats ADD COLUMN instance_did VARCHAR(64);
41
+ ALTER TABLE revenue_snapshots ADD COLUMN instance_did VARCHAR(64);
42
+ ALTER TABLE auto_recharge_configs ADD COLUMN instance_did VARCHAR(64);
43
+ ALTER TABLE tax_rates ADD COLUMN instance_did VARCHAR(64);
44
+ ALTER TABLE settings ADD COLUMN instance_did VARCHAR(64);
45
+ ALTER TABLE payment_currencies ADD COLUMN instance_did VARCHAR(64);
46
+ ALTER TABLE product_vendors ADD COLUMN instance_did VARCHAR(64);