@beyondwork/docx-react-component 1.0.42 → 1.0.45
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/README.md +17 -0
- package/package.json +5 -4
- package/src/api/editor-state-types.ts +110 -0
- package/src/api/public-types.ts +333 -4
- package/src/core/commands/formatting-commands.ts +7 -1
- package/src/core/commands/index.ts +60 -10
- package/src/core/commands/text-commands.ts +59 -0
- package/src/core/search/search-text.ts +15 -2
- package/src/core/selection/review-anchors.ts +131 -21
- package/src/index.ts +29 -1
- package/src/io/chart-preview-resolver.ts +281 -0
- package/src/io/docx-session.ts +692 -2
- package/src/io/export/build-app-properties-xml.ts +1 -1
- package/src/io/export/serialize-comments.ts +38 -9
- package/src/io/export/twip.ts +1 -1
- package/src/io/load-scheduler.ts +230 -0
- package/src/io/normalize/normalize-text.ts +116 -0
- package/src/io/ooxml/parse-comments.ts +0 -33
- package/src/io/ooxml/parse-complex-content.ts +14 -0
- package/src/io/ooxml/parse-main-document.ts +4 -0
- package/src/io/ooxml/workflow-payload-validator.ts +97 -1
- package/src/io/ooxml/workflow-payload.ts +172 -1
- package/src/preservation/opaque-region.ts +5 -0
- package/src/review/store/comment-remapping.ts +2 -2
- package/src/runtime/collab-session.ts +1 -1
- package/src/runtime/document-runtime.ts +661 -42
- package/src/runtime/edit-dispatch/dispatch-text-command.ts +98 -0
- package/src/runtime/edit-dispatch/index.ts +2 -0
- package/src/runtime/edit-dispatch/list-aware-dispatch.ts +125 -0
- package/src/runtime/editor-state-channel.ts +544 -0
- package/src/runtime/editor-state-integration.ts +217 -0
- package/src/runtime/editor-surface/capabilities.ts +411 -0
- package/src/runtime/layout/index.ts +2 -0
- package/src/runtime/layout/inert-layout-facet.ts +4 -0
- package/src/runtime/layout/layout-engine-instance.ts +63 -2
- package/src/runtime/layout/layout-engine-version.ts +41 -0
- package/src/runtime/layout/paginated-layout-engine.ts +211 -14
- package/src/runtime/layout/public-facet.ts +430 -1
- package/src/runtime/perf-counters.ts +28 -0
- package/src/runtime/prerender/cache-envelope.ts +29 -0
- package/src/runtime/prerender/cache-key.ts +66 -0
- package/src/runtime/prerender/font-fingerprint.ts +17 -0
- package/src/runtime/prerender/graph-canonicalize.ts +121 -0
- package/src/runtime/prerender/indexeddb-cache.ts +184 -0
- package/src/runtime/prerender/prerender-document.ts +145 -0
- package/src/runtime/render/block-fragment-projection.ts +2 -0
- package/src/runtime/render/render-frame-types.ts +17 -0
- package/src/runtime/render/render-kernel.ts +172 -29
- package/src/runtime/selection/post-edit-validator.ts +77 -0
- package/src/runtime/surface-projection.ts +45 -7
- package/src/runtime/workflow-markup.ts +71 -16
- package/src/ui/WordReviewEditor.tsx +142 -237
- package/src/ui/editor-command-bag.ts +14 -0
- package/src/ui/editor-runtime-boundary.ts +115 -12
- package/src/ui/editor-shell-view.tsx +10 -0
- package/src/ui/editor-surface-controller.tsx +5 -0
- package/src/ui/headless/selection-helpers.ts +10 -0
- package/src/ui/runtime-shortcut-dispatch.ts +28 -68
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +62 -2
- package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +281 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +48 -0
- package/src/ui-tailwind/editor-surface/paste-plain-text.ts +72 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +118 -8
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +76 -165
- package/src/ui-tailwind/editor-surface/pm-schema.ts +170 -4
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +58 -7
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +265 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +8 -255
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +47 -0
- package/src/ui-tailwind/index.ts +5 -1
- package/src/ui-tailwind/page-stack/tw-endnote-area.tsx +57 -0
- package/src/ui-tailwind/page-stack/tw-footnote-area.tsx +71 -0
- package/src/ui-tailwind/page-stack/tw-page-footer-band.tsx +73 -0
- package/src/ui-tailwind/page-stack/tw-page-header-band.tsx +74 -0
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +477 -0
- package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +374 -0
- package/src/ui-tailwind/page-stack/use-visible-block-range.ts +157 -0
- package/src/ui-tailwind/review/comment-markdown-renderer.tsx +155 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +77 -16
- package/src/ui-tailwind/theme/editor-theme.css +47 -14
- package/src/ui-tailwind/tw-review-workspace.tsx +303 -123
|
@@ -19,7 +19,14 @@ export type ValidatorIssueCode =
|
|
|
19
19
|
| "external_field_body_ignored"
|
|
20
20
|
| "internal_entry_unexpected_storage_ref"
|
|
21
21
|
| "internal_field_unexpected_storage_ref"
|
|
22
|
-
| "unsupported_version"
|
|
22
|
+
| "unsupported_version"
|
|
23
|
+
// Schema 1.2 editor-state codes
|
|
24
|
+
| "editor_state_unknown_namespace"
|
|
25
|
+
| "editor_state_duplicate_content"
|
|
26
|
+
| "editor_state_empty_content"
|
|
27
|
+
| "editor_state_invalid_inline_json"
|
|
28
|
+
| "editor_state_missing_entry_key"
|
|
29
|
+
| "editor_state_invalid_location";
|
|
23
30
|
|
|
24
31
|
export type ValidatorIssueSeverity = "error" | "warning";
|
|
25
32
|
|
|
@@ -145,6 +152,95 @@ export function validateWorkflowPayloadEnvelope(xml: string): ValidatorIssue[] {
|
|
|
145
152
|
}
|
|
146
153
|
}
|
|
147
154
|
|
|
155
|
+
// Schema 1.2: <bw:editorState> checks.
|
|
156
|
+
const editorStateMatch = xml.match(/<bw:editorState\b[^>]*>([\s\S]*?)<\/bw:editorState>/u);
|
|
157
|
+
if (editorStateMatch) {
|
|
158
|
+
const editorStateBody = editorStateMatch[1] ?? "";
|
|
159
|
+
const nsRe = /<bw:namespace\b([^>]*)>([\s\S]*?)<\/bw:namespace>/gu;
|
|
160
|
+
for (const nsMatch of editorStateBody.matchAll(nsRe)) {
|
|
161
|
+
const attrsStr = nsMatch[1] ?? "";
|
|
162
|
+
const nsBody = nsMatch[2] ?? "";
|
|
163
|
+
const attrs = parseAttrs(attrsStr);
|
|
164
|
+
const name = attrs.name ?? "";
|
|
165
|
+
const nsPath = `bw:editorState/bw:namespace[@name='${name}']`;
|
|
166
|
+
|
|
167
|
+
// 1. Unknown namespace name (not in closed set) → warning.
|
|
168
|
+
const knownNames = ["hostAnnotations", "workflowOverlay", "workflowMetadata", "workItems"];
|
|
169
|
+
if (!knownNames.includes(name)) {
|
|
170
|
+
issues.push({
|
|
171
|
+
code: "editor_state_unknown_namespace",
|
|
172
|
+
path: nsPath,
|
|
173
|
+
severity: "warning",
|
|
174
|
+
value: name,
|
|
175
|
+
});
|
|
176
|
+
// Still check structural rules below for forward-compat awareness.
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 2. Detect presence of storageRef and inline.
|
|
180
|
+
const hasStorageRef = /<bw:storageRef\b/u.test(nsBody);
|
|
181
|
+
const hasInline = /<bw:inline\b/u.test(nsBody);
|
|
182
|
+
|
|
183
|
+
if (hasStorageRef && hasInline) {
|
|
184
|
+
// Both present → duplicate_content error.
|
|
185
|
+
issues.push({
|
|
186
|
+
code: "editor_state_duplicate_content",
|
|
187
|
+
path: nsPath,
|
|
188
|
+
severity: "error",
|
|
189
|
+
});
|
|
190
|
+
} else if (!hasStorageRef && !hasInline) {
|
|
191
|
+
// Neither present → empty_content error.
|
|
192
|
+
issues.push({
|
|
193
|
+
code: "editor_state_empty_content",
|
|
194
|
+
path: nsPath,
|
|
195
|
+
severity: "error",
|
|
196
|
+
});
|
|
197
|
+
} else if (hasStorageRef) {
|
|
198
|
+
// 3a. storageRef checks.
|
|
199
|
+
const refMatch = nsBody.match(/<bw:storageRef\b([^>]*)\/>/u);
|
|
200
|
+
if (refMatch) {
|
|
201
|
+
const refAttrs = parseAttrs(refMatch[1] ?? "");
|
|
202
|
+
const entryKey = refAttrs.entryKey ?? "";
|
|
203
|
+
const location = refAttrs.location ?? "";
|
|
204
|
+
|
|
205
|
+
if (entryKey === "") {
|
|
206
|
+
issues.push({
|
|
207
|
+
code: "editor_state_missing_entry_key",
|
|
208
|
+
path: `${nsPath}/bw:storageRef`,
|
|
209
|
+
severity: "error",
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const knownLocations = ["rowstore", "key-only"];
|
|
214
|
+
if (location !== "" && !knownLocations.includes(location)) {
|
|
215
|
+
issues.push({
|
|
216
|
+
code: "editor_state_invalid_location",
|
|
217
|
+
path: `${nsPath}/bw:storageRef/@location`,
|
|
218
|
+
severity: "warning",
|
|
219
|
+
value: location,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} else if (hasInline) {
|
|
224
|
+
// 3b. inline JSON parse check.
|
|
225
|
+
const inlineMatch = nsBody.match(/<bw:inline\b[^>]*>([\s\S]*?)<\/bw:inline>/u);
|
|
226
|
+
if (inlineMatch) {
|
|
227
|
+
const rawContent = inlineMatch[1] ?? "";
|
|
228
|
+
// Strip CDATA markers (handles split CDATA too).
|
|
229
|
+
const text = rawContent.replace(/<!\[CDATA\[|\]\]>/g, "").trim();
|
|
230
|
+
try {
|
|
231
|
+
JSON.parse(text);
|
|
232
|
+
} catch {
|
|
233
|
+
issues.push({
|
|
234
|
+
code: "editor_state_invalid_inline_json",
|
|
235
|
+
path: `${nsPath}/bw:inline`,
|
|
236
|
+
severity: "error",
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
148
244
|
// Top-level entries (bw:metadata body, outside scopes).
|
|
149
245
|
// These resolve against overlay-only (no scope context available unless
|
|
150
246
|
// the entry carries its own `scope="scope:{id}"` attribute, in which case
|
|
@@ -12,11 +12,36 @@ import type {
|
|
|
12
12
|
WorkflowScope,
|
|
13
13
|
WorkflowWorkItem,
|
|
14
14
|
} from "../../api/public-types.ts";
|
|
15
|
+
import type { EditorStateNamespace, EditorStateLocation } from "../../api/editor-state-types.ts";
|
|
15
16
|
import {
|
|
16
17
|
validateWorkflowPayloadEnvelope,
|
|
17
18
|
type ValidatorIssue,
|
|
18
19
|
} from "./workflow-payload-validator.ts";
|
|
19
20
|
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Schema 1.2 editor-state types (edge-of-module shape, channel-free)
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
export interface EditorStatePayloadNamespaceEntry {
|
|
26
|
+
namespace: EditorStateNamespace;
|
|
27
|
+
schemaVersion: string;
|
|
28
|
+
/** JSON-serializable blob (CDATA-wrapped on serialize). Exactly one of inline/storageRef. */
|
|
29
|
+
inline?: unknown;
|
|
30
|
+
storageRef?: { location: Exclude<EditorStateLocation, "in-document">; entryKey: string };
|
|
31
|
+
/**
|
|
32
|
+
* Parser-internal flag: set when the `<bw:inline>` CDATA block contained
|
|
33
|
+
* malformed JSON. Hydration surfaces this as `editor_state_part_load_failed`
|
|
34
|
+
* rather than silently dropping the entry.
|
|
35
|
+
*/
|
|
36
|
+
malformedInline?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface EditorStatePayload {
|
|
40
|
+
entries: EditorStatePayloadNamespaceEntry[];
|
|
41
|
+
/** Unknown namespaces preserved for round-trip — raw XML fragment per entry, keyed by name. */
|
|
42
|
+
unknownNamespaces?: Array<{ name: string; rawXml: string }>;
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
// ---------------------------------------------------------------------------
|
|
21
46
|
// Schema 1.1 parser helpers (fail-closed per spec §8.2)
|
|
22
47
|
// ---------------------------------------------------------------------------
|
|
@@ -62,6 +87,8 @@ type EmbeddedWorkflowPayloadDescriptor = {
|
|
|
62
87
|
export interface WorkflowPayloadEnvelope {
|
|
63
88
|
workflowMetadata: WorkflowMetadataSnapshot;
|
|
64
89
|
workflowOverlay?: WorkflowOverlay;
|
|
90
|
+
/** Present only when the payload was version 1.2+ and carried a non-empty <bw:editorState> block. */
|
|
91
|
+
editorState?: EditorStatePayload;
|
|
65
92
|
validatorIssues?: readonly ValidatorIssue[];
|
|
66
93
|
}
|
|
67
94
|
|
|
@@ -87,6 +114,8 @@ export function buildWorkflowPayloadParts(input: {
|
|
|
87
114
|
sourcePackage: OpcPackage;
|
|
88
115
|
workflowMetadata: WorkflowMetadataSnapshot | undefined;
|
|
89
116
|
workflowOverlay?: WorkflowOverlay;
|
|
117
|
+
/** Optional schema 1.2 editor-state block. Omitted when empty. */
|
|
118
|
+
editorState?: EditorStatePayload;
|
|
90
119
|
documentId: string;
|
|
91
120
|
createdAt: string;
|
|
92
121
|
updatedAt: string;
|
|
@@ -126,6 +155,7 @@ export function buildWorkflowPayloadParts(input: {
|
|
|
126
155
|
producerVersion: input.producerVersion,
|
|
127
156
|
workflowMetadata,
|
|
128
157
|
workflowOverlay: input.workflowOverlay,
|
|
158
|
+
editorState: input.editorState,
|
|
129
159
|
preservedExtensionsXml: getPreservedExtensionsXml(input.sourcePackage, descriptor.payloadPartPath),
|
|
130
160
|
});
|
|
131
161
|
const itemPropsXml = buildItemPropsXml(descriptor.itemId);
|
|
@@ -238,12 +268,14 @@ export function parseWorkflowPayloadEnvelopeFromPackage(
|
|
|
238
268
|
}
|
|
239
269
|
|
|
240
270
|
const validatorIssues = validateWorkflowPayloadEnvelope(xml);
|
|
271
|
+
const editorState = parseEditorStateXml(xml);
|
|
241
272
|
return {
|
|
242
273
|
workflowMetadata: {
|
|
243
274
|
definitions,
|
|
244
275
|
entries,
|
|
245
276
|
},
|
|
246
277
|
workflowOverlay: parseWorkflowOverlay(xml),
|
|
278
|
+
...(editorState !== undefined ? { editorState } : {}),
|
|
247
279
|
...(validatorIssues.length > 0 ? { validatorIssues } : {}),
|
|
248
280
|
};
|
|
249
281
|
}
|
|
@@ -287,6 +319,136 @@ function needsSchemaV11(input: {
|
|
|
287
319
|
return false;
|
|
288
320
|
}
|
|
289
321
|
|
|
322
|
+
/** Returns true when the payload has at least one namespace entry or unknown namespace to emit. */
|
|
323
|
+
function hasNonEmptyEditorState(es: EditorStatePayload | undefined): boolean {
|
|
324
|
+
if (!es) return false;
|
|
325
|
+
return (es.entries.length > 0) || ((es.unknownNamespaces?.length ?? 0) > 0);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ---------------------------------------------------------------------------
|
|
329
|
+
// Known namespace names (closed set for round-trip; unknown names are opaque)
|
|
330
|
+
// ---------------------------------------------------------------------------
|
|
331
|
+
|
|
332
|
+
const KNOWN_EDITOR_STATE_NAMESPACES: readonly EditorStateNamespace[] = [
|
|
333
|
+
"hostAnnotations",
|
|
334
|
+
"workflowOverlay",
|
|
335
|
+
"workflowMetadata",
|
|
336
|
+
"workItems",
|
|
337
|
+
];
|
|
338
|
+
|
|
339
|
+
const KNOWN_STORAGE_LOCATIONS: ReadonlyArray<Exclude<EditorStateLocation, "in-document">> = [
|
|
340
|
+
"rowstore",
|
|
341
|
+
"key-only",
|
|
342
|
+
];
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Escapes `]]>` inside CDATA content using the standard XML split:
|
|
346
|
+
* `]]>` → `]]]]><![CDATA[>`
|
|
347
|
+
*/
|
|
348
|
+
function escapeCdata(text: string): string {
|
|
349
|
+
return text.replace(/\]\]>/g, "]]]]><![CDATA[>");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Builds the `<bw:editorState>…</bw:editorState>` block.
|
|
354
|
+
* Returns an empty string when both entries and unknownNamespaces are empty.
|
|
355
|
+
*/
|
|
356
|
+
export function buildEditorStateXml(payload: EditorStatePayload): string {
|
|
357
|
+
if (!hasNonEmptyEditorState(payload)) {
|
|
358
|
+
return "";
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const knownLines = payload.entries.map((entry) => {
|
|
362
|
+
const nsOpen = `<bw:namespace name="${escapeXml(entry.namespace)}" schemaVersion="${escapeXml(entry.schemaVersion)}">`;
|
|
363
|
+
let content: string;
|
|
364
|
+
if (entry.storageRef !== undefined) {
|
|
365
|
+
content = `<bw:storageRef location="${escapeXml(entry.storageRef.location)}" entryKey="${escapeXml(entry.storageRef.entryKey)}" />`;
|
|
366
|
+
} else {
|
|
367
|
+
const json = escapeCdata(JSON.stringify(entry.inline));
|
|
368
|
+
content = `<bw:inline><![CDATA[${json}]]></bw:inline>`;
|
|
369
|
+
}
|
|
370
|
+
return `${nsOpen}${content}</bw:namespace>`;
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
const unknownLines = (payload.unknownNamespaces ?? []).map((u) => u.rawXml);
|
|
374
|
+
|
|
375
|
+
const innerXml = [...knownLines, ...unknownLines].join("\n");
|
|
376
|
+
return `<bw:editorState>\n${indentLines(innerXml, 2)}\n</bw:editorState>`;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Parses the `<bw:editorState>` block from a full workflow payload XML string.
|
|
381
|
+
* Returns `undefined` when no block is present.
|
|
382
|
+
* Malformed JSON is silently skipped (validator flags it separately).
|
|
383
|
+
*/
|
|
384
|
+
export function parseEditorStateXml(xml: string): EditorStatePayload | undefined {
|
|
385
|
+
const blockMatch = xml.match(/<bw:editorState\b[^>]*>([\s\S]*?)<\/bw:editorState>/u);
|
|
386
|
+
if (!blockMatch) {
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
const blockBody = blockMatch[1] ?? "";
|
|
390
|
+
|
|
391
|
+
const entries: EditorStatePayloadNamespaceEntry[] = [];
|
|
392
|
+
const unknownNamespaces: Array<{ name: string; rawXml: string }> = [];
|
|
393
|
+
|
|
394
|
+
// Match each <bw:namespace ... > ... </bw:namespace>
|
|
395
|
+
const nsRe = /<bw:namespace\b([^>]*)>([\s\S]*?)<\/bw:namespace>/gu;
|
|
396
|
+
for (const nsMatch of blockBody.matchAll(nsRe)) {
|
|
397
|
+
const attrsStr = nsMatch[1] ?? "";
|
|
398
|
+
const nsBody = nsMatch[2] ?? "";
|
|
399
|
+
const rawXml = nsMatch[0] ?? "";
|
|
400
|
+
const attrs = parseAttributes(attrsStr);
|
|
401
|
+
const name = attrs.name ?? "";
|
|
402
|
+
const schemaVersion = attrs.schemaVersion ?? "";
|
|
403
|
+
|
|
404
|
+
if (!(KNOWN_EDITOR_STATE_NAMESPACES as readonly string[]).includes(name)) {
|
|
405
|
+
unknownNamespaces.push({ name, rawXml });
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const namespace = name as EditorStateNamespace;
|
|
410
|
+
|
|
411
|
+
// Parse <bw:storageRef ... />
|
|
412
|
+
const storageRefMatch = nsBody.match(/<bw:storageRef\b([^>]*)\/>/u);
|
|
413
|
+
if (storageRefMatch) {
|
|
414
|
+
const refAttrs = parseAttributes(storageRefMatch[1] ?? "");
|
|
415
|
+
const location = refAttrs.location as Exclude<EditorStateLocation, "in-document"> | undefined;
|
|
416
|
+
const entryKey = refAttrs.entryKey ?? "";
|
|
417
|
+
entries.push({
|
|
418
|
+
namespace,
|
|
419
|
+
schemaVersion,
|
|
420
|
+
storageRef: { location: location ?? "rowstore", entryKey },
|
|
421
|
+
});
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Parse <bw:inline>...</bw:inline> — extract CDATA content
|
|
426
|
+
const inlineMatch = nsBody.match(/<bw:inline\b[^>]*>([\s\S]*?)<\/bw:inline>/u);
|
|
427
|
+
if (inlineMatch) {
|
|
428
|
+
const raw = inlineMatch[1] ?? "";
|
|
429
|
+
// Extract CDATA content — handles split CDATA sections from ]]> escaping
|
|
430
|
+
const cdataText = raw.replace(/<!\[CDATA\[|\]\]>/g, "").trim();
|
|
431
|
+
try {
|
|
432
|
+
const parsed = JSON.parse(cdataText) as unknown;
|
|
433
|
+
entries.push({ namespace, schemaVersion, inline: parsed });
|
|
434
|
+
} catch {
|
|
435
|
+
// Malformed JSON: surface to the runtime so the host sees a
|
|
436
|
+
// load-failure event rather than silently losing the entry.
|
|
437
|
+
entries.push({ namespace, schemaVersion, malformedInline: true });
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (entries.length === 0 && unknownNamespaces.length === 0) {
|
|
443
|
+
return undefined;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return {
|
|
447
|
+
entries,
|
|
448
|
+
...(unknownNamespaces.length > 0 ? { unknownNamespaces } : {}),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
290
452
|
function buildPayloadXml(input: {
|
|
291
453
|
descriptor: EmbeddedWorkflowPayloadDescriptor;
|
|
292
454
|
createdAt: string;
|
|
@@ -294,9 +456,15 @@ function buildPayloadXml(input: {
|
|
|
294
456
|
producerVersion: string;
|
|
295
457
|
workflowMetadata: WorkflowMetadataSnapshot;
|
|
296
458
|
workflowOverlay?: WorkflowOverlay;
|
|
459
|
+
editorState?: EditorStatePayload;
|
|
297
460
|
preservedExtensionsXml: string;
|
|
298
461
|
}): string {
|
|
299
|
-
const
|
|
462
|
+
const hasEditorState = hasNonEmptyEditorState(input.editorState);
|
|
463
|
+
const schemaVersion = hasEditorState
|
|
464
|
+
? "1.2"
|
|
465
|
+
: needsSchemaV11(input)
|
|
466
|
+
? "1.1"
|
|
467
|
+
: "1.0";
|
|
300
468
|
|
|
301
469
|
const definitionEntriesXml = input.workflowMetadata.definitions
|
|
302
470
|
.map((definition) => [
|
|
@@ -351,6 +519,8 @@ function buildPayloadXml(input: {
|
|
|
351
519
|
.filter((value) => value.trim().length > 0)
|
|
352
520
|
.join("\n");
|
|
353
521
|
|
|
522
|
+
const editorStateXml = hasEditorState ? buildEditorStateXml(input.editorState!) : "";
|
|
523
|
+
|
|
354
524
|
return [
|
|
355
525
|
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
356
526
|
`<bw:workflowPayload xmlns:bw="urn:beyondwork:workflow-payload:1" version="${schemaVersion}" payloadId="${escapeXml(input.descriptor.payloadId)}" itemId="${escapeXml(input.descriptor.itemId)}" documentId="${escapeXml(input.descriptor.documentId)}" createdAt="${escapeXml(input.createdAt)}" updatedAt="${escapeXml(input.updatedAt)}">`,
|
|
@@ -362,6 +532,7 @@ function buildPayloadXml(input: {
|
|
|
362
532
|
definitionEntriesXml ? indentLines(definitionEntriesXml, 4) : "",
|
|
363
533
|
metadataEntriesXml ? indentLines(metadataEntriesXml, 4) : "",
|
|
364
534
|
` </bw:metadata>`,
|
|
535
|
+
editorStateXml,
|
|
365
536
|
extensionsXml
|
|
366
537
|
? ` <bw:extensions>\n${indentLines(extensionsXml, 4)}\n </bw:extensions>`
|
|
367
538
|
: ` <bw:extensions />`,
|
|
@@ -121,6 +121,11 @@ export function createOpaqueRegionSurfaceModel(
|
|
|
121
121
|
export function createOpaqueRegionSurfaceModelFromSurfaceBlock(
|
|
122
122
|
block: Extract<SurfaceBlockSnapshot, { kind: "opaque_block" }>,
|
|
123
123
|
): OpaqueRegionSurfaceModel {
|
|
124
|
+
if (block.state === "placeholder-culled") {
|
|
125
|
+
throw new Error(
|
|
126
|
+
"createOpaqueRegionSurfaceModelFromSurfaceBlock: placeholder-culled block has no real fragment",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
124
129
|
return {
|
|
125
130
|
fragmentId: block.fragmentId,
|
|
126
131
|
warningId: block.warningId,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
getAnchorRange,
|
|
5
5
|
mapReviewAnchor,
|
|
6
6
|
mappingTouchesAnchorContent,
|
|
7
|
-
|
|
7
|
+
rangeStaysWithinCommentableStory,
|
|
8
8
|
type ReviewAnchor,
|
|
9
9
|
} from "../../core/selection/review-anchors.ts";
|
|
10
10
|
import type { TransactionMapping } from "../../core/selection/mapping.ts";
|
|
@@ -85,7 +85,7 @@ function normalizeCommentAnchor(
|
|
|
85
85
|
|
|
86
86
|
if (
|
|
87
87
|
mappedAnchor.kind === "range" &&
|
|
88
|
-
!
|
|
88
|
+
!rangeStaysWithinCommentableStory(nextContent, mappedAnchor.range)
|
|
89
89
|
) {
|
|
90
90
|
return detachReviewAnchor(previousRange, "invalidatedByStructureChange");
|
|
91
91
|
}
|
|
@@ -64,7 +64,7 @@ export interface AttachPayloadArgs {
|
|
|
64
64
|
|
|
65
65
|
export type SendToExternalCallArgs = Omit<
|
|
66
66
|
RuntimeSendToExternalArgs,
|
|
67
|
-
"bridge" | "tamperGate" | "signer" | "role"
|
|
67
|
+
"bridge" | "tamperGate" | "signer" | "role" | "resolver"
|
|
68
68
|
> & {
|
|
69
69
|
role?: "author" | "reviewer" | "observer";
|
|
70
70
|
};
|