create-ailk 0.23.0 → 0.25.1
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/README.md +68 -33
- package/component-catalog.json +3 -3
- package/component-catalog.md +3 -3
- package/dist/add-module.js +10 -3
- package/dist/add-route.d.ts +12 -1
- package/dist/add-route.js +38 -4
- package/dist/cli.js +12 -7
- package/dist/derive-architecture.d.ts +3 -4
- package/dist/derive-architecture.js +75 -22
- package/dist/lib/design-checks.d.ts +9 -4
- package/dist/lib/design-checks.js +13 -7
- package/dist/lib/extract-module-bundle.js +29 -2
- package/dist/lib/fetch-template-snapshot.d.ts +1 -1
- package/dist/lib/fetch-template-snapshot.js +7 -3
- package/dist/lib/import-graph.d.ts +1 -1
- package/dist/lib/import-graph.js +4 -4
- package/dist/lib/module-license-gate.d.ts +12 -1
- package/dist/lib/module-license-gate.js +34 -12
- package/dist/lib/scaffold-render-sweep.d.ts +33 -0
- package/dist/lib/scaffold-render-sweep.js +45 -0
- package/dist/module-architecture.d.ts +20 -3
- package/dist/module-architecture.js +122 -538
- package/dist/paid-sections.d.ts +25 -1
- package/dist/paid-sections.js +88 -3
- package/dist/surfaces.js +10 -2
- package/dist/sync-routes.d.ts +30 -4
- package/dist/sync-routes.js +271 -18
- package/dist/template-record.d.ts +14 -4
- package/dist/template-record.js +23 -5
- package/dist/topology.d.ts +16 -3
- package/dist/topology.js +31 -19
- package/dist/update.d.ts +10 -1
- package/dist/update.js +540 -16
- package/package.json +3 -3
- package/release-scope.json +1 -1
- package/templates/.claude/cloudparity-repo-hooks.json +5 -0
- package/templates/.claude/hooks/template-guard.sh +137 -0
- package/templates/.claude/rules/extending.md +106 -0
- package/templates/.claude/rules/loop-contract.md +2 -2
- package/templates/.claude/settings.json +11 -0
- package/templates/.env.example +9 -5
- package/templates/.github/workflows/ci.yml +7 -4
- package/templates/CLAUDE.md +15 -3
- package/templates/CONVENTIONS.md +8 -10
- package/templates/README.md +14 -13
- package/templates/apps/api/.env.example +9 -2
- package/templates/apps/api/CLAUDE.md +122 -82
- package/templates/apps/api/jest.config.cjs +15 -5
- package/templates/apps/api/package.json +16 -20
- package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
- package/templates/apps/api/src/index.ts +1 -1
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +7 -4
- package/templates/apps/api/src/modules/commerce.ts +10 -0
- package/templates/apps/api/src/modules/content-write.ts +10 -0
- package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
- package/templates/apps/api/src/modules/scheduling.ts +10 -0
- package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
- package/templates/apps/api/src/modules/workspace.ts +10 -0
- package/templates/apps/api/src/server.ts +117 -1857
- package/templates/apps/api/vercel.json +2 -2
- package/templates/apps/mcp/CLAUDE.md +77 -24
- package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
- package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
- package/templates/apps/mcp/jest.config.cjs +6 -1
- package/templates/apps/mcp/package.json +5 -12
- package/templates/apps/mcp/src/app.ts +8 -7
- package/templates/apps/mcp/src/index.ts +6 -34
- package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
- package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
- package/templates/apps/mcp/src/site.ts +12 -0
- package/templates/apps/web/.env.example +1 -1
- package/templates/apps/web/CLAUDE.md +21 -5
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +14 -4
- package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
- package/templates/apps/web/app/[locale]/contact/intake-script.ts +1 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +28 -7
- package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
- package/templates/apps/web/app/api/revalidate/route.ts +3 -3
- package/templates/apps/web/auth.ts +2 -2
- package/templates/apps/web/jest.config.cjs +1 -0
- package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +7 -0
- package/templates/apps/web/lib/auth-email.ts +1 -1
- package/templates/apps/web/lib/magnet-routes.ts +3 -1
- package/templates/apps/web/lib/newsletter.actions.ts +9 -6
- package/templates/apps/web/lib/relay.ts +2 -2
- package/templates/apps/web/lib/release-scope.ts +47 -0
- package/templates/apps/web/lib/server-api.ts +1 -1
- package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
- package/templates/customizations.yaml +37 -0
- package/templates/database/prisma.config.ts +10 -14
- package/templates/database/seed-test.ts +2 -2
- package/templates/database/seed.ts +32 -5
- package/templates/package.json +12 -6
- package/templates/pnpm-workspace.yaml +0 -1
- package/templates/project.yaml +16 -8
- package/templates/tools/jest/reporters.cjs +65 -0
- package/templates/tools/lint-architecture.ts +757 -7
- package/templates/tsconfig.json +1 -2
- package/versions.json +48 -35
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
- package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
- package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
- package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
- package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
- package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
- package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
- package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
- package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
- package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
- package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
- package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
- package/templates/apps/api/src/bin/spokes.ts +0 -198
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
- package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
- package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
- package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
- package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
- package/templates/apps/api/src/config/index.ts +0 -596
- package/templates/apps/api/src/config/modules.ts +0 -83
- package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
- package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
- package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
- package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
- package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
- package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
- package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
- package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
- package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
- package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
- package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
- package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
- package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
- package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
- package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
- package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -292
- package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
- package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
- package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
- package/templates/apps/api/src/lib/agent-store.ts +0 -613
- package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
- package/templates/apps/api/src/lib/consent-store.ts +0 -363
- package/templates/apps/api/src/lib/content-adapter.ts +0 -112
- package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
- package/templates/apps/api/src/lib/error-serializer.ts +0 -164
- package/templates/apps/api/src/lib/errors.ts +0 -95
- package/templates/apps/api/src/lib/file-fallback.ts +0 -87
- package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
- package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
- package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
- package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
- package/templates/apps/api/src/lib/license-key-store.ts +0 -45
- package/templates/apps/api/src/lib/locales.ts +0 -201
- package/templates/apps/api/src/lib/outbound-http.ts +0 -127
- package/templates/apps/api/src/lib/prisma.ts +0 -21
- package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
- package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
- package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
- package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
- package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
- package/templates/apps/api/src/lib/site.ts +0 -254
- package/templates/apps/api/src/lib/slice-load.ts +0 -90
- package/templates/apps/api/src/lib/spoke-store.ts +0 -180
- package/templates/apps/api/src/lib/stripe.ts +0 -318
- package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
- package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
- package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
- package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
- package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
- package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
- package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
- package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
- package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
- package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
- package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
- package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
- package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
- package/templates/apps/api/src/middleware/auth.ts +0 -864
- package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
- package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -264
- package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
- package/templates/apps/api/src/openapi/index.ts +0 -18
- package/templates/apps/api/src/openapi/spec.ts +0 -1815
- package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
- package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
- package/templates/apps/api/src/routes/aeo/index.ts +0 -107
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
- package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
- package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
- package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
- package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
- package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
- package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
- package/templates/apps/api/src/routes/auth/user.ts +0 -305
- package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -325
- package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
- package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1300
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
- package/templates/apps/api/src/routes/checkout/index.ts +0 -34
- package/templates/apps/api/src/routes/checkout/session.ts +0 -171
- package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
- package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
- package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
- package/templates/apps/api/src/routes/consent/account.ts +0 -268
- package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
- package/templates/apps/api/src/routes/consent/index.ts +0 -26
- package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
- package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
- package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
- package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
- package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
- package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
- package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
- package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
- package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
- package/templates/apps/api/src/routes/content/get-page.ts +0 -268
- package/templates/apps/api/src/routes/content/index.ts +0 -49
- package/templates/apps/api/src/routes/content/list-pages.ts +0 -95
- package/templates/apps/api/src/routes/content/list-types.ts +0 -19
- package/templates/apps/api/src/routes/content/offerings.ts +0 -184
- package/templates/apps/api/src/routes/content/pricing.ts +0 -176
- package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
- package/templates/apps/api/src/routes/content/search.ts +0 -129
- package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
- package/templates/apps/api/src/routes/content/slug.ts +0 -9
- package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
- package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
- package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
- package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
- package/templates/apps/api/src/routes/leads/index.ts +0 -573
- package/templates/apps/api/src/routes/leads/list.ts +0 -104
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
- package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -480
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -465
- package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
- package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
- package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
- package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
- package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
- package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
- package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
- package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
- package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
- package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
- package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
- package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
- package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
- package/templates/apps/api/src/routes/requests/index.ts +0 -54
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
- package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
- package/templates/apps/api/src/routes/webhooks/README.md +0 -398
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -448
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -808
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
- package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
- package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
- package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2026
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -528
- package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
- package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
- package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
- package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
- package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
- package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
- package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -867
- package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
- package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
- package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
- package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
- package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
- package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
- package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
- package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
- package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1176
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -444
- package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -154
- package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
- package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
- package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
- package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
- package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
- package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
- package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
- package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
- package/templates/apps/api/src/services/abandon-email.ts +0 -313
- package/templates/apps/api/src/services/aeo-score.ts +0 -325
- package/templates/apps/api/src/services/answer-distributions.ts +0 -138
- package/templates/apps/api/src/services/audit-log.ts +0 -961
- package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
- package/templates/apps/api/src/services/consent.ts +0 -834
- package/templates/apps/api/src/services/default-tenant.ts +0 -416
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -755
- package/templates/apps/api/src/services/dunning-policy.ts +0 -294
- package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
- package/templates/apps/api/src/services/entitlements.ts +0 -338
- package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
- package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
- package/templates/apps/api/src/services/lead-promotion.ts +0 -160
- package/templates/apps/api/src/services/lead-routing.ts +0 -1372
- package/templates/apps/api/src/services/leads-inbox.ts +0 -312
- package/templates/apps/api/src/services/listing-config.ts +0 -178
- package/templates/apps/api/src/services/magnet-completion.ts +0 -242
- package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -295
- package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
- package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -868
- package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
- package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -396
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -681
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
- package/templates/apps/api/src/services/offerings/catalog.ts +0 -308
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -385
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
- package/templates/apps/api/src/services/offerings/connection.ts +0 -1003
- package/templates/apps/api/src/services/offerings/index.ts +0 -614
- package/templates/apps/api/src/services/offerings/source.ts +0 -140
- package/templates/apps/api/src/services/offerings/store.ts +0 -150
- package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
- package/templates/apps/api/src/services/person.ts +0 -1188
- package/templates/apps/api/src/services/plan-offerings.ts +0 -125
- package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
- package/templates/apps/api/src/services/project-listings.ts +0 -2073
- package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
- package/templates/apps/api/src/services/request-confirm.ts +0 -698
- package/templates/apps/api/src/services/revalidation.ts +0 -235
- package/templates/apps/api/src/services/slack-notify.ts +0 -291
- package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
- package/templates/apps/api/src/services/usage-credits.ts +0 -340
- package/templates/apps/api/src/services/verified-email.ts +0 -71
- package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
- package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
- package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
- package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
- package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
- package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
- package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
- package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
- package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
- package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
- package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
- package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
- package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1151
- package/templates/apps/mcp/__tests__/index.test.ts +0 -195
- package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
- package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
- package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -65
- package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -187
- package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
- package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
- package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -165
- package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
- package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -228
- package/templates/apps/mcp/__tests__/locale.test.ts +0 -135
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
- package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
- package/templates/apps/mcp/__tests__/read_content.test.ts +0 -474
- package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -225
- package/templates/apps/mcp/__tests__/search_content.test.ts +0 -256
- package/templates/apps/mcp/__tests__/server.test.ts +0 -388
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -307
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -223
- package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
- package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
- package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
- package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
- package/templates/apps/mcp/src/abuse/index.ts +0 -342
- package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
- package/templates/apps/mcp/src/boot.ts +0 -167
- package/templates/apps/mcp/src/config/modules.ts +0 -43
- package/templates/apps/mcp/src/http-transport.ts +0 -526
- package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
- package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
- package/templates/apps/mcp/src/lib/content-adapter.ts +0 -142
- package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -139
- package/templates/apps/mcp/src/lib/errors.ts +0 -61
- package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
- package/templates/apps/mcp/src/lib/locales.ts +0 -171
- package/templates/apps/mcp/src/lib/prisma.ts +0 -39
- package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
- package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
- package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
- package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
- package/templates/apps/mcp/src/request-context.ts +0 -52
- package/templates/apps/mcp/src/server.ts +0 -343
- package/templates/apps/mcp/src/serverless-app.ts +0 -88
- package/templates/apps/mcp/src/tools/audit.ts +0 -127
- package/templates/apps/mcp/src/tools/capture_lead.ts +0 -64
- package/templates/apps/mcp/src/tools/create_project.ts +0 -134
- package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
- package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
- package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
- package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
- package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
- package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
- package/templates/apps/mcp/src/tools/index.ts +0 -137
- package/templates/apps/mcp/src/tools/list_pages.ts +0 -74
- package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
- package/templates/apps/mcp/src/tools/proposals.ts +0 -27
- package/templates/apps/mcp/src/tools/purchase.ts +0 -205
- package/templates/apps/mcp/src/tools/read_content.ts +0 -75
- package/templates/apps/mcp/src/tools/request_callback.ts +0 -59
- package/templates/apps/mcp/src/tools/search_content.ts +0 -67
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -57
- package/templates/apps/mcp/src/workspace-server.ts +0 -224
- package/templates/database/CHANGELOG.md +0 -961
- package/templates/database/LICENSE +0 -202
- package/templates/database/NOTICE +0 -2
- package/templates/database/README.md +0 -243
- package/templates/database/__tests__/agents.db.test.ts +0 -320
- package/templates/database/__tests__/appointment.db.test.ts +0 -106
- package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
- package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
- package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
- package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
- package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
- package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
- package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
- package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
- package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
- package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
- package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
- package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
- package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
- package/templates/database/__tests__/flows-presets.test.ts +0 -173
- package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
- package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
- package/templates/database/__tests__/member-area.db.test.ts +0 -257
- package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
- package/templates/database/__tests__/member-contract.db.test.ts +0 -413
- package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
- package/templates/database/__tests__/offerings-migration.test.ts +0 -197
- package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
- package/templates/database/__tests__/offerings.db.test.ts +0 -303
- package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
- package/templates/database/__tests__/person-contact.db.test.ts +0 -563
- package/templates/database/__tests__/person-notes.db.test.ts +0 -249
- package/templates/database/__tests__/person.db.test.ts +0 -586
- package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
- package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
- package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
- package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
- package/templates/database/__tests__/seed.test.ts +0 -240
- package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
- package/templates/database/__tests__/tenancy.test.ts +0 -141
- package/templates/database/__tests__/user-cascade.test.ts +0 -140
- package/templates/database/_gitignore +0 -8
- package/templates/database/auth/.gitkeep +0 -0
- package/templates/database/auth/schema.prisma +0 -641
- package/templates/database/config/.gitkeep +0 -0
- package/templates/database/config/schema.prisma +0 -441
- package/templates/database/content/.gitkeep +0 -0
- package/templates/database/content/schema.prisma +0 -339
- package/templates/database/eslint.config.mjs +0 -69
- package/templates/database/flows/listing-diagnostic.ts +0 -182
- package/templates/database/flows/presets.ts +0 -315
- package/templates/database/inbox/.gitkeep +0 -0
- package/templates/database/inbox/README.md +0 -3
- package/templates/database/inbox/__tests__/schema.test.ts +0 -44
- package/templates/database/inbox/schema.prisma +0 -1447
- package/templates/database/jest.config.cjs +0 -36
- package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
- package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
- package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
- package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
- package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
- package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
- package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
- package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
- package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
- package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
- package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
- package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
- package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
- package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
- package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
- package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
- package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
- package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
- package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
- package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
- package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
- package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
- package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
- package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
- package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
- package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
- package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
- package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
- package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
- package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
- package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
- package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
- package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
- package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
- package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
- package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
- package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
- package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
- package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
- package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
- package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
- package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
- package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
- package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
- package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
- package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
- package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
- package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
- package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
- package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
- package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
- package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
- package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
- package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
- package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
- package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
- package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
- package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
- package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
- package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
- package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
- package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
- package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
- package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
- package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
- package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
- package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
- package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
- package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
- package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
- package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
- package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
- package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
- package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
- package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
- package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
- package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
- package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
- package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
- package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
- package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
- package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
- package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
- package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
- package/templates/database/migrations/migration_lock.toml +0 -3
- package/templates/database/ops/.gitkeep +0 -0
- package/templates/database/ops/schema.prisma +0 -43
- package/templates/database/package.json +0 -89
- package/templates/database/schema.prisma +0 -71
- package/templates/database/scripts/db-generate-locked.sh +0 -80
- package/templates/database/scripts/person-backfill.sql +0 -132
- package/templates/database/tenancy.ts +0 -183
- package/templates/database/tsconfig.build.json +0 -16
- package/templates/database/tsconfig.flows.json +0 -15
- package/templates/database/tsconfig.json +0 -16
- package/templates/database/tsconfig.tenancy.json +0 -14
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file piece-kind.db.test.ts
|
|
3
|
-
*
|
|
4
|
-
* LIVE-DATABASE proof of the piece kind and a proposal's price and payment
|
|
5
|
-
* columns (#8516, spec docs/specs/8516-proposals-as-an-artifact-kind-spec.md
|
|
6
|
-
* D1, D2, AC-1). Requires DATABASE_URL pointing at a Postgres with the
|
|
7
|
-
* migrations applied — SKIPS when DATABASE_URL is unset (the repo convention;
|
|
8
|
-
* the `apps/api Route Tests (Postgres)` workflow exercises it).
|
|
9
|
-
*
|
|
10
|
-
* Uses the `pg` driver directly, in ONE transaction that is rolled back, so
|
|
11
|
-
* dropping and re-adding the columns never outlives the suite. What it proves
|
|
12
|
-
* that a mock cannot:
|
|
13
|
-
* 1. Re-running the migration's own text over a piece written with the
|
|
14
|
-
* pre-#8516 column set reads it back as a `deliverable`, the seven other
|
|
15
|
-
* columns NULL and every pre-existing column (`updated_at` included)
|
|
16
|
-
* byte-equal — no row is rewritten.
|
|
17
|
-
* 2. Each CHECK and the unique index refuse what they name.
|
|
18
|
-
*/
|
|
19
|
-
import { readFileSync } from "node:fs";
|
|
20
|
-
import { join } from "node:path";
|
|
21
|
-
|
|
22
|
-
import { Client } from "pg";
|
|
23
|
-
|
|
24
|
-
const describeDb = process.env.DATABASE_URL ? describe : describe.skip;
|
|
25
|
-
|
|
26
|
-
const MIGRATION = join(__dirname, "..", "migrations", "20261016120000_piece_kind", "migration.sql");
|
|
27
|
-
|
|
28
|
-
const WS = "wksp_01920000-8516-7000-8000-0000000000c1";
|
|
29
|
-
const USER = "user_01920000-8516-7000-8000-0000000000a1";
|
|
30
|
-
const NEW_COLUMNS = [
|
|
31
|
-
"kind",
|
|
32
|
-
"price_amount",
|
|
33
|
-
"price_currency",
|
|
34
|
-
"checkout_session_id",
|
|
35
|
-
"checkout_url",
|
|
36
|
-
"checkout_expires_at",
|
|
37
|
-
"paid_at",
|
|
38
|
-
"paid_session_id",
|
|
39
|
-
] as const;
|
|
40
|
-
|
|
41
|
-
describeDb("the piece kind columns (#8516 D1, D2, AC-1, live DB)", () => {
|
|
42
|
-
let db: Client;
|
|
43
|
-
let personId: string;
|
|
44
|
-
|
|
45
|
-
beforeAll(async () => {
|
|
46
|
-
db = new Client({ connectionString: process.env.DATABASE_URL });
|
|
47
|
-
await db.connect();
|
|
48
|
-
await db.query("BEGIN");
|
|
49
|
-
personId = (
|
|
50
|
-
await db.query<{ id: string }>(
|
|
51
|
-
`INSERT INTO "people" ("workspace_id", "email", "updated_at") VALUES ($1, $2, now()) RETURNING "id"`,
|
|
52
|
-
[WS, "p8516@example.com"],
|
|
53
|
-
)
|
|
54
|
-
).rows[0]!.id;
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
afterAll(async () => {
|
|
58
|
-
await db.query("ROLLBACK");
|
|
59
|
-
await db.end();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
/** Insert one piece with the pre-#8516 column set plus any of the new ones. */
|
|
63
|
-
const insertPiece = (cols: Record<string, unknown> = {}) => {
|
|
64
|
-
const all: Record<string, unknown> = {
|
|
65
|
-
workspace_id: WS,
|
|
66
|
-
person_id: personId,
|
|
67
|
-
title: "Site redesign",
|
|
68
|
-
stage: "requested",
|
|
69
|
-
updated_by: USER,
|
|
70
|
-
updated_at: new Date("2026-10-01T09:00:00.000Z"),
|
|
71
|
-
...cols,
|
|
72
|
-
};
|
|
73
|
-
const names = Object.keys(all);
|
|
74
|
-
return db.query<{ id: string }>(
|
|
75
|
-
`INSERT INTO "pieces" (${names.map((n) => `"${n}"`).join(", ")})
|
|
76
|
-
VALUES (${names.map((_, i) => `$${i + 1}`).join(", ")}) RETURNING "id"`,
|
|
77
|
-
names.map((n) => all[n]),
|
|
78
|
-
);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/** Run `sql` inside a savepoint; resolve to the violated constraint's name, or null. */
|
|
82
|
-
const violation = async (run: () => Promise<unknown>): Promise<string | null> => {
|
|
83
|
-
await db.query("SAVEPOINT attempt");
|
|
84
|
-
try {
|
|
85
|
-
await run();
|
|
86
|
-
await db.query("RELEASE SAVEPOINT attempt");
|
|
87
|
-
return null;
|
|
88
|
-
} catch (err) {
|
|
89
|
-
await db.query("ROLLBACK TO SAVEPOINT attempt");
|
|
90
|
-
return (err as { constraint?: string }).constraint ?? String(err);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
it("re-running the migration over a pre-#8516 row reads it as a deliverable, nothing else changed", async () => {
|
|
95
|
-
await db.query(
|
|
96
|
-
`ALTER TABLE "pieces" ${NEW_COLUMNS.map((c) => `DROP COLUMN "${c}"`).join(", ")}`,
|
|
97
|
-
);
|
|
98
|
-
const pieceId = (await insertPiece()).rows[0]!.id;
|
|
99
|
-
await db.query(
|
|
100
|
-
`INSERT INTO "piece_versions" ("workspace_id", "person_id", "piece_id", "version", "link", "delivered_by")
|
|
101
|
-
VALUES ($1, $2, $3, 1, 'https://example.com/v1.pdf', $4)`,
|
|
102
|
-
[WS, personId, pieceId, USER],
|
|
103
|
-
);
|
|
104
|
-
const before = (
|
|
105
|
-
await db.query<{ row: Record<string, unknown> }>(
|
|
106
|
-
`SELECT row_to_json(p) AS row FROM "pieces" p WHERE "id" = $1`,
|
|
107
|
-
[pieceId],
|
|
108
|
-
)
|
|
109
|
-
).rows[0]!.row;
|
|
110
|
-
|
|
111
|
-
await db.query(readFileSync(MIGRATION, "utf8"));
|
|
112
|
-
|
|
113
|
-
const after = (
|
|
114
|
-
await db.query<{ row: Record<string, unknown> }>(
|
|
115
|
-
`SELECT row_to_json(p) AS row FROM "pieces" p WHERE "id" = $1`,
|
|
116
|
-
[pieceId],
|
|
117
|
-
)
|
|
118
|
-
).rows[0]!.row;
|
|
119
|
-
expect(after.kind).toBe("deliverable");
|
|
120
|
-
for (const column of NEW_COLUMNS.slice(1)) expect(after[column]).toBeNull();
|
|
121
|
-
const kept = Object.fromEntries(
|
|
122
|
-
Object.entries(after).filter(([key]) => !(NEW_COLUMNS as readonly string[]).includes(key)),
|
|
123
|
-
);
|
|
124
|
-
expect(kept).toEqual(before);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("refuses a kind outside the two", async () => {
|
|
128
|
-
expect(await violation(() => insertPiece({ kind: "other" }))).toBe("pieces_kind_allowed");
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("refuses a price on a deliverable, half a price, and an amount out of range", async () => {
|
|
132
|
-
expect(
|
|
133
|
-
await violation(() => insertPiece({ price_amount: 1000, price_currency: "usd" })),
|
|
134
|
-
).toBe("pieces_price_proposal_only");
|
|
135
|
-
expect(await violation(() => insertPiece({ kind: "proposal", price_amount: 1000 }))).toBe(
|
|
136
|
-
"pieces_price_pair",
|
|
137
|
-
);
|
|
138
|
-
for (const amount of [0, 100000001]) {
|
|
139
|
-
expect(
|
|
140
|
-
await violation(() =>
|
|
141
|
-
insertPiece({ kind: "proposal", price_amount: amount, price_currency: "usd" }),
|
|
142
|
-
),
|
|
143
|
-
).toBe("pieces_price_range");
|
|
144
|
-
}
|
|
145
|
-
expect(
|
|
146
|
-
await violation(() =>
|
|
147
|
-
insertPiece({ kind: "proposal", price_amount: 1, price_currency: "usd" }),
|
|
148
|
-
),
|
|
149
|
-
).toBeNull();
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const SESSION = {
|
|
153
|
-
checkout_session_id: "cs_test_a1",
|
|
154
|
-
checkout_url: "https://checkout.stripe.com/c/pay/cs_test_a1",
|
|
155
|
-
checkout_expires_at: new Date("2026-10-16T13:00:00.000Z"),
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
it("refuses a checkout session on an unapproved or unpriced piece, and a partial session", async () => {
|
|
159
|
-
expect(
|
|
160
|
-
await violation(() =>
|
|
161
|
-
insertPiece({ kind: "proposal", price_amount: 5000, price_currency: "usd", ...SESSION }),
|
|
162
|
-
),
|
|
163
|
-
).toBe("pieces_checkout_needs_approved_price");
|
|
164
|
-
expect(
|
|
165
|
-
await violation(() => insertPiece({ kind: "proposal", approved_at: new Date(), ...SESSION })),
|
|
166
|
-
).toBe("pieces_checkout_needs_approved_price");
|
|
167
|
-
expect(
|
|
168
|
-
await violation(() =>
|
|
169
|
-
insertPiece({
|
|
170
|
-
kind: "proposal",
|
|
171
|
-
price_amount: 5000,
|
|
172
|
-
price_currency: "usd",
|
|
173
|
-
approved_at: new Date(),
|
|
174
|
-
checkout_session_id: "cs_test_a2",
|
|
175
|
-
}),
|
|
176
|
-
),
|
|
177
|
-
).toBe("pieces_checkout_triple");
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it("refuses paid_at without the session that paid it", async () => {
|
|
181
|
-
expect(
|
|
182
|
-
await violation(() =>
|
|
183
|
-
insertPiece({
|
|
184
|
-
kind: "proposal",
|
|
185
|
-
price_amount: 5000,
|
|
186
|
-
price_currency: "usd",
|
|
187
|
-
approved_at: new Date(),
|
|
188
|
-
paid_at: new Date(),
|
|
189
|
-
}),
|
|
190
|
-
),
|
|
191
|
-
).toBe("pieces_paid_pair");
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it("refuses two pieces holding one checkout session", async () => {
|
|
195
|
-
const approvedPriced = {
|
|
196
|
-
kind: "proposal",
|
|
197
|
-
price_amount: 5000,
|
|
198
|
-
price_currency: "usd",
|
|
199
|
-
approved_at: new Date(),
|
|
200
|
-
...SESSION,
|
|
201
|
-
checkout_session_id: "cs_test_dup",
|
|
202
|
-
};
|
|
203
|
-
expect(await violation(() => insertPiece(approvedPriced))).toBeNull();
|
|
204
|
-
expect(await violation(() => insertPiece(approvedPriced))).toBe(
|
|
205
|
-
"pieces_checkout_session_id_key",
|
|
206
|
-
);
|
|
207
|
-
});
|
|
208
|
-
});
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file prefixed-ids.db.test.ts
|
|
3
|
-
*
|
|
4
|
-
* LIVE-DATABASE proof of the ADR-0031 mechanical tier. Requires DATABASE_URL
|
|
5
|
-
* pointing at a Postgres with the migrations applied (`prisma migrate deploy`)
|
|
6
|
-
* — the whole suite SKIPS when DATABASE_URL is unset, keeping the workspace
|
|
7
|
-
* Jest run DB-free (the repo convention; the `apps/api Route Tests (Postgres)`
|
|
8
|
-
* workflow and local runs with a real DB exercise it).
|
|
9
|
-
*
|
|
10
|
-
* Uses the `pg` driver directly (raw SQL): the generated Prisma client is
|
|
11
|
-
* ESM-only (`import.meta`) and cannot load under this package's CJS ts-jest
|
|
12
|
-
* transform — and raw SQL is the sharper proof anyway, since the CHECK
|
|
13
|
-
* constraints must hold on the path no application helper can guard.
|
|
14
|
-
* (Client-level coverage — plain + nested `create` and Better Auth inserts
|
|
15
|
-
* landing DB-minted prefixed ids — was verified live against the migrated
|
|
16
|
-
* schema; see PR #3671's verification log.)
|
|
17
|
-
*
|
|
18
|
-
* What it proves — the ADR-0031 Tier-2 success criteria:
|
|
19
|
-
* 1. uuidv7() property tests: version nibble 7, RFC-4122 variant,
|
|
20
|
-
* non-decreasing across a millisecond boundary. A failure here is a
|
|
21
|
-
* staging bug to surface to Sam, NOT a signal to rewrite the SQL.
|
|
22
|
-
* 2. An insert with NO caller-supplied id lands a correctly-prefixed id via
|
|
23
|
-
* the DATABASE default.
|
|
24
|
-
* 3. An insert with a malformed id is REJECTED by the CHECK constraint.
|
|
25
|
-
* 4. The relation-free scope columns (workspaceId refs) are CHECKed too.
|
|
26
|
-
* 5. The reserved-range sentinel ids are admitted by the CHECKs.
|
|
27
|
-
*/
|
|
28
|
-
import { readdirSync, readFileSync } from "node:fs";
|
|
29
|
-
import { join } from "node:path";
|
|
30
|
-
|
|
31
|
-
import { Client } from "pg";
|
|
32
|
-
|
|
33
|
-
import { DEFAULT_ORG_ID, DEFAULT_WORKSPACE_ID } from "../tenancy.js";
|
|
34
|
-
|
|
35
|
-
const describeDb = process.env.DATABASE_URL ? describe : describe.skip;
|
|
36
|
-
|
|
37
|
-
const V7_RE =
|
|
38
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Every distinct `_format` CHECK constraint name declared across
|
|
42
|
-
* `database/migrations/*\/migration.sql` — both the inline `CREATE TABLE`
|
|
43
|
-
* form and the `ALTER TABLE ... ADD CONSTRAINT` form (including the
|
|
44
|
-
* existence-guarded `DO $$` blocks later migrations use for a NULLABLE
|
|
45
|
-
* scope column, e.g. 20260919120000_flow_workspace_key). Comment lines are
|
|
46
|
-
* skipped so a rollback note that merely mentions a constraint name doesn't
|
|
47
|
-
* count as a second declaration.
|
|
48
|
-
*
|
|
49
|
-
* Derived from the migration source rather than hard-coded (#6119): a
|
|
50
|
-
* hard-coded literal here goes stale the moment a later migration adds a
|
|
51
|
-
* new prefixed-id model or scope column, failing this test for a reason
|
|
52
|
-
* that has nothing to do with the database under test. Deriving it instead
|
|
53
|
-
* still catches the real defect this test guards — the live database
|
|
54
|
-
* missing a CHECK its own migrations declare (a partial/failed deploy,
|
|
55
|
-
* migrations applied out of order, one silently dropped) — because the
|
|
56
|
-
* expected count comes from the repo's migration files while the actual
|
|
57
|
-
* count comes from a live query against the database those migrations were
|
|
58
|
-
* run against; the two are independent unless the migrations actually ran
|
|
59
|
-
* to completion.
|
|
60
|
-
*/
|
|
61
|
-
function declaredFormatCheckCount(): number {
|
|
62
|
-
const migrationsDir = join(__dirname, "..", "migrations");
|
|
63
|
-
const names = new Set<string>();
|
|
64
|
-
for (const entry of readdirSync(migrationsDir, { withFileTypes: true })) {
|
|
65
|
-
if (!entry.isDirectory()) continue;
|
|
66
|
-
const sqlPath = join(migrationsDir, entry.name, "migration.sql");
|
|
67
|
-
let sql: string;
|
|
68
|
-
try {
|
|
69
|
-
sql = readFileSync(sqlPath, "utf-8");
|
|
70
|
-
} catch {
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
for (const line of sql.split("\n")) {
|
|
74
|
-
if (line.trim().startsWith("--")) continue;
|
|
75
|
-
const match = line.match(/CONSTRAINT\s+"([a-z_]+_format)"/);
|
|
76
|
-
if (match) names.add(match[1]);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return names.size;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
describeDb("prefixed UUIDv7 ids (ADR-0031, live DB)", () => {
|
|
83
|
-
let db: Client;
|
|
84
|
-
// #6254 (the tenancy-fence keystone) retrofitted `leads.workspace_id` to
|
|
85
|
-
// NOT NULL plus `leads_workspace_site_agree CHECK (workspace_id =
|
|
86
|
-
// site_id)` and `leads_workspace_id_format CHECK (workspace_id ~
|
|
87
|
-
// '^wksp_...')`. Every "leads" insert below now needs a well-formed
|
|
88
|
-
// `wksp_` id in BOTH columns — a real seeded workspace (mirroring
|
|
89
|
-
// `composite-fence.db.test.ts`'s own fixture pattern), not the prior
|
|
90
|
-
// free-text `'adr31-test'` literal, which satisfied neither CHECK.
|
|
91
|
-
let workspaceId: string;
|
|
92
|
-
|
|
93
|
-
beforeAll(async () => {
|
|
94
|
-
db = new Client({ connectionString: process.env.DATABASE_URL });
|
|
95
|
-
await db.connect();
|
|
96
|
-
|
|
97
|
-
const org = (
|
|
98
|
-
await db.query<{ id: string }>(
|
|
99
|
-
`INSERT INTO "organizations" ("name", "slug", "updated_at")
|
|
100
|
-
VALUES ('ADR31 Fence Org', 'adr31-fence-org', now()) RETURNING "id"`,
|
|
101
|
-
)
|
|
102
|
-
).rows[0]!;
|
|
103
|
-
workspaceId = (
|
|
104
|
-
await db.query<{ id: string }>(
|
|
105
|
-
`INSERT INTO "workspaces" ("organization_id", "name", "slug", "updated_at")
|
|
106
|
-
VALUES ($1, 'ADR31 Fence Workspace', 'adr31-fence-ws', now()) RETURNING "id"`,
|
|
107
|
-
[org.id],
|
|
108
|
-
)
|
|
109
|
-
).rows[0]!.id;
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
afterAll(async () => {
|
|
113
|
-
await db.query(`DELETE FROM "leads" WHERE "workspace_id" = $1`, [
|
|
114
|
-
workspaceId,
|
|
115
|
-
]);
|
|
116
|
-
await db.query(
|
|
117
|
-
`DELETE FROM "organizations" WHERE "slug" LIKE 'adr31-%'`,
|
|
118
|
-
);
|
|
119
|
-
await db.end();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe("uuidv7() SQL function properties", () => {
|
|
123
|
-
it("version nibble is 7 and variant is RFC-4122 across 200 samples", async () => {
|
|
124
|
-
const { rows } = await db.query<{ id: string }>(
|
|
125
|
-
"SELECT uuidv7()::text AS id FROM generate_series(1, 200)",
|
|
126
|
-
);
|
|
127
|
-
expect(rows).toHaveLength(200);
|
|
128
|
-
for (const { id } of rows) {
|
|
129
|
-
expect(id).toMatch(V7_RE);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it("is non-decreasing across a millisecond boundary", async () => {
|
|
134
|
-
const first = (await db.query<{ id: string }>(
|
|
135
|
-
"SELECT uuidv7()::text AS id",
|
|
136
|
-
)).rows[0].id;
|
|
137
|
-
await new Promise((r) => setTimeout(r, 5));
|
|
138
|
-
const second = (await db.query<{ id: string }>(
|
|
139
|
-
"SELECT uuidv7()::text AS id",
|
|
140
|
-
)).rows[0].id;
|
|
141
|
-
expect(second >= first).toBe(true);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
describe("DB-generated prefixed defaults", () => {
|
|
146
|
-
it("an insert with NO id lands a prefixed id via the database default", async () => {
|
|
147
|
-
const org = (await db.query<{ id: string }>(
|
|
148
|
-
`INSERT INTO "organizations" ("name", "slug", "updated_at")
|
|
149
|
-
VALUES ('ADR31 Org', 'adr31-org', now()) RETURNING "id"`,
|
|
150
|
-
)).rows[0];
|
|
151
|
-
expect(org.id).toMatch(/^org_/);
|
|
152
|
-
expect(org.id.slice("org_".length)).toMatch(V7_RE);
|
|
153
|
-
|
|
154
|
-
const lead = (await db.query<{ id: string }>(
|
|
155
|
-
`INSERT INTO "leads" ("site_id", "workspace_id", "source", "email", "payload")
|
|
156
|
-
VALUES ($1, $1, 'test', 'adr31@example.com', '{}') RETURNING "id"`,
|
|
157
|
-
[workspaceId],
|
|
158
|
-
)).rows[0];
|
|
159
|
-
expect(lead.id).toMatch(/^lead_/);
|
|
160
|
-
expect(lead.id.slice("lead_".length)).toMatch(V7_RE);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
describe("CHECK constraints — the mechanical tier", () => {
|
|
165
|
-
it("REJECTS an insert with a malformed primary key", async () => {
|
|
166
|
-
// workspace_id (= site_id) is supplied and well-formed here so the
|
|
167
|
-
// ONLY constraint this insert can violate is leads_id_format — proving
|
|
168
|
-
// the malformed-id rejection still fires for its original reason,
|
|
169
|
-
// not the (now also NOT NULL) workspace_id (#6373 AC-3).
|
|
170
|
-
await expect(
|
|
171
|
-
db.query(
|
|
172
|
-
`INSERT INTO "leads" ("id", "site_id", "workspace_id", "source", "email", "payload")
|
|
173
|
-
VALUES ('bad', $1, $1, 'x', 'a@b.co', '{}')`,
|
|
174
|
-
[workspaceId],
|
|
175
|
-
),
|
|
176
|
-
).rejects.toThrow(/leads_id_format/);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it("REJECTS an insert with a bare (unprefixed) uuid primary key", async () => {
|
|
180
|
-
await expect(
|
|
181
|
-
db.query(
|
|
182
|
-
`INSERT INTO "leads" ("id", "site_id", "workspace_id", "source", "email", "payload")
|
|
183
|
-
VALUES ('0190f3a2-7c1d-7e4a-9b2c-0123456789ab', $1, $1, 'x', 'a@b.co', '{}')`,
|
|
184
|
-
[workspaceId],
|
|
185
|
-
),
|
|
186
|
-
).rejects.toThrow(/leads_id_format/);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it("REJECTS a malformed relation-free scope ref (workspaceId with no FK)", async () => {
|
|
190
|
-
await expect(
|
|
191
|
-
db.query(
|
|
192
|
-
`INSERT INTO "workspace_themes" ("workspace_id", "data", "updated_at")
|
|
193
|
-
VALUES ('not-a-workspace-id', '{}', now())`,
|
|
194
|
-
),
|
|
195
|
-
).rejects.toThrow(/workspace_themes_workspace_id_format/);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("ADMITS the reserved-range sentinel ids (seed path stays valid)", async () => {
|
|
199
|
-
const org = (await db.query<{ id: string }>(
|
|
200
|
-
`INSERT INTO "organizations" ("id", "name", "slug", "updated_at")
|
|
201
|
-
VALUES ($1, 'ADR31 Sentinel', 'adr31-sentinel', now()) RETURNING "id"`,
|
|
202
|
-
[DEFAULT_ORG_ID],
|
|
203
|
-
)).rows[0];
|
|
204
|
-
expect(org.id).toBe(DEFAULT_ORG_ID);
|
|
205
|
-
|
|
206
|
-
const ws = (await db.query<{ id: string }>(
|
|
207
|
-
`INSERT INTO "workspaces" ("id", "organization_id", "name", "slug", "updated_at")
|
|
208
|
-
VALUES ($1, $2, 'Sentinel WS', 'sentinel', now()) RETURNING "id"`,
|
|
209
|
-
[DEFAULT_WORKSPACE_ID, DEFAULT_ORG_ID],
|
|
210
|
-
)).rows[0];
|
|
211
|
-
expect(ws.id).toBe(DEFAULT_WORKSPACE_ID);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it("carries the full CHECK complement declared by the migrations", async () => {
|
|
215
|
-
const { rows } = await db.query<{ n: string }>(
|
|
216
|
-
`SELECT count(*)::text AS n FROM pg_constraint
|
|
217
|
-
WHERE contype = 'c' AND conname LIKE '%_format'`,
|
|
218
|
-
);
|
|
219
|
-
expect(rows[0].n).toBe(String(declaredFormatCheckCount()));
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
});
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file project-listing-consent-at.db.test.ts
|
|
3
|
-
*
|
|
4
|
-
* LIVE-DATABASE proof that `ProjectListing.consentAt` round-trips through
|
|
5
|
-
* the real Prisma Client with timezone information preserved (#6171).
|
|
6
|
-
* Requires DATABASE_URL pointing at a Postgres with the migrations applied
|
|
7
|
-
* (`prisma migrate deploy`) — the whole suite SKIPS when DATABASE_URL is
|
|
8
|
-
* unset, keeping the workspace Jest run DB-free (the repo convention; see
|
|
9
|
-
* `prefixed-ids.db.test.ts` / `appointment.db.test.ts`).
|
|
10
|
-
*
|
|
11
|
-
* The bug this guards: `database/inbox/schema.prisma`'s `consentAt` field
|
|
12
|
-
* declared `DateTime @default(now()) @map("consent_at")` with no native-type
|
|
13
|
-
* annotation, so Prisma treated it as `TIMESTAMP(3)` (no time zone) by
|
|
14
|
-
* default, while its migration
|
|
15
|
-
* (`20260909180000_listing_draft_and_fields/migration.sql`) created the
|
|
16
|
-
* actual column as `TIMESTAMPTZ` — deliberately, since it records a legal
|
|
17
|
-
* consent timestamp. The fix adds `@db.Timestamptz(3)` so the schema's
|
|
18
|
-
* declared type agrees with what the column actually is.
|
|
19
|
-
*
|
|
20
|
-
* Spawns `project-listing-consent-probe.ts` via `tsx` (a real ESM process)
|
|
21
|
-
* rather than importing the generated client directly, for the same reason
|
|
22
|
-
* `appointment.db.test.ts` does: the generated client is ESM-only
|
|
23
|
-
* (`import.meta.url`) and cannot load under this package's CJS `ts-jest`
|
|
24
|
-
* transform.
|
|
25
|
-
*/
|
|
26
|
-
import { spawnSync } from "node:child_process";
|
|
27
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
28
|
-
import { join } from "node:path";
|
|
29
|
-
|
|
30
|
-
const describeDb = process.env.DATABASE_URL ? describe : describe.skip;
|
|
31
|
-
|
|
32
|
-
const DATABASE_DIR = join(__dirname, "..");
|
|
33
|
-
const PROBE_SCRIPT = join(
|
|
34
|
-
__dirname,
|
|
35
|
-
"fixtures",
|
|
36
|
-
"project-listing-consent-probe.ts",
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
// Runs with no DATABASE_URL required — a deterministic guard so the schema
|
|
40
|
-
// declaration can't silently regress even in a DB-free run (the live-DB
|
|
41
|
-
// round trip below still runs whenever DATABASE_URL is set).
|
|
42
|
-
describe("ProjectListing.consentAt — schema declares the real column type (#6171)", () => {
|
|
43
|
-
it("carries @db.Timestamptz(3), matching the TIMESTAMPTZ column created by 20260909180000_listing_draft_and_fields", () => {
|
|
44
|
-
const schema = readFileSync(
|
|
45
|
-
join(DATABASE_DIR, "inbox", "schema.prisma"),
|
|
46
|
-
"utf-8",
|
|
47
|
-
);
|
|
48
|
-
const fieldLine = schema
|
|
49
|
-
.split("\n")
|
|
50
|
-
.find((line) => /^\s*consentAt\s+DateTime\b/.test(line));
|
|
51
|
-
expect(fieldLine).toBeDefined();
|
|
52
|
-
expect(fieldLine).toMatch(/@db\.Timestamptz\(3\)/);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
/** Walk up from DATABASE_DIR to find node_modules/.bin/tsx (worktree-safe —
|
|
57
|
-
* mirrors `appointment.db.test.ts`'s own resolution). */
|
|
58
|
-
function findTsxBin(): string {
|
|
59
|
-
let dir = DATABASE_DIR;
|
|
60
|
-
for (let i = 0; i < 5; i++) {
|
|
61
|
-
const candidate = join(dir, "node_modules", ".bin", "tsx");
|
|
62
|
-
if (existsSync(candidate)) return candidate;
|
|
63
|
-
dir = join(dir, "..");
|
|
64
|
-
}
|
|
65
|
-
throw new Error(`tsx binary not found searching up from ${DATABASE_DIR}.`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
describeDb(
|
|
69
|
-
"ProjectListing.consentAt — live DB round trip via prisma.projectListing (#6171)",
|
|
70
|
-
() => {
|
|
71
|
-
it("preserves the exact instant through create() + a fresh findUniqueOrThrow(), regardless of session timezone", () => {
|
|
72
|
-
const tsxBin = findTsxBin();
|
|
73
|
-
const result = spawnSync(tsxBin, [PROBE_SCRIPT], {
|
|
74
|
-
cwd: DATABASE_DIR,
|
|
75
|
-
encoding: "utf-8",
|
|
76
|
-
env: process.env,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// Exit status + a successful stdout parse is the full signal (see
|
|
80
|
-
// appointment.db.test.ts for why this, rather than empty stderr, is
|
|
81
|
-
// the right assertion — a stray Node/tsx diagnostic must not fail an
|
|
82
|
-
// otherwise-successful run).
|
|
83
|
-
if (result.status !== 0) {
|
|
84
|
-
throw new Error(
|
|
85
|
-
`probe exited ${result.status}: ${result.stderr || "(no stderr)"}`,
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const probe = JSON.parse(result.stdout) as {
|
|
90
|
-
writtenIso: string;
|
|
91
|
-
createdConsentAtIso: string;
|
|
92
|
-
rereadConsentAtIso: string;
|
|
93
|
-
liveColumnDataType: string | null;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// The instant `create()` returns must be exactly what was written —
|
|
97
|
-
// not shifted by the pinned Asia/Kolkata (+05:30) session timezone.
|
|
98
|
-
expect(probe.createdConsentAtIso).toBe(probe.writtenIso);
|
|
99
|
-
|
|
100
|
-
// A SECOND, independent read (a fresh findUniqueOrThrow, not the
|
|
101
|
-
// object create() already returned) must agree too — the read path,
|
|
102
|
-
// not just the write path, preserves the instant.
|
|
103
|
-
expect(probe.rereadConsentAtIso).toBe(probe.writtenIso);
|
|
104
|
-
|
|
105
|
-
// Ground truth: the live column really is timezone-aware, which is
|
|
106
|
-
// what makes the schema's `@db.Timestamptz(3)` annotation correct
|
|
107
|
-
// rather than merely quiet.
|
|
108
|
-
expect(probe.liveColumnDataType).toBe("timestamp with time zone");
|
|
109
|
-
});
|
|
110
|
-
},
|
|
111
|
-
);
|