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,416 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default-tenant resolution — the BASE-build half of the tenant guard (#5677).
|
|
3
|
-
*
|
|
4
|
-
* A single-tenant site is a ONE-WORKSPACE TENANT, not a special case. The
|
|
5
|
-
* default Organization / Workspace / operator Membership are already declared
|
|
6
|
-
* as fixed reserved-range sentinels in `database/tenancy.ts` and already
|
|
7
|
-
* seeded by `database/seed.ts`, so there is nothing to synthesize here — this
|
|
8
|
-
* file resolves the seeded default and nothing else.
|
|
9
|
-
*
|
|
10
|
-
* WHY IT LIVES IN THE BASE BUILD. `services/tenant-context.ts` and
|
|
11
|
-
* `middleware/tenant.ts` are multi-tenant SLICE files (`// oss: false`), so on
|
|
12
|
-
* a build without that module they are not present and the routes behind them
|
|
13
|
-
* were never REGISTERED — not denied (#5677). The default
|
|
14
|
-
* resolution and the `TenantContext` shape it yields are needed on every
|
|
15
|
-
* build, so they live here, in a file that always ships; the multi-tenant
|
|
16
|
-
* slice imports this one rather than carrying its own copy, which is what
|
|
17
|
-
* keeps the two paths from drifting.
|
|
18
|
-
*
|
|
19
|
-
* PRECEDENCE, NOT PARALLELISM. When the multi-tenant module is present,
|
|
20
|
-
* `resolveActiveTenant` (the slice) is the entry point and, on its
|
|
21
|
-
* null-binding branch only (the session carries no active workspace), calls
|
|
22
|
-
* `resolveDefaultTenantForOperator` — the same pinned, verified-operator entry
|
|
23
|
-
* point the base guard uses (#7523). Its explicit-binding branch never reaches
|
|
24
|
-
* this file. Without the module, `middleware/default-tenant.ts` calls
|
|
25
|
-
* `resolveDefaultTenantForOperator` directly. There is one resolution, behind
|
|
26
|
-
* one pin check, reached two ways — never two resolutions.
|
|
27
|
-
*
|
|
28
|
-
* DEFAULT-DENY IS THE FLOOR. `resolveDefaultTenant` returns `null` — never a
|
|
29
|
-
* grant — the instant the deployment is not unambiguously single-tenant
|
|
30
|
-
* (a second Workspace exists, or the sole Workspace is not the well-known
|
|
31
|
-
* default), and `null` again for a caller holding no Membership on the default
|
|
32
|
-
* Organization. Both branches were written for the multi-tenant slice by the
|
|
33
|
-
* owner-pin fix (docs/specs/single-tenant-owner-pin-spec.md, #3631) and are
|
|
34
|
-
* moved here BYTE-FOR-BYTE, not rewritten.
|
|
35
|
-
*
|
|
36
|
-
* This file is a sanctioned exception to architecture.yaml's tenant-scope
|
|
37
|
-
* forbidden pattern, for the same reason `tenant-context.ts` is: it is a
|
|
38
|
-
* tenancy-model boundary, not a domain-data reader.
|
|
39
|
-
*/
|
|
40
|
-
import {
|
|
41
|
-
DEFAULT_ORG_ID,
|
|
42
|
-
OPERATOR_MEMBERSHIP_ID,
|
|
43
|
-
resolveDefaultWorkspaceRow as resolveDefaultWorkspaceRowShared,
|
|
44
|
-
} from "@working-theory/database/tenancy";
|
|
45
|
-
import type { Id } from "@working-theory/ids";
|
|
46
|
-
import {
|
|
47
|
-
AGENT_GRANTABLE_PERMISSIONS,
|
|
48
|
-
can,
|
|
49
|
-
lowerRole,
|
|
50
|
-
type AgentGrantablePermission,
|
|
51
|
-
} from "@working-theory/validation";
|
|
52
|
-
|
|
53
|
-
import type { AgentGrant } from "../lib/agent-store.js";
|
|
54
|
-
import { prisma } from "../lib/prisma.js";
|
|
55
|
-
|
|
56
|
-
import { findVerifiedEmail } from "./verified-email.js";
|
|
57
|
-
|
|
58
|
-
export type MembershipRole = "owner" | "admin" | "member";
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The tenant scope every domain query is bound to. Ids carry the ADR-0031
|
|
62
|
-
* brand; values originating from Prisma reads are brand-asserted at the read
|
|
63
|
-
* edge (the DB CHECK constraints are the runtime guarantee).
|
|
64
|
-
*/
|
|
65
|
-
export interface TenantContext {
|
|
66
|
-
userId: Id<"user">;
|
|
67
|
-
organizationId: Id<"organization">;
|
|
68
|
-
workspaceId: Id<"workspace">;
|
|
69
|
-
role: MembershipRole;
|
|
70
|
-
/**
|
|
71
|
-
* Set ONLY on an agent's tenant (#7864 D3), and only when at least one of
|
|
72
|
-
* its grants survives the clamp: the grantable permissions it holds on top
|
|
73
|
-
* of its role. A person's tenant never carries it. Read through
|
|
74
|
-
* `@working-theory/validation`'s `allows`.
|
|
75
|
-
*/
|
|
76
|
-
grants?: readonly AgentGrantablePermission[];
|
|
77
|
-
/**
|
|
78
|
-
* Set ONLY by `agentTenant` (#8514 D4); a person's tenant never carries it.
|
|
79
|
-
* `@working-theory/validation`'s `roleAllows` / `allows` read it to withhold
|
|
80
|
-
* `AGENT_WITHHELD_PERMISSIONS` from an agent's role, and both tenant guards
|
|
81
|
-
* refuse an agent request whose tenant lacks it (fail closed).
|
|
82
|
-
*/
|
|
83
|
-
agent?: true;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export type TenantErrorKind = "forbidden" | "not_found" | "conflict";
|
|
87
|
-
|
|
88
|
-
export type TenantResult<T> =
|
|
89
|
-
| { ok: true; value: T }
|
|
90
|
-
| { ok: false; error: { kind: TenantErrorKind; message: string } };
|
|
91
|
-
|
|
92
|
-
export function isUniqueViolation(error: unknown): boolean {
|
|
93
|
-
return (
|
|
94
|
-
typeof error === "object" &&
|
|
95
|
-
error !== null &&
|
|
96
|
-
"code" in error &&
|
|
97
|
-
(error as { code?: unknown }).code === "P2002"
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* TOFU-binds the operator Membership for a single-tenant deployment (spec
|
|
103
|
-
* D1–D4) — the replacement for the deleted user-agnostic `owner` grant. The
|
|
104
|
-
* Membership is created with a fixed, well-known id
|
|
105
|
-
* (`OPERATOR_MEMBERSHIP_ID`); the `Membership.id` primary-key uniqueness —
|
|
106
|
-
* not a read-then-write "is this the first user?" guard — enforces exactly
|
|
107
|
-
* one owner under a concurrent first-login race. The losing caller's
|
|
108
|
-
* `create` raises `P2002`, swallowed here: that caller is then unbound and
|
|
109
|
-
* denied by the `membership.findUnique` the caller of this function runs
|
|
110
|
-
* next.
|
|
111
|
-
*
|
|
112
|
-
* Idempotent + at-most-once: a caller who already holds the Membership (a
|
|
113
|
-
* repeat call, or the deployment's steady state after the first bind) hits
|
|
114
|
-
* the same `P2002` path and is a no-op. Reachable ONLY from
|
|
115
|
-
* `resolveDefaultTenant`, itself gated by the
|
|
116
|
-
* `count === 1 && default-workspace-exists` check — unreachable from any
|
|
117
|
-
* multi-tenant state (`count > 1`).
|
|
118
|
-
*
|
|
119
|
-
* When `AILK_OPERATOR_EMAIL` is set (spec D4 — trimmed + lowercased before
|
|
120
|
-
* comparison), the bind is attempted ONLY for the caller whose VERIFIED
|
|
121
|
-
* `User.email` matches it (#5701 AC-2 — the read goes through
|
|
122
|
-
* `findVerifiedEmail`, so an unverified address is refused here and not only
|
|
123
|
-
* at the base-build entry above); every other caller returns without writing
|
|
124
|
-
* and is denied downstream. An empty/whitespace-only `AILK_OPERATOR_EMAIL` normalizes to
|
|
125
|
-
* `""`, which is falsy — treated as unset (pure TOFU), so a blank pin can
|
|
126
|
-
* never "match" a blank `User.email`. When unset, the bind is pure TOFU —
|
|
127
|
-
* first caller wins.
|
|
128
|
-
*/
|
|
129
|
-
async function bindOperatorMembership(userId: Id<"user">): Promise<void> {
|
|
130
|
-
const pinnedEmail = process.env.AILK_OPERATOR_EMAIL?.trim().toLowerCase();
|
|
131
|
-
if (pinnedEmail) {
|
|
132
|
-
// The verified-email read is `services/verified-email.ts` (#5701 D4) — the
|
|
133
|
-
// same one `resolveDefaultTenantForOperator` uses. It returns the address
|
|
134
|
-
// only when `emailVerified === true`, so an address that merely CLAIMS to
|
|
135
|
-
// be the pin can no longer mint `OPERATOR_MEMBERSHIP_ID`. Both refusals
|
|
136
|
-
// (`user_not_found`, `email_unverified`) take the branch's existing early
|
|
137
|
-
// return — the caller is then unbound and denied by the
|
|
138
|
-
// `membership.findUnique` that follows.
|
|
139
|
-
const verified = await findVerifiedEmail(userId);
|
|
140
|
-
if (!verified.ok) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
if (verified.value.email.trim().toLowerCase() !== pinnedEmail) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
try {
|
|
148
|
-
await prisma.membership.create({
|
|
149
|
-
data: {
|
|
150
|
-
id: OPERATOR_MEMBERSHIP_ID,
|
|
151
|
-
organizationId: DEFAULT_ORG_ID,
|
|
152
|
-
userId,
|
|
153
|
-
role: "owner",
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
} catch (error) {
|
|
157
|
-
if (!isUniqueViolation(error)) {
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
// Another caller already holds OPERATOR_MEMBERSHIP_ID (the TOFU race
|
|
161
|
-
// winner, or a prior deployment run) — swallow and fall through.
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* The BASE-BUILD entry point: `resolveDefaultTenant` narrowed to the caller
|
|
167
|
-
* whose `User.email` matches `AILK_OPERATOR_EMAIL`, denying everyone when the
|
|
168
|
-
* pin is unset (#5693 security review, High finding).
|
|
169
|
-
*
|
|
170
|
-
* WHY BOTH PATHS NEED THIS. Registering the review surface on a module-less
|
|
171
|
-
* build made two things reachable together that were previously unreachable
|
|
172
|
-
* there: this resolution's TOFU operator bind, and
|
|
173
|
-
* `services/waitlist-operator-reads.ts`'s `isPlatformOperator`, which grants
|
|
174
|
-
* `{kind: "all"}` — every site's rows, unfiltered — to an `owner` of the
|
|
175
|
-
* sentinel default Organization. Until #7523 that predicate never compared the
|
|
176
|
-
* caller to the pin; the pin was an on/off switch for it. It now goes through
|
|
177
|
-
* `isPinnedOperator` below too, but the bind is the half this function closes.
|
|
178
|
-
*
|
|
179
|
-
* Unpinned TOFU plus that predicate is an escalation. The site's auth
|
|
180
|
-
* auto-provisions a `User` on first login, so on a deployment with the pin
|
|
181
|
-
* unset the FIRST authenticated caller to touch a review route — any public
|
|
182
|
-
* respondent, not necessarily the operator — wins `OPERATOR_MEMBERSHIP_ID`.
|
|
183
|
-
* The real operator is then denied (their `create` raises `P2002`, swallowed),
|
|
184
|
-
* finds an empty dashboard, and sets `AILK_OPERATOR_EMAIL` to fix it — which
|
|
185
|
-
* flips the squatter, not the operator, to `{kind: "all"}`.
|
|
186
|
-
*
|
|
187
|
-
* So the base path requires the pin and requires the caller to BE it. Both
|
|
188
|
-
* halves matter: requiring the pin stops an unpinned race from seating anyone,
|
|
189
|
-
* and re-checking the caller's email on every request denies a squatter who
|
|
190
|
-
* was already bound before this code shipped — a Membership row alone is no
|
|
191
|
-
* longer enough. `bindOperatorMembership` below performs its own email check,
|
|
192
|
-
* but only at bind time and only for the bind; this is the one that gates the
|
|
193
|
-
* grant.
|
|
194
|
-
*
|
|
195
|
-
* The multi-tenant module reached the same race the same way: its null-binding
|
|
196
|
-
* branch called `resolveDefaultTenant` directly, so on a one-workspace
|
|
197
|
-
* multi-tenant deployment with the pin unset the first signed-in caller to
|
|
198
|
-
* touch a tenant route from `apps/web` (whose sessions never carry an active
|
|
199
|
-
* workspace) was seated as owner. Since #7523 that branch calls this wrapper
|
|
200
|
-
* too (docs/specs/7523-a-multi-tenant-session-with-spec.md D1), so a session
|
|
201
|
-
* with no active workspace is granted the default tenant only when its
|
|
202
|
-
* caller is the pinned, verified operator. Sessions that DO carry an active
|
|
203
|
-
* workspace — every Admin-app request — never reach this function.
|
|
204
|
-
*
|
|
205
|
-
* `docs/specs/single-tenant-owner-pin-spec.md` D5 already recommended pinning;
|
|
206
|
-
* on both paths it is now mandatory rather than advisory, and unset fails
|
|
207
|
-
* closed.
|
|
208
|
-
*
|
|
209
|
-
* ONE KNOWN IMPRECISION, deliberate. `User.email` is `@unique` in Postgres,
|
|
210
|
-
* which is byte-exact, while this comparison lowercases both sides — so two
|
|
211
|
-
* distinct rows (`Operator@x.com` and `operator@x.com`) could both satisfy one
|
|
212
|
-
* pin. `apps/web/auth.ts` no longer configures social providers only: it also
|
|
213
|
-
* enables email+password and magic-link sign-in, so the address can be
|
|
214
|
-
* caller-chosen. Only a VERIFIED row is compared (`findVerifiedEmail`), and
|
|
215
|
-
* verifying it needs a mailbox proof, so a second row for the pin's address
|
|
216
|
-
* in a different case is reachable only by someone who controls that
|
|
217
|
-
* mailbox. The durable fix is still case-insensitive email uniqueness in the
|
|
218
|
-
* schema (citext, or lowercase-at-write) so "matches the pin" and "is unique"
|
|
219
|
-
* agree. Matching case-sensitively here instead would be worse: it would lock
|
|
220
|
-
* out an operator who typed their own address with different capitalisation.
|
|
221
|
-
*/
|
|
222
|
-
export async function resolveDefaultTenantForOperator(
|
|
223
|
-
userId: Id<"user">,
|
|
224
|
-
): Promise<TenantContext | null> {
|
|
225
|
-
return (await isPinnedOperator(userId)) ? resolveDefaultTenant(userId) : null;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* An agent's tenant (#3591 D5, #7864): its person's tenant with the role
|
|
230
|
-
* clamped to the agent's ceiling and, when any survive, the agent's grants
|
|
231
|
-
* that its person's own role holds. `grants` is omitted when none survive,
|
|
232
|
-
* so an agent with no effective grant is the same shape as before. It always
|
|
233
|
-
* carries `agent: true` (#8514 D4), which withholds the client-keeping rows a
|
|
234
|
-
* member holds by role.
|
|
235
|
-
*
|
|
236
|
-
* The one clamp both tenant guards apply — `resolveAgentTenant` (multi-tenant)
|
|
237
|
-
* and `resolveDefaultTenantForAgent` (base build) — so the two builds cannot
|
|
238
|
-
* hold an agent to different rules.
|
|
239
|
-
*/
|
|
240
|
-
export function agentTenant(
|
|
241
|
-
personTenant: TenantContext,
|
|
242
|
-
agent: AgentGrant,
|
|
243
|
-
): TenantContext {
|
|
244
|
-
const role = lowerRole(personTenant.role, agent.permissionLevel);
|
|
245
|
-
// D1 order, no duplicates, only the five, and only what the person holds.
|
|
246
|
-
const grants = AGENT_GRANTABLE_PERMISSIONS.filter(
|
|
247
|
-
(p) => agent.grants.includes(p) && can(personTenant.role, p),
|
|
248
|
-
);
|
|
249
|
-
return grants.length > 0
|
|
250
|
-
? { ...personTenant, role, agent: true, grants }
|
|
251
|
-
: { ...personTenant, role, agent: true };
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* The base-build grant for an AGENT (#3591 spec D5, D7). The same steps as
|
|
256
|
-
* `resolveDefaultTenantForOperator` — the pin check, then the default
|
|
257
|
-
* resolution and its one Membership read — so an agent and its person's
|
|
258
|
-
* session drive the same reads. On top of them: the resolved workspace must
|
|
259
|
-
* be the one the agent is bound to, and the Membership the read found must be
|
|
260
|
-
* the one the agent was created under. The tenant is then clamped
|
|
261
|
-
* (`agentTenant`), so the operator's agent acts as a member plus the grants
|
|
262
|
-
* the operator holds.
|
|
263
|
-
*
|
|
264
|
-
* The membership id is compared here rather than carried on `TenantContext`,
|
|
265
|
-
* which stays one shape for every caller. On a base build only the pinned,
|
|
266
|
-
* verified operator holds a membership this admits, so only the operator's
|
|
267
|
-
* agents, bound to the default workspace, ever pass.
|
|
268
|
-
*/
|
|
269
|
-
export async function resolveDefaultTenantForAgent(
|
|
270
|
-
userId: Id<"user">,
|
|
271
|
-
agent: AgentGrant,
|
|
272
|
-
): Promise<TenantContext | null> {
|
|
273
|
-
if (!(await isPinnedOperator(userId))) return null;
|
|
274
|
-
const granted = await resolveDefaultGrant(userId);
|
|
275
|
-
if (
|
|
276
|
-
!granted ||
|
|
277
|
-
granted.tenant.workspaceId !== agent.workspaceId ||
|
|
278
|
-
granted.tenant.organizationId !== agent.organizationId ||
|
|
279
|
-
granted.membershipId !== agent.responsibleMembershipId
|
|
280
|
-
) {
|
|
281
|
-
return null;
|
|
282
|
-
}
|
|
283
|
-
return agentTenant(granted.tenant, agent);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* The one pin-match predicate in `apps/api` (#7523 D2): `true` only when
|
|
288
|
-
* `AILK_OPERATOR_EMAIL` is set and the caller's VERIFIED `User.email` equals
|
|
289
|
-
* it. Both sides are trimmed and lowercased; a blank pin counts as unset and
|
|
290
|
-
* refuses before any read, so it can never "match" a blank `User.email`.
|
|
291
|
-
*
|
|
292
|
-
* Shared by the two tenant guards (through `resolveDefaultTenantForOperator`)
|
|
293
|
-
* and by `services/waitlist-operator-reads.ts`'s `isPlatformOperator`. It
|
|
294
|
-
* lives in this base-build file because that operator-read file rides more
|
|
295
|
-
* than one module slice and may import only files every build ships.
|
|
296
|
-
* `bindOperatorMembership` keeps its own inline check: it must allow a bind
|
|
297
|
-
* when the pin is unset, which this predicate never does.
|
|
298
|
-
*/
|
|
299
|
-
export async function isPinnedOperator(userId: Id<"user">): Promise<boolean> {
|
|
300
|
-
const pinnedEmail = process.env.AILK_OPERATOR_EMAIL?.trim().toLowerCase();
|
|
301
|
-
if (!pinnedEmail) {
|
|
302
|
-
return false;
|
|
303
|
-
}
|
|
304
|
-
// The verified-email read is `services/verified-email.ts` (#5701 D4) — the
|
|
305
|
-
// one this and the four other email-keyed paths share. It returns the
|
|
306
|
-
// address only when `emailVerified === true`, which is what makes a match
|
|
307
|
-
// against the pin a proven claim rather than an asserted one.
|
|
308
|
-
const verified = await findVerifiedEmail(userId);
|
|
309
|
-
if (!verified.ok) {
|
|
310
|
-
return false;
|
|
311
|
-
}
|
|
312
|
-
return verified.value.email.trim().toLowerCase() === pinnedEmail;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* The DEPLOYMENT half of the default resolution, extracted so it exists once
|
|
317
|
-
* (#5852 D2). Returns the sole, well-known default Workspace row, or `null`
|
|
318
|
-
* the instant the deployment is not unambiguously one-workspace — a second
|
|
319
|
-
* Workspace exists, none does, or the sole one is not the seeded default.
|
|
320
|
-
*
|
|
321
|
-
* Carries no authentication: it answers "is this deployment one-workspace, and
|
|
322
|
-
* which workspace is it", nothing about the caller. `resolveDefaultTenant`
|
|
323
|
-
* adds the authentication half on top; `services/public-site-resolver.ts`
|
|
324
|
-
* (unauthenticated public reads) uses the deployment half alone. One
|
|
325
|
-
* predicate, reached two ways — never two predicates.
|
|
326
|
-
*
|
|
327
|
-
* The predicate itself is `@working-theory/database/tenancy`'s
|
|
328
|
-
* `resolveDefaultWorkspaceRow` (#5876 spec D2/D3) — this is now a thin
|
|
329
|
-
* pass-through of `apps/api`'s own `prisma` singleton, kept as a named local
|
|
330
|
-
* function (rather than re-exporting the shared one directly) so every
|
|
331
|
-
* existing caller — this file's own `resolveDefaultWorkspaceId` and
|
|
332
|
-
* `resolveDefaultTenant`, and `services/public-site-resolver.ts`'s dynamic
|
|
333
|
-
* import of the wrapper — is untouched. There is exactly one implementation
|
|
334
|
-
* of the one-workspace predicate in the repository (NFR-7); apps/mcp's own
|
|
335
|
-
* resolution (`apps/mcp/src/lib/public-workspace.ts`) delegates to the same
|
|
336
|
-
* shared export.
|
|
337
|
-
*/
|
|
338
|
-
async function resolveDefaultWorkspaceRow(): Promise<{
|
|
339
|
-
id: string;
|
|
340
|
-
organizationId: string;
|
|
341
|
-
} | null> {
|
|
342
|
-
return resolveDefaultWorkspaceRowShared(prisma);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* The one-workspace deployment predicate, as a workspace id (#5852 D2).
|
|
347
|
-
* `null` means the deployment is not unambiguously one-workspace, and every
|
|
348
|
-
* caller fails closed on it.
|
|
349
|
-
*/
|
|
350
|
-
export async function resolveDefaultWorkspaceId(): Promise<Id<"workspace"> | null> {
|
|
351
|
-
const workspace = await resolveDefaultWorkspaceRow();
|
|
352
|
-
return workspace ? (workspace.id as Id<"workspace">) : null;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Resolves the default single-tenant scope when the deployment is
|
|
357
|
-
* unambiguously single-tenant — the default Workspace (`DEFAULT_WORKSPACE_ID`)
|
|
358
|
-
* exists AND it is the ONLY Workspace (`workspace.count() === 1`), the exact
|
|
359
|
-
* mirror of the Phase-1 provision guard's `count === 0` check (spec D2).
|
|
360
|
-
* Returns `null` (never grants) the instant a second Workspace exists, or the
|
|
361
|
-
* sole Workspace is not the well-known default — the caller falls through to
|
|
362
|
-
* its own default-deny in that case.
|
|
363
|
-
*
|
|
364
|
-
* Converges on the SAME Membership-based authz the multi-tenant path uses
|
|
365
|
-
* (spec D1 — the fix): attempts to TOFU-bind the caller as operator
|
|
366
|
-
* (`bindOperatorMembership`, a no-op once an operator is already bound or
|
|
367
|
-
* the caller doesn't match the optional env pin), then runs the real
|
|
368
|
-
* `membership.findUnique` check. A caller holding no Membership on the
|
|
369
|
-
* default Org — including every caller after the first once TOFU has bound
|
|
370
|
-
* someone else — resolves `null` here, and the caller denies. There is no
|
|
371
|
-
* user-agnostic `owner` grant.
|
|
372
|
-
*
|
|
373
|
-
* Formerly `resolveSingleTenantDefault` in `services/tenant-context.ts`
|
|
374
|
-
* (#3631); moved here verbatim by #5677 so the base build can reach it.
|
|
375
|
-
*/
|
|
376
|
-
export async function resolveDefaultTenant(
|
|
377
|
-
userId: Id<"user">,
|
|
378
|
-
): Promise<TenantContext | null> {
|
|
379
|
-
return (await resolveDefaultGrant(userId))?.tenant ?? null;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* `resolveDefaultTenant`'s body, also handing back the id of the Membership
|
|
384
|
-
* it read, which the agent path compares (#3591 D5). One read serves both:
|
|
385
|
-
* its `select` is widened from `{ role }` to `{ id, role }`.
|
|
386
|
-
*/
|
|
387
|
-
async function resolveDefaultGrant(
|
|
388
|
-
userId: Id<"user">,
|
|
389
|
-
): Promise<{ tenant: TenantContext; membershipId: string } | null> {
|
|
390
|
-
const workspace = await resolveDefaultWorkspaceRow();
|
|
391
|
-
if (!workspace) {
|
|
392
|
-
return null;
|
|
393
|
-
}
|
|
394
|
-
await bindOperatorMembership(userId);
|
|
395
|
-
const membership = await prisma.membership.findUnique({
|
|
396
|
-
where: {
|
|
397
|
-
organizationId_userId: {
|
|
398
|
-
organizationId: workspace.organizationId,
|
|
399
|
-
userId,
|
|
400
|
-
},
|
|
401
|
-
},
|
|
402
|
-
select: { id: true, role: true },
|
|
403
|
-
});
|
|
404
|
-
if (!membership) {
|
|
405
|
-
return null;
|
|
406
|
-
}
|
|
407
|
-
return {
|
|
408
|
-
tenant: {
|
|
409
|
-
userId,
|
|
410
|
-
organizationId: workspace.organizationId as Id<"organization">,
|
|
411
|
-
workspaceId: workspace.id as Id<"workspace">,
|
|
412
|
-
role: membership.role as MembershipRole,
|
|
413
|
-
},
|
|
414
|
-
membershipId: membership.id,
|
|
415
|
-
};
|
|
416
|
-
}
|