payment-kit 1.29.0 → 1.29.2
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 +36 -0
- package/api/src/crons/base.ts +3 -3
- package/api/src/crons/currency.ts +1 -1
- package/api/src/crons/index.ts +27 -24
- 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/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 +99 -38
- package/api/src/libs/context.ts +78 -1
- package/api/src/libs/currency.ts +2 -2
- package/api/src/libs/dayjs.ts +8 -2
- 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 +81 -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 +50 -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 +259 -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 +73 -0
- package/api/src/middlewares/hono/csrf.ts +72 -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 +214 -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 +17 -12
- 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 +12 -4
- 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 +41 -28
- package/api/src/queues/payout.ts +9 -5
- package/api/src/queues/refund.ts +18 -12
- 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} +193 -223
- 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} +96 -80
- 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 +667 -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 +66 -22
- 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/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/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/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 +236 -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/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/README.md +26 -6
- package/cloudflare/build.ts +28 -13
- package/cloudflare/did-connect-auth.ts +0 -217
- package/cloudflare/docs/2026-06-10-bundle-size-analysis.md +288 -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 +31 -56
- 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/util-csrf.ts +13 -0
- package/cloudflare/shims/blocklet-sdk/util-wallet.ts +8 -0
- 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/node-fetch.ts +35 -0
- package/cloudflare/shims/xss.ts +8 -0
- package/cloudflare/tenant-middleware.ts +36 -0
- package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
- package/cloudflare/tests/worker-handler-gate.spec.ts +44 -0
- package/cloudflare/worker.ts +204 -433
- package/cloudflare/wrangler.local-e2e.jsonc +26 -0
- package/jest.config.js +3 -1
- package/package.json +33 -38
- 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/env.d.ts +13 -1
- package/tsconfig.json +1 -1
- 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/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
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
// Phase 3 (express→hono) — hono fork of routes/payment-links.ts. Sub-app with
|
|
2
|
+
// routes relative to /api/payment-links (mounted via mountResourceGroup). The
|
|
3
|
+
// business logic is unchanged; only the express plumbing becomes hono:
|
|
4
|
+
// req.body → c.get('sanitizedBody'); res.status(n).json(x) → c.json(x, n).
|
|
5
|
+
import { Hono } from 'hono';
|
|
1
6
|
import Joi from 'joi';
|
|
2
|
-
import { Router } from 'express';
|
|
3
7
|
import pick from 'lodash/pick';
|
|
4
8
|
import { Op } from 'sequelize';
|
|
5
9
|
import type { WhereOptions } from 'sequelize';
|
|
6
10
|
|
|
7
|
-
import { createListParamSchema, getOrder, MetadataSchema } from '
|
|
8
|
-
import logger from '
|
|
9
|
-
import { authenticate } from '
|
|
10
|
-
import { isLineItemAligned } from '
|
|
11
|
-
import { formatMetadata } from '
|
|
12
|
-
import { PaymentLink } from '
|
|
13
|
-
import { Price } from '
|
|
14
|
-
import { Product } from '
|
|
15
|
-
import { getDonationBenefits } from '
|
|
16
|
-
|
|
17
|
-
const
|
|
11
|
+
import { createListParamSchema, getOrder, MetadataSchema } from '../../libs/api';
|
|
12
|
+
import logger from '../../libs/logger';
|
|
13
|
+
import { authenticate } from '../../middlewares/hono/security';
|
|
14
|
+
import { isLineItemAligned } from '../../libs/session';
|
|
15
|
+
import { formatMetadata } from '../../libs/util';
|
|
16
|
+
import { PaymentLink } from '../../store/models/payment-link';
|
|
17
|
+
import { Price } from '../../store/models/price';
|
|
18
|
+
import { Product } from '../../store/models/product';
|
|
19
|
+
import { getDonationBenefits } from '../../libs/payment';
|
|
20
|
+
|
|
21
|
+
const app = new Hono();
|
|
18
22
|
const auth = authenticate<PaymentLink>({ component: true, roles: ['owner', 'admin'] });
|
|
19
23
|
|
|
20
24
|
const formatBeforeSave = (payload: any) => {
|
|
@@ -219,26 +223,59 @@ const PaymentLinkCreateSchema = Joi.object({
|
|
|
219
223
|
.min(0)
|
|
220
224
|
.optional(),
|
|
221
225
|
}).unknown(true);
|
|
222
|
-
|
|
226
|
+
|
|
227
|
+
// static route — registered before /:id to avoid shadowing
|
|
228
|
+
app.post('/stash', auth, async (c) => {
|
|
229
|
+
try {
|
|
230
|
+
const body = c.get('sanitizedBody') ?? {};
|
|
231
|
+
const raw: Partial<PaymentLink> = body;
|
|
232
|
+
raw.id = `plink_${c.get('user')?.did}`;
|
|
233
|
+
raw.active = true;
|
|
234
|
+
raw.livemode = !!c.get('livemode');
|
|
235
|
+
raw.created_via = c.get('user')?.via;
|
|
236
|
+
raw.currency_id = raw.currency_id || c.get('baseCurrency').id;
|
|
237
|
+
// Merge existing metadata with preview flag
|
|
238
|
+
raw.metadata = { ...raw.metadata, preview: '1' };
|
|
239
|
+
|
|
240
|
+
let doc = await PaymentLink.findByPk(raw.id);
|
|
241
|
+
if (doc) {
|
|
242
|
+
await doc.update({ ...formatBeforeSave(body), livemode: raw.livemode });
|
|
243
|
+
logger.info('Stashed payment link updated', { id: raw.id, user: c.get('user')?.did });
|
|
244
|
+
} else {
|
|
245
|
+
doc = await PaymentLink.create(raw as PaymentLink);
|
|
246
|
+
logger.info('New stashed payment link created', { id: raw.id, user: c.get('user')?.did });
|
|
247
|
+
}
|
|
248
|
+
return c.json(doc);
|
|
249
|
+
} catch (err) {
|
|
250
|
+
logger.error('Stash payment link error', { error: err.message, stack: err.stack, body: c.get('sanitizedBody') });
|
|
251
|
+
return c.json({ error: err.message }, 500);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
app.post('/', auth, async (c) => {
|
|
223
256
|
try {
|
|
224
|
-
const
|
|
257
|
+
const body = c.get('sanitizedBody') ?? {};
|
|
258
|
+
const { error } = PaymentLinkCreateSchema.validate(body);
|
|
225
259
|
if (error) {
|
|
226
|
-
logger.warn('Payment link create request invalid', { error: error.message, body
|
|
227
|
-
|
|
228
|
-
return;
|
|
260
|
+
logger.warn('Payment link create request invalid', { error: error.message, body });
|
|
261
|
+
return c.json({ error: `Payment link create request invalid: ${error.message}` }, 400);
|
|
229
262
|
}
|
|
230
263
|
const result = await createPaymentLink({
|
|
231
|
-
...
|
|
232
|
-
livemode: !!
|
|
233
|
-
created_via:
|
|
234
|
-
currency_id:
|
|
235
|
-
metadata: formatMetadata(
|
|
264
|
+
...body,
|
|
265
|
+
livemode: !!c.get('livemode'),
|
|
266
|
+
created_via: c.get('user')?.via,
|
|
267
|
+
currency_id: (body as any).currency_id || c.get('baseCurrency').id,
|
|
268
|
+
metadata: formatMetadata((body as any).metadata),
|
|
236
269
|
});
|
|
237
|
-
logger.info('Payment link created successfully', { id: result.id, user:
|
|
238
|
-
|
|
270
|
+
logger.info('Payment link created successfully', { id: result.id, user: c.get('user')?.did });
|
|
271
|
+
return c.json(result);
|
|
239
272
|
} catch (err) {
|
|
240
|
-
logger.error('Create payment link error', {
|
|
241
|
-
|
|
273
|
+
logger.error('Create payment link error', {
|
|
274
|
+
error: err.message,
|
|
275
|
+
stack: err.stack,
|
|
276
|
+
body: c.get('sanitizedBody'),
|
|
277
|
+
});
|
|
278
|
+
return c.json({ error: err.message }, 400);
|
|
242
279
|
}
|
|
243
280
|
});
|
|
244
281
|
|
|
@@ -247,24 +284,25 @@ const paginationSchema = createListParamSchema<{ active?: boolean; donation?: st
|
|
|
247
284
|
active: Joi.boolean().empty(''),
|
|
248
285
|
donation: Joi.string().empty(''),
|
|
249
286
|
});
|
|
250
|
-
|
|
251
|
-
const
|
|
287
|
+
app.get('/', auth, async (c) => {
|
|
288
|
+
const query = c.req.query();
|
|
289
|
+
const { page, pageSize, ...q } = await paginationSchema.validateAsync(query, { stripUnknown: true });
|
|
252
290
|
const where: WhereOptions<PaymentLink> = { 'metadata.preview': null };
|
|
253
291
|
|
|
254
|
-
if (typeof
|
|
255
|
-
where.active =
|
|
292
|
+
if (typeof q.active === 'boolean') {
|
|
293
|
+
where.active = q.active;
|
|
256
294
|
}
|
|
257
|
-
if (typeof
|
|
258
|
-
where.livemode =
|
|
295
|
+
if (typeof q.livemode === 'boolean') {
|
|
296
|
+
where.livemode = q.livemode;
|
|
259
297
|
}
|
|
260
|
-
if (
|
|
298
|
+
if (q.donation === 'hide') {
|
|
261
299
|
where.submit_type = { [Op.not]: 'donate' };
|
|
262
300
|
}
|
|
263
301
|
|
|
264
302
|
try {
|
|
265
303
|
const { rows: list, count } = await PaymentLink.findAndCountAll({
|
|
266
304
|
where,
|
|
267
|
-
order: getOrder(
|
|
305
|
+
order: getOrder(query, [['created_at', 'DESC']]),
|
|
268
306
|
offset: (page - 1) * pageSize,
|
|
269
307
|
limit: pageSize,
|
|
270
308
|
include: [],
|
|
@@ -282,15 +320,32 @@ router.get('/', auth, async (req, res) => {
|
|
|
282
320
|
});
|
|
283
321
|
});
|
|
284
322
|
|
|
285
|
-
|
|
323
|
+
return c.json({ count, list, paging: { page, pageSize } });
|
|
286
324
|
} catch (err) {
|
|
287
325
|
logger.error(err);
|
|
288
|
-
|
|
326
|
+
return c.json({ count: 0, list: [], paging: { page, pageSize } });
|
|
289
327
|
}
|
|
290
328
|
});
|
|
291
329
|
|
|
292
|
-
|
|
293
|
-
|
|
330
|
+
app.get('/:id/benefits', async (c) => {
|
|
331
|
+
try {
|
|
332
|
+
const doc = await PaymentLink.findByPk(c.req.param('id'), {
|
|
333
|
+
attributes: ['id', 'donation_settings'],
|
|
334
|
+
});
|
|
335
|
+
if (!doc) {
|
|
336
|
+
return c.json({ error: 'payment link not found' }, 404);
|
|
337
|
+
}
|
|
338
|
+
const locale = c.req.query('locale') as string;
|
|
339
|
+
const benefits = await getDonationBenefits(doc, '', locale);
|
|
340
|
+
return c.json(benefits);
|
|
341
|
+
} catch (err) {
|
|
342
|
+
logger.error('Get donation benefits error', { error: err.message, stack: err.stack, id: c.req.param('id') });
|
|
343
|
+
return c.json({ error: err.message }, 400);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
app.get('/:id', auth, async (c) => {
|
|
348
|
+
const doc = await PaymentLink.findByPkOrLookupKey(c.req.param('id') || '');
|
|
294
349
|
|
|
295
350
|
if (doc) {
|
|
296
351
|
// @ts-ignore
|
|
@@ -298,10 +353,9 @@ router.get('/:id', auth, async (req, res) => {
|
|
|
298
353
|
}
|
|
299
354
|
|
|
300
355
|
if (doc) {
|
|
301
|
-
|
|
302
|
-
} else {
|
|
303
|
-
res.status(404).json(null);
|
|
356
|
+
return c.json(doc);
|
|
304
357
|
}
|
|
358
|
+
return c.json(null, 404);
|
|
305
359
|
});
|
|
306
360
|
|
|
307
361
|
const PaymentLinkUpdateSchema = Joi.object({
|
|
@@ -351,126 +405,89 @@ const PaymentLinkUpdateSchema = Joi.object({
|
|
|
351
405
|
.min(0)
|
|
352
406
|
.optional(),
|
|
353
407
|
}).unknown(true);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
logger.warn('Payment link update request invalid', { error: error.message, id: req.params.id, body: req.body });
|
|
359
|
-
return res.status(400).json({ error: `Payment link update request invalid: ${error.message}` });
|
|
360
|
-
}
|
|
361
|
-
const doc = await PaymentLink.findByPk(req.params.id);
|
|
408
|
+
|
|
409
|
+
// archive — static sub-path, registered before /:id to avoid shadowing
|
|
410
|
+
app.put('/:id/archive', auth, async (c) => {
|
|
411
|
+
const doc = await PaymentLink.findByPk(c.req.param('id'));
|
|
362
412
|
|
|
363
413
|
if (!doc) {
|
|
364
|
-
logger.warn('Payment link not found for
|
|
365
|
-
return
|
|
414
|
+
logger.warn('Payment link not found for archiving', { id: c.req.param('id') });
|
|
415
|
+
return c.json({ error: 'payment link not found' }, 404);
|
|
366
416
|
}
|
|
417
|
+
|
|
367
418
|
if (doc.active === false) {
|
|
368
|
-
logger.warn('Attempt to
|
|
369
|
-
return
|
|
419
|
+
logger.warn('Attempt to archive already archived payment link', { id: c.req.param('id') });
|
|
420
|
+
return c.json({ error: 'payment link already archived' }, 403);
|
|
370
421
|
}
|
|
371
422
|
|
|
372
423
|
try {
|
|
373
|
-
await doc.update(
|
|
374
|
-
logger.info('Payment link
|
|
375
|
-
|
|
424
|
+
await doc.update({ active: false });
|
|
425
|
+
logger.info('Payment link archived successfully', { id: c.req.param('id'), user: c.get('user')?.did });
|
|
426
|
+
return c.json(doc);
|
|
376
427
|
} catch (err) {
|
|
377
|
-
logger.error('
|
|
378
|
-
|
|
379
|
-
stack: err.stack,
|
|
380
|
-
id: req.params.id,
|
|
381
|
-
body: req.body,
|
|
382
|
-
});
|
|
383
|
-
res.status(500).json({ error: 'Failed to update payment link' });
|
|
428
|
+
logger.error('Archive payment link error', { error: err.message, stack: err.stack, id: c.req.param('id') });
|
|
429
|
+
return c.json({ error: 'Failed to archive payment link' }, 500);
|
|
384
430
|
}
|
|
385
431
|
});
|
|
386
432
|
|
|
387
|
-
//
|
|
388
|
-
|
|
389
|
-
const
|
|
433
|
+
// eslint-disable-next-line consistent-return
|
|
434
|
+
app.put('/:id', auth, async (c) => {
|
|
435
|
+
const body = c.get('sanitizedBody') ?? {};
|
|
436
|
+
const { error } = PaymentLinkUpdateSchema.validate(body);
|
|
437
|
+
if (error) {
|
|
438
|
+
logger.warn('Payment link update request invalid', {
|
|
439
|
+
error: error.message,
|
|
440
|
+
id: c.req.param('id'),
|
|
441
|
+
body,
|
|
442
|
+
});
|
|
443
|
+
return c.json({ error: `Payment link update request invalid: ${error.message}` }, 400);
|
|
444
|
+
}
|
|
445
|
+
const doc = await PaymentLink.findByPk(c.req.param('id'));
|
|
390
446
|
|
|
391
447
|
if (!doc) {
|
|
392
|
-
logger.warn('Payment link not found for
|
|
393
|
-
return
|
|
448
|
+
logger.warn('Payment link not found for update', { id: c.req.param('id') });
|
|
449
|
+
return c.json({ error: 'payment link not found' }, 404);
|
|
394
450
|
}
|
|
395
|
-
|
|
396
451
|
if (doc.active === false) {
|
|
397
|
-
logger.warn('Attempt to
|
|
398
|
-
return
|
|
452
|
+
logger.warn('Attempt to update archived payment link', { id: c.req.param('id') });
|
|
453
|
+
return c.json({ error: 'payment link archived' }, 403);
|
|
399
454
|
}
|
|
400
455
|
|
|
401
456
|
try {
|
|
402
|
-
await doc.update({
|
|
403
|
-
logger.info('Payment link
|
|
404
|
-
return
|
|
457
|
+
await doc.update(formatBeforeSave(Object.assign({}, doc.dataValues, body)));
|
|
458
|
+
logger.info('Payment link updated successfully', { id: c.req.param('id'), user: c.get('user')?.did });
|
|
459
|
+
return c.json(doc);
|
|
405
460
|
} catch (err) {
|
|
406
|
-
logger.error('
|
|
407
|
-
|
|
461
|
+
logger.error('Update payment link error', {
|
|
462
|
+
error: err.message,
|
|
463
|
+
stack: err.stack,
|
|
464
|
+
id: c.req.param('id'),
|
|
465
|
+
body,
|
|
466
|
+
});
|
|
467
|
+
return c.json({ error: 'Failed to update payment link' }, 500);
|
|
408
468
|
}
|
|
409
469
|
});
|
|
410
470
|
|
|
411
471
|
// delete
|
|
412
|
-
|
|
413
|
-
const doc = await PaymentLink.findByPk(req.
|
|
472
|
+
app.delete('/:id', auth, async (c) => {
|
|
473
|
+
const doc = await PaymentLink.findByPk(c.req.param('id'));
|
|
414
474
|
|
|
415
475
|
if (!doc) {
|
|
416
|
-
return
|
|
476
|
+
return c.json({ error: 'payment link not found' }, 404);
|
|
417
477
|
}
|
|
418
478
|
|
|
419
479
|
if (doc.active === false) {
|
|
420
|
-
return
|
|
480
|
+
return c.json({ error: 'payment link archived' }, 403);
|
|
421
481
|
}
|
|
422
482
|
|
|
423
483
|
try {
|
|
424
484
|
await doc.destroy();
|
|
425
|
-
logger.info('Payment link deleted successfully', { id: req.
|
|
426
|
-
return
|
|
427
|
-
} catch (err) {
|
|
428
|
-
logger.error('Delete payment link error', { error: err.message, stack: err.stack, id: req.params.id });
|
|
429
|
-
return res.status(500).json({ error: 'Failed to delete payment link' });
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
router.post('/stash', auth, async (req, res) => {
|
|
434
|
-
try {
|
|
435
|
-
const raw: Partial<PaymentLink> = req.body;
|
|
436
|
-
raw.id = `plink_${req.user?.did}`;
|
|
437
|
-
raw.active = true;
|
|
438
|
-
raw.livemode = !!req.livemode;
|
|
439
|
-
raw.created_via = req.user?.via;
|
|
440
|
-
raw.currency_id = raw.currency_id || req.baseCurrency.id;
|
|
441
|
-
// Merge existing metadata with preview flag
|
|
442
|
-
raw.metadata = { ...raw.metadata, preview: '1' };
|
|
443
|
-
|
|
444
|
-
let doc = await PaymentLink.findByPk(raw.id);
|
|
445
|
-
if (doc) {
|
|
446
|
-
await doc.update({ ...formatBeforeSave(req.body), livemode: raw.livemode });
|
|
447
|
-
logger.info('Stashed payment link updated', { id: raw.id, user: req.user?.did });
|
|
448
|
-
} else {
|
|
449
|
-
doc = await PaymentLink.create(raw as PaymentLink);
|
|
450
|
-
logger.info('New stashed payment link created', { id: raw.id, user: req.user?.did });
|
|
451
|
-
}
|
|
452
|
-
res.json(doc);
|
|
453
|
-
} catch (err) {
|
|
454
|
-
logger.error('Stash payment link error', { error: err.message, stack: err.stack, body: req.body });
|
|
455
|
-
res.status(500).json({ error: err.message });
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
router.get('/:id/benefits', async (req, res) => {
|
|
460
|
-
try {
|
|
461
|
-
const doc = await PaymentLink.findByPk(req.params.id, {
|
|
462
|
-
attributes: ['id', 'donation_settings'],
|
|
463
|
-
});
|
|
464
|
-
if (!doc) {
|
|
465
|
-
return res.status(404).json({ error: 'payment link not found' });
|
|
466
|
-
}
|
|
467
|
-
const locale = req.query.locale as string;
|
|
468
|
-
const benefits = await getDonationBenefits(doc, '', locale);
|
|
469
|
-
return res.json(benefits);
|
|
485
|
+
logger.info('Payment link deleted successfully', { id: c.req.param('id'), user: c.get('user')?.did });
|
|
486
|
+
return c.json(doc);
|
|
470
487
|
} catch (err) {
|
|
471
|
-
logger.error('
|
|
472
|
-
return
|
|
488
|
+
logger.error('Delete payment link error', { error: err.message, stack: err.stack, id: c.req.param('id') });
|
|
489
|
+
return c.json({ error: 'Failed to delete payment link' }, 500);
|
|
473
490
|
}
|
|
474
491
|
});
|
|
475
492
|
|
|
476
|
-
export default
|
|
493
|
+
export default app;
|