create-ailk 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -22
- package/component-catalog.json +3 -3
- package/component-catalog.md +3 -3
- package/dist/add-module.js +4 -2
- package/dist/add-route.d.ts +12 -1
- package/dist/add-route.js +31 -3
- package/dist/cli.js +12 -7
- package/dist/derive-architecture.d.ts +3 -4
- package/dist/derive-architecture.js +65 -29
- 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 +2 -1
- package/dist/lib/fetch-template-snapshot.js +8 -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 +36 -15
- package/dist/lib/module-tier.d.ts +2 -8
- package/dist/lib/module-tier.js +13 -12
- package/dist/module-architecture.d.ts +20 -3
- package/dist/module-architecture.js +129 -552
- package/dist/paid-sections.d.ts +25 -1
- package/dist/paid-sections.js +88 -3
- package/dist/starter-grid.d.ts +6 -6
- package/dist/starter-grid.js +12 -5
- package/dist/surfaces.js +39 -2
- package/dist/template-record.d.ts +21 -3
- package/dist/template-record.js +38 -7
- package/dist/topology.d.ts +16 -3
- package/dist/topology.js +54 -23
- package/dist/update.d.ts +10 -1
- package/dist/update.js +715 -21
- package/package.json +3 -3
- package/release-scope.json +2 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +8 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +2 -2
- package/site-templates/marketing-site/ailk-template.json +7 -1
- package/site-templates/marketing-site/provenance.json +7 -1
- package/site-templates/saas-product/ailk-template.json +2 -1
- package/site-templates/saas-product/provenance.json +1 -0
- 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 +20 -5
- package/templates/.github/workflows/ci.yml +7 -4
- package/templates/CLAUDE.md +11 -1
- package/templates/CONVENTIONS.md +8 -10
- package/templates/README.md +14 -13
- package/templates/apps/api/.env.example +23 -2
- package/templates/apps/api/CLAUDE.md +119 -83
- 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-client.js +16 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
- 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 -1882
- package/templates/apps/api/vercel.json +2 -2
- package/templates/apps/mcp/CLAUDE.md +90 -26
- 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 -13
- 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 +31 -3
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
- package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +43 -4
- package/templates/apps/web/app/[locale]/(auth)/legal-footnote.tsx +35 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +117 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +14 -37
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +6 -6
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +20 -35
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/page.test.tsx +108 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +111 -5
- package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +78 -16
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +132 -12
- package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +53 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/billing.test.tsx +38 -0
- package/templates/apps/web/app/[locale]/(authed)/account/billing/page.tsx +4 -2
- package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +47 -24
- package/templates/apps/web/app/[locale]/(authed)/signed-out-gate.generated.tsx +23 -4
- package/templates/apps/web/app/[locale]/contact/intake-analytics.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 +7 -3
- package/templates/apps/web/app/[locale]/layout.tsx +33 -13
- package/templates/apps/web/app/[locale]/meet/confirmed/BookingHandOff.tsx +128 -0
- package/templates/apps/web/app/[locale]/meet/confirmed/__tests__/BookingHandOff.test.tsx +126 -0
- 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 +10 -6
- package/templates/apps/web/i18n/request.ts +49 -1
- package/templates/apps/web/jest.config.cjs +1 -0
- package/templates/apps/web/lib/__tests__/account-config.test.ts +7 -0
- package/templates/apps/web/lib/__tests__/auth-email.test.ts +276 -0
- package/templates/apps/web/lib/auth-email.ts +103 -21
- package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +72 -23
- package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +94 -70
- package/templates/apps/web/lib/prisma-for-auth.ts +5 -2
- 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/lib/sign-up-agreements.ts +291 -28
- package/templates/apps/web/lib/site-contributions.ts +18 -0
- package/templates/apps/web/messages/en.json +186 -20
- package/templates/apps/web/messages/site/en.json +1 -0
- 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 +5 -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 +553 -7
- package/templates/tsconfig.json +1 -2
- package/versions.json +49 -36
- 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 -308
- 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 -257
- 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 -321
- 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 -391
- 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 -2148
- 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 -332
- 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 -1426
- 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 -183
- package/templates/apps/api/src/routes/content/index.ts +0 -49
- package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
- 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 -100
- package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
- 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 -639
- 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 -491
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
- 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 -449
- 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 -809
- 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 -2028
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
- 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 -877
- 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 -1204
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
- package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
- package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
- 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 -336
- 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 -750
- 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 -348
- 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 -975
- 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 -400
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
- package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
- package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
- 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 -1211
- 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 -2085
- 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 -1232
- 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 -70
- package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
- 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 -180
- package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
- package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
- package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
- 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__/rate-limit-write.test.ts +0 -189
- package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
- package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
- package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
- 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 -222
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
- 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 -349
- 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 -564
- 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 -116
- package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
- 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/site-config.ts +0 -53
- 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 -66
- 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 -138
- package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
- 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 -81
- package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
- package/templates/apps/mcp/src/tools/search_content.ts +0 -63
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
- package/templates/apps/mcp/src/workspace-server.ts +0 -224
- package/templates/database/CHANGELOG.md +0 -981
- 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 -272
- package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
- package/templates/database/__tests__/tenancy.test.ts +0 -141
- package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
- 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/20261025120000_trial_magnet/migration.sql +0 -28
- package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
- 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,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The rate limiter's database store (#5040 D1/D3/D4). Counts a bucket in
|
|
3
|
-
* `rate_limit_counters` so one visitor's limit holds across every concurrent
|
|
4
|
-
* isolate on a deployment with a database — see
|
|
5
|
-
* `apps/api/src/middleware/rate-limit.ts`'s `SHARED STORE` header for the
|
|
6
|
-
* full picture (what this protects against, and what it does not).
|
|
7
|
-
*
|
|
8
|
-
* The only file naming `rate_limit_counters` outside `database/`. All SQL is
|
|
9
|
-
* `db.$queryRaw` / `db.$executeRaw` tagged templates — never `…Unsafe` — so
|
|
10
|
-
* every value is a bound parameter, never string-interpolated.
|
|
11
|
-
*/
|
|
12
|
-
import { createHash } from "node:crypto";
|
|
13
|
-
|
|
14
|
-
import type { Prisma } from "@working-theory/database";
|
|
15
|
-
|
|
16
|
-
/** One bucket's state, as both the memory and database stores report it. */
|
|
17
|
-
export type RateLimitBucket = {
|
|
18
|
-
count: number;
|
|
19
|
-
windowStartMs: number;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/** What a store call reports when it ran against a backing database. */
|
|
23
|
-
export type RateLimitStore = {
|
|
24
|
-
/** Count one request against `key`'s visitor bucket. */
|
|
25
|
-
hit(key: string, now: number, windowMs: number): Promise<RateLimitBucket>;
|
|
26
|
-
/** Count one request against `key`'s forwarding-key bucket (#7394 DD-8). */
|
|
27
|
-
hitKey(key: string, now: number, windowMs: number): Promise<RateLimitBucket>;
|
|
28
|
-
/** True when `key` has a bucket whose window has not yet ended. */
|
|
29
|
-
hasOpenWindow(key: string, now: number, windowMs: number): Promise<boolean>;
|
|
30
|
-
/** Evict expired buckets. `reason` is why the sweep fired (D6). */
|
|
31
|
-
sweep(now: number, windowMs: number, reason: "interval" | "limited"): Promise<void>;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/** What `createDatabaseRateLimitStore` needs of a Prisma client (D3). */
|
|
35
|
-
export type RateLimitSqlClient = Pick<
|
|
36
|
-
Prisma.TransactionClient,
|
|
37
|
-
"$queryRaw" | "$executeRaw"
|
|
38
|
-
>;
|
|
39
|
-
|
|
40
|
-
function sha256Hex(value: string): string {
|
|
41
|
-
return createHash("sha256").update(value).digest("hex");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The database store (D1/D3): one atomic upsert per hit, same window rules as
|
|
46
|
-
* the memory store. `bucketKey` is the exact string the memory store uses as
|
|
47
|
-
* its Map key; this store hashes it before it ever reaches SQL (FR-5) — the
|
|
48
|
-
* table never holds a plaintext IP or bucket key.
|
|
49
|
-
*/
|
|
50
|
-
export function createDatabaseRateLimitStore(
|
|
51
|
-
db: RateLimitSqlClient,
|
|
52
|
-
): RateLimitStore {
|
|
53
|
-
async function countHit(
|
|
54
|
-
bucketKey: string,
|
|
55
|
-
now: number,
|
|
56
|
-
windowMs: number,
|
|
57
|
-
): Promise<RateLimitBucket> {
|
|
58
|
-
const hash = sha256Hex(bucketKey);
|
|
59
|
-
const rows = await db.$queryRaw<
|
|
60
|
-
Array<{ count: number; window_start_ms: bigint | string }>
|
|
61
|
-
>`
|
|
62
|
-
INSERT INTO "rate_limit_counters" ("key_hash", "window_start_ms", "window_ms", "count")
|
|
63
|
-
VALUES (${hash}, ${now}::bigint, ${windowMs}::integer, 1)
|
|
64
|
-
ON CONFLICT ("key_hash") DO UPDATE SET
|
|
65
|
-
"count" = CASE WHEN ${now}::bigint - "rate_limit_counters"."window_start_ms" >= ${windowMs}::integer
|
|
66
|
-
THEN 1 ELSE "rate_limit_counters"."count" + 1 END,
|
|
67
|
-
"window_start_ms" = CASE WHEN ${now}::bigint - "rate_limit_counters"."window_start_ms" >= ${windowMs}::integer
|
|
68
|
-
THEN ${now}::bigint ELSE "rate_limit_counters"."window_start_ms" END,
|
|
69
|
-
"window_ms" = ${windowMs}::integer
|
|
70
|
-
RETURNING "count", "window_start_ms"
|
|
71
|
-
`;
|
|
72
|
-
const row = rows[0];
|
|
73
|
-
if (!row) {
|
|
74
|
-
throw new Error("rate_limit_counters upsert returned no row");
|
|
75
|
-
}
|
|
76
|
-
return {
|
|
77
|
-
count: Number(row.count),
|
|
78
|
-
windowStartMs: Number(row.window_start_ms),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function hasOpenWindow(
|
|
83
|
-
bucketKey: string,
|
|
84
|
-
now: number,
|
|
85
|
-
windowMs: number,
|
|
86
|
-
): Promise<boolean> {
|
|
87
|
-
const hash = sha256Hex(bucketKey);
|
|
88
|
-
const rows = await db.$queryRaw<Array<{ one: number }>>`
|
|
89
|
-
SELECT 1 AS "one" FROM "rate_limit_counters"
|
|
90
|
-
WHERE "key_hash" = ${hash}
|
|
91
|
-
AND ${now}::bigint - "window_start_ms" < ${windowMs}::integer
|
|
92
|
-
LIMIT 1
|
|
93
|
-
`;
|
|
94
|
-
return rows.length > 0;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
hit: (key, now, windowMs) => countHit(key, now, windowMs),
|
|
99
|
-
hitKey: (key, now, windowMs) => countHit(key, now, windowMs),
|
|
100
|
-
hasOpenWindow,
|
|
101
|
-
async sweep(now, _windowMs, reason) {
|
|
102
|
-
// D6 — the database store sweeps on the interval trigger only. Sweeping
|
|
103
|
-
// on every 429 would let an attacker buy a table scan per refused
|
|
104
|
-
// request.
|
|
105
|
-
if (reason !== "interval") return;
|
|
106
|
-
await db.$executeRaw`
|
|
107
|
-
DELETE FROM "rate_limit_counters"
|
|
108
|
-
WHERE "window_start_ms" + "window_ms" <= ${now}::bigint
|
|
109
|
-
`;
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Which store a registration with no explicit `store` option uses (D4),
|
|
116
|
-
* resolved once per process and memoized by the middleware. `warn` is called
|
|
117
|
-
* exactly once for each of the two misconfiguration rows below.
|
|
118
|
-
*/
|
|
119
|
-
export type RateLimitStoreEnv = {
|
|
120
|
-
DATABASE_URL?: string | undefined;
|
|
121
|
-
AILK_RATE_LIMIT_STORE?: string | undefined;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
export function resolveRateLimitStoreKind(
|
|
125
|
-
env: RateLimitStoreEnv,
|
|
126
|
-
warn: (msg: string) => void,
|
|
127
|
-
): "memory" | "database" {
|
|
128
|
-
const hasDatabase = !!env.DATABASE_URL;
|
|
129
|
-
const raw = env.AILK_RATE_LIMIT_STORE;
|
|
130
|
-
|
|
131
|
-
if (raw === undefined || raw === "") {
|
|
132
|
-
return hasDatabase ? "database" : "memory";
|
|
133
|
-
}
|
|
134
|
-
if (raw === "memory") return "memory";
|
|
135
|
-
if (raw === "database") {
|
|
136
|
-
if (hasDatabase) return "database";
|
|
137
|
-
warn("AILK_RATE_LIMIT_STORE=database needs DATABASE_URL; using memory");
|
|
138
|
-
return "memory";
|
|
139
|
-
}
|
|
140
|
-
warn("AILK_RATE_LIMIT_STORE is not memory or database and is ignored");
|
|
141
|
-
return hasDatabase ? "database" : "memory";
|
|
142
|
-
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Commerce license-claim guard for the commerce PRIMITIVES that live in the
|
|
3
|
-
* base tree (DECISION-LOG D-64, epic #5770, #5796).
|
|
4
|
-
*
|
|
5
|
-
* The checkout launcher, the Stripe webhook receiver, customer mapping and
|
|
6
|
-
* `lib/stripe.ts` ship unconditionally now — they are no longer registered
|
|
7
|
-
* behind `isModuleEnabled("commerce")`. What decides whether they SERVE is the
|
|
8
|
-
* JWT `features[]` claim `commerce`, read at CALL time through `checkLicense()`
|
|
9
|
-
* from `@working-theory/license`.
|
|
10
|
-
*
|
|
11
|
-
* This is the same shape as `./require-paid-tier.ts` — that file is the
|
|
12
|
-
* PATTERN, not the code (D-64): this gate reads
|
|
13
|
-
* `result.features.includes("commerce")` and never looks at `result.tier` as
|
|
14
|
-
* the claim test. A `commerce` claim can ride any paid level, so a tier test
|
|
15
|
-
* would be the wrong question.
|
|
16
|
-
*
|
|
17
|
-
* Response without the claim: the SAME module-disabled response the
|
|
18
|
-
* module-conditional path produced — a 404. `server.ts`'s root-endpoint
|
|
19
|
-
* comment (§ `deriveRootEndpoints`) documents that a build with commerce off
|
|
20
|
-
* simply does not advertise these routes and answers 404 on them, and
|
|
21
|
-
* `src/__tests__/module-exclusion.test.ts` measures exactly that status. The
|
|
22
|
-
* body is `notFoundError()` from `./errors.ts` — this repo's one reusable 404
|
|
23
|
-
* body — rather than a newly invented `module_disabled` code, which exists
|
|
24
|
-
* nowhere in the tree. The message deliberately does not mention commerce: a
|
|
25
|
-
* site without the claim is indistinguishable from a site built without the
|
|
26
|
-
* module, which is the point.
|
|
27
|
-
*
|
|
28
|
-
* ── TRI-STATE, not a boolean ────────────────────────────────────────────────
|
|
29
|
-
*
|
|
30
|
-
* Security review 2026-09-16, High; widened by the operator in round 2. A
|
|
31
|
-
* single `false` for "no claim" and "could not tell" is a data-loss bug on the
|
|
32
|
-
* webhook: a signed `checkout.session.completed` on a live commerce site whose
|
|
33
|
-
* licence read merely FAILED would be acked 200 and dropped, Stripe would
|
|
34
|
-
* record success and never retry, and the charge would never be mapped.
|
|
35
|
-
*
|
|
36
|
-
* So `resolveCommerceClaim()` answers `claimed | unclaimed | undetermined`:
|
|
37
|
-
*
|
|
38
|
-
* claimed — read successfully; `features[]` carries `commerce`.
|
|
39
|
-
* unclaimed — a positively-established "no": either a licence that reads
|
|
40
|
-
* successfully and simply lacks the claim, or a KEYLESS
|
|
41
|
-
* deployment that configures no licence at all.
|
|
42
|
-
* undetermined — the read established no "no". These states reach it:
|
|
43
|
-
* 1. `checkLicense()` threw.
|
|
44
|
-
* 2. `revoked === true` — a revoked licence is still a
|
|
45
|
-
* PAYING site inside its JWT window (ADR 0014).
|
|
46
|
-
* 3. a licence IS configured yet resolves free — the JWT
|
|
47
|
-
* expired, or no longer verifies.
|
|
48
|
-
* 4. (3) also absorbs a configured-but-unparseable key.
|
|
49
|
-
* 5. the licence STORAGE FILE could not be read — EACCES,
|
|
50
|
-
* EIO, EMFILE, a directory at its path (#5820).
|
|
51
|
-
*
|
|
52
|
-
* Why (3) needs the env read. `checkLicense()` returns the SAME `FREE_RESULT`
|
|
53
|
-
* for expired, invalid and keyless alike (`check-license.ts` — `expiresAt` is
|
|
54
|
-
* `null` and `revoked` is `false` in all three), so nothing on `LicenseResult`
|
|
55
|
-
* separates "this deployment's licence stopped verifying" from "this
|
|
56
|
-
* deployment never had one". The one signal that does is whether a licence is
|
|
57
|
-
* CONFIGURED at all, which is an env read this app already makes elsewhere
|
|
58
|
-
* (`services/enrichment-shim.ts`). No JWT is parsed here and no verification
|
|
59
|
-
* is re-implemented — presence is the entire test.
|
|
60
|
-
*
|
|
61
|
-
* ── The storage file, read for what it actually says (#5820) ────────────────
|
|
62
|
-
*
|
|
63
|
-
* A licence sourced from the refresh STORAGE FILE is covered on both axes.
|
|
64
|
-
* `readStoredJwtState()` — added to `@working-theory/license` for this gate —
|
|
65
|
-
* answers `absent | unreadable | present` where `readStoredJwt()` answered one
|
|
66
|
-
* `null` for the first two. Only `absent` (no file, or a file holding nothing
|
|
67
|
-
* but whitespace) is evidence that a deployment is unlicensed; a file that
|
|
68
|
-
* merely could not be READ is evidence of nothing, so it holds. An EXPIRED
|
|
69
|
-
* storage licence (`present`, resolving free) holds too.
|
|
70
|
-
*
|
|
71
|
-
* Before that distinction existed, a transient EACCES on a storage-licensed
|
|
72
|
-
* site read as keyless: a signed `checkout.session.completed` arriving in that
|
|
73
|
-
* window was acked 200, Stripe never redelivered it, and the charge was never
|
|
74
|
-
* mapped. `readStoredJwt()`'s own contract is untouched — `checkLicense()` and
|
|
75
|
-
* every other caller still see `null` for both states.
|
|
76
|
-
*
|
|
77
|
-
* ── Why the two routes answer differently ───────────────────────────────────
|
|
78
|
-
*
|
|
79
|
-
* The checkout launcher answers the module-disabled 404 on BOTH non-serving
|
|
80
|
-
* states: a checkout that cannot be started loses nothing, so there is no call
|
|
81
|
-
* to leak a "configured but unreadable" shape on it. The webhook receiver
|
|
82
|
-
* holds an `undetermined` event with a retryable 503 + `Retry-After`, because
|
|
83
|
-
* by the time it arrives the buyer's money has already moved.
|
|
84
|
-
*
|
|
85
|
-
* Usage as a Fastify preHandler (the checkout launcher):
|
|
86
|
-
*
|
|
87
|
-
* fastify.post("/path", { preHandler: requireCommerceClaim }, handler);
|
|
88
|
-
*
|
|
89
|
-
* The Stripe webhook receiver does NOT use the preHandler: D3 puts signature
|
|
90
|
-
* verification BEFORE the claim check, so it consults `resolveCommerceClaim()`
|
|
91
|
-
* from inside its handler. See `routes/webhooks/README.md` § Commerce claim.
|
|
92
|
-
*/
|
|
93
|
-
|
|
94
|
-
import {
|
|
95
|
-
checkLicense,
|
|
96
|
-
readStoredJwtState,
|
|
97
|
-
type ProFeature,
|
|
98
|
-
} from "@working-theory/license";
|
|
99
|
-
import type { FastifyReply, FastifyRequest } from "fastify";
|
|
100
|
-
|
|
101
|
-
import { notFoundError } from "./errors.js";
|
|
102
|
-
|
|
103
|
-
/** The claim the commerce primitives serve behind (`ProFeature`, verify-jwt.ts). */
|
|
104
|
-
export const COMMERCE_FEATURE: ProFeature = "commerce";
|
|
105
|
-
|
|
106
|
-
const MODULE_DISABLED_MESSAGE = "Not found";
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* What the licence read actually established. See the header for the four
|
|
110
|
-
* states that reach `undetermined`.
|
|
111
|
-
*/
|
|
112
|
-
export type CommerceClaimState = "claimed" | "unclaimed" | "undetermined";
|
|
113
|
-
|
|
114
|
-
/** The module-disabled response — a 404, the canonical `not_found` body. */
|
|
115
|
-
export function commerceDisabledResponse() {
|
|
116
|
-
return notFoundError(MODULE_DISABLED_MESSAGE);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* The retryable answer for `undetermined` on the webhook. A local error
|
|
121
|
-
* vocabulary (`{ error: "..." }`), matching what `routes/webhooks/stripe.ts`
|
|
122
|
-
* already emits for its own failure modes, rather than `errors.ts`'s closed
|
|
123
|
-
* `ErrorCode` set, which has no service-unavailable member and whose MCP twin
|
|
124
|
-
* would have to grow one too.
|
|
125
|
-
*
|
|
126
|
-
* `Retry-After` is in SECONDS and is read by Stripe: five minutes is long
|
|
127
|
-
* enough for a transient licence-read failure or a refresh round-trip to
|
|
128
|
-
* clear, and short enough that a queued `checkout.session.completed` is mapped
|
|
129
|
-
* well inside Stripe's three-day redelivery window.
|
|
130
|
-
*/
|
|
131
|
-
export const LICENSE_UNDETERMINED_STATUS = 503;
|
|
132
|
-
export const LICENSE_UNDETERMINED_BODY = { error: "license-undetermined" };
|
|
133
|
-
export const LICENSE_UNDETERMINED_RETRY_AFTER_SECONDS = 300;
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* What this deployment's licence CONFIGURATION says — three answers, not two.
|
|
137
|
-
*
|
|
138
|
-
* configured — an env key is set, or the storage file holds a token.
|
|
139
|
-
* absent — no env key, and the storage file is genuinely not there (or
|
|
140
|
-
* holds nothing but whitespace). The only state that is
|
|
141
|
-
* evidence of an unlicensed site.
|
|
142
|
-
* unreadable — no env key, and the storage file could not be read at all.
|
|
143
|
-
*
|
|
144
|
-
* Presence only — the token is never parsed, verified or logged. This is the
|
|
145
|
-
* one signal that separates an EXPIRED/unverifiable licence from a keyless
|
|
146
|
-
* site, because `checkLicense()` collapses both into the same free result.
|
|
147
|
-
*
|
|
148
|
-
* It asks the question the SAME WAY `check-license.ts#resolveToken` does —
|
|
149
|
-
* `AILK_LICENSE_KEY`, else the refresh storage file — because that is where
|
|
150
|
-
* `checkLicense()` itself just looked. An env-only test would miss a
|
|
151
|
-
* deployment licensed purely from storage, so an EXPIRED storage licence would
|
|
152
|
-
* read as keyless and its already-charged events would be dropped.
|
|
153
|
-
*
|
|
154
|
-
* `unreadable` is kept separate from `absent` rather than folded into
|
|
155
|
-
* `configured` so the caller can LOG why it is holding (#5820): "this site has
|
|
156
|
-
* no licence" and "this site's licence could not be read" are different
|
|
157
|
-
* operator problems, and only the first is a fact.
|
|
158
|
-
*/
|
|
159
|
-
type LicenseConfigurationState = "configured" | "absent" | "unreadable";
|
|
160
|
-
|
|
161
|
-
async function resolveLicenseConfiguration(): Promise<LicenseConfigurationState> {
|
|
162
|
-
const key = process.env["AILK_LICENSE_KEY"];
|
|
163
|
-
if (typeof key === "string" && key.length > 0) return "configured";
|
|
164
|
-
|
|
165
|
-
const stored = await readStoredJwtState();
|
|
166
|
-
if (stored.state === "present") return "configured";
|
|
167
|
-
if (stored.state === "absent") return "absent";
|
|
168
|
-
|
|
169
|
-
// `console.warn` rather than a request logger: `resolveCommerceClaim()` is
|
|
170
|
-
// called from the webhook handler with no logger threaded through, and the
|
|
171
|
-
// routes are out of scope for this change. The cause's `code` is the whole
|
|
172
|
-
// point of the line — EACCES and EISDIR are different operator fixes. The
|
|
173
|
-
// token is never in scope here, so nothing secret can reach the log.
|
|
174
|
-
const code =
|
|
175
|
-
(stored.cause as NodeJS.ErrnoException | undefined)?.code ?? "UNKNOWN";
|
|
176
|
-
console.warn(
|
|
177
|
-
"commerce-claim: licence storage file unreadable — holding rather than dropping",
|
|
178
|
-
{ outcome: "license_storage_unreadable", code },
|
|
179
|
-
);
|
|
180
|
-
return "unreadable";
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Resolve what this deployment's licence says about `commerce`.
|
|
185
|
-
*
|
|
186
|
-
* Never throws: a failed read is a state, not an exception, because both
|
|
187
|
-
* callers must be able to tell "no" from "could not tell".
|
|
188
|
-
*/
|
|
189
|
-
export async function resolveCommerceClaim(): Promise<CommerceClaimState> {
|
|
190
|
-
let result;
|
|
191
|
-
try {
|
|
192
|
-
result = await checkLicense();
|
|
193
|
-
} catch {
|
|
194
|
-
// The read FAILED. Not a "no" — callers hold rather than drop.
|
|
195
|
-
return "undetermined";
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// A revoked licence keeps verifying locally until JWT `exp` (ADR 0014), so
|
|
199
|
-
// this is a PAYING commerce site mid-window whose events are still real.
|
|
200
|
-
// Closing the gate is right; DROPPING them is the security review's High
|
|
201
|
-
// under a different label.
|
|
202
|
-
if (result.revoked === true) return "undetermined";
|
|
203
|
-
|
|
204
|
-
if (result.features.includes(COMMERCE_FEATURE)) return "claimed";
|
|
205
|
-
|
|
206
|
-
if (result.tier === "free") {
|
|
207
|
-
const configuration = await resolveLicenseConfiguration();
|
|
208
|
-
// A licence is configured yet resolved free: expired, or no longer
|
|
209
|
-
// verifying. `checkLicense()` cannot say which, and neither is a "no".
|
|
210
|
-
if (configuration === "configured") return "undetermined";
|
|
211
|
-
// The storage file could not be read (#5820). An unreadable file is not
|
|
212
|
-
// evidence of a keyless site, and dropping a signed Stripe event needs
|
|
213
|
-
// evidence — so this holds and Stripe retries.
|
|
214
|
-
if (configuration === "unreadable") return "undetermined";
|
|
215
|
-
// `absent` — no env key and no storage file. A positively-established
|
|
216
|
-
// "no", and the only state on this path that may drop an event.
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return "unclaimed";
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Fastify preHandler for the checkout launcher: serve only with the claim.
|
|
224
|
-
*
|
|
225
|
-
* Both non-serving states answer the module-disabled 404 — see the header:
|
|
226
|
-
* an unstartable checkout loses nothing, so the route stays indistinguishable
|
|
227
|
-
* from a build without the module rather than advertising that a licence
|
|
228
|
-
* exists but could not be read. The `undetermined` case is still logged, so
|
|
229
|
-
* an operator can tell a lapsed licence from a deliberate free build.
|
|
230
|
-
*
|
|
231
|
-
* Returns void (proceed) with the claim and short-circuits with `reply.send`
|
|
232
|
-
* otherwise, matching Fastify's preHandler contract.
|
|
233
|
-
*/
|
|
234
|
-
export async function requireCommerceClaim(
|
|
235
|
-
request: FastifyRequest,
|
|
236
|
-
reply: FastifyReply,
|
|
237
|
-
): Promise<void> {
|
|
238
|
-
const state = await resolveCommerceClaim();
|
|
239
|
-
if (state === "claimed") return;
|
|
240
|
-
|
|
241
|
-
if (state === "undetermined") {
|
|
242
|
-
request.log.warn(
|
|
243
|
-
{ outcome: "license_undetermined" },
|
|
244
|
-
"commerce licence could not be read — checkout answering the module-disabled response",
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const err = commerceDisabledResponse();
|
|
249
|
-
return reply.status(err.status).send(err.body);
|
|
250
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Paid-tier license guard for apps/api content-write routes (D14a Stage 0).
|
|
3
|
-
*
|
|
4
|
-
* Calls `checkLicense()` from @working-theory/license; on free tier emits a 402 with the
|
|
5
|
-
* canonical `payment_required` shape from `./errors.ts`. Paid tier proceeds.
|
|
6
|
-
* Network/refresh failures inside checkLicense() degrade gracefully to free
|
|
7
|
-
* (per ADR 0014 — local-verify, no remote-validate path).
|
|
8
|
-
*
|
|
9
|
-
* Usage as Fastify preHandler:
|
|
10
|
-
*
|
|
11
|
-
* fastify.post("/path", { preHandler: requirePaidTier }, handler);
|
|
12
|
-
*
|
|
13
|
-
* Or composed with other preHandlers:
|
|
14
|
-
*
|
|
15
|
-
* fastify.post("/path", {
|
|
16
|
-
* preHandler: [requirePaidTier, ...others],
|
|
17
|
-
* }, handler);
|
|
18
|
-
*
|
|
19
|
-
* The handler returns nothing (void) on pro and short-circuits with reply.send
|
|
20
|
-
* on free, matching Fastify's preHandler contract.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import { checkLicense } from "@working-theory/license";
|
|
24
|
-
import type { FastifyReply, FastifyRequest } from "fastify";
|
|
25
|
-
|
|
26
|
-
import { paymentRequiredError } from "./errors.js";
|
|
27
|
-
|
|
28
|
-
const FREE_TIER_MESSAGE =
|
|
29
|
-
"This endpoint requires a paid license. Visit https://ailaunchkit.ai to upgrade.";
|
|
30
|
-
|
|
31
|
-
export async function requirePaidTier(
|
|
32
|
-
_request: FastifyRequest,
|
|
33
|
-
reply: FastifyReply,
|
|
34
|
-
): Promise<void> {
|
|
35
|
-
let result;
|
|
36
|
-
try {
|
|
37
|
-
result = await checkLicense();
|
|
38
|
-
} catch {
|
|
39
|
-
// Per ADR 0014 — license verification is local; an exception here means a
|
|
40
|
-
// bug, not a network failure. Treat as free for safe-by-default gating.
|
|
41
|
-
const err = paymentRequiredError(FREE_TIER_MESSAGE);
|
|
42
|
-
return reply.status(err.status).send(err.body);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Revoked paid licenses keep verifying until JWT exp (up to 24h after the
|
|
46
|
-
// server reports `revoked`). Closing the gate when `revoked === true`
|
|
47
|
-
// shrinks that window to "next request" without waiting for exp. See
|
|
48
|
-
// packages/license/src/types.ts § LicenseResult and ADR 0014.
|
|
49
|
-
if (result.revoked === true || result.tier === "free") {
|
|
50
|
-
const err = paymentRequiredError(FREE_TIER_MESSAGE);
|
|
51
|
-
return reply.status(err.status).send(err.body);
|
|
52
|
-
}
|
|
53
|
-
}
|