create-ailk 0.17.0 → 0.19.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/LICENSE +6 -5
- package/NOTICE +2 -0
- package/dist/add-module.js +4 -1
- package/dist/category-profile.d.ts +10 -0
- package/dist/category-profile.js +21 -0
- package/dist/derive-architecture.d.ts +5 -1
- package/dist/derive-architecture.js +8 -3
- package/dist/lib/env-catalog.js +5 -9
- package/dist/lib/license-key-files.d.ts +6 -3
- package/dist/lib/license-key-files.js +8 -2
- package/dist/lib/scaffold-render-sweep.d.ts +9 -0
- package/dist/lib/scaffold-render-sweep.js +24 -3
- package/dist/license-set.d.ts +1 -1
- package/dist/license-set.js +13 -8
- package/dist/module-architecture.js +119 -0
- package/dist/programmatic.js +3 -0
- package/dist/spoke-checkout.d.ts +11 -3
- package/dist/spoke-checkout.js +62 -12
- package/dist/starter-grid.d.ts +1 -1
- package/dist/surfaces.js +140 -1
- package/dist/template-manifest.d.ts +4 -3
- package/dist/topology.d.ts +15 -2
- package/dist/topology.js +83 -4
- package/package.json +5 -4
- package/templates/.env.example +3 -3
- package/templates/.github/workflows/ci.yml +5 -0
- package/templates/apps/api/CLAUDE.md +25 -7
- package/templates/apps/api/LICENSE +6 -5
- package/templates/apps/api/NOTICE +2 -0
- package/templates/apps/api/jest.config.cjs +4 -29
- package/templates/apps/api/package.json +1 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +9 -0
- package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +38 -0
- package/templates/apps/api/src/lib/deliverable-asset-store.ts +5 -4
- package/templates/apps/api/src/lib/stripe.ts +81 -0
- package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +266 -39
- package/templates/apps/api/src/middleware/auth.ts +206 -46
- package/templates/apps/api/src/routes/leads/index.ts +4 -0
- package/templates/apps/api/src/server.ts +107 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +58 -0
- package/templates/apps/api/src/services/lead-routing.ts +30 -2
- package/templates/apps/api/vercel.json +2 -2
- package/templates/apps/mcp/.env.example +10 -0
- package/templates/apps/mcp/CLAUDE.md +58 -7
- package/templates/apps/mcp/LICENSE +6 -5
- package/templates/apps/mcp/NOTICE +2 -0
- package/templates/apps/mcp/__tests__/abuse/guard.test.ts +198 -0
- package/templates/apps/mcp/__tests__/app-entry.test.ts +325 -0
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +15 -3
- package/templates/apps/mcp/__tests__/boot.test.ts +280 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +291 -2
- package/templates/apps/mcp/__tests__/index.test.ts +86 -47
- package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +5 -6
- package/templates/apps/mcp/__tests__/lib/content-root.test.ts +93 -0
- package/templates/apps/mcp/__tests__/request_callback.test.ts +69 -7
- package/templates/apps/mcp/__tests__/server.test.ts +63 -6
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +69 -8
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +69 -7
- package/templates/apps/mcp/jest.config.cjs +3 -44
- package/templates/apps/mcp/src/abuse/index.ts +117 -21
- package/templates/apps/mcp/src/app.ts +32 -0
- package/templates/apps/mcp/src/boot.ts +167 -0
- package/templates/apps/mcp/src/http-transport.ts +132 -88
- package/templates/apps/mcp/src/index.ts +19 -126
- package/templates/apps/mcp/src/lib/audit-single-page.ts +7 -6
- package/templates/apps/mcp/src/lib/content-adapter.ts +34 -5
- package/templates/apps/mcp/src/lib/topology.generated.ts +3 -0
- package/templates/apps/mcp/src/request-context.ts +52 -0
- package/templates/apps/mcp/src/server.ts +10 -2
- package/templates/apps/mcp/src/serverless-app.ts +88 -0
- package/templates/apps/mcp/src/tools/capture_lead.ts +9 -1
- package/templates/apps/mcp/src/tools/get_business_hours.ts +6 -5
- package/templates/apps/mcp/src/tools/get_faq.ts +6 -5
- package/templates/apps/mcp/src/tools/get_locations.ts +6 -5
- package/templates/apps/mcp/src/tools/get_offerings.ts +6 -5
- package/templates/apps/mcp/src/tools/get_pricing.ts +6 -5
- package/templates/apps/mcp/src/tools/get_site_info.ts +6 -5
- package/templates/apps/mcp/src/tools/list_pages.ts +8 -7
- package/templates/apps/mcp/src/tools/read_content.ts +7 -7
- package/templates/apps/mcp/src/tools/request_callback.ts +9 -1
- package/templates/apps/mcp/src/tools/search_content.ts +6 -5
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +9 -1
- package/templates/apps/mcp/tsconfig.json +2 -0
- package/templates/apps/web/LICENSE +6 -5
- package/templates/apps/web/NOTICE +2 -0
- package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +3 -3
- package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +16 -4
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +3 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/billing.test.tsx +288 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/general.test.tsx +568 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/hub-mode.test.tsx +272 -42
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/item.test.tsx +11 -13
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +115 -16
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/new-menu.test.tsx +305 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/new-popups.test.tsx +82 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/notifications.test.tsx +126 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +163 -72
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/popups.test.tsx +451 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/security.test.tsx +139 -0
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/settings.test.tsx +20 -390
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/support.test.tsx +16 -11
- package/templates/apps/web/app/[locale]/(authed)/account/account-data.ts +1 -1
- package/templates/apps/web/app/[locale]/(authed)/account/account-frame.tsx +114 -50
- package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +25 -32
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/[pieceId]/page.tsx +253 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/[pieceId]/review-form.tsx +145 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/[pieceId]/versions/[version]/file/route.ts +100 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/__tests__/file-route.test.ts +179 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/__tests__/page.test.tsx +514 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/__tests__/review.test.tsx +288 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/artifact-actions.ts +123 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/artifact-data.ts +82 -0
- package/templates/apps/web/app/[locale]/(authed)/account/artifacts/page.tsx +177 -0
- package/templates/apps/web/app/[locale]/(authed)/account/billing/page.tsx +172 -0
- package/templates/apps/web/app/[locale]/(authed)/account/billing-source.ts +147 -0
- package/templates/apps/web/app/[locale]/(authed)/account/components/request-quote.tsx +229 -0
- package/templates/apps/web/app/[locale]/(authed)/account/components/schedule-service.tsx +276 -0
- package/templates/apps/web/app/[locale]/(authed)/account/components/send-message.tsx +128 -0
- package/templates/apps/web/app/[locale]/(authed)/account/general/billing-anchor.tsx +27 -0
- package/templates/apps/web/app/[locale]/(authed)/account/general/deletion-request.tsx +132 -0
- package/templates/apps/web/app/[locale]/(authed)/account/general/page.tsx +131 -0
- package/templates/apps/web/app/[locale]/(authed)/account/general/profile-form.tsx +104 -0
- package/templates/apps/web/app/[locale]/(authed)/account/general/profile-source.ts +73 -0
- package/templates/apps/web/app/[locale]/(authed)/account/inbox/message/[id]/file/__tests__/route.test.ts +18 -8
- package/templates/apps/web/app/[locale]/(authed)/account/inbox/message/[id]/file/route.ts +4 -6
- package/templates/apps/web/app/[locale]/(authed)/account/layout.tsx +4 -1
- package/templates/apps/web/app/[locale]/(authed)/account/new-actions.ts +219 -0
- package/templates/apps/web/app/[locale]/(authed)/account/new-menu.tsx +340 -0
- package/templates/apps/web/app/[locale]/(authed)/account/new-popups.tsx +107 -0
- package/templates/apps/web/app/[locale]/(authed)/account/notifications/page.tsx +57 -0
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +85 -26
- package/templates/apps/web/app/[locale]/(authed)/account/profile-actions.ts +116 -0
- package/templates/apps/web/app/[locale]/(authed)/account/security/page.tsx +80 -0
- package/templates/apps/web/app/[locale]/(authed)/account/settings/page.tsx +13 -354
- package/templates/apps/web/app/[locale]/(authed)/account/settings-frame.tsx +108 -0
- package/templates/apps/web/app/[locale]/(authed)/account/sign-in-method.ts +37 -0
- package/templates/apps/web/app/[locale]/(authed)/account/support-actions.ts +9 -10
- package/templates/apps/web/app/[locale]/layout.tsx +23 -4
- package/templates/apps/web/app/api/auth/hub/__tests__/continuation.test.ts +143 -0
- package/templates/apps/web/app/api/auth/hub/authorize/__tests__/route.test.ts +62 -10
- package/templates/apps/web/app/api/auth/hub/authorize/route.ts +22 -7
- package/templates/apps/web/app/api/auth/hub/continuation.ts +73 -0
- package/templates/apps/web/app/api/auth/hub/continue/[ref]/__tests__/route.test.ts +188 -0
- package/templates/apps/web/app/api/auth/hub/continue/[ref]/route.ts +53 -0
- package/templates/apps/web/app/robots.txt/route.ts +10 -4
- package/templates/apps/web/auth.ts +5 -1
- package/templates/apps/web/lib/__tests__/account-config.test.ts +258 -46
- package/templates/apps/web/lib/__tests__/site-brand.test.ts +42 -0
- package/templates/apps/web/lib/account-config.ts +188 -52
- package/templates/apps/web/lib/hub-session/__tests__/hub-session.test.ts +143 -0
- package/templates/apps/web/lib/hub-session/index.ts +1 -0
- package/templates/apps/web/lib/hub-session/reseal.ts +90 -0
- package/templates/apps/web/lib/hub-session/seal.ts +13 -9
- package/templates/apps/web/lib/site-brand.tsx +22 -6
- package/templates/apps/web/lib/topology.generated.ts +27 -0
- package/templates/apps/web/messages/en.json +156 -35
- package/templates/database/CHANGELOG.md +21 -0
- package/templates/database/LICENSE +6 -5
- package/templates/database/NOTICE +2 -0
- package/templates/database/README.md +1 -1
- package/templates/database/__tests__/member-area.db.test.ts +15 -3
- package/templates/database/__tests__/member-contract-migration.test.ts +85 -0
- package/templates/database/__tests__/member-contract.db.test.ts +413 -0
- package/templates/database/__tests__/seed.test.ts +54 -2
- package/templates/database/inbox/schema.prisma +90 -15
- package/templates/database/migrations/20261012120000_member_contract/migration.sql +192 -0
- package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +20 -0
- package/templates/database/package.json +3 -2
- package/templates/database/seed.ts +34 -2
- package/versions.json +36 -36
- package/templates/apps/api/src/__tests__/content-write-production-boot.test.ts +0 -104
- package/templates/apps/api/src/__tests__/cors.test.ts +0 -276
- package/templates/apps/api/src/__tests__/module-exclusion.test.ts +0 -279
- package/templates/apps/api/src/__tests__/openapi-keyless-hub.test.ts +0 -122
- package/templates/apps/api/src/__tests__/review-surface-registration.test.ts +0 -167
- package/templates/apps/api/src/__tests__/root-modules.test.ts +0 -175
- package/templates/apps/api/src/__tests__/schedule-forwarded-rate-limit.test.ts +0 -117
- package/templates/apps/api/src/__tests__/server.test.ts +0 -591
- package/templates/apps/api/src/__tests__/workspace-module-registration.test.ts +0 -175
- package/templates/apps/api/src/openapi/__tests__/surface-drift.test.ts +0 -293
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +0 -1620
- package/templates/apps/api/src/routes/project-listings/__tests__/directory.test.ts +0 -528
- package/templates/apps/api/src/routes/workspaces/__tests__/inbox-wire-schemas.test.ts +0 -198
- package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +0 -652
- package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +0 -408
- package/templates/apps/api/src/services/__tests__/leads-inbox.test.ts +0 -476
- package/templates/apps/mcp/__tests__/audit.test.ts +0 -346
- package/templates/apps/mcp/__tests__/parity.test.ts +0 -325
- package/templates/apps/mcp/__tests__/workspace-surface.test.ts +0 -364
- package/templates/apps/web/app/[locale]/(authed)/account/settings/color-mode.tsx +0 -68
- package/templates/apps/web/app/[locale]/(authed)/account/settings/deletion-request.tsx +0 -55
- package/templates/apps/web/app/[locale]/(authed)/account/settings/name-form.tsx +0 -118
- package/templates/database/__tests__/build.test.ts +0 -131
package/dist/spoke-checkout.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The spoke checkout slice (#7838) — what a spoke carrying `commerce` gets in
|
|
3
|
-
* `apps/web`: the buy route and the Stripe webhook route (
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* `apps/web`: the buy route and the Stripe webhook route (allowed to import
|
|
4
|
+
* the checkout package, #7873), the site's own `lib/checkout-config.ts`, and
|
|
5
|
+
* the thank-you and unavailable return pages. A spoke that signs in through
|
|
6
|
+
* its hub also gets the billing action, the third file allowed to import the
|
|
7
|
+
* package, and the web seam render that reaches it (#8217 D6–D8).
|
|
6
8
|
*
|
|
7
9
|
* Every guarantee lives in `@working-theory/spoke-checkout` and arrives by a
|
|
8
10
|
* package bump; these files are thin and, apart from the config's one stamp
|
|
@@ -23,7 +25,7 @@ import { SPOKE_CHECKOUT_ROUTE_FILES } from "./derive-architecture.js";
|
|
|
23
25
|
import { ENV_CATALOG } from "./lib/env-catalog.js";
|
|
24
26
|
import { diffTwoStrings, } from "./lib/extract-module-bundle.js";
|
|
25
27
|
import { substituteWorkspaceVersions, } from "./substitute.js";
|
|
26
|
-
import { TopologyError } from "./topology.js";
|
|
28
|
+
import { TopologyError, WEB_SEAM_PATH, renderWebSeam, } from "./topology.js";
|
|
27
29
|
/** The checkout package a spoke's two route files import. */
|
|
28
30
|
export const SPOKE_CHECKOUT_PACKAGE = "@working-theory/spoke-checkout";
|
|
29
31
|
const API_CLIENT_PACKAGE = "@working-theory/api-client";
|
|
@@ -131,6 +133,33 @@ const WEBHOOK_ROUTE = renderRoute({
|
|
|
131
133
|
waiver: "the endpoint URL registered in Stripe, not a versioned API contract",
|
|
132
134
|
exportLine: "export const { POST } = createSpokeCheckout(checkoutConfig).webhook;",
|
|
133
135
|
});
|
|
136
|
+
/**
|
|
137
|
+
* The spoke billing action (#8217 D6): wiring only, byte-identical across
|
|
138
|
+
* sites, so every guarantee arrives by a package bump. A plain server module
|
|
139
|
+
* (C2): its two exports take no argument, and the hub's read is its only
|
|
140
|
+
* source of customer ids.
|
|
141
|
+
*/
|
|
142
|
+
const BILLING_ACTION = [
|
|
143
|
+
"// The spoke billing action — GENERATED by create-ailk (#8217). Do not edit:",
|
|
144
|
+
"// every guarantee lives in the spoke-checkout package and arrives by a",
|
|
145
|
+
"// package bump. A plain server module, not a Server Action file: neither",
|
|
146
|
+
"// export takes an argument, and the hub's GET /v1/member/billing is the only",
|
|
147
|
+
"// source of customer ids. billing-source.ts reaches it through",
|
|
148
|
+
"// lib/topology.generated.ts and never imports the package.",
|
|
149
|
+
`import { member } from "${API_CLIENT_PACKAGE}";`,
|
|
150
|
+
`import { createSpokeCheckout } from "${SPOKE_CHECKOUT_PACKAGE}";`,
|
|
151
|
+
"",
|
|
152
|
+
`import { checkoutConfig } from "../../../../../lib/checkout-config";`,
|
|
153
|
+
`import { forwardedCookieInit } from "../../../../../lib/server-api";`,
|
|
154
|
+
"",
|
|
155
|
+
"const billing = createSpokeCheckout(checkoutConfig).billing.forMember(",
|
|
156
|
+
" async () => member.billing(await forwardedCookieInit()),",
|
|
157
|
+
");",
|
|
158
|
+
"",
|
|
159
|
+
"export const readSpokeBilling = billing.read;",
|
|
160
|
+
"export const spokeBillingPortalUrl = billing.portalUrl;",
|
|
161
|
+
"",
|
|
162
|
+
].join("\n");
|
|
134
163
|
/** The site's checkout data (D5). Only the `const SITE` line varies by site. */
|
|
135
164
|
function renderConfig(site) {
|
|
136
165
|
return [
|
|
@@ -138,9 +167,10 @@ function renderConfig(site) {
|
|
|
138
167
|
"//",
|
|
139
168
|
"// Written once by create-ailk and yours from then on: create-ailk never",
|
|
140
169
|
"// rewrites it. The buy route and the Stripe webhook route build their",
|
|
141
|
-
"// handlers from it
|
|
142
|
-
"//
|
|
143
|
-
"//
|
|
170
|
+
"// handlers from it, and so does the billing action on a spoke that signs",
|
|
171
|
+
"// in through its hub. Only those files may import the checkout package",
|
|
172
|
+
"// (architecture.yaml), so this file never imports it, stripe-client or the",
|
|
173
|
+
"// stripe SDK. Keep it to data and the fulfil callback.",
|
|
144
174
|
"//",
|
|
145
175
|
"// site Stamped on every Checkout Session as metadata.site. This site's",
|
|
146
176
|
"// webhook acts only on its own stamp, and the hub ignores any stamp",
|
|
@@ -462,15 +492,20 @@ jobs:
|
|
|
462
492
|
/**
|
|
463
493
|
* The slice for `site`, in order: the two route files, the config, the two
|
|
464
494
|
* pages (D3), then the checkout e2e workflow (#7839 D8), which does not
|
|
465
|
-
* depend on `site`.
|
|
495
|
+
* depend on `site`. With `signIn: "hub"` the billing action is the third
|
|
496
|
+
* pair, so the first three paths are `SPOKE_CHECKOUT_ROUTE_FILES` (#8217 D8).
|
|
497
|
+
* Throws `TopologyError` for an invalid stamp (SEC-7838-10).
|
|
466
498
|
*/
|
|
467
|
-
export function renderSpokeCheckoutFiles(site) {
|
|
499
|
+
export function renderSpokeCheckoutFiles(site, opts = {}) {
|
|
468
500
|
assertSite(site);
|
|
469
|
-
const [buyPath, webhookPath] = SPOKE_CHECKOUT_ROUTE_FILES;
|
|
501
|
+
const [buyPath, webhookPath, billingActionPath] = SPOKE_CHECKOUT_ROUTE_FILES;
|
|
470
502
|
const [thankYouPath, unavailablePath] = SPOKE_CHECKOUT_PAGE_FILES;
|
|
471
503
|
return [
|
|
472
504
|
[buyPath, BUY_ROUTE],
|
|
473
505
|
[webhookPath, WEBHOOK_ROUTE],
|
|
506
|
+
...(opts.signIn === "hub"
|
|
507
|
+
? [[billingActionPath, BILLING_ACTION]]
|
|
508
|
+
: []),
|
|
474
509
|
[SPOKE_CHECKOUT_CONFIG_PATH, renderConfig(site)],
|
|
475
510
|
[thankYouPath, THANK_YOU_PAGE],
|
|
476
511
|
[unavailablePath, UNAVAILABLE_PAGE],
|
|
@@ -516,7 +551,9 @@ function isOlderPin(current, wanted) {
|
|
|
516
551
|
/**
|
|
517
552
|
* Write the slice into `targetDir` (D3). A file that already exists is left
|
|
518
553
|
* byte-for-byte and reported `skipped` — the config is the site's once
|
|
519
|
-
* written.
|
|
554
|
+
* written. With `signIn: "hub"` (#8217 D8) the slice carries the billing
|
|
555
|
+
* action, and the web seam — generated, so always rewritten — becomes the
|
|
556
|
+
* billing render: reported `patched` when it changed, not at all when equal. Adds the package to `apps/web/package.json` when absent, and
|
|
520
557
|
* raises a plain pin older than the one it writes (#7839): the generated
|
|
521
558
|
* checkout e2e workflow runs a command a `^0.2.0` pin never reaches. Any
|
|
522
559
|
* other range — newer, `workspace:`, a tag — is the site's and is kept.
|
|
@@ -524,7 +561,7 @@ function isOlderPin(current, wanted) {
|
|
|
524
561
|
* missing or malformed `apps/web/package.json`) throws before the first write.
|
|
525
562
|
*/
|
|
526
563
|
export function writeSpokeCheckoutSlice(targetDir, opts) {
|
|
527
|
-
const files = renderSpokeCheckoutFiles(opts.site);
|
|
564
|
+
const files = renderSpokeCheckoutFiles(opts.site, { signIn: opts.signIn });
|
|
528
565
|
const range = JSON.parse(substituteWorkspaceVersions(`{"${SPOKE_CHECKOUT_PACKAGE}": "workspace:*"}`, opts.versions));
|
|
529
566
|
const version = range[SPOKE_CHECKOUT_PACKAGE];
|
|
530
567
|
const pkgPath = join(targetDir, WEB_PACKAGE_JSON);
|
|
@@ -541,6 +578,19 @@ export function writeSpokeCheckoutSlice(targetDir, opts) {
|
|
|
541
578
|
writeFileSync(abs, text);
|
|
542
579
|
rows.push({ path, action: "written" });
|
|
543
580
|
}
|
|
581
|
+
if (opts.signIn === "hub") {
|
|
582
|
+
const seamPath = join(targetDir, WEB_SEAM_PATH);
|
|
583
|
+
const seamBefore = existsSync(seamPath) ? readFileSync(seamPath, "utf8") : "";
|
|
584
|
+
const seam = renderWebSeam("spoke", "hub", { spokeBilling: true });
|
|
585
|
+
if (seamBefore !== seam) {
|
|
586
|
+
writeFileSync(seamPath, seam);
|
|
587
|
+
rows.push({
|
|
588
|
+
path: WEB_SEAM_PATH,
|
|
589
|
+
action: "patched",
|
|
590
|
+
change: diffTwoStrings(WEB_SEAM_PATH, seamBefore, seam, true),
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
}
|
|
544
594
|
const deps = pkg.dependencies ?? {};
|
|
545
595
|
const current = Object.prototype.hasOwnProperty.call(deps, SPOKE_CHECKOUT_PACKAGE)
|
|
546
596
|
? deps[SPOKE_CHECKOUT_PACKAGE]
|
package/dist/starter-grid.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* lives in `template-manifest.ts`, whose `resolveTemplate` is the one reader
|
|
15
15
|
* that yields a template's roster. Nothing but those two files imports this one.
|
|
16
16
|
*/
|
|
17
|
-
import type { CategorySlug } from "
|
|
17
|
+
import type { CategorySlug } from "./category-profile.js";
|
|
18
18
|
import type { ModuleName } from "./parse-args.js";
|
|
19
19
|
import type { TemplateLayout } from "./site-chrome.js";
|
|
20
20
|
import type { StarterDesign, StarterShape, TemplateRosterRow } from "./template-manifest.js";
|
package/dist/surfaces.js
CHANGED
|
@@ -630,6 +630,23 @@ export const ROUTE_SINCE = {
|
|
|
630
630
|
// new, so it attaches at today's fixed-group version, the same rule #7430
|
|
631
631
|
// applied above.
|
|
632
632
|
"(authed)/account/inbox/message/[id]/file": "0.37.0",
|
|
633
|
+
// #8232 — User settings' two pages, General and Billing (the old
|
|
634
|
+
// `(authed)/account/settings` now redirects to General). Genuinely new, so
|
|
635
|
+
// they attach at today's fixed-group version, the same rule #7430 applied.
|
|
636
|
+
"(authed)/account/general": "0.38.0",
|
|
637
|
+
"(authed)/account/billing": "0.38.0",
|
|
638
|
+
// #8339 — User settings' two new tabs, Security and Notifications
|
|
639
|
+
// (General and Billing now render through the shared account-settings
|
|
640
|
+
// composition). Genuinely new, so they attach at today's fixed-group
|
|
641
|
+
// version, the same rule #7430/#8232 applied.
|
|
642
|
+
"(authed)/account/security": "0.38.0",
|
|
643
|
+
"(authed)/account/notifications": "0.38.0",
|
|
644
|
+
// #8234 — the member Artifacts pages and a version's file route. Genuinely
|
|
645
|
+
// new, so they attach at today's fixed-group version, the same rule #7430
|
|
646
|
+
// applied.
|
|
647
|
+
"(authed)/account/artifacts": "0.38.0",
|
|
648
|
+
"(authed)/account/artifacts/[pieceId]": "0.38.0",
|
|
649
|
+
"(authed)/account/artifacts/[pieceId]/versions/[version]/file": "0.38.0",
|
|
633
650
|
// The leads inbox (#5678). The ROUTE ships in every scaffold, Free
|
|
634
651
|
// included — lead capture is a never-gate surface, so reading a lead back
|
|
635
652
|
// is one too. Whether it shows a ROW is a separate question with two
|
|
@@ -759,24 +776,139 @@ export const ROUTE_DEPENDENCIES = {
|
|
|
759
776
|
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
760
777
|
`${ROUTE_ROOT}/(authed)/account/error-row.tsx`,
|
|
761
778
|
`${ROUTE_ROOT}/(authed)/account/retry-button.tsx`,
|
|
779
|
+
// #8233 C9 — the New menu's files beside account-config.ts: new-popups.tsx
|
|
780
|
+
// binds the config's actions to the popups, which import the menu and its
|
|
781
|
+
// server actions. (account-config.ts itself imports none of them — a
|
|
782
|
+
// spoke without sign-in drops the `(authed)` group and keeps the config.)
|
|
783
|
+
`${ROUTE_ROOT}/(authed)/account/new-menu.tsx`,
|
|
784
|
+
`${ROUTE_ROOT}/(authed)/account/new-actions.ts`,
|
|
785
|
+
`${ROUTE_ROOT}/(authed)/account/new-popups.tsx`,
|
|
786
|
+
`${ROUTE_ROOT}/(authed)/account/components/schedule-service.tsx`,
|
|
787
|
+
`${ROUTE_ROOT}/(authed)/account/components/request-quote.tsx`,
|
|
788
|
+
`${ROUTE_ROOT}/(authed)/account/components/send-message.tsx`,
|
|
762
789
|
],
|
|
763
790
|
// #7920 — the member file read re-serves the hub's bytes with the
|
|
764
791
|
// credential `forwardedCookieInit` returns.
|
|
765
792
|
"(authed)/account/inbox/message/[id]/file": ["apps/web/lib/server-api.ts"],
|
|
793
|
+
// #8232 D13 — the settings route is a redirect now; what it still imports
|
|
794
|
+
// from outside itself is `theme-modes.ts`'s theme reader and the brand file
|
|
795
|
+
// that reader imports.
|
|
766
796
|
"(authed)/account/settings": [
|
|
797
|
+
"apps/web/lib/site-brand.tsx",
|
|
798
|
+
"apps/web/lib/site-theme.ts",
|
|
799
|
+
],
|
|
800
|
+
// #8232 D13 — General and Billing import files in their parent's directory
|
|
801
|
+
// too. Each listed parent file is new in #8232 or unchanged by it, so a
|
|
802
|
+
// scaffold that already has one keeps a copy that still compiles; the
|
|
803
|
+
// settings components General changed moved into `general/` instead (C3).
|
|
804
|
+
// `profile-actions.ts` imports `lib/hub-session/reseal.ts` by its own path,
|
|
805
|
+
// since a scaffold's existing `lib/hub-session/index.ts` is never updated.
|
|
806
|
+
//
|
|
807
|
+
// #8339 D11 — `settings/color-mode.tsx` drops: General's own color-mode
|
|
808
|
+
// control is now the shared `AccountSettings` composition's
|
|
809
|
+
// (@working-theory/templates/account). `sign-in-method.ts` stays: General no
|
|
810
|
+
// longer renders the Sign-in section itself (moved to Security), but it
|
|
811
|
+
// still imports `sign-in-method.ts` transitively through
|
|
812
|
+
// `profile-source.ts`'s `via` derivation.
|
|
813
|
+
"(authed)/account/general": [
|
|
767
814
|
"apps/web/lib/account-config.ts",
|
|
768
815
|
"apps/web/lib/auth-env.ts",
|
|
769
816
|
"apps/web/lib/server-api.ts",
|
|
770
817
|
"apps/web/lib/site-brand.tsx",
|
|
771
818
|
"apps/web/lib/site-theme.ts",
|
|
819
|
+
"apps/web/lib/hub-session/reseal.ts",
|
|
772
820
|
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
773
|
-
`${ROUTE_ROOT}/(authed)/account/
|
|
821
|
+
`${ROUTE_ROOT}/(authed)/account/settings-frame.tsx`,
|
|
822
|
+
`${ROUTE_ROOT}/(authed)/account/sign-in-method.ts`,
|
|
823
|
+
`${ROUTE_ROOT}/(authed)/account/profile-actions.ts`,
|
|
824
|
+
`${ROUTE_ROOT}/(authed)/account/settings/theme-modes.ts`,
|
|
825
|
+
// #8233 C9 — the New menu's files beside account-config.ts: new-popups.tsx
|
|
826
|
+
// binds the config's actions to the popups, which import the menu and its
|
|
827
|
+
// server actions. (account-config.ts itself imports none of them — a
|
|
828
|
+
// spoke without sign-in drops the `(authed)` group and keeps the config.)
|
|
829
|
+
`${ROUTE_ROOT}/(authed)/account/new-menu.tsx`,
|
|
830
|
+
`${ROUTE_ROOT}/(authed)/account/new-actions.ts`,
|
|
831
|
+
`${ROUTE_ROOT}/(authed)/account/new-popups.tsx`,
|
|
832
|
+
`${ROUTE_ROOT}/(authed)/account/components/schedule-service.tsx`,
|
|
833
|
+
`${ROUTE_ROOT}/(authed)/account/components/request-quote.tsx`,
|
|
834
|
+
`${ROUTE_ROOT}/(authed)/account/components/send-message.tsx`,
|
|
835
|
+
],
|
|
836
|
+
// #8339 D11 — Security holds the former Sign-in section, moved verbatim
|
|
837
|
+
// from General: `sign-in-method.ts` and what it imports.
|
|
838
|
+
"(authed)/account/security": [
|
|
839
|
+
"apps/web/lib/account-config.ts",
|
|
840
|
+
"apps/web/lib/auth-env.ts",
|
|
841
|
+
"apps/web/lib/server-api.ts",
|
|
842
|
+
"apps/web/lib/hub-session/config.ts",
|
|
843
|
+
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
844
|
+
`${ROUTE_ROOT}/(authed)/account/settings-frame.tsx`,
|
|
845
|
+
`${ROUTE_ROOT}/(authed)/account/sign-in-method.ts`,
|
|
846
|
+
],
|
|
847
|
+
// #8339 D11 — Notifications holds the former Privacy section's
|
|
848
|
+
// cookie-settings link, moved verbatim from General.
|
|
849
|
+
"(authed)/account/notifications": [
|
|
850
|
+
"apps/web/lib/account-config.ts",
|
|
851
|
+
"apps/web/lib/server-api.ts",
|
|
852
|
+
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
853
|
+
`${ROUTE_ROOT}/(authed)/account/settings-frame.tsx`,
|
|
854
|
+
],
|
|
855
|
+
"(authed)/account/billing": [
|
|
856
|
+
"apps/web/lib/account-config.ts",
|
|
857
|
+
"apps/web/lib/server-api.ts",
|
|
858
|
+
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
859
|
+
`${ROUTE_ROOT}/(authed)/account/actions.ts`,
|
|
860
|
+
`${ROUTE_ROOT}/(authed)/account/error-row.tsx`,
|
|
861
|
+
`${ROUTE_ROOT}/(authed)/account/retry-button.tsx`,
|
|
862
|
+
`${ROUTE_ROOT}/(authed)/account/settings-frame.tsx`,
|
|
863
|
+
`${ROUTE_ROOT}/(authed)/account/billing-source.ts`,
|
|
864
|
+
// #8233 C9 — the New menu's files beside account-config.ts: new-popups.tsx
|
|
865
|
+
// binds the config's actions to the popups, which import the menu and its
|
|
866
|
+
// server actions. (account-config.ts itself imports none of them — a
|
|
867
|
+
// spoke without sign-in drops the `(authed)` group and keeps the config.)
|
|
868
|
+
`${ROUTE_ROOT}/(authed)/account/new-menu.tsx`,
|
|
869
|
+
`${ROUTE_ROOT}/(authed)/account/new-actions.ts`,
|
|
870
|
+
`${ROUTE_ROOT}/(authed)/account/new-popups.tsx`,
|
|
871
|
+
`${ROUTE_ROOT}/(authed)/account/components/schedule-service.tsx`,
|
|
872
|
+
`${ROUTE_ROOT}/(authed)/account/components/request-quote.tsx`,
|
|
873
|
+
`${ROUTE_ROOT}/(authed)/account/components/send-message.tsx`,
|
|
874
|
+
],
|
|
875
|
+
// #8234 — the Artifacts pages import files in their parent's directory, as
|
|
876
|
+
// #7430's children do; the artifact page also imports its own parent's
|
|
877
|
+
// `artifact-data.ts` and `artifact-actions.ts`, which an older synced
|
|
878
|
+
// `artifacts/` might lack. The file route re-serves the hub's bytes with
|
|
879
|
+
// the credential `forwardedCookieInit` returns.
|
|
880
|
+
"(authed)/account/artifacts": [
|
|
881
|
+
"apps/web/lib/account-config.ts",
|
|
882
|
+
"apps/web/lib/server-api.ts",
|
|
883
|
+
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
884
|
+
`${ROUTE_ROOT}/(authed)/account/error-row.tsx`,
|
|
885
|
+
`${ROUTE_ROOT}/(authed)/account/retry-button.tsx`,
|
|
886
|
+
],
|
|
887
|
+
"(authed)/account/artifacts/[pieceId]": [
|
|
888
|
+
"apps/web/lib/account-config.ts",
|
|
889
|
+
"apps/web/lib/server-api.ts",
|
|
890
|
+
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
891
|
+
`${ROUTE_ROOT}/(authed)/account/error-row.tsx`,
|
|
892
|
+
`${ROUTE_ROOT}/(authed)/account/retry-button.tsx`,
|
|
893
|
+
`${ROUTE_ROOT}/(authed)/account/artifacts/artifact-data.ts`,
|
|
894
|
+
`${ROUTE_ROOT}/(authed)/account/artifacts/artifact-actions.ts`,
|
|
774
895
|
],
|
|
896
|
+
"(authed)/account/artifacts/[pieceId]/versions/[version]/file": ["apps/web/lib/server-api.ts"],
|
|
775
897
|
"(authed)/account/support": [
|
|
776
898
|
"apps/web/lib/account-config.ts",
|
|
777
899
|
"apps/web/lib/server-api.ts",
|
|
778
900
|
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
779
901
|
`${ROUTE_ROOT}/(authed)/account/support-actions.ts`,
|
|
902
|
+
// #8233 C9 — the New menu's files beside account-config.ts: new-popups.tsx
|
|
903
|
+
// binds the config's actions to the popups, which import the menu and its
|
|
904
|
+
// server actions. (account-config.ts itself imports none of them — a
|
|
905
|
+
// spoke without sign-in drops the `(authed)` group and keeps the config.)
|
|
906
|
+
`${ROUTE_ROOT}/(authed)/account/new-menu.tsx`,
|
|
907
|
+
`${ROUTE_ROOT}/(authed)/account/new-actions.ts`,
|
|
908
|
+
`${ROUTE_ROOT}/(authed)/account/new-popups.tsx`,
|
|
909
|
+
`${ROUTE_ROOT}/(authed)/account/components/schedule-service.tsx`,
|
|
910
|
+
`${ROUTE_ROOT}/(authed)/account/components/request-quote.tsx`,
|
|
911
|
+
`${ROUTE_ROOT}/(authed)/account/components/send-message.tsx`,
|
|
780
912
|
],
|
|
781
913
|
"(authed)/admin": [
|
|
782
914
|
"apps/web/lib/server-api.ts",
|
|
@@ -832,6 +964,13 @@ export const ROUTE_MESSAGE_NAMESPACES = {
|
|
|
832
964
|
"(authed)/account/inbox/[kind]/[id]": ["account"],
|
|
833
965
|
"(authed)/account/settings": ["account"],
|
|
834
966
|
"(authed)/account/support": ["account"],
|
|
967
|
+
"(authed)/account/general": ["account"],
|
|
968
|
+
"(authed)/account/security": ["account"],
|
|
969
|
+
"(authed)/account/notifications": ["account"],
|
|
970
|
+
"(authed)/account/billing": ["account"],
|
|
971
|
+
// #8234 — the two Artifacts pages; the file route renders no string.
|
|
972
|
+
"(authed)/account/artifacts": ["account"],
|
|
973
|
+
"(authed)/account/artifacts/[pieceId]": ["account"],
|
|
835
974
|
"(authed)/admin": ["admin"],
|
|
836
975
|
"(authed)/leads": ["leadsInbox"],
|
|
837
976
|
// #5977 — every string on both editor routes comes from the `edit`
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* package already twice records that a fixed template FILE is the drift a
|
|
15
15
|
* registry removes.
|
|
16
16
|
*/
|
|
17
|
-
import type { CategorySlug } from "
|
|
17
|
+
import type { CategorySlug } from "./category-profile.js";
|
|
18
18
|
import { type PageRosterRow } from "./module-architecture.js";
|
|
19
19
|
import type { ModuleName } from "./parse-args.js";
|
|
20
20
|
import type { TemplateLayout } from "./site-chrome.js";
|
|
@@ -66,8 +66,9 @@ export interface TemplateManifest {
|
|
|
66
66
|
* The business categories this template is FOR — one or more LEAF slugs from
|
|
67
67
|
* the site-category registry (`@working-theory/schema/categories`, #5830),
|
|
68
68
|
* shared with content's frontmatter `categories`. Required, and typed against
|
|
69
|
-
* `CategorySlug
|
|
70
|
-
* `
|
|
69
|
+
* `CategorySlug` — create-ailk's drift-tested copy of the registry's leaves
|
|
70
|
+
* (`category-profile.ts`, #8412) — for the same reason `requires` is typed
|
|
71
|
+
* against `ModuleName`: an unrecognized name fails type-check rather than a runtime
|
|
71
72
|
* validation, and every template must be findable under at least one
|
|
72
73
|
* category on the hub's "Browse by business" band.
|
|
73
74
|
*
|
package/dist/topology.d.ts
CHANGED
|
@@ -122,13 +122,26 @@ export declare function isSpokeExcluded(path: string, opts: IsSpokeExcludedOptio
|
|
|
122
122
|
* install passes no remap.
|
|
123
123
|
*/
|
|
124
124
|
export declare function spokeDestination(destination: string): string;
|
|
125
|
+
/**
|
|
126
|
+
* The MCP tools a spoke does not serve (#8070 D7). `create_project` spawns
|
|
127
|
+
* `packages/create-ailk/dist/cli.js` from the MCP host's working directory,
|
|
128
|
+
* which a spoke does not carry. Both seams carry the list, so the MCP
|
|
129
|
+
* server's registration and the web discovery manifest agree; a hub's is
|
|
130
|
+
* empty.
|
|
131
|
+
*/
|
|
132
|
+
export declare const SPOKE_UNSERVED_MCP_TOOLS: readonly string[];
|
|
125
133
|
/**
|
|
126
134
|
* `apps/web/lib/topology.generated.ts` for `topology` (D5) and, on a spoke,
|
|
127
135
|
* its sign-in mode (#7894 D8). The hub render loads `auth.ts` only when a
|
|
128
136
|
* session is read, so a module that imports this seam for a constant never
|
|
129
|
-
* loads Better Auth.
|
|
137
|
+
* loads Better Auth. `opts.spokeBilling` (#8217 D7) makes `loadSpokeBilling`
|
|
138
|
+
* reach the spoke billing action — only on a spoke that signs in through its
|
|
139
|
+
* hub, the one render whose account area can call it.
|
|
140
|
+
* @throws TopologyError for `spokeBilling` on a hub or a default-mode spoke.
|
|
130
141
|
*/
|
|
131
|
-
export declare function renderWebSeam(topology: Topology, signIn?: SignInMode
|
|
142
|
+
export declare function renderWebSeam(topology: Topology, signIn?: SignInMode, opts?: {
|
|
143
|
+
spokeBilling?: boolean;
|
|
144
|
+
}): string;
|
|
132
145
|
/**
|
|
133
146
|
* `apps/web/app/[locale]/(authed)/signed-out-gate.generated.tsx` (#7894 D8).
|
|
134
147
|
* The hub render is the `(authed)` layout's no-session branch, moved; the
|
package/dist/topology.js
CHANGED
|
@@ -269,13 +269,32 @@ const WEB_SEAM_HEADER = `// topology.generated.ts — how this site reads a sess
|
|
|
269
269
|
// every scaffold rewrites it. A hub reads the session through Better Auth.
|
|
270
270
|
// A spoke (\`--topology spoke\`) has no database of its own: by default it
|
|
271
271
|
// has no sign-in, so its render reads no session and imports nothing; with
|
|
272
|
-
// \`--hub-sign-in\` (#7894) it reads the sealed hub-session cookie
|
|
272
|
+
// \`--hub-sign-in\` (#7894) it reads the sealed hub-session cookie.
|
|
273
|
+
// UNSERVED_MCP_TOOLS names the MCP tools /.well-known/mcp.json leaves out
|
|
274
|
+
// on this topology (#8070).
|
|
275
|
+
// loadSpokeBilling reaches the spoke billing action only on a spoke that
|
|
276
|
+
// signs in through its hub and carries commerce (#8217); elsewhere, null.`;
|
|
273
277
|
const MCP_SEAM_HEADER = `// topology.generated.ts — how this MCP server resolves its workspace store.
|
|
274
278
|
//
|
|
275
279
|
// GENERATED by create-ailk for this site's topology (#7426). Do not edit:
|
|
276
280
|
// every scaffold rewrites it. A hub resolves its workspace through the
|
|
277
281
|
// database; a spoke (\`--topology spoke\`) has none, so its content tools
|
|
278
|
-
// read the spoke's own MDX and its writes go to the hub at AILK_API_URL
|
|
282
|
+
// read the spoke's own MDX and its writes go to the hub at AILK_API_URL.
|
|
283
|
+
// UNSERVED_MCP_TOOLS names the tools this server does not register on this
|
|
284
|
+
// topology (#8070).`;
|
|
285
|
+
/**
|
|
286
|
+
* The MCP tools a spoke does not serve (#8070 D7). `create_project` spawns
|
|
287
|
+
* `packages/create-ailk/dist/cli.js` from the MCP host's working directory,
|
|
288
|
+
* which a spoke does not carry. Both seams carry the list, so the MCP
|
|
289
|
+
* server's registration and the web discovery manifest agree; a hub's is
|
|
290
|
+
* empty.
|
|
291
|
+
*/
|
|
292
|
+
export const SPOKE_UNSERVED_MCP_TOOLS = ["create_project"];
|
|
293
|
+
/** The `UNSERVED_MCP_TOOLS` export every web and mcp seam render carries. */
|
|
294
|
+
function unservedToolsExport(topology) {
|
|
295
|
+
const list = topology === "spoke" ? SPOKE_UNSERVED_MCP_TOOLS : [];
|
|
296
|
+
return `export const UNSERVED_MCP_TOOLS: readonly string[] = ${JSON.stringify(list)};`;
|
|
297
|
+
}
|
|
279
298
|
const SITE_SESSION_TYPE = `export type SiteSession = {
|
|
280
299
|
user: {
|
|
281
300
|
name?: string | null;
|
|
@@ -293,17 +312,67 @@ export const SIGN_IN_PATH: string | null = ${literal(values.signInPath)};
|
|
|
293
312
|
export const SIGN_UP_PATH: string | null = ${literal(values.signUpPath)};
|
|
294
313
|
export const SIGN_OUT_ENDPOINT: string | null = ${literal(values.signOutEndpoint)};`;
|
|
295
314
|
}
|
|
315
|
+
/** The spoke billing action (#8217 D6), relative to the web seam. */
|
|
316
|
+
const SPOKE_BILLING_ACTION_IMPORT = "../app/[locale]/(authed)/account/billing/spoke-billing.action";
|
|
317
|
+
/** The billing types every web seam render carries (#8217 D7). */
|
|
318
|
+
const SPOKE_BILLING_TYPES = `export type SpokeCard = { brand: string; last4: string; expMonth: number; expYear: number };
|
|
319
|
+
|
|
320
|
+
export type SpokeBillingRead =
|
|
321
|
+
| {
|
|
322
|
+
kind: "subscription";
|
|
323
|
+
status: "trialing" | "active" | "past_due" | "canceled";
|
|
324
|
+
planName: string | null;
|
|
325
|
+
paymentMethod: SpokeCard | null;
|
|
326
|
+
unreadable: boolean;
|
|
327
|
+
}
|
|
328
|
+
| { kind: "none"; unreadable: boolean }
|
|
329
|
+
| { kind: "failed" };
|
|
330
|
+
|
|
331
|
+
export type SpokeBilling = {
|
|
332
|
+
read(): Promise<SpokeBillingRead>;
|
|
333
|
+
portalUrl(): Promise<string | null>;
|
|
334
|
+
};`;
|
|
335
|
+
/**
|
|
336
|
+
* `loadSpokeBilling` (#8217 D7): the billing render imports the action, by a
|
|
337
|
+
* dynamic import, so a module that reads this seam for a constant never
|
|
338
|
+
* loads the checkout package; every other render resolves `null`.
|
|
339
|
+
*/
|
|
340
|
+
function spokeBillingLoader(spokeBilling) {
|
|
341
|
+
if (!spokeBilling) {
|
|
342
|
+
return `${SPOKE_BILLING_TYPES}
|
|
343
|
+
|
|
344
|
+
export function loadSpokeBilling(): Promise<SpokeBilling | null> {
|
|
345
|
+
return Promise.resolve(null);
|
|
346
|
+
}`;
|
|
347
|
+
}
|
|
348
|
+
return `${SPOKE_BILLING_TYPES}
|
|
349
|
+
|
|
350
|
+
export async function loadSpokeBilling(): Promise<SpokeBilling | null> {
|
|
351
|
+
const { readSpokeBilling, spokeBillingPortalUrl } = await import(
|
|
352
|
+
"${SPOKE_BILLING_ACTION_IMPORT}"
|
|
353
|
+
);
|
|
354
|
+
return { read: readSpokeBilling, portalUrl: spokeBillingPortalUrl };
|
|
355
|
+
}`;
|
|
356
|
+
}
|
|
296
357
|
/**
|
|
297
358
|
* `apps/web/lib/topology.generated.ts` for `topology` (D5) and, on a spoke,
|
|
298
359
|
* its sign-in mode (#7894 D8). The hub render loads `auth.ts` only when a
|
|
299
360
|
* session is read, so a module that imports this seam for a constant never
|
|
300
|
-
* loads Better Auth.
|
|
361
|
+
* loads Better Auth. `opts.spokeBilling` (#8217 D7) makes `loadSpokeBilling`
|
|
362
|
+
* reach the spoke billing action — only on a spoke that signs in through its
|
|
363
|
+
* hub, the one render whose account area can call it.
|
|
364
|
+
* @throws TopologyError for `spokeBilling` on a hub or a default-mode spoke.
|
|
301
365
|
*/
|
|
302
|
-
export function renderWebSeam(topology, signIn = "off") {
|
|
366
|
+
export function renderWebSeam(topology, signIn = "off", opts = {}) {
|
|
367
|
+
const spokeBilling = opts.spokeBilling === true;
|
|
368
|
+
if (spokeBilling && (topology !== "spoke" || signIn !== "hub")) {
|
|
369
|
+
throw new TopologyError("the spoke billing loader renders only on a spoke that signs in through its hub (--hub-sign-in)");
|
|
370
|
+
}
|
|
303
371
|
if (topology === "hub") {
|
|
304
372
|
return `${WEB_SEAM_HEADER}
|
|
305
373
|
|
|
306
374
|
export const TOPOLOGY: "hub" | "spoke" = "hub";
|
|
375
|
+
${unservedToolsExport("hub")}
|
|
307
376
|
${signInExports({ enabled: true, provider: "site", signInPath: "/sign-in", signUpPath: "/sign-up", signOutEndpoint: null })}
|
|
308
377
|
|
|
309
378
|
${SITE_SESSION_TYPE}
|
|
@@ -317,6 +386,8 @@ export async function registerSiteStores(): Promise<void> {
|
|
|
317
386
|
const { registerLicenseKeyStore } = await import("./license-key-store");
|
|
318
387
|
await registerLicenseKeyStore();
|
|
319
388
|
}
|
|
389
|
+
|
|
390
|
+
${spokeBillingLoader(false)}
|
|
320
391
|
`;
|
|
321
392
|
}
|
|
322
393
|
if (signIn === "hub") {
|
|
@@ -324,6 +395,7 @@ export async function registerSiteStores(): Promise<void> {
|
|
|
324
395
|
import { readHubSession } from "./hub-session/session";
|
|
325
396
|
|
|
326
397
|
export const TOPOLOGY: "hub" | "spoke" = "spoke";
|
|
398
|
+
${unservedToolsExport("spoke")}
|
|
327
399
|
${signInExports({ enabled: true, provider: "hub", signInPath: "/account", signUpPath: null, signOutEndpoint: "/api/hub-session/sign-out" })}
|
|
328
400
|
|
|
329
401
|
${SITE_SESSION_TYPE}
|
|
@@ -335,11 +407,14 @@ export function readSession(headers: Headers): Promise<SiteSession> {
|
|
|
335
407
|
export function registerSiteStores(): Promise<void> {
|
|
336
408
|
return Promise.resolve();
|
|
337
409
|
}
|
|
410
|
+
|
|
411
|
+
${spokeBillingLoader(spokeBilling)}
|
|
338
412
|
`;
|
|
339
413
|
}
|
|
340
414
|
return `${WEB_SEAM_HEADER}
|
|
341
415
|
|
|
342
416
|
export const TOPOLOGY: "hub" | "spoke" = "spoke";
|
|
417
|
+
${unservedToolsExport("spoke")}
|
|
343
418
|
${signInExports({ enabled: false, provider: "none", signInPath: null, signUpPath: null, signOutEndpoint: null })}
|
|
344
419
|
|
|
345
420
|
${SITE_SESSION_TYPE}
|
|
@@ -352,6 +427,8 @@ export function readSession(headers: Headers): Promise<SiteSession> {
|
|
|
352
427
|
export function registerSiteStores(): Promise<void> {
|
|
353
428
|
return Promise.resolve();
|
|
354
429
|
}
|
|
430
|
+
|
|
431
|
+
${spokeBillingLoader(false)}
|
|
355
432
|
`;
|
|
356
433
|
}
|
|
357
434
|
const AUTHED_GATE_SEAM_HEADER = `// signed-out-gate.generated.tsx — what the (authed) group shows a signed-out visitor.
|
|
@@ -504,6 +581,7 @@ export { registerLicenseKeyStore } from "./license-key-store.js";
|
|
|
504
581
|
export type { McpWorkspaceResolution };
|
|
505
582
|
|
|
506
583
|
export const TOPOLOGY: "hub" | "spoke" = "hub";
|
|
584
|
+
${unservedToolsExport("hub")}
|
|
507
585
|
|
|
508
586
|
export async function initPublicWorkspace(): Promise<void> {
|
|
509
587
|
await initMcpPublicWorkspace();
|
|
@@ -523,6 +601,7 @@ export type McpWorkspaceResolution =
|
|
|
523
601
|
| { kind: "unresolved"; reason: "ambiguous" };
|
|
524
602
|
|
|
525
603
|
export const TOPOLOGY: "hub" | "spoke" = "spoke";
|
|
604
|
+
${unservedToolsExport("spoke")}
|
|
526
605
|
|
|
527
606
|
export function initPublicWorkspace(): Promise<void> {
|
|
528
607
|
return Promise.resolve();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-ailk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.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",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"component-catalog.json",
|
|
19
19
|
"component-catalog.md",
|
|
20
20
|
"README.md",
|
|
21
|
-
"LICENSE"
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"NOTICE"
|
|
22
23
|
],
|
|
23
24
|
"publishConfig": {
|
|
24
25
|
"access": "public"
|
|
@@ -27,8 +28,8 @@
|
|
|
27
28
|
"tar": "^7.5.21"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"@working-theory/
|
|
31
|
-
"@working-theory/
|
|
31
|
+
"@working-theory/schema": "0.39.0",
|
|
32
|
+
"@working-theory/templates": "0.39.0"
|
|
32
33
|
},
|
|
33
34
|
"repository": {
|
|
34
35
|
"type": "git",
|
package/templates/.env.example
CHANGED
|
@@ -9,9 +9,9 @@ AILK_PUBLIC_DOMAIN=ailaunchkit.ai
|
|
|
9
9
|
# STEALTH defaults to "true" for new installs so a freshly-deployed instance
|
|
10
10
|
# isn't indexed by crawlers or unfurled by Slack/Twitter/LinkedIn before the
|
|
11
11
|
# operator is ready. Three layers gate on this single flag:
|
|
12
|
-
# 1. apps
|
|
13
|
-
# 2. X-Robots-Tag: noindex, nofollow, noarchive HTTP header (next.config.
|
|
14
|
-
# 3. <meta name="robots" content="noindex,nofollow"> tag (app/layout.tsx)
|
|
12
|
+
# 1. robots.txt answers "Disallow: /" for every crawler (apps/web/app/robots.txt/route.ts)
|
|
13
|
+
# 2. X-Robots-Tag: noindex, nofollow, noarchive HTTP header (apps/web/next.config.mjs)
|
|
14
|
+
# 3. <meta name="robots" content="noindex,nofollow"> tag (apps/web/app/[locale]/layout.tsx)
|
|
15
15
|
# At launch, set STEALTH=false on the hosting platform's env vars and redeploy.
|
|
16
16
|
# See README.md § "Going live" for the full flip checklist.
|
|
17
17
|
STEALTH=true
|
|
@@ -54,4 +54,9 @@ jobs:
|
|
|
54
54
|
|
|
55
55
|
- run: pnpm test
|
|
56
56
|
|
|
57
|
+
# apps/web's `next build` with the docs module outgrows Node's default
|
|
58
|
+
# ~2 GB heap and aborts with "JavaScript heap out of memory" (#8069).
|
|
59
|
+
# The hosted runner has ~7 GB; give the build room.
|
|
57
60
|
- run: pnpm build
|
|
61
|
+
env:
|
|
62
|
+
NODE_OPTIONS: --max-old-space-size=6144
|