create-ailk 0.11.4 → 0.11.5

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.
@@ -821,7 +821,7 @@
821
821
  "sourcePath": "packages/ui/src/blocks/AssetLightbox.tsx",
822
822
  "importPath": "@working-theory/ui/blocks",
823
823
  "exported": true,
824
- "description": "The asset detail lightbox: the image with zoom on the stage, a Details rail with in-place pencil-edit Title and Description, then Filename/Type/Size/Dimensions/Created, then Tags (from the seeded set the caller passes), then Copy URL/Replace/Delete. Renders inside a ResponsiveSheet — the SAME field sequence in both its dialog and sheet forms (: one field array, walked once, shared by both forms).",
824
+ "description": "The asset detail lightbox: the image with zoom on the stage, a Details rail with in-place pencil-edit Title and Description, then Filename/Type/Size/Dimensions/Created, then Tags (from the seeded set the caller passes), then Copy link/Replace/Delete. Renders inside a ResponsiveSheet — the SAME field sequence in both layouts (: one field array, walked once, shared by both).",
825
825
  "descriptionSource": "doc-comment",
826
826
  "descriptionGrade": "strong",
827
827
  "sectionType": null
@@ -134,7 +134,7 @@ Import: `import { X } from "@working-theory/ui/blocks";` (or from the `@working-
134
134
  | `ArticlePager` | The footer prev/next pager. Given the previous and next destinations — docs pages in tree order, or blog posts in date order — renders two link tiles (a directional label + the destination title). Either side may be absent (first / last item) — the present side still anchors to its edge. Renders nothing when both sides are absent. | `import { ArticlePager } from "@working-theory/ui/blocks"` |
135
135
  | `AskAiCommandGroup` | The ⌘K palette's composable "Ask AI" group; one CommandItem per provider seeding "About <entity>: <query>" (or the entity promptText when the query is empty); composed by the consumer's own CommandDialog. | `import { AskAiCommandGroup } from "@working-theory/ui/blocks"` |
136
136
  | `AskAiProviderRow` | The ONE shared provider-link row every ask-AI placement composes — the AskAi section (band + ticker variant) and the Hero `askAi` opt-in all render THIS block, never a per-placement fork. Renders a bounded set of five measured providers, each a deep link seeded with an AUTHORED `promptText` — the prompt is always consumer-supplied data, never derived from page context (headline, entity name, etc.). | `import { AskAiProviderRow } from "@working-theory/ui/blocks"` |
137
- | `AssetLightbox` | The asset detail lightbox: the image with zoom on the stage, a Details rail with in-place pencil-edit Title and Description, then Filename/Type/Size/Dimensions/Created, then Tags (from the seeded set the caller passes), then Copy URL/Replace/Delete. Renders inside a ResponsiveSheet — the SAME field sequence in both its dialog and sheet forms (: one field array, walked once, shared by both forms). | `import { AssetLightbox } from "@working-theory/ui/blocks"` |
137
+ | `AssetLightbox` | The asset detail lightbox: the image with zoom on the stage, a Details rail with in-place pencil-edit Title and Description, then Filename/Type/Size/Dimensions/Created, then Tags (from the seeded set the caller passes), then Copy link/Replace/Delete. Renders inside a ResponsiveSheet — the SAME field sequence in both layouts (: one field array, walked once, shared by both). | `import { AssetLightbox } from "@working-theory/ui/blocks"` |
138
138
  | `AuthCard` | Multi-flow auth card: sign-in, sign-up, invitation, forgot, reset and sent, from one skeleton. One self-contained card renders every auth surface a site needs: signing in, signing up, a closed sign-up that requires an invitation, requesting a password reset, choosing a new password, and the check-your-email state that follows a magic link or a reset request. | `import { AuthCard } from "@working-theory/ui/blocks"` |
139
139
  | `AwardBadgePlaceholder` | The labeled placeholder an Awards badge slot renders when no image has been supplied — mirrors MediaPlaceholder's role but in an award-chevron/ laurel badge silhouette rather than a generic photo frame, since an unfilled award slot should read as "an award badge goes here," not "a photo goes here." The shape (a laurel-flanked medallion over a chevron ribbon) is a hand-drawn SVG outline — never a copied G2/Capterra/Apollo asset. | internal — compose from `packages/ui/src/blocks/AwardBadgePlaceholder.tsx` |
140
140
  | `BackgroundPattern` | Decorative SVG dot-grid / line pattern for ContactForm section. Decorative block (generalized beyond its original single consumer). Renders an absolutely-positioned decoration behind a section's content. Originally the pattern anchored behind ContactForm's form column; SpotlightPanel composes it as a full-bleed section backdrop (dimmed + blurred, behind a centered card) — same block, a second placement. | `import { BackgroundPattern } from "@working-theory/ui/blocks"` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ailk",
3
- "version": "0.11.4",
3
+ "version": "0.11.5",
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",
@@ -27,8 +27,8 @@
27
27
  "tar": "^7.5.21"
28
28
  },
29
29
  "devDependencies": {
30
- "@working-theory/schema": "0.32.0",
31
- "@working-theory/templates": "0.32.0"
30
+ "@working-theory/schema": "0.33.0",
31
+ "@working-theory/templates": "0.33.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @file content-write-production-boot.test.ts
3
+ * @description A production build with `content-write` enabled boots without
4
+ * pino-pretty (#7502).
5
+ *
6
+ * `services/revalidation.ts` is loaded only by the content-write routes, and it
7
+ * used to build its logger with `createLogger({ service })` alone. The
8
+ * observability package read a missing `environment` as development and asked
9
+ * pino for a `pino-pretty` transport, which a production install does not carry:
10
+ * pino threw `unable to determine transport target for "pino-pretty"` at module
11
+ * load, `build()` rejected, and every route — `/health` included — answered 500.
12
+ *
13
+ * "Without pino-pretty installed" is simulated at the pino boundary: the mock
14
+ * below throws pino's own error whenever a `pino-pretty` transport is requested,
15
+ * and passes every other call through to the real pino. pino is mocked by its
16
+ * resolved path because `apps/api` does not depend on it directly — only
17
+ * `@working-theory/observability` does.
18
+ *
19
+ * Mirrors `module-exclusion.test.ts`'s external-boundary mocks (CORS,
20
+ * rate-limit, email).
21
+ */
22
+
23
+ import type { FastifyInstance } from "fastify";
24
+
25
+ jest.mock(
26
+ require.resolve("pino", {
27
+ paths: [`${__dirname}/../../../../packages/observability`],
28
+ }),
29
+ () => {
30
+ const realPino = jest.requireActual(
31
+ require.resolve("pino", {
32
+ paths: [`${__dirname}/../../../../packages/observability`],
33
+ }),
34
+ );
35
+ const withoutPinoPretty = (
36
+ options?: { transport?: { target?: string } },
37
+ ...rest: unknown[]
38
+ ) => {
39
+ if (options?.transport?.target === "pino-pretty") {
40
+ throw new Error(
41
+ 'unable to determine transport target for "pino-pretty"',
42
+ );
43
+ }
44
+ return realPino(options, ...rest);
45
+ };
46
+ // pino exports itself as `default` and as `pino` too; both are replaced.
47
+ return Object.assign(withoutPinoPretty, realPino, {
48
+ default: withoutPinoPretty,
49
+ pino: withoutPinoPretty,
50
+ });
51
+ },
52
+ );
53
+
54
+ jest.mock("@fastify/cors", () => {
55
+ return jest.fn().mockResolvedValue(undefined);
56
+ });
57
+
58
+ jest.mock("@fastify/rate-limit", () => {
59
+ return jest.fn().mockResolvedValue(undefined);
60
+ });
61
+
62
+ jest.mock("@working-theory/email", () => ({
63
+ sendLeadNotification: jest.fn().mockResolvedValue({ ok: true }),
64
+ }));
65
+
66
+ describe("production boot with content-write enabled (#7502)", () => {
67
+ const prior = {
68
+ NODE_ENV: process.env.NODE_ENV,
69
+ AILK_ENABLED_MODULES: process.env.AILK_ENABLED_MODULES,
70
+ };
71
+ let app: FastifyInstance;
72
+
73
+ beforeAll(async () => {
74
+ process.env.NODE_ENV = "production";
75
+ // content-write registers only alongside a tenancy module (server.ts).
76
+ process.env.AILK_ENABLED_MODULES = "multi-tenant,content-write";
77
+ // The config and the observability singleton read NODE_ENV at import, so
78
+ // the server is loaded only after the environment is set.
79
+ const { build } = await import("../server");
80
+ app = await build();
81
+ });
82
+
83
+ afterAll(async () => {
84
+ await app?.close();
85
+ for (const [key, value] of Object.entries(prior)) {
86
+ if (value === undefined) delete process.env[key];
87
+ else process.env[key] = value;
88
+ }
89
+ });
90
+
91
+ it("answers /health with 200", async () => {
92
+ const res = await app.inject({ method: "GET", url: "/health" });
93
+ expect(res.statusCode).toBe(200);
94
+ });
95
+
96
+ it("registers the content-write routes, so revalidation.ts was loaded", async () => {
97
+ // Registered and session-less: 401, where an unregistered route is a 404.
98
+ const res = await app.inject({
99
+ method: "POST",
100
+ url: "/v1/workspaces/wksp_00000000-0000-7000-8000-0000000000aa/content",
101
+ });
102
+ expect(res.statusCode).toBe(401);
103
+ });
104
+ });
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @file root-modules.test.ts
3
+ * @description `GET /` reports the optional modules this process registered
4
+ * routes for (#7501), so the Admin can hide what a build does not serve.
5
+ *
6
+ * Builds the REAL server under several `AILK_ENABLED_MODULES` values and reads
7
+ * the root index over `inject`. `modules` must agree with the route table
8
+ * Fastify actually registered — the content and meetings reads the Admin makes
9
+ * are present exactly when their module is listed.
10
+ *
11
+ * Mirrors `src/openapi/__tests__/surface-drift.test.ts`'s external-boundary
12
+ * mocks (CORS, rate-limit, email) — see that file's header for why each is
13
+ * mocked.
14
+ */
15
+
16
+ jest.mock("@fastify/cors", () => {
17
+ return jest.fn().mockResolvedValue(undefined);
18
+ });
19
+
20
+ jest.mock("@fastify/rate-limit", () => {
21
+ return jest.fn().mockResolvedValue(undefined);
22
+ });
23
+
24
+ jest.mock("@working-theory/email", () => ({
25
+ sendLeadNotification: jest.fn().mockResolvedValue({ ok: true }),
26
+ }));
27
+
28
+ import { execFileSync } from "node:child_process";
29
+ import path from "node:path";
30
+ import { build } from "../server";
31
+ import { readRegisteredRoutes } from "../openapi/spec";
32
+ import { routeKey } from "../openapi/surface-drift";
33
+
34
+ const CONTENT_READ = routeKey("GET", "/v1/workspaces/:workspaceId/content");
35
+ const MEETINGS_READ = routeKey("GET", "/v1/workspaces/:workspaceId/meetings");
36
+
37
+ /** Every route the Admin reads under `multi-tenant` alone (spec §1 fact 4). */
38
+ const ADMIN_MULTI_TENANT_READS = [
39
+ routeKey("GET", "/v1/workspaces"),
40
+ routeKey("GET", "/v1/billing"),
41
+ routeKey("GET", "/v1/project-listings"),
42
+ routeKey("GET", "/v1/workspaces/:workspaceId/messages"),
43
+ routeKey("GET", "/v1/workspaces/:workspaceId/magnets"),
44
+ routeKey("GET", "/v1/workspaces/:workspaceId/assets"),
45
+ routeKey("GET", "/v1/workspaces/:workspaceId/sessions"),
46
+ routeKey("GET", "/v1/sessions/:sessionId/artifacts"),
47
+ ];
48
+
49
+ const CONFIGS: Array<[string, string | undefined, string[]]> = [
50
+ ["unset", undefined, []],
51
+ ["multi-tenant", "multi-tenant", ["multi-tenant"]],
52
+ [
53
+ "scheduling, content-write,multi-tenant",
54
+ "scheduling, content-write,multi-tenant",
55
+ ["content-write", "multi-tenant", "scheduling"],
56
+ ],
57
+ ["content-write alone", "content-write", []],
58
+ [
59
+ "multi-tenant,bogus,signal-collectors",
60
+ "multi-tenant,bogus,signal-collectors",
61
+ ["multi-tenant", "signal-collectors"],
62
+ ],
63
+ // `docs` registers no apps/api route, so it is never reported as served.
64
+ ["docs,multi-tenant", "docs,multi-tenant", ["multi-tenant"]],
65
+ ];
66
+
67
+ function setEnv(value: string | undefined): string | undefined {
68
+ const prior = process.env.AILK_ENABLED_MODULES;
69
+ if (value === undefined) {
70
+ delete process.env.AILK_ENABLED_MODULES;
71
+ } else {
72
+ process.env.AILK_ENABLED_MODULES = value;
73
+ }
74
+ return prior;
75
+ }
76
+
77
+ describe("GET / modules (#7501)", () => {
78
+ let prior: string | undefined;
79
+
80
+ beforeEach(() => {
81
+ prior = process.env.AILK_ENABLED_MODULES;
82
+ });
83
+
84
+ afterEach(() => {
85
+ setEnv(prior);
86
+ });
87
+
88
+ describe.each(CONFIGS)("AILK_ENABLED_MODULES = %s", (_label, env, expected) => {
89
+ let modules: unknown;
90
+ let routes: Set<string>;
91
+
92
+ beforeAll(async () => {
93
+ const before = setEnv(env);
94
+ try {
95
+ const app = await build();
96
+ await app.ready();
97
+ const res = await app.inject({ method: "GET", url: "/" });
98
+ routes = new Set(
99
+ readRegisteredRoutes(app).map((r) => routeKey(r.method, r.url)),
100
+ );
101
+ await app.close();
102
+ expect(res.statusCode).toBe(200);
103
+ modules = JSON.parse(res.body).modules;
104
+ } finally {
105
+ setEnv(before);
106
+ }
107
+ }, 60000);
108
+
109
+ it("AC-1: lists exactly the served optional modules, sorted", () => {
110
+ expect(modules).toEqual(expected);
111
+ });
112
+
113
+ it("AC-2: content-write is listed exactly when the content read registered", () => {
114
+ expect((modules as string[]).includes("content-write")).toBe(
115
+ routes.has(CONTENT_READ),
116
+ );
117
+ });
118
+
119
+ it("AC-2: scheduling is listed exactly when the meetings read registered", () => {
120
+ expect((modules as string[]).includes("scheduling")).toBe(
121
+ routes.has(MEETINGS_READ),
122
+ );
123
+ });
124
+ });
125
+
126
+ it("AC-1: a built server keeps its module list after the env changes", async () => {
127
+ const before = setEnv("multi-tenant,content-write");
128
+ let app: Awaited<ReturnType<typeof build>>;
129
+ try {
130
+ app = await build();
131
+ await app.ready();
132
+ } finally {
133
+ setEnv(before);
134
+ }
135
+ process.env.AILK_ENABLED_MODULES = "";
136
+ try {
137
+ const res = await app.inject({ method: "GET", url: "/" });
138
+ expect(JSON.parse(res.body).modules).toEqual([
139
+ "content-write",
140
+ "multi-tenant",
141
+ ]);
142
+ } finally {
143
+ await app.close();
144
+ }
145
+ }, 60000);
146
+
147
+ it("AC-2: multi-tenant alone registers every route the Admin reads, bar content and meetings", async () => {
148
+ const before = setEnv("multi-tenant");
149
+ try {
150
+ const app = await build();
151
+ await app.ready();
152
+ const routes = new Set(
153
+ readRegisteredRoutes(app).map((r) => routeKey(r.method, r.url)),
154
+ );
155
+ await app.close();
156
+ for (const read of ADMIN_MULTI_TENANT_READS) {
157
+ expect(routes).toContain(read);
158
+ }
159
+ expect(routes).not.toContain(CONTENT_READ);
160
+ expect(routes).not.toContain(MEETINGS_READ);
161
+ } finally {
162
+ setEnv(before);
163
+ }
164
+ }, 60000);
165
+
166
+ it("AC-2: pnpm lint:slice-registration exits 0", () => {
167
+ const repoRoot = path.resolve(__dirname, "../../../..");
168
+ expect(() =>
169
+ execFileSync("pnpm", ["lint:slice-registration"], {
170
+ cwd: repoRoot,
171
+ stdio: "pipe",
172
+ }),
173
+ ).not.toThrow();
174
+ }, 120000);
175
+ });
@@ -43,3 +43,41 @@ function enabledModules(): Set<string> {
43
43
  export function isModuleEnabled(moduleName: string): boolean {
44
44
  return enabledModules().has(moduleName);
45
45
  }
46
+
47
+ /**
48
+ * The recognized optional-module keys, sorted — the vocabulary the root index
49
+ * may report (#7501). Filtering to this list is what keeps the anonymous
50
+ * `GET /` from echoing whatever text an operator typed into
51
+ * `AILK_ENABLED_MODULES`. `docs` is deliberately absent: no apps/api route
52
+ * registers under it, so reporting it would break "modules this process
53
+ * registered routes for".
54
+ */
55
+ export const OPTIONAL_MODULES = [
56
+ "commerce",
57
+ "content-write",
58
+ "multi-tenant",
59
+ "scheduling",
60
+ "signal-collectors",
61
+ "workspace",
62
+ ] as const;
63
+
64
+ /**
65
+ * The optional modules whose routes this process registers, sorted. Called
66
+ * once at build time by `server.ts`, so the answer matches what registered
67
+ * even if the env changes afterwards.
68
+ *
69
+ * `content-write` counts only alongside a tenancy module (`workspace` or
70
+ * `multi-tenant`) — the exact predicate `server.ts` registers the editor's
71
+ * content routes under. That gate stays a literal there (the
72
+ * slice-registration lint reads `isModuleEnabled("X")` guards by text), so the
73
+ * predicate is repeated here and `root-modules.test.ts` asserts they agree.
74
+ */
75
+ export function servedModules(): string[] {
76
+ return OPTIONAL_MODULES.filter((name) => {
77
+ if (!isModuleEnabled(name)) return false;
78
+ if (name === "content-write") {
79
+ return isModuleEnabled("workspace") || isModuleEnabled("multi-tenant");
80
+ }
81
+ return true;
82
+ });
83
+ }
@@ -21,7 +21,7 @@ import type {
21
21
  } from "fastify";
22
22
 
23
23
  import { config } from "./config/index.js";
24
- import { isModuleEnabled } from "./config/modules.js";
24
+ import { isModuleEnabled, servedModules } from "./config/modules.js";
25
25
  import { registerErrorSerializer } from "./lib/error-serializer.js";
26
26
  import { validateLeadCaptureDir } from "./lib/lead-capture-store.js";
27
27
  import { registerLicenseKeyStore } from "./lib/license-key-store.js";
@@ -722,12 +722,19 @@ export async function build() {
722
722
  // Root endpoint — introduces this deployment as the SITE it serves, not as
723
723
  // the kit it was built with (#5307). `_site.mdx` is read once per process;
724
724
  // a site without one degrades to a neutral name, never to the kit's.
725
+ //
726
+ // `modules` (#7501) is the optional modules whose routes this build
727
+ // registers, computed once here — before any route registers — so the index
728
+ // reports what registered rather than re-reading the env per request. The
729
+ // Admin reads it to hide the surfaces whose module is off.
730
+ const modules = servedModules();
725
731
  server.get("/", async () => {
726
732
  const identity = resolveApiIdentity();
727
733
  return {
728
734
  name: apiDisplayName(identity),
729
735
  version: API_VERSION,
730
736
  description: apiDescription(identity),
737
+ modules,
731
738
  // Derived from the routes this process actually registered (#5314),
732
739
  // not a hand-maintained literal. The literal listed 11 endpoints against
733
740
  // 68 registered routes, omitted `/v1/project-listings/public` and
@@ -311,3 +311,22 @@ describe("notifyRevalidate", () => {
311
311
  });
312
312
  });
313
313
  });
314
+
315
+ describe("logger environment (#7502)", () => {
316
+ it.each(["production", "development"])(
317
+ "builds its logger for NODE_ENV=%s, as the api's main logger does",
318
+ (nodeEnv) => {
319
+ process.env.NODE_ENV = nodeEnv;
320
+
321
+ loadService();
322
+
323
+ const { createLogger } = require("@working-theory/observability") as {
324
+ createLogger: jest.Mock;
325
+ };
326
+ expect(createLogger).toHaveBeenCalledWith({
327
+ service: "revalidation",
328
+ environment: nodeEnv,
329
+ });
330
+ },
331
+ );
332
+ });
@@ -49,7 +49,14 @@ import { z } from "zod";
49
49
  import { config } from "../config/index.js";
50
50
  import { outboundFetch } from "../lib/outbound-http.js";
51
51
 
52
- const log = createLogger({ service: "revalidation" });
52
+ // The environment is the api's own NODE_ENV, as the observability `logger`
53
+ // singleton reads it. Omitted, createLogger assumes development and asks for a
54
+ // pino-pretty transport a production install does not carry — a throw at load
55
+ // that took the whole api down once content-write was enabled (#7502).
56
+ const log = createLogger({
57
+ service: "revalidation",
58
+ environment: config.NODE_ENV,
59
+ });
53
60
 
54
61
  const SIGNATURE_HEADER = "x-ailk-revalidate-signature";
55
62
  const EVENT_HEADER = "x-ailk-revalidate-event";
@@ -768,39 +768,63 @@
768
768
  "notFoundHeadline": "Page not found",
769
769
  "notFoundDescription": "There is no page at this address. It may have been renamed or removed.",
770
770
  "editor": {
771
- "tabForm": "Details",
772
- "tabBody": "Body",
773
771
  "tabPreview": "Preview",
774
- "tabCode": "Code",
772
+ "toolChanges": "Show unsaved changes",
773
+ "backLabel": "Pages",
775
774
  "statusDraft": "Draft",
776
775
  "statusNotYetLive": "Not yet live",
777
776
  "statusPublished": "Published",
778
- "frontmatterHeading": "Page details",
777
+ "publishedSwitch": "Published",
778
+ "publishBlockedHint": "Fix the items under For you before publishing.",
779
+ "unsaved": "Unsaved",
780
+ "unsavedChanges": "Unsaved changes",
781
+ "discardButton": "Discard",
782
+ "loading": "Loading…",
783
+ "loadError": "Could not load this page. Try again.",
784
+ "retryButton": "Try again",
779
785
  "frontmatterTitle": "Title",
780
786
  "frontmatterSlug": "Slug",
781
787
  "frontmatterDescription": "Description",
782
- "issuesHeading": "Fix these before publishing",
783
- "saveButton": "Save draft",
788
+ "titlePlaceholder": "Page title",
789
+ "fieldPageType": "Page type",
790
+ "toolbarLabel": "Formatting",
791
+ "formatMenu": "Page actions",
792
+ "closeSheet": "Close",
793
+ "toolH1": "Heading 1",
794
+ "toolH2": "Heading 2",
795
+ "toolH3": "Heading 3",
796
+ "toolBold": "Bold",
797
+ "toolItalic": "Italic",
798
+ "toolBulletList": "Bulleted list",
799
+ "toolNumberedList": "Numbered list",
800
+ "toolLink": "Link",
801
+ "toolImage": "Insert image",
802
+ "issueRequired": "{field} is required.",
803
+ "issueInvalid": "{field} isn't a valid choice.",
804
+ "forYou": {
805
+ "typeFix": "Blocks publish",
806
+ "typeSuggestion": "Suggestion",
807
+ "fixWhy": "The page can't go live until this is fixed.",
808
+ "fixOutcome": "Once it is fixed, the Published switch turns on.",
809
+ "descriptionTitle": "Add a search description",
810
+ "descriptionWhy": "Search engines and AI answers show this line under the page's title. Without it they write their own.",
811
+ "descriptionOutcome": "A sentence you chose appears wherever this page is listed.",
812
+ "altTitle": "{count, plural, one {Describe # image} other {Describe # images}}",
813
+ "altWhy": "Screen readers and search engines can't see an image without alt text.",
814
+ "altOutcome": "Every reader gets the image's meaning, and the page is easier to find."
815
+ },
816
+ "saveButton": "Save",
784
817
  "saving": "Saving…",
785
818
  "saved": "Saved",
786
819
  "saveError": "Could not save. Try again.",
787
- "publishButton": "Publish",
788
- "publishing": "Publishing…",
789
- "published": "Published",
790
820
  "publishError": "Could not publish. Try again.",
791
- "unpublishButton": "Unpublish",
792
- "unpublishing": "Unpublishing…",
793
- "unpublished": "Unpublished",
794
821
  "unpublishError": "Could not unpublish. Try again.",
795
822
  "conflictHeading": "Someone else saved this page",
796
823
  "conflictMessage": "This page changed since you opened it. Reload to take their version, or overwrite it with yours.",
797
824
  "conflictReload": "Reload their version",
798
825
  "conflictOverwrite": "Overwrite with mine",
799
- "imageInsertLabel": "Insert an image",
800
- "imageInsertHint": "The image is uploaded and its markdown inserted at the cursor.",
801
826
  "imageAlt": "Image",
802
827
  "imageInsertError": "Could not upload that image. Try again.",
803
- "codeHeading": "Composed MDX",
804
828
  "diffLegendAdded": "Added",
805
829
  "diffLegendRemoved": "Removed",
806
830
  "diffLegendUnchanged": "Unchanged"
@@ -1,5 +1,12 @@
1
1
  # @working-theory/database
2
2
 
3
+ ## 0.33.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`bf2c0a7`](https://github.com/Working-Theory-Labs/ai-launch-kit-internal/commit/bf2c0a722c08974f6a199e9f8bf3d837a100be58)]:
8
+ - @working-theory/validation@0.33.0
9
+
3
10
  ## 0.32.0
4
11
 
5
12
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@working-theory/database",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "license": "Apache-2.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/versions.json CHANGED
@@ -1,52 +1,52 @@
1
1
  {
2
- "@working-theory/admin-ui": "0.32.0",
3
- "@working-theory/aeo": "0.32.0",
4
- "@working-theory/agent-context": "0.32.0",
2
+ "@working-theory/admin-ui": "0.33.0",
3
+ "@working-theory/aeo": "0.33.0",
4
+ "@working-theory/agent-context": "0.33.0",
5
5
  "@working-theory/agent-contract": "0.1.0",
6
6
  "@working-theory/agent-memory": "0.0.0",
7
7
  "@working-theory/ai": "0.1.0",
8
- "@working-theory/analytics": "0.32.0",
9
- "@working-theory/api-client": "0.32.0",
8
+ "@working-theory/analytics": "0.33.0",
9
+ "@working-theory/api-client": "0.33.0",
10
10
  "@working-theory/cda-filesystem": "0.0.0",
11
- "@working-theory/cli": "0.32.0",
12
- "@working-theory/common": "0.32.0",
11
+ "@working-theory/cli": "0.33.0",
12
+ "@working-theory/common": "0.33.0",
13
13
  "@working-theory/consent": "0.1.0",
14
- "@working-theory/content-adapters": "0.32.0",
15
- "@working-theory/content-projection": "0.32.0",
16
- "@working-theory/email": "0.32.0",
14
+ "@working-theory/content-adapters": "0.33.0",
15
+ "@working-theory/content-projection": "0.33.0",
16
+ "@working-theory/email": "0.33.0",
17
17
  "@working-theory/env": "0.0.0",
18
- "@working-theory/eslint-config": "0.32.0",
19
- "@working-theory/fumadocs-schema": "0.32.0",
18
+ "@working-theory/eslint-config": "0.33.0",
19
+ "@working-theory/fumadocs-schema": "0.33.0",
20
20
  "@working-theory/ids": "0.8.0",
21
- "@working-theory/jsonld": "0.32.0",
22
- "@working-theory/license": "0.32.0",
23
- "@working-theory/metadata": "0.32.0",
24
- "@working-theory/observability": "0.32.0",
25
- "@working-theory/page-renderer": "0.32.0",
21
+ "@working-theory/jsonld": "0.33.0",
22
+ "@working-theory/license": "0.33.0",
23
+ "@working-theory/metadata": "0.33.0",
24
+ "@working-theory/observability": "0.33.0",
25
+ "@working-theory/page-renderer": "0.33.0",
26
26
  "@working-theory/plugin-mcp": "0.1.1",
27
- "@working-theory/schema": "0.32.0",
28
- "@working-theory/schema-pack-registry": "0.32.0",
29
- "@working-theory/schema-validator": "0.32.0",
30
- "@working-theory/sections-registry": "0.32.0",
31
- "@working-theory/site-config": "0.32.0",
32
- "@working-theory/stripe-client": "0.32.0",
33
- "@working-theory/templates": "0.32.0",
34
- "@working-theory/theme": "0.32.0",
35
- "@working-theory/ui": "0.32.0",
36
- "@working-theory/validation": "0.32.0",
37
- "@working-theory/web-i18n": "0.32.0",
27
+ "@working-theory/schema": "0.33.0",
28
+ "@working-theory/schema-pack-registry": "0.33.0",
29
+ "@working-theory/schema-validator": "0.33.0",
30
+ "@working-theory/sections-registry": "0.33.0",
31
+ "@working-theory/site-config": "0.33.0",
32
+ "@working-theory/stripe-client": "0.33.0",
33
+ "@working-theory/templates": "0.33.0",
34
+ "@working-theory/theme": "0.33.0",
35
+ "@working-theory/ui": "0.33.0",
36
+ "@working-theory/validation": "0.33.0",
37
+ "@working-theory/web-i18n": "0.33.0",
38
38
  "@working-theory/billing-client": "0.0.0",
39
39
  "@working-theory/branding": "0.0.0",
40
40
  "@working-theory/license-client": "0.0.0",
41
41
  "@working-theory/license-manifest": "0.0.0",
42
42
  "@working-theory/partner-session": "0.0.0",
43
43
  "@working-theory/preview-protocol": "0.0.0",
44
- "@working-theory/ui-commerce": "0.23.9",
45
- "@working-theory/ui-docs-blog": "0.23.9",
46
- "@working-theory/ui-scheduling": "0.23.9",
47
- "@working-theory/ui-signal-collectors": "0.24.7",
44
+ "@working-theory/ui-commerce": "0.23.10",
45
+ "@working-theory/ui-docs-blog": "0.23.10",
46
+ "@working-theory/ui-scheduling": "0.23.10",
47
+ "@working-theory/ui-signal-collectors": "0.24.8",
48
48
  "@working-theory/web": "0.0.0",
49
49
  "@working-theory/api": "1.0.0",
50
50
  "@working-theory/mcp": "0.0.0",
51
- "@working-theory/database": "0.32.0"
51
+ "@working-theory/database": "0.33.0"
52
52
  }