@paged-media/plugin-sdk 0.2.42-canary.0 → 0.2.45-canary.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +561 -6
  2. package/dist/index.js +10897 -58
  3. package/package.json +4 -3
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PagedBundle, BindingProvider, Disposable, ActiveBindingProvider, BindingPropertyRequest, BindingReadResult, BindingPropertyWrite, BindingWriteResult, BindingCollectionRequest, BindingCollectionResult, MutationInput, FontFaceAsset, BundleHost, ClipboardPayload, ConsentResult, DataProviderRegistration, DataProviderHandle, DataProviderInfo, DataProviderSnapshot, JournalRecord, ShellSurface, WidgetSurface, WillSaveEvent, ToolSettingValue, SchemaPanelRenderer, SchemaPanelContribution, EditContextContribution, ObjectTypeContribution, Diagnostic, TextCaret, OpenDocumentResult, PagedEditor, PluginManifest, ToolContribution, PanelContribution, CommandContribution, KeybindingContribution, OverlayContribution, ImporterContribution, ExporterContribution, ToolPreviewShape, EnteredEditContext, BindingsSurface, PanelProps, SchemaGate, WasmArtifact, CanvasPointerEvent, Mutation, MutationOutcome, BindingProviderHandle } from '@paged-media/plugin-api';
1
+ import { PagedBundle, ParsedAddress, ElementId, MutationInput, MutationOutcome, ObjectErrorCode, ObjectKindInfo, PropertySchema, ObjectValue, ObjectOp, PagedEditor, ObjectsSurface, ObjectModelContribution, PartsSurface, PluginLogger, ObjectModelHandle, BindingProvider, Disposable, ActiveBindingProvider, BindingPropertyRequest, BindingReadResult, BindingPropertyWrite, BindingWriteResult, BindingCollectionRequest, BindingCollectionResult, FontFaceAsset, BundleHost, ClipboardPayload, ConsentResult, DataProviderRegistration, DataProviderHandle, DataProviderInfo, DataProviderSnapshot, JournalRecord, ShellSurface, WidgetSurface, WillSaveEvent, ToolSettingValue, SchemaPanelRenderer, SchemaPanelContribution, EditContextContribution, ObjectTypeContribution, Diagnostic, TextCaret, OpenDocumentResult, PluginManifest, ToolContribution, PanelContribution, CommandContribution, KeybindingContribution, OverlayContribution, ImporterContribution, ExporterContribution, ToolPreviewShape, EnteredEditContext, ValueType, ObjectCommandInfo, PropertyPath, BindingsSurface, PanelProps, SchemaGate, WasmArtifact, CanvasPointerEvent, Mutation, PanelSchemaPropertyRow, PanelSchemaRow, PropertyFieldAddress, PanelSchema, ValueEdit, Address, ListEdit, StructEdit, ObjectWriteResult, BindingProviderHandle } from '@paged-media/plugin-api';
2
2
  import { ComponentType } from 'react';
3
3
 
4
4
  /**
@@ -9,6 +9,167 @@ import { ComponentType } from 'react';
9
9
  */
10
10
  declare function defineBundle(bundle: PagedBundle): PagedBundle;
11
11
 
