@paged-media/plugin-sdk 0.2.13-canary.0 → 0.2.16-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 CHANGED
@@ -1,4 +1,4 @@
1
- import { PagedBundle, FontFaceAsset, BundleHost, ConsentResult, DataProviderRegistration, DataProviderHandle, DataProviderInfo, DataProviderSnapshot, Disposable, ShellSurface, WidgetSurface, SchemaPanelRenderer, SchemaPanelContribution, EditContextContribution, ObjectTypeContribution, Diagnostic, PagedEditor, PluginManifest, ToolContribution, PanelContribution, CommandContribution, KeybindingContribution, OverlayContribution, ImporterContribution, ExporterContribution, ToolPreviewShape, BindingsSurface, PanelProps, SchemaGate, WasmArtifact, CanvasPointerEvent, Mutation, MutationOutcome } from '@paged-media/plugin-api';
1
+ import { PagedBundle, FontFaceAsset, BundleHost, ClipboardPayload, ConsentResult, DataProviderRegistration, DataProviderHandle, DataProviderInfo, DataProviderSnapshot, Disposable, ShellSurface, WidgetSurface, SchemaPanelRenderer, SchemaPanelContribution, EditContextContribution, ObjectTypeContribution, Diagnostic, PagedEditor, PluginManifest, ToolContribution, PanelContribution, CommandContribution, KeybindingContribution, OverlayContribution, ImporterContribution, ExporterContribution, ToolPreviewShape, BindingsSurface, PanelProps, SchemaGate, WasmArtifact, CanvasPointerEvent, Mutation, MutationOutcome } from '@paged-media/plugin-api';
2
2
  import { ComponentType } from 'react';
3
3
 
4
4
  /**
@@ -113,6 +113,20 @@ interface BlobStore {
113
113
  /** Total bytes this plugin currently stores. */
114
114
  used(pluginId: string): Promise<number>;
115
115
  }
116
+ /**
117
+ * The backend the editor injects to back `host.clipboard` (K-6 / S-14): a
118
+ * thin read/write pair over the REAL system clipboard (`navigator.clipboard`
119
+ * in-browser; a fake in the headless harness). The SDK adapter owns the
120
+ * capability gate + the `"vector"` tabular-stripping; this backend only does
121
+ * the raw IO. `read` recovers a `{ text?, tabular? }` payload (or `null` when
122
+ * the platform offers nothing / refuses); `write` puts a payload on the
123
+ * clipboard (the editor backend lays down BOTH `text/plain` TSV and a
124
+ * `text/html` `<table>` so a paste into Excel/Sheets/Word lands a real grid).
125
+ */
126
+ interface ClipboardBackend {
127
+ read(): Promise<ClipboardPayload | null>;
128
+ write(payload: ClipboardPayload): Promise<void>;
129
+ }
116
130
  /** The SHARED cross-plugin data-provider registry (paged.data §7.1 / D-09). The
117
131
  * editor creates ONE (`createDataProviderRegistry`) and injects the SAME
118
132
  * instance into every plugin host, so a provider plugin and a consumer plugin
@@ -220,6 +234,12 @@ interface CreateBundleHostOptions {
220
234
  * When absent, reads answer empty and writes reject (the honest
221
235
  * no-store door). */
222
236
  blobStore?: BlobStore;
237
+ /** Host-provided CLIPBOARD backend (K-6 / S-14). When present,
238
+ * `host.clipboard.read/write` go through it (capability-gated on
239
+ * `capabilities.clipboard`) and `supports("clipboard@1")` answers true.
240
+ * When absent, `read` answers `null` and `write` is a no-op (the honest
241
+ * no-clipboard door). */
242
+ clipboard?: ClipboardBackend;
223
243
  /**
224
244
  * How the host treats a declaration↔use mismatch — a bundle that
225
245
  * USES a door (`contribute.tool`, `document.mutate`, …) it did not
@@ -314,7 +334,7 @@ interface RecordedContribution {
314
334
  id: string;
315
335
  value: ToolContribution | PanelContribution | SchemaPanelContribution | CommandContribution | KeybindingContribution | OverlayContribution | EditContextContribution | ObjectTypeContribution | ImporterContribution | ExporterContribution;
316
336
  }
317
- interface HarnessOptions extends LoadHeadlessEngineOptions, Pick<CreateBundleHostOptions, "console" | "storage" | "capabilityMode" | "assetSource" | "blobStore"> {
337
+ interface HarnessOptions extends LoadHeadlessEngineOptions, Pick<CreateBundleHostOptions, "console" | "storage" | "capabilityMode" | "assetSource" | "blobStore" | "clipboard"> {
318
338
  }
319
339
  /** What `createHeadlessHost` resolves to: a real engine-backed host plus
320
340
  * the conformance affordances (load an IDML, read the contribution log,
@@ -460,13 +480,19 @@ declare function loadBundle(getEditor: () => PagedEditor, bundle: PagedBundle, o
460
480
  * KEEP IN SYNC with plugin-cli's WASM_MAX_* and the schema's `maxBytes`
461
481
  * maximum — the CLI hand-mirrors the contract. */
462
482
  declare const WASM_BUDGETS: {
463
- /** Hard per-artifact byte ceiling. A release-optimised wasm layout
464
- * engine (Blitz-class) lands in the low-single-digit MiB; 8 MiB
465
- * rejects an accidentally-bundled debug build while leaving headroom
466
- * for one real engine. A manifest `maxBytes` may only TIGHTEN this. */
483
+ /** Hard per-artifact byte ceiling for layout/codec/compute. A
484
+ * release-optimised wasm layout engine (Blitz-class) lands in the
485
+ * low-single-digit MiB; 8 MiB rejects an accidentally-bundled debug
486
+ * build while leaving headroom for one real engine. A manifest
487
+ * `maxBytes` may only TIGHTEN this. */
467
488
  readonly maxArtifactBytes: number;
468
- /** Total declared wasm across one bundle. Bounds a bundle that ships
469
- * several modules (engine + a codec, say). */
489
+ /** D-07b the governed HIGHER ceiling for `purpose: "engine"` (a
490
+ * vendored DB/query engine like DuckDB-WASM 36 MiB). 64 MiB fits the
491
+ * real artifacts with headroom; still a hard cap a manifest may only
492
+ * tighten. Only the `engine` purpose earns it. */
493
+ readonly maxEngineArtifactBytes: number;
494
+ /** Total declared wasm across one bundle. Sized so one `engine`
495
+ * artifact + a codec fit. */
470
496
  readonly maxTotalBytes: number;
471
497
  /** Wall-clock budget for fetch + compile + instantiate. Protects the
472
498
  * editor's main flow from a pathological module; advisory, the loader
@@ -577,4 +603,4 @@ declare function contributeEditContext(host: BundleHost, contribution: EditConte
577
603
  * descent. Capability-gated on `contributes.objectTypes`. */
578
604
  declare function contributeObjectType(host: BundleHost, contribution: ObjectTypeContribution): Disposable;
579
605
 
580
- export { API_VERSION, ASSET_BUDGETS, BLOB_BUDGETS, type BlobStore, type BundleAssetProvider, type BundleAssetSource, type BundleHostHandle, type BundleTrust, CANVAS_WASM_PKG, CLICK_DRAG_THRESHOLD_PX, type ConsentBackend, type CreateBundleHostOptions, type DataProviderBackend, type DiagnosticsSink, DisposableStore, FALLBACK_WIDGETS, HOST_FEATURES, type HarnessOptions, type HeadlessCanvasWorker, type HeadlessHost, type HeadlessHostHandle, type LoadBundleWasmOptions, type LoadHeadlessEngineOptions, type LoadedBundle, type LoadedBundleWasm, type LoadedEngine, type PageDrag, PluginApiNotImplemented, PluginCapabilityError, type RecordableAssetSource, type RecordedContribution, type RecordedFontFaceRequest, type SeededFace, type StorageBacking, WASM_BUDGETS, beginPageDrag, commitAndSelect, contributeEditContext, contributeObjectType, contributePanel, contributeSchemaPanel, contributeTool, createBundleHost, createDataProviderRegistry, createHeadlessHost, createRecordableAssetSource, defineBundle, endLocalFor, loadBundle, loadBundleWasm, loadHeadlessEngine, makeSchemaPanelComponent, protocolFromVersion, pxToPt, readVendoredWireVersion, resolveCanvasWasm, resolveGate, satisfiesApiVersion, toDisposable };
606
+ export { API_VERSION, ASSET_BUDGETS, BLOB_BUDGETS, 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 LoadBundleWasmOptions, type LoadHeadlessEngineOptions, type LoadedBundle, type LoadedBundleWasm, type LoadedEngine, type PageDrag, PluginApiNotImplemented, PluginCapabilityError, type RecordableAssetSource, type RecordedContribution, type RecordedFontFaceRequest, type SeededFace, type StorageBacking, WASM_BUDGETS, beginPageDrag, commitAndSelect, contributeEditContext, contributeObjectType, contributePanel, contributeSchemaPanel, contributeTool, createBundleHost, createDataProviderRegistry, createHeadlessHost, createRecordableAssetSource, defineBundle, endLocalFor, loadBundle, loadBundleWasm, loadHeadlessEngine, makeSchemaPanelComponent, protocolFromVersion, pxToPt, readVendoredWireVersion, resolveCanvasWasm, resolveGate, satisfiesApiVersion, toDisposable };
package/dist/index.js CHANGED
@@ -272,6 +272,7 @@ function createBundleHost(getEditor, manifest, options) {
272
272
  const hasRendering = (s) => caps?.rendering?.includes(s) ?? false;
273
273
  const hasAsset = (k) => caps?.assets?.includes(k) ?? false;
274
274
  const hasBlobStore = () => caps?.storage?.blob === true;
275
+ const clipboardGrant = () => caps?.clipboard === "full" ? "full" : caps?.clipboard === "vector" ? "vector" : "none";
275
276
  const lists = (arr, id) => arr?.includes(id) ?? false;
276
277
  const declaresType = (arr, type) => arr?.some((e) => e.type === type) ?? false;
277
278
  const requireDeclared = (ok, door, missing) => {
@@ -1031,6 +1032,51 @@ function createBundleHost(getEditor, manifest, options) {
1031
1032
  return { used: await blobBackend.used(manifest.id), quota: blobQuota };
1032
1033
  }
1033
1034
  };
1035
+ const clipboardBackend = options?.clipboard;
1036
+ const clipboardGate = (door) => {
1037
+ const grant = clipboardGrant();
1038
+ requireDeclared(
1039
+ grant !== "none",
1040
+ door,
1041
+ 'capabilities.clipboard must be "full" or "vector"'
1042
+ );
1043
+ return grant === "full" ? "full" : "vector";
1044
+ };
1045
+ const clipboard = {
1046
+ async read() {
1047
+ const tier = clipboardGate("clipboard.read");
1048
+ if (!clipboardBackend) return null;
1049
+ let payload;
1050
+ try {
1051
+ payload = await clipboardBackend.read();
1052
+ } catch {
1053
+ return null;
1054
+ }
1055
+ if (!payload) return null;
1056
+ if (tier === "vector" && payload.tabular !== void 0) {
1057
+ const { tabular: _dropped, ...rest } = payload;
1058
+ return rest;
1059
+ }
1060
+ return payload;
1061
+ },
1062
+ async write(payload) {
1063
+ const tier = clipboardGate("clipboard.write");
1064
+ if (!clipboardBackend) return;
1065
+ let toWrite = payload;
1066
+ if (tier === "vector" && payload.tabular !== void 0) {
1067
+ log.warn(
1068
+ 'clipboard.write: dropping the tabular payload \u2014 capabilities.clipboard is "vector" (text only); declare "full" to copy a cell grid'
1069
+ );
1070
+ const { tabular: _dropped, ...rest } = payload;
1071
+ toWrite = rest;
1072
+ }
1073
+ try {
1074
+ await clipboardBackend.write(toWrite);
1075
+ } catch (err) {
1076
+ log.warn("clipboard.write: the platform refused the write", err);
1077
+ }
1078
+ }
1079
+ };
1034
1080
  const featureSet = new Set(HOST_FEATURES);
1035
1081
  if (getEditor().text) {
1036
1082
  featureSet.add("text.measure@1");
@@ -1063,6 +1109,9 @@ function createBundleHost(getEditor, manifest, options) {
1063
1109
  if (options?.blobStore) {
1064
1110
  featureSet.add("storage.blob@1");
1065
1111
  }
1112
+ if (options?.clipboard) {
1113
+ featureSet.add("clipboard@1");
1114
+ }
1066
1115
  const host = {
1067
1116
  manifest,
1068
1117
  log,
@@ -1081,6 +1130,7 @@ function createBundleHost(getEditor, manifest, options) {
1081
1130
  bindings,
1082
1131
  widgets,
1083
1132
  assets,
1133
+ clipboard,
1084
1134
  supports: (feature) => featureSet.has(feature),
1085
1135
  get editor() {
1086
1136
  return getEditor();
@@ -1255,6 +1305,24 @@ function inMemoryBlobStore() {
1255
1305
  }
1256
1306
  };
1257
1307
  }
1308
+ function inMemoryClipboard() {
1309
+ let slot = null;
1310
+ return {
1311
+ async read() {
1312
+ if (!slot) return null;
1313
+ return {
1314
+ ...slot.text !== void 0 ? { text: slot.text } : {},
1315
+ ...slot.tabular ? { tabular: { rows: slot.tabular.rows.map((r) => [...r]) } } : {}
1316
+ };
1317
+ },
1318
+ async write(payload) {
1319
+ slot = {
1320
+ ...payload.text !== void 0 ? { text: payload.text } : {},
1321
+ ...payload.tabular ? { tabular: { rows: payload.tabular.rows.map((r) => [...r]) } } : {}
1322
+ };
1323
+ }
1324
+ };
1325
+ }
1258
1326
  var seqCounter = 1;
1259
1327
  function makeEngineEditor(worker, recorder, onToolPreview) {
1260
1328
  const protocol = worker.protocolVersion;
@@ -1417,10 +1485,12 @@ async function createHeadlessHost(options = {}) {
1417
1485
  let currentHost = null;
1418
1486
  let disposed = false;
1419
1487
  const blobStore = options.blobStore ?? inMemoryBlobStore();
1488
+ const clipboard = options.clipboard ?? inMemoryClipboard();
1420
1489
  const buildHost = (manifest, mode) => createBundleHost(() => editor, manifest, {
1421
1490
  console: options.console,
1422
1491
  storage: options.storage,
1423
1492
  blobStore,
1493
+ clipboard,
1424
1494
  capabilityMode: mode,
1425
1495
  // W-06 — a recordable fake asset source the conformance harness
1426
1496
  // can pass so a bundle's `@font-face` byte path is exercisable
@@ -1672,14 +1742,20 @@ function loadBundle(getEditor, bundle, options) {
1672
1742
 
1673
1743
  // src/wasm-bundle-loader.ts
1674
1744
  var WASM_BUDGETS = {
1675
- /** Hard per-artifact byte ceiling. A release-optimised wasm layout
1676
- * engine (Blitz-class) lands in the low-single-digit MiB; 8 MiB
1677
- * rejects an accidentally-bundled debug build while leaving headroom
1678
- * for one real engine. A manifest `maxBytes` may only TIGHTEN this. */
1745
+ /** Hard per-artifact byte ceiling for layout/codec/compute. A
1746
+ * release-optimised wasm layout engine (Blitz-class) lands in the
1747
+ * low-single-digit MiB; 8 MiB rejects an accidentally-bundled debug
1748
+ * build while leaving headroom for one real engine. A manifest
1749
+ * `maxBytes` may only TIGHTEN this. */
1679
1750
  maxArtifactBytes: 8 * 1024 * 1024,
1680
- /** Total declared wasm across one bundle. Bounds a bundle that ships
1681
- * several modules (engine + a codec, say). */
1682
- maxTotalBytes: 16 * 1024 * 1024,
1751
+ /** D-07b the governed HIGHER ceiling for `purpose: "engine"` (a
1752
+ * vendored DB/query engine like DuckDB-WASM 36 MiB). 64 MiB fits the
1753
+ * real artifacts with headroom; still a hard cap a manifest may only
1754
+ * tighten. Only the `engine` purpose earns it. */
1755
+ maxEngineArtifactBytes: 64 * 1024 * 1024,
1756
+ /** Total declared wasm across one bundle. Sized so one `engine`
1757
+ * artifact + a codec fit. */
1758
+ maxTotalBytes: 80 * 1024 * 1024,
1683
1759
  /** Wall-clock budget for fetch + compile + instantiate. Protects the
1684
1760
  * editor's main flow from a pathological module; advisory, the loader
1685
1761
  * aborts with a clear error when exceeded. */
@@ -1724,7 +1800,8 @@ async function loadBundleWasm(bundle, name, options) {
1724
1800
  const src = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
1725
1801
  const view = new Uint8Array(src.byteLength);
1726
1802
  view.set(src);
1727
- const ceiling = typeof artifact.maxBytes === "number" && artifact.maxBytes > 0 ? Math.min(artifact.maxBytes, WASM_BUDGETS.maxArtifactBytes) : WASM_BUDGETS.maxArtifactBytes;
1803
+ const hostCeiling = artifact.purpose === "engine" ? WASM_BUDGETS.maxEngineArtifactBytes : WASM_BUDGETS.maxArtifactBytes;
1804
+ const ceiling = typeof artifact.maxBytes === "number" && artifact.maxBytes > 0 ? Math.min(artifact.maxBytes, hostCeiling) : hostCeiling;
1728
1805
  if (view.byteLength > ceiling) {
1729
1806
  throw new Error(
1730
1807
  `loadBundleWasm: "${name}" of ${id} is ${view.byteLength} bytes, over its ${ceiling}-byte ceiling.`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paged-media/plugin-sdk",
3
- "version": "0.2.13-canary.0",
3
+ "version": "0.2.16-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.13-canary.0"
14
+ "@paged-media/plugin-api": "0.2.16-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.43.0",
25
+ "@paged-media/canvas-wasm": "0.44.0",
26
26
  "@types/node": "20.19.39",
27
27
  "@types/react": "^18.3.12",
28
28
  "react": "^18.3.0",