@roottale/cms-core 0.70.1 → 0.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +21 -0
- package/dist/chunk-WNU53PSH.js +197 -0
- package/dist/chunk-WNU53PSH.js.map +1 -0
- package/dist/index.cjs +424 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +130 -1
- package/dist/index.d.ts +130 -1
- package/dist/index.js +151 -1
- package/dist/index.js.map +1 -1
- package/dist/visual-edit-contract-DzlMel7r.d.cts +822 -0
- package/dist/visual-edit-contract-DzlMel7r.d.ts +822 -0
- package/dist/visual-edit.cjs +339 -0
- package/dist/visual-edit.cjs.map +1 -0
- package/dist/visual-edit.d.cts +77 -0
- package/dist/visual-edit.d.ts +77 -0
- package/dist/visual-edit.js +153 -0
- package/dist/visual-edit.js.map +1 -0
- package/package.json +7 -1
package/dist/index.cjs
CHANGED
|
@@ -69,11 +69,15 @@ __export(src_exports, {
|
|
|
69
69
|
SITE_PATTERN_KEY_PATTERN: () => SITE_PATTERN_KEY_PATTERN,
|
|
70
70
|
SITE_PATTERN_PLACEMENTS_KEY: () => SITE_PATTERN_PLACEMENTS_KEY,
|
|
71
71
|
SITE_PATTERN_SLOTS: () => SITE_PATTERN_SLOTS,
|
|
72
|
+
VISUAL_EDIT_ATTRIBUTE: () => VISUAL_EDIT_ATTRIBUTE,
|
|
73
|
+
VISUAL_EDIT_PROTOCOL: () => VISUAL_EDIT_PROTOCOL,
|
|
74
|
+
VISUAL_EDIT_PROTOCOL_VERSION: () => VISUAL_EDIT_PROTOCOL_VERSION,
|
|
72
75
|
applyBlockBindings: () => applyBlockBindings,
|
|
73
76
|
bindingSrcValue: () => bindingSrcValue,
|
|
74
77
|
bindingTextValue: () => bindingTextValue,
|
|
75
78
|
blockSchema: () => blockSchema,
|
|
76
79
|
boundFieldValue: () => boundFieldValue,
|
|
80
|
+
buildVisualEditPreviewUrl: () => buildVisualEditPreviewUrl,
|
|
77
81
|
chainResolvers: () => chainResolvers,
|
|
78
82
|
cmsFontSize: () => cmsFontSize,
|
|
79
83
|
cmsImageAlign: () => cmsImageAlign,
|
|
@@ -99,6 +103,7 @@ __export(src_exports, {
|
|
|
99
103
|
findSitePatternPlacementRule: () => findSitePatternPlacementRule,
|
|
100
104
|
formatMetadataDefaults: () => formatMetadataDefaults,
|
|
101
105
|
formatSectionLockViolations: () => formatSectionLockViolations,
|
|
106
|
+
getContentValue: () => getContentValue,
|
|
102
107
|
htmlToPlainText: () => htmlToPlainText,
|
|
103
108
|
injectStableIdsTree: () => injectStableIdsTree,
|
|
104
109
|
internalContentKeyFromPath: () => internalContentKeyFromPath,
|
|
@@ -113,6 +118,7 @@ __export(src_exports, {
|
|
|
113
118
|
isSitePatternSlotKey: () => isSitePatternSlotKey,
|
|
114
119
|
isValidBlock: () => isValidBlock,
|
|
115
120
|
isValidSitePatternKey: () => isValidSitePatternKey,
|
|
121
|
+
isVisualEditOrigin: () => isVisualEditOrigin,
|
|
116
122
|
issuePreviewToken: () => issuePreviewToken,
|
|
117
123
|
matchesContentScalarCheck: () => matchesContentScalarCheck,
|
|
118
124
|
mergeMetadataPatch: () => mergeMetadataPatch,
|
|
@@ -126,9 +132,12 @@ __export(src_exports, {
|
|
|
126
132
|
normalizeRedirectSource: () => normalizeRedirectSource,
|
|
127
133
|
normalizeRedirectTarget: () => normalizeRedirectTarget,
|
|
128
134
|
parseBlock: () => parseBlock,
|
|
135
|
+
parseVisualEditAddress: () => parseVisualEditAddress,
|
|
136
|
+
parseVisualEditMessage: () => parseVisualEditMessage,
|
|
129
137
|
postsForCollection: () => postsForCollection,
|
|
130
138
|
postsInAnyCollection: () => postsInAnyCollection,
|
|
131
139
|
postsNotInAnyCollection: () => postsNotInAnyCollection,
|
|
140
|
+
profileQualificationJsonLdProperties: () => profileQualificationJsonLdProperties,
|
|
132
141
|
readMetadataValues: () => readMetadataValues,
|
|
133
142
|
readSitePatternPlacements: () => readSitePatternPlacements,
|
|
134
143
|
readSitePatternPresentation: () => readSitePatternPresentation,
|
|
@@ -141,6 +150,8 @@ __export(src_exports, {
|
|
|
141
150
|
resolveCategoryTreeEntryPath: () => resolveCategoryTreeEntryPath,
|
|
142
151
|
resolveCategoryTreeHubPaths: () => resolveCategoryTreeHubPaths,
|
|
143
152
|
resolveCategoryTreeSelection: () => resolveCategoryTreeSelection,
|
|
153
|
+
resolveContentCta: () => resolveContentCta,
|
|
154
|
+
resolveContentDependencyPaths: () => resolveContentDependencyPaths,
|
|
144
155
|
resolveMetadata: () => resolveMetadata,
|
|
145
156
|
resolvePatternSlots: () => resolvePatternSlots,
|
|
146
157
|
resolvePostBodySource: () => resolvePostBodySource,
|
|
@@ -149,17 +160,28 @@ __export(src_exports, {
|
|
|
149
160
|
resolvePostPath: () => resolvePostPath,
|
|
150
161
|
resolvePostPublicPath: () => resolvePostPublicPath,
|
|
151
162
|
resolvePostUrl: () => resolvePostUrl,
|
|
163
|
+
sameVisualDependencies: () => sameVisualDependencies,
|
|
164
|
+
sameVisualPreviewTarget: () => sameVisualPreviewTarget,
|
|
152
165
|
sanitizeHtml: () => sanitizeHtml,
|
|
153
166
|
sanitizeImportedCss: () => sanitizeImportedCss,
|
|
154
167
|
sanitizeImportedHtml: () => sanitizeImportedHtml,
|
|
155
168
|
scopeImportedCss: () => scopeImportedCss,
|
|
156
169
|
selectContentQuery: () => selectContentQuery,
|
|
170
|
+
selectRelatedContent: () => selectRelatedContent,
|
|
171
|
+
selectVisibleFaqEntries: () => selectVisibleFaqEntries,
|
|
157
172
|
serializeBlock: () => serializeBlock,
|
|
173
|
+
setContentValue: () => setContentValue,
|
|
158
174
|
setSitePatternPlacementRule: () => setSitePatternPlacementRule,
|
|
159
175
|
sitePatternButtonColor: () => sitePatternButtonColor,
|
|
160
176
|
sitePatternPresentationAttributes: () => sitePatternPresentationAttributes,
|
|
161
177
|
validateCollections: () => validateCollections,
|
|
162
|
-
verifyPreviewToken: () => verifyPreviewToken
|
|
178
|
+
verifyPreviewToken: () => verifyPreviewToken,
|
|
179
|
+
visibleFaqPageJsonLd: () => visibleFaqPageJsonLd,
|
|
180
|
+
visualEditAddressKey: () => visualEditAddressKey,
|
|
181
|
+
visualEditAddressSchema: () => visualEditAddressSchema,
|
|
182
|
+
visualEditAttributes: () => visualEditAttributes,
|
|
183
|
+
visualPreviewTargetSchema: () => visualPreviewTargetSchema,
|
|
184
|
+
visualRenderReceiptSchema: () => visualRenderReceiptSchema
|
|
163
185
|
});
|
|
164
186
|
module.exports = __toCommonJS(src_exports);
|
|
165
187
|
|
|
@@ -1338,6 +1360,109 @@ function verifyPreviewToken(secret, token) {
|
|
|
1338
1360
|
return { postId, expiresAt: new Date(exp) };
|
|
1339
1361
|
}
|
|
1340
1362
|
|
|
1363
|
+
// src/visual-edit-contract.ts
|
|
1364
|
+
var import_zod2 = require("zod");
|
|
1365
|
+
var VISUAL_EDIT_PROTOCOL = "roottale:visual-edit";
|
|
1366
|
+
var VISUAL_EDIT_PROTOCOL_VERSION = 1;
|
|
1367
|
+
var VISUAL_EDIT_ATTRIBUTE = "data-rt-edit";
|
|
1368
|
+
var identifier = import_zod2.z.string().min(1).max(160).refine((value) => !/[\u0000-\u001f]/.test(value));
|
|
1369
|
+
var safeKey = identifier.refine((value) => !["__proto__", "prototype", "constructor"].includes(value));
|
|
1370
|
+
var pathKey = safeKey.refine((value) => !/^\d+$/.test(value), "\uBC18\uBCF5 \uD56D\uBAA9\uC740 \uC21C\uBC88 \uB300\uC2E0 itemId\uB85C \uC120\uD0DD\uD569\uB2C8\uB2E4.");
|
|
1371
|
+
var version = import_zod2.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
1372
|
+
var session = import_zod2.z.string().uuid();
|
|
1373
|
+
var position = import_zod2.z.object({ left: import_zod2.z.number().finite().min(0).max(1e7), top: import_zod2.z.number().finite().min(0).max(1e7) }).strict();
|
|
1374
|
+
var pathname = import_zod2.z.string().min(1).max(2e3).refine((value) => value.startsWith("/") && !value.startsWith("//") && !/[\\?#\u0000-\u001f]/.test(value));
|
|
1375
|
+
var visualEditAddressSchema = import_zod2.z.object({
|
|
1376
|
+
entityId: identifier,
|
|
1377
|
+
fieldKey: safeKey,
|
|
1378
|
+
itemId: identifier.optional(),
|
|
1379
|
+
path: import_zod2.z.array(pathKey).max(16).optional()
|
|
1380
|
+
}).strict().refine((address) => {
|
|
1381
|
+
const selector = [...address.path ?? []].reverse().find((part) => part.startsWith("@"));
|
|
1382
|
+
return !selector || !address.itemId || selector.slice(1) === address.itemId;
|
|
1383
|
+
}, "itemId\uB294 \uACBD\uB85C\uC758 \uB9C8\uC9C0\uB9C9 \uBC18\uBCF5 \uD56D\uBAA9 ID\uC640 \uAC19\uC544\uC57C \uD569\uB2C8\uB2E4.");
|
|
1384
|
+
var visualPreviewTargetSchema = import_zod2.z.object({
|
|
1385
|
+
entityId: identifier,
|
|
1386
|
+
draftId: identifier,
|
|
1387
|
+
draftVersion: version,
|
|
1388
|
+
contractVersion: identifier,
|
|
1389
|
+
templateVersion: identifier
|
|
1390
|
+
}).strict();
|
|
1391
|
+
var visualRenderReceiptSchema = visualPreviewTargetSchema.extend({
|
|
1392
|
+
dependencyVersions: import_zod2.z.record(safeKey, identifier).refine((value) => Object.keys(value).length <= 256)
|
|
1393
|
+
}).strict();
|
|
1394
|
+
var envelope = {
|
|
1395
|
+
protocol: import_zod2.z.literal(VISUAL_EDIT_PROTOCOL),
|
|
1396
|
+
protocolVersion: import_zod2.z.literal(VISUAL_EDIT_PROTOCOL_VERSION),
|
|
1397
|
+
session,
|
|
1398
|
+
sequence: import_zod2.z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
1399
|
+
target: visualPreviewTargetSchema
|
|
1400
|
+
};
|
|
1401
|
+
var messageSchema = import_zod2.z.discriminatedUnion("type", [
|
|
1402
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("connect") }).strict(),
|
|
1403
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("ready") }).strict(),
|
|
1404
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("select"), address: visualEditAddressSchema, position: position.optional() }).strict(),
|
|
1405
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("focus"), address: visualEditAddressSchema.optional(), position: position.optional() }).strict(),
|
|
1406
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("navigate"), pathname }).strict(),
|
|
1407
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("mode"), mode: import_zod2.z.enum(["select", "navigate"]) }).strict(),
|
|
1408
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("refresh") }).strict(),
|
|
1409
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("viewport"), position }).strict(),
|
|
1410
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("rendered"), receipt: visualRenderReceiptSchema }).strict(),
|
|
1411
|
+
import_zod2.z.object({ ...envelope, type: import_zod2.z.literal("error"), code: import_zod2.z.enum(["unavailable", "superseded", "unsupported_contract", "expired"]), message: import_zod2.z.string().max(500).optional() }).strict()
|
|
1412
|
+
]);
|
|
1413
|
+
function parseVisualEditAddress(value) {
|
|
1414
|
+
const result = visualEditAddressSchema.safeParse(value);
|
|
1415
|
+
return result.success ? result.data : null;
|
|
1416
|
+
}
|
|
1417
|
+
function parseVisualEditMessage(value) {
|
|
1418
|
+
try {
|
|
1419
|
+
if (JSON.stringify(value).length > 64e3) return null;
|
|
1420
|
+
const result = messageSchema.safeParse(value);
|
|
1421
|
+
if (!result.success) return null;
|
|
1422
|
+
const message = result.data;
|
|
1423
|
+
if (message.type === "rendered" && !sameVisualPreviewTarget(message.target, message.receipt)) return null;
|
|
1424
|
+
if (message.type === "focus" && message.address && message.address.entityId !== message.target.entityId) return null;
|
|
1425
|
+
return message;
|
|
1426
|
+
} catch {
|
|
1427
|
+
return null;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
function sameVisualPreviewTarget(a, b) {
|
|
1431
|
+
return a.entityId === b.entityId && a.draftId === b.draftId && a.draftVersion === b.draftVersion && a.contractVersion === b.contractVersion && a.templateVersion === b.templateVersion;
|
|
1432
|
+
}
|
|
1433
|
+
function sameVisualDependencies(a, b) {
|
|
1434
|
+
const keys = Object.keys(a);
|
|
1435
|
+
return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && a[key] === b[key]);
|
|
1436
|
+
}
|
|
1437
|
+
function visualEditAddressKey(address) {
|
|
1438
|
+
const path = address.path ?? [];
|
|
1439
|
+
const itemId = [...path].reverse().find((part) => part.startsWith("@"))?.slice(1) ?? address.itemId ?? null;
|
|
1440
|
+
return JSON.stringify([address.entityId, address.fieldKey, itemId, path]);
|
|
1441
|
+
}
|
|
1442
|
+
function visualEditAttributes(address, enabled = true) {
|
|
1443
|
+
const parsed = enabled ? parseVisualEditAddress(address) : null;
|
|
1444
|
+
return parsed ? { [VISUAL_EDIT_ATTRIBUTE]: JSON.stringify(parsed) } : {};
|
|
1445
|
+
}
|
|
1446
|
+
function isVisualEditOrigin(value) {
|
|
1447
|
+
try {
|
|
1448
|
+
const url = new URL(value);
|
|
1449
|
+
const local = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
1450
|
+
return value === url.origin && (url.protocol === "https:" || local && url.protocol === "http:");
|
|
1451
|
+
} catch {
|
|
1452
|
+
return false;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
function buildVisualEditPreviewUrl(urlValue, editorOrigin, sessionId) {
|
|
1456
|
+
try {
|
|
1457
|
+
const url = new URL(urlValue);
|
|
1458
|
+
if (url.username || url.password || !isVisualEditOrigin(url.origin) || !isVisualEditOrigin(editorOrigin) || !session.safeParse(sessionId).success) return null;
|
|
1459
|
+
url.hash = new URLSearchParams({ "rt-visual-edit": sessionId, origin: editorOrigin }).toString();
|
|
1460
|
+
return url.href;
|
|
1461
|
+
} catch {
|
|
1462
|
+
return null;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1341
1466
|
// src/sanitize.ts
|
|
1342
1467
|
var import_sanitize_html2 = __toESM(require("sanitize-html"), 1);
|
|
1343
1468
|
var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "xlink:href"]);
|
|
@@ -2088,11 +2213,11 @@ function resolveMetadata(input) {
|
|
|
2088
2213
|
}
|
|
2089
2214
|
|
|
2090
2215
|
// src/metadata-contract.ts
|
|
2091
|
-
var
|
|
2216
|
+
var import_zod3 = require("zod");
|
|
2092
2217
|
var METADATA_FIELDS = ["title", "description", "ogImage", "ogImageAlt", "noindex", "nofollow"];
|
|
2093
|
-
var MetadataFieldSchema =
|
|
2094
|
-
var MetadataTargetKindSchema =
|
|
2095
|
-
var textValue = (max) =>
|
|
2218
|
+
var MetadataFieldSchema = import_zod3.z.enum(METADATA_FIELDS);
|
|
2219
|
+
var MetadataTargetKindSchema = import_zod3.z.enum(["route", "post", "term"]);
|
|
2220
|
+
var textValue = (max) => import_zod3.z.string().trim().min(1).max(max);
|
|
2096
2221
|
var imageValue = textValue(2048).refine((value) => {
|
|
2097
2222
|
if (/[\\\u0000-\u0020\u007f]/u.test(value) || value.startsWith("//")) return false;
|
|
2098
2223
|
if (value.startsWith("/")) return true;
|
|
@@ -2110,11 +2235,11 @@ var metadataFields = {
|
|
|
2110
2235
|
ogImage: imageValue,
|
|
2111
2236
|
// Automatic alt text may use the complete automatic title and its site suffix.
|
|
2112
2237
|
ogImageAlt: textValue(1e3),
|
|
2113
|
-
noindex:
|
|
2114
|
-
nofollow:
|
|
2238
|
+
noindex: import_zod3.z.boolean(),
|
|
2239
|
+
nofollow: import_zod3.z.boolean()
|
|
2115
2240
|
};
|
|
2116
|
-
var MetadataValuesSchema =
|
|
2117
|
-
var MetadataPatchSchema =
|
|
2241
|
+
var MetadataValuesSchema = import_zod3.z.object(metadataFields).partial().strict();
|
|
2242
|
+
var MetadataPatchSchema = import_zod3.z.object({
|
|
2118
2243
|
title: textValue(300).nullable().optional(),
|
|
2119
2244
|
description: metadataFields.description.nullable().optional(),
|
|
2120
2245
|
ogImage: metadataFields.ogImage.nullable().optional(),
|
|
@@ -2122,11 +2247,11 @@ var MetadataPatchSchema = import_zod2.z.object({
|
|
|
2122
2247
|
noindex: metadataFields.noindex.nullable().optional(),
|
|
2123
2248
|
nofollow: metadataFields.nofollow.nullable().optional()
|
|
2124
2249
|
}).strict();
|
|
2125
|
-
var MetadataRobotsPolicySchema =
|
|
2126
|
-
forceNoindex:
|
|
2127
|
-
forceNofollow:
|
|
2250
|
+
var MetadataRobotsPolicySchema = import_zod3.z.object({
|
|
2251
|
+
forceNoindex: import_zod3.z.boolean().optional(),
|
|
2252
|
+
forceNofollow: import_zod3.z.boolean().optional(),
|
|
2128
2253
|
/** Stable policy reason codes. They explain an enforced exclusion, never relax it. */
|
|
2129
|
-
noindexReasons:
|
|
2254
|
+
noindexReasons: import_zod3.z.array(import_zod3.z.string().trim().min(1).max(200)).max(64).optional()
|
|
2130
2255
|
}).strict();
|
|
2131
2256
|
function readMetadataValues(input) {
|
|
2132
2257
|
if (!input || typeof input !== "object" || Array.isArray(input)) return {};
|
|
@@ -2149,35 +2274,35 @@ function mergeMetadataPatch(current, input) {
|
|
|
2149
2274
|
}
|
|
2150
2275
|
|
|
2151
2276
|
// src/metadata-defaults.ts
|
|
2152
|
-
var
|
|
2277
|
+
var import_zod7 = require("zod");
|
|
2153
2278
|
|
|
2154
2279
|
// src/metadata-text.ts
|
|
2155
|
-
var
|
|
2156
|
-
var fallbackText =
|
|
2280
|
+
var import_zod4 = require("zod");
|
|
2281
|
+
var fallbackText = import_zod4.z.string().max(2e3);
|
|
2157
2282
|
var templateToken = /\{\{(?:title|field:[a-zA-Z][a-zA-Z0-9_-]{0,159})\}\}/gu;
|
|
2158
2283
|
var template = fallbackText.refine(
|
|
2159
2284
|
(value) => !/[{}]/u.test(value.replace(templateToken, "")),
|
|
2160
2285
|
"\uC790\uB3D9 \uD14D\uC2A4\uD2B8\uC5D0\uB294 {{title}} \uB610\uB294 {{field:\uD544\uB4DC\uC774\uB984}} \uD1A0\uD070\uB9CC \uC0AC\uC6A9\uD569\uB2C8\uB2E4"
|
|
2161
2286
|
);
|
|
2162
|
-
var MetadataTextRuleSchema =
|
|
2163
|
-
source:
|
|
2287
|
+
var MetadataTextRuleSchema = import_zod4.z.object({
|
|
2288
|
+
source: import_zod4.z.enum(["content", "fallback", "template"]).optional(),
|
|
2164
2289
|
template: template.optional(),
|
|
2165
|
-
stripLeadingLabel:
|
|
2166
|
-
replaceLineBreakTokens:
|
|
2167
|
-
removeEmDashes:
|
|
2168
|
-
normalizeWhitespace:
|
|
2169
|
-
maxLength:
|
|
2170
|
-
lengthUnit:
|
|
2171
|
-
wordBoundaryMinLength:
|
|
2172
|
-
ellipsis:
|
|
2173
|
-
bodyFallback:
|
|
2174
|
-
preferContaining:
|
|
2175
|
-
stripLeadingLabel:
|
|
2290
|
+
stripLeadingLabel: import_zod4.z.enum(["question", "answer"]).optional(),
|
|
2291
|
+
replaceLineBreakTokens: import_zod4.z.boolean().optional(),
|
|
2292
|
+
removeEmDashes: import_zod4.z.boolean().optional(),
|
|
2293
|
+
normalizeWhitespace: import_zod4.z.boolean().optional(),
|
|
2294
|
+
maxLength: import_zod4.z.number().int().min(1).max(2e3).optional(),
|
|
2295
|
+
lengthUnit: import_zod4.z.enum(["code-units", "code-points"]).optional(),
|
|
2296
|
+
wordBoundaryMinLength: import_zod4.z.number().int().min(1).max(2e3).optional(),
|
|
2297
|
+
ellipsis: import_zod4.z.string().max(10).optional(),
|
|
2298
|
+
bodyFallback: import_zod4.z.object({
|
|
2299
|
+
preferContaining: import_zod4.z.string().trim().min(1).max(100).optional(),
|
|
2300
|
+
stripLeadingLabel: import_zod4.z.literal("conclusion").optional()
|
|
2176
2301
|
}).strict().optional(),
|
|
2177
2302
|
fallback: fallbackText.optional(),
|
|
2178
2303
|
fallbackWithParent: fallbackText.optional(),
|
|
2179
2304
|
fallbackWithoutParent: fallbackText.optional(),
|
|
2180
|
-
fallbackBySlug:
|
|
2305
|
+
fallbackBySlug: import_zod4.z.record(import_zod4.z.string().max(200), fallbackText).optional()
|
|
2181
2306
|
}).strict().refine((rule) => !rule.ellipsis || rule.maxLength !== void 0 && rule.ellipsis.length < rule.maxLength, "\uB9D0\uC904\uC784\uD45C\uC5D0\uB294 \uB354 \uAE34 \uCD5C\uB300 \uAE38\uC774\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4").refine((rule) => rule.source === "template" ? rule.template !== void 0 : rule.template === void 0, "\uD14D\uC2A4\uD2B8 template\uC740 source: template\uACFC \uD568\uAED8 \uC120\uC5B8\uD569\uB2C8\uB2E4").refine((rule) => !rule.wordBoundaryMinLength || Boolean(rule.maxLength && rule.wordBoundaryMinLength < rule.maxLength), "\uB2E8\uC5B4 \uACBD\uACC4\uC5D0\uB294 \uB354 \uAE34 \uCD5C\uB300 \uAE38\uC774\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4");
|
|
2182
2307
|
function cleanMetadataText(value, rule) {
|
|
2183
2308
|
let text3 = value.trim();
|
|
@@ -2247,29 +2372,29 @@ function formatMetadataText(value, rule, input, name) {
|
|
|
2247
2372
|
}
|
|
2248
2373
|
|
|
2249
2374
|
// src/content-policy-schema.ts
|
|
2250
|
-
var
|
|
2251
|
-
var ContentPolicyFieldNameSchema =
|
|
2252
|
-
var ContentPolicyScalarSchema =
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2375
|
+
var import_zod5 = require("zod");
|
|
2376
|
+
var ContentPolicyFieldNameSchema = import_zod5.z.string().min(1).max(64).regex(/^[A-Za-z_][A-Za-z0-9_]*$/).refine((name) => name !== "prototype" && !Object.hasOwn(Object.prototype, name));
|
|
2377
|
+
var ContentPolicyScalarSchema = import_zod5.z.union([
|
|
2378
|
+
import_zod5.z.string().max(2048),
|
|
2379
|
+
import_zod5.z.number().finite(),
|
|
2380
|
+
import_zod5.z.boolean(),
|
|
2381
|
+
import_zod5.z.null()
|
|
2257
2382
|
]);
|
|
2258
|
-
var contentPolicyEquality =
|
|
2383
|
+
var contentPolicyEquality = import_zod5.z.object({
|
|
2259
2384
|
field: ContentPolicyFieldNameSchema,
|
|
2260
2385
|
equals: ContentPolicyScalarSchema
|
|
2261
2386
|
}).strict();
|
|
2262
|
-
var ContentPolicyWhenSchema =
|
|
2387
|
+
var ContentPolicyWhenSchema = import_zod5.z.union([
|
|
2263
2388
|
contentPolicyEquality,
|
|
2264
|
-
|
|
2265
|
-
all:
|
|
2266
|
-
unlessAll:
|
|
2389
|
+
import_zod5.z.object({
|
|
2390
|
+
all: import_zod5.z.array(contentPolicyEquality).min(1).max(4).optional(),
|
|
2391
|
+
unlessAll: import_zod5.z.array(contentPolicyEquality).min(1).max(4).optional()
|
|
2267
2392
|
}).strict().refine(
|
|
2268
2393
|
(when2) => when2.all !== void 0 || when2.unlessAll !== void 0,
|
|
2269
2394
|
"\uCF58\uD150\uCE20 \uC870\uAC74\uC5D0\uB294 all \uB610\uB294 unlessAll \uADF8\uB8F9\uC774 \uD544\uC694\uD569\uB2C8\uB2E4"
|
|
2270
2395
|
)
|
|
2271
2396
|
]);
|
|
2272
|
-
var ContentPolicyInternalPathSchema =
|
|
2397
|
+
var ContentPolicyInternalPathSchema = import_zod5.z.string().min(1).max(2048).refine((path) => {
|
|
2273
2398
|
if (!path.startsWith("/") || path.startsWith("//") || /[\\?#\u0000-\u0020\u007f]/u.test(path)) return false;
|
|
2274
2399
|
try {
|
|
2275
2400
|
return path.split("/").every((part, index) => {
|
|
@@ -2283,17 +2408,17 @@ var ContentPolicyInternalPathSchema = import_zod4.z.string().min(1).max(2048).re
|
|
|
2283
2408
|
}, "\uCF58\uD150\uCE20 \uACBD\uB85C\uB294 \uC548\uC804\uD55C \uC0AC\uC774\uD2B8 \uB0B4\uBD80 \uACBD\uB85C\uC5EC\uC57C \uD569\uB2C8\uB2E4");
|
|
2284
2409
|
var field = { field: ContentPolicyFieldNameSchema };
|
|
2285
2410
|
var scalarChecks = [
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2411
|
+
import_zod5.z.object({ ...field, op: import_zod5.z.literal("equals"), value: ContentPolicyScalarSchema }).strict(),
|
|
2412
|
+
import_zod5.z.object({ ...field, op: import_zod5.z.literal("notEquals"), value: ContentPolicyScalarSchema }).strict(),
|
|
2413
|
+
import_zod5.z.object({ ...field, op: import_zod5.z.literal("oneOf"), values: import_zod5.z.array(ContentPolicyScalarSchema).min(1).max(16), allowEmpty: import_zod5.z.boolean().optional() }).strict(),
|
|
2414
|
+
import_zod5.z.object({ ...field, op: import_zod5.z.literal("text") }).strict(),
|
|
2415
|
+
import_zod5.z.object({ ...field, op: import_zod5.z.literal("date") }).strict(),
|
|
2416
|
+
import_zod5.z.object({ ...field, op: import_zod5.z.literal("safeHttps") }).strict(),
|
|
2417
|
+
import_zod5.z.object({ ...field, op: import_zod5.z.literal("allowedPath"), paths: import_zod5.z.array(ContentPolicyInternalPathSchema).min(1).max(512) }).strict()
|
|
2293
2418
|
];
|
|
2294
|
-
var ContentPolicyScalarCheckSchema =
|
|
2419
|
+
var ContentPolicyScalarCheckSchema = import_zod5.z.discriminatedUnion("op", scalarChecks);
|
|
2295
2420
|
var when = { when: ContentPolicyWhenSchema.optional() };
|
|
2296
|
-
var ContentPolicyCheckSchema =
|
|
2421
|
+
var ContentPolicyCheckSchema = import_zod5.z.discriminatedUnion("op", [
|
|
2297
2422
|
scalarChecks[0].extend(when),
|
|
2298
2423
|
scalarChecks[1].extend(when),
|
|
2299
2424
|
scalarChecks[2].extend(when),
|
|
@@ -2301,26 +2426,26 @@ var ContentPolicyCheckSchema = import_zod4.z.discriminatedUnion("op", [
|
|
|
2301
2426
|
scalarChecks[4].extend(when),
|
|
2302
2427
|
scalarChecks[5].extend(when),
|
|
2303
2428
|
scalarChecks[6].extend(when),
|
|
2304
|
-
|
|
2305
|
-
|
|
2429
|
+
import_zod5.z.object({ ...field, ...when, op: import_zod5.z.literal("some"), checks: import_zod5.z.array(ContentPolicyScalarCheckSchema).min(1).max(8) }).strict(),
|
|
2430
|
+
import_zod5.z.object({
|
|
2306
2431
|
...when,
|
|
2307
|
-
op:
|
|
2308
|
-
allowExcerpt:
|
|
2309
|
-
allowFeaturedImage:
|
|
2310
|
-
additionalUrl:
|
|
2432
|
+
op: import_zod5.z.literal("bodyContent"),
|
|
2433
|
+
allowExcerpt: import_zod5.z.boolean().optional(),
|
|
2434
|
+
allowFeaturedImage: import_zod5.z.boolean().optional(),
|
|
2435
|
+
additionalUrl: import_zod5.z.object({ ...field, ...when }).strict().optional()
|
|
2311
2436
|
}).strict(),
|
|
2312
|
-
|
|
2437
|
+
import_zod5.z.object({ ...when, op: import_zod5.z.literal("bodyText") }).strict()
|
|
2313
2438
|
]);
|
|
2314
|
-
var contentPolicy =
|
|
2315
|
-
visibility:
|
|
2316
|
-
indexing:
|
|
2317
|
-
pathSegmentFormat:
|
|
2439
|
+
var contentPolicy = import_zod5.z.object({
|
|
2440
|
+
visibility: import_zod5.z.array(ContentPolicyCheckSchema).max(24),
|
|
2441
|
+
indexing: import_zod5.z.array(ContentPolicyCheckSchema).max(24),
|
|
2442
|
+
pathSegmentFormat: import_zod5.z.literal("lower-kebab").optional()
|
|
2318
2443
|
}).strict();
|
|
2319
2444
|
var ContentPolicySchema = contentPolicy.superRefine((policy, ctx) => {
|
|
2320
2445
|
const refs = collectContentPolicyFieldRefs(policy);
|
|
2321
|
-
if (refs.length > 64) ctx.addIssue({ code:
|
|
2446
|
+
if (refs.length > 64) ctx.addIssue({ code: import_zod5.z.ZodIssueCode.custom, message: "\uCF58\uD150\uCE20 \uC815\uCC45\uC740 \uACF5\uAC1C \uD544\uB4DC 64\uAC1C\uAE4C\uC9C0 \uCC38\uC870\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4" });
|
|
2322
2447
|
for (const ref of refs) {
|
|
2323
|
-
if ((ref.children?.length ?? 0) > 8) ctx.addIssue({ code:
|
|
2448
|
+
if ((ref.children?.length ?? 0) > 8) ctx.addIssue({ code: import_zod5.z.ZodIssueCode.custom, message: `\uBC18\uBCF5 \uD544\uB4DC ${ref.name}\uC758 \uC790\uC2DD \uCC38\uC870\uB294 8\uAC1C\uAE4C\uC9C0 \uD5C8\uC6A9\uD569\uB2C8\uB2E4` });
|
|
2324
2449
|
}
|
|
2325
2450
|
});
|
|
2326
2451
|
function collectContentPolicyFieldRefs(policy) {
|
|
@@ -2495,9 +2620,9 @@ function evaluateContentPolicy(policy, post, options = {}) {
|
|
|
2495
2620
|
}
|
|
2496
2621
|
|
|
2497
2622
|
// src/metadata-video-thumbnail.ts
|
|
2498
|
-
var
|
|
2499
|
-
var MetadataVideoThumbnailRuleSchema =
|
|
2500
|
-
source:
|
|
2623
|
+
var import_zod6 = require("zod");
|
|
2624
|
+
var MetadataVideoThumbnailRuleSchema = import_zod6.z.object({
|
|
2625
|
+
source: import_zod6.z.literal("youtube"),
|
|
2501
2626
|
field: ContentPolicyFieldNameSchema,
|
|
2502
2627
|
when: ContentPolicyWhenSchema.optional()
|
|
2503
2628
|
}).strict();
|
|
@@ -2530,7 +2655,7 @@ function collectMetadataDefaultFieldRefs(rule) {
|
|
|
2530
2655
|
}
|
|
2531
2656
|
|
|
2532
2657
|
// src/metadata-defaults.ts
|
|
2533
|
-
var imageOrigin =
|
|
2658
|
+
var imageOrigin = import_zod7.z.string().max(2048).refine((value) => {
|
|
2534
2659
|
try {
|
|
2535
2660
|
const url = new URL(value);
|
|
2536
2661
|
return url.protocol === "https:" && url.origin === value;
|
|
@@ -2538,30 +2663,30 @@ var imageOrigin = import_zod6.z.string().max(2048).refine((value) => {
|
|
|
2538
2663
|
return false;
|
|
2539
2664
|
}
|
|
2540
2665
|
}, "\uC774\uBBF8\uC9C0 \uD5C8\uC6A9 \uBAA9\uB85D\uC5D0\uB294 \uACBD\uB85C \uC5C6\uB294 HTTPS origin\uB9CC \uC120\uC5B8\uD569\uB2C8\uB2E4");
|
|
2541
|
-
var MetadataDefaultRulesSchema =
|
|
2666
|
+
var MetadataDefaultRulesSchema = import_zod7.z.object({
|
|
2542
2667
|
title: MetadataTextRuleSchema.optional(),
|
|
2543
|
-
titleTemplateMaxLength:
|
|
2668
|
+
titleTemplateMaxLength: import_zod7.z.number().int().min(1).max(1e3).optional(),
|
|
2544
2669
|
description: MetadataTextRuleSchema.optional(),
|
|
2545
2670
|
/** Code-owned defaults precede site defaults but always follow manual overrides. */
|
|
2546
2671
|
defaults: MetadataValuesSchema.optional(),
|
|
2547
2672
|
robots: MetadataRobotsPolicySchema.optional(),
|
|
2548
|
-
useFeaturedImage:
|
|
2673
|
+
useFeaturedImage: import_zod7.z.boolean().optional(),
|
|
2549
2674
|
videoThumbnail: MetadataVideoThumbnailRuleSchema.optional(),
|
|
2550
|
-
useFirstBodyImage:
|
|
2551
|
-
useTermImage:
|
|
2552
|
-
imageAltSource:
|
|
2553
|
-
legacyImageSource:
|
|
2554
|
-
imageAllowedOrigins:
|
|
2555
|
-
legacyImageAllowedOrigins:
|
|
2556
|
-
normalizeCloudflareImages:
|
|
2675
|
+
useFirstBodyImage: import_zod7.z.boolean().optional(),
|
|
2676
|
+
useTermImage: import_zod7.z.boolean().optional(),
|
|
2677
|
+
imageAltSource: import_zod7.z.enum(["content", "title"]).optional(),
|
|
2678
|
+
legacyImageSource: import_zod7.z.literal("legacy-thumbnail").optional(),
|
|
2679
|
+
imageAllowedOrigins: import_zod7.z.array(imageOrigin).min(1).max(32).optional(),
|
|
2680
|
+
legacyImageAllowedOrigins: import_zod7.z.array(imageOrigin).min(1).max(32).optional(),
|
|
2681
|
+
normalizeCloudflareImages: import_zod7.z.boolean().optional(),
|
|
2557
2682
|
fallback: MetadataValuesSchema.optional()
|
|
2558
2683
|
}).strict().refine((rule) => !rule.legacyImageSource || Boolean(rule.legacyImageAllowedOrigins?.length), "\uC774\uC804 \uC774\uBBF8\uC9C0 \uC6D0\uBCF8\uC5D0\uB294 \uD5C8\uC6A9 origin \uC120\uC5B8\uC774 \uD544\uC694\uD569\uB2C8\uB2E4").superRefine((rule, context) => {
|
|
2559
2684
|
if (!rule.videoThumbnail) return;
|
|
2560
2685
|
const refs = collectMetadataDefaultFieldRefs(rule);
|
|
2561
|
-
if (refs.length > 64) context.addIssue({ code:
|
|
2686
|
+
if (refs.length > 64) context.addIssue({ code: import_zod7.z.ZodIssueCode.custom, message: "\uC601\uC0C1 \uC790\uB3D9\uAC12\uC740 \uACF5\uAC1C \uD544\uB4DC 64\uAC1C\uAE4C\uC9C0 \uCC38\uC870\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4" });
|
|
2562
2687
|
for (const { name } of refs) {
|
|
2563
2688
|
if (!ContentPolicyFieldNameSchema.safeParse(name).success) context.addIssue({
|
|
2564
|
-
code:
|
|
2689
|
+
code: import_zod7.z.ZodIssueCode.custom,
|
|
2565
2690
|
message: "\uC601\uC0C1 \uC790\uB3D9\uAC12\uC758 \uD14D\uC2A4\uD2B8\xB7\uC870\uAC74\uC740 \uC548\uC804\uD55C \uACF5\uAC1C \uD544\uB4DC \uC774\uB984\uC744 \uC0AC\uC6A9\uD569\uB2C8\uB2E4"
|
|
2566
2691
|
});
|
|
2567
2692
|
}
|
|
@@ -2625,20 +2750,20 @@ function formatMetadataDefaults(input, declaration) {
|
|
|
2625
2750
|
}
|
|
2626
2751
|
|
|
2627
2752
|
// src/content-query.ts
|
|
2628
|
-
var
|
|
2753
|
+
var import_zod8 = require("zod");
|
|
2629
2754
|
var field2 = { field: ContentPolicyFieldNameSchema };
|
|
2630
|
-
var ContentQueryFilterSchema =
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2755
|
+
var ContentQueryFilterSchema = import_zod8.z.discriminatedUnion("op", [
|
|
2756
|
+
import_zod8.z.object({ ...field2, op: import_zod8.z.literal("equals"), value: ContentPolicyScalarSchema }).strict(),
|
|
2757
|
+
import_zod8.z.object({ ...field2, op: import_zod8.z.literal("notEquals"), value: ContentPolicyScalarSchema }).strict(),
|
|
2758
|
+
import_zod8.z.object({ ...field2, op: import_zod8.z.literal("oneOf"), values: import_zod8.z.array(ContentPolicyScalarSchema).min(1).max(16), allowEmpty: import_zod8.z.boolean().optional() }).strict()
|
|
2634
2759
|
]);
|
|
2635
|
-
var ContentQuerySchema =
|
|
2636
|
-
modelKeys:
|
|
2637
|
-
filters:
|
|
2638
|
-
scope:
|
|
2760
|
+
var ContentQuerySchema = import_zod8.z.object({
|
|
2761
|
+
modelKeys: import_zod8.z.array(import_zod8.z.string().min(1).max(100).regex(/^[a-z][a-z0-9_-]*$/)).min(1).max(16),
|
|
2762
|
+
filters: import_zod8.z.array(ContentQueryFilterSchema).max(8).optional(),
|
|
2763
|
+
scope: import_zod8.z.enum(["currentTerm", "currentPath"]).optional(),
|
|
2639
2764
|
pinnedField: ContentPolicyFieldNameSchema.optional(),
|
|
2640
|
-
pageSize:
|
|
2641
|
-
requireItems:
|
|
2765
|
+
pageSize: import_zod8.z.number().int().min(1).max(100),
|
|
2766
|
+
requireItems: import_zod8.z.boolean().optional()
|
|
2642
2767
|
}).strict();
|
|
2643
2768
|
function collectContentQueryFieldRefs(query) {
|
|
2644
2769
|
return [.../* @__PURE__ */ new Set([...(query.filters ?? []).map((filter) => filter.field), ...query.pinnedField ? [query.pinnedField] : []])].map((name) => ({ name }));
|
|
@@ -2703,6 +2828,190 @@ function selectContentQuery(query, posts, policies, options) {
|
|
|
2703
2828
|
return evaluateContentQuery(query, candidates, options);
|
|
2704
2829
|
}
|
|
2705
2830
|
|
|
2831
|
+
// src/content-relations.ts
|
|
2832
|
+
function assertScope(scope) {
|
|
2833
|
+
if (!scope.tenantId.trim() || !scope.siteId.trim()) throw new Error("Content scope requires tenantId and siteId");
|
|
2834
|
+
}
|
|
2835
|
+
function publishedCandidates(candidates, scope, sourceId) {
|
|
2836
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2837
|
+
return candidates.filter((candidate) => {
|
|
2838
|
+
if (candidate.tenantId !== scope.tenantId || candidate.siteId !== scope.siteId || candidate.id === sourceId || candidate.status !== "published" || !candidate.id.trim() || !candidate.title.trim() || !ContentPolicyInternalPathSchema.safeParse(candidate.path).success || !Number.isFinite(Date.parse(candidate.publishedAt ?? "")) || seen.has(candidate.id)) return false;
|
|
2839
|
+
seen.add(candidate.id);
|
|
2840
|
+
return true;
|
|
2841
|
+
});
|
|
2842
|
+
}
|
|
2843
|
+
function latestFirst(left, right) {
|
|
2844
|
+
return Date.parse(right.publishedAt) - Date.parse(left.publishedAt) || (left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
|
|
2845
|
+
}
|
|
2846
|
+
function selectRelatedContent(candidates, options) {
|
|
2847
|
+
assertScope(options.scope);
|
|
2848
|
+
const termIds = new Set(options.termIds.filter((id) => id.trim()));
|
|
2849
|
+
if (options.includeDescendants) {
|
|
2850
|
+
for (const termId of options.termIds) {
|
|
2851
|
+
if (!termId.trim() || !Object.hasOwn(options.descendantTermIds ?? {}, termId)) continue;
|
|
2852
|
+
for (const descendantId of options.descendantTermIds[termId] ?? []) {
|
|
2853
|
+
if (descendantId.trim()) termIds.add(descendantId);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
const selected = publishedCandidates(candidates, options.scope, options.sourceId).filter((candidate) => candidate.termIds.some((id) => termIds.has(id))).sort(latestFirst);
|
|
2858
|
+
return options.models.map(({ modelKey, maxCount }) => {
|
|
2859
|
+
if (!Number.isSafeInteger(maxCount) || maxCount < 0) throw new Error("Related content maxCount must be a non-negative integer");
|
|
2860
|
+
return { modelKey, items: selected.filter((candidate) => candidate.modelKey === modelKey).slice(0, maxCount) };
|
|
2861
|
+
});
|
|
2862
|
+
}
|
|
2863
|
+
function resolveContentCta(candidates, options) {
|
|
2864
|
+
assertScope(options.scope);
|
|
2865
|
+
const { mode, targetPostId } = options.cta;
|
|
2866
|
+
const hidden = (reason) => ({ state: "hidden", mode, reason });
|
|
2867
|
+
if (mode === "off") return hidden("disabled");
|
|
2868
|
+
const published = publishedCandidates(candidates, options.scope, options.sourceId);
|
|
2869
|
+
if (mode === "manual") {
|
|
2870
|
+
if (!targetPostId?.trim()) return hidden("manual_target_missing");
|
|
2871
|
+
const target = published.find((candidate) => candidate.id === targetPostId);
|
|
2872
|
+
return target ? { state: "resolved", mode, target } : hidden("manual_target_unavailable");
|
|
2873
|
+
}
|
|
2874
|
+
if (!options.primaryTermId?.trim()) return hidden("primary_term_missing");
|
|
2875
|
+
const targets = published.filter((candidate) => options.detailModelKeys.includes(candidate.modelKey) && candidate.termIds.includes(options.primaryTermId));
|
|
2876
|
+
if (targets.length === 0) return hidden("auto_target_missing");
|
|
2877
|
+
if (targets.length > 1) return hidden("auto_target_ambiguous");
|
|
2878
|
+
return { state: "resolved", mode, target: targets[0] };
|
|
2879
|
+
}
|
|
2880
|
+
function plainFact(value) {
|
|
2881
|
+
return value.replace(/\s+/gu, " ").trim();
|
|
2882
|
+
}
|
|
2883
|
+
function selectVisibleFaqEntries(entries) {
|
|
2884
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2885
|
+
const selected = [];
|
|
2886
|
+
for (const entry of entries) {
|
|
2887
|
+
const id = entry.id.trim();
|
|
2888
|
+
const question = plainFact(entry.question);
|
|
2889
|
+
const answer = plainFact(entry.answer);
|
|
2890
|
+
if (!entry.visible || entry.deleted || !id || !question || !answer || seen.has(id)) continue;
|
|
2891
|
+
seen.add(id);
|
|
2892
|
+
selected.push({ id, question, answer });
|
|
2893
|
+
}
|
|
2894
|
+
return selected;
|
|
2895
|
+
}
|
|
2896
|
+
function visibleFaqPageJsonLd(entries) {
|
|
2897
|
+
return faqPageJsonLd(selectVisibleFaqEntries(entries));
|
|
2898
|
+
}
|
|
2899
|
+
function enteredNames(value) {
|
|
2900
|
+
const values = typeof value === "string" ? [value] : value ?? [];
|
|
2901
|
+
return [...new Set(values.map(plainFact).filter(Boolean))];
|
|
2902
|
+
}
|
|
2903
|
+
function profileQualificationJsonLdProperties(input) {
|
|
2904
|
+
const qualifications = enteredNames(input.qualification);
|
|
2905
|
+
const alumni = enteredNames(input.alumniOf);
|
|
2906
|
+
return {
|
|
2907
|
+
...qualifications.length ? { hasCredential: qualifications.map((name) => ({ "@type": "EducationalOccupationalCredential", name })) } : {},
|
|
2908
|
+
...alumni.length ? { alumniOf: alumni.map((name) => ({ "@type": "EducationalOrganization", name })) } : {}
|
|
2909
|
+
};
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
// src/content-values.ts
|
|
2913
|
+
var import_zod9 = require("zod");
|
|
2914
|
+
var itemIdSchema = import_zod9.z.string().uuid();
|
|
2915
|
+
var forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
2916
|
+
function isContentRecord(value) {
|
|
2917
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
2918
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2919
|
+
return prototype === Object.prototype || prototype === null;
|
|
2920
|
+
}
|
|
2921
|
+
function validatePath(path) {
|
|
2922
|
+
if (!Array.isArray(path) || !path.length || path.some((key) => typeof key !== "string" || !key || forbiddenKeys.has(key) || /^\d+$/u.test(key) || /[\u0000-\u001f]/u.test(key))) {
|
|
2923
|
+
throw new Error("Content path must use safe property names and stable item IDs");
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
function findItemIndex(items, token) {
|
|
2927
|
+
if (!token.startsWith("@") || !itemIdSchema.safeParse(token.slice(1)).success) {
|
|
2928
|
+
throw new Error("Content repeater path requires @<uuid>");
|
|
2929
|
+
}
|
|
2930
|
+
const targetId = token.slice(1);
|
|
2931
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2932
|
+
let selected = -1;
|
|
2933
|
+
for (const [index, item] of items.entries()) {
|
|
2934
|
+
if (!isContentRecord(item) || !Object.hasOwn(item, "_id")) throw new Error("Content repeater item has no stable ID");
|
|
2935
|
+
const parsed = itemIdSchema.safeParse(item._id);
|
|
2936
|
+
if (!parsed.success) throw new Error("Content repeater item has an invalid ID");
|
|
2937
|
+
if (seen.has(parsed.data)) throw new Error("Content repeater item IDs are ambiguous");
|
|
2938
|
+
seen.add(parsed.data);
|
|
2939
|
+
if (parsed.data === targetId) selected = index;
|
|
2940
|
+
}
|
|
2941
|
+
if (selected < 0) throw new Error("Content repeater item was not found");
|
|
2942
|
+
return selected;
|
|
2943
|
+
}
|
|
2944
|
+
function locateContentValue(values, path) {
|
|
2945
|
+
validatePath(path);
|
|
2946
|
+
if (!isContentRecord(values)) throw new Error("Content values must be a serialized object");
|
|
2947
|
+
const frames = [];
|
|
2948
|
+
let current = values;
|
|
2949
|
+
for (const key of path) {
|
|
2950
|
+
if (Array.isArray(current)) {
|
|
2951
|
+
const index = findItemIndex(current, key);
|
|
2952
|
+
frames.push({ kind: "array", parent: current, index, itemId: key.slice(1) });
|
|
2953
|
+
current = current[index];
|
|
2954
|
+
} else {
|
|
2955
|
+
if (!isContentRecord(current) || key.startsWith("@") || !Object.hasOwn(current, key)) {
|
|
2956
|
+
throw new Error("Content property was not found");
|
|
2957
|
+
}
|
|
2958
|
+
frames.push({ kind: "object", parent: current, key });
|
|
2959
|
+
current = current[key];
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
return { value: current, frames };
|
|
2963
|
+
}
|
|
2964
|
+
function getContentValue(values, path) {
|
|
2965
|
+
return locateContentValue(values, path).value;
|
|
2966
|
+
}
|
|
2967
|
+
function setContentValue(values, path, value) {
|
|
2968
|
+
const { frames } = locateContentValue(values, path);
|
|
2969
|
+
const leaf = frames[frames.length - 1];
|
|
2970
|
+
if (leaf.kind === "object" && leaf.key === "_id" || leaf.kind === "array" && (!isContentRecord(value) || !Object.hasOwn(value, "_id") || value._id !== leaf.itemId)) {
|
|
2971
|
+
throw new Error("Content edits must preserve stable item IDs");
|
|
2972
|
+
}
|
|
2973
|
+
let patched = value;
|
|
2974
|
+
for (let index = frames.length - 1; index >= 0; index--) {
|
|
2975
|
+
const frame = frames[index];
|
|
2976
|
+
if (frame.kind === "array") {
|
|
2977
|
+
const items = [...frame.parent];
|
|
2978
|
+
items[frame.index] = patched;
|
|
2979
|
+
patched = items;
|
|
2980
|
+
} else {
|
|
2981
|
+
patched = { ...frame.parent, [frame.key]: patched };
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
return patched;
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
// src/content-dependencies.ts
|
|
2988
|
+
function inScope(value, scope) {
|
|
2989
|
+
return value.tenantId === scope.tenantId && value.siteId === scope.siteId;
|
|
2990
|
+
}
|
|
2991
|
+
function matchesQuery(entity, query) {
|
|
2992
|
+
return query.modelKeys.includes(entity.modelKey) && (query.termIds === void 0 || entity.termIds.some((id) => id.trim() && query.termIds.includes(id)));
|
|
2993
|
+
}
|
|
2994
|
+
function resolveContentDependencyPaths(dependencies, change) {
|
|
2995
|
+
const { scope } = change;
|
|
2996
|
+
if (!scope.tenantId.trim() || !scope.siteId.trim()) throw new Error("Content scope requires tenantId and siteId");
|
|
2997
|
+
const snapshots = [change.before, change.after].filter((entity) => entity != null && inScope(entity, scope));
|
|
2998
|
+
const entityIds = new Set([...snapshots.map(({ id }) => id), ...change.entityIds ?? []].filter((id) => id.trim()));
|
|
2999
|
+
const singletonKeys = new Set((change.singletonKeys ?? []).filter((key) => key.trim()));
|
|
3000
|
+
const paths = /* @__PURE__ */ new Set();
|
|
3001
|
+
const includePath = (path) => {
|
|
3002
|
+
if (path !== null && ContentPolicyInternalPathSchema.safeParse(path).success) paths.add(path);
|
|
3003
|
+
};
|
|
3004
|
+
for (const snapshot of snapshots) includePath(snapshot.path);
|
|
3005
|
+
for (const dependency of dependencies) {
|
|
3006
|
+
if (!inScope(dependency, scope)) continue;
|
|
3007
|
+
const direct = dependency.entityIds?.some((id) => entityIds.has(id));
|
|
3008
|
+
const shared = dependency.singletonKeys?.some((key) => singletonKeys.has(key));
|
|
3009
|
+
const queried = dependency.queries?.some((query) => snapshots.some((entity) => matchesQuery(entity, query)));
|
|
3010
|
+
if (direct || shared || queried) includePath(dependency.path);
|
|
3011
|
+
}
|
|
3012
|
+
return [...paths].sort();
|
|
3013
|
+
}
|
|
3014
|
+
|
|
2706
3015
|
// src/redirect-paths.ts
|
|
2707
3016
|
var CONTROL_OR_BACKSLASH = /[\\\u0000-\u001f\u007f]/u;
|
|
2708
3017
|
var PROTECTED_PREFIX = /^\/(?:api|_next|_vercel|auth|admin|login|logout|revalidate|preview|assets|static|images|fonts|\.well-known)(?:\/|$)/i;
|
|
@@ -2804,11 +3113,15 @@ function normalizeRedirectTarget(raw) {
|
|
|
2804
3113
|
SITE_PATTERN_KEY_PATTERN,
|
|
2805
3114
|
SITE_PATTERN_PLACEMENTS_KEY,
|
|
2806
3115
|
SITE_PATTERN_SLOTS,
|
|
3116
|
+
VISUAL_EDIT_ATTRIBUTE,
|
|
3117
|
+
VISUAL_EDIT_PROTOCOL,
|
|
3118
|
+
VISUAL_EDIT_PROTOCOL_VERSION,
|
|
2807
3119
|
applyBlockBindings,
|
|
2808
3120
|
bindingSrcValue,
|
|
2809
3121
|
bindingTextValue,
|
|
2810
3122
|
blockSchema,
|
|
2811
3123
|
boundFieldValue,
|
|
3124
|
+
buildVisualEditPreviewUrl,
|
|
2812
3125
|
chainResolvers,
|
|
2813
3126
|
cmsFontSize,
|
|
2814
3127
|
cmsImageAlign,
|
|
@@ -2834,6 +3147,7 @@ function normalizeRedirectTarget(raw) {
|
|
|
2834
3147
|
findSitePatternPlacementRule,
|
|
2835
3148
|
formatMetadataDefaults,
|
|
2836
3149
|
formatSectionLockViolations,
|
|
3150
|
+
getContentValue,
|
|
2837
3151
|
htmlToPlainText,
|
|
2838
3152
|
injectStableIdsTree,
|
|
2839
3153
|
internalContentKeyFromPath,
|
|
@@ -2848,6 +3162,7 @@ function normalizeRedirectTarget(raw) {
|
|
|
2848
3162
|
isSitePatternSlotKey,
|
|
2849
3163
|
isValidBlock,
|
|
2850
3164
|
isValidSitePatternKey,
|
|
3165
|
+
isVisualEditOrigin,
|
|
2851
3166
|
issuePreviewToken,
|
|
2852
3167
|
matchesContentScalarCheck,
|
|
2853
3168
|
mergeMetadataPatch,
|
|
@@ -2861,9 +3176,12 @@ function normalizeRedirectTarget(raw) {
|
|
|
2861
3176
|
normalizeRedirectSource,
|
|
2862
3177
|
normalizeRedirectTarget,
|
|
2863
3178
|
parseBlock,
|
|
3179
|
+
parseVisualEditAddress,
|
|
3180
|
+
parseVisualEditMessage,
|
|
2864
3181
|
postsForCollection,
|
|
2865
3182
|
postsInAnyCollection,
|
|
2866
3183
|
postsNotInAnyCollection,
|
|
3184
|
+
profileQualificationJsonLdProperties,
|
|
2867
3185
|
readMetadataValues,
|
|
2868
3186
|
readSitePatternPlacements,
|
|
2869
3187
|
readSitePatternPresentation,
|
|
@@ -2876,6 +3194,8 @@ function normalizeRedirectTarget(raw) {
|
|
|
2876
3194
|
resolveCategoryTreeEntryPath,
|
|
2877
3195
|
resolveCategoryTreeHubPaths,
|
|
2878
3196
|
resolveCategoryTreeSelection,
|
|
3197
|
+
resolveContentCta,
|
|
3198
|
+
resolveContentDependencyPaths,
|
|
2879
3199
|
resolveMetadata,
|
|
2880
3200
|
resolvePatternSlots,
|
|
2881
3201
|
resolvePostBodySource,
|
|
@@ -2884,16 +3204,27 @@ function normalizeRedirectTarget(raw) {
|
|
|
2884
3204
|
resolvePostPath,
|
|
2885
3205
|
resolvePostPublicPath,
|
|
2886
3206
|
resolvePostUrl,
|
|
3207
|
+
sameVisualDependencies,
|
|
3208
|
+
sameVisualPreviewTarget,
|
|
2887
3209
|
sanitizeHtml,
|
|
2888
3210
|
sanitizeImportedCss,
|
|
2889
3211
|
sanitizeImportedHtml,
|
|
2890
3212
|
scopeImportedCss,
|
|
2891
3213
|
selectContentQuery,
|
|
3214
|
+
selectRelatedContent,
|
|
3215
|
+
selectVisibleFaqEntries,
|
|
2892
3216
|
serializeBlock,
|
|
3217
|
+
setContentValue,
|
|
2893
3218
|
setSitePatternPlacementRule,
|
|
2894
3219
|
sitePatternButtonColor,
|
|
2895
3220
|
sitePatternPresentationAttributes,
|
|
2896
3221
|
validateCollections,
|
|
2897
|
-
verifyPreviewToken
|
|
3222
|
+
verifyPreviewToken,
|
|
3223
|
+
visibleFaqPageJsonLd,
|
|
3224
|
+
visualEditAddressKey,
|
|
3225
|
+
visualEditAddressSchema,
|
|
3226
|
+
visualEditAttributes,
|
|
3227
|
+
visualPreviewTargetSchema,
|
|
3228
|
+
visualRenderReceiptSchema
|
|
2898
3229
|
});
|
|
2899
3230
|
//# sourceMappingURL=index.cjs.map
|