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,65 @@
1
+ -- Payment Kit: tenant unique keys + indexes (Phase 2, W1-1b)
2
+ -- Mirrors the index/unique-key part of api/src/store/migrations/20260611-tenant-backfill.ts.
3
+ --
4
+ -- IMPORTANT: the instance_did BACKFILL is NOT here. Static migration SQL
5
+ -- cannot know the deployment app DID, so the backfill (and the table rebuilds
6
+ -- that drop old inline single-column UNIQUE constraints) runs through the
7
+ -- shared runtime routine `runTenantBackfill()` (api/src/store/tenant-backfill.ts),
8
+ -- invoked idempotently from the worker's scheduled() handler.
9
+ --
10
+ -- Everything below is NULL-safe before that backfill runs: SQLite treats each
11
+ -- NULL as distinct in unique indexes, and existing single-column uniqueness
12
+ -- (identifier / did / key / idempotency_key) guarantees no composite dupes.
13
+
14
+ -- composite tenant unique keys (W1 §2.1, decisions D1/D3)
15
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_customers_tenant_did` ON `customers` (`instance_did`, `did`);
16
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_meter_events_tenant_identifier` ON `meter_events` (`instance_did`, `identifier`);
17
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_meters_tenant_event_name` ON `meters` (`instance_did`, `event_name`);
18
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_entitlements_tenant_key` ON `entitlements` (`instance_did`, `key`);
19
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_price_quotes_tenant_idem` ON `price_quotes` (`instance_did`, `idempotency_key`);
20
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_promotion_codes_tenant_code` ON `promotion_codes` (`instance_did`, `livemode`, `code`);
21
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_product_vendors_tenant_key` ON `product_vendors` (`instance_did`, `vendor_key`);
22
+ CREATE UNIQUE INDEX IF NOT EXISTS `uq_revenue_snapshots_tenant` ON `revenue_snapshots` (`instance_did`, `timestamp`, `currency_id`, `livemode`, `period_type`);
23
+ DROP INDEX IF EXISTS `idx_revenue_snapshots_unique`;
24
+ DROP INDEX IF EXISTS `idx_entitlements_key`;
25
+ DROP INDEX IF EXISTS `idx_pq_idempotency`;
26
+
27
+ -- plain tenant indexes for scoped queries (Phase 3+); meter_events is served
28
+ -- by its composite unique above (high-write table, avoid a second index)
29
+ CREATE INDEX IF NOT EXISTS `idx_customers_instance_did` ON `customers` (`instance_did`);
30
+ CREATE INDEX IF NOT EXISTS `idx_products_instance_did` ON `products` (`instance_did`);
31
+ CREATE INDEX IF NOT EXISTS `idx_prices_instance_did` ON `prices` (`instance_did`);
32
+ CREATE INDEX IF NOT EXISTS `idx_pricing_tables_instance_did` ON `pricing_tables` (`instance_did`);
33
+ CREATE INDEX IF NOT EXISTS `idx_payment_methods_instance_did` ON `payment_methods` (`instance_did`);
34
+ CREATE INDEX IF NOT EXISTS `idx_checkout_sessions_instance_did` ON `checkout_sessions` (`instance_did`);
35
+ CREATE INDEX IF NOT EXISTS `idx_payment_intents_instance_did` ON `payment_intents` (`instance_did`);
36
+ CREATE INDEX IF NOT EXISTS `idx_payment_links_instance_did` ON `payment_links` (`instance_did`);
37
+ CREATE INDEX IF NOT EXISTS `idx_setup_intents_instance_did` ON `setup_intents` (`instance_did`);
38
+ CREATE INDEX IF NOT EXISTS `idx_price_quotes_instance_did` ON `price_quotes` (`instance_did`);
39
+ CREATE INDEX IF NOT EXISTS `idx_subscriptions_instance_did` ON `subscriptions` (`instance_did`);
40
+ CREATE INDEX IF NOT EXISTS `idx_subscription_items_instance_did` ON `subscription_items` (`instance_did`);
41
+ CREATE INDEX IF NOT EXISTS `idx_subscription_schedules_instance_did` ON `subscription_schedules` (`instance_did`);
42
+ CREATE INDEX IF NOT EXISTS `idx_invoices_instance_did` ON `invoices` (`instance_did`);
43
+ CREATE INDEX IF NOT EXISTS `idx_invoice_items_instance_did` ON `invoice_items` (`instance_did`);
44
+ CREATE INDEX IF NOT EXISTS `idx_refunds_instance_did` ON `refunds` (`instance_did`);
45
+ CREATE INDEX IF NOT EXISTS `idx_credit_grants_instance_did` ON `credit_grants` (`instance_did`);
46
+ CREATE INDEX IF NOT EXISTS `idx_credit_transactions_instance_did` ON `credit_transactions` (`instance_did`);
47
+ CREATE INDEX IF NOT EXISTS `idx_meters_instance_did` ON `meters` (`instance_did`);
48
+ CREATE INDEX IF NOT EXISTS `idx_usage_records_instance_did` ON `usage_records` (`instance_did`);
49
+ CREATE INDEX IF NOT EXISTS `idx_coupons_instance_did` ON `coupons` (`instance_did`);
50
+ CREATE INDEX IF NOT EXISTS `idx_promotion_codes_instance_did` ON `promotion_codes` (`instance_did`);
51
+ CREATE INDEX IF NOT EXISTS `idx_discounts_instance_did` ON `discounts` (`instance_did`);
52
+ CREATE INDEX IF NOT EXISTS `idx_entitlements_instance_did` ON `entitlements` (`instance_did`);
53
+ CREATE INDEX IF NOT EXISTS `idx_entitlement_grants_instance_did` ON `entitlement_grants` (`instance_did`);
54
+ CREATE INDEX IF NOT EXISTS `idx_entitlement_products_instance_did` ON `entitlement_products` (`instance_did`);
55
+ CREATE INDEX IF NOT EXISTS `idx_events_instance_did` ON `events` (`instance_did`);
56
+ CREATE INDEX IF NOT EXISTS `idx_webhook_endpoints_instance_did` ON `webhook_endpoints` (`instance_did`);
57
+ CREATE INDEX IF NOT EXISTS `idx_webhook_attempts_instance_did` ON `webhook_attempts` (`instance_did`);
58
+ CREATE INDEX IF NOT EXISTS `idx_payouts_instance_did` ON `payouts` (`instance_did`);
59
+ CREATE INDEX IF NOT EXISTS `idx_payment_stats_instance_did` ON `payment_stats` (`instance_did`);
60
+ CREATE INDEX IF NOT EXISTS `idx_revenue_snapshots_instance_did` ON `revenue_snapshots` (`instance_did`);
61
+ CREATE INDEX IF NOT EXISTS `idx_auto_recharge_configs_instance_did` ON `auto_recharge_configs` (`instance_did`);
62
+ CREATE INDEX IF NOT EXISTS `idx_tax_rates_instance_did` ON `tax_rates` (`instance_did`);
63
+ CREATE INDEX IF NOT EXISTS `idx_settings_instance_did` ON `settings` (`instance_did`);
64
+ CREATE INDEX IF NOT EXISTS `idx_payment_currencies_instance_did` ON `payment_currencies` (`instance_did`);
65
+ CREATE INDEX IF NOT EXISTS `idx_product_vendors_instance_did` ON `product_vendors` (`instance_did`);
@@ -0,0 +1,16 @@
1
+ -- Phase 11 (W2′) schema parity: close the D1-lineage gaps the schema-drift guard
2
+ -- (scripts/schema-drift-guard.ts) found versus the Umzug canonical schema.
3
+ -- Additive only — safe to apply on a deployed D1 (no drops, no rewrites).
4
+
5
+ -- events: the Umzug genesis creates `events` with api_version (NOT NULL) and
6
+ -- metadata (JSON); the D1 0001 events table predates both, so the worker could
7
+ -- not write them. Backfill api_version with the app constant
8
+ -- (api/src/libs/audit.ts API_VERSION = '2023-09-05'); new rows carry the same.
9
+ ALTER TABLE `events` ADD COLUMN `api_version` VARCHAR(16) NOT NULL DEFAULT '2023-09-05';
10
+ ALTER TABLE `events` ADD COLUMN `metadata` JSON;
11
+
12
+ -- Indexes present in the canonical but missing in the D1 lineage (perf parity;
13
+ -- names match the Umzug migrations 20250904-discount / 20251007-relate-tax-rate).
14
+ CREATE INDEX IF NOT EXISTS `idx_discounts_customer_id` ON `discounts` (`customer_id`);
15
+ CREATE INDEX IF NOT EXISTS `idx_invoice_items_tax_rate_id` ON `invoice_items` (`tax_rate_id`);
16
+ CREATE INDEX IF NOT EXISTS `idx_promotion_codes_verification_type_coupon_id` ON `promotion_codes` (`verification_type`, `coupon_id`);
@@ -0,0 +1,5 @@
1
+ -- The DID Space billing-mirror integration was removed (libs/did-space.ts,
2
+ -- queues/space.ts). Rows in `jobs` with queue='did-space' can never be picked
3
+ -- up again (the scheduled scan only matches registered queue names), so they
4
+ -- would sit in the table forever. Delete them. Idempotent.
5
+ DELETE FROM jobs WHERE queue = 'did-space';
@@ -0,0 +1,13 @@
1
+ // Phase 12b (W2′): pin the core queue engine to 'workerd' mode.
2
+ //
3
+ // This MUST be imported before any business queue module (api/src/queues/*),
4
+ // because createQueue runs at import time and reads the mode to decide whether
5
+ // to start the node background poll loop(). A frozen CF isolate cannot run a
6
+ // background timer, so the worker disables the loop and drives due-job
7
+ // re-dispatch from scheduled() via the core dispatchDueJobs() surface instead.
8
+ //
9
+ // ESM executes imported module bodies in source order, so importing this first
10
+ // in worker.ts guarantees the mode is set before the engine is constructed.
11
+ import { setQueueRuntimeMode } from '../api/src/libs/queue/runtime';
12
+
13
+ setQueueRuntimeMode('workerd');
@@ -1,412 +1,42 @@
1
1
  const { build } = require("esbuild");
2
2
  const path = require("path");
3
+ const { buildCfEsbuildOptions } = require("./esbuild-cf-config.cjs");
4
+
3
5
  const cfDir = __dirname;
4
6
  const s = (f) => path.resolve(cfDir, f);
5
7
 
6
- // Resolve the absolute path of the original queue module so we can intercept it
7
- const queueModulePath = path.resolve(cfDir, "../api/src/libs/queue/index.ts");
8
- const queueShimPath = s("shims/queue.ts");
9
-
10
- // Resolve the absolute path of the original lock module so we can intercept it
11
- const lockModulePath = path.resolve(cfDir, "../api/src/libs/lock.ts");
12
- const lockShimPath = s("shims/lock.ts");
13
-
14
- // Plugin to redirect libs/queue to our CF Workers shim
15
- const queueNormalizedTarget = queueModulePath.replace(/\/index\.ts$/, '').replace(/\/index$/, '');
16
- const queueShimPlugin = {
17
- name: 'queue-shim',
18
- setup(build) {
19
- // Intercept any import that resolves to the original queue module
20
- build.onResolve({ filter: /libs\/queue/ }, (args) => {
21
- const resolveDir = args.resolveDir;
22
- if (!resolveDir) return undefined;
23
-
24
- // Resolve the relative import to an absolute path
25
- const resolved = path.resolve(resolveDir, args.path).replace(/\/index(\.ts)?$/, '');
26
- const match = resolved === queueNormalizedTarget;
27
- if (args.path.includes('queue')) {
28
- console.log(`[queue-shim] ${match ? 'MATCH' : 'skip'}: ${args.path} -> ${resolved} (target: ${queueNormalizedTarget})`);
29
- }
30
- if (match) {
31
- return { path: queueShimPath };
32
- }
33
- return undefined;
34
- });
35
- },
36
- };
37
-
38
- // Plugin to redirect libs/lock to our CF Workers D1-based lock shim
39
- const lockNormalizedTarget = lockModulePath.replace(/\.ts$/, '');
40
- const lockShimPlugin = {
41
- name: 'lock-shim',
42
- setup(build) {
43
- build.onResolve({ filter: /libs\/lock/ }, (args) => {
44
- const resolveDir = args.resolveDir;
45
- if (!resolveDir) return undefined;
46
-
47
- const resolved = path.resolve(resolveDir, args.path).replace(/\.ts$/, '');
48
- const match = resolved === lockNormalizedTarget;
49
- if (args.path.includes('lock')) {
50
- console.log(`[lock-shim] ${match ? 'MATCH' : 'skip'}: ${args.path} -> ${resolved} (target: ${lockNormalizedTarget})`);
51
- }
52
- if (match) {
53
- return { path: lockShimPath };
54
- }
55
- return undefined;
56
- });
57
- },
58
- };
59
-
60
- // Plugin to neutralize rolldown-generated `__require(import.meta.url)` helpers
61
- // that ship inside npm packages built with rolldown (e.g. @ocap/message,
62
- // @arcblock/did-connect-js). These helpers use `createRequire(import.meta.url)`
63
- // at module init to pull in CJS deps like `google-protobuf`, `debug`, etc. —
64
- // which neither resolve nor work in the CF Workers runtime.
65
- //
66
- // The downstream patches/shims that use these require calls are all either:
67
- // - monkey-patches for edge cases Payment Kit doesn't exercise, or
68
- // - debug()/logger() factories that Payment Kit doesn't need on CF.
69
- //
70
- // Replace every `_virtual/rolldown_runtime.mjs` with a stub whose `__require`
71
- // returns a Proxy that swallows further property accesses + function calls,
72
- // and whose `__commonJSMin` returns an empty-module factory. This lets the
73
- // importing modules finish loading without crashing the worker at startup.
74
- const rolldownRuntimeStub = `
75
- // After the Phase 2 CBOR switch (payment-method.ts + did-connect-auth.ts
76
- // moved off @ocap/client/legacy), no codepath in the worker calls
77
- // __require('google-protobuf') at runtime. The CBOR-only @ocap/client
78
- // default entry + @ocap/client/encode use plain ESM imports for their
79
- // deps. Any remaining __require calls in Rolldown-compiled packages
80
- // (debug, @arcblock/event-hub, etc.) are handled by the __noop Proxy
81
- // below — they don't need real modules for payment-kit's flows.
82
- const __requireMap = {};
83
- const __noopTarget = function(){};
84
- const __noopHandler = {
85
- get(t, p) {
86
- if (p === Symbol.toPrimitive || p === 'toString') return () => '';
87
- if (p === 'default') return new Proxy(__noopTarget, __noopHandler);
88
- return new Proxy(__noopTarget, __noopHandler);
89
- },
90
- apply() { return new Proxy(__noopTarget, __noopHandler); },
91
- construct() { return new Proxy(__noopTarget, __noopHandler); },
92
- };
93
- const __noop = new Proxy(__noopTarget, __noopHandler);
94
- export const __commonJSMin = function(cb){
95
- return function(){
96
- var m = { exports: {} };
97
- try { cb(m.exports, m); } catch (_) {}
98
- return m.exports;
99
- };
100
- };
101
- export const __require = function(id){
102
- if (__requireMap[id]) return __requireMap[id];
103
- return __noop;
104
- };
105
- export const __exportAll = function(target, source){
106
- if (source) {
107
- try {
108
- for (var key in source) {
109
- if (key !== 'default' && !Object.prototype.hasOwnProperty.call(target, key)) {
110
- Object.defineProperty(target, key, {
111
- get: function() { return source[key]; },
112
- enumerable: true,
113
- configurable: true,
114
- });
115
- }
116
- }
117
- } catch (_) {}
118
- }
119
- return target;
120
- };
121
- export const __toESM = function(mod){ return mod && mod.__esModule ? mod : { default: mod }; };
122
- export const __toCommonJS = function(mod){ return mod; };
123
- export const __copyProps = function(target){ return target; };
124
- export default { __commonJSMin, __require, __exportAll, __toESM, __toCommonJS, __copyProps };
125
- `;
126
- const rolldownRuntimeNoopPlugin = {
127
- name: 'rolldown-runtime-noop',
128
- setup(build) {
129
- // Catch any import that resolves to a `_virtual/rolldown_runtime.mjs`
130
- // file, regardless of which package it comes from.
131
- build.onResolve({ filter: /_virtual\/rolldown_runtime\.mjs$/ }, (args) => {
132
- return { path: args.path, namespace: 'rolldown-runtime-noop' };
133
- });
134
- build.onLoad({ filter: /.*/, namespace: 'rolldown-runtime-noop' }, () => ({
135
- contents: rolldownRuntimeStub,
136
- loader: 'js',
137
- // Need a resolveDir so the virtual stub's `import "google-protobuf"` resolves
138
- // against the workspace's node_modules. Pointing at cfDir is sufficient since
139
- // pnpm hoists google-protobuf up to the repo root node_modules.
140
- resolveDir: cfDir,
141
- }));
142
- },
143
- };
144
-
145
- // Plugin: fix lodash sub-path CJS/ESM interop
146
- // The "lodash" → "lodash-es" alias also redirects require('lodash/camelCase')
147
- // to lodash-es/camelCase (ESM). CJS consumers get { __esModule, default: fn }
148
- // instead of the function itself, causing "_m is not a function" at runtime.
149
- // Fix: intercept lodash-es sub-path imports from CJS contexts and generate a
150
- // virtual wrapper that re-exports the default as module.exports.
151
- const lodashSubpathPlugin = {
152
- name: 'lodash-subpath-interop',
153
- setup(build) {
154
- // Intercept resolved lodash-es sub-path imports that come from require() calls
155
- // Intercept CJS require('lodash/xxx') — the alias hasn't applied yet at this stage
156
- build.onResolve({ filter: /^lodash\/.+/ }, (args) => {
157
- if (args.kind === 'require-call') {
158
- // Convert lodash/xxx → lodash-es/xxx and wrap for CJS compat
159
- const esPath = args.path.replace(/^lodash\//, 'lodash-es/');
160
- return {
161
- path: esPath,
162
- namespace: 'lodash-cjs-compat',
163
- };
8
+ // S3-CF Phase 2: the worker-safe alias / shim / plugin / banner table now lives in
9
+ // esbuild-cf-config.cjs, shared with packages/payment-core/build-cf.mjs (the
10
+ // re-bundleable @arcblock/payment-service/cf library) so the standalone Worker and
11
+ // the embedded ./cf artifact can never drift. This script only adds the bits unique
12
+ // to the standalone Worker bundle: the worker.ts entry point (with a default
13
+ // export) and the dist/meta.json + size report.
14
+
15
+ build(
16
+ buildCfEsbuildOptions({
17
+ entryPoints: [s("worker.ts")],
18
+ outdir: s("dist"),
19
+ })
20
+ )
21
+ .then((result) => {
22
+ require("fs").writeFileSync(s("dist/meta.json"), JSON.stringify(result.metafile));
23
+ Object.entries(result.metafile.outputs).forEach(function (entry) {
24
+ var k = entry[0],
25
+ v = entry[1];
26
+ if (k.indexOf(".map") === -1) {
27
+ console.log(k + ": " + (v.bytes / 1024).toFixed(1) + "KB");
164
28
  }
165
29
  });
166
- build.onLoad({ filter: /.*/, namespace: 'lodash-cjs-compat' }, (args) => {
167
- // Resolve the actual file path, then read and re-export as CJS.
168
- // By loading the original ESM source as 'js' with CJS-style wrapping,
169
- // esbuild treats the result as CJS, avoiding the __toModule interop.
170
- const subPath = args.path.replace('lodash-es/', '');
171
- const filePath = require.resolve(`lodash-es/${subPath}`);
172
- const source = require('fs').readFileSync(filePath, 'utf8');
173
- // Transform: replace ESM export default with module.exports
174
- // lodash-es modules all follow: import deps... ; function fn(...){...}; export default fn;
175
- const transformed = source
176
- .replace(/^export default /m, 'module.exports = ')
177
- .replace(/^export\s*\{[^}]*\}\s*;?\s*$/m, '');
178
- return {
179
- contents: transformed,
180
- loader: 'js',
181
- resolveDir: require('path').dirname(filePath),
182
- };
183
- });
184
- },
185
- };
186
-
187
- // Plugin: redirect bare `@arcblock/did-util` and `@ocap/message` imports to their
188
- // CBOR-only subpath entries, and noop `@arcblock/did-util/protobuf`. This strips
189
- // the protobuf runtime (`@ocap/proto/runtime`, `google-protobuf`, `*_pb.js`) out
190
- // of the CF Workers bundle. Only matches EXACT bare specifiers — subpath imports
191
- // (e.g. `@arcblock/did-util/cbor`) pass through untouched.
192
- const cborOnlyPlugin = {
193
- name: 'cbor-only-redirect',
194
- setup(build) {
195
- build.onResolve({ filter: /^@arcblock\/did-util$/ }, () => ({
196
- path: path.resolve(__dirname, '../../..', 'node_modules/@arcblock/did-util/esm/cbor.mjs'),
197
- }));
198
- build.onResolve({ filter: /^@ocap\/message$/ }, () => ({
199
- path: path.resolve(__dirname, '../../..', 'node_modules/@ocap/message/esm/cbor.mjs'),
200
- }));
201
- build.onResolve({ filter: /^@arcblock\/did-util\/protobuf$/ }, () => ({
202
- path: s('shims/noop.ts'),
203
- }));
204
- },
205
- };
206
-
207
- // Plugin: noop entire package trees that have sub-path imports (alias alone
208
- // doesn't work because esbuild treats "axon" alias as prefix, breaking
209
- // "axon/lib/plugins/queue"). This plugin intercepts bare + sub-path imports.
210
- const noopPackagesPlugin = {
211
- name: 'noop-packages',
212
- setup(build) {
213
- const packages = ['axon', '@arcblock/ws', '@arcblock/event-hub', 'graphql', 'follow-redirects', 'proxy-from-env'];
214
- const filter = new RegExp('^(' + packages.join('|') + ')(\\/|$)');
215
- build.onResolve({ filter }, () => ({ path: s('shims/noop.ts') }));
216
- },
217
- };
218
-
219
- // Plugin: drop ethers' non-English BIP39 wordlists (~70K dead weight). The payment
220
- // worker never uses Mnemonic/HD wallets (0 source refs to Mnemonic/HDNode/wordlist),
221
- // so the 8 non-English word tables never execute. ethers' own /dist build strips
222
- // these too (~80kb). Keep LangEn (Mnemonic default). Stub the rest with a static
223
- // wordlist() returning null so wordlists.js's top-level LangXx.wordlist() calls
224
- // (run at module init) don't crash.
225
- const dropEthersWordlistsPlugin = {
226
- name: 'drop-ethers-wordlists',
227
- setup(build) {
228
- build.onLoad({ filter: /ethers\/lib\.esm\/wordlists\/lang-(cz|es|fr|ja|ko|it|pt|zh)\.js$/ }, (args) => {
229
- const lang = /lang-(\w+)\.js$/.exec(args.path)[1];
230
- const cls = 'Lang' + lang.charAt(0).toUpperCase() + lang.slice(1);
231
- return { contents: `export class ${cls} { static wordlist() { return null; } }`, loader: 'js' };
232
- });
233
- },
234
- };
235
-
236
- build({
237
- entryPoints: [s("worker.ts")],
238
- bundle: true, format: "esm", platform: "node", target: "esnext",
239
- outdir: s("dist"), minify: true, sourcemap: true, metafile: true,
240
- mainFields: ["module", "main"],
241
- plugins: [
242
- noopPackagesPlugin, queueShimPlugin, lockShimPlugin, rolldownRuntimeNoopPlugin, lodashSubpathPlugin, dropEthersWordlistsPlugin,
243
- ],
244
- external: ["cloudflare:*", "__STATIC_CONTENT_MANIFEST"],
245
- // Give import.meta.url a stable fallback so bundled deps that call
246
- // createRequire(import.meta.url) at module init don't throw at worker
247
- // startup. The polyfill in banner handles any legitimate require() lookups.
248
- define: {
249
- "import.meta.url": '"file:///worker.js"',
250
- },
251
- banner: {
252
- js: [
253
- '// Polyfill require() for CJS modules that dynamically require Node builtins',
254
- 'import __nodeCrypto from "node:crypto";',
255
- 'import __nodeBuffer from "node:buffer";',
256
- 'import __nodeEvents from "node:events";',
257
- 'import __nodeStream from "node:stream";',
258
- 'import __nodeUtil from "node:util";',
259
- 'import __nodeAssert from "node:assert";',
260
- 'import __nodePath from "node:path";',
261
- 'import __nodeUrl from "node:url";',
262
- 'import __nodeProcess from "node:process";',
263
- 'const __qsShim = { stringify: function(o) { return new URLSearchParams(o).toString(); }, parse: function(s) { return Object.fromEntries(new URLSearchParams(s).entries()); } };',
264
- 'const __nodeModules = { crypto: __nodeCrypto, buffer: __nodeBuffer, events: __nodeEvents, stream: __nodeStream, util: __nodeUtil, assert: __nodeAssert, path: __nodePath, url: __nodeUrl, process: __nodeProcess, querystring: __qsShim };',
265
- '// Accept both "xxx" and "node:xxx" specifier forms; return empty stub for unknown modules',
266
- '// (some deps tree-shake to nothing but still call require() at init — a hard throw crashes the worker).',
267
- '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 {}; };',
268
- '// Ensure process.stderr.fd exists for debug/supports-color',
269
- '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; }',
270
- '// Polyfill process.on/process.exit for modules that use them at init',
271
- 'if (typeof process !== "undefined" && !process.on) { process.on = function(){}; process.once = function(){}; process.off = function(){}; process.removeListener = function(){}; process.emit = function(){}; process.exit = function(){}; }',
272
- '// CF Workers: defer timers called during global scope init until first request',
273
- 'var __deferredTimers = []; var __timersReady = false;',
274
- '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); } }); };',
275
- '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; };',
276
- '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; };',
277
- '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); }; }',
278
- '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); }; } }',
279
- ].join('\n'),
280
- },
281
- alias: {
282
- // axios → lightweight fetch-based shim (115KB → ~2KB)
283
- "axios": s("shims/axios-lite.ts"),
284
-
285
- // node-fetch → native fetch (drops encoding/tr46/whatwg-url polyfill ~754KB
286
- // pulled in by @apple/app-store-server-library; dead weight on CF Workers)
287
- "node-fetch": s("shims/node-fetch.ts"),
288
-
289
- // Stripe — wrap constructor to use fetch HTTP client in CF Workers
290
- "stripe": s("shims/stripe-cf.ts"),
291
- "__real_stripe__": require.resolve("stripe"),
292
-
293
- // @ocap/message ships a patch.mjs that monkey-patches google-protobuf at
294
- // module init. google-protobuf isn't available in CF Workers (no filesystem
295
- // for createRequire to resolve), and Payment Kit doesn't use the features
296
- // that patch touches. Replace with a noop so the import chain stays alive
297
- // but the patch is skipped. Same for the rolldown_runtime helper that
298
- // relies on createRequire(import.meta.url).
299
- "@ocap/message/esm/patch.mjs": s("shims/noop.ts"),
300
- "@ocap/message/esm/_virtual/rolldown_runtime.mjs": s("shims/noop.ts"),
301
-
302
- "sequelize": s("shims/sequelize-d1/index.ts"),
303
- "sqlite3": s("shims/noop.ts"),
304
- "cls-hooked": s("shims/noop.ts"),
305
- "express-async-errors": s("shims/noop.ts"),
306
- "express": s("shims/express-compat/index.ts"),
307
- "cors": s("shims/cors.ts"),
308
- "cookie-parser": s("shims/cookie-parser.ts"),
309
- "@blocklet/sdk/lib/middlewares/fallback": s("shims/blocklet-sdk/fallback.ts"),
310
- "@blocklet/sdk/lib/middlewares/cdn": s("shims/blocklet-sdk/cdn.ts"),
311
- "@blocklet/sdk/lib/middlewares/session": s("shims/blocklet-sdk/session.ts"),
312
- "@blocklet/sdk/lib/middlewares": s("shims/blocklet-sdk/middlewares.ts"),
313
- "@blocklet/sdk/lib/env": s("shims/blocklet-sdk/env.ts"),
314
- "@blocklet/sdk/lib/config": s("shims/blocklet-sdk/config.ts"),
315
- "@blocklet/sdk/lib/component": s("shims/blocklet-sdk/component.ts"),
316
- "@blocklet/sdk/lib/wallet": s("shims/blocklet-sdk/wallet.ts"),
317
- "@blocklet/sdk/lib/wallet-authenticator": s("shims/blocklet-sdk/wallet-authenticator.ts"),
318
- "@blocklet/sdk/lib/wallet-handler": s("shims/blocklet-sdk/wallet-handler.ts"),
319
- "@blocklet/sdk/lib/security": s("shims/blocklet-sdk/security.ts"),
320
- "@blocklet/sdk/lib/util/verify-sign": s("shims/blocklet-sdk/verify-sign.ts"),
321
- "@blocklet/sdk/lib/util/verify-session": s("shims/blocklet-sdk/verify-session.ts"),
322
- "@blocklet/sdk/lib/util/component-api": s("shims/blocklet-sdk/component-api.ts"),
323
- "@blocklet/sdk/lib/error-handler": s("shims/noop.ts"),
324
- "@blocklet/sdk/lib/did": s("shims/blocklet-sdk/did.ts"),
325
- "@blocklet/sdk/lib/types/notification": s("shims/noop.ts"),
326
- "@blocklet/sdk/service/notification": s("shims/blocklet-sdk/notification.ts"),
327
- "@blocklet/sdk/service/eventbus": s("shims/blocklet-sdk/eventbus.ts"),
328
- "@blocklet/sdk/service/auth": s("shims/blocklet-sdk/auth-service.ts"),
329
- "@blocklet/sdk/service/blocklet": s("shims/blocklet-sdk/auth-service.ts"),
330
- "@blocklet/sdk": s("shims/blocklet-sdk/index.ts"),
331
- "@blocklet/xss": s("shims/xss.ts"),
332
- "@blocklet/error": s("shims/error.ts"),
333
- "@blocklet/logger": s("shims/blocklet-sdk/logger.ts"),
334
- "@blocklet/did-space-js": s("shims/did-space.ts"),
335
- "@blocklet/payment-vendor": s("shims/payment-vendor.ts"),
336
- "@arcblock/did-connect-storage-nedb": s("shims/nedb-storage.ts"),
337
- "@abtnode/cron": s("shims/cron.ts"),
338
- "dotenv-flow": s("shims/noop.ts"),
339
- "fastq": s("shims/fastq.ts"),
340
-
341
- // Bundle size optimizations — lodash base import aliased to lodash-es for tree-shaking.
342
- // Sub-path imports (lodash/camelCase etc.) handled by lodashSubpathPlugin below.
343
- "lodash": "lodash-es", // 357KB CJS → tree-shakeable ESM
344
- "esprima": s("shims/noop.ts"), // 215KB — only used by @ocap/contract, not called in payment-kit
345
- "mustache": s("shims/noop.ts"), // 16KB — template engine, not used in payment-kit
346
- "mime-types": s("shims/mime-types.ts"), // 150KB — lightweight shim with common MIME types
347
- "mime-db": s("shims/noop.ts"),
348
- "ws": s("shims/ws-lite.ts"), // 66KB — native WebSocket wrapper for CF Workers
349
- "crypto-js": s("shims/crypto-js-warn.ts"), // 115KB — AES legacy not used, warns if called
350
- "crypto-js/aes": s("shims/crypto-js-warn.ts"),
351
- "crypto-js/enc-base64": s("shims/noop.ts"),
352
- "crypto-js/enc-hex": s("shims/noop.ts"),
353
- "crypto-js/enc-latin1": s("shims/noop.ts"),
354
- "crypto-js/enc-utf8": s("shims/noop.ts"),
355
- "crypto-js/enc-utf16": s("shims/noop.ts"),
356
-
357
- // Force ESM-only to avoid CJS+ESM double-bundling
358
- "valibot": path.resolve(__dirname, "../../..", "node_modules/valibot/dist/index.mjs"), // 396KB → ~200KB
359
- // CF Workers: noop modules not useful in Workers environment
360
- "phoenix": s("shims/noop.ts"), // 36KB — Phoenix channels, only used by @arcblock/ws
361
- "numbro": s("shims/noop.ts"), // 49KB — number formatting, replaced inline in util.ts
362
-
363
- // Node built-in shims (not fully supported in CF Workers nodejs_compat)
364
- "os": s("shims/node-os.ts"),
365
- "node:os": s("shims/node-os.ts"),
366
- "tty": s("shims/node-tty.ts"),
367
- "node:tty": s("shims/node-tty.ts"),
368
- "http": s("shims/node-http.ts"),
369
- "node:http": s("shims/node-http.ts"),
370
- "https": s("shims/node-https.ts"),
371
- "node:https": s("shims/node-https.ts"),
372
- "http2": s("shims/node-http.ts"),
373
- "node:http2": s("shims/node-http.ts"),
374
- "net": s("shims/node-net.ts"),
375
- "node:net": s("shims/node-net.ts"),
376
- "tls": s("shims/node-misc.ts"),
377
- "node:tls": s("shims/node-misc.ts"),
378
- "fs": s("shims/node-fs.ts"),
379
- "node:fs": s("shims/node-fs.ts"),
380
- "cluster": s("shims/node-misc.ts"),
381
- "node:cluster": s("shims/node-misc.ts"),
382
- "zlib": s("shims/node-zlib.ts"),
383
- "node:zlib": s("shims/node-zlib.ts"),
384
- "child_process": s("shims/node-child-process.ts"),
385
- "node:child_process": s("shims/node-child-process.ts"),
386
- "bufferutil": s("shims/noop.ts"),
387
- "utf-8-validate": s("shims/noop.ts"),
388
- "dns": s("shims/noop.ts"),
389
- "node:dns": s("shims/noop.ts"),
390
- "pg": s("shims/noop.ts"),
391
- "postgres": s("shims/noop.ts"),
392
- },
393
- logLevel: "warning",
394
- }).then(result => {
395
- require('fs').writeFileSync(s('dist/meta.json'), JSON.stringify(result.metafile));
396
- Object.entries(result.metafile.outputs).forEach(function(entry) {
397
- var k = entry[0], v = entry[1];
398
- if (k.indexOf(".map") === -1) {
399
- console.log(k + ": " + (v.bytes / 1024).toFixed(1) + "KB");
30
+ console.log("BUILD SUCCESS");
31
+ })
32
+ .catch((err) => {
33
+ console.error("BUILD FAILED: " + (err.errors ? err.errors.length + " errors" : err.message));
34
+ if (err.errors) {
35
+ err.errors.slice(0, 20).forEach(function (e) {
36
+ var loc = e.location ? " at " + e.location.file + ":" + e.location.line : "";
37
+ console.error(" " + e.text + loc);
38
+ });
39
+ if (err.errors.length > 20) console.error(" ... and " + (err.errors.length - 20) + " more");
400
40
  }
41
+ process.exitCode = 1;
401
42
  });
402
- console.log("BUILD SUCCESS");
403
- }).catch(err => {
404
- console.error("BUILD FAILED: " + (err.errors ? err.errors.length + " errors" : err.message));
405
- if (err.errors) {
406
- err.errors.slice(0, 20).forEach(function(e) {
407
- var loc = e.location ? " at " + e.location.file + ":" + e.location.line : "";
408
- console.error(" " + e.text + loc);
409
- });
410
- if (err.errors.length > 20) console.error(" ... and " + (err.errors.length - 20) + " more");
411
- }
412
- });
@@ -0,0 +1,90 @@
1
+ // S3-CF Phase 2 命门 acceptance gate — the tiny-worker dynamic import probe.
2
+ //
3
+ // Builds a throwaway Worker whose ONLY payment touchpoint is
4
+ // import { createCloudflarePaymentAdapter } from "@arcblock/payment-service/cf";
5
+ // and runs `wrangler deploy --dry-run` with a CLEAN wrangler config: NO alias, NO
6
+ // define, NO external rules of its own — only `nodejs_compat`. If the published
7
+ // `./cf` artifact is genuinely self-contained + re-bundleable, this succeeds. If
8
+ // the consumer would need ANY alias/define/external, wrangler reports an unresolved
9
+ // import and the probe fails (命门 RED → architecture §3 service-binding fallback).
10
+ //
11
+ // node blocklets/core/cloudflare/scripts/cf-package-import-probe.mjs
12
+ //
13
+ // Reproducible: a fixed temp dir, the local payment-core symlinked as
14
+ // @arcblock/payment-service so the package `exports` map ("./cf" → dist/cf.js) is
15
+ // what resolves — exactly what arc sees from the published tarball.
16
+
17
+ import { mkdirSync, writeFileSync, rmSync, symlinkSync, existsSync } from 'fs';
18
+ import { dirname, join, resolve } from 'path';
19
+ import { fileURLToPath } from 'url';
20
+ import { execFileSync } from 'child_process';
21
+ import { tmpdir } from 'os';
22
+
23
+ const here = dirname(fileURLToPath(import.meta.url));
24
+ const paymentCoreDir = resolve(here, '../../../../packages/payment-core');
25
+ const cfDist = join(paymentCoreDir, 'dist', 'cf.js');
26
+
27
+ if (!existsSync(cfDist)) {
28
+ console.error(`probe RED — ${cfDist} missing. Run \`node packages/payment-core/build-cf.mjs\` first.`);
29
+ process.exit(1);
30
+ }
31
+
32
+ const probeDir = join(tmpdir(), 'cf-import-probe');
33
+ rmSync(probeDir, { recursive: true, force: true });
34
+ mkdirSync(join(probeDir, 'src'), { recursive: true });
35
+ mkdirSync(join(probeDir, 'node_modules', '@arcblock'), { recursive: true });
36
+
37
+ // Symlink the local payment-core as @arcblock/payment-service so the import
38
+ // resolves through the real package `exports` map — NOT a bypass path.
39
+ symlinkSync(paymentCoreDir, join(probeDir, 'node_modules', '@arcblock', 'payment-service'), 'dir');
40
+
41
+ // The tiny worker. Reference the imported symbol so esbuild can't tree-shake the
42
+ // import away (the whole point is to force the ./cf graph into the bundle).
43
+ writeFileSync(
44
+ join(probeDir, 'src', 'index.ts'),
45
+ `import { createCloudflarePaymentAdapter, PAYMENT_PREFIX } from "@arcblock/payment-service/cf";
46
+ export default {
47
+ async fetch() {
48
+ // touch the import so it is retained; never actually called in --dry-run
49
+ if (typeof createCloudflarePaymentAdapter !== "function") throw new Error("not a function");
50
+ return new Response("ok:" + PAYMENT_PREFIX);
51
+ },
52
+ };
53
+ `,
54
+ );
55
+
56
+ // CLEAN wrangler config — the load-bearing part of the gate: zero alias / zero
57
+ // define / zero external rules. Only nodejs_compat (a platform flag every Workers
58
+ // host sets), the same the standalone worker uses.
59
+ writeFileSync(
60
+ join(probeDir, 'wrangler.jsonc'),
61
+ JSON.stringify(
62
+ {
63
+ name: 'cf-import-probe',
64
+ main: 'src/index.ts',
65
+ compatibility_date: '2026-01-01',
66
+ compatibility_flags: ['nodejs_compat'],
67
+ },
68
+ null,
69
+ 2,
70
+ ),
71
+ );
72
+
73
+ writeFileSync(join(probeDir, 'package.json'), JSON.stringify({ name: 'cf-import-probe', private: true }, null, 2));
74
+
75
+ const outDir = join(probeDir, 'out');
76
+ console.log(`[probe] wrangler deploy --dry-run in ${probeDir} (clean config: nodejs_compat only)`);
77
+ try {
78
+ const stdout = execFileSync(
79
+ 'npx',
80
+ ['wrangler', 'deploy', '--dry-run', '--outdir', outDir],
81
+ { cwd: probeDir, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] },
82
+ );
83
+ console.log(stdout);
84
+ console.log('\n命门 GREEN — tiny worker built + dry-run deployed with ZERO consumer-side alias/define/external ✓');
85
+ } catch (err) {
86
+ console.error('\n命门 RED — tiny worker dry-run FAILED. Consumer would need alias/define/external:');
87
+ console.error(err.stdout || '');
88
+ console.error(err.stderr || err.message);
89
+ process.exit(1);
90
+ }