payment-kit 1.29.2 → 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 (67) hide show
  1. package/api/src/bootstrap.ts +11 -0
  2. package/api/src/crons/index.ts +14 -13
  3. package/api/src/crons/tenant-fanout.ts +82 -0
  4. package/api/src/host-node/did-connect-runtime-node.ts +33 -0
  5. package/api/src/host-node/serve-static-arc.ts +68 -0
  6. package/api/src/host-node/serve-static.ts +41 -0
  7. package/api/src/libs/auth.ts +166 -27
  8. package/api/src/libs/context.ts +11 -0
  9. package/api/src/libs/did-connect/runtime-did-connect-js.ts +88 -0
  10. package/api/src/libs/did-connect/tenant-identity.ts +221 -0
  11. package/api/src/libs/drivers/identity.ts +61 -0
  12. package/api/src/libs/drivers/index.ts +1 -1
  13. package/api/src/libs/http-fetch-adapter.ts +11 -1
  14. package/api/src/libs/queue/index.ts +14 -2
  15. package/api/src/middlewares/hono/context.ts +7 -0
  16. package/api/src/middlewares/hono/csrf.ts +13 -2
  17. package/api/src/middlewares/hono/security.ts +6 -11
  18. package/api/src/queues/checkout-session.ts +21 -9
  19. package/api/src/queues/event.ts +29 -7
  20. package/api/src/queues/payment.ts +23 -9
  21. package/api/src/queues/payout.ts +28 -16
  22. package/api/src/queues/refund.ts +18 -6
  23. package/api/src/routes/hono/customers.ts +6 -1
  24. package/api/src/routes/hono/refunds.ts +2 -3
  25. package/api/src/service.ts +178 -31
  26. package/api/src/store/sequelize.ts +16 -1
  27. package/api/tests/bootstrap/bootstrap.spec.ts +162 -0
  28. package/api/tests/crons/tenant-fanout.spec.ts +158 -0
  29. package/api/tests/libs/did-connect-runtime-js.spec.ts +98 -0
  30. package/api/tests/libs/did-connect-tenant-identity.spec.ts +159 -0
  31. package/api/tests/libs/service-host.spec.ts +37 -0
  32. package/api/tests/queues/event-tenant.spec.ts +60 -4
  33. package/api/tests/service/didconnect-storage-slot.spec.ts +60 -0
  34. package/api/tests/service/fail-closed-http.spec.ts +79 -0
  35. package/api/tests/service/static-arc-handler.spec.ts +101 -0
  36. package/api/tests/service/static-externalized.spec.ts +48 -0
  37. package/blocklet.yml +1 -1
  38. package/cloudflare/MIGRATION-RUNBOOK.md +3 -8
  39. package/cloudflare/README.md +8 -21
  40. package/cloudflare/STAGING-MIGRATION-GUIDE.md +3 -15
  41. package/cloudflare/build.ts +10 -5
  42. package/cloudflare/cf-adapter.ts +419 -0
  43. package/cloudflare/did-connect-runtime.ts +96 -0
  44. package/cloudflare/did-connect-token-storage.ts +151 -0
  45. package/cloudflare/esbuild-cf-config.cjs +407 -0
  46. package/cloudflare/run-build.js +33 -357
  47. package/cloudflare/scripts/cf-package-import-probe.mjs +90 -0
  48. package/cloudflare/scripts/didconnect-mock-smoke.mjs +140 -0
  49. package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +16 -1
  50. package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +18 -3
  51. package/cloudflare/tests/cf-adapter.spec.ts +244 -0
  52. package/cloudflare/tests/did-connect-token-storage.spec.ts +105 -0
  53. package/cloudflare/tests/worker-handler-gate.spec.ts +35 -10
  54. package/cloudflare/vite.config.ts +53 -45
  55. package/cloudflare/worker.ts +98 -56
  56. package/cloudflare/wrangler.json +0 -6
  57. package/cloudflare/wrangler.jsonc +0 -6
  58. package/cloudflare/wrangler.local-e2e.jsonc +0 -1
  59. package/cloudflare/wrangler.staging.json +0 -6
  60. package/package.json +7 -7
  61. package/scripts/bootstrap-inject.ts +166 -0
  62. package/src/app.tsx +2 -1
  63. package/src/libs/service-host.ts +13 -0
  64. package/vite.arc.config.ts +159 -0
  65. package/cloudflare/did-connect-auth.ts +0 -310
  66. package/cloudflare/shims/blocklet-sdk/util-csrf.ts +0 -13
  67. package/cloudflare/shims/blocklet-sdk/util-wallet.ts +0 -8
@@ -0,0 +1,159 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ // P1 (README D1 / F1) — arc-targeted SPA build.
3
+ //
4
+ // The standalone `vite.config.ts` injects its base via createBlockletPlugin
5
+ // (vite.config.ts:56), whose base is CLI-immutable — so a `--base` override
6
+ // cannot retarget it. arc needs a DETERMINISTIC base of '/.well-known/payment/',
7
+ // so this config (like cloudflare/vite.config.ts) drops createBlockletPlugin and
8
+ // sets `base` + `outDir` explicitly. Output lands directly in
9
+ // packages/payment-core/web/ so the @arcblock/payment-service tarball ships the
10
+ // frontend (T1.3 appends web/** to files). There is no blocklet-server doing
11
+ // runtime window.blocklet injection here, so the P2 bootstrap helper injects it
12
+ // at build time (single source — same helper the CF build uses).
13
+ import path from 'path';
14
+
15
+ import react from '@vitejs/plugin-react';
16
+ import { defineConfig } from 'vite';
17
+ import svgr from 'vite-plugin-svgr';
18
+ import tsconfigPaths from 'vite-tsconfig-paths';
19
+
20
+ import { PAYMENT_KIT_DID, buildBootstrapScript } from './scripts/bootstrap-inject';
21
+
22
+ const coreDir = __dirname; // blocklets/core — where index.html and src/ live
23
+ const UI_PREFIX = '/.well-known/payment';
24
+ // Physical isolation (README D1 / data-leak): arc artifacts live in payment-core's
25
+ // web/, never mixed with the standalone did-pay worker output (cloudflare/public).
26
+ const webOutDir = path.resolve(coreDir, '../../packages/payment-core/web');
27
+
28
+ export default defineConfig({
29
+ root: coreDir,
30
+ base: `${UI_PREFIX}/`,
31
+ plugins: [
32
+ tsconfigPaths({ root: coreDir }),
33
+ react(),
34
+ // Build-time window.blocklet bootstrap (P2 helper, single source). The
35
+ // remoteBlockletUrl is root-exact (the helper throws otherwise, T2.3), prefix
36
+ // is local-only (G3), componentId = PAYMENT_KIT_DID so getPrefix resolves to
37
+ // the arc UI prefix (packages/react/src/libs/util.ts:87).
38
+ {
39
+ name: 'arc-inject-blocklet',
40
+ transformIndexHtml(html: string) {
41
+ const injection = buildBootstrapScript({
42
+ uiPrefix: UI_PREFIX,
43
+ componentId: PAYMENT_KIT_DID,
44
+ remoteBlockletUrl: '/__blocklet__.js?type=json',
45
+ // serviceHost = ORIGIN ROOT, not '/.well-known/service'. The DID-Connect
46
+ // SessionProvider treats serviceHost as the API base and appends its OWN
47
+ // auth-service prefix (groupPrefix + servicePrefix + '/api/did' =
48
+ // '/.well-known/service/api/did') — so the session/csrf URLs resolve to
49
+ // <origin>/.well-known/service/api/did/*. Passing '/.well-known/service'
50
+ // double-counts it (=> /.well-known/service/.well-known/service/api/did/session).
51
+ // Root '/' lets the lib's appended prefix land at origin root, where arc
52
+ // serves the auth service (a sibling of /.well-known/payment, not under it).
53
+ serviceHost: '/',
54
+ // protect serviceHost too: the remote __blocklet__.js carries arc's own
55
+ // serviceHost/servicePrefix — must not clobber this build-time root base.
56
+ localOnly: ['prefix', 'serviceHost', 'navigation', 'componentMountPoints'],
57
+ // the payment blocklet's own nav + mount point — AUTH_SERVICE's
58
+ // __blocklet__.js doesn't carry them, so @blocklet/ui-react's dashboard
59
+ // would crash on `navigation.forEach` without these (localOnly-protected).
60
+ extra: {
61
+ componentMountPoints: [
62
+ {
63
+ did: PAYMENT_KIT_DID,
64
+ name: 'Payment Kit',
65
+ mountPoint: UI_PREFIX,
66
+ appId: PAYMENT_KIT_DID,
67
+ status: 'running',
68
+ capabilities: { component: true },
69
+ },
70
+ ],
71
+ navigation: [
72
+ {
73
+ id: 'payments',
74
+ title: { en: 'Payments', zh: '支付管理' },
75
+ icon: 'ion:card-outline',
76
+ link: '/admin',
77
+ section: ['dashboard', 'sessionManager'],
78
+ role: ['admin', 'owner'],
79
+ },
80
+ {
81
+ id: 'integrations',
82
+ title: { en: 'Integrations', zh: '快速集成' },
83
+ icon: 'ion:flash-outline',
84
+ link: '/integrations',
85
+ section: ['dashboard', 'sessionManager'],
86
+ role: ['admin', 'owner'],
87
+ },
88
+ {
89
+ id: 'billing',
90
+ title: { en: 'Billing', zh: '我的账单' },
91
+ icon: 'ion:receipt-outline',
92
+ link: '/customer',
93
+ private: true,
94
+ section: ['userCenter', 'sessionManager'],
95
+ role: ['owner', 'admin', 'member', 'guest'],
96
+ },
97
+ ],
98
+ },
99
+ });
100
+ return html.replace('<head>', `<head>${injection}`);
101
+ },
102
+ },
103
+ svgr(),
104
+ ],
105
+ resolve: {
106
+ alias: {
107
+ // Point workspace packages at source (same as the standalone dev/CF builds).
108
+ '@blocklet/payment-react': path.resolve(coreDir, '../../packages/react/src'),
109
+ '@blocklet/payment-react-headless': path.resolve(coreDir, '../../packages/payment-react-headless/src'),
110
+ '@blocklet/payment-js': path.resolve(coreDir, '../../packages/client/src'),
111
+ 'lodash.assign': 'lodash/assign',
112
+ 'lodash.clonedeep': 'lodash/cloneDeep',
113
+ 'lodash.isequal': 'lodash/isEqual',
114
+ 'lodash.merge': 'lodash/merge',
115
+ 'lodash.find': 'lodash/find',
116
+ },
117
+ dedupe: [
118
+ '@blocklet/ui-react',
119
+ '@arcblock/ux',
120
+ '@arcblock/did-connect-react',
121
+ '@mui/material',
122
+ '@mui/icons-material',
123
+ 'react',
124
+ 'react-dom',
125
+ 'lodash',
126
+ 'bn.js',
127
+ ],
128
+ },
129
+ build: {
130
+ outDir: webOutDir,
131
+ emptyOutDir: true,
132
+ cssCodeSplit: false,
133
+ modulePreload: false,
134
+ // Align with build.mjs sourcemap:false — the shipped web/ carries no source
135
+ // maps (no source-layout leak, Security spec).
136
+ sourcemap: false,
137
+ reportCompressedSize: false,
138
+ chunkSizeWarningLimit: 2000,
139
+ commonjsOptions: { include: [/node_modules/], transformMixedEsModules: true },
140
+ rollupOptions: {
141
+ output: {
142
+ manualChunks: {
143
+ 'vendor-react': ['react', 'react-dom', 'react-router-dom'],
144
+ 'vendor-mui': ['@mui/material', '@mui/icons-material', '@mui/system'],
145
+ 'vendor-arcblock': ['@arcblock/did-connect-react', '@arcblock/ux'],
146
+ 'vendor-blocklet': ['@blocklet/ui-react'],
147
+ },
148
+ },
149
+ },
150
+ },
151
+ define: {
152
+ global: 'globalThis',
153
+ 'process.env': {},
154
+ },
155
+ optimizeDeps: {
156
+ include: ['react', 'react-dom', 'react/jsx-runtime'],
157
+ esbuildOptions: { mainFields: ['module', 'main'], resolveExtensions: ['.ts', '.tsx', '.js', '.jsx'] },
158
+ },
159
+ });
@@ -1,310 +0,0 @@
1
- /**
2
- * DID Connect authentication for Cloudflare Workers.
3
- *
4
- * Since the published @arcblock/did-connect-js@1.28.0 does not include the Hono adapter,
5
- * we port the adapter logic here. When a newer version with native Hono support ships,
6
- * this file can be replaced by a direct import.
7
- *
8
- * Reference: blockchain/did/did-connect/src/adapters/hono.ts
9
- */
10
- import { WalletAuthenticator, WalletHandlers } from '@arcblock/did-connect-js';
11
- // abt-wallet 4.20+ is dual-decode (both CBOR + protobuf), so we can go back
12
- // to @ocap/client/encode's CBOR-only txEncoder. Drops ~300KB google-protobuf
13
- // runtime from the worker bundle. Requires abt-wallet >= 4.20.
14
- // fetchContext is also exported so we can pre-warm the module-level cache
15
- // at isolate init time — avoids the first-request 8s merchant timeout that
16
- // comes from fetchContext hitting beta chain (2 GraphQL queries in parallel).
17
- import { createTxEncoder, fetchContext } from '@ocap/client/encode';
18
- import * as Mcrypto from '@ocap/mcrypto';
19
- import { fromSecretKey } from '@ocap/wallet';
20
- import { EventEmitter } from 'events';
21
-
22
- // Import original connect handlers — esbuild aliases handle all dependency replacements
23
- import collectHandlers from '../api/src/routes/connect/collect';
24
- import collectBatchHandlers from '../api/src/routes/connect/collect-batch';
25
- import payHandlers from '../api/src/routes/connect/pay';
26
- import setupHandlers from '../api/src/routes/connect/setup';
27
- import subscribeHandlers from '../api/src/routes/connect/subscribe';
28
- import changePaymentHandlers from '../api/src/routes/connect/change-payment';
29
- import changePlanHandlers from '../api/src/routes/connect/change-plan';
30
- import changePayerHandlers from '../api/src/routes/connect/change-payer';
31
- import rechargeHandlers from '../api/src/routes/connect/recharge';
32
- import rechargeAccountHandlers from '../api/src/routes/connect/recharge-account';
33
- import delegationHandlers from '../api/src/routes/connect/delegation';
34
- import overdraftProtectionHandlers from '../api/src/routes/connect/overdraft-protection';
35
- import reStakeHandlers from '../api/src/routes/connect/re-stake';
36
- import autoRechargeAuthHandlers from '../api/src/routes/connect/auto-recharge-auth';
37
-
38
- const walletType = {
39
- role: Mcrypto.types.RoleType.ROLE_APPLICATION,
40
- pk: Mcrypto.types.KeyType.ED25519,
41
- hash: Mcrypto.types.HashType.SHA3,
42
- };
43
-
44
- // ---------------------------------------------------------------------------
45
- // CloudflareKVStorage – ported from blockchain/did/did-connect/src/storage/kv.ts
46
- // Not yet published in @arcblock/did-connect-js@1.28.0
47
- // ---------------------------------------------------------------------------
48
-
49
- // D1-based storage for DID Connect tokens.
50
- // Replaces KV which is eventually consistent across datacenters (up to 60s delay).
51
- // D1 is strongly consistent — writes are immediately visible to all readers.
52
- // This fixes mobile wallet scanning: wallet POST auth writes to datacenter A,
53
- // browser status polling reads from datacenter B, and sees the update immediately.
54
- class CloudflareD1Storage extends EventEmitter {
55
- private ttl: number;
56
-
57
- constructor(options: { ttl?: number } = {}) {
58
- super();
59
- this.ttl = options.ttl ?? 300;
60
- }
61
-
62
- private _getDB() {
63
- const env = (globalThis as any).__CF_ENV__;
64
- const db = env?.DB;
65
- if (!db) {
66
- console.error('[D1Storage] DB not available - __CF_ENV__ missing or no DB binding');
67
- return db;
68
- }
69
- return db.withSession('first-primary');
70
- }
71
-
72
- async create(token: string, status = 'created') {
73
- try {
74
- const db = this._getDB();
75
- if (!db) throw new Error('DB not available');
76
- const record = { token, status };
77
- const expiresAt = Math.floor(Date.now() / 1000) + this.ttl;
78
- await db
79
- .prepare('INSERT OR REPLACE INTO _did_connect_tokens (token, data, expires_at) VALUES (?, ?, ?)')
80
- .bind(token, JSON.stringify(record), expiresAt)
81
- .run();
82
- this.emit('create', record);
83
- return record;
84
- } catch (err: any) {
85
- console.error('[D1Storage] create failed:', token, err?.message || err);
86
- throw err;
87
- }
88
- }
89
-
90
- async read(token: string) {
91
- try {
92
- const db = this._getDB();
93
- if (!db) return null;
94
- const now = Math.floor(Date.now() / 1000);
95
- const row = await db
96
- .prepare('SELECT data FROM _did_connect_tokens WHERE token = ? AND expires_at > ?')
97
- .bind(token, now)
98
- .first();
99
- if (!row) return null;
100
- return JSON.parse(row.data as string);
101
- } catch (err: any) {
102
- console.error('[D1Storage] read failed:', token, err?.message || err);
103
- return null;
104
- }
105
- }
106
-
107
- update(token: string, updates: Record<string, any>) {
108
- // did-connect-js's handlers/util.ts onProcessError calls tokenStorage.update
109
- // without awaiting it (fire-and-forget). On CF Workers a non-awaited Promise
110
- // is terminated when the request handler returns, so the UPDATE never hits
111
- // D1 and the token stays at "scanned" forever — the wallet UI then loops on
112
- // `status: scanned` and shows "validating..." indefinitely.
113
- //
114
- // We wrap the real write in a promise, and register it via the global
115
- // ctx.waitUntil (exposed as __cfWaitUntil__ in worker.ts) so the runtime
116
- // keeps the isolate alive until the D1 write finishes, regardless of
117
- // whether the caller awaits us.
118
- const promise = (async () => {
119
- try {
120
- const existing = await this.read(token);
121
- if (!existing) return null;
122
-
123
- delete updates.token;
124
- const merged = { ...existing, ...updates };
125
- const expiresAt = Math.floor(Date.now() / 1000) + this.ttl;
126
- const db = this._getDB();
127
- if (!db) throw new Error('DB not available');
128
- await db
129
- .prepare('UPDATE _did_connect_tokens SET data = ?, expires_at = ? WHERE token = ?')
130
- .bind(JSON.stringify(merged), expiresAt, token)
131
- .run();
132
- this.emit('update', merged);
133
- return merged;
134
- } catch (err: any) {
135
- console.error('[D1Storage] update failed:', token, err?.message || err);
136
- throw err;
137
- }
138
- })();
139
-
140
- const waitUntil = (globalThis as any).__cfWaitUntil__ as ((p: Promise<any>) => void) | undefined;
141
- if (typeof waitUntil === 'function') {
142
- // Swallow rejection in waitUntil — the inner promise will still reject
143
- // for any caller that does await us.
144
- waitUntil(promise.catch(() => {}));
145
- }
146
- return promise;
147
- }
148
-
149
- async delete(token: string) {
150
- try {
151
- const existing = await this.read(token);
152
- if (existing) {
153
- this.emit('destroy', existing);
154
- }
155
- const db = this._getDB();
156
- if (!db) return;
157
- await db.prepare('DELETE FROM _did_connect_tokens WHERE token = ?').bind(token).run();
158
- } catch (err: any) {
159
- console.error('[D1Storage] delete failed:', token, err?.message || err);
160
- }
161
- }
162
-
163
- async exist(token: string, did?: string) {
164
- const record = await this.read(token);
165
- if (!record) return false;
166
- if (did) return record.did === did;
167
- return true;
168
- }
169
- }
170
-
171
-
172
- // ---------------------------------------------------------------------------
173
- // Public API
174
- // ---------------------------------------------------------------------------
175
-
176
- export function initAuth(kv: KVNamespace, appSK: string) {
177
- const wallet = fromSecretKey(appSK, walletType);
178
- const tokenStorage = new CloudflareD1Storage({ ttl: 300 });
179
- // Trailing slash is REQUIRED — without it the host 50% times out (verified 2026-04-20).
180
- // Matches the format used by D1 payment_methods.settings.arcblock.api_host.
181
- const chainHost = 'https://beta.abtnetwork.io/api/';
182
-
183
- // Pre-warm @ocap/client/encode's module-level context cache. The first
184
- // createTxEncoder()(...) call internally awaits fetchContext, which POSTs
185
- // getChainInfo + getForgeState to beta — ~1-3s on warm isolates, more on
186
- // cold. When `genRequestedClaims` is called by the merchant and triggers
187
- // the encoder, merchant's did-connect-js aborts after 8s. Firing the fetch
188
- // here at init (module load) lets the cache populate while the worker sets
189
- // up the rest of the request pipeline.
190
- fetchContext(chainHost).catch((err) => {
191
- // Non-fatal: on failure the first real request will retry via the
192
- // encoder's own fetchContext call.
193
- console.warn('[initAuth] pre-warm chainInfo failed:', err?.message);
194
- });
195
-
196
- const authenticator = new WalletAuthenticator({
197
- wallet: wallet.toJSON(),
198
- appInfo: ({ baseUrl }: { baseUrl: string }) => ({
199
- name: 'Payment Kit',
200
- description: 'Payment Kit on Cloudflare Workers',
201
- icon: 'https://www.arcblock.io/favicon.ico',
202
- link: baseUrl,
203
- }),
204
- chainInfo: {
205
- type: 'arcblock',
206
- host: chainHost,
207
- id: 'beta',
208
- },
209
- txEncoder: createTxEncoder(),
210
- // CF Workers: chain RPC to beta.abtnetwork.io + getContext warm-up can exceed
211
- // the default 8s. Extend to 30s to match Node.js payment-kit behavior.
212
- timeout: 30000,
213
- });
214
-
215
- // did-connect-js 4.0.0 natively detects Hono apps via isHonoApp()
216
- const handlers = new WalletHandlers({ tokenStorage, authenticator });
217
-
218
- return { wallet, authenticator, handlers, tokenStorage };
219
- }
220
-
221
- /**
222
- * Attach DID Connect routes to a Hono app.
223
- *
224
- * Registers the login action with full profile handling, and all payment-related
225
- * DID Connect actions using the original handler implementations from
226
- * api/src/routes/connect/*.ts. The handlers execute real on-chain operations
227
- * (transfers, delegations, staking) via @ocap/client HTTP RPC calls, which
228
- * work in CF Workers. If a handler fails to attach, it falls back to a stub.
229
- *
230
- * Payment actions registered:
231
- * collect, collect-batch, payment, subscription, setup,
232
- * change-payment, change-plan, change-payer,
233
- * recharge, recharge-account,
234
- * delegation, overdraft-protection, re-stake,
235
- * auto-recharge-auth
236
- */
237
- export function attachDIDConnectRoutes(app: any, kv: KVNamespace, appSK: string) {
238
- const { handlers, tokenStorage } = initAuth(kv, appSK);
239
-
240
- // ---- Login action (full implementation) ----
241
- handlers.attach({
242
- app,
243
- action: 'login',
244
- claims: {
245
- profile: () => ({
246
- description: 'Please provide your profile to login',
247
- fields: ['fullName', 'email', 'avatar'],
248
- }),
249
- },
250
- onAuth: async ({ userDid, userPk, claims, updateSession }: any) => {
251
- const claim = claims.find((x: any) => x.type === 'profile');
252
- const { type: _type, signature: _sig, ...rest } = claim || {};
253
- await updateSession({
254
- result: {
255
- ...rest,
256
- did: userDid,
257
- pk: userPk,
258
- },
259
- });
260
- },
261
- });
262
-
263
- // ---- Payment DID Connect actions (real implementations) ----
264
- // These use the original handlers from api/src/routes/connect/*.ts.
265
- // esbuild aliases handle all dependency replacements (@blocklet/sdk, sequelize, etc.)
266
- // so that @ocap/client HTTP-based RPC calls work in CF Workers.
267
- const paymentHandlerList = [
268
- collectHandlers,
269
- collectBatchHandlers,
270
- payHandlers,
271
- setupHandlers,
272
- subscribeHandlers,
273
- changePaymentHandlers,
274
- changePlanHandlers,
275
- changePayerHandlers,
276
- rechargeHandlers,
277
- rechargeAccountHandlers,
278
- delegationHandlers,
279
- overdraftProtectionHandlers,
280
- reStakeHandlers,
281
- autoRechargeAuthHandlers,
282
- ];
283
-
284
- for (const handler of paymentHandlerList) {
285
- try {
286
- handlers.attach({ app, ...handler });
287
- console.log(`[CF DID Connect] Attached real handler: ${handler.action}`);
288
- } catch (err: any) {
289
- console.error(`[CF DID Connect] Failed to attach handler ${handler.action}, using stub:`, err?.message);
290
- // Fallback to stub if real handler fails to attach
291
- handlers.attach({
292
- app,
293
- action: handler.action,
294
- claims: {
295
- profile: () => ({
296
- description: `Please connect your wallet to proceed with ${handler.action}`,
297
- fields: ['fullName', 'email'],
298
- }),
299
- },
300
- onAuth: async ({ userDid, userPk, updateSession }: any) => {
301
- await updateSession({
302
- result: { did: userDid, pk: userPk },
303
- });
304
- },
305
- });
306
- }
307
- }
308
-
309
- return { handlers, tokenStorage };
310
- }
@@ -1,13 +0,0 @@
1
- // CF shim for @blocklet/sdk/lib/util/csrf.
2
- //
3
- // DEAD on the CF path: the csrf middleware (middlewares/hono/csrf) lives only on
4
- // the NODE app-shell pipeline (service.ts buildHonoApp / configureNativePipeline,
5
- // reached via getHonoApp). The CF worker mounts a LITE app-shell (xss only) and
6
- // owns its own cors, so csrf never executes on the worker. These stubs exist only
7
- // so esbuild can resolve the import in the bundled-but-unreachable node code.
8
- export const getCsrfSecret = (): string => '';
9
- export const sign = (_secret: string, _value: string): string => '';
10
- export const verify = (_secret: string, _value: string, _token: string): boolean => false;
11
- export const hmac = (_secret: string, _value: string): string => '';
12
-
13
- export default { getCsrfSecret, sign, verify, hmac };
@@ -1,8 +0,0 @@
1
- // CF shim for @blocklet/sdk/lib/util/wallet.
2
- //
3
- // DEAD on the CF path: the only importer is the csrf middleware (node-shell only;
4
- // see util-csrf.ts), which reads isDidWalletConnect to skip csrf for DID-wallet
5
- // requests. Never executes on the worker — a resolving stub is enough.
6
- export const isDidWalletConnect = (_userAgent?: string): boolean => false;
7
-
8
- export default { isDidWalletConnect };