@roottale/cms-core 0.71.0 → 0.72.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/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
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/visual-edit.ts
|
|
21
|
+
var visual_edit_exports = {};
|
|
22
|
+
__export(visual_edit_exports, {
|
|
23
|
+
VISUAL_EDIT_ATTRIBUTE: () => VISUAL_EDIT_ATTRIBUTE,
|
|
24
|
+
VISUAL_EDIT_PROTOCOL: () => VISUAL_EDIT_PROTOCOL,
|
|
25
|
+
VISUAL_EDIT_PROTOCOL_VERSION: () => VISUAL_EDIT_PROTOCOL_VERSION,
|
|
26
|
+
buildVisualEditPreviewUrl: () => buildVisualEditPreviewUrl,
|
|
27
|
+
checkPreviewCompatibility: () => checkPreviewCompatibility,
|
|
28
|
+
coverageReport: () => coverageReport,
|
|
29
|
+
createVisualEditMessage: () => createVisualEditMessage,
|
|
30
|
+
isCurrentVisualEditMessage: () => isCurrentVisualEditMessage,
|
|
31
|
+
isVisualEditOrigin: () => isVisualEditOrigin,
|
|
32
|
+
parseVisualEditAddress: () => parseVisualEditAddress,
|
|
33
|
+
parseVisualEditMessage: () => parseVisualEditMessage,
|
|
34
|
+
sameVisualDependencies: () => sameVisualDependencies,
|
|
35
|
+
sameVisualPreviewTarget: () => sameVisualPreviewTarget,
|
|
36
|
+
visualEditAddressKey: () => visualEditAddressKey,
|
|
37
|
+
visualEditAddressSchema: () => visualEditAddressSchema,
|
|
38
|
+
visualEditAttributes: () => visualEditAttributes,
|
|
39
|
+
visualEditorOrigins: () => visualEditorOrigins,
|
|
40
|
+
visualPreviewTargetSchema: () => visualPreviewTargetSchema,
|
|
41
|
+
visualRenderReceiptSchema: () => visualRenderReceiptSchema
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(visual_edit_exports);
|
|
44
|
+
|
|
45
|
+
// src/visual-edit-contract.ts
|
|
46
|
+
var import_zod = require("zod");
|
|
47
|
+
var VISUAL_EDIT_PROTOCOL = "roottale:visual-edit";
|
|
48
|
+
var VISUAL_EDIT_PROTOCOL_VERSION = 1;
|
|
49
|
+
var VISUAL_EDIT_ATTRIBUTE = "data-rt-edit";
|
|
50
|
+
var identifier = import_zod.z.string().min(1).max(160).refine((value) => !/[\u0000-\u001f]/.test(value));
|
|
51
|
+
var safeKey = identifier.refine((value) => !["__proto__", "prototype", "constructor"].includes(value));
|
|
52
|
+
var pathKey = safeKey.refine((value) => !/^\d+$/.test(value), "\uBC18\uBCF5 \uD56D\uBAA9\uC740 \uC21C\uBC88 \uB300\uC2E0 itemId\uB85C \uC120\uD0DD\uD569\uB2C8\uB2E4.");
|
|
53
|
+
var version = import_zod.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
54
|
+
var session = import_zod.z.string().uuid();
|
|
55
|
+
var position = import_zod.z.object({ left: import_zod.z.number().finite().min(0).max(1e7), top: import_zod.z.number().finite().min(0).max(1e7) }).strict();
|
|
56
|
+
var pathname = import_zod.z.string().min(1).max(2e3).refine((value) => value.startsWith("/") && !value.startsWith("//") && !/[\\?#\u0000-\u001f]/.test(value));
|
|
57
|
+
var visualEditAddressSchema = import_zod.z.object({
|
|
58
|
+
entityId: identifier,
|
|
59
|
+
fieldKey: safeKey,
|
|
60
|
+
itemId: identifier.optional(),
|
|
61
|
+
path: import_zod.z.array(pathKey).max(16).optional()
|
|
62
|
+
}).strict().refine((address) => {
|
|
63
|
+
const selector = [...address.path ?? []].reverse().find((part) => part.startsWith("@"));
|
|
64
|
+
return !selector || !address.itemId || selector.slice(1) === address.itemId;
|
|
65
|
+
}, "itemId\uB294 \uACBD\uB85C\uC758 \uB9C8\uC9C0\uB9C9 \uBC18\uBCF5 \uD56D\uBAA9 ID\uC640 \uAC19\uC544\uC57C \uD569\uB2C8\uB2E4.");
|
|
66
|
+
var visualPreviewTargetSchema = import_zod.z.object({
|
|
67
|
+
entityId: identifier,
|
|
68
|
+
draftId: identifier,
|
|
69
|
+
draftVersion: version,
|
|
70
|
+
contractVersion: identifier,
|
|
71
|
+
templateVersion: identifier
|
|
72
|
+
}).strict();
|
|
73
|
+
var visualRenderReceiptSchema = visualPreviewTargetSchema.extend({
|
|
74
|
+
dependencyVersions: import_zod.z.record(safeKey, identifier).refine((value) => Object.keys(value).length <= 256)
|
|
75
|
+
}).strict();
|
|
76
|
+
var envelope = {
|
|
77
|
+
protocol: import_zod.z.literal(VISUAL_EDIT_PROTOCOL),
|
|
78
|
+
protocolVersion: import_zod.z.literal(VISUAL_EDIT_PROTOCOL_VERSION),
|
|
79
|
+
session,
|
|
80
|
+
sequence: import_zod.z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
81
|
+
target: visualPreviewTargetSchema
|
|
82
|
+
};
|
|
83
|
+
var messageSchema = import_zod.z.discriminatedUnion("type", [
|
|
84
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("connect") }).strict(),
|
|
85
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("ready") }).strict(),
|
|
86
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("select"), address: visualEditAddressSchema, position: position.optional() }).strict(),
|
|
87
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("focus"), address: visualEditAddressSchema.optional(), position: position.optional() }).strict(),
|
|
88
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("navigate"), pathname }).strict(),
|
|
89
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("mode"), mode: import_zod.z.enum(["select", "navigate"]) }).strict(),
|
|
90
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("refresh") }).strict(),
|
|
91
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("viewport"), position }).strict(),
|
|
92
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("rendered"), receipt: visualRenderReceiptSchema }).strict(),
|
|
93
|
+
import_zod.z.object({ ...envelope, type: import_zod.z.literal("error"), code: import_zod.z.enum(["unavailable", "superseded", "unsupported_contract", "expired"]), message: import_zod.z.string().max(500).optional() }).strict()
|
|
94
|
+
]);
|
|
95
|
+
function parseVisualEditAddress(value) {
|
|
96
|
+
const result = visualEditAddressSchema.safeParse(value);
|
|
97
|
+
return result.success ? result.data : null;
|
|
98
|
+
}
|
|
99
|
+
function parseVisualEditMessage(value) {
|
|
100
|
+
try {
|
|
101
|
+
if (JSON.stringify(value).length > 64e3) return null;
|
|
102
|
+
const result = messageSchema.safeParse(value);
|
|
103
|
+
if (!result.success) return null;
|
|
104
|
+
const message = result.data;
|
|
105
|
+
if (message.type === "rendered" && !sameVisualPreviewTarget(message.target, message.receipt)) return null;
|
|
106
|
+
if (message.type === "focus" && message.address && message.address.entityId !== message.target.entityId) return null;
|
|
107
|
+
return message;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function sameVisualPreviewTarget(a, b) {
|
|
113
|
+
return a.entityId === b.entityId && a.draftId === b.draftId && a.draftVersion === b.draftVersion && a.contractVersion === b.contractVersion && a.templateVersion === b.templateVersion;
|
|
114
|
+
}
|
|
115
|
+
function sameVisualDependencies(a, b) {
|
|
116
|
+
const keys = Object.keys(a);
|
|
117
|
+
return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && a[key] === b[key]);
|
|
118
|
+
}
|
|
119
|
+
function visualEditAddressKey(address) {
|
|
120
|
+
const path = address.path ?? [];
|
|
121
|
+
const itemId = [...path].reverse().find((part) => part.startsWith("@"))?.slice(1) ?? address.itemId ?? null;
|
|
122
|
+
return JSON.stringify([address.entityId, address.fieldKey, itemId, path]);
|
|
123
|
+
}
|
|
124
|
+
function visualEditAttributes(address, enabled = true) {
|
|
125
|
+
const parsed = enabled ? parseVisualEditAddress(address) : null;
|
|
126
|
+
return parsed ? { [VISUAL_EDIT_ATTRIBUTE]: JSON.stringify(parsed) } : {};
|
|
127
|
+
}
|
|
128
|
+
function isVisualEditOrigin(value) {
|
|
129
|
+
try {
|
|
130
|
+
const url = new URL(value);
|
|
131
|
+
const local = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
132
|
+
return value === url.origin && (url.protocol === "https:" || local && url.protocol === "http:");
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function buildVisualEditPreviewUrl(urlValue, editorOrigin, sessionId) {
|
|
138
|
+
try {
|
|
139
|
+
const url = new URL(urlValue);
|
|
140
|
+
if (url.username || url.password || !isVisualEditOrigin(url.origin) || !isVisualEditOrigin(editorOrigin) || !session.safeParse(sessionId).success) return null;
|
|
141
|
+
url.hash = new URLSearchParams({ "rt-visual-edit": sessionId, origin: editorOrigin }).toString();
|
|
142
|
+
return url.href;
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/visual-edit-preview.ts
|
|
149
|
+
function createVisualEditMessage(envelope2, payload) {
|
|
150
|
+
return { protocol: VISUAL_EDIT_PROTOCOL, protocolVersion: VISUAL_EDIT_PROTOCOL_VERSION, ...envelope2, ...payload };
|
|
151
|
+
}
|
|
152
|
+
function isCurrentVisualEditMessage(message, expected) {
|
|
153
|
+
return message !== null && message.session === expected.session && message.sequence > expected.sequence && sameVisualPreviewTarget(message.target, expected.target);
|
|
154
|
+
}
|
|
155
|
+
function checkPreviewCompatibility(target, receipt, templateVersion) {
|
|
156
|
+
return receipt.schemaVersion === 1 && target.contractVersion === receipt.contractVersion && target.templateVersion === templateVersion && receipt.templateVersion === templateVersion;
|
|
157
|
+
}
|
|
158
|
+
function visualEditorOrigins(extra) {
|
|
159
|
+
const origins = /* @__PURE__ */ new Set(["https://admin.roottale.com"]);
|
|
160
|
+
for (const value of extra) {
|
|
161
|
+
try {
|
|
162
|
+
const url = new URL(value.trim());
|
|
163
|
+
if (isVisualEditOrigin(url.origin) && !url.username && !url.password && !url.hostname.includes("*")) {
|
|
164
|
+
origins.add(url.origin);
|
|
165
|
+
}
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return [...origins];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/content-values.ts
|
|
173
|
+
var import_zod2 = require("zod");
|
|
174
|
+
var itemIdSchema = import_zod2.z.string().uuid();
|
|
175
|
+
var forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
176
|
+
function isContentRecord(value) {
|
|
177
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
178
|
+
const prototype = Object.getPrototypeOf(value);
|
|
179
|
+
return prototype === Object.prototype || prototype === null;
|
|
180
|
+
}
|
|
181
|
+
function validatePath(path) {
|
|
182
|
+
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))) {
|
|
183
|
+
throw new Error("Content path must use safe property names and stable item IDs");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function findItemIndex(items, token) {
|
|
187
|
+
if (!token.startsWith("@") || !itemIdSchema.safeParse(token.slice(1)).success) {
|
|
188
|
+
throw new Error("Content repeater path requires @<uuid>");
|
|
189
|
+
}
|
|
190
|
+
const targetId = token.slice(1);
|
|
191
|
+
const seen = /* @__PURE__ */ new Set();
|
|
192
|
+
let selected = -1;
|
|
193
|
+
for (const [index, item] of items.entries()) {
|
|
194
|
+
if (!isContentRecord(item) || !Object.hasOwn(item, "_id")) throw new Error("Content repeater item has no stable ID");
|
|
195
|
+
const parsed = itemIdSchema.safeParse(item._id);
|
|
196
|
+
if (!parsed.success) throw new Error("Content repeater item has an invalid ID");
|
|
197
|
+
if (seen.has(parsed.data)) throw new Error("Content repeater item IDs are ambiguous");
|
|
198
|
+
seen.add(parsed.data);
|
|
199
|
+
if (parsed.data === targetId) selected = index;
|
|
200
|
+
}
|
|
201
|
+
if (selected < 0) throw new Error("Content repeater item was not found");
|
|
202
|
+
return selected;
|
|
203
|
+
}
|
|
204
|
+
function locateContentValue(values, path) {
|
|
205
|
+
validatePath(path);
|
|
206
|
+
if (!isContentRecord(values)) throw new Error("Content values must be a serialized object");
|
|
207
|
+
const frames = [];
|
|
208
|
+
let current = values;
|
|
209
|
+
for (const key of path) {
|
|
210
|
+
if (Array.isArray(current)) {
|
|
211
|
+
const index = findItemIndex(current, key);
|
|
212
|
+
frames.push({ kind: "array", parent: current, index, itemId: key.slice(1) });
|
|
213
|
+
current = current[index];
|
|
214
|
+
} else {
|
|
215
|
+
if (!isContentRecord(current) || key.startsWith("@") || !Object.hasOwn(current, key)) {
|
|
216
|
+
throw new Error("Content property was not found");
|
|
217
|
+
}
|
|
218
|
+
frames.push({ kind: "object", parent: current, key });
|
|
219
|
+
current = current[key];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return { value: current, frames };
|
|
223
|
+
}
|
|
224
|
+
function getContentValue(values, path) {
|
|
225
|
+
return locateContentValue(values, path).value;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/visual-edit-coverage.ts
|
|
229
|
+
function checkFieldPath(address, definitions, values) {
|
|
230
|
+
let fields = definitions;
|
|
231
|
+
let leaf;
|
|
232
|
+
let previous;
|
|
233
|
+
const ids = [];
|
|
234
|
+
const keys = [];
|
|
235
|
+
const path = [];
|
|
236
|
+
for (const segment of address.path ?? []) {
|
|
237
|
+
path.push(segment);
|
|
238
|
+
if (segment.startsWith("@")) {
|
|
239
|
+
if (leaf?.type !== "repeater" && leaf?.type !== "flexible_content" || previous?.startsWith("@")) {
|
|
240
|
+
throw new Error("\uD589 \uC8FC\uC18C\uB294 \uBC18\uBCF5 \uD544\uB4DC \uB2E4\uC74C\uC5D0 \uC640\uC57C \uD569\uB2C8\uB2E4.");
|
|
241
|
+
}
|
|
242
|
+
ids.push(segment.slice(1));
|
|
243
|
+
if (leaf.type === "flexible_content") {
|
|
244
|
+
const row = getContentValue(values, path);
|
|
245
|
+
const layout = row && typeof row === "object" && !Array.isArray(row) ? row.__layout : void 0;
|
|
246
|
+
const definition = leaf.layouts?.find((candidate) => candidate.name === layout);
|
|
247
|
+
if (!definition) throw new Error("\uBC18\uBCF5 \uD56D\uBAA9\uC758 \uB808\uC774\uC544\uC6C3\uC774 \uC815\uC758\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
248
|
+
fields = definition.subFields;
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
if ((leaf?.type === "repeater" || leaf?.type === "flexible_content") && !previous?.startsWith("@")) {
|
|
252
|
+
throw new Error("\uBC18\uBCF5 \uD544\uB4DC\uC5D0\uB294 \uD589 \uC8FC\uC18C\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
253
|
+
}
|
|
254
|
+
leaf = fields.find((field) => field.name === segment);
|
|
255
|
+
if (!leaf) throw new Error("\uD544\uB4DC \uACBD\uB85C\uAC00 \uC815\uC758\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
256
|
+
keys.push(leaf.key);
|
|
257
|
+
fields = leaf.subFields ?? [];
|
|
258
|
+
}
|
|
259
|
+
previous = segment;
|
|
260
|
+
}
|
|
261
|
+
if (leaf?.key !== address.fieldKey) throw new Error("\uD544\uB4DC key\uC640 \uC804\uCCB4 \uACBD\uB85C\uAC00 \uB2E4\uB985\uB2C8\uB2E4.");
|
|
262
|
+
if (address.itemId !== void 0 && address.itemId !== ids.at(-1)) {
|
|
263
|
+
throw new Error("itemId\uC640 \uB9C8\uC9C0\uB9C9 \uD589 \uC8FC\uC18C\uAC00 \uB2E4\uB985\uB2C8\uB2E4.");
|
|
264
|
+
}
|
|
265
|
+
return keys;
|
|
266
|
+
}
|
|
267
|
+
function coverageReport(contract, observations, exceptions) {
|
|
268
|
+
const report = {
|
|
269
|
+
missingFields: [],
|
|
270
|
+
invalidAddresses: [],
|
|
271
|
+
invalidSections: [],
|
|
272
|
+
invalidExceptions: [],
|
|
273
|
+
repeaterSegments: 0
|
|
274
|
+
};
|
|
275
|
+
const templates = new Map(contract.visualEditing.templates.map((template) => [template.key, template]));
|
|
276
|
+
const documents = new Map(observations.documents.map((document) => [document.id, document]));
|
|
277
|
+
const exceptionKeys = /* @__PURE__ */ new Set();
|
|
278
|
+
for (const exception of exceptions) {
|
|
279
|
+
const key = `${exception.templateKey}:${exception.fieldKey}`;
|
|
280
|
+
const template = templates.get(exception.templateKey);
|
|
281
|
+
if (exceptionKeys.has(key) || !exception.reason.trim() || !template?.sections.some((section) => section.fieldKeys.includes(exception.fieldKey))) {
|
|
282
|
+
report.invalidExceptions.push(key);
|
|
283
|
+
}
|
|
284
|
+
exceptionKeys.add(key);
|
|
285
|
+
}
|
|
286
|
+
for (const template of templates.values()) {
|
|
287
|
+
const rendered = new Set(observations.addresses.filter(
|
|
288
|
+
(address) => documents.get(address.entityId)?.templateKey === template.key
|
|
289
|
+
).map((address) => address.fieldKey));
|
|
290
|
+
for (const fieldKey of new Set(template.sections.flatMap((section) => [...section.fieldKeys]))) {
|
|
291
|
+
const key = `${template.key}:${fieldKey}`;
|
|
292
|
+
if (!rendered.has(fieldKey) && !exceptionKeys.has(key)) report.missingFields.push(key);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
for (const address of observations.addresses) {
|
|
296
|
+
try {
|
|
297
|
+
if (!parseVisualEditAddress(address)) throw new Error("\uD3B8\uC9D1 \uC8FC\uC18C \uD615\uC2DD\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
298
|
+
const document = documents.get(address.entityId);
|
|
299
|
+
if (!document) throw new Error("\uBB38\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
300
|
+
const fieldKeys = checkFieldPath(address, document.fieldDefinitions, document.fields);
|
|
301
|
+
if (!templates.get(document.templateKey)?.sections.some((section) => section.fieldKeys.some((key) => fieldKeys.includes(key)))) {
|
|
302
|
+
throw new Error("\uACC4\uC57D\uC5D0 \uC5C6\uB294 \uD3B8\uC9D1 \uD544\uB4DC\uC785\uB2C8\uB2E4.");
|
|
303
|
+
}
|
|
304
|
+
if (getContentValue(document.fields, address.path ?? []) === void 0) {
|
|
305
|
+
throw new Error("\uD544\uB4DC \uAC12\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
306
|
+
}
|
|
307
|
+
report.repeaterSegments += (address.path ?? []).filter((segment) => segment.startsWith("@")).length;
|
|
308
|
+
} catch (error) {
|
|
309
|
+
report.invalidAddresses.push({ address, reason: error instanceof Error ? error.message : "\uC8FC\uC18C \uAC80\uC0AC \uC2E4\uD328" });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
report.invalidSections = [...new Set(observations.sections.filter(
|
|
313
|
+
({ template, key }) => !templates.get(template)?.sections.some((section) => section.key === key)
|
|
314
|
+
).map(({ template, key }) => `${template}:${key}`))];
|
|
315
|
+
return report;
|
|
316
|
+
}
|
|
317
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
318
|
+
0 && (module.exports = {
|
|
319
|
+
VISUAL_EDIT_ATTRIBUTE,
|
|
320
|
+
VISUAL_EDIT_PROTOCOL,
|
|
321
|
+
VISUAL_EDIT_PROTOCOL_VERSION,
|
|
322
|
+
buildVisualEditPreviewUrl,
|
|
323
|
+
checkPreviewCompatibility,
|
|
324
|
+
coverageReport,
|
|
325
|
+
createVisualEditMessage,
|
|
326
|
+
isCurrentVisualEditMessage,
|
|
327
|
+
isVisualEditOrigin,
|
|
328
|
+
parseVisualEditAddress,
|
|
329
|
+
parseVisualEditMessage,
|
|
330
|
+
sameVisualDependencies,
|
|
331
|
+
sameVisualPreviewTarget,
|
|
332
|
+
visualEditAddressKey,
|
|
333
|
+
visualEditAddressSchema,
|
|
334
|
+
visualEditAttributes,
|
|
335
|
+
visualEditorOrigins,
|
|
336
|
+
visualPreviewTargetSchema,
|
|
337
|
+
visualRenderReceiptSchema
|
|
338
|
+
});
|
|
339
|
+
//# sourceMappingURL=visual-edit.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/visual-edit.ts","../src/visual-edit-contract.ts","../src/visual-edit-preview.ts","../src/content-values.ts","../src/visual-edit-coverage.ts"],"sourcesContent":["/** 브라우저에서 사용하는 실제화면 편집 계약. 서버 토큰·본문 변환을 가져오지 않는다. */\nexport * from \"./visual-edit-contract\";\nexport * from \"./visual-edit-preview\";\nexport * from \"./visual-edit-coverage\";\n","import { z } from \"zod\";\n\nexport const VISUAL_EDIT_PROTOCOL = \"roottale:visual-edit\";\nexport const VISUAL_EDIT_PROTOCOL_VERSION = 1;\nexport const VISUAL_EDIT_ATTRIBUTE = \"data-rt-edit\";\n\nconst identifier = z.string().min(1).max(160).refine(value => !/[\\u0000-\\u001f]/.test(value));\nconst safeKey = identifier.refine(value => ![\"__proto__\", \"prototype\", \"constructor\"].includes(value));\nconst pathKey = safeKey.refine(value => !/^\\d+$/.test(value), \"반복 항목은 순번 대신 itemId로 선택합니다.\");\nconst version = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);\nconst session = z.string().uuid();\nconst position = z.object({ left: z.number().finite().min(0).max(10_000_000), top: z.number().finite().min(0).max(10_000_000) }).strict();\nconst pathname = z.string().min(1).max(2000).refine(value => value.startsWith(\"/\") && !value.startsWith(\"//\") && !/[\\\\?#\\u0000-\\u001f]/.test(value));\n\n/** 필드 정의의 key와 저장 경로는 구분한다. 반복행의 영속 주소는 _id다. */\nexport const visualEditAddressSchema = z.object({\n entityId: identifier,\n fieldKey: safeKey,\n itemId: identifier.optional(),\n path: z.array(pathKey).max(16).optional(),\n}).strict().refine(address => {\n const selector = [...(address.path ?? [])].reverse().find(part => part.startsWith(\"@\"));\n return !selector || !address.itemId || selector.slice(1) === address.itemId;\n}, \"itemId는 경로의 마지막 반복 항목 ID와 같아야 합니다.\");\n\nexport const visualPreviewTargetSchema = z.object({\n entityId: identifier,\n draftId: identifier,\n draftVersion: version,\n contractVersion: identifier,\n templateVersion: identifier,\n}).strict();\n\nexport const visualRenderReceiptSchema = visualPreviewTargetSchema.extend({\n dependencyVersions: z.record(safeKey, identifier).refine(value => Object.keys(value).length <= 256),\n}).strict();\n\nexport type VisualEditAddress = z.infer<typeof visualEditAddressSchema>;\nexport type VisualPreviewTarget = z.infer<typeof visualPreviewTargetSchema>;\nexport type VisualRenderReceipt = z.infer<typeof visualRenderReceiptSchema>;\nexport type VisualViewportPosition = z.infer<typeof position>;\nexport type VisualEditMode = \"select\" | \"navigate\";\n\nconst envelope = {\n protocol: z.literal(VISUAL_EDIT_PROTOCOL),\n protocolVersion: z.literal(VISUAL_EDIT_PROTOCOL_VERSION),\n session,\n sequence: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),\n target: visualPreviewTargetSchema,\n};\n\nconst messageSchema = z.discriminatedUnion(\"type\", [\n z.object({ ...envelope, type: z.literal(\"connect\") }).strict(),\n z.object({ ...envelope, type: z.literal(\"ready\") }).strict(),\n z.object({ ...envelope, type: z.literal(\"select\"), address: visualEditAddressSchema, position: position.optional() }).strict(),\n z.object({ ...envelope, type: z.literal(\"focus\"), address: visualEditAddressSchema.optional(), position: position.optional() }).strict(),\n z.object({ ...envelope, type: z.literal(\"navigate\"), pathname }).strict(),\n z.object({ ...envelope, type: z.literal(\"mode\"), mode: z.enum([\"select\", \"navigate\"]) }).strict(),\n z.object({ ...envelope, type: z.literal(\"refresh\") }).strict(),\n z.object({ ...envelope, type: z.literal(\"viewport\"), position }).strict(),\n z.object({ ...envelope, type: z.literal(\"rendered\"), receipt: visualRenderReceiptSchema }).strict(),\n z.object({ ...envelope, type: z.literal(\"error\"), code: z.enum([\"unavailable\", \"superseded\", \"unsupported_contract\", \"expired\"]), message: z.string().max(500).optional() }).strict(),\n]);\n\nexport type VisualEditMessage = z.infer<typeof messageSchema>;\nexport type VisualEditPayload = VisualEditMessage extends infer Message\n ? Message extends VisualEditMessage ? Omit<Message, keyof typeof envelope> : never : never;\n\nexport function parseVisualEditAddress(value: unknown): VisualEditAddress | null {\n const result = visualEditAddressSchema.safeParse(value);\n return result.success ? result.data : null;\n}\n\nexport function parseVisualEditMessage(value: unknown): VisualEditMessage | null {\n try {\n if (JSON.stringify(value).length > 64_000) return null;\n const result = messageSchema.safeParse(value);\n if (!result.success) return null;\n const message = result.data;\n if (message.type === \"rendered\" && !sameVisualPreviewTarget(message.target, message.receipt)) return null;\n if (message.type === \"focus\" && message.address && message.address.entityId !== message.target.entityId) return null;\n return message;\n } catch { return null; }\n}\n\nexport function sameVisualPreviewTarget(a: VisualPreviewTarget, b: VisualPreviewTarget): boolean {\n return a.entityId === b.entityId && a.draftId === b.draftId && a.draftVersion === b.draftVersion\n && a.contractVersion === b.contractVersion && a.templateVersion === b.templateVersion;\n}\n\nexport function sameVisualDependencies(a: Record<string, string>, b: Record<string, string>): boolean {\n const keys = Object.keys(a);\n return keys.length === Object.keys(b).length && keys.every(key => Object.hasOwn(b, key) && a[key] === b[key]);\n}\n\nexport function visualEditAddressKey(address: VisualEditAddress): string {\n const path = address.path ?? [];\n // 중첩 반복행은 경로가 정본이다. itemId는 사이트가 생략할 수 있는 보조값이다.\n const itemId = [...path].reverse().find(part => part.startsWith(\"@\"))?.slice(1) ?? address.itemId ?? null;\n return JSON.stringify([address.entityId, address.fieldKey, itemId, path]);\n}\n\n/** 미리보기에서만 사용한다. RSC에서도 호출하는 순수 속성 생성 함수다. */\nexport function visualEditAttributes(address: VisualEditAddress, enabled = true): { \"data-rt-edit\"?: string } {\n const parsed = enabled ? parseVisualEditAddress(address) : null;\n return parsed ? { [VISUAL_EDIT_ATTRIBUTE]: JSON.stringify(parsed) } : {};\n}\n\nexport function isVisualEditOrigin(value: string): boolean {\n try {\n const url = new URL(value);\n const local = [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname);\n return value === url.origin && (url.protocol === \"https:\" || (local && url.protocol === \"http:\"));\n } catch { return false; }\n}\n\n/** 내용·권한은 기존 서버 snapshot 경로가 소유한다. fragment에는 연결 식별자만 싣는다. */\nexport function buildVisualEditPreviewUrl(urlValue: string, editorOrigin: string, sessionId: string): string | null {\n try {\n const url = new URL(urlValue);\n if (url.username || url.password || !isVisualEditOrigin(url.origin) || !isVisualEditOrigin(editorOrigin) || !session.safeParse(sessionId).success) return null;\n url.hash = new URLSearchParams({ \"rt-visual-edit\": sessionId, origin: editorOrigin }).toString();\n return url.href;\n } catch { return null; }\n}\n","import {\n isVisualEditOrigin, sameVisualPreviewTarget, VISUAL_EDIT_PROTOCOL, VISUAL_EDIT_PROTOCOL_VERSION,\n type VisualEditMessage, type VisualEditPayload, type VisualPreviewTarget,\n} from \"./visual-edit-contract\";\n\nexport type VisualEditEnvelope = Pick<VisualEditMessage, \"session\" | \"sequence\" | \"target\">;\nexport interface VisualPreviewRuntimeReceipt {\n schemaVersion: number;\n contractVersion: string;\n templateVersion: string;\n}\n\n/** sequence의 증가와 연결 수명은 호출자가 소유한다. wire 형식은 그대로 조립한다. */\nexport function createVisualEditMessage(envelope: VisualEditEnvelope, payload: VisualEditPayload): VisualEditMessage {\n return { protocol: VISUAL_EDIT_PROTOCOL, protocolVersion: VISUAL_EDIT_PROTOCOL_VERSION, ...envelope, ...payload };\n}\n\n/** 파싱한 메시지를 비교한다. source·origin 확인과 수신 sequence 갱신은 호출자 책임이다. */\nexport function isCurrentVisualEditMessage(message: VisualEditMessage | null, expected: VisualEditEnvelope): message is VisualEditMessage {\n return message !== null && message.session === expected.session && message.sequence > expected.sequence\n && sameVisualPreviewTarget(message.target, expected.target);\n}\n\n/** 인증된 target과 사이트에 배포한 계약 영수증·템플릿을 대조한다. */\nexport function checkPreviewCompatibility(target: VisualPreviewTarget, receipt: VisualPreviewRuntimeReceipt, templateVersion: string): boolean {\n return receipt.schemaVersion === 1 && target.contractVersion === receipt.contractVersion\n && target.templateVersion === templateVersion && receipt.templateVersion === templateVersion;\n}\n\n/** env는 사이트가 읽는다. CSP와 브리지에 같은 정규화 목록을 전달한다. */\nexport function visualEditorOrigins(extra: readonly string[]): string[] {\n const origins = new Set([\"https://admin.roottale.com\"]);\n for (const value of extra) {\n try {\n const url = new URL(value.trim());\n if (isVisualEditOrigin(url.origin) && !url.username && !url.password && !url.hostname.includes(\"*\")) {\n origins.add(url.origin);\n }\n } catch {\n // 빈 값·와일드카드·잘못된 URL은 허용 목록에 넣지 않는다.\n }\n }\n return [...origins];\n}\n","import { z } from \"zod\";\n\nconst itemIdSchema = z.string().uuid();\nconst forbiddenKeys = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\ntype PathFrame =\n | { readonly kind: \"object\"; readonly parent: Record<string, unknown>; readonly key: string }\n | { readonly kind: \"array\"; readonly parent: readonly unknown[]; readonly index: number; readonly itemId: string };\n\nfunction isContentRecord(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n const prototype: unknown = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction validatePath(path: readonly string[]): void {\n if (!Array.isArray(path) || !path.length || path.some((key) => typeof key !== \"string\" || !key\n || forbiddenKeys.has(key) || /^\\d+$/u.test(key) || /[\\u0000-\\u001f]/u.test(key))) {\n throw new Error(\"Content path must use safe property names and stable item IDs\");\n }\n}\n\nfunction findItemIndex(items: readonly unknown[], token: string): number {\n if (!token.startsWith(\"@\") || !itemIdSchema.safeParse(token.slice(1)).success) {\n throw new Error(\"Content repeater path requires @<uuid>\");\n }\n const targetId = token.slice(1);\n const seen = new Set<string>();\n let selected = -1;\n for (const [index, item] of items.entries()) {\n if (!isContentRecord(item) || !Object.hasOwn(item, \"_id\")) throw new Error(\"Content repeater item has no stable ID\");\n const parsed = itemIdSchema.safeParse(item._id);\n if (!parsed.success) throw new Error(\"Content repeater item has an invalid ID\");\n if (seen.has(parsed.data)) throw new Error(\"Content repeater item IDs are ambiguous\");\n seen.add(parsed.data);\n if (parsed.data === targetId) selected = index;\n }\n if (selected < 0) throw new Error(\"Content repeater item was not found\");\n return selected;\n}\n\nfunction locateContentValue(values: Readonly<Record<string, unknown>>, path: readonly string[]): {\n readonly value: unknown; readonly frames: readonly PathFrame[];\n} {\n validatePath(path);\n if (!isContentRecord(values)) throw new Error(\"Content values must be a serialized object\");\n const frames: PathFrame[] = [];\n let current: unknown = values;\n for (const key of path) {\n if (Array.isArray(current)) {\n const index = findItemIndex(current, key);\n frames.push({ kind: \"array\", parent: current, index, itemId: key.slice(1) });\n current = current[index];\n } else {\n if (!isContentRecord(current) || key.startsWith(\"@\") || !Object.hasOwn(current, key)) {\n throw new Error(\"Content property was not found\");\n }\n frames.push({ kind: \"object\", parent: current, key });\n current = current[key];\n }\n }\n return { value: current, frames };\n}\n\n/**\n * Paths start at the serialized ACF root. Each array traversal requires @<uuid>.\n * Unknown properties and repeaters with missing or duplicate IDs throw; no defaults are invented.\n */\nexport function getContentValue(values: Readonly<Record<string, unknown>>, path: readonly string[]): unknown {\n return locateContentValue(values, path).value;\n}\n\n/**\n * Clone only the changed branch and preserve stable IDs. Whole-array replacement is allowed.\n * Leaf permissions and all replacement-value validation belong to the compiled content contract.\n */\nexport function setContentValue(\n values: Readonly<Record<string, unknown>>, path: readonly string[], value: unknown,\n): Record<string, unknown> {\n const { frames } = locateContentValue(values, path);\n const leaf = frames[frames.length - 1]!;\n if ((leaf.kind === \"object\" && leaf.key === \"_id\") || (leaf.kind === \"array\"\n && (!isContentRecord(value) || !Object.hasOwn(value, \"_id\") || value._id !== leaf.itemId))) {\n throw new Error(\"Content edits must preserve stable item IDs\");\n }\n let patched: unknown = value;\n for (let index = frames.length - 1; index >= 0; index--) {\n const frame = frames[index]!;\n if (frame.kind === \"array\") {\n const items = [...frame.parent];\n items[frame.index] = patched;\n patched = items;\n } else {\n patched = { ...frame.parent, [frame.key]: patched };\n }\n }\n return patched as Record<string, unknown>;\n}\n","import { getContentValue } from \"./content-values\";\nimport { parseVisualEditAddress, type VisualEditAddress } from \"./visual-edit-contract\";\n\n/** 실제 계약과 필드 정의에서 비교에 필요한 부분만 받는다. */\nexport interface CoverageContract {\n visualEditing: { templates: readonly {\n key: string;\n sections: readonly { key: string; fieldKeys: readonly string[] }[];\n }[] };\n}\n\nexport interface CoverageFieldDefinition {\n key: string;\n name: string;\n type: string;\n subFields?: readonly CoverageFieldDefinition[];\n layouts?: readonly { name: string; subFields: readonly CoverageFieldDefinition[] }[];\n}\n\nexport interface CoverageException {\n templateKey: string;\n fieldKey: string;\n reason: string;\n}\n\nexport interface CoverageObservations {\n documents: readonly {\n id: string;\n templateKey: string;\n fields: Readonly<Record<string, unknown>>;\n fieldDefinitions: readonly CoverageFieldDefinition[];\n }[];\n addresses: readonly VisualEditAddress[];\n sections: readonly { template: string; key: string }[];\n}\n\nexport interface CoverageReport {\n missingFields: string[];\n invalidAddresses: { address: VisualEditAddress; reason: string }[];\n invalidSections: string[];\n invalidExceptions: string[];\n repeaterSegments: number;\n}\n\nfunction checkFieldPath(address: VisualEditAddress, definitions: readonly CoverageFieldDefinition[], values: Readonly<Record<string, unknown>>): string[] {\n let fields = definitions;\n let leaf: CoverageFieldDefinition | undefined;\n let previous: string | undefined;\n const ids: string[] = [];\n const keys: string[] = [];\n const path: string[] = [];\n for (const segment of address.path ?? []) {\n path.push(segment);\n if (segment.startsWith(\"@\")) {\n if ((leaf?.type !== \"repeater\" && leaf?.type !== \"flexible_content\") || previous?.startsWith(\"@\")) {\n throw new Error(\"행 주소는 반복 필드 다음에 와야 합니다.\");\n }\n ids.push(segment.slice(1));\n if (leaf.type === \"flexible_content\") {\n const row = getContentValue(values, path);\n const layout = row && typeof row === \"object\" && !Array.isArray(row)\n ? (row as Record<string, unknown>).__layout : undefined;\n const definition = leaf.layouts?.find(candidate => candidate.name === layout);\n if (!definition) throw new Error(\"반복 항목의 레이아웃이 정의에 없습니다.\");\n fields = definition.subFields;\n }\n } else {\n // 반복 필드는 반드시 @id를 거쳐 자식 필드로 내려간다.\n if ((leaf?.type === \"repeater\" || leaf?.type === \"flexible_content\") && !previous?.startsWith(\"@\")) {\n throw new Error(\"반복 필드에는 행 주소가 필요합니다.\");\n }\n leaf = fields.find(field => field.name === segment);\n if (!leaf) throw new Error(\"필드 경로가 정의에 없습니다.\");\n keys.push(leaf.key);\n fields = leaf.subFields ?? [];\n }\n previous = segment;\n }\n if (leaf?.key !== address.fieldKey) throw new Error(\"필드 key와 전체 경로가 다릅니다.\");\n if (address.itemId !== undefined && address.itemId !== ids.at(-1)) {\n throw new Error(\"itemId와 마지막 행 주소가 다릅니다.\");\n }\n return keys;\n}\n\n/**\n * ① 계약 → 렌더 필드, ② 전체 주소·섹션 → 계약을 비교한다.\n * 렌더·fixture 생성·예외 선정·③ 클릭 도달 검사는 호출 사이트가 소유한다.\n * 예외는 미연결 필드에만 적용하며 잘못된 주소·섹션을 숨기지 않는다.\n */\nexport function coverageReport(\n contract: CoverageContract,\n observations: CoverageObservations,\n exceptions: readonly CoverageException[],\n): CoverageReport {\n const report: CoverageReport = {\n missingFields: [], invalidAddresses: [], invalidSections: [], invalidExceptions: [], repeaterSegments: 0,\n };\n const templates = new Map(contract.visualEditing.templates.map(template => [template.key, template]));\n const documents = new Map(observations.documents.map(document => [document.id, document]));\n const exceptionKeys = new Set<string>();\n for (const exception of exceptions) {\n const key = `${exception.templateKey}:${exception.fieldKey}`;\n const template = templates.get(exception.templateKey);\n if (exceptionKeys.has(key) || !exception.reason.trim()\n || !template?.sections.some(section => section.fieldKeys.includes(exception.fieldKey))) {\n report.invalidExceptions.push(key);\n }\n exceptionKeys.add(key);\n }\n for (const template of templates.values()) {\n const rendered = new Set(observations.addresses.filter(address =>\n documents.get(address.entityId)?.templateKey === template.key,\n ).map(address => address.fieldKey));\n for (const fieldKey of new Set(template.sections.flatMap(section => [...section.fieldKeys]))) {\n const key = `${template.key}:${fieldKey}`;\n if (!rendered.has(fieldKey) && !exceptionKeys.has(key)) report.missingFields.push(key);\n }\n }\n for (const address of observations.addresses) {\n try {\n if (!parseVisualEditAddress(address)) throw new Error(\"편집 주소 형식이 잘못되었습니다.\");\n const document = documents.get(address.entityId);\n if (!document) throw new Error(\"문서를 찾을 수 없습니다.\");\n const fieldKeys = checkFieldPath(address, document.fieldDefinitions, document.fields);\n if (!templates.get(document.templateKey)?.sections.some(section => section.fieldKeys.some(key => fieldKeys.includes(key)))) {\n throw new Error(\"계약에 없는 편집 필드입니다.\");\n }\n if (getContentValue(document.fields, address.path ?? []) === undefined) {\n throw new Error(\"필드 값이 없습니다.\");\n }\n report.repeaterSegments += (address.path ?? []).filter(segment => segment.startsWith(\"@\")).length;\n } catch (error) {\n report.invalidAddresses.push({ address, reason: error instanceof Error ? error.message : \"주소 검사 실패\" });\n }\n }\n report.invalidSections = [...new Set(observations.sections.filter(({ template, key }) =>\n !templates.get(template)?.sections.some(section => section.key === key),\n ).map(({ template, key }) => `${template}:${key}`))];\n return report;\n}\n"],"mappings":"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","names":["envelope","import_zod"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { d as VisualEditMessage, g as VisualPreviewTarget, f as VisualEditPayload, c as VisualEditAddress } from './visual-edit-contract-DzlMel7r.cjs';
|
|
2
|
+
export { V as VISUAL_EDIT_ATTRIBUTE, a as VISUAL_EDIT_PROTOCOL, b as VISUAL_EDIT_PROTOCOL_VERSION, e as VisualEditMode, h as VisualRenderReceipt, i as VisualViewportPosition, j as buildVisualEditPreviewUrl, k as isVisualEditOrigin, p as parseVisualEditAddress, l as parseVisualEditMessage, s as sameVisualDependencies, m as sameVisualPreviewTarget, v as visualEditAddressKey, n as visualEditAddressSchema, o as visualEditAttributes, q as visualPreviewTargetSchema, r as visualRenderReceiptSchema } from './visual-edit-contract-DzlMel7r.cjs';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
type VisualEditEnvelope = Pick<VisualEditMessage, "session" | "sequence" | "target">;
|
|
6
|
+
interface VisualPreviewRuntimeReceipt {
|
|
7
|
+
schemaVersion: number;
|
|
8
|
+
contractVersion: string;
|
|
9
|
+
templateVersion: string;
|
|
10
|
+
}
|
|
11
|
+
/** sequence의 증가와 연결 수명은 호출자가 소유한다. wire 형식은 그대로 조립한다. */
|
|
12
|
+
declare function createVisualEditMessage(envelope: VisualEditEnvelope, payload: VisualEditPayload): VisualEditMessage;
|
|
13
|
+
/** 파싱한 메시지를 비교한다. source·origin 확인과 수신 sequence 갱신은 호출자 책임이다. */
|
|
14
|
+
declare function isCurrentVisualEditMessage(message: VisualEditMessage | null, expected: VisualEditEnvelope): message is VisualEditMessage;
|
|
15
|
+
/** 인증된 target과 사이트에 배포한 계약 영수증·템플릿을 대조한다. */
|
|
16
|
+
declare function checkPreviewCompatibility(target: VisualPreviewTarget, receipt: VisualPreviewRuntimeReceipt, templateVersion: string): boolean;
|
|
17
|
+
/** env는 사이트가 읽는다. CSP와 브리지에 같은 정규화 목록을 전달한다. */
|
|
18
|
+
declare function visualEditorOrigins(extra: readonly string[]): string[];
|
|
19
|
+
|
|
20
|
+
/** 실제 계약과 필드 정의에서 비교에 필요한 부분만 받는다. */
|
|
21
|
+
interface CoverageContract {
|
|
22
|
+
visualEditing: {
|
|
23
|
+
templates: readonly {
|
|
24
|
+
key: string;
|
|
25
|
+
sections: readonly {
|
|
26
|
+
key: string;
|
|
27
|
+
fieldKeys: readonly string[];
|
|
28
|
+
}[];
|
|
29
|
+
}[];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
interface CoverageFieldDefinition {
|
|
33
|
+
key: string;
|
|
34
|
+
name: string;
|
|
35
|
+
type: string;
|
|
36
|
+
subFields?: readonly CoverageFieldDefinition[];
|
|
37
|
+
layouts?: readonly {
|
|
38
|
+
name: string;
|
|
39
|
+
subFields: readonly CoverageFieldDefinition[];
|
|
40
|
+
}[];
|
|
41
|
+
}
|
|
42
|
+
interface CoverageException {
|
|
43
|
+
templateKey: string;
|
|
44
|
+
fieldKey: string;
|
|
45
|
+
reason: string;
|
|
46
|
+
}
|
|
47
|
+
interface CoverageObservations {
|
|
48
|
+
documents: readonly {
|
|
49
|
+
id: string;
|
|
50
|
+
templateKey: string;
|
|
51
|
+
fields: Readonly<Record<string, unknown>>;
|
|
52
|
+
fieldDefinitions: readonly CoverageFieldDefinition[];
|
|
53
|
+
}[];
|
|
54
|
+
addresses: readonly VisualEditAddress[];
|
|
55
|
+
sections: readonly {
|
|
56
|
+
template: string;
|
|
57
|
+
key: string;
|
|
58
|
+
}[];
|
|
59
|
+
}
|
|
60
|
+
interface CoverageReport {
|
|
61
|
+
missingFields: string[];
|
|
62
|
+
invalidAddresses: {
|
|
63
|
+
address: VisualEditAddress;
|
|
64
|
+
reason: string;
|
|
65
|
+
}[];
|
|
66
|
+
invalidSections: string[];
|
|
67
|
+
invalidExceptions: string[];
|
|
68
|
+
repeaterSegments: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* ① 계약 → 렌더 필드, ② 전체 주소·섹션 → 계약을 비교한다.
|
|
72
|
+
* 렌더·fixture 생성·예외 선정·③ 클릭 도달 검사는 호출 사이트가 소유한다.
|
|
73
|
+
* 예외는 미연결 필드에만 적용하며 잘못된 주소·섹션을 숨기지 않는다.
|
|
74
|
+
*/
|
|
75
|
+
declare function coverageReport(contract: CoverageContract, observations: CoverageObservations, exceptions: readonly CoverageException[]): CoverageReport;
|
|
76
|
+
|
|
77
|
+
export { type CoverageContract, type CoverageException, type CoverageFieldDefinition, type CoverageObservations, type CoverageReport, VisualEditAddress, type VisualEditEnvelope, VisualEditMessage, VisualEditPayload, type VisualPreviewRuntimeReceipt, VisualPreviewTarget, checkPreviewCompatibility, coverageReport, createVisualEditMessage, isCurrentVisualEditMessage, visualEditorOrigins };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { d as VisualEditMessage, g as VisualPreviewTarget, f as VisualEditPayload, c as VisualEditAddress } from './visual-edit-contract-DzlMel7r.js';
|
|
2
|
+
export { V as VISUAL_EDIT_ATTRIBUTE, a as VISUAL_EDIT_PROTOCOL, b as VISUAL_EDIT_PROTOCOL_VERSION, e as VisualEditMode, h as VisualRenderReceipt, i as VisualViewportPosition, j as buildVisualEditPreviewUrl, k as isVisualEditOrigin, p as parseVisualEditAddress, l as parseVisualEditMessage, s as sameVisualDependencies, m as sameVisualPreviewTarget, v as visualEditAddressKey, n as visualEditAddressSchema, o as visualEditAttributes, q as visualPreviewTargetSchema, r as visualRenderReceiptSchema } from './visual-edit-contract-DzlMel7r.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
type VisualEditEnvelope = Pick<VisualEditMessage, "session" | "sequence" | "target">;
|
|
6
|
+
interface VisualPreviewRuntimeReceipt {
|
|
7
|
+
schemaVersion: number;
|
|
8
|
+
contractVersion: string;
|
|
9
|
+
templateVersion: string;
|
|
10
|
+
}
|
|
11
|
+
/** sequence의 증가와 연결 수명은 호출자가 소유한다. wire 형식은 그대로 조립한다. */
|
|
12
|
+
declare function createVisualEditMessage(envelope: VisualEditEnvelope, payload: VisualEditPayload): VisualEditMessage;
|
|
13
|
+
/** 파싱한 메시지를 비교한다. source·origin 확인과 수신 sequence 갱신은 호출자 책임이다. */
|
|
14
|
+
declare function isCurrentVisualEditMessage(message: VisualEditMessage | null, expected: VisualEditEnvelope): message is VisualEditMessage;
|
|
15
|
+
/** 인증된 target과 사이트에 배포한 계약 영수증·템플릿을 대조한다. */
|
|
16
|
+
declare function checkPreviewCompatibility(target: VisualPreviewTarget, receipt: VisualPreviewRuntimeReceipt, templateVersion: string): boolean;
|
|
17
|
+
/** env는 사이트가 읽는다. CSP와 브리지에 같은 정규화 목록을 전달한다. */
|
|
18
|
+
declare function visualEditorOrigins(extra: readonly string[]): string[];
|
|
19
|
+
|
|
20
|
+
/** 실제 계약과 필드 정의에서 비교에 필요한 부분만 받는다. */
|
|
21
|
+
interface CoverageContract {
|
|
22
|
+
visualEditing: {
|
|
23
|
+
templates: readonly {
|
|
24
|
+
key: string;
|
|
25
|
+
sections: readonly {
|
|
26
|
+
key: string;
|
|
27
|
+
fieldKeys: readonly string[];
|
|
28
|
+
}[];
|
|
29
|
+
}[];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
interface CoverageFieldDefinition {
|
|
33
|
+
key: string;
|
|
34
|
+
name: string;
|
|
35
|
+
type: string;
|
|
36
|
+
subFields?: readonly CoverageFieldDefinition[];
|
|
37
|
+
layouts?: readonly {
|
|
38
|
+
name: string;
|
|
39
|
+
subFields: readonly CoverageFieldDefinition[];
|
|
40
|
+
}[];
|
|
41
|
+
}
|
|
42
|
+
interface CoverageException {
|
|
43
|
+
templateKey: string;
|
|
44
|
+
fieldKey: string;
|
|
45
|
+
reason: string;
|
|
46
|
+
}
|
|
47
|
+
interface CoverageObservations {
|
|
48
|
+
documents: readonly {
|
|
49
|
+
id: string;
|
|
50
|
+
templateKey: string;
|
|
51
|
+
fields: Readonly<Record<string, unknown>>;
|
|
52
|
+
fieldDefinitions: readonly CoverageFieldDefinition[];
|
|
53
|
+
}[];
|
|
54
|
+
addresses: readonly VisualEditAddress[];
|
|
55
|
+
sections: readonly {
|
|
56
|
+
template: string;
|
|
57
|
+
key: string;
|
|
58
|
+
}[];
|
|
59
|
+
}
|
|
60
|
+
interface CoverageReport {
|
|
61
|
+
missingFields: string[];
|
|
62
|
+
invalidAddresses: {
|
|
63
|
+
address: VisualEditAddress;
|
|
64
|
+
reason: string;
|
|
65
|
+
}[];
|
|
66
|
+
invalidSections: string[];
|
|
67
|
+
invalidExceptions: string[];
|
|
68
|
+
repeaterSegments: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* ① 계약 → 렌더 필드, ② 전체 주소·섹션 → 계약을 비교한다.
|
|
72
|
+
* 렌더·fixture 생성·예외 선정·③ 클릭 도달 검사는 호출 사이트가 소유한다.
|
|
73
|
+
* 예외는 미연결 필드에만 적용하며 잘못된 주소·섹션을 숨기지 않는다.
|
|
74
|
+
*/
|
|
75
|
+
declare function coverageReport(contract: CoverageContract, observations: CoverageObservations, exceptions: readonly CoverageException[]): CoverageReport;
|
|
76
|
+
|
|
77
|
+
export { type CoverageContract, type CoverageException, type CoverageFieldDefinition, type CoverageObservations, type CoverageReport, VisualEditAddress, type VisualEditEnvelope, VisualEditMessage, VisualEditPayload, type VisualPreviewRuntimeReceipt, VisualPreviewTarget, checkPreviewCompatibility, coverageReport, createVisualEditMessage, isCurrentVisualEditMessage, visualEditorOrigins };
|