@paged-media/plugin-sdk 0.2.40-canary.0 → 0.2.41-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 +70 -2
- package/dist/index.js +168 -18
- 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, BindingsSurface, PanelProps, SchemaGate, WasmArtifact, CanvasPointerEvent, Mutation, MutationOutcome, BindingProviderHandle } from '@paged-media/plugin-api';
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -240,6 +240,27 @@ interface NativeDocumentBackend {
|
|
|
240
240
|
listParts(prefix?: string): Promise<string[]>;
|
|
241
241
|
open(bytes: Uint8Array): Promise<void>;
|
|
242
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* D-26 — the backend the editor injects to back `host.documents`. The SDK
|
|
245
|
+
* owns the capability gate (`capabilities.documents.export` / `.open`); the
|
|
246
|
+
* backend owns the IO AND the unsaved-edits decision: `open` must ask the
|
|
247
|
+
* user (host UI) before discarding a dirty active document and answer
|
|
248
|
+
* `{ opened: false, reason: "declined" }` when they keep it. `requester`
|
|
249
|
+
* is filled by the SDK from the calling bundle's manifest (not from the
|
|
250
|
+
* plugin's arguments), so the prompt can name who is asking. No backend →
|
|
251
|
+
* both doors reject and `supports("documents.open@1")` /
|
|
252
|
+
* `supports("documents.exportPaged@1")` are false.
|
|
253
|
+
*/
|
|
254
|
+
interface DocumentsBackend {
|
|
255
|
+
exportPaged(): Promise<Uint8Array>;
|
|
256
|
+
open(bytes: Uint8Array, request: {
|
|
257
|
+
name: string | null;
|
|
258
|
+
requester: {
|
|
259
|
+
id: string;
|
|
260
|
+
name: string;
|
|
261
|
+
};
|
|
262
|
+
}): Promise<OpenDocumentResult>;
|
|
263
|
+
}
|
|
243
264
|
/** The SHARED cross-plugin data-provider registry (paged.data §7.1 / D-09). The
|
|
244
265
|
* editor creates ONE (`createDataProviderRegistry`) and injects the SAME
|
|
245
266
|
* instance into every plugin host, so a provider plugin and a consumer plugin
|
|
@@ -469,6 +490,12 @@ interface CreateBundleHostOptions {
|
|
|
469
490
|
* `supports("document.openNative@1")` answer true. When absent, the reads
|
|
470
491
|
* answer `null`/`[]` and `open` rejects (the honest no-backend door). */
|
|
471
492
|
nativeDocument?: NativeDocumentBackend;
|
|
493
|
+
/** D-26 — host-provided DOCUMENTS backend. When present,
|
|
494
|
+
* `host.documents.exportPaged` / `open` go through it (gated on
|
|
495
|
+
* `capabilities.documents.export` / `.open`) and
|
|
496
|
+
* `supports("documents.exportPaged@1")` / `supports("documents.open@1")`
|
|
497
|
+
* answer true. When absent, both doors reject. */
|
|
498
|
+
documents?: DocumentsBackend;
|
|
472
499
|
/** Host-provided WORKER backend (K-3 / S-07 / I-02). When present,
|
|
473
500
|
* `host.workers.spawn` resolves a declared bundle-relative module +
|
|
474
501
|
* constructs a host-owned `Worker` through it (capability-gated,
|
|
@@ -521,6 +548,14 @@ interface HeadlessCanvasWorker {
|
|
|
521
548
|
handleMessage(input: string): string;
|
|
522
549
|
loadDocumentDirect(seq: number, bytes: Uint8Array, font?: Uint8Array, cmykIccProfile?: Uint8Array): string;
|
|
523
550
|
runResolveJson(): string | undefined;
|
|
551
|
+
/** The engine shaper (v38): `{ advance, ascender, descender }` in pt, or
|
|
552
|
+
* null when no document is loaded / the face resolves to nothing.
|
|
553
|
+
* Optional so a structural fake need not carry it. */
|
|
554
|
+
measureText?(family: string, style: string | null | undefined, text: string, sizePt: number): {
|
|
555
|
+
advance: number;
|
|
556
|
+
ascender: number;
|
|
557
|
+
descender: number;
|
|
558
|
+
} | null;
|
|
524
559
|
free(): void;
|
|
525
560
|
}
|
|
526
561
|
interface LoadedEngine {
|
|
@@ -580,6 +615,32 @@ interface RecordedContribution {
|
|
|
580
615
|
value: ToolContribution | PanelContribution | SchemaPanelContribution | CommandContribution | KeybindingContribution | OverlayContribution | EditContextContribution | ObjectTypeContribution | ImporterContribution | ExporterContribution;
|
|
581
616
|
}
|
|
582
617
|
interface HarnessOptions extends LoadHeadlessEngineOptions, Pick<CreateBundleHostOptions, "console" | "storage" | "capabilityMode" | "assetSource" | "blobStore" | "clipboard" | "secrets" | "bindingProviders" | "willSave" | "toolSettings"> {
|
|
618
|
+
/** D-27 — back `host.text` with the ENGINE's shaper
|
|
619
|
+
* (`CanvasWorker.measureText`, the one the editor's worker calls)
|
|
620
|
+
* instead of the estimate, so `measureString` / `measureStrings`
|
|
621
|
+
* answer real widths against the loaded document's fonts and
|
|
622
|
+
* `supports("text.measure@1")` / `("text.measureStrings@1")` are true.
|
|
623
|
+
* Off by default: existing headless suites pinned the estimate. */
|
|
624
|
+
engineShaper?: boolean;
|
|
625
|
+
/** D-26 — the headless stand-in for the editor's keep/discard prompt.
|
|
626
|
+
* `host.documents.open` calls it ONLY when the active document has
|
|
627
|
+
* unsaved edits; resolve `false` to keep them (the door then answers
|
|
628
|
+
* `{ opened: false, reason: "declined" }`). Default: discard. */
|
|
629
|
+
confirmReplace?: (request: {
|
|
630
|
+
name: string | null;
|
|
631
|
+
requester: {
|
|
632
|
+
id: string;
|
|
633
|
+
name: string;
|
|
634
|
+
};
|
|
635
|
+
}) => boolean | Promise<boolean>;
|
|
636
|
+
/** D-28 — the default font every load lays out with, the headless
|
|
637
|
+
* stand-in for the editor's `defaultFontProvider` (the editor passes
|
|
638
|
+
* `/fonts/Inter.ttf`). The engine lays text out, and reports a story
|
|
639
|
+
* `overset`, only when it has a font: without one nothing is laid out and
|
|
640
|
+
* every story reads `overset: false` (not measured). Passed to every
|
|
641
|
+
* load, `load()` and `host.documents.open` alike. Absent: no font, as
|
|
642
|
+
* before. */
|
|
643
|
+
defaultFont?: Uint8Array;
|
|
583
644
|
}
|
|
584
645
|
/** A headless will-save registry: listeners register per plugin and
|
|
585
646
|
* `fire()` awaits them all, the way the editor's save path does — so a
|
|
@@ -656,6 +717,13 @@ interface HeadlessHost {
|
|
|
656
717
|
/** Load an IDML package into the headless document. Resolves to the
|
|
657
718
|
* loaded page ids (or throws on a parse failure). */
|
|
658
719
|
load(idml: Uint8Array): Promise<string[]>;
|
|
720
|
+
/** D-26 — every document a bundle opened through `host.documents.open`,
|
|
721
|
+
* in order (declined opens are not listed). */
|
|
722
|
+
openedDocuments(): ReadonlyArray<{
|
|
723
|
+
name: string | null;
|
|
724
|
+
requester: string;
|
|
725
|
+
pageIds: string[];
|
|
726
|
+
}>;
|
|
659
727
|
/** Activate a bundle against this host (apiVersion-negotiated). The
|
|
660
728
|
* returned disposer runs the bundle's teardown; the host's own
|
|
661
729
|
* facade teardown runs on `dispose()`. */
|
|
@@ -921,4 +989,4 @@ declare function contributeObjectType(host: BundleHost, contribution: ObjectType
|
|
|
921
989
|
*/
|
|
922
990
|
declare function contributeBindingProvider(host: BundleHost, contextType: string, provider: BindingProvider): BindingProviderHandle;
|
|
923
991
|
|
|
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 };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -230,6 +230,11 @@ var HOST_FEATURES = [
|
|
|
230
230
|
"document.onDidChange@1",
|
|
231
231
|
"document.getMetadata@1",
|
|
232
232
|
"document.setMetadata@1",
|
|
233
|
+
// Protocol 69 — the document-scoped label. Static like the snap door:
|
|
234
|
+
// the flag says this SDK forwards the two calls; an engine older than 69
|
|
235
|
+
// answers `null` on read (no `pluginMetadata` in its DocumentMeta) and
|
|
236
|
+
// `applied: false` on write (it does not know the op).
|
|
237
|
+
"document.documentMetadata@1",
|
|
233
238
|
"selection@1",
|
|
234
239
|
"viewport@1",
|
|
235
240
|
"overlay.toolPreview@1",
|
|
@@ -628,6 +633,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
628
633
|
const hasWorkers = () => typeof caps?.workers?.max === "number";
|
|
629
634
|
const hasSecrets = () => caps?.secrets?.sources === true;
|
|
630
635
|
const hasGpu = () => caps?.gpu?.realm === "bundle";
|
|
636
|
+
const hasDocuments = (dir) => caps?.documents?.[dir] === true;
|
|
631
637
|
const lists = (arr, id) => arr?.includes(id) ?? false;
|
|
632
638
|
const declaresType = (arr, type) => arr?.some((e) => e.type === type) ?? false;
|
|
633
639
|
const requireDeclared = (ok, door, missing) => {
|
|
@@ -1098,7 +1104,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1098
1104
|
}
|
|
1099
1105
|
};
|
|
1100
1106
|
const foreignMetadataKey = (m) => {
|
|
1101
|
-
if (m.op === "setPluginMetadata") {
|
|
1107
|
+
if (m.op === "setPluginMetadata" || m.op === "setDocumentMetadata") {
|
|
1102
1108
|
return m.args.key === metadataKey(manifest) ? null : m.args.key;
|
|
1103
1109
|
}
|
|
1104
1110
|
if (m.op === "batch") {
|
|
@@ -1147,7 +1153,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1147
1153
|
if (denied !== null) return { applied: false, error: denied };
|
|
1148
1154
|
const foreign = foreignMetadataKey(mutation);
|
|
1149
1155
|
if (foreign !== null) {
|
|
1150
|
-
const error = `
|
|
1156
|
+
const error = `metadata key "${foreign}" is outside this plugin's namespace ("${metadataKey(manifest)}")`;
|
|
1151
1157
|
log.warn(error);
|
|
1152
1158
|
return { applied: false, error };
|
|
1153
1159
|
}
|
|
@@ -1384,6 +1390,28 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1384
1390
|
}
|
|
1385
1391
|
});
|
|
1386
1392
|
},
|
|
1393
|
+
async getDocumentMetadata() {
|
|
1394
|
+
requireDocRead("document.getDocumentMetadata");
|
|
1395
|
+
const key = metadataKey(manifest);
|
|
1396
|
+
const meta = await getEditor().client.documentMeta();
|
|
1397
|
+
const entry = meta.pluginMetadata?.find((e) => e.key === key);
|
|
1398
|
+
if (!entry) return null;
|
|
1399
|
+
try {
|
|
1400
|
+
return JSON.parse(entry.value);
|
|
1401
|
+
} catch {
|
|
1402
|
+
return null;
|
|
1403
|
+
}
|
|
1404
|
+
},
|
|
1405
|
+
async setDocumentMetadata(envelope) {
|
|
1406
|
+
return this.mutate({
|
|
1407
|
+
op: "setDocumentMetadata",
|
|
1408
|
+
args: {
|
|
1409
|
+
key: metadataKey(manifest),
|
|
1410
|
+
value: envelope === null ? null : JSON.stringify(envelope),
|
|
1411
|
+
caller: manifest.id
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1414
|
+
},
|
|
1387
1415
|
async frameChain(storyId) {
|
|
1388
1416
|
requireDocRead("document.frameChain");
|
|
1389
1417
|
const reply = await getEditor().client.send({
|
|
@@ -1487,6 +1515,25 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
1487
1515
|
// "no reader").
|
|
1488
1516
|
caret() {
|
|
1489
1517
|
return options?.textCaret?.read() ?? null;
|
|
1518
|
+
},
|
|
1519
|
+
// D-27 — the batched measure. One round-trip when the editor wires
|
|
1520
|
+
// `measureMany`; otherwise the same answers one call at a time (or
|
|
1521
|
+
// the estimate), so a bundle never needs two code paths.
|
|
1522
|
+
async measureStrings(family, style, texts, sizePt) {
|
|
1523
|
+
if (texts.length === 0) return [];
|
|
1524
|
+
const editorText = getEditor().text;
|
|
1525
|
+
if (editorText?.measureMany) {
|
|
1526
|
+
const out = await editorText.measureMany(family, style, texts, sizePt);
|
|
1527
|
+
if (out.length !== texts.length) {
|
|
1528
|
+
throw new Error(
|
|
1529
|
+
`host.text.measureStrings: the host answered ${out.length} metrics for ${texts.length} strings`
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1532
|
+
return out;
|
|
1533
|
+
}
|
|
1534
|
+
return Promise.all(
|
|
1535
|
+
texts.map((t) => text.measureString(family, style, t, sizePt))
|
|
1536
|
+
);
|
|
1490
1537
|
}
|
|
1491
1538
|
};
|
|
1492
1539
|
const overlay = {
|
|
@@ -2058,6 +2105,42 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2058
2105
|
return nativeDocBackend.open(bytes);
|
|
2059
2106
|
}
|
|
2060
2107
|
};
|
|
2108
|
+
const documentsBackend = options?.documents;
|
|
2109
|
+
const documents = {
|
|
2110
|
+
async exportPaged() {
|
|
2111
|
+
requireDeclared(
|
|
2112
|
+
hasDocuments("export"),
|
|
2113
|
+
"documents.exportPaged",
|
|
2114
|
+
"capabilities.documents.export must be declared"
|
|
2115
|
+
);
|
|
2116
|
+
if (!documentsBackend) {
|
|
2117
|
+
throw new Error(
|
|
2118
|
+
'host.documents.exportPaged: the host wired no documents backend (supports("documents.exportPaged@1") is false)'
|
|
2119
|
+
);
|
|
2120
|
+
}
|
|
2121
|
+
return documentsBackend.exportPaged();
|
|
2122
|
+
},
|
|
2123
|
+
async open(bytes, opts) {
|
|
2124
|
+
requireDeclared(
|
|
2125
|
+
hasDocuments("open"),
|
|
2126
|
+
"documents.open",
|
|
2127
|
+
"capabilities.documents.open must be declared"
|
|
2128
|
+
);
|
|
2129
|
+
if (!documentsBackend) {
|
|
2130
|
+
throw new Error(
|
|
2131
|
+
'host.documents.open: the host wired no documents backend (supports("documents.open@1") is false)'
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
if (!(bytes instanceof Uint8Array) || bytes.byteLength === 0) {
|
|
2135
|
+
throw new Error("host.documents.open: bytes must be a non-empty Uint8Array");
|
|
2136
|
+
}
|
|
2137
|
+
const name = typeof opts?.name === "string" && opts.name.trim() !== "" ? opts.name.trim() : null;
|
|
2138
|
+
return documentsBackend.open(bytes.slice(), {
|
|
2139
|
+
name,
|
|
2140
|
+
requester: { id: manifest.id, name: manifest.name }
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
};
|
|
2061
2144
|
const clipboardBackend = options?.clipboard;
|
|
2062
2145
|
const clipboardGate = (door) => {
|
|
2063
2146
|
const grant = clipboardGrant();
|
|
@@ -2263,6 +2346,9 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2263
2346
|
if (getEditor().text) {
|
|
2264
2347
|
featureSet.add("text.measure@1");
|
|
2265
2348
|
}
|
|
2349
|
+
if (getEditor().text?.measureMany) {
|
|
2350
|
+
featureSet.add("text.measureStrings@1");
|
|
2351
|
+
}
|
|
2266
2352
|
if (getEditor().sceneLayers) {
|
|
2267
2353
|
featureSet.add("rendering.sceneLayer@1");
|
|
2268
2354
|
featureSet.add("rendering.sceneLayer.faces@1");
|
|
@@ -2335,6 +2421,10 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2335
2421
|
featureSet.add("document.readNative@1");
|
|
2336
2422
|
featureSet.add("document.openNative@1");
|
|
2337
2423
|
}
|
|
2424
|
+
if (options?.documents) {
|
|
2425
|
+
featureSet.add("documents.exportPaged@1");
|
|
2426
|
+
featureSet.add("documents.open@1");
|
|
2427
|
+
}
|
|
2338
2428
|
if (options?.workers) {
|
|
2339
2429
|
featureSet.add("workers@1");
|
|
2340
2430
|
}
|
|
@@ -2358,6 +2448,7 @@ function createBundleHost(getEditor, manifest, options) {
|
|
|
2358
2448
|
blob,
|
|
2359
2449
|
parts,
|
|
2360
2450
|
nativeDocument,
|
|
2451
|
+
documents,
|
|
2361
2452
|
network,
|
|
2362
2453
|
dataProviders,
|
|
2363
2454
|
diagnostics,
|
|
@@ -2612,7 +2703,7 @@ function inMemorySecretStore() {
|
|
|
2612
2703
|
};
|
|
2613
2704
|
}
|
|
2614
2705
|
var seqCounter = 1;
|
|
2615
|
-
function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews) {
|
|
2706
|
+
function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews, engineShaper = false) {
|
|
2616
2707
|
const protocol = worker.protocolVersion;
|
|
2617
2708
|
const listeners = /* @__PURE__ */ new Set();
|
|
2618
2709
|
const fanOut = (reply) => {
|
|
@@ -2772,7 +2863,23 @@ function makeEngineEditor(worker, recorder, onToolPreview, onToolPreviews) {
|
|
|
2772
2863
|
},
|
|
2773
2864
|
contentSelection: { contentSelection: null }
|
|
2774
2865
|
};
|
|
2775
|
-
|
|
2866
|
+
const measureText = worker.measureText?.bind(worker);
|
|
2867
|
+
if (engineShaper && measureText) {
|
|
2868
|
+
const zero = { advance: 0, ascender: 0, descender: 0 };
|
|
2869
|
+
const one = (family, style, t, sizePt) => {
|
|
2870
|
+
const m = measureText(family, style, t, sizePt);
|
|
2871
|
+
return m ? { advance: m.advance, ascender: m.ascender, descender: m.descender } : zero;
|
|
2872
|
+
};
|
|
2873
|
+
editor.text = {
|
|
2874
|
+
async measure(family, style, t, sizePt) {
|
|
2875
|
+
return one(family, style, t, sizePt);
|
|
2876
|
+
},
|
|
2877
|
+
async measureMany(family, style, texts, sizePt) {
|
|
2878
|
+
return texts.map((t) => one(family, style, t, sizePt));
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
}
|
|
2882
|
+
return { editor, fanOut };
|
|
2776
2883
|
}
|
|
2777
2884
|
async function createHeadlessHost(options = {}) {
|
|
2778
2885
|
const engine = await loadHeadlessEngine(options);
|
|
@@ -2780,7 +2887,7 @@ async function createHeadlessHost(options = {}) {
|
|
|
2780
2887
|
const contributions = [];
|
|
2781
2888
|
let lastPreview = null;
|
|
2782
2889
|
let lastPreviews = null;
|
|
2783
|
-
const editor = makeEngineEditor(
|
|
2890
|
+
const { editor, fanOut } = makeEngineEditor(
|
|
2784
2891
|
worker,
|
|
2785
2892
|
contributions,
|
|
2786
2893
|
(value) => {
|
|
@@ -2788,8 +2895,54 @@ async function createHeadlessHost(options = {}) {
|
|
|
2788
2895
|
},
|
|
2789
2896
|
(value) => {
|
|
2790
2897
|
lastPreviews = value;
|
|
2791
|
-
}
|
|
2898
|
+
},
|
|
2899
|
+
options.engineShaper === true
|
|
2792
2900
|
);
|
|
2901
|
+
const loadDirect = (bytes) => {
|
|
2902
|
+
const reply = JSON.parse(
|
|
2903
|
+
options.defaultFont ? worker.loadDocumentDirect(seqCounter++, bytes, options.defaultFont) : worker.loadDocumentDirect(seqCounter++, bytes)
|
|
2904
|
+
);
|
|
2905
|
+
if (reply.kind === "documentLoaded") {
|
|
2906
|
+
try {
|
|
2907
|
+
worker.runResolveJson();
|
|
2908
|
+
} catch {
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
return reply;
|
|
2912
|
+
};
|
|
2913
|
+
const loadFailure = (reply) => {
|
|
2914
|
+
const errKind = reply.kind === "loadFailed" ? reply.payload.error.kind : reply.kind;
|
|
2915
|
+
return new Error(`headless load failed (${reply.kind}: ${errKind})`);
|
|
2916
|
+
};
|
|
2917
|
+
const opened = [];
|
|
2918
|
+
const documentsBackend = {
|
|
2919
|
+
async exportPaged() {
|
|
2920
|
+
const reply = await editor.client.send({ kind: "exportPaged", payload: {} });
|
|
2921
|
+
if (reply.kind === "pagedExported") return Uint8Array.from(reply.payload.bytes);
|
|
2922
|
+
if (reply.kind === "pagedPartFailed") throw new Error(reply.payload.error);
|
|
2923
|
+
throw new Error(`unexpected reply: ${reply.kind}`);
|
|
2924
|
+
},
|
|
2925
|
+
async open(bytes, request) {
|
|
2926
|
+
let dirty = false;
|
|
2927
|
+
try {
|
|
2928
|
+
dirty = (await editor.client.documentMeta()).dirty;
|
|
2929
|
+
} catch {
|
|
2930
|
+
dirty = false;
|
|
2931
|
+
}
|
|
2932
|
+
if (dirty && options.confirmReplace && !await options.confirmReplace(request)) {
|
|
2933
|
+
return { opened: false, reason: "declined" };
|
|
2934
|
+
}
|
|
2935
|
+
const reply = loadDirect(bytes);
|
|
2936
|
+
if (reply.kind !== "documentLoaded") throw loadFailure(reply);
|
|
2937
|
+
fanOut(reply);
|
|
2938
|
+
opened.push({
|
|
2939
|
+
name: request.name,
|
|
2940
|
+
requester: request.requester.id,
|
|
2941
|
+
pageIds: reply.payload.pageIds
|
|
2942
|
+
});
|
|
2943
|
+
return { opened: true, pageIds: reply.payload.pageIds };
|
|
2944
|
+
}
|
|
2945
|
+
};
|
|
2793
2946
|
let active = null;
|
|
2794
2947
|
let currentHost = null;
|
|
2795
2948
|
let disposed = false;
|
|
@@ -2814,6 +2967,7 @@ async function createHeadlessHost(options = {}) {
|
|
|
2814
2967
|
// headlessly (the editor's real adapter currently serves null;
|
|
2815
2968
|
// DESIGN.md §13.4). Absent → the no-bytes door.
|
|
2816
2969
|
assetSource: options.assetSource,
|
|
2970
|
+
documents: documentsBackend,
|
|
2817
2971
|
// Record the SCHEMA verbatim at registration — the panel registry
|
|
2818
2972
|
// only ever sees the synthesized React panel, so the conformance
|
|
2819
2973
|
// log gets the schema through this adapter seam (no host renderer
|
|
@@ -2875,7 +3029,8 @@ async function createHeadlessHost(options = {}) {
|
|
|
2875
3029
|
rendering: ["overlay", "hitTest", "sceneLayer"],
|
|
2876
3030
|
keybindings: true,
|
|
2877
3031
|
storage: { blob: true },
|
|
2878
|
-
secrets: { sources: true }
|
|
3032
|
+
secrets: { sources: true },
|
|
3033
|
+
documents: { export: true, open: true }
|
|
2879
3034
|
},
|
|
2880
3035
|
// Broad contribution declarations so the neutral DRIVER host (which
|
|
2881
3036
|
// registers arbitrary contributions directly in 'warn' mode) never
|
|
@@ -2931,17 +3086,12 @@ async function createHeadlessHost(options = {}) {
|
|
|
2931
3086
|
willSave,
|
|
2932
3087
|
toolSettings,
|
|
2933
3088
|
async load(idml) {
|
|
2934
|
-
const
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
}
|
|
2941
|
-
return reply.payload.pageIds;
|
|
2942
|
-
}
|
|
2943
|
-
const errKind = reply.kind === "loadFailed" ? reply.payload.error.kind : reply.kind;
|
|
2944
|
-
throw new Error(`headless load failed (${reply.kind}: ${errKind})`);
|
|
3089
|
+
const reply = loadDirect(idml);
|
|
3090
|
+
if (reply.kind === "documentLoaded") return reply.payload.pageIds;
|
|
3091
|
+
throw loadFailure(reply);
|
|
3092
|
+
},
|
|
3093
|
+
openedDocuments() {
|
|
3094
|
+
return opened;
|
|
2945
3095
|
},
|
|
2946
3096
|
loadBundle(bundle) {
|
|
2947
3097
|
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.41-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.41-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.69.0",
|
|
26
26
|
"@types/node": "20.19.39",
|
|
27
27
|
"@types/react": "^18.3.31",
|
|
28
28
|
"react": "^18.3.1",
|