payment-kit 1.29.1 → 1.29.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/dev.ts +41 -2
- package/api/hono.d.ts +42 -0
- package/api/node-sqlite.d.ts +12 -0
- package/api/src/bootstrap.ts +47 -0
- package/api/src/crons/base.ts +3 -3
- package/api/src/crons/currency.ts +1 -1
- package/api/src/crons/index.ts +41 -37
- package/api/src/crons/metering-subscription-detection.ts +1 -1
- package/api/src/crons/overdue-detection.ts +2 -2
- package/api/src/crons/retry-pending-events.ts +6 -0
- package/api/src/crons/tenant-fanout.ts +82 -0
- package/api/src/host-node/did-connect-runtime-node.ts +33 -0
- package/api/src/host-node/serve-static-arc.ts +68 -0
- package/api/src/host-node/serve-static.ts +41 -0
- package/api/src/index.ts +22 -161
- package/api/src/integrations/app-store/client.ts +3 -4
- package/api/src/integrations/app-store/handlers/subscription.ts +7 -7
- package/api/src/integrations/app-store/signed-data-verifier.ts +3 -2
- package/api/src/integrations/arcblock/token.ts +21 -7
- package/api/src/integrations/google-play/handlers/subscription.ts +6 -6
- package/api/src/integrations/google-play/handlers/voided.ts +2 -2
- package/api/src/integrations/google-play/verify.ts +3 -2
- package/api/src/integrations/iap-reconcile.ts +3 -5
- package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
- package/api/src/integrations/stripe/handlers/subscription.ts +3 -3
- package/api/src/libs/archive/query.ts +19 -0
- package/api/src/libs/audit.ts +61 -4
- package/api/src/libs/auth.ts +247 -47
- package/api/src/libs/context.ts +89 -1
- package/api/src/libs/currency.ts +2 -2
- package/api/src/libs/dayjs.ts +8 -2
- package/api/src/libs/did-connect/runtime-did-connect-js.ts +88 -0
- package/api/src/libs/did-connect/tenant-identity.ts +221 -0
- package/api/src/libs/drivers/auth-storage.ts +118 -0
- package/api/src/libs/drivers/cron.ts +264 -0
- package/api/src/libs/drivers/db.ts +170 -0
- package/api/src/libs/drivers/identity.ts +142 -0
- package/api/src/libs/drivers/index.ts +40 -0
- package/api/src/libs/drivers/locks.ts +226 -0
- package/api/src/libs/drivers/migrate-runner.ts +70 -0
- package/api/src/libs/drivers/queue.ts +104 -0
- package/api/src/libs/drivers/secrets.ts +194 -0
- package/api/src/libs/env.ts +170 -54
- package/api/src/libs/exchange-rate/service.ts +7 -6
- package/api/src/libs/http-fetch-adapter.ts +60 -0
- package/api/src/libs/invoice.ts +1 -1
- package/api/src/libs/lock.ts +51 -47
- package/api/src/libs/logger.ts +48 -8
- package/api/src/libs/notification/index.ts +1 -1
- package/api/src/libs/notification/template/customer-credit-low-balance.ts +2 -1
- package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -1
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -1
- package/api/src/libs/overdraft-protection.ts +1 -1
- package/api/src/libs/payout.ts +1 -1
- package/api/src/libs/queue/index.ts +271 -52
- package/api/src/libs/queue/runtime.ts +175 -0
- package/api/src/libs/resource.ts +3 -3
- package/api/src/libs/secrets.ts +38 -0
- package/api/src/libs/session.ts +3 -2
- package/api/src/libs/subscription.ts +5 -5
- package/api/src/libs/tenant.ts +92 -0
- package/api/src/libs/url.ts +3 -3
- package/api/src/libs/util.ts +21 -13
- package/api/src/middlewares/hono/cdn.ts +63 -0
- package/api/src/middlewares/hono/context.ts +80 -0
- package/api/src/middlewares/hono/csrf.ts +83 -0
- package/api/src/middlewares/hono/fallback.ts +194 -0
- package/api/src/middlewares/hono/pipeline.ts +73 -0
- package/api/src/middlewares/hono/resource-mount.ts +42 -0
- package/api/src/middlewares/hono/resource.ts +63 -0
- package/api/src/middlewares/hono/security.ts +209 -0
- package/api/src/middlewares/hono/session.ts +114 -0
- package/api/src/middlewares/hono/xss.ts +61 -0
- package/api/src/queues/auto-recharge.ts +12 -10
- package/api/src/queues/checkout-session.ts +38 -21
- package/api/src/queues/credit-consume.ts +40 -36
- package/api/src/queues/credit-grant.ts +25 -18
- package/api/src/queues/credit-reconciliation.ts +7 -5
- package/api/src/queues/discount-status.ts +9 -6
- package/api/src/queues/event.ts +41 -11
- package/api/src/queues/exchange-rate-health.ts +49 -30
- package/api/src/queues/invoice.ts +18 -15
- package/api/src/queues/notification.ts +14 -7
- package/api/src/queues/payment.ts +64 -37
- package/api/src/queues/payout.ts +37 -21
- package/api/src/queues/refund.ts +36 -18
- package/api/src/queues/subscription.ts +83 -53
- package/api/src/queues/token-transfer.ts +15 -10
- package/api/src/queues/usage-record.ts +8 -5
- package/api/src/queues/vendors/commission.ts +7 -5
- package/api/src/queues/vendors/fulfillment-coordinator.ts +17 -13
- package/api/src/queues/vendors/fulfillment.ts +4 -2
- package/api/src/queues/vendors/return-processor.ts +5 -3
- package/api/src/queues/vendors/return-scanner.ts +5 -4
- package/api/src/queues/vendors/status-check.ts +10 -7
- package/api/src/queues/webhook.ts +60 -32
- package/api/src/routes/connect/shared.ts +1 -2
- package/api/src/routes/connect/subscribe.ts +3 -3
- package/api/src/routes/{archive.ts → hono/archive.ts} +69 -64
- package/api/src/routes/{auto-recharge-configs.ts → hono/auto-recharge-configs.ts} +39 -28
- package/api/src/routes/{checkout-sessions.ts → hono/checkout-sessions.ts} +790 -923
- package/api/src/routes/{coupons.ts → hono/coupons.ts} +93 -76
- package/api/src/routes/{credit-grants.ts → hono/credit-grants.ts} +140 -126
- package/api/src/routes/hono/credit-tokens.ts +43 -0
- package/api/src/routes/{credit-transactions.ts → hono/credit-transactions.ts} +37 -29
- package/api/src/routes/{customers.ts → hono/customers.ts} +199 -224
- package/api/src/routes/{donations.ts → hono/donations.ts} +41 -32
- package/api/src/routes/{entitlements.ts → hono/entitlements.ts} +28 -25
- package/api/src/routes/{events.ts → hono/events.ts} +107 -71
- package/api/src/routes/{exchange-rate-providers.ts → hono/exchange-rate-providers.ts} +138 -126
- package/api/src/routes/hono/exchange-rates.ts +77 -0
- package/api/src/routes/hono/index.ts +115 -0
- package/api/src/routes/{integrations → hono/integrations}/app-store.ts +68 -48
- package/api/src/routes/{integrations → hono/integrations}/google-play.ts +78 -58
- package/api/src/routes/hono/integrations/stripe.ts +74 -0
- package/api/src/routes/{invoices.ts → hono/invoices.ts} +253 -244
- package/api/src/routes/{meter-events.ts → hono/meter-events.ts} +120 -110
- package/api/src/routes/hono/meters.ts +288 -0
- package/api/src/routes/hono/passports.ts +73 -0
- package/api/src/routes/{payment-currencies.ts → hono/payment-currencies.ts} +219 -197
- package/api/src/routes/{payment-intents.ts → hono/payment-intents.ts} +136 -132
- package/api/src/routes/{payment-links.ts → hono/payment-links.ts} +145 -128
- package/api/src/routes/{payment-methods.ts → hono/payment-methods.ts} +125 -93
- package/api/src/routes/{payment-stats.ts → hono/payment-stats.ts} +30 -25
- package/api/src/routes/{payouts.ts → hono/payouts.ts} +55 -47
- package/api/src/routes/{prices.ts → hono/prices.ts} +265 -242
- package/api/src/routes/{pricing-table.ts → hono/pricing-table.ts} +94 -87
- package/api/src/routes/{products.ts → hono/products.ts} +172 -159
- package/api/src/routes/{promotion-codes.ts → hono/promotion-codes.ts} +207 -185
- package/api/src/routes/hono/redirect.ts +24 -0
- package/api/src/routes/{refunds.ts → hono/refunds.ts} +98 -83
- package/api/src/routes/{settings.ts → hono/settings.ts} +64 -55
- package/api/src/routes/{subscription-items.ts → hono/subscription-items.ts} +64 -57
- package/api/src/routes/{subscriptions.ts → hono/subscriptions.ts} +475 -528
- package/api/src/routes/{tax-rates.ts → hono/tax-rates.ts} +71 -70
- package/api/src/routes/hono/tool.ts +69 -0
- package/api/src/routes/{usage-records.ts → hono/usage-records.ts} +47 -42
- package/api/src/routes/{vendor.ts → hono/vendor.ts} +315 -167
- package/api/src/routes/{webhook-attempts.ts → hono/webhook-attempts.ts} +17 -13
- package/api/src/routes/hono/webhook-endpoints.ts +126 -0
- package/api/src/service.ts +814 -0
- package/api/src/store/migrations/20230911-seeding.ts +2 -1
- package/api/src/store/migrations/20260609-remove-did-space-jobs.ts +23 -0
- package/api/src/store/migrations/20260610-tenant-columns.ts +40 -0
- package/api/src/store/migrations/20260611-tenant-backfill.ts +33 -0
- package/api/src/store/models/auto-recharge-config.ts +22 -10
- package/api/src/store/models/checkout-session.ts +15 -14
- package/api/src/store/models/coupon.ts +29 -20
- package/api/src/store/models/credit-grant.ts +38 -29
- package/api/src/store/models/credit-transaction.ts +32 -21
- package/api/src/store/models/customer.ts +19 -17
- package/api/src/store/models/discount.ts +11 -2
- package/api/src/store/models/entitlement-grant.ts +21 -9
- package/api/src/store/models/entitlement-product.ts +21 -9
- package/api/src/store/models/entitlement.ts +19 -10
- package/api/src/store/models/event.ts +18 -9
- package/api/src/store/models/exchange-rate-provider.ts +17 -4
- package/api/src/store/models/invoice-item.ts +18 -9
- package/api/src/store/models/invoice.ts +16 -8
- package/api/src/store/models/meter-event.ts +27 -9
- package/api/src/store/models/meter.ts +31 -22
- package/api/src/store/models/payment-currency.ts +25 -8
- package/api/src/store/models/payment-intent.ts +15 -6
- package/api/src/store/models/payment-link.ts +15 -6
- package/api/src/store/models/payment-method.ts +38 -22
- package/api/src/store/models/payment-stat.ts +18 -9
- package/api/src/store/models/payout.ts +15 -6
- package/api/src/store/models/price-quote.ts +17 -8
- package/api/src/store/models/price.ts +24 -12
- package/api/src/store/models/pricing-table.ts +29 -20
- package/api/src/store/models/product-vendor.ts +20 -10
- package/api/src/store/models/product.ts +15 -6
- package/api/src/store/models/promotion-code.ts +14 -6
- package/api/src/store/models/refund.ts +15 -6
- package/api/src/store/models/revenue-snapshot.ts +21 -9
- package/api/src/store/models/setting.ts +18 -9
- package/api/src/store/models/setup-intent.ts +36 -27
- package/api/src/store/models/subscription-item.ts +21 -9
- package/api/src/store/models/subscription-schedule.ts +21 -9
- package/api/src/store/models/subscription.ts +21 -10
- package/api/src/store/models/tax-rate.ts +29 -21
- package/api/src/store/models/usage-record.ts +11 -2
- package/api/src/store/models/webhook-attempt.ts +18 -9
- package/api/src/store/models/webhook-endpoint.ts +18 -9
- package/api/src/store/scoped-core.ts +55 -0
- package/api/src/store/scoped.ts +247 -0
- package/api/src/store/sequelize.ts +82 -23
- package/api/src/store/sql-migrations.ts +20 -0
- package/api/src/store/tenant-backfill.ts +260 -0
- package/api/src/store/tenant-model.ts +124 -0
- package/api/src/store/tenant-tables.ts +50 -0
- package/api/tests/bootstrap/bootstrap.spec.ts +162 -0
- package/api/tests/crons/tenant-fanout.spec.ts +158 -0
- package/api/tests/embedded/embedded-multi-mode-d3.spec.ts +257 -0
- package/api/tests/fixtures/bare-query-violation.ts +13 -0
- package/api/tests/fixtures/core-env-violation.ts +10 -0
- package/api/tests/fixtures/host-read-violation.ts +19 -0
- package/api/tests/fixtures/tenants.ts +4 -0
- package/api/tests/integrations/iap-tenant.spec.ts +284 -0
- package/api/tests/libs/archive-query.spec.ts +26 -0
- package/api/tests/libs/audit-tenant.spec.ts +153 -0
- package/api/tests/libs/context.spec.ts +204 -0
- package/api/tests/libs/core-config.spec.ts +115 -0
- package/api/tests/libs/cron-driver-d2.spec.ts +237 -0
- package/api/tests/libs/crons-conservation-d2.spec.ts +52 -0
- package/api/tests/libs/did-connect-runtime-js.spec.ts +98 -0
- package/api/tests/libs/did-connect-tenant-identity.spec.ts +159 -0
- package/api/tests/libs/lock-tenant.spec.ts +66 -0
- package/api/tests/libs/scoped.spec.ts +222 -0
- package/api/tests/libs/secrets-facade.spec.ts +52 -0
- package/api/tests/libs/service-host.spec.ts +37 -0
- package/api/tests/libs/tenancy-slot-authority.spec.ts +209 -0
- package/api/tests/libs/tenant-middleware.spec.ts +42 -0
- package/api/tests/libs/tenant-scanner.spec.ts +120 -0
- package/api/tests/middlewares/hono/cdn.spec.ts +70 -0
- package/api/tests/middlewares/hono/context.spec.ts +113 -0
- package/api/tests/middlewares/hono/csrf.spec.ts +136 -0
- package/api/tests/middlewares/hono/fallback.spec.ts +67 -0
- package/api/tests/middlewares/hono/pipeline.spec.ts +47 -0
- package/api/tests/middlewares/hono/security.spec.ts +181 -0
- package/api/tests/middlewares/hono/session.spec.ts +42 -0
- package/api/tests/middlewares/hono/xss.spec.ts +81 -0
- package/api/tests/models/tenant-backfill.spec.ts +287 -0
- package/api/tests/models/tenant-columns-model.spec.ts +46 -0
- package/api/tests/models/tenant-columns.spec.ts +161 -0
- package/api/tests/queues/credit-consume-batch.spec.ts +8 -1
- package/api/tests/queues/credit-consume.spec.ts +8 -1
- package/api/tests/queues/event-tenant.spec.ts +292 -0
- package/api/tests/queues/exchange-rate-health-tenant-d6.spec.ts +62 -0
- package/api/tests/queues/queue-parity.spec.ts +249 -0
- package/api/tests/queues/queue-runtime-surface.spec.ts +277 -0
- package/api/tests/queues/queue-teardown-d2.spec.ts +127 -0
- package/api/tests/queues/tenant-matrix-a.spec.ts +245 -0
- package/api/tests/queues/tenant-matrix-b.spec.ts +168 -0
- package/api/tests/routes/connect/hono-attach.spec.ts +107 -0
- package/api/tests/service/collapse.spec.ts +96 -0
- package/api/tests/service/didconnect-storage-slot.spec.ts +60 -0
- package/api/tests/service/fail-closed-http.spec.ts +79 -0
- package/api/tests/service/static-arc-handler.spec.ts +101 -0
- package/api/tests/service/static-externalized.spec.ts +48 -0
- package/api/tests/store/tenant-crosscut.spec.ts +202 -0
- package/api/tests/store/tenant-model-spike.spec.ts +177 -0
- package/api/tests/store/tenant-model.spec.ts +162 -0
- package/api/tests/store/tenant-residual.spec.ts +196 -0
- package/api/third.d.ts +4 -0
- package/blocklet.yml +1 -1
- package/cloudflare/MIGRATION-RUNBOOK.md +3 -8
- package/cloudflare/README.md +34 -27
- package/cloudflare/STAGING-MIGRATION-GUIDE.md +3 -15
- package/cloudflare/build.ts +33 -13
- package/cloudflare/cf-adapter.ts +419 -0
- package/cloudflare/did-connect-runtime.ts +96 -0
- package/cloudflare/did-connect-token-storage.ts +151 -0
- package/cloudflare/esbuild-cf-config.cjs +407 -0
- package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
- package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
- package/cloudflare/migrations/0008_schema_parity.sql +16 -0
- package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
- package/cloudflare/queue-runtime-mode.ts +13 -0
- package/cloudflare/run-build.js +33 -403
- package/cloudflare/scripts/cf-package-import-probe.mjs +90 -0
- package/cloudflare/scripts/didconnect-mock-smoke.mjs +140 -0
- package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
- package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
- package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
- package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
- package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
- package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
- package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +16 -1
- package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +18 -3
- package/cloudflare/shims/cron.ts +38 -158
- package/cloudflare/shims/events.ts +124 -0
- package/cloudflare/shims/fastq.ts +15 -1
- package/cloudflare/shims/nedb-storage.ts +16 -8
- package/cloudflare/shims/xss.ts +8 -0
- package/cloudflare/tenant-middleware.ts +36 -0
- package/cloudflare/tests/cf-adapter.spec.ts +244 -0
- package/cloudflare/tests/did-connect-token-storage.spec.ts +105 -0
- package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
- package/cloudflare/tests/worker-handler-gate.spec.ts +69 -0
- package/cloudflare/vite.config.ts +53 -45
- package/cloudflare/worker.ts +261 -448
- package/cloudflare/wrangler.json +0 -6
- package/cloudflare/wrangler.jsonc +0 -6
- package/cloudflare/wrangler.local-e2e.jsonc +25 -0
- package/cloudflare/wrangler.staging.json +0 -6
- package/jest.config.js +3 -1
- package/package.json +33 -38
- package/scripts/bootstrap-inject.ts +166 -0
- package/scripts/core-env-whitelist.json +1 -0
- package/scripts/e2e-12b-runtime.ts +149 -0
- package/scripts/e2e-core-config.ts +125 -0
- package/scripts/e2e-d1-tenancy.ts +116 -0
- package/scripts/e2e-d2-cron-queue.ts +139 -0
- package/scripts/e2e-d3-embedded-multi.ts +171 -0
- package/scripts/e2e-hono-s2.ts +125 -0
- package/scripts/e2e-hono-s3e.ts +135 -0
- package/scripts/e2e-hono-s4.ts +114 -0
- package/scripts/e2e-migration-contract.ts +100 -0
- package/scripts/e2e-s0.ts +61 -0
- package/scripts/e2e-s1.ts +107 -0
- package/scripts/e2e-s2.ts +178 -0
- package/scripts/e2e-s3.ts +110 -0
- package/scripts/e2e-s4.ts +191 -0
- package/scripts/e2e-s5.ts +139 -0
- package/scripts/e2e-s6.ts +127 -0
- package/scripts/e2e-tenant-model.ts +119 -0
- package/scripts/e2e-tenant-worker.ts +199 -0
- package/scripts/gen-sql-migrations.js +46 -0
- package/scripts/phase8-codemod.js +219 -0
- package/scripts/phase9a-env-getters-codemod.js +82 -0
- package/scripts/scan-core-env.js +109 -0
- package/scripts/scan-tenant-queries.js +235 -0
- package/scripts/schema-drift-guard.ts +210 -0
- package/scripts/tenant-scan-whitelist.json +1 -0
- package/src/app.tsx +2 -1
- package/src/env.d.ts +13 -1
- package/src/libs/service-host.ts +13 -0
- package/tsconfig.json +1 -1
- package/vite.arc.config.ts +159 -0
- package/api/src/libs/did-space.ts +0 -235
- package/api/src/libs/middleware.ts +0 -50
- package/api/src/libs/security.ts +0 -192
- package/api/src/queues/space.ts +0 -662
- package/api/src/routes/credit-tokens.ts +0 -38
- package/api/src/routes/exchange-rates.ts +0 -87
- package/api/src/routes/index.ts +0 -142
- package/api/src/routes/integrations/stripe.ts +0 -61
- package/api/src/routes/meters.ts +0 -274
- package/api/src/routes/passports.ts +0 -68
- package/api/src/routes/redirect.ts +0 -20
- package/api/src/routes/tool.ts +0 -65
- package/api/src/routes/webhook-endpoints.ts +0 -126
- package/api/tests/routes/credit-grants.spec.ts +0 -1261
- package/cloudflare/did-connect-auth.ts +0 -527
- package/cloudflare/shims/did-space-js.ts +0 -17
- package/cloudflare/shims/did-space.ts +0 -11
- package/cloudflare/shims/express-compat/index.ts +0 -80
- package/cloudflare/shims/express-compat/types.ts +0 -41
- package/cloudflare/shims/lock.ts +0 -115
- package/cloudflare/shims/queue.ts +0 -611
- package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
- package/cloudflare/tests/shims/queue-scheduled.spec.ts +0 -186
package/api/src/libs/env.ts
CHANGED
|
@@ -1,68 +1,184 @@
|
|
|
1
1
|
import { env } from '@blocklet/sdk/lib/env';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export
|
|
3
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
4
|
+
// Phase 8 (W2′): the injected-config slot, made authoritative here.
|
|
5
|
+
//
|
|
6
|
+
// libs/env.ts is the ONE module the core-env scanner exempts — the single
|
|
7
|
+
// allowed reader of process.env / the CF env mirror. Phase 8 converges every
|
|
8
|
+
// scattered `process.env.X` read in api/src INTO the accessors below so the
|
|
9
|
+
// whitelist goes to zero.
|
|
10
|
+
//
|
|
11
|
+
// The factory (createEmbeddedPaymentService) calls setCoreConfig(config) so the
|
|
12
|
+
// injected config object becomes the source of truth. Reads fall back to
|
|
13
|
+
// process.env when a key is absent from the injected config — which keeps every
|
|
14
|
+
// host working unchanged: the blocklet server populates process.env natively,
|
|
15
|
+
// and the CF worker mirrors CF env into process.env per request (that mirror is
|
|
16
|
+
// deleted in Phase 12, once the worker routes through the factory config slot).
|
|
17
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
18
|
+
let activeConfig: Record<string, any> | undefined;
|
|
19
|
+
|
|
20
|
+
/** Wire the injected config object (factory only). Pass undefined to clear (tests). */
|
|
21
|
+
export function setCoreConfig(config: Record<string, any> | undefined): void {
|
|
22
|
+
activeConfig = config;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The injected config object, or undefined before the factory has run. */
|
|
26
|
+
export function getCoreConfig(): Record<string, any> | undefined {
|
|
27
|
+
return activeConfig;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Read a config key: the injected config wins; otherwise the process.env
|
|
32
|
+
* fallback (blocklet server native / worker mirror). Returns a string or
|
|
33
|
+
* undefined — callers parse/typecheck. This is the single boundary read.
|
|
34
|
+
*/
|
|
35
|
+
export function readConfig(key: string): string | undefined {
|
|
36
|
+
const injected = activeConfig?.[key];
|
|
37
|
+
if (injected !== undefined && injected !== null) return String(injected);
|
|
38
|
+
const fromEnv = process.env[key];
|
|
39
|
+
return fromEnv === undefined ? undefined : fromEnv;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** True iff the key is present (non-empty) in injected config or process.env. */
|
|
43
|
+
export function hasConfig(key: string): boolean {
|
|
44
|
+
const v = readConfig(key);
|
|
45
|
+
return v !== undefined && v !== '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
49
|
+
// P1 (9a review fix): these were import-time `process.env` consts — frozen
|
|
50
|
+
// before the factory could setCoreConfig, so injected config could never
|
|
51
|
+
// override them (now that 9a bundles the canonical core into the published
|
|
52
|
+
// package, that mattered for arc). They are LAZY getters now, reading via the
|
|
53
|
+
// readConfig boundary, honored at call time. Consumers call them at use time.
|
|
54
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
55
|
+
const numConfig = (key: string, fallback: number): number => {
|
|
56
|
+
const v = readConfig(key);
|
|
57
|
+
return v ? +v : fallback;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const paymentStatCronTime = (): string => '0 1 0 * * *'; // 默认每天一次,计算前一天的
|
|
61
|
+
export const subscriptionCronTime = (): string => readConfig('SUBSCRIPTION_CRON_TIME') || '0 */30 * * * *';
|
|
62
|
+
export const notificationCronTime = (): string => readConfig('NOTIFICATION_CRON_TIME') || '0 5 */6 * * *';
|
|
63
|
+
export const expiredSessionCleanupCronTime = (): string =>
|
|
64
|
+
readConfig('EXPIRED_SESSION_CLEANUP_CRON_TIME') || '0 1 * * * *';
|
|
65
|
+
export const notificationCronConcurrency = (): number => Number(readConfig('NOTIFICATION_CRON_CONCURRENCY')) || 8;
|
|
66
|
+
export const stripeInvoiceCronTime = (): string => readConfig('STRIPE_INVOICE_CRON_TIME') || '0 */30 * * * *';
|
|
67
|
+
export const stripePaymentCronTime = (): string => readConfig('STRIPE_PAYMENT_CRON_TIME') || '0 */20 * * * *';
|
|
68
|
+
export const stripeSubscriptionCronTime = (): string => readConfig('STRIPE_SUBSCRIPTION_CRON_TIME') || '0 10 */8 * * *';
|
|
69
|
+
export const revokeStakeCronTime = (): string => readConfig('REVOKE_STAKE_CRON_TIME') || '0 */5 * * * *';
|
|
70
|
+
export const daysUntilCancel = (): string | undefined => readConfig('DAYS_UNTIL_CANCEL');
|
|
71
|
+
export const meteringSubscriptionDetectionCronTime = (): string =>
|
|
72
|
+
readConfig('METERING_SUBSCRIPTION_DETECTION_CRON_TIME') || '0 0 10 * * *';
|
|
73
|
+
export const overdueDetectionCronTime = (): string => readConfig('OVERDUE_DETECTION_CRON_TIME') || '0 0 10 * * *';
|
|
74
|
+
export const overdueThreshold = (): number => numConfig('OVERDUE_THRESHOLD', 5);
|
|
75
|
+
export const depositVaultCronTime = (): string => readConfig('DEPOSIT_VAULT_CRON_TIME') || '0 */5 * * * *';
|
|
76
|
+
export const creditConsumptionCronTime = (): string => readConfig('CREDIT_CONSUMPTION_CRON_TIME') || '0 */10 * * * *';
|
|
77
|
+
export const vendorStatusCheckCronTime = (): string => readConfig('VENDOR_STATUS_CHECK_CRON_TIME') || '0 */10 * * * *';
|
|
78
|
+
export const vendorReturnScanCronTime = (): string => readConfig('VENDOR_RETURN_SCAN_CRON_TIME') || '0 */10 * * * *';
|
|
79
|
+
export const iapReconcileCronTime = (): string => readConfig('IAP_RECONCILE_CRON_TIME') || '0 */5 * * * *';
|
|
80
|
+
export const eventRetryCronTime = (): string => readConfig('EVENT_RETRY_CRON_TIME') || '30 */5 * * * *';
|
|
81
|
+
export const quoteCleanupCronTime = (): string => readConfig('QUOTE_CLEANUP_CRON_TIME') || '0 0 2 * * *';
|
|
82
|
+
export const vendorTimeoutMinutes = (): number => numConfig('VENDOR_TIMEOUT_MINUTES', 10);
|
|
83
|
+
export const webhookAlertWindowMinutes = (): number => numConfig('WEBHOOK_ALERT_WINDOW_MINUTES', 10);
|
|
84
|
+
export const webhookAlertMinFailures = (): number => numConfig('WEBHOOK_ALERT_MIN_FAILURES', 3);
|
|
85
|
+
|
|
86
|
+
export const shortUrlApiKey = (): string => readConfig('SHORT_URL_API_KEY') || '';
|
|
87
|
+
export const shortUrlDomain = (): string => readConfig('SHORT_URL_DOMAIN') || 's.abtnet.io';
|
|
36
88
|
|
|
37
89
|
// sequelize 配置相关
|
|
38
|
-
export const sequelizeOptionsPoolMin: number
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
: 5;
|
|
44
|
-
export const sequelizeOptionsPoolIdle: number = process.env.SEQUELIZE_OPTIONS_POOL_IDLE
|
|
45
|
-
? +process.env.SEQUELIZE_OPTIONS_POOL_IDLE
|
|
46
|
-
: 10 * 1000;
|
|
47
|
-
|
|
48
|
-
export const updateDataConcurrency: number = process.env.UPDATE_DATA_CONCURRENCY
|
|
49
|
-
? +process.env.UPDATE_DATA_CONCURRENCY
|
|
50
|
-
: 5; // 默认并发数为 5
|
|
90
|
+
export const sequelizeOptionsPoolMin = (): number => numConfig('SEQUELIZE_OPTIONS_POOL_MIN', 0);
|
|
91
|
+
export const sequelizeOptionsPoolMax = (): number => numConfig('SEQUELIZE_OPTIONS_POOL_MAX', 5);
|
|
92
|
+
export const sequelizeOptionsPoolIdle = (): number => numConfig('SEQUELIZE_OPTIONS_POOL_IDLE', 10 * 1000);
|
|
93
|
+
|
|
94
|
+
export const updateDataConcurrency = (): number => numConfig('UPDATE_DATA_CONCURRENCY', 5);
|
|
51
95
|
|
|
52
96
|
// When set to 'true' or '1', the system stops accepting new orders.
|
|
53
97
|
// Existing checkout sessions can still be viewed but new submissions will be rejected.
|
|
54
|
-
export const stopAcceptingOrders: boolean
|
|
55
|
-
|
|
98
|
+
export const stopAcceptingOrders = (): boolean =>
|
|
99
|
+
readConfig('PAYMENT_KIT_STOP_ACCEPTING_ORDERS') === 'true' || readConfig('PAYMENT_KIT_STOP_ACCEPTING_ORDERS') === '1';
|
|
56
100
|
|
|
57
|
-
export const exchangeRateCacheTTLSeconds: number
|
|
58
|
-
? +process.env.EXCHANGE_RATE_CACHE_TTL_SECONDS
|
|
59
|
-
: 10 * 60;
|
|
101
|
+
export const exchangeRateCacheTTLSeconds = (): number => numConfig('EXCHANGE_RATE_CACHE_TTL_SECONDS', 10 * 60);
|
|
60
102
|
|
|
61
103
|
// System-level maximum pending amount limit (in token format, e.g., "10")
|
|
62
104
|
// Default is 0 (disabled). Set PAYMENT_KIT_MAX_PENDING_AMOUNT to enable this limit.
|
|
63
|
-
export const systemMaxPendingAmount: number
|
|
64
|
-
|
|
65
|
-
|
|
105
|
+
export const systemMaxPendingAmount = (): number => numConfig('PAYMENT_KIT_MAX_PENDING_AMOUNT', 5);
|
|
106
|
+
|
|
107
|
+
// Whether a locked price may still be edited. Lazy (reads injected config via
|
|
108
|
+
// the boundary at call time) like every other Phase 8 accessor.
|
|
109
|
+
export const allowChangeLockedPrice = (): boolean => readConfig('PAYMENT_CHANGE_LOCKED_PRICE') === '1';
|
|
110
|
+
|
|
111
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
112
|
+
// Phase 8 (W2′): converged accessors. Every read below used to live inline in
|
|
113
|
+
// api/src as a direct process.env / __CF_ENV__ access (the 57-entry whitelist).
|
|
114
|
+
// They are LAZY (functions, not import-time consts) so the injected config —
|
|
115
|
+
// wired by the factory AFTER module import — is honored at call time, and so
|
|
116
|
+
// tests that flip process.env at runtime keep working.
|
|
117
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
// -- runtime mode / environment --
|
|
120
|
+
export const blockletMode = (): string | undefined => readConfig('BLOCKLET_MODE');
|
|
121
|
+
export const isProduction = (): boolean => blockletMode() === 'production';
|
|
122
|
+
export const nodeEnv = (): string | undefined => readConfig('NODE_ENV');
|
|
123
|
+
export const isTestEnv = (): boolean => nodeEnv() === 'test';
|
|
124
|
+
export const isDevelopmentEnv = (): boolean => nodeEnv() === 'development';
|
|
125
|
+
export const enableDevFakeAuth = (): boolean => readConfig('ENABLE_DEV_FAKE_AUTH') === '1';
|
|
126
|
+
|
|
127
|
+
// -- tenant mode-source (getTenantMode / getDefaultInstanceDid read these) --
|
|
128
|
+
export const tenantModeRaw = (): string | undefined => readConfig('PAYMENT_TENANT_MODE');
|
|
129
|
+
export const blockletAppPid = (): string | undefined => readConfig('BLOCKLET_APP_PID');
|
|
130
|
+
|
|
131
|
+
// -- app identity / urls --
|
|
132
|
+
export const blockletAppId = (): string | undefined => readConfig('BLOCKLET_APP_ID');
|
|
133
|
+
export const blockletAppName = (): string | undefined => readConfig('BLOCKLET_APP_NAME');
|
|
134
|
+
export const blockletAppUrl = (): string | undefined => readConfig('BLOCKLET_APP_URL');
|
|
135
|
+
export const blockletAppHost = (): string | undefined => readConfig('BLOCKLET_APP_HOST');
|
|
136
|
+
export const blockletAppDir = (): string | undefined => readConfig('BLOCKLET_APP_DIR');
|
|
137
|
+
export const blockletPort = (): string | undefined => readConfig('BLOCKLET_PORT');
|
|
138
|
+
export const blockletMountPoints = (): string | undefined => readConfig('BLOCKLET_MOUNT_POINTS');
|
|
139
|
+
|
|
140
|
+
// -- integrations --
|
|
141
|
+
export const appStoreWriteEnabled = (): boolean => readConfig('APP_STORE_WRITE_ENABLED') === 'true';
|
|
142
|
+
export const appStoreSkipSignatureVerify = (): boolean => readConfig('APP_STORE_SKIP_SIGNATURE_VERIFY') === 'true';
|
|
143
|
+
export const googlePubsubSkipSignatureVerify = (): boolean =>
|
|
144
|
+
readConfig('GOOGLE_PUBSUB_SKIP_SIGNATURE_VERIFY') === 'true';
|
|
145
|
+
export const googlePubsubPushServiceAccount = (): string | undefined =>
|
|
146
|
+
readConfig('GOOGLE_PUBSUB_PUSH_SERVICE_ACCOUNT');
|
|
147
|
+
export const googlePubsubAllowUnverifiedSender = (): boolean =>
|
|
148
|
+
readConfig('GOOGLE_PUBSUB_ALLOW_UNVERIFIED_SENDER') === 'true';
|
|
149
|
+
export const googlePlayWebhookUrl = (): string | undefined => readConfig('GOOGLE_PLAY_WEBHOOK_URL');
|
|
150
|
+
export const stripeWebhookSecret = (): string | undefined => readConfig('STRIPE_WEBHOOK_SECRET');
|
|
151
|
+
export const iapReconcileBatchSize = (): number => Number(readConfig('IAP_RECONCILE_BATCH_SIZE') ?? '100');
|
|
152
|
+
|
|
153
|
+
// -- payment params --
|
|
154
|
+
export const paymentBillingThreshold = (): number => +(readConfig('PAYMENT_BILLING_THRESHOLD') as string);
|
|
155
|
+
export const paymentMinStakeAmount = (): number => +(readConfig('PAYMENT_MIN_STAKE_AMOUNT') as string);
|
|
156
|
+
export const paymentDaysUntilDue = (): string | undefined => readConfig('PAYMENT_DAYS_UNTIL_DUE');
|
|
157
|
+
export const paymentDaysUntilCancel = (): string | undefined => readConfig('PAYMENT_DAYS_UNTIL_CANCEL');
|
|
158
|
+
export const paymentReloadSubscriptionJobs = (): boolean => readConfig('PAYMENT_RELOAD_SUBSCRIPTION_JOBS') === '1';
|
|
159
|
+
export const paymentRateVolatilityThreshold = (): string | undefined => readConfig('PAYMENT_RATE_VOLATILITY_THRESHOLD');
|
|
160
|
+
export const paymentLivemode = (): boolean => readConfig('PAYMENT_LIVEMODE') !== 'false';
|
|
161
|
+
|
|
162
|
+
// -- credit queue --
|
|
163
|
+
export const creditLowBalanceThresholdPercentage = (): number =>
|
|
164
|
+
parseInt(readConfig('CREDIT_LOW_BALANCE_THRESHOLD_PERCENTAGE') || '10', 10);
|
|
165
|
+
export const creditBatchSize = (): number => Math.max(1, parseInt(readConfig('CREDIT_BATCH_SIZE') || '50', 10));
|
|
166
|
+
export const creditBatchWindowMs = (): number =>
|
|
167
|
+
Math.max(10, parseInt(readConfig('CREDIT_BATCH_WINDOW_MS') || '3000', 10));
|
|
168
|
+
export const creditQueueConcurrency = (): number =>
|
|
169
|
+
Math.max(1, Math.min(20, parseInt(readConfig('CREDIT_QUEUE_CONCURRENCY') || '5', 10) || 5));
|
|
170
|
+
|
|
171
|
+
// -- exchange rate cache TTL source (the value itself is exchangeRateCacheTTLSeconds above) --
|
|
172
|
+
export const exchangeRateCacheTTLFromEnv = (): boolean => hasConfig('EXCHANGE_RATE_CACHE_TTL_SECONDS');
|
|
173
|
+
|
|
174
|
+
// -- store / sequelize logging --
|
|
175
|
+
export const sqlLog = (): boolean => readConfig('SQL_LOG') === '1';
|
|
176
|
+
export const sqlBenchmark = (): boolean => readConfig('SQL_BENCHMARK') === '1';
|
|
177
|
+
|
|
178
|
+
// -- CF worker runtime detection + env mirror (set by cloudflare/worker.ts on
|
|
179
|
+
// globalThis; the boundary so core never reads the global directly) --
|
|
180
|
+
export const cfEnv = (): any => (globalThis as any).__CF_ENV__;
|
|
181
|
+
export const isCfWorker = (): boolean => !!cfEnv();
|
|
66
182
|
|
|
67
183
|
export default {
|
|
68
184
|
...env,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
import BigNumber from 'bignumber.js';
|
|
3
|
+
import { exchangeRateCacheTTLFromEnv, exchangeRateCacheTTLSeconds } from '../env';
|
|
3
4
|
import { ExchangeRateProvider } from '../../store/models/exchange-rate-provider';
|
|
4
5
|
import logger from '../logger';
|
|
5
6
|
import { events } from '../event';
|
|
@@ -8,15 +9,15 @@ import { SymbolNotSupportedError } from './types';
|
|
|
8
9
|
import { TokenDataProvider } from './token-data-provider';
|
|
9
10
|
import { CoinGeckoProvider } from './coingecko-provider';
|
|
10
11
|
import { CoinMarketCapProvider } from './coinmarketcap-provider';
|
|
11
|
-
import { exchangeRateCacheTTLSeconds } from '../env';
|
|
12
12
|
|
|
13
13
|
interface CacheEntry {
|
|
14
14
|
data: ExchangeRateResult;
|
|
15
15
|
timestamp: number;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// Cache TTL from
|
|
19
|
-
|
|
18
|
+
// Cache TTL from config, default 10 minutes. Lazy so injected config (set after
|
|
19
|
+
// module import) is honored — not frozen in a module-level const.
|
|
20
|
+
const cacheTtlMs = (): number => (exchangeRateCacheTTLSeconds() || 10 * 60) * 1000;
|
|
20
21
|
const MAX_RATE_AGE_MS = 5 * 60 * 1000; // 5 minutes
|
|
21
22
|
const MAX_DEVIATION_PERCENT = 5; // 5%
|
|
22
23
|
const HISTORY_WINDOW_SIZE = 10;
|
|
@@ -185,7 +186,7 @@ export class ExchangeRateService {
|
|
|
185
186
|
|
|
186
187
|
// Check cache first
|
|
187
188
|
const cached = this.cache.get(cacheKey);
|
|
188
|
-
if (cached && Date.now() - cached.timestamp <
|
|
189
|
+
if (cached && Date.now() - cached.timestamp < cacheTtlMs()) {
|
|
189
190
|
logger.debug('Exchange rate cache hit', { symbol, age: Date.now() - cached.timestamp });
|
|
190
191
|
return cached.data;
|
|
191
192
|
}
|
|
@@ -575,8 +576,8 @@ export function getExchangeRateService(): ExchangeRateService {
|
|
|
575
576
|
if (!serviceInstance) {
|
|
576
577
|
serviceInstance = new ExchangeRateService();
|
|
577
578
|
logger.info('Exchange rate service initialized', {
|
|
578
|
-
cache_ttl_seconds:
|
|
579
|
-
cache_ttl_source:
|
|
579
|
+
cache_ttl_seconds: cacheTtlMs() / 1000,
|
|
580
|
+
cache_ttl_source: exchangeRateCacheTTLFromEnv() ? 'env' : 'default',
|
|
580
581
|
});
|
|
581
582
|
}
|
|
582
583
|
return serviceInstance;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// D5 — the Web-Fetch entry for hosts that own their own app shell (arc-node's
|
|
2
|
+
// registerPrefixHandler): `svc.http.fetch(req, {basePath})` with no express bridge.
|
|
3
|
+
//
|
|
4
|
+
// Phase 4 (express→hono): the loopback http.Server + express app are gone, so this
|
|
5
|
+
// is just a base-strip wrapper over `honoApp.fetch`. The outward signature +
|
|
6
|
+
// strip semantics are unchanged (arc consumes this contract); raw-body fidelity
|
|
7
|
+
// (Stripe webhook signature) holds because the stripped path reuses the exact
|
|
8
|
+
// request bytes/headers, and status/Set-Cookie/redirect come from the hono Response.
|
|
9
|
+
|
|
10
|
+
import type { Hono } from 'hono';
|
|
11
|
+
|
|
12
|
+
/** Options for svc.http.fetch — basePath is stripped to reach the internal /api/*. */
|
|
13
|
+
export interface PaymentFetchOptions {
|
|
14
|
+
/** the host's mount prefix (e.g. "/.well-known/payment"); stripped, no alias special-case */
|
|
15
|
+
basePath?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface FetchHandler {
|
|
19
|
+
(request: Request, opts?: PaymentFetchOptions): Promise<Response>;
|
|
20
|
+
/** teardown hook (host lifecycle). No-op now that there is no loopback server. */
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createFetchHandler(app: Hono): FetchHandler {
|
|
25
|
+
const handler = (async (request: Request, opts?: PaymentFetchOptions): Promise<Response> => {
|
|
26
|
+
const url = new URL(request.url);
|
|
27
|
+
|
|
28
|
+
// ① base-strip: remove basePath → internal /api/* path (no alias special-case).
|
|
29
|
+
// Precise segment-boundary check (=== basePath || startsWith(basePath + '/'))
|
|
30
|
+
// so "/foo" never matches "/foobar" — byte-identical to the old loopback strip.
|
|
31
|
+
const basePath = opts?.basePath ?? '';
|
|
32
|
+
if (basePath && (url.pathname === basePath || url.pathname.startsWith(`${basePath}/`))) {
|
|
33
|
+
url.pathname = url.pathname.slice(basePath.length) || '/';
|
|
34
|
+
// ② rebuild the request at the stripped URL. The body is read ONCE into a
|
|
35
|
+
// fixed buffer (raw bytes preserved for Stripe webhook signature) and the
|
|
36
|
+
// original headers/method are carried verbatim (Host preserved).
|
|
37
|
+
const method = request.method.toUpperCase();
|
|
38
|
+
const hasBody = method !== 'GET' && method !== 'HEAD';
|
|
39
|
+
const body = hasBody ? await request.arrayBuffer() : undefined;
|
|
40
|
+
// ③ re-expose the stripped mount prefix as `x-path-prefix` so internal
|
|
41
|
+
// absolute-URL builders reconstruct the PUBLIC url. The DID-Connect
|
|
42
|
+
// authenticator's wallet callback URL is built by did-connect-js
|
|
43
|
+
// `prepareBaseUrl`, which reads `x-path-prefix`; without it the wallet is
|
|
44
|
+
// told to call <origin>/api/did/payment/auth instead of
|
|
45
|
+
// <origin><basePath>/api/did/payment/auth and the connect times out. The
|
|
46
|
+
// Request's headers are immutable, so set it on a fresh Headers; never
|
|
47
|
+
// clobber a host-provided value (blocklet-server sets its own mount).
|
|
48
|
+
const headers = new Headers(request.headers);
|
|
49
|
+
if (!headers.has('x-path-prefix')) headers.set('x-path-prefix', basePath);
|
|
50
|
+
return app.fetch(new Request(url.toString(), { method, headers, body }));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// no strip needed — hand the request straight to hono (it owns body parsing).
|
|
54
|
+
return app.fetch(request);
|
|
55
|
+
}) as FetchHandler;
|
|
56
|
+
|
|
57
|
+
handler.close = (): Promise<void> => Promise.resolve();
|
|
58
|
+
|
|
59
|
+
return handler;
|
|
60
|
+
}
|
package/api/src/libs/invoice.ts
CHANGED
package/api/src/libs/lock.ts
CHANGED
|
@@ -1,53 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
// Phase 8 (W2-1a): lock facade over the locks slot driver.
|
|
2
|
+
//
|
|
3
|
+
// Call sites keep using `getLock(name)` unchanged. Behind the facade:
|
|
4
|
+
// - the active locks driver is injectable (`setLocksDriver`) — default is the
|
|
5
|
+
// in-process memory driver (Blocklet Server / Node). The worker injects the
|
|
6
|
+
// D1 driver through the locks slot.
|
|
7
|
+
// - lock names are tenant-prefixed (W1 §2.2) by default. Per-resource locks
|
|
8
|
+
// are tenant-scoped; process-level singleton guards (queue start guards,
|
|
9
|
+
// recovery) opt out with `{ scope: 'global' }`. In single-tenant mode the
|
|
10
|
+
// prefix is the constant deployment app DID, so lock identity is unchanged.
|
|
11
|
+
|
|
12
|
+
import { getInstanceDid } from './context';
|
|
13
|
+
import {
|
|
14
|
+
createMemoryLocksDriver,
|
|
15
|
+
scopedLockName,
|
|
16
|
+
MemoryLock,
|
|
17
|
+
type LockHandle,
|
|
18
|
+
type LocksDriver,
|
|
19
|
+
type LockScope,
|
|
20
|
+
} from './drivers';
|
|
21
|
+
|
|
22
|
+
let activeDriver: LocksDriver = createMemoryLocksDriver();
|
|
23
|
+
|
|
24
|
+
/** Inject the locks driver (worker wires the D1 driver here). */
|
|
25
|
+
export function setLocksDriver(driver: LocksDriver): void {
|
|
26
|
+
activeDriver = driver;
|
|
27
|
+
}
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.locked = true;
|
|
30
|
-
resolve(true);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
29
|
+
export function getLocksDriver(): LocksDriver {
|
|
30
|
+
return activeDriver;
|
|
31
|
+
}
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
33
|
+
export interface GetLockOptions {
|
|
34
|
+
ttl?: number;
|
|
35
|
+
/** 'tenant' (default) prefixes the lock name with the current tenant; 'global' keeps the bare name. */
|
|
36
|
+
scope?: LockScope;
|
|
40
37
|
}
|
|
41
38
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Acquire a handle to a named lock. Tenant-scoped by default; resolving the
|
|
41
|
+
* tenant fails closed in multi-tenant mode when no context is present (matching
|
|
42
|
+
* the scoped-query helpers from Phase 3).
|
|
43
|
+
*/
|
|
44
|
+
export function getLock(name: string, options: GetLockOptions = {}): LockHandle {
|
|
45
|
+
if (!name || typeof name !== 'string') {
|
|
46
|
+
throw new Error('getLock: a non-empty lock name is required');
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return lock;
|
|
48
|
+
const scope: LockScope = options.scope ?? 'tenant';
|
|
49
|
+
const instanceDid = scope === 'tenant' ? getInstanceDid() : null;
|
|
50
|
+
const resolvedName = scopedLockName(name, instanceDid, scope);
|
|
51
|
+
return activeDriver.getLock(resolvedName, options.ttl !== undefined ? { ttl: options.ttl } : undefined);
|
|
53
52
|
}
|
|
53
|
+
|
|
54
|
+
// `Lock` is the in-process memory lock class — kept as a public export so the
|
|
55
|
+
// standalone constructor form (`new Lock(name)`) and `LockHandle` annotations
|
|
56
|
+
// both keep working.
|
|
57
|
+
export { MemoryLock as Lock };
|
package/api/src/libs/logger.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
// Phase 13b: lazy logging boundary.
|
|
2
|
+
//
|
|
3
|
+
// @blocklet/logger throws at REQUIRE time when BLOCKLET_LOG_DIR is absent
|
|
4
|
+
// ("valid BLOCKLET_LOG_DIR env is required by logger"). That made importing the
|
|
5
|
+
// core — and therefore createEmbeddedPaymentService / rpc.entitlements.check,
|
|
6
|
+
// which transitively import this module — demand a blocklet log env even for a
|
|
7
|
+
// bare host (arc embedding before its blocklet runtime is wired). Defer the
|
|
8
|
+
// require to first use and fall back to console when no blocklet log env exists.
|
|
9
|
+
// The blocklet server (BLOCKLET_LOG_DIR set) and the CF worker (aliased shim)
|
|
10
|
+
// still get the real logger on first call — behavior unchanged for them.
|
|
2
11
|
|
|
3
12
|
interface Logger {
|
|
4
13
|
debug: (...args: any[]) => void;
|
|
@@ -7,14 +16,45 @@ interface Logger {
|
|
|
7
16
|
warn: (...args: any[]) => void;
|
|
8
17
|
}
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
const instance = createLogger(label || '');
|
|
12
|
-
return instance;
|
|
13
|
-
};
|
|
19
|
+
let resolved: Logger | undefined;
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
function resolveLogger(): Logger {
|
|
22
|
+
if (resolved) return resolved;
|
|
23
|
+
try {
|
|
24
|
+
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
25
|
+
const createLogger = require('@blocklet/logger');
|
|
26
|
+
resolved = createLogger('app') as Logger;
|
|
27
|
+
} catch {
|
|
28
|
+
// bare host without a blocklet log env — console fallback.
|
|
29
|
+
/* eslint-disable no-console */
|
|
30
|
+
resolved = {
|
|
31
|
+
debug: (...args: any[]) => console.debug(...args),
|
|
32
|
+
info: (...args: any[]) => console.info(...args),
|
|
33
|
+
error: (...args: any[]) => console.error(...args),
|
|
34
|
+
warn: (...args: any[]) => console.warn(...args),
|
|
35
|
+
};
|
|
36
|
+
/* eslint-enable no-console */
|
|
37
|
+
}
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const logger: Logger = {
|
|
42
|
+
debug: (...args: any[]) => resolveLogger().debug(...args),
|
|
43
|
+
info: (...args: any[]) => resolveLogger().info(...args),
|
|
44
|
+
error: (...args: any[]) => resolveLogger().error(...args),
|
|
45
|
+
warn: (...args: any[]) => resolveLogger().warn(...args),
|
|
46
|
+
};
|
|
16
47
|
|
|
17
48
|
export default logger;
|
|
18
49
|
|
|
19
|
-
|
|
20
|
-
|
|
50
|
+
// Express access logger — also lazy. A bare host that never mounts the node
|
|
51
|
+
// handler (where setupAccessLogger runs) never needs the blocklet log env.
|
|
52
|
+
export function setupAccessLogger(app: any): void {
|
|
53
|
+
try {
|
|
54
|
+
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
55
|
+
const createLogger = require('@blocklet/logger');
|
|
56
|
+
createLogger.setupAccessLogger?.(app);
|
|
57
|
+
} catch {
|
|
58
|
+
// bare host: no access logging
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BlockletNotification from '@blocklet/sdk/service/notification';
|
|
2
2
|
|
|
3
3
|
import type { BaseEmailTemplate, BaseEmailTemplateType } from './template/base';
|
|
4
4
|
import { CheckoutSession, CreditGrant, Invoice, Meter, MeterEvent, Subscription } from '../../store/models';
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/indent */
|
|
3
3
|
import { withQuery } from 'ufo';
|
|
4
4
|
import { BN } from '@ocap/util';
|
|
5
|
+
import { creditLowBalanceThresholdPercentage } from '../../env';
|
|
5
6
|
import { getUserLocale } from '../../../integrations/blocklet/notification';
|
|
6
7
|
import { translate } from '../../../locales';
|
|
7
8
|
import { Customer, PaymentCurrency, CreditGrant } from '../../../store/models';
|
|
@@ -35,7 +36,7 @@ export class CustomerCreditLowBalanceEmailTemplate implements BaseEmailTemplate<
|
|
|
35
36
|
* @returns threshold percentage (default: 10)
|
|
36
37
|
*/
|
|
37
38
|
static getLowBalanceThresholdPercent(): number {
|
|
38
|
-
return
|
|
39
|
+
return creditLowBalanceThresholdPercentage();
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/brace-style */
|
|
2
2
|
/* eslint-disable @typescript-eslint/indent */
|
|
3
|
-
import { getUrl } from '@blocklet/sdk';
|
|
3
|
+
import { getUrl } from '@blocklet/sdk/lib/component';
|
|
4
4
|
import { getUserLocale } from '../../../integrations/blocklet/notification';
|
|
5
5
|
import { translate } from '../../../locales';
|
|
6
6
|
import { CheckoutSession, Customer, PaymentLink, PaymentMethod, Payout } from '../../../store/models';
|
|
@@ -4,7 +4,7 @@ import isEmpty from 'lodash/isEmpty';
|
|
|
4
4
|
import pWaitFor from 'p-wait-for';
|
|
5
5
|
import type { LiteralUnion } from 'type-fest';
|
|
6
6
|
|
|
7
|
-
import { getUrl } from '@blocklet/sdk';
|
|
7
|
+
import { getUrl } from '@blocklet/sdk/lib/component';
|
|
8
8
|
import { getUserLocale } from '../../../integrations/blocklet/notification';
|
|
9
9
|
import { translate } from '../../../locales';
|
|
10
10
|
import {
|
package/api/src/libs/payout.ts
CHANGED