create-ailk 0.22.0 → 0.23.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/component-catalog.json +149 -5
- package/component-catalog.md +7 -6
- package/dist/add-module.js +11 -9
- package/dist/add-route.d.ts +55 -1
- package/dist/add-route.js +294 -12
- package/dist/cli.js +27 -10
- package/dist/derive-architecture.d.ts +7 -5
- package/dist/derive-architecture.js +9 -32
- package/dist/lib/design-checks.js +4 -2
- package/dist/lib/env-catalog.js +0 -4
- package/dist/lib/npm-auth.d.ts +9 -0
- package/dist/lib/npm-auth.js +48 -0
- package/dist/lib/scaffold-render-sweep.d.ts +3 -2
- package/dist/lib/scaffold-render-sweep.js +5 -8
- package/dist/module-architecture.js +98 -10
- package/dist/paid-sections.d.ts +21 -2
- package/dist/paid-sections.js +69 -7
- package/dist/seed-flows.d.ts +4 -1
- package/dist/seed-flows.js +50 -4
- package/dist/spoke-checkout.d.ts +38 -35
- package/dist/spoke-checkout.js +66 -229
- package/dist/starter-grid.d.ts +0 -3
- package/dist/starter-grid.js +24 -14
- package/dist/surfaces.js +33 -12
- package/dist/sync-routes.d.ts +38 -1
- package/dist/sync-routes.js +184 -11
- package/dist/template-record.d.ts +1 -1
- package/dist/template-record.js +3 -2
- package/dist/update.js +10 -0
- package/package.json +3 -3
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +4 -49
- package/site-templates/_base/content/en/Pricing/pricing.mdx +3 -21
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +23 -20
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +28 -14
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +15 -39
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +38 -34
- package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +14 -31
- package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +26 -25
- package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
- package/templates/.env.example +9 -7
- package/templates/.github/workflows/ci.yml +13 -0
- package/templates/README.md +1 -0
- package/templates/_gitignore +4 -0
- package/templates/apps/api/.env.example +27 -0
- package/templates/apps/api/CLAUDE.md +77 -16
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +2 -0
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +45 -0
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +185 -0
- package/templates/apps/api/src/config/index.ts +109 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +116 -0
- package/templates/apps/api/src/lib/error-serializer.ts +74 -7
- package/templates/apps/api/src/lib/stripe.ts +74 -4
- package/templates/apps/api/src/lib/webhook-idempotency.ts +66 -2
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +218 -0
- package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +174 -0
- package/templates/apps/api/src/middleware/rate-limit.ts +226 -4
- package/templates/apps/api/src/openapi/spec.ts +10 -7
- package/templates/apps/api/src/routes/billing/plan-checkout.ts +325 -0
- package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +1300 -0
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +11 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +49 -0
- package/templates/apps/api/src/routes/checkout/session.ts +57 -25
- package/templates/apps/api/src/routes/checkout/sessions.ts +232 -82
- package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +5 -5
- package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +160 -0
- package/templates/apps/api/src/routes/consent/account.ts +4 -2
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +2 -2
- package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +731 -0
- package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +753 -0
- package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +762 -0
- package/templates/apps/api/src/routes/content/index.ts +16 -2
- package/templates/apps/api/src/routes/content/offerings.ts +184 -0
- package/templates/apps/api/src/routes/content/pricing.ts +176 -0
- package/templates/apps/api/src/routes/content/shown-offerings.ts +229 -0
- package/templates/apps/api/src/routes/leads/index.ts +17 -14
- package/templates/apps/api/src/routes/webhooks/README.md +66 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +814 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +80 -68
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +5 -5
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +8 -2
- package/templates/apps/api/src/routes/webhooks/index.ts +23 -0
- package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +384 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +91 -17
- package/templates/apps/api/src/server.ts +140 -51
- package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +313 -0
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +51 -2
- package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +234 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +374 -44
- package/templates/apps/api/src/services/__tests__/person.test.ts +232 -1
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +444 -0
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +13 -5
- package/templates/apps/api/src/services/entitlements.ts +157 -1
- package/templates/apps/api/src/services/lead-routing.ts +113 -58
- package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +295 -0
- package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +268 -0
- package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +868 -0
- package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +416 -0
- package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +396 -0
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +681 -0
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +231 -0
- package/templates/apps/api/src/services/offerings/catalog.ts +308 -0
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +385 -0
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +192 -0
- package/templates/apps/api/src/services/offerings/connection.ts +1003 -0
- package/templates/apps/api/src/services/offerings/index.ts +614 -0
- package/templates/apps/api/src/services/offerings/source.ts +140 -0
- package/templates/apps/api/src/services/offerings/store.ts +150 -0
- package/templates/apps/api/src/services/person.ts +124 -9
- package/templates/apps/api/src/services/plan-offerings.ts +96 -30
- package/templates/apps/api/src/services/public-site-resolver.ts +19 -14
- package/templates/apps/mcp/CLAUDE.md +22 -14
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +9 -4
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +358 -0
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +364 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +4 -4
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +2 -2
- package/templates/apps/mcp/__tests__/server.test.ts +13 -11
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +208 -12
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +11 -11
- package/templates/apps/mcp/src/lib/shown-offerings.ts +105 -0
- package/templates/apps/mcp/src/server.ts +5 -0
- package/templates/apps/mcp/src/tools/get_offerings.ts +47 -30
- package/templates/apps/mcp/src/tools/get_pricing.ts +40 -40
- package/templates/apps/mcp/src/tools/purchase.ts +30 -2
- package/templates/apps/mcp/src/workspace-server.ts +15 -0
- package/templates/apps/web/.env.example +10 -31
- package/templates/apps/web/CLAUDE.md +315 -42
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/careers/[slug]/[action]/page.tsx +189 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/apply.actions.ts +4 -2
- package/templates/apps/web/app/[locale]/careers/[slug]/job-application-form.ts +8 -3
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +22 -144
- package/templates/apps/web/app/[locale]/careers/__tests__/apply.actions.test.ts +9 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-hub.test.tsx +172 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/careers-set.test.tsx +149 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/job-application-form.test.ts +22 -24
- package/templates/apps/web/app/[locale]/careers/__tests__/job-apply-page.test.tsx +140 -66
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +57 -22
- package/templates/apps/web/app/[locale]/careers/page.tsx +129 -5
- package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +119 -11
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +28 -5
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +6 -2
- package/templates/apps/web/app/[locale]/contact/page.tsx +99 -92
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +237 -5
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.count.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.deliverable.test.tsx +200 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.ending.test.tsx +197 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +430 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +21 -9
- package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +352 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +12 -73
- package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +10 -31
- package/templates/apps/web/app/[locale]/layout.tsx +55 -4
- package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +174 -104
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +95 -58
- package/templates/apps/web/app/[locale]/pricing/__tests__/__snapshots__/unconnected.test.tsx.snap +7 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/offerings.test.tsx +599 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/page.test.tsx +216 -0
- package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +236 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +367 -6
- package/templates/apps/web/app/[locale]/team/__tests__/team-routes.test.tsx +4 -1
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe-rsc-boundary.test.tsx +17 -0
- package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe.test.tsx +62 -3
- package/templates/apps/web/app/[locale]/unsubscribe/page.tsx +70 -18
- package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe-button.tsx +30 -9
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +316 -0
- package/templates/apps/web/app/api/offerings/checkout/__tests__/route.test.ts +810 -0
- package/templates/apps/web/lib/__tests__/auth-routes.test.ts +27 -1
- package/templates/apps/web/lib/__tests__/deck-page.test.ts +2 -1
- package/templates/apps/web/lib/__tests__/in-page-magnet.test.ts +265 -0
- package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +57 -0
- package/templates/apps/web/lib/__tests__/newsletter.actions.test.ts +293 -0
- package/templates/apps/web/lib/__tests__/offerings-pricing.test.ts +601 -0
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +67 -8
- package/templates/apps/web/lib/auth-routes.ts +36 -2
- package/templates/apps/web/lib/checkout-config.ts +9 -20
- package/templates/apps/web/lib/deck-page.ts +1 -0
- package/templates/apps/web/lib/deliverable-grant.ts +18 -0
- package/templates/apps/web/lib/in-page-magnet.ts +416 -0
- package/templates/apps/web/lib/magnet-routes.ts +42 -0
- package/templates/apps/web/lib/modules.generated.ts +9 -0
- package/templates/apps/web/lib/newsletter.actions.ts +202 -0
- package/templates/apps/web/lib/offerings-pricing.ts +326 -0
- package/templates/apps/web/lib/posting-title.ts +17 -0
- package/templates/apps/web/lib/sign-up-agreements.ts +4 -2
- package/templates/apps/web/messages/en.json +49 -15
- package/templates/apps/web/middleware.ts +12 -2
- package/templates/apps/web/security-headers.config.ts +17 -0
- package/templates/content/en/BlogList/blog.mdx +4 -71
- package/templates/content/en/BookCall/book-a-call.mdx +1 -41
- package/templates/content/en/BookCall/onsite-estimate.mdx +1 -17
- package/templates/content/en/BookCall/onsite-service.mdx +1 -17
- package/templates/content/en/BookCall/start-project.mdx +1 -17
- package/templates/content/en/ContactPage/contact.mdx +6 -63
- package/templates/content/en/HomePage/home.mdx +3 -21
- package/templates/database/CHANGELOG.md +31 -0
- package/templates/database/__tests__/in-page-magnets-migration.test.ts +161 -0
- package/templates/database/__tests__/offerings-checkout-session.db.test.ts +270 -0
- package/templates/database/__tests__/offerings-migration.test.ts +197 -0
- package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +86 -0
- package/templates/database/__tests__/offerings.db.test.ts +303 -0
- package/templates/database/__tests__/seed.test.ts +31 -1
- package/templates/database/auth/schema.prisma +4 -0
- package/templates/database/config/schema.prisma +91 -0
- package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +146 -0
- package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +77 -0
- package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +45 -0
- package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +47 -0
- package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +16 -0
- package/templates/database/package.json +1 -1
- package/templates/database/seed.ts +30 -2
- package/versions.json +35 -35
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +0 -199
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +0 -93
- package/templates/apps/web/app/[locale]/downloads/page.tsx +0 -37
- package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +0 -139
- package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +0 -93
- package/templates/apps/web/app/api/checkout/[offering]/route.ts +0 -48
- package/templates/apps/web/app/api/checkout/__tests__/route.test.ts +0 -120
- package/templates/apps/web/app/api/checkout/__tests__/success-path.test.ts +0 -86
- package/templates/apps/web/app/api/webhooks/stripe/__tests__/route.test.ts +0 -92
- package/templates/apps/web/app/api/webhooks/stripe/route.ts +0 -31
- package/templates/apps/web/lib/__tests__/checkout.test.ts +0 -243
- package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +0 -120
- package/templates/apps/web/lib/checkout.ts +0 -93
- package/templates/apps/web/lib/meeting-slugs.ts +0 -63
package/dist/surfaces.js
CHANGED
|
@@ -229,15 +229,15 @@ export const GATEABLE_SURFACES = [
|
|
|
229
229
|
content: [],
|
|
230
230
|
},
|
|
231
231
|
{
|
|
232
|
-
// The `scheduling` MODULE's presentation tier — the
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
// so there is no MDX of its own.
|
|
232
|
+
// The `scheduling` MODULE's presentation tier — the meeting index, the
|
|
233
|
+
// meeting page and the confirmation page the module OWNS (`/meet`,
|
|
234
|
+
// `/meet/:slug`, `/meet/confirmed`, one directory; renamed from the
|
|
235
|
+
// schedule/ directory by #5563), and the private index `/private`
|
|
236
|
+
// (#8843 D10), a second directory gated with it. API-backed like
|
|
237
|
+
// `flows`: every meeting fact comes from apps/api's
|
|
238
|
+
// `GET /v1/schedule/meetings`, so there is no MDX of its own.
|
|
239
239
|
id: "meet",
|
|
240
|
-
routes: [`${ROUTE_ROOT}/meet`],
|
|
240
|
+
routes: [`${ROUTE_ROOT}/meet`, `${ROUTE_ROOT}/private`],
|
|
241
241
|
content: [],
|
|
242
242
|
// `navLabelKey` names COPY, not a route — D1 R2 (#5563): renaming it would
|
|
243
243
|
// orphan an operator's customised `messages/<locale>.json` for zero
|
|
@@ -395,7 +395,9 @@ export const MODULE_SURFACES = {
|
|
|
395
395
|
// vocabulary assertion covers exactly the recognized module set.
|
|
396
396
|
workspace: [],
|
|
397
397
|
scheduling: ["meet"],
|
|
398
|
-
|
|
398
|
+
// #8848 D12 — `/downloads` is now a redirect into `/reports`, both this
|
|
399
|
+
// module's, so `--surfaces downloads` without it is refused as `flows` is.
|
|
400
|
+
"signal-collectors": ["flows", "downloads"],
|
|
399
401
|
commerce: [],
|
|
400
402
|
};
|
|
401
403
|
/** Thrown on an unrecognized surface id. Mirrors parse-args' ParseError shape. */
|
|
@@ -563,6 +565,13 @@ export const ROUTE_SINCE = {
|
|
|
563
565
|
"blog/[[...slug]]": "0.0.0",
|
|
564
566
|
careers: "0.0.0",
|
|
565
567
|
"careers/[slug]": "0.0.0",
|
|
568
|
+
// #8840 D11 — the Job application magnet's two walks, signal-collectors
|
|
569
|
+
// slice files. Genuinely new, so they attach at the fixed group's next
|
|
570
|
+
// release line, the same rule #8661 D10 applied.
|
|
571
|
+
"careers/apply": "0.44.0",
|
|
572
|
+
"careers/[slug]/apply": "0.44.0",
|
|
573
|
+
// #8849 D7 — the Free apply page, a core file of the careers surface.
|
|
574
|
+
"careers/[slug]/[action]": "0.44.0",
|
|
566
575
|
"case-studies": "0.0.0",
|
|
567
576
|
"case-studies/[slug]": "0.0.0",
|
|
568
577
|
clients: "0.0.0",
|
|
@@ -572,6 +581,9 @@ export const ROUTE_SINCE = {
|
|
|
572
581
|
"dev/purchase": "0.0.0",
|
|
573
582
|
"docs/[[...slug]]": "0.0.0",
|
|
574
583
|
downloads: "0.0.0",
|
|
584
|
+
// #8848 D12 — the per-slug redirect into `/reports/<slug>`, a
|
|
585
|
+
// signal-collectors slice file at the fixed group's next release line.
|
|
586
|
+
"downloads/[slug]": "0.44.0",
|
|
575
587
|
events: "0.0.0",
|
|
576
588
|
"events/[slug]": "0.0.0",
|
|
577
589
|
// #6721 — the feature pages, a new route pair at today's line.
|
|
@@ -751,6 +763,9 @@ export const ROUTE_SINCE = {
|
|
|
751
763
|
// new route directory, so it attaches at today's fixed-group version, the
|
|
752
764
|
// same rule applied above.
|
|
753
765
|
"[slug]/[detail]": "0.28.0",
|
|
766
|
+
// #8843 D8 — the private meeting index, a new route directory gated with
|
|
767
|
+
// `meet`, attached at today's fixed-group version by the same rule.
|
|
768
|
+
private: "0.43.0",
|
|
754
769
|
};
|
|
755
770
|
/**
|
|
756
771
|
* Surface id of the registry that owns `routeDir` (ROUTE_ROOT-relative): the
|
|
@@ -1044,9 +1059,13 @@ export const ROUTE_DEPENDENCIES = {
|
|
|
1044
1059
|
`${ROUTE_ROOT}/(authed)/waitlist/components/ForbiddenState.tsx`,
|
|
1045
1060
|
],
|
|
1046
1061
|
"(authed)/waitlist": ["apps/web/lib/server-api.ts"],
|
|
1047
|
-
// #
|
|
1048
|
-
meet
|
|
1049
|
-
|
|
1062
|
+
// #8843 D6 — the booking pages share one builder over the meetings read;
|
|
1063
|
+
// `/private` returns the index frame that lives under `meet/`.
|
|
1064
|
+
meet: ["apps/web/lib/meetings.tsx"],
|
|
1065
|
+
"meet/[slug]": ["apps/web/lib/meetings.tsx"],
|
|
1066
|
+
private: ["apps/web/lib/meetings.tsx", `${ROUTE_ROOT}/meet/meeting-index.tsx`],
|
|
1067
|
+
// #8927 D8 — /pricing maps the Offerings shown set through the mapper.
|
|
1068
|
+
pricing: ["apps/web/lib/offerings-pricing.ts"],
|
|
1050
1069
|
};
|
|
1051
1070
|
/**
|
|
1052
1071
|
* i18n message namespaces (dot-path into `apps/web/messages/<locale>.json`) a
|
|
@@ -1093,6 +1112,8 @@ export const ROUTE_MESSAGE_NAMESPACES = {
|
|
|
1093
1112
|
team: ["team"],
|
|
1094
1113
|
// #8438 D21 — the unsubscribe landing's own namespace.
|
|
1095
1114
|
unsubscribe: ["unsubscribe"],
|
|
1115
|
+
// #8927 D6 — the Offerings cards' CTA, recommendation and period phrases.
|
|
1116
|
+
pricing: ["pricing", "pricingOfferings"],
|
|
1096
1117
|
};
|
|
1097
1118
|
/** Template-relative path of the generated site-nav registry. */
|
|
1098
1119
|
export const NAV_CONFIG_PATH = "apps/web/lib/nav-config.ts";
|
package/dist/sync-routes.d.ts
CHANGED
|
@@ -78,6 +78,23 @@ export interface SyncRoutesResult {
|
|
|
78
78
|
routes: string[];
|
|
79
79
|
entry: string;
|
|
80
80
|
}>;
|
|
81
|
+
/**
|
|
82
|
+
* The retired legacy spoke checkout (#9142), on a spoke only — empty lists
|
|
83
|
+
* on a hub. See `retireLegacySpokeCheckout`.
|
|
84
|
+
*/
|
|
85
|
+
retiredCheckout: RetiredCheckoutReport;
|
|
86
|
+
}
|
|
87
|
+
/** What `retireLegacySpokeCheckout` found, and did when `apply` was set. */
|
|
88
|
+
export interface RetiredCheckoutReport {
|
|
89
|
+
/** Files deleted (without `apply`: to delete), scaffold-relative, sorted. */
|
|
90
|
+
retired: string[];
|
|
91
|
+
/** Retired files left in place, with why — the site deletes them by hand. Sorted by path. */
|
|
92
|
+
kept: Array<{
|
|
93
|
+
path: string;
|
|
94
|
+
reason: string;
|
|
95
|
+
}>;
|
|
96
|
+
/** Generated files rewritten (without `apply`: to rewrite) — the billing action. */
|
|
97
|
+
rewritten: string[];
|
|
81
98
|
}
|
|
82
99
|
/** One `NO_STRUCTURED_DATA_ROUTES` element: its source text, dedented, and the routes it exempts. */
|
|
83
100
|
interface StructuredDataExemption {
|
|
@@ -102,6 +119,26 @@ export declare function parseStructuredDataExemptions(source: string): Structure
|
|
|
102
119
|
* the registry recognizes (`surfaceForRouteDir`).
|
|
103
120
|
*/
|
|
104
121
|
export declare function listTemplateRouteDirs(templatesDir: string): string[];
|
|
122
|
+
/**
|
|
123
|
+
* Retire the legacy env-key spoke checkout from a spoke (#9142): its buy
|
|
124
|
+
* route, Stripe webhook route, `lib/checkout.ts`, their tests
|
|
125
|
+
* (`RETIRED_SPOKE_CHECKOUT_PATHS`) and the generated checkout e2e workflow.
|
|
126
|
+
*
|
|
127
|
+
* - A copied file is deleted only when the template record lists it and its
|
|
128
|
+
* bytes still hash to the recorded copy — the rule `create-ailk update`
|
|
129
|
+
* uses for a file the template dropped; its record row goes with it. An
|
|
130
|
+
* edited file, or one the record does not list, is reported in `kept`.
|
|
131
|
+
* - The workflow, never recorded, is deleted only when its first line is
|
|
132
|
+
* still create-ailk's generated marker.
|
|
133
|
+
* - The billing action (a spoke that signs in through its hub) imported
|
|
134
|
+
* `lib/checkout.ts`; when its first line is still the generated marker and
|
|
135
|
+
* it differs from the current render, it is rewritten to `BILLING_ACTION`.
|
|
136
|
+
* An edited one that still imports `lib/checkout` is reported in `kept`.
|
|
137
|
+
*
|
|
138
|
+
* Without `apply` nothing is written: the lists say what `--apply` would do.
|
|
139
|
+
* Directories the deletes leave empty are removed, up to `RETIRE_STOP_DIRS`.
|
|
140
|
+
*/
|
|
141
|
+
export declare function retireLegacySpokeCheckout(targetAbs: string, apply: boolean): RetiredCheckoutReport;
|
|
105
142
|
/**
|
|
106
143
|
* Compare an already-scaffolded repo's route tree with the template's and,
|
|
107
144
|
* when `apply` is set, copy in the route dirs it is missing.
|
|
@@ -120,7 +157,7 @@ export interface SyncRoutesArgs {
|
|
|
120
157
|
apply: boolean;
|
|
121
158
|
help: boolean;
|
|
122
159
|
}
|
|
123
|
-
export declare const SYNC_ROUTES_HELP = "create-ailk sync-routes \u2014 copy template routes an existing site is missing.\n\nUsage:\n create-ailk sync-routes [<target-dir>] [--apply]\n\nArguments:\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --apply Copy the missing route directories into the target.\n Without it the command only reports: exit 1 when a\n route is missing, 0 when in sync.\n --help, -h Print this message.\n\nChecks every core route plus the routes of each surface the site carries; a\nsurface gated off at scaffold time is skipped, not drift. A route the site has\nchanged locally is reported and never overwritten. Nothing is
|
|
160
|
+
export declare const SYNC_ROUTES_HELP = "create-ailk sync-routes \u2014 copy template routes an existing site is missing.\n\nUsage:\n create-ailk sync-routes [<target-dir>] [--apply]\n\nArguments:\n <target-dir> An already-scaffolded repo (contains\n architecture.yaml). Defaults to the current dir.\n\nOptions:\n --apply Copy the missing route directories into the target.\n Without it the command only reports: exit 1 when a\n route is missing, 0 when in sync.\n --help, -h Print this message.\n\nChecks every core route plus the routes of each surface the site carries; a\nsurface gated off at scaffold time is skipped, not drift. A route the site has\nchanged locally is reported and never overwritten. Nothing is deleted except,\non a spoke, the retired legacy checkout's files that still match create-ailk's\ncopy: --apply removes them and rewrites the generated billing action (#9142).\n";
|
|
124
161
|
/**
|
|
125
162
|
* Parse the argv AFTER the `sync-routes` word. Strict `node:util` parseArgs,
|
|
126
163
|
* like `parseCliArgs`; at most one positional.
|
package/dist/sync-routes.js
CHANGED
|
@@ -19,26 +19,33 @@
|
|
|
19
19
|
* - Expected bytes are what `copyTemplate` would write. The copier's
|
|
20
20
|
* text/binary + marker rules are NOT re-implemented here: the template's
|
|
21
21
|
* route root is copied once into a scratch dir and compared from there.
|
|
22
|
-
* - Never overwrite, never delete
|
|
23
|
-
* reported as modified and left alone; `--apply`
|
|
24
|
-
* that do not exist, so a second run is a no-op.
|
|
25
|
-
* its structured-data test, a route `--apply`
|
|
26
|
-
* exempts there is reported with the exact
|
|
27
|
-
* entry to add — the test itself is never
|
|
22
|
+
* - Never overwrite, never delete — with one named exception. A route dir
|
|
23
|
+
* the site has changed is reported as modified and left alone; `--apply`
|
|
24
|
+
* only creates directories that do not exist, so a second run is a no-op.
|
|
25
|
+
* When the site has edited its structured-data test, a route `--apply`
|
|
26
|
+
* adds that the template exempts there is reported with the exact
|
|
27
|
+
* `NO_STRUCTURED_DATA_ROUTES` entry to add — the test itself is never
|
|
28
|
+
* written (#8704). The exception is the retired legacy spoke checkout
|
|
29
|
+
* (#9142): on a spoke, `--apply` deletes its files that are still
|
|
30
|
+
* byte-identical to the template record and rewrites the generated
|
|
31
|
+
* billing action off them (`retireLegacySpokeCheckout`); an edited or
|
|
32
|
+
* unrecorded file is reported and left alone.
|
|
28
33
|
*
|
|
29
34
|
* Pure module: no `import.meta.url`, so jest can import it directly. The
|
|
30
35
|
* package's own `templates/` dir is supplied by programmatic.ts.
|
|
31
36
|
*/
|
|
32
|
-
import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
37
|
+
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
33
38
|
import { tmpdir } from "node:os";
|
|
34
39
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
35
40
|
import { parseArgs } from "node:util";
|
|
36
41
|
import { copyTemplate } from "./copy.js";
|
|
42
|
+
import { SPOKE_BILLING_ACTION_PATH } from "./derive-architecture.js";
|
|
37
43
|
import { appendEnvRows } from "./lib/declared-env.js";
|
|
38
44
|
import { ENV_CATALOG } from "./lib/env-catalog.js";
|
|
45
|
+
import { BILLING_ACTION, BILLING_ACTION_MARKER, RETIRED_CHECKOUT_E2E_MARKER, RETIRED_CHECKOUT_E2E_WORKFLOW_PATH, RETIRED_SPOKE_CHECKOUT_PATHS, } from "./spoke-checkout.js";
|
|
39
46
|
import { substituteMarkers } from "./substitute.js";
|
|
40
47
|
import { GATEABLE_SURFACES, NON_ROUTE_DIRS, ROUTE_DEPENDENCIES, ROUTE_MESSAGE_NAMESPACES, ROUTE_SINCE, surfaceForRouteDir, } from "./surfaces.js";
|
|
41
|
-
import { TEMPLATE_RECORD_PATH, parseTemplateRecord, sha256Hex } from "./template-record.js";
|
|
48
|
+
import { TEMPLATE_RECORD_PATH, parseTemplateRecord, serializeTemplateRecord, sha256Hex, } from "./template-record.js";
|
|
42
49
|
import { SPOKE_SEAM_FILES, isSpokeExcluded, readSpokeShape, } from "./topology.js";
|
|
43
50
|
/** Template-relative prefix every `apps/web` route directory sits under. */
|
|
44
51
|
const ROUTE_ROOT = "apps/web/app/[locale]";
|
|
@@ -50,11 +57,18 @@ export const STRUCTURED_DATA_TEST_PATH = "apps/web/lib/__tests__/structured-data
|
|
|
50
57
|
* `projects/apply` (#5048) is signal-collectors' own owned file
|
|
51
58
|
* (`ListingApplicationClient.tsx`, D-48) — its module bundle restores it
|
|
52
59
|
* whenever signal-collectors is selected, independent of the unrelated
|
|
53
|
-
* "projects" content surface's own selection.
|
|
54
|
-
* `
|
|
60
|
+
* "projects" content surface's own selection. `careers/apply` and
|
|
61
|
+
* `careers/[slug]` (#8840 D13) are the same case: signal-collectors' bundle
|
|
62
|
+
* lands the Job application walks (`careers/apply/page.tsx`,
|
|
63
|
+
* `careers/[slug]/apply/**`) whenever the module is selected, so a site that
|
|
64
|
+
* turned the careers pages off must not read as carrying "careers" — a site
|
|
65
|
+
* that carries them keeps `careers/page.tsx`, which still counts. See the doc
|
|
66
|
+
* comment on `syncRoutes`'s `carried` computation.
|
|
55
67
|
*/
|
|
56
68
|
const NESTED_FOREIGN_MODULE_ENTRIES = new Set([
|
|
57
69
|
"projects/apply",
|
|
70
|
+
"careers/apply",
|
|
71
|
+
"careers/[slug]",
|
|
58
72
|
]);
|
|
59
73
|
/**
|
|
60
74
|
* The elements of `source`'s `NO_STRUCTURED_DATA_ROUTES` array literal, by a
|
|
@@ -229,6 +243,141 @@ function isModified(expectedDir, targetDir, skip = () => false) {
|
|
|
229
243
|
}
|
|
230
244
|
return false;
|
|
231
245
|
}
|
|
246
|
+
/** Directories a retirement never removes, even when it leaves them empty. */
|
|
247
|
+
const RETIRE_STOP_DIRS = new Set([
|
|
248
|
+
"apps/web/app/api",
|
|
249
|
+
"apps/web/lib",
|
|
250
|
+
"apps/web/lib/__tests__",
|
|
251
|
+
".github/workflows",
|
|
252
|
+
]);
|
|
253
|
+
/** Every regular file at or under `rel` in `targetAbs`, `/`-separated. A symlink is skipped, never followed. */
|
|
254
|
+
function regularFilesUnder(targetAbs, rel) {
|
|
255
|
+
const abs = join(targetAbs, ...rel.split("/"));
|
|
256
|
+
let stat;
|
|
257
|
+
try {
|
|
258
|
+
stat = lstatSync(abs);
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return [];
|
|
262
|
+
}
|
|
263
|
+
if (stat.isFile())
|
|
264
|
+
return [rel];
|
|
265
|
+
if (!stat.isDirectory())
|
|
266
|
+
return [];
|
|
267
|
+
return readdirSync(abs)
|
|
268
|
+
.sort()
|
|
269
|
+
.flatMap((name) => regularFilesUnder(targetAbs, `${rel}/${name}`));
|
|
270
|
+
}
|
|
271
|
+
/** The first line of a text file. */
|
|
272
|
+
function firstLine(text) {
|
|
273
|
+
const eol = text.indexOf("\n");
|
|
274
|
+
return eol === -1 ? text : text.slice(0, eol);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Retire the legacy env-key spoke checkout from a spoke (#9142): its buy
|
|
278
|
+
* route, Stripe webhook route, `lib/checkout.ts`, their tests
|
|
279
|
+
* (`RETIRED_SPOKE_CHECKOUT_PATHS`) and the generated checkout e2e workflow.
|
|
280
|
+
*
|
|
281
|
+
* - A copied file is deleted only when the template record lists it and its
|
|
282
|
+
* bytes still hash to the recorded copy — the rule `create-ailk update`
|
|
283
|
+
* uses for a file the template dropped; its record row goes with it. An
|
|
284
|
+
* edited file, or one the record does not list, is reported in `kept`.
|
|
285
|
+
* - The workflow, never recorded, is deleted only when its first line is
|
|
286
|
+
* still create-ailk's generated marker.
|
|
287
|
+
* - The billing action (a spoke that signs in through its hub) imported
|
|
288
|
+
* `lib/checkout.ts`; when its first line is still the generated marker and
|
|
289
|
+
* it differs from the current render, it is rewritten to `BILLING_ACTION`.
|
|
290
|
+
* An edited one that still imports `lib/checkout` is reported in `kept`.
|
|
291
|
+
*
|
|
292
|
+
* Without `apply` nothing is written: the lists say what `--apply` would do.
|
|
293
|
+
* Directories the deletes leave empty are removed, up to `RETIRE_STOP_DIRS`.
|
|
294
|
+
*/
|
|
295
|
+
export function retireLegacySpokeCheckout(targetAbs, apply) {
|
|
296
|
+
const retired = [];
|
|
297
|
+
const kept = [];
|
|
298
|
+
const rewritten = [];
|
|
299
|
+
const recordPath = join(targetAbs, TEMPLATE_RECORD_PATH);
|
|
300
|
+
let record;
|
|
301
|
+
if (existsSync(recordPath)) {
|
|
302
|
+
try {
|
|
303
|
+
record = parseTemplateRecord(readFileSync(recordPath, "utf8"));
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
record = undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
for (const path of RETIRED_SPOKE_CHECKOUT_PATHS.flatMap((rel) => regularFilesUnder(targetAbs, rel))) {
|
|
310
|
+
const recorded = record?.files[path]?.sha256;
|
|
311
|
+
if (recorded === undefined) {
|
|
312
|
+
kept.push({
|
|
313
|
+
path,
|
|
314
|
+
reason: record === undefined
|
|
315
|
+
? "no readable template record, so an edit cannot be told apart"
|
|
316
|
+
: "not in the template record",
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
else if (sha256Hex(readFileSync(join(targetAbs, ...path.split("/")))) !== recorded) {
|
|
320
|
+
kept.push({ path, reason: "edited here" });
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
retired.push(path);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const workflow = regularFilesUnder(targetAbs, RETIRED_CHECKOUT_E2E_WORKFLOW_PATH);
|
|
327
|
+
for (const path of workflow) {
|
|
328
|
+
const text = readFileSync(join(targetAbs, ...path.split("/")), "utf8");
|
|
329
|
+
if (firstLine(text) === RETIRED_CHECKOUT_E2E_MARKER)
|
|
330
|
+
retired.push(path);
|
|
331
|
+
else
|
|
332
|
+
kept.push({ path, reason: "edited here" });
|
|
333
|
+
}
|
|
334
|
+
const billingAbs = join(targetAbs, ...SPOKE_BILLING_ACTION_PATH.split("/"));
|
|
335
|
+
if (regularFilesUnder(targetAbs, SPOKE_BILLING_ACTION_PATH).length === 1) {
|
|
336
|
+
const text = readFileSync(billingAbs, "utf8");
|
|
337
|
+
if (text !== BILLING_ACTION) {
|
|
338
|
+
if (firstLine(text) === BILLING_ACTION_MARKER) {
|
|
339
|
+
rewritten.push(SPOKE_BILLING_ACTION_PATH);
|
|
340
|
+
}
|
|
341
|
+
else if (/lib\/checkout["'`]/.test(text)) {
|
|
342
|
+
kept.push({
|
|
343
|
+
path: SPOKE_BILLING_ACTION_PATH,
|
|
344
|
+
reason: "edited here, and it imports the retired lib/checkout",
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (apply) {
|
|
350
|
+
for (const path of retired) {
|
|
351
|
+
const abs = resolve(join(targetAbs, ...path.split("/")));
|
|
352
|
+
if (!abs.startsWith(targetAbs + sep)) {
|
|
353
|
+
throw new Error(`refusing to delete outside target dir: ${abs}`);
|
|
354
|
+
}
|
|
355
|
+
rmSync(abs);
|
|
356
|
+
let dir = dirname(path);
|
|
357
|
+
while (dir !== "." && !RETIRE_STOP_DIRS.has(dir)) {
|
|
358
|
+
const dirAbs = join(targetAbs, ...dir.split("/"));
|
|
359
|
+
if (!existsSync(dirAbs) || readdirSync(dirAbs).length > 0)
|
|
360
|
+
break;
|
|
361
|
+
rmdirSync(dirAbs);
|
|
362
|
+
dir = dirname(dir);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (rewritten.length > 0)
|
|
366
|
+
writeFileSync(billingAbs, BILLING_ACTION);
|
|
367
|
+
if (record !== undefined && retired.some((path) => path in record.files)) {
|
|
368
|
+
const files = { ...record.files };
|
|
369
|
+
for (const path of retired)
|
|
370
|
+
delete files[path];
|
|
371
|
+
writeFileSync(recordPath, serializeTemplateRecord({ ...record, files }));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
const byPath = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
375
|
+
return {
|
|
376
|
+
retired: retired.sort(byPath),
|
|
377
|
+
kept: kept.sort((a, b) => byPath(a.path, b.path)),
|
|
378
|
+
rewritten,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
232
381
|
/**
|
|
233
382
|
* Compare an already-scaffolded repo's route tree with the template's and,
|
|
234
383
|
* when `apply` is set, copy in the route dirs it is missing.
|
|
@@ -392,6 +541,9 @@ export function syncRoutes(opts) {
|
|
|
392
541
|
missingMessageNamespaces,
|
|
393
542
|
skippedSurfaces,
|
|
394
543
|
structuredDataEntries: structuredDataEntriesFor(targetAbs, opts.templatesDir, applied),
|
|
544
|
+
retiredCheckout: spoke !== undefined
|
|
545
|
+
? retireLegacySpokeCheckout(targetAbs, opts.apply === true)
|
|
546
|
+
: { retired: [], kept: [], rewritten: [] },
|
|
395
547
|
};
|
|
396
548
|
}
|
|
397
549
|
/**
|
|
@@ -478,6 +630,25 @@ export function formatSyncRoutesReport(result, apply) {
|
|
|
478
630
|
lines.push(...entry.split("\n").map((line) => ` ${line}`));
|
|
479
631
|
}
|
|
480
632
|
}
|
|
633
|
+
// #9142 — the retired legacy spoke checkout, named so the operator sees
|
|
634
|
+
// exactly what left and what stays for them to delete.
|
|
635
|
+
const retiredCheckout = result.retiredCheckout;
|
|
636
|
+
if (retiredCheckout.retired.length > 0) {
|
|
637
|
+
lines.push(apply
|
|
638
|
+
? `[create-ailk] Removed ${retiredCheckout.retired.length} file(s) of the retired legacy spoke checkout (a spoke sells through its hub's Offerings buy route):`
|
|
639
|
+
: `[create-ailk] ${retiredCheckout.retired.length} file(s) of the retired legacy spoke checkout to remove with --apply (a spoke sells through its hub's Offerings buy route):`);
|
|
640
|
+
lines.push(...retiredCheckout.retired.map((path) => ` ${path}`));
|
|
641
|
+
}
|
|
642
|
+
if (retiredCheckout.rewritten.length > 0) {
|
|
643
|
+
lines.push(apply
|
|
644
|
+
? "[create-ailk] Rewrote the generated billing action off the retired lib/checkout:"
|
|
645
|
+
: "[create-ailk] The generated billing action imports the retired lib/checkout; --apply rewrites it:");
|
|
646
|
+
lines.push(...retiredCheckout.rewritten.map((path) => ` ${path}`));
|
|
647
|
+
}
|
|
648
|
+
if (retiredCheckout.kept.length > 0) {
|
|
649
|
+
lines.push(`[create-ailk] ${retiredCheckout.kept.length} file(s) of the retired legacy spoke checkout left in place — delete or rewrite by hand:`);
|
|
650
|
+
lines.push(...retiredCheckout.kept.map(({ path, reason }) => ` ${path} (${reason})`));
|
|
651
|
+
}
|
|
481
652
|
if (result.missing.length > 0 && !apply) {
|
|
482
653
|
lines.push("Run `create-ailk sync-routes <target> --apply` to copy the missing routes.");
|
|
483
654
|
}
|
|
@@ -500,7 +671,9 @@ Options:
|
|
|
500
671
|
|
|
501
672
|
Checks every core route plus the routes of each surface the site carries; a
|
|
502
673
|
surface gated off at scaffold time is skipped, not drift. A route the site has
|
|
503
|
-
changed locally is reported and never overwritten. Nothing is
|
|
674
|
+
changed locally is reported and never overwritten. Nothing is deleted except,
|
|
675
|
+
on a spoke, the retired legacy checkout's files that still match create-ailk's
|
|
676
|
+
copy: --apply removes them and rewrites the generated billing action (#9142).
|
|
504
677
|
`;
|
|
505
678
|
/**
|
|
506
679
|
* Parse the argv AFTER the `sync-routes` word. Strict `node:util` parseArgs,
|
|
@@ -3,7 +3,7 @@ export declare const TEMPLATE_RECORD_PATH = ".ailk-template-files.json";
|
|
|
3
3
|
/**
|
|
4
4
|
* The app paths a generator rewrites after `copyTemplate` lands its copy
|
|
5
5
|
* (§1): the nav, the site chrome, the site fonts, the paid-sections
|
|
6
|
-
* registry, the four spoke seams, and a commerce spoke's checkout config,
|
|
6
|
+
* registry and its module-presence flags (#8843 D10), the four spoke seams, and a commerce spoke's checkout config,
|
|
7
7
|
* which the checkout writer stamps and the site owns from then on (#8748
|
|
8
8
|
* D2). Composed from each writer's own exported path constant, so a renamed
|
|
9
9
|
* constant carries its path along here too (#8522 D2).
|
package/dist/template-record.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { createHash } from "node:crypto";
|
|
19
19
|
import { existsSync, readFileSync } from "node:fs";
|
|
20
20
|
import { join } from "node:path";
|
|
21
|
-
import { PAID_SECTIONS_PATH } from "./paid-sections.js";
|
|
21
|
+
import { MODULE_FLAGS_PATH, PAID_SECTIONS_PATH } from "./paid-sections.js";
|
|
22
22
|
import { SITE_CHROME_PATH } from "./site-chrome.js";
|
|
23
23
|
import { SITE_FONTS_PATH } from "./site-fonts.js";
|
|
24
24
|
import { SPOKE_CHECKOUT_CONFIG_PATH } from "./spoke-checkout.js";
|
|
@@ -29,7 +29,7 @@ export const TEMPLATE_RECORD_PATH = ".ailk-template-files.json";
|
|
|
29
29
|
/**
|
|
30
30
|
* The app paths a generator rewrites after `copyTemplate` lands its copy
|
|
31
31
|
* (§1): the nav, the site chrome, the site fonts, the paid-sections
|
|
32
|
-
* registry, the four spoke seams, and a commerce spoke's checkout config,
|
|
32
|
+
* registry and its module-presence flags (#8843 D10), the four spoke seams, and a commerce spoke's checkout config,
|
|
33
33
|
* which the checkout writer stamps and the site owns from then on (#8748
|
|
34
34
|
* D2). Composed from each writer's own exported path constant, so a renamed
|
|
35
35
|
* constant carries its path along here too (#8522 D2).
|
|
@@ -39,6 +39,7 @@ export const REGENERATED_APP_PATHS = [
|
|
|
39
39
|
SITE_CHROME_PATH,
|
|
40
40
|
SITE_FONTS_PATH,
|
|
41
41
|
PAID_SECTIONS_PATH,
|
|
42
|
+
MODULE_FLAGS_PATH,
|
|
42
43
|
...SPOKE_SEAM_FILES,
|
|
43
44
|
SPOKE_CHECKOUT_CONFIG_PATH,
|
|
44
45
|
];
|
package/dist/update.js
CHANGED
|
@@ -26,6 +26,7 @@ import { AddModuleRefusedError, readArchitectureHeader } from "./add-module-core
|
|
|
26
26
|
import { buildScaffoldMarkers, isExcluded, isTextFile, renderTemplateFile, templateDestination } from "./copy.js";
|
|
27
27
|
import { fetchTemplateSnapshot } from "./lib/fetch-template-snapshot.js";
|
|
28
28
|
import { mergeThreeWay } from "./lib/merge-three-way.js";
|
|
29
|
+
import { MODULE_FLAGS_PATH, writeModuleFlags } from "./paid-sections.js";
|
|
29
30
|
import { ParseError } from "./parse-args.js";
|
|
30
31
|
import { SITE_ROSTER_PATH } from "./site-roster.js";
|
|
31
32
|
import { SPOKE_CHECKOUT_TEMPLATE_PATHS } from "./spoke-checkout.js";
|
|
@@ -514,6 +515,15 @@ export async function updateSite(opts) {
|
|
|
514
515
|
if (recordChanged) {
|
|
515
516
|
writeFileSync(recordPath, serializeTemplateRecord({ schema: 1, projectName: record.projectName, files: nextFiles }));
|
|
516
517
|
}
|
|
518
|
+
// #8843 D10 — the module-presence flags are generated, never copied
|
|
519
|
+
// (REGENERATED_APP_PATHS): render them from this site's own
|
|
520
|
+
// apps/web/package.json on every run, so a site updated onto a layout
|
|
521
|
+
// that imports them has them before it builds. Not recorded.
|
|
522
|
+
const flags = writeModuleFlags(targetDir);
|
|
523
|
+
if (flags === "added")
|
|
524
|
+
moved.added.push(MODULE_FLAGS_PATH);
|
|
525
|
+
else if (flags === "updated")
|
|
526
|
+
moved.updated.push(MODULE_FLAGS_PATH);
|
|
517
527
|
return {
|
|
518
528
|
targetDir,
|
|
519
529
|
version,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-ailk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Scaffolder for AI Launch Kit — `pnpm create ailk@latest <dir>` produces a starter repo consuming @working-theory/* from npm (per ADR 0007).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"tar": "^7.5.21"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@working-theory/schema": "0.
|
|
32
|
-
"@working-theory/templates": "0.
|
|
31
|
+
"@working-theory/schema": "0.44.0",
|
|
32
|
+
"@working-theory/templates": "0.44.0"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: "NewsletterSignup"
|
|
3
3
|
slug: "newsletter"
|
|
4
|
-
title: "
|
|
4
|
+
title: "Get the newsletter"
|
|
5
5
|
description: "{One sentence on what this newsletter covers and who it is for}"
|
|
6
6
|
schema:
|
|
7
7
|
mainEntity:
|
|
@@ -11,57 +11,12 @@ schema:
|
|
|
11
11
|
priceCurrency: "USD"
|
|
12
12
|
sections:
|
|
13
13
|
[
|
|
14
|
-
{
|
|
15
|
-
"id": "hero",
|
|
16
|
-
"type": "hero",
|
|
17
|
-
"data":
|
|
18
|
-
{
|
|
19
|
-
"eyebrow": "Newsletter",
|
|
20
|
-
"headline": "{Newsletter: what subscribers get and how often}",
|
|
21
|
-
"subheadline": "{One sentence on what this newsletter covers and who it is for}",
|
|
22
|
-
"primaryCta": { "label": "Subscribe", "href": "#signup" },
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
14
|
{
|
|
26
15
|
"id": "signup",
|
|
27
|
-
"type": "
|
|
28
|
-
"data":
|
|
29
|
-
{
|
|
30
|
-
"headline": "Subscribe",
|
|
31
|
-
"description": "{One sentence on what lands in the inbox}",
|
|
32
|
-
"action": "/v1/leads/subscribe",
|
|
33
|
-
"source": "newsletter",
|
|
34
|
-
"placeholder": "you@example.com",
|
|
35
|
-
"submitLabel": "Subscribe",
|
|
36
|
-
"consentText": "{One line on how you use the address, and that readers can unsubscribe any time}",
|
|
37
|
-
"pattern": "none",
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"id": "faq",
|
|
42
|
-
"type": "faq",
|
|
43
|
-
"data":
|
|
44
|
-
{
|
|
45
|
-
"headline": "FAQs",
|
|
46
|
-
"presentation": "expanded",
|
|
47
|
-
"items":
|
|
48
|
-
[
|
|
49
|
-
{
|
|
50
|
-
"question": "{How often will I hear from you?}",
|
|
51
|
-
"answer": "{Answer in one or two plain sentences}",
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"question": "{What will I get?}",
|
|
55
|
-
"answer": "{Answer in one or two plain sentences}",
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"question": "{Can I unsubscribe?}",
|
|
59
|
-
"answer": "{Answer in one or two plain sentences}",
|
|
60
|
-
},
|
|
61
|
-
],
|
|
62
|
-
},
|
|
16
|
+
"type": "contact-form",
|
|
17
|
+
"data": { "variant": "column", "fields": [] },
|
|
63
18
|
},
|
|
64
19
|
]
|
|
65
20
|
---
|
|
66
21
|
|
|
67
|
-
{/* Rendered from frontmatter `sections[]` by the /newsletter route. The
|
|
22
|
+
{/* Rendered from frontmatter `sections[]` by the /newsletter route. The page's one signup surface is the workspace's Newsletter magnet: its heading, sentence, field, consent, button and ending all come from the magnet, mounted by the route in this section's slot. To change the signup, change the magnet in Admin → Magnets. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Replace every {brace} with your own words before you launch. */}
|
|
@@ -67,27 +67,9 @@ sections:
|
|
|
67
67
|
"headlineStyle": "label",
|
|
68
68
|
"logos":
|
|
69
69
|
[
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"darkSrc": "/logos/salessmyth-light.svg",
|
|
74
|
-
"width": 1118,
|
|
75
|
-
"height": 147,
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
"name": "AI Launch Kit",
|
|
79
|
-
"src": "/logos/ai-launch-kit.svg",
|
|
80
|
-
"darkSrc": "/logos/ai-launch-kit-light.svg",
|
|
81
|
-
"width": 1248,
|
|
82
|
-
"height": 144,
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"name": "Atomic Agent",
|
|
86
|
-
"src": "/logos/atomic-agent.svg",
|
|
87
|
-
"darkSrc": "/logos/atomic-agent-light.svg",
|
|
88
|
-
"width": 1320,
|
|
89
|
-
"height": 148,
|
|
90
|
-
},
|
|
70
|
+
{ "name": "Placeholder logo", "src": "/logomark.svg" },
|
|
71
|
+
{ "name": "Placeholder logo", "src": "/logomark.svg" },
|
|
72
|
+
{ "name": "Placeholder logo", "src": "/logomark.svg" },
|
|
91
73
|
],
|
|
92
74
|
"layout": "inline",
|
|
93
75
|
"treatment": "monochrome",
|