@paged-media/plugin-sdk 0.2.40-canary.0 → 0.2.42-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 +102 -2
- package/dist/index.js +349 -15
- package/package.json +3 -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, PagedEditor, PluginManifest, ToolContribution, PanelContribution, CommandContribution, KeybindingContribution, OverlayContribution, ImporterContribution, ExporterContribution, ToolPreviewShape, BindingsSurface, PanelProps, SchemaGate, WasmArtifact, CanvasPointerEvent, Mutation, MutationOutcome, BindingProviderHandle } from '@paged-media/plugin-api';
|
|
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';
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -104,6 +104,18 @@ interface BundleAssetProvider {
|
|
|
104
104
|
/** The bytes of a document font face, or `null` when the host has
|
|
105
105
|
* none. Style-agnostic when `style` is omitted. */
|
|
106
106
|
getFontFace(family: string, style?: string): Promise<FontFaceAsset | null>;
|
|
107
|
+
/** W-15 — register a face in the engine's SCENE-LAYER face table
|
|
108
|
+
* (`registerFont` with `scope: "sceneLayer"`): scene-layer text
|
|
109
|
+
* resolves it, the document never sees it. The SDK calls it once per
|
|
110
|
+
* `host.assets.registerFont` and again when it replays the live faces
|
|
111
|
+
* after a disposal. Optional: a host without it (with
|
|
112
|
+
* `clearSceneFonts`) leaves `supports("assets.registerFont@1")` false. */
|
|
113
|
+
registerFont?(family: string, bytes: Uint8Array, style?: string): Promise<void>;
|
|
114
|
+
/** W-15 — drop every scene-layer face (`clearFontRegistry` with
|
|
115
|
+
* `scope: "sceneLayer"`), leaving the document's faces alone. The SDK
|
|
116
|
+
* owns which faces are live, so disposing one face is "clear, then
|
|
117
|
+
* register the rest again". */
|
|
118
|
+
clearSceneFonts?(): Promise<void>;
|
|
107
119
|
}
|
|
108
120
|
/** Blob-store budgets (K-4 / S-08). The default per-plugin quota when a
|
|
109
121
|
* manifest requests none; a manifest's `storage.quotaBytes` may only
|
|
@@ -240,6 +252,27 @@ interface NativeDocumentBackend {
|
|
|
240
252
|
listParts(prefix?: string): Promise<string[]>;
|
|
241
253
|
open(bytes: Uint8Array): Promise<void>;
|
|
242
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* D-26 — the backend the editor injects to back `host.documents`. The SDK
|
|
257
|
+
* owns the capability gate (`capabilities.documents.export` / `.open`); the
|
|
258
|
+
* backend owns the IO AND the unsaved-edits decision: `open` must ask the
|
|
259
|
+
* user (host UI) before discarding a dirty active document and answer
|
|
260
|
+
* `{ opened: false, reason: "declined" }` when they keep it. `requester`
|
|
261
|
+
* is filled by the SDK from the calling bundle's manifest (not from the
|
|
262
|
+
* plugin's arguments), so the prompt can name who is asking. No backend →
|
|
263
|
+
* both doors reject and `supports("documents.open@1")` /
|
|
264
|
+
* `supports("documents.exportPaged@1")` are false.
|
|
265
|
+
*/
|
|
266
|
+
interface DocumentsBackend {
|
|
267
|
+
exportPaged(): Promise<Uint8Array>;
|
|
268
|
+
open(bytes: Uint8Array, request: {
|
|
269
|
+
name: string | null;
|
|
270
|
+
requester: {
|
|
271
|
+
id: string;
|
|
272
|
+
name: string;
|
|
273
|
+
};
|
|
274
|
+
}): Promise<OpenDocumentResult>;
|
|
275
|
+
}
|
|
243
276
|
/** The SHARED cross-plugin data-provider registry (paged.data §7.1 / D-09). The
|
|
244
277
|
* editor creates ONE (`createDataProviderRegistry`) and injects the SAME
|
|
245
278
|
* instance into every plugin host, so a provider plugin and a consumer plugin
|
|
@@ -402,6 +435,13 @@ interface CreateBundleHostOptions {
|
|
|
402
435
|
* holds listeners that never run and `supports("document.onWillSave@1")`
|
|
403
436
|
* is false. */
|
|
404
437
|
willSave?: WillSaveBackend;
|
|
438
|
+
/** W-19 — the host's shell fills `pageId` / `pagePoint` /
|
|
439
|
+
* `contentPoint` on the `EnteredEditContext` of a POINTER entry (the
|
|
440
|
+
* double-click, the Type-tool click on owned content). The SDK passes
|
|
441
|
+
* the entered context through untouched either way; this flag only
|
|
442
|
+
* makes `supports("editContext.enterPoint@1")` true, so it is the HOST
|
|
443
|
+
* that vouches for delivery. */
|
|
444
|
+
editContextEnterPoint?: boolean;
|
|
405
445
|
/** The host's tool-options store. When absent, `host.tools.settings`
|
|
406
446
|
* answers `{}` and `supports("tools.settings@1")` is false. */
|
|
407
447
|
toolSettings?: ToolSettingsBackend;
|
|
@@ -469,6 +509,12 @@ interface CreateBundleHostOptions {
|
|
|
469
509
|
* `supports("document.openNative@1")` answer true. When absent, the reads
|
|
470
510
|
* answer `null`/`[]` and `open` rejects (the honest no-backend door). */
|
|
471
511
|
nativeDocument?: NativeDocumentBackend;
|
|
512
|
+
/** D-26 — host-provided DOCUMENTS backend. When present,
|
|
513
|
+
* `host.documents.exportPaged` / `open` go through it (gated on
|
|
514
|
+
* `capabilities.documents.export` / `.open`) and
|
|
515
|
+
* `supports("documents.exportPaged@1")` / `supports("documents.open@1")`
|
|
516
|
+
* answer true. When absent, both doors reject. */
|
|
517
|
+
documents?: DocumentsBackend;
|
|
472
518
|
/** Host-provided WORKER backend (K-3 / S-07 / I-02). When present,
|
|
473
519
|
* `host.workers.spawn` resolves a declared bundle-relative module +
|
|
474
520
|
* constructs a host-owned `Worker` through it (capability-gated,
|
|
@@ -521,6 +567,14 @@ interface HeadlessCanvasWorker {
|
|
|
521
567
|
handleMessage(input: string): string;
|
|
522
568
|
loadDocumentDirect(seq: number, bytes: Uint8Array, font?: Uint8Array, cmykIccProfile?: Uint8Array): string;
|
|
523
569
|
runResolveJson(): string | undefined;
|
|
570
|
+
/** The engine shaper (v38): `{ advance, ascender, descender }` in pt, or
|
|
571
|
+
* null when no document is loaded / the face resolves to nothing.
|
|
572
|
+
* Optional so a structural fake need not carry it. */
|
|
573
|
+
measureText?(family: string, style: string | null | undefined, text: string, sizePt: number): {
|
|
574
|
+
advance: number;
|
|
575
|
+
ascender: number;
|
|
576
|
+
descender: number;
|
|
577
|
+
} | null;
|
|
524
578
|
free(): void;
|
|
525
579
|
}
|
|
526
580
|
interface LoadedEngine {
|
|
@@ -580,6 +634,32 @@ interface RecordedContribution {
|
|
|
580
634
|
value: ToolContribution | PanelContribution | SchemaPanelContribution | CommandContribution | KeybindingContribution | OverlayContribution | EditContextContribution | ObjectTypeContribution | ImporterContribution | ExporterContribution;
|
|
581
635
|
}
|
|
582
636
|
interface HarnessOptions extends LoadHeadlessEngineOptions, Pick<CreateBundleHostOptions, "console" | "storage" | "capabilityMode" | "assetSource" | "blobStore" | "clipboard" | "secrets" | "bindingProviders" | "willSave" | "toolSettings"> {
|
|
637
|
+
/** D-27 — back `host.text` with the ENGINE's shaper
|
|
638
|
+
* (`CanvasWorker.measureText`, the one the editor's worker calls)
|
|
639
|
+
* instead of the estimate, so `measureString` / `measureStrings`
|
|
640
|
+
* answer real widths against the loaded document's fonts and
|
|
641
|
+
* `supports("text.measure@1")` / `("text.measureStrings@1")` are true.
|
|
642
|
+
* Off by default: existing headless suites pinned the estimate. */
|
|
643
|
+
engineShaper?: boolean;
|
|
644
|
+
/** D-26 — the headless stand-in for the editor's keep/discard prompt.
|
|
645
|
+
* `host.documents.open` calls it ONLY when the active document has
|
|
646
|
+
* unsaved edits; resolve `false` to keep them (the door then answers
|
|
647
|
+
* `{ opened: false, reason: "declined" }`). Default: discard. */
|
|
648
|
+
confirmReplace?: (request: {
|
|
649
|
+
name: string | null;
|
|
650
|
+
requester: {
|
|
651
|
+
id: string;
|
|
652
|
+
name: string;
|
|
653
|
+
};
|
|
654
|
+
}) => boolean | Promise<boolean>;
|
|
655
|
+
/** D-28 — the default font every load lays out with, the headless
|
|
656
|
+
* stand-in for the editor's `defaultFontProvider` (the editor passes
|
|
657
|
+
* `/fonts/Inter.ttf`). The engine lays text out, and reports a story
|
|
658
|
+
* `overset`, only when it has a font: without one nothing is laid out and
|
|
659
|
+
* every story reads `overset: false` (not measured). Passed to every
|
|
660
|
+
* load, `load()` and `host.documents.open` alike. Absent: no font, as
|
|
661
|
+
* before. */
|
|
662
|
+
defaultFont?: Uint8Array;
|
|
583
663
|
}
|
|
584
664
|
/** A headless will-save registry: listeners register per plugin and
|
|
585
665
|
* `fire()` awaits them all, the way the editor's save path does — so a
|
|
@@ -638,6 +718,19 @@ interface HeadlessHost {
|
|
|
638
718
|
* bundle's "geometry AND label at once" claim is assertable without a
|
|
639
719
|
* browser. `lastToolPreview()` tracks the list's FIRST shape. */
|
|
640
720
|
lastToolPreviews(): readonly ToolPreviewShape[] | null;
|
|
721
|
+
/** W-20 — every LIVE overlay layer (`host.overlay.layer`), in stack
|
|
722
|
+
* order (bottom-most first), keyed `<manifest id>/<layer id>`, with the
|
|
723
|
+
* shapes it holds now (`[]` once cleared). A disposed layer is gone. */
|
|
724
|
+
overlayLayers(): ReadonlyArray<{
|
|
725
|
+
key: string;
|
|
726
|
+
shapes: readonly ToolPreviewShape[];
|
|
727
|
+
}>;
|
|
728
|
+
/** W-19 — play the SHELL's part on a pointer entry: call the registered
|
|
729
|
+
* edit context's `onEnter` with `ctx` (which may carry `pageId` /
|
|
730
|
+
* `pagePoint` / `contentPoint`, as the editor fills them). The harness
|
|
731
|
+
* advertises `editContext.enterPoint@1`. Returns `false` when no
|
|
732
|
+
* context of `ctx.type` is registered. */
|
|
733
|
+
enterEditContext(ctx: EnteredEditContext): boolean;
|
|
641
734
|
/** ADR-023 phase A — the SHARED binding-provider registry this host
|
|
642
735
|
* injected. It is the HOST side of the seam, so a conformance test
|
|
643
736
|
* plays the part the editor's shared panel plays in phase C: enter
|
|
@@ -656,6 +749,13 @@ interface HeadlessHost {
|
|
|
656
749
|
/** Load an IDML package into the headless document. Resolves to the
|
|
657
750
|
* loaded page ids (or throws on a parse failure). */
|
|
658
751
|
load(idml: Uint8Array): Promise<string[]>;
|
|
752
|
+
/** D-26 — every document a bundle opened through `host.documents.open`,
|
|
753
|
+
* in order (declined opens are not listed). */
|
|
754
|
+
openedDocuments(): ReadonlyArray<{
|
|
755
|
+
name: string | null;
|
|
756
|
+
requester: string;
|
|
757
|
+
pageIds: string[];
|
|
758
|
+
}>;
|
|
659
759
|
/** Activate a bundle against this host (apiVersion-negotiated). The
|
|
660
760
|
* returned disposer runs the bundle's teardown; the host's own
|
|
661
761
|
* facade teardown runs on `dispose()`. */
|
|
@@ -921,4 +1021,4 @@ declare function contributeObjectType(host: BundleHost, contribution: ObjectType
|
|
|
921
1021
|
*/
|
|
922
1022
|
declare function contributeBindingProvider(host: BundleHost, contextType: string, provider: BindingProvider): BindingProviderHandle;
|
|
923
1023
|
|
|
924
|
-
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, 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 };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -228,8 +228,17 @@ var HOST_FEATURES = [
|
|
|
228
228
|
// needed — DESIGN.md §4.3d).
|
|
229
229
|
"document.parentOf@1",
|
|
230
230
|
"document.onDidChange@1",
|
|
231
|
+
// W-22 — the document-opened event. STATIC: it is the client's
|
|
232
|
+
// `documentLoaded` broadcast filtered, and every host posts that on
|
|
233
|
+
// every load (File ▸ Open, File ▸ New, a native-document open).
|
|
234
|
+
"document.onDidOpen@1",
|
|
231
235
|
"document.getMetadata@1",
|
|
232
236
|
"document.setMetadata@1",
|
|
237
|
+
// Protocol 69 — the document-scoped label. Static like the snap door:
|
|
238
|
+
// the flag says this SDK forwards the two calls; an engine older than 69
|
|
239
|
+
// answers `null` on read (no `pluginMetadata` in its DocumentMeta) and
|
|
240
|
+
// `applied: false` on write (it does not know the op).
|
|
241
|
+
"document.documentMetadata@1",
|
|
233
242
|
"selection@1",
|
|
234
243
|
"viewport@1",
|
|
235
244
|
"overlay.toolPreview@1",
|
|
@@ -328,6 +337,15 @@ var ASSET_BUDGETS = {
|
|
|
328
337
|
/** Largest font face the door will serve, in bytes (8 MiB). */
|
|
329
338
|
maxFontFaceBytes: 8 * 1024 * 1024
|
|
330
339
|
};
|
|
340
|
+
var sceneFaceLedgers = /* @__PURE__ */ new WeakMap();
|
|
341
|
+
function sceneFaceLedger(provider) {
|
|
342
|
+
let ledger = sceneFaceLedgers.get(provider);
|
|
343
|
+
if (!ledger) {
|
|
344
|
+
ledger = { entries: [], queue: Promise.resolve() };
|
|
345
|
+
sceneFaceLedgers.set(provider, ledger);
|
|
346
|
+
}
|
|
347
|
+
return ledger;
|
|
348
|
+
}
|
|
331
349
|
var BLOB_BUDGETS = {
|
|
332
350
|
/** Default per-plugin blob ceiling, in bytes (64 MiB). */
|
|
333
351
|
defaultQuotaBytes: 64 * 1024 * 1024
|
|
@@ -628,6 +646,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
628
646
|
const hasWorkers = () => typeof caps?.workers?.max === "number";
|
|
629
647
|
const hasSecrets = () => caps?.secrets?.sources === true;
|
|
630
648
|
const hasGpu = () => caps?.gpu?.realm === "bundle";
|
|
649
|
+
const hasDocuments = (dir) => caps?.documents?.[dir] === true;
|
|
631
650
|
const lists = (arr, id) => arr?.includes(id) ?? false;
|
|
632
651
|
const declaresType = (arr, type) => arr?.some((e) => e.type === type) ?? false;
|
|
633
652
|
const requireDeclared = (ok, door, missing) => {
|
|
@@ -1098,7 +1117,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1098
1117
|
}
|
|
1099
1118
|
};
|
|
1100
1119
|
const foreignMetadataKey = (m) => {
|
|
1101
|
-
if (m.op === "setPluginMetadata") {
|
|
1120
|
+
if (m.op === "setPluginMetadata" || m.op === "setDocumentMetadata" || m.op === "setPageMetadata") {
|
|
1102
1121
|
return m.args.key === metadataKey(manifest) ? null : m.args.key;
|
|
1103
1122
|
}
|
|
1104
1123
|
if (m.op === "batch") {
|
|
@@ -1147,7 +1166,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1147
1166
|
if (denied !== null) return { applied: false, error: denied };
|
|
1148
1167
|
const foreign = foreignMetadataKey(mutation);
|
|
1149
1168
|
if (foreign !== null) {
|
|
1150
|
-
const error = `
|
|
1169
|
+
const error = `metadata key "${foreign}" is outside this plugin's namespace ("${metadataKey(manifest)}")`;
|
|
1151
1170
|
log.warn(error);
|
|
1152
1171
|
return { applied: false, error };
|
|
1153
1172
|
}
|
|
@@ -1384,6 +1403,28 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1384
1403
|
}
|
|
1385
1404
|
});
|
|
1386
1405
|
},
|
|
1406
|
+
async getDocumentMetadata() {
|
|
1407
|
+
requireDocRead("document.getDocumentMetadata");
|
|
1408
|
+
const key = metadataKey(manifest);
|
|
1409
|
+
const meta = await getEditor().client.documentMeta();
|
|
1410
|
+
const entry = meta.pluginMetadata?.find((e) => e.key === key);
|
|
1411
|
+
if (!entry) return null;
|
|
1412
|
+
try {
|
|
1413
|
+
return JSON.parse(entry.value);
|
|
1414
|
+
} catch {
|
|
1415
|
+
return null;
|
|
1416
|
+
}
|
|
1417
|
+
},
|
|
1418
|
+
async setDocumentMetadata(envelope) {
|
|
1419
|
+
return this.mutate({
|
|
1420
|
+
op: "setDocumentMetadata",
|
|
1421
|
+
args: {
|
|
1422
|
+
key: metadataKey(manifest),
|
|
1423
|
+
value: envelope === null ? null : JSON.stringify(envelope),
|
|
1424
|
+
caller: manifest.id
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
},
|
|
1387
1428
|
async frameChain(storyId) {
|
|
1388
1429
|
requireDocRead("document.frameChain");
|
|
1389
1430
|
const reply = await getEditor().client.send({
|
|
@@ -1414,6 +1455,28 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1414
1455
|
});
|
|
1415
1456
|
return store.add(toDisposable(off));
|
|
1416
1457
|
},
|
|
1458
|
+
// W-22 — the raw `documentLoaded` broadcast, narrowed to a clonable
|
|
1459
|
+
// snapshot (the handle's stats / ruler guides stay host-side).
|
|
1460
|
+
onDidOpen(listener) {
|
|
1461
|
+
requireDocRead("document.onDidOpen");
|
|
1462
|
+
const off = getEditor().client.subscribe((msg) => {
|
|
1463
|
+
if (msg.kind !== "documentLoaded") return;
|
|
1464
|
+
const h2 = msg.payload;
|
|
1465
|
+
try {
|
|
1466
|
+
listener({
|
|
1467
|
+
docId: h2.docId,
|
|
1468
|
+
pageCount: h2.pageCount,
|
|
1469
|
+
pageIds: [...h2.pageIds],
|
|
1470
|
+
pageSizesPt: h2.pageSizesPt.map(
|
|
1471
|
+
([w, hgt]) => [w, hgt]
|
|
1472
|
+
)
|
|
1473
|
+
});
|
|
1474
|
+
} catch (err) {
|
|
1475
|
+
log.error(`document.onDidOpen listener failed: ${String(err)}`);
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
return store.add(toDisposable(off));
|
|
1479
|
+
},
|
|
1417
1480
|
// Protocol 66 batch — the save hook. The host awaits every
|
|
1418
1481
|
// registered listener before it serialises the document; the wrapper
|
|
1419
1482
|
// makes a bundle's failure a logged event, never a failed save.
|
|
@@ -1487,8 +1550,30 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1487
1550
|
// "no reader").
|
|
1488
1551
|
caret() {
|
|
1489
1552
|
return options?.textCaret?.read() ?? null;
|
|
1553
|
+
},
|
|
1554
|
+
// D-27 — the batched measure. One round-trip when the editor wires
|
|
1555
|
+
// `measureMany`; otherwise the same answers one call at a time (or
|
|
1556
|
+
// the estimate), so a bundle never needs two code paths.
|
|
1557
|
+
async measureStrings(family, style, texts, sizePt) {
|
|
1558
|
+
if (texts.length === 0) return [];
|
|
1559
|
+
const editorText = getEditor().text;
|
|
1560
|
+
if (editorText?.measureMany) {
|
|
1561
|
+
const out = await editorText.measureMany(family, style, texts, sizePt);
|
|
1562
|
+
if (out.length !== texts.length) {
|
|
1563
|
+
throw new Error(
|
|
1564
|
+
`host.text.measureStrings: the host answered ${out.length} metrics for ${texts.length} strings`
|
|
1565
|
+
);
|
|
1566
|
+
}
|
|
1567
|
+
return out;
|
|
1568
|
+
}
|
|
1569
|
+
return Promise.all(
|
|
1570
|
+
texts.map((t) => text.measureString(family, style, t, sizePt))
|
|
1571
|
+
);
|
|
1490
1572
|
}
|
|
1491
1573
|
};
|
|
1574
|
+
let overlayLayerSeq = 0;
|
|
1575
|
+
let overlayLayerWarned = false;
|
|
1576
|
+
const liveOverlayLayers = /* @__PURE__ */ new Set();
|
|
1492
1577
|
const overlay = {
|
|
1493
1578
|
setToolPreview(shape) {
|
|
1494
1579
|
requireDeclared(
|
|
@@ -1518,6 +1603,56 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1518
1603
|
return;
|
|
1519
1604
|
}
|
|
1520
1605
|
signals.setToolPreview(list ? list[0] : null);
|
|
1606
|
+
},
|
|
1607
|
+
// W-20 — retained per-bundle layers. Each layer is a host-wide key
|
|
1608
|
+
// `<manifest id>/<layer id>`; registering it with `[]` at creation
|
|
1609
|
+
// fixes its place in the stack (creation order), so a later `set`
|
|
1610
|
+
// never reorders it. Without a host sink the handle is inert (warned
|
|
1611
|
+
// once per bundle) — never a throw, never a write into the shared
|
|
1612
|
+
// tool-preview slot, which would erase the active tool's preview.
|
|
1613
|
+
layer(id) {
|
|
1614
|
+
requireDeclared(
|
|
1615
|
+
hasRendering("overlay"),
|
|
1616
|
+
"overlay.layer",
|
|
1617
|
+
'capabilities.rendering must include "overlay"'
|
|
1618
|
+
);
|
|
1619
|
+
const layerId = id ?? `layer-${++overlayLayerSeq}`;
|
|
1620
|
+
if (liveOverlayLayers.has(layerId)) {
|
|
1621
|
+
throw new Error(
|
|
1622
|
+
`host.overlay.layer("${layerId}"): a layer with this id is already live in ${manifest.id} \u2014 dispose it first or pick another id`
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
const key = `${manifest.id}/${layerId}`;
|
|
1626
|
+
const signals = getEditor().overlaySignals;
|
|
1627
|
+
const sink2 = typeof signals?.setOverlayLayer === "function" && typeof signals?.removeOverlayLayer === "function" ? signals : null;
|
|
1628
|
+
if (!sink2 && !overlayLayerWarned) {
|
|
1629
|
+
overlayLayerWarned = true;
|
|
1630
|
+
log.warn(
|
|
1631
|
+
'host.overlay.layer \u2014 this host renders no overlay layers (supports("overlay.layers@1") is false); shapes are dropped'
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
liveOverlayLayers.add(layerId);
|
|
1635
|
+
sink2?.setOverlayLayer(key, []);
|
|
1636
|
+
let disposed = false;
|
|
1637
|
+
const handle = {
|
|
1638
|
+
id: layerId,
|
|
1639
|
+
set(shapes) {
|
|
1640
|
+
if (disposed) return;
|
|
1641
|
+
sink2?.setOverlayLayer(key, [...shapes]);
|
|
1642
|
+
},
|
|
1643
|
+
clear() {
|
|
1644
|
+
if (disposed) return;
|
|
1645
|
+
sink2?.setOverlayLayer(key, []);
|
|
1646
|
+
},
|
|
1647
|
+
dispose() {
|
|
1648
|
+
if (disposed) return;
|
|
1649
|
+
disposed = true;
|
|
1650
|
+
liveOverlayLayers.delete(layerId);
|
|
1651
|
+
sink2?.removeOverlayLayer(key);
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
store.add(handle);
|
|
1655
|
+
return handle;
|
|
1521
1656
|
}
|
|
1522
1657
|
};
|
|
1523
1658
|
const backing = options?.storage ?? defaultStorageBacking();
|
|
@@ -1782,6 +1917,65 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1782
1917
|
}
|
|
1783
1918
|
return face;
|
|
1784
1919
|
},
|
|
1920
|
+
// W-15 — the one WRITE: a scene-layer face. The engine has a single
|
|
1921
|
+
// scene table that `clearFontRegistry` can only empty as a whole, so
|
|
1922
|
+
// the SDK keeps the list of live faces per provider (across bundles)
|
|
1923
|
+
// and disposes one face by clearing and replaying the others. Every
|
|
1924
|
+
// engine call goes through the ledger's queue, so a replay never
|
|
1925
|
+
// interleaves with a registration.
|
|
1926
|
+
async registerFont(bytes, family, style) {
|
|
1927
|
+
requireDeclared(
|
|
1928
|
+
hasAsset("fonts"),
|
|
1929
|
+
"assets.registerFont",
|
|
1930
|
+
'capabilities.assets must include "fonts"'
|
|
1931
|
+
);
|
|
1932
|
+
const label = `assets.registerFont("${family}"${style ? `, "${style}"` : ""})`;
|
|
1933
|
+
if (bytes.byteLength > ASSET_BUDGETS.maxFontFaceBytes) {
|
|
1934
|
+
throw new Error(
|
|
1935
|
+
`${label}: ${bytes.byteLength} bytes is over the ${ASSET_BUDGETS.maxFontFaceBytes}-byte per-face cap`
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
const provider = assetSource;
|
|
1939
|
+
const register = provider?.registerFont?.bind(provider);
|
|
1940
|
+
const clear = provider?.clearSceneFonts?.bind(provider);
|
|
1941
|
+
if (!provider || !register || !clear) {
|
|
1942
|
+
log.warn(
|
|
1943
|
+
`${label} ignored \u2014 the host cannot register scene faces (probe supports("assets.registerFont@1")); scene text keeps its fallback face`
|
|
1944
|
+
);
|
|
1945
|
+
return toDisposable(() => {
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
const ledger = sceneFaceLedger(provider);
|
|
1949
|
+
const entry = style === void 0 ? { family, bytes: bytes.slice() } : { family, style, bytes: bytes.slice() };
|
|
1950
|
+
const run = (job) => {
|
|
1951
|
+
const next = ledger.queue.then(job);
|
|
1952
|
+
ledger.queue = next.catch(() => {
|
|
1953
|
+
});
|
|
1954
|
+
return next;
|
|
1955
|
+
};
|
|
1956
|
+
await run(async () => {
|
|
1957
|
+
await register(entry.family, entry.bytes, entry.style);
|
|
1958
|
+
ledger.entries.push(entry);
|
|
1959
|
+
});
|
|
1960
|
+
let disposed = false;
|
|
1961
|
+
return store.add(
|
|
1962
|
+
toDisposable(() => {
|
|
1963
|
+
if (disposed) return;
|
|
1964
|
+
disposed = true;
|
|
1965
|
+
void run(async () => {
|
|
1966
|
+
const i = ledger.entries.indexOf(entry);
|
|
1967
|
+
if (i < 0) return;
|
|
1968
|
+
ledger.entries.splice(i, 1);
|
|
1969
|
+
await clear();
|
|
1970
|
+
for (const live of ledger.entries) {
|
|
1971
|
+
await register(live.family, live.bytes, live.style);
|
|
1972
|
+
}
|
|
1973
|
+
}).catch((error) => {
|
|
1974
|
+
log.warn(`${label}: dropping the face failed: ${String(error)}`);
|
|
1975
|
+
});
|
|
1976
|
+
})
|
|
1977
|
+
);
|
|
1978
|
+
},
|
|
1785
1979
|
// C-5 / I-04 (core v42): a placed DOCUMENT image's ORIGINAL bytes,
|
|
1786
1980
|
// straight from the engine's resolver/parse cache through the
|
|
1787
1981
|
// `requestPlacedAssetBytes` wire query — no injected source needed
|
|
@@ -2058,6 +2252,42 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2058
2252
|
return nativeDocBackend.open(bytes);
|
|
2059
2253
|
}
|
|
2060
2254
|
};
|
|
2255
|
+
const documentsBackend = options?.documents;
|
|
2256
|
+
const documents = {
|
|
2257
|
+
async exportPaged() {
|
|
2258
|
+
requireDeclared(
|
|
2259
|
+
hasDocuments("export"),
|
|
2260
|
+
"documents.exportPaged",
|
|
2261
|
+
"capabilities.documents.export must be declared"
|
|
2262
|
+
);
|
|
2263
|
+
if (!documentsBackend) {
|
|
2264
|
+
throw new Error(
|
|
2265
|
+
'host.documents.exportPaged: the host wired no documents backend (supports("documents.exportPaged@1") is false)'
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
2268
|
+
return documentsBackend.exportPaged();
|
|
2269
|
+
},
|
|
2270
|
+
async open(bytes, opts) {
|
|
2271
|
+
requireDeclared(
|
|
2272
|
+
hasDocuments("open"),
|
|
2273
|
+
"documents.open",
|
|
2274
|
+
"capabilities.documents.open must be declared"
|
|
2275
|
+
);
|
|
2276
|
+
if (!documentsBackend) {
|
|
2277
|
+
throw new Error(
|
|
2278
|
+
'host.documents.open: the host wired no documents backend (supports("documents.open@1") is false)'
|
|
2279
|
+
);
|
|
2280
|
+
}
|
|
2281
|
+
if (!(bytes instanceof Uint8Array) || bytes.byteLength === 0) {
|
|
2282
|
+
throw new Error("host.documents.open: bytes must be a non-empty Uint8Array");
|
|
2283
|
+
}
|
|
2284
|
+
const name = typeof opts?.name === "string" && opts.name.trim() !== "" ? opts.name.trim() : null;
|
|
2285
|
+
return documentsBackend.open(bytes.slice(), {
|
|
2286
|
+
name,
|
|
2287
|
+
requester: { id: manifest.id, name: manifest.name }
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2290
|
+
};
|
|
2061
2291
|
const clipboardBackend = options?.clipboard;
|
|
2062
2292
|
const clipboardGate = (door) => {
|
|
2063
2293
|
const grant = clipboardGrant();
|
|
@@ -2263,6 +2493,9 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2263
2493
|
if (getEditor().text) {
|
|
2264
2494
|
featureSet.add("text.measure@1");
|
|
2265
2495
|
}
|
|
2496
|
+
if (getEditor().text?.measureMany) {
|
|
2497
|
+
featureSet.add("text.measureStrings@1");
|
|
2498
|
+
}
|
|
2266
2499
|
if (getEditor().sceneLayers) {
|
|
2267
2500
|
featureSet.add("rendering.sceneLayer@1");
|
|
2268
2501
|
featureSet.add("rendering.sceneLayer.faces@1");
|
|
@@ -2270,6 +2503,12 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2270
2503
|
if (typeof getEditor().overlaySignals?.setToolPreviews === "function") {
|
|
2271
2504
|
featureSet.add("overlay.multiPreview@1");
|
|
2272
2505
|
}
|
|
2506
|
+
if (typeof getEditor().overlaySignals?.setOverlayLayer === "function" && typeof getEditor().overlaySignals?.removeOverlayLayer === "function") {
|
|
2507
|
+
featureSet.add("overlay.layers@1");
|
|
2508
|
+
}
|
|
2509
|
+
if (options?.editContextEnterPoint === true) {
|
|
2510
|
+
featureSet.add("editContext.enterPoint@1");
|
|
2511
|
+
}
|
|
2273
2512
|
if (getEditor().images) {
|
|
2274
2513
|
featureSet.add("rendering.resourceProvider@1");
|
|
2275
2514
|
}
|
|
@@ -2313,6 +2552,9 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2313
2552
|
if (options?.assetSource) {
|
|
2314
2553
|
featureSet.add("assets.fonts@1");
|
|
2315
2554
|
}
|
|
2555
|
+
if (typeof options?.assetSource?.registerFont === "function" && typeof options?.assetSource?.clearSceneFonts === "function") {
|
|
2556
|
+
featureSet.add("assets.registerFont@1");
|
|
2557
|
+
}
|
|
2316
2558
|
if (options?.consent) {
|
|
2317
2559
|
featureSet.add("network.consent@1");
|
|
2318
2560
|
}
|
|
@@ -2335,6 +2577,10 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2335
2577
|
featureSet.add("document.readNative@1");
|
|
2336
2578
|
featureSet.add("document.openNative@1");
|
|
2337
2579
|
}
|
|
2580
|
+
if (options?.documents) {
|
|
2581
|
+
featureSet.add("documents.exportPaged@1");
|
|
2582
|
+
featureSet.add("documents.open@1");
|
|
2583
|
+
}
|
|
2338
2584
|
if (options?.workers) {
|
|
2339
2585
|
featureSet.add("workers@1");
|
|
2340
2586
|
}
|
|
@@ -2358,6 +2604,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2358
2604
|
blob,
|
|
2359
2605
|
parts,
|
|
2360
2606
|
nativeDocument,
|
|
2607
|
+
documents,
|
|
2361
2608
|
network,
|
|
2362
2609
|
dataProviders,
|
|
2363
2610
|
diagnostics,
|
|
@@ -2612,7 +2859,7 @@ function inMemorySecretStore() {
|
|
|
2612
2859
|
};
|
|
2613
2860
|
}
|
|
2614
2861
|
var seqCounter = 1;
|
|
2615
|
-
function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews) {
|
|
2862
|
+
function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews, overlayLayers, engineShaper = false) {
|
|
2616
2863
|
const protocol = worker.protocolVersion;
|
|
2617
2864
|
const listeners = /* @__PURE__ */ new Set();
|
|
2618
2865
|
const fanOut = (reply) => {
|
|
@@ -2762,6 +3009,15 @@ function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews) {
|
|
|
2762
3009
|
toolPreview = toolPreviews ? toolPreviews[0] : null;
|
|
2763
3010
|
onToolPreviews(toolPreviews);
|
|
2764
3011
|
onToolPreview(toolPreview);
|
|
3012
|
+
},
|
|
3013
|
+
// W-20 — the retained layers. A Map keeps first-insertion order,
|
|
3014
|
+
// which is the stack order the editor renders; a re-set keeps the
|
|
3015
|
+
// key's place.
|
|
3016
|
+
setOverlayLayer(key, shapes) {
|
|
3017
|
+
overlayLayers.set(key, shapes);
|
|
3018
|
+
},
|
|
3019
|
+
removeOverlayLayer(key) {
|
|
3020
|
+
overlayLayers.delete(key);
|
|
2765
3021
|
}
|
|
2766
3022
|
},
|
|
2767
3023
|
// No tool spine + no content caret headlessly — both are inert
|
|
@@ -2772,7 +3028,23 @@ function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews) {
|
|
|
2772
3028
|
},
|
|
2773
3029
|
contentSelection: { contentSelection: null }
|
|
2774
3030
|
};
|
|
2775
|
-
|
|
3031
|
+
const measureText = worker.measureText?.bind(worker);
|
|
3032
|
+
if (engineShaper && measureText) {
|
|
3033
|
+
const zero = { advance: 0, ascender: 0, descender: 0 };
|
|
3034
|
+
const one = (family, style, t, sizePt) => {
|
|
3035
|
+
const m = measureText(family, style, t, sizePt);
|
|
3036
|
+
return m ? { advance: m.advance, ascender: m.ascender, descender: m.descender } : zero;
|
|
3037
|
+
};
|
|
3038
|
+
editor.text = {
|
|
3039
|
+
async measure(family, style, t, sizePt) {
|
|
3040
|
+
return one(family, style, t, sizePt);
|
|
3041
|
+
},
|
|
3042
|
+
async measureMany(family, style, texts, sizePt) {
|
|
3043
|
+
return texts.map((t) => one(family, style, t, sizePt));
|
|
3044
|
+
}
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
return { editor, fanOut };
|
|
2776
3048
|
}
|
|
2777
3049
|
async function createHeadlessHost(options = {}) {
|
|
2778
3050
|
const engine = await loadHeadlessEngine(options);
|
|
@@ -2780,7 +3052,8 @@ async function createHeadlessHost(options = {}) {
|
|
|
2780
3052
|
const contributions = [];
|
|
2781
3053
|
let lastPreview = null;
|
|
2782
3054
|
let lastPreviews = null;
|
|
2783
|
-
const
|
|
3055
|
+
const overlayLayerMap = /* @__PURE__ */ new Map();
|
|
3056
|
+
const { editor, fanOut } = makeEngineEditor(
|
|
2784
3057
|
worker,
|
|
2785
3058
|
contributions,
|
|
2786
3059
|
(value) => {
|
|
@@ -2788,8 +3061,55 @@ async function createHeadlessHost(options = {}) {
|
|
|
2788
3061
|
},
|
|
2789
3062
|
(value) => {
|
|
2790
3063
|
lastPreviews = value;
|
|
2791
|
-
}
|
|
3064
|
+
},
|
|
3065
|
+
overlayLayerMap,
|
|
3066
|
+
options.engineShaper === true
|
|
2792
3067
|
);
|
|
3068
|
+
const loadDirect = (bytes) => {
|
|
3069
|
+
const reply = JSON.parse(
|
|
3070
|
+
options.defaultFont ? worker.loadDocumentDirect(seqCounter++, bytes, options.defaultFont) : worker.loadDocumentDirect(seqCounter++, bytes)
|
|
3071
|
+
);
|
|
3072
|
+
if (reply.kind === "documentLoaded") {
|
|
3073
|
+
try {
|
|
3074
|
+
worker.runResolveJson();
|
|
3075
|
+
} catch {
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
return reply;
|
|
3079
|
+
};
|
|
3080
|
+
const loadFailure = (reply) => {
|
|
3081
|
+
const errKind = reply.kind === "loadFailed" ? reply.payload.error.kind : reply.kind;
|
|
3082
|
+
return new Error(`headless load failed (${reply.kind}: ${errKind})`);
|
|
3083
|
+
};
|
|
3084
|
+
const opened = [];
|
|
3085
|
+
const documentsBackend = {
|
|
3086
|
+
async exportPaged() {
|
|
3087
|
+
const reply = await editor.client.send({ kind: "exportPaged", payload: {} });
|
|
3088
|
+
if (reply.kind === "pagedExported") return Uint8Array.from(reply.payload.bytes);
|
|
3089
|
+
if (reply.kind === "pagedPartFailed") throw new Error(reply.payload.error);
|
|
3090
|
+
throw new Error(`unexpected reply: ${reply.kind}`);
|
|
3091
|
+
},
|
|
3092
|
+
async open(bytes, request) {
|
|
3093
|
+
let dirty = false;
|
|
3094
|
+
try {
|
|
3095
|
+
dirty = (await editor.client.documentMeta()).dirty;
|
|
3096
|
+
} catch {
|
|
3097
|
+
dirty = false;
|
|
3098
|
+
}
|
|
3099
|
+
if (dirty && options.confirmReplace && !await options.confirmReplace(request)) {
|
|
3100
|
+
return { opened: false, reason: "declined" };
|
|
3101
|
+
}
|
|
3102
|
+
const reply = loadDirect(bytes);
|
|
3103
|
+
if (reply.kind !== "documentLoaded") throw loadFailure(reply);
|
|
3104
|
+
fanOut(reply);
|
|
3105
|
+
opened.push({
|
|
3106
|
+
name: request.name,
|
|
3107
|
+
requester: request.requester.id,
|
|
3108
|
+
pageIds: reply.payload.pageIds
|
|
3109
|
+
});
|
|
3110
|
+
return { opened: true, pageIds: reply.payload.pageIds };
|
|
3111
|
+
}
|
|
3112
|
+
};
|
|
2793
3113
|
let active = null;
|
|
2794
3114
|
let currentHost = null;
|
|
2795
3115
|
let disposed = false;
|
|
@@ -2814,6 +3134,10 @@ async function createHeadlessHost(options = {}) {
|
|
|
2814
3134
|
// headlessly (the editor's real adapter currently serves null;
|
|
2815
3135
|
// DESIGN.md §13.4). Absent → the no-bytes door.
|
|
2816
3136
|
assetSource: options.assetSource,
|
|
3137
|
+
// W-19 — `enterEditContext()` below delivers the entering point the
|
|
3138
|
+
// way the editor shell does, so the harness vouches for it.
|
|
3139
|
+
editContextEnterPoint: true,
|
|
3140
|
+
documents: documentsBackend,
|
|
2817
3141
|
// Record the SCHEMA verbatim at registration — the panel registry
|
|
2818
3142
|
// only ever sees the synthesized React panel, so the conformance
|
|
2819
3143
|
// log gets the schema through this adapter seam (no host renderer
|
|
@@ -2875,7 +3199,8 @@ async function createHeadlessHost(options = {}) {
|
|
|
2875
3199
|
rendering: ["overlay", "hitTest", "sceneLayer"],
|
|
2876
3200
|
keybindings: true,
|
|
2877
3201
|
storage: { blob: true },
|
|
2878
|
-
secrets: { sources: true }
|
|
3202
|
+
secrets: { sources: true },
|
|
3203
|
+
documents: { export: true, open: true }
|
|
2879
3204
|
},
|
|
2880
3205
|
// Broad contribution declarations so the neutral DRIVER host (which
|
|
2881
3206
|
// registers arbitrary contributions directly in 'warn' mode) never
|
|
@@ -2927,21 +3252,30 @@ async function createHeadlessHost(options = {}) {
|
|
|
2927
3252
|
lastToolPreviews() {
|
|
2928
3253
|
return lastPreviews;
|
|
2929
3254
|
},
|
|
3255
|
+
overlayLayers() {
|
|
3256
|
+
return [...overlayLayerMap].map(([key, shapes]) => ({ key, shapes }));
|
|
3257
|
+
},
|
|
3258
|
+
enterEditContext(ctx) {
|
|
3259
|
+
const entry = contributions.find(
|
|
3260
|
+
(c) => c.kind === "editContext" && c.id === ctx.type
|
|
3261
|
+
);
|
|
3262
|
+
if (!entry) return false;
|
|
3263
|
+
entry.value.onEnter?.(ctx);
|
|
3264
|
+
return true;
|
|
3265
|
+
},
|
|
2930
3266
|
bindingProviders,
|
|
2931
3267
|
willSave,
|
|
2932
3268
|
toolSettings,
|
|
2933
3269
|
async load(idml) {
|
|
2934
|
-
const
|
|
2935
|
-
const reply = JSON.parse(raw);
|
|
3270
|
+
const reply = loadDirect(idml);
|
|
2936
3271
|
if (reply.kind === "documentLoaded") {
|
|
2937
|
-
|
|
2938
|
-
worker.runResolveJson();
|
|
2939
|
-
} catch {
|
|
2940
|
-
}
|
|
3272
|
+
fanOut(reply);
|
|
2941
3273
|
return reply.payload.pageIds;
|
|
2942
3274
|
}
|
|
2943
|
-
|
|
2944
|
-
|
|
3275
|
+
throw loadFailure(reply);
|
|
3276
|
+
},
|
|
3277
|
+
openedDocuments() {
|
|
3278
|
+
return opened;
|
|
2945
3279
|
},
|
|
2946
3280
|
loadBundle(bundle) {
|
|
2947
3281
|
if (active) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paged-media/plugin-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.42-canary.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@paged-media/plugin-api": "0.2.
|
|
14
|
+
"@paged-media/plugin-api": "0.2.42-canary.0"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"react": "^18.3.0"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@paged-media/canvas-wasm": "0.
|
|
25
|
+
"@paged-media/canvas-wasm": "0.70.0",
|
|
26
26
|
"@types/node": "20.19.39",
|
|
27
27
|
"@types/react": "^18.3.31",
|
|
28
28
|
"react": "^18.3.1",
|