payment-kit 1.29.7 → 1.29.9

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 (32) hide show
  1. package/api/src/host-glue.ts +79 -0
  2. package/api/src/host-node/serve-static-arc.ts +1 -0
  3. package/api/src/integrations/app-store/native-asn1.ts +1 -0
  4. package/api/src/integrations/app-store/signed-data-verifier.ts +6 -1
  5. package/api/src/integrations/stripe/setup.ts +3 -3
  6. package/api/src/libs/arcblock-transfer.ts +27 -0
  7. package/api/src/libs/context.ts +10 -2
  8. package/api/src/libs/did-connect/tenant-identity.ts +19 -1
  9. package/api/src/libs/env.ts +65 -22
  10. package/api/src/libs/notification/index.ts +4 -3
  11. package/api/src/libs/util.ts +31 -2
  12. package/api/src/middlewares/hono/csrf.ts +6 -0
  13. package/api/src/middlewares/hono/session.ts +22 -0
  14. package/api/src/routes/connect/pay.ts +21 -9
  15. package/api/src/routes/hono/credit-grants.ts +1 -1
  16. package/api/src/routes/hono/entitlements.ts +8 -1
  17. package/api/src/routes/hono/payment-methods.ts +6 -2
  18. package/api/src/service.ts +42 -4
  19. package/api/src/store/models/payment-currency.ts +7 -1
  20. package/api/src/store/models/payment-method.ts +30 -6
  21. package/api/tests/libs/arcblock-transfer.spec.ts +58 -0
  22. package/api/tests/libs/notification-guard.spec.ts +25 -8
  23. package/api/tests/libs/util.spec.ts +51 -0
  24. package/blocklet.yml +1 -1
  25. package/cloudflare/cf-adapter.ts +46 -50
  26. package/cloudflare/did-connect-runtime.ts +43 -5
  27. package/cloudflare/esbuild-cf-config.cjs +12 -7
  28. package/cloudflare/tests/cf-adapter.spec.ts +12 -2
  29. package/cloudflare/worker.ts +41 -1
  30. package/package.json +9 -9
  31. package/src/components/layout/user.tsx +7 -1
  32. package/vite.arc.config.ts +19 -0
@@ -10,6 +10,11 @@ import { Client as PgClient } from 'pg';
10
10
  import postgres from 'postgres';
11
11
  import { Hono } from 'hono';
12
12
  import { cors } from 'hono/cors';
13
+ import { getCookie } from 'hono/cookie';
14
+ // Worker-safe CSRF crypto (the SAME module the csrf middleware verifies with —
15
+ // util/csrf passes through to the real package in the CF bundle, see build.ts).
16
+ // eslint-disable-next-line import/no-extraneous-dependencies
17
+ import { sign as signCsrf, getCsrfSecret } from '@blocklet/sdk/lib/util/csrf';
13
18
  import { setDB } from './shims/sequelize-d1/model';
14
19
  import { initialize } from '../api/src/store/models';
15
20
  import { Sequelize } from './shims/sequelize-d1/sequelize-class';
@@ -386,6 +391,20 @@ function buildApp(env: Env): Hono<HonoEnv> {
386
391
  // Flag: HTTP request context. createEvent uses waitUntil (non-blocking).
387
392
  // In queue consumer/cron, this flag is absent — createEvent uses __cfPendingJobs__ (blocking).
388
393
  (globalThis as any).__cfHttpContext__ = true;
394
+ // The @blocklet/sdk CSRF util reads its signing secret DIRECTLY from
395
+ // process.env (`BLOCKLET_APP_ASK || BLOCKLET_APP_SK`), not the config slot. The
396
+ // Phase-12a removal of the per-request process.env mirror left it undefined, so
397
+ // every CSRF-signed response hit `createHmac(<undefined key>)` → 500 (e.g.
398
+ // GET /api/settings). Restore just that one var from the APP_SK binding (the
399
+ // standalone worker's app secret key). Idempotent within the isolate.
400
+ if (c.env.APP_SK && !process.env.BLOCKLET_APP_SK) {
401
+ process.env.BLOCKLET_APP_SK = c.env.APP_SK;
402
+ }
403
+ // Test/staging escape hatch: forward PAYMENT_DISABLE_CSRF to the config boundary
404
+ // so the csrf middleware (readConfig) can honor it. Default-absent → CSRF stays on.
405
+ if ((c.env as any).PAYMENT_DISABLE_CSRF && !process.env.PAYMENT_DISABLE_CSRF) {
406
+ process.env.PAYMENT_DISABLE_CSRF = (c.env as any).PAYMENT_DISABLE_CSRF;
407
+ }
389
408
  setDB(withD1Retry(c.env.DB.withSession('first-primary')));
390
409
  ensureModelsInit();
391
410
 
@@ -496,6 +515,28 @@ function buildApp(env: Env): Hono<HonoEnv> {
496
515
  // Health check
497
516
  app.get('/health', (c) => c.json({ status: 'ok' }));
498
517
 
518
+ // did/csrfToken — the @blocklet/js-sdk axios adapter fetches its CSRF header from
519
+ // THIS endpoint (getCSRFTokenByLoginToken), not from the cookie. The shared
520
+ // blocklet-service (AUTH_SERVICE) only implements it on newer versions, so the
521
+ // catch-all proxy below 404s on older AUTH_SERVICE — leaving the SDK with no CSRF
522
+ // header and every mutating request 403'ing ("csrf token mismatch"). Sign it
523
+ // LOCALLY with the SAME secret + algorithm the payment csrf middleware verifies
524
+ // with (util/csrf sign over login_token), so token == cookie == what verify()
525
+ // expects. Must be registered BEFORE the /.well-known/service/* catch-all. This
526
+ // also makes the embedded arc-node CF runtime self-sufficient (no AUTH_SERVICE
527
+ // csrfToken endpoint required).
528
+ app.get('/.well-known/service/api/did/csrfToken', (c) => {
529
+ const loginToken = getCookie(c, 'login_token');
530
+ if (!loginToken) return c.json({ loginToken: null, csrfToken: null });
531
+ // Same secret resolution as the csrf middleware's csrfSecret() (PAYMENT_CSRF_SECRET
532
+ // override else the app secret key). Read APP_SK from the binding directly so we
533
+ // do not depend on the process.env.BLOCKLET_APP_SK mirror timing; getCsrfSecret()
534
+ // is the final fallback.
535
+ const secret = (c.env as any).PAYMENT_CSRF_SECRET || c.env.APP_SK || getCsrfSecret();
536
+ if (!secret) return c.json({ loginToken, csrfToken: null });
537
+ return c.json({ loginToken, csrfToken: signCsrf(secret, loginToken) });
538
+ });
539
+
499
540
  // user-session under /.well-known/service — proxy to blocklet-service session API
500
541
  // Returns full session data including connectedAccounts (needed by @arcblock/ux SessionUser)
501
542
  app.get('/.well-known/service/api/user-session', async (c) => {
@@ -691,7 +732,6 @@ function buildApp(env: Env): Hono<HonoEnv> {
691
732
  startsWithZ: sk.startsWith('z'),
692
733
  });
693
734
  });
694
-
695
735
  // === DID Auth Login routes ===
696
736
  // Only proxy login-related /api/did/* paths to blocklet-service.
697
737
  // Other /api/did/* paths (subscription, pay, collect, etc.) are Payment Kit's own
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payment-kit",
3
- "version": "1.29.7",
3
+ "version": "1.29.9",
4
4
  "scripts": {
5
5
  "dev": "blocklet dev --open",
6
6
  "prelint": "npm run types",
@@ -48,7 +48,7 @@
48
48
  "dependencies": {
49
49
  "@abtnode/cron": "^1.17.13-beta-20260613-094425-b81920c8",
50
50
  "@arcblock/did": "^1.30.24",
51
- "@arcblock/did-connect-js": "^4.0.7",
51
+ "@arcblock/did-connect-js": "^4.1.2",
52
52
  "@arcblock/did-connect-react": "^3.5.4",
53
53
  "@arcblock/did-connect-storage-nedb": "^1.8.0",
54
54
  "@arcblock/did-util": "^1.30.24",
@@ -60,13 +60,13 @@
60
60
  "@blocklet/error": "^0.3.5",
61
61
  "@blocklet/js-sdk": "^1.17.13-beta-20260613-094425-b81920c8",
62
62
  "@blocklet/logger": "^1.17.13-beta-20260613-094425-b81920c8",
63
- "@blocklet/payment-broker-client": "1.29.7",
64
- "@blocklet/payment-react": "1.29.7",
65
- "@blocklet/payment-vendor": "1.29.7",
63
+ "@blocklet/payment-broker-client": "1.29.9",
64
+ "@blocklet/payment-react": "1.29.9",
65
+ "@blocklet/payment-vendor": "1.29.9",
66
66
  "@blocklet/sdk": "^1.17.13-beta-20260613-094425-b81920c8",
67
67
  "@blocklet/ui-react": "^3.5.4",
68
- "@blocklet/uploader": "^0.3.20",
69
- "@blocklet/xss": "^0.3.16",
68
+ "@blocklet/uploader": "^0.15.4",
69
+ "@blocklet/xss": "^0.15.4",
70
70
  "@hono/node-server": "2.0.4",
71
71
  "@mui/icons-material": "^7.1.2",
72
72
  "@mui/lab": "7.0.0-beta.14",
@@ -133,7 +133,7 @@
133
133
  "devDependencies": {
134
134
  "@abtnode/types": "^1.17.13-beta-20260613-094425-b81920c8",
135
135
  "@arcblock/eslint-config-ts": "^0.3.3",
136
- "@blocklet/payment-types": "1.29.7",
136
+ "@blocklet/payment-types": "1.29.9",
137
137
  "@types/connect": "^3.4.38",
138
138
  "@types/debug": "^4.1.12",
139
139
  "@types/dotenv-flow": "^3.3.3",
@@ -180,5 +180,5 @@
180
180
  "parser": "typescript"
181
181
  }
182
182
  },
183
- "gitHead": "e1999aecfa9ce64bfd56da14bf47b255a19ef394"
183
+ "gitHead": "249bd9bf3c6cc54f77c260edb4b4d3c0be60f126"
184
184
  }
@@ -34,7 +34,13 @@ export default function UserLayout(props: any) {
34
34
  return (
35
35
  <PaymentProvider session={session} connect={connectApi}>
36
36
  <UserCenter
37
- currentTab={`${window.blocklet.prefix}customer`}
37
+ // Must match the userCenter nav link declared in blocklet.yml (`link: /customer`).
38
+ // UserCenter resolves both this prop and the nav link via `new URL(x, origin).pathname`,
39
+ // which strips any mount prefix — so the nav tab always resolves to the bare `/customer`.
40
+ // Prefixing here (e.g. `${prefix}customer`) makes the active tab fail to match, which
41
+ // triggers UserCenter's auto-redirect to the bare nav link and 404s the embedded mount
42
+ // (#1394). The bare path also works in the non-embedded form, where prefix is `/`.
43
+ currentTab="/customer"
38
44
  hideFooter
39
45
  embed={embed === '1'}
40
46
  notLoginContent="undefined">
@@ -29,6 +29,25 @@ export default defineConfig({
29
29
  root: coreDir,
30
30
  base: `${UI_PREFIX}/`,
31
31
  plugins: [
32
+ // Inject the Buffer polyfill at the top of the entry — the did-connect
33
+ // SessionProvider.refresh path serializes request bodies with Buffer, which is
34
+ // undefined in the browser, so without this the arc-embedded payment SPA throws
35
+ // "ReferenceError: Buffer is not defined" on session refresh and never renders.
36
+ // The standalone cloudflare/vite.config.ts already does this (cf-buffer-polyfill);
37
+ // the arc build was missing it. Reuses the same shim.
38
+ {
39
+ name: 'arc-buffer-polyfill',
40
+ enforce: 'pre' as const,
41
+ transform(code: string, id: string) {
42
+ if (id.endsWith('/src/index.tsx')) {
43
+ const shim = path
44
+ .resolve(coreDir, 'cloudflare/frontend-shims/buffer-polyfill.ts')
45
+ .replace(/\\/g, '/');
46
+ return `import '${shim}';\n` + code;
47
+ }
48
+ return undefined;
49
+ },
50
+ },
32
51
  tsconfigPaths({ root: coreDir }),
33
52
  react(),
34
53
  // Build-time window.blocklet bootstrap (P2 helper, single source). The