@embedpdf/core 1.5.0 → 2.0.0-next.1

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.
Files changed (55) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +680 -113
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/base/base-plugin.d.ts +52 -0
  6. package/dist/lib/index.d.ts +1 -0
  7. package/dist/lib/registry/plugin-registry.d.ts +6 -2
  8. package/dist/lib/store/actions.d.ts +122 -31
  9. package/dist/lib/store/initial-state.d.ts +22 -6
  10. package/dist/lib/store/reducer-helpers.d.ts +11 -0
  11. package/dist/lib/store/selectors.d.ts +21 -3
  12. package/dist/lib/types/plugin.d.ts +2 -2
  13. package/dist/lib/utils/event-control.d.ts +37 -2
  14. package/dist/lib/utils/eventing.d.ts +1 -1
  15. package/dist/lib/utils/scoped-eventing.d.ts +71 -0
  16. package/dist/preact/index.cjs +1 -1
  17. package/dist/preact/index.cjs.map +1 -1
  18. package/dist/preact/index.js +53 -18
  19. package/dist/preact/index.js.map +1 -1
  20. package/dist/react/index.cjs +1 -1
  21. package/dist/react/index.cjs.map +1 -1
  22. package/dist/react/index.js +53 -18
  23. package/dist/react/index.js.map +1 -1
  24. package/dist/shared/context.d.ts +6 -1
  25. package/dist/shared/hooks/index.d.ts +1 -0
  26. package/dist/shared/hooks/use-core-state.d.ts +4 -2
  27. package/dist/shared/hooks/use-document-state.d.ts +8 -0
  28. package/dist/shared-preact/context.d.ts +6 -1
  29. package/dist/shared-preact/hooks/index.d.ts +1 -0
  30. package/dist/shared-preact/hooks/use-core-state.d.ts +4 -2
  31. package/dist/shared-preact/hooks/use-document-state.d.ts +8 -0
  32. package/dist/shared-react/context.d.ts +6 -1
  33. package/dist/shared-react/hooks/index.d.ts +1 -0
  34. package/dist/shared-react/hooks/use-core-state.d.ts +4 -2
  35. package/dist/shared-react/hooks/use-document-state.d.ts +8 -0
  36. package/dist/svelte/hooks/index.d.ts +1 -0
  37. package/dist/svelte/hooks/use-core-state.svelte.d.ts +5 -4
  38. package/dist/svelte/hooks/use-document-state.svelte.d.ts +9 -0
  39. package/dist/svelte/hooks/use-registry.svelte.d.ts +6 -1
  40. package/dist/svelte/index.cjs +1 -1
  41. package/dist/svelte/index.cjs.map +1 -1
  42. package/dist/svelte/index.js +55 -17
  43. package/dist/svelte/index.js.map +1 -1
  44. package/dist/vue/components/auto-mount.vue.d.ts +3 -2
  45. package/dist/vue/components/embed-pdf.vue.d.ts +13 -2
  46. package/dist/vue/components/nested-wrapper.vue.d.ts +3 -2
  47. package/dist/vue/composables/index.d.ts +1 -0
  48. package/dist/vue/composables/use-core-state.d.ts +8 -1
  49. package/dist/vue/composables/use-document-state.d.ts +8 -0
  50. package/dist/vue/context.d.ts +6 -1
  51. package/dist/vue/index.cjs +1 -1
  52. package/dist/vue/index.cjs.map +1 -1
  53. package/dist/vue/index.js +88 -27
  54. package/dist/vue/index.js.map +1 -1
  55. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Rotation, transformSize, NoopLogger } from "@embedpdf/models";
1
+ import { Rotation, NoopLogger } from "@embedpdf/models";
2
2
  class DependencyResolver {
3
3
  constructor() {
4
4
  this.dependencyGraph = /* @__PURE__ */ new Map();
@@ -161,48 +161,103 @@ class PluginStore {
161
161
  });
162
162
  }
163
163
  }
164
- const LOAD_DOCUMENT = "LOAD_DOCUMENT";
164
+ const START_LOADING_DOCUMENT = "START_LOADING_DOCUMENT";
165
+ const UPDATE_DOCUMENT_LOADING_PROGRESS = "UPDATE_DOCUMENT_LOADING_PROGRESS";
166
+ const SET_DOCUMENT_LOADED = "SET_DOCUMENT_LOADED";
167
+ const SET_DOCUMENT_ERROR = "SET_DOCUMENT_ERROR";
168
+ const RETRY_LOADING_DOCUMENT = "RETRY_LOADING_DOCUMENT";
169
+ const CLOSE_DOCUMENT = "CLOSE_DOCUMENT";
170
+ const SET_ACTIVE_DOCUMENT = "SET_ACTIVE_DOCUMENT";
171
+ const REORDER_DOCUMENTS = "REORDER_DOCUMENTS";
172
+ const MOVE_DOCUMENT = "MOVE_DOCUMENT";
165
173
  const REFRESH_DOCUMENT = "REFRESH_DOCUMENT";
166
174
  const REFRESH_PAGES = "REFRESH_PAGES";
167
- const SET_DOCUMENT = "SET_DOCUMENT";
168
- const SET_DOCUMENT_ERROR = "SET_DOCUMENT_ERROR";
175
+ const SET_PAGES = "SET_PAGES";
169
176
  const SET_SCALE = "SET_SCALE";
170
177
  const SET_ROTATION = "SET_ROTATION";
171
- const SET_PAGES = "SET_PAGES";
178
+ const SET_DEFAULT_SCALE = "SET_DEFAULT_SCALE";
179
+ const SET_DEFAULT_ROTATION = "SET_DEFAULT_ROTATION";
172
180
  const CORE_ACTION_TYPES = [
173
- LOAD_DOCUMENT,
174
- REFRESH_DOCUMENT,
175
- SET_DOCUMENT,
181
+ START_LOADING_DOCUMENT,
182
+ UPDATE_DOCUMENT_LOADING_PROGRESS,
183
+ SET_DOCUMENT_LOADED,
184
+ CLOSE_DOCUMENT,
185
+ SET_ACTIVE_DOCUMENT,
176
186
  SET_DOCUMENT_ERROR,
187
+ RETRY_LOADING_DOCUMENT,
188
+ REFRESH_DOCUMENT,
189
+ REFRESH_PAGES,
190
+ SET_PAGES,
177
191
  SET_SCALE,
178
192
  SET_ROTATION,
179
- SET_PAGES
193
+ SET_DEFAULT_SCALE,
194
+ SET_DEFAULT_ROTATION,
195
+ REORDER_DOCUMENTS,
196
+ MOVE_DOCUMENT
180
197
  ];
181
- const loadDocument = () => ({ type: LOAD_DOCUMENT });
182
- const refreshDocument = (document) => ({
198
+ const startLoadingDocument = (documentId, name, scale, rotation, passwordProvided, autoActivate) => ({
199
+ type: START_LOADING_DOCUMENT,
200
+ payload: { documentId, name, scale, rotation, passwordProvided, autoActivate }
201
+ });
202
+ const updateDocumentLoadingProgress = (documentId, progress) => ({
203
+ type: UPDATE_DOCUMENT_LOADING_PROGRESS,
204
+ payload: { documentId, progress }
205
+ });
206
+ const setDocumentLoaded = (documentId, document) => ({
207
+ type: SET_DOCUMENT_LOADED,
208
+ payload: { documentId, document }
209
+ });
210
+ const setDocumentError = (documentId, error, errorCode, errorDetails) => ({
211
+ type: SET_DOCUMENT_ERROR,
212
+ payload: { documentId, error, errorCode, errorDetails }
213
+ });
214
+ const retryLoadingDocument = (documentId, passwordProvided) => ({
215
+ type: RETRY_LOADING_DOCUMENT,
216
+ payload: { documentId, passwordProvided }
217
+ });
218
+ const closeDocument = (documentId, nextActiveDocumentId) => ({
219
+ type: CLOSE_DOCUMENT,
220
+ payload: { documentId, nextActiveDocumentId }
221
+ });
222
+ const setActiveDocument = (documentId) => ({
223
+ type: SET_ACTIVE_DOCUMENT,
224
+ payload: documentId
225
+ });
226
+ const refreshDocument = (documentId, document) => ({
183
227
  type: REFRESH_DOCUMENT,
184
- payload: document
228
+ payload: { documentId, document }
185
229
  });
186
- const refreshPages = (pages) => ({
230
+ const refreshPages = (documentId, pageIndexes) => ({
187
231
  type: REFRESH_PAGES,
188
- payload: pages
232
+ payload: { documentId, pageIndexes }
189
233
  });
190
- const setDocument = (document) => ({
191
- type: SET_DOCUMENT,
192
- payload: document
234
+ const setPages = (documentId, pages) => ({
235
+ type: SET_PAGES,
236
+ payload: { documentId, pages }
193
237
  });
194
- const setDocumentError = (error) => ({
195
- type: SET_DOCUMENT_ERROR,
196
- payload: error
238
+ const setScale = (scale, documentId) => ({
239
+ type: SET_SCALE,
240
+ payload: { scale, documentId }
197
241
  });
198
- const setScale = (scale) => ({ type: SET_SCALE, payload: scale });
199
- const setRotation = (rotation) => ({
242
+ const setRotation = (rotation, documentId) => ({
200
243
  type: SET_ROTATION,
244
+ payload: { rotation, documentId }
245
+ });
246
+ const setDefaultScale = (scale) => ({
247
+ type: SET_DEFAULT_SCALE,
248
+ payload: scale
249
+ });
250
+ const setDefaultRotation = (rotation) => ({
251
+ type: SET_DEFAULT_ROTATION,
201
252
  payload: rotation
202
253
  });
203
- const setPages = (pages) => ({
204
- type: SET_PAGES,
205
- payload: pages
254
+ const reorderDocuments = (order) => ({
255
+ type: REORDER_DOCUMENTS,
256
+ payload: order
257
+ });
258
+ const moveDocument = (documentId, toIndex) => ({
259
+ type: MOVE_DOCUMENT,
260
+ payload: { documentId, toIndex }
206
261
  });
207
262
  class Store {
208
263
  /**
@@ -460,66 +515,252 @@ class Store {
460
515
  }
461
516
  }
462
517
  const initialCoreState = (config) => ({
463
- scale: (config == null ? void 0 : config.scale) ?? 1,
464
- rotation: (config == null ? void 0 : config.rotation) ?? Rotation.Degree0,
465
- document: null,
466
- pages: [],
467
- loading: false,
468
- error: null
518
+ documents: {},
519
+ documentOrder: [],
520
+ activeDocumentId: null,
521
+ defaultScale: (config == null ? void 0 : config.defaultScale) ?? 1,
522
+ defaultRotation: (config == null ? void 0 : config.defaultRotation) ?? Rotation.Degree0
469
523
  });
470
- const getPagesWithRotatedSize = (state) => {
471
- return state.pages.map(
472
- (page) => page.map((p) => ({
473
- ...p,
474
- rotatedSize: transformSize(p.size, state.rotation, 1)
475
- }))
476
- );
524
+ const getActiveDocumentState = (state) => {
525
+ if (!state.activeDocumentId) return null;
526
+ return state.documents[state.activeDocumentId] ?? null;
527
+ };
528
+ const getDocumentState = (state, documentId) => {
529
+ return state.documents[documentId] ?? null;
530
+ };
531
+ const getDocumentIds = (state) => {
532
+ return Object.keys(state.documents);
533
+ };
534
+ const isDocumentLoaded = (state, documentId) => {
535
+ return !!state.documents[documentId];
536
+ };
537
+ const getDocumentCount = (state) => {
538
+ return Object.keys(state.documents).length;
477
539
  };
540
+ function calculateNextActiveDocument(state, closingDocumentId, explicitNext) {
541
+ const currentActiveId = state.activeDocumentId;
542
+ if (currentActiveId !== closingDocumentId) {
543
+ return currentActiveId;
544
+ }
545
+ if (explicitNext !== void 0) {
546
+ return explicitNext && state.documents[explicitNext] ? explicitNext : null;
547
+ }
548
+ const closingIndex = state.documentOrder.indexOf(closingDocumentId);
549
+ if (closingIndex === -1) {
550
+ return null;
551
+ }
552
+ if (closingIndex > 0) {
553
+ return state.documentOrder[closingIndex - 1];
554
+ }
555
+ if (closingIndex < state.documentOrder.length - 1) {
556
+ return state.documentOrder[closingIndex + 1];
557
+ }
558
+ return null;
559
+ }
560
+ function moveDocumentInOrder(currentOrder, documentId, toIndex) {
561
+ const fromIndex = currentOrder.indexOf(documentId);
562
+ if (fromIndex === -1) return null;
563
+ if (toIndex < 0 || toIndex >= currentOrder.length) return null;
564
+ if (fromIndex === toIndex) return null;
565
+ const newOrder = [...currentOrder];
566
+ newOrder.splice(fromIndex, 1);
567
+ newOrder.splice(toIndex, 0, documentId);
568
+ return newOrder;
569
+ }
478
570
  const coreReducer = (state, action) => {
479
571
  switch (action.type) {
480
- case LOAD_DOCUMENT:
572
+ case START_LOADING_DOCUMENT: {
573
+ const {
574
+ documentId,
575
+ name,
576
+ scale,
577
+ rotation,
578
+ passwordProvided,
579
+ autoActivate = true
580
+ } = action.payload;
581
+ const newDocState = {
582
+ id: documentId,
583
+ name,
584
+ status: "loading",
585
+ loadingProgress: 0,
586
+ error: null,
587
+ document: null,
588
+ scale: scale ?? state.defaultScale,
589
+ rotation: rotation ?? state.defaultRotation,
590
+ passwordProvided: passwordProvided ?? false,
591
+ pageRefreshVersions: {},
592
+ loadStartedAt: Date.now()
593
+ };
594
+ return {
595
+ ...state,
596
+ documents: {
597
+ ...state.documents,
598
+ [documentId]: newDocState
599
+ },
600
+ documentOrder: [...state.documentOrder, documentId],
601
+ // Only activate if autoActivate is true (default), or if no document is currently active
602
+ activeDocumentId: autoActivate || !state.activeDocumentId ? documentId : state.activeDocumentId
603
+ };
604
+ }
605
+ case UPDATE_DOCUMENT_LOADING_PROGRESS: {
606
+ const { documentId, progress } = action.payload;
607
+ const docState = state.documents[documentId];
608
+ if (!docState || docState.status !== "loading") return state;
609
+ return {
610
+ ...state,
611
+ documents: {
612
+ ...state.documents,
613
+ [documentId]: {
614
+ ...docState,
615
+ loadingProgress: progress
616
+ }
617
+ }
618
+ };
619
+ }
620
+ case SET_DOCUMENT_LOADED: {
621
+ const { documentId, document } = action.payload;
622
+ const docState = state.documents[documentId];
623
+ if (!docState) return state;
624
+ return {
625
+ ...state,
626
+ documents: {
627
+ ...state.documents,
628
+ [documentId]: {
629
+ ...docState,
630
+ status: "loaded",
631
+ document,
632
+ error: null,
633
+ errorCode: void 0,
634
+ errorDetails: void 0,
635
+ passwordProvided: void 0,
636
+ loadedAt: Date.now()
637
+ }
638
+ }
639
+ };
640
+ }
641
+ case SET_DOCUMENT_ERROR: {
642
+ const { documentId, error, errorCode, errorDetails } = action.payload;
643
+ const docState = state.documents[documentId];
644
+ if (!docState) return state;
645
+ return {
646
+ ...state,
647
+ documents: {
648
+ ...state.documents,
649
+ [documentId]: {
650
+ ...docState,
651
+ status: "error",
652
+ error,
653
+ errorCode,
654
+ errorDetails
655
+ }
656
+ }
657
+ };
658
+ }
659
+ case RETRY_LOADING_DOCUMENT: {
660
+ const { documentId, passwordProvided } = action.payload;
661
+ const docState = state.documents[documentId];
662
+ if (!docState || docState.status !== "error") return state;
481
663
  return {
482
664
  ...state,
483
- loading: true,
484
- error: null
665
+ documents: {
666
+ ...state.documents,
667
+ [documentId]: {
668
+ ...docState,
669
+ status: "loading",
670
+ loadingProgress: 0,
671
+ error: null,
672
+ errorCode: void 0,
673
+ errorDetails: void 0,
674
+ passwordProvided: passwordProvided ?? false,
675
+ loadStartedAt: Date.now()
676
+ }
677
+ }
485
678
  };
486
- case SET_DOCUMENT:
679
+ }
680
+ case CLOSE_DOCUMENT: {
681
+ const { documentId, nextActiveDocumentId } = action.payload;
682
+ const { [documentId]: removed, ...remainingDocs } = state.documents;
683
+ return {
684
+ ...state,
685
+ documents: remainingDocs,
686
+ documentOrder: state.documentOrder.filter((id) => id !== documentId),
687
+ activeDocumentId: calculateNextActiveDocument(state, documentId, nextActiveDocumentId)
688
+ };
689
+ }
690
+ case MOVE_DOCUMENT: {
691
+ const { documentId, toIndex } = action.payload;
692
+ const newOrder = moveDocumentInOrder(state.documentOrder, documentId, toIndex);
693
+ if (!newOrder) return state;
487
694
  return {
488
695
  ...state,
489
- document: action.payload,
490
- pages: action.payload.pages.map((page) => [page]),
491
- loading: false,
492
- error: null
696
+ documentOrder: newOrder
493
697
  };
494
- case REFRESH_DOCUMENT:
698
+ }
699
+ case REORDER_DOCUMENTS: {
495
700
  return {
496
701
  ...state,
497
- document: action.payload,
498
- pages: action.payload.pages.map((page) => [page]),
499
- loading: false,
500
- error: null
702
+ documentOrder: action.payload
501
703
  };
502
- case SET_ROTATION:
704
+ }
705
+ case SET_ACTIVE_DOCUMENT: {
503
706
  return {
504
707
  ...state,
505
- rotation: action.payload
708
+ activeDocumentId: action.payload
506
709
  };
507
- case SET_PAGES:
710
+ }
711
+ case SET_SCALE: {
712
+ const { scale, documentId } = action.payload;
713
+ const targetId = documentId ?? state.activeDocumentId;
714
+ if (!targetId) return state;
715
+ const docState = state.documents[targetId];
716
+ if (!docState) return state;
508
717
  return {
509
718
  ...state,
510
- pages: action.payload
719
+ documents: {
720
+ ...state.documents,
721
+ [targetId]: {
722
+ ...docState,
723
+ scale
724
+ }
725
+ }
511
726
  };
512
- case SET_DOCUMENT_ERROR:
727
+ }
728
+ case SET_ROTATION: {
729
+ const { rotation, documentId } = action.payload;
730
+ const targetId = documentId ?? state.activeDocumentId;
731
+ if (!targetId) return state;
732
+ const docState = state.documents[targetId];
733
+ if (!docState) return state;
513
734
  return {
514
735
  ...state,
515
- loading: false,
516
- error: action.payload
736
+ documents: {
737
+ ...state.documents,
738
+ [targetId]: {
739
+ ...docState,
740
+ rotation
741
+ }
742
+ }
517
743
  };
518
- case SET_SCALE:
744
+ }
745
+ case REFRESH_PAGES: {
746
+ const { documentId, pageIndexes } = action.payload;
747
+ const docState = state.documents[documentId];
748
+ if (!docState) return state;
749
+ const newVersions = { ...docState.pageRefreshVersions };
750
+ for (const pageIndex of pageIndexes) {
751
+ newVersions[pageIndex] = (newVersions[pageIndex] || 0) + 1;
752
+ }
519
753
  return {
520
754
  ...state,
521
- scale: action.payload
755
+ documents: {
756
+ ...state.documents,
757
+ [documentId]: {
758
+ ...docState,
759
+ pageRefreshVersions: newVersions
760
+ }
761
+ }
522
762
  };
763
+ }
523
764
  default:
524
765
  return state;
525
766
  }
@@ -633,20 +874,15 @@ class PluginRegistry {
633
874
  return this.initPromise;
634
875
  }
635
876
  this.initPromise = (async () => {
636
- var _a;
637
877
  if (this.initialized) {
638
878
  throw new PluginRegistrationError("Registry is already initialized");
639
879
  }
640
880
  this.isInitializing = true;
641
881
  try {
642
882
  await this.ensureEngineInitialized();
643
- if (this.destroyed) {
644
- return;
645
- }
883
+ if (this.destroyed) return;
646
884
  while (this.pendingRegistrations.length > 0) {
647
- if (this.destroyed) {
648
- return;
649
- }
885
+ if (this.destroyed) return;
650
886
  this.processingRegistrations = [...this.pendingRegistrations];
651
887
  this.pendingRegistrations = [];
652
888
  for (const reg of this.processingRegistrations) {
@@ -656,24 +892,23 @@ class PluginRegistry {
656
892
  const provider = this.processingRegistrations.find(
657
893
  (r) => r.package.manifest.provides.includes(cap)
658
894
  );
659
- if (provider) dependsOn.add(provider.package.manifest.id);
895
+ if (provider) {
896
+ dependsOn.add(provider.package.manifest.id);
897
+ }
660
898
  }
661
899
  this.resolver.addNode(reg.package.manifest.id, [...dependsOn]);
662
900
  }
663
901
  const loadOrder = this.resolver.resolveLoadOrder();
664
902
  for (const id of loadOrder) {
665
903
  const reg = this.processingRegistrations.find((r) => r.package.manifest.id === id);
666
- await this.initializePlugin(reg.package.manifest, reg.package.create, reg.config);
904
+ this.instantiatePlugin(reg.package.manifest, reg.package.create, reg.config);
905
+ }
906
+ for (const id of loadOrder) {
907
+ await this.runPluginInitialization(id);
667
908
  }
668
909
  this.processingRegistrations = [];
669
910
  this.resolver = new DependencyResolver();
670
911
  }
671
- for (const plugin of this.plugins.values()) {
672
- await ((_a = plugin.postInitialize) == null ? void 0 : _a.call(plugin).catch((e) => {
673
- console.error(`Error in postInitialize for plugin ${plugin.id}`, e);
674
- this.status.set(plugin.id, "error");
675
- }));
676
- }
677
912
  this.initialized = true;
678
913
  } catch (err) {
679
914
  if (err instanceof Error) {
@@ -689,9 +924,9 @@ class PluginRegistry {
689
924
  return this.initPromise;
690
925
  }
691
926
  /**
692
- * Initialize a single plugin with all necessary checks
927
+ * Phase 2: Create instance and register capabilities
693
928
  */
694
- async initializePlugin(manifest, packageCreator, config) {
929
+ instantiatePlugin(manifest, packageCreator, config) {
695
930
  const finalConfig = {
696
931
  ...manifest.defaultConfig,
697
932
  ...config
@@ -699,25 +934,6 @@ class PluginRegistry {
699
934
  this.validateConfig(manifest.id, finalConfig, manifest.defaultConfig);
700
935
  const plugin = packageCreator(this, finalConfig);
701
936
  this.validatePlugin(plugin);
702
- for (const capability of manifest.requires) {
703
- if (!this.capabilities.has(capability)) {
704
- throw new PluginRegistrationError(
705
- `Missing required capability: ${capability} for plugin ${manifest.id}`
706
- );
707
- }
708
- }
709
- for (const capability of manifest.optional) {
710
- if (this.capabilities.has(capability)) {
711
- this.logger.debug(
712
- "PluginRegistry",
713
- "OptionalCapability",
714
- `Optional capability ${capability} is available for plugin ${manifest.id}`
715
- );
716
- }
717
- }
718
- this.logger.debug("PluginRegistry", "InitializePlugin", `Initializing plugin ${manifest.id}`, {
719
- provides: manifest.provides
720
- });
721
937
  for (const capability of manifest.provides) {
722
938
  if (this.capabilities.has(capability)) {
723
939
  throw new PluginRegistrationError(
@@ -730,26 +946,41 @@ class PluginRegistry {
730
946
  this.manifests.set(manifest.id, manifest);
731
947
  this.status.set(manifest.id, "registered");
732
948
  this.configurations.set(manifest.id, finalConfig);
949
+ }
950
+ /**
951
+ * Phase 3: Run the initialize method
952
+ */
953
+ async runPluginInitialization(pluginId) {
954
+ const plugin = this.plugins.get(pluginId);
955
+ if (!plugin) return;
956
+ const manifest = this.manifests.get(pluginId);
957
+ const config = this.configurations.get(pluginId);
958
+ for (const capability of manifest.requires) {
959
+ if (!this.capabilities.has(capability)) {
960
+ throw new PluginRegistrationError(
961
+ `Missing required capability: ${capability} for plugin ${pluginId}`
962
+ );
963
+ }
964
+ }
965
+ this.logger.debug("PluginRegistry", "InitializePlugin", `Initializing plugin ${pluginId}`);
733
966
  try {
734
967
  if (plugin.initialize) {
735
- await plugin.initialize(finalConfig);
968
+ await plugin.initialize(config);
736
969
  }
737
- this.status.set(manifest.id, "active");
970
+ this.status.set(pluginId, "active");
738
971
  this.logger.info(
739
972
  "PluginRegistry",
740
973
  "PluginInitialized",
741
- `Plugin ${manifest.id} initialized successfully`
974
+ `Plugin ${pluginId} initialized successfully`
742
975
  );
743
976
  } catch (error) {
744
- this.plugins.delete(manifest.id);
745
- this.manifests.delete(manifest.id);
977
+ this.status.set(pluginId, "error");
746
978
  this.logger.error(
747
979
  "PluginRegistry",
748
980
  "InitializationFailed",
749
- `Plugin ${manifest.id} initialization failed`,
750
- { provides: manifest.provides, error }
981
+ `Plugin ${pluginId} initialization failed`,
982
+ { error }
751
983
  );
752
- manifest.provides.forEach((cap) => this.capabilities.delete(cap));
753
984
  throw error;
754
985
  }
755
986
  }
@@ -957,6 +1188,11 @@ class BasePlugin {
957
1188
  this.debouncedTimeouts = {};
958
1189
  this.unsubscribeFromState = null;
959
1190
  this.unsubscribeFromCoreStore = null;
1191
+ this.unsubscribeFromStartLoadingDocument = null;
1192
+ this.unsubscribeFromSetDocumentLoaded = null;
1193
+ this.unsubscribeFromCloseDocument = null;
1194
+ this.unsubscribeFromSetScale = null;
1195
+ this.unsubscribeFromSetRotation = null;
960
1196
  if (id !== this.constructor.id) {
961
1197
  throw new Error(
962
1198
  `Plugin ID mismatch: ${id} !== ${this.constructor.id}`
@@ -971,6 +1207,39 @@ class BasePlugin {
971
1207
  });
972
1208
  this.unsubscribeFromCoreStore = this.coreStore.subscribe((action, newState, oldState) => {
973
1209
  this.onCoreStoreUpdated(oldState, newState);
1210
+ if (newState.core.activeDocumentId !== oldState.core.activeDocumentId) {
1211
+ this.onActiveDocumentChanged(
1212
+ oldState.core.activeDocumentId,
1213
+ newState.core.activeDocumentId
1214
+ );
1215
+ }
1216
+ });
1217
+ this.unsubscribeFromStartLoadingDocument = this.coreStore.onAction(
1218
+ START_LOADING_DOCUMENT,
1219
+ (action) => {
1220
+ this.onDocumentLoadingStarted(action.payload.documentId);
1221
+ }
1222
+ );
1223
+ this.unsubscribeFromSetDocumentLoaded = this.coreStore.onAction(
1224
+ SET_DOCUMENT_LOADED,
1225
+ (action) => {
1226
+ this.onDocumentLoaded(action.payload.documentId);
1227
+ }
1228
+ );
1229
+ this.unsubscribeFromCloseDocument = this.coreStore.onAction(CLOSE_DOCUMENT, (action) => {
1230
+ this.onDocumentClosed(action.payload.documentId);
1231
+ });
1232
+ this.unsubscribeFromSetScale = this.coreStore.onAction(SET_SCALE, (action, state) => {
1233
+ const targetId = action.payload.documentId ?? state.core.activeDocumentId;
1234
+ if (targetId) {
1235
+ this.onScaleChanged(targetId, action.payload.scale);
1236
+ }
1237
+ });
1238
+ this.unsubscribeFromSetRotation = this.coreStore.onAction(SET_ROTATION, (action, state) => {
1239
+ const targetId = action.payload.documentId ?? state.core.activeDocumentId;
1240
+ if (targetId) {
1241
+ this.onRotationChanged(targetId, action.payload.rotation);
1242
+ }
974
1243
  });
975
1244
  this.readyPromise = new Promise((resolve) => {
976
1245
  this.readyResolve = resolve;
@@ -1095,6 +1364,37 @@ class BasePlugin {
1095
1364
  */
1096
1365
  onCoreStoreUpdated(oldState, newState) {
1097
1366
  }
1367
+ /**
1368
+ * Called when a document is opened
1369
+ * Override to initialize per-document state
1370
+ * @param documentId The ID of the document that was opened
1371
+ */
1372
+ onDocumentLoadingStarted(documentId) {
1373
+ }
1374
+ /**
1375
+ * Called when a document is loaded
1376
+ * @param documentId The ID of the document that is loaded
1377
+ */
1378
+ onDocumentLoaded(documentId) {
1379
+ }
1380
+ /**
1381
+ * Called when a document is closed
1382
+ * Override to cleanup per-document state
1383
+ * @param documentId The ID of the document that was closed
1384
+ */
1385
+ onDocumentClosed(documentId) {
1386
+ }
1387
+ /**
1388
+ * Called when the active document changes
1389
+ * @param previousId The ID of the previous active document
1390
+ * @param currentId The ID of the new active document
1391
+ */
1392
+ onActiveDocumentChanged(previousId, currentId) {
1393
+ }
1394
+ onScaleChanged(documentId, scale) {
1395
+ }
1396
+ onRotationChanged(documentId, rotation) {
1397
+ }
1098
1398
  /**
1099
1399
  * Cleanup method to be called when plugin is being destroyed
1100
1400
  */
@@ -1111,6 +1411,26 @@ class BasePlugin {
1111
1411
  this.unsubscribeFromCoreStore();
1112
1412
  this.unsubscribeFromCoreStore = null;
1113
1413
  }
1414
+ if (this.unsubscribeFromStartLoadingDocument) {
1415
+ this.unsubscribeFromStartLoadingDocument();
1416
+ this.unsubscribeFromStartLoadingDocument = null;
1417
+ }
1418
+ if (this.unsubscribeFromSetDocumentLoaded) {
1419
+ this.unsubscribeFromSetDocumentLoaded();
1420
+ this.unsubscribeFromSetDocumentLoaded = null;
1421
+ }
1422
+ if (this.unsubscribeFromCloseDocument) {
1423
+ this.unsubscribeFromCloseDocument();
1424
+ this.unsubscribeFromCloseDocument = null;
1425
+ }
1426
+ if (this.unsubscribeFromSetScale) {
1427
+ this.unsubscribeFromSetScale();
1428
+ this.unsubscribeFromSetScale = null;
1429
+ }
1430
+ if (this.unsubscribeFromSetRotation) {
1431
+ this.unsubscribeFromSetRotation();
1432
+ this.unsubscribeFromSetRotation = null;
1433
+ }
1114
1434
  }
1115
1435
  /**
1116
1436
  * Returns a promise that resolves when the plugin is ready
@@ -1132,6 +1452,45 @@ class BasePlugin {
1132
1452
  this.readyResolve = resolve;
1133
1453
  });
1134
1454
  }
1455
+ /**
1456
+ * Get the active document ID
1457
+ * @throws Error if no active document exists
1458
+ */
1459
+ getActiveDocumentId() {
1460
+ const id = this.coreState.core.activeDocumentId;
1461
+ if (!id) {
1462
+ throw new Error("No active document");
1463
+ }
1464
+ return id;
1465
+ }
1466
+ /**
1467
+ * Get the active document ID or null if none exists
1468
+ */
1469
+ getActiveDocumentIdOrNull() {
1470
+ return this.coreState.core.activeDocumentId;
1471
+ }
1472
+ /**
1473
+ * Get core document state for a specific document
1474
+ * @param documentId Document ID (optional, defaults to active document)
1475
+ * @returns Document state or null if not found
1476
+ */
1477
+ getCoreDocument(documentId) {
1478
+ const id = documentId ?? this.getActiveDocumentIdOrNull();
1479
+ if (!id) return null;
1480
+ return this.coreState.core.documents[id] ?? null;
1481
+ }
1482
+ /**
1483
+ * Get core document state for a specific document
1484
+ * @param documentId Document ID (optional, defaults to active document)
1485
+ * @throws Error if document not found
1486
+ */
1487
+ getCoreDocumentOrThrow(documentId) {
1488
+ const doc = this.getCoreDocument(documentId);
1489
+ if (!doc) {
1490
+ throw new Error(`Document not found: ${documentId ?? "active"}`);
1491
+ }
1492
+ return doc;
1493
+ }
1135
1494
  }
1136
1495
  class EventControl {
1137
1496
  constructor(handler, options) {
@@ -1183,6 +1542,36 @@ class EventControl {
1183
1542
  }
1184
1543
  }
1185
1544
  }
1545
+ class KeyedEventControl {
1546
+ constructor(handler, options) {
1547
+ this.handler = handler;
1548
+ this.options = options;
1549
+ this.controls = /* @__PURE__ */ new Map();
1550
+ this.handle = (data) => {
1551
+ const key = String(this.options.keyExtractor(data));
1552
+ let control = this.controls.get(key);
1553
+ if (!control) {
1554
+ control = new EventControl(this.handler, this.baseOptions);
1555
+ this.controls.set(key, control);
1556
+ }
1557
+ control.handle(data);
1558
+ };
1559
+ this.baseOptions = {
1560
+ mode: options.mode,
1561
+ wait: options.wait,
1562
+ ...options.mode === "throttle" && "throttleMode" in options ? { throttleMode: options.throttleMode } : {}
1563
+ };
1564
+ }
1565
+ destroy() {
1566
+ for (const control of this.controls.values()) {
1567
+ control.destroy();
1568
+ }
1569
+ this.controls.clear();
1570
+ }
1571
+ }
1572
+ function isKeyedOptions(options) {
1573
+ return "keyExtractor" in options;
1574
+ }
1186
1575
  function clamp(value, min, max) {
1187
1576
  return value < min ? min : value > max ? max : value;
1188
1577
  }
@@ -1281,9 +1670,15 @@ function createBehaviorEmitter(initial, equality = arePropsEqual) {
1281
1670
  let destroy = () => {
1282
1671
  };
1283
1672
  if (options) {
1284
- const ctl = new EventControl(listener, options);
1285
- realListener = ctl.handle;
1286
- destroy = () => ctl.destroy();
1673
+ if (isKeyedOptions(options)) {
1674
+ const ctl = new KeyedEventControl(listener, options);
1675
+ realListener = ctl.handle;
1676
+ destroy = () => ctl.destroy();
1677
+ } else {
1678
+ const ctl = new EventControl(listener, options);
1679
+ realListener = ctl.handle;
1680
+ destroy = () => ctl.destroy();
1681
+ }
1287
1682
  proxyMap.set(listener, { wrapped: realListener, destroy });
1288
1683
  }
1289
1684
  if (_value !== void 0) realListener(_value);
@@ -1344,6 +1739,155 @@ function createBehaviorEmitter(initial, equality = arePropsEqual) {
1344
1739
  }
1345
1740
  };
1346
1741
  }
1742
+ function createScopedEmitter(toGlobalEvent, options) {
1743
+ const shouldCache = (options == null ? void 0 : options.cache) ?? true;
1744
+ const equality = (options == null ? void 0 : options.equality) ?? arePropsEqual;
1745
+ const scopeCaches = /* @__PURE__ */ new Map();
1746
+ const scopeListeners = /* @__PURE__ */ new Map();
1747
+ const scopeProxyMaps = /* @__PURE__ */ new Map();
1748
+ const globalListeners = /* @__PURE__ */ new Set();
1749
+ const globalProxyMap = /* @__PURE__ */ new Map();
1750
+ const normalizeKey = (key) => String(key);
1751
+ const getOrCreateListeners = (key) => {
1752
+ let listeners = scopeListeners.get(key);
1753
+ if (!listeners) {
1754
+ listeners = /* @__PURE__ */ new Set();
1755
+ scopeListeners.set(key, listeners);
1756
+ }
1757
+ return listeners;
1758
+ };
1759
+ const getOrCreateProxyMap = (key) => {
1760
+ let proxyMap = scopeProxyMaps.get(key);
1761
+ if (!proxyMap) {
1762
+ proxyMap = /* @__PURE__ */ new Map();
1763
+ scopeProxyMaps.set(key, proxyMap);
1764
+ }
1765
+ return proxyMap;
1766
+ };
1767
+ const onGlobal = (listener, options2) => {
1768
+ let realListener = listener;
1769
+ let destroy = () => {
1770
+ };
1771
+ if (options2) {
1772
+ if (isKeyedOptions(options2)) {
1773
+ const ctl = new KeyedEventControl(listener, options2);
1774
+ realListener = ctl.handle;
1775
+ destroy = () => ctl.destroy();
1776
+ } else {
1777
+ const ctl = new EventControl(listener, options2);
1778
+ realListener = ctl.handle;
1779
+ destroy = () => ctl.destroy();
1780
+ }
1781
+ globalProxyMap.set(listener, { wrapped: realListener, destroy });
1782
+ }
1783
+ globalListeners.add(realListener);
1784
+ return () => {
1785
+ globalListeners.delete(realListener);
1786
+ destroy();
1787
+ globalProxyMap.delete(listener);
1788
+ };
1789
+ };
1790
+ return {
1791
+ emit(key, data) {
1792
+ const normalizedKey = normalizeKey(key);
1793
+ if (shouldCache) {
1794
+ const cached = scopeCaches.get(normalizedKey);
1795
+ if (cached !== void 0 && equality(cached, data)) {
1796
+ return;
1797
+ }
1798
+ scopeCaches.set(normalizedKey, data);
1799
+ }
1800
+ const listeners = scopeListeners.get(normalizedKey);
1801
+ if (listeners) {
1802
+ listeners.forEach((l) => l(data));
1803
+ }
1804
+ const globalEvent = toGlobalEvent(key, data);
1805
+ globalListeners.forEach((l) => l(globalEvent));
1806
+ },
1807
+ forScope(key) {
1808
+ const normalizedKey = normalizeKey(key);
1809
+ return (listener, options2) => {
1810
+ const listeners = getOrCreateListeners(normalizedKey);
1811
+ const proxyMap = getOrCreateProxyMap(normalizedKey);
1812
+ let realListener = listener;
1813
+ let destroy = () => {
1814
+ };
1815
+ if (options2) {
1816
+ if (isKeyedOptions(options2)) {
1817
+ const ctl = new KeyedEventControl(listener, options2);
1818
+ realListener = ctl.handle;
1819
+ destroy = () => ctl.destroy();
1820
+ } else {
1821
+ const ctl = new EventControl(listener, options2);
1822
+ realListener = ctl.handle;
1823
+ destroy = () => ctl.destroy();
1824
+ }
1825
+ proxyMap.set(listener, { wrapped: realListener, destroy });
1826
+ }
1827
+ if (shouldCache) {
1828
+ const cached = scopeCaches.get(normalizedKey);
1829
+ if (cached !== void 0) {
1830
+ realListener(cached);
1831
+ }
1832
+ }
1833
+ listeners.add(realListener);
1834
+ return () => {
1835
+ listeners.delete(realListener);
1836
+ destroy();
1837
+ proxyMap.delete(listener);
1838
+ if (listeners.size === 0) {
1839
+ scopeListeners.delete(normalizedKey);
1840
+ }
1841
+ if (proxyMap.size === 0) {
1842
+ scopeProxyMaps.delete(normalizedKey);
1843
+ }
1844
+ };
1845
+ };
1846
+ },
1847
+ onGlobal,
1848
+ getValue(key) {
1849
+ return shouldCache ? scopeCaches.get(normalizeKey(key)) : void 0;
1850
+ },
1851
+ getScopes() {
1852
+ if (shouldCache) {
1853
+ return Array.from(scopeCaches.keys());
1854
+ }
1855
+ return Array.from(scopeListeners.keys());
1856
+ },
1857
+ clearScope(key) {
1858
+ const normalizedKey = normalizeKey(key);
1859
+ if (shouldCache) {
1860
+ scopeCaches.delete(normalizedKey);
1861
+ }
1862
+ const listeners = scopeListeners.get(normalizedKey);
1863
+ if (listeners) {
1864
+ listeners.clear();
1865
+ scopeListeners.delete(normalizedKey);
1866
+ }
1867
+ const proxyMap = scopeProxyMaps.get(normalizedKey);
1868
+ if (proxyMap) {
1869
+ proxyMap.forEach((p) => p.destroy());
1870
+ proxyMap.clear();
1871
+ scopeProxyMaps.delete(normalizedKey);
1872
+ }
1873
+ },
1874
+ clear() {
1875
+ if (shouldCache) {
1876
+ scopeCaches.clear();
1877
+ }
1878
+ scopeListeners.forEach((set) => set.clear());
1879
+ scopeListeners.clear();
1880
+ scopeProxyMaps.forEach((map) => {
1881
+ map.forEach((p) => p.destroy());
1882
+ map.clear();
1883
+ });
1884
+ scopeProxyMaps.clear();
1885
+ globalListeners.clear();
1886
+ globalProxyMap.forEach((p) => p.destroy());
1887
+ globalProxyMap.clear();
1888
+ }
1889
+ };
1890
+ }
1347
1891
  function enumEntries(record) {
1348
1892
  return Object.entries(record).map(([k, v]) => {
1349
1893
  const maybeNum = Number(k);
@@ -1376,13 +1920,15 @@ function createPluginPackage(basePackage) {
1376
1920
  }
1377
1921
  export {
1378
1922
  BasePlugin,
1923
+ CLOSE_DOCUMENT,
1379
1924
  CORE_ACTION_TYPES,
1380
1925
  CapabilityConflictError,
1381
1926
  CapabilityNotFoundError,
1382
1927
  CircularDependencyError,
1383
1928
  DependencyResolver,
1384
1929
  EventControl,
1385
- LOAD_DOCUMENT,
1930
+ KeyedEventControl,
1931
+ MOVE_DOCUMENT,
1386
1932
  PluginConfigurationError,
1387
1933
  PluginInitializationError,
1388
1934
  PluginNotFoundError,
@@ -1391,28 +1937,49 @@ export {
1391
1937
  PluginRegistry,
1392
1938
  REFRESH_DOCUMENT,
1393
1939
  REFRESH_PAGES,
1394
- SET_DOCUMENT,
1940
+ REORDER_DOCUMENTS,
1941
+ RETRY_LOADING_DOCUMENT,
1942
+ SET_ACTIVE_DOCUMENT,
1943
+ SET_DEFAULT_ROTATION,
1944
+ SET_DEFAULT_SCALE,
1395
1945
  SET_DOCUMENT_ERROR,
1946
+ SET_DOCUMENT_LOADED,
1396
1947
  SET_PAGES,
1397
1948
  SET_ROTATION,
1398
1949
  SET_SCALE,
1950
+ START_LOADING_DOCUMENT,
1951
+ UPDATE_DOCUMENT_LOADING_PROGRESS,
1399
1952
  arePropsEqual,
1400
1953
  clamp,
1954
+ closeDocument,
1401
1955
  createBehaviorEmitter,
1402
1956
  createEmitter,
1403
1957
  createPluginPackage,
1404
1958
  createPluginRegistration,
1959
+ createScopedEmitter,
1405
1960
  enumEntries,
1406
- getPagesWithRotatedSize,
1961
+ getActiveDocumentState,
1962
+ getDocumentCount,
1963
+ getDocumentIds,
1964
+ getDocumentState,
1407
1965
  hasAutoMountElements,
1408
1966
  initialCoreState,
1409
- loadDocument,
1967
+ isDocumentLoaded,
1968
+ isKeyedOptions,
1969
+ moveDocument,
1410
1970
  refreshDocument,
1411
1971
  refreshPages,
1412
- setDocument,
1972
+ reorderDocuments,
1973
+ retryLoadingDocument,
1974
+ setActiveDocument,
1975
+ setDefaultRotation,
1976
+ setDefaultScale,
1413
1977
  setDocumentError,
1978
+ setDocumentLoaded,
1414
1979
  setPages,
1415
1980
  setRotation,
1416
- setScale
1981
+ setScale,
1982
+ startLoadingDocument,
1983
+ updateDocumentLoadingProgress
1417
1984
  };
1418
1985
  //# sourceMappingURL=index.js.map