create-ailk 0.25.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/lib/fetch-template-snapshot.d.ts +2 -1
- package/dist/lib/fetch-template-snapshot.js +6 -5
- package/dist/lib/module-license-gate.js +2 -3
- package/dist/lib/module-tier.d.ts +2 -8
- package/dist/lib/module-tier.js +13 -12
- package/dist/module-architecture.js +12 -2
- package/dist/starter-grid.d.ts +6 -6
- package/dist/starter-grid.js +12 -5
- package/dist/surfaces.js +29 -0
- package/dist/template-record.d.ts +11 -3
- package/dist/template-record.js +20 -7
- package/dist/topology.js +23 -4
- package/dist/update.d.ts +1 -1
- package/dist/update.js +188 -18
- package/package.json +3 -3
- package/release-scope.json +1 -1
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +8 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +2 -2
- package/site-templates/marketing-site/ailk-template.json +7 -1
- package/site-templates/marketing-site/provenance.json +7 -1
- package/site-templates/saas-product/ailk-template.json +2 -1
- package/site-templates/saas-product/provenance.json +1 -0
- package/templates/.env.example +15 -0
- package/templates/apps/api/.env.example +21 -0
- package/templates/apps/api/CLAUDE.md +18 -8
- package/templates/apps/api/src/lib/__mocks__/prisma-client.js +16 -0
- package/templates/apps/mcp/CLAUDE.md +27 -10
- package/templates/apps/web/CLAUDE.md +22 -1
- package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +43 -4
- package/templates/apps/web/app/[locale]/(auth)/legal-footnote.tsx +35 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +117 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +14 -37
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +6 -6
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +20 -35
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/page.test.tsx +108 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +111 -5
- package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +78 -16
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +132 -12
- package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +53 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/billing.test.tsx +38 -0
- package/templates/apps/web/app/[locale]/(authed)/account/billing/page.tsx +4 -2
- package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +47 -24
- package/templates/apps/web/app/[locale]/(authed)/signed-out-gate.generated.tsx +23 -4
- package/templates/apps/web/app/[locale]/layout.tsx +33 -13
- package/templates/apps/web/app/[locale]/meet/confirmed/BookingHandOff.tsx +128 -0
- package/templates/apps/web/app/[locale]/meet/confirmed/__tests__/BookingHandOff.test.tsx +126 -0
- package/templates/apps/web/auth.ts +8 -4
- package/templates/apps/web/i18n/request.ts +49 -1
- package/templates/apps/web/lib/__tests__/account-config.test.ts +7 -0
- package/templates/apps/web/lib/__tests__/auth-email.test.ts +276 -0
- package/templates/apps/web/lib/auth-email.ts +102 -20
- package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +72 -23
- package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +94 -70
- package/templates/apps/web/lib/prisma-for-auth.ts +5 -2
- package/templates/apps/web/lib/sign-up-agreements.ts +291 -28
- package/templates/apps/web/lib/site-contributions.ts +18 -0
- package/templates/apps/web/messages/en.json +186 -20
- package/templates/apps/web/messages/site/en.json +1 -0
- package/versions.json +48 -48
package/README.md
CHANGED
|
@@ -18,15 +18,17 @@ Compose the site from modules with `--modules`. The recognized vocabulary is
|
|
|
18
18
|
`multi-tenant`, `workspace`, `scheduling`, `signal-collectors`, `commerce` —
|
|
19
19
|
and `--modules` TRIMS or ADDS relative to the level your licence key unlocks
|
|
20
20
|
(#6759), never replaces it: Free is `marketing` alone; a Pro key switches
|
|
21
|
-
on `docs-blog`, `
|
|
21
|
+
on `docs-blog`, `workspace` (the `/admin` settings surface, #9696),
|
|
22
|
+
`scheduling` and `signal-collectors` too; Pro Plus adds
|
|
22
23
|
`multi-tenant`. A run with no key is a Free run, and Free is held for now
|
|
23
24
|
(`release-scope.json` marks `levels.free` `deferred`, #6484): the CLI refuses
|
|
24
25
|
it before its first write, naming `https://ailaunchkit.ai/pricing` and the
|
|
25
26
|
two ways to pass a key (`--license <key>` or `AILK_LICENSE_KEY`). The Free
|
|
26
27
|
template and level stay defined; only the keyless path is held. Naming modules here
|
|
27
28
|
keeps exactly those, trimming the level's default; naming only `commerce`
|
|
28
|
-
(a per-site add-on)
|
|
29
|
-
|
|
29
|
+
(a per-site add-on) adds it on top of the level's default without trimming,
|
|
30
|
+
and naming only `workspace` is a no-op at Pro and Pro Plus, whose defaults already
|
|
31
|
+
carry it (below Pro it is refused, naming Pro). The level is always DERIVED from
|
|
30
32
|
what the module registry answers for your key — never read from a flag, a
|
|
31
33
|
manifest or a key claim (`src/lib/module-tier.ts` `LEVEL_MODULES`,
|
|
32
34
|
`src/lib/module-license-gate.ts` `deriveLevel`):
|
|
@@ -76,6 +78,13 @@ AILK_LICENSE_KEY=<key> create-ailk add-module docs-blog
|
|
|
76
78
|
AILK_LICENSE_KEY=<key> create-ailk upgrade docs-blog ./my-site
|
|
77
79
|
```
|
|
78
80
|
|
|
81
|
+
A Pro site scaffolded before a Pro key switched on `workspace` (#9696) has no
|
|
82
|
+
`/admin`. This is how it gains the owner's settings surface:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
AILK_LICENSE_KEY=<key> create-ailk add-module workspace
|
|
86
|
+
```
|
|
87
|
+
|
|
79
88
|
It fetches the module's bundle through the same licence gate a scaffold uses
|
|
80
89
|
(no key, or a key that does not cover the module, is refused with the same
|
|
81
90
|
message, before anything is written) and merges it **without overwriting
|
|
@@ -12,7 +12,8 @@ export interface FetchTemplateSnapshotOptions {
|
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Fetch and re-materialise create-ailk `version`'s `templates/apps/{web,api,mcp}/`
|
|
15
|
-
* tree, plus its `templates/database/` boot files
|
|
15
|
+
* tree, plus its `templates/database/` boot files and root `templates/tools/`
|
|
16
|
+
* files, from its published npm tarball.
|
|
16
17
|
*
|
|
17
18
|
* @throws FetchTemplateSnapshotError on an invalid version, an unreachable
|
|
18
19
|
* or malformed registry response, an integrity mismatch, or a symlink /
|
|
@@ -21,7 +21,7 @@ import { createHash } from "node:crypto";
|
|
|
21
21
|
import { gunzipSync } from "node:zlib";
|
|
22
22
|
import * as tar from "tar";
|
|
23
23
|
import { templateDestination } from "../copy.js";
|
|
24
|
-
import { DATABASE_BOOT_FILES } from "../template-record.js";
|
|
24
|
+
import { DATABASE_BOOT_FILES, ROOT_TOOL_FILES } from "../template-record.js";
|
|
25
25
|
import { MAX_TOTAL_SIZE_BYTES } from "./extract-module-bundle.js";
|
|
26
26
|
import { assertContentLengthWithinLimit, assertHttpsRegistryUrl, fetchTimeoutSignal, } from "./fetch-guard.js";
|
|
27
27
|
export const DEFAULT_AILK_NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
@@ -30,8 +30,8 @@ const VERSION_PATTERN = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;
|
|
|
30
30
|
/** The one tar path prefix a snapshot is read from, and the three app roots inside it. */
|
|
31
31
|
const TAR_ROOT = "package/templates/";
|
|
32
32
|
const APP_PREFIXES = ["apps/web/", "apps/api/", "apps/mcp/"];
|
|
33
|
-
/** The paths outside the app roots a snapshot keeps: a hub's three database boot files (#9569 DD8). */
|
|
34
|
-
const BOOT_FILES = new Set(DATABASE_BOOT_FILES);
|
|
33
|
+
/** The paths outside the app roots a snapshot keeps: a hub's three database boot files (#9569 DD8) and the root tools/ files the app configs require (#9654). */
|
|
34
|
+
const BOOT_FILES = new Set([...DATABASE_BOOT_FILES, ...ROOT_TOOL_FILES]);
|
|
35
35
|
export class FetchTemplateSnapshotError extends Error {
|
|
36
36
|
constructor(message) {
|
|
37
37
|
super(message);
|
|
@@ -113,7 +113,7 @@ async function fetchTarball(tarballUrl, integrity, version, fetchImpl) {
|
|
|
113
113
|
}
|
|
114
114
|
return buf;
|
|
115
115
|
}
|
|
116
|
-
/** The template-relative path (no `package/templates/` prefix) for a tar entry path, or undefined outside the three app trees
|
|
116
|
+
/** The template-relative path (no `package/templates/` prefix) for a tar entry path, or undefined outside the three app trees, the database boot files and the root tools/ files. */
|
|
117
117
|
function appRelativePath(tarPath) {
|
|
118
118
|
if (!tarPath.startsWith(TAR_ROOT))
|
|
119
119
|
return undefined;
|
|
@@ -180,7 +180,8 @@ function parseSnapshot(gunzipped, version) {
|
|
|
180
180
|
}
|
|
181
181
|
/**
|
|
182
182
|
* Fetch and re-materialise create-ailk `version`'s `templates/apps/{web,api,mcp}/`
|
|
183
|
-
* tree, plus its `templates/database/` boot files
|
|
183
|
+
* tree, plus its `templates/database/` boot files and root `templates/tools/`
|
|
184
|
+
* files, from its published npm tarball.
|
|
184
185
|
*
|
|
185
186
|
* @throws FetchTemplateSnapshotError on an invalid version, an unreachable
|
|
186
187
|
* or malformed registry response, an integrity mismatch, or a symlink /
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
import releaseScopeJson from "../../release-scope.json" with { type: "json" };
|
|
30
30
|
import { FetchModuleError, fetchModule } from "./fetch-module.js";
|
|
31
31
|
import { assertLicenseKeyShape } from "./license-key-files.js";
|
|
32
|
-
import {
|
|
32
|
+
import { LEVEL_LABEL, LEVEL_MODULES, PAID_MODULES, classifyModules, composeModuleSet, isAddition, levelOf, } from "./module-tier.js";
|
|
33
33
|
/**
|
|
34
34
|
* Where a refused run sends the buyer. `/pricing`, not `/pro`: there is no
|
|
35
35
|
* `/pro` route and there will not be one (#6439, operator decision OD-2) —
|
|
@@ -346,8 +346,7 @@ export async function deriveDesignLevel(options) {
|
|
|
346
346
|
*/
|
|
347
347
|
export async function resolveModuleSet(options) {
|
|
348
348
|
const namedList = options.named ?? [];
|
|
349
|
-
const
|
|
350
|
-
const isKeep = namedList.some((m) => !additions.includes(m));
|
|
349
|
+
const isKeep = namedList.some((m) => !isAddition(m));
|
|
351
350
|
if (isKeep) {
|
|
352
351
|
const modules = composeModuleSet(namedList, "free");
|
|
353
352
|
const { paid } = classifyModules(modules);
|
|
@@ -23,13 +23,6 @@ export declare const LEVEL_LABEL: Readonly<Record<Level, string>>;
|
|
|
23
23
|
* an add-on ON TOP of.
|
|
24
24
|
*/
|
|
25
25
|
export declare const ADD_ONS: readonly ModuleName[];
|
|
26
|
-
/**
|
|
27
|
-
* Included at Pro and above (the licence manifest's `pro` tier), but not
|
|
28
|
-
* switched on by default at any level (D1) — an authed app surface
|
|
29
|
-
* contributing no PUBLIC page to a marketing site. Naming it in `--modules`
|
|
30
|
-
* adds it without trimming, exactly like an add-on.
|
|
31
|
-
*/
|
|
32
|
-
export declare const OPT_IN_MODULES: readonly ModuleName[];
|
|
33
26
|
/** Whether naming `m` in `--modules` adds it without trimming the level default. */
|
|
34
27
|
export declare function isAddition(m: ModuleName): boolean;
|
|
35
28
|
/**
|
|
@@ -42,7 +35,8 @@ export declare const LEVEL_MODULES: Readonly<Record<Level, readonly ModuleName[]
|
|
|
42
35
|
/**
|
|
43
36
|
* Which level (or add-on status) a module belongs to (D2). `"free"` for
|
|
44
37
|
* `FREE_MODULES`, `"add-on"` for `ADD_ONS`, `"pro-plus"` for
|
|
45
|
-
* `PRO_PLUS_MODULES`, else `"pro"` (`workspace` included —
|
|
38
|
+
* `PRO_PLUS_MODULES`, else `"pro"` (`workspace` included — in the Pro default
|
|
39
|
+
* since #9696, the DECISION-LOG row in salessmyth/ailaunchkit-site#134). Pure.
|
|
46
40
|
*/
|
|
47
41
|
export declare function levelOf(m: ModuleName): Level | "add-on";
|
|
48
42
|
/**
|
package/dist/lib/module-tier.js
CHANGED
|
@@ -43,22 +43,22 @@ export const LEVEL_LABEL = {
|
|
|
43
43
|
* an add-on ON TOP of.
|
|
44
44
|
*/
|
|
45
45
|
export const ADD_ONS = ["commerce"];
|
|
46
|
-
/**
|
|
47
|
-
* Included at Pro and above (the licence manifest's `pro` tier), but not
|
|
48
|
-
* switched on by default at any level (D1) — an authed app surface
|
|
49
|
-
* contributing no PUBLIC page to a marketing site. Naming it in `--modules`
|
|
50
|
-
* adds it without trimming, exactly like an add-on.
|
|
51
|
-
*/
|
|
52
|
-
export const OPT_IN_MODULES = ["workspace"];
|
|
53
46
|
/** The Pro Plus membership: what Pro Plus switches on beyond Pro. */
|
|
54
47
|
const PRO_PLUS_MODULES = ["multi-tenant"];
|
|
55
|
-
/**
|
|
56
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Named modules that never trim the level default when composing a set (D2):
|
|
50
|
+
* the add-ons, and `workspace` — the authed /admin surface, which contributes
|
|
51
|
+
* no PUBLIC page. Since #9696 (reversing #6759 D1; the DECISION-LOG row dated
|
|
52
|
+
* 2026-10-24, salessmyth/ailaunchkit-site#134) `workspace` is IN the Pro and
|
|
53
|
+
* Pro Plus defaults, so naming it is a no-op there; below Pro it adds it, and
|
|
54
|
+
* the gate refuses it naming Pro.
|
|
55
|
+
*/
|
|
56
|
+
const ADDITIONS = [...ADD_ONS, "workspace"];
|
|
57
57
|
/** Whether naming `m` in `--modules` adds it without trimming the level default. */
|
|
58
58
|
export function isAddition(m) {
|
|
59
59
|
return ADDITIONS.includes(m);
|
|
60
60
|
}
|
|
61
|
-
const PRO_EXCLUDED = new Set([...
|
|
61
|
+
const PRO_EXCLUDED = new Set([...ADD_ONS, ...PRO_PLUS_MODULES]);
|
|
62
62
|
/**
|
|
63
63
|
* What a key at each level switches on with no `--modules` (D2). Derived —
|
|
64
64
|
* every list is `RECOGNIZED_MODULES.filter(...)`, so declaration order is
|
|
@@ -70,12 +70,13 @@ export const LEVEL_MODULES = Object.freeze({
|
|
|
70
70
|
pro: RECOGNIZED_MODULES.filter((m) => FREE_MODULES.includes(m) ||
|
|
71
71
|
(PAID_MODULES.includes(m) && !PRO_EXCLUDED.has(m))),
|
|
72
72
|
"pro-plus": RECOGNIZED_MODULES.filter((m) => FREE_MODULES.includes(m) ||
|
|
73
|
-
(PAID_MODULES.includes(m) && !
|
|
73
|
+
(PAID_MODULES.includes(m) && !ADD_ONS.includes(m))),
|
|
74
74
|
});
|
|
75
75
|
/**
|
|
76
76
|
* Which level (or add-on status) a module belongs to (D2). `"free"` for
|
|
77
77
|
* `FREE_MODULES`, `"add-on"` for `ADD_ONS`, `"pro-plus"` for
|
|
78
|
-
* `PRO_PLUS_MODULES`, else `"pro"` (`workspace` included —
|
|
78
|
+
* `PRO_PLUS_MODULES`, else `"pro"` (`workspace` included — in the Pro default
|
|
79
|
+
* since #9696, the DECISION-LOG row in salessmyth/ailaunchkit-site#134). Pure.
|
|
79
80
|
*/
|
|
80
81
|
export function levelOf(m) {
|
|
81
82
|
if (FREE_MODULES.includes(m))
|
|
@@ -794,7 +794,7 @@ export const MODULE_SLICES = {
|
|
|
794
794
|
webImports: [WEB_AUTH_ADAPTER_IMPORT, "packages/admin-ui"],
|
|
795
795
|
packages: {
|
|
796
796
|
"admin-ui": {
|
|
797
|
-
description: "Shared Admin
|
|
797
|
+
description: "Shared Admin components — the settings shell plus the General / Site / Team panels, and the Magnets (flow wizard, flow list) and Meetings (meeting types, meeting detail) screens, presentational only (data + save callbacks as props)",
|
|
798
798
|
// packages/templates is required because AdminSettingsShell
|
|
799
799
|
// composes AppShell from @working-theory/templates/shells — the same
|
|
800
800
|
// composition apps/web's own account page uses.
|
|
@@ -807,7 +807,7 @@ export const MODULE_SLICES = {
|
|
|
807
807
|
},
|
|
808
808
|
},
|
|
809
809
|
// SOURCE files only, and only the ones this module physically owns: the
|
|
810
|
-
//
|
|
810
|
+
// apps/web /admin route files and the two modules they share.
|
|
811
811
|
//
|
|
812
812
|
// `packages/admin-ui/**` is deliberately NOT listed (D1a). It is a
|
|
813
813
|
// whole package that is paid end to end, whose strip disposition is
|
|
@@ -832,6 +832,16 @@ export const MODULE_SLICES = {
|
|
|
832
832
|
"apps/web/app/[locale]/(authed)/admin/page.tsx",
|
|
833
833
|
"apps/web/app/[locale]/(authed)/admin/site/page.tsx",
|
|
834
834
|
"apps/web/app/[locale]/(authed)/admin/team/page.tsx",
|
|
835
|
+
// #9746 D10 — the shared nav, the client bindings, and the Magnets and
|
|
836
|
+
// Meetings tabs. Not routes themselves (the first two), but owned the
|
|
837
|
+
// same way: a keyless scaffold drops them with the pages that import
|
|
838
|
+
// them.
|
|
839
|
+
"apps/web/app/[locale]/(authed)/admin/admin-nav.ts",
|
|
840
|
+
"apps/web/app/[locale]/(authed)/admin/admin-panels.tsx",
|
|
841
|
+
"apps/web/app/[locale]/(authed)/admin/magnets/page.tsx",
|
|
842
|
+
"apps/web/app/[locale]/(authed)/admin/magnets/new/[kind]/page.tsx",
|
|
843
|
+
"apps/web/app/[locale]/(authed)/admin/meetings/page.tsx",
|
|
844
|
+
"apps/web/app/[locale]/(authed)/admin/meetings/[slug]/page.tsx",
|
|
835
845
|
],
|
|
836
846
|
// patches — the dependency add that delivers the shared package to the
|
|
837
847
|
// buyer's apps/web, mirroring docs-blog's own fumadocs-schema merge-keys
|
package/dist/starter-grid.d.ts
CHANGED
|
@@ -83,10 +83,10 @@ export declare const SHAPE_ROSTERS: Readonly<Record<BuildableShape, readonly Tem
|
|
|
83
83
|
* in the declaration order both keep. The plain name is the Pro one: it is
|
|
84
84
|
* the flagship and the demo (Sam, 2026-09-14, parent § D12).
|
|
85
85
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
86
|
+
* Both paid aliases carry `workspace` because a Pro or Pro Plus key switches
|
|
87
|
+
* it on (#9696, reversing parent § D15), and a template's `requires` is what
|
|
88
|
+
* the alias path fetches, since it derives no level. It is an authed app
|
|
89
|
+
* surface, so it contributes no PUBLIC row to either roster.
|
|
90
90
|
*
|
|
91
91
|
* `commerce` is a per-site add-on available at any level, so no alias exists
|
|
92
92
|
* FOR it (parent § D13); it still contributes rows to whichever alias takes
|
|
@@ -120,7 +120,7 @@ export declare const ALIASES: Readonly<{
|
|
|
120
120
|
readonly "marketing-site": {
|
|
121
121
|
readonly shape: "organization-product";
|
|
122
122
|
readonly design: "standard";
|
|
123
|
-
readonly modules: readonly ["marketing", "docs-blog", "scheduling", "signal-collectors"];
|
|
123
|
+
readonly modules: readonly ["marketing", "docs-blog", "scheduling", "signal-collectors", "workspace"];
|
|
124
124
|
readonly categories: readonly ["accounting", "legal", "consulting", "hvac", "roofing", "plumbing", "electrical", "landscaping", "auto-repair", "real-estate", "technology", "medical-specialty"];
|
|
125
125
|
readonly differences: {
|
|
126
126
|
readonly drop: readonly ["/blog", "/meet", "/meet/[slug]"];
|
|
@@ -140,7 +140,7 @@ export declare const ALIASES: Readonly<{
|
|
|
140
140
|
readonly "saas-product": {
|
|
141
141
|
readonly shape: "organization-product";
|
|
142
142
|
readonly design: "standard";
|
|
143
|
-
readonly modules: readonly ["marketing", "docs-blog", "scheduling", "signal-collectors", "multi-tenant"];
|
|
143
|
+
readonly modules: readonly ["marketing", "docs-blog", "scheduling", "signal-collectors", "workspace", "multi-tenant"];
|
|
144
144
|
readonly categories: readonly ["technology", "medical-specialty"];
|
|
145
145
|
readonly differences: {
|
|
146
146
|
readonly drop: readonly ["/blog", "/meet", "/meet/[slug]"];
|
package/dist/starter-grid.js
CHANGED
|
@@ -372,10 +372,10 @@ export const SHAPE_ROSTERS = Object.freeze({
|
|
|
372
372
|
* in the declaration order both keep. The plain name is the Pro one: it is
|
|
373
373
|
* the flagship and the demo (Sam, 2026-09-14, parent § D12).
|
|
374
374
|
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
375
|
+
* Both paid aliases carry `workspace` because a Pro or Pro Plus key switches
|
|
376
|
+
* it on (#9696, reversing parent § D15), and a template's `requires` is what
|
|
377
|
+
* the alias path fetches, since it derives no level. It is an authed app
|
|
378
|
+
* surface, so it contributes no PUBLIC row to either roster.
|
|
379
379
|
*
|
|
380
380
|
* `commerce` is a per-site add-on available at any level, so no alias exists
|
|
381
381
|
* FOR it (parent § D13); it still contributes rows to whichever alias takes
|
|
@@ -415,7 +415,13 @@ export const ALIASES = Object.freeze({
|
|
|
415
415
|
"marketing-site": {
|
|
416
416
|
shape: "organization-product",
|
|
417
417
|
design: "standard",
|
|
418
|
-
modules: [
|
|
418
|
+
modules: [
|
|
419
|
+
"marketing",
|
|
420
|
+
"docs-blog",
|
|
421
|
+
"scheduling",
|
|
422
|
+
"signal-collectors",
|
|
423
|
+
"workspace",
|
|
424
|
+
],
|
|
419
425
|
// The flagship is the general-purpose template: it carries the whole
|
|
420
426
|
// registry, so every group tile on the hub has at least one template.
|
|
421
427
|
categories: [
|
|
@@ -455,6 +461,7 @@ export const ALIASES = Object.freeze({
|
|
|
455
461
|
"docs-blog",
|
|
456
462
|
"scheduling",
|
|
457
463
|
"signal-collectors",
|
|
464
|
+
"workspace",
|
|
458
465
|
"multi-tenant",
|
|
459
466
|
],
|
|
460
467
|
categories: ["technology", "medical-specialty"],
|
package/dist/surfaces.js
CHANGED
|
@@ -725,6 +725,12 @@ export const ROUTE_SINCE = {
|
|
|
725
725
|
"(authed)/admin": "0.22.1",
|
|
726
726
|
"(authed)/admin/site": "0.22.1",
|
|
727
727
|
"(authed)/admin/team": "0.22.1",
|
|
728
|
+
// #9746 D10 — the Magnets and Meetings tabs. Genuinely new route
|
|
729
|
+
// directories, so they attach at today's fixed-group version.
|
|
730
|
+
"(authed)/admin/magnets": "0.46.0",
|
|
731
|
+
"(authed)/admin/magnets/new/[kind]": "0.46.0",
|
|
732
|
+
"(authed)/admin/meetings": "0.46.0",
|
|
733
|
+
"(authed)/admin/meetings/[slug]": "0.46.0",
|
|
728
734
|
// #5977 — the Pro content host's editor routes (spec 5872 FR1/FR2), added
|
|
729
735
|
// to apps/web by #5957. Genuinely new route directories, so they attach at
|
|
730
736
|
// today's fixed-group version, the same "attach at today's version" rule
|
|
@@ -785,6 +791,13 @@ export function surfaceForRouteDir(routeDir) {
|
|
|
785
791
|
return "core";
|
|
786
792
|
return GATEABLE_SURFACES.find((s) => s.routes.includes(top))?.id;
|
|
787
793
|
}
|
|
794
|
+
/** #9746 D10 — what each Magnets and Meetings tab page imports beside itself. */
|
|
795
|
+
const ADMIN_PANEL_ROUTE_DEPENDENCIES = [
|
|
796
|
+
"apps/web/lib/server-api.ts",
|
|
797
|
+
`${ROUTE_ROOT}/(authed)/waitlist/components/ForbiddenState.tsx`,
|
|
798
|
+
`${ROUTE_ROOT}/(authed)/admin/admin-nav.ts`,
|
|
799
|
+
`${ROUTE_ROOT}/(authed)/admin/admin-panels.tsx`,
|
|
800
|
+
];
|
|
788
801
|
/**
|
|
789
802
|
* Non-route consumer-side files a route's own source imports, that a sync
|
|
790
803
|
* must ALSO bring along so `--apply` never leaves a route that cannot
|
|
@@ -964,6 +977,8 @@ export const ROUTE_DEPENDENCIES = {
|
|
|
964
977
|
],
|
|
965
978
|
"(authed)/account/billing": [
|
|
966
979
|
"apps/web/lib/account-config.ts",
|
|
980
|
+
// #9401 D7 — the site's own Billing sections, the frozen stub the page imports.
|
|
981
|
+
"apps/web/lib/site-contributions.ts",
|
|
967
982
|
"apps/web/lib/server-api.ts",
|
|
968
983
|
`${ROUTE_ROOT}/(authed)/account/account-data.ts`,
|
|
969
984
|
`${ROUTE_ROOT}/(authed)/account/actions.ts`,
|
|
@@ -1034,6 +1049,8 @@ export const ROUTE_DEPENDENCIES = {
|
|
|
1034
1049
|
"(authed)/admin": [
|
|
1035
1050
|
"apps/web/lib/server-api.ts",
|
|
1036
1051
|
`${ROUTE_ROOT}/(authed)/waitlist/components/ForbiddenState.tsx`,
|
|
1052
|
+
// #9746 D8 — the shared nav every /admin tab imports.
|
|
1053
|
+
`${ROUTE_ROOT}/(authed)/admin/admin-nav.ts`,
|
|
1037
1054
|
],
|
|
1038
1055
|
"(authed)/leads": ["apps/web/lib/server-api.ts"],
|
|
1039
1056
|
// #5977 — the editor routes' own imports, read from their sources: both
|
|
@@ -1053,11 +1070,19 @@ export const ROUTE_DEPENDENCIES = {
|
|
|
1053
1070
|
"(authed)/admin/site": [
|
|
1054
1071
|
"apps/web/lib/server-api.ts",
|
|
1055
1072
|
`${ROUTE_ROOT}/(authed)/waitlist/components/ForbiddenState.tsx`,
|
|
1073
|
+
`${ROUTE_ROOT}/(authed)/admin/admin-nav.ts`,
|
|
1056
1074
|
],
|
|
1057
1075
|
"(authed)/admin/team": [
|
|
1058
1076
|
"apps/web/lib/server-api.ts",
|
|
1059
1077
|
`${ROUTE_ROOT}/(authed)/waitlist/components/ForbiddenState.tsx`,
|
|
1078
|
+
`${ROUTE_ROOT}/(authed)/admin/admin-nav.ts`,
|
|
1060
1079
|
],
|
|
1080
|
+
// #9746 D10 — the Magnets and Meetings tabs: the nav plus the client
|
|
1081
|
+
// bindings of the shared admin-ui components.
|
|
1082
|
+
"(authed)/admin/magnets": ADMIN_PANEL_ROUTE_DEPENDENCIES,
|
|
1083
|
+
"(authed)/admin/magnets/new/[kind]": ADMIN_PANEL_ROUTE_DEPENDENCIES,
|
|
1084
|
+
"(authed)/admin/meetings": ADMIN_PANEL_ROUTE_DEPENDENCIES,
|
|
1085
|
+
"(authed)/admin/meetings/[slug]": ADMIN_PANEL_ROUTE_DEPENDENCIES,
|
|
1061
1086
|
"(authed)/waitlist": ["apps/web/lib/server-api.ts"],
|
|
1062
1087
|
// #8843 D6 — the booking pages share one builder over the meetings read;
|
|
1063
1088
|
// `/private` returns the index frame that lives under `meet/`.
|
|
@@ -1115,6 +1140,10 @@ export const ROUTE_MESSAGE_NAMESPACES = {
|
|
|
1115
1140
|
"(authed)/edit/[type]/[slug]": ["edit"],
|
|
1116
1141
|
"(authed)/admin/site": ["admin"],
|
|
1117
1142
|
"(authed)/admin/team": ["admin"],
|
|
1143
|
+
"(authed)/admin/magnets": ["admin"],
|
|
1144
|
+
"(authed)/admin/magnets/new/[kind]": ["admin"],
|
|
1145
|
+
"(authed)/admin/meetings": ["admin"],
|
|
1146
|
+
"(authed)/admin/meetings/[slug]": ["admin"],
|
|
1118
1147
|
"(authed)/waitlist": ["waitlistDashboard.gate"],
|
|
1119
1148
|
// #7744 — the /team hub's empty state reads the `team` namespace.
|
|
1120
1149
|
team: ["team"],
|
|
@@ -18,12 +18,20 @@ export declare const REGENERATED_APP_PATHS: readonly string[];
|
|
|
18
18
|
* are bundle output, never recorded.
|
|
19
19
|
*/
|
|
20
20
|
export declare const DATABASE_BOOT_FILES: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* The root `tools/` files every app `jest.config.cjs` requires by its
|
|
23
|
+
* repo-relative path (#9654): the timezone pin (#8657) and the shared
|
|
24
|
+
* reporters (#9430) — `SNAPSHOT_FILES` in `scripts/build-templates.mjs`
|
|
25
|
+
* ships both at that path. Recorded and carried by `update` like an app
|
|
26
|
+
* file, so a merged config never names a file the site lacks.
|
|
27
|
+
*/
|
|
28
|
+
export declare const ROOT_TOOL_FILES: readonly string[];
|
|
21
29
|
/**
|
|
22
30
|
* Whether a destination path (`/`-separated, as `templateDestination`
|
|
23
31
|
* returns it) is one `update` ever records or touches (#8522 D2): one of
|
|
24
|
-
* the three `DATABASE_BOOT_FILES`, or under one of
|
|
25
|
-
* a `package.json`, not an `.env*` file, no
|
|
26
|
-
* path a generator rewrites after the copy.
|
|
32
|
+
* the three `DATABASE_BOOT_FILES` or the `ROOT_TOOL_FILES`, or under one of
|
|
33
|
+
* the three app trees, not a `package.json`, not an `.env*` file, no
|
|
34
|
+
* `.claude` segment, and not a path a generator rewrites after the copy.
|
|
27
35
|
*/
|
|
28
36
|
export declare function isRecordable(destRel: string): boolean;
|
|
29
37
|
/** The hex sha256 digest of `bytes` — the one hash every record row uses. */
|
package/dist/template-record.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Written beside `.ailk-site-manifest.json` at the site root, it lists every
|
|
6
6
|
* `apps/web/`, `apps/api/` and `apps/mcp/` file the base `templates/` copy
|
|
7
|
-
* wrote and no later layer rewrote
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* wrote and no later layer rewrote — and the few files outside them the
|
|
8
|
+
* record also carries (`DATABASE_BOOT_FILES`, `ROOT_TOOL_FILES`) — with the
|
|
9
|
+
* sha256 of the template's copy of that file and the create-ailk version it
|
|
10
|
+
* came from. `create-ailk update` (`update.ts`) reads it to tell an untouched copy from an owner's
|
|
10
11
|
* edit; `scaffold()` (`programmatic.ts`) writes it, as its last write, from
|
|
11
12
|
* the `onWrite` hook `copyTemplate` (`copy.ts`) calls once per file.
|
|
12
13
|
*
|
|
@@ -60,15 +61,27 @@ export const DATABASE_BOOT_FILES = [
|
|
|
60
61
|
"database/seed-test.ts",
|
|
61
62
|
];
|
|
62
63
|
const DATABASE_BOOT_SET = new Set(DATABASE_BOOT_FILES);
|
|
64
|
+
/**
|
|
65
|
+
* The root `tools/` files every app `jest.config.cjs` requires by its
|
|
66
|
+
* repo-relative path (#9654): the timezone pin (#8657) and the shared
|
|
67
|
+
* reporters (#9430) — `SNAPSHOT_FILES` in `scripts/build-templates.mjs`
|
|
68
|
+
* ships both at that path. Recorded and carried by `update` like an app
|
|
69
|
+
* file, so a merged config never names a file the site lacks.
|
|
70
|
+
*/
|
|
71
|
+
export const ROOT_TOOL_FILES = [
|
|
72
|
+
"tools/jest/pin-timezone.cjs",
|
|
73
|
+
"tools/jest/reporters.cjs",
|
|
74
|
+
];
|
|
75
|
+
const ROOT_TOOL_SET = new Set(ROOT_TOOL_FILES);
|
|
63
76
|
/**
|
|
64
77
|
* Whether a destination path (`/`-separated, as `templateDestination`
|
|
65
78
|
* returns it) is one `update` ever records or touches (#8522 D2): one of
|
|
66
|
-
* the three `DATABASE_BOOT_FILES`, or under one of
|
|
67
|
-
* a `package.json`, not an `.env*` file, no
|
|
68
|
-
* path a generator rewrites after the copy.
|
|
79
|
+
* the three `DATABASE_BOOT_FILES` or the `ROOT_TOOL_FILES`, or under one of
|
|
80
|
+
* the three app trees, not a `package.json`, not an `.env*` file, no
|
|
81
|
+
* `.claude` segment, and not a path a generator rewrites after the copy.
|
|
69
82
|
*/
|
|
70
83
|
export function isRecordable(destRel) {
|
|
71
|
-
if (DATABASE_BOOT_SET.has(destRel))
|
|
84
|
+
if (DATABASE_BOOT_SET.has(destRel) || ROOT_TOOL_SET.has(destRel))
|
|
72
85
|
return true;
|
|
73
86
|
if (!RECORDABLE_APP_ROOT.test(destRel))
|
|
74
87
|
return false;
|
package/dist/topology.js
CHANGED
|
@@ -515,9 +515,11 @@ import { readLocales } from "${WEB_I18N_PACKAGE}";
|
|
|
515
515
|
import { getTranslations } from "${NEXT_INTL_SERVER}";
|
|
516
516
|
import type { ReactElement } from "${REACT_PACKAGE}";
|
|
517
517
|
|
|
518
|
+
import { legalFootnote } from "../(auth)/legal-footnote";
|
|
518
519
|
import { resolveSignInCardText } from "../(auth)/sign-in/sign-in-text";
|
|
519
520
|
import { getActiveProviderIds } from "../../../lib/auth-env";
|
|
520
521
|
import { isAccountPath } from "../../../lib/auth-routes";
|
|
522
|
+
import { siteLogo } from "../../../lib/site-logo";
|
|
521
523
|
|
|
522
524
|
import { SignInGate } from "./sign-in-gate";
|
|
523
525
|
|
|
@@ -539,9 +541,7 @@ export async function SignedOutGate({
|
|
|
539
541
|
namespace: isAccount ? "account.gate" : "waitlistDashboard.gate",
|
|
540
542
|
});
|
|
541
543
|
const active = getActiveProviderIds();
|
|
542
|
-
const emailLink = active.includes("magic-link")
|
|
543
|
-
? { text: await resolveSignInCardText(locale) }
|
|
544
|
-
: undefined;
|
|
544
|
+
const emailLink = active.includes("magic-link");
|
|
545
545
|
const providers = active.filter((id): id is AuthPanelProvider =>
|
|
546
546
|
(SUPPORTED_PROVIDERS as readonly string[]).includes(id),
|
|
547
547
|
);
|
|
@@ -575,6 +575,25 @@ export async function SignedOutGate({
|
|
|
575
575
|
);
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
+
// The sign-in card: with the email link on, and on the member gate, which
|
|
579
|
+
// also wears the one card's frame — the mark, the toggle line to /sign-up
|
|
580
|
+
// and the Terms + Privacy acknowledgement (#9662).
|
|
581
|
+
const text =
|
|
582
|
+
emailLink || isAccount ? await resolveSignInCardText(locale) : undefined;
|
|
583
|
+
const card = text
|
|
584
|
+
? {
|
|
585
|
+
text,
|
|
586
|
+
emailLink,
|
|
587
|
+
...(isAccount
|
|
588
|
+
? {
|
|
589
|
+
logo: siteLogo(),
|
|
590
|
+
prospect: { ...text.prospect, href: localeHref(locale, "/sign-up") },
|
|
591
|
+
footnote: legalFootnote(locale, text.acknowledgement),
|
|
592
|
+
}
|
|
593
|
+
: {}),
|
|
594
|
+
}
|
|
595
|
+
: undefined;
|
|
596
|
+
|
|
578
597
|
return (
|
|
579
598
|
<SignInGate
|
|
580
599
|
labels={{
|
|
@@ -584,7 +603,7 @@ export async function SignedOutGate({
|
|
|
584
603
|
}}
|
|
585
604
|
signInPath={signInPath}
|
|
586
605
|
providers={providers}
|
|
587
|
-
{...(
|
|
606
|
+
{...(card ? { card } : {})}
|
|
588
607
|
/>
|
|
589
608
|
);
|
|
590
609
|
}
|
package/dist/update.d.ts
CHANGED
|
@@ -57,6 +57,6 @@ export interface UpdateArgs {
|
|
|
57
57
|
target: string | undefined;
|
|
58
58
|
help: boolean;
|
|
59
59
|
}
|
|
60
|
-
export declare const UPDATE_HELP = "create-ailk update \u2014 bring template fixes into a site's copied app code.\n\nUsage:\n create-ailk update [<target-dir>]\n\nArguments:\n <target-dir> The existing site. Defaults to the current dir.\n\nOptions:\n --help, -h Print this message.\n\nReads .ailk-template-files.json (written beside .ailk-site-manifest.json by\nevery template scaffold) to tell an untouched copy from an edit. An\nuntouched apps/web, apps/api or apps/mcp file whose template copy changed is
|
|
60
|
+
export declare const UPDATE_HELP = "create-ailk update \u2014 bring template fixes into a site's copied app code.\n\nUsage:\n create-ailk update [<target-dir>]\n\nArguments:\n <target-dir> The existing site. Defaults to the current dir.\n\nOptions:\n --help, -h Print this message.\n\nReads .ailk-template-files.json (written beside .ailk-site-manifest.json by\nevery template scaffold) to tell an untouched copy from an edit. An\nuntouched apps/web, apps/api or apps/mcp file, or a root tools/jest file the\napp jest configs require, whose template copy changed is overwritten. An\nedited file whose template copy also changed is three-way merged with\n`git` (git must be on PATH); a conflict leaves the file alone and is\nlisted under \"Needs review\". Every template test that imports a file\nleft under \"Needs review\" or \"Skipped\" (by a relative import) is held at the\nsite's version with it, its record entry is not advanced, and it is listed\nunder \"Held back with <file>\" \u2014 reconcile the file, then run update again to\nbring its tests forward. Every other file in the run still updates.\nA site with no record gets one on its first run, from the version its\n.ailk-site-manifest.json already records. A site scaffolded before\n@working-theory/mcp-server has its copied apps/mcp moved to the boot set:\nthe server and each module's paid MCP pack join apps/mcp/package.json, the\ncopied server files go, and apps/mcp/src/lib/paid-tools.generated.ts is\nrewritten on every run. A site scaffolded before @working-theory/api has its\ncopied apps/api moved to the boot file: the app becomes @working-theory/app-api,\nthe package and the six @working-theory/api-<module> packages join\napps/api/package.json, its bins and build:vercel delegate to the package, and\nthe copied server files go. Run `pnpm install` after either move, since the\napp's package.json gained dependencies. Commit before running, and review the\ndiff after.\n";
|
|
61
61
|
/** Parse the argv AFTER the `update` word. Strict `node:util` parseArgs, like `parseAdoptArgs`. */
|
|
62
62
|
export declare function parseUpdateArgs(argv: string[]): UpdateArgs;
|