@arnilo/prism-tools 0.0.0-stage → 0.13.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 +410 -0
- package/LICENSE +21 -0
- package/README.md +44 -2
- package/browser/README.md +98 -0
- package/browser/skills/browser-automation/SKILL.md +14 -0
- package/browser/src/actions/cdp.ts +131 -0
- package/browser/src/actions/dialog.ts +25 -0
- package/browser/src/actions/download_release.ts +22 -0
- package/browser/src/actions/index.ts +37 -0
- package/browser/src/actions/locator.ts +70 -0
- package/browser/src/actions/navigate.ts +23 -0
- package/browser/src/actions/screenshot.ts +27 -0
- package/browser/src/actions/scroll.ts +24 -0
- package/browser/src/actions/select_page.ts +21 -0
- package/browser/src/actions/types.ts +114 -0
- package/browser/src/actions/upload.ts +44 -0
- package/browser/src/actions/wait.ts +45 -0
- package/browser/src/browser.ts +197 -0
- package/browser/src/cdp.ts +178 -0
- package/browser/src/checkpoint.ts +189 -0
- package/browser/src/config.ts +72 -0
- package/browser/src/downloads.ts +253 -0
- package/browser/src/errors.ts +31 -0
- package/browser/src/evaluate.ts +101 -0
- package/browser/src/index.ts +129 -0
- package/browser/src/limits.ts +271 -0
- package/browser/src/manager.ts +730 -0
- package/browser/src/network.ts +263 -0
- package/browser/src/observe.ts +178 -0
- package/browser/src/policy.ts +133 -0
- package/browser/src/screenshot.ts +107 -0
- package/browser/src/shared-sandbox.ts +53 -0
- package/browser/src/snapshot.ts +99 -0
- package/browser/src/targets.ts +165 -0
- package/browser/src/tools.ts +480 -0
- package/browser/src/types.ts +316 -0
- package/browser/src/uploads.ts +174 -0
- package/coding/README.md +337 -0
- package/coding/src/agent/acp-operations.ts +146 -0
- package/coding/src/agent/artifacts.ts +38 -0
- package/coding/src/agent/ask-user-decision.ts +623 -0
- package/coding/src/agent/atomic-write.ts +23 -0
- package/coding/src/agent/bounded-file.ts +21 -0
- package/coding/src/agent/checks.ts +301 -0
- package/coding/src/agent/coding-checkpoint.ts +828 -0
- package/coding/src/agent/delete.ts +237 -0
- package/coding/src/agent/diagnostics-tool.ts +163 -0
- package/coding/src/agent/diagnostics.ts +262 -0
- package/coding/src/agent/edit-diff.ts +382 -0
- package/coding/src/agent/edit.ts +322 -0
- package/coding/src/agent/effects.ts +102 -0
- package/coding/src/agent/env.ts +28 -0
- package/coding/src/agent/execution-policy.ts +89 -0
- package/coding/src/agent/file-mutation-queue.ts +72 -0
- package/coding/src/agent/forge/github.ts +603 -0
- package/coding/src/agent/forge/index.ts +16 -0
- package/coding/src/agent/forge/types.ts +185 -0
- package/coding/src/agent/git-aware-repository.ts +305 -0
- package/coding/src/agent/git-exec.ts +326 -0
- package/coding/src/agent/git-status.ts +177 -0
- package/coding/src/agent/git-tools.ts +360 -0
- package/coding/src/agent/git.ts +1074 -0
- package/coding/src/agent/glob-match.ts +146 -0
- package/coding/src/agent/glob.ts +182 -0
- package/coding/src/agent/goal-verify.ts +385 -0
- package/coding/src/agent/grep-worker.ts +74 -0
- package/coding/src/agent/grep.ts +459 -0
- package/coding/src/agent/identity.ts +48 -0
- package/coding/src/agent/index.ts +676 -0
- package/coding/src/agent/language/client.ts +429 -0
- package/coding/src/agent/language/framing.ts +190 -0
- package/coding/src/agent/language/index.ts +23 -0
- package/coding/src/agent/language/intelligence.ts +682 -0
- package/coding/src/agent/language/types.ts +187 -0
- package/coding/src/agent/lifecycle-events.ts +121 -0
- package/coding/src/agent/lifecycle.ts +166 -0
- package/coding/src/agent/limits.ts +214 -0
- package/coding/src/agent/move.ts +178 -0
- package/coding/src/agent/mutation-path.ts +52 -0
- package/coding/src/agent/output-accumulator.ts +304 -0
- package/coding/src/agent/path-utils.ts +120 -0
- package/coding/src/agent/process/index.ts +58 -0
- package/coding/src/agent/process/recovery.ts +508 -0
- package/coding/src/agent/process/sessions-host.ts +222 -0
- package/coding/src/agent/process/sessions-monitor.ts +141 -0
- package/coding/src/agent/process/sessions-recovery.ts +241 -0
- package/coding/src/agent/process/sessions-spawn.ts +613 -0
- package/coding/src/agent/process/sessions-teardown.ts +281 -0
- package/coding/src/agent/process/sessions.ts +30 -0
- package/coding/src/agent/process/types.ts +358 -0
- package/coding/src/agent/read-path-set.ts +126 -0
- package/coding/src/agent/read.ts +713 -0
- package/coding/src/agent/repository/glob.ts +147 -0
- package/coding/src/agent/repository/indexed-search.ts +480 -0
- package/coding/src/agent/repository/list.ts +131 -0
- package/coding/src/agent/repository/operations.ts +22 -0
- package/coding/src/agent/repository/path.ts +98 -0
- package/coding/src/agent/repository/search.ts +277 -0
- package/coding/src/agent/repository/types.ts +243 -0
- package/coding/src/agent/repository/walk.ts +126 -0
- package/coding/src/agent/repository.ts +12 -0
- package/coding/src/agent/shell-background.ts +264 -0
- package/coding/src/agent/shell-output.ts +75 -0
- package/coding/src/agent/shell.ts +526 -0
- package/coding/src/agent/todo.ts +399 -0
- package/coding/src/agent/truncate.ts +251 -0
- package/coding/src/agent/write.ts +170 -0
- package/coding/src/ask-user-host.ts +48 -0
- package/coding/src/config.ts +278 -0
- package/coding/src/hard-deny.ts +97 -0
- package/coding/src/index.ts +318 -0
- package/coding/src/principal-guard.ts +84 -0
- package/coding/src/sandbox.ts +92 -0
- package/coding/src/security/approval.ts +144 -0
- package/coding/src/security/command-rules.ts +57 -0
- package/coding/src/security/docker-cli.ts +222 -0
- package/coding/src/security/docker-sandbox.ts +1205 -0
- package/coding/src/security/e2b-sandbox.ts +853 -0
- package/coding/src/security/egress/dns-pin.ts +88 -0
- package/coding/src/security/egress/index.ts +32 -0
- package/coding/src/security/egress/limits.ts +57 -0
- package/coding/src/security/egress/policy.ts +137 -0
- package/coding/src/security/egress/proxy.ts +599 -0
- package/coding/src/security/egress/types.ts +30 -0
- package/coding/src/security/index.ts +199 -0
- package/coding/src/security/native-sandbox.ts +639 -0
- package/coding/src/security/path-containment.ts +55 -0
- package/coding/src/security/sandbox-coding-operations.ts +392 -0
- package/coding/src/security/sandbox-fs-operations.ts +644 -0
- package/coding/src/security/sandbox-limits.ts +147 -0
- package/coding/src/security/sandbox-tar.ts +308 -0
- package/coding/src/security/sandbox.ts +179 -0
- package/coding/src/security/semaphore.ts +55 -0
- package/coding/src/targets.ts +110 -0
- package/coding/src/workspace/diff.ts +78 -0
- package/coding/src/workspace/errors.ts +28 -0
- package/coding/src/workspace/index.ts +5 -0
- package/coding/src/workspace/merge.ts +151 -0
- package/coding/src/workspace/routing.ts +76 -0
- package/coding/src/workspace/service.ts +545 -0
- package/computer-use/README.md +105 -0
- package/computer-use/skills/computer-use-linux/SKILL.md +17 -0
- package/computer-use/src/classify.ts +53 -0
- package/computer-use/src/command.ts +29 -0
- package/computer-use/src/config.ts +69 -0
- package/computer-use/src/create.ts +170 -0
- package/computer-use/src/devices.ts +247 -0
- package/computer-use/src/env.ts +28 -0
- package/computer-use/src/index.ts +157 -0
- package/computer-use/src/skill.ts +21 -0
- package/openapi/README.md +97 -0
- package/openapi/src/compile.ts +386 -0
- package/openapi/src/config.ts +73 -0
- package/openapi/src/errors.ts +16 -0
- package/openapi/src/execute.ts +241 -0
- package/openapi/src/index.ts +124 -0
- package/openapi/src/limits.ts +63 -0
- package/openapi/src/specs.ts +86 -0
- package/openapi/src/tools.ts +60 -0
- package/openapi/src/types.ts +61 -0
- package/package.json +171 -4
- package/research/README.md +72 -0
- package/research/skills/research-report/SKILL.md +12 -0
- package/research/skills/research-scoping/SKILL.md +10 -0
- package/research/skills/research-synthesis/SKILL.md +10 -0
- package/research/skills/source-triage/SKILL.md +10 -0
- package/research/src/check.ts +71 -0
- package/research/src/config.ts +41 -0
- package/research/src/index.ts +147 -0
- package/research/src/ledger.ts +157 -0
- package/research/src/urls.ts +21 -0
- package/web/README.md +287 -0
- package/web/skills/web-research/SKILL.md +17 -0
- package/web/src/brave.ts +66 -0
- package/web/src/cache.ts +151 -0
- package/web/src/config.ts +210 -0
- package/web/src/controls.ts +128 -0
- package/web/src/domains.ts +114 -0
- package/web/src/exa.ts +60 -0
- package/web/src/firecrawl.ts +160 -0
- package/web/src/index.ts +387 -0
- package/web/src/kagi.ts +73 -0
- package/web/src/limits.ts +55 -0
- package/web/src/native/convert.ts +84 -0
- package/web/src/native/fetch.ts +226 -0
- package/web/src/normalize.ts +131 -0
- package/web/src/obscura/cdp.ts +201 -0
- package/web/src/obscura/classify.ts +35 -0
- package/web/src/obscura/cli.ts +254 -0
- package/web/src/obscura/errors.ts +8 -0
- package/web/src/obscura/index.ts +59 -0
- package/web/src/obscura/limits.ts +92 -0
- package/web/src/obscura/mcp.ts +104 -0
- package/web/src/obscura/playwright.ts +133 -0
- package/web/src/obscura/process.ts +235 -0
- package/web/src/obscura/search-profile.ts +73 -0
- package/web/src/obscura/types.ts +48 -0
- package/web/src/obscura/web.ts +419 -0
- package/web/src/prompt-fetch.ts +88 -0
- package/web/src/render.ts +75 -0
- package/web/src/searxng.ts +78 -0
- package/web/src/slice.ts +139 -0
- package/web/src/tavily.ts +77 -0
- package/web/src/tools.ts +182 -0
- package/web/src/transport.ts +310 -0
- package/web/src/types.ts +199 -0
- package/work/README.md +77 -0
- package/work/THIRD_PARTY_NOTICES +24 -0
- package/work/docling/ocr.py +150 -0
- package/work/sandbox/Dockerfile +36 -0
- package/work/sandbox/soffice.sh +12 -0
- package/work/src/command.ts +29 -0
- package/work/src/config.ts +138 -0
- package/work/src/connectors/cli.ts +343 -0
- package/work/src/connectors/drafts.ts +647 -0
- package/work/src/connectors/errors.ts +8 -0
- package/work/src/connectors/file-bytes.ts +149 -0
- package/work/src/connectors/google-workspace-http.ts +399 -0
- package/work/src/connectors/google-workspace.ts +465 -0
- package/work/src/connectors/gws-tools.ts +378 -0
- package/work/src/connectors/http.ts +123 -0
- package/work/src/connectors/idempotency.ts +235 -0
- package/work/src/connectors/identity.ts +34 -0
- package/work/src/connectors/index.ts +93 -0
- package/work/src/connectors/limits.ts +50 -0
- package/work/src/connectors/m365-tools.ts +308 -0
- package/work/src/connectors/microsoft365-http.ts +428 -0
- package/work/src/connectors/microsoft365.ts +402 -0
- package/work/src/connectors/normalize.ts +120 -0
- package/work/src/connectors/tool-helpers.ts +398 -0
- package/work/src/connectors/tools.ts +42 -0
- package/work/src/connectors/types.ts +399 -0
- package/work/src/diagrams/canonicalize.ts +166 -0
- package/work/src/diagrams/caps.ts +52 -0
- package/work/src/diagrams/embed.ts +340 -0
- package/work/src/diagrams/errors.ts +76 -0
- package/work/src/diagrams/index.ts +81 -0
- package/work/src/diagrams/messages.ts +150 -0
- package/work/src/diagrams/origin.ts +52 -0
- package/work/src/diagrams/telemetry.ts +34 -0
- package/work/src/diagrams/xml.ts +267 -0
- package/work/src/document-extraction/index.ts +563 -0
- package/work/src/document-reader/ambient.d.ts +2 -0
- package/work/src/document-reader/errors.ts +7 -0
- package/work/src/document-reader/index.ts +181 -0
- package/work/src/document-reader/mistral-ocr.ts +318 -0
- package/work/src/document-reader/parsers.ts +171 -0
- package/work/src/documents/caps.ts +135 -0
- package/work/src/documents/diff.ts +269 -0
- package/work/src/documents/errors.ts +44 -0
- package/work/src/documents/fidelity.ts +98 -0
- package/work/src/documents/generate.ts +96 -0
- package/work/src/documents/hash.ts +8 -0
- package/work/src/documents/index.ts +14 -0
- package/work/src/documents/model-schema.ts +639 -0
- package/work/src/documents/parse.ts +252 -0
- package/work/src/documents/patch-history.ts +81 -0
- package/work/src/documents/patch.ts +476 -0
- package/work/src/documents/preview-html.ts +245 -0
- package/work/src/documents/preview.ts +227 -0
- package/work/src/documents/telemetry.ts +36 -0
- package/work/src/documents/translate/docx.ts +292 -0
- package/work/src/documents/translate/pptx.ts +304 -0
- package/work/src/documents/translate/xlsx.ts +137 -0
- package/work/src/documents/types.ts +188 -0
- package/work/src/index.ts +311 -0
- package/work/src/runtime/worker-pool-entry.ts +102 -0
- package/work/src/runtime/worker-pool.ts +267 -0
- package/work/src/sandbox/composition.ts +212 -0
- package/work/src/sandbox/image.ts +6 -0
- package/work/src/sandbox/index.ts +14 -0
- package/work/src/sheets/caps.ts +68 -0
- package/work/src/sheets/csv.ts +351 -0
- package/work/src/sheets/decimal.ts +388 -0
- package/work/src/sheets/errors.ts +52 -0
- package/work/src/sheets/index.ts +62 -0
- package/work/src/sheets/inference.ts +378 -0
- package/work/src/sheets/telemetry.ts +34 -0
- package/work/src/sheets/types.ts +162 -0
- package/work/src/sheets/xlsx.ts +388 -0
- package/work/src/skills/index.ts +8 -0
- package/work/src/skills/load.ts +43 -0
- package/work/src/tools/filesystem.ts +21 -0
- package/work/src/tools/index.ts +1 -0
- package/work/src/tools/local-filesystem.ts +33 -0
- package/work/src/tools/office.ts +311 -0
- package/work/vendor/hermes-agent/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_comments.py +289 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_common.py +94 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_create.py +177 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_edit.py +250 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_read.py +149 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_revisions.py +147 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_template.py +70 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_validate.py +156 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/SKILL.md +125 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/_raster.py +76 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_marker.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_pymupdf.py +101 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_create.py +130 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_fill_form.py +97 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_form_layout.py +168 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_make_form.py +145 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_merge.py +50 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_meta.py +115 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_page_image.py +99 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_read.py +153 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_secure.py +71 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_split.py +84 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_stamp.py +143 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_watermark.py +51 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/SKILL.md +220 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_create.py +214 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_edit.py +436 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_from_template.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_read.py +131 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_render.py +93 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/csv_to_xlsx.py +104 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_create.py +259 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_edit.py +263 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_read.py +160 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_recalc.py +111 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_restructure.py +337 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_to_csv.py +69 -0
- package/work/vendor-lock.json +11 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { DocumentsPatchError, DocumentsValidationError } from "./errors.js";
|
|
2
|
+
import { validateDocumentModel } from "./model-schema.js";
|
|
3
|
+
import type { DocumentsTelemetry } from "./telemetry.js";
|
|
4
|
+
|
|
5
|
+
/** Rejected dynamic property access paths. Single definition, reusable at every site. */
|
|
6
|
+
const UNSAFE_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]);
|
|
7
|
+
|
|
8
|
+
function assertSafeTarget(target: PatchTarget): void {
|
|
9
|
+
if ("metadata" in target && typeof target.metadata === "string" && UNSAFE_SEGMENTS.has(target.metadata)) {
|
|
10
|
+
throw new DocumentsPatchError(`patch metadata target must not be prototype-polluting key "${target.metadata}"`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function assertSafePatchSegments(patch: SetPatch): void {
|
|
15
|
+
if (!patch.patch || typeof patch.patch !== "object") return;
|
|
16
|
+
for (const key of Object.keys(patch.patch)) {
|
|
17
|
+
if (UNSAFE_SEGMENTS.has(key)) {
|
|
18
|
+
throw new DocumentsPatchError(`patch segment must not be prototype-polluting key "${key}"`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
import type { CellValue, DeckModel, DocBlock, DocModel, DocumentModel, SheetData, SheetModel, SlideData } from "./types.js";
|
|
24
|
+
|
|
25
|
+
export interface BlockTarget {
|
|
26
|
+
readonly block: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface BlockInsertTarget {
|
|
30
|
+
readonly afterBlock?: number;
|
|
31
|
+
readonly beforeBlock?: number;
|
|
32
|
+
readonly atIndex?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface TableCellTarget {
|
|
36
|
+
readonly table: {
|
|
37
|
+
readonly block: number;
|
|
38
|
+
readonly row: number;
|
|
39
|
+
readonly column: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SheetCellTarget {
|
|
44
|
+
readonly cell: {
|
|
45
|
+
readonly sheet: number;
|
|
46
|
+
readonly row: number;
|
|
47
|
+
readonly column: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SlideTarget {
|
|
52
|
+
readonly slide: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SlideInsertTarget {
|
|
56
|
+
readonly afterSlide?: number;
|
|
57
|
+
readonly beforeSlide?: number;
|
|
58
|
+
readonly atIndex?: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface SheetTarget {
|
|
62
|
+
readonly sheet: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface TitleTarget {
|
|
66
|
+
readonly title: true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface MetadataTarget {
|
|
70
|
+
readonly metadata: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type PatchTarget =
|
|
74
|
+
| BlockTarget
|
|
75
|
+
| BlockInsertTarget
|
|
76
|
+
| TableCellTarget
|
|
77
|
+
| SheetCellTarget
|
|
78
|
+
| SlideTarget
|
|
79
|
+
| SlideInsertTarget
|
|
80
|
+
| SheetTarget
|
|
81
|
+
| TitleTarget
|
|
82
|
+
| MetadataTarget;
|
|
83
|
+
|
|
84
|
+
export interface SetPatch {
|
|
85
|
+
readonly op: "set";
|
|
86
|
+
readonly target: PatchTarget;
|
|
87
|
+
readonly patch?: Record<string, unknown>;
|
|
88
|
+
readonly value?: unknown;
|
|
89
|
+
readonly block?: DocBlock;
|
|
90
|
+
readonly slide?: SlideData;
|
|
91
|
+
readonly sheet?: SheetData;
|
|
92
|
+
readonly cell?: CellValue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface InsertPatch {
|
|
96
|
+
readonly op: "insert";
|
|
97
|
+
readonly target: PatchTarget;
|
|
98
|
+
readonly block?: DocBlock;
|
|
99
|
+
readonly slide?: SlideData;
|
|
100
|
+
readonly sheet?: SheetData;
|
|
101
|
+
readonly value?: unknown;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface RemovePatch {
|
|
105
|
+
readonly op: "remove";
|
|
106
|
+
readonly target: PatchTarget;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface MovePatch {
|
|
110
|
+
readonly op: "move";
|
|
111
|
+
readonly from: PatchTarget;
|
|
112
|
+
readonly to: PatchTarget;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type DocumentPatch = SetPatch | InsertPatch | RemovePatch | MovePatch;
|
|
116
|
+
|
|
117
|
+
export interface PatchDocumentOptions {
|
|
118
|
+
/** Optional telemetry seam hook. */
|
|
119
|
+
readonly telemetry?: DocumentsTelemetry;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function applySetPatch(model: DocumentModel, patch: SetPatch): void {
|
|
123
|
+
const target = patch.target;
|
|
124
|
+
assertSafeTarget(target);
|
|
125
|
+
assertSafePatchSegments(patch);
|
|
126
|
+
|
|
127
|
+
if ("title" in target && target.title === true) {
|
|
128
|
+
const val = patch.value ?? (patch.patch as { title?: string } | undefined)?.title;
|
|
129
|
+
if (typeof val === "string" || val === undefined) {
|
|
130
|
+
(model as { title?: string }).title = val;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
throw new DocumentsValidationError("patch 'set title' value must be a string or undefined");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if ("metadata" in target && typeof target.metadata === "string") {
|
|
137
|
+
assertSafeTarget(target);
|
|
138
|
+
const val = patch.value;
|
|
139
|
+
if (!model.metadata) {
|
|
140
|
+
(model as { metadata?: Record<string, unknown> }).metadata = {};
|
|
141
|
+
}
|
|
142
|
+
if (val === undefined) {
|
|
143
|
+
delete (model.metadata as Record<string, unknown>)[target.metadata];
|
|
144
|
+
} else {
|
|
145
|
+
(model.metadata as Record<string, unknown>)[target.metadata] = val;
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if ("table" in target && target.table) {
|
|
151
|
+
if (model.kind !== "doc") {
|
|
152
|
+
throw new DocumentsValidationError("table cell target can only be applied to doc model");
|
|
153
|
+
}
|
|
154
|
+
const doc = model as DocModel;
|
|
155
|
+
const { block: blockIdx, row, column } = target.table;
|
|
156
|
+
if (blockIdx < 0 || blockIdx >= doc.blocks.length) {
|
|
157
|
+
throw new DocumentsValidationError(`table target block index ${blockIdx} out of bounds`);
|
|
158
|
+
}
|
|
159
|
+
const block = doc.blocks[blockIdx];
|
|
160
|
+
if (block.type !== "table") {
|
|
161
|
+
throw new DocumentsValidationError(`block at index ${blockIdx} is not a table`);
|
|
162
|
+
}
|
|
163
|
+
const cells = block.cells as CellValue[][];
|
|
164
|
+
if (row < 0 || row >= cells.length) {
|
|
165
|
+
throw new DocumentsValidationError(`table row index ${row} out of bounds`);
|
|
166
|
+
}
|
|
167
|
+
if (column < 0 || column >= cells[row].length) {
|
|
168
|
+
throw new DocumentsValidationError(`table column index ${column} out of bounds`);
|
|
169
|
+
}
|
|
170
|
+
const cellVal = (patch.cell !== undefined ? patch.cell : patch.value) as CellValue;
|
|
171
|
+
cells[row][column] = cellVal;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if ("cell" in target && target.cell) {
|
|
176
|
+
if (model.kind !== "sheet") {
|
|
177
|
+
throw new DocumentsValidationError("cell target can only be applied to sheet model");
|
|
178
|
+
}
|
|
179
|
+
const sheetModel = model as SheetModel;
|
|
180
|
+
const { sheet: sheetIdx, row, column } = target.cell;
|
|
181
|
+
if (sheetIdx < 0 || sheetIdx >= sheetModel.sheets.length) {
|
|
182
|
+
throw new DocumentsValidationError(`sheet index ${sheetIdx} out of bounds`);
|
|
183
|
+
}
|
|
184
|
+
const sheet = sheetModel.sheets[sheetIdx];
|
|
185
|
+
const cells = sheet.cells as CellValue[][];
|
|
186
|
+
if (row < 0 || row >= cells.length) {
|
|
187
|
+
throw new DocumentsValidationError(`sheet row index ${row} out of bounds`);
|
|
188
|
+
}
|
|
189
|
+
if (column < 0 || column >= cells[row].length) {
|
|
190
|
+
throw new DocumentsValidationError(`sheet column index ${column} out of bounds`);
|
|
191
|
+
}
|
|
192
|
+
const cellVal = (patch.cell !== undefined ? patch.cell : patch.value) as CellValue;
|
|
193
|
+
cells[row][column] = cellVal;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if ("block" in target && typeof target.block === "number") {
|
|
198
|
+
if (model.kind !== "doc") {
|
|
199
|
+
throw new DocumentsValidationError("block target can only be applied to doc model");
|
|
200
|
+
}
|
|
201
|
+
const doc = model as DocModel;
|
|
202
|
+
const blocks = doc.blocks as DocBlock[];
|
|
203
|
+
const idx = target.block;
|
|
204
|
+
if (idx < 0 || idx >= blocks.length) {
|
|
205
|
+
throw new DocumentsValidationError(`block index ${idx} out of bounds`);
|
|
206
|
+
}
|
|
207
|
+
if (patch.block) {
|
|
208
|
+
blocks[idx] = patch.block;
|
|
209
|
+
} else if (patch.patch) {
|
|
210
|
+
blocks[idx] = { ...blocks[idx], ...patch.patch } as DocBlock;
|
|
211
|
+
} else if (patch.value && typeof patch.value === "object") {
|
|
212
|
+
blocks[idx] = patch.value as DocBlock;
|
|
213
|
+
} else {
|
|
214
|
+
throw new DocumentsValidationError("set patch on block requires block, patch, or value object");
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if ("slide" in target && typeof target.slide === "number") {
|
|
220
|
+
if (model.kind !== "deck") {
|
|
221
|
+
throw new DocumentsValidationError("slide target can only be applied to deck model");
|
|
222
|
+
}
|
|
223
|
+
const deck = model as DeckModel;
|
|
224
|
+
const slides = deck.slides as SlideData[];
|
|
225
|
+
const idx = target.slide;
|
|
226
|
+
if (idx < 0 || idx >= slides.length) {
|
|
227
|
+
throw new DocumentsValidationError(`slide index ${idx} out of bounds`);
|
|
228
|
+
}
|
|
229
|
+
if (patch.slide) {
|
|
230
|
+
slides[idx] = patch.slide;
|
|
231
|
+
} else if (patch.patch) {
|
|
232
|
+
slides[idx] = { ...slides[idx], ...patch.patch } as SlideData;
|
|
233
|
+
} else if (patch.value && typeof patch.value === "object") {
|
|
234
|
+
slides[idx] = patch.value as SlideData;
|
|
235
|
+
} else {
|
|
236
|
+
throw new DocumentsValidationError("set patch on slide requires slide, patch, or value object");
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if ("sheet" in target && typeof target.sheet === "number") {
|
|
242
|
+
if (model.kind !== "sheet") {
|
|
243
|
+
throw new DocumentsValidationError("sheet target can only be applied to sheet model");
|
|
244
|
+
}
|
|
245
|
+
const sheetModel = model as SheetModel;
|
|
246
|
+
const sheets = sheetModel.sheets as SheetData[];
|
|
247
|
+
const idx = target.sheet;
|
|
248
|
+
if (idx < 0 || idx >= sheets.length) {
|
|
249
|
+
throw new DocumentsValidationError(`sheet index ${idx} out of bounds`);
|
|
250
|
+
}
|
|
251
|
+
if (patch.sheet) {
|
|
252
|
+
sheets[idx] = patch.sheet;
|
|
253
|
+
} else if (patch.patch) {
|
|
254
|
+
sheets[idx] = { ...sheets[idx], ...patch.patch } as SheetData;
|
|
255
|
+
} else if (patch.value && typeof patch.value === "object") {
|
|
256
|
+
sheets[idx] = patch.value as SheetData;
|
|
257
|
+
} else {
|
|
258
|
+
throw new DocumentsValidationError("set patch on sheet requires sheet, patch, or value object");
|
|
259
|
+
}
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
throw new DocumentsValidationError("unsupported target selector for set operation");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function resolveInsertIndex(target: PatchTarget, arrayLength: number): number {
|
|
267
|
+
if ("afterBlock" in target && typeof target.afterBlock === "number") {
|
|
268
|
+
if (target.afterBlock < -1 || target.afterBlock >= arrayLength) {
|
|
269
|
+
throw new DocumentsValidationError(`afterBlock index ${target.afterBlock} out of bounds`);
|
|
270
|
+
}
|
|
271
|
+
return target.afterBlock + 1;
|
|
272
|
+
}
|
|
273
|
+
if ("beforeBlock" in target && typeof target.beforeBlock === "number") {
|
|
274
|
+
if (target.beforeBlock < 0 || target.beforeBlock > arrayLength) {
|
|
275
|
+
throw new DocumentsValidationError(`beforeBlock index ${target.beforeBlock} out of bounds`);
|
|
276
|
+
}
|
|
277
|
+
return target.beforeBlock;
|
|
278
|
+
}
|
|
279
|
+
if ("afterSlide" in target && typeof target.afterSlide === "number") {
|
|
280
|
+
if (target.afterSlide < -1 || target.afterSlide >= arrayLength) {
|
|
281
|
+
throw new DocumentsValidationError(`afterSlide index ${target.afterSlide} out of bounds`);
|
|
282
|
+
}
|
|
283
|
+
return target.afterSlide + 1;
|
|
284
|
+
}
|
|
285
|
+
if ("beforeSlide" in target && typeof target.beforeSlide === "number") {
|
|
286
|
+
if (target.beforeSlide < 0 || target.beforeSlide > arrayLength) {
|
|
287
|
+
throw new DocumentsValidationError(`beforeSlide index ${target.beforeSlide} out of bounds`);
|
|
288
|
+
}
|
|
289
|
+
return target.beforeSlide;
|
|
290
|
+
}
|
|
291
|
+
if ("atIndex" in target && typeof target.atIndex === "number") {
|
|
292
|
+
if (target.atIndex < 0 || target.atIndex > arrayLength) {
|
|
293
|
+
throw new DocumentsValidationError(`atIndex ${target.atIndex} out of bounds`);
|
|
294
|
+
}
|
|
295
|
+
return target.atIndex;
|
|
296
|
+
}
|
|
297
|
+
return arrayLength;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function applyInsertPatch(model: DocumentModel, patch: InsertPatch): void {
|
|
301
|
+
if (model.kind === "doc") {
|
|
302
|
+
const doc = model as DocModel;
|
|
303
|
+
const item = (patch.block ?? patch.value) as DocBlock | undefined;
|
|
304
|
+
if (!item || typeof item !== "object" || !("type" in item)) {
|
|
305
|
+
throw new DocumentsValidationError("insert patch on doc requires a valid DocBlock");
|
|
306
|
+
}
|
|
307
|
+
const blocks = doc.blocks as DocBlock[];
|
|
308
|
+
const idx = resolveInsertIndex(patch.target, blocks.length);
|
|
309
|
+
blocks.splice(idx, 0, item);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (model.kind === "deck") {
|
|
314
|
+
const deck = model as DeckModel;
|
|
315
|
+
const item = (patch.slide ?? patch.value) as SlideData | undefined;
|
|
316
|
+
if (!item || typeof item !== "object" || !("layout" in item)) {
|
|
317
|
+
throw new DocumentsValidationError("insert patch on deck requires a valid SlideData");
|
|
318
|
+
}
|
|
319
|
+
const slides = deck.slides as SlideData[];
|
|
320
|
+
const idx = resolveInsertIndex(patch.target, slides.length);
|
|
321
|
+
slides.splice(idx, 0, item);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (model.kind === "sheet") {
|
|
326
|
+
const sheetModel = model as SheetModel;
|
|
327
|
+
const item = (patch.sheet ?? patch.value) as SheetData | undefined;
|
|
328
|
+
if (!item || typeof item !== "object" || !("name" in item)) {
|
|
329
|
+
throw new DocumentsValidationError("insert patch on sheet model requires a valid SheetData");
|
|
330
|
+
}
|
|
331
|
+
const sheets = sheetModel.sheets as SheetData[];
|
|
332
|
+
const idx = resolveInsertIndex(patch.target, sheets.length);
|
|
333
|
+
sheets.splice(idx, 0, item);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
throw new DocumentsValidationError(`unsupported document kind for insert operation: ${String((model as DocumentModel).kind)}`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function applyRemovePatch(model: DocumentModel, patch: RemovePatch): void {
|
|
341
|
+
const target = patch.target;
|
|
342
|
+
|
|
343
|
+
if ("block" in target && typeof target.block === "number") {
|
|
344
|
+
if (model.kind !== "doc") {
|
|
345
|
+
throw new DocumentsValidationError("remove block target can only be applied to doc model");
|
|
346
|
+
}
|
|
347
|
+
const doc = model as DocModel;
|
|
348
|
+
const blocks = doc.blocks as DocBlock[];
|
|
349
|
+
const idx = target.block;
|
|
350
|
+
if (idx < 0 || idx >= blocks.length) {
|
|
351
|
+
throw new DocumentsValidationError(`remove block index ${idx} out of bounds`);
|
|
352
|
+
}
|
|
353
|
+
blocks.splice(idx, 1);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if ("slide" in target && typeof target.slide === "number") {
|
|
358
|
+
if (model.kind !== "deck") {
|
|
359
|
+
throw new DocumentsValidationError("remove slide target can only be applied to deck model");
|
|
360
|
+
}
|
|
361
|
+
const deck = model as DeckModel;
|
|
362
|
+
const slides = deck.slides as SlideData[];
|
|
363
|
+
const idx = target.slide;
|
|
364
|
+
if (idx < 0 || idx >= slides.length) {
|
|
365
|
+
throw new DocumentsValidationError(`remove slide index ${idx} out of bounds`);
|
|
366
|
+
}
|
|
367
|
+
slides.splice(idx, 1);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if ("sheet" in target && typeof target.sheet === "number") {
|
|
372
|
+
if (model.kind !== "sheet") {
|
|
373
|
+
throw new DocumentsValidationError("remove sheet target can only be applied to sheet model");
|
|
374
|
+
}
|
|
375
|
+
const sheetModel = model as SheetModel;
|
|
376
|
+
const sheets = sheetModel.sheets as SheetData[];
|
|
377
|
+
const idx = target.sheet;
|
|
378
|
+
if (idx < 0 || idx >= sheets.length) {
|
|
379
|
+
throw new DocumentsValidationError(`remove sheet index ${idx} out of bounds`);
|
|
380
|
+
}
|
|
381
|
+
sheets.splice(idx, 1);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
throw new DocumentsValidationError("unsupported target selector for remove operation");
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function applyMovePatch(model: DocumentModel, patch: MovePatch): void {
|
|
389
|
+
if (model.kind === "doc") {
|
|
390
|
+
const doc = model as DocModel;
|
|
391
|
+
if (!("block" in patch.from) || typeof patch.from.block !== "number") {
|
|
392
|
+
throw new DocumentsValidationError("move patch 'from' must specify a block index");
|
|
393
|
+
}
|
|
394
|
+
const blocks = doc.blocks as DocBlock[];
|
|
395
|
+
const fromIdx = patch.from.block;
|
|
396
|
+
if (fromIdx < 0 || fromIdx >= blocks.length) {
|
|
397
|
+
throw new DocumentsValidationError(`move from block index ${fromIdx} out of bounds`);
|
|
398
|
+
}
|
|
399
|
+
const [item] = blocks.splice(fromIdx, 1);
|
|
400
|
+
const toIdx = resolveInsertIndex(patch.to, blocks.length);
|
|
401
|
+
blocks.splice(toIdx, 0, item);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (model.kind === "deck") {
|
|
406
|
+
const deck = model as DeckModel;
|
|
407
|
+
if (!("slide" in patch.from) || typeof patch.from.slide !== "number") {
|
|
408
|
+
throw new DocumentsValidationError("move patch 'from' must specify a slide index");
|
|
409
|
+
}
|
|
410
|
+
const slides = deck.slides as SlideData[];
|
|
411
|
+
const fromIdx = patch.from.slide;
|
|
412
|
+
if (fromIdx < 0 || fromIdx >= slides.length) {
|
|
413
|
+
throw new DocumentsValidationError(`move from slide index ${fromIdx} out of bounds`);
|
|
414
|
+
}
|
|
415
|
+
const [item] = slides.splice(fromIdx, 1);
|
|
416
|
+
const toIdx = resolveInsertIndex(patch.to, slides.length);
|
|
417
|
+
slides.splice(toIdx, 0, item);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
throw new DocumentsValidationError(`move operation not supported on ${model.kind} model`);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Applies a sequence of typed patch operations to a Prism Document Model.
|
|
426
|
+
*
|
|
427
|
+
* Immutably clones the input model, validates targets and bounds,
|
|
428
|
+
* and validates the final output model against its schema.
|
|
429
|
+
*/
|
|
430
|
+
export function patchDocument(model: DocumentModel, patches: readonly DocumentPatch[], options?: PatchDocumentOptions): DocumentModel {
|
|
431
|
+
const span = options?.telemetry?.startSpan("documents.patch", {
|
|
432
|
+
"documents.kind": model?.kind ?? "unknown",
|
|
433
|
+
"documents.patches_count": patches?.length ?? 0,
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
try {
|
|
437
|
+
if (!patches || patches.length === 0) {
|
|
438
|
+
return structuredClone(model);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const patched = structuredClone(model);
|
|
442
|
+
|
|
443
|
+
for (const patch of patches) {
|
|
444
|
+
if (!patch || typeof patch !== "object" || !("op" in patch)) {
|
|
445
|
+
throw new DocumentsValidationError("invalid patch operation: missing 'op'");
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
switch (patch.op) {
|
|
449
|
+
case "set":
|
|
450
|
+
applySetPatch(patched, patch);
|
|
451
|
+
break;
|
|
452
|
+
case "insert":
|
|
453
|
+
applyInsertPatch(patched, patch);
|
|
454
|
+
break;
|
|
455
|
+
case "remove":
|
|
456
|
+
applyRemovePatch(patched, patch);
|
|
457
|
+
break;
|
|
458
|
+
case "move":
|
|
459
|
+
applyMovePatch(patched, patch);
|
|
460
|
+
break;
|
|
461
|
+
default:
|
|
462
|
+
throw new DocumentsValidationError(`unknown patch operation "${(patch as { op: string }).op}"`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Structural trust boundary: every patch output passes validateDocumentModel
|
|
467
|
+
validateDocumentModel(patched);
|
|
468
|
+
|
|
469
|
+
return patched;
|
|
470
|
+
} catch (err) {
|
|
471
|
+
span?.recordError();
|
|
472
|
+
throw err;
|
|
473
|
+
} finally {
|
|
474
|
+
span?.end();
|
|
475
|
+
}
|
|
476
|
+
}
|