12
+ /** Parse an address (ADR 131); `null` when it is not one. Never throws. */
13
+ declare function parseAddress(text: string): ParsedAddress | null;
14
+ /** Format a parsed address in its CANONICAL form (aliases never emitted). */
15
+ declare function formatAddress(a: ParsedAddress): string;
16
+ /** Canonicalise an address string; `null` when it does not parse. */
17
+ declare function normalizeAddress(text: string): string | null;
18
+ /** The QUALIFIED kind an address belongs to for schema/routing purposes:
19
+ * `frame` for every page item, `story` for ranges, `page` for `page:#n`,
20
+ * `plugin:<id>/<kind>` for plugin objects. */
21
+ declare function addressKindOf(a: ParsedAddress): string;
22
+ /** The `ElementId` today's wire carries for an address, or `null` when the
23
+ * wire has no form for it (layers, swatches, pages, the document… — the
24
+ * forms core's `Set` will carry as strings). Tables and cells need their
25
+ * owning story, which only a resolver knows: see core-objects.ts. */
26
+ declare function toElementId(a: ParsedAddress): ElementId | null;
27
+ /** The canonical address of a wire `ElementId` (total, ADR 131). */
28
+ declare function fromElementId(id: ElementId): string;
29
+ type SelectorHead = {
30
+ type: "address";
31
+ address: ParsedAddress;
32
+ } | {
33
+ type: "kind";
34
+ kind: string;
35
+ } | {
36
+ type: "any";
37
+ };
38
+ interface SelectorPredicate {
39
+ key: string;
40
+ op: "=" | "!=" | "^=" | "*=";
41
+ value: string;
42
+ }
43
+ interface SelectorStep {
44
+ /** How this step relates to the previous one (absent on the first). */
45
+ combinator?: "child" | "descendant";
46
+ head: SelectorHead;
47
+ predicates: SelectorPredicate[];
48
+ /** `:nth(n)`, 1-based. */
49
+ nth?: number;
50
+ }
51
+ interface ParsedSelector {
52
+ steps: SelectorStep[];
53
+ }
54
+ /** Parse a selector (ADR 131); `null` when it is not one. Never throws. */
55
+ declare function parseSelector(text: string): ParsedSelector | null;
56
+
57
+ /** A core write plan: the ops, or a typed refusal. */
58
+ type CorePlan = {
59
+ ok: true;
60
+ mutations: MutationInput[];
61
+ } | {
62
+ ok: false;
63
+ code: ObjectErrorCode;
64
+ reason: string;
65
+ };
66
+ /** A core `create` plan (protocol 71). `address` is the new object's
67
+ * address when its id is known up front (a swatch, a style, a text
68
+ * variable), else `$h:<handle>`; `resolve` names the object after the
69
+ * commit (a minted page item, page or layer). `kind` is the SDK kind the
70
+ * rows of later ops on `$h:<handle>` come from. */
71
+ type CoreCreatePlan = {
72
+ ok: true;
73
+ mutations: MutationInput[];
74
+ kind: string;
75
+ address: string;
76
+ /** Props the create op does not carry: set on the new object. */
77
+ props?: Record<string, unknown>;
78
+ resolve?: (outcome: MutationOutcome) => Promise<string | null>;
79
+ } | {
80
+ ok: false;
81
+ code: ObjectErrorCode;
82
+ reason: string;
83
+ };
84
+ /** The core backend the registry routes to. */
85
+ interface CoreObjects {
86
+ /** The engine protocol this seam speaks, once known (feature-detected
87
+ * on first use; the registry awaits it before reading rows). */
88
+ ready?(): Promise<number>;
89
+ kinds(): ObjectKindInfo[];
90
+ schema(kind: string): PropertySchema[];
91
+ get(a: ParsedAddress, path: string): Promise<ObjectValue>;
92
+ /** Plan a write (value already schema-validated). `kind` names the SDK
93
+ * kind of a `$h:` handle address made earlier in the same batch. */
94
+ planSet(a: ParsedAddress, path: string, value: unknown, kind?: string): Promise<CorePlan>;
95
+ /** Plan a `create` of a core object (protocol 71). `handle` binds the
96
+ * new object for later ops of the same batch. */
97
+ planCreate?(op: Extract<ObjectOp, {
98
+ op: "create";
99
+ }>, handle: string): Promise<CoreCreatePlan>;
100
+ /** Plan a `delete` of a core object. */
101
+ planDelete?(a: ParsedAddress): Promise<CorePlan>;
102
+ /** The wire `ElementId` of an address (labels go here). */
103
+ elementIdOf(a: ParsedAddress): Promise<ElementId | null>;
104
+ /** The `x-paged:` labels on a label HOST — a page item, a story (range),
105
+ * a page or the document — as key → raw value; null when the address
106
+ * is not a label host or does not exist. */
107
+ labelsOf(a: ParsedAddress): Promise<Record<string, string> | null>;
108
+ /** The mutation that sets (`value`) or clears (`null`) one plugin label
109
+ * on a label host: `setPluginMetadata` (item / story), `setPageMetadata`
110
+ * (page, protocol 70) or `setDocumentMetadata` (doc); null when the
111
+ * address is not a label host. */
112
+ planLabel(a: ParsedAddress, key: string, value: string | null, caller: string): Promise<MutationInput | null>;
113
+ /** Evaluate core selector steps (no plugin steps). */
114
+ query(steps: readonly SelectorStep[]): Promise<string[]>;
115
+ /** Commit mutations as ONE engine mutation (a `batch` when > 1). */
116
+ commit(mutations: readonly MutationInput[]): Promise<MutationOutcome>;
117
+ /** Pre-71 only: remember a table's story (a `cell:` address carries
118
+ * none; the old wire's `TableCell` id needs it). A no-op at 71. */
119
+ noteTableStory?(tableId: string, storyId: string): void;
120
+ /** Engine changes (mutation / undo / redo / load). */
121
+ onDidChange(listener: () => void): () => void;
122
+ /** Drop derived caches (a host that loads without a broadcast). */
123
+ invalidate(): void;
124
+ /** Release the engine subscription (a private, per-host backend). */
125
+ dispose(): void;
126
+ }
127
+ interface CreateCoreObjectsOptions {
128
+ /** The engine's protocol, when the caller knows it (skips the probe). */
129
+ protocol?: number | (() => number | undefined);
130
+ }
131
+ /** The first protocol with `Set` / `RequestGet` / `RequestQuery`. */
132
+ declare const OBJECT_MODEL_PROTOCOL = 71;
133
+ /**
134
+ * The core seam over a live engine. Feature-detects the engine protocol
135
+ * and delegates to the protocol-71 seam or the pre-71 table.
136
+ */
137
+ declare function createCoreObjects(getEditor: () => PagedEditor, options?: CreateCoreObjectsOptions): CoreObjects;
138
+ /** Every item kind word a selector may use for core frames. */
139
+ declare const FRAME_KIND_WORDS: readonly string[];
140
+
141
+ /** What a plugin host hands the registry at registration. */
142
+ interface ObjectModelRegistration {
143
+ plugin: string;
144
+ model: ObjectModelContribution;
145
+ /** The plugin's OWN parts door — `state` writes land in its namespace. */
146
+ parts?: PartsSurface;
147
+ log?: PluginLogger;
148
+ }
149
+ /** The shared registry: the ungated `ObjectsSurface` (what the host app,
150
+ * the harness and the CLI call) plus the adapter-side `register`. */
151
+ interface ObjectRegistry extends ObjectsSurface {
152
+ register(registration: ObjectModelRegistration): ObjectModelHandle;
153
+ /** The core backend, when one is wired (null = plugin objects only). */
154
+ readonly core: CoreObjects | null;
155
+ /** A view of this registry whose writes report each engine commit they
156
+ * make (its `appliedSeq`) to `note` — including the writes a plugin
157
+ * command's handler makes, since an `invoke` through the view hands the
158
+ * handler the same view. Writes through any other surface (a panel, a
159
+ * UI edit made meanwhile) are never reported. The script bridge answers
160
+ * a round through one, so the host can send exactly the script's own
161
+ * writes as `HostObjectsResult.committed` (protocol 71). */
162
+ tracked(note: (appliedSeq: number) => void): ObjectsSurface;
163
+ }
164
+ interface CreateObjectRegistryOptions {
165
+ core?: CoreObjects | null;
166
+ log?: Pick<PluginLogger, "warn">;
167
+ }
168
+ /** Non-ASCII → `\uXXXX`, as InDesign keeps label values (survey,
169
+ * 2026-10-06); still valid JSON. */
170
+ declare function escapeLabelValue(text: string): string;
171
+ declare function createObjectRegistry(options?: CreateObjectRegistryOptions): ObjectRegistry;
172
+
12
173
  /** The implemented feature set — `host.supports()` answers from this,
13
174
  * so docs/tests can't drift from code. Form: `"area.member@major"`. */
14
175
  declare const HOST_FEATURES: readonly string[];
@@ -273,6 +434,18 @@ interface DocumentsBackend {
273
434
  };
274
435
  }): Promise<OpenDocumentResult>;
275
436
  }
437
+ /**
438
+ * v70 — the backend the editor injects to back `host.viewport`'s page
439
+ * members. The editor owns the camera and the page layout, so it answers
440
+ * which page is active and moves the camera to one. No backend →
441
+ * `goToPage` answers false, `activePage` null, the event never fires and
442
+ * `supports("viewport.pages@1")` is false.
443
+ */
444
+ interface PagesBackend {
445
+ goToPage(pageId: string, fit: "page" | "width"): boolean | Promise<boolean>;
446
+ activePage(): string | null;
447
+ onDidChangeActivePage(listener: (pageId: string | null) => void): () => void;
448
+ }
276
449
  /** The SHARED cross-plugin data-provider registry (paged.data §7.1 / D-09). The
277
450
  * editor creates ONE (`createDataProviderRegistry`) and injects the SAME
278
451
  * instance into every plugin host, so a provider plugin and a consumer plugin
@@ -408,6 +581,13 @@ interface CreateBundleHostOptions {
408
581
  * (nothing would ever consult the provider) and
409
582
  * `supports("bindings.provider@1")` is false. */
410
583
  bindingProviders?: BindingProviderBackend;
584
+ /** Host-provided SHARED OBJECT REGISTRY (ADR 323): the editor / headless
585
+ * host / Node CLI creates ONE (`createObjectRegistry({ core:
586
+ * createCoreObjects(getEditor) })`) and injects the SAME instance into
587
+ * every plugin host, so `host.objects` routes across bundles. When
588
+ * absent, the host builds a PRIVATE registry (core + this bundle's own
589
+ * kinds) and `supports("objects.shared@1")` is false. */
590
+ objects?: ObjectRegistry;
411
591
  /** Console sink override.
412
592
  *
413
593
  * Originally a test hook, and now ALSO the production capture point: the
@@ -431,6 +611,11 @@ interface CreateBundleHostOptions {
431
611
  * `host.widgets` is the plain-textarea fallback and
432
612
  * `supports("widgets.codeEditor@1")` answers false. */
433
613
  widgets?: Partial<WidgetSurface>;
614
+ /** §12.8 — the host's `PropertyField` (and its schema-panel property
615
+ * rows) render LIST and STRUCT values with `items` / `fields`, editing
616
+ * through `editValue`. Makes `supports("widgets.propertyField.values@1")`
617
+ * true (only together with `widgets.PropertyField`). */
618
+ propertyFieldValues?: boolean;
434
619
  /** The host's will-save registry. When absent, `document.onWillSave`
435
620
  * holds listeners that never run and `supports("document.onWillSave@1")`
436
621
  * is false. */
@@ -515,6 +700,10 @@ interface CreateBundleHostOptions {
515
700
  * `supports("documents.exportPaged@1")` / `supports("documents.open@1")`
516
701
  * answer true. When absent, both doors reject. */
517
702
  documents?: DocumentsBackend;
703
+ /** v70 — page navigation for `host.viewport` (`goToPage`,
704
+ * `activePage`, `onDidChangeActivePage`). When present,
705
+ * `supports("viewport.pages@1")` is true. */
706
+ pages?: PagesBackend;
518
707
  /** Host-provided WORKER backend (K-3 / S-07 / I-02). When present,
519
708
  * `host.workers.spawn` resolves a declared bundle-relative module +
520
709
  * constructs a host-owned `Worker` through it (capability-gated,
@@ -552,6 +741,75 @@ interface BundleHostHandle {
552
741
  }
553
742
  declare function createBundleHost(getEditor: () => PagedEditor, manifest: PluginManifest, options?: CreateBundleHostOptions): BundleHostHandle;
554
743
 
744
+ /** One call a suspended script makes (core `HostObjectCall`). */
745
+ type HostObjectCall = {
746
+ op: "get";
747
+ address: string;
748
+ path: string;
749
+ } | {
750
+ op: "batch";
751
+ ops: unknown[];
752
+ } | {
753
+ op: "query";
754
+ selector: string;
755
+ } | {
756
+ op: "schema";
757
+ target: string;
758
+ }
759
+ /** A typed command (`paged.invoke`): `core.<op>` or a plugin's. */
760
+ | {
761
+ op: "invoke";
762
+ id: string;
763
+ args?: unknown;
764
+ }
765
+ /** The typed commands on offer (`paged.commands`), optionally one owner's. */
766
+ | {
767
+ op: "commands";
768
+ owner?: string;
769
+ };
770
+ /** The answer to one call (core `HostObjectAnswer`). */
771
+ interface HostObjectAnswer {
772
+ value?: unknown;
773
+ error?: {
774
+ code: string;
775
+ reason: string;
776
+ index?: number;
777
+ } | null;
778
+ }
779
+ interface ScriptRunResult {
780
+ output: string[];
781
+ error: string | null;
782
+ budgetKind?: string | null;
783
+ /** Host round trips the script took (0 = it never touched a plugin). */
784
+ hostRounds: number;
785
+ }
786
+ /** A request/reply door onto the engine (`client.send`). */
787
+ type ScriptSend = (message: {
788
+ kind: string;
789
+ payload: unknown;
790
+ }) => Promise<{
791
+ kind: string;
792
+ payload?: any;
793
+ }>;
794
+ /** Answer a suspended script's calls through the object registry, one
795
+ * answer per call, in order. Never throws: a failure is the answer's
796
+ * `error` (the script sees an exception carrying its `code`). */
797
+ declare function answerHostObjects(objects: ObjectsSurface, calls: readonly HostObjectCall[]): Promise<HostObjectAnswer[]>;
798
+ /** {@link answerHostObjects}, plus `committed`: the engine `appliedSeq` of
799
+ * every write made ANSWERING these calls (a batch that committed). The
800
+ * host sends it as `HostObjectsResult.committed` — protocol 71 folds only
801
+ * a script session's own undo records, so without it a script's plugin
802
+ * write would be a separate undo step; a write made by anyone else
803
+ * while the script waits is never listed and stays its own step. */
804
+ declare function answerHostObjectsRound(objects: ObjectsSurface, calls: readonly HostObjectCall[]): Promise<{
805
+ answers: HostObjectAnswer[];
806
+ committed: number[];
807
+ }>;
808
+ /** Run a script whose `plugin:` calls are answered by `objects`. */
809
+ declare function runScriptWithObjects(send: ScriptSend, objects: ObjectsSurface | null, source: string, options?: {
810
+ budget?: unknown;
811
+ }): Promise<ScriptRunResult>;
812
+
555
813
  /** The published package the headless harness boots. */
556
814
  declare const CANVAS_WASM_PKG = "@paged-media/canvas-wasm";
557
815
  /**
@@ -633,7 +891,7 @@ interface RecordedContribution {
633
891
  id: string;
634
892
  value: ToolContribution | PanelContribution | SchemaPanelContribution | CommandContribution | KeybindingContribution | OverlayContribution | EditContextContribution | ObjectTypeContribution | ImporterContribution | ExporterContribution;
635
893
  }
636
- interface HarnessOptions extends LoadHeadlessEngineOptions, Pick<CreateBundleHostOptions, "console" | "storage" | "capabilityMode" | "assetSource" | "blobStore" | "clipboard" | "secrets" | "bindingProviders" | "willSave" | "toolSettings"> {
894
+ interface HarnessOptions extends LoadHeadlessEngineOptions, Pick<CreateBundleHostOptions, "console" | "storage" | "capabilityMode" | "assetSource" | "blobStore" | "clipboard" | "secrets" | "bindingProviders" | "dataProviders" | "objects" | "willSave" | "toolSettings"> {
637
895
  /** D-27 — back `host.text` with the ENGINE's shaper
638
896
  * (`CanvasWorker.measureText`, the one the editor's worker calls)
639
897
  * instead of the estimate, so `measureString` / `measureStrings`
@@ -739,6 +997,22 @@ interface HeadlessHost {
739
997
  * that a path it does not declare comes back as a typed refusal to
740
998
  * fall through to core). */
741
999
  readonly bindingProviders: BindingProviderBackend;
1000
+ /** ADR 323 — the SHARED object registry every bundle host here routes
1001
+ * through (core addresses over this engine + every loaded bundle's
1002
+ * kinds). The ungated host side: what the Node CLI, a Boa bridge or a
1003
+ * conformance test calls. */
1004
+ readonly objects: ObjectRegistry;
1005
+ /** Run a `paged.*` Boa script against the loaded document with the
1006
+ * async host bridge armed (ADR 323, engine protocol 71): its `plugin:`
1007
+ * addresses are answered by `objects`, so core and plugin writes of one
1008
+ * script land as ONE undo step. */
1009
+ runScript(source: string, options?: {
1010
+ budget?: unknown;
1011
+ }): Promise<ScriptRunResult>;
1012
+ /** The SHARED data-provider registry (D-09) injected into every bundle
1013
+ * host here, so a provider bundle and a consumer bundle rendezvous
1014
+ * headlessly and `supports("dataProviders@1")` is true. */
1015
+ readonly dataProviders: DataProviderBackend;
742
1016
  /** The will-save registry this host injected: `fire()` runs every
743
1017
  * bundle's `document.onWillSave` listener and awaits them, as a save
744
1018
  * would. */
@@ -749,6 +1023,21 @@ interface HeadlessHost {
749
1023
  /** Load an IDML package into the headless document. Resolves to the
750
1024
  * loaded page ids (or throws on a parse failure). */
751
1025
  load(idml: Uint8Array): Promise<string[]>;
1026
+ /** ADR 324 — the core EXPORT door the Node CLI (and a conformance test)
1027
+ * calls: the active document as `.paged` (`exportPaged`), `.idml`
1028
+ * (`exportIdml`, `linkBase` for relative links) or PDF (the
1029
+ * `exportPdfBegin` → one `exportPdfPage` per page → `exportPdfFinish`
1030
+ * loop the editor's client drives; `pdf` is the wire's
1031
+ * `ExportPdfWireOptions`). Rejects with the engine's error. Plugin
1032
+ * formats go through `exportersContributed()`. */
1033
+ exportDocument(format: "paged" | "idml" | "pdf", options?: {
1034
+ pdf?: Record<string, unknown>;
1035
+ linkBase?: string | null;
1036
+ }): Promise<{
1037
+ bytes: Uint8Array;
1038
+ diagnostics: string[];
1039
+ lost?: string[];
1040
+ }>;
752
1041
  /** D-26 — every document a bundle opened through `host.documents.open`,
753
1042
  * in order (declined opens are not listed). */
754
1043
  openedDocuments(): ReadonlyArray<{
@@ -756,9 +1045,11 @@ interface HeadlessHost {
756
1045
  requester: string;
757
1046
  pageIds: string[];
758
1047
  }>;
759
- /** Activate a bundle against this host (apiVersion-negotiated). The
760
- * returned disposer runs the bundle's teardown; the host's own
761
- * facade teardown runs on `dispose()`. */
1048
+ /** Activate a bundle against this host (apiVersion-negotiated). Several
1049
+ * bundles may be loaded at once (each gets its own host bound to its
1050
+ * manifest; they meet through the shared registries — objects, data
1051
+ * providers, binding providers). `host` is the LAST loaded bundle's.
1052
+ * The returned disposer runs that bundle's teardown. */
762
1053
  loadBundle(bundle: PagedBundle): Disposable;
763
1054
  /** Tear down: bundle teardown + facade teardown + free the wasm. The
764
1055
  * honesty contract — after dispose the contribution log is empty and
@@ -802,6 +1093,168 @@ declare const API_VERSION = "0.2.0";
802
1093
  */
803
1094
  declare function satisfiesApiVersion(range: string, version?: string): boolean;
804
1095
 
1096
+ declare const VALUE_TYPE_KINDS: readonly ["bool", "number", "length", "color", "enum", "text", "ref", "bounds", "transform", "point", "bytes", "asset", "list", "map", "struct"];
1097
+ /** Why `t` is not a well-formed `ValueType`, or null. */
1098
+ declare function checkValueType(t: unknown, at?: string): string | null;
1099
+ /**
1100
+ * Path grammar of a schema ROW: dotted identifiers, each optionally
1101
+ * followed by bracket segments. `[]` makes an INDEXED row (`points[]`,
1102
+ * `points[].anchor`, `ranges[][]`) that stands for every `points[3]` /
1103
+ * `cells[B4]` a caller names; its type is the type of ONE item at that
1104
+ * index. A concrete index (`colorize[0]`) is an ordinary row and wins
1105
+ * over the indexed one.
1106
+ */
1107
+ declare const ROW_PATH: RegExp;
1108
+ /** The row path a concrete path resolves to: every `[<index>]` becomes
1109
+ * `[]` (`points[3].anchor` → `points[].anchor`). Bracket contents may be
1110
+ * any text without `]` (a list index, a map key such as `x-paged:oid`). */
1111
+ declare function rowPathOf(path: string): string;
1112
+ /** Find the row for a concrete path: exact first, then its indexed form. */
1113
+ declare function findRow<R extends {
1114
+ path: string;
1115
+ }>(rows: ReadonlyMap<string, R>, path: string): R | null;
1116
+ /** Why a schema row list is unusable (empty, malformed, duplicate path). */
1117
+ declare function checkSchemaRows(rows: unknown): string | null;
1118
+ /** Why `value` does not satisfy `type` (and the row's range / nullable), or
1119
+ * null when it does. */
1120
+ declare function validateValue(type: ValueType, value: unknown, row?: Pick<PropertySchema, "nullable" | "range">, at?: string): string | null;
1121
+ /** Bytes → the `data:` URI core reads an asset back as (the MIME typed by
1122
+ * the bytes' magic, the same table core uses; otherwise
1123
+ * `application/octet-stream`). */
1124
+ declare function assetFromBytes(bytes: Uint8Array | ArrayBuffer): string;
1125
+ /**
1126
+ * Fill struct DEFAULTS into a value that already validated: a missing
1127
+ * field with a `default` gets it (recursively, also inside lists and
1128
+ * maps); optional fields stay absent. An `asset` given as bytes is
1129
+ * encoded to its `data:` URI. Returns a new value; the input is
1130
+ * not mutated.
1131
+ */
1132
+ declare function applyDefaults(type: ValueType, value: unknown): unknown;
1133
+ /** Parse a length with an optional unit (`"3mm"`, `"12"`, `"0.5in"`) into
1134
+ * points; null when it is not one. */
1135
+ declare function parseLength(text: string): number | null;
1136
+ /**
1137
+ * EXPLICIT coercion of a loosely typed input (a CLI argument, a CSV cell)
1138
+ * to `type`. Returns `{ ok: true, value }` or `{ ok: false, reason }`; the
1139
+ * coerced value is then checked with `validateValue` as usual. Values that
1140
+ * already have the right shape pass through unchanged.
1141
+ */
1142
+ declare function coerceValue(type: ValueType, input: unknown): {
1143
+ ok: true;
1144
+ value: unknown;
1145
+ } | {
1146
+ ok: false;
1147
+ reason: string;
1148
+ };
1149
+
1150
+ /** An engine error text → the refusal code it means. */
1151
+ declare function codeOfEngineError(text: string): ObjectErrorCode;
1152
+
1153
+ /** The command id prefix: `core.insertTable`. */
1154
+ declare const CORE_COMMAND_PREFIX = "core.";
1155
+ /** Wire ops that are NOT typed commands, each with the reason. */
1156
+ declare const CORE_COMMAND_EXCLUSIONS: Readonly<Record<string, string>>;
1157
+ /** What a creating command makes. `element`: the engine mints it (reported
1158
+ * in `minted`, bindable by handle) — `multi` mints one per `elementIds`
1159
+ * entry; `page` / `layer`: found by diffing the page / layer list;
1160
+ * `named`: the address follows from the args. The Rust side of this table
1161
+ * is paged-canvas `created_element_id` (and `duplicate_roots`). */
1162
+ type Creates = {
1163
+ by: "element";
1164
+ kind: "frame" | "table";
1165
+ multi?: true;
1166
+ } | {
1167
+ by: "page";
1168
+ } | {
1169
+ by: "layer";
1170
+ } | {
1171
+ by: "named";
1172
+ address: (args: Record<string, unknown>) => string | null;
1173
+ };
1174
+ declare const CORE_COMMAND_CREATES: Readonly<Record<string, Creates>>;
1175
+ /** The ops that are typed commands, in wire order. */
1176
+ declare const CORE_COMMAND_OPS: readonly string[];
1177
+ /** The typed command list (static: it is the vendored wire's). */
1178
+ declare function coreCommandInfos(): ObjectCommandInfo[];
1179
+ declare const isCoreCommand: (id: string) => boolean;
1180
+
1181
+ interface CoreWireOpRow {
1182
+ args: Extract<ValueType, {
1183
+ kind: "struct";
1184
+ }>;
1185
+ nullFill: readonly string[];
1186
+ }
1187
+ declare const CORE_WIRE_OPS: Readonly<Record<string, CoreWireOpRow>>;
1188
+
1189
+ type CorePathScope = "frame" | "story" | "cell" | "table" | "layer" | "page";
1190
+ interface CorePathRow {
1191
+ scope: CorePathScope;
1192
+ /** The wire `Value` variant a write carries. */
1193
+ wire: string;
1194
+ type?: ValueType;
1195
+ inferred?: true;
1196
+ readOnly?: true;
1197
+ }
1198
+ declare const OP: {
1199
+ readonly op: true;
1200
+ };
1201
+ /** A path the pre-71 wire does not carry: only the protocol-71 seam reaches it. */
1202
+ declare const V71: {
1203
+ readonly since: 71;
1204
+ };
1205
+ declare const CORE_PATHS: Record<PropertyPath, CorePathRow | typeof OP | typeof V71>;
1206
+ /** The catalog's advertised ALIASES (Boa names) → the wire path, mirrored
1207
+ * from `catalog.json` `pathAliases`. Accepted on input, never listed. */
1208
+ declare const CORE_PATH_ALIASES: Readonly<Record<string, PropertyPath>>;
1209
+ /** One `propertySchemas` row as core's catalog publishes it (protocol 71). */
1210
+ interface CoreCatalogRow {
1211
+ addressKind: string;
1212
+ appliesTo?: readonly string[];
1213
+ path: string;
1214
+ type: {
1215
+ kind: string;
1216
+ unit?: string;
1217
+ members?: readonly string[];
1218
+ to?: string;
1219
+ of?: string;
1220
+ shape?: string;
1221
+ };
1222
+ wire: string;
1223
+ nullable?: boolean;
1224
+ range?: {
1225
+ min?: number;
1226
+ max?: number;
1227
+ step?: number;
1228
+ };
1229
+ default?: unknown;
1230
+ access?: "readWrite" | "readOnly" | "derived";
1231
+ virtual?: {
1232
+ op: string;
1233
+ field?: string;
1234
+ clearOp?: string;
1235
+ } | null;
1236
+ bindable?: boolean;
1237
+ }
1238
+ /** A normalised core row: the SDK schema row, the wire `Value` variant a
1239
+ * write carries, and the CORE address kind the row belongs to (the SDK
1240
+ * folds `storyRange` into `story` and `group` into `frame`). */
1241
+ interface CoreRow71 {
1242
+ schema: PropertySchema;
1243
+ wire: string;
1244
+ coreKind: string;
1245
+ /** Not in core's catalog: typed from the interim table (CORE_ROWLESS_PATHS). */
1246
+ inferred?: true;
1247
+ }
1248
+ /** Core's catalog type → the SDK's `ValueType`; null for an OPERATION row
1249
+ * (path-point edits, outline / offset / simplify): those are geometry
1250
+ * ops, not values, and stay reachable as a raw wire `{ type, value }`. */
1251
+ declare function normalizeCoreType(t: CoreCatalogRow["type"]): ValueType | null;
1252
+ /** The raw rows of the vendored catalog (empty before protocol 71). */
1253
+ declare const CORE_CATALOG_ROWS: readonly CoreCatalogRow[];
1254
+ /** SDK kind → path → normalised row, from the vendored catalog. Indexed
1255
+ * core paths (`labels[key]`, `rows[i].height`) become `[]` rows. */
1256
+ declare function coreSchema71(): ReadonlyMap<string, ReadonlyMap<string, CoreRow71>>;
1257
+
805
1258
  /** The default widget catalog: a textarea CodeEditor and a native colour
806
1259
  * input. Each member is replaced by the one the host app injects through
807
1260
  * `createBundleHost({ widgets })`; members it omits keep the fallback. */
@@ -994,6 +1447,108 @@ declare function contributePanel(host: BundleHost, panel: PanelContribution): Di
994
1447
  * list the id). */
995
1448
  declare function contributeSchemaPanel(host: BundleHost, panel: SchemaPanelContribution): Disposable;
996
1449
 
1450
+ /** Is this row an object-model property row (the property row)? */
1451
+ declare function isPropertyRow(row: PanelSchemaRow): row is PanelSchemaPropertyRow;
1452
+ /** Options shared by the row builders (everything but `field`/`path`/`address`). */
1453
+ type PropertyRowOptions = Omit<PanelSchemaPropertyRow, "field" | "path" | "address">;
1454
+ /** One property row. */
1455
+ declare function propertyRow(path: string, address: PropertyFieldAddress, opts?: PropertyRowOptions): PanelSchemaPropertyRow;
1456
+ /** Rows for several paths of one kind, in order. `labels` maps a path to
1457
+ * its row label (absent = the schema row's title). */
1458
+ declare function propertyRows(kind: string, paths: readonly string[], address: PropertyFieldAddress, opts?: {
1459
+ labels?: Readonly<Record<string, string>>;
1460
+ row?: (path: string) => PropertyRowOptions;
1461
+ }): PanelSchemaPropertyRow[];
1462
+ /** Every property row of a schema, with where it sits. */
1463
+ declare function propertyRowsOf(schema: PanelSchema): Array<{
1464
+ section: number;
1465
+ row: number;
1466
+ field: PanelSchemaPropertyRow;
1467
+ }>;
1468
+ interface PanelSchemaIssue {
1469
+ /** `sections[1].rows[3]` — where the problem is. */
1470
+ at: string;
1471
+ message: string;
1472
+ }
1473
+ interface ValidatePanelSchemaOptions {
1474
+ /** The schema rows of a qualified kind (`plugin:<id>/<kind>`), or
1475
+ * `undefined` when unknown. With it, every property row's path is
1476
+ * checked against its kind's schema. */
1477
+ schemaOf?: (kind: string) => readonly PropertySchema[] | undefined;
1478
+ /** The bundle's plugin id: a `plugin:` kind or address of ANOTHER plugin
1479
+ * is then reported (a panel edits its own objects or core's). */
1480
+ pluginId?: string;
1481
+ }
1482
+ /** The qualified kind a selector selects (its last step's head), if any. */
1483
+ declare function selectorKind(selector: string): string | null;
1484
+ /**
1485
+ * Every problem in a panel schema, as data. An empty list = it renders as
1486
+ * declared. Checks the property rows in full (address form, kind,
1487
+ * path against `schemaOf`) and the v1 rows' one structural rule (a
1488
+ * non-empty widget id).
1489
+ */
1490
+ declare function validatePanelSchema(schema: PanelSchema, opts?: ValidatePanelSchemaOptions): PanelSchemaIssue[];
1491
+
1492
+ type Ok<T> = {
1493
+ ok: true;
1494
+ } & T;
1495
+ type No = {
1496
+ ok: false;
1497
+ code: ObjectErrorCode;
1498
+ reason: string;
1499
+ };
1500
+ /** The value a new item / an unset field starts from: a struct's field
1501
+ * defaults (required fields without one get their type's default,
1502
+ * optional ones stay absent), an enum's first member, 0, "", false, [],
1503
+ * `Color/Black` for a colour, the zero point / identity transform. */
1504
+ declare function defaultValueOf(type: ValueType, row?: Pick<PropertySchema, "default" | "range">): unknown;
1505
+ /**
1506
+ * Apply one edit to a value of `type` (a list, or a struct for
1507
+ * `fieldSet`). Pure; the result is validated against `type`.
1508
+ */
1509
+ declare function applyValueEdit(current: unknown, edit: ValueEdit, type: ValueType): Ok<{
1510
+ value: unknown;
1511
+ }> | No;
1512
+ type Reader = Pick<ObjectsSurface, "get" | "schema">;
1513
+ /**
1514
+ * Lower one edit of `path` on every target to `set` ops (read, apply,
1515
+ * set). Each target is edited from its OWN current value, so a multi-
1516
+ * selection stays per-object. Refusals are typed; no op is produced
1517
+ * unless every target accepts the edit.
1518
+ */
1519
+ declare function planValueEdit(objects: Reader, addresses: readonly Address[], path: string, edit: ValueEdit): Promise<Ok<{
1520
+ ops: ObjectOp[];
1521
+ }> | No>;
1522
+ /** {@link planValueEdit}, then ONE `batch` (one undo step). */
1523
+ declare function editValue(objects: Reader & Pick<ObjectsSurface, "batch">, addresses: readonly Address[], path: string, edit: ListEdit | StructEdit, opts?: {
1524
+ label?: string;
1525
+ }): Promise<ObjectWriteResult>;
1526
+
1527
+ interface ObjectListRow {
1528
+ selfId: Address;
1529
+ name: string;
1530
+ secondary?: string;
1531
+ }
1532
+ interface PublishObjectListOptions {
1533
+ /** Binding the rows are published under (the list row's `items.bind`). */
1534
+ rows: string;
1535
+ /** Binding holding the chosen address (the list row's
1536
+ * `selectionBinding`, the property rows' `{ bind }`). */
1537
+ select: string;
1538
+ /** The selector to list, from the selection's addresses; `null` = no
1539
+ * list (empty rows). E.g. `(sel) => sel.length === 1 ? `${sel[0]} > plugin:x/layer` : null`. */
1540
+ selector(selection: readonly Address[]): string | null;
1541
+ /** Path read for the row label (default `name`; the address id else). */
1542
+ labelPath?: string;
1543
+ /** Path read for the secondary line. */
1544
+ secondaryPath?: string;
1545
+ }
1546
+ /** Publish the list and keep it live. Dispose to stop. */
1547
+ declare function publishObjectList(host: BundleHost, opts: PublishObjectListOptions): Disposable & {
1548
+ /** Re-read now (resolves when published). */
1549
+ refresh(): Promise<void>;
1550
+ };
1551
+
997
1552
  /** Register an EDIT CONTEXT (B-02): a content type that, on
998
1553
  * double-click (or programmatically), pushes a scoped context —
999
1554
  * restricted tools, emphasized panels, breadcrumb, narrowed
@@ -1021,4 +1576,4 @@ declare function contributeObjectType(host: BundleHost, contribution: ObjectType
1021
1576
  */
1022
1577
  declare function contributeBindingProvider(host: BundleHost, contextType: string, provider: BindingProvider): BindingProviderHandle;
1023
1578
 
1024
- export { API_VERSION, ASSET_BUDGETS, BLOB_BUDGETS, type BindingProviderBackend, type BlobStore, type BundleAssetProvider, type BundleAssetSource, type BundleHostHandle, type BundleTrust, CANVAS_WASM_PKG, CLICK_DRAG_THRESHOLD_PX, type ClipboardBackend, type ConsentBackend, type CreateBundleHostOptions, type DataProviderBackend, type DiagnosticsSink, DisposableStore, type DocumentsBackend, FALLBACK_WIDGETS, HOST_FEATURES, type HarnessOptions, type HeadlessCanvasWorker, type HeadlessHost, type HeadlessHostHandle, type JournalSink, type LoadBundleWasmOptions, type LoadHeadlessEngineOptions, type LoadedBundle, type LoadedBundleWasm, type LoadedEngine, type NativeDocumentBackend, type PageDrag, PluginApiNotImplemented, PluginCapabilityError, type RecordableAssetSource, type RecordedContribution, type RecordedFontFaceRequest, type RegisteredBindingProvider, type SecretStoreBackend, type SeededFace, type ShellBackend, type SpawnedWorker, type StorageBacking, type TextCaretBackend, type ToolSettingsBackend, WASM_BUDGETS, WORKER_BUDGETS, type WillSaveBackend, type WorkerBackend, beginPageDrag, commitAndSelect, contributeBindingProvider, contributeEditContext, contributeObjectType, contributePanel, contributeSchemaPanel, contributeTool, createBindingProviderRegistry, createBundleHost, createDataProviderRegistry, createHeadlessHost, createRecordableAssetSource, defineBundle, endLocalFor, inMemoryToolSettings, inMemoryWillSave, loadBundle, loadBundleWasm, loadHeadlessEngine, makeSchemaPanelComponent, protocolFromVersion, pxToPt, readVendoredWireVersion, resolveCanvasWasm, resolveGate, satisfiesApiVersion, toDisposable };
1579
+ export { API_VERSION, ASSET_BUDGETS, BLOB_BUDGETS, type BindingProviderBackend, type BlobStore, type BundleAssetProvider, type BundleAssetSource, type BundleHostHandle, type BundleTrust, CANVAS_WASM_PKG, CLICK_DRAG_THRESHOLD_PX, CORE_CATALOG_ROWS, CORE_COMMAND_CREATES, CORE_COMMAND_EXCLUSIONS, CORE_COMMAND_OPS, CORE_COMMAND_PREFIX, CORE_PATHS, CORE_PATH_ALIASES, CORE_WIRE_OPS, type ClipboardBackend, type ConsentBackend, type CoreCatalogRow, type CoreCreatePlan, type CoreObjects, type CorePathRow, type CorePathScope, type CorePlan, type CoreRow71, type CoreWireOpRow, type CreateBundleHostOptions, type CreateCoreObjectsOptions, type CreateObjectRegistryOptions, type DataProviderBackend, type DiagnosticsSink, DisposableStore, type DocumentsBackend, FALLBACK_WIDGETS, FRAME_KIND_WORDS, HOST_FEATURES, type HarnessOptions, type HeadlessCanvasWorker, type HeadlessHost, type HeadlessHostHandle, type HostObjectAnswer, type HostObjectCall, type JournalSink, type LoadBundleWasmOptions, type LoadHeadlessEngineOptions, type LoadedBundle, type LoadedBundleWasm, type LoadedEngine, type NativeDocumentBackend, OBJECT_MODEL_PROTOCOL, type ObjectListRow, type ObjectModelRegistration, type ObjectRegistry, type PageDrag, type PagesBackend, type PanelSchemaIssue, type ParsedSelector, PluginApiNotImplemented, PluginCapabilityError, type PropertyRowOptions, type PublishObjectListOptions, ROW_PATH, type RecordableAssetSource, type RecordedContribution, type RecordedFontFaceRequest, type RegisteredBindingProvider, type ScriptRunResult, type ScriptSend, type SecretStoreBackend, type SeededFace, type SelectorHead, type SelectorPredicate, type SelectorStep, type ShellBackend, type SpawnedWorker, type StorageBacking, type TextCaretBackend, type ToolSettingsBackend, VALUE_TYPE_KINDS, type ValidatePanelSchemaOptions, WASM_BUDGETS, WORKER_BUDGETS, type WillSaveBackend, type WorkerBackend, addressKindOf, answerHostObjects, answerHostObjectsRound, applyDefaults, applyValueEdit, assetFromBytes, beginPageDrag, checkSchemaRows, checkValueType, codeOfEngineError, coerceValue, commitAndSelect, contributeBindingProvider, contributeEditContext, contributeObjectType, contributePanel, contributeSchemaPanel, contributeTool, coreCommandInfos, coreSchema71, createBindingProviderRegistry, createBundleHost, createCoreObjects, createDataProviderRegistry, createHeadlessHost, createObjectRegistry, createRecordableAssetSource, defaultValueOf, defineBundle, editValue, endLocalFor, escapeLabelValue, findRow, formatAddress, fromElementId, inMemoryToolSettings, inMemoryWillSave, isCoreCommand, isPropertyRow, loadBundle, loadBundleWasm, loadHeadlessEngine, makeSchemaPanelComponent, normalizeAddress, normalizeCoreType, parseAddress, parseLength, parseSelector, planValueEdit, propertyRow, propertyRows, propertyRowsOf, protocolFromVersion, publishObjectList, pxToPt, readVendoredWireVersion, resolveCanvasWasm, resolveGate, rowPathOf, runScriptWithObjects, satisfiesApiVersion, selectorKind, toDisposable, toElementId, validatePanelSchema, validateValue };