@paged-media/plugin-sdk 0.2.6-canary.0 → 0.2.8-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.
- package/dist/index.d.ts +480 -32
- package/dist/index.js +1294 -38
- package/package.json +14 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { PagedBundle, BundleHost, Disposable, ShellSurface,
|
|
1
|
+
import { PagedBundle, FontFaceAsset, BundleHost, ConsentResult, DataProviderRegistration, DataProviderHandle, DataProviderInfo, DataProviderSnapshot, Disposable, ShellSurface, WidgetSurface, SchemaPanelRenderer, SchemaPanelContribution, EditContextContribution, ObjectTypeContribution, Diagnostic, PagedEditor, PluginManifest, ToolContribution, PanelContribution, CommandContribution, KeybindingContribution, OverlayContribution, ImporterContribution, ExporterContribution, ToolPreviewShape, BindingsSurface, PanelProps, SchemaGate, WasmArtifact, CanvasPointerEvent, Mutation, MutationOutcome } from '@paged-media/plugin-api';
|
|
2
|
+
import { ComponentType } from 'react';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Identity helper that pins a bundle to the `PagedBundle` contract
|
|
@@ -8,36 +9,6 @@ import { PagedBundle, BundleHost, Disposable, ShellSurface, PagedEditor, PluginM
|
|
|
8
9
|
*/
|
|
9
10
|
declare function defineBundle(bundle: PagedBundle): PagedBundle;
|
|
10
11
|
|
|
11
|
-
interface HarnessOptions {
|
|
12
|
-
/** IDML bytes to load into the headless document. */
|
|
13
|
-
idml?: Uint8Array;
|
|
14
|
-
}
|
|
15
|
-
/** Not implemented in API v0 — see module comment. */
|
|
16
|
-
declare function createHeadlessHost(_options?: HarnessOptions): BundleHost;
|
|
17
|
-
|
|
18
|
-
declare class DisposableStore implements Disposable {
|
|
19
|
-
private items;
|
|
20
|
-
private disposed;
|
|
21
|
-
get isDisposed(): boolean;
|
|
22
|
-
/** Track `d`; returns it for chaining. */
|
|
23
|
-
add<T extends Disposable>(d: T): T;
|
|
24
|
-
dispose(): void;
|
|
25
|
-
}
|
|
26
|
-
/** Wrap a plain cleanup function as a Disposable. */
|
|
27
|
-
declare function toDisposable(fn: () => void): Disposable;
|
|
28
|
-
|
|
29
|
-
/** The plugin API version this SDK implements. */
|
|
30
|
-
declare const API_VERSION = "0.2.0";
|
|
31
|
-
/**
|
|
32
|
-
* Does `version` satisfy `range`? Supported forms:
|
|
33
|
-
* `*` — anything
|
|
34
|
-
* `1.2.3` / `1.2`— exact (missing patch = 0)
|
|
35
|
-
* `^1.2.3` — npm caret: same major, >= base (major > 0);
|
|
36
|
-
* same major+minor, >= patch (major == 0 — the 0.x
|
|
37
|
-
* rule: minors are breaking during incubation)
|
|
38
|
-
*/
|
|
39
|
-
declare function satisfiesApiVersion(range: string, version?: string): boolean;
|
|
40
|
-
|
|
41
12
|
/** The implemented feature set — `host.supports()` answers from this,
|
|
42
13
|
* so docs/tests can't drift from code. Form: `"area.member@major"`. */
|
|
43
14
|
declare const HOST_FEATURES: readonly string[];
|
|
@@ -46,6 +17,27 @@ declare const HOST_FEATURES: readonly string[];
|
|
|
46
17
|
declare class PluginApiNotImplemented extends Error {
|
|
47
18
|
constructor(member: string, pointer: string);
|
|
48
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Thrown (in `capabilityMode: 'enforce'`) when a bundle USES a host
|
|
22
|
+
* door it did not DECLARE in its manifest — the trust-line record's
|
|
23
|
+
* (W0.11) "manifest capabilities ENFORCED, not advisory" gate, applied
|
|
24
|
+
* at the chokepoint. Same loud-honesty style as the namespace gate: the
|
|
25
|
+
* message names the door, the missing declaration, and where to add it.
|
|
26
|
+
*
|
|
27
|
+
* v1 stance (in-process, no isolation): this is HONESTY +
|
|
28
|
+
* accident-prevention, not a security boundary — a bundle holding the
|
|
29
|
+
* raw `host.editor` handle can still bypass the facade. The error makes
|
|
30
|
+
* declaration↔use drift loud during dogfooding so the manifest stays a
|
|
31
|
+
* truthful description of what the bundle actually touches.
|
|
32
|
+
*/
|
|
33
|
+
declare class PluginCapabilityError extends Error {
|
|
34
|
+
/** The host door that was called (e.g. `"contribute.tool"`). */
|
|
35
|
+
readonly door: string;
|
|
36
|
+
/** The manifest declaration that would authorize it (e.g.
|
|
37
|
+
* `'contributes.tools[] must include "media.paged.web.tool.pen"'`). */
|
|
38
|
+
readonly missingDeclaration: string;
|
|
39
|
+
constructor(door: string, missingDeclaration: string, pluginId: string);
|
|
40
|
+
}
|
|
49
41
|
/** Minimal storage backing so tests / headless hosts can inject one;
|
|
50
42
|
* defaults to localStorage when present, else an in-memory Map. */
|
|
51
43
|
interface StorageBacking {
|
|
@@ -55,14 +47,168 @@ interface StorageBacking {
|
|
|
55
47
|
/** All keys currently in the backing (unfiltered). */
|
|
56
48
|
keys(): string[];
|
|
57
49
|
}
|
|
50
|
+
/** The host-provided network consent primitive (paged.data D-03; base-idea §11).
|
|
51
|
+
* The editor owns the consent UI (the visible data-source manifest) and the
|
|
52
|
+
* CSP `connect-src` enforcement; this hook is how the host adapter asks the
|
|
53
|
+
* user. When absent, `host.network.requestConsent` DENIES every origin (the
|
|
54
|
+
* honest no-consent posture) and `supports("network.consent@1")` is false. */
|
|
55
|
+
interface ConsentBackend {
|
|
56
|
+
request(origins: readonly string[], purpose: string): Promise<ConsentResult>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A host-side aggregator the editor injects to power a PROBLEMS PANEL
|
|
60
|
+
* (paged.web W-05): every `host.diagnostics.set/clear` is mirrored
|
|
61
|
+
* here keyed by `(bundleId, key)`, so one editor surface can list
|
|
62
|
+
* diagnostics across all loaded bundles. The per-bundle in-host store
|
|
63
|
+
* (`host.diagnostics.get`) is unchanged — this is a fan-out, not a
|
|
64
|
+
* replacement. `bundleId` lets the panel attribute + de-dupe and
|
|
65
|
+
* lets click-to-focus resolve the owning panel.
|
|
66
|
+
*/
|
|
67
|
+
interface DiagnosticsSink {
|
|
68
|
+
publish(bundleId: string, key: string, diagnostics: Diagnostic[]): void;
|
|
69
|
+
clear(bundleId: string, key?: string): void;
|
|
70
|
+
}
|
|
71
|
+
/** Asset-store budgets (W-06). The per-face cap mirrors the wasm lane's
|
|
72
|
+
* per-artifact ceiling (DESIGN.md §10/§13.3) — a bundle can never be
|
|
73
|
+
* handed an unbounded face buffer. The host facade refuses an
|
|
74
|
+
* over-budget face (returns `null` + a `log.warn`). */
|
|
75
|
+
declare const ASSET_BUDGETS: {
|
|
76
|
+
/** Largest font face the door will serve, in bytes (8 MiB). */
|
|
77
|
+
readonly maxFontFaceBytes: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The byte source the editor injects to back `host.assets` (W-06). The
|
|
81
|
+
* same injection shape as `widgets`/`diagnosticsSink`: a value the host
|
|
82
|
+
* app passes at `loadBundle` time. It serves the bytes the DOCUMENT
|
|
83
|
+
* already holds for a face — READ-ONLY, never a network fetch on the
|
|
84
|
+
* bundle's behalf (offline-forever, DESIGN.md §13.3). Returning `null`
|
|
85
|
+
* is the honest no-bytes answer (an unregistered family, or — in v1 of
|
|
86
|
+
* the editor adapter — every family, until the engine exposes a
|
|
87
|
+
* font-bytes read-back; DESIGN.md §13.4).
|
|
88
|
+
*/
|
|
89
|
+
interface BundleAssetProvider {
|
|
90
|
+
/** The bytes of a document font face, or `null` when the host has
|
|
91
|
+
* none. Style-agnostic when `style` is omitted. */
|
|
92
|
+
getFontFace(family: string, style?: string): Promise<FontFaceAsset | null>;
|
|
93
|
+
}
|
|
94
|
+
/** Blob-store budgets (K-4 / S-08). The default per-plugin quota when a
|
|
95
|
+
* manifest requests none; a manifest's `storage.quotaBytes` may only
|
|
96
|
+
* TIGHTEN it (the adapter enforces the stricter). */
|
|
97
|
+
declare const BLOB_BUDGETS: {
|
|
98
|
+
/** Default per-plugin blob ceiling, in bytes (64 MiB). */
|
|
99
|
+
readonly defaultQuotaBytes: number;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* The backend the editor injects to back `host.blob` (K-4 / S-08): a
|
|
103
|
+
* RAW per-plugin byte store (OPFS in-browser; an in-memory map in the
|
|
104
|
+
* headless harness). The SDK adapter owns namespacing (passes the
|
|
105
|
+
* plugin id), the capability gate, and the quota — the backend only does
|
|
106
|
+
* scoped IO. Keys are opaque strings the adapter forwards verbatim.
|
|
107
|
+
*/
|
|
108
|
+
interface BlobStore {
|
|
109
|
+
write(pluginId: string, key: string, bytes: Uint8Array): Promise<void>;
|
|
110
|
+
read(pluginId: string, key: string): Promise<Uint8Array | null>;
|
|
111
|
+
delete(pluginId: string, key: string): Promise<void>;
|
|
112
|
+
keys(pluginId: string): Promise<string[]>;
|
|
113
|
+
/** Total bytes this plugin currently stores. */
|
|
114
|
+
used(pluginId: string): Promise<number>;
|
|
115
|
+
}
|
|
116
|
+
/** The SHARED cross-plugin data-provider registry (paged.data §7.1 / D-09). The
|
|
117
|
+
* editor creates ONE (`createDataProviderRegistry`) and injects the SAME
|
|
118
|
+
* instance into every plugin host, so a provider plugin and a consumer plugin
|
|
119
|
+
* rendezvous through it. The per-plugin capability gate lives in the host
|
|
120
|
+
* surface; this backend is the neutral store + fan-out. */
|
|
121
|
+
interface DataProviderBackend {
|
|
122
|
+
register(registration: DataProviderRegistration): DataProviderHandle;
|
|
123
|
+
discover(category?: string): readonly DataProviderInfo[];
|
|
124
|
+
get(id: string): Promise<DataProviderSnapshot | null>;
|
|
125
|
+
onDidChange(id: string, listener: (revision: string) => void): Disposable;
|
|
126
|
+
}
|
|
127
|
+
/** Build a shared in-memory data-provider registry (D-09). The editor holds ONE
|
|
128
|
+
* and injects it into every `createBundleHost` call as `options.dataProviders`;
|
|
129
|
+
* providers and consumers (different plugin hosts) meet through it. Reference
|
|
130
|
+
* implementation — an RPC/isolate host swaps a proxy with the same contract. */
|
|
131
|
+
declare function createDataProviderRegistry(): DataProviderBackend;
|
|
58
132
|
interface CreateBundleHostOptions {
|
|
59
133
|
storage?: StorageBacking;
|
|
134
|
+
/** Host-provided network consent (paged.data D-03; base-idea §11): the editor
|
|
135
|
+
* injects the consent prompt + the data-source-manifest UI. When absent,
|
|
136
|
+
* `host.network` denies every origin and `supports("network.consent@1")` is
|
|
137
|
+
* false (the honest no-consent posture). */
|
|
138
|
+
consent?: ConsentBackend;
|
|
139
|
+
/** Host-provided SHARED data-provider registry (paged.data §7.1 / D-09): the
|
|
140
|
+
* editor creates ONE (`createDataProviderRegistry`) and injects the SAME
|
|
141
|
+
* instance into every plugin host, so a provider and a consumer rendezvous
|
|
142
|
+
* through it. When absent, `host.dataProviders` discover() is empty +
|
|
143
|
+
* register() is a no-op and `supports("dataProviders@1")` is false. */
|
|
144
|
+
dataProviders?: DataProviderBackend;
|
|
60
145
|
/** Console sink override (tests). */
|
|
61
146
|
console?: Pick<Console, "debug" | "info" | "warn" | "error">;
|
|
62
147
|
/** Shell actions the HOST APP owns (the cockpit's panel placement).
|
|
63
148
|
* When absent, `host.shell` warns and no-ops, and
|
|
64
149
|
* `supports("shell.openPanel@1")` answers false. */
|
|
65
150
|
shell?: ShellSurface;
|
|
151
|
+
/** Host-provided panel widgets (W-04): the real code editor lives in
|
|
152
|
+
* the editor's UI package and is injected here. When absent,
|
|
153
|
+
* `host.widgets` is the plain-textarea fallback and
|
|
154
|
+
* `supports("widgets.codeEditor@1")` answers false. */
|
|
155
|
+
widgets?: WidgetSurface;
|
|
156
|
+
/** Host-provided SCHEMA-PANEL renderer (W3.1): the editor's
|
|
157
|
+
* `SchemaPanelRenderer` that walks a `PanelSchema` through the
|
|
158
|
+
* catalog + subscribes to the bundle's bindings. When absent,
|
|
159
|
+
* `contribute.schemaPanel` registers a visible "needs a host
|
|
160
|
+
* renderer" seam panel (never a throw, never fake UI) and
|
|
161
|
+
* `supports("contribute.schemaPanel@1")` still answers true (the
|
|
162
|
+
* door exists; only the rich rendering is host-injected). */
|
|
163
|
+
schemaPanelRenderer?: SchemaPanelRenderer;
|
|
164
|
+
/** Internal registration hook (the headless harness): called at the
|
|
165
|
+
* moment a schema panel registers, with the verbatim contribution,
|
|
166
|
+
* so the conformance log can record the SCHEMA assertably (the
|
|
167
|
+
* registry only sees the synthesized React `PanelContribution`). The
|
|
168
|
+
* returned disposer (if any) is tracked alongside the panel
|
|
169
|
+
* registration. Not part of the public contract — a host-adapter
|
|
170
|
+
* seam. */
|
|
171
|
+
onSchemaPanelRegistered?: (contribution: SchemaPanelContribution) => Disposable | void;
|
|
172
|
+
/** Internal registration hook (the headless harness, W3.2): called
|
|
173
|
+
* when an EDIT CONTEXT registers (after the namespace + capability
|
|
174
|
+
* gates pass), with the verbatim contribution, so the conformance log
|
|
175
|
+
* can record it. When the editor provides no `editContexts` registry,
|
|
176
|
+
* this is ALSO the recording stub's only consumer — the door no
|
|
177
|
+
* longer throws, it records. Not part of the public contract. */
|
|
178
|
+
onEditContextRegistered?: (contribution: EditContextContribution) => Disposable | void;
|
|
179
|
+
/** Internal registration hook (the headless harness, W3.2): the
|
|
180
|
+
* object-type analogue of `onEditContextRegistered`. */
|
|
181
|
+
onObjectTypeRegistered?: (contribution: ObjectTypeContribution) => Disposable | void;
|
|
182
|
+
/** Host-side problems-panel aggregator (W-05). When present,
|
|
183
|
+
* `supports("diagnostics.publish@1")` answers true and every
|
|
184
|
+
* `host.diagnostics.set/clear` fans out to it. */
|
|
185
|
+
diagnosticsSink?: DiagnosticsSink;
|
|
186
|
+
/** Host-provided ASSET byte source (W-06). When present,
|
|
187
|
+
* `host.assets.getFontFace` serves DOCUMENT font face bytes through
|
|
188
|
+
* it (capability-gated, budget-clamped) and
|
|
189
|
+
* `supports("assets.fonts@1")` answers true. When absent, every
|
|
190
|
+
* asset read answers `null` (the honest no-bytes door) and the
|
|
191
|
+
* feature flag is false. */
|
|
192
|
+
assetSource?: BundleAssetProvider;
|
|
193
|
+
/** Host-provided BLOB backend (K-4 / S-08). When present,
|
|
194
|
+
* `host.blob.*` persists per-plugin bytes through it (capability-
|
|
195
|
+
* gated, quota-clamped) and `supports("storage.blob@1")` answers true.
|
|
196
|
+
* When absent, reads answer empty and writes reject (the honest
|
|
197
|
+
* no-store door). */
|
|
198
|
+
blobStore?: BlobStore;
|
|
199
|
+
/**
|
|
200
|
+
* How the host treats a declaration↔use mismatch — a bundle that
|
|
201
|
+
* USES a door (`contribute.tool`, `document.mutate`, …) it did not
|
|
202
|
+
* DECLARE in its manifest (trust-line W0.11). Defaults to
|
|
203
|
+
* `'enforce'`: the violating call throws `PluginCapabilityError`
|
|
204
|
+
* (contribution registrations) or returns a non-applied
|
|
205
|
+
* `MutationOutcome` for the write doors (mutate-never-throws). In
|
|
206
|
+
* `'warn'` mode the violation is logged through `host.log.warn`
|
|
207
|
+
* and the call proceeds — the migration escape hatch for a host
|
|
208
|
+
* that loads not-yet-adopted manifests. The namespace gate and the
|
|
209
|
+
* metadata-namespace gate are UNAFFECTED — they are always loud.
|
|
210
|
+
*/
|
|
211
|
+
capabilityMode?: "enforce" | "warn";
|
|
66
212
|
}
|
|
67
213
|
interface BundleHostHandle {
|
|
68
214
|
host: BundleHost;
|
|
@@ -71,6 +217,214 @@ interface BundleHostHandle {
|
|
|
71
217
|
}
|
|
72
218
|
declare function createBundleHost(getEditor: () => PagedEditor, manifest: PluginManifest, options?: CreateBundleHostOptions): BundleHostHandle;
|
|
73
219
|
|
|
220
|
+
/** The published package the headless harness boots. */
|
|
221
|
+
declare const CANVAS_WASM_PKG = "@paged-media/canvas-wasm";
|
|
222
|
+
/**
|
|
223
|
+
* The wasm `CanvasWorker` surface the harness drives. A structural
|
|
224
|
+
* subset of the package's class — only the members the headless host
|
|
225
|
+
* needs. `handleMessage` is the JSON-envelope door; `loadDocumentDirect`
|
|
226
|
+
* is the binary side-channel for IDML bytes (the editor uses it to dodge
|
|
227
|
+
* the 8× `number[]` JSON inflation, and it is the only load path that
|
|
228
|
+
* does not require a `LoadDocument` envelope round-trip).
|
|
229
|
+
*/
|
|
230
|
+
interface HeadlessCanvasWorker {
|
|
231
|
+
readonly protocolVersion: number;
|
|
232
|
+
handleMessage(input: string): string;
|
|
233
|
+
loadDocumentDirect(seq: number, bytes: Uint8Array, font?: Uint8Array, cmykIccProfile?: Uint8Array): string;
|
|
234
|
+
runResolveJson(): string | undefined;
|
|
235
|
+
free(): void;
|
|
236
|
+
}
|
|
237
|
+
interface LoadedEngine {
|
|
238
|
+
worker: HeadlessCanvasWorker;
|
|
239
|
+
/** The resolved package version (`0.<protocol>.<patch>`). */
|
|
240
|
+
version: string;
|
|
241
|
+
/** The wasm's reported protocol (the package minor). */
|
|
242
|
+
protocolVersion: number;
|
|
243
|
+
}
|
|
244
|
+
interface LoadHeadlessEngineOptions {
|
|
245
|
+
/**
|
|
246
|
+
* Where to resolve `@paged-media/canvas-wasm` from. Defaults to this
|
|
247
|
+
* module's own resolution (the SDK's node_modules), then the editor's
|
|
248
|
+
* `packages/client` (the sibling-checkout dev luxury) — mirroring
|
|
249
|
+
* scripts/sync-wire.mjs so the loader and the wire stamp agree on
|
|
250
|
+
* WHICH installed package they describe.
|
|
251
|
+
*/
|
|
252
|
+
resolveFrom?: string;
|
|
253
|
+
/**
|
|
254
|
+
* Override the expected protocol the booted wasm must report. Defaults
|
|
255
|
+
* to the protocol derived from the vendored wire stamp. A mismatch
|
|
256
|
+
* throws — never silently downgrades.
|
|
257
|
+
*/
|
|
258
|
+
expectedProtocol?: number;
|
|
259
|
+
}
|
|
260
|
+
/** Extract `@<version>` from the vendored wire stamp, or null. Async:
|
|
261
|
+
* the file read pulls `node:fs`, deferred so the browser barrel stays
|
|
262
|
+
* import-safe (only the Node headless path ever calls this). */
|
|
263
|
+
declare function readVendoredWireVersion(wireDtsPath?: string): Promise<string | null>;
|
|
264
|
+
/** The package minor IS the wire protocol (`0.<protocol>.<patch>`). */
|
|
265
|
+
declare function protocolFromVersion(version: string): number | null;
|
|
266
|
+
/**
|
|
267
|
+
* Resolve the published package's loader JS + `_bg.wasm` on disk.
|
|
268
|
+
* Throws (never warn-skips) when the package cannot be resolved: a
|
|
269
|
+
* headless host with no engine behind it is the exact fiction the
|
|
270
|
+
* harness exists to prevent (B-13).
|
|
271
|
+
*/
|
|
272
|
+
declare function resolveCanvasWasm(resolveFrom?: string): Promise<{
|
|
273
|
+
loaderUrl: string;
|
|
274
|
+
wasmPath: string;
|
|
275
|
+
version: string;
|
|
276
|
+
dir: string;
|
|
277
|
+
}>;
|
|
278
|
+
/**
|
|
279
|
+
* Boot the published engine wasm in Node and return a `CanvasWorker`
|
|
280
|
+
* driving the editor's own dispatch. Asserts the booted protocol
|
|
281
|
+
* matches the vendored wire stamp.
|
|
282
|
+
*/
|
|
283
|
+
declare function loadHeadlessEngine(options?: LoadHeadlessEngineOptions): Promise<LoadedEngine>;
|
|
284
|
+
|
|
285
|
+
/** One captured contribution — the assertable conformance log entry.
|
|
286
|
+
* `kind` is the surface; `value` is the contribution object verbatim
|
|
287
|
+
* (so a test can assert ids, titles, shortcuts, dock edges, …). */
|
|
288
|
+
interface RecordedContribution {
|
|
289
|
+
kind: "tool" | "panel" | "schemaPanel" | "command" | "keybinding" | "overlay" | "editContext" | "objectType" | "importer" | "exporter";
|
|
290
|
+
id: string;
|
|
291
|
+
value: ToolContribution | PanelContribution | SchemaPanelContribution | CommandContribution | KeybindingContribution | OverlayContribution | EditContextContribution | ObjectTypeContribution | ImporterContribution | ExporterContribution;
|
|
292
|
+
}
|
|
293
|
+
interface HarnessOptions extends LoadHeadlessEngineOptions, Pick<CreateBundleHostOptions, "console" | "storage" | "capabilityMode" | "assetSource" | "blobStore"> {
|
|
294
|
+
}
|
|
295
|
+
/** What `createHeadlessHost` resolves to: a real engine-backed host plus
|
|
296
|
+
* the conformance affordances (load an IDML, read the contribution log,
|
|
297
|
+
* load a bundle, dispose honestly). */
|
|
298
|
+
interface HeadlessHost {
|
|
299
|
+
/** The BundleHost a bundle's `activate(host)` receives. */
|
|
300
|
+
readonly host: BundleHost;
|
|
301
|
+
/** The booted package version (`0.<protocol>.<patch>`). */
|
|
302
|
+
readonly engineVersion: string;
|
|
303
|
+
/** The wasm's reported protocol (the package minor). */
|
|
304
|
+
readonly protocolVersion: number;
|
|
305
|
+
/** Every contribution registered through `host.contribute.*`, in
|
|
306
|
+
* registration order. Cleared structurally on dispose. */
|
|
307
|
+
readonly contributions: readonly RecordedContribution[];
|
|
308
|
+
/** Contributions of one surface (e.g. `tools()` for the rail). */
|
|
309
|
+
toolsContributed(): ToolContribution[];
|
|
310
|
+
panelsContributed(): PanelContribution[];
|
|
311
|
+
/** Declarative (schema) panels registered through
|
|
312
|
+
* `contribute.schemaPanel` — the W3.1 surface, recorded verbatim. */
|
|
313
|
+
schemaPanelsContributed(): SchemaPanelContribution[];
|
|
314
|
+
/** Edit contexts registered through `contribute.editContext` — the
|
|
315
|
+
* W3.2 surface (B-02), recorded verbatim (matcher fn included). */
|
|
316
|
+
editContextsContributed(): EditContextContribution[];
|
|
317
|
+
/** Object types registered through `contribute.objectType` — the W3.2
|
|
318
|
+
* surface (W-03), recorded verbatim. */
|
|
319
|
+
objectTypesContributed(): ObjectTypeContribution[];
|
|
320
|
+
/** Document importers registered through `contribute.importer` (K-2 /
|
|
321
|
+
* S-06), recorded verbatim (extensions + the `import()` callback). */
|
|
322
|
+
importersContributed(): ImporterContribution[];
|
|
323
|
+
/** Document exporters registered through `contribute.exporter` (K-2 /
|
|
324
|
+
* S-06), recorded verbatim. */
|
|
325
|
+
exportersContributed(): ExporterContribution[];
|
|
326
|
+
/** The last tool preview a bundle pushed through
|
|
327
|
+
* `host.overlay.setToolPreview` (B-07). There is no overlay SURFACE
|
|
328
|
+
* headlessly, but the channel is RECORDED so conformance can assert a
|
|
329
|
+
* pen/anchor handler emits the cubic `ToolPreviewPath` variant (true
|
|
330
|
+
* Béziers) rather than a flattened polyline. `null` until set, and
|
|
331
|
+
* reset to `null` when the bundle clears its preview. */
|
|
332
|
+
lastToolPreview(): ToolPreviewShape | null;
|
|
333
|
+
/** Load an IDML package into the headless document. Resolves to the
|
|
334
|
+
* loaded page ids (or throws on a parse failure). */
|
|
335
|
+
load(idml: Uint8Array): Promise<string[]>;
|
|
336
|
+
/** Activate a bundle against this host (apiVersion-negotiated). The
|
|
337
|
+
* returned disposer runs the bundle's teardown; the host's own
|
|
338
|
+
* facade teardown runs on `dispose()`. */
|
|
339
|
+
loadBundle(bundle: PagedBundle): Disposable;
|
|
340
|
+
/** Tear down: bundle teardown + facade teardown + free the wasm. The
|
|
341
|
+
* honesty contract — after dispose the contribution log is empty and
|
|
342
|
+
* the engine handle is released. */
|
|
343
|
+
dispose(): void;
|
|
344
|
+
}
|
|
345
|
+
/** Reserved alias kept for source/back-compat — see `createHeadlessHost`. */
|
|
346
|
+
type HeadlessHostHandle = HeadlessHost;
|
|
347
|
+
/**
|
|
348
|
+
* Build a headless, engine-backed `BundleHost`. Async because booting
|
|
349
|
+
* the wasm is async. The returned handle drives the conformance loop:
|
|
350
|
+
* load an IDML, activate a bundle, assert its contribution log, run real
|
|
351
|
+
* mutations, and dispose honestly.
|
|
352
|
+
*
|
|
353
|
+
* Resolves B-13 (RESOLVED + residuals — see module header). Replaces the
|
|
354
|
+
* v0 throw: the harness now stands on a real engine, so a bundle can no
|
|
355
|
+
* longer "pass against fiction".
|
|
356
|
+
*/
|
|
357
|
+
declare function createHeadlessHost(options?: HarnessOptions): Promise<HeadlessHost>;
|
|
358
|
+
|
|
359
|
+
declare class DisposableStore implements Disposable {
|
|
360
|
+
private items;
|
|
361
|
+
private disposed;
|
|
362
|
+
get isDisposed(): boolean;
|
|
363
|
+
/** Track `d`; returns it for chaining. */
|
|
364
|
+
add<T extends Disposable>(d: T): T;
|
|
365
|
+
dispose(): void;
|
|
366
|
+
}
|
|
367
|
+
/** Wrap a plain cleanup function as a Disposable. */
|
|
368
|
+
declare function toDisposable(fn: () => void): Disposable;
|
|
369
|
+
|
|
370
|
+
/** The plugin API version this SDK implements. */
|
|
371
|
+
declare const API_VERSION = "0.2.0";
|
|
372
|
+
/**
|
|
373
|
+
* Does `version` satisfy `range`? Supported forms:
|
|
374
|
+
* `*` — anything
|
|
375
|
+
* `1.2.3` / `1.2`— exact (missing patch = 0)
|
|
376
|
+
* `^1.2.3` — npm caret: same major, >= base (major > 0);
|
|
377
|
+
* same major+minor, >= patch (major == 0 — the 0.x
|
|
378
|
+
* rule: minors are breaking during incubation)
|
|
379
|
+
*/
|
|
380
|
+
declare function satisfiesApiVersion(range: string, version?: string): boolean;
|
|
381
|
+
|
|
382
|
+
/** The default widget catalog: a textarea CodeEditor. Replaced wholesale
|
|
383
|
+
* when the host app injects `widgets` into `createBundleHost`. */
|
|
384
|
+
declare const FALLBACK_WIDGETS: WidgetSurface;
|
|
385
|
+
|
|
386
|
+
/** One recorded `getFontFace` call. */
|
|
387
|
+
interface RecordedFontFaceRequest {
|
|
388
|
+
family: string;
|
|
389
|
+
style?: string;
|
|
390
|
+
}
|
|
391
|
+
/** A seeded face the fake serves. `family` match is case-insensitive
|
|
392
|
+
* (the document registry and CSS often differ only in casing). When
|
|
393
|
+
* `style` is given on a seed, the request must match it; a seed with no
|
|
394
|
+
* style answers any style request for that family. */
|
|
395
|
+
interface SeededFace extends FontFaceAsset {
|
|
396
|
+
/** When set, the seed only answers a request for this exact style. */
|
|
397
|
+
matchStyle?: string;
|
|
398
|
+
}
|
|
399
|
+
interface RecordableAssetSource extends BundleAssetProvider {
|
|
400
|
+
/** Every `getFontFace` call, in order. */
|
|
401
|
+
readonly requests: readonly RecordedFontFaceRequest[];
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Build a recordable, in-memory asset source from a set of seeded
|
|
405
|
+
* faces. Families match case-insensitively; a seed carrying
|
|
406
|
+
* `matchStyle` only answers that style. Unknown families resolve to
|
|
407
|
+
* `null` (the honest no-bytes answer). Every call is recorded.
|
|
408
|
+
*/
|
|
409
|
+
declare function createRecordableAssetSource(seeds?: readonly SeededFace[]): RecordableAssetSource;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Resolve a schema visibility / enablement gate against a published-
|
|
413
|
+
* bindings LOOKUP — the host-side evaluation (B-01: a lookup, NOT an
|
|
414
|
+
* expression language). Rules:
|
|
415
|
+
* · absent gate → `true` (always shown / enabled);
|
|
416
|
+
* · literal boolean → itself;
|
|
417
|
+
* · `{ bind }` → `Boolean(lookup(bind))`, a MISSING name reads
|
|
418
|
+
* `false` (a visible seam, never a throw);
|
|
419
|
+
* · `{ bind, negate: true }` → the inverse (the ONE transform — a
|
|
420
|
+
* NOT, not a DSL).
|
|
421
|
+
* Shared by the editor's `SchemaPanelRenderer` and the conformance
|
|
422
|
+
* tests so the two can't drift.
|
|
423
|
+
*/
|
|
424
|
+
declare function resolveGate(gate: SchemaGate | undefined, lookup: (name: string) => unknown): boolean;
|
|
425
|
+
/** Build the registry `component` for a schema panel. */
|
|
426
|
+
declare function makeSchemaPanelComponent(contribution: SchemaPanelContribution, bindings: BindingsSurface, renderer: SchemaPanelRenderer | undefined): ComponentType<PanelProps>;
|
|
427
|
+
|
|
74
428
|
interface LoadedBundle {
|
|
75
429
|
readonly id: string;
|
|
76
430
|
readonly active: boolean;
|
|
@@ -78,6 +432,81 @@ interface LoadedBundle {
|
|
|
78
432
|
}
|
|
79
433
|
declare function loadBundle(getEditor: () => PagedEditor, bundle: PagedBundle, options?: CreateBundleHostOptions): LoadedBundle;
|
|
80
434
|
|
|
435
|
+
/** WASM packaging budgets (v1). Rationale in docs/wasm-packaging.md.
|
|
436
|
+
* KEEP IN SYNC with plugin-cli's WASM_MAX_* and the schema's `maxBytes`
|
|
437
|
+
* maximum — the CLI hand-mirrors the contract. */
|
|
438
|
+
declare const WASM_BUDGETS: {
|
|
439
|
+
/** Hard per-artifact byte ceiling. A release-optimised wasm layout
|
|
440
|
+
* engine (Blitz-class) lands in the low-single-digit MiB; 8 MiB
|
|
441
|
+
* rejects an accidentally-bundled debug build while leaving headroom
|
|
442
|
+
* for one real engine. A manifest `maxBytes` may only TIGHTEN this. */
|
|
443
|
+
readonly maxArtifactBytes: number;
|
|
444
|
+
/** Total declared wasm across one bundle. Bounds a bundle that ships
|
|
445
|
+
* several modules (engine + a codec, say). */
|
|
446
|
+
readonly maxTotalBytes: number;
|
|
447
|
+
/** Wall-clock budget for fetch + compile + instantiate. Protects the
|
|
448
|
+
* editor's main flow from a pathological module; advisory, the loader
|
|
449
|
+
* aborts with a clear error when exceeded. */
|
|
450
|
+
readonly loadTimeBudgetMs: 3000;
|
|
451
|
+
/** Linear-memory growth ceiling, in 64 KiB wasm pages (4096 = 256 MiB).
|
|
452
|
+
* Passed as `WebAssembly.Memory({ maximum })` when the host owns the
|
|
453
|
+
* memory; a per-page layout pass should sit far under this. */
|
|
454
|
+
readonly maxMemoryPages: 4096;
|
|
455
|
+
};
|
|
456
|
+
/** A loaded bundle wasm module + the resources the host owns for it. */
|
|
457
|
+
interface LoadedBundleWasm {
|
|
458
|
+
/** The artifact descriptor it was loaded from. */
|
|
459
|
+
artifact: WasmArtifact;
|
|
460
|
+
module: WebAssembly.Module;
|
|
461
|
+
instance: WebAssembly.Instance;
|
|
462
|
+
/** The host-owned, non-shared memory the module was given (when the
|
|
463
|
+
* host provided one — see `provideMemory`). */
|
|
464
|
+
memory?: WebAssembly.Memory;
|
|
465
|
+
/** Compiled byte length (post-budget-check, for telemetry). */
|
|
466
|
+
byteLength: number;
|
|
467
|
+
}
|
|
468
|
+
/** How the loader reads a bundle-relative asset. The host supplies this
|
|
469
|
+
* (a URL fetch rooted at the bundle's asset base in the browser; a file
|
|
470
|
+
* read in Node/tests). The loader passes ONLY the declared `path`. */
|
|
471
|
+
type BundleAssetSource = (path: string) => Promise<Uint8Array> | Uint8Array;
|
|
472
|
+
interface LoadBundleWasmOptions {
|
|
473
|
+
/** Reads the declared artifact's bytes (required). */
|
|
474
|
+
assetSource: BundleAssetSource;
|
|
475
|
+
/**
|
|
476
|
+
* The host grant. A wasm artifact loads only if the host has granted
|
|
477
|
+
* it — `"*"` grants all declared artifacts; a `Set`/array grants by
|
|
478
|
+
* name. ABSENT means NO grant (refuse): wasm is opt-in, never ambient.
|
|
479
|
+
*/
|
|
480
|
+
grant?: "*" | ReadonlyArray<string> | ReadonlySet<string>;
|
|
481
|
+
/**
|
|
482
|
+
* Import object handed to the module at instantiation. The loader adds
|
|
483
|
+
* NOTHING implicitly — if `provideMemory` is true and the imports omit
|
|
484
|
+
* `env.memory`, a host-owned bounded `WebAssembly.Memory` is injected;
|
|
485
|
+
* otherwise the module is on its own (no ambient engine/DOM/network).
|
|
486
|
+
*/
|
|
487
|
+
imports?: WebAssembly.Imports;
|
|
488
|
+
/**
|
|
489
|
+
* When true (default), the loader owns linear memory: it creates a
|
|
490
|
+
* non-shared `WebAssembly.Memory` bounded by `maxMemoryPages` and
|
|
491
|
+
* injects it as `imports.env.memory` if not already present. Set false
|
|
492
|
+
* to let a module declare its own (still non-shared) memory.
|
|
493
|
+
*/
|
|
494
|
+
provideMemory?: boolean;
|
|
495
|
+
/** Initial pages for the host-owned memory (default 16 = 1 MiB). */
|
|
496
|
+
initialMemoryPages?: number;
|
|
497
|
+
/** Override the load-time budget (ms). */
|
|
498
|
+
loadTimeBudgetMs?: number;
|
|
499
|
+
/** Clock injection for deterministic tests. */
|
|
500
|
+
now?: () => number;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Load a bundle-declared wasm artifact, enforcing declared-only access,
|
|
504
|
+
* the host grant, and the v1 budgets. Resolves to the instantiated
|
|
505
|
+
* module; rejects (loudly) on an undeclared name, a missing grant, an
|
|
506
|
+
* over-budget artifact, or a load-time overrun.
|
|
507
|
+
*/
|
|
508
|
+
declare function loadBundleWasm(bundle: PagedBundle, name: string, options: LoadBundleWasmOptions): Promise<LoadedBundleWasm>;
|
|
509
|
+
|
|
81
510
|
declare const CLICK_DRAG_THRESHOLD_PX = 4;
|
|
82
511
|
/** A drag anchored to the page under the pointer at pointer-down. */
|
|
83
512
|
interface PageDrag {
|
|
@@ -104,5 +533,24 @@ declare function commitAndSelect(paged: PagedEditor, mutation: Mutation, label:
|
|
|
104
533
|
declare function contributeTool(host: BundleHost, tool: ToolContribution): Disposable;
|
|
105
534
|
|
|
106
535
|
declare function contributePanel(host: BundleHost, panel: PanelContribution): Disposable;
|
|
536
|
+
/** Register a DECLARATIVE panel (W3.1, B-01): the host renders the
|
|
537
|
+
* schema from the catalog and subscribes to this bundle's published
|
|
538
|
+
* bindings (`host.bindings`) for visibility/enablement. No React
|
|
539
|
+
* crosses the boundary — the isolate-ready panel form. Same namespace
|
|
540
|
+
* + capability gate as `contributePanel` (`contributes.panels[]` must
|
|
541
|
+
* list the id). */
|
|
542
|
+
declare function contributeSchemaPanel(host: BundleHost, panel: SchemaPanelContribution): Disposable;
|
|
543
|
+
|
|
544
|
+
/** Register an EDIT CONTEXT (B-02): a content type that, on
|
|
545
|
+
* double-click (or programmatically), pushes a scoped context —
|
|
546
|
+
* restricted tools, emphasized panels, breadcrumb, narrowed
|
|
547
|
+
* write-scope, Esc pops. Capability-gated on `contributes.editContexts`.
|
|
548
|
+
*/
|
|
549
|
+
declare function contributeEditContext(host: BundleHost, contribution: EditContextContribution): Disposable;
|
|
550
|
+
/** Register an OBJECT TYPE (W-03): a plugin-defined object (a webFrame
|
|
551
|
+
* is a rectangle with attached source metadata). A double-click on a
|
|
552
|
+
* matching element enters its `editContextType` instead of group
|
|
553
|
+
* descent. Capability-gated on `contributes.objectTypes`. */
|
|
554
|
+
declare function contributeObjectType(host: BundleHost, contribution: ObjectTypeContribution): Disposable;
|
|
107
555
|
|
|
108
|
-
export { API_VERSION, type BundleHostHandle, CLICK_DRAG_THRESHOLD_PX, type CreateBundleHostOptions, DisposableStore, HOST_FEATURES, type HarnessOptions, type LoadedBundle, type PageDrag, PluginApiNotImplemented, type StorageBacking, beginPageDrag, commitAndSelect, contributePanel, contributeTool, createBundleHost, createHeadlessHost, defineBundle, endLocalFor, loadBundle, pxToPt, satisfiesApiVersion, toDisposable };
|
|
556
|
+
export { API_VERSION, ASSET_BUDGETS, BLOB_BUDGETS, type BlobStore, type BundleAssetProvider, type BundleAssetSource, type BundleHostHandle, CANVAS_WASM_PKG, CLICK_DRAG_THRESHOLD_PX, type ConsentBackend, type CreateBundleHostOptions, type DataProviderBackend, type DiagnosticsSink, DisposableStore, FALLBACK_WIDGETS, HOST_FEATURES, type HarnessOptions, type HeadlessCanvasWorker, type HeadlessHost, type HeadlessHostHandle, type LoadBundleWasmOptions, type LoadHeadlessEngineOptions, type LoadedBundle, type LoadedBundleWasm, type LoadedEngine, type PageDrag, PluginApiNotImplemented, PluginCapabilityError, type RecordableAssetSource, type RecordedContribution, type RecordedFontFaceRequest, type SeededFace, type StorageBacking, WASM_BUDGETS, beginPageDrag, commitAndSelect, contributeEditContext, contributeObjectType, contributePanel, contributeSchemaPanel, contributeTool, createBundleHost, createDataProviderRegistry, createHeadlessHost, createRecordableAssetSource, defineBundle, endLocalFor, loadBundle, loadBundleWasm, loadHeadlessEngine, makeSchemaPanelComponent, protocolFromVersion, pxToPt, readVendoredWireVersion, resolveCanvasWasm, resolveGate, satisfiesApiVersion, toDisposable };
|