create-ailk 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -20
- 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 +1 -1
- package/dist/lib/fetch-template-snapshot.js +7 -3
- package/dist/lib/import-graph.d.ts +1 -1
- package/dist/lib/import-graph.js +4 -4
- package/dist/lib/module-license-gate.d.ts +12 -1
- package/dist/lib/module-license-gate.js +34 -12
- package/dist/module-architecture.d.ts +20 -3
- package/dist/module-architecture.js +117 -550
- package/dist/paid-sections.d.ts +25 -1
- package/dist/paid-sections.js +88 -3
- package/dist/surfaces.js +10 -2
- package/dist/template-record.d.ts +14 -4
- package/dist/template-record.js +23 -5
- package/dist/topology.d.ts +16 -3
- package/dist/topology.js +31 -19
- package/dist/update.d.ts +10 -1
- package/dist/update.js +540 -16
- package/package.json +3 -3
- package/release-scope.json +1 -1
- package/templates/.claude/cloudparity-repo-hooks.json +5 -0
- package/templates/.claude/hooks/template-guard.sh +137 -0
- package/templates/.claude/rules/extending.md +106 -0
- package/templates/.claude/rules/loop-contract.md +2 -2
- package/templates/.claude/settings.json +11 -0
- package/templates/.env.example +5 -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 +2 -2
- package/templates/apps/api/CLAUDE.md +102 -76
- package/templates/apps/api/jest.config.cjs +15 -5
- package/templates/apps/api/package.json +16 -20
- package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
- package/templates/apps/api/src/index.ts +1 -1
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +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 +67 -20
- 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 +10 -3
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
- 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]/pricing/__tests__/unconnected.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
- package/templates/apps/web/app/api/revalidate/route.ts +3 -3
- package/templates/apps/web/auth.ts +2 -2
- package/templates/apps/web/jest.config.cjs +1 -0
- package/templates/apps/web/lib/auth-email.ts +1 -1
- package/templates/apps/web/lib/relay.ts +2 -2
- package/templates/apps/web/lib/release-scope.ts +47 -0
- package/templates/apps/web/lib/server-api.ts +1 -1
- package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
- package/templates/customizations.yaml +37 -0
- package/templates/database/prisma.config.ts +10 -14
- package/templates/database/seed-test.ts +2 -2
- package/templates/database/seed.ts +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 +48 -35
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
- package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
- package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
- package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
- package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
- package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
- package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
- package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
- package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
- package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
- package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
- package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
- package/templates/apps/api/src/bin/spokes.ts +0 -198
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
- package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
- package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
- package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
- package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
- package/templates/apps/api/src/config/index.ts +0 -596
- package/templates/apps/api/src/config/modules.ts +0 -83
- package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
- package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
- package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
- package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
- package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
- package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
- package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
- package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
- package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
- package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
- package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
- package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
- package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
- package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
- package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
- package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -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,317 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the commerce claim gate (D-64, #5796; round 2).
|
|
3
|
-
*
|
|
4
|
-
* Mocks @working-theory/license `checkLicense` and asserts the TRI-STATE
|
|
5
|
-
* contract (security review 2026-09-16, High; operator-disposed round 2):
|
|
6
|
-
*
|
|
7
|
-
* claimed — read successfully, features[] carries `commerce`
|
|
8
|
-
* unclaimed — read successfully and positively WITHOUT the claim, on a
|
|
9
|
-
* deployment that configures no licence at all
|
|
10
|
-
* undetermined — the read did not establish a "no": it threw, the licence
|
|
11
|
-
* is revoked, a licence IS configured yet resolves free
|
|
12
|
-
* (expired or otherwise unverifiable), or the licence storage
|
|
13
|
-
* file could not be READ at all (#5820)
|
|
14
|
-
*
|
|
15
|
-
* Route behaviour differs by what is at stake, which is why this is not one
|
|
16
|
-
* response: the checkout launcher answers the module-disabled 404 on both
|
|
17
|
-
* non-serving states (a checkout that cannot start loses nothing), while the
|
|
18
|
-
* webhook receiver holds an `undetermined` event with a retryable 503 rather
|
|
19
|
-
* than dropping a charge that already happened.
|
|
20
|
-
*
|
|
21
|
-
* The tier is deliberately varied against the claim: this gate reads
|
|
22
|
-
* `features`, never `tier` (D-64).
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
const mockCheckLicense = jest.fn();
|
|
26
|
-
|
|
27
|
-
// Only `checkLicense` is stubbed. `readStoredJwtState()` runs for real against
|
|
28
|
-
// a per-test fixture directory pointed at by `AILK_LICENSE_STORAGE_PATH`
|
|
29
|
-
// (#5820): the absent-vs-unreadable distinction IS the thing under test, and a
|
|
30
|
-
// stub of it would assert only that the stub was called — which is exactly how
|
|
31
|
-
// the previous "the storage read throws" case passed against a throw the
|
|
32
|
-
// package can never produce.
|
|
33
|
-
jest.mock("@working-theory/license", () => ({
|
|
34
|
-
...jest.requireActual("@working-theory/license"),
|
|
35
|
-
checkLicense: (...args: unknown[]) => mockCheckLicense(...args),
|
|
36
|
-
}));
|
|
37
|
-
|
|
38
|
-
import { promises as fs } from "fs";
|
|
39
|
-
import { tmpdir } from "os";
|
|
40
|
-
import { join } from "path";
|
|
41
|
-
|
|
42
|
-
import type { FastifyReply, FastifyRequest } from "fastify";
|
|
43
|
-
|
|
44
|
-
import {
|
|
45
|
-
resolveCommerceClaim,
|
|
46
|
-
requireCommerceClaim,
|
|
47
|
-
} from "../require-commerce-claim.js";
|
|
48
|
-
|
|
49
|
-
interface StubReply {
|
|
50
|
-
statusCalled: number | null;
|
|
51
|
-
sendCalled: unknown;
|
|
52
|
-
status: jest.MockedFunction<(code: number) => StubReply>;
|
|
53
|
-
send: jest.MockedFunction<(body: unknown) => StubReply>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function makeReply(): StubReply {
|
|
57
|
-
const reply: StubReply = {
|
|
58
|
-
statusCalled: null,
|
|
59
|
-
sendCalled: undefined,
|
|
60
|
-
status: jest.fn(),
|
|
61
|
-
send: jest.fn(),
|
|
62
|
-
};
|
|
63
|
-
reply.status.mockImplementation((code: number) => {
|
|
64
|
-
reply.statusCalled = code;
|
|
65
|
-
return reply;
|
|
66
|
-
});
|
|
67
|
-
reply.send.mockImplementation((body: unknown) => {
|
|
68
|
-
reply.sendCalled = body;
|
|
69
|
-
return reply;
|
|
70
|
-
});
|
|
71
|
-
return reply;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const logWarn = jest.fn();
|
|
75
|
-
|
|
76
|
-
// The gate reads exactly one thing off the request — `log.warn`. Cast at one
|
|
77
|
-
// typed boundary, the same shape require-paid-tier.test.ts uses.
|
|
78
|
-
function makeRequest(): FastifyRequest {
|
|
79
|
-
// @ts-expect-error: a stub carrying only `log.warn`; a full FastifyRequest
|
|
80
|
-
// cannot be constructed without a live server instance in unit tests.
|
|
81
|
-
return { log: { warn: logWarn } };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const request = makeRequest();
|
|
85
|
-
|
|
86
|
-
function asReply(stub: StubReply): FastifyReply {
|
|
87
|
-
// @ts-expect-error: StubReply satisfies the status+send surface requireCommerceClaim uses;
|
|
88
|
-
// a full Fastify reply cannot be constructed without a live server instance in unit tests.
|
|
89
|
-
return stub;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function license(overrides: Record<string, unknown> = {}) {
|
|
93
|
-
return {
|
|
94
|
-
tier: "pro",
|
|
95
|
-
plan: "pro-monthly",
|
|
96
|
-
features: [],
|
|
97
|
-
expiresAt: null,
|
|
98
|
-
revoked: false,
|
|
99
|
-
...overrides,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** The shape `checkLicense()` returns for expired, invalid AND keyless alike. */
|
|
104
|
-
function freeResult() {
|
|
105
|
-
return license({ tier: "free", plan: null, features: [], revoked: false });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const ORIGINAL_LICENSE_KEY = process.env["AILK_LICENSE_KEY"];
|
|
109
|
-
|
|
110
|
-
/** A deployment that configures a licence (env key present). */
|
|
111
|
-
function withLicenceConfigured() {
|
|
112
|
-
// Presence is the whole test — the gate never parses this value, so it is
|
|
113
|
-
// deliberately not JWT-shaped (a realistic stub trips the secret scanner's
|
|
114
|
-
// entropy rule for no benefit).
|
|
115
|
-
process.env["AILK_LICENSE_KEY"] = "fixture";
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** A keyless deployment — no env key, and no storage file at the fixture path. */
|
|
119
|
-
function withNoLicenceConfigured() {
|
|
120
|
-
delete process.env["AILK_LICENSE_KEY"];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ── The storage file, for real ──────────────────────────────────────────────
|
|
124
|
-
//
|
|
125
|
-
// Every test points `AILK_LICENSE_STORAGE_PATH` at a fresh temp path that does
|
|
126
|
-
// not exist, which is the `absent` state. The two cases below create the file
|
|
127
|
-
// the package will actually read.
|
|
128
|
-
|
|
129
|
-
let storageDir: string;
|
|
130
|
-
let storagePath: string;
|
|
131
|
-
|
|
132
|
-
/** A deployment licensed purely from the refresh storage file. */
|
|
133
|
-
async function withStoredLicence() {
|
|
134
|
-
await fs.writeFile(storagePath, "stored.jwt.token", "utf8");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** A storage file that exists and cannot be read — a directory at its path. */
|
|
138
|
-
async function withUnreadableStorage() {
|
|
139
|
-
await fs.mkdir(storagePath);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
beforeEach(async () => {
|
|
143
|
-
storageDir = await fs.mkdtemp(join(tmpdir(), "ailk-claim-gate-"));
|
|
144
|
-
storagePath = join(storageDir, ".ailk-license.jwt");
|
|
145
|
-
process.env["AILK_LICENSE_STORAGE_PATH"] = storagePath;
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
afterEach(async () => {
|
|
149
|
-
delete process.env["AILK_LICENSE_STORAGE_PATH"];
|
|
150
|
-
await fs.rm(storageDir, { recursive: true, force: true });
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
afterAll(() => {
|
|
154
|
-
if (ORIGINAL_LICENSE_KEY === undefined) delete process.env["AILK_LICENSE_KEY"];
|
|
155
|
-
else process.env["AILK_LICENSE_KEY"] = ORIGINAL_LICENSE_KEY;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
describe("requireCommerceClaim (the checkout launcher's preHandler)", () => {
|
|
159
|
-
beforeEach(() => {
|
|
160
|
-
mockCheckLicense.mockReset();
|
|
161
|
-
logWarn.mockReset();
|
|
162
|
-
withNoLicenceConfigured();
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("404s the module-disabled body when features[] lacks 'commerce'", async () => {
|
|
166
|
-
mockCheckLicense.mockResolvedValue(freeResult());
|
|
167
|
-
const reply = makeReply();
|
|
168
|
-
|
|
169
|
-
await requireCommerceClaim(request, asReply(reply));
|
|
170
|
-
|
|
171
|
-
expect(reply.statusCalled).toBe(404);
|
|
172
|
-
expect(reply.sendCalled).toEqual({
|
|
173
|
-
error: "not_found",
|
|
174
|
-
message: "Not found",
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it("404s a PAID tier that carries other features but not 'commerce'", async () => {
|
|
179
|
-
mockCheckLicense.mockResolvedValue(
|
|
180
|
-
license({ tier: "enterprise", features: ["docs", "multi-tenant"] }),
|
|
181
|
-
);
|
|
182
|
-
const reply = makeReply();
|
|
183
|
-
|
|
184
|
-
await requireCommerceClaim(request, asReply(reply));
|
|
185
|
-
|
|
186
|
-
expect(reply.statusCalled).toBe(404);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it("proceeds when features[] includes 'commerce'", async () => {
|
|
190
|
-
mockCheckLicense.mockResolvedValue(license({ features: ["commerce"] }));
|
|
191
|
-
const reply = makeReply();
|
|
192
|
-
|
|
193
|
-
await requireCommerceClaim(request, asReply(reply));
|
|
194
|
-
|
|
195
|
-
expect(reply.statusCalled).toBeNull();
|
|
196
|
-
expect(reply.send).not.toHaveBeenCalled();
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Round 2, D1: the checkout launcher answers the module-disabled response on
|
|
200
|
-
// BOTH non-serving states. A checkout that cannot be started loses nothing,
|
|
201
|
-
// so there is no reason to leak a "configured but unreadable" shape here —
|
|
202
|
-
// it is the webhook, where money has already moved, that holds with a 503.
|
|
203
|
-
it("404s — not 503s — on an undetermined read, because a checkout that cannot start loses nothing", async () => {
|
|
204
|
-
mockCheckLicense.mockRejectedValue(new Error("boom"));
|
|
205
|
-
const reply = makeReply();
|
|
206
|
-
|
|
207
|
-
await requireCommerceClaim(request, asReply(reply));
|
|
208
|
-
|
|
209
|
-
expect(reply.statusCalled).toBe(404);
|
|
210
|
-
expect(reply.sendCalled).toEqual({
|
|
211
|
-
error: "not_found",
|
|
212
|
-
message: "Not found",
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it("404s a revoked license even while the claim is still in the JWT", async () => {
|
|
217
|
-
mockCheckLicense.mockResolvedValue(
|
|
218
|
-
license({ features: ["commerce"], revoked: true }),
|
|
219
|
-
);
|
|
220
|
-
const reply = makeReply();
|
|
221
|
-
|
|
222
|
-
await requireCommerceClaim(request, asReply(reply));
|
|
223
|
-
|
|
224
|
-
expect(reply.statusCalled).toBe(404);
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
describe("resolveCommerceClaim", () => {
|
|
229
|
-
beforeEach(() => {
|
|
230
|
-
mockCheckLicense.mockReset();
|
|
231
|
-
withNoLicenceConfigured();
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it("is 'claimed' for a live license carrying the claim", async () => {
|
|
235
|
-
mockCheckLicense.mockResolvedValue(license({ features: ["commerce"] }));
|
|
236
|
-
await expect(resolveCommerceClaim()).resolves.toBe("claimed");
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it("is 'unclaimed' for a license read successfully that lacks the claim", async () => {
|
|
240
|
-
mockCheckLicense.mockResolvedValue(license({ features: ["docs"] }));
|
|
241
|
-
await expect(resolveCommerceClaim()).resolves.toBe("unclaimed");
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it("is 'unclaimed' on a KEYLESS build — no licence configured is a positive 'no'", async () => {
|
|
245
|
-
mockCheckLicense.mockResolvedValue(freeResult());
|
|
246
|
-
await expect(resolveCommerceClaim()).resolves.toBe("unclaimed");
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// The storage-file path. `checkLicense()` resolves a licence from
|
|
250
|
-
// AILK_LICENSE_KEY *or* the refresh storage file, so a deployment can be
|
|
251
|
-
// fully licensed with no env key at all. An env-only "is a licence
|
|
252
|
-
// configured" test read that site as keyless, so its EXPIRED licence
|
|
253
|
-
// resolved `unclaimed` and its already-charged events were dropped — the
|
|
254
|
-
// same High the tri-state exists to prevent, one path over.
|
|
255
|
-
it("is 'undetermined' for an EXPIRED licence held only in the storage file", async () => {
|
|
256
|
-
delete process.env["AILK_LICENSE_KEY"];
|
|
257
|
-
mockCheckLicense.mockResolvedValue(freeResult());
|
|
258
|
-
await withStoredLicence();
|
|
259
|
-
await expect(resolveCommerceClaim()).resolves.toBe("undetermined");
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it("is 'unclaimed' when neither the env key nor the storage file has a token", async () => {
|
|
263
|
-
delete process.env["AILK_LICENSE_KEY"];
|
|
264
|
-
mockCheckLicense.mockResolvedValue(freeResult());
|
|
265
|
-
await expect(resolveCommerceClaim()).resolves.toBe("unclaimed");
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// #5820. Holding is the safe direction: a file that could not be READ is not
|
|
269
|
-
// evidence that a site is keyless, and dropping a signed Stripe event needs
|
|
270
|
-
// evidence. The previous version of this case stubbed `readStoredJwt()` into
|
|
271
|
-
// rejecting — a throw the package never produces, since it catches every
|
|
272
|
-
// error — so it passed while the real path acked 200 and lost the charge.
|
|
273
|
-
it("is 'undetermined' when the storage file exists and cannot be READ", async () => {
|
|
274
|
-
delete process.env["AILK_LICENSE_KEY"];
|
|
275
|
-
mockCheckLicense.mockResolvedValue(freeResult());
|
|
276
|
-
await withUnreadableStorage();
|
|
277
|
-
await expect(resolveCommerceClaim()).resolves.toBe("undetermined");
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it("is 'undetermined' when the read itself throws", async () => {
|
|
281
|
-
mockCheckLicense.mockRejectedValue(new Error("boom"));
|
|
282
|
-
await expect(resolveCommerceClaim()).resolves.toBe("undetermined");
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
// Round 2, D1 (operator-disposed): a revoked licence is a PAYING commerce
|
|
286
|
-
// deployment inside its JWT window. Dropping its already-charged events is
|
|
287
|
-
// the same data loss the security review's High named, so it holds.
|
|
288
|
-
it("is 'undetermined' for a revoked license — a revoked site is still a live one mid-window", async () => {
|
|
289
|
-
mockCheckLicense.mockResolvedValue(
|
|
290
|
-
license({ features: ["commerce"], revoked: true }),
|
|
291
|
-
);
|
|
292
|
-
await expect(resolveCommerceClaim()).resolves.toBe("undetermined");
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
// Round 2, D1: an EXPIRED licence. `checkLicense()` collapses expired,
|
|
296
|
-
// invalid and keyless into one identical free result (check-license.ts
|
|
297
|
-
// returns FREE_RESULT for all three), so the only signal that separates
|
|
298
|
-
// "this site configured a licence that no longer verifies" from "this site
|
|
299
|
-
// never had one" is whether a licence is configured at all.
|
|
300
|
-
it("is 'undetermined' when a licence IS configured yet resolves free — expired or unverifiable", async () => {
|
|
301
|
-
withLicenceConfigured();
|
|
302
|
-
mockCheckLicense.mockResolvedValue(freeResult());
|
|
303
|
-
await expect(resolveCommerceClaim()).resolves.toBe("undetermined");
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it("is 'claimed' for a configured licence that verifies and carries the claim", async () => {
|
|
307
|
-
withLicenceConfigured();
|
|
308
|
-
mockCheckLicense.mockResolvedValue(license({ features: ["commerce"] }));
|
|
309
|
-
await expect(resolveCommerceClaim()).resolves.toBe("claimed");
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it("is 'unclaimed' for a configured licence that verifies to a paid tier without the claim", async () => {
|
|
313
|
-
withLicenceConfigured();
|
|
314
|
-
mockCheckLicense.mockResolvedValue(license({ features: ["docs"] }));
|
|
315
|
-
await expect(resolveCommerceClaim()).resolves.toBe("unclaimed");
|
|
316
|
-
});
|
|
317
|
-
});
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the require-paid-tier Fastify preHandler.
|
|
3
|
-
*
|
|
4
|
-
* Mocks @working-theory/license `checkLicense` and asserts:
|
|
5
|
-
* - free tier → reply.status(402).send(payment_required canonical body)
|
|
6
|
-
* - pro tier → preHandler returns void (handler proceeds)
|
|
7
|
-
* - checkLicense throws → safe-by-default 402 (no false-positive proceed)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const mockCheckLicense = jest.fn();
|
|
11
|
-
|
|
12
|
-
jest.mock("@working-theory/license", () => ({
|
|
13
|
-
checkLicense: (...args: unknown[]) => mockCheckLicense(...args),
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
import type { FastifyReply, FastifyRequest } from "fastify";
|
|
17
|
-
|
|
18
|
-
import { requirePaidTier } from "../require-paid-tier.js";
|
|
19
|
-
|
|
20
|
-
// ── Typed reply builder ───────────────────────────────────────────────────────
|
|
21
|
-
//
|
|
22
|
-
// A minimal Fastify reply stub that satisfies the FastifyReply interface surface
|
|
23
|
-
// used by requirePaidTier (status + send chain). Using a properly typed factory
|
|
24
|
-
// avoids the `as unknown as FastifyReply` double assertion pattern.
|
|
25
|
-
|
|
26
|
-
interface StubReply {
|
|
27
|
-
statusCalled: number | null;
|
|
28
|
-
sendCalled: unknown;
|
|
29
|
-
status: jest.MockedFunction<(code: number) => StubReply>;
|
|
30
|
-
send: jest.MockedFunction<(body: unknown) => StubReply>;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function makeReply(): StubReply {
|
|
34
|
-
const reply: StubReply = {
|
|
35
|
-
statusCalled: null,
|
|
36
|
-
sendCalled: undefined,
|
|
37
|
-
status: jest.fn(),
|
|
38
|
-
send: jest.fn(),
|
|
39
|
-
};
|
|
40
|
-
reply.status.mockImplementation((code: number) => {
|
|
41
|
-
reply.statusCalled = code;
|
|
42
|
-
return reply;
|
|
43
|
-
});
|
|
44
|
-
reply.send.mockImplementation((body: unknown) => {
|
|
45
|
-
reply.sendCalled = body;
|
|
46
|
-
return reply;
|
|
47
|
-
});
|
|
48
|
-
return reply;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Cast the stub to FastifyReply once, at a typed boundary, so all call-sites
|
|
52
|
-
// use the actual StubReply type rather than repeating the double assertion.
|
|
53
|
-
function asReply(stub: StubReply): FastifyReply {
|
|
54
|
-
// @ts-expect-error: StubReply satisfies the status+send surface used by requirePaidTier;
|
|
55
|
-
// a full Fastify reply cannot be constructed without a live server instance in unit tests.
|
|
56
|
-
return stub;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const fakeRequest = {} as FastifyRequest;
|
|
60
|
-
|
|
61
|
-
describe("requirePaidTier", () => {
|
|
62
|
-
beforeEach(() => {
|
|
63
|
-
mockCheckLicense.mockReset();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("free tier — replies 402 with canonical payment_required body", async () => {
|
|
67
|
-
mockCheckLicense.mockResolvedValue({
|
|
68
|
-
tier: "free",
|
|
69
|
-
plan: null,
|
|
70
|
-
features: [],
|
|
71
|
-
expiresAt: null,
|
|
72
|
-
revoked: false,
|
|
73
|
-
});
|
|
74
|
-
const reply = makeReply();
|
|
75
|
-
|
|
76
|
-
await requirePaidTier(fakeRequest, asReply(reply));
|
|
77
|
-
|
|
78
|
-
expect(reply.statusCalled).toBe(402);
|
|
79
|
-
expect(reply.sendCalled).toEqual({
|
|
80
|
-
error: "payment_required",
|
|
81
|
-
message: expect.stringContaining("paid license"),
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it("pro tier — proceeds without calling reply.status/send", async () => {
|
|
86
|
-
mockCheckLicense.mockResolvedValue({
|
|
87
|
-
tier: "pro",
|
|
88
|
-
plan: "pro",
|
|
89
|
-
features: [],
|
|
90
|
-
expiresAt: null,
|
|
91
|
-
revoked: false,
|
|
92
|
-
});
|
|
93
|
-
const reply = makeReply();
|
|
94
|
-
|
|
95
|
-
await requirePaidTier(fakeRequest, asReply(reply));
|
|
96
|
-
|
|
97
|
-
expect(reply.status).not.toHaveBeenCalled();
|
|
98
|
-
expect(reply.send).not.toHaveBeenCalled();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it("checkLicense throws — degrades to 402 (safe default)", async () => {
|
|
102
|
-
mockCheckLicense.mockRejectedValue(new Error("boom"));
|
|
103
|
-
const reply = makeReply();
|
|
104
|
-
|
|
105
|
-
await requirePaidTier(fakeRequest, asReply(reply));
|
|
106
|
-
|
|
107
|
-
expect(reply.statusCalled).toBe(402);
|
|
108
|
-
expect(reply.sendCalled).toMatchObject({ error: "payment_required" });
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("revoked paid license — replies 402 even though tier is pro (issue #398)", async () => {
|
|
112
|
-
// After a 403/revoked refresh, checkLicense() returns tier:'pro' until
|
|
113
|
-
// the existing JWT exp (up to 24h). The revoked flag is the early
|
|
114
|
-
// signal — we must close the gate now, not wait for exp.
|
|
115
|
-
mockCheckLicense.mockResolvedValue({
|
|
116
|
-
tier: "pro",
|
|
117
|
-
plan: "pro",
|
|
118
|
-
features: [],
|
|
119
|
-
expiresAt: null,
|
|
120
|
-
revoked: true,
|
|
121
|
-
});
|
|
122
|
-
const reply = makeReply();
|
|
123
|
-
|
|
124
|
-
await requirePaidTier(fakeRequest, asReply(reply));
|
|
125
|
-
|
|
126
|
-
expect(reply.statusCalled).toBe(402);
|
|
127
|
-
expect(reply.sendCalled).toMatchObject({ error: "payment_required" });
|
|
128
|
-
});
|
|
129
|
-
});
|