payment-kit 1.27.2 → 1.28.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.
- package/__blocklet__.js +37 -0
- package/api/ocap-1.30-subpath-shims.d.ts +35 -0
- package/api/src/crons/index.ts +10 -0
- package/api/src/crons/metering-subscription-detection.ts +12 -14
- package/api/src/crons/overdue-detection.ts +51 -74
- package/api/src/integrations/arcblock/nft.ts +6 -2
- package/api/src/integrations/arcblock/stake.ts +3 -2
- package/api/src/integrations/arcblock/token.ts +4 -4
- package/api/src/integrations/blocklet/notification.ts +1 -1
- package/api/src/integrations/ethereum/tx.ts +29 -0
- package/api/src/integrations/stripe/handlers/invoice.ts +70 -53
- package/api/src/integrations/stripe/handlers/payment-intent.ts +8 -1
- package/api/src/integrations/stripe/resource.ts +8 -0
- package/api/src/libs/audit.ts +32 -16
- package/api/src/libs/auth.ts +49 -2
- package/api/src/libs/chain-error.ts +31 -0
- package/api/src/libs/error.ts +15 -0
- package/api/src/libs/event.ts +42 -1
- package/api/src/libs/invoice.ts +69 -34
- package/api/src/libs/notification/template/customer-auto-recharge-daily-limit-exceeded.ts +1 -3
- package/api/src/libs/notification/template/customer-auto-recharge-failed.ts +1 -3
- package/api/src/libs/notification/template/customer-credit-grant-granted.ts +1 -3
- package/api/src/libs/notification/template/customer-credit-insufficient.ts +1 -3
- package/api/src/libs/notification/template/customer-credit-low-balance.ts +1 -3
- package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -3
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -3
- package/api/src/libs/notification/template/one-time-payment-refund-succeeded.ts +1 -3
- package/api/src/libs/notification/template/one-time-payment-succeeded.ts +1 -3
- package/api/src/libs/notification/template/subscription-renew-failed.ts +1 -3
- package/api/src/libs/notification/template/subscription-slippage-exceeded.ts +1 -3
- package/api/src/libs/notification/template/subscription-slippage-warning.ts +1 -3
- package/api/src/libs/notification/template/subscription-succeeded.ts +1 -1
- package/api/src/libs/pagination.ts +14 -9
- package/api/src/libs/payment.ts +25 -10
- package/api/src/libs/session.ts +1 -1
- package/api/src/libs/timing.ts +35 -0
- package/api/src/libs/util.ts +16 -15
- package/api/src/libs/wallet-migration.ts +72 -53
- package/api/src/queues/auto-recharge.ts +1 -1
- package/api/src/queues/credit-consume.ts +94 -12
- package/api/src/queues/credit-grant.ts +4 -0
- package/api/src/queues/event.ts +14 -2
- package/api/src/queues/invoice.ts +1 -0
- package/api/src/queues/payment.ts +83 -15
- package/api/src/queues/refund.ts +84 -71
- package/api/src/queues/subscription.ts +1 -0
- package/api/src/routes/checkout-sessions.ts +82 -43
- package/api/src/routes/connect/change-payment.ts +2 -0
- package/api/src/routes/connect/change-plan.ts +2 -0
- package/api/src/routes/connect/pay.ts +12 -3
- package/api/src/routes/connect/setup.ts +3 -1
- package/api/src/routes/connect/shared.ts +52 -39
- package/api/src/routes/connect/subscribe.ts +4 -1
- package/api/src/routes/credit-grants.ts +25 -17
- package/api/src/routes/donations.ts +2 -2
- package/api/src/routes/meter-events.ts +16 -6
- package/api/src/routes/payment-links.ts +1 -1
- package/api/src/routes/payment-methods.ts +1 -1
- package/api/src/routes/settings.ts +1 -1
- package/api/src/routes/tax-rates.ts +1 -1
- package/api/src/store/models/customer.ts +23 -1
- package/api/src/store/models/payment-method.ts +4 -0
- package/api/src/store/models/price.ts +23 -14
- package/api/tests/libs/wallet-migration.spec.ts +4 -4
- package/api/tests/queues/credit-consume-batch.spec.ts +5 -2
- package/api/tests/queues/credit-consume.spec.ts +8 -4
- package/api/tests/routes/credit-grants.spec.ts +1 -0
- package/blocklet.yml +1 -1
- package/cloudflare/MIGRATION-CHALLENGES.md +676 -0
- package/cloudflare/MIGRATION-RUNBOOK.md +777 -0
- package/cloudflare/README.md +499 -0
- package/cloudflare/STAGING-MIGRATION-GUIDE.md +602 -0
- package/cloudflare/build.ts +151 -0
- package/cloudflare/did-connect-auth.ts +527 -0
- package/cloudflare/docs/2026-04-22-sdk-1.30.9-upgrade-retro.md +324 -0
- package/cloudflare/docs/2026-04-24-queue-ops-followup.md +218 -0
- package/cloudflare/docs/cf-queues-ops-alert-analysis.md +663 -0
- package/cloudflare/docs/cf-workers-local-dev-and-fixes.md +284 -0
- package/cloudflare/docs/cleanup-tasks-2026-05.md +62 -0
- package/cloudflare/docs/payment-kit-platform-analysis-2026-04-20.md +354 -0
- package/cloudflare/frontend-shims/buffer-polyfill.ts +9 -0
- package/cloudflare/frontend-shims/js-sdk.ts +43 -0
- package/cloudflare/frontend-shims/mime-types.ts +46 -0
- package/cloudflare/frontend-shims/session.ts +24 -0
- package/cloudflare/frontend-shims/vite-plugin-noop.ts +6 -0
- package/cloudflare/index.html +40 -0
- package/cloudflare/migrate-to-d1.js +252 -0
- package/cloudflare/migrations/0001_initial_schema.sql +82 -0
- package/cloudflare/migrations/0002_indexes.sql +75 -0
- package/cloudflare/migrations/0003_locks_and_constraints.sql +18 -0
- package/cloudflare/run-build.js +390 -0
- package/cloudflare/scripts/test-decrypt.js +102 -0
- package/cloudflare/shims/arcblock-ws.ts +20 -0
- package/cloudflare/shims/axios-http-adapter.ts +4 -0
- package/cloudflare/shims/axios-lite.ts +117 -0
- package/cloudflare/shims/blocklet-sdk/auth-service.ts +33 -0
- package/cloudflare/shims/blocklet-sdk/cdn.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/component-api.ts +35 -0
- package/cloudflare/shims/blocklet-sdk/component.ts +18 -0
- package/cloudflare/shims/blocklet-sdk/config.ts +8 -0
- package/cloudflare/shims/blocklet-sdk/did.ts +14 -0
- package/cloudflare/shims/blocklet-sdk/env.ts +12 -0
- package/cloudflare/shims/blocklet-sdk/eventbus.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/fallback.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/index.ts +11 -0
- package/cloudflare/shims/blocklet-sdk/logger.ts +11 -0
- package/cloudflare/shims/blocklet-sdk/middlewares.ts +15 -0
- package/cloudflare/shims/blocklet-sdk/notification.ts +11 -0
- package/cloudflare/shims/blocklet-sdk/security.ts +53 -0
- package/cloudflare/shims/blocklet-sdk/session.ts +8 -0
- package/cloudflare/shims/blocklet-sdk/verify-sign.ts +38 -0
- package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +6 -0
- package/cloudflare/shims/blocklet-sdk/wallet.ts +103 -0
- package/cloudflare/shims/cookie-parser.ts +3 -0
- package/cloudflare/shims/cors.ts +21 -0
- package/cloudflare/shims/cron.ts +189 -0
- package/cloudflare/shims/crypto-js-warn.ts +7 -0
- package/cloudflare/shims/did-space-js.ts +17 -0
- package/cloudflare/shims/did-space.ts +11 -0
- package/cloudflare/shims/error.ts +18 -0
- package/cloudflare/shims/express-compat/index.ts +80 -0
- package/cloudflare/shims/express-compat/types.ts +41 -0
- package/cloudflare/shims/fastq.ts +105 -0
- package/cloudflare/shims/lock.ts +115 -0
- package/cloudflare/shims/mime-types.ts +56 -0
- package/cloudflare/shims/nedb-storage.ts +9 -0
- package/cloudflare/shims/node-child-process.ts +9 -0
- package/cloudflare/shims/node-fs.ts +20 -0
- package/cloudflare/shims/node-http.ts +13 -0
- package/cloudflare/shims/node-https.ts +4 -0
- package/cloudflare/shims/node-misc.ts +15 -0
- package/cloudflare/shims/node-net.ts +8 -0
- package/cloudflare/shims/node-os.ts +14 -0
- package/cloudflare/shims/node-tty.ts +8 -0
- package/cloudflare/shims/node-zlib.ts +17 -0
- package/cloudflare/shims/noop.ts +26 -0
- package/cloudflare/shims/payment-vendor.ts +14 -0
- package/cloudflare/shims/querystring.ts +12 -0
- package/cloudflare/shims/queue.ts +585 -0
- package/cloudflare/shims/rolldown-runtime.ts +43 -0
- package/cloudflare/shims/sequelize-d1/datatypes.ts +24 -0
- package/cloudflare/shims/sequelize-d1/helpers.ts +46 -0
- package/cloudflare/shims/sequelize-d1/index.ts +34 -0
- package/cloudflare/shims/sequelize-d1/model.ts +1157 -0
- package/cloudflare/shims/sequelize-d1/operators.ts +293 -0
- package/cloudflare/shims/sequelize-d1/retry.ts +85 -0
- package/cloudflare/shims/sequelize-d1/sequelize-class.ts +119 -0
- package/cloudflare/shims/sequelize-d1/timing.ts +81 -0
- package/cloudflare/shims/sequelize-d1/types.ts +35 -0
- package/cloudflare/shims/stripe-cf.ts +29 -0
- package/cloudflare/shims/ws-lite.ts +103 -0
- package/cloudflare/shims/xss.ts +3 -0
- package/cloudflare/tests/shims/cron.spec.ts +210 -0
- package/cloudflare/tests/shims/queue-scheduled.spec.ts +186 -0
- package/cloudflare/vite.config.ts +162 -0
- package/cloudflare/worker.ts +1553 -0
- package/cloudflare/wrangler.json +63 -0
- package/cloudflare/wrangler.jsonc +69 -0
- package/cloudflare/wrangler.staging.json +66 -0
- package/cloudflare/wrangler.toml +28 -0
- package/jest.config.js +4 -12
- package/package.json +26 -22
- package/src/app.tsx +62 -4
- package/src/components/customer/link.tsx +9 -13
- package/src/components/customer/notification-preference.tsx +3 -2
- package/src/components/filter-toolbar.tsx +4 -0
- package/src/components/invoice/list.tsx +9 -1
- package/src/components/invoice-pdf/utils.ts +2 -1
- package/src/components/layout/admin.tsx +39 -5
- package/src/components/layout/user-cf.tsx +77 -0
- package/src/components/payment-intent/actions.tsx +23 -3
- package/src/components/safe-did-address.tsx +75 -0
- package/src/libs/patch-user-card.ts +25 -0
- package/src/libs/util.ts +5 -7
- package/src/pages/admin/billing/meter-events/index.tsx +4 -0
- package/src/pages/admin/customers/customers/detail.tsx +2 -2
- package/src/pages/admin/customers/customers/index.tsx +2 -2
- package/src/pages/admin/overview.tsx +3 -1
- package/src/pages/customer/subscription/detail.tsx +4 -4
- package/tsconfig.api.json +1 -6
- package/tsconfig.json +3 -4
- package/tsconfig.types.json +2 -1
- package/vite.config.ts +6 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "payment-kit",
|
|
3
|
+
"main": "dist/worker.js",
|
|
4
|
+
"compatibility_date": "2024-12-01",
|
|
5
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
6
|
+
"assets": {
|
|
7
|
+
"directory": "public",
|
|
8
|
+
"binding": "ASSETS",
|
|
9
|
+
"html_handling": "auto-trailing-slash",
|
|
10
|
+
"not_found_handling": "single-page-application"
|
|
11
|
+
},
|
|
12
|
+
"d1_databases": [
|
|
13
|
+
{
|
|
14
|
+
"binding": "DB",
|
|
15
|
+
"database_name": "payment-kit-prod",
|
|
16
|
+
"database_id": "ea6c75d0-39b8-40cd-a0ae-a2062e77c4b9",
|
|
17
|
+
"migrations_dir": "migrations"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"kv_namespaces": [
|
|
21
|
+
{
|
|
22
|
+
"binding": "DID_CONNECT_KV",
|
|
23
|
+
"id": "ca0bd29c73864115b713e1db11d97cd2"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"services": [
|
|
27
|
+
{
|
|
28
|
+
"binding": "MEDIA_KIT",
|
|
29
|
+
"service": "media-kit"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"binding": "AUTH_SERVICE",
|
|
33
|
+
"service": "blocklet-service",
|
|
34
|
+
"entrypoint": "BlockletServiceRPC"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"vars": {
|
|
38
|
+
"APP_NAME": "Payment Kit",
|
|
39
|
+
"APP_PID": "zNKuN3XwXN7xq2NsJQjjfwujyqCxx26DhwgV",
|
|
40
|
+
"COMPONENT_DID": "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk",
|
|
41
|
+
"MEDIA_KIT_URL": "https://media-kit.yexiaofang.workers.dev"
|
|
42
|
+
},
|
|
43
|
+
"queues": {
|
|
44
|
+
"producers": [
|
|
45
|
+
{
|
|
46
|
+
"binding": "JOB_QUEUE",
|
|
47
|
+
"queue": "payment-kit-jobs"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"consumers": [
|
|
51
|
+
{
|
|
52
|
+
"queue": "payment-kit-jobs",
|
|
53
|
+
"max_batch_size": 10,
|
|
54
|
+
"max_batch_timeout": 5,
|
|
55
|
+
"max_retries": 3,
|
|
56
|
+
"dead_letter_queue": "payment-kit-jobs-dlq"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"triggers": {
|
|
61
|
+
"crons": ["*/5 * * * *"]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "payment-kit",
|
|
3
|
+
"main": "dist/worker.js",
|
|
4
|
+
"compatibility_date": "2024-12-01",
|
|
5
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
6
|
+
"placement": { "mode": "smart" },
|
|
7
|
+
"assets": {
|
|
8
|
+
"directory": "public",
|
|
9
|
+
"binding": "ASSETS",
|
|
10
|
+
"html_handling": "auto-trailing-slash",
|
|
11
|
+
"not_found_handling": "single-page-application"
|
|
12
|
+
},
|
|
13
|
+
"d1_databases": [
|
|
14
|
+
{
|
|
15
|
+
"binding": "DB",
|
|
16
|
+
"database_name": "payment-kit-prod",
|
|
17
|
+
"database_id": "ea6c75d0-39b8-40cd-a0ae-a2062e77c4b9"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"kv_namespaces": [
|
|
21
|
+
{
|
|
22
|
+
"binding": "DID_CONNECT_KV",
|
|
23
|
+
"id": "ca0bd29c73864115b713e1db11d97cd2"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"hyperdrive": [
|
|
27
|
+
{
|
|
28
|
+
"binding": "HYPERDRIVE",
|
|
29
|
+
"id": "18184fbdb1554c6a9f916d57fbc5d43e"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"services": [
|
|
33
|
+
{
|
|
34
|
+
"binding": "MEDIA_KIT",
|
|
35
|
+
"service": "media-kit"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"binding": "AUTH_SERVICE",
|
|
39
|
+
"service": "blocklet-service",
|
|
40
|
+
"entrypoint": "BlockletServiceRPC"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"vars": {
|
|
44
|
+
"APP_NAME": "Payment Kit",
|
|
45
|
+
"APP_PID": "zNKuN3XwXN7xq2NsJQjjfwujyqCxx26DhwgV",
|
|
46
|
+
"COMPONENT_DID": "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk",
|
|
47
|
+
"MEDIA_KIT_URL": "https://media-kit.yexiaofang.workers.dev"
|
|
48
|
+
},
|
|
49
|
+
"queues": {
|
|
50
|
+
"producers": [
|
|
51
|
+
{
|
|
52
|
+
"binding": "JOB_QUEUE",
|
|
53
|
+
"queue": "payment-kit-jobs"
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"consumers": [
|
|
57
|
+
{
|
|
58
|
+
"queue": "payment-kit-jobs",
|
|
59
|
+
"max_batch_size": 10,
|
|
60
|
+
"max_batch_timeout": 5,
|
|
61
|
+
"max_retries": 3,
|
|
62
|
+
"dead_letter_queue": "payment-kit-jobs-dlq"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"triggers": {
|
|
67
|
+
"crons": ["* * * * *"]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "staging-aigne-hub-payment-kit",
|
|
3
|
+
"main": "dist/worker.js",
|
|
4
|
+
"compatibility_date": "2024-12-01",
|
|
5
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
6
|
+
"placement": { "mode": "smart" },
|
|
7
|
+
"assets": {
|
|
8
|
+
"directory": "public",
|
|
9
|
+
"binding": "ASSETS",
|
|
10
|
+
"html_handling": "auto-trailing-slash",
|
|
11
|
+
"not_found_handling": "single-page-application"
|
|
12
|
+
},
|
|
13
|
+
"d1_databases": [
|
|
14
|
+
{
|
|
15
|
+
"binding": "DB",
|
|
16
|
+
"database_name": "staging-aigne-hub-payment-kit",
|
|
17
|
+
"database_id": "978e726b-ad9d-4dcc-bc66-f0d3fb01a1dd",
|
|
18
|
+
"migrations_dir": "migrations"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"kv_namespaces": [
|
|
22
|
+
{
|
|
23
|
+
"binding": "DID_CONNECT_KV",
|
|
24
|
+
"id": "a2c98f81bc974fcabc191766698d170f"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"services": [
|
|
28
|
+
{
|
|
29
|
+
"binding": "MEDIA_KIT",
|
|
30
|
+
"service": "staging-aigne-hub-media-kit"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"binding": "AUTH_SERVICE",
|
|
34
|
+
"service": "blocklet-service-staging",
|
|
35
|
+
"entrypoint": "BlockletServiceRPC"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"vars": {
|
|
39
|
+
"APP_NAME": "AIGNE Hub Payment Kit (staging)",
|
|
40
|
+
"APP_PID": "zNKWm5HBgaTLptTZBzjHo6PPFAp8X3n8pabY",
|
|
41
|
+
"APP_URL": "https://staging-aigne-hub-payment-kit.arcblock.workers.dev",
|
|
42
|
+
"COMPONENT_DID": "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk",
|
|
43
|
+
"MEDIA_KIT_URL": "https://staging-aigne-hub-media-kit.arcblock.workers.dev/image-bin",
|
|
44
|
+
"PAYMENT_CHANGE_LOCKED_PRICE": "1"
|
|
45
|
+
},
|
|
46
|
+
"queues": {
|
|
47
|
+
"producers": [
|
|
48
|
+
{
|
|
49
|
+
"binding": "JOB_QUEUE",
|
|
50
|
+
"queue": "staging-aigne-hub-payment-kit-jobs"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"consumers": [
|
|
54
|
+
{
|
|
55
|
+
"queue": "staging-aigne-hub-payment-kit-jobs",
|
|
56
|
+
"max_batch_size": 10,
|
|
57
|
+
"max_batch_timeout": 5,
|
|
58
|
+
"max_retries": 3,
|
|
59
|
+
"dead_letter_queue": "staging-aigne-hub-payment-kit-jobs-dlq"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"triggers": {
|
|
64
|
+
"crons": ["* * * * *"]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name = "payment-kit"
|
|
2
|
+
main = "dist/worker.js"
|
|
3
|
+
compatibility_date = "2024-12-01"
|
|
4
|
+
compatibility_flags = ["nodejs_compat"]
|
|
5
|
+
|
|
6
|
+
[build]
|
|
7
|
+
command = "node run-build.js"
|
|
8
|
+
|
|
9
|
+
[[d1_databases]]
|
|
10
|
+
binding = "DB"
|
|
11
|
+
database_name = "payment-kit-prod"
|
|
12
|
+
database_id = "ea6c75d0-39b8-40cd-a0ae-a2062e77c4b9"
|
|
13
|
+
migrations_dir = "migrations"
|
|
14
|
+
|
|
15
|
+
# Service Binding to DID Connect Auth Worker (blocklet-service)
|
|
16
|
+
[[services]]
|
|
17
|
+
binding = "AUTH_SERVICE"
|
|
18
|
+
service = "blocklet-service"
|
|
19
|
+
entrypoint = "BlockletServiceRPC"
|
|
20
|
+
|
|
21
|
+
[triggers]
|
|
22
|
+
crons = ["* * * * *"]
|
|
23
|
+
|
|
24
|
+
[vars]
|
|
25
|
+
APP_URL = "http://localhost:8787"
|
|
26
|
+
APP_NAME = "Payment Kit"
|
|
27
|
+
APP_PID = "payment-kit-dev"
|
|
28
|
+
COMPONENT_DID = "did:abt:test"
|
package/jest.config.js
CHANGED
|
@@ -10,19 +10,11 @@ module.exports = {
|
|
|
10
10
|
globalTeardown: '../../tools/jest-teardown.js',
|
|
11
11
|
transform: {
|
|
12
12
|
'^.+\\.ts$': 'ts-jest',
|
|
13
|
-
'^.+\\.js$': [
|
|
14
|
-
'ts-jest',
|
|
15
|
-
{
|
|
16
|
-
tsconfig: {
|
|
17
|
-
allowJs: true,
|
|
18
|
-
module: 'commonjs',
|
|
19
|
-
target: 'es2019',
|
|
20
|
-
},
|
|
21
|
-
diagnostics: false,
|
|
22
|
-
},
|
|
23
|
-
],
|
|
13
|
+
'^.+\\.js$': ['babel-jest', { presets: [['@babel/preset-env', { targets: { node: 'current' } }]] }],
|
|
24
14
|
},
|
|
25
|
-
transformIgnorePatterns: [
|
|
15
|
+
transformIgnorePatterns: [
|
|
16
|
+
'node_modules/(?!.*(@noble|@scure|string-width|strip-ansi|ansi-regex)/)',
|
|
17
|
+
],
|
|
26
18
|
testMatch: ['**/tests/**/*.spec.ts'],
|
|
27
19
|
collectCoverageFrom: ['api/src/**/*.ts'],
|
|
28
20
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"prelint": "npm run types",
|
|
@@ -47,35 +47,36 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@abtnode/cron": "^1.17.12",
|
|
50
|
-
"@arcblock/did": "^1.
|
|
51
|
-
"@arcblock/did-connect-
|
|
50
|
+
"@arcblock/did": "^1.30.9",
|
|
51
|
+
"@arcblock/did-connect-js": "4.0.0",
|
|
52
|
+
"@arcblock/did-connect-react": "^3.5.2",
|
|
52
53
|
"@arcblock/did-connect-storage-nedb": "^1.8.0",
|
|
53
|
-
"@arcblock/did-util": "^1.
|
|
54
|
-
"@arcblock/jwt": "^1.
|
|
55
|
-
"@arcblock/react-hooks": "^3.5.
|
|
56
|
-
"@arcblock/ux": "^3.5.
|
|
57
|
-
"@arcblock/validator": "^1.
|
|
58
|
-
"@arcblock/vc": "^1.
|
|
54
|
+
"@arcblock/did-util": "^1.30.9",
|
|
55
|
+
"@arcblock/jwt": "^1.30.9",
|
|
56
|
+
"@arcblock/react-hooks": "^3.5.2",
|
|
57
|
+
"@arcblock/ux": "^3.5.2",
|
|
58
|
+
"@arcblock/validator": "^1.30.9",
|
|
59
|
+
"@arcblock/vc": "^1.30.9",
|
|
59
60
|
"@blocklet/did-space-js": "^1.2.23",
|
|
60
61
|
"@blocklet/error": "^0.3.5",
|
|
61
62
|
"@blocklet/js-sdk": "^1.17.12",
|
|
62
63
|
"@blocklet/logger": "^1.17.12",
|
|
63
|
-
"@blocklet/payment-broker-client": "1.
|
|
64
|
-
"@blocklet/payment-react": "1.
|
|
65
|
-
"@blocklet/payment-vendor": "1.
|
|
64
|
+
"@blocklet/payment-broker-client": "1.28.0",
|
|
65
|
+
"@blocklet/payment-react": "1.28.0",
|
|
66
|
+
"@blocklet/payment-vendor": "1.28.0",
|
|
66
67
|
"@blocklet/sdk": "^1.17.12",
|
|
67
|
-
"@blocklet/ui-react": "^3.5.
|
|
68
|
-
"@blocklet/uploader": "^0.3.
|
|
68
|
+
"@blocklet/ui-react": "^3.5.2",
|
|
69
|
+
"@blocklet/uploader": "^0.3.20",
|
|
69
70
|
"@blocklet/xss": "^0.3.16",
|
|
70
71
|
"@mui/icons-material": "^7.1.2",
|
|
71
72
|
"@mui/lab": "7.0.0-beta.14",
|
|
72
73
|
"@mui/material": "^7.1.2",
|
|
73
74
|
"@mui/system": "^7.1.1",
|
|
74
|
-
"@ocap/asset": "^1.
|
|
75
|
-
"@ocap/client": "^1.
|
|
76
|
-
"@ocap/mcrypto": "^1.
|
|
77
|
-
"@ocap/util": "^1.
|
|
78
|
-
"@ocap/wallet": "^1.
|
|
75
|
+
"@ocap/asset": "^1.30.9",
|
|
76
|
+
"@ocap/client": "^1.30.9",
|
|
77
|
+
"@ocap/mcrypto": "^1.30.9",
|
|
78
|
+
"@ocap/util": "^1.30.9",
|
|
79
|
+
"@ocap/wallet": "^1.30.9",
|
|
79
80
|
"@stripe/react-stripe-js": "^2.9.0",
|
|
80
81
|
"@stripe/stripe-js": "^2.4.0",
|
|
81
82
|
"ahooks": "^3.8.5",
|
|
@@ -102,13 +103,16 @@
|
|
|
102
103
|
"joi": "17.12.2",
|
|
103
104
|
"json-stable-stringify": "^1.3.0",
|
|
104
105
|
"jspdf": "^4.2.1",
|
|
105
|
-
"lodash": "^4.
|
|
106
|
+
"lodash": "^4.17.21",
|
|
107
|
+
"lodash-es": "^4.18.1",
|
|
106
108
|
"morgan": "^1.10.0",
|
|
107
109
|
"mui-daterange-picker": "^1.0.5",
|
|
108
110
|
"nanoid": "^3.3.11",
|
|
109
111
|
"numbro": "^2.5.0",
|
|
110
112
|
"p-all": "3.0.0",
|
|
111
113
|
"p-wait-for": "^3.2.0",
|
|
114
|
+
"pg": "^8.20.0",
|
|
115
|
+
"postgres": "^3.4.8",
|
|
112
116
|
"pretty-ms-i18n": "^1.0.3",
|
|
113
117
|
"react": "^19.1.0",
|
|
114
118
|
"react-dom": "^19.1.0",
|
|
@@ -133,7 +137,7 @@
|
|
|
133
137
|
"devDependencies": {
|
|
134
138
|
"@abtnode/types": "^1.17.12",
|
|
135
139
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
136
|
-
"@blocklet/payment-types": "1.
|
|
140
|
+
"@blocklet/payment-types": "1.28.0",
|
|
137
141
|
"@types/cookie-parser": "^1.4.9",
|
|
138
142
|
"@types/cors": "^2.8.19",
|
|
139
143
|
"@types/debug": "^4.1.12",
|
|
@@ -180,5 +184,5 @@
|
|
|
180
184
|
"parser": "typescript"
|
|
181
185
|
}
|
|
182
186
|
},
|
|
183
|
-
"gitHead": "
|
|
187
|
+
"gitHead": "1486b54f913b83fb42323a89cce7503814d0685a"
|
|
184
188
|
}
|
package/src/app.tsx
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import './global.css';
|
|
2
|
+
import './libs/patch-user-card';
|
|
2
3
|
|
|
3
4
|
import Center from '@arcblock/ux/lib/Center';
|
|
4
5
|
import withTracker from '@arcblock/ux/lib/withTracker';
|
|
5
6
|
import { ConfigProvider } from '@arcblock/ux/lib/Config';
|
|
6
7
|
import { ToastProvider } from '@arcblock/ux/lib/Toast';
|
|
7
8
|
import { CircularProgress } from '@mui/material';
|
|
8
|
-
import React, { Suspense } from 'react';
|
|
9
|
+
import React, { Suspense, useEffect } from 'react';
|
|
9
10
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
10
11
|
import { PaymentThemeProvider, usePreventWheel } from '@blocklet/payment-react';
|
|
11
|
-
import { Navigate, Route, BrowserRouter as Router, Routes } from 'react-router-dom';
|
|
12
|
+
import { Navigate, Route, BrowserRouter as Router, Routes, useNavigate } from 'react-router-dom';
|
|
12
13
|
import { joinURL } from 'ufo';
|
|
13
14
|
|
|
14
15
|
import ErrorFallback from './components/error-fallback';
|
|
15
|
-
import
|
|
16
|
+
import UserLayoutDefault from './components/layout/user';
|
|
17
|
+
import UserLayoutCF from './components/layout/user-cf';
|
|
16
18
|
import { TransitionProvider } from './components/progress-bar';
|
|
17
19
|
import { SessionProvider } from './contexts/session';
|
|
18
20
|
import { translations } from './locales';
|
|
19
21
|
|
|
22
|
+
const UserLayout = (window as any).blocklet?.cloudflareWorker ? UserLayoutCF : UserLayoutDefault;
|
|
23
|
+
|
|
20
24
|
const HomePage = React.lazy(() => import('./pages/home'));
|
|
21
25
|
const CheckoutPage = React.lazy(() => import('./pages/checkout'));
|
|
22
26
|
const AdminPage = React.lazy(() => import('./pages/admin'));
|
|
@@ -43,10 +47,63 @@ const CustomerBalanceRecharge = React.lazy(() => import('./pages/customer/rechar
|
|
|
43
47
|
// },
|
|
44
48
|
// });
|
|
45
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Intercept anchor clicks on internal URLs and do client-side navigation.
|
|
52
|
+
*
|
|
53
|
+
* Some third-party components (e.g. @blocklet/ui-react Dashboard sidebar) render
|
|
54
|
+
* navigation items as `<a href="/admin">` with `external: true`, which triggers
|
|
55
|
+
* a full page reload on click. That reload re-runs session bootstrap and races
|
|
56
|
+
* with page-level auth checks, sometimes redirecting the user back to "/".
|
|
57
|
+
*
|
|
58
|
+
* This handler catches all left-clicks on `<a>` elements with same-origin URLs
|
|
59
|
+
* and converts them into React Router navigation. Modified clicks (cmd/ctrl/shift),
|
|
60
|
+
* target="_blank", and external URLs are left untouched.
|
|
61
|
+
*/
|
|
62
|
+
function useInternalLinkInterceptor() {
|
|
63
|
+
const navigate = useNavigate();
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const handler = (e: MouseEvent) => {
|
|
66
|
+
// Only primary button, no modifier keys (so cmd+click still opens in new tab)
|
|
67
|
+
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
68
|
+
const anchor = (e.target as HTMLElement | null)?.closest('a');
|
|
69
|
+
if (!anchor) return;
|
|
70
|
+
// Skip if not a real anchor with href
|
|
71
|
+
const href = anchor.getAttribute('href');
|
|
72
|
+
if (!href) return;
|
|
73
|
+
// Skip target="_blank" / download / rel=external
|
|
74
|
+
if (anchor.target && anchor.target !== '' && anchor.target !== '_self') return;
|
|
75
|
+
if (anchor.hasAttribute('download')) return;
|
|
76
|
+
// Skip non-http(s) schemes: mailto:, tel:, javascript:, #hash, etc.
|
|
77
|
+
if (/^[a-z]+:/i.test(href) && !/^https?:/i.test(href)) return;
|
|
78
|
+
if (href.startsWith('#')) return;
|
|
79
|
+
// Resolve to absolute URL and check same-origin
|
|
80
|
+
let url: URL;
|
|
81
|
+
try {
|
|
82
|
+
url = new URL(href, window.location.href);
|
|
83
|
+
} catch {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (url.origin !== window.location.origin) return;
|
|
87
|
+
// Convert to client-side navigation — strip basename prefix so React Router
|
|
88
|
+
// doesn't double it (e.g. /payment/integrations → /integrations when basename="/payment/")
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
const prefix = window?.blocklet?.prefix || '/';
|
|
91
|
+
let navPath = url.pathname + url.search + url.hash;
|
|
92
|
+
if (prefix !== '/' && navPath.startsWith(prefix.replace(/\/$/, ''))) {
|
|
93
|
+
navPath = navPath.slice(prefix.replace(/\/$/, '').length) || '/';
|
|
94
|
+
}
|
|
95
|
+
navigate(navPath);
|
|
96
|
+
};
|
|
97
|
+
document.addEventListener('click', handler);
|
|
98
|
+
return () => document.removeEventListener('click', handler);
|
|
99
|
+
}, [navigate]);
|
|
100
|
+
}
|
|
101
|
+
|
|
46
102
|
function App() {
|
|
103
|
+
useInternalLinkInterceptor();
|
|
47
104
|
return (
|
|
48
105
|
<TransitionProvider>
|
|
49
|
-
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={window.location.reload}>
|
|
106
|
+
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => window.location.reload()}>
|
|
50
107
|
<Suspense
|
|
51
108
|
fallback={
|
|
52
109
|
<Center>
|
|
@@ -194,6 +251,7 @@ export default function WrappedApp() {
|
|
|
194
251
|
<PaymentThemeProvider>
|
|
195
252
|
<SessionProvider
|
|
196
253
|
serviceHost={prefix}
|
|
254
|
+
useSocket={!(window as any).blocklet?.cloudflareWorker}
|
|
197
255
|
protectedRoutes={['/admin/*', '/customer/*', '/integrations/*'].map((item) => joinURL(prefix, item))}>
|
|
198
256
|
<Router basename={prefix}>
|
|
199
257
|
<AppWithTracker />
|
|
@@ -51,19 +51,15 @@ export default function CustomerLink({
|
|
|
51
51
|
popupInfoType={InfoType.Minimal}
|
|
52
52
|
showDid={size !== 'small'}
|
|
53
53
|
popupShowDid
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
),
|
|
64
|
-
},
|
|
65
|
-
}
|
|
66
|
-
: {})}
|
|
54
|
+
user={{
|
|
55
|
+
fullName: customer.name || customer.email,
|
|
56
|
+
did: customer.did,
|
|
57
|
+
email: customer.email,
|
|
58
|
+
avatar: getCustomerAvatar(
|
|
59
|
+
customer?.did,
|
|
60
|
+
customer?.updated_at ? new Date(customer.updated_at).toISOString() : ''
|
|
61
|
+
),
|
|
62
|
+
}}
|
|
67
63
|
{...cardProps}
|
|
68
64
|
/>
|
|
69
65
|
);
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
ClickAwayListener,
|
|
19
19
|
} from '@mui/material';
|
|
20
20
|
import { useRequest } from 'ahooks';
|
|
21
|
-
import { FormProvider, useForm, Controller
|
|
21
|
+
import { FormProvider, useForm, Controller } from 'react-hook-form';
|
|
22
22
|
import { useMobile } from '@blocklet/payment-react';
|
|
23
23
|
import api from '../../libs/api';
|
|
24
24
|
|
|
@@ -61,7 +61,8 @@ function TimeSelector({
|
|
|
61
61
|
timeFormatErrorMessage,
|
|
62
62
|
}: {
|
|
63
63
|
name: string;
|
|
64
|
-
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
control: any;
|
|
65
66
|
required: boolean;
|
|
66
67
|
timeFormatErrorMessage: string;
|
|
67
68
|
}) {
|
|
@@ -309,6 +309,10 @@ function SearchCustomers({ setSearch, search = defaultProps.search }: Pick<Props
|
|
|
309
309
|
e.stopPropagation();
|
|
310
310
|
}}
|
|
311
311
|
onClick={(e) => e.stopPropagation()}
|
|
312
|
+
// Stop MUI <Menu>'s built-in letter-key navigation from stealing keystrokes
|
|
313
|
+
// (it jumps to a MenuItem starting with the typed letter, which makes the
|
|
314
|
+
// search field appear to "swallow" inputs like 'a'/'w'). See #1357.
|
|
315
|
+
onKeyDown={(e) => e.stopPropagation()}
|
|
312
316
|
/>
|
|
313
317
|
</Box>
|
|
314
318
|
{customers.map((x: any) => (
|
|
@@ -431,7 +431,15 @@ export default function InvoiceList({
|
|
|
431
431
|
sort: true,
|
|
432
432
|
customBodyRenderLite: (_: string, index: number) => {
|
|
433
433
|
const item = data.list[index] as TInvoiceExpanded;
|
|
434
|
-
|
|
434
|
+
const hasPeriod = item.period_start > 0 && item.period_end > 0;
|
|
435
|
+
const content = <InvoiceLink invoice={item}>{formatTime(item.updated_at)}</InvoiceLink>;
|
|
436
|
+
if (!hasPeriod) return content;
|
|
437
|
+
return (
|
|
438
|
+
<Tooltip
|
|
439
|
+
title={`${t('common.billingPeriod')}: ${formatTime(item.period_start * 1000)} ~ ${formatTime(item.period_end * 1000)}`}>
|
|
440
|
+
{content}
|
|
441
|
+
</Tooltip>
|
|
442
|
+
);
|
|
435
443
|
},
|
|
436
444
|
},
|
|
437
445
|
},
|
|
@@ -17,7 +17,8 @@ export async function loadFont(): Promise<boolean> {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function loadImage(url: string): Promise<HTMLImageElement> {
|
|
20
|
+
export function loadImage(url: string): Promise<HTMLImageElement | null> {
|
|
21
|
+
if (!url) return Promise.resolve(null);
|
|
21
22
|
return new Promise((resolve, reject) => {
|
|
22
23
|
const img = new Image();
|
|
23
24
|
img.crossOrigin = 'anonymous';
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
|
-
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
2
|
import { PaymentProvider } from '@blocklet/payment-react';
|
|
4
3
|
import Dashboard from '@blocklet/ui-react/lib/Dashboard';
|
|
5
4
|
import { styled } from '@mui/system';
|
|
6
5
|
import { useEffect } from 'react';
|
|
7
6
|
|
|
8
|
-
import {
|
|
7
|
+
import { Box, CircularProgress } from '@mui/material';
|
|
9
8
|
import { useSessionContext } from '../../contexts/session';
|
|
10
9
|
|
|
10
|
+
function LayoutLoading() {
|
|
11
|
+
return (
|
|
12
|
+
<Box
|
|
13
|
+
sx={{
|
|
14
|
+
minHeight: '100vh',
|
|
15
|
+
display: 'flex',
|
|
16
|
+
alignItems: 'center',
|
|
17
|
+
justifyContent: 'center',
|
|
18
|
+
}}>
|
|
19
|
+
<CircularProgress />
|
|
20
|
+
</Box>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// window.blocklet is bootstrapped synchronously in public/index.html (CF) but
|
|
25
|
+
// the full payload is overlaid from /__blocklet__.js. Don't render children
|
|
26
|
+
// (which may fire API requests on mount) until the critical fields are in
|
|
27
|
+
// place — otherwise requests go out against a half-initialized config and
|
|
28
|
+
// can cascade into auth failures / unintended redirects.
|
|
29
|
+
function isBlockletReady() {
|
|
30
|
+
const b = (window as any).blocklet;
|
|
31
|
+
return !!(b && b.appPid && b.prefix);
|
|
32
|
+
}
|
|
33
|
+
|
|
11
34
|
const Root = styled(Dashboard)<{ padding: string }>`
|
|
12
35
|
width: 100%;
|
|
13
36
|
background-color: ${({ theme }) => theme.palette.background.default};
|
|
@@ -62,12 +85,11 @@ const Root = styled(Dashboard)<{ padding: string }>`
|
|
|
62
85
|
`;
|
|
63
86
|
|
|
64
87
|
export default function Layout(props: any) {
|
|
65
|
-
const { t } = useLocaleContext();
|
|
66
88
|
const { session, connectApi, events } = useSessionContext();
|
|
67
89
|
|
|
68
90
|
useEffect(() => {
|
|
69
91
|
events.once('logout', () => {
|
|
70
|
-
window.location.href = '/';
|
|
92
|
+
window.location.href = window?.blocklet?.prefix || '/';
|
|
71
93
|
});
|
|
72
94
|
}, []);
|
|
73
95
|
|
|
@@ -78,6 +100,14 @@ export default function Layout(props: any) {
|
|
|
78
100
|
}
|
|
79
101
|
}, [session.initialized]);
|
|
80
102
|
|
|
103
|
+
// Show a loading state — not a "Redirecting..." text and not a blank page —
|
|
104
|
+
// while either window.blocklet or the session is still resolving. Admin
|
|
105
|
+
// pages fire authenticated API requests on mount, so children must not
|
|
106
|
+
// render until both are fully in place.
|
|
107
|
+
if (!isBlockletReady() || !session.initialized) {
|
|
108
|
+
return <LayoutLoading />;
|
|
109
|
+
}
|
|
110
|
+
|
|
81
111
|
if (session.user) {
|
|
82
112
|
return (
|
|
83
113
|
<PaymentProvider session={session} connect={connectApi}>
|
|
@@ -86,5 +116,9 @@ export default function Layout(props: any) {
|
|
|
86
116
|
);
|
|
87
117
|
}
|
|
88
118
|
|
|
89
|
-
|
|
119
|
+
// Session initialized but not logged in: the effect above triggers a
|
|
120
|
+
// redirect-based login. Keep showing the loading state (instead of a
|
|
121
|
+
// "Redirecting..." text) so the user isn't confused when the actual
|
|
122
|
+
// navigation hasn't happened yet.
|
|
123
|
+
return <LayoutLoading />;
|
|
90
124
|
}
|