@paged-media/plugin-sdk 0.2.41-canary.0 → 0.2.43-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 +50 -2
- package/dist/index.js +243 -3
- 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, OpenDocumentResult, 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
|
|
@@ -261,6 +273,18 @@ interface DocumentsBackend {
|
|
|
261
273
|
};
|
|
262
274
|
}): Promise<OpenDocumentResult>;
|
|
263
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* v70 — the backend the editor injects to back `host.viewport`'s page
|
|
278
|
+
* members. The editor owns the camera and the page layout, so it answers
|
|
279
|
+
* which page is active and moves the camera to one. No backend →
|
|
280
|
+
* `goToPage` answers false, `activePage` null, the event never fires and
|
|
281
|
+
* `supports("viewport.pages@1")` is false.
|
|
282
|
+
*/
|
|
283
|
+
interface PagesBackend {
|
|
284
|
+
goToPage(pageId: string, fit: "page" | "width"): boolean | Promise<boolean>;
|
|
285
|
+
activePage(): string | null;
|
|
286
|
+
onDidChangeActivePage(listener: (pageId: string | null) => void): () => void;
|
|
287
|
+
}
|
|
264
288
|
/** The SHARED cross-plugin data-provider registry (paged.data §7.1 / D-09). The
|
|
265
289
|
* editor creates ONE (`createDataProviderRegistry`) and injects the SAME
|
|
266
290
|
* instance into every plugin host, so a provider plugin and a consumer plugin
|
|
@@ -423,6 +447,13 @@ interface CreateBundleHostOptions {
|
|
|
423
447
|
* holds listeners that never run and `supports("document.onWillSave@1")`
|
|
424
448
|
* is false. */
|
|
425
449
|
willSave?: WillSaveBackend;
|
|
450
|
+
/** W-19 — the host's shell fills `pageId` / `pagePoint` /
|
|
451
|
+
* `contentPoint` on the `EnteredEditContext` of a POINTER entry (the
|
|
452
|
+
* double-click, the Type-tool click on owned content). The SDK passes
|
|
453
|
+
* the entered context through untouched either way; this flag only
|
|
454
|
+
* makes `supports("editContext.enterPoint@1")` true, so it is the HOST
|
|
455
|
+
* that vouches for delivery. */
|
|
456
|
+
editContextEnterPoint?: boolean;
|
|
426
457
|
/** The host's tool-options store. When absent, `host.tools.settings`
|
|
427
458
|
* answers `{}` and `supports("tools.settings@1")` is false. */
|
|
428
459
|
toolSettings?: ToolSettingsBackend;
|
|
@@ -496,6 +527,10 @@ interface CreateBundleHostOptions {
|
|
|
496
527
|
* `supports("documents.exportPaged@1")` / `supports("documents.open@1")`
|
|
497
528
|
* answer true. When absent, both doors reject. */
|
|
498
529
|
documents?: DocumentsBackend;
|
|
530
|
+
/** v70 — page navigation for `host.viewport` (`goToPage`,
|
|
531
|
+
* `activePage`, `onDidChangeActivePage`). When present,
|
|
532
|
+
* `supports("viewport.pages@1")` is true. */
|
|
533
|
+
pages?: PagesBackend;
|
|
499
534
|
/** Host-provided WORKER backend (K-3 / S-07 / I-02). When present,
|
|
500
535
|
* `host.workers.spawn` resolves a declared bundle-relative module +
|
|
501
536
|
* constructs a host-owned `Worker` through it (capability-gated,
|
|
@@ -699,6 +734,19 @@ interface HeadlessHost {
|
|
|
699
734
|
* bundle's "geometry AND label at once" claim is assertable without a
|
|
700
735
|
* browser. `lastToolPreview()` tracks the list's FIRST shape. */
|
|
701
736
|
lastToolPreviews(): readonly ToolPreviewShape[] | null;
|
|
737
|
+
/** W-20 — every LIVE overlay layer (`host.overlay.layer`), in stack
|
|
738
|
+
* order (bottom-most first), keyed `<manifest id>/<layer id>`, with the
|
|
739
|
+
* shapes it holds now (`[]` once cleared). A disposed layer is gone. */
|
|
740
|
+
overlayLayers(): ReadonlyArray<{
|
|
741
|
+
key: string;
|
|
742
|
+
shapes: readonly ToolPreviewShape[];
|
|
743
|
+
}>;
|
|
744
|
+
/** W-19 — play the SHELL's part on a pointer entry: call the registered
|
|
745
|
+
* edit context's `onEnter` with `ctx` (which may carry `pageId` /
|
|
746
|
+
* `pagePoint` / `contentPoint`, as the editor fills them). The harness
|
|
747
|
+
* advertises `editContext.enterPoint@1`. Returns `false` when no
|
|
748
|
+
* context of `ctx.type` is registered. */
|
|
749
|
+
enterEditContext(ctx: EnteredEditContext): boolean;
|
|
702
750
|
/** ADR-023 phase A — the SHARED binding-provider registry this host
|
|
703
751
|
* injected. It is the HOST side of the seam, so a conformance test
|
|
704
752
|
* plays the part the editor's shared panel plays in phase C: enter
|
|
@@ -989,4 +1037,4 @@ declare function contributeObjectType(host: BundleHost, contribution: ObjectType
|
|
|
989
1037
|
*/
|
|
990
1038
|
declare function contributeBindingProvider(host: BundleHost, contextType: string, provider: BindingProvider): BindingProviderHandle;
|
|
991
1039
|
|
|
992
|
-
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 };
|
|
1040
|
+
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, type PagesBackend, 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,6 +228,10 @@ 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",
|
|
233
237
|
// Protocol 69 — the document-scoped label. Static like the snap door:
|
|
@@ -275,6 +279,10 @@ var HOST_FEATURES = [
|
|
|
275
279
|
// door: the flag says this SDK forwards `snapPoint`; an engine older
|
|
276
280
|
// than v67 answers the point unsnapped, never a throw.
|
|
277
281
|
"document.snapPoint@1",
|
|
282
|
+
// v70 — page images from the engine's renderer (`requestSnapshot` with
|
|
283
|
+
// `hideItems`). Static like the snapper: the flag says this SDK
|
|
284
|
+
// forwards the query; an engine that refuses answers null.
|
|
285
|
+
"render.snapshot@1",
|
|
278
286
|
// DOC-03 structured whole-story read (canvas-wasm v54). Static for the same
|
|
279
287
|
// reason as storage.parts@1: the pinned engine is the server, and the worker
|
|
280
288
|
// handshake refuses a protocol older than the pin — so a running bundle is
|
|
@@ -333,6 +341,15 @@ var ASSET_BUDGETS = {
|
|
|
333
341
|
/** Largest font face the door will serve, in bytes (8 MiB). */
|
|
334
342
|
maxFontFaceBytes: 8 * 1024 * 1024
|
|
335
343
|
};
|
|
344
|
+
var sceneFaceLedgers = /* @__PURE__ */ new WeakMap();
|
|
345
|
+
function sceneFaceLedger(provider) {
|
|
346
|
+
let ledger = sceneFaceLedgers.get(provider);
|
|
347
|
+
if (!ledger) {
|
|
348
|
+
ledger = { entries: [], queue: Promise.resolve() };
|
|
349
|
+
sceneFaceLedgers.set(provider, ledger);
|
|
350
|
+
}
|
|
351
|
+
return ledger;
|
|
352
|
+
}
|
|
336
353
|
var BLOB_BUDGETS = {
|
|
337
354
|
/** Default per-plugin blob ceiling, in bytes (64 MiB). */
|
|
338
355
|
defaultQuotaBytes: 64 * 1024 * 1024
|
|
@@ -1104,7 +1121,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1104
1121
|
}
|
|
1105
1122
|
};
|
|
1106
1123
|
const foreignMetadataKey = (m) => {
|
|
1107
|
-
if (m.op === "setPluginMetadata" || m.op === "setDocumentMetadata") {
|
|
1124
|
+
if (m.op === "setPluginMetadata" || m.op === "setDocumentMetadata" || m.op === "setPageMetadata") {
|
|
1108
1125
|
return m.args.key === metadataKey(manifest) ? null : m.args.key;
|
|
1109
1126
|
}
|
|
1110
1127
|
if (m.op === "batch") {
|
|
@@ -1442,6 +1459,28 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1442
1459
|
});
|
|
1443
1460
|
return store.add(toDisposable(off));
|
|
1444
1461
|
},
|
|
1462
|
+
// W-22 — the raw `documentLoaded` broadcast, narrowed to a clonable
|
|
1463
|
+
// snapshot (the handle's stats / ruler guides stay host-side).
|
|
1464
|
+
onDidOpen(listener) {
|
|
1465
|
+
requireDocRead("document.onDidOpen");
|
|
1466
|
+
const off = getEditor().client.subscribe((msg) => {
|
|
1467
|
+
if (msg.kind !== "documentLoaded") return;
|
|
1468
|
+
const h2 = msg.payload;
|
|
1469
|
+
try {
|
|
1470
|
+
listener({
|
|
1471
|
+
docId: h2.docId,
|
|
1472
|
+
pageCount: h2.pageCount,
|
|
1473
|
+
pageIds: [...h2.pageIds],
|
|
1474
|
+
pageSizesPt: h2.pageSizesPt.map(
|
|
1475
|
+
([w, hgt]) => [w, hgt]
|
|
1476
|
+
)
|
|
1477
|
+
});
|
|
1478
|
+
} catch (err) {
|
|
1479
|
+
log.error(`document.onDidOpen listener failed: ${String(err)}`);
|
|
1480
|
+
}
|
|
1481
|
+
});
|
|
1482
|
+
return store.add(toDisposable(off));
|
|
1483
|
+
},
|
|
1445
1484
|
// Protocol 66 batch — the save hook. The host awaits every
|
|
1446
1485
|
// registered listener before it serialises the document; the wrapper
|
|
1447
1486
|
// makes a bundle's failure a logged event, never a failed save.
|
|
@@ -1485,6 +1524,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1485
1524
|
return store.add(toDisposable(off));
|
|
1486
1525
|
}
|
|
1487
1526
|
};
|
|
1527
|
+
const pagesBackend = options?.pages;
|
|
1488
1528
|
const viewport = {
|
|
1489
1529
|
camera() {
|
|
1490
1530
|
const cam = getEditor().camera.camera;
|
|
@@ -1493,6 +1533,53 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1493
1533
|
pxToPt(px) {
|
|
1494
1534
|
const scale = getEditor().camera.camera.scale;
|
|
1495
1535
|
return px / (scale > 0 ? scale : 1);
|
|
1536
|
+
},
|
|
1537
|
+
async goToPage(pageId, opts) {
|
|
1538
|
+
if (!pagesBackend || typeof pageId !== "string" || pageId === "") {
|
|
1539
|
+
return false;
|
|
1540
|
+
}
|
|
1541
|
+
const fit = opts?.fit === "width" ? "width" : "page";
|
|
1542
|
+
return await pagesBackend.goToPage(pageId, fit) === true;
|
|
1543
|
+
},
|
|
1544
|
+
activePage() {
|
|
1545
|
+
return pagesBackend ? pagesBackend.activePage() : null;
|
|
1546
|
+
},
|
|
1547
|
+
onDidChangeActivePage(listener) {
|
|
1548
|
+
if (!pagesBackend) {
|
|
1549
|
+
return toDisposable(() => {
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
return store.add(toDisposable(pagesBackend.onDidChangeActivePage(listener)));
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
const render = {
|
|
1556
|
+
async snapshot(pageId, opts) {
|
|
1557
|
+
requireDocRead("render.snapshot");
|
|
1558
|
+
const widthPx = Math.round(opts?.widthPx ?? 0);
|
|
1559
|
+
if (!(widthPx >= 1 && widthPx <= 8192)) {
|
|
1560
|
+
throw new Error("host.render.snapshot: widthPx must be 1 to 8192");
|
|
1561
|
+
}
|
|
1562
|
+
const hideItems = Array.isArray(opts?.hideItems) ? opts.hideItems : [];
|
|
1563
|
+
let reply;
|
|
1564
|
+
try {
|
|
1565
|
+
reply = await getEditor().client.send({
|
|
1566
|
+
kind: "requestSnapshot",
|
|
1567
|
+
payload: { pageId, targetWidthPx: widthPx, hideItems }
|
|
1568
|
+
});
|
|
1569
|
+
} catch {
|
|
1570
|
+
return null;
|
|
1571
|
+
}
|
|
1572
|
+
if (reply.kind !== "snapshotReady") {
|
|
1573
|
+
return null;
|
|
1574
|
+
}
|
|
1575
|
+
const p = reply.payload;
|
|
1576
|
+
return {
|
|
1577
|
+
pageId: p.pageId,
|
|
1578
|
+
widthPx: p.widthPx,
|
|
1579
|
+
heightPx: p.heightPx,
|
|
1580
|
+
png: Uint8Array.from(p.pngBytes),
|
|
1581
|
+
layoutGeneration: p.layoutGeneration
|
|
1582
|
+
};
|
|
1496
1583
|
}
|
|
1497
1584
|
};
|
|
1498
1585
|
const text = {
|
|
@@ -1536,6 +1623,9 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1536
1623
|
);
|
|
1537
1624
|
}
|
|
1538
1625
|
};
|
|
1626
|
+
let overlayLayerSeq = 0;
|
|
1627
|
+
let overlayLayerWarned = false;
|
|
1628
|
+
const liveOverlayLayers = /* @__PURE__ */ new Set();
|
|
1539
1629
|
const overlay = {
|
|
1540
1630
|
setToolPreview(shape) {
|
|
1541
1631
|
requireDeclared(
|
|
@@ -1565,6 +1655,56 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1565
1655
|
return;
|
|
1566
1656
|
}
|
|
1567
1657
|
signals.setToolPreview(list ? list[0] : null);
|
|
1658
|
+
},
|
|
1659
|
+
// W-20 — retained per-bundle layers. Each layer is a host-wide key
|
|
1660
|
+
// `<manifest id>/<layer id>`; registering it with `[]` at creation
|
|
1661
|
+
// fixes its place in the stack (creation order), so a later `set`
|
|
1662
|
+
// never reorders it. Without a host sink the handle is inert (warned
|
|
1663
|
+
// once per bundle) — never a throw, never a write into the shared
|
|
1664
|
+
// tool-preview slot, which would erase the active tool's preview.
|
|
1665
|
+
layer(id) {
|
|
1666
|
+
requireDeclared(
|
|
1667
|
+
hasRendering("overlay"),
|
|
1668
|
+
"overlay.layer",
|
|
1669
|
+
'capabilities.rendering must include "overlay"'
|
|
1670
|
+
);
|
|
1671
|
+
const layerId = id ?? `layer-${++overlayLayerSeq}`;
|
|
1672
|
+
if (liveOverlayLayers.has(layerId)) {
|
|
1673
|
+
throw new Error(
|
|
1674
|
+
`host.overlay.layer("${layerId}"): a layer with this id is already live in ${manifest.id} \u2014 dispose it first or pick another id`
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
const key = `${manifest.id}/${layerId}`;
|
|
1678
|
+
const signals = getEditor().overlaySignals;
|
|
1679
|
+
const sink2 = typeof signals?.setOverlayLayer === "function" && typeof signals?.removeOverlayLayer === "function" ? signals : null;
|
|
1680
|
+
if (!sink2 && !overlayLayerWarned) {
|
|
1681
|
+
overlayLayerWarned = true;
|
|
1682
|
+
log.warn(
|
|
1683
|
+
'host.overlay.layer \u2014 this host renders no overlay layers (supports("overlay.layers@1") is false); shapes are dropped'
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
liveOverlayLayers.add(layerId);
|
|
1687
|
+
sink2?.setOverlayLayer(key, []);
|
|
1688
|
+
let disposed = false;
|
|
1689
|
+
const handle = {
|
|
1690
|
+
id: layerId,
|
|
1691
|
+
set(shapes) {
|
|
1692
|
+
if (disposed) return;
|
|
1693
|
+
sink2?.setOverlayLayer(key, [...shapes]);
|
|
1694
|
+
},
|
|
1695
|
+
clear() {
|
|
1696
|
+
if (disposed) return;
|
|
1697
|
+
sink2?.setOverlayLayer(key, []);
|
|
1698
|
+
},
|
|
1699
|
+
dispose() {
|
|
1700
|
+
if (disposed) return;
|
|
1701
|
+
disposed = true;
|
|
1702
|
+
liveOverlayLayers.delete(layerId);
|
|
1703
|
+
sink2?.removeOverlayLayer(key);
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
store.add(handle);
|
|
1707
|
+
return handle;
|
|
1568
1708
|
}
|
|
1569
1709
|
};
|
|
1570
1710
|
const backing = options?.storage ?? defaultStorageBacking();
|
|
@@ -1829,6 +1969,65 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1829
1969
|
}
|
|
1830
1970
|
return face;
|
|
1831
1971
|
},
|
|
1972
|
+
// W-15 — the one WRITE: a scene-layer face. The engine has a single
|
|
1973
|
+
// scene table that `clearFontRegistry` can only empty as a whole, so
|
|
1974
|
+
// the SDK keeps the list of live faces per provider (across bundles)
|
|
1975
|
+
// and disposes one face by clearing and replaying the others. Every
|
|
1976
|
+
// engine call goes through the ledger's queue, so a replay never
|
|
1977
|
+
// interleaves with a registration.
|
|
1978
|
+
async registerFont(bytes, family, style) {
|
|
1979
|
+
requireDeclared(
|
|
1980
|
+
hasAsset("fonts"),
|
|
1981
|
+
"assets.registerFont",
|
|
1982
|
+
'capabilities.assets must include "fonts"'
|
|
1983
|
+
);
|
|
1984
|
+
const label = `assets.registerFont("${family}"${style ? `, "${style}"` : ""})`;
|
|
1985
|
+
if (bytes.byteLength > ASSET_BUDGETS.maxFontFaceBytes) {
|
|
1986
|
+
throw new Error(
|
|
1987
|
+
`${label}: ${bytes.byteLength} bytes is over the ${ASSET_BUDGETS.maxFontFaceBytes}-byte per-face cap`
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
const provider = assetSource;
|
|
1991
|
+
const register = provider?.registerFont?.bind(provider);
|
|
1992
|
+
const clear = provider?.clearSceneFonts?.bind(provider);
|
|
1993
|
+
if (!provider || !register || !clear) {
|
|
1994
|
+
log.warn(
|
|
1995
|
+
`${label} ignored \u2014 the host cannot register scene faces (probe supports("assets.registerFont@1")); scene text keeps its fallback face`
|
|
1996
|
+
);
|
|
1997
|
+
return toDisposable(() => {
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
const ledger = sceneFaceLedger(provider);
|
|
2001
|
+
const entry = style === void 0 ? { family, bytes: bytes.slice() } : { family, style, bytes: bytes.slice() };
|
|
2002
|
+
const run = (job) => {
|
|
2003
|
+
const next = ledger.queue.then(job);
|
|
2004
|
+
ledger.queue = next.catch(() => {
|
|
2005
|
+
});
|
|
2006
|
+
return next;
|
|
2007
|
+
};
|
|
2008
|
+
await run(async () => {
|
|
2009
|
+
await register(entry.family, entry.bytes, entry.style);
|
|
2010
|
+
ledger.entries.push(entry);
|
|
2011
|
+
});
|
|
2012
|
+
let disposed = false;
|
|
2013
|
+
return store.add(
|
|
2014
|
+
toDisposable(() => {
|
|
2015
|
+
if (disposed) return;
|
|
2016
|
+
disposed = true;
|
|
2017
|
+
void run(async () => {
|
|
2018
|
+
const i = ledger.entries.indexOf(entry);
|
|
2019
|
+
if (i < 0) return;
|
|
2020
|
+
ledger.entries.splice(i, 1);
|
|
2021
|
+
await clear();
|
|
2022
|
+
for (const live of ledger.entries) {
|
|
2023
|
+
await register(live.family, live.bytes, live.style);
|
|
2024
|
+
}
|
|
2025
|
+
}).catch((error) => {
|
|
2026
|
+
log.warn(`${label}: dropping the face failed: ${String(error)}`);
|
|
2027
|
+
});
|
|
2028
|
+
})
|
|
2029
|
+
);
|
|
2030
|
+
},
|
|
1832
2031
|
// C-5 / I-04 (core v42): a placed DOCUMENT image's ORIGINAL bytes,
|
|
1833
2032
|
// straight from the engine's resolver/parse cache through the
|
|
1834
2033
|
// `requestPlacedAssetBytes` wire query — no injected source needed
|
|
@@ -2356,6 +2555,12 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2356
2555
|
if (typeof getEditor().overlaySignals?.setToolPreviews === "function") {
|
|
2357
2556
|
featureSet.add("overlay.multiPreview@1");
|
|
2358
2557
|
}
|
|
2558
|
+
if (typeof getEditor().overlaySignals?.setOverlayLayer === "function" && typeof getEditor().overlaySignals?.removeOverlayLayer === "function") {
|
|
2559
|
+
featureSet.add("overlay.layers@1");
|
|
2560
|
+
}
|
|
2561
|
+
if (options?.editContextEnterPoint === true) {
|
|
2562
|
+
featureSet.add("editContext.enterPoint@1");
|
|
2563
|
+
}
|
|
2359
2564
|
if (getEditor().images) {
|
|
2360
2565
|
featureSet.add("rendering.resourceProvider@1");
|
|
2361
2566
|
}
|
|
@@ -2399,6 +2604,9 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2399
2604
|
if (options?.assetSource) {
|
|
2400
2605
|
featureSet.add("assets.fonts@1");
|
|
2401
2606
|
}
|
|
2607
|
+
if (typeof options?.assetSource?.registerFont === "function" && typeof options?.assetSource?.clearSceneFonts === "function") {
|
|
2608
|
+
featureSet.add("assets.registerFont@1");
|
|
2609
|
+
}
|
|
2402
2610
|
if (options?.consent) {
|
|
2403
2611
|
featureSet.add("network.consent@1");
|
|
2404
2612
|
}
|
|
@@ -2421,6 +2629,9 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2421
2629
|
featureSet.add("document.readNative@1");
|
|
2422
2630
|
featureSet.add("document.openNative@1");
|
|
2423
2631
|
}
|
|
2632
|
+
if (options?.pages) {
|
|
2633
|
+
featureSet.add("viewport.pages@1");
|
|
2634
|
+
}
|
|
2424
2635
|
if (options?.documents) {
|
|
2425
2636
|
featureSet.add("documents.exportPaged@1");
|
|
2426
2637
|
featureSet.add("documents.open@1");
|
|
@@ -2441,6 +2652,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2441
2652
|
document,
|
|
2442
2653
|
selection,
|
|
2443
2654
|
viewport,
|
|
2655
|
+
render,
|
|
2444
2656
|
text,
|
|
2445
2657
|
overlay,
|
|
2446
2658
|
shell,
|
|
@@ -2703,7 +2915,7 @@ function inMemorySecretStore() {
|
|
|
2703
2915
|
};
|
|
2704
2916
|
}
|
|
2705
2917
|
var seqCounter = 1;
|
|
2706
|
-
function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews, engineShaper = false) {
|
|
2918
|
+
function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews, overlayLayers, engineShaper = false) {
|
|
2707
2919
|
const protocol = worker.protocolVersion;
|
|
2708
2920
|
const listeners = /* @__PURE__ */ new Set();
|
|
2709
2921
|
const fanOut = (reply) => {
|
|
@@ -2853,6 +3065,15 @@ function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews, engin
|
|
|
2853
3065
|
toolPreview = toolPreviews ? toolPreviews[0] : null;
|
|
2854
3066
|
onToolPreviews(toolPreviews);
|
|
2855
3067
|
onToolPreview(toolPreview);
|
|
3068
|
+
},
|
|
3069
|
+
// W-20 — the retained layers. A Map keeps first-insertion order,
|
|
3070
|
+
// which is the stack order the editor renders; a re-set keeps the
|
|
3071
|
+
// key's place.
|
|
3072
|
+
setOverlayLayer(key, shapes) {
|
|
3073
|
+
overlayLayers.set(key, shapes);
|
|
3074
|
+
},
|
|
3075
|
+
removeOverlayLayer(key) {
|
|
3076
|
+
overlayLayers.delete(key);
|
|
2856
3077
|
}
|
|
2857
3078
|
},
|
|
2858
3079
|
// No tool spine + no content caret headlessly — both are inert
|
|
@@ -2887,6 +3108,7 @@ async function createHeadlessHost(options = {}) {
|
|
|
2887
3108
|
const contributions = [];
|
|
2888
3109
|
let lastPreview = null;
|
|
2889
3110
|
let lastPreviews = null;
|
|
3111
|
+
const overlayLayerMap = /* @__PURE__ */ new Map();
|
|
2890
3112
|
const { editor, fanOut } = makeEngineEditor(
|
|
2891
3113
|
worker,
|
|
2892
3114
|
contributions,
|
|
@@ -2896,6 +3118,7 @@ async function createHeadlessHost(options = {}) {
|
|
|
2896
3118
|
(value) => {
|
|
2897
3119
|
lastPreviews = value;
|
|
2898
3120
|
},
|
|
3121
|
+
overlayLayerMap,
|
|
2899
3122
|
options.engineShaper === true
|
|
2900
3123
|
);
|
|
2901
3124
|
const loadDirect = (bytes) => {
|
|
@@ -2967,6 +3190,9 @@ async function createHeadlessHost(options = {}) {
|
|
|
2967
3190
|
// headlessly (the editor's real adapter currently serves null;
|
|
2968
3191
|
// DESIGN.md §13.4). Absent → the no-bytes door.
|
|
2969
3192
|
assetSource: options.assetSource,
|
|
3193
|
+
// W-19 — `enterEditContext()` below delivers the entering point the
|
|
3194
|
+
// way the editor shell does, so the harness vouches for it.
|
|
3195
|
+
editContextEnterPoint: true,
|
|
2970
3196
|
documents: documentsBackend,
|
|
2971
3197
|
// Record the SCHEMA verbatim at registration — the panel registry
|
|
2972
3198
|
// only ever sees the synthesized React panel, so the conformance
|
|
@@ -3082,12 +3308,26 @@ async function createHeadlessHost(options = {}) {
|
|
|
3082
3308
|
lastToolPreviews() {
|
|
3083
3309
|
return lastPreviews;
|
|
3084
3310
|
},
|
|
3311
|
+
overlayLayers() {
|
|
3312
|
+
return [...overlayLayerMap].map(([key, shapes]) => ({ key, shapes }));
|
|
3313
|
+
},
|
|
3314
|
+
enterEditContext(ctx) {
|
|
3315
|
+
const entry = contributions.find(
|
|
3316
|
+
(c) => c.kind === "editContext" && c.id === ctx.type
|
|
3317
|
+
);
|
|
3318
|
+
if (!entry) return false;
|
|
3319
|
+
entry.value.onEnter?.(ctx);
|
|
3320
|
+
return true;
|
|
3321
|
+
},
|
|
3085
3322
|
bindingProviders,
|
|
3086
3323
|
willSave,
|
|
3087
3324
|
toolSettings,
|
|
3088
3325
|
async load(idml) {
|
|
3089
3326
|
const reply = loadDirect(idml);
|
|
3090
|
-
if (reply.kind === "documentLoaded")
|
|
3327
|
+
if (reply.kind === "documentLoaded") {
|
|
3328
|
+
fanOut(reply);
|
|
3329
|
+
return reply.payload.pageIds;
|
|
3330
|
+
}
|
|
3091
3331
|
throw loadFailure(reply);
|
|
3092
3332
|
},
|
|
3093
3333
|
openedDocuments() {
|
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.43-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.43-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",
|