@paged-media/plugin-sdk 0.2.32-canary.0 → 0.2.34-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, BindingProvider, Disposable, ActiveBindingProvider, BindingPropertyRequest, BindingReadResult, BindingPropertyWrite, BindingWriteResult, BindingCollectionRequest, BindingCollectionResult, MutationInput, FontFaceAsset, BundleHost, ClipboardPayload, ConsentResult, DataProviderRegistration, DataProviderHandle, DataProviderInfo, DataProviderSnapshot, ShellSurface, WidgetSurface, 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, 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';
2
2
  import { ComponentType } from 'react';
3
3
 
4
4
  /**
@@ -68,6 +68,20 @@ interface DiagnosticsSink {
68
68
  publish(bundleId: string, key: string, diagnostics: Diagnostic[]): void;
69
69
  clear(bundleId: string, key?: string): void;
70
70
  }
71
+ /**
72
+ * ADR 025 — the host's journal buffer, injected the same way `DiagnosticsSink`
73
+ * is, and for the same reason: the ring lives in the app (one per session,
74
+ * created outside any bundle), and every loaded bundle fans INTO it with its
75
+ * own id stamped by the host.
76
+ *
77
+ * Structurally identical to the diagnostics fan-out on purpose: `manifest`,
78
+ * `storage`, `diagnostics`, `supports` and `log` are the members DESIGN.md §6
79
+ * already lists as "trivial proxy" across the future isolate boundary, and a
80
+ * plain-JSON, bundleId-keyed sink joins them without adding a new problem.
81
+ */
82
+ interface JournalSink {
83
+ record(bundleId: string, entry: JournalRecord): void;
84
+ }
71
85
  /** Asset-store budgets (W-06). The per-face cap mirrors the wasm lane's
72
86
  * per-artifact ceiling (DESIGN.md §10/§13.3) — a bundle can never be
73
87
  * handed an unbounded face buffer. The host facade refuses an
@@ -349,8 +363,17 @@ interface CreateBundleHostOptions {
349
363
  * (nothing would ever consult the provider) and
350
364
  * `supports("bindings.provider@1")` is false. */
351
365
  bindingProviders?: BindingProviderBackend;
352
- /** Console sink override (tests). */
366
+ /** Console sink override.
367
+ *
368
+ * Originally a test hook, and now ALSO the production capture point: the
369
+ * editor passes a sink that censuses every `host.log` line (severity + a
370
+ * hash of the message) into the journal while forwarding the real text to
371
+ * the real console. See ADR 025 §5 — a census, not a mirror, because
372
+ * `host.log` is free text across ~900 call sites. */
353
373
  console?: Pick<Console, "debug" | "info" | "warn" | "error">;
374
+ /** ADR 025 — where `host.journal` entries go. Absent = the surface is
375
+ * inert and `supports("journal@1")` is false. */
376
+ journal?: JournalSink;
354
377
  /** Shell actions the HOST APP owns (the cockpit's panel placement).
355
378
  * When absent, `host.shell` warns and no-ops, and
356
379
  * `supports("shell.openPanel@1")` answers false. Typed as
@@ -690,6 +713,10 @@ declare function makeSchemaPanelComponent(contribution: SchemaPanelContribution,
690
713
  interface LoadedBundle {
691
714
  readonly id: string;
692
715
  readonly active: boolean;
716
+ /** Set when `activate()` threw. `active` is then false and this bundle
717
+ * contributed nothing — the host can surface the reason rather than
718
+ * discovering an inert plugin by its absence. */
719
+ readonly activationError?: unknown;
693
720
  dispose(): void;
694
721
  }
695
722
  declare function loadBundle(getEditor: () => PagedEditor, bundle: PagedBundle, options?: CreateBundleHostOptions): LoadedBundle;
@@ -855,4 +882,4 @@ declare function contributeObjectType(host: BundleHost, contribution: ObjectType
855
882
  */
856
883
  declare function contributeBindingProvider(host: BundleHost, contextType: string, provider: BindingProvider): BindingProviderHandle;
857
884
 
858
- 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 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, WASM_BUDGETS, WORKER_BUDGETS, type WorkerBackend, beginPageDrag, commitAndSelect, contributeBindingProvider, contributeEditContext, contributeObjectType, contributePanel, contributeSchemaPanel, contributeTool, createBindingProviderRegistry, createBundleHost, createDataProviderRegistry, createHeadlessHost, createRecordableAssetSource, defineBundle, endLocalFor, loadBundle, loadBundleWasm, loadHeadlessEngine, makeSchemaPanelComponent, protocolFromVersion, pxToPt, readVendoredWireVersion, resolveCanvasWasm, resolveGate, satisfiesApiVersion, toDisposable };
885
+ 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, WASM_BUDGETS, WORKER_BUDGETS, type WorkerBackend, beginPageDrag, commitAndSelect, contributeBindingProvider, contributeEditContext, contributeObjectType, contributePanel, contributeSchemaPanel, contributeTool, createBindingProviderRegistry, createBundleHost, createDataProviderRegistry, createHeadlessHost, createRecordableAssetSource, defineBundle, endLocalFor, loadBundle, loadBundleWasm, loadHeadlessEngine, makeSchemaPanelComponent, protocolFromVersion, pxToPt, readVendoredWireVersion, resolveCanvasWasm, resolveGate, satisfiesApiVersion, toDisposable };
package/dist/index.js CHANGED
@@ -478,6 +478,34 @@ function createBundleHost(getEditor, manifest, options) {
478
478
  warn: (m, ...a) => sink.warn(`${tag} ${m}`, ...a),
479
479
  error: (m, ...a) => sink.error(`${tag} ${m}`, ...a)
480
480
  };
481
+ const journalSink = options?.journal;
482
+ const journal = {
483
+ record(entry) {
484
+ if (!journalSink) return;
485
+ try {
486
+ assertNamespaced(entry.code, "journal");
487
+ journalSink.record(manifest.id, entry);
488
+ } catch (err) {
489
+ log.warn(`journal.record refused: ${String(err)}`);
490
+ }
491
+ },
492
+ async time(code, fn) {
493
+ const t0 = Date.now();
494
+ try {
495
+ const out = await fn();
496
+ journal.record({ code, durMs: Date.now() - t0, data: { ok: true } });
497
+ return out;
498
+ } catch (err) {
499
+ journal.record({
500
+ code,
501
+ severity: "error",
502
+ durMs: Date.now() - t0,
503
+ data: { ok: false }
504
+ });
505
+ throw err;
506
+ }
507
+ }
508
+ };
481
509
  const capabilityMode = options?.capabilityMode ?? "enforce";
482
510
  const caps = manifest.capabilities;
483
511
  const declared = manifest.contributes;
@@ -624,6 +652,42 @@ function createBundleHost(getEditor, manifest, options) {
624
652
  );
625
653
  return store.add(getEditor().registries.keybindings.register(c));
626
654
  },
655
+ menu(c) {
656
+ assertNamespaced(c.command, "menu");
657
+ requireDeclared(
658
+ lists(declared?.commands, c.command),
659
+ "contribute.menu",
660
+ `contributes.commands[] must include "${c.command}" before a menu entry can invoke it`
661
+ );
662
+ const scope = c.scope ?? "document";
663
+ const editContext = typeof scope === "object" ? scope.editContext : null;
664
+ const menus = getEditor().registries.menus;
665
+ if (!menus) {
666
+ return { dispose() {
667
+ } };
668
+ }
669
+ return store.add(
670
+ menus.register({
671
+ path: c.path,
672
+ command: c.command,
673
+ order: c.order,
674
+ group: c.group,
675
+ // The scope becomes a `when` predicate, which is the host's
676
+ // existing vocabulary for "does this apply where you are
677
+ // standing" — the same field the Insert items and the Window
678
+ // menu already use. A context-scoped entry is simply one whose
679
+ // predicate asks what context is active.
680
+ when: (state2) => {
681
+ const st = state2;
682
+ if (!st?.document?.handle || (st.document.handle.pageCount ?? 0) === 0) {
683
+ return false;
684
+ }
685
+ if (editContext === null) return true;
686
+ return st.editContext?.type === editContext;
687
+ }
688
+ })
689
+ );
690
+ },
627
691
  overlay(c) {
628
692
  assertNamespaced(c.id, "overlay");
629
693
  requireDeclared(
@@ -1879,6 +1943,9 @@ function createBundleHost(getEditor, manifest, options) {
1879
1943
  }
1880
1944
  };
1881
1945
  const featureSet = new Set(HOST_FEATURES);
1946
+ if (options?.journal) {
1947
+ featureSet.add("journal@1");
1948
+ }
1882
1949
  if (getEditor().text) {
1883
1950
  featureSet.add("text.measure@1");
1884
1951
  }
@@ -1958,6 +2025,7 @@ function createBundleHost(getEditor, manifest, options) {
1958
2025
  network,
1959
2026
  dataProviders,
1960
2027
  diagnostics,
2028
+ journal,
1961
2029
  bindings,
1962
2030
  widgets,
1963
2031
  assets,
@@ -2604,7 +2672,31 @@ function loadBundle(getEditor, bundle, options) {
2604
2672
  manifest,
2605
2673
  options
2606
2674
  );
2607
- const handle = bundle.activate(host);
2675
+ let handle;
2676
+ try {
2677
+ handle = bundle.activate(host);
2678
+ } catch (err) {
2679
+ options?.journal?.record(manifest.id, {
2680
+ code: `${manifest.id}.activate`,
2681
+ severity: "error",
2682
+ // Only the error KIND crosses: an activation throw routinely carries a
2683
+ // module path or a bundler message in its text.
2684
+ data: { ok: false, error: errorKind(err) }
2685
+ });
2686
+ options?.diagnosticsSink?.publish(manifest.id, "activation", [
2687
+ {
2688
+ severity: "error",
2689
+ message: `${manifest.id} failed to activate: ${String(err)}`,
2690
+ source: "loadBundle"
2691
+ }
2692
+ ]);
2693
+ disposeHost();
2694
+ return inertBundle(manifest.id, err);
2695
+ }
2696
+ options?.journal?.record(manifest.id, {
2697
+ code: `${manifest.id}.activate`,
2698
+ data: { ok: true }
2699
+ });
2608
2700
  let active = true;
2609
2701
  return {
2610
2702
  id: manifest.id,
@@ -2622,6 +2714,22 @@ function loadBundle(getEditor, bundle, options) {
2622
2714
  }
2623
2715
  };
2624
2716
  }
2717
+ function errorKind(err) {
2718
+ const raw = err && typeof err === "object" && typeof err.constructor?.name === "string" ? err.constructor.name : typeof err;
2719
+ const lowered = raw.toLowerCase();
2720
+ return /^[a-z0-9][a-z0-9._:-]{0,63}$/.test(lowered) ? lowered : "unknown";
2721
+ }
2722
+ function inertBundle(id, error) {
2723
+ return {
2724
+ id,
2725
+ get active() {
2726
+ return false;
2727
+ },
2728
+ activationError: error,
2729
+ dispose() {
2730
+ }
2731
+ };
2732
+ }
2625
2733
 
2626
2734
  // src/wasm-bundle-loader.ts
2627
2735
  var WASM_BUDGETS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paged-media/plugin-sdk",
3
- "version": "0.2.32-canary.0",
3
+ "version": "0.2.34-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.32-canary.0"
14
+ "@paged-media/plugin-api": "0.2.34-canary.0"
15
15
  },
16
16
  "peerDependencies": {
17
17
  "react": "^18.3.0"