@caelo-cms/provisioning 0.10.72 → 0.11.1
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/agent-db.js +605 -134
- package/dist/cdn-copy.d.ts +3 -4
- package/dist/cdn-copy.d.ts.map +1 -1
- package/dist/cdn-copy.js.map +1 -1
- package/dist/stack-contract.d.ts +13 -0
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +18 -0
- package/dist/stack-contract.js.map +1 -1
- package/dist/stack-converge.d.ts +13 -0
- package/dist/stack-converge.d.ts.map +1 -1
- package/dist/stack-converge.js +26 -0
- package/dist/stack-converge.js.map +1 -1
- package/dist/upgrade/app-roll.d.ts +4 -1
- package/dist/upgrade/app-roll.d.ts.map +1 -1
- package/dist/upgrade/app-roll.js +7 -3
- package/dist/upgrade/app-roll.js.map +1 -1
- package/dist/wizards/gcp-cost.d.ts.map +1 -1
- package/dist/wizards/gcp-cost.js +5 -2
- package/dist/wizards/gcp-cost.js.map +1 -1
- package/package.json +2 -2
- package/src/cdn-copy.ts +3 -4
- package/src/cpu-idle.test.ts +64 -0
- package/src/stack-contract.ts +19 -0
- package/src/stack-converge.ts +31 -0
- package/src/upgrade/app-roll.ts +12 -2
- package/src/upgrade/upgrade.test.ts +17 -1
- package/src/wizards/gcp-cost.ts +5 -2
- package/stacks/gcp/index.ts +6 -1
- package/stacks/gcp-firebase/index.ts +6 -1
package/dist/agent-db.js
CHANGED
|
@@ -6335,6 +6335,350 @@ var ZodIssueCode = {
|
|
|
6335
6335
|
};
|
|
6336
6336
|
var ZodFirstPartyTypeKind;
|
|
6337
6337
|
(function(ZodFirstPartyTypeKind) {})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
6338
|
+
// ../shared/src/escaped-line-breaks.ts
|
|
6339
|
+
function escapedLineBreakLength(value, i) {
|
|
6340
|
+
if (value[i] !== "\\")
|
|
6341
|
+
return 0;
|
|
6342
|
+
if (value[i + 1] === "n")
|
|
6343
|
+
return 2;
|
|
6344
|
+
if (value[i + 1] === "r" && value[i + 2] === "\\" && value[i + 3] === "n")
|
|
6345
|
+
return 4;
|
|
6346
|
+
return 0;
|
|
6347
|
+
}
|
|
6348
|
+
var REGEX_PRECEDERS = new Set([..."(,=:[!&|?{};+-*%<>~^"]);
|
|
6349
|
+
function skipQuoted(value, start) {
|
|
6350
|
+
const quote = value[start];
|
|
6351
|
+
let j = start + 1;
|
|
6352
|
+
while (j < value.length) {
|
|
6353
|
+
const ch = value[j];
|
|
6354
|
+
if (ch === "\\") {
|
|
6355
|
+
if (value[j + 1] === "n" || value[j + 1] === "r")
|
|
6356
|
+
return -1;
|
|
6357
|
+
j += 2;
|
|
6358
|
+
continue;
|
|
6359
|
+
}
|
|
6360
|
+
if (ch === quote)
|
|
6361
|
+
return j + 1;
|
|
6362
|
+
j += 1;
|
|
6363
|
+
}
|
|
6364
|
+
return j;
|
|
6365
|
+
}
|
|
6366
|
+
function jsLiteralHoldsEscape(value) {
|
|
6367
|
+
let prev = "";
|
|
6368
|
+
let i = 0;
|
|
6369
|
+
while (i < value.length) {
|
|
6370
|
+
const ch = value[i];
|
|
6371
|
+
const lineBreak = escapedLineBreakLength(value, i);
|
|
6372
|
+
if (lineBreak > 0) {
|
|
6373
|
+
prev = "";
|
|
6374
|
+
i += lineBreak;
|
|
6375
|
+
continue;
|
|
6376
|
+
}
|
|
6377
|
+
if (ch === "\\") {
|
|
6378
|
+
i += 2;
|
|
6379
|
+
continue;
|
|
6380
|
+
}
|
|
6381
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
6382
|
+
const end = skipQuoted(value, i);
|
|
6383
|
+
if (end < 0)
|
|
6384
|
+
return true;
|
|
6385
|
+
prev = ch;
|
|
6386
|
+
i = end;
|
|
6387
|
+
continue;
|
|
6388
|
+
}
|
|
6389
|
+
if (ch === "/" && value[i + 1] === "/") {
|
|
6390
|
+
i += 2;
|
|
6391
|
+
while (i < value.length && escapedLineBreakLength(value, i) === 0)
|
|
6392
|
+
i += 1;
|
|
6393
|
+
continue;
|
|
6394
|
+
}
|
|
6395
|
+
if (ch === "/" && value[i + 1] === "*") {
|
|
6396
|
+
const close = value.indexOf("*/", i + 2);
|
|
6397
|
+
i = close < 0 ? value.length : close + 2;
|
|
6398
|
+
continue;
|
|
6399
|
+
}
|
|
6400
|
+
if (ch === "/" && (prev === "" || REGEX_PRECEDERS.has(prev))) {
|
|
6401
|
+
let j = i + 1;
|
|
6402
|
+
let inClass = false;
|
|
6403
|
+
while (j < value.length) {
|
|
6404
|
+
const r = value[j];
|
|
6405
|
+
if (r === "\\") {
|
|
6406
|
+
if (value[j + 1] === "n" || value[j + 1] === "r")
|
|
6407
|
+
return true;
|
|
6408
|
+
j += 2;
|
|
6409
|
+
continue;
|
|
6410
|
+
}
|
|
6411
|
+
if (r === "[")
|
|
6412
|
+
inClass = true;
|
|
6413
|
+
else if (r === "]")
|
|
6414
|
+
inClass = false;
|
|
6415
|
+
else if (r === "/" && !inClass)
|
|
6416
|
+
break;
|
|
6417
|
+
j += 1;
|
|
6418
|
+
}
|
|
6419
|
+
prev = "/";
|
|
6420
|
+
i = j + 1;
|
|
6421
|
+
continue;
|
|
6422
|
+
}
|
|
6423
|
+
if (ch !== " " && ch !== "\t")
|
|
6424
|
+
prev = ch;
|
|
6425
|
+
i += 1;
|
|
6426
|
+
}
|
|
6427
|
+
return false;
|
|
6428
|
+
}
|
|
6429
|
+
function cssLiteralHoldsEscape(value) {
|
|
6430
|
+
let i = 0;
|
|
6431
|
+
while (i < value.length) {
|
|
6432
|
+
const ch = value[i];
|
|
6433
|
+
if (ch === "/" && value[i + 1] === "*") {
|
|
6434
|
+
const close = value.indexOf("*/", i + 2);
|
|
6435
|
+
i = close < 0 ? value.length : close + 2;
|
|
6436
|
+
continue;
|
|
6437
|
+
}
|
|
6438
|
+
if (ch === '"' || ch === "'") {
|
|
6439
|
+
const end = skipQuoted(value, i);
|
|
6440
|
+
if (end < 0)
|
|
6441
|
+
return true;
|
|
6442
|
+
i = end;
|
|
6443
|
+
continue;
|
|
6444
|
+
}
|
|
6445
|
+
i += ch === "\\" ? 2 : 1;
|
|
6446
|
+
}
|
|
6447
|
+
return false;
|
|
6448
|
+
}
|
|
6449
|
+
var RAW_TEXT_ELEMENTS = new Set(["script", "style", "pre", "textarea"]);
|
|
6450
|
+
function htmlLiteralHoldsEscape(value) {
|
|
6451
|
+
const lower = value.toLowerCase();
|
|
6452
|
+
let i = 0;
|
|
6453
|
+
while (i < value.length) {
|
|
6454
|
+
if (value[i] !== "<") {
|
|
6455
|
+
i += 1;
|
|
6456
|
+
continue;
|
|
6457
|
+
}
|
|
6458
|
+
if (value.startsWith("<!--", i)) {
|
|
6459
|
+
const close = value.indexOf("-->", i + 4);
|
|
6460
|
+
const end = close < 0 ? value.length : close + 3;
|
|
6461
|
+
if (/(?<!\\)\\[nr]/.test(value.slice(i, end)))
|
|
6462
|
+
return true;
|
|
6463
|
+
i = end;
|
|
6464
|
+
continue;
|
|
6465
|
+
}
|
|
6466
|
+
const name = /^<([a-zA-Z][a-zA-Z0-9-]*)/.exec(value.slice(i, i + 64))?.[1]?.toLowerCase();
|
|
6467
|
+
let j = i + 1;
|
|
6468
|
+
while (j < value.length && value[j] !== ">") {
|
|
6469
|
+
if (value[j] === '"' || value[j] === "'") {
|
|
6470
|
+
const end = skipQuoted(value, j);
|
|
6471
|
+
if (end < 0)
|
|
6472
|
+
return true;
|
|
6473
|
+
j = end;
|
|
6474
|
+
continue;
|
|
6475
|
+
}
|
|
6476
|
+
j += 1;
|
|
6477
|
+
}
|
|
6478
|
+
i = j + 1;
|
|
6479
|
+
if (name && RAW_TEXT_ELEMENTS.has(name)) {
|
|
6480
|
+
const close = lower.indexOf(`</${name}`, i);
|
|
6481
|
+
const end = close < 0 ? value.length : close;
|
|
6482
|
+
if (/(?<!\\)\\[nr]/.test(value.slice(i, end)))
|
|
6483
|
+
return true;
|
|
6484
|
+
i = end;
|
|
6485
|
+
}
|
|
6486
|
+
}
|
|
6487
|
+
return false;
|
|
6488
|
+
}
|
|
6489
|
+
var LITERAL_HOLDS_ESCAPE = {
|
|
6490
|
+
html: htmlLiteralHoldsEscape,
|
|
6491
|
+
css: cssLiteralHoldsEscape,
|
|
6492
|
+
js: jsLiteralHoldsEscape
|
|
6493
|
+
};
|
|
6494
|
+
var ESCAPED_LINE_BREAK = /(?<!\\)(?:\\r)?\\n/g;
|
|
6495
|
+
function hasEscapedLineBreaks(value, language) {
|
|
6496
|
+
if (/[\r\n]/.test(value))
|
|
6497
|
+
return false;
|
|
6498
|
+
const hits = value.match(ESCAPED_LINE_BREAK)?.length ?? 0;
|
|
6499
|
+
if (hits < 2)
|
|
6500
|
+
return false;
|
|
6501
|
+
if (!/(?<!\\)\\n(?:[ \t]|\\t)/.test(value))
|
|
6502
|
+
return false;
|
|
6503
|
+
return !LITERAL_HOLDS_ESCAPE[language](value);
|
|
6504
|
+
}
|
|
6505
|
+
function decodeEscapedLineBreaks(value, language) {
|
|
6506
|
+
if (typeof value !== "string" || !hasEscapedLineBreaks(value, language))
|
|
6507
|
+
return value;
|
|
6508
|
+
return value.replace(/(?<!\\)(?:\\r)?\\n((?:\\t)*)/g, (_m, tabs) => `
|
|
6509
|
+
${"\t".repeat(tabs.length / 2)}`);
|
|
6510
|
+
}
|
|
6511
|
+
|
|
6512
|
+
// ../shared/src/lists/fields.ts
|
|
6513
|
+
var LIST_RESERVED_NAMES = new Set([
|
|
6514
|
+
"id",
|
|
6515
|
+
"node",
|
|
6516
|
+
"index",
|
|
6517
|
+
"depth",
|
|
6518
|
+
"first",
|
|
6519
|
+
"last",
|
|
6520
|
+
"items",
|
|
6521
|
+
"page",
|
|
6522
|
+
"site_text",
|
|
6523
|
+
"recurse"
|
|
6524
|
+
]);
|
|
6525
|
+
var listNameSchema = string2().regex(/^[a-z][a-z0-9_]{0,63}$/, "must be snake_case (lowercase letters, digits, underscores)");
|
|
6526
|
+
var fieldLabel = string2().min(1).max(128);
|
|
6527
|
+
var fieldExtSchema = record(string2().regex(/^[a-z0-9-]+$/), unknown());
|
|
6528
|
+
var base = {
|
|
6529
|
+
name: listNameSchema,
|
|
6530
|
+
label: fieldLabel,
|
|
6531
|
+
required: boolean2().optional(),
|
|
6532
|
+
default: unknown().optional(),
|
|
6533
|
+
ext: fieldExtSchema.optional()
|
|
6534
|
+
};
|
|
6535
|
+
var textField = object({
|
|
6536
|
+
...base,
|
|
6537
|
+
type: literal("text"),
|
|
6538
|
+
maxLength: number2().int().min(1).max(2000).optional()
|
|
6539
|
+
}).strict();
|
|
6540
|
+
var richtextField = object({
|
|
6541
|
+
...base,
|
|
6542
|
+
type: literal("richtext"),
|
|
6543
|
+
maxLength: number2().int().min(1).max(20000).optional()
|
|
6544
|
+
}).strict();
|
|
6545
|
+
var linkField = object({ ...base, type: literal("link") }).strict();
|
|
6546
|
+
var mediaField = object({ ...base, type: literal("media") }).strict();
|
|
6547
|
+
var selectField = object({
|
|
6548
|
+
...base,
|
|
6549
|
+
type: literal("select"),
|
|
6550
|
+
options: array(listNameSchema).min(1).max(64)
|
|
6551
|
+
}).strict();
|
|
6552
|
+
var booleanField = object({ ...base, type: literal("boolean") }).strict();
|
|
6553
|
+
var numberField = object({
|
|
6554
|
+
...base,
|
|
6555
|
+
type: literal("number"),
|
|
6556
|
+
min: number2().optional(),
|
|
6557
|
+
max: number2().optional()
|
|
6558
|
+
}).strict();
|
|
6559
|
+
var dateField = object({ ...base, type: literal("date") }).strict();
|
|
6560
|
+
var iconField = object({ ...base, type: literal("icon") }).strict();
|
|
6561
|
+
var moduleField = object({
|
|
6562
|
+
...base,
|
|
6563
|
+
type: literal("module"),
|
|
6564
|
+
accepts: array(string2().regex(/^[a-z0-9-]+$/)).max(32).optional()
|
|
6565
|
+
}).strict();
|
|
6566
|
+
var termField = object({
|
|
6567
|
+
...base,
|
|
6568
|
+
type: literal("term"),
|
|
6569
|
+
list: string2().regex(/^[a-z0-9-]+$/),
|
|
6570
|
+
multiple: boolean2().optional()
|
|
6571
|
+
}).strict();
|
|
6572
|
+
var fieldDefSchema = discriminatedUnion("type", [
|
|
6573
|
+
textField,
|
|
6574
|
+
richtextField,
|
|
6575
|
+
linkField,
|
|
6576
|
+
mediaField,
|
|
6577
|
+
selectField,
|
|
6578
|
+
booleanField,
|
|
6579
|
+
numberField,
|
|
6580
|
+
dateField,
|
|
6581
|
+
iconField,
|
|
6582
|
+
moduleField,
|
|
6583
|
+
termField
|
|
6584
|
+
]);
|
|
6585
|
+
var linkValueSchema = object({
|
|
6586
|
+
href: string2().min(1).max(2000),
|
|
6587
|
+
target: _enum(["_self", "_blank"]).optional()
|
|
6588
|
+
}).strict();
|
|
6589
|
+
var embeddedModuleValueSchema = object({ moduleId: string2().uuid(), contentInstanceId: string2().uuid() }).strict();
|
|
6590
|
+
|
|
6591
|
+
// ../shared/src/lists/list-type.ts
|
|
6592
|
+
var LIST_MAX_DEPTH = 8;
|
|
6593
|
+
var LIST_MAX_ITEMS = 500;
|
|
6594
|
+
var LIST_QUERY_MAX_LIMIT = 50;
|
|
6595
|
+
var QUERY_KNOBS = [
|
|
6596
|
+
"page_type",
|
|
6597
|
+
"terms",
|
|
6598
|
+
"terms_mode",
|
|
6599
|
+
"parent",
|
|
6600
|
+
"exclude_current",
|
|
6601
|
+
"order",
|
|
6602
|
+
"limit"
|
|
6603
|
+
];
|
|
6604
|
+
var SYSTEM_SOURCE_NAMES = [
|
|
6605
|
+
"breadcrumbs",
|
|
6606
|
+
"children",
|
|
6607
|
+
"siblings",
|
|
6608
|
+
"page_terms",
|
|
6609
|
+
"term_pages"
|
|
6610
|
+
];
|
|
6611
|
+
var queryOrderSchema = union([
|
|
6612
|
+
_enum(["published_desc", "published_asc", "title_asc"]),
|
|
6613
|
+
string2().regex(/^prop_(?:desc|asc):[a-z][a-z0-9_]{0,63}$/)
|
|
6614
|
+
]);
|
|
6615
|
+
var pageQuerySchema = object({
|
|
6616
|
+
page_type: string2().regex(/^[a-z0-9-]+$/).optional(),
|
|
6617
|
+
terms: array(string2().regex(/^caelo:term\/[0-9a-f-]{36}\/[0-9a-f-]{36}$/)).max(20).optional(),
|
|
6618
|
+
terms_mode: _enum(["any", "all"]).optional(),
|
|
6619
|
+
parent: string2().regex(/^caelo:page\/[0-9a-f-]{36}$/).optional(),
|
|
6620
|
+
exclude_current: boolean2().optional(),
|
|
6621
|
+
order: queryOrderSchema,
|
|
6622
|
+
limit: number2().int().min(1).max(LIST_QUERY_MAX_LIMIT)
|
|
6623
|
+
}).strict();
|
|
6624
|
+
var pageQueryPartialSchema = pageQuerySchema.partial();
|
|
6625
|
+
var sourceDefSchema = discriminatedUnion("kind", [
|
|
6626
|
+
object({
|
|
6627
|
+
kind: literal("query"),
|
|
6628
|
+
editable: array(_enum(QUERY_KNOBS)).max(QUERY_KNOBS.length),
|
|
6629
|
+
defaults: pageQueryPartialSchema
|
|
6630
|
+
}).strict(),
|
|
6631
|
+
object({
|
|
6632
|
+
kind: literal("system"),
|
|
6633
|
+
name: _enum(SYSTEM_SOURCE_NAMES, {
|
|
6634
|
+
error: () => `system sources are ${SYSTEM_SOURCE_NAMES.join(", ")} \u2014 a plugin's list source (consent_categories, language_links, \u2026) is {kind:"plugin", name:"<source>"}, and a module that only iterates it needs no field at all: {{#<source>}}\u2026{{/<source>}}.`
|
|
6635
|
+
})
|
|
6636
|
+
}).strict(),
|
|
6637
|
+
object({
|
|
6638
|
+
kind: literal("plugin"),
|
|
6639
|
+
name: string2().regex(/^[a-z][a-z0-9_]{0,63}$/)
|
|
6640
|
+
}).strict()
|
|
6641
|
+
]);
|
|
6642
|
+
var childrenSchema = object({
|
|
6643
|
+
name: listNameSchema,
|
|
6644
|
+
allow: array(listNameSchema).min(1).max(32),
|
|
6645
|
+
max: number2().int().min(1).max(LIST_MAX_ITEMS).optional()
|
|
6646
|
+
}).strict();
|
|
6647
|
+
var nodeDefSchema = object({
|
|
6648
|
+
label: string2().min(1).max(128),
|
|
6649
|
+
fields: array(fieldDefSchema).max(32),
|
|
6650
|
+
children: childrenSchema.optional(),
|
|
6651
|
+
current_from: listNameSchema.optional(),
|
|
6652
|
+
source: sourceDefSchema.optional(),
|
|
6653
|
+
ext: fieldExtSchema.optional()
|
|
6654
|
+
}).strict();
|
|
6655
|
+
var LIST_TYPE_ROLES = ["navigation", "vocabulary", "content"];
|
|
6656
|
+
var listTypeDefSchema = object({
|
|
6657
|
+
slug: string2().regex(/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/),
|
|
6658
|
+
name: string2().min(1).max(200),
|
|
6659
|
+
purpose: string2().min(1).max(1000),
|
|
6660
|
+
role: _enum(LIST_TYPE_ROLES),
|
|
6661
|
+
root: object({
|
|
6662
|
+
allow: array(listNameSchema).min(1).max(32),
|
|
6663
|
+
max: number2().int().min(1).max(LIST_MAX_ITEMS).optional()
|
|
6664
|
+
}).strict(),
|
|
6665
|
+
nodes: record(listNameSchema, nodeDefSchema),
|
|
6666
|
+
max_depth: number2().int().min(1).max(LIST_MAX_DEPTH).optional()
|
|
6667
|
+
}).strict();
|
|
6668
|
+
|
|
6669
|
+
// ../shared/src/lists/items.ts
|
|
6670
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
6671
|
+
var listItemInputSchema = lazy(() => object({
|
|
6672
|
+
id: string2().regex(UUID_RE, "id must be a lowercase uuid").optional(),
|
|
6673
|
+
node: string2().min(1).max(64),
|
|
6674
|
+
values: record(string2(), unknown()).default({}),
|
|
6675
|
+
children: array(listItemInputSchema).optional(),
|
|
6676
|
+
query: record(string2(), unknown()).optional()
|
|
6677
|
+
}).strict());
|
|
6678
|
+
|
|
6679
|
+
// ../shared/src/lists/refs.ts
|
|
6680
|
+
var LIST_REF_RE = /^caelo:list\/([0-9a-f-]{36})$/;
|
|
6681
|
+
|
|
6338
6682
|
// ../shared/src/content.ts
|
|
6339
6683
|
var slugSchema = string2().regex(/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/, "slug must be lowercase letters, digits, or hyphens (1\u201364 chars, no leading/trailing hyphen)");
|
|
6340
6684
|
var displayNameSchema = string2().min(1).max(128);
|
|
@@ -6343,12 +6687,49 @@ var MODULE_CSS_MAX = 128 * 1024;
|
|
|
6343
6687
|
var MODULE_JS_MAX = 256 * 1024;
|
|
6344
6688
|
var TEMPLATE_HTML_MAX = 512 * 1024;
|
|
6345
6689
|
var TEMPLATE_CSS_MAX = 128 * 1024;
|
|
6346
|
-
|
|
6690
|
+
function jsonEncodedCodeMessage(field, value) {
|
|
6691
|
+
const t = value.trim();
|
|
6692
|
+
if (t.length < 2 || !t.startsWith('"') || !t.endsWith('"'))
|
|
6693
|
+
return null;
|
|
6694
|
+
try {
|
|
6695
|
+
if (typeof JSON.parse(t) !== "string")
|
|
6696
|
+
return null;
|
|
6697
|
+
} catch {
|
|
6698
|
+
return null;
|
|
6699
|
+
}
|
|
6700
|
+
return `${field} is JSON-encoded (wrapped in quotes with \\" escapes) \u2014 send the raw ${field} itself, not a JSON string of it.`;
|
|
6701
|
+
}
|
|
6702
|
+
function htmlEscapedMarkupMessage(field, value) {
|
|
6703
|
+
if (value.includes("<") || !/<\/?[a-zA-Z]/.test(value))
|
|
6704
|
+
return null;
|
|
6705
|
+
return `${field} is HTML-escaped (<\u2026> instead of <\u2026>) \u2014 send the markup itself, unescaped.`;
|
|
6706
|
+
}
|
|
6707
|
+
function escapedLineBreaksMessage(field, value) {
|
|
6708
|
+
if (!hasEscapedLineBreaks(value, field))
|
|
6709
|
+
return null;
|
|
6710
|
+
return `${field} has its line breaks escaped (literal \\n sequences, no real line break) \u2014 send the ${field} with real line breaks.`;
|
|
6711
|
+
}
|
|
6712
|
+
var noCorruptMarkup = (field) => (value, ctx) => {
|
|
6713
|
+
const message = jsonEncodedCodeMessage(field, value) ?? htmlEscapedMarkupMessage(field, value) ?? escapedLineBreaksMessage(field, value);
|
|
6714
|
+
if (message)
|
|
6715
|
+
ctx.addIssue({ code: "custom", message });
|
|
6716
|
+
};
|
|
6717
|
+
var noJsonEncodedCode = (field) => (value, ctx) => {
|
|
6718
|
+
const message = jsonEncodedCodeMessage(field, value);
|
|
6719
|
+
if (message)
|
|
6720
|
+
ctx.addIssue({ code: "custom", message });
|
|
6721
|
+
};
|
|
6722
|
+
var noCorruptCss = (value, ctx) => {
|
|
6723
|
+
const message = jsonEncodedCodeMessage("css", value) ?? escapedLineBreaksMessage("css", value);
|
|
6724
|
+
if (message)
|
|
6725
|
+
ctx.addIssue({ code: "custom", message });
|
|
6726
|
+
};
|
|
6727
|
+
var moduleHtml = string2().max(MODULE_HTML_MAX, `html exceeds ${MODULE_HTML_MAX} bytes`).superRefine(noCorruptMarkup("html"));
|
|
6347
6728
|
var CDATA_OPEN = "<![CDATA[";
|
|
6348
6729
|
var noCdata = (value) => !value.includes(CDATA_OPEN);
|
|
6349
6730
|
var cdataMessage = (field) => `${field} contains an XML CDATA marker (${CDATA_OPEN}) \u2014 module ${field} is stored and served ` + `verbatim, so CDATA wrappers reach the browser unparsed and break rendering. ` + `Remove the wrapper and resend plain ${field === "css" ? "CSS" : "JavaScript"}.`;
|
|
6350
|
-
var moduleCss = string2().max(MODULE_CSS_MAX, `css exceeds ${MODULE_CSS_MAX} bytes`).refine(noCdata, cdataMessage("css"));
|
|
6351
|
-
var moduleJs = string2().max(MODULE_JS_MAX, `js exceeds ${MODULE_JS_MAX} bytes`).refine(noCdata, cdataMessage("js"));
|
|
6731
|
+
var moduleCss = string2().max(MODULE_CSS_MAX, `css exceeds ${MODULE_CSS_MAX} bytes`).refine(noCdata, cdataMessage("css")).superRefine(noCorruptCss);
|
|
6732
|
+
var moduleJs = string2().max(MODULE_JS_MAX, `js exceeds ${MODULE_JS_MAX} bytes`).refine(noCdata, cdataMessage("js")).superRefine(noJsonEncodedCode("js"));
|
|
6352
6733
|
var MODULE_FIELD_PRIMITIVE_KINDS = [
|
|
6353
6734
|
"text",
|
|
6354
6735
|
"richtext",
|
|
@@ -6358,7 +6739,7 @@ var MODULE_FIELD_PRIMITIVE_KINDS = [
|
|
|
6358
6739
|
"boolean",
|
|
6359
6740
|
"link"
|
|
6360
6741
|
];
|
|
6361
|
-
var MODULE_FIELD_LIST_KINDS = ["
|
|
6742
|
+
var MODULE_FIELD_LIST_KINDS = ["list"];
|
|
6362
6743
|
var MODULE_FIELD_NESTED_KINDS = ["module", "module-list"];
|
|
6363
6744
|
var MODULE_FIELD_KINDS = [
|
|
6364
6745
|
...MODULE_FIELD_PRIMITIVE_KINDS,
|
|
@@ -6388,26 +6769,55 @@ var moduleFieldModuleListSchema = object({
|
|
|
6388
6769
|
min: number2().int().nonnegative().optional(),
|
|
6389
6770
|
max: number2().int().positive().max(256).optional()
|
|
6390
6771
|
}).strict();
|
|
6391
|
-
var
|
|
6392
|
-
name: moduleFieldName,
|
|
6393
|
-
kind: literal("text-list"),
|
|
6394
|
-
label: moduleFieldLabel,
|
|
6395
|
-
min: number2().int().nonnegative().optional(),
|
|
6396
|
-
max: number2().int().positive().max(256).optional(),
|
|
6397
|
-
default: array(string2()).optional()
|
|
6398
|
-
}).strict();
|
|
6399
|
-
var moduleFieldLinkListSchema = object({
|
|
6772
|
+
var moduleFieldListSchema = object({
|
|
6400
6773
|
name: moduleFieldName,
|
|
6401
|
-
kind: literal("
|
|
6774
|
+
kind: literal("list"),
|
|
6402
6775
|
label: moduleFieldLabel,
|
|
6776
|
+
listType: slugSchema,
|
|
6777
|
+
bind: _enum(["local", "shared", "source"]).optional(),
|
|
6778
|
+
list: string2().regex(LIST_REF_RE, "list must be caelo:list/<id>").optional(),
|
|
6779
|
+
source: sourceDefSchema.optional(),
|
|
6403
6780
|
min: number2().int().nonnegative().optional(),
|
|
6404
|
-
max: number2().int().positive().max(
|
|
6405
|
-
default:
|
|
6781
|
+
max: number2().int().positive().max(LIST_MAX_ITEMS).optional(),
|
|
6782
|
+
default: union([
|
|
6783
|
+
array(listItemInputSchema),
|
|
6784
|
+
string2().regex(LIST_REF_RE, "a shared default must be caelo:list/<id>")
|
|
6785
|
+
]).optional()
|
|
6406
6786
|
}).strict();
|
|
6787
|
+
function listFieldIssues(f) {
|
|
6788
|
+
const bind = f.bind ?? "local";
|
|
6789
|
+
const issues = [];
|
|
6790
|
+
if (bind === "source" && f.source === undefined) {
|
|
6791
|
+
issues.push(`list field "${f.name}": bind "source" needs a source (query, system or plugin).`);
|
|
6792
|
+
}
|
|
6793
|
+
if (bind !== "source" && f.source !== undefined) {
|
|
6794
|
+
issues.push(`list field "${f.name}": source is only allowed with bind "source".`);
|
|
6795
|
+
}
|
|
6796
|
+
if (bind === "local" && f.list !== undefined) {
|
|
6797
|
+
issues.push(`list field "${f.name}": list is only allowed with bind "shared" \u2014 a local list stores its entries in the placement.`);
|
|
6798
|
+
}
|
|
6799
|
+
if (bind === "source" && f.list !== undefined && f.source?.kind !== "system") {
|
|
6800
|
+
issues.push(`list field "${f.name}": list on a source field names the vocabulary of a page_terms source only.`);
|
|
6801
|
+
}
|
|
6802
|
+
if (f.default !== undefined) {
|
|
6803
|
+
if (bind === "local" && typeof f.default === "string") {
|
|
6804
|
+
issues.push(`list field "${f.name}": a local default is an array of entries, not a list reference.`);
|
|
6805
|
+
}
|
|
6806
|
+
if (bind === "shared" && Array.isArray(f.default)) {
|
|
6807
|
+
issues.push(`list field "${f.name}": a shared default is caelo:list/<id> \u2014 create the list with upsert_lists_many first.`);
|
|
6808
|
+
}
|
|
6809
|
+
if (bind === "source") {
|
|
6810
|
+
issues.push(`list field "${f.name}": a source field has no default; its entries are generated.`);
|
|
6811
|
+
}
|
|
6812
|
+
}
|
|
6813
|
+
if (f.min !== undefined && f.max !== undefined && f.min > f.max) {
|
|
6814
|
+
issues.push(`list field "${f.name}": min is greater than max.`);
|
|
6815
|
+
}
|
|
6816
|
+
return issues;
|
|
6817
|
+
}
|
|
6407
6818
|
var moduleFieldSchema = discriminatedUnion("kind", [
|
|
6408
6819
|
moduleFieldPrimitiveSchema,
|
|
6409
|
-
|
|
6410
|
-
moduleFieldLinkListSchema,
|
|
6820
|
+
moduleFieldListSchema,
|
|
6411
6821
|
moduleFieldModuleSchema,
|
|
6412
6822
|
moduleFieldModuleListSchema
|
|
6413
6823
|
]);
|
|
@@ -6448,11 +6858,16 @@ var moduleFieldsArray = array(moduleFieldSchema).max(64, "modules may declare at
|
|
|
6448
6858
|
return;
|
|
6449
6859
|
}
|
|
6450
6860
|
seen.add(f.name);
|
|
6861
|
+
if (f.kind === "list") {
|
|
6862
|
+
for (const message of listFieldIssues(f)) {
|
|
6863
|
+
ctx.addIssue({ code: ZodIssueCode.custom, message });
|
|
6864
|
+
}
|
|
6865
|
+
}
|
|
6451
6866
|
}
|
|
6452
6867
|
for (const run of findNumberedScalarFanoutRuns(arr)) {
|
|
6453
6868
|
ctx.addIssue({
|
|
6454
6869
|
code: ZodIssueCode.custom,
|
|
6455
|
-
message: `numbered-scalar fanout: ${run.map((n) => `"${n}"`).join(", ")} repeat one role as ` + "numbered scalar fields \u2014 repeating content is ONE list field, never numbered scalars " + '(CLAUDE.md \xA71A). Replace the run with a single field: kind "
|
|
6870
|
+
message: `numbered-scalar fanout: ${run.map((n) => `"${n}"`).join(", ")} repeat one role as ` + "numbered scalar fields \u2014 repeating content is ONE list field, never numbered scalars " + '(CLAUDE.md \xA71A). Replace the run with a single field: kind "list" with a list type ' + '(listType "texts" for plain strings \u2014 the template iterates {{#f}}{{text}}{{/f}}; ' + '"links" for label + link \u2014 {{#f}}<a href="{{link}}">{{label}}</a>{{/f}}), or ' + '"module-list" (rich per-item structure: mint a card sub-module and reference it per ' + "item \u2014 in build_page, author the card detached with `ref` and pass " + '[{"$ref": "<ref>"}, \u2026] as the field value). A two-field split like col1/col2 is fine; ' + `${NUMBERED_SCALAR_FANOUT_THRESHOLD}+ numbered siblings is a list.`
|
|
6456
6871
|
});
|
|
6457
6872
|
}
|
|
6458
6873
|
});
|
|
@@ -6481,21 +6896,12 @@ var moduleUpdateSchema = object({
|
|
|
6481
6896
|
js: moduleJs.optional(),
|
|
6482
6897
|
fields: moduleFieldsArray.optional()
|
|
6483
6898
|
}).strict();
|
|
6484
|
-
var
|
|
6485
|
-
"home",
|
|
6486
|
-
"landing",
|
|
6487
|
-
"product",
|
|
6488
|
-
"blog",
|
|
6489
|
-
"doc",
|
|
6490
|
-
"content",
|
|
6491
|
-
"utility"
|
|
6492
|
-
];
|
|
6493
|
-
var templateKindSchema = _enum(TEMPLATE_KINDS);
|
|
6899
|
+
var pageTypeSlugSchema = string2().regex(/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/, "page type slug: lowercase letters, digits, hyphens");
|
|
6494
6900
|
var templateCreateSchema = object({
|
|
6495
6901
|
slug: slugSchema,
|
|
6496
6902
|
displayName: displayNameSchema,
|
|
6497
|
-
|
|
6498
|
-
html: string2().max(TEMPLATE_HTML_MAX, `html exceeds ${TEMPLATE_HTML_MAX} bytes`),
|
|
6903
|
+
pageType: pageTypeSlugSchema.optional(),
|
|
6904
|
+
html: string2().max(TEMPLATE_HTML_MAX, `html exceeds ${TEMPLATE_HTML_MAX} bytes`).superRefine(noCorruptMarkup("html")),
|
|
6499
6905
|
css: string2().max(TEMPLATE_CSS_MAX, `css exceeds ${TEMPLATE_CSS_MAX} bytes`).default(""),
|
|
6500
6906
|
layoutId: string2().uuid().optional(),
|
|
6501
6907
|
blocks: array(object({
|
|
@@ -6512,8 +6918,8 @@ var templateBlockSchema = object({
|
|
|
6512
6918
|
var templateUpdateSchema = object({
|
|
6513
6919
|
templateId: string2().uuid(),
|
|
6514
6920
|
displayName: displayNameSchema.optional(),
|
|
6515
|
-
|
|
6516
|
-
html: string2().max(TEMPLATE_HTML_MAX).optional(),
|
|
6921
|
+
pageType: pageTypeSlugSchema.optional(),
|
|
6922
|
+
html: string2().max(TEMPLATE_HTML_MAX).superRefine(noCorruptMarkup("html")).optional(),
|
|
6517
6923
|
css: string2().max(TEMPLATE_CSS_MAX).optional(),
|
|
6518
6924
|
layoutId: string2().uuid().optional(),
|
|
6519
6925
|
blocks: array(templateBlockSchema).optional()
|
|
@@ -6523,13 +6929,17 @@ var templateBlocksSetSchema = object({
|
|
|
6523
6929
|
blocks: array(templateBlockSchema)
|
|
6524
6930
|
}).strict();
|
|
6525
6931
|
var pageStatusSchema = _enum(["draft", "published"]);
|
|
6932
|
+
var pageShortTitleSchema = string2().trim().min(1, "the short title is the page's breadcrumb label and cannot be blank").max(256);
|
|
6526
6933
|
var pageCreateSchema = object({
|
|
6527
6934
|
slug: slugSchema,
|
|
6528
|
-
name: string2().min(1).max(256).optional(),
|
|
6529
6935
|
title: string2().min(1).max(256),
|
|
6936
|
+
shortTitle: pageShortTitleSchema.optional(),
|
|
6530
6937
|
templateId: string2().uuid().optional(),
|
|
6531
6938
|
status: pageStatusSchema.optional(),
|
|
6532
|
-
parentPageId: string2().uuid().nullable().optional()
|
|
6939
|
+
parentPageId: string2().uuid().nullable().optional(),
|
|
6940
|
+
pageType: pageTypeSlugSchema.optional(),
|
|
6941
|
+
properties: record(string2(), unknown()).optional(),
|
|
6942
|
+
terms: array(string2().max(120)).max(100).optional()
|
|
6533
6943
|
}).strict();
|
|
6534
6944
|
var pageMoveSchema = object({
|
|
6535
6945
|
pageId: string2().uuid(),
|
|
@@ -6543,12 +6953,15 @@ var pagesMoveManySchema = object({
|
|
|
6543
6953
|
var pageUpdateSchema = object({
|
|
6544
6954
|
pageId: string2().uuid(),
|
|
6545
6955
|
expectedVersion: number2().int().nonnegative().optional(),
|
|
6546
|
-
name: string2().min(1).max(256).optional(),
|
|
6547
6956
|
title: string2().min(1).max(256).optional(),
|
|
6957
|
+
shortTitle: pageShortTitleSchema.optional(),
|
|
6548
6958
|
slug: slugSchema.optional(),
|
|
6549
6959
|
templateId: string2().uuid().optional(),
|
|
6550
6960
|
status: pageStatusSchema.optional(),
|
|
6551
|
-
redirectFromOld: _enum(["auto", "skip"]).optional()
|
|
6961
|
+
redirectFromOld: _enum(["auto", "skip"]).optional(),
|
|
6962
|
+
pageType: pageTypeSlugSchema.optional(),
|
|
6963
|
+
properties: record(string2(), unknown()).optional(),
|
|
6964
|
+
terms: array(string2().max(120)).max(100).optional()
|
|
6552
6965
|
}).strict();
|
|
6553
6966
|
var pageSetModulesSchema = object({
|
|
6554
6967
|
pageId: string2().uuid(),
|
|
@@ -6592,6 +7005,11 @@ var forkPlacementContentSchema = object({
|
|
|
6592
7005
|
position: number2().int().nonnegative()
|
|
6593
7006
|
}).strict();
|
|
6594
7007
|
|
|
7008
|
+
// ../shared/src/lists/item-attr.ts
|
|
7009
|
+
var UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
7010
|
+
var NAME = "[a-z][a-z0-9_]{0,63}";
|
|
7011
|
+
var LIST_ITEM_ATTR_RE = new RegExp(`^(?:${UUID}/${UUID}|instance/${UUID}/${NAME}/${UUID}|local/${NAME}/${UUID})$`);
|
|
7012
|
+
|
|
6595
7013
|
// ../shared/src/plugin-preview.ts
|
|
6596
7014
|
var identifier = string2().regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/);
|
|
6597
7015
|
var pluginPreviewTargetSchema = object({
|
|
@@ -6683,6 +7101,42 @@ function unwrapCdataEnvelope(value) {
|
|
|
6683
7101
|
return m[1];
|
|
6684
7102
|
}
|
|
6685
7103
|
|
|
7104
|
+
// ../shared/src/source-text-transport.ts
|
|
7105
|
+
function decodeJsonEncodedSource(value) {
|
|
7106
|
+
if (typeof value !== "string")
|
|
7107
|
+
return value;
|
|
7108
|
+
const t = value.trim();
|
|
7109
|
+
if (t.length < 2 || !t.startsWith('"') || !t.endsWith('"'))
|
|
7110
|
+
return value;
|
|
7111
|
+
if (!/\\["ntr\\/u]/.test(t))
|
|
7112
|
+
return value;
|
|
7113
|
+
try {
|
|
7114
|
+
const decoded = JSON.parse(t);
|
|
7115
|
+
return typeof decoded === "string" ? decoded : value;
|
|
7116
|
+
} catch {
|
|
7117
|
+
return value;
|
|
7118
|
+
}
|
|
7119
|
+
}
|
|
7120
|
+
var ENTITIES = {
|
|
7121
|
+
"<": "<",
|
|
7122
|
+
">": ">",
|
|
7123
|
+
""": '"',
|
|
7124
|
+
""": '"',
|
|
7125
|
+
"'": "'",
|
|
7126
|
+
"'": "'",
|
|
7127
|
+
"'": "'"
|
|
7128
|
+
};
|
|
7129
|
+
function decodeHtmlEscapedSource(value) {
|
|
7130
|
+
if (typeof value !== "string")
|
|
7131
|
+
return value;
|
|
7132
|
+
if (value.includes("<") || !/<\/?[a-zA-Z]/.test(value))
|
|
7133
|
+
return value;
|
|
7134
|
+
return value.replace(/<|>|"|"|'|'|'/g, (e) => ENTITIES[e] ?? e).replace(/&/g, "&");
|
|
7135
|
+
}
|
|
7136
|
+
function decodeSourceTextTransport(value, language) {
|
|
7137
|
+
return decodeEscapedLineBreaks(decodeHtmlEscapedSource(decodeJsonEncodedSource(unwrapCdataEnvelope(value))), language);
|
|
7138
|
+
}
|
|
7139
|
+
|
|
6686
7140
|
// ../shared/src/ai-tools.ts
|
|
6687
7141
|
function stripSurroundingQuotes(v) {
|
|
6688
7142
|
if (typeof v !== "string")
|
|
@@ -6690,31 +7144,13 @@ function stripSurroundingQuotes(v) {
|
|
|
6690
7144
|
const m = v.match(/^(["'])([\s\S]+)\1$/);
|
|
6691
7145
|
return m ? m[2] : v;
|
|
6692
7146
|
}
|
|
6693
|
-
function sourceTextArg(schema) {
|
|
6694
|
-
return preprocess(
|
|
7147
|
+
function sourceTextArg(schema, language) {
|
|
7148
|
+
return preprocess((value) => decodeSourceTextTransport(value, language), schema);
|
|
6695
7149
|
}
|
|
6696
7150
|
var positionInputSchema = preprocess(stripSurroundingQuotes, union([
|
|
6697
7151
|
_enum(["top", "bottom"]),
|
|
6698
7152
|
preprocess((v) => typeof v === "string" && /^\d+$/.test(v) ? Number.parseInt(v, 10) : v, number2().int().min(0).max(1000))
|
|
6699
7153
|
]));
|
|
6700
|
-
var editModuleToolInput = object({
|
|
6701
|
-
moduleId: string2().uuid(),
|
|
6702
|
-
displayName: string2().min(1).max(128).optional(),
|
|
6703
|
-
description: string2().max(1000).optional(),
|
|
6704
|
-
kind: _enum(["chrome", "hero", "content", "cta", "utility"]).optional(),
|
|
6705
|
-
type: slugSchema.optional(),
|
|
6706
|
-
html: sourceTextArg(string2().max(MODULE_HTML_MAX)).optional(),
|
|
6707
|
-
css: sourceTextArg(string2().max(MODULE_CSS_MAX)).optional(),
|
|
6708
|
-
js: sourceTextArg(string2().max(MODULE_JS_MAX)).optional(),
|
|
6709
|
-
fields: array(moduleFieldSchema).max(64).optional(),
|
|
6710
|
-
bindThemeLiterals: boolean2().optional()
|
|
6711
|
-
}).strict();
|
|
6712
|
-
var setPageModuleContentToolInput = object({
|
|
6713
|
-
pageId: string2().uuid(),
|
|
6714
|
-
blockName: string2().min(1).max(64),
|
|
6715
|
-
position: number2().int().nonnegative(),
|
|
6716
|
-
contentValues: record(string2(), unknown())
|
|
6717
|
-
}).strict();
|
|
6718
7154
|
var siteMemoryProposeToolInput = object({
|
|
6719
7155
|
slot: _enum(["purpose", "brand-voice", "tone", "banned-phrases", "instructions", "glossary"]),
|
|
6720
7156
|
body: string2().min(1).max(4000),
|
|
@@ -6734,9 +7170,9 @@ var addModuleToolInput = object({
|
|
|
6734
7170
|
description: string2().max(1000).optional(),
|
|
6735
7171
|
kind: _enum(["chrome", "hero", "content", "cta", "utility"]).optional(),
|
|
6736
7172
|
type: slugSchema.optional(),
|
|
6737
|
-
html: sourceTextArg(string2().min(1).max(50000)).optional(),
|
|
6738
|
-
css: sourceTextArg(string2().max(50000)).optional(),
|
|
6739
|
-
js: sourceTextArg(string2().max(50000)).optional(),
|
|
7173
|
+
html: sourceTextArg(string2().min(1).max(50000), "html").optional(),
|
|
7174
|
+
css: sourceTextArg(string2().max(50000), "css").optional(),
|
|
7175
|
+
js: sourceTextArg(string2().max(50000), "js").optional(),
|
|
6740
7176
|
fields: array(moduleFieldSchema).max(64).optional(),
|
|
6741
7177
|
bindThemeLiterals: boolean2().optional(),
|
|
6742
7178
|
values: record(string2(), unknown()).optional()
|
|
@@ -6745,7 +7181,7 @@ var addModuleToolInput = object({
|
|
|
6745
7181
|
if (input.moduleId !== undefined) {
|
|
6746
7182
|
ctx.addIssue({
|
|
6747
7183
|
code: ZodIssueCode.custom,
|
|
6748
|
-
message: "Reusing a module on a layout renders the module's STORED field defaults \u2014 `values` has nothing to bind to. Drop `values` (the chrome shows the module as-is), or change the shared copy via
|
|
7184
|
+
message: "Reusing a module on a layout renders the module's STORED field defaults \u2014 `values` has nothing to bind to. Drop `values` (the chrome shows the module as-is), or change the shared copy via update_modules_many."
|
|
6749
7185
|
});
|
|
6750
7186
|
} else if (input.fields === undefined || input.fields.length === 0) {
|
|
6751
7187
|
ctx.addIssue({
|
|
@@ -6771,10 +7207,11 @@ var addModuleToolInput = object({
|
|
|
6771
7207
|
message: "Pass either `moduleId` (place an existing module from list_modules) " + "or `displayName` + `html` (mint a new module)."
|
|
6772
7208
|
});
|
|
6773
7209
|
}
|
|
6774
|
-
|
|
7210
|
+
const carriesContent = (f) => ("default" in f) && f.default !== undefined || f.kind === "list" && (f.bind === "source" || f.bind === "shared" && f.list !== undefined);
|
|
7211
|
+
if (input.fields !== undefined && input.fields.length > 0 && input.values === undefined && !input.fields.some(carriesContent)) {
|
|
6775
7212
|
ctx.addIssue({
|
|
6776
7213
|
code: ZodIssueCode.custom,
|
|
6777
|
-
message: "A minted module needs its initial content IN THIS CALL: pass `values` " + "({fieldName: value, \u2026}) for this placement, or give the fields `default`s. " + "Without either, the module renders empty placeholders until a second call."
|
|
7214
|
+
message: "A minted module needs its initial content IN THIS CALL: pass `values` " + "({fieldName: value, \u2026}) for this placement, or give the fields `default`s. " + 'A list field bound to a site list carries its content through `list` ({kind:"list", bind:"shared", list:"caelo:list/<id>"} \u2014 create the list first with upsert_lists_many). ' + "Without either, the module renders empty placeholders until a second call."
|
|
6778
7215
|
});
|
|
6779
7216
|
}
|
|
6780
7217
|
});
|
|
@@ -6821,7 +7258,9 @@ var chatChipSchema = object({
|
|
|
6821
7258
|
blockName: string2().min(1).max(80).optional(),
|
|
6822
7259
|
position: number2().int().nonnegative().optional(),
|
|
6823
7260
|
field: string2().min(1).max(200).optional(),
|
|
6824
|
-
|
|
7261
|
+
item: string2().uuid().optional(),
|
|
7262
|
+
key: string2().regex(/^[a-z][a-z0-9_]{0,63}$/).optional(),
|
|
7263
|
+
listItem: string2().max(200).regex(LIST_ITEM_ATTR_RE).optional()
|
|
6825
7264
|
}).strict();
|
|
6826
7265
|
var CHAT_MAX_CHIPS = 20;
|
|
6827
7266
|
var chatSendMessageInput = object({
|
|
@@ -6853,7 +7292,9 @@ var chatPublishInput = object({
|
|
|
6853
7292
|
"pageLayout",
|
|
6854
7293
|
"pageModuleContent",
|
|
6855
7294
|
"layout",
|
|
6856
|
-
"
|
|
7295
|
+
"listType",
|
|
7296
|
+
"list",
|
|
7297
|
+
"pageType",
|
|
6857
7298
|
"theme",
|
|
6858
7299
|
"pluginRow"
|
|
6859
7300
|
]),
|
|
@@ -6882,9 +7323,10 @@ var slugInputSchema = string2().min(1).max(120).regex(/^[a-z0-9][a-z0-9-]*$/, "l
|
|
|
6882
7323
|
var createTemplateToolInput = object({
|
|
6883
7324
|
slug: slugInputSchema,
|
|
6884
7325
|
displayName: string2().min(1).max(256),
|
|
6885
|
-
html: sourceTextArg(string2().min(1).max(2000000)),
|
|
6886
|
-
css: sourceTextArg(string2().max(2000000)).default(""),
|
|
7326
|
+
html: sourceTextArg(string2().min(1).max(2000000), "html"),
|
|
7327
|
+
css: sourceTextArg(string2().max(2000000), "css").default(""),
|
|
6887
7328
|
layoutId: string2().uuid().optional(),
|
|
7329
|
+
pageType: pageTypeSlugSchema.optional(),
|
|
6888
7330
|
blocks: array(object({
|
|
6889
7331
|
name: string2().min(1).max(80),
|
|
6890
7332
|
displayName: string2().min(1).max(200),
|
|
@@ -6896,12 +7338,6 @@ var removeModuleFromToolInput = object({
|
|
|
6896
7338
|
targetRef: string2().min(1).max(500),
|
|
6897
7339
|
moduleId: string2().uuid()
|
|
6898
7340
|
}).strict();
|
|
6899
|
-
var setStructuredSetToolInput = object({
|
|
6900
|
-
kind: _enum(["nav-menu", "taxonomy", "tags", "link-list"]),
|
|
6901
|
-
slug: slugInputSchema,
|
|
6902
|
-
displayName: string2().min(1).max(200),
|
|
6903
|
-
items: array(unknown())
|
|
6904
|
-
}).strict();
|
|
6905
7341
|
var setTemplateLayoutToolInput = object({
|
|
6906
7342
|
templateId: string2().uuid(),
|
|
6907
7343
|
layoutSlug: slugInputSchema
|
|
@@ -6909,8 +7345,8 @@ var setTemplateLayoutToolInput = object({
|
|
|
6909
7345
|
var createLayoutToolInput = object({
|
|
6910
7346
|
slug: slugInputSchema,
|
|
6911
7347
|
displayName: string2().min(1).max(200),
|
|
6912
|
-
html: sourceTextArg(string2().min(1).max(50000)),
|
|
6913
|
-
css: sourceTextArg(string2().max(50000)).optional(),
|
|
7348
|
+
html: sourceTextArg(string2().min(1).max(50000), "html"),
|
|
7349
|
+
css: sourceTextArg(string2().max(50000), "css").optional(),
|
|
6914
7350
|
blocks: array(object({
|
|
6915
7351
|
name: string2().min(1).max(80),
|
|
6916
7352
|
displayName: string2().min(1).max(200),
|
|
@@ -6926,8 +7362,8 @@ var setSiteDefaultsToolInput = object({
|
|
|
6926
7362
|
var duplicatePageToolInput = object({
|
|
6927
7363
|
sourcePageId: string2().uuid(),
|
|
6928
7364
|
newSlug: slugInputSchema,
|
|
6929
|
-
newName: string2().min(1).max(256).optional(),
|
|
6930
7365
|
newTitle: string2().min(1).max(256).optional(),
|
|
7366
|
+
newShortTitle: pageShortTitleSchema.optional(),
|
|
6931
7367
|
targetTemplateId: string2().uuid().optional(),
|
|
6932
7368
|
newParentPageId: string2().uuid().nullable().optional()
|
|
6933
7369
|
}).strict();
|
|
@@ -6939,16 +7375,15 @@ var repointPageTemplateToolInput = object({
|
|
|
6939
7375
|
object({ kind: literal("preserve-as-block"), blockName: slugInputSchema }).strict()
|
|
6940
7376
|
]).default({ kind: "drop" })
|
|
6941
7377
|
}).strict();
|
|
7378
|
+
var movePositionInputSchema = preprocess(stripSurroundingQuotes, union([
|
|
7379
|
+
_enum(["top", "bottom", "up", "down"]),
|
|
7380
|
+
preprocess((v) => typeof v === "string" && /^\d+$/.test(v) ? Number.parseInt(v, 10) : v, number2().int().min(0).max(1000))
|
|
7381
|
+
]));
|
|
6942
7382
|
var moveModuleToolInput = object({
|
|
6943
7383
|
pageId: string2().uuid(),
|
|
6944
7384
|
moduleId: string2().uuid(),
|
|
6945
|
-
toBlockName: string2().min(1).max(80),
|
|
6946
|
-
position:
|
|
6947
|
-
}).strict();
|
|
6948
|
-
var reorderModuleToolInput = object({
|
|
6949
|
-
pageId: string2().uuid(),
|
|
6950
|
-
moduleId: string2().uuid(),
|
|
6951
|
-
direction: union([_enum(["up", "down"]), number2().int().min(0).max(1000)])
|
|
7385
|
+
toBlockName: string2().min(1).max(80).optional(),
|
|
7386
|
+
position: movePositionInputSchema
|
|
6952
7387
|
}).strict();
|
|
6953
7388
|
var findMediaToolInput = object({
|
|
6954
7389
|
query: string2().max(256).optional(),
|
|
@@ -6997,19 +7432,13 @@ var autofillPageSeoToolInput = object({
|
|
|
6997
7432
|
metaDescription: string2().trim().min(1).max(320),
|
|
6998
7433
|
ogImageAssetId: string2().uuid().nullable().optional()
|
|
6999
7434
|
}).strict();
|
|
7000
|
-
var optimizePageSeoToolInput = object({
|
|
7001
|
-
pageId: string2().uuid(),
|
|
7002
|
-
metaDescription: string2().min(1).max(320),
|
|
7003
|
-
ogImageAssetId: string2().uuid().nullable().optional(),
|
|
7004
|
-
context: string2().max(4000).optional()
|
|
7005
|
-
}).strict();
|
|
7006
7435
|
var findRedirectsToolInput = object({
|
|
7007
7436
|
query: string2().max(500).optional(),
|
|
7008
7437
|
statusCode: union([literal(301), literal(302), literal(307), literal(308), literal(410)]).optional(),
|
|
7009
7438
|
limit: number2().int().min(1).max(200).default(50)
|
|
7010
7439
|
}).strict();
|
|
7011
7440
|
var bulkCreateRedirectsToolInput = object({
|
|
7012
|
-
|
|
7441
|
+
items: array(object({
|
|
7013
7442
|
fromPath: string2().min(1).max(500),
|
|
7014
7443
|
toPath: redirectTargetPathSchema,
|
|
7015
7444
|
statusCode: union([
|
|
@@ -7032,7 +7461,7 @@ var bulkDeleteRedirectsToolInput = object({
|
|
|
7032
7461
|
matches: string2().min(1).max(500).optional()
|
|
7033
7462
|
}).strict();
|
|
7034
7463
|
var bulkOptimizeSeoToolInput = object({
|
|
7035
|
-
|
|
7464
|
+
items: array(object({
|
|
7036
7465
|
pageId: string2().uuid(),
|
|
7037
7466
|
metaDescription: string2().min(1).max(320),
|
|
7038
7467
|
ogImageAssetId: string2().uuid().nullable().optional()
|
|
@@ -7263,7 +7692,7 @@ var buildPageContentSchema = discriminatedUnion("source", [
|
|
|
7263
7692
|
var buildPageModuleSchema = object({
|
|
7264
7693
|
blockName: slugSchema.optional(),
|
|
7265
7694
|
position: positionInputSchema.optional(),
|
|
7266
|
-
ref: string2().regex(/^[
|
|
7695
|
+
ref: string2().regex(/^[A-Za-z][A-Za-z0-9_-]{0,31}$/, "ref must be a short handle: a letter, then letters, digits, _ or -").optional(),
|
|
7267
7696
|
moduleId: union([
|
|
7268
7697
|
string2().uuid('moduleId must be a UUID from list_modules \u2014 to re-place a module minted earlier in THIS call, pass {"$ref": "<its ref>"} instead'),
|
|
7269
7698
|
object({ $ref: string2() }).strict()
|
|
@@ -7272,9 +7701,9 @@ var buildPageModuleSchema = object({
|
|
|
7272
7701
|
description: string2().max(1000).optional(),
|
|
7273
7702
|
kind: moduleKindSchema.optional(),
|
|
7274
7703
|
type: slugSchema.optional(),
|
|
7275
|
-
html: sourceTextArg(string2().min(1).max(MODULE_HTML_MAX)).optional(),
|
|
7276
|
-
css: sourceTextArg(string2().max(MODULE_CSS_MAX)).optional(),
|
|
7277
|
-
js: sourceTextArg(string2().max(MODULE_JS_MAX)).optional(),
|
|
7704
|
+
html: sourceTextArg(string2().min(1).max(MODULE_HTML_MAX), "html").optional(),
|
|
7705
|
+
css: sourceTextArg(string2().max(MODULE_CSS_MAX), "css").optional(),
|
|
7706
|
+
js: sourceTextArg(string2().max(MODULE_JS_MAX), "js").optional(),
|
|
7278
7707
|
fields: array(moduleFieldSchema).max(64).optional(),
|
|
7279
7708
|
bindThemeLiterals: boolean2().optional(),
|
|
7280
7709
|
content: buildPageContentSchema.optional()
|
|
@@ -7304,14 +7733,27 @@ var buildPageTargetSchema = object({
|
|
|
7304
7733
|
pageId: string2().uuid().optional(),
|
|
7305
7734
|
slug: slugSchema.optional(),
|
|
7306
7735
|
title: string2().min(1).max(256).optional(),
|
|
7307
|
-
|
|
7736
|
+
shortTitle: pageCreateSchema.shape.shortTitle,
|
|
7308
7737
|
templateId: string2().uuid().optional(),
|
|
7309
7738
|
status: pageStatusSchema.optional(),
|
|
7310
|
-
parentPageId: string2().uuid().optional(),
|
|
7739
|
+
parentPageId: string2().uuid().nullable().optional(),
|
|
7740
|
+
pageType: pageCreateSchema.shape.pageType,
|
|
7741
|
+
properties: pageCreateSchema.shape.properties,
|
|
7742
|
+
terms: pageCreateSchema.shape.terms,
|
|
7311
7743
|
importPageId: string2().uuid().optional(),
|
|
7312
7744
|
metaDescription: string2().trim().min(1).max(SEO_DESCRIPTION_HARD_MAX).optional()
|
|
7313
7745
|
}).strict().superRefine((page, ctx) => {
|
|
7314
|
-
const createKeys = [
|
|
7746
|
+
const createKeys = [
|
|
7747
|
+
"slug",
|
|
7748
|
+
"title",
|
|
7749
|
+
"shortTitle",
|
|
7750
|
+
"templateId",
|
|
7751
|
+
"status",
|
|
7752
|
+
"parentPageId",
|
|
7753
|
+
"pageType",
|
|
7754
|
+
"properties",
|
|
7755
|
+
"terms"
|
|
7756
|
+
].filter((k) => page[k] !== undefined);
|
|
7315
7757
|
if (page.pageId !== undefined) {
|
|
7316
7758
|
if (createKeys.length > 0) {
|
|
7317
7759
|
ctx.addIssue({
|
|
@@ -7386,7 +7828,7 @@ var INTERACTIONS = {
|
|
|
7386
7828
|
carousel: { css: CAROUSEL_CSS, js: CAROUSEL_JS }
|
|
7387
7829
|
};
|
|
7388
7830
|
var INTERACTION_IDS = Object.keys(INTERACTIONS);
|
|
7389
|
-
var INTERACTION_MARKUP_CONTRACT =
|
|
7831
|
+
var INTERACTION_MARKUP_CONTRACT = "`data-caelo-ui` kit \u2014 use it instead of JS for these (accessible, shipped once per page, style freely in module CSS):\n" + '- `accordion` (FAQ, collapsible): `<div data-caelo-ui="accordion" data-single>` with `<details id="..."><summary>Question</summary><div>Answer</div></details>` items; `data-single` keeps one open; a link to `#<details id>` opens it.\n' + '- `tabs`: `<div data-caelo-ui="tabs"><div role="tablist" aria-label="..."><button type="button" role="tab" id="t1" aria-controls="p1" aria-selected="true">...</button><button type="button" role="tab" id="t2" aria-controls="p2" aria-selected="false" tabindex="-1">...</button></div><div role="tabpanel" id="p1" aria-labelledby="t1">...</div><div role="tabpanel" id="p2" aria-labelledby="t2" hidden>...</div></div>`; ids unique on the page.\n' + '- `carousel` (slider, testimonials): `<section data-caelo-ui="carousel" aria-roledescription="carousel" aria-label="..."><div data-caelo-carousel-track tabindex="0"><div role="group" aria-roledescription="slide" aria-label="1 of 3">...</div>...</div><button type="button" data-caelo-carousel-prev aria-label="Previous slide"><span aria-hidden="true">‹</span></button><button type="button" data-caelo-carousel-next aria-label="Next slide"><span aria-hidden="true">›</span></button></section>`; icon buttons keep visible content aria-hidden, text buttons need no aria-label. One slide per view; set the slides\' `flex-basis` in module CSS to show more.\n' + '- `mobile-nav` (menu collapsing behind a toggle on small screens): `<nav class="caelo-nav-menu" data-caelo-ui="mobile-nav" data-nav-open="false"><button type="button" class="caelo-nav-toggle" aria-expanded="false" aria-label="Menu"><span class="caelo-nav-bar"></span><span class="caelo-nav-bar"></span><span class="caelo-nav-bar"></span></button><ul>{{#menu}}<li>\u2026</li>{{/menu}}</ul></nav>` around the module\'s menu `list` field.\n' + "Write module JS only for behaviour the kit does not cover.";
|
|
7390
7832
|
|
|
7391
7833
|
// ../shared/src/media.ts
|
|
7392
7834
|
var MEDIA_ALLOWED_MIMES = [
|
|
@@ -7967,6 +8409,9 @@ mustache.Context = Context;
|
|
|
7967
8409
|
mustache.Writer = Writer;
|
|
7968
8410
|
var mustache_default = mustache;
|
|
7969
8411
|
|
|
8412
|
+
// ../shared/src/template-sections.ts
|
|
8413
|
+
var CONTEXT_HEADS = new Set(["page", "site_text"]);
|
|
8414
|
+
|
|
7970
8415
|
// ../shared/src/template-engine.ts
|
|
7971
8416
|
mustache_default.escape = (s) => s === null || s === undefined ? "" : String(s);
|
|
7972
8417
|
var SECTION_KINDS = new Set(MODULE_FIELD_SECTION_KINDS);
|
|
@@ -7979,7 +8424,7 @@ var THEME_ASSET_KEY_TO_SLOT = {
|
|
|
7979
8424
|
var THEME_ASSET_KEYS = Object.keys(THEME_ASSET_KEY_TO_SLOT);
|
|
7980
8425
|
|
|
7981
8426
|
// ../shared/src/template-balance.ts
|
|
7982
|
-
var
|
|
8427
|
+
var RAW_TEXT_ELEMENTS2 = new Set([
|
|
7983
8428
|
"script",
|
|
7984
8429
|
"style",
|
|
7985
8430
|
"textarea",
|
|
@@ -8297,9 +8742,9 @@ var languageTagSchema = string2().max(35).regex(/^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8
|
|
|
8297
8742
|
var HTML_WS = new Set(["\t", `
|
|
8298
8743
|
`, "\f", "\r", " "]);
|
|
8299
8744
|
// ../shared/src/edit-markers.ts
|
|
8300
|
-
var EDITABLE_KINDS = new Set(["text", "
|
|
8745
|
+
var EDITABLE_KINDS = new Set(["text", "url", "image", "list"]);
|
|
8301
8746
|
var MARKABLE_ATTRIBUTES = new Set(["href", "src", "alt"]);
|
|
8302
|
-
var
|
|
8747
|
+
var RAW_TEXT_ELEMENTS3 = new Set(["script", "style", "title", "textarea"]);
|
|
8303
8748
|
// ../shared/src/font-usage.ts
|
|
8304
8749
|
var GLOBAL_KEYWORDS = new Set(["inherit", "initial", "unset", "revert", "revert-layer"]);
|
|
8305
8750
|
var SYSTEM_FONTS = new Set([
|
|
@@ -8456,6 +8901,31 @@ var VARIANT_RE = LINK_REF_PART_PATTERNS.variant;
|
|
|
8456
8901
|
var SITE_SERVED_FILES = new Set(["/robots.txt", "/sitemap.xml"]);
|
|
8457
8902
|
var URL_KINDS = new Set(["url", "link", "image"]);
|
|
8458
8903
|
var NESTED_KINDS = new Set(["module", "module-list"]);
|
|
8904
|
+
// ../shared/src/lists/address.ts
|
|
8905
|
+
var SEG = "[a-z0-9_-]+";
|
|
8906
|
+
var ADDRESS_RE = new RegExp(`^(?:list/(${SEG})/item/(${SEG})/(${SEG})` + `|instance/(${SEG})/(${SEG})/item/(${SEG})/(${SEG})` + `|page/(${SEG})/props/(${SEG})` + `|list_type/(${SEG})/node/(${SEG})/(${SEG}))$`);
|
|
8907
|
+
// ../shared/src/lists/page-type.ts
|
|
8908
|
+
var pageTypeDefSchema = object({
|
|
8909
|
+
slug: string2().regex(/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/),
|
|
8910
|
+
name: string2().min(1).max(200),
|
|
8911
|
+
purpose: string2().min(1).max(1000),
|
|
8912
|
+
templates: array(string2().uuid()).min(1).max(64),
|
|
8913
|
+
defaultTemplate: string2().uuid(),
|
|
8914
|
+
properties: array(fieldDefSchema).max(32).default([]),
|
|
8915
|
+
vocabularies: array(object({
|
|
8916
|
+
list: string2().uuid(),
|
|
8917
|
+
cardinality: _enum(["one", "many"]),
|
|
8918
|
+
required: boolean2().optional()
|
|
8919
|
+
}).strict()).max(16).default([])
|
|
8920
|
+
}).strict();
|
|
8921
|
+
// ../shared/src/lists/resolve.ts
|
|
8922
|
+
var SEG2 = "[a-z0-9_-]+";
|
|
8923
|
+
var LIST_VALUE_RE = new RegExp(`^list/(${SEG2})/item/(${SEG2})/(${SEG2})$`);
|
|
8924
|
+
var INSTANCE_VALUE_RE = new RegExp(`^instance/(${SEG2})/(${SEG2})/item/(${SEG2})/(${SEG2})$`);
|
|
8925
|
+
var PAGE_PROP_RE = new RegExp(`^page/(${SEG2})/props/(${SEG2})$`);
|
|
8926
|
+
var LIST_HIDDEN_RE = new RegExp(`^list/(${SEG2})/item/(${SEG2})$`);
|
|
8927
|
+
var INSTANCE_HIDDEN_RE = new RegExp(`^instance/(${SEG2})/(${SEG2})/item/(${SEG2})$`);
|
|
8928
|
+
var STRUCTURAL_TYPES = new Set(["module", "term"]);
|
|
8459
8929
|
// ../shared/src/markup-structure.ts
|
|
8460
8930
|
var LEAF_TAGS = new Set(["svg", "math", "script", "style", "noscript", "iframe"]);
|
|
8461
8931
|
// ../shared/src/page-log.ts
|
|
@@ -8588,31 +9058,6 @@ var PINNED_FONT_SLICE_FILE_PATTERN = "[0-9a-f]{64}\\.[0-9a-f]{12}\\.[a-z]+(?:-[a
|
|
|
8588
9058
|
var PINNED_FONT_SLICE_FILE_RE = new RegExp(`^${PINNED_FONT_SLICE_FILE_PATTERN}$`);
|
|
8589
9059
|
var CONTENT_HASHED_PATH_PATTERN = `^/(?:_app/immutable/.+|_assets/fonts/[^/]+/[0-9a-f]{16}\\.woff2|_assets/fonts/pinned/${PINNED_FONT_SLICE_FILE_PATTERN}|_assets/[a-z0-9][a-z0-9-]*(?:/[a-z][a-z0-9-]*)?\\.[0-9a-f]{16}\\.[a-z0-9]{2,5}|_caelo/plugin/[^/]+/[^/]+\\.[0-9a-f]{12}\\.(?:js|css))$`;
|
|
8590
9060
|
var CONTENT_HASHED_PATH_RE = new RegExp(CONTENT_HASHED_PATH_PATTERN);
|
|
8591
|
-
// ../shared/src/structured-sets.ts
|
|
8592
|
-
var navMenuItem = lazy(() => object({
|
|
8593
|
-
label: string2().min(1).max(120),
|
|
8594
|
-
href: string2().min(1).max(500),
|
|
8595
|
-
target: _enum(["_self", "_blank"]).optional(),
|
|
8596
|
-
children: array(navMenuItem).optional(),
|
|
8597
|
-
adSlotId: string2().min(1).max(100).optional()
|
|
8598
|
-
}).strict());
|
|
8599
|
-
var taxonomyItem = object({
|
|
8600
|
-
slug: string2().min(1).max(120),
|
|
8601
|
-
displayName: string2().min(1).max(200),
|
|
8602
|
-
parentSlug: string2().min(1).max(120).optional(),
|
|
8603
|
-
description: string2().max(2000).optional()
|
|
8604
|
-
}).strict();
|
|
8605
|
-
var tagItem = object({
|
|
8606
|
-
slug: string2().min(1).max(120).regex(/^[a-z0-9-]+$/, "lowercase letters/digits/hyphens"),
|
|
8607
|
-
displayName: string2().min(1).max(200),
|
|
8608
|
-
color: string2().regex(/^#[0-9a-fA-F]{3,8}$/, "hex color").optional()
|
|
8609
|
-
}).strict();
|
|
8610
|
-
var linkListItem = object({
|
|
8611
|
-
label: string2().min(1).max(200),
|
|
8612
|
-
href: string2().min(1).max(500),
|
|
8613
|
-
description: string2().max(500).optional()
|
|
8614
|
-
}).strict();
|
|
8615
|
-
var structuredSetKind = _enum(["nav-menu", "taxonomy", "tags", "link-list"]);
|
|
8616
9061
|
// ../shared/src/subagents.ts
|
|
8617
9062
|
var expectedReturnShape = _enum(["verdict", "tree", "freeform", "rebuild"]);
|
|
8618
9063
|
var EXPECTED_RETURN_SHAPES = expectedReturnShape.options;
|
|
@@ -18008,7 +18453,7 @@ async function recordAudit(tx, opts) {
|
|
|
18008
18453
|
var SYSTEM_ACTOR_ID = "00000000-0000-0000-0000-00000000ffff";
|
|
18009
18454
|
|
|
18010
18455
|
// ../query-api/src/branch-access.ts
|
|
18011
|
-
var
|
|
18456
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
18012
18457
|
function namedBranches(ctx, input) {
|
|
18013
18458
|
const out = new Set;
|
|
18014
18459
|
if (ctx.chatBranchId)
|
|
@@ -18029,11 +18474,11 @@ function branchNotFound(operation, chatBranchId) {
|
|
|
18029
18474
|
};
|
|
18030
18475
|
}
|
|
18031
18476
|
function firstMalformedBranch(branches) {
|
|
18032
|
-
return branches.find((b) => !
|
|
18477
|
+
return branches.find((b) => !UUID_RE2.test(b)) ?? null;
|
|
18033
18478
|
}
|
|
18034
18479
|
async function firstInvisibleBranch(tx, branches) {
|
|
18035
18480
|
for (const branch of branches) {
|
|
18036
|
-
if (!
|
|
18481
|
+
if (!UUID_RE2.test(branch))
|
|
18037
18482
|
return branch;
|
|
18038
18483
|
const rows = await tx.execute(sql`SELECT caelo_branch_visible(${branch}::uuid) AS visible`);
|
|
18039
18484
|
if (rows[0]?.visible !== true)
|
|
@@ -18096,6 +18541,7 @@ function isRlsDenial(error) {
|
|
|
18096
18541
|
|
|
18097
18542
|
// ../query-api/src/plugin-schema-provision.ts
|
|
18098
18543
|
import { createHash } from "crypto";
|
|
18544
|
+
var DROPPED_COLUMNS_SETTING = "caelo.plugin_dropped_columns";
|
|
18099
18545
|
var SCHEMA_HEADER_RE = /^CREATE SCHEMA IF NOT EXISTS "(plugin_[a-z][a-z0-9_]*)";/;
|
|
18100
18546
|
function provisionedSchemaName(caller, ddl) {
|
|
18101
18547
|
const name = SCHEMA_HEADER_RE.exec(ddl)?.[1];
|
|
@@ -18116,14 +18562,19 @@ async function provisionPluginSchemaInTx(tx, caller, opts) {
|
|
|
18116
18562
|
AND to_regnamespace(${schemaName}) IS NOT NULL
|
|
18117
18563
|
`);
|
|
18118
18564
|
if (recorded.length > 0)
|
|
18119
|
-
return;
|
|
18565
|
+
return { schemaName, droppedColumns: [] };
|
|
18120
18566
|
await tx.execute(sql.raw(opts.sql));
|
|
18567
|
+
const dropped = await tx.execute(sql.raw(`SELECT coalesce(current_setting('${DROPPED_COLUMNS_SETTING}', true), '') AS v`));
|
|
18121
18568
|
await tx.execute(sql`
|
|
18122
18569
|
INSERT INTO plugin_schema_provisions (schema_name, sql_digest)
|
|
18123
18570
|
VALUES (${schemaName}, ${digest})
|
|
18124
18571
|
ON CONFLICT (schema_name) DO UPDATE
|
|
18125
18572
|
SET sql_digest = EXCLUDED.sql_digest, provisioned_at = now()
|
|
18126
18573
|
`);
|
|
18574
|
+
return {
|
|
18575
|
+
schemaName,
|
|
18576
|
+
droppedColumns: (dropped[0]?.v ?? "").split(",").filter((c) => c.length > 0)
|
|
18577
|
+
};
|
|
18127
18578
|
}
|
|
18128
18579
|
|
|
18129
18580
|
// ../query-api/src/post-commit.ts
|
|
@@ -18494,9 +18945,16 @@ class DatabaseAdapter {
|
|
|
18494
18945
|
}
|
|
18495
18946
|
if (!this.#skipVerify)
|
|
18496
18947
|
await this.verifyRoles();
|
|
18497
|
-
await this.#public.transaction(async (tx) => {
|
|
18498
|
-
|
|
18948
|
+
const outcome = await this.#public.transaction(async (tx) => {
|
|
18949
|
+
return provisionPluginSchemaInTx(tx, "provisionPluginPublicSchema", opts);
|
|
18499
18950
|
});
|
|
18951
|
+
if (outcome.droppedColumns.length > 0) {
|
|
18952
|
+
const admin = this.#adminDb("provisionPluginPublicSchema");
|
|
18953
|
+
await admin.transaction(async (tx) => {
|
|
18954
|
+
await tx.execute(sql.raw("SELECT set_config('caelo.actor_kind', 'system', true)"));
|
|
18955
|
+
await auditDroppedColumns(tx, "cms_public", opts.pluginId, outcome);
|
|
18956
|
+
});
|
|
18957
|
+
}
|
|
18500
18958
|
}
|
|
18501
18959
|
async provisionPluginAdminSchema(opts) {
|
|
18502
18960
|
if (!/^[0-9a-f-]{36}$/i.test(opts.pluginId)) {
|
|
@@ -18506,7 +18964,10 @@ class DatabaseAdapter {
|
|
|
18506
18964
|
if (!this.#skipVerify)
|
|
18507
18965
|
await this.verifyRoles();
|
|
18508
18966
|
await admin.transaction(async (tx) => {
|
|
18509
|
-
await provisionPluginSchemaInTx(tx, "provisionPluginAdminSchema", opts);
|
|
18967
|
+
const outcome = await provisionPluginSchemaInTx(tx, "provisionPluginAdminSchema", opts);
|
|
18968
|
+
if (outcome.droppedColumns.length > 0) {
|
|
18969
|
+
await auditDroppedColumns(tx, "cms_admin", opts.pluginId, outcome);
|
|
18970
|
+
}
|
|
18510
18971
|
});
|
|
18511
18972
|
}
|
|
18512
18973
|
async dropPluginAdminSchema(opts) {
|
|
@@ -18541,6 +19002,16 @@ class DatabaseAdapter {
|
|
|
18541
19002
|
return this.#public;
|
|
18542
19003
|
}
|
|
18543
19004
|
}
|
|
19005
|
+
async function auditDroppedColumns(tx, database, pluginId, outcome) {
|
|
19006
|
+
await recordAudit(tx, {
|
|
19007
|
+
actorId: SYSTEM_ACTOR_ID,
|
|
19008
|
+
operation: "plugins.schema_drop_columns",
|
|
19009
|
+
input: { database, schema: outcome.schemaName, columns: outcome.droppedColumns },
|
|
19010
|
+
succeeded: true,
|
|
19011
|
+
entityId: pluginId,
|
|
19012
|
+
resultSummary: `${database}.${outcome.schemaName}: dropped ${outcome.droppedColumns.join(", ")}`
|
|
19013
|
+
});
|
|
19014
|
+
}
|
|
18544
19015
|
// ../query-api/src/execute.ts
|
|
18545
19016
|
var allowAllRateLimiter = {
|
|
18546
19017
|
async check() {
|