payment-kit 1.27.2 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/__blocklet__.js +37 -0
  2. package/api/ocap-1.30-subpath-shims.d.ts +35 -0
  3. package/api/src/crons/index.ts +32 -0
  4. package/api/src/crons/metering-subscription-detection.ts +12 -14
  5. package/api/src/crons/overdue-detection.ts +51 -74
  6. package/api/src/crons/retry-pending-events.ts +58 -0
  7. package/api/src/integrations/app-store/apple-root-certs.ts +26 -0
  8. package/api/src/integrations/app-store/client.ts +369 -0
  9. package/api/src/integrations/app-store/handlers/index.ts +46 -0
  10. package/api/src/integrations/app-store/handlers/subscription.ts +635 -0
  11. package/api/src/integrations/app-store/node-apple-receipt-verify.d.ts +17 -0
  12. package/api/src/integrations/app-store/notification-routing.ts +18 -0
  13. package/api/src/integrations/app-store/signed-data-verifier.ts +150 -0
  14. package/api/src/integrations/arcblock/nft.ts +6 -2
  15. package/api/src/integrations/arcblock/stake.ts +3 -2
  16. package/api/src/integrations/arcblock/token.ts +4 -4
  17. package/api/src/integrations/blocklet/notification.ts +1 -1
  18. package/api/src/integrations/ethereum/tx.ts +29 -0
  19. package/api/src/integrations/google-play/client.ts +276 -0
  20. package/api/src/integrations/google-play/handlers/index.ts +69 -0
  21. package/api/src/integrations/google-play/handlers/subscription.ts +565 -0
  22. package/api/src/integrations/google-play/handlers/voided.ts +106 -0
  23. package/api/src/integrations/google-play/setup.ts +43 -0
  24. package/api/src/integrations/google-play/verify.ts +251 -0
  25. package/api/src/integrations/iap-reconcile.ts +415 -0
  26. package/api/src/integrations/stripe/handlers/invoice.ts +70 -53
  27. package/api/src/integrations/stripe/handlers/payment-intent.ts +8 -1
  28. package/api/src/integrations/stripe/resource.ts +8 -0
  29. package/api/src/libs/audit.ts +70 -24
  30. package/api/src/libs/auth.ts +49 -2
  31. package/api/src/libs/chain-error.ts +31 -0
  32. package/api/src/libs/entitlement.ts +399 -0
  33. package/api/src/libs/env.ts +2 -0
  34. package/api/src/libs/error.ts +15 -0
  35. package/api/src/libs/event.ts +42 -1
  36. package/api/src/libs/invoice.ts +69 -34
  37. package/api/src/libs/notification/template/customer-auto-recharge-daily-limit-exceeded.ts +1 -3
  38. package/api/src/libs/notification/template/customer-auto-recharge-failed.ts +1 -3
  39. package/api/src/libs/notification/template/customer-credit-grant-granted.ts +1 -3
  40. package/api/src/libs/notification/template/customer-credit-insufficient.ts +1 -3
  41. package/api/src/libs/notification/template/customer-credit-low-balance.ts +1 -3
  42. package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -3
  43. package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -3
  44. package/api/src/libs/notification/template/one-time-payment-refund-succeeded.ts +1 -3
  45. package/api/src/libs/notification/template/one-time-payment-succeeded.ts +1 -3
  46. package/api/src/libs/notification/template/subscription-renew-failed.ts +1 -3
  47. package/api/src/libs/notification/template/subscription-slippage-exceeded.ts +1 -3
  48. package/api/src/libs/notification/template/subscription-slippage-warning.ts +1 -3
  49. package/api/src/libs/notification/template/subscription-succeeded.ts +1 -1
  50. package/api/src/libs/pagination.ts +14 -9
  51. package/api/src/libs/payment.ts +25 -10
  52. package/api/src/libs/security.ts +51 -0
  53. package/api/src/libs/session.ts +1 -1
  54. package/api/src/libs/subscription.ts +13 -1
  55. package/api/src/libs/timing.ts +35 -0
  56. package/api/src/libs/util.ts +29 -15
  57. package/api/src/libs/wallet-migration.ts +72 -53
  58. package/api/src/queues/auto-recharge.ts +1 -1
  59. package/api/src/queues/credit-consume.ts +94 -12
  60. package/api/src/queues/credit-grant.ts +4 -0
  61. package/api/src/queues/event.ts +39 -21
  62. package/api/src/queues/invoice.ts +1 -0
  63. package/api/src/queues/payment.ts +83 -15
  64. package/api/src/queues/refund.ts +84 -71
  65. package/api/src/queues/subscription.ts +1 -0
  66. package/api/src/queues/webhook.ts +12 -2
  67. package/api/src/routes/checkout-sessions.ts +82 -43
  68. package/api/src/routes/connect/change-payment.ts +2 -0
  69. package/api/src/routes/connect/change-plan.ts +2 -0
  70. package/api/src/routes/connect/pay.ts +12 -3
  71. package/api/src/routes/connect/setup.ts +3 -1
  72. package/api/src/routes/connect/shared.ts +52 -39
  73. package/api/src/routes/connect/subscribe.ts +4 -1
  74. package/api/src/routes/credit-grants.ts +25 -17
  75. package/api/src/routes/donations.ts +2 -2
  76. package/api/src/routes/entitlements.ts +105 -0
  77. package/api/src/routes/events.ts +2 -2
  78. package/api/src/routes/index.ts +12 -2
  79. package/api/src/routes/integrations/app-store.ts +267 -0
  80. package/api/src/routes/integrations/google-play.ts +324 -0
  81. package/api/src/routes/meter-events.ts +16 -6
  82. package/api/src/routes/payment-links.ts +1 -1
  83. package/api/src/routes/payment-methods.ts +131 -1
  84. package/api/src/routes/settings.ts +1 -1
  85. package/api/src/routes/tax-rates.ts +1 -1
  86. package/api/src/store/migrations/20260526-iap-foundation.ts +105 -0
  87. package/api/src/store/models/customer.ts +37 -1
  88. package/api/src/store/models/entitlement-grant.ts +118 -0
  89. package/api/src/store/models/entitlement-product.ts +48 -0
  90. package/api/src/store/models/entitlement.ts +86 -0
  91. package/api/src/store/models/index.ts +9 -0
  92. package/api/src/store/models/invoice.ts +20 -0
  93. package/api/src/store/models/payment-method.ts +66 -1
  94. package/api/src/store/models/price.ts +23 -14
  95. package/api/src/store/models/refund.ts +10 -0
  96. package/api/src/store/models/subscription.ts +14 -0
  97. package/api/src/store/models/types.ts +32 -0
  98. package/api/tests/integrations/app-store/client.spec.ts +335 -0
  99. package/api/tests/integrations/app-store/handlers.spec.ts +480 -0
  100. package/api/tests/integrations/app-store/notifications.spec.ts +381 -0
  101. package/api/tests/integrations/app-store/signed-data-verifier.spec.ts +72 -0
  102. package/api/tests/integrations/app-store/webhook-routing.spec.ts +27 -0
  103. package/api/tests/integrations/google-play/handlers.spec.ts +341 -0
  104. package/api/tests/integrations/google-play/verify.spec.ts +215 -0
  105. package/api/tests/integrations/iap-reconcile.spec.ts +237 -0
  106. package/api/tests/libs/entitlement.spec.ts +347 -0
  107. package/api/tests/libs/wallet-migration.spec.ts +4 -4
  108. package/api/tests/queues/credit-consume-batch.spec.ts +5 -2
  109. package/api/tests/queues/credit-consume.spec.ts +8 -4
  110. package/api/tests/routes/credit-grants.spec.ts +1 -0
  111. package/blocklet.yml +1 -1
  112. package/cloudflare/MIGRATION-CHALLENGES.md +676 -0
  113. package/cloudflare/MIGRATION-RUNBOOK.md +777 -0
  114. package/cloudflare/README.md +499 -0
  115. package/cloudflare/STAGING-MIGRATION-GUIDE.md +602 -0
  116. package/cloudflare/build.ts +151 -0
  117. package/cloudflare/did-connect-auth.ts +527 -0
  118. package/cloudflare/docs/2026-04-22-sdk-1.30.9-upgrade-retro.md +324 -0
  119. package/cloudflare/docs/2026-04-24-queue-ops-followup.md +218 -0
  120. package/cloudflare/docs/cf-queues-ops-alert-analysis.md +663 -0
  121. package/cloudflare/docs/cf-workers-local-dev-and-fixes.md +284 -0
  122. package/cloudflare/docs/cleanup-tasks-2026-05.md +62 -0
  123. package/cloudflare/docs/payment-kit-platform-analysis-2026-04-20.md +354 -0
  124. package/cloudflare/frontend-shims/buffer-polyfill.ts +9 -0
  125. package/cloudflare/frontend-shims/js-sdk.ts +43 -0
  126. package/cloudflare/frontend-shims/mime-types.ts +46 -0
  127. package/cloudflare/frontend-shims/session.ts +24 -0
  128. package/cloudflare/frontend-shims/vite-plugin-noop.ts +6 -0
  129. package/cloudflare/index.html +40 -0
  130. package/cloudflare/migrate-to-d1.js +252 -0
  131. package/cloudflare/migrations/0001_initial_schema.sql +82 -0
  132. package/cloudflare/migrations/0002_indexes.sql +75 -0
  133. package/cloudflare/migrations/0003_locks_and_constraints.sql +18 -0
  134. package/cloudflare/migrations/0004_iap_foundation.sql +72 -0
  135. package/cloudflare/migrations/0005_iap_tenant_backfill.sql +112 -0
  136. package/cloudflare/run-build.js +391 -0
  137. package/cloudflare/scripts/test-decrypt.js +102 -0
  138. package/cloudflare/shims/arcblock-ws.ts +20 -0
  139. package/cloudflare/shims/axios-http-adapter.ts +4 -0
  140. package/cloudflare/shims/axios-lite.ts +117 -0
  141. package/cloudflare/shims/blocklet-sdk/auth-service.ts +33 -0
  142. package/cloudflare/shims/blocklet-sdk/cdn.ts +3 -0
  143. package/cloudflare/shims/blocklet-sdk/component-api.ts +35 -0
  144. package/cloudflare/shims/blocklet-sdk/component.ts +18 -0
  145. package/cloudflare/shims/blocklet-sdk/config.ts +8 -0
  146. package/cloudflare/shims/blocklet-sdk/did.ts +14 -0
  147. package/cloudflare/shims/blocklet-sdk/env.ts +12 -0
  148. package/cloudflare/shims/blocklet-sdk/eventbus.ts +3 -0
  149. package/cloudflare/shims/blocklet-sdk/fallback.ts +3 -0
  150. package/cloudflare/shims/blocklet-sdk/index.ts +11 -0
  151. package/cloudflare/shims/blocklet-sdk/logger.ts +11 -0
  152. package/cloudflare/shims/blocklet-sdk/middlewares.ts +15 -0
  153. package/cloudflare/shims/blocklet-sdk/notification.ts +11 -0
  154. package/cloudflare/shims/blocklet-sdk/security.ts +53 -0
  155. package/cloudflare/shims/blocklet-sdk/session.ts +8 -0
  156. package/cloudflare/shims/blocklet-sdk/verify-session.ts +44 -0
  157. package/cloudflare/shims/blocklet-sdk/verify-sign.ts +38 -0
  158. package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +3 -0
  159. package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +6 -0
  160. package/cloudflare/shims/blocklet-sdk/wallet.ts +103 -0
  161. package/cloudflare/shims/cookie-parser.ts +3 -0
  162. package/cloudflare/shims/cors.ts +21 -0
  163. package/cloudflare/shims/cron.ts +189 -0
  164. package/cloudflare/shims/crypto-js-warn.ts +7 -0
  165. package/cloudflare/shims/did-space-js.ts +17 -0
  166. package/cloudflare/shims/did-space.ts +11 -0
  167. package/cloudflare/shims/error.ts +18 -0
  168. package/cloudflare/shims/express-compat/index.ts +80 -0
  169. package/cloudflare/shims/express-compat/types.ts +41 -0
  170. package/cloudflare/shims/fastq.ts +105 -0
  171. package/cloudflare/shims/lock.ts +115 -0
  172. package/cloudflare/shims/mime-types.ts +56 -0
  173. package/cloudflare/shims/nedb-storage.ts +9 -0
  174. package/cloudflare/shims/node-child-process.ts +9 -0
  175. package/cloudflare/shims/node-fs.ts +20 -0
  176. package/cloudflare/shims/node-http.ts +13 -0
  177. package/cloudflare/shims/node-https.ts +4 -0
  178. package/cloudflare/shims/node-misc.ts +15 -0
  179. package/cloudflare/shims/node-net.ts +8 -0
  180. package/cloudflare/shims/node-os.ts +14 -0
  181. package/cloudflare/shims/node-tty.ts +8 -0
  182. package/cloudflare/shims/node-zlib.ts +17 -0
  183. package/cloudflare/shims/noop.ts +26 -0
  184. package/cloudflare/shims/payment-vendor.ts +14 -0
  185. package/cloudflare/shims/querystring.ts +12 -0
  186. package/cloudflare/shims/queue.ts +611 -0
  187. package/cloudflare/shims/rolldown-runtime.ts +43 -0
  188. package/cloudflare/shims/sequelize-d1/datatypes.ts +24 -0
  189. package/cloudflare/shims/sequelize-d1/helpers.ts +46 -0
  190. package/cloudflare/shims/sequelize-d1/index.ts +34 -0
  191. package/cloudflare/shims/sequelize-d1/model.ts +1176 -0
  192. package/cloudflare/shims/sequelize-d1/operators.ts +306 -0
  193. package/cloudflare/shims/sequelize-d1/retry.ts +85 -0
  194. package/cloudflare/shims/sequelize-d1/sequelize-class.ts +119 -0
  195. package/cloudflare/shims/sequelize-d1/timing.ts +81 -0
  196. package/cloudflare/shims/sequelize-d1/types.ts +35 -0
  197. package/cloudflare/shims/stripe-cf.ts +29 -0
  198. package/cloudflare/shims/ws-lite.ts +103 -0
  199. package/cloudflare/shims/xss.ts +3 -0
  200. package/cloudflare/tests/shims/cron.spec.ts +210 -0
  201. package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +87 -0
  202. package/cloudflare/tests/shims/queue-scheduled.spec.ts +186 -0
  203. package/cloudflare/vite.config.ts +162 -0
  204. package/cloudflare/worker.ts +1608 -0
  205. package/cloudflare/wrangler.json +63 -0
  206. package/cloudflare/wrangler.jsonc +75 -0
  207. package/cloudflare/wrangler.staging.json +67 -0
  208. package/cloudflare/wrangler.toml +28 -0
  209. package/jest.config.js +4 -12
  210. package/package.json +30 -22
  211. package/scripts/seed-google-play.ts +79 -0
  212. package/src/app.tsx +62 -4
  213. package/src/components/customer/link.tsx +9 -13
  214. package/src/components/customer/notification-preference.tsx +3 -2
  215. package/src/components/filter-toolbar.tsx +4 -0
  216. package/src/components/invoice/list.tsx +9 -1
  217. package/src/components/invoice-pdf/utils.ts +2 -1
  218. package/src/components/layout/admin.tsx +39 -5
  219. package/src/components/layout/user-cf.tsx +77 -0
  220. package/src/components/payment-intent/actions.tsx +23 -3
  221. package/src/components/payment-method/app-store.tsx +103 -0
  222. package/src/components/payment-method/form.tsx +7 -1
  223. package/src/components/payment-method/google-play.tsx +85 -0
  224. package/src/components/safe-did-address.tsx +75 -0
  225. package/src/components/subscription/list.tsx +20 -0
  226. package/src/libs/patch-user-card.ts +25 -0
  227. package/src/libs/util.ts +5 -7
  228. package/src/locales/en.tsx +63 -0
  229. package/src/locales/zh.tsx +63 -0
  230. package/src/pages/admin/billing/meter-events/index.tsx +4 -0
  231. package/src/pages/admin/billing/subscriptions/detail.tsx +80 -0
  232. package/src/pages/admin/customers/customers/detail.tsx +8 -2
  233. package/src/pages/admin/customers/customers/index.tsx +2 -2
  234. package/src/pages/admin/overview.tsx +3 -1
  235. package/src/pages/admin/settings/payment-methods/create.tsx +12 -0
  236. package/src/pages/admin/settings/payment-methods/index.tsx +1 -1
  237. package/src/pages/customer/subscription/detail.tsx +4 -4
  238. package/tsconfig.api.json +1 -6
  239. package/tsconfig.json +3 -4
  240. package/tsconfig.types.json +2 -1
  241. package/vite.config.ts +6 -1
@@ -0,0 +1,33 @@
1
+ export class BlockletService {
2
+ async getVault() {
3
+ return { address: (globalThis as any).__CF_ENV__?.VAULT_ADDRESS || '' };
4
+ }
5
+ async getBlocklet() {
6
+ return { id: '', site: { id: '' } };
7
+ }
8
+ async updateRoutingRule() {}
9
+ async addRoutingRule() {}
10
+ async getPermissionsByRole(_role: string) {
11
+ return [];
12
+ }
13
+ async getRoles() {
14
+ return [];
15
+ }
16
+ async getUsers(_params?: any) {
17
+ return [];
18
+ }
19
+ async getUser(did: string, _opts?: any) {
20
+ // In CF Workers, the DID from DID Connect IS the wallet DID.
21
+ // Return it as a connectedAccount so getWalletDid(user) works correctly.
22
+ return {
23
+ user: {
24
+ did,
25
+ fullName: did,
26
+ email: '',
27
+ phone: '',
28
+ remark: '',
29
+ connectedAccounts: [{ provider: 'wallet', did }],
30
+ },
31
+ };
32
+ }
33
+ }
@@ -0,0 +1,3 @@
1
+ export function cdn() {
2
+ return (_req: any, _res: any, next: any) => next();
3
+ }
@@ -0,0 +1,35 @@
1
+ // componentApi shim — HTTP client with signature headers
2
+ // Mirrors the subset of axios API used by payment-kit (post, get, request)
3
+ export const componentApi = {
4
+ post: async (url: string, data: any, _opts?: any) => {
5
+ const res = await fetch(url, {
6
+ method: 'POST',
7
+ headers: { 'Content-Type': 'application/json' },
8
+ body: JSON.stringify(data),
9
+ });
10
+ return { data: await res.json() };
11
+ },
12
+ get: async (url: string, _opts?: any) => {
13
+ const res = await fetch(url);
14
+ return { data: await res.json() };
15
+ },
16
+ // Used by queues/webhook.ts for webhook delivery
17
+ request: async (config: { url: string; method?: string; data?: any; headers?: Record<string, string>; timeout?: number }) => {
18
+ const controller = new AbortController();
19
+ const timeoutId = config.timeout ? setTimeout(() => controller.abort(), config.timeout) : null;
20
+ try {
21
+ const res = await fetch(config.url, {
22
+ method: config.method || 'POST',
23
+ headers: { 'Content-Type': 'application/json', ...config.headers },
24
+ body: config.data ? JSON.stringify(config.data) : undefined,
25
+ signal: controller.signal,
26
+ });
27
+ const data = await res.json().catch(() => null);
28
+ return { data, status: res.status, headers: Object.fromEntries(res.headers.entries()) };
29
+ } finally {
30
+ if (timeoutId) clearTimeout(timeoutId);
31
+ }
32
+ },
33
+ };
34
+
35
+ export default componentApi;
@@ -0,0 +1,18 @@
1
+ // @blocklet/sdk/lib/component shim
2
+ function _getUrl(path?: string) {
3
+ const base = (globalThis as any).__CF_ENV__?.APP_URL || '';
4
+ if (!path) return base;
5
+ // In CF Workers there is no blocklet prefix — assets are served from root
6
+ return `${base}${path.startsWith('/') ? path : '/' + path}`;
7
+ }
8
+
9
+ const component = {
10
+ getUrl: _getUrl,
11
+ };
12
+
13
+ export default component;
14
+ export function getUrl(path?: string) {
15
+ return _getUrl(path);
16
+ }
17
+ export function getResources() { return []; }
18
+ export function getPackResources() { return []; }
@@ -0,0 +1,8 @@
1
+ import { env } from './env';
2
+
3
+ export { env };
4
+ export const Events = {};
5
+ export const events = { on: () => {}, emit: () => {} };
6
+
7
+ const config = { env, Events, events };
8
+ export default config;
@@ -0,0 +1,14 @@
1
+ // In Blocklet Server, getWalletDid(user) extracts wallet DID from user.connectedAccounts.
2
+ // In CF Workers, the user's DID from DID Connect IS the wallet DID (wallet signed directly).
3
+ export function getWalletDid(user?: any) {
4
+ if (user) {
5
+ // If user has connectedAccounts (from enriched getUser), use it
6
+ if (user.connectedAccounts) {
7
+ const walletAccount = user.connectedAccounts.find((a: any) => a.provider === 'wallet');
8
+ if (walletAccount) return walletAccount.did;
9
+ }
10
+ // In CF Workers, user.did IS the wallet DID (signed via DID Connect)
11
+ if (user.did) return user.did;
12
+ }
13
+ return (globalThis as any).__CF_ENV__?.WALLET_DID || '';
14
+ }
@@ -0,0 +1,12 @@
1
+ // @blocklet/sdk/lib/env shim
2
+ const env = {
3
+ get appPid() { return (globalThis as any).__CF_ENV__?.APP_PID || ''; },
4
+ get appName() { return (globalThis as any).__CF_ENV__?.APP_NAME || 'Payment Kit'; },
5
+ get appUrl() { return (globalThis as any).__CF_ENV__?.APP_URL || ''; },
6
+ get componentDid() { return (globalThis as any).__CF_ENV__?.COMPONENT_DID || ''; },
7
+ get dataDir() { return '/tmp'; },
8
+ get appId() { return (globalThis as any).__CF_ENV__?.APP_ID || ''; },
9
+ };
10
+
11
+ export { env };
12
+ export default env;
@@ -0,0 +1,3 @@
1
+ export async function publish(_event: string, _data: any) {
2
+ // TODO: CF Queues or HTTP POST
3
+ }
@@ -0,0 +1,3 @@
1
+ export function fallback(_file: string, _opts?: any) {
2
+ return (_req: any, _res: any, next: any) => next();
3
+ }
@@ -0,0 +1,11 @@
1
+ // @blocklet/sdk main entry shim
2
+ export { env } from './env';
3
+ export { Notification } from './notification';
4
+
5
+ export const component = {
6
+ getUrl: (..._args: any[]) => (globalThis as any).__CF_ENV__?.APP_URL || '',
7
+ };
8
+
9
+ export function getUrl(..._args: any[]) {
10
+ return (globalThis as any).__CF_ENV__?.APP_URL || '';
11
+ }
@@ -0,0 +1,11 @@
1
+ // @blocklet/logger shim
2
+ function createLogger(_name) {
3
+ return {
4
+ info: function() { console.log.apply(console, ['[INFO]'].concat(Array.from(arguments))); },
5
+ warn: function() { console.warn.apply(console, ['[WARN]'].concat(Array.from(arguments))); },
6
+ error: function() { console.error.apply(console, ['[ERROR]'].concat(Array.from(arguments))); },
7
+ debug: function() {},
8
+ };
9
+ }
10
+
11
+ module.exports = createLogger;
@@ -0,0 +1,15 @@
1
+ // @blocklet/sdk/lib/middlewares shim
2
+ export function csrf() {
3
+ return (_req: any, _res: any, next: any) => next();
4
+ }
5
+
6
+ export function auth(options?: { roles?: string[] }) {
7
+ return (req: any, res: any, next: any) => {
8
+ if (!options?.roles) return next();
9
+ if (!req.user?.did) return res.status(401).json({ error: 'Login required' });
10
+ if (!options.roles.includes(req.user.role)) {
11
+ return res.status(403).json({ error: 'Insufficient permissions' });
12
+ }
13
+ next();
14
+ };
15
+ }
@@ -0,0 +1,11 @@
1
+ export async function sendToRelay(_channel: string, _event: string, _data: any) {
2
+ // TODO: HTTP POST to notification service
3
+ }
4
+
5
+ export class Notification {
6
+ static async sendToUser(_did: string, _notification: any, _opts?: any) {
7
+ // TODO: HTTP POST to notification service
8
+ }
9
+ }
10
+
11
+ export default Notification;
@@ -0,0 +1,53 @@
1
+ // @blocklet/sdk/lib/security shim for CF Workers
2
+ //
3
+ // Uses the same crypto chain as original Blocklet Server:
4
+ // password = PBKDF2(BLOCKLET_APP_EK, BLOCKLET_DID, 256, 32, sha512).hex()
5
+ // plaintext = CryptoJS.AES.decrypt(ciphertext, password)
6
+
7
+ import crypto from 'crypto';
8
+ import CryptoJS from 'crypto-js';
9
+
10
+ let _password: string | null = null;
11
+
12
+ /** Initialize with EK + DID. After this, encrypt/decrypt work identically to Blocklet Server. */
13
+ export function initSecurity(appEk: string, blockletDid: string): void {
14
+ _password = crypto.pbkdf2Sync(appEk, blockletDid, 256, 32, 'sha512').toString('hex');
15
+ }
16
+
17
+ export function encrypt(data: string, password?: string, salt?: string): string {
18
+ const pw = password || _password;
19
+ if (!pw) return data;
20
+ return CryptoJS.AES.encrypt(data, pw).toString();
21
+ }
22
+
23
+ export function decrypt(data: string, password?: string, salt?: string): string {
24
+ const pw = password || _password;
25
+ if (!pw || !data) return data;
26
+ return CryptoJS.AES.decrypt(data, pw).toString(CryptoJS.enc.Utf8);
27
+ }
28
+
29
+ /**
30
+ * Fetch EK from AUTH_SERVICE and initialize. Call once at worker startup.
31
+ */
32
+ export async function initFromAuthService(env: {
33
+ AUTH_SERVICE?: any;
34
+ APP_PID?: string;
35
+ }): Promise<void> {
36
+ const { AUTH_SERVICE, APP_PID } = env;
37
+ if (!AUTH_SERVICE || !APP_PID) return;
38
+
39
+ try {
40
+ const appEk = await AUTH_SERVICE.getAppEk(APP_PID);
41
+ if (!appEk) {
42
+ console.warn('[Security] No APP_EK found for instance', APP_PID);
43
+ return;
44
+ }
45
+ // BLOCKLET_DID = APP_PID in Blocklet Server
46
+ initSecurity(appEk, APP_PID);
47
+ console.log('[Security] Initialized with EK from AUTH_SERVICE');
48
+ } catch (err: any) {
49
+ console.error('[Security] initFromAuthService failed:', err?.message);
50
+ }
51
+ }
52
+
53
+ export default { encrypt, decrypt, initSecurity, initFromAuthService };
@@ -0,0 +1,8 @@
1
+ // @blocklet/sdk/lib/middlewares/session shim
2
+ // Auth is resolved in Hono middleware layer via AUTH_SERVICE RPC.
3
+ // req.user is already populated by mountExpressRoutes().
4
+ export default function sessionMiddleware(_options?: any) {
5
+ return (_req: any, _res: any, next: any) => next();
6
+ }
7
+
8
+ export { sessionMiddleware };
@@ -0,0 +1,44 @@
1
+ // CF Workers no-op shim for @blocklet/sdk/lib/util/verify-session.
2
+ //
3
+ // In CF Workers, Bearer / cookie validation happens *before* Express routes
4
+ // run — see worker.ts auth middleware at /api/*, which calls
5
+ // `c.env.AUTH_SERVICE.resolveIdentity(...)` and injects x-user-did into the
6
+ // request headers when the token is valid. By the time security.ts'
7
+ // `authenticate` middleware sees the request, the x-user-did branch handles
8
+ // it. The fallback Bearer-validation path that calls verifyLoginToken
9
+ // directly is only needed in the Express dev server, where the tunnel
10
+ // bypasses Blocklet Server's nginx and we can't rely on header injection.
11
+ //
12
+ // So in Workers we return null — security.ts treats null as "couldn't
13
+ // validate locally, fall through" — and the x-user-did set by the worker
14
+ // layer is the source of truth.
15
+
16
+ export type SessionUser = {
17
+ did: string;
18
+ role?: string;
19
+ fullName?: string;
20
+ provider?: string;
21
+ walletOS?: string;
22
+ method?: string;
23
+ org?: string;
24
+ };
25
+
26
+ export async function verifyLoginToken(_opts: { token: string; strictMode?: boolean }): Promise<SessionUser | null> {
27
+ return null;
28
+ }
29
+
30
+ export async function verifyAccessKey(_opts: { token: string; strictMode?: boolean }): Promise<SessionUser | null> {
31
+ return null;
32
+ }
33
+
34
+ export async function verifyComponentCall(_opts: { req: any; strictMode?: boolean }): Promise<SessionUser | null> {
35
+ return null;
36
+ }
37
+
38
+ export async function verifySignedToken(_opts: { token: string; strictMode?: boolean }): Promise<SessionUser | null> {
39
+ return null;
40
+ }
41
+
42
+ export function getSessionSecret(): string {
43
+ return '';
44
+ }
@@ -0,0 +1,38 @@
1
+ // @blocklet/sdk/lib/util/verify-sign shim for CF Workers
2
+ //
3
+ // In Blocklet Server, component.call uses ED25519 signatures (x-component-sig)
4
+ // to authenticate inter-component calls.
5
+ //
6
+ // In CF Workers, all authentication is delegated to AUTH_SERVICE (blocklet-service)
7
+ // via the Hono caller middleware. By the time security.ts runs, the caller identity
8
+ // is already resolved and injected into req.headers['x-user-did'] / req.user.
9
+ //
10
+ // This shim delegates to AUTH_SERVICE.resolveIdentity() using the request's
11
+ // existing credentials (Cookie JWT or Authorization header), instead of
12
+ // doing local ED25519 signature verification.
13
+
14
+ export function getVerifyData(req: any, type = 'component') {
15
+ const sig = req.get?.(`x-${type}-sig`) || req.headers?.[`x-${type}-sig`] || '';
16
+ return { sig, data: {}, sigVersion: '', sigPk: '' };
17
+ }
18
+
19
+ export async function verify(_data: any, _sig: any): Promise<boolean> {
20
+ // AUTH_SERVICE handles all authentication in CF Workers.
21
+ // The Hono caller middleware (worker.ts) already called AUTH_SERVICE.resolveIdentity()
22
+ // and injected the result into x-user-did / x-user-role headers before Express runs.
23
+ //
24
+ // If AUTH_SERVICE verified the caller → x-user-did is set → security.ts x-user-did path handles it.
25
+ // If AUTH_SERVICE couldn't verify → caller is null → this path should reject.
26
+ //
27
+ // We return false here so the component.call path in security.ts falls through
28
+ // to the x-user-did path, which uses the AUTH_SERVICE-resolved identity.
29
+ const env = (globalThis as any).__CF_ENV__;
30
+ if (env?.AUTH_SERVICE) {
31
+ // AUTH_SERVICE is available — don't trust local signature, let the x-user-did path handle auth
32
+ return false;
33
+ }
34
+ // No AUTH_SERVICE — cannot verify
35
+ return false;
36
+ }
37
+
38
+ export default { verify, getVerifyData };
@@ -0,0 +1,3 @@
1
+ export class WalletAuthenticator {
2
+ constructor(_opts?: any) {}
3
+ }
@@ -0,0 +1,6 @@
1
+ export class WalletHandlers {
2
+ constructor(_opts?: any) {}
3
+ attach(_opts: any) {
4
+ // TODO: implement DID Connect for CF
5
+ }
6
+ }
@@ -0,0 +1,103 @@
1
+ // @blocklet/sdk/lib/wallet shim
2
+ // Uses @ocap/wallet to create real wallets from APP_SK for on-chain operations
3
+ import * as Mcrypto from '@ocap/mcrypto';
4
+ import { fromSecretKey } from '@ocap/wallet';
5
+
6
+ const walletTypeArcblock = {
7
+ role: Mcrypto.types.RoleType.ROLE_APPLICATION,
8
+ pk: Mcrypto.types.KeyType.ED25519,
9
+ hash: Mcrypto.types.HashType.SHA3,
10
+ };
11
+
12
+ const walletTypeEthereum = {
13
+ role: Mcrypto.types.RoleType.ROLE_APPLICATION,
14
+ pk: Mcrypto.types.KeyType.SECP256K1,
15
+ hash: Mcrypto.types.HashType.KECCAK,
16
+ };
17
+
18
+ // Cache wallets per type so they are not re-created on every call
19
+ let _arcblockWallet: any = null;
20
+ let _ethereumWallet: any = null;
21
+ let _lastSK: string = '';
22
+
23
+ function getAppSK(): string {
24
+ return (globalThis as any).__CF_ENV__?.APP_SK || process.env.APP_SK || '';
25
+ }
26
+
27
+ function ensureWallet(type?: string): any {
28
+ const sk = getAppSK();
29
+ if (!sk) {
30
+ return null;
31
+ }
32
+
33
+ // If SK changed, invalidate cached wallets
34
+ if (sk !== _lastSK) {
35
+ _arcblockWallet = null;
36
+ _ethereumWallet = null;
37
+ _lastSK = sk;
38
+ }
39
+
40
+ try {
41
+ if (type === 'ethereum') {
42
+ if (!_ethereumWallet) {
43
+ // Ethereum wallet uses first 66 chars of SK (0x + 32 bytes hex)
44
+ // matching @blocklet/sdk behavior: appSk.slice(0, 66)
45
+ const ethSk = sk.slice(0, 66);
46
+ _ethereumWallet = fromSecretKey(ethSk, walletTypeEthereum);
47
+ }
48
+ return _ethereumWallet;
49
+ }
50
+
51
+ if (!_arcblockWallet) {
52
+ _arcblockWallet = fromSecretKey(sk, walletTypeArcblock);
53
+ }
54
+ return _arcblockWallet;
55
+ } catch (e: any) {
56
+ console.error(`[CF Worker] ensureWallet(${type}) failed:`, e?.message);
57
+ return null;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Returns a wallet proxy that lazily initializes the real wallet on first property access.
63
+ * This is needed because auth.ts calls getWallet() at module init time, before __CF_ENV__
64
+ * is available. The proxy defers the real wallet creation to request time.
65
+ */
66
+ export function getWallet(type?: string, _appSk?: string, _keyType?: string): any {
67
+ return new Proxy(
68
+ {},
69
+ {
70
+ get(_target, prop) {
71
+ const realWallet = ensureWallet(type);
72
+ if (!realWallet) {
73
+ if (prop === 'address') return '';
74
+ if (prop === 'publicKey') return '';
75
+ if (prop === 'toJSON') return () => ({});
76
+ if (prop === 'sign') return async () => '';
77
+ if (prop === 'verify') return async () => true;
78
+ if (prop === 'signJWT') return async () => '';
79
+ if (prop === 'then') return undefined;
80
+ return undefined;
81
+ }
82
+ const value = realWallet[prop];
83
+ if (typeof value === 'function') {
84
+ return value.bind(realWallet);
85
+ }
86
+ return value;
87
+ },
88
+ has(_target, prop) {
89
+ const realWallet = ensureWallet(type);
90
+ if (!realWallet) return false;
91
+ return prop in realWallet;
92
+ },
93
+ }
94
+ );
95
+ }
96
+
97
+ // CF shim re-exports: on CF the runtime/permanent/access wallets all derive
98
+ // from the single APP_SK, so these just alias getWallet. Needed because
99
+ // payment-kit's api/src/libs/auth.ts imports { getAccessWallet } and the
100
+ // patch in that file calls getWallet(undefined, '', 'sk').
101
+ export const getAccessWallet = () => getWallet('arcblock');
102
+ export const getPermanentWallet = () => getWallet('arcblock');
103
+ export const getEthereumWallet = () => getWallet('ethereum');
@@ -0,0 +1,3 @@
1
+ export default function cookieParser() {
2
+ return (_req: any, _res: any, next: any) => next();
3
+ }
@@ -0,0 +1,21 @@
1
+ // Minimal cors shim for CF Workers
2
+ // Uses Object.assign pattern so both ESM and CJS interop work:
3
+ // - ESM: import cors from 'cors' -> cors is the function
4
+ // - CJS: const cors = require('cors') -> cors is the function (via __toCommonJS default)
5
+ function cors(_opts?: any) {
6
+ return (_req: any, res: any, next: any) => {
7
+ res?.set?.('Access-Control-Allow-Origin', '*');
8
+ res?.set?.('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,PATCH,OPTIONS');
9
+ res?.set?.('Access-Control-Allow-Headers', 'Content-Type,Authorization,x-user-did,x-csrf-token');
10
+ if (_req?.method === 'OPTIONS') {
11
+ res?.status?.(204)?.end?.();
12
+ return;
13
+ }
14
+ next();
15
+ };
16
+ }
17
+
18
+ // @ts-ignore - module.exports for CJS compat
19
+ module.exports = cors;
20
+ // @ts-ignore
21
+ module.exports.default = cors;