create-ailk 0.11.0 → 0.11.2
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/dist/content-payloads.js +2 -2
- package/dist/lib/scaffold-render-sweep.d.ts +16 -0
- package/dist/lib/scaffold-render-sweep.js +52 -3
- package/dist/module-architecture.js +11 -0
- package/package.json +1 -1
- package/site-templates/shapes/local-business-service/content/en/Service/first-job.mdx +8 -8
- package/site-templates/shapes/local-business-service/content/en/Service/second-job.mdx +8 -8
- package/site-templates/shapes/local-business-service/content/en/Service/third-job.mdx +8 -8
- package/site-templates/shapes/organization-service/content/en/Service/first-engagement.mdx +8 -8
- package/site-templates/shapes/organization-service/content/en/Service/second-engagement.mdx +8 -8
- package/site-templates/shapes/organization-service/content/en/Service/third-engagement.mdx +8 -8
- package/site-templates/shapes/person-service/content/en/Service/first-engagement.mdx +8 -8
- package/site-templates/shapes/person-service/content/en/Service/second-engagement.mdx +8 -8
- package/site-templates/shapes/person-service/content/en/Service/third-engagement.mdx +8 -8
- package/templates/.env.example +13 -7
- package/templates/apps/api/.env.example +5 -0
- package/templates/apps/api/package.json +1 -1
- package/templates/apps/api/src/__tests__/cors.test.ts +91 -10
- package/templates/apps/api/src/__tests__/server.test.ts +5 -1
- package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +135 -0
- package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +238 -0
- package/templates/apps/api/src/config/index.ts +136 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +2 -2
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +142 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +1 -1
- package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +1 -1
- package/templates/apps/api/src/middleware/auth.ts +19 -21
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +1 -1
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +1 -1
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +168 -39
- package/templates/apps/api/src/routes/checkout/sessions.ts +20 -34
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +1 -1
- package/templates/apps/api/src/server.ts +21 -16
- package/templates/apps/mcp/package.json +1 -1
- package/templates/apps/web/CLAUDE.md +1 -1
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +1 -14
- package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/features/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/for/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +1 -14
- package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/layout.tsx +57 -56
- package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +1 -15
- package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +1 -14
- package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +4 -16
- package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +3 -15
- package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +0 -10
- package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +1 -14
- package/templates/apps/web/auth.ts +73 -13
- package/templates/apps/web/components/sign-out-trigger.tsx +3 -2
- package/templates/apps/web/components/signed-in-nav.tsx +58 -0
- package/versions.json +0 -1
package/dist/content-payloads.js
CHANGED
|
@@ -29,8 +29,8 @@ export const CONTENT_PAYLOADS = Object.freeze([
|
|
|
29
29
|
kind: "template-set",
|
|
30
30
|
name: "scaffold-commerce",
|
|
31
31
|
feature: "commerce",
|
|
32
|
-
version: "1.0.
|
|
33
|
-
digest: "
|
|
32
|
+
version: "1.0.1",
|
|
33
|
+
digest: "112704a7910dba3275defc0cb86b1b4f33fc8f262f4c09320e8f6b3a8d873916",
|
|
34
34
|
sourceRoot: "packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce",
|
|
35
35
|
files: Object.freeze([
|
|
36
36
|
"references/lookup-keys-template.md",
|
|
@@ -103,3 +103,19 @@ export declare function assessConfigGatedRoute(input: {
|
|
|
103
103
|
* a socket) throws rather than being silently followed or skipped.
|
|
104
104
|
*/
|
|
105
105
|
export declare function listPublicFiles(dir: string): string[];
|
|
106
|
+
/** The slug the sweep requests to prove a detail route 404s an unknown slug. */
|
|
107
|
+
export declare const UNKNOWN_SLUG = "ailk-unknown-slug-7379";
|
|
108
|
+
/** `/features/[slug]` → `/features`; null unless `[slug]` is the one dynamic segment and the last. */
|
|
109
|
+
export declare function detailRoutePrefix(route: string): string | null;
|
|
110
|
+
/** The sorted basenames (sans `.mdx`) of the `*.mdx` files directly in `dir`; [] when `dir` is absent. */
|
|
111
|
+
export declare function listSeedSlugs(dir: string): string[];
|
|
112
|
+
/** An unknown slug must answer exactly 404, with no redirect. A 500 is the #7379 failure; a 200 means no 404 branch ran. */
|
|
113
|
+
export declare function assessUnknownSlug(input: {
|
|
114
|
+
route: string;
|
|
115
|
+
hops: RedirectHop[];
|
|
116
|
+
status: number | null;
|
|
117
|
+
}): SweepVerdict;
|
|
118
|
+
/** Fails, naming each route, when `.next/prerender-manifest.json`'s `dynamicRoutes` has a key under `/[locale]/`. */
|
|
119
|
+
export declare function assessPrerenderManifest(manifest: {
|
|
120
|
+
dynamicRoutes?: Record<string, unknown>;
|
|
121
|
+
}): SweepVerdict;
|
|
@@ -13,10 +13,17 @@
|
|
|
13
13
|
* not cost a templates build, an install and a `next build`. Each is a pure
|
|
14
14
|
* function of what the driver observed, so
|
|
15
15
|
* `__tests__/verify-scaffold-render-sweep.test.ts` drives them directly. The
|
|
16
|
-
* driver loads this module from `dist/`. Only `listPublicFiles`
|
|
17
|
-
* filesystem, and none of it touches the network.
|
|
16
|
+
* driver loads this module from `dist/`. Only `listPublicFiles` and
|
|
17
|
+
* `listSeedSlugs` touch the filesystem, and none of it touches the network.
|
|
18
|
+
*
|
|
19
|
+
* #7379 added two sweeps. A starter roster's detail row that names a seed
|
|
20
|
+
* directory (`/features/[slug]` → `content/en/Feature`) is probed: each seed
|
|
21
|
+
* must render, and `UNKNOWN_SLUG` must answer 404. And the build's
|
|
22
|
+
* `prerender-manifest.json` must register no `/[locale]/…` route as an
|
|
23
|
+
* on-demand prerender — under the cookie-reading locale layout, such a route
|
|
24
|
+
* answers 500 for every slug, seeded or not.
|
|
18
25
|
*/
|
|
19
|
-
import { readdirSync } from "node:fs";
|
|
26
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
20
27
|
import { join } from "node:path";
|
|
21
28
|
/** More hops than this is a redirect chain, not a render. */
|
|
22
29
|
export const MAX_REDIRECTS = 5;
|
|
@@ -234,3 +241,45 @@ function listFilesUnder(dir, relPrefix) {
|
|
|
234
241
|
}
|
|
235
242
|
return out;
|
|
236
243
|
}
|
|
244
|
+
/** The slug the sweep requests to prove a detail route 404s an unknown slug. */
|
|
245
|
+
export const UNKNOWN_SLUG = "ailk-unknown-slug-7379";
|
|
246
|
+
/** `/features/[slug]` → `/features`; null unless `[slug]` is the one dynamic segment and the last. */
|
|
247
|
+
export function detailRoutePrefix(route) {
|
|
248
|
+
const match = /^((?:\/[^/[\]]+)+)\/\[slug\]$/.exec(route);
|
|
249
|
+
return match?.[1] ?? null;
|
|
250
|
+
}
|
|
251
|
+
/** The sorted basenames (sans `.mdx`) of the `*.mdx` files directly in `dir`; [] when `dir` is absent. */
|
|
252
|
+
export function listSeedSlugs(dir) {
|
|
253
|
+
if (!existsSync(dir))
|
|
254
|
+
return [];
|
|
255
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
256
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".mdx"))
|
|
257
|
+
.map((entry) => entry.name.slice(0, -".mdx".length))
|
|
258
|
+
.sort();
|
|
259
|
+
}
|
|
260
|
+
/** An unknown slug must answer exactly 404, with no redirect. A 500 is the #7379 failure; a 200 means no 404 branch ran. */
|
|
261
|
+
export function assessUnknownSlug(input) {
|
|
262
|
+
const { route, hops, status } = input;
|
|
263
|
+
const first = hops[0];
|
|
264
|
+
if (first !== undefined) {
|
|
265
|
+
return { ok: false, reason: `${route} -> ${first.status} redirect (an unknown slug must answer 404, not redirect)` };
|
|
266
|
+
}
|
|
267
|
+
if (status === 200)
|
|
268
|
+
return { ok: false, reason: `${route} -> 200 (no 404 branch ran for an unknown slug)` };
|
|
269
|
+
if (status !== 404)
|
|
270
|
+
return { ok: false, reason: `${route} -> status ${status} (expected 404 for an unknown slug)` };
|
|
271
|
+
return { ok: true, reason: "404" };
|
|
272
|
+
}
|
|
273
|
+
/** Fails, naming each route, when `.next/prerender-manifest.json`'s `dynamicRoutes` has a key under `/[locale]/`. */
|
|
274
|
+
export function assessPrerenderManifest(manifest) {
|
|
275
|
+
const locale = Object.keys(manifest.dynamicRoutes ?? {})
|
|
276
|
+
.filter((route) => route.startsWith("/[locale]/"))
|
|
277
|
+
.sort();
|
|
278
|
+
if (locale.length > 0) {
|
|
279
|
+
return {
|
|
280
|
+
ok: false,
|
|
281
|
+
reason: `on-demand prerender under the cookie-reading locale layout (500s every slug, #7379): ${locale.join(", ")}`,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return { ok: true, reason: "no /[locale] on-demand prerender route" };
|
|
285
|
+
}
|
|
@@ -790,6 +790,15 @@ export const MODULE_SLICES = {
|
|
|
790
790
|
// deliverable by BOTH bundles.
|
|
791
791
|
"apps/api/src/services/inbox-messages.ts",
|
|
792
792
|
"apps/api/src/routes/workspaces/messages.ts",
|
|
793
|
+
// #7399 — the two siblings #6216 left `workspace`-only. They register
|
|
794
|
+
// under that same `workspace || multi-tenant` gate, so a scaffold with
|
|
795
|
+
// `multi-tenant` and without `workspace` loaded them with no file behind
|
|
796
|
+
// the specifier and 500'd every request at server construction. Co-owned
|
|
797
|
+
// with `workspace` (see that slice's entry below); both import only
|
|
798
|
+
// `lib/tenant-db.ts` (owned here) and base files.
|
|
799
|
+
// `__tests__/tenancy-slice-resolution.test.ts` holds the whole gate set.
|
|
800
|
+
"apps/api/src/routes/workspaces/general.ts",
|
|
801
|
+
"apps/api/src/routes/workspaces/members.ts",
|
|
793
802
|
"apps/api/src/lib/tenant-db.ts",
|
|
794
803
|
"apps/api/src/lib/ws-token.ts",
|
|
795
804
|
// #6157 D16 — the magnet Admin authoring surface, co-owned with
|
|
@@ -890,6 +899,8 @@ export const MODULE_SLICES = {
|
|
|
890
899
|
"apps/web/app/[locale]/(authed)/admin/page.tsx",
|
|
891
900
|
"apps/web/app/[locale]/(authed)/admin/site/page.tsx",
|
|
892
901
|
"apps/web/app/[locale]/(authed)/admin/team/page.tsx",
|
|
902
|
+
// Co-owned with `multi-tenant` (#7399) — see that slice's entry: both
|
|
903
|
+
// register under the workspace||multi-tenant gate.
|
|
893
904
|
"apps/api/src/routes/workspaces/general.ts",
|
|
894
905
|
"apps/api/src/routes/workspaces/members.ts",
|
|
895
906
|
// Co-owned with `multi-tenant` (#6216) — see that slice's entry: the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-ailk",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
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",
|
|
@@ -11,29 +11,29 @@ schema:
|
|
|
11
11
|
name: "Your Company"
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
# {First job}
|
|
14
|
+
# \{First job}
|
|
15
15
|
|
|
16
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
17
17
|
three sentences, no more — the detail belongs under the headings below.}
|
|
18
18
|
|
|
19
19
|
## What it covers
|
|
20
20
|
|
|
21
|
-
- {The first thing you actually do}
|
|
22
|
-
- {The second thing you actually do}
|
|
23
|
-
- {The third thing you actually do}
|
|
21
|
+
- \{The first thing you actually do}
|
|
22
|
+
- \{The second thing you actually do}
|
|
23
|
+
- \{The third thing you actually do}
|
|
24
24
|
|
|
25
25
|
## How it runs
|
|
26
26
|
|
|
27
|
-
{One paragraph on the shape of the visit: how it is scheduled, how long it
|
|
27
|
+
\{One paragraph on the shape of the visit: how it is scheduled, how long it
|
|
28
28
|
takes, who turns up, and what you need from the customer beforehand.}
|
|
29
29
|
|
|
30
30
|
## What you end up with
|
|
31
31
|
|
|
32
|
-
{One paragraph on the result. Be concrete — describe the property when the
|
|
32
|
+
\{One paragraph on the result. Be concrete — describe the property when the
|
|
33
33
|
crew drives away.}
|
|
34
34
|
|
|
35
35
|
## What it costs
|
|
36
36
|
|
|
37
|
-
{One line on the pricing shape — flat rate, hourly, or by the job — and what it
|
|
37
|
+
\{One line on the pricing shape — flat rate, hourly, or by the job — and what it
|
|
38
38
|
excludes. Replace with your real numbers, or delete this section and let a
|
|
39
39
|
call do it.}
|
|
@@ -11,29 +11,29 @@ schema:
|
|
|
11
11
|
name: "Your Company"
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
# {Second job}
|
|
14
|
+
# \{Second job}
|
|
15
15
|
|
|
16
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
17
17
|
three sentences, no more — the detail belongs under the headings below.}
|
|
18
18
|
|
|
19
19
|
## What it covers
|
|
20
20
|
|
|
21
|
-
- {The first thing you actually do}
|
|
22
|
-
- {The second thing you actually do}
|
|
23
|
-
- {The third thing you actually do}
|
|
21
|
+
- \{The first thing you actually do}
|
|
22
|
+
- \{The second thing you actually do}
|
|
23
|
+
- \{The third thing you actually do}
|
|
24
24
|
|
|
25
25
|
## How it runs
|
|
26
26
|
|
|
27
|
-
{One paragraph on the shape of the visit: how it is scheduled, how long it
|
|
27
|
+
\{One paragraph on the shape of the visit: how it is scheduled, how long it
|
|
28
28
|
takes, who turns up, and what you need from the customer beforehand.}
|
|
29
29
|
|
|
30
30
|
## What you end up with
|
|
31
31
|
|
|
32
|
-
{One paragraph on the result. Be concrete — describe the property when the
|
|
32
|
+
\{One paragraph on the result. Be concrete — describe the property when the
|
|
33
33
|
crew drives away.}
|
|
34
34
|
|
|
35
35
|
## What it costs
|
|
36
36
|
|
|
37
|
-
{One line on the pricing shape — flat rate, hourly, or by the job — and what it
|
|
37
|
+
\{One line on the pricing shape — flat rate, hourly, or by the job — and what it
|
|
38
38
|
excludes. Replace with your real numbers, or delete this section and let a
|
|
39
39
|
call do it.}
|
|
@@ -11,29 +11,29 @@ schema:
|
|
|
11
11
|
name: "Your Company"
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
# {Third job}
|
|
14
|
+
# \{Third job}
|
|
15
15
|
|
|
16
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
17
17
|
three sentences, no more — the detail belongs under the headings below.}
|
|
18
18
|
|
|
19
19
|
## What it covers
|
|
20
20
|
|
|
21
|
-
- {The first thing you actually do}
|
|
22
|
-
- {The second thing you actually do}
|
|
23
|
-
- {The third thing you actually do}
|
|
21
|
+
- \{The first thing you actually do}
|
|
22
|
+
- \{The second thing you actually do}
|
|
23
|
+
- \{The third thing you actually do}
|
|
24
24
|
|
|
25
25
|
## How it runs
|
|
26
26
|
|
|
27
|
-
{One paragraph on the shape of the visit: how it is scheduled, how long it
|
|
27
|
+
\{One paragraph on the shape of the visit: how it is scheduled, how long it
|
|
28
28
|
takes, who turns up, and what you need from the customer beforehand.}
|
|
29
29
|
|
|
30
30
|
## What you end up with
|
|
31
31
|
|
|
32
|
-
{One paragraph on the result. Be concrete — describe the property when the
|
|
32
|
+
\{One paragraph on the result. Be concrete — describe the property when the
|
|
33
33
|
crew drives away.}
|
|
34
34
|
|
|
35
35
|
## What it costs
|
|
36
36
|
|
|
37
|
-
{One line on the pricing shape — flat rate, hourly, or by the job — and what it
|
|
37
|
+
\{One line on the pricing shape — flat rate, hourly, or by the job — and what it
|
|
38
38
|
excludes. Replace with your real numbers, or delete this section and let a
|
|
39
39
|
call do it.}
|
|
@@ -10,29 +10,29 @@ schema:
|
|
|
10
10
|
name: "Your Company"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# {First engagement}
|
|
13
|
+
# \{First engagement}
|
|
14
14
|
|
|
15
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
15
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
16
|
three sentences, no more — the detail belongs under the headings below.}
|
|
17
17
|
|
|
18
18
|
## What it covers
|
|
19
19
|
|
|
20
|
-
- {The first thing you actually do}
|
|
21
|
-
- {The second thing you actually do}
|
|
22
|
-
- {The third thing you actually do}
|
|
20
|
+
- \{The first thing you actually do}
|
|
21
|
+
- \{The second thing you actually do}
|
|
22
|
+
- \{The third thing you actually do}
|
|
23
23
|
|
|
24
24
|
## How it runs
|
|
25
25
|
|
|
26
|
-
{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
26
|
+
\{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
27
27
|
who is involved on both sides, and what a week looks like.}
|
|
28
28
|
|
|
29
29
|
## What you end up with
|
|
30
30
|
|
|
31
|
-
{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
31
|
+
\{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
32
32
|
feeling.}
|
|
33
33
|
|
|
34
34
|
## What it costs
|
|
35
35
|
|
|
36
|
-
{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
36
|
+
\{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
37
37
|
excludes. Replace with your real numbers, or delete this section and let the
|
|
38
38
|
call do it.}
|
|
@@ -10,29 +10,29 @@ schema:
|
|
|
10
10
|
name: "Your Company"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# {Second engagement}
|
|
13
|
+
# \{Second engagement}
|
|
14
14
|
|
|
15
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
15
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
16
|
three sentences, no more — the detail belongs under the headings below.}
|
|
17
17
|
|
|
18
18
|
## What it covers
|
|
19
19
|
|
|
20
|
-
- {The first thing you actually do}
|
|
21
|
-
- {The second thing you actually do}
|
|
22
|
-
- {The third thing you actually do}
|
|
20
|
+
- \{The first thing you actually do}
|
|
21
|
+
- \{The second thing you actually do}
|
|
22
|
+
- \{The third thing you actually do}
|
|
23
23
|
|
|
24
24
|
## How it runs
|
|
25
25
|
|
|
26
|
-
{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
26
|
+
\{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
27
27
|
who is involved on both sides, and what a week looks like.}
|
|
28
28
|
|
|
29
29
|
## What you end up with
|
|
30
30
|
|
|
31
|
-
{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
31
|
+
\{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
32
32
|
feeling.}
|
|
33
33
|
|
|
34
34
|
## What it costs
|
|
35
35
|
|
|
36
|
-
{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
36
|
+
\{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
37
37
|
excludes. Replace with your real numbers, or delete this section and let the
|
|
38
38
|
call do it.}
|
|
@@ -10,29 +10,29 @@ schema:
|
|
|
10
10
|
name: "Your Company"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# {Third engagement}
|
|
13
|
+
# \{Third engagement}
|
|
14
14
|
|
|
15
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
15
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
16
|
three sentences, no more — the detail belongs under the headings below.}
|
|
17
17
|
|
|
18
18
|
## What it covers
|
|
19
19
|
|
|
20
|
-
- {The first thing you actually do}
|
|
21
|
-
- {The second thing you actually do}
|
|
22
|
-
- {The third thing you actually do}
|
|
20
|
+
- \{The first thing you actually do}
|
|
21
|
+
- \{The second thing you actually do}
|
|
22
|
+
- \{The third thing you actually do}
|
|
23
23
|
|
|
24
24
|
## How it runs
|
|
25
25
|
|
|
26
|
-
{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
26
|
+
\{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
27
27
|
who is involved on both sides, and what a week looks like.}
|
|
28
28
|
|
|
29
29
|
## What you end up with
|
|
30
30
|
|
|
31
|
-
{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
31
|
+
\{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
32
32
|
feeling.}
|
|
33
33
|
|
|
34
34
|
## What it costs
|
|
35
35
|
|
|
36
|
-
{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
36
|
+
\{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
37
37
|
excludes. Replace with your real numbers, or delete this section and let the
|
|
38
38
|
call do it.}
|
|
@@ -10,29 +10,29 @@ schema:
|
|
|
10
10
|
name: "Your Name"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# {First engagement}
|
|
13
|
+
# \{First engagement}
|
|
14
14
|
|
|
15
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
15
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
16
|
three sentences, no more — the detail belongs under the headings below.}
|
|
17
17
|
|
|
18
18
|
## What it covers
|
|
19
19
|
|
|
20
|
-
- {The first thing you actually do}
|
|
21
|
-
- {The second thing you actually do}
|
|
22
|
-
- {The third thing you actually do}
|
|
20
|
+
- \{The first thing you actually do}
|
|
21
|
+
- \{The second thing you actually do}
|
|
22
|
+
- \{The third thing you actually do}
|
|
23
23
|
|
|
24
24
|
## How it runs
|
|
25
25
|
|
|
26
|
-
{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
26
|
+
\{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
27
27
|
who is involved, and what a week looks like.}
|
|
28
28
|
|
|
29
29
|
## What you end up with
|
|
30
30
|
|
|
31
|
-
{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
31
|
+
\{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
32
32
|
feeling.}
|
|
33
33
|
|
|
34
34
|
## What it costs
|
|
35
35
|
|
|
36
|
-
{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
36
|
+
\{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
37
37
|
excludes. Replace with your real numbers, or delete this section and let the
|
|
38
38
|
call do it.}
|
|
@@ -10,29 +10,29 @@ schema:
|
|
|
10
10
|
name: "Your Name"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# {Second engagement}
|
|
13
|
+
# \{Second engagement}
|
|
14
14
|
|
|
15
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
15
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
16
|
three sentences, no more — the detail belongs under the headings below.}
|
|
17
17
|
|
|
18
18
|
## What it covers
|
|
19
19
|
|
|
20
|
-
- {The first thing you actually do}
|
|
21
|
-
- {The second thing you actually do}
|
|
22
|
-
- {The third thing you actually do}
|
|
20
|
+
- \{The first thing you actually do}
|
|
21
|
+
- \{The second thing you actually do}
|
|
22
|
+
- \{The third thing you actually do}
|
|
23
23
|
|
|
24
24
|
## How it runs
|
|
25
25
|
|
|
26
|
-
{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
26
|
+
\{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
27
27
|
who is involved, and what a week looks like.}
|
|
28
28
|
|
|
29
29
|
## What you end up with
|
|
30
30
|
|
|
31
|
-
{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
31
|
+
\{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
32
32
|
feeling.}
|
|
33
33
|
|
|
34
34
|
## What it costs
|
|
35
35
|
|
|
36
|
-
{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
36
|
+
\{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
37
37
|
excludes. Replace with your real numbers, or delete this section and let the
|
|
38
38
|
call do it.}
|
|
@@ -10,29 +10,29 @@ schema:
|
|
|
10
10
|
name: "Your Name"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# {Third engagement}
|
|
13
|
+
# \{Third engagement}
|
|
14
14
|
|
|
15
|
-
{Open with the situation a reader is in when they come looking for this. Two or
|
|
15
|
+
\{Open with the situation a reader is in when they come looking for this. Two or
|
|
16
16
|
three sentences, no more — the detail belongs under the headings below.}
|
|
17
17
|
|
|
18
18
|
## What it covers
|
|
19
19
|
|
|
20
|
-
- {The first thing you actually do}
|
|
21
|
-
- {The second thing you actually do}
|
|
22
|
-
- {The third thing you actually do}
|
|
20
|
+
- \{The first thing you actually do}
|
|
21
|
+
- \{The second thing you actually do}
|
|
22
|
+
- \{The third thing you actually do}
|
|
23
23
|
|
|
24
24
|
## How it runs
|
|
25
25
|
|
|
26
|
-
{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
26
|
+
\{One paragraph on the shape of the engagement: how it starts, how long it runs,
|
|
27
27
|
who is involved, and what a week looks like.}
|
|
28
28
|
|
|
29
29
|
## What you end up with
|
|
30
30
|
|
|
31
|
-
{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
31
|
+
\{One paragraph on the deliverable. Be concrete — name the artefact, not the
|
|
32
32
|
feeling.}
|
|
33
33
|
|
|
34
34
|
## What it costs
|
|
35
35
|
|
|
36
|
-
{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
36
|
+
\{One line on the pricing shape — fixed fee, retainer, day rate — and what it
|
|
37
37
|
excludes. Replace with your real numbers, or delete this section and let the
|
|
38
38
|
call do it.}
|
package/templates/.env.example
CHANGED
|
@@ -50,10 +50,6 @@ CONTENT_ADAPTER=mdx
|
|
|
50
50
|
# Developers → Webhooks → <your endpoint> → Signing secret.
|
|
51
51
|
# Format: whsec_*. Server-only — must NOT be prefixed with NEXT_PUBLIC_.
|
|
52
52
|
# STRIPE_WEBHOOK_SECRET=
|
|
53
|
-
# Internal URL of the billing service — used by marketing-api's webhook
|
|
54
|
-
# proxy (POST /v1/webhooks/stripe) to forward verified deliveries. Format:
|
|
55
|
-
# https://<vercel-deployment>.vercel.app (no trailing slash, no path).
|
|
56
|
-
# BILLING_SERVICE_URL=
|
|
57
53
|
|
|
58
54
|
# ── Auth (Better Auth — apps/web only) ───────────────────────────────────────
|
|
59
55
|
# BETTER_AUTH_URL=http://localhost:3000
|
|
@@ -63,10 +59,20 @@ CONTENT_ADAPTER=mdx
|
|
|
63
59
|
# Unset in production, either one makes the API log a startup warning; the
|
|
64
60
|
# API keeps running.
|
|
65
61
|
# FRONTEND_URL is the site the browser loads (no trailing slash). Set it on the
|
|
66
|
-
# API project:
|
|
67
|
-
#
|
|
68
|
-
#
|
|
62
|
+
# API project: it is the first trusted origin for CORS, cookie-authenticated
|
|
63
|
+
# writes and checkout redirects. Unset in production, those three trust only
|
|
64
|
+
# AILK_TRUSTED_ORIGINS below (with neither set, they refuse every browser
|
|
65
|
+
# origin and checkout answers 500 to a caller without X-Internal-Auth), and the
|
|
66
|
+
# billing-portal return URLs fall back to http://localhost:3000.
|
|
69
67
|
# FRONTEND_URL=https://your-domain.com
|
|
68
|
+
# AILK_TRUSTED_ORIGINS lists MORE browser origins the API trusts, beside
|
|
69
|
+
# FRONTEND_URL — the Admin app and spoke sites a hub API serves. Comma-separated
|
|
70
|
+
# exact origins, written as a browser sends them: scheme + host (+ port), no
|
|
71
|
+
# path, no trailing slash, lower-case. `*`, wildcard hosts and any other form
|
|
72
|
+
# are refused and the API does not start; production requires https. Each
|
|
73
|
+
# listed origin gets CORS reads, cookie writes and checkout-redirect trust, so
|
|
74
|
+
# list ONLY origins the deployment owner operates — never another party's site.
|
|
75
|
+
# AILK_TRUSTED_ORIGINS=https://admin.your-domain.com,https://spoke.example
|
|
70
76
|
# OSS_API_INTERNAL_SECRET gates POST /v1/checkout/sessions. Unset, the route
|
|
71
77
|
# admits every caller. Set, it answers 401 to any caller that does not send it
|
|
72
78
|
# as X-Internal-Auth — including the MCP start_purchase tool and a browser
|
|
@@ -15,6 +15,11 @@ PORT=3002
|
|
|
15
15
|
# Frontend URL (for CORS)
|
|
16
16
|
# =============================================================================
|
|
17
17
|
FRONTEND_URL=http://localhost:3000
|
|
18
|
+
# More trusted browser origins (Admin app, spoke sites): comma-separated exact
|
|
19
|
+
# origins, no path or trailing slash; `*` is refused at startup; https in production.
|
|
20
|
+
# Each listed origin gets credentialed CORS, cookie writes and checkout-redirect
|
|
21
|
+
# trust — list only origins the deployment owner operates.
|
|
22
|
+
# AILK_TRUSTED_ORIGINS=https://admin.your-domain.com,https://spoke.example
|
|
18
23
|
|
|
19
24
|
# =============================================================================
|
|
20
25
|
# Local Database (required in production)
|