@caelo-cms/shared 0.11.4 → 0.11.6
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/ai-tools.d.ts +206 -2
- package/dist/ai-tools.d.ts.map +1 -1
- package/dist/ai-tools.js +23 -9
- package/dist/ai-tools.js.map +1 -1
- package/dist/change-journal.d.ts +71 -0
- package/dist/change-journal.d.ts.map +1 -0
- package/dist/change-journal.js +251 -0
- package/dist/change-journal.js.map +1 -0
- package/dist/content.d.ts +214 -0
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +29 -11
- package/dist/content.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lists/fields.d.ts +5 -0
- package/dist/lists/fields.d.ts.map +1 -1
- package/dist/lists/fields.js +6 -1
- package/dist/lists/fields.js.map +1 -1
- package/dist/lists/list-type.d.ts.map +1 -1
- package/dist/lists/list-type.js +6 -3
- package/dist/lists/list-type.js.map +1 -1
- package/dist/lists/page-type.d.ts +1 -0
- package/dist/lists/page-type.d.ts.map +1 -1
- package/dist/lists/page-type.js +7 -0
- package/dist/lists/page-type.js.map +1 -1
- package/dist/live-events.d.ts +8 -4
- package/dist/live-events.d.ts.map +1 -1
- package/dist/live-events.js +18 -3
- package/dist/live-events.js.map +1 -1
- package/dist/media.d.ts +19 -0
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +16 -0
- package/dist/media.js.map +1 -1
- package/dist/phase-timer.d.ts +43 -2
- package/dist/phase-timer.d.ts.map +1 -1
- package/dist/phase-timer.js +170 -4
- package/dist/phase-timer.js.map +1 -1
- package/dist/pool-budget.d.ts +152 -0
- package/dist/pool-budget.d.ts.map +1 -0
- package/dist/pool-budget.js +151 -0
- package/dist/pool-budget.js.map +1 -0
- package/dist/themes-errors.js +1 -1
- package/dist/themes-errors.js.map +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/ai-tools.ts +23 -8
- package/src/change-journal.ts +323 -0
- package/src/content.ts +32 -11
- package/src/index.ts +2 -0
- package/src/lists/fields.ts +7 -1
- package/src/lists/list-fixtures.test.ts +1 -0
- package/src/lists/list-type.ts +6 -2
- package/src/lists/lists.test.ts +1 -0
- package/src/lists/page-type.ts +7 -0
- package/src/live-events.ts +18 -3
- package/src/media.test.ts +31 -0
- package/src/media.ts +17 -0
- package/src/phase-timer.test.ts +37 -0
- package/src/phase-timer.ts +182 -4
- package/src/pool-budget.test.ts +111 -0
- package/src/pool-budget.ts +234 -0
- package/src/themes-errors.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Issue #1254 — the database connection budget of an install.
|
|
4
|
+
*
|
|
5
|
+
* Every Caelo process that talks to Postgres holds connection pools, and
|
|
6
|
+
* they all draw from ONE server-wide `max_connections` (cms_admin and
|
|
7
|
+
* cms_public live on the same server). Before #1254 every pool took Bun's
|
|
8
|
+
* default of 10, so the admin alone asked for `adminMaxInstances × 2 × 10`
|
|
9
|
+
* — exactly the 100 slots of a default install, with nothing left for the
|
|
10
|
+
* gateway, the static generator, migrations or the provider's own agents.
|
|
11
|
+
* Under load the last admin instance to scale up could not connect at all.
|
|
12
|
+
*
|
|
13
|
+
* The budget turns that around: provisioning states how many connections
|
|
14
|
+
* the server has and how many instances may run, every fixed consumer is
|
|
15
|
+
* named as a {@link PoolBudgetReserve}, and what is left is split across
|
|
16
|
+
* the admin instances' cms_admin pools — the pool the write path uses.
|
|
17
|
+
* The admin's cms_public pool is small and fixed: the admin only reads
|
|
18
|
+
* plugin data there and publishes the gateway projection.
|
|
19
|
+
*
|
|
20
|
+
* Why not simply raise the pool: a larger pool only moves the wait from
|
|
21
|
+
* the pool to the server. A pool sized past the budget fails with "too
|
|
22
|
+
* many clients" at the worst moment (scale-out under load) instead of
|
|
23
|
+
* waiting a bounded time for a free connection of its own pool
|
|
24
|
+
* (query-api pool-guard.ts). docs/dev/connection-budget.md has the long
|
|
25
|
+
* version.
|
|
26
|
+
*
|
|
27
|
+
* Pure module — no I/O. Used by the provisioning stacks (which set the
|
|
28
|
+
* resulting env on each service) and re-exported by `@caelo-cms/query-api`.
|
|
29
|
+
*/
|
|
30
|
+
/** Env var sizing every pool of a `DatabaseAdapter` (both pools, unless the next one is set). */
|
|
31
|
+
export const DB_POOL_MAX_ENV = "CAELO_DB_POOL_MAX";
|
|
32
|
+
/**
|
|
33
|
+
* Env var sizing the cms_public pool of a `DatabaseAdapter` on its own. It
|
|
34
|
+
* wins over {@link DB_POOL_MAX_ENV} for that pool, so the admin can run a
|
|
35
|
+
* large cms_admin pool next to a small cms_public one.
|
|
36
|
+
*/
|
|
37
|
+
export const DB_PUBLIC_POOL_MAX_ENV = "CAELO_DB_PUBLIC_POOL_MAX";
|
|
38
|
+
/** Smallest pool a `DatabaseAdapter` accepts: one connection self-deadlocks it. */
|
|
39
|
+
export const MIN_POOL_MAX = 2;
|
|
40
|
+
/**
|
|
41
|
+
* Smallest cms_admin pool the budget hands an admin instance. Below it a
|
|
42
|
+
* handful of concurrent editors and agents queue on every write; an install
|
|
43
|
+
* whose server cannot afford it must get a larger tier or fewer instances,
|
|
44
|
+
* so {@link computePoolBudget} refuses instead of shipping a starved pool.
|
|
45
|
+
*/
|
|
46
|
+
export const ADMIN_POOL_FLOOR = 4;
|
|
47
|
+
/** The admin's cms_public pool: plugin-data reads and the gateway projection. */
|
|
48
|
+
export const ADMIN_PUBLIC_POOL_MAX = 4;
|
|
49
|
+
/** The gateway's only pool (public_role on cms_public), per instance. */
|
|
50
|
+
export const GATEWAY_POOL_MAX = 2;
|
|
51
|
+
/**
|
|
52
|
+
* Each pool of one static-generator subprocess. A build runs in ONE
|
|
53
|
+
* transaction (pool-guard.ts LONG_TRANSACTION_ALLOWLIST) and takes no
|
|
54
|
+
* second checkout, so the minimum pool ({@link MIN_POOL_MAX}) is enough.
|
|
55
|
+
*/
|
|
56
|
+
export const GENERATOR_POOL_MAX = 2;
|
|
57
|
+
/**
|
|
58
|
+
* #1267 — the dedicated connection each admin instance keeps open for
|
|
59
|
+
* `LISTEN` on the change journal's wake-up channel. A LISTEN connection is
|
|
60
|
+
* held for the instance's lifetime and can never serve a query of the pool,
|
|
61
|
+
* so it is budgeted outside the pools, one per admin instance.
|
|
62
|
+
*/
|
|
63
|
+
export const LISTEN_CONNECTIONS_PER_ADMIN_INSTANCE = 1;
|
|
64
|
+
/**
|
|
65
|
+
* The connection each gateway instance keeps open for `LISTEN
|
|
66
|
+
* caelo_gateway_settings` on cms_public (api-gateway server.ts): outside the
|
|
67
|
+
* gateway's pool, held for the instance's lifetime.
|
|
68
|
+
*/
|
|
69
|
+
export const LISTEN_CONNECTIONS_PER_GATEWAY_INSTANCE = 1;
|
|
70
|
+
function positiveInteger(value, name, min) {
|
|
71
|
+
if (!Number.isInteger(value) || value < min) {
|
|
72
|
+
throw new Error(`pool budget: ${name} must be an integer >= ${min} (got ${value})`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Split `maxConnections` across every process of the install.
|
|
77
|
+
*
|
|
78
|
+
* `adminPoolMax = floor((maxConnections − Σ reserves) / adminMaxInstances)`,
|
|
79
|
+
* where the reserves are the fixed consumers of {@link PoolBudgetInput} plus
|
|
80
|
+
* `gateway = gatewayMaxInstances × GATEWAY_POOL_MAX`,
|
|
81
|
+
* `generator = concurrentBuilds × 2 × GENERATOR_POOL_MAX`,
|
|
82
|
+
* `listen = adminMaxInstances × LISTEN_CONNECTIONS_PER_ADMIN_INSTANCE`,
|
|
83
|
+
* `gateway-listen = gatewayMaxInstances × LISTEN_CONNECTIONS_PER_GATEWAY_INSTANCE` and
|
|
84
|
+
* `admin-public = adminMaxInstances × ADMIN_PUBLIC_POOL_MAX`.
|
|
85
|
+
*
|
|
86
|
+
* @throws Error naming what to change when the server cannot give every
|
|
87
|
+
* admin instance at least {@link ADMIN_POOL_FLOOR} cms_admin connections.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* computePoolBudget({ maxConnections: 100, adminMaxInstances: 5,
|
|
91
|
+
* gatewayMaxInstances: 10, concurrentBuilds: 2, maintenanceReserve: 5,
|
|
92
|
+
* migrationsReserve: 2, jobsReserve: 4 }).adminPoolMax // → 7
|
|
93
|
+
*/
|
|
94
|
+
export function computePoolBudget(input) {
|
|
95
|
+
positiveInteger(input.maxConnections, "maxConnections", 1);
|
|
96
|
+
positiveInteger(input.adminMaxInstances, "adminMaxInstances", 1);
|
|
97
|
+
positiveInteger(input.gatewayMaxInstances, "gatewayMaxInstances", 0);
|
|
98
|
+
positiveInteger(input.concurrentBuilds, "concurrentBuilds", 0);
|
|
99
|
+
positiveInteger(input.maintenanceReserve, "maintenanceReserve", 0);
|
|
100
|
+
positiveInteger(input.migrationsReserve, "migrationsReserve", 0);
|
|
101
|
+
positiveInteger(input.jobsReserve, "jobsReserve", 0);
|
|
102
|
+
const reserves = [
|
|
103
|
+
{ name: "maintenance", connections: input.maintenanceReserve },
|
|
104
|
+
{ name: "migrations", connections: input.migrationsReserve },
|
|
105
|
+
{ name: "jobs", connections: input.jobsReserve },
|
|
106
|
+
{ name: "generator", connections: input.concurrentBuilds * 2 * GENERATOR_POOL_MAX },
|
|
107
|
+
{ name: "gateway", connections: input.gatewayMaxInstances * GATEWAY_POOL_MAX },
|
|
108
|
+
{
|
|
109
|
+
name: "listen",
|
|
110
|
+
connections: input.adminMaxInstances * LISTEN_CONNECTIONS_PER_ADMIN_INSTANCE,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "gateway-listen",
|
|
114
|
+
connections: input.gatewayMaxInstances * LISTEN_CONNECTIONS_PER_GATEWAY_INSTANCE,
|
|
115
|
+
},
|
|
116
|
+
{ name: "admin-public", connections: input.adminMaxInstances * ADMIN_PUBLIC_POOL_MAX },
|
|
117
|
+
];
|
|
118
|
+
const reserved = reserves.reduce((sum, r) => sum + r.connections, 0);
|
|
119
|
+
const forAdmin = input.maxConnections - reserved;
|
|
120
|
+
const adminPoolMax = Math.floor(forAdmin / input.adminMaxInstances);
|
|
121
|
+
if (adminPoolMax < ADMIN_POOL_FLOOR) {
|
|
122
|
+
const needed = reserved + ADMIN_POOL_FLOOR * input.adminMaxInstances;
|
|
123
|
+
const breakdown = reserves.map((r) => `${r.name} ${r.connections}`).join(", ");
|
|
124
|
+
throw new Error(`pool budget: max_connections ${input.maxConnections} cannot give each of ${input.adminMaxInstances} admin instances the minimum of ${ADMIN_POOL_FLOOR} cms_admin connections ` +
|
|
125
|
+
`(reserved: ${breakdown}; ${needed} needed). Raise maxConnections to at least ${needed} (a larger database tier may be required), ` +
|
|
126
|
+
"or lower adminMaxInstances / gatewayMaxInstances.");
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
adminPoolMax,
|
|
130
|
+
adminPublicPoolMax: ADMIN_PUBLIC_POOL_MAX,
|
|
131
|
+
gatewayPoolMax: GATEWAY_POOL_MAX,
|
|
132
|
+
generatorPoolMax: GENERATOR_POOL_MAX,
|
|
133
|
+
reserves,
|
|
134
|
+
unassigned: forAdmin - adminPoolMax * input.adminMaxInstances,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The env that sizes `service`'s pools from `budget`, for the stacks to set.
|
|
139
|
+
* The admin gets both pools; the gateway, whose only pool is cms_public,
|
|
140
|
+
* gets just that one.
|
|
141
|
+
*/
|
|
142
|
+
export function poolBudgetEnv(budget, service) {
|
|
143
|
+
if (service === "gateway") {
|
|
144
|
+
return [{ name: DB_PUBLIC_POOL_MAX_ENV, value: String(budget.gatewayPoolMax) }];
|
|
145
|
+
}
|
|
146
|
+
return [
|
|
147
|
+
{ name: DB_POOL_MAX_ENV, value: String(budget.adminPoolMax) },
|
|
148
|
+
{ name: DB_PUBLIC_POOL_MAX_ENV, value: String(budget.adminPublicPoolMax) },
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=pool-budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool-budget.js","sourceRoot":"","sources":["../src/pool-budget.ts"],"names":[],"mappings":"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"}
|
package/dist/themes-errors.js
CHANGED
|
@@ -160,7 +160,7 @@ export class TokenCategoryMismatch extends Error {
|
|
|
160
160
|
expected;
|
|
161
161
|
got;
|
|
162
162
|
constructor(canonicalPath, expected, got) {
|
|
163
|
-
super(`TokenCategoryMismatch: '${canonicalPath}' expects a ${expected} value, got a ${got} —
|
|
163
|
+
super(`TokenCategoryMismatch: '${canonicalPath}' expects a ${expected} value, got a ${got} — use a value matching ${expected}.`);
|
|
164
164
|
this.name = "TokenCategoryMismatch";
|
|
165
165
|
this.canonicalPath = canonicalPath;
|
|
166
166
|
this.expected = expected;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themes-errors.js","sourceRoot":"","sources":["../src/themes-errors.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"themes-errors.js","sourceRoot":"","sources":["../src/themes-errors.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Format: SemVer 2.0.0. Pre-1.0 minor bumps are breaking; post-1.0
|
|
20
20
|
* follow standard SemVer.
|
|
21
21
|
*/
|
|
22
|
-
export declare const CAELO_VERSION = "0.11.
|
|
22
|
+
export declare const CAELO_VERSION = "0.11.6";
|
|
23
23
|
/**
|
|
24
24
|
* Deprecated alias for back-compat — early P17 work spelled this
|
|
25
25
|
* `CALEO_VERSION` (typo of "Caelo"). New code should import
|
|
@@ -31,7 +31,7 @@ export declare const CAELO_VERSION = "0.11.4";
|
|
|
31
31
|
*
|
|
32
32
|
* @deprecated use CAELO_VERSION
|
|
33
33
|
*/
|
|
34
|
-
export declare const CALEO_VERSION = "0.11.
|
|
34
|
+
export declare const CALEO_VERSION = "0.11.6";
|
|
35
35
|
/**
|
|
36
36
|
* Parsed shape — major/minor/patch + optional pre-release tag.
|
|
37
37
|
* Stable interface for callers that need to feature-gate (rare —
|
package/dist/version.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* Format: SemVer 2.0.0. Pre-1.0 minor bumps are breaking; post-1.0
|
|
21
21
|
* follow standard SemVer.
|
|
22
22
|
*/
|
|
23
|
-
export const CAELO_VERSION = "0.11.
|
|
23
|
+
export const CAELO_VERSION = "0.11.6";
|
|
24
24
|
/**
|
|
25
25
|
* Deprecated alias for back-compat — early P17 work spelled this
|
|
26
26
|
* `CALEO_VERSION` (typo of "Caelo"). New code should import
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caelo-cms/shared",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"description": "Shared Zod schemas + types + the two-pass HTML composer used by every Caelo CMS workspace package. Stable enough for plugin authors and embedders to depend on directly.",
|
package/src/ai-tools.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
forkPlacementContentSchema,
|
|
20
20
|
type ModuleField,
|
|
21
21
|
moduleFieldSchema,
|
|
22
|
+
newPageTypeSchema,
|
|
22
23
|
pageShortTitleSchema,
|
|
23
24
|
pageTypeSlugSchema,
|
|
24
25
|
setPlacementContentSchema,
|
|
@@ -333,6 +334,13 @@ export const chatCreateSessionInput = z
|
|
|
333
334
|
* draft: an explicit experiment ("try a redesign") or a site migration.
|
|
334
335
|
*/
|
|
335
336
|
isolation: z.enum(["experiment", "migration"]).optional(),
|
|
337
|
+
/**
|
|
338
|
+
* Issue #1253 — the session is an external agent's (one chat per
|
|
339
|
+
* agent): the client app it works for ("Claude Code", a token's label).
|
|
340
|
+
* The chat list groups such chats per client, and Live Edit never picks
|
|
341
|
+
* one as the operator's own chat.
|
|
342
|
+
*/
|
|
343
|
+
agentClient: z.string().min(1).max(200).optional(),
|
|
336
344
|
})
|
|
337
345
|
.strict();
|
|
338
346
|
|
|
@@ -584,8 +592,10 @@ export const createTemplateToolInput = z
|
|
|
584
592
|
html: sourceTextArg(z.string().min(1).max(2_000_000), "html"),
|
|
585
593
|
css: sourceTextArg(z.string().max(2_000_000), "css").default(""),
|
|
586
594
|
layoutId: z.string().uuid().optional(),
|
|
587
|
-
/**
|
|
595
|
+
/** #1276 — exactly one of: the existing page type this template serves… */
|
|
588
596
|
pageType: pageTypeSlugSchema.optional(),
|
|
597
|
+
/** …or a new page type created with this template as its default. */
|
|
598
|
+
newPageType: newPageTypeSchema.optional(),
|
|
589
599
|
// Optional block-set metadata, symmetric with create_layout. Omit to
|
|
590
600
|
// auto-derive blocks from <caelo-slot> tags; pass to set displayName /
|
|
591
601
|
// position (each name must match a slot). Enforced op-side in
|
|
@@ -650,15 +660,12 @@ export const createLayoutToolInput = z
|
|
|
650
660
|
})
|
|
651
661
|
.strict();
|
|
652
662
|
|
|
663
|
+
/** #1276 — the default layout only: there is no default template or page type. */
|
|
653
664
|
export const setSiteDefaultsToolInput = z
|
|
654
665
|
.object({
|
|
655
|
-
defaultLayoutSlug: slugInputSchema
|
|
656
|
-
defaultTemplateSlug: slugInputSchema.optional(),
|
|
666
|
+
defaultLayoutSlug: slugInputSchema,
|
|
657
667
|
})
|
|
658
|
-
.strict()
|
|
659
|
-
.refine((v) => v.defaultLayoutSlug !== undefined || v.defaultTemplateSlug !== undefined, {
|
|
660
|
-
message: "must provide at least one of defaultLayoutSlug, defaultTemplateSlug",
|
|
661
|
-
});
|
|
668
|
+
.strict();
|
|
662
669
|
|
|
663
670
|
/**
|
|
664
671
|
* P6.7.7 — content-ops follow-ups: clone a page, swap a page's
|
|
@@ -674,6 +681,8 @@ export const duplicatePageToolInput = z
|
|
|
674
681
|
/** #1142 — the copy's breadcrumb label; omitted = newTitle when given, else the source's. */
|
|
675
682
|
newShortTitle: pageShortTitleSchema.optional(),
|
|
676
683
|
targetTemplateId: z.string().uuid().optional(),
|
|
684
|
+
/** #1276 — the copy's page type (slug); omitted = the source's. */
|
|
685
|
+
pageType: pageTypeSlugSchema.optional(),
|
|
677
686
|
/** Where the copy sits: a parent page id, or null for the top level.
|
|
678
687
|
* Omitted = next to the source (same parent). */
|
|
679
688
|
newParentPageId: z.string().uuid().nullable().optional(),
|
|
@@ -1073,7 +1082,13 @@ export const bootstrapSiteScaffoldToolInput = z
|
|
|
1073
1082
|
templateSlug: z.string().min(1).max(120).optional(),
|
|
1074
1083
|
/** Display name for the new template. Defaults to `Home template`. */
|
|
1075
1084
|
templateDisplayName: z.string().min(1).max(256).optional(),
|
|
1076
|
-
/**
|
|
1085
|
+
/**
|
|
1086
|
+
* #1276 — the page type the new template serves (every template has
|
|
1087
|
+
* one). An existing slug joins that type; else the type is created
|
|
1088
|
+
* with the template. Defaults to the `home` page type.
|
|
1089
|
+
*/
|
|
1090
|
+
templatePageType: newPageTypeSchema.optional(),
|
|
1091
|
+
/** Whether to pin the new layout as the site's default layout. Defaults to true. */
|
|
1077
1092
|
setAsDefaults: z.boolean().optional(),
|
|
1078
1093
|
})
|
|
1079
1094
|
.strict();
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Issue #1267 — the change journal's registry: which `cms_admin` tables
|
|
5
|
+
* write journal rows, under which kind, and why every other table does not.
|
|
6
|
+
* The contract is `docs/dev/state-and-changes.md`.
|
|
7
|
+
*
|
|
8
|
+
* The journal (`entity_changes`, migration 0430) is written by generic row
|
|
9
|
+
* triggers that migrations attach with `caelo_journal_attach(...)`. This
|
|
10
|
+
* file is the readable copy of that set, and the CI test
|
|
11
|
+
* `change-journal-registry.integration.test.ts` holds both in step: every
|
|
12
|
+
* `cms_admin` table must be either journaled here with the exact trigger
|
|
13
|
+
* arguments the database carries, or exempt here with a written reason. A
|
|
14
|
+
* new table that is neither fails CI, so no table can silently fall
|
|
15
|
+
* outside the journal.
|
|
16
|
+
*
|
|
17
|
+
* Plugin storage tables (`plugin_<slug>.*`) are not listed: the host
|
|
18
|
+
* attaches the trigger when it provisions a plugin's schema, under the kind
|
|
19
|
+
* `plugin_storage` keyed on the plugin's id (never on its reusable slug), so
|
|
20
|
+
* a new plugin or domain needs no journal migration.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** Every kind a journal row can carry. A consumer names the kinds it reads. */
|
|
24
|
+
export const JOURNAL_KINDS = [
|
|
25
|
+
"page",
|
|
26
|
+
"page_terms",
|
|
27
|
+
"page_seo",
|
|
28
|
+
"page_layout",
|
|
29
|
+
"page_module_content",
|
|
30
|
+
"module",
|
|
31
|
+
"template",
|
|
32
|
+
"template_blocks",
|
|
33
|
+
"layout",
|
|
34
|
+
"layout_blocks",
|
|
35
|
+
"layout_module",
|
|
36
|
+
"content_instance",
|
|
37
|
+
"list",
|
|
38
|
+
"list_type",
|
|
39
|
+
"page_type",
|
|
40
|
+
"theme",
|
|
41
|
+
"media",
|
|
42
|
+
"media_variant",
|
|
43
|
+
"media_crop",
|
|
44
|
+
"font",
|
|
45
|
+
"redirect",
|
|
46
|
+
"domain",
|
|
47
|
+
"site_defaults",
|
|
48
|
+
"site_settings",
|
|
49
|
+
"site_memory",
|
|
50
|
+
"skill",
|
|
51
|
+
"plugin",
|
|
52
|
+
"plugin_installation",
|
|
53
|
+
"plugin_grant",
|
|
54
|
+
"plugin_file",
|
|
55
|
+
"plugin_row",
|
|
56
|
+
"plugin_storage",
|
|
57
|
+
"snapshot",
|
|
58
|
+
] as const;
|
|
59
|
+
|
|
60
|
+
/** One kind of the journal (`entity_changes.kind`). */
|
|
61
|
+
export type JournalKind = (typeof JOURNAL_KINDS)[number];
|
|
62
|
+
|
|
63
|
+
const KIND_SET: ReadonlySet<string> = new Set(JOURNAL_KINDS);
|
|
64
|
+
|
|
65
|
+
/** Is `value` a journal kind? */
|
|
66
|
+
export function isJournalKind(value: string): value is JournalKind {
|
|
67
|
+
return KIND_SET.has(value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* How a journaled table's rows map to journal rows (the trigger's
|
|
72
|
+
* arguments, `caelo_journal_attach` in migration 0430):
|
|
73
|
+
*
|
|
74
|
+
* - `row` — a live entity table. The journal row carries the entity id
|
|
75
|
+
* (`key`), the row's own branch when the table has one (`branch`), and
|
|
76
|
+
* the chat from the writing transaction's attribution settings.
|
|
77
|
+
* - `snapshot` — an entity snapshot table. Branch, chat and snapshot id
|
|
78
|
+
* come from the snapshot's `site_snapshots` header, and an inserted
|
|
79
|
+
* snapshot records the snapshot it replaces on the same line
|
|
80
|
+
* (`prev_snapshot_id`), so a consumer can diff the two states.
|
|
81
|
+
* - `header` — `site_snapshots` itself: Stage (`staged_at`), undo
|
|
82
|
+
* (`undone_at`) and lock takeover (`chat_branch_id`) are UPDATEs of it.
|
|
83
|
+
*/
|
|
84
|
+
export type JournalMode = "row" | "snapshot" | "header";
|
|
85
|
+
|
|
86
|
+
/** One journaled table, exactly as its trigger is attached. */
|
|
87
|
+
export interface JournaledTable {
|
|
88
|
+
readonly kind: JournalKind;
|
|
89
|
+
readonly mode: JournalMode;
|
|
90
|
+
/** The column that holds the entity id (`entity_changes.row_id`). */
|
|
91
|
+
readonly key: string;
|
|
92
|
+
/** The primary-key columns an UPDATE's old and new rows are paired on. */
|
|
93
|
+
readonly pair: readonly string[];
|
|
94
|
+
/** A column naming the entity this row belongs to (`entity_changes.parent_id`). */
|
|
95
|
+
readonly parent?: string;
|
|
96
|
+
/** The row's own branch column (`row` mode only). */
|
|
97
|
+
readonly branch?: string;
|
|
98
|
+
/** The column holding the owning plugin's id. */
|
|
99
|
+
readonly plugin?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const row = (
|
|
103
|
+
kind: JournalKind,
|
|
104
|
+
key: string,
|
|
105
|
+
pair: readonly string[],
|
|
106
|
+
extra: Partial<Pick<JournaledTable, "parent" | "branch" | "plugin">> = {},
|
|
107
|
+
): JournaledTable => ({ kind, mode: "row", key, pair, ...extra });
|
|
108
|
+
|
|
109
|
+
const snapshot = (
|
|
110
|
+
kind: JournalKind,
|
|
111
|
+
key: string,
|
|
112
|
+
extra: Partial<Pick<JournaledTable, "parent" | "plugin">> = {},
|
|
113
|
+
): JournaledTable => ({ kind, mode: "snapshot", key, pair: ["id"], ...extra });
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The journaled `cms_admin` tables. Everything an editor, a render, a
|
|
117
|
+
* build or a plugin derives from: content and its snapshots, media,
|
|
118
|
+
* settings that render into pages, redirects, plugins and their grants.
|
|
119
|
+
*/
|
|
120
|
+
export const JOURNALED_TABLES: Readonly<Record<string, JournaledTable>> = {
|
|
121
|
+
pages: row("page", "id", ["id"], { branch: "chat_branch_id" }),
|
|
122
|
+
page_terms: row("page_terms", "page_id", ["page_id", "list_id", "item_id"]),
|
|
123
|
+
pages_seo: row("page_seo", "page_id", ["page_id"]),
|
|
124
|
+
page_modules: row("page_layout", "page_id", ["page_id", "block_name", "position"]),
|
|
125
|
+
page_module_content: row("page_module_content", "id", ["id"], { parent: "page_id" }),
|
|
126
|
+
modules: row("module", "id", ["id"], { branch: "chat_branch_id" }),
|
|
127
|
+
templates: row("template", "id", ["id"], { branch: "chat_branch_id" }),
|
|
128
|
+
template_blocks: row("template_blocks", "template_id", ["template_id", "name"]),
|
|
129
|
+
layouts: row("layout", "id", ["id"], { branch: "chat_branch_id" }),
|
|
130
|
+
layout_blocks: row("layout_blocks", "layout_id", ["layout_id", "name"]),
|
|
131
|
+
layout_modules: row("layout_module", "layout_id", ["layout_id", "block_name", "position"]),
|
|
132
|
+
content_instances: row("content_instance", "id", ["id"], {
|
|
133
|
+
branch: "chat_branch_id",
|
|
134
|
+
parent: "module_id",
|
|
135
|
+
}),
|
|
136
|
+
lists: row("list", "id", ["id"], { branch: "chat_branch_id" }),
|
|
137
|
+
list_types: row("list_type", "id", ["id"], { branch: "chat_branch_id" }),
|
|
138
|
+
page_types: row("page_type", "id", ["id"], { branch: "chat_branch_id" }),
|
|
139
|
+
themes: row("theme", "id", ["id"]),
|
|
140
|
+
media_assets: row("media", "id", ["id"]),
|
|
141
|
+
media_variants: row("media_variant", "asset_id", ["asset_id", "variant"]),
|
|
142
|
+
media_crops: row("media_crop", "id", ["id"], { parent: "asset_id" }),
|
|
143
|
+
font_assets: row("font", "id", ["id"]),
|
|
144
|
+
redirects: row("redirect", "id", ["id"]),
|
|
145
|
+
domains: row("domain", "id", ["id"]),
|
|
146
|
+
site_defaults: row("site_defaults", "id", ["id"]),
|
|
147
|
+
site_settings: row("site_settings", "id", ["id"]),
|
|
148
|
+
site_ai_memory: row("site_memory", "id", ["id"]),
|
|
149
|
+
skills: row("skill", "id", ["id"]),
|
|
150
|
+
plugins: row("plugin", "id", ["id"]),
|
|
151
|
+
plugin_installation_versions: row("plugin_installation", "id", ["id"], { parent: "plugin_id" }),
|
|
152
|
+
plugin_capability_grants: row("plugin_grant", "id", ["id"], { parent: "plugin_id" }),
|
|
153
|
+
plugin_private_files: row("plugin_file", "id", ["plugin_id", "id"], { plugin: "plugin_id" }),
|
|
154
|
+
|
|
155
|
+
site_snapshots: { kind: "snapshot", mode: "header", key: "id", pair: ["id"] },
|
|
156
|
+
page_snapshots: snapshot("page", "page_id"),
|
|
157
|
+
page_layout_snapshots: snapshot("page_layout", "page_id"),
|
|
158
|
+
page_module_content_snapshots: snapshot("page_module_content", "page_module_content_id", {
|
|
159
|
+
parent: "page_id",
|
|
160
|
+
}),
|
|
161
|
+
module_snapshots: snapshot("module", "module_id"),
|
|
162
|
+
template_snapshots: snapshot("template", "template_id"),
|
|
163
|
+
layout_module_snapshots: snapshot("layout_module", "layout_id"),
|
|
164
|
+
content_instance_snapshots: snapshot("content_instance", "content_instance_id"),
|
|
165
|
+
list_snapshots: snapshot("list", "list_id"),
|
|
166
|
+
list_type_snapshots: snapshot("list_type", "list_type_id"),
|
|
167
|
+
page_type_snapshots: snapshot("page_type", "page_type_id"),
|
|
168
|
+
theme_snapshots: snapshot("theme", "theme_id"),
|
|
169
|
+
plugin_row_snapshots: snapshot("plugin_row", "row_id", {
|
|
170
|
+
parent: "table_name",
|
|
171
|
+
plugin: "plugin_id",
|
|
172
|
+
}),
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const QUEUE = "a proposal queue; its changes reach editors as the op-classified `pending` topic";
|
|
176
|
+
const LOG = "an append-only log or history; nothing is derived from it";
|
|
177
|
+
const LEASE = "a lease or lock that coordinates processes; nothing is derived from it";
|
|
178
|
+
const SECURITY = "identity and permission rows, read per request by the auth layer";
|
|
179
|
+
const RUNTIME = "runtime bookkeeping of a process (health, progress, cache)";
|
|
180
|
+
const RETIRED = "retired by #1267; nothing reads it any more, migration 0442 drops it";
|
|
181
|
+
const RETIRED_SIGNAL =
|
|
182
|
+
"retired by #1267; nothing reads it, its writer triggers stay one release for the previous image (roll, rollback), migration 0442 drops both";
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Every `cms_admin` table that writes no journal rows, with the reason.
|
|
186
|
+
* Adding a table here is a decision a reviewer reads, not a default.
|
|
187
|
+
*/
|
|
188
|
+
export const JOURNAL_EXEMPT_TABLES: Readonly<Record<string, string>> = {
|
|
189
|
+
__drizzle_migrations: "the migration runner's own bookkeeping",
|
|
190
|
+
entity_changes: "the journal itself",
|
|
191
|
+
entity_change_horizons: "the journal's garbage-collection horizons",
|
|
192
|
+
change_consumers: "the journal's consumer cursors",
|
|
193
|
+
domain_events: RETIRED,
|
|
194
|
+
font_usage_changes: RETIRED_SIGNAL,
|
|
195
|
+
site_view_generation: RETIRED_SIGNAL,
|
|
196
|
+
plugin_event_cursors: RETIRED,
|
|
197
|
+
|
|
198
|
+
actors: SECURITY,
|
|
199
|
+
users: SECURITY,
|
|
200
|
+
roles: SECURITY,
|
|
201
|
+
permissions: SECURITY,
|
|
202
|
+
role_permissions: SECURITY,
|
|
203
|
+
user_roles: SECURITY,
|
|
204
|
+
sessions: SECURITY,
|
|
205
|
+
password_reset_tokens: SECURITY,
|
|
206
|
+
owner_bootstrap_tokens: SECURITY,
|
|
207
|
+
mcp_tokens: SECURITY,
|
|
208
|
+
mcp_remote_connections: SECURITY,
|
|
209
|
+
mcp_remote_access_blocks: SECURITY,
|
|
210
|
+
mcp_transport_sessions: SECURITY,
|
|
211
|
+
operator_oauth_client: SECURITY,
|
|
212
|
+
credential_handoffs:
|
|
213
|
+
"one-time credentials an approval left; delivered as the `credentials` topic",
|
|
214
|
+
user_preferences: "one person's editor preferences, read only by that person's own requests",
|
|
215
|
+
skill_pin_defaults: "one person's skill pins, read only by that person's own chats",
|
|
216
|
+
|
|
217
|
+
audit_events: LOG,
|
|
218
|
+
ai_calls: LOG,
|
|
219
|
+
ai_bug_reports: LOG,
|
|
220
|
+
ai_moduleize_attempts: LOG,
|
|
221
|
+
page_edit_log: LOG,
|
|
222
|
+
import_run_events: LOG,
|
|
223
|
+
platform_update_events: LOG,
|
|
224
|
+
plugin_errors: LOG,
|
|
225
|
+
redirect_syncs: LOG,
|
|
226
|
+
operator_access_sync_runs: LOG,
|
|
227
|
+
link_migration_runs: LOG,
|
|
228
|
+
comment_archive:
|
|
229
|
+
"visitor comments copied from cms_public: untrusted visitor data, nothing is derived from it",
|
|
230
|
+
|
|
231
|
+
chat_sessions:
|
|
232
|
+
"conversation metadata; what a chat changed is journaled through its snapshots, its run state reaches editors as the `agents` topic",
|
|
233
|
+
chat_messages: "conversation history (the provider's message log)",
|
|
234
|
+
chat_tool_results: "conversation history (tool results)",
|
|
235
|
+
chat_agent_runs: "running agents; reach editors as the op-classified `agents` topic",
|
|
236
|
+
chat_turn_approvals: "paused approval cards; reach editors as the `pending` topic",
|
|
237
|
+
chat_turn_leases: LEASE,
|
|
238
|
+
chat_entity_locks:
|
|
239
|
+
"cross-branch entity locks; a takeover re-points the snapshots, which are journaled",
|
|
240
|
+
chat_lock_takeovers: LOG,
|
|
241
|
+
chat_branch_publish_marks:
|
|
242
|
+
"which branch states reached main; the Stage that writes it also updates the journaled site_snapshots",
|
|
243
|
+
draft_entity_observations: "which draft entity states a chat has read (conflict detection)",
|
|
244
|
+
subagent_runs: "subagent bookkeeping of a chat turn",
|
|
245
|
+
mcp_approval_handoffs: "approval hand-offs to an MCP client",
|
|
246
|
+
tool_approval_actions: "approval decisions of chat tool calls",
|
|
247
|
+
plugin_tool_approval_bindings: "the binding of an approved plugin tool call to its arguments",
|
|
248
|
+
site_draft: "the shared draft branch's registry row; branch changes are journaled as snapshots",
|
|
249
|
+
genesis_drafts: "design drafts before a site exists; no page renders from them",
|
|
250
|
+
image_requests: "image generation requests; the resulting media asset is journaled",
|
|
251
|
+
media_alt_proposals:
|
|
252
|
+
"alt-text suggestions awaiting review; the accepted alt is journaled on media_assets",
|
|
253
|
+
entity_leases: LEASE,
|
|
254
|
+
deploy_leases: LEASE,
|
|
255
|
+
plugin_activation_leases: LEASE,
|
|
256
|
+
rate_limit_buckets: "visitor and login rate-limit counters",
|
|
257
|
+
rate_limit_profiles: "gateway rate-limit profiles, published to the gateway's projection",
|
|
258
|
+
plugin_rate_limit_overrides:
|
|
259
|
+
"gateway rate-limit overrides, published to the gateway's projection",
|
|
260
|
+
plugin_rate_limit_proposals: QUEUE,
|
|
261
|
+
|
|
262
|
+
ai_providers: "Owner AI configuration; read per call, nothing is derived from it",
|
|
263
|
+
ai_budgets: "Owner AI budgets; read per call, nothing is derived from it",
|
|
264
|
+
ai_pricing: "Owner AI pricing; read per call, nothing is derived from it",
|
|
265
|
+
email_config: "Owner email configuration; read per send",
|
|
266
|
+
telemetry_settings: "the install's telemetry consent",
|
|
267
|
+
staging_access:
|
|
268
|
+
"staging access settings, synced to the hosting provider on save (docs/dev/redirects-and-settings-sync.md)",
|
|
269
|
+
provisioning_outputs: "what the provisioner recorded about the install",
|
|
270
|
+
release_check_cache: RUNTIME,
|
|
271
|
+
deploy_targets: "deploy target configuration; read by the deploy ops",
|
|
272
|
+
deploy_runs: "deploy runs; reach editors as the op-classified `deploys` topic",
|
|
273
|
+
redirect_sync_state: RUNTIME,
|
|
274
|
+
redirect_changes:
|
|
275
|
+
"which transactions changed redirects, folded by the redirect sync; the journaled redirects table is the source",
|
|
276
|
+
static_bakes: "derived build output of plugin-baked regions",
|
|
277
|
+
plugin_data_build_state: RUNTIME,
|
|
278
|
+
plugin_data_stale_pages: "derived: which pages' baked plugin regions are stale",
|
|
279
|
+
plugin_runtime: RUNTIME,
|
|
280
|
+
plugin_schema_migrations: "plugin DDL bookkeeping",
|
|
281
|
+
plugin_schema_provisions: "plugin DDL bookkeeping",
|
|
282
|
+
plugin_private_file_chunks:
|
|
283
|
+
"the bytes of plugin_private_files rows, journaled through the file row",
|
|
284
|
+
public_projection_outbox: "the outbox of the cms_public projection, drained by its publisher",
|
|
285
|
+
platform_update_agent: RUNTIME,
|
|
286
|
+
platform_update_notifications: RUNTIME,
|
|
287
|
+
platform_update_policy: "the Owner's update policy, read by the update scheduler",
|
|
288
|
+
platform_update_requests: "update requests, run by the upgrader job",
|
|
289
|
+
platform_update_scheduler: RUNTIME,
|
|
290
|
+
|
|
291
|
+
import_runs: "site-import runs; reach editors as the op-classified `crawl` topic",
|
|
292
|
+
import_pages: "crawled pages of a site import, before they become pages",
|
|
293
|
+
import_run_links: "links found by a site import",
|
|
294
|
+
quality_audit_runs: "quality audits; reach editors as the op-classified `quality` topic",
|
|
295
|
+
quality_audit_pages: "quality audit results per page",
|
|
296
|
+
quality_baselines: "quality baselines per page, written by the audit worker",
|
|
297
|
+
quality_acceptances: "accepted quality findings; reach editors as the `quality` topic",
|
|
298
|
+
site_memory_proposals: QUEUE,
|
|
299
|
+
skill_proposals: QUEUE,
|
|
300
|
+
|
|
301
|
+
ai_providers_pending_actions: QUEUE,
|
|
302
|
+
deploy_pending_actions: QUEUE,
|
|
303
|
+
domain_pending_actions: QUEUE,
|
|
304
|
+
email_config_pending_actions: QUEUE,
|
|
305
|
+
layout_pending_actions: QUEUE,
|
|
306
|
+
mcp_token_pending_actions: QUEUE,
|
|
307
|
+
owner_settings_pending_actions: QUEUE,
|
|
308
|
+
plugin_pending_actions: QUEUE,
|
|
309
|
+
quality_pending_actions: QUEUE,
|
|
310
|
+
role_pending_actions: QUEUE,
|
|
311
|
+
site_defaults_pending_actions: QUEUE,
|
|
312
|
+
snapshot_revert_pending_actions: QUEUE,
|
|
313
|
+
template_pending_actions: QUEUE,
|
|
314
|
+
theme_pending_actions: QUEUE,
|
|
315
|
+
url_migration_pending_actions: QUEUE,
|
|
316
|
+
user_pending_actions: QUEUE,
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
/** NOTIFY channel the journal trigger wakes consumers on (payload empty). */
|
|
320
|
+
export const JOURNAL_CHANNEL = "caelo_entity_changes";
|
|
321
|
+
|
|
322
|
+
/** NOTIFY channel carrying operation-classified live topics across instances. */
|
|
323
|
+
export const LIVE_TOPICS_CHANNEL = "caelo_live_topics";
|