@powerhousedao/powerhouse-vetra-packages 6.2.2-dev.76 → 6.2.2-dev.77

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 (41) hide show
  1. package/dist/browser/{connect-2yVh7pKg.js → connect-Dfa445EK.js} +2 -2
  2. package/dist/browser/{connect-2yVh7pKg.js.map → connect-Dfa445EK.js.map} +1 -1
  3. package/dist/browser/{dist-n6WRzvGW.js → dist-Dq_xli8e.js} +1888 -1884
  4. package/dist/browser/dist-Dq_xli8e.js.map +1 -0
  5. package/dist/browser/{editor-BOqgBTL2.js → editor-BVHBckgy.js} +4 -4
  6. package/dist/browser/{editor-BOqgBTL2.js.map → editor-BVHBckgy.js.map} +1 -1
  7. package/dist/browser/{editor-BHS8IZ9o.js → editor-CjtwhcdJ.js} +5 -5
  8. package/dist/browser/{editor-BHS8IZ9o.js.map → editor-CjtwhcdJ.js.map} +1 -1
  9. package/dist/browser/editors/document-model-editor/module.js +1 -1
  10. package/dist/browser/editors/generic-drive-explorer/index.js +3 -3
  11. package/dist/browser/editors/generic-drive-explorer/module.js +1 -1
  12. package/dist/browser/{folder-view-N9lf6Mpv.js → folder-view-DEAGV1EC.js} +3 -3
  13. package/dist/browser/{folder-view-N9lf6Mpv.js.map → folder-view-DEAGV1EC.js.map} +1 -1
  14. package/dist/browser/{graphql-editor-CCabCu2K.js → graphql-editor-CJtKg7XI.js} +2 -2
  15. package/dist/browser/{graphql-editor-CCabCu2K.js.map → graphql-editor-CJtKg7XI.js.map} +1 -1
  16. package/dist/browser/{json-editor-DyNatyzP.js → json-editor-COLbuEyO.js} +2 -2
  17. package/dist/browser/{json-editor-DyNatyzP.js.map → json-editor-COLbuEyO.js.map} +1 -1
  18. package/dist/browser/{state-schemas-sOOHeCL5.js → state-schemas-DIcbtLEN.js} +3 -3
  19. package/dist/browser/{state-schemas-sOOHeCL5.js.map → state-schemas-DIcbtLEN.js.map} +1 -1
  20. package/dist/node/{connect-AGyqHlSg.mjs → connect-BH48bo-2.mjs} +2 -2
  21. package/dist/node/{connect-AGyqHlSg.mjs.map → connect-BH48bo-2.mjs.map} +1 -1
  22. package/dist/node/{dist-Bmp6vCZK.mjs → dist-BzJZJOzf.mjs} +1882 -1878
  23. package/dist/node/dist-BzJZJOzf.mjs.map +1 -0
  24. package/dist/node/{editor-CRFs_N-o.mjs → editor-BfEM_nAZ.mjs} +4 -4
  25. package/dist/node/{editor-CRFs_N-o.mjs.map → editor-BfEM_nAZ.mjs.map} +1 -1
  26. package/dist/node/{editor-DjTKgFi-.mjs → editor-DIpITIp4.mjs} +5 -5
  27. package/dist/node/{editor-DjTKgFi-.mjs.map → editor-DIpITIp4.mjs.map} +1 -1
  28. package/dist/node/editors/document-model-editor/module.mjs +1 -1
  29. package/dist/node/editors/generic-drive-explorer/index.mjs +3 -3
  30. package/dist/node/editors/generic-drive-explorer/module.mjs +1 -1
  31. package/dist/node/{folder-view-Bw9lf-FE.mjs → folder-view-CgGhHD-n.mjs} +3 -3
  32. package/dist/node/{folder-view-Bw9lf-FE.mjs.map → folder-view-CgGhHD-n.mjs.map} +1 -1
  33. package/dist/node/{graphql-editor-Bee3v_a1.mjs → graphql-editor-C8N05Tui.mjs} +2 -2
  34. package/dist/node/{graphql-editor-Bee3v_a1.mjs.map → graphql-editor-C8N05Tui.mjs.map} +1 -1
  35. package/dist/node/{json-editor-DkNyMP5s.mjs → json-editor-D0HBH78f.mjs} +2 -2
  36. package/dist/node/{json-editor-DkNyMP5s.mjs.map → json-editor-D0HBH78f.mjs.map} +1 -1
  37. package/dist/node/{state-schemas-DlTrdE-3.mjs → state-schemas-BxV-MnqS.mjs} +3 -3
  38. package/dist/node/{state-schemas-DlTrdE-3.mjs.map → state-schemas-BxV-MnqS.mjs.map} +1 -1
  39. package/package.json +7 -7
  40. package/dist/browser/dist-n6WRzvGW.js.map +0 -1
  41. package/dist/node/dist-Bmp6vCZK.mjs.map +0 -1
@@ -241,779 +241,6 @@ function useDocumentById(id) {
241
241
  const [, dispatch] = useDispatch(document);
242
242
  return [document, dispatch];
243
243
  }
244
- Error;
245
- require_graphql();
246
- JSON;
247
- //#endregion
248
- //#region ../reactor-browser/dist/client-DB8gP4hz.js
249
- var import_main = require_main();
250
- let DocumentChangeType = /* @__PURE__ */ function(DocumentChangeType) {
251
- DocumentChangeType["ChildAdded"] = "CHILD_ADDED";
252
- DocumentChangeType["ChildRemoved"] = "CHILD_REMOVED";
253
- DocumentChangeType["Created"] = "CREATED";
254
- DocumentChangeType["Deleted"] = "DELETED";
255
- DocumentChangeType["ParentAdded"] = "PARENT_ADDED";
256
- DocumentChangeType["ParentRemoved"] = "PARENT_REMOVED";
257
- DocumentChangeType["Updated"] = "UPDATED";
258
- return DocumentChangeType;
259
- }({});
260
- let PropagationMode = /* @__PURE__ */ function(PropagationMode) {
261
- PropagationMode["Cascade"] = "CASCADE";
262
- PropagationMode["Orphan"] = "ORPHAN";
263
- return PropagationMode;
264
- }({});
265
- const PhDocumentFieldsFragmentDoc = import_main.gql`
266
- fragment PHDocumentFields on PHDocument {
267
- id
268
- slug
269
- name
270
- documentType
271
- state
272
- revisionsList {
273
- scope
274
- revision
275
- }
276
- createdAtUtcIso
277
- lastModifiedAtUtcIso
278
- }
279
- `;
280
- import_main.gql`
281
- query GetDocumentModels($namespace: String, $paging: PagingInput) {
282
- documentModels(namespace: $namespace, paging: $paging) {
283
- items {
284
- id
285
- name
286
- namespace
287
- version
288
- specification
289
- }
290
- totalCount
291
- hasNextPage
292
- hasPreviousPage
293
- cursor
294
- }
295
- }
296
- `;
297
- const GetDocumentDocument = import_main.gql`
298
- query GetDocument($identifier: String!, $view: ViewFilterInput) {
299
- document(identifier: $identifier, view: $view) {
300
- document {
301
- ...PHDocumentFields
302
- }
303
- childIds
304
- }
305
- }
306
- ${PhDocumentFieldsFragmentDoc}
307
- `;
308
- const GetDocumentWithOperationsDocument = import_main.gql`
309
- query GetDocumentWithOperations(
310
- $identifier: String!
311
- $view: ViewFilterInput
312
- $operationsFilter: DocumentOperationsFilterInput
313
- $operationsPaging: PagingInput
314
- ) {
315
- document(identifier: $identifier, view: $view) {
316
- document {
317
- ...PHDocumentFields
318
- operations(filter: $operationsFilter, paging: $operationsPaging) {
319
- items {
320
- index
321
- timestampUtcMs
322
- hash
323
- skip
324
- error
325
- deniedReason
326
- id
327
- action {
328
- id
329
- type
330
- timestampUtcMs
331
- input
332
- scope
333
- context {
334
- signer {
335
- user {
336
- address
337
- networkId
338
- chainId
339
- }
340
- app {
341
- name
342
- key
343
- }
344
- signatures
345
- }
346
- }
347
- }
348
- }
349
- totalCount
350
- hasNextPage
351
- hasPreviousPage
352
- cursor
353
- }
354
- }
355
- childIds
356
- }
357
- }
358
- ${PhDocumentFieldsFragmentDoc}
359
- `;
360
- import_main.gql`
361
- query GetDocumentOutgoingRelationships(
362
- $sourceIdentifier: String!
363
- $relationshipType: String!
364
- $view: ViewFilterInput
365
- $paging: PagingInput
366
- ) {
367
- documentOutgoingRelationships(
368
- sourceIdentifier: $sourceIdentifier
369
- relationshipType: $relationshipType
370
- view: $view
371
- paging: $paging
372
- ) {
373
- items {
374
- ...PHDocumentFields
375
- }
376
- totalCount
377
- hasNextPage
378
- hasPreviousPage
379
- cursor
380
- }
381
- }
382
- ${PhDocumentFieldsFragmentDoc}
383
- `;
384
- import_main.gql`
385
- query GetDocumentIncomingRelationships(
386
- $targetIdentifier: String!
387
- $relationshipType: String!
388
- $view: ViewFilterInput
389
- $paging: PagingInput
390
- ) {
391
- documentIncomingRelationships(
392
- targetIdentifier: $targetIdentifier
393
- relationshipType: $relationshipType
394
- view: $view
395
- paging: $paging
396
- ) {
397
- items {
398
- ...PHDocumentFields
399
- }
400
- totalCount
401
- hasNextPage
402
- hasPreviousPage
403
- cursor
404
- }
405
- }
406
- ${PhDocumentFieldsFragmentDoc}
407
- `;
408
- import_main.gql`
409
- query FindDocuments(
410
- $search: SearchFilterInput
411
- $view: ViewFilterInput
412
- $paging: PagingInput
413
- ) {
414
- findDocuments(search: $search, view: $view, paging: $paging) {
415
- items {
416
- ...PHDocumentFields
417
- }
418
- totalCount
419
- hasNextPage
420
- hasPreviousPage
421
- cursor
422
- }
423
- }
424
- ${PhDocumentFieldsFragmentDoc}
425
- `;
426
- const GetDocumentOperationsDocument = import_main.gql`
427
- query GetDocumentOperations(
428
- $filter: OperationsFilterInput!
429
- $paging: PagingInput
430
- ) {
431
- documentOperations(filter: $filter, paging: $paging) {
432
- items {
433
- index
434
- timestampUtcMs
435
- hash
436
- skip
437
- error
438
- deniedReason
439
- id
440
- action {
441
- id
442
- type
443
- timestampUtcMs
444
- input
445
- scope
446
- context {
447
- signer {
448
- user {
449
- address
450
- networkId
451
- chainId
452
- }
453
- app {
454
- name
455
- key
456
- }
457
- signatures
458
- }
459
- }
460
- }
461
- }
462
- totalCount
463
- hasNextPage
464
- hasPreviousPage
465
- cursor
466
- }
467
- }
468
- `;
469
- import_main.gql`
470
- query GetJobStatus($jobId: String!) {
471
- jobStatus(jobId: $jobId) {
472
- id
473
- status
474
- result
475
- error
476
- createdAt
477
- completedAt
478
- }
479
- }
480
- `;
481
- import_main.gql`
482
- query EvaluateActions(
483
- $documentIdentifier: String!
484
- $branch: String
485
- $candidates: [ActionCandidateInput!]!
486
- ) {
487
- evaluateActions(
488
- documentIdentifier: $documentIdentifier
489
- branch: $branch
490
- candidates: $candidates
491
- ) {
492
- evaluations {
493
- decision
494
- reason
495
- }
496
- allAllowed
497
- anyAllowed
498
- allDenied
499
- anyDenied
500
- }
501
- }
502
- `;
503
- import_main.gql`
504
- mutation CreateDocument($document: JSONObject!, $parentIdentifier: String) {
505
- createDocument(document: $document, parentIdentifier: $parentIdentifier) {
506
- ...PHDocumentFields
507
- }
508
- }
509
- ${PhDocumentFieldsFragmentDoc}
510
- `;
511
- import_main.gql`
512
- mutation CreateEmptyDocument(
513
- $documentType: String!
514
- $parentIdentifier: String
515
- ) {
516
- createEmptyDocument(
517
- documentType: $documentType
518
- parentIdentifier: $parentIdentifier
519
- ) {
520
- ...PHDocumentFields
521
- }
522
- }
523
- ${PhDocumentFieldsFragmentDoc}
524
- `;
525
- import_main.gql`
526
- mutation MutateDocument(
527
- $documentIdentifier: String!
528
- $actions: [ActionInput!]!
529
- $branch: String
530
- ) {
531
- mutateDocument: execute(
532
- documentIdentifier: $documentIdentifier
533
- actions: $actions
534
- branch: $branch
535
- ) {
536
- ...PHDocumentFields
537
- }
538
- }
539
- ${PhDocumentFieldsFragmentDoc}
540
- `;
541
- import_main.gql`
542
- mutation MutateDocumentAsync(
543
- $documentIdentifier: String!
544
- $actions: [ActionInput!]!
545
- $branch: String
546
- ) {
547
- mutateDocumentAsync: executeAsync(
548
- documentIdentifier: $documentIdentifier
549
- actions: $actions
550
- branch: $branch
551
- ) {
552
- id
553
- status
554
- result
555
- error
556
- createdAt
557
- completedAt
558
- }
559
- }
560
- `;
561
- import_main.gql`
562
- mutation RenameDocument(
563
- $documentIdentifier: String!
564
- $name: String!
565
- $branch: String
566
- ) {
567
- renameDocument(
568
- documentIdentifier: $documentIdentifier
569
- name: $name
570
- branch: $branch
571
- ) {
572
- ...PHDocumentFields
573
- }
574
- }
575
- ${PhDocumentFieldsFragmentDoc}
576
- `;
577
- import_main.gql`
578
- mutation SetPreferredEditor(
579
- $documentIdentifier: String!
580
- $preferredEditor: String
581
- $branch: String
582
- ) {
583
- setPreferredEditor(
584
- documentIdentifier: $documentIdentifier
585
- preferredEditor: $preferredEditor
586
- branch: $branch
587
- ) {
588
- ...PHDocumentFields
589
- }
590
- }
591
- ${PhDocumentFieldsFragmentDoc}
592
- `;
593
- import_main.gql`
594
- mutation AddRelationship(
595
- $sourceIdentifier: String!
596
- $targetIdentifier: String!
597
- $relationshipType: String!
598
- $branch: String
599
- ) {
600
- addRelationship(
601
- sourceIdentifier: $sourceIdentifier
602
- targetIdentifier: $targetIdentifier
603
- relationshipType: $relationshipType
604
- branch: $branch
605
- ) {
606
- ...PHDocumentFields
607
- }
608
- }
609
- ${PhDocumentFieldsFragmentDoc}
610
- `;
611
- import_main.gql`
612
- mutation RemoveRelationship(
613
- $sourceIdentifier: String!
614
- $targetIdentifier: String!
615
- $relationshipType: String!
616
- $branch: String
617
- ) {
618
- removeRelationship(
619
- sourceIdentifier: $sourceIdentifier
620
- targetIdentifier: $targetIdentifier
621
- relationshipType: $relationshipType
622
- branch: $branch
623
- ) {
624
- ...PHDocumentFields
625
- }
626
- }
627
- ${PhDocumentFieldsFragmentDoc}
628
- `;
629
- import_main.gql`
630
- mutation MoveRelationship(
631
- $sourceParentIdentifier: String!
632
- $targetParentIdentifier: String!
633
- $targetIdentifier: String!
634
- $relationshipType: String!
635
- $branch: String
636
- ) {
637
- moveRelationship(
638
- sourceParentIdentifier: $sourceParentIdentifier
639
- targetParentIdentifier: $targetParentIdentifier
640
- targetIdentifier: $targetIdentifier
641
- relationshipType: $relationshipType
642
- branch: $branch
643
- ) {
644
- source {
645
- ...PHDocumentFields
646
- }
647
- target {
648
- ...PHDocumentFields
649
- }
650
- }
651
- }
652
- ${PhDocumentFieldsFragmentDoc}
653
- `;
654
- import_main.gql`
655
- mutation DeleteDocument($identifier: String!, $propagate: PropagationMode) {
656
- deleteDocument(identifier: $identifier, propagate: $propagate)
657
- }
658
- `;
659
- import_main.gql`
660
- mutation DeleteDocuments(
661
- $identifiers: [String!]!
662
- $propagate: PropagationMode
663
- ) {
664
- deleteDocuments(identifiers: $identifiers, propagate: $propagate)
665
- }
666
- `;
667
- import_main.gql`
668
- subscription DocumentChanges(
669
- $search: SearchFilterInput
670
- $view: ViewFilterInput
671
- ) {
672
- documentChanges(search: $search, view: $view) {
673
- type
674
- documents {
675
- ...PHDocumentFields
676
- }
677
- context {
678
- parentId
679
- childId
680
- }
681
- }
682
- }
683
- ${PhDocumentFieldsFragmentDoc}
684
- `;
685
- import_main.gql`
686
- subscription JobChanges($jobId: String!) {
687
- jobChanges(jobId: $jobId) {
688
- jobId
689
- status
690
- result
691
- error
692
- }
693
- }
694
- `;
695
- import_main.gql`
696
- query PollSyncEnvelopes(
697
- $channelId: String!
698
- $outboxAck: Int!
699
- $outboxLatest: Int!
700
- ) {
701
- pollSyncEnvelopes(
702
- channelId: $channelId
703
- outboxAck: $outboxAck
704
- outboxLatest: $outboxLatest
705
- ) {
706
- envelopes {
707
- type
708
- channelMeta {
709
- id
710
- }
711
- operations {
712
- operation {
713
- index
714
- timestampUtcMs
715
- hash
716
- skip
717
- error
718
- deniedReason
719
- id
720
- action {
721
- id
722
- type
723
- timestampUtcMs
724
- input
725
- scope
726
- context {
727
- signer {
728
- user {
729
- address
730
- networkId
731
- chainId
732
- }
733
- app {
734
- name
735
- key
736
- }
737
- signatures
738
- }
739
- }
740
- }
741
- }
742
- context {
743
- documentId
744
- documentType
745
- scope
746
- branch
747
- }
748
- }
749
- cursor {
750
- remoteName
751
- cursorOrdinal
752
- lastSyncedAtUtcMs
753
- }
754
- key
755
- dependsOn
756
- }
757
- ackOrdinal
758
- deadLetters {
759
- documentId
760
- error
761
- errorType
762
- }
763
- hasMore
764
- }
765
- }
766
- `;
767
- import_main.gql`
768
- mutation TouchChannel($input: TouchChannelInput!) {
769
- touchChannel(input: $input) {
770
- success
771
- ackOrdinal
772
- }
773
- }
774
- `;
775
- import_main.gql`
776
- mutation PushSyncEnvelopes($envelopes: [SyncEnvelopeInput!]!) {
777
- pushSyncEnvelopes(envelopes: $envelopes)
778
- }
779
- `;
780
- /** Get the source string from a GraphQL document (string or DocumentNode). */
781
- function getDocumentSource(doc) {
782
- return typeof doc === "string" ? doc : doc.loc?.source.body ?? "";
783
- }
784
- /**
785
- * Extract the inner selection set of a named field from a GraphQL document source.
786
- * Returns the `{ ... }` block including braces.
787
- */
788
- function extractSelectionSet(doc, fieldName, fallback) {
789
- const source = getDocumentSource(doc);
790
- return new RegExp(`${fieldName}\\([^)]*\\)\\s*(\\{[\\s\\S]*\\})\\s*\\}`).exec(source)?.[1] ?? fallback;
791
- }
792
- /**
793
- * Extract the query body and any fragment definitions from a GraphQL document.
794
- * Returns { body, fragments } where body is the content inside the query `{ ... }`
795
- * and fragments are any trailing fragment definitions.
796
- */
797
- function extractQueryParts(doc, fallbackBody) {
798
- const source = getDocumentSource(doc);
799
- const queryMatch = /^[^{]*\{([\s\S]*?)\}\s*(fragment[\s\S]*)?$/.exec(source);
800
- return {
801
- body: queryMatch?.[1]?.trim() ?? fallbackBody,
802
- fragments: queryMatch?.[2]?.trim() ?? ""
803
- };
804
- }
805
- extractSelectionSet(GetDocumentOperationsDocument, "documentOperations", "{ items { index } }");
806
- extractQueryParts(GetDocumentDocument, "document(identifier: $identifier) { document { id name documentType state revisionsList { scope revision } createdAtUtcIso lastModifiedAtUtcIso } childIds }");
807
- //#endregion
808
- //#region ../reactor-browser/dist/renown-6w_ImTvm.js
809
- const { useValue: useLoading, setValue: setLoading, addEventHandler: addLoadingEventHandler } = makePHEventFunctions("loading");
810
- const RenownInitialUserContext = createContext({ state: "unknown" });
811
- /** First-render auth as a three-state value; use this to skip a spinner when anonymous. */
812
- function useRenownInitialAuth() {
813
- return useContext(RenownInitialUserContext);
814
- }
815
- function useRenownInitialUser() {
816
- const initial = useRenownInitialAuth();
817
- return initial.state === "authenticated" ? initial.user : void 0;
818
- }
819
- const renownEventFunctions = makePHEventFunctions("renown");
820
- renownEventFunctions.addEventHandler;
821
- /** Returns the renown instance */
822
- const useRenown = renownEventFunctions.useValue;
823
- renownEventFunctions.setValue;
824
- function jsonEqual(a, b) {
825
- if (a === b) return true;
826
- if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
827
- if (Array.isArray(a) !== Array.isArray(b)) return false;
828
- const ra = a;
829
- const rb = b;
830
- const keys = Object.keys(ra).filter((k) => ra[k] !== void 0);
831
- if (keys.length !== Object.keys(rb).filter((k) => rb[k] !== void 0).length) return false;
832
- return keys.every((k) => jsonEqual(ra[k], rb[k]));
833
- }
834
- function sameUser(a, b) {
835
- return jsonEqual(a, b);
836
- }
837
- function resolveInstanceUser(instance, seed) {
838
- const restored = instance.user;
839
- if (restored) return sameUser(seed, restored) ? seed : restored;
840
- return instance.status === "initial" ? void 0 : seed;
841
- }
842
- /** Returns the current user from the renown instance, subscribing to user events */
843
- function useUser() {
844
- const renown = useRenown();
845
- const initialUser = useRenownInitialUser();
846
- const instance = renown ? renown : void 0;
847
- const [tracked, setTracked] = useState(() => ({
848
- instance,
849
- user: instance ? resolveInstanceUser(instance, initialUser) : initialUser
850
- }));
851
- const current = tracked.instance === instance ? tracked : {
852
- instance,
853
- user: instance ? resolveInstanceUser(instance, tracked.user ?? initialUser) : tracked.user
854
- };
855
- useEffect(() => {
856
- if (current !== tracked) setTracked(current);
857
- }, [current, tracked]);
858
- useEffect(() => {
859
- if (!instance) return;
860
- return instance.on("user", (user) => setTracked((prev) => ({
861
- instance,
862
- user: sameUser(prev.user, user) ? prev.user : user
863
- })));
864
- }, [instance]);
865
- return instance ? current.user : initialUser ?? current.user;
866
- }
867
- //#endregion
868
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/lazyDataLastImpl-DtF3cihj.js
869
- function e$8(e, t, n) {
870
- let r = (n) => e(n, ...t);
871
- return n === void 0 ? r : Object.assign(r, {
872
- lazy: n,
873
- lazyArgs: t
874
- });
875
- }
876
- //#endregion
877
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/purry.js
878
- function t$5(t, n, r) {
879
- let i = t.length - n.length;
880
- if (i === 0) return t(...n);
881
- if (i === 1) return e$8(t, n, r);
882
- throw Error(`Wrong number of arguments`);
883
- }
884
- //#endregion
885
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/allPass.js
886
- function t$4(...t) {
887
- return t$5(n$4, t);
888
- }
889
- const n$4 = (e, t) => t.every((t) => t(e));
890
- //#endregion
891
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/conditional-CTEJD5TX.js
892
- function e$7(e, t, n) {
893
- return e(n[0]) ? (e) => t(e, ...n) : t(...n);
894
- }
895
- function t$3(...t) {
896
- return e$7(r, n$3, t);
897
- }
898
- function n$3(e, ...t) {
899
- for (let n of t) {
900
- if (typeof n == `function`) return n(e);
901
- let [t, r] = n;
902
- if (t(e)) return r(e);
903
- }
904
- throw Error(`conditional: data failed for all cases`);
905
- }
906
- function r(e) {
907
- if (!Array.isArray(e)) return !1;
908
- let [t, n, ...r] = e;
909
- return typeof t == `function` && t.length <= 1 && typeof n == `function` && n.length <= 1 && r.length === 0;
910
- }
911
- //#endregion
912
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/constant.js
913
- function e$6(e) {
914
- return () => e;
915
- }
916
- //#endregion
917
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/hasAtLeast.js
918
- function t$2(...t) {
919
- return t$5(n$2, t);
920
- }
921
- const n$2 = (e, t) => e.length >= t;
922
- //#endregion
923
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/funnel.js
924
- const e$5 = Symbol(`funnel/voidReducer`), t$1 = () => e$5;
925
- function n$1(n, { triggerAt: r = `end`, minQuietPeriodMs: i, maxBurstDurationMs: a, minGapMs: o, reducer: s = t$1 }) {
926
- let c, l, u, d, f = () => {
927
- let t = u;
928
- t !== void 0 && (u = void 0, t === e$5 ? n() : n(t), o !== void 0 && (l = setTimeout(p, o)));
929
- }, p = () => {
930
- clearTimeout(l), l = void 0, c === void 0 && f();
931
- }, m = () => {
932
- clearTimeout(c), c = void 0, d = void 0, l === void 0 && f();
933
- };
934
- return {
935
- call: (...e) => {
936
- let t = c === void 0 && l === void 0;
937
- if ((r !== `start` || t) && (u = s(u, ...e)), !(c === void 0 && !t)) {
938
- if (i !== void 0 || a !== void 0 || o === void 0) {
939
- clearTimeout(c);
940
- let e = Date.now();
941
- d ??= e;
942
- let t = a === void 0 ? i ?? 0 : Math.min(i ?? a, Math.max(0, a - (e - d)));
943
- c = setTimeout(m, t);
944
- }
945
- r !== `end` && t && f();
946
- }
947
- },
948
- cancel: () => {
949
- clearTimeout(c), c = void 0, d = void 0, clearTimeout(l), l = void 0, u = void 0;
950
- },
951
- flush: () => {
952
- m(), p();
953
- },
954
- get isIdle() {
955
- return c === void 0 && l === void 0;
956
- }
957
- };
958
- }
959
- //#endregion
960
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isDefined.js
961
- function e$4(e) {
962
- return e !== void 0;
963
- }
964
- //#endregion
965
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isNot.js
966
- function e$3(e) {
967
- return (t) => !e(t);
968
- }
969
- //#endregion
970
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isStrictEqual.js
971
- function t(...t) {
972
- return t$5(n, t);
973
- }
974
- const n = (e, t) => e === t || Object.is(e, t);
975
- //#endregion
976
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isString.js
977
- function e$2(e) {
978
- return typeof e == `string`;
979
- }
980
- //#endregion
981
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isTruthy.js
982
- function e$1(e) {
983
- return !!e;
984
- }
985
- //#endregion
986
- //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/once.js
987
- function e(e) {
988
- let t = !1, n;
989
- return () => (t ||= (n = e(), !0), n);
990
- }
991
- var CloseCode = /* @__PURE__ */ ((CloseCode2) => {
992
- CloseCode2[CloseCode2["InternalServerError"] = 4500] = "InternalServerError";
993
- CloseCode2[CloseCode2["InternalClientError"] = 4005] = "InternalClientError";
994
- CloseCode2[CloseCode2["BadRequest"] = 4400] = "BadRequest";
995
- CloseCode2[CloseCode2["BadResponse"] = 4004] = "BadResponse";
996
- CloseCode2[CloseCode2["Unauthorized"] = 4401] = "Unauthorized";
997
- CloseCode2[CloseCode2["Forbidden"] = 4403] = "Forbidden";
998
- CloseCode2[CloseCode2["SubprotocolNotAcceptable"] = 4406] = "SubprotocolNotAcceptable";
999
- CloseCode2[CloseCode2["ConnectionInitialisationTimeout"] = 4408] = "ConnectionInitialisationTimeout";
1000
- CloseCode2[CloseCode2["ConnectionAcknowledgementTimeout"] = 4504] = "ConnectionAcknowledgementTimeout";
1001
- CloseCode2[CloseCode2["SubscriberAlreadyExists"] = 4409] = "SubscriberAlreadyExists";
1002
- CloseCode2[CloseCode2["TooManyInitialisationRequests"] = 4429] = "TooManyInitialisationRequests";
1003
- return CloseCode2;
1004
- })(CloseCode || {});
1005
- var MessageType = /* @__PURE__ */ ((MessageType2) => {
1006
- MessageType2["ConnectionInit"] = "connection_init";
1007
- MessageType2["ConnectionAck"] = "connection_ack";
1008
- MessageType2["Ping"] = "ping";
1009
- MessageType2["Pong"] = "pong";
1010
- MessageType2["Subscribe"] = "subscribe";
1011
- MessageType2["Next"] = "next";
1012
- MessageType2["Error"] = "error";
1013
- MessageType2["Complete"] = "complete";
1014
- return MessageType2;
1015
- })(MessageType || {});
1016
- Error;
1017
244
  //#endregion
1018
245
  //#region ../../node_modules/.pnpm/slug@11.0.1/node_modules/slug/slug.js
1019
246
  let base64;
@@ -1801,7 +1028,7 @@ slug.setLocale = function(locale) {
1801
1028
  defaultLocale = locales[locale] || {};
1802
1029
  };
1803
1030
  //#endregion
1804
- //#region ../reactor-browser/dist/document-operations-DZ-oUHRy.js
1031
+ //#region ../reactor-browser/dist/document-model-modules-BB9s6a3m.js
1805
1032
  var UnsupportedDocumentTypeError = class extends Error {
1806
1033
  constructor(documentType) {
1807
1034
  super(`Document type ${documentType} is not supported`);
@@ -1832,1082 +1059,1923 @@ var NoSelectedDocumentError = class extends Error {
1832
1059
  super("There is no selected document. Did you mean to call 'useSelectedDocumentSafe' instead?");
1833
1060
  }
1834
1061
  };
1835
- const modalEventFunctions = makePHEventFunctions("modal");
1836
- modalEventFunctions.useValue;
1837
- /** Sets the current modal */
1838
- const setPHModal = modalEventFunctions.setValue;
1839
- modalEventFunctions.addEventHandler;
1840
- /** Shows a modal */
1841
- function showPHModal(modal) {
1842
- setPHModal(modal);
1062
+ function resolveUrlPathname(path) {
1063
+ return new URL(path.replace(/^\/+/, ""), window.location.origin + (window.ph?.basePath ?? "/")).pathname;
1843
1064
  }
1844
- /** Shows the delete node modal */
1845
- function showDeleteNodeModal(nodeOrId) {
1846
- setPHModal({
1847
- type: "deleteItem",
1848
- id: typeof nodeOrId === "string" ? nodeOrId : nodeOrId.id
1849
- });
1065
+ /** Returns the current path without the base path */
1066
+ function getPathWithoutBase(path) {
1067
+ const basePath = window.ph?.basePath ?? "/";
1068
+ return path.replace(basePath, basePath.endsWith("/") ? "/" : "");
1850
1069
  }
1851
- function isDocumentTypeSupported(documentType, supportedDocuments) {
1852
- if (!supportedDocuments?.length) return true;
1853
- return supportedDocuments.some((pattern) => {
1854
- if (pattern.endsWith("/*")) {
1855
- const prefix = pattern.slice(0, -2);
1856
- return documentType.startsWith(prefix + "/");
1857
- }
1858
- if (pattern.endsWith("*") && !pattern.endsWith("/*")) {
1859
- const prefix = pattern.slice(0, -1);
1860
- return documentType.startsWith(prefix);
1070
+ /** Makes a URL component for a node. */
1071
+ function makeNodeSlug(node) {
1072
+ if (!node) return "";
1073
+ const nodeName = node.name;
1074
+ if (!nodeName) return slug(node.id);
1075
+ return slug(`${nodeName}-${node.id}`);
1076
+ }
1077
+ /** Extracts the node slug from a path.
1078
+ *
1079
+ * The path is expected to be in the format `/d/<drive-slug>/<node-slug>`.
1080
+ */
1081
+ function extractNodeSlugFromPath(path) {
1082
+ const currentPath = getPathWithoutBase(path);
1083
+ return /^\/d\/[^/]+\/([^/]+)$/.exec(currentPath)?.[1];
1084
+ }
1085
+ /** Finds a UUID in a string, used for extracting node ids from node slugs in the URL. */
1086
+ function findUuid(input) {
1087
+ if (!input) return void 0;
1088
+ return /\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/.exec(input)?.[0];
1089
+ }
1090
+ function extractNodeIdFromSlug(nodeSlug) {
1091
+ return findUuid(nodeSlug);
1092
+ }
1093
+ /** Extracts the drive slug from a path.
1094
+ * Used for extracting drive ids from drive slugs in the URL.
1095
+ * Expects the path to be in the format `/d/<drive-slug>`.
1096
+ */
1097
+ function extractDriveSlugFromPath(path) {
1098
+ const currentPath = getPathWithoutBase(path);
1099
+ return /^\/d\/([^/]+)/.exec(currentPath)?.[1] ?? "";
1100
+ }
1101
+ /**
1102
+ * Creates a URL string with the given pathname while preserving existing query parameters.
1103
+ */
1104
+ function createUrlWithPreservedParams(pathname) {
1105
+ const search = window.location.search;
1106
+ return search ? `${pathname}${search}` : pathname;
1107
+ }
1108
+ const drivesEventFunctions = makePHEventFunctions("drives");
1109
+ /** Returns all of the drives in the reactor */
1110
+ const useDrives = drivesEventFunctions.useValue;
1111
+ /** Sets the drives in the reactor */
1112
+ const setDrives = drivesEventFunctions.setValue;
1113
+ drivesEventFunctions.addEventHandler;
1114
+ const selectedNodeIdEventFunctions = makePHEventFunctions("selectedNodeId");
1115
+ const useSelectedNodeId = selectedNodeIdEventFunctions.useValue;
1116
+ const setSelectedNodeId = selectedNodeIdEventFunctions.setValue;
1117
+ selectedNodeIdEventFunctions.addEventHandler;
1118
+ /** Sets the selected node (file or folder). */
1119
+ function setSelectedNode(nodeOrNodeSlug) {
1120
+ const nodeSlug = typeof nodeOrNodeSlug === "string" ? nodeOrNodeSlug : makeNodeSlug(nodeOrNodeSlug);
1121
+ setSelectedNodeId(extractNodeIdFromSlug(nodeSlug));
1122
+ const driveSlugFromPath = extractDriveSlugFromPath(window.location.pathname);
1123
+ if (!driveSlugFromPath) return;
1124
+ if (!nodeSlug) {
1125
+ const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}`);
1126
+ if (pathname === window.location.pathname) return;
1127
+ window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
1128
+ return;
1129
+ }
1130
+ const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}/${nodeSlug}`);
1131
+ if (pathname === window.location.pathname) return;
1132
+ window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
1133
+ }
1134
+ const selectedDriveIdEventFunctions = makePHEventFunctions("selectedDriveId");
1135
+ /** Returns the selected drive id */
1136
+ const useSelectedDriveId = selectedDriveIdEventFunctions.useValue;
1137
+ /** Sets the selected drive id */
1138
+ const setSelectedDriveId = selectedDriveIdEventFunctions.setValue;
1139
+ selectedDriveIdEventFunctions.addEventHandler;
1140
+ /** Returns the selected drive, or undefined if no drive is selected */
1141
+ function useSelectedDriveSafe() {
1142
+ const selectedDriveId = useSelectedDriveId();
1143
+ const selectedDrive = useDrives()?.find((drive) => drive.header.id === selectedDriveId);
1144
+ const [drive, dispatch] = useDispatch(selectedDrive);
1145
+ if (!selectedDrive) return [void 0, void 0];
1146
+ return [drive, dispatch];
1147
+ }
1148
+ function setSelectedDrive(driveOrDriveSlug) {
1149
+ const driveSlug = typeof driveOrDriveSlug === "string" ? driveOrDriveSlug : driveOrDriveSlug?.header.slug;
1150
+ const drives = window.ph?.drives;
1151
+ const driveId = (typeof driveOrDriveSlug === "object" && driveOrDriveSlug !== null ? driveOrDriveSlug : drives?.find((d) => d.header.slug === driveSlug))?.header.id;
1152
+ if (!driveId && driveSlug && extractDriveSlugFromPath(window.location.pathname) === driveSlug) {
1153
+ if (window.ph?.selectedDriveId) setSelectedDriveId(void 0);
1154
+ deferDriveSelection(driveSlug);
1155
+ return;
1156
+ }
1157
+ cancelPendingDriveSelection();
1158
+ setSelectedDriveId(driveId);
1159
+ if (!driveId) {
1160
+ const pathname = resolveUrlPathname("/");
1161
+ if (pathname === window.location.pathname) return;
1162
+ window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
1163
+ return;
1164
+ }
1165
+ const pathname = resolveUrlPathname(`/d/${driveSlug}`);
1166
+ if (pathname === window.location.pathname) return;
1167
+ window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
1168
+ }
1169
+ const DEFERRED_DRIVE_TICK_MS = 2e3;
1170
+ const DEFERRED_DRIVE_MAX_WAIT_MS = 15e3;
1171
+ function isInitialSyncInFlight() {
1172
+ const remotes = window.ph?.reactorClientModule?.reactorModule?.syncModule?.syncManager?.list();
1173
+ if (!remotes?.length) return false;
1174
+ return remotes.some((remote) => {
1175
+ try {
1176
+ const snapshot = remote.channel.getConnectionState();
1177
+ return snapshot.receivingPages || !snapshot.lastSuccessUtcMs && snapshot.state !== "error";
1178
+ } catch {
1179
+ return false;
1861
1180
  }
1862
- return pattern === documentType;
1863
1181
  });
1864
1182
  }
1865
- function getUserPermissions() {
1866
- const user = window.ph?.renown?.user;
1867
- const allowList = window.ph?.allowList;
1868
- if (!allowList) return {
1869
- isAllowedToCreateDocuments: true,
1870
- isAllowedToEditDocuments: true
1871
- };
1872
- return {
1873
- isAllowedToCreateDocuments: allowList.includes(user?.address ?? ""),
1874
- isAllowedToEditDocuments: allowList.includes(user?.address ?? "")
1875
- };
1183
+ let pendingHandler;
1184
+ let pendingTimeout;
1185
+ function cancelPendingDriveSelection() {
1186
+ if (pendingHandler) {
1187
+ window.removeEventListener("ph:drivesUpdated", pendingHandler);
1188
+ pendingHandler = void 0;
1189
+ }
1190
+ if (pendingTimeout) {
1191
+ clearTimeout(pendingTimeout);
1192
+ pendingTimeout = void 0;
1193
+ }
1876
1194
  }
1877
- const NON_DOMAIN_SCOPES = new Set(["auth", "document"]);
1878
- /** An unreadable drive cannot be shown to hold no duplicate, so reads throw. */
1879
- async function isDocumentInLocation(reactorClient, document, driveId, parentFolder) {
1880
- const drive = await reactorClient.get(driveId);
1881
- const nodeById = drive.state.global.nodes.find((node) => node.id === document.header.id);
1882
- if (nodeById && nodeById.parentFolder === (parentFolder ?? null)) return {
1883
- isDuplicate: true,
1884
- duplicateType: "id",
1885
- nodeId: nodeById.id
1195
+ function deferDriveSelection(driveSlug) {
1196
+ cancelPendingDriveSelection();
1197
+ const nodeSlug = extractNodeSlugFromPath(window.location.pathname);
1198
+ const handler = () => {
1199
+ if (!window.ph?.drives?.find((d) => d.header.slug === driveSlug)) return;
1200
+ cancelPendingDriveSelection();
1201
+ setSelectedDrive(driveSlug);
1202
+ setSelectedNode(nodeSlug);
1886
1203
  };
1887
- const nodeByNameAndType = drive.state.global.nodes.find((node) => isFileNode(node) && node.name === document.header.name && node.documentType === document.header.documentType && node.parentFolder === (parentFolder ?? null));
1888
- if (nodeByNameAndType) return {
1889
- isDuplicate: true,
1890
- duplicateType: "name",
1891
- nodeId: nodeByNameAndType.id
1204
+ pendingHandler = handler;
1205
+ window.addEventListener("ph:drivesUpdated", handler);
1206
+ const deadline = Date.now() + DEFERRED_DRIVE_MAX_WAIT_MS;
1207
+ const scheduleTick = () => {
1208
+ pendingTimeout = setTimeout(() => {
1209
+ if (Date.now() < deadline && isInitialSyncInFlight()) {
1210
+ scheduleTick();
1211
+ return;
1212
+ }
1213
+ cancelPendingDriveSelection();
1214
+ const pathname = resolveUrlPathname("/");
1215
+ if (pathname === window.location.pathname) return;
1216
+ window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
1217
+ }, DEFERRED_DRIVE_TICK_MS);
1892
1218
  };
1893
- return { isDuplicate: false };
1219
+ scheduleTick();
1894
1220
  }
1895
- function getDocumentTypeIcon(document) {
1896
- switch (document.header.documentType) {
1897
- case "powerhouse/document-model": return "document-model";
1898
- case "powerhouse/app": return "app";
1899
- case "powerhouse/document-editor": return "editor";
1900
- case "powerhouse/subgraph": return "subgraph";
1901
- case "powerhouse/package": return "package";
1902
- case "powerhouse/processor": {
1903
- const processorType = document.state.global?.type;
1904
- if (processorType === "analytics") return "analytics-processor";
1905
- if (processorType === "relational") return "relational-processor";
1906
- if (processorType === "codegen") return "codegen-processor";
1907
- return;
1908
- }
1909
- default: return;
1910
- }
1221
+ /** Sorts nodes by name. */
1222
+ function sortNodesByName(nodes) {
1223
+ return nodes.toSorted((a, b) => a.name.localeCompare(b.name));
1911
1224
  }
1912
- async function downloadFile(document, fileName) {
1913
- try {
1914
- const data = await createZip(document);
1915
- const blob = new Blob([new Uint8Array(data)], { type: "application/zip" });
1916
- const link = window.document.createElement("a");
1917
- link.style.display = "none";
1918
- link.href = URL.createObjectURL(blob);
1919
- link.download = fileName;
1920
- window.document.body.appendChild(link);
1921
- link.click();
1922
- window.document.body.removeChild(link);
1923
- } catch (e) {
1924
- logger.error(e instanceof Error ? e.message : String(e));
1925
- }
1225
+ /** Returns whether a node is a file. */
1226
+ function isFileNodeKind(node) {
1227
+ if (!node) return false;
1228
+ return node.kind.toUpperCase() === "FILE";
1926
1229
  }
1927
- async function getDocumentExtension(document) {
1928
- const documentType = document.header.documentType;
1929
- let rawExtension;
1930
- if (documentType === "powerhouse/document-model") rawExtension = document.state.global?.extension;
1931
- else {
1932
- const reactorClient = window.ph?.reactorClientModule?.client;
1933
- if (reactorClient) {
1934
- const { results: documentModelModules } = await reactorClient.getDocumentModelModules();
1935
- rawExtension = documentModelModules.find((m) => m.documentModel.global.id === documentType)?.utils.fileExtension;
1936
- }
1937
- }
1938
- return (rawExtension ?? "").replace(/^\.+|\.+$/g, "");
1230
+ /** Returns whether a node is a folder. */
1231
+ function isFolderNodeKind(node) {
1232
+ if (!node) return false;
1233
+ return node.kind.toUpperCase() === "FOLDER";
1939
1234
  }
1940
- /**
1941
- * Fetches all operations for a document using cursor-based pagination.
1942
- * The reactor client handles multi-scope cursors transparently via
1943
- * composite cursors, so all scopes are fetched in a single paginated stream.
1944
- */
1945
- async function fetchDocumentOperations(reactorClient, document, pageSize = 100) {
1946
- const scopes = Object.keys(document.state);
1947
- const operations = {};
1948
- for (const scope of scopes) operations[scope] = [];
1949
- let cursor = "";
1950
- do {
1951
- const page = await reactorClient.getOperations(document.header.id, { scopes }, void 0, {
1952
- cursor,
1953
- limit: pageSize
1954
- });
1955
- for (const op of page.results) {
1956
- const scope = op.action.scope ?? "global";
1957
- if (operations[scope]) operations[scope].push(op);
1958
- }
1959
- cursor = page.nextCursor ?? "";
1960
- } while (cursor);
1961
- return operations;
1235
+ /** Returns the nodes in the selected drive. */
1236
+ function useNodesInSelectedDrive() {
1237
+ const [selectedDrive] = useSelectedDriveSafe();
1238
+ return selectedDrive?.state.global.nodes;
1962
1239
  }
1963
- function extractInitialState(documentScopeOps) {
1964
- const upgradeOp = documentScopeOps.find((op) => op.action.type === "UPGRADE_DOCUMENT");
1965
- if (!upgradeOp) throw new Error("No UPGRADE_DOCUMENT operation found — document is invalid");
1966
- const input = upgradeOp.action.input;
1967
- const initialState = input.initialState ?? input.state;
1968
- if (!initialState) throw new Error("UPGRADE_DOCUMENT operation has no initialState — document is invalid");
1969
- return initialState;
1240
+ /** Returns the folder nodes in the selected drive. */
1241
+ function useFolderNodesInSelectedDrive() {
1242
+ return useNodesInSelectedDrive()?.filter((n) => isFolderNodeKind(n));
1970
1243
  }
1971
- function filterDomainOperations(operations) {
1972
- return Object.fromEntries(Object.entries(operations).filter(([scope]) => !NON_DOMAIN_SCOPES.has(scope)));
1244
+ /** Returns the selected node. */
1245
+ function useSelectedNode() {
1246
+ const selectedNodeId = useSelectedNodeId();
1247
+ return useNodesInSelectedDrive()?.find((n) => n.id === selectedNodeId);
1973
1248
  }
1974
- function countOperations(operations) {
1975
- let total = 0;
1976
- for (const ops of Object.values(operations)) total += ops?.length ?? 0;
1977
- return total;
1249
+ const vetraPackageManagerFunctions = makePHEventFunctions("vetraPackageManager");
1250
+ const useVetraPackageManager = vetraPackageManagerFunctions.useValue;
1251
+ /** Returns all of the Vetra packages loaded by the Connect instance */
1252
+ const useVetraPackages = () => {
1253
+ const packageManager = useVetraPackageManager();
1254
+ return useSyncExternalStore((cb) => packageManager ? packageManager.subscribe(cb) : () => {}, () => packageManager?.packages ?? []);
1255
+ };
1256
+ vetraPackageManagerFunctions.addEventHandler;
1257
+ function useDocumentModelModules() {
1258
+ return useVetraPackages().flatMap((pkg) => pkg.documentModels).filter((module, index, modules) => modules.findIndex((m) => m.documentModel.global.id === module.documentModel.global.id && m.version === module.version) === index);
1978
1259
  }
1979
1260
  /**
1980
- * Split an imported document's domain operations at its mid-history upgrade
1981
- * boundaries, so the caller can re-dispatch each upgrade between segments.
1982
- *
1983
- * The seed's CREATE_DOCUMENT and 0 -> N upgrade are replayed by the creation
1984
- * path and must not be repeated. A later upgrade must be: it is where the
1985
- * reducer version changes, and dropping it replays everything after it through
1986
- * the module the document was created with.
1261
+ * Resolves a document model module by document type, mirroring the registry's
1262
+ * semantics (`IDocumentModelRegistry.getModule`): with `version` omitted the
1263
+ * LATEST version of the type wins (`version ?? 1` as each module's default),
1264
+ * with `version` given only an exact match is returned. The reactor resolves
1265
+ * modules the same way when a document is created, so metadata read through
1266
+ * this hook and the version a creation actually uses cannot disagree.
1987
1267
  */
1988
- function splitAtUpgradeBoundaries(operations) {
1989
- const upgrades = (operations.document ?? []).filter((op) => op.action.type === "UPGRADE_DOCUMENT").filter((op) => op.action.input.fromVersion > 0).sort((a, b) => a.index - b.index);
1990
- const domain = filterDomainOperations(operations);
1991
- if (upgrades.length === 0) return [{ operations: domain }];
1992
- const segments = [];
1993
- const consumed = /* @__PURE__ */ new Map();
1994
- const take = (until) => {
1995
- const slice = {};
1996
- for (const [scope, ops] of Object.entries(domain)) {
1997
- if (!ops) continue;
1998
- const from = consumed.get(scope) ?? 0;
1999
- const stop = Math.max(from, until(scope, ops));
2000
- const chunk = ops.slice(from, stop);
2001
- if (chunk.length > 0) slice[scope] = chunk;
2002
- consumed.set(scope, stop);
1268
+ function useDocumentModelModuleById(id, version) {
1269
+ const documentModelModules = useDocumentModelModules();
1270
+ if (!id || !documentModelModules) return void 0;
1271
+ let latestModule;
1272
+ let latestVersion = -1;
1273
+ for (const module of documentModelModules) {
1274
+ if (module.documentModel.global.id !== id) continue;
1275
+ const moduleVersion = module.version ?? 1;
1276
+ if (version !== void 0) {
1277
+ if (moduleVersion === version) return module;
1278
+ continue;
1279
+ }
1280
+ if (moduleVersion > latestVersion) {
1281
+ latestVersion = moduleVersion;
1282
+ latestModule = module;
2003
1283
  }
2004
- return slice;
2005
- };
2006
- for (const upgrade of upgrades) {
2007
- const input = upgrade.action.input;
2008
- const slice = take((scope, ops) => boundary(upgrade, scope, ops));
2009
- segments.push({
2010
- operations: slice,
2011
- upgradeTo: input.toVersion
2012
- });
2013
- }
2014
- const tail = take((_scope, ops) => ops.length);
2015
- if (countOperations(tail) > 0) segments.push({ operations: tail });
2016
- return segments;
2017
- }
2018
- /**
2019
- * How many of a scope's operations precede an upgrade. Must stay identical to
2020
- * the boundary computation in `replayDocumentVersioned` — snapshots compare
2021
- * against operation indices, not array positions, and the timestamp fallback
2022
- * excludes the upgrade's own instant.
2023
- */
2024
- function boundary(upgrade, scope, ops) {
2025
- const snapshot = upgrade.action.input.revision;
2026
- if (snapshot !== void 0) {
2027
- const revision = snapshot[scope] ?? 0;
2028
- let count = 0;
2029
- for (let i = 0; i < ops.length; i++) if (ops[i].index < revision) count = i + 1;
2030
- return count;
2031
1284
  }
2032
- for (let i = 0; i < ops.length; i++) if (ops[i].timestampUtcMs >= upgrade.timestampUtcMs) return i;
2033
- return ops.length;
1285
+ return latestModule;
2034
1286
  }
2035
- async function exportFile(document, suggestedName) {
2036
- const reactorClient = window.ph?.reactorClient;
2037
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2038
- const operations = await fetchDocumentOperations(reactorClient, document);
2039
- const initialState = extractInitialState(operations["document"] ?? []);
2040
- const documentWithOps = {
2041
- ...document,
2042
- operations,
2043
- initialState
2044
- };
2045
- const extension = await getDocumentExtension(documentWithOps);
2046
- const baseName = suggestedName || documentWithOps.header.name || "Untitled";
2047
- const name = extension ? `${baseName}.${extension}.phd` : `${baseName}.phd`;
2048
- if (!window.showSaveFilePicker) return await downloadFile(documentWithOps, name);
2049
- try {
2050
- const fileHandle = await window.showSaveFilePicker({ suggestedName: name });
2051
- await baseSaveToFileHandle(documentWithOps, fileHandle);
2052
- return fileHandle;
2053
- } catch (e) {
2054
- if (!(e instanceof DOMException && e.name === "AbortError")) throw e;
2055
- }
1287
+ Error;
1288
+ require_graphql();
1289
+ JSON;
1290
+ //#endregion
1291
+ //#region ../reactor-browser/dist/client-D66jVnot.js
1292
+ var import_main = require_main();
1293
+ let DocumentChangeType = /* @__PURE__ */ function(DocumentChangeType) {
1294
+ DocumentChangeType["ChildAdded"] = "CHILD_ADDED";
1295
+ DocumentChangeType["ChildRemoved"] = "CHILD_REMOVED";
1296
+ DocumentChangeType["Created"] = "CREATED";
1297
+ DocumentChangeType["Deleted"] = "DELETED";
1298
+ DocumentChangeType["ParentAdded"] = "PARENT_ADDED";
1299
+ DocumentChangeType["ParentRemoved"] = "PARENT_REMOVED";
1300
+ DocumentChangeType["Updated"] = "UPDATED";
1301
+ return DocumentChangeType;
1302
+ }({});
1303
+ let PropagationMode = /* @__PURE__ */ function(PropagationMode) {
1304
+ PropagationMode["Cascade"] = "CASCADE";
1305
+ PropagationMode["Orphan"] = "ORPHAN";
1306
+ return PropagationMode;
1307
+ }({});
1308
+ const PhDocumentFieldsFragmentDoc = import_main.gql`
1309
+ fragment PHDocumentFields on PHDocument {
1310
+ id
1311
+ slug
1312
+ name
1313
+ documentType
1314
+ state
1315
+ revisionsList {
1316
+ scope
1317
+ revision
1318
+ }
1319
+ createdAtUtcIso
1320
+ lastModifiedAtUtcIso
1321
+ }
1322
+ `;
1323
+ import_main.gql`
1324
+ query GetDocumentModels($namespace: String, $paging: PagingInput) {
1325
+ documentModels(namespace: $namespace, paging: $paging) {
1326
+ items {
1327
+ id
1328
+ name
1329
+ namespace
1330
+ version
1331
+ specification
1332
+ }
1333
+ totalCount
1334
+ hasNextPage
1335
+ hasPreviousPage
1336
+ cursor
1337
+ }
1338
+ }
1339
+ `;
1340
+ const GetDocumentDocument = import_main.gql`
1341
+ query GetDocument($identifier: String!, $view: ViewFilterInput) {
1342
+ document(identifier: $identifier, view: $view) {
1343
+ document {
1344
+ ...PHDocumentFields
1345
+ }
1346
+ childIds
1347
+ }
1348
+ }
1349
+ ${PhDocumentFieldsFragmentDoc}
1350
+ `;
1351
+ const GetDocumentWithOperationsDocument = import_main.gql`
1352
+ query GetDocumentWithOperations(
1353
+ $identifier: String!
1354
+ $view: ViewFilterInput
1355
+ $operationsFilter: DocumentOperationsFilterInput
1356
+ $operationsPaging: PagingInput
1357
+ ) {
1358
+ document(identifier: $identifier, view: $view) {
1359
+ document {
1360
+ ...PHDocumentFields
1361
+ operations(filter: $operationsFilter, paging: $operationsPaging) {
1362
+ items {
1363
+ index
1364
+ timestampUtcMs
1365
+ hash
1366
+ skip
1367
+ error
1368
+ deniedReason
1369
+ id
1370
+ action {
1371
+ id
1372
+ type
1373
+ timestampUtcMs
1374
+ input
1375
+ scope
1376
+ context {
1377
+ signer {
1378
+ user {
1379
+ address
1380
+ networkId
1381
+ chainId
1382
+ }
1383
+ app {
1384
+ name
1385
+ key
1386
+ }
1387
+ signatures
1388
+ }
1389
+ }
1390
+ }
1391
+ }
1392
+ totalCount
1393
+ hasNextPage
1394
+ hasPreviousPage
1395
+ cursor
1396
+ }
1397
+ }
1398
+ childIds
1399
+ }
1400
+ }
1401
+ ${PhDocumentFieldsFragmentDoc}
1402
+ `;
1403
+ import_main.gql`
1404
+ query GetDocumentOutgoingRelationships(
1405
+ $sourceIdentifier: String!
1406
+ $relationshipType: String!
1407
+ $view: ViewFilterInput
1408
+ $paging: PagingInput
1409
+ ) {
1410
+ documentOutgoingRelationships(
1411
+ sourceIdentifier: $sourceIdentifier
1412
+ relationshipType: $relationshipType
1413
+ view: $view
1414
+ paging: $paging
1415
+ ) {
1416
+ items {
1417
+ ...PHDocumentFields
1418
+ }
1419
+ totalCount
1420
+ hasNextPage
1421
+ hasPreviousPage
1422
+ cursor
1423
+ }
1424
+ }
1425
+ ${PhDocumentFieldsFragmentDoc}
1426
+ `;
1427
+ import_main.gql`
1428
+ query GetDocumentIncomingRelationships(
1429
+ $targetIdentifier: String!
1430
+ $relationshipType: String!
1431
+ $view: ViewFilterInput
1432
+ $paging: PagingInput
1433
+ ) {
1434
+ documentIncomingRelationships(
1435
+ targetIdentifier: $targetIdentifier
1436
+ relationshipType: $relationshipType
1437
+ view: $view
1438
+ paging: $paging
1439
+ ) {
1440
+ items {
1441
+ ...PHDocumentFields
1442
+ }
1443
+ totalCount
1444
+ hasNextPage
1445
+ hasPreviousPage
1446
+ cursor
1447
+ }
1448
+ }
1449
+ ${PhDocumentFieldsFragmentDoc}
1450
+ `;
1451
+ import_main.gql`
1452
+ query FindDocuments(
1453
+ $search: SearchFilterInput
1454
+ $view: ViewFilterInput
1455
+ $paging: PagingInput
1456
+ ) {
1457
+ findDocuments(search: $search, view: $view, paging: $paging) {
1458
+ items {
1459
+ ...PHDocumentFields
1460
+ }
1461
+ totalCount
1462
+ hasNextPage
1463
+ hasPreviousPage
1464
+ cursor
1465
+ }
1466
+ }
1467
+ ${PhDocumentFieldsFragmentDoc}
1468
+ `;
1469
+ const GetDocumentOperationsDocument = import_main.gql`
1470
+ query GetDocumentOperations(
1471
+ $filter: OperationsFilterInput!
1472
+ $paging: PagingInput
1473
+ ) {
1474
+ documentOperations(filter: $filter, paging: $paging) {
1475
+ items {
1476
+ index
1477
+ timestampUtcMs
1478
+ hash
1479
+ skip
1480
+ error
1481
+ deniedReason
1482
+ id
1483
+ action {
1484
+ id
1485
+ type
1486
+ timestampUtcMs
1487
+ input
1488
+ scope
1489
+ context {
1490
+ signer {
1491
+ user {
1492
+ address
1493
+ networkId
1494
+ chainId
1495
+ }
1496
+ app {
1497
+ name
1498
+ key
1499
+ }
1500
+ signatures
1501
+ }
1502
+ }
1503
+ }
1504
+ }
1505
+ totalCount
1506
+ hasNextPage
1507
+ hasPreviousPage
1508
+ cursor
1509
+ }
1510
+ }
1511
+ `;
1512
+ import_main.gql`
1513
+ query GetJobStatus($jobId: String!) {
1514
+ jobStatus(jobId: $jobId) {
1515
+ id
1516
+ status
1517
+ result
1518
+ error
1519
+ createdAt
1520
+ completedAt
1521
+ }
1522
+ }
1523
+ `;
1524
+ import_main.gql`
1525
+ query EvaluateActions(
1526
+ $documentIdentifier: String!
1527
+ $branch: String
1528
+ $candidates: [ActionCandidateInput!]!
1529
+ ) {
1530
+ evaluateActions(
1531
+ documentIdentifier: $documentIdentifier
1532
+ branch: $branch
1533
+ candidates: $candidates
1534
+ ) {
1535
+ evaluations {
1536
+ decision
1537
+ reason
1538
+ }
1539
+ allAllowed
1540
+ anyAllowed
1541
+ allDenied
1542
+ anyDenied
1543
+ }
1544
+ }
1545
+ `;
1546
+ import_main.gql`
1547
+ mutation CreateDocument($document: JSONObject!, $parentIdentifier: String) {
1548
+ createDocument(document: $document, parentIdentifier: $parentIdentifier) {
1549
+ ...PHDocumentFields
1550
+ }
1551
+ }
1552
+ ${PhDocumentFieldsFragmentDoc}
1553
+ `;
1554
+ import_main.gql`
1555
+ mutation CreateEmptyDocument(
1556
+ $documentType: String!
1557
+ $parentIdentifier: String
1558
+ ) {
1559
+ createEmptyDocument(
1560
+ documentType: $documentType
1561
+ parentIdentifier: $parentIdentifier
1562
+ ) {
1563
+ ...PHDocumentFields
1564
+ }
1565
+ }
1566
+ ${PhDocumentFieldsFragmentDoc}
1567
+ `;
1568
+ import_main.gql`
1569
+ mutation MutateDocument(
1570
+ $documentIdentifier: String!
1571
+ $actions: [ActionInput!]!
1572
+ $branch: String
1573
+ ) {
1574
+ mutateDocument: execute(
1575
+ documentIdentifier: $documentIdentifier
1576
+ actions: $actions
1577
+ branch: $branch
1578
+ ) {
1579
+ ...PHDocumentFields
1580
+ }
1581
+ }
1582
+ ${PhDocumentFieldsFragmentDoc}
1583
+ `;
1584
+ import_main.gql`
1585
+ mutation MutateDocumentAsync(
1586
+ $documentIdentifier: String!
1587
+ $actions: [ActionInput!]!
1588
+ $branch: String
1589
+ ) {
1590
+ mutateDocumentAsync: executeAsync(
1591
+ documentIdentifier: $documentIdentifier
1592
+ actions: $actions
1593
+ branch: $branch
1594
+ ) {
1595
+ id
1596
+ status
1597
+ result
1598
+ error
1599
+ createdAt
1600
+ completedAt
1601
+ }
1602
+ }
1603
+ `;
1604
+ import_main.gql`
1605
+ mutation RenameDocument(
1606
+ $documentIdentifier: String!
1607
+ $name: String!
1608
+ $branch: String
1609
+ ) {
1610
+ renameDocument(
1611
+ documentIdentifier: $documentIdentifier
1612
+ name: $name
1613
+ branch: $branch
1614
+ ) {
1615
+ ...PHDocumentFields
1616
+ }
1617
+ }
1618
+ ${PhDocumentFieldsFragmentDoc}
1619
+ `;
1620
+ import_main.gql`
1621
+ mutation SetPreferredEditor(
1622
+ $documentIdentifier: String!
1623
+ $preferredEditor: String
1624
+ $branch: String
1625
+ ) {
1626
+ setPreferredEditor(
1627
+ documentIdentifier: $documentIdentifier
1628
+ preferredEditor: $preferredEditor
1629
+ branch: $branch
1630
+ ) {
1631
+ ...PHDocumentFields
1632
+ }
1633
+ }
1634
+ ${PhDocumentFieldsFragmentDoc}
1635
+ `;
1636
+ import_main.gql`
1637
+ mutation AddRelationship(
1638
+ $sourceIdentifier: String!
1639
+ $targetIdentifier: String!
1640
+ $relationshipType: String!
1641
+ $branch: String
1642
+ ) {
1643
+ addRelationship(
1644
+ sourceIdentifier: $sourceIdentifier
1645
+ targetIdentifier: $targetIdentifier
1646
+ relationshipType: $relationshipType
1647
+ branch: $branch
1648
+ ) {
1649
+ ...PHDocumentFields
1650
+ }
1651
+ }
1652
+ ${PhDocumentFieldsFragmentDoc}
1653
+ `;
1654
+ import_main.gql`
1655
+ mutation RemoveRelationship(
1656
+ $sourceIdentifier: String!
1657
+ $targetIdentifier: String!
1658
+ $relationshipType: String!
1659
+ $branch: String
1660
+ ) {
1661
+ removeRelationship(
1662
+ sourceIdentifier: $sourceIdentifier
1663
+ targetIdentifier: $targetIdentifier
1664
+ relationshipType: $relationshipType
1665
+ branch: $branch
1666
+ ) {
1667
+ ...PHDocumentFields
1668
+ }
1669
+ }
1670
+ ${PhDocumentFieldsFragmentDoc}
1671
+ `;
1672
+ import_main.gql`
1673
+ mutation MoveRelationship(
1674
+ $sourceParentIdentifier: String!
1675
+ $targetParentIdentifier: String!
1676
+ $targetIdentifier: String!
1677
+ $relationshipType: String!
1678
+ $branch: String
1679
+ ) {
1680
+ moveRelationship(
1681
+ sourceParentIdentifier: $sourceParentIdentifier
1682
+ targetParentIdentifier: $targetParentIdentifier
1683
+ targetIdentifier: $targetIdentifier
1684
+ relationshipType: $relationshipType
1685
+ branch: $branch
1686
+ ) {
1687
+ source {
1688
+ ...PHDocumentFields
1689
+ }
1690
+ target {
1691
+ ...PHDocumentFields
1692
+ }
1693
+ }
1694
+ }
1695
+ ${PhDocumentFieldsFragmentDoc}
1696
+ `;
1697
+ import_main.gql`
1698
+ mutation DeleteDocument($identifier: String!, $propagate: PropagationMode) {
1699
+ deleteDocument(identifier: $identifier, propagate: $propagate)
1700
+ }
1701
+ `;
1702
+ import_main.gql`
1703
+ mutation DeleteDocuments(
1704
+ $identifiers: [String!]!
1705
+ $propagate: PropagationMode
1706
+ ) {
1707
+ deleteDocuments(identifiers: $identifiers, propagate: $propagate)
1708
+ }
1709
+ `;
1710
+ import_main.gql`
1711
+ subscription DocumentChanges(
1712
+ $search: SearchFilterInput
1713
+ $view: ViewFilterInput
1714
+ ) {
1715
+ documentChanges(search: $search, view: $view) {
1716
+ type
1717
+ documents {
1718
+ ...PHDocumentFields
1719
+ }
1720
+ context {
1721
+ parentId
1722
+ childId
1723
+ }
1724
+ }
1725
+ }
1726
+ ${PhDocumentFieldsFragmentDoc}
1727
+ `;
1728
+ import_main.gql`
1729
+ subscription JobChanges($jobId: String!) {
1730
+ jobChanges(jobId: $jobId) {
1731
+ jobId
1732
+ status
1733
+ result
1734
+ error
1735
+ }
1736
+ }
1737
+ `;
1738
+ import_main.gql`
1739
+ query PollSyncEnvelopes(
1740
+ $channelId: String!
1741
+ $outboxAck: Int!
1742
+ $outboxLatest: Int!
1743
+ ) {
1744
+ pollSyncEnvelopes(
1745
+ channelId: $channelId
1746
+ outboxAck: $outboxAck
1747
+ outboxLatest: $outboxLatest
1748
+ ) {
1749
+ envelopes {
1750
+ type
1751
+ channelMeta {
1752
+ id
1753
+ }
1754
+ operations {
1755
+ operation {
1756
+ index
1757
+ timestampUtcMs
1758
+ hash
1759
+ skip
1760
+ error
1761
+ deniedReason
1762
+ id
1763
+ action {
1764
+ id
1765
+ type
1766
+ timestampUtcMs
1767
+ input
1768
+ scope
1769
+ context {
1770
+ signer {
1771
+ user {
1772
+ address
1773
+ networkId
1774
+ chainId
1775
+ }
1776
+ app {
1777
+ name
1778
+ key
1779
+ }
1780
+ signatures
1781
+ }
1782
+ }
1783
+ }
1784
+ }
1785
+ context {
1786
+ documentId
1787
+ documentType
1788
+ scope
1789
+ branch
1790
+ }
1791
+ }
1792
+ cursor {
1793
+ remoteName
1794
+ cursorOrdinal
1795
+ lastSyncedAtUtcMs
1796
+ }
1797
+ key
1798
+ dependsOn
1799
+ }
1800
+ ackOrdinal
1801
+ deadLetters {
1802
+ documentId
1803
+ error
1804
+ errorType
1805
+ }
1806
+ hasMore
1807
+ }
1808
+ }
1809
+ `;
1810
+ import_main.gql`
1811
+ mutation TouchChannel($input: TouchChannelInput!) {
1812
+ touchChannel(input: $input) {
1813
+ success
1814
+ ackOrdinal
1815
+ }
1816
+ }
1817
+ `;
1818
+ import_main.gql`
1819
+ mutation PushSyncEnvelopes($envelopes: [SyncEnvelopeInput!]!) {
1820
+ pushSyncEnvelopes(envelopes: $envelopes)
1821
+ }
1822
+ `;
1823
+ /** Get the source string from a GraphQL document (string or DocumentNode). */
1824
+ function getDocumentSource(doc) {
1825
+ return typeof doc === "string" ? doc : doc.loc?.source.body ?? "";
2056
1826
  }
2057
1827
  /**
2058
- * Loads a document file and replays it with version-aware reducers from the registry.
2059
- * Falls back to single-version legacy replay when no upgrade manifest is registered for
2060
- * the document type.
1828
+ * Extract the inner selection set of a named field from a GraphQL document source.
1829
+ * Returns the `{ ... }` block including braces.
2061
1830
  */
2062
- async function loadFile(path) {
2063
- const baseDocument = await baseLoadFromInput(path, (state) => state, { checkHashes: true });
2064
- const reactorClient = window.ph?.reactorClientModule?.client;
2065
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2066
- const documentType = baseDocument.header.documentType;
2067
- const { results: documentModelModules } = await reactorClient.getDocumentModelModules();
2068
- const modulesForType = documentModelModules.filter((module) => module.documentModel.global.id === documentType);
2069
- if (modulesForType.length === 0) throw new DocumentModelNotFoundError(documentType);
2070
- const reducers = {};
2071
- for (const module of modulesForType) reducers[module.version ?? 1] = module.reducer;
2072
- const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
2073
- let upgradeManifest;
2074
- if (registry) try {
2075
- upgradeManifest = registry.getUpgradeManifest(documentType);
2076
- } catch {}
2077
- return baseLoadFromInputVersioned(path, {
2078
- reducers,
2079
- upgradeManifest
2080
- });
1831
+ function extractSelectionSet(doc, fieldName, fallback) {
1832
+ const source = getDocumentSource(doc);
1833
+ return new RegExp(`${fieldName}\\([^)]*\\)\\s*(\\{[\\s\\S]*\\})\\s*\\}`).exec(source)?.[1] ?? fallback;
2081
1834
  }
2082
- async function addDocument(driveId, name, documentType, parentFolder, document, id, preferredEditor, documentModelVersion) {
2083
- const { isAllowedToCreateDocuments } = getUserPermissions();
2084
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create documents");
2085
- const reactorClient = window.ph?.reactorClientModule?.client;
2086
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2087
- let documentModelModule;
2088
- if (documentModelVersion !== void 0) {
2089
- const { results: documentModelModules } = await reactorClient.getDocumentModelModules();
2090
- const module = documentModelModules.find((m) => m.documentModel.global.id === documentType && (m.version ?? 1) === documentModelVersion);
2091
- if (!module) throw new Error(`Document model not found for type: ${documentType} with version: ${documentModelVersion}`);
2092
- documentModelModule = module;
2093
- } else documentModelModule = await reactorClient.getDocumentModelModule(documentType);
2094
- const newDocument = document ?? documentModelModule.utils.createDocument();
2095
- if (!document) newDocument.state.document.version = documentModelModule.version ?? 1;
2096
- newDocument.header.name = name;
2097
- if (preferredEditor) newDocument.header.meta = {
2098
- ...newDocument.header.meta,
2099
- preferredEditor
2100
- };
2101
- let newDoc;
2102
- try {
2103
- newDoc = await reactorClient.drives.addFile(driveId, newDocument, parentFolder);
2104
- } catch (e) {
2105
- logger.error("Error adding document: @error", e);
2106
- throw new Error("There was an error adding document", { cause: e });
2107
- }
1835
+ /**
1836
+ * Extract the query body and any fragment definitions from a GraphQL document.
1837
+ * Returns { body, fragments } where body is the content inside the query `{ ... }`
1838
+ * and fragments are any trailing fragment definitions.
1839
+ */
1840
+ function extractQueryParts(doc, fallbackBody) {
1841
+ const source = getDocumentSource(doc);
1842
+ const queryMatch = /^[^{]*\{([\s\S]*?)\}\s*(fragment[\s\S]*)?$/.exec(source);
2108
1843
  return {
2109
- id: newDoc.header.id,
2110
- name: newDoc.header.name,
2111
- documentType,
2112
- parentFolder: parentFolder ?? null,
2113
- kind: "file"
1844
+ body: queryMatch?.[1]?.trim() ?? fallbackBody,
1845
+ fragments: queryMatch?.[2]?.trim() ?? ""
2114
1846
  };
2115
1847
  }
2116
- /**
2117
- * How many ids an import will try before giving up. The check before the create
2118
- * catches an id that is already taken; this bound covers the window between the
2119
- * two, where a create can still lose to a claim made in the meantime.
2120
- */
2121
- const IMPORT_ID_ATTEMPTS = 3;
2122
- /** True when this error, or anything it wraps, is a taken document id. */
2123
- function isDocumentAlreadyExists(error) {
2124
- let current = error;
2125
- while (current instanceof Error) {
2126
- if (current.name === "DocumentAlreadyExistsError") return true;
2127
- current = current.cause;
2128
- }
2129
- return false;
1848
+ extractSelectionSet(GetDocumentOperationsDocument, "documentOperations", "{ items { index } }");
1849
+ extractQueryParts(GetDocumentDocument, "document(identifier: $identifier) { document { id name documentType state revisionsList { scope revision } createdAtUtcIso lastModifiedAtUtcIso } childIds }");
1850
+ //#endregion
1851
+ //#region ../reactor-browser/dist/renown-BHxwP7xU.js
1852
+ const { useValue: useLoading, setValue: setLoading, addEventHandler: addLoadingEventHandler } = makePHEventFunctions("loading");
1853
+ const RenownInitialUserContext = createContext({ state: "unknown" });
1854
+ /** First-render auth as a three-state value; use this to skip a spinner when anonymous. */
1855
+ function useRenownInitialAuth() {
1856
+ return useContext(RenownInitialUserContext);
2130
1857
  }
2131
- /**
2132
- * Creates the imported document under an id that is free, retrying on a
2133
- * collision.
2134
- *
2135
- * The check cannot stand on its own: it answers for the moment it ran, and the
2136
- * create that follows can still land on an id claimed in between. The store
2137
- * rejects that create as DocumentAlreadyExistsError, which is not retryable
2138
- * under the same id and is resolved by minting another one. A create that
2139
- * fails leaves the drive untouched, so a retry has nothing to clean up.
2140
- */
2141
- async function createImportedDocument(reactor, document, driveId, name, parentFolder) {
2142
- let documentId = await reactor.isDocumentIdTaken(document.header.id) ? generateId() : document.header.id;
2143
- for (let attempt = 1;; attempt++) {
2144
- const header = createPresignedHeader(documentId, document.header.documentType);
2145
- header.lastModifiedAtUtcIso = document.header.createdAtUtcIso;
2146
- header.meta = document.header.meta;
2147
- header.name = name || document.header.name;
2148
- const initialDocument = {
2149
- ...document,
2150
- header,
2151
- state: document.initialState,
2152
- operations: Object.keys(document.operations).reduce((acc, key) => {
2153
- acc[key] = [];
2154
- return acc;
2155
- }, {})
2156
- };
2157
- try {
2158
- const fileNode = await addDocument(driveId, name || document.header.name, document.header.documentType, parentFolder, initialDocument, documentId, document.header.meta?.preferredEditor);
2159
- if (!fileNode) throw new Error("There was an error adding file");
2160
- return {
2161
- documentId,
2162
- fileNode
2163
- };
2164
- } catch (error) {
2165
- if (!isDocumentAlreadyExists(error) || attempt === IMPORT_ID_ATTEMPTS) throw error;
2166
- logger.warn(`Document id ${documentId} was taken between the check and the create; importing under a new id`);
2167
- documentId = generateId();
2168
- }
2169
- }
1858
+ function useRenownInitialUser() {
1859
+ const initial = useRenownInitialAuth();
1860
+ return initial.state === "authenticated" ? initial.user : void 0;
2170
1861
  }
2171
- async function addFileWithProgress(file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict) {
2172
- logger.verbose(`addFileWithProgress(drive: ${driveId}, name: ${name}, folder: ${parentFolder})`);
2173
- const reactor = window.ph?.reactorClientModule?.client;
2174
- if (!reactor) {
2175
- onProgress?.({
2176
- stage: "failed",
2177
- progress: 100,
2178
- error: "ReactorClient not initialized"
2179
- });
2180
- throw new Error("ReactorClient not initialized");
2181
- }
2182
- const { isAllowedToCreateDocuments } = getUserPermissions();
2183
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create files");
2184
- try {
2185
- onProgress?.({
2186
- stage: "loading",
2187
- progress: 0
2188
- });
2189
- let document;
2190
- try {
2191
- document = await loadFile(file);
2192
- } catch (loadError) {
2193
- if (UnsupportedDocumentModelVersionError.isError(loadError)) {
2194
- showPHModal({
2195
- type: "documentVersionUnsupported",
2196
- documentType: loadError.documentType,
2197
- requiredVersion: loadError.requiredVersion,
2198
- availableVersions: loadError.availableVersions
2199
- });
2200
- onProgress?.({
2201
- stage: "failed",
2202
- progress: 100,
2203
- error: loadError.message
2204
- });
2205
- return;
2206
- }
2207
- const discoveryService = window.ph?.packageDiscoveryService;
2208
- if (discoveryService && DocumentModelNotFoundError.isError(loadError)) {
2209
- retryAfterDiscovery(discoveryService, loadError.documentType, file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict).catch((retryError) => {
2210
- logger.error("Import retry after discovery failed: @error", retryError);
2211
- onProgress?.({
2212
- stage: "failed",
2213
- progress: 100,
2214
- error: retryError instanceof Error ? retryError.message : String(retryError)
2215
- });
2216
- });
2217
- return;
1862
+ const renownEventFunctions = makePHEventFunctions("renown");
1863
+ renownEventFunctions.addEventHandler;
1864
+ /** Returns the renown instance */
1865
+ const useRenown = renownEventFunctions.useValue;
1866
+ renownEventFunctions.setValue;
1867
+ function jsonEqual(a, b) {
1868
+ if (a === b) return true;
1869
+ if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
1870
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
1871
+ const ra = a;
1872
+ const rb = b;
1873
+ const keys = Object.keys(ra).filter((k) => ra[k] !== void 0);
1874
+ if (keys.length !== Object.keys(rb).filter((k) => rb[k] !== void 0).length) return false;
1875
+ return keys.every((k) => jsonEqual(ra[k], rb[k]));
1876
+ }
1877
+ function sameUser(a, b) {
1878
+ return jsonEqual(a, b);
1879
+ }
1880
+ function resolveInstanceUser(instance, seed) {
1881
+ const restored = instance.user;
1882
+ if (restored) return sameUser(seed, restored) ? seed : restored;
1883
+ return instance.status === "initial" ? void 0 : seed;
1884
+ }
1885
+ /** Returns the current user from the renown instance, subscribing to user events */
1886
+ function useUser() {
1887
+ const renown = useRenown();
1888
+ const initialUser = useRenownInitialUser();
1889
+ const instance = renown ? renown : void 0;
1890
+ const [tracked, setTracked] = useState(() => ({
1891
+ instance,
1892
+ user: instance ? resolveInstanceUser(instance, initialUser) : initialUser
1893
+ }));
1894
+ const current = tracked.instance === instance ? tracked : {
1895
+ instance,
1896
+ user: instance ? resolveInstanceUser(instance, tracked.user ?? initialUser) : tracked.user
1897
+ };
1898
+ useEffect(() => {
1899
+ if (current !== tracked) setTracked(current);
1900
+ }, [current, tracked]);
1901
+ useEffect(() => {
1902
+ if (!instance) return;
1903
+ return instance.on("user", (user) => setTracked((prev) => ({
1904
+ instance,
1905
+ user: sameUser(prev.user, user) ? prev.user : user
1906
+ })));
1907
+ }, [instance]);
1908
+ return instance ? current.user : initialUser ?? current.user;
1909
+ }
1910
+ //#endregion
1911
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/lazyDataLastImpl-DtF3cihj.js
1912
+ function e$8(e, t, n) {
1913
+ let r = (n) => e(n, ...t);
1914
+ return n === void 0 ? r : Object.assign(r, {
1915
+ lazy: n,
1916
+ lazyArgs: t
1917
+ });
1918
+ }
1919
+ //#endregion
1920
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/purry.js
1921
+ function t$5(t, n, r) {
1922
+ let i = t.length - n.length;
1923
+ if (i === 0) return t(...n);
1924
+ if (i === 1) return e$8(t, n, r);
1925
+ throw Error(`Wrong number of arguments`);
1926
+ }
1927
+ //#endregion
1928
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/allPass.js
1929
+ function t$4(...t) {
1930
+ return t$5(n$4, t);
1931
+ }
1932
+ const n$4 = (e, t) => t.every((t) => t(e));
1933
+ //#endregion
1934
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/conditional-CTEJD5TX.js
1935
+ function e$7(e, t, n) {
1936
+ return e(n[0]) ? (e) => t(e, ...n) : t(...n);
1937
+ }
1938
+ function t$3(...t) {
1939
+ return e$7(r, n$3, t);
1940
+ }
1941
+ function n$3(e, ...t) {
1942
+ for (let n of t) {
1943
+ if (typeof n == `function`) return n(e);
1944
+ let [t, r] = n;
1945
+ if (t(e)) return r(e);
1946
+ }
1947
+ throw Error(`conditional: data failed for all cases`);
1948
+ }
1949
+ function r(e) {
1950
+ if (!Array.isArray(e)) return !1;
1951
+ let [t, n, ...r] = e;
1952
+ return typeof t == `function` && t.length <= 1 && typeof n == `function` && n.length <= 1 && r.length === 0;
1953
+ }
1954
+ //#endregion
1955
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/constant.js
1956
+ function e$6(e) {
1957
+ return () => e;
1958
+ }
1959
+ //#endregion
1960
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/hasAtLeast.js
1961
+ function t$2(...t) {
1962
+ return t$5(n$2, t);
1963
+ }
1964
+ const n$2 = (e, t) => e.length >= t;
1965
+ //#endregion
1966
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/funnel.js
1967
+ const e$5 = Symbol(`funnel/voidReducer`), t$1 = () => e$5;
1968
+ function n$1(n, { triggerAt: r = `end`, minQuietPeriodMs: i, maxBurstDurationMs: a, minGapMs: o, reducer: s = t$1 }) {
1969
+ let c, l, u, d, f = () => {
1970
+ let t = u;
1971
+ t !== void 0 && (u = void 0, t === e$5 ? n() : n(t), o !== void 0 && (l = setTimeout(p, o)));
1972
+ }, p = () => {
1973
+ clearTimeout(l), l = void 0, c === void 0 && f();
1974
+ }, m = () => {
1975
+ clearTimeout(c), c = void 0, d = void 0, l === void 0 && f();
1976
+ };
1977
+ return {
1978
+ call: (...e) => {
1979
+ let t = c === void 0 && l === void 0;
1980
+ if ((r !== `start` || t) && (u = s(u, ...e)), !(c === void 0 && !t)) {
1981
+ if (i !== void 0 || a !== void 0 || o === void 0) {
1982
+ clearTimeout(c);
1983
+ let e = Date.now();
1984
+ d ??= e;
1985
+ let t = a === void 0 ? i ?? 0 : Math.min(i ?? a, Math.max(0, a - (e - d)));
1986
+ c = setTimeout(m, t);
1987
+ }
1988
+ r !== `end` && t && f();
2218
1989
  }
2219
- throw loadError;
2220
- }
2221
- const duplicateCheck = await isDocumentInLocation(reactor, document, driveId, parentFolder);
2222
- if (duplicateCheck.isDuplicate && !resolveConflict) {
2223
- onProgress?.({
2224
- stage: "conflict",
2225
- progress: 0,
2226
- duplicateType: duplicateCheck.duplicateType
2227
- });
2228
- return;
2229
- }
2230
- const documentType = getDocumentTypeIcon(document);
2231
- if (documentType) onProgress?.({
2232
- stage: "loading",
2233
- progress: 10,
2234
- documentType
2235
- });
2236
- else onProgress?.({
2237
- stage: "loading",
2238
- progress: 10
2239
- });
2240
- if (!isDocumentTypeSupported(document.header.documentType, documentTypes)) {
2241
- onProgress?.({
2242
- stage: "unsupported-document-type",
2243
- progress: 100,
2244
- error: `Document type ${document.header.documentType} is not supported`
2245
- });
2246
- throw new UnsupportedDocumentTypeError(document.header.documentType);
2247
- }
2248
- await reactor.getDocumentModelModule(document.header.documentType);
2249
- onProgress?.({
2250
- stage: "initializing",
2251
- progress: 10
2252
- });
2253
- const created = await createImportedDocument(reactor, document, driveId, name, parentFolder);
2254
- const documentId = created.documentId;
2255
- const fileNode = created.fileNode;
2256
- onProgress?.({
2257
- stage: "initializing",
2258
- progress: 20
2259
- });
2260
- await reactor.get(documentId);
2261
- console.log("Document created, starting upload of operations");
2262
- const segments = splitAtUpgradeBoundaries(document.operations);
2263
- const totalOperations = segments.reduce((total, segment) => total + countOperations(segment.operations), 0);
2264
- let uploadedBefore = 0;
2265
- for (const segment of segments) {
2266
- await uploadOperations(documentId, segment.operations, queueOperations, { onProgress: (uploadProgress) => {
2267
- if (uploadProgress.uploadedOperations === void 0) return;
2268
- const uploaded = uploadedBefore + uploadProgress.uploadedOperations;
2269
- const uploadPercent = totalOperations > 0 ? uploaded / totalOperations : 0;
2270
- onProgress?.({
2271
- stage: "uploading",
2272
- progress: 20 + Math.round(uploadPercent * 80),
2273
- totalOperations,
2274
- uploadedOperations: uploaded
2275
- });
2276
- } });
2277
- uploadedBefore += countOperations(segment.operations);
2278
- if (segment.upgradeTo !== void 0) await reactor.upgradeDocument(documentId, segment.upgradeTo);
2279
- }
2280
- onProgress?.({
2281
- stage: "complete",
2282
- progress: 100,
2283
- fileNode
2284
- });
2285
- return fileNode;
2286
- } catch (error) {
2287
- if (!UnsupportedDocumentTypeError.isError(error)) {
2288
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
2289
- onProgress?.({
2290
- stage: "failed",
2291
- progress: 100,
2292
- error: errorMessage
2293
- });
1990
+ },
1991
+ cancel: () => {
1992
+ clearTimeout(c), c = void 0, d = void 0, clearTimeout(l), l = void 0, u = void 0;
1993
+ },
1994
+ flush: () => {
1995
+ m(), p();
1996
+ },
1997
+ get isIdle() {
1998
+ return c === void 0 && l === void 0;
2294
1999
  }
2295
- throw error;
2296
- }
2000
+ };
2297
2001
  }
2298
- async function retryAfterDiscovery(discoveryService, documentType, file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict) {
2299
- if (!discoveryService) return;
2300
- try {
2301
- await discoveryService.load(documentType);
2302
- } catch {
2303
- onProgress?.({
2304
- stage: "unsupported-document-type",
2305
- progress: 100,
2306
- error: `Document type ${documentType} is not supported`
2307
- });
2308
- return;
2309
- }
2310
- await addFileWithProgress(file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict);
2002
+ //#endregion
2003
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isDefined.js
2004
+ function e$4(e) {
2005
+ return e !== void 0;
2311
2006
  }
2312
- async function addFolder$1(driveId, name, parentFolder) {
2313
- const { isAllowedToCreateDocuments } = getUserPermissions();
2314
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create folders");
2315
- const reactorClient = window.ph?.reactorClient;
2316
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2317
- await reactorClient.get(driveId);
2318
- const folderId = generateId();
2319
- const node = (await reactorClient.execute(driveId, "main", [addFolder({
2320
- id: folderId,
2321
- name,
2322
- parentFolder
2323
- })])).state.global.nodes.find((node) => node.id === folderId);
2324
- if (!node || !isFolderNode(node)) throw new Error("There was an error adding folder");
2325
- return node;
2007
+ //#endregion
2008
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isNot.js
2009
+ function e$3(e) {
2010
+ return (t) => !e(t);
2326
2011
  }
2327
- async function renameNode(driveId, nodeId, name) {
2328
- const { isAllowedToCreateDocuments } = getUserPermissions();
2329
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to rename documents");
2330
- const reactorClient = window.ph?.reactorClient;
2331
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2332
- if ((await reactorClient.execute(nodeId, "main", [setName({ name })])).header.name !== name) throw new Error("There was an error renaming the node");
2333
- const node = (await reactorClient.execute(driveId, "main", [updateNode({
2334
- id: nodeId,
2335
- name
2336
- })])).state.global.nodes.find((n) => n.id === nodeId);
2337
- if (!node) throw new Error("There was an error renaming node in the drive");
2338
- return node;
2012
+ //#endregion
2013
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isStrictEqual.js
2014
+ function t(...t) {
2015
+ return t$5(n, t);
2339
2016
  }
2340
- async function renameDriveNode(driveId, nodeId, name) {
2341
- const { isAllowedToCreateDocuments } = getUserPermissions();
2342
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to rename documents");
2343
- const reactorClient = window.ph?.reactorClient;
2344
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2345
- if ((await reactorClient.execute(nodeId, "main", [setName({ name })])).header.name !== name) throw new Error("There was an error renaming the node");
2346
- await reactorClient.execute(driveId, "main", [updateNode({
2347
- id: nodeId,
2348
- name
2349
- })]);
2350
- return (await reactorClient.get(driveId)).state.global.nodes.find((n) => n.id === nodeId);
2017
+ const n = (e, t) => e === t || Object.is(e, t);
2018
+ //#endregion
2019
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isString.js
2020
+ function e$2(e) {
2021
+ return typeof e == `string`;
2022
+ }
2023
+ //#endregion
2024
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/isTruthy.js
2025
+ function e$1(e) {
2026
+ return !!e;
2027
+ }
2028
+ //#endregion
2029
+ //#region ../../node_modules/.pnpm/remeda@2.33.7/node_modules/remeda/dist/once.js
2030
+ function e(e) {
2031
+ let t = !1, n;
2032
+ return () => (t ||= (n = e(), !0), n);
2033
+ }
2034
+ var CloseCode = /* @__PURE__ */ ((CloseCode2) => {
2035
+ CloseCode2[CloseCode2["InternalServerError"] = 4500] = "InternalServerError";
2036
+ CloseCode2[CloseCode2["InternalClientError"] = 4005] = "InternalClientError";
2037
+ CloseCode2[CloseCode2["BadRequest"] = 4400] = "BadRequest";
2038
+ CloseCode2[CloseCode2["BadResponse"] = 4004] = "BadResponse";
2039
+ CloseCode2[CloseCode2["Unauthorized"] = 4401] = "Unauthorized";
2040
+ CloseCode2[CloseCode2["Forbidden"] = 4403] = "Forbidden";
2041
+ CloseCode2[CloseCode2["SubprotocolNotAcceptable"] = 4406] = "SubprotocolNotAcceptable";
2042
+ CloseCode2[CloseCode2["ConnectionInitialisationTimeout"] = 4408] = "ConnectionInitialisationTimeout";
2043
+ CloseCode2[CloseCode2["ConnectionAcknowledgementTimeout"] = 4504] = "ConnectionAcknowledgementTimeout";
2044
+ CloseCode2[CloseCode2["SubscriberAlreadyExists"] = 4409] = "SubscriberAlreadyExists";
2045
+ CloseCode2[CloseCode2["TooManyInitialisationRequests"] = 4429] = "TooManyInitialisationRequests";
2046
+ return CloseCode2;
2047
+ })(CloseCode || {});
2048
+ var MessageType = /* @__PURE__ */ ((MessageType2) => {
2049
+ MessageType2["ConnectionInit"] = "connection_init";
2050
+ MessageType2["ConnectionAck"] = "connection_ack";
2051
+ MessageType2["Ping"] = "ping";
2052
+ MessageType2["Pong"] = "pong";
2053
+ MessageType2["Subscribe"] = "subscribe";
2054
+ MessageType2["Next"] = "next";
2055
+ MessageType2["Error"] = "error";
2056
+ MessageType2["Complete"] = "complete";
2057
+ return MessageType2;
2058
+ })(MessageType || {});
2059
+ Error;
2060
+ //#endregion
2061
+ //#region ../reactor-browser/dist/document-operations-I1cGIcPg.js
2062
+ const modalEventFunctions = makePHEventFunctions("modal");
2063
+ modalEventFunctions.useValue;
2064
+ /** Sets the current modal */
2065
+ const setPHModal = modalEventFunctions.setValue;
2066
+ modalEventFunctions.addEventHandler;
2067
+ /** Shows a modal */
2068
+ function showPHModal(modal) {
2069
+ setPHModal(modal);
2351
2070
  }
2352
- async function moveNodeById(args) {
2353
- const { driveId, srcId, targetId } = args;
2354
- if (!driveId || !srcId) return;
2355
- const { isAllowedToCreateDocuments } = getUserPermissions();
2356
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to move documents");
2357
- const reactorClient = window.ph?.reactorClient;
2358
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2359
- const targetParentFolder = t$3(targetId, [e$3(e$4), e$6(void 0)], [t(driveId), e$6(void 0)], e$6(targetId));
2360
- if (t(targetParentFolder, srcId)) return;
2361
- return await reactorClient.execute(driveId, "main", [moveNode({
2362
- srcFolder: srcId,
2363
- targetParentFolder
2364
- })]);
2071
+ /** Shows the delete node modal */
2072
+ function showDeleteNodeModal(nodeOrId) {
2073
+ setPHModal({
2074
+ type: "deleteItem",
2075
+ id: typeof nodeOrId === "string" ? nodeOrId : nodeOrId.id
2076
+ });
2365
2077
  }
2366
- async function moveNode$1(driveId, src, target) {
2367
- const { isAllowedToCreateDocuments } = getUserPermissions();
2368
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to move documents");
2369
- const reactorClient = window.ph?.reactorClient;
2370
- if (!reactorClient) throw new Error("ReactorClient not initialized");
2371
- return await reactorClient.execute(driveId, "main", [moveNode({
2372
- srcFolder: src.id,
2373
- targetParentFolder: target?.id
2374
- })]);
2078
+ function isDocumentTypeSupported(documentType, supportedDocuments) {
2079
+ if (!supportedDocuments?.length) return true;
2080
+ return supportedDocuments.some((pattern) => {
2081
+ if (pattern.endsWith("/*")) {
2082
+ const prefix = pattern.slice(0, -2);
2083
+ return documentType.startsWith(prefix + "/");
2084
+ }
2085
+ if (pattern.endsWith("*") && !pattern.endsWith("/*")) {
2086
+ const prefix = pattern.slice(0, -1);
2087
+ return documentType.startsWith(prefix);
2088
+ }
2089
+ return pattern === documentType;
2090
+ });
2375
2091
  }
2376
- /**
2377
- * Duplicates a document under a new id using version-aware replay.
2378
- * Falls back gracefully when no upgrade manifest is registered for the document type.
2379
- */
2380
- async function _duplicateDocument(reactor, document, newId = generateId()) {
2381
- const documentType = document.header.documentType;
2382
- const { results: allModules } = await reactor.getDocumentModelModules();
2383
- const modulesForType = allModules.filter((m) => m.documentModel.global.id === documentType);
2384
- const reducers = {};
2385
- for (const m of modulesForType) reducers[m.version ?? 1] = m.reducer;
2386
- if (Object.keys(reducers).length === 0) throw new Error(`Document model module not found for type: ${documentType}`);
2387
- const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
2388
- let upgradeManifest;
2389
- if (registry) try {
2390
- upgradeManifest = registry.getUpgradeManifest(documentType);
2391
- } catch {}
2392
- const config = {
2393
- reducers,
2394
- upgradeManifest
2092
+ function getUserPermissions() {
2093
+ const user = window.ph?.renown?.user;
2094
+ const allowList = window.ph?.allowList;
2095
+ if (!allowList) return {
2096
+ isAllowedToCreateDocuments: true,
2097
+ isAllowedToEditDocuments: true
2098
+ };
2099
+ return {
2100
+ isAllowedToCreateDocuments: allowList.includes(user?.address ?? ""),
2101
+ isAllowedToEditDocuments: allowList.includes(user?.address ?? "")
2395
2102
  };
2396
- const header = createPresignedHeader(newId, documentType);
2397
- const duplicated = replayDocumentVersioned(document.initialState, document.operations, config, header);
2398
- assertAuthPreservedOnDuplicate(document.header.id, document.state.auth, duplicated.state.auth);
2399
- return duplicated;
2400
2103
  }
2401
- async function copyNode$1(driveId, src, target) {
2402
- const reactor = window.ph?.reactorClientModule?.client;
2403
- if (!reactor) return;
2404
- const { isAllowedToCreateDocuments } = getUserPermissions();
2405
- if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to copy documents");
2406
- const drive = await reactor.get(driveId);
2407
- const copyNodesInput = generateNodesCopy({
2408
- srcId: src.id,
2409
- targetParentFolder: target?.id,
2410
- targetName: src.name
2411
- }, () => generateId(), drive.state.global.nodes);
2412
- const resolvedNamesMap = /* @__PURE__ */ new Map();
2413
- for (const copyNodeInput of copyNodesInput) {
2414
- const node = drive.state.global.nodes.find((n) => n.id === copyNodeInput.srcId);
2415
- if (node) {
2416
- const resolvedName = handleTargetNameCollisions({
2417
- nodes: drive.state.global.nodes,
2418
- srcName: copyNodeInput.targetName || node.name,
2419
- srcKind: isFileNode(node) ? "file" : "folder",
2420
- targetParentFolder: copyNodeInput.targetParentFolder || null
2421
- });
2422
- resolvedNamesMap.set(copyNodeInput.targetId, resolvedName);
2104
+ const NON_DOMAIN_SCOPES = new Set(["auth", "document"]);
2105
+ /** An unreadable drive cannot be shown to hold no duplicate, so reads throw. */
2106
+ async function isDocumentInLocation(reactorClient, document, driveId, parentFolder) {
2107
+ const drive = await reactorClient.get(driveId);
2108
+ const nodeById = drive.state.global.nodes.find((node) => node.id === document.header.id);
2109
+ if (nodeById && nodeById.parentFolder === (parentFolder ?? null)) return {
2110
+ isDuplicate: true,
2111
+ duplicateType: "id",
2112
+ nodeId: nodeById.id
2113
+ };
2114
+ const nodeByNameAndType = drive.state.global.nodes.find((node) => isFileNode(node) && node.name === document.header.name && node.documentType === document.header.documentType && node.parentFolder === (parentFolder ?? null));
2115
+ if (nodeByNameAndType) return {
2116
+ isDuplicate: true,
2117
+ duplicateType: "name",
2118
+ nodeId: nodeByNameAndType.id
2119
+ };
2120
+ return { isDuplicate: false };
2121
+ }
2122
+ function getDocumentTypeIcon(document) {
2123
+ switch (document.header.documentType) {
2124
+ case "powerhouse/document-model": return "document-model";
2125
+ case "powerhouse/app": return "app";
2126
+ case "powerhouse/document-editor": return "editor";
2127
+ case "powerhouse/subgraph": return "subgraph";
2128
+ case "powerhouse/package": return "package";
2129
+ case "powerhouse/processor": {
2130
+ const processorType = document.state.global?.type;
2131
+ if (processorType === "analytics") return "analytics-processor";
2132
+ if (processorType === "relational") return "relational-processor";
2133
+ if (processorType === "codegen") return "codegen-processor";
2134
+ return;
2423
2135
  }
2136
+ default: return;
2424
2137
  }
2425
- const fileNodesToCopy = copyNodesInput.filter((copyNodeInput) => {
2426
- const node = drive.state.global.nodes.find((node) => node.id === copyNodeInput.srcId);
2427
- return node !== void 0 && isFileNode(node);
2428
- });
2429
- for (const fileNodeToCopy of fileNodesToCopy) try {
2430
- const duplicatedDocument = await _duplicateDocument(reactor, await reactor.get(fileNodeToCopy.srcId), fileNodeToCopy.targetId);
2431
- const resolvedName = resolvedNamesMap.get(fileNodeToCopy.targetId);
2432
- if (resolvedName) duplicatedDocument.header.name = resolvedName;
2433
- await reactor.drives.addFile(driveId, duplicatedDocument, target?.id);
2138
+ }
2139
+ async function downloadFile(document, fileName) {
2140
+ try {
2141
+ const data = await createZip(document);
2142
+ const blob = new Blob([new Uint8Array(data)], { type: "application/zip" });
2143
+ const link = window.document.createElement("a");
2144
+ link.style.display = "none";
2145
+ link.href = URL.createObjectURL(blob);
2146
+ link.download = fileName;
2147
+ window.document.body.appendChild(link);
2148
+ link.click();
2149
+ window.document.body.removeChild(link);
2434
2150
  } catch (e) {
2435
- logger.error(`Error copying document ${fileNodeToCopy.srcId}: ${String(e)}`);
2151
+ logger.error(e instanceof Error ? e.message : String(e));
2436
2152
  }
2437
- return await queueActions(drive, copyNodesInput.map((copyNodeInput) => copyNode(copyNodeInput)));
2438
2153
  }
2439
- /**
2440
- * The operation selection of `GetDocumentOperations`, lifted into a fragment so
2441
- * the write path can reuse `remoteOperationToLocal` on the items it selects.
2442
- */
2443
- const ReactorOperationFieldsFragmentDoc = import_main.gql`
2444
- fragment ReactorOperationFields on ReactorOperation {
2445
- index
2446
- timestampUtcMs
2447
- hash
2448
- skip
2449
- error
2450
- deniedReason
2451
- id
2452
- action {
2453
- id
2454
- type
2455
- timestampUtcMs
2456
- input
2457
- scope
2458
- context {
2459
- signer {
2460
- user {
2461
- address
2462
- networkId
2463
- chainId
2464
- }
2465
- app {
2466
- name
2467
- key
2468
- }
2469
- signatures
2470
- }
2471
- }
2472
- }
2473
- }
2474
- `;
2475
- import_main.gql`
2476
- mutation MutateDocumentWithOperations(
2477
- $documentIdentifier: String!
2478
- $actions: [ActionInput!]!
2479
- $sinceRevision: Int
2480
- $scopes: [String!]
2481
- $branch: String
2482
- ) {
2483
- mutateDocument: execute(
2484
- documentIdentifier: $documentIdentifier
2485
- actions: $actions
2486
- branch: $branch
2487
- ) {
2488
- ...PHDocumentFields
2489
- operations(
2490
- filter: {
2491
- sinceRevision: $sinceRevision
2492
- scopes: $scopes
2493
- branch: $branch
2494
- }
2495
- ) {
2496
- items {
2497
- ...ReactorOperationFields
2498
- }
2499
- }
2500
- }
2501
- }
2502
- ${PhDocumentFieldsFragmentDoc}
2503
- ${ReactorOperationFieldsFragmentDoc}
2504
- `;
2505
- DocumentChangeType.Created, DOCUMENT_CHANGE_TYPE.Created, DocumentChangeType.Deleted, DOCUMENT_CHANGE_TYPE.Deleted, DocumentChangeType.Updated, DOCUMENT_CHANGE_TYPE.Updated, DocumentChangeType.ParentAdded, DOCUMENT_CHANGE_TYPE.ParentAdded, DocumentChangeType.ParentRemoved, DOCUMENT_CHANGE_TYPE.ParentRemoved, DocumentChangeType.ChildAdded, DOCUMENT_CHANGE_TYPE.ChildAdded, DocumentChangeType.ChildRemoved, DOCUMENT_CHANGE_TYPE.ChildRemoved;
2506
- PropagationMode.Cascade, PropagationMode.Orphan;
2507
- const isExternalControlsEnabledEventFunctions = makePHEventFunctions("isExternalControlsEnabled");
2508
- /** Sets whether external controls are enabled for a given editor. */
2509
- const setIsExternalControlsEnabled = isExternalControlsEnabledEventFunctions.setValue;
2510
- /** Gets whether external controls are enabled for a given editor. */
2511
- const useIsExternalControlsEnabled = isExternalControlsEnabledEventFunctions.useValue;
2512
- isExternalControlsEnabledEventFunctions.addEventHandler;
2513
- const isDragAndDropEnabledEventFunctions = makePHEventFunctions("isDragAndDropEnabled");
2514
- /** Sets whether drag and drop is enabled for a given app. */
2515
- const setIsDragAndDropEnabled = isDragAndDropEnabledEventFunctions.setValue;
2516
- /** Gets whether drag and drop is enabled for a given app. */
2517
- const useIsDragAndDropEnabled = isDragAndDropEnabledEventFunctions.useValue;
2518
- isDragAndDropEnabledEventFunctions.addEventHandler;
2519
- const allowedDocumentTypesEventFunctions = makePHEventFunctions("allowedDocumentTypes");
2520
- /** Sets the allowed document types for a given app. */
2521
- const setAllowedDocumentTypes = allowedDocumentTypesEventFunctions.setValue;
2522
- /** Defines the document types a drive supports.
2523
- *
2524
- * Defaults to all of the document types registered in the reactor.
2154
+ async function getDocumentExtension(document) {
2155
+ const documentType = document.header.documentType;
2156
+ let rawExtension;
2157
+ if (documentType === "powerhouse/document-model") rawExtension = document.state.global?.extension;
2158
+ else {
2159
+ const reactorClient = window.ph?.reactorClientModule?.client;
2160
+ if (reactorClient) {
2161
+ const { results: documentModelModules } = await reactorClient.getDocumentModelModules();
2162
+ rawExtension = documentModelModules.find((m) => m.documentModel.global.id === documentType)?.utils.fileExtension;
2163
+ }
2164
+ }
2165
+ return (rawExtension ?? "").replace(/^\.+|\.+$/g, "");
2166
+ }
2167
+ /**
2168
+ * Fetches all operations for a document using cursor-based pagination.
2169
+ * The reactor client handles multi-scope cursors transparently via
2170
+ * composite cursors, so all scopes are fetched in a single paginated stream.
2525
2171
  */
2526
- function useAllowedDocumentTypes() {
2527
- return allowedDocumentTypesEventFunctions.useValue();
2172
+ async function fetchDocumentOperations(reactorClient, document, pageSize = 100) {
2173
+ const scopes = Object.keys(document.state);
2174
+ const operations = {};
2175
+ for (const scope of scopes) operations[scope] = [];
2176
+ let cursor = "";
2177
+ do {
2178
+ const page = await reactorClient.getOperations(document.header.id, { scopes }, void 0, {
2179
+ cursor,
2180
+ limit: pageSize
2181
+ });
2182
+ for (const op of page.results) {
2183
+ const scope = op.action.scope ?? "global";
2184
+ if (operations[scope]) operations[scope].push(op);
2185
+ }
2186
+ cursor = page.nextCursor ?? "";
2187
+ } while (cursor);
2188
+ return operations;
2528
2189
  }
2529
- allowedDocumentTypesEventFunctions.addEventHandler;
2530
- const phAppConfigSetters = {
2531
- allowedDocumentTypes: setAllowedDocumentTypes,
2532
- isDragAndDropEnabled: setIsDragAndDropEnabled
2533
- };
2534
- const phDocumentEditorConfigSetters = { isExternalControlsEnabled: setIsExternalControlsEnabled };
2535
- const phAppConfigHooks = {
2536
- allowedDocumentTypes: useAllowedDocumentTypes,
2537
- isDragAndDropEnabled: useIsDragAndDropEnabled
2538
- };
2539
- const phDocumentEditorConfigHooks = { isExternalControlsEnabled: useIsExternalControlsEnabled };
2540
- const { useValue: useRouterBasename, setValue: setRouterBasename, addEventHandler: addRouterBasenameEventHandler } = makePHEventFunctions("routerBasename");
2541
- const { useValue: useVersion, setValue: setVersion, addEventHandler: addVersionEventHandler } = makePHEventFunctions("version");
2542
- const { useValue: useRequiresHardRefresh, setValue: setRequiresHardRefresh, addEventHandler: addRequiresHardRefreshEventHandler } = makePHEventFunctions("requiresHardRefresh");
2543
- const { useValue: useWarnOutdatedApp, setValue: setWarnOutdatedApp, addEventHandler: addWarnOutdatedAppEventHandler } = makePHEventFunctions("warnOutdatedApp");
2544
- const { useValue: useStudioMode, setValue: setStudioMode, addEventHandler: addStudioModeEventHandler } = makePHEventFunctions("studioMode");
2545
- const { useValue: useBasePath, setValue: setBasePath, addEventHandler: addBasePathEventHandler } = makePHEventFunctions("basePath");
2546
- const { useValue: useVersionCheckInterval, setValue: setVersionCheckInterval, addEventHandler: addVersionCheckIntervalEventHandler } = makePHEventFunctions("versionCheckInterval");
2547
- const { useValue: useCliVersion, setValue: setCliVersion, addEventHandler: addCliVersionEventHandler } = makePHEventFunctions("cliVersion");
2548
- const { useValue: useFileUploadOperationsChunkSize, setValue: setFileUploadOperationsChunkSize, addEventHandler: addFileUploadOperationsChunkSizeEventHandler } = makePHEventFunctions("fileUploadOperationsChunkSize");
2549
- const { useValue: useIsDocumentModelSelectionSettingsEnabled, setValue: setIsDocumentModelSelectionSettingsEnabled, addEventHandler: addIsDocumentModelSelectionSettingsEnabledEventHandler } = makePHEventFunctions("isDocumentModelSelectionSettingsEnabled");
2550
- const { useValue: useGaTrackingId, setValue: setGaTrackingId, addEventHandler: addGaTrackingIdEventHandler } = makePHEventFunctions("gaTrackingId");
2551
- const { useValue: useDefaultDrivesUrl, setValue: setDefaultDrivesUrl, addEventHandler: addDefaultDrivesUrlEventHandler } = makePHEventFunctions("defaultDrivesUrl");
2552
- const { useValue: useDrivesPreserveStrategy, setValue: setDrivesPreserveStrategy, addEventHandler: addDrivesPreserveStrategyEventHandler } = makePHEventFunctions("drivesPreserveStrategy");
2553
- const { useValue: useIsLocalDrivesEnabled, setValue: setIsLocalDrivesEnabled, addEventHandler: addIsLocalDrivesEnabledEventHandler } = makePHEventFunctions("isLocalDrivesEnabled");
2554
- const { useValue: useIsAddDriveEnabled, setValue: setIsAddDriveEnabled, addEventHandler: addIsAddDriveEnabledEventHandler } = makePHEventFunctions("isAddDriveEnabled");
2555
- const { useValue: useIsPublicDrivesEnabled, setValue: setIsPublicDrivesEnabled, addEventHandler: addIsPublicDrivesEnabledEventHandler } = makePHEventFunctions("isPublicDrivesEnabled");
2556
- const { useValue: useIsAddPublicDrivesEnabled, setValue: setIsAddPublicDrivesEnabled, addEventHandler: addIsAddPublicDrivesEnabledEventHandler } = makePHEventFunctions("isAddPublicDrivesEnabled");
2557
- const { useValue: useIsDeletePublicDrivesEnabled, setValue: setIsDeletePublicDrivesEnabled, addEventHandler: addIsDeletePublicDrivesEnabledEventHandler } = makePHEventFunctions("isDeletePublicDrivesEnabled");
2558
- const { useValue: useIsCloudDrivesEnabled, setValue: setIsCloudDrivesEnabled, addEventHandler: addIsCloudDrivesEnabledEventHandler } = makePHEventFunctions("isCloudDrivesEnabled");
2559
- const { useValue: useIsAddCloudDrivesEnabled, setValue: setIsAddCloudDrivesEnabled, addEventHandler: addIsAddCloudDrivesEnabledEventHandler } = makePHEventFunctions("isAddCloudDrivesEnabled");
2560
- const { useValue: useIsDeleteCloudDrivesEnabled, setValue: setIsDeleteCloudDrivesEnabled, addEventHandler: addIsDeleteCloudDrivesEnabledEventHandler } = makePHEventFunctions("isDeleteCloudDrivesEnabled");
2561
- const { useValue: useLocalDrivesEnabled, setValue: setLocalDrivesEnabled, addEventHandler: addLocalDrivesEnabledEventHandler } = makePHEventFunctions("isLocalDrivesEnabled");
2562
- const { useValue: useIsAddLocalDrivesEnabled, setValue: setIsAddLocalDrivesEnabled, addEventHandler: addIsAddLocalDrivesEnabledEventHandler } = makePHEventFunctions("isAddLocalDrivesEnabled");
2563
- const { useValue: useIsDeleteLocalDrivesEnabled, setValue: setIsDeleteLocalDrivesEnabled, addEventHandler: addIsDeleteLocalDrivesEnabledEventHandler } = makePHEventFunctions("isDeleteLocalDrivesEnabled");
2564
- const { useValue: useIsEditorDebugModeEnabled, setValue: setIsEditorDebugModeEnabled, addEventHandler: addIsEditorDebugModeEnabledEventHandler } = makePHEventFunctions("isEditorDebugModeEnabled");
2565
- const { useValue: useIsEditorReadModeEnabled, setValue: setIsEditorReadModeEnabled, addEventHandler: addIsEditorReadModeEnabledEventHandler } = makePHEventFunctions("isEditorReadModeEnabled");
2566
- const { useValue: useIsAnalyticsDatabaseWorkerEnabled, setValue: setIsAnalyticsDatabaseWorkerEnabled, addEventHandler: addIsAnalyticsDatabaseWorkerEnabledEventHandler } = makePHEventFunctions("isAnalyticsDatabaseWorkerEnabled");
2567
- const { useValue: useIsDiffAnalyticsEnabled, setValue: setIsDiffAnalyticsEnabled, addEventHandler: addIsDiffAnalyticsEnabledEventHandler } = makePHEventFunctions("isDiffAnalyticsEnabled");
2568
- const { useValue: useIsDriveAnalyticsEnabled, setValue: setIsDriveAnalyticsEnabled, addEventHandler: addIsDriveAnalyticsEnabledEventHandler } = makePHEventFunctions("isDriveAnalyticsEnabled");
2569
- const { useValue: useRenownUrl, setValue: setRenownUrl, addEventHandler: addRenownUrlEventHandler } = makePHEventFunctions("renownUrl");
2570
- const { useValue: useRenownNetworkId, setValue: setRenownNetworkId, addEventHandler: addRenownNetworkIdEventHandler } = makePHEventFunctions("renownNetworkId");
2571
- const { useValue: useRenownChainId, setValue: setRenownChainId, addEventHandler: addRenownChainIdEventHandler } = makePHEventFunctions("renownChainId");
2572
- const { useValue: useSwitchboardUrl, setValue: setSwitchboardUrl, addEventHandler: addSwitchboardUrlEventHandler } = makePHEventFunctions("switchboardUrl");
2573
- const { useValue: useRenownAdapters, setValue: setRenownAdapters, addEventHandler: addRenownAdaptersEventHandler } = makePHEventFunctions("renownAdapters");
2574
- const { useValue: useSentryRelease, setValue: setSentryRelease, addEventHandler: addSentryReleaseEventHandler } = makePHEventFunctions("sentryRelease");
2575
- const { useValue: useSentryDsn, setValue: setSentryDsn, addEventHandler: addSentryDsnEventHandler } = makePHEventFunctions("sentryDsn");
2576
- const { useValue: useSentryEnv, setValue: setSentryEnv, addEventHandler: addSentryEnvEventHandler } = makePHEventFunctions("sentryEnv");
2577
- const { useValue: useIsSentryTracingEnabled, setValue: setIsSentryTracingEnabled, addEventHandler: addIsSentryTracingEnabledEventHandler } = makePHEventFunctions("isSentryTracingEnabled");
2578
- const { useValue: useIsExternalProcessorsEnabled, setValue: setIsExternalProcessorsEnabled, addEventHandler: addIsExternalProcessorsEnabledEventHandler } = makePHEventFunctions("isExternalProcessorsEnabled");
2579
- const { useValue: useIsExternalPackagesEnabled, setValue: setIsExternalPackagesEnabled, addEventHandler: addIsExternalPackagesEnabledEventHandler } = makePHEventFunctions("isExternalPackagesEnabled");
2580
- const enabledEditorsEventFunctions = makePHEventFunctions("enabledEditors");
2581
- /** Sets the enabled editors for Connect. */
2582
- const setEnabledEditors = enabledEditorsEventFunctions.setValue;
2583
- /** Gets the enabled editors for Connect. */
2584
- const useEnabledEditors = enabledEditorsEventFunctions.useValue;
2585
- enabledEditorsEventFunctions.addEventHandler;
2586
- const disabledEditorsEventFunctions = makePHEventFunctions("disabledEditors");
2587
- /** Sets the disabled editors for Connect. */
2588
- const setDisabledEditors = disabledEditorsEventFunctions.setValue;
2589
- /** Gets the disabled editors for Connect. */
2590
- const useDisabledEditors = disabledEditorsEventFunctions.useValue;
2591
- disabledEditorsEventFunctions.addEventHandler;
2592
- const isRelationalProcessorsEnabled = makePHEventFunctions("isRelationalProcessorsEnabled");
2593
- /** Sets the isRelationalProcessorsEnabled for Connect. */
2594
- const setIsRelationalProcessorsEnabled = isRelationalProcessorsEnabled.setValue;
2595
- /** Gets the isRelationalProcessorsEnabled for Connect. */
2596
- const useIsRelationalProcessorsEnabled = isRelationalProcessorsEnabled.useValue;
2597
- isRelationalProcessorsEnabled.addEventHandler;
2598
- const isExternalRelationalProcessorsEnabled = makePHEventFunctions("isExternalRelationalProcessorsEnabled");
2599
- /** Sets the isExternalRelationalProcessorsEnabled for Connect. */
2600
- const setIsExternalRelationalProcessorsEnabled = isExternalRelationalProcessorsEnabled.setValue;
2601
- /** Gets the isExternalRelationalProcessorsEnabled for Connect. */
2602
- const useIsExternalRelationalProcessorsEnabled = isExternalRelationalProcessorsEnabled.useValue;
2603
- isExternalRelationalProcessorsEnabled.addEventHandler;
2604
- const isAnalyticsEnabledEventFunctions = makePHEventFunctions("isAnalyticsEnabled");
2605
- /** Sets the isAnalyticsEnabled for Connect. */
2606
- const setIsAnalyticsEnabled = isAnalyticsEnabledEventFunctions.setValue;
2607
- /** Gets the isAnalyticsEnabled for Connect. */
2608
- const useIsAnalyticsEnabled = isAnalyticsEnabledEventFunctions.useValue;
2609
- isAnalyticsEnabledEventFunctions.addEventHandler;
2610
- const isAnalyticsExternalProcessorsEnabled = makePHEventFunctions("isAnalyticsExternalProcessorsEnabled");
2611
- /** Sets the isAnalyticsExternalProcessorsEnabled for Connect. */
2612
- const setIsAnalyticsExternalProcessorsEnabled = isAnalyticsExternalProcessorsEnabled.setValue;
2613
- /** Gets the isAnalyticsExternalProcessorsEnabled for Connect. */
2614
- const useIsAnalyticsExternalProcessorsEnabled = isAnalyticsExternalProcessorsEnabled.useValue;
2615
- isAnalyticsExternalProcessorsEnabled.addEventHandler;
2616
- const analyticsDatabaseNameEventFunctions = makePHEventFunctions("analyticsDatabaseName");
2617
- /** Sets the analytics database name for Connect. */
2618
- const setAnalyticsDatabaseName = analyticsDatabaseNameEventFunctions.setValue;
2619
- /** Gets the analytics database name for Connect. */
2620
- const useAnalyticsDatabaseName = analyticsDatabaseNameEventFunctions.useValue;
2621
- analyticsDatabaseNameEventFunctions.addEventHandler;
2622
- const logLevelEventFunctions = makePHEventFunctions("logLevel");
2623
- /** Sets the log level for Connect. */
2624
- const setLogLevel = logLevelEventFunctions.setValue;
2625
- /** Gets the log level for Connect. */
2626
- const useLogLevel = logLevelEventFunctions.useValue;
2627
- logLevelEventFunctions.addEventHandler;
2628
- const allowListEventFunctions = makePHEventFunctions("allowList");
2629
- /** Sets the allow list for Connect. */
2630
- const setAllowList = allowListEventFunctions.setValue;
2631
- /** Gets the allow list for Connect. */
2632
- const useAllowList = allowListEventFunctions.useValue;
2633
- allowListEventFunctions.addEventHandler;
2634
- const nonUserConfigSetters = {
2635
- routerBasename: setRouterBasename,
2636
- version: setVersion,
2637
- requiresHardRefresh: setRequiresHardRefresh,
2638
- warnOutdatedApp: setWarnOutdatedApp,
2639
- studioMode: setStudioMode,
2640
- basePath: setBasePath,
2641
- versionCheckInterval: setVersionCheckInterval,
2642
- cliVersion: setCliVersion,
2643
- fileUploadOperationsChunkSize: setFileUploadOperationsChunkSize,
2644
- isDocumentModelSelectionSettingsEnabled: setIsDocumentModelSelectionSettingsEnabled,
2645
- gaTrackingId: setGaTrackingId,
2646
- defaultDrivesUrl: setDefaultDrivesUrl,
2647
- drivesPreserveStrategy: setDrivesPreserveStrategy,
2648
- isLocalDrivesEnabled: setIsLocalDrivesEnabled,
2649
- isAddDriveEnabled: setIsAddDriveEnabled,
2650
- isPublicDrivesEnabled: setIsPublicDrivesEnabled,
2651
- isAddPublicDrivesEnabled: setIsAddPublicDrivesEnabled,
2652
- isDeletePublicDrivesEnabled: setIsDeletePublicDrivesEnabled,
2653
- isCloudDrivesEnabled: setIsCloudDrivesEnabled,
2654
- isAddCloudDrivesEnabled: setIsAddCloudDrivesEnabled,
2655
- isDeleteCloudDrivesEnabled: setIsDeleteCloudDrivesEnabled,
2656
- isAddLocalDrivesEnabled: setIsAddLocalDrivesEnabled,
2657
- isDeleteLocalDrivesEnabled: setIsDeleteLocalDrivesEnabled,
2658
- isEditorDebugModeEnabled: setIsEditorDebugModeEnabled,
2659
- isEditorReadModeEnabled: setIsEditorReadModeEnabled,
2660
- isRelationalProcessorsEnabled: setIsRelationalProcessorsEnabled,
2661
- isExternalRelationalProcessorsEnabled: setIsExternalRelationalProcessorsEnabled,
2662
- isAnalyticsEnabled: setIsAnalyticsEnabled,
2663
- analyticsDatabaseName: setAnalyticsDatabaseName,
2664
- isAnalyticsExternalProcessorsEnabled: setIsAnalyticsExternalProcessorsEnabled,
2665
- isAnalyticsDatabaseWorkerEnabled: setIsAnalyticsDatabaseWorkerEnabled,
2666
- isDiffAnalyticsEnabled: setIsDiffAnalyticsEnabled,
2667
- isDriveAnalyticsEnabled: setIsDriveAnalyticsEnabled,
2668
- renownUrl: setRenownUrl,
2669
- renownNetworkId: setRenownNetworkId,
2670
- renownChainId: setRenownChainId,
2671
- switchboardUrl: setSwitchboardUrl,
2672
- renownAdapters: setRenownAdapters,
2673
- sentryRelease: setSentryRelease,
2674
- sentryDsn: setSentryDsn,
2675
- sentryEnv: setSentryEnv,
2676
- isSentryTracingEnabled: setIsSentryTracingEnabled,
2677
- isExternalProcessorsEnabled: setIsExternalProcessorsEnabled,
2678
- isExternalPackagesEnabled: setIsExternalPackagesEnabled,
2679
- allowList: setAllowList,
2680
- logLevel: setLogLevel,
2681
- disabledEditors: setDisabledEditors,
2682
- enabledEditors: setEnabledEditors
2683
- };
2684
- const phGlobalConfigSetters = {
2685
- ...phAppConfigSetters,
2686
- ...phDocumentEditorConfigSetters,
2687
- ...nonUserConfigSetters
2688
- };
2689
- const nonUserConfigHooks = {
2690
- routerBasename: useRouterBasename,
2691
- version: useVersion,
2692
- requiresHardRefresh: useRequiresHardRefresh,
2693
- warnOutdatedApp: useWarnOutdatedApp,
2694
- studioMode: useStudioMode,
2695
- basePath: useBasePath,
2696
- versionCheckInterval: useVersionCheckInterval,
2697
- cliVersion: useCliVersion,
2698
- fileUploadOperationsChunkSize: useFileUploadOperationsChunkSize,
2699
- isDocumentModelSelectionSettingsEnabled: useIsDocumentModelSelectionSettingsEnabled,
2700
- gaTrackingId: useGaTrackingId,
2701
- defaultDrivesUrl: useDefaultDrivesUrl,
2702
- drivesPreserveStrategy: useDrivesPreserveStrategy,
2703
- isAddDriveEnabled: useIsAddDriveEnabled,
2704
- isPublicDrivesEnabled: useIsPublicDrivesEnabled,
2705
- isAddPublicDrivesEnabled: useIsAddPublicDrivesEnabled,
2706
- isDeletePublicDrivesEnabled: useIsDeletePublicDrivesEnabled,
2707
- isCloudDrivesEnabled: useIsCloudDrivesEnabled,
2708
- isAddCloudDrivesEnabled: useIsAddCloudDrivesEnabled,
2709
- isDeleteCloudDrivesEnabled: useIsDeleteCloudDrivesEnabled,
2710
- isLocalDrivesEnabled: useIsLocalDrivesEnabled,
2711
- isAddLocalDrivesEnabled: useIsAddLocalDrivesEnabled,
2712
- isDeleteLocalDrivesEnabled: useIsDeleteLocalDrivesEnabled,
2713
- isEditorDebugModeEnabled: useIsEditorDebugModeEnabled,
2714
- isEditorReadModeEnabled: useIsEditorReadModeEnabled,
2715
- isAnalyticsDatabaseWorkerEnabled: useIsAnalyticsDatabaseWorkerEnabled,
2716
- isDiffAnalyticsEnabled: useIsDiffAnalyticsEnabled,
2717
- isDriveAnalyticsEnabled: useIsDriveAnalyticsEnabled,
2718
- renownUrl: useRenownUrl,
2719
- renownNetworkId: useRenownNetworkId,
2720
- renownChainId: useRenownChainId,
2721
- switchboardUrl: useSwitchboardUrl,
2722
- renownAdapters: useRenownAdapters,
2723
- sentryRelease: useSentryRelease,
2724
- sentryDsn: useSentryDsn,
2725
- sentryEnv: useSentryEnv,
2726
- isSentryTracingEnabled: useIsSentryTracingEnabled,
2727
- isExternalProcessorsEnabled: useIsExternalProcessorsEnabled,
2728
- isExternalPackagesEnabled: useIsExternalPackagesEnabled,
2729
- allowList: useAllowList,
2730
- isAnalyticsEnabled: useIsAnalyticsEnabled,
2731
- isAnalyticsExternalProcessorsEnabled: useIsAnalyticsExternalProcessorsEnabled,
2732
- isRelationalProcessorsEnabled: useIsRelationalProcessorsEnabled,
2733
- isExternalRelationalProcessorsEnabled: useIsExternalRelationalProcessorsEnabled,
2734
- analyticsDatabaseName: useAnalyticsDatabaseName,
2735
- logLevel: useLogLevel,
2736
- disabledEditors: useDisabledEditors,
2737
- enabledEditors: useEnabledEditors
2738
- };
2739
- ({
2740
- ...phAppConfigHooks,
2741
- ...phDocumentEditorConfigHooks,
2742
- ...nonUserConfigHooks
2743
- });
2744
- const attachmentServiceEventFunctions = makePHEventFunctions("attachmentService");
2745
- attachmentServiceEventFunctions.useValue;
2746
- attachmentServiceEventFunctions.setValue;
2747
- attachmentServiceEventFunctions.addEventHandler;
2748
- const featuresEventFunctions = makePHEventFunctions("features");
2749
- featuresEventFunctions.useValue;
2750
- featuresEventFunctions.setValue;
2751
- featuresEventFunctions.addEventHandler;
2752
- function resolveUrlPathname(path) {
2753
- return new URL(path.replace(/^\/+/, ""), window.location.origin + (window.ph?.basePath ?? "/")).pathname;
2190
+ function extractInitialState(documentScopeOps) {
2191
+ const upgradeOp = documentScopeOps.find((op) => op.action.type === "UPGRADE_DOCUMENT");
2192
+ if (!upgradeOp) throw new Error("No UPGRADE_DOCUMENT operation found — document is invalid");
2193
+ const input = upgradeOp.action.input;
2194
+ const initialState = input.initialState ?? input.state;
2195
+ if (!initialState) throw new Error("UPGRADE_DOCUMENT operation has no initialState — document is invalid");
2196
+ return initialState;
2197
+ }
2198
+ function filterDomainOperations(operations) {
2199
+ return Object.fromEntries(Object.entries(operations).filter(([scope]) => !NON_DOMAIN_SCOPES.has(scope)));
2200
+ }
2201
+ function countOperations(operations) {
2202
+ let total = 0;
2203
+ for (const ops of Object.values(operations)) total += ops?.length ?? 0;
2204
+ return total;
2205
+ }
2206
+ /**
2207
+ * Split an imported document's domain operations at its mid-history upgrade
2208
+ * boundaries, so the caller can re-dispatch each upgrade between segments.
2209
+ *
2210
+ * The seed's CREATE_DOCUMENT and 0 -> N upgrade are replayed by the creation
2211
+ * path and must not be repeated. A later upgrade must be: it is where the
2212
+ * reducer version changes, and dropping it replays everything after it through
2213
+ * the module the document was created with.
2214
+ */
2215
+ function splitAtUpgradeBoundaries(operations) {
2216
+ const upgrades = (operations.document ?? []).filter((op) => op.action.type === "UPGRADE_DOCUMENT").filter((op) => op.action.input.fromVersion > 0).sort((a, b) => a.index - b.index);
2217
+ const domain = filterDomainOperations(operations);
2218
+ if (upgrades.length === 0) return [{ operations: domain }];
2219
+ const segments = [];
2220
+ const consumed = /* @__PURE__ */ new Map();
2221
+ const take = (until) => {
2222
+ const slice = {};
2223
+ for (const [scope, ops] of Object.entries(domain)) {
2224
+ if (!ops) continue;
2225
+ const from = consumed.get(scope) ?? 0;
2226
+ const stop = Math.max(from, until(scope, ops));
2227
+ const chunk = ops.slice(from, stop);
2228
+ if (chunk.length > 0) slice[scope] = chunk;
2229
+ consumed.set(scope, stop);
2230
+ }
2231
+ return slice;
2232
+ };
2233
+ for (const upgrade of upgrades) {
2234
+ const input = upgrade.action.input;
2235
+ const slice = take((scope, ops) => boundary(upgrade, scope, ops));
2236
+ segments.push({
2237
+ operations: slice,
2238
+ upgradeTo: input.toVersion
2239
+ });
2240
+ }
2241
+ const tail = take((_scope, ops) => ops.length);
2242
+ if (countOperations(tail) > 0) segments.push({ operations: tail });
2243
+ return segments;
2244
+ }
2245
+ /**
2246
+ * How many of a scope's operations precede an upgrade. Must stay identical to
2247
+ * the boundary computation in `replayDocumentVersioned` — snapshots compare
2248
+ * against operation indices, not array positions, and the timestamp fallback
2249
+ * excludes the upgrade's own instant.
2250
+ */
2251
+ function boundary(upgrade, scope, ops) {
2252
+ const snapshot = upgrade.action.input.revision;
2253
+ if (snapshot !== void 0) {
2254
+ const revision = snapshot[scope] ?? 0;
2255
+ let count = 0;
2256
+ for (let i = 0; i < ops.length; i++) if (ops[i].index < revision) count = i + 1;
2257
+ return count;
2258
+ }
2259
+ for (let i = 0; i < ops.length; i++) if (ops[i].timestampUtcMs >= upgrade.timestampUtcMs) return i;
2260
+ return ops.length;
2261
+ }
2262
+ async function exportFile(document, suggestedName) {
2263
+ const reactorClient = window.ph?.reactorClient;
2264
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2265
+ const operations = await fetchDocumentOperations(reactorClient, document);
2266
+ const initialState = extractInitialState(operations["document"] ?? []);
2267
+ const documentWithOps = {
2268
+ ...document,
2269
+ operations,
2270
+ initialState
2271
+ };
2272
+ const extension = await getDocumentExtension(documentWithOps);
2273
+ const baseName = suggestedName || documentWithOps.header.name || "Untitled";
2274
+ const name = extension ? `${baseName}.${extension}.phd` : `${baseName}.phd`;
2275
+ if (!window.showSaveFilePicker) return await downloadFile(documentWithOps, name);
2276
+ try {
2277
+ const fileHandle = await window.showSaveFilePicker({ suggestedName: name });
2278
+ await baseSaveToFileHandle(documentWithOps, fileHandle);
2279
+ return fileHandle;
2280
+ } catch (e) {
2281
+ if (!(e instanceof DOMException && e.name === "AbortError")) throw e;
2282
+ }
2283
+ }
2284
+ /**
2285
+ * Loads a document file and replays it with version-aware reducers from the registry.
2286
+ * Falls back to single-version legacy replay when no upgrade manifest is registered for
2287
+ * the document type.
2288
+ */
2289
+ async function loadFile(path) {
2290
+ const baseDocument = await baseLoadFromInput(path, (state) => state, { checkHashes: true });
2291
+ const reactorClient = window.ph?.reactorClientModule?.client;
2292
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2293
+ const documentType = baseDocument.header.documentType;
2294
+ const { results: documentModelModules } = await reactorClient.getDocumentModelModules();
2295
+ const modulesForType = documentModelModules.filter((module) => module.documentModel.global.id === documentType);
2296
+ if (modulesForType.length === 0) throw new DocumentModelNotFoundError(documentType);
2297
+ const reducers = {};
2298
+ for (const module of modulesForType) reducers[module.version ?? 1] = module.reducer;
2299
+ const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
2300
+ let upgradeManifest;
2301
+ if (registry) try {
2302
+ upgradeManifest = registry.getUpgradeManifest(documentType);
2303
+ } catch {}
2304
+ return baseLoadFromInputVersioned(path, {
2305
+ reducers,
2306
+ upgradeManifest
2307
+ });
2308
+ }
2309
+ async function addDocument(driveId, name, documentType, parentFolder, document, id, preferredEditor, documentModelVersion) {
2310
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2311
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create documents");
2312
+ const reactorClient = window.ph?.reactorClientModule?.client;
2313
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2314
+ let documentModelModule;
2315
+ if (documentModelVersion !== void 0) {
2316
+ const { results: documentModelModules } = await reactorClient.getDocumentModelModules();
2317
+ const module = documentModelModules.find((m) => m.documentModel.global.id === documentType && (m.version ?? 1) === documentModelVersion);
2318
+ if (!module) throw new Error(`Document model not found for type: ${documentType} with version: ${documentModelVersion}`);
2319
+ documentModelModule = module;
2320
+ } else documentModelModule = await reactorClient.getDocumentModelModule(documentType);
2321
+ const newDocument = document ?? documentModelModule.utils.createDocument();
2322
+ if (!document) newDocument.state.document.version = documentModelModule.version ?? 1;
2323
+ newDocument.header.name = name;
2324
+ if (preferredEditor) newDocument.header.meta = {
2325
+ ...newDocument.header.meta,
2326
+ preferredEditor
2327
+ };
2328
+ let newDoc;
2329
+ try {
2330
+ newDoc = await reactorClient.drives.addFile(driveId, newDocument, parentFolder);
2331
+ } catch (e) {
2332
+ logger.error("Error adding document: @error", e);
2333
+ throw new Error("There was an error adding document", { cause: e });
2334
+ }
2335
+ return {
2336
+ id: newDoc.header.id,
2337
+ name: newDoc.header.name,
2338
+ documentType,
2339
+ parentFolder: parentFolder ?? null,
2340
+ kind: "file"
2341
+ };
2342
+ }
2343
+ /**
2344
+ * How many ids an import will try before giving up. The check before the create
2345
+ * catches an id that is already taken; this bound covers the window between the
2346
+ * two, where a create can still lose to a claim made in the meantime.
2347
+ */
2348
+ const IMPORT_ID_ATTEMPTS = 3;
2349
+ /** True when this error, or anything it wraps, is a taken document id. */
2350
+ function isDocumentAlreadyExists(error) {
2351
+ let current = error;
2352
+ while (current instanceof Error) {
2353
+ if (current.name === "DocumentAlreadyExistsError") return true;
2354
+ current = current.cause;
2355
+ }
2356
+ return false;
2357
+ }
2358
+ /**
2359
+ * Creates the imported document under an id that is free, retrying on a
2360
+ * collision.
2361
+ *
2362
+ * The check cannot stand on its own: it answers for the moment it ran, and the
2363
+ * create that follows can still land on an id claimed in between. The store
2364
+ * rejects that create as DocumentAlreadyExistsError, which is not retryable
2365
+ * under the same id and is resolved by minting another one. A create that
2366
+ * fails leaves the drive untouched, so a retry has nothing to clean up.
2367
+ */
2368
+ async function createImportedDocument(reactor, document, driveId, name, parentFolder) {
2369
+ let documentId = await reactor.isDocumentIdTaken(document.header.id) ? generateId() : document.header.id;
2370
+ for (let attempt = 1;; attempt++) {
2371
+ const header = createPresignedHeader(documentId, document.header.documentType);
2372
+ header.lastModifiedAtUtcIso = document.header.createdAtUtcIso;
2373
+ header.meta = document.header.meta;
2374
+ header.name = name || document.header.name;
2375
+ const initialDocument = {
2376
+ ...document,
2377
+ header,
2378
+ state: document.initialState,
2379
+ operations: Object.keys(document.operations).reduce((acc, key) => {
2380
+ acc[key] = [];
2381
+ return acc;
2382
+ }, {})
2383
+ };
2384
+ try {
2385
+ const fileNode = await addDocument(driveId, name || document.header.name, document.header.documentType, parentFolder, initialDocument, documentId, document.header.meta?.preferredEditor);
2386
+ if (!fileNode) throw new Error("There was an error adding file");
2387
+ return {
2388
+ documentId,
2389
+ fileNode
2390
+ };
2391
+ } catch (error) {
2392
+ if (!isDocumentAlreadyExists(error) || attempt === IMPORT_ID_ATTEMPTS) throw error;
2393
+ logger.warn(`Document id ${documentId} was taken between the check and the create; importing under a new id`);
2394
+ documentId = generateId();
2395
+ }
2396
+ }
2397
+ }
2398
+ async function addFileWithProgress(file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict) {
2399
+ logger.verbose(`addFileWithProgress(drive: ${driveId}, name: ${name}, folder: ${parentFolder})`);
2400
+ const reactor = window.ph?.reactorClientModule?.client;
2401
+ if (!reactor) {
2402
+ onProgress?.({
2403
+ stage: "failed",
2404
+ progress: 100,
2405
+ error: "ReactorClient not initialized"
2406
+ });
2407
+ throw new Error("ReactorClient not initialized");
2408
+ }
2409
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2410
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create files");
2411
+ try {
2412
+ onProgress?.({
2413
+ stage: "loading",
2414
+ progress: 0
2415
+ });
2416
+ let document;
2417
+ try {
2418
+ document = await loadFile(file);
2419
+ } catch (loadError) {
2420
+ if (UnsupportedDocumentModelVersionError.isError(loadError)) {
2421
+ showPHModal({
2422
+ type: "documentVersionUnsupported",
2423
+ documentType: loadError.documentType,
2424
+ requiredVersion: loadError.requiredVersion,
2425
+ availableVersions: loadError.availableVersions
2426
+ });
2427
+ onProgress?.({
2428
+ stage: "failed",
2429
+ progress: 100,
2430
+ error: loadError.message
2431
+ });
2432
+ return;
2433
+ }
2434
+ const discoveryService = window.ph?.packageDiscoveryService;
2435
+ if (discoveryService && DocumentModelNotFoundError.isError(loadError)) {
2436
+ retryAfterDiscovery(discoveryService, loadError.documentType, file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict).catch((retryError) => {
2437
+ logger.error("Import retry after discovery failed: @error", retryError);
2438
+ onProgress?.({
2439
+ stage: "failed",
2440
+ progress: 100,
2441
+ error: retryError instanceof Error ? retryError.message : String(retryError)
2442
+ });
2443
+ });
2444
+ return;
2445
+ }
2446
+ throw loadError;
2447
+ }
2448
+ const duplicateCheck = await isDocumentInLocation(reactor, document, driveId, parentFolder);
2449
+ if (duplicateCheck.isDuplicate && !resolveConflict) {
2450
+ onProgress?.({
2451
+ stage: "conflict",
2452
+ progress: 0,
2453
+ duplicateType: duplicateCheck.duplicateType
2454
+ });
2455
+ return;
2456
+ }
2457
+ const documentType = getDocumentTypeIcon(document);
2458
+ if (documentType) onProgress?.({
2459
+ stage: "loading",
2460
+ progress: 10,
2461
+ documentType
2462
+ });
2463
+ else onProgress?.({
2464
+ stage: "loading",
2465
+ progress: 10
2466
+ });
2467
+ if (!isDocumentTypeSupported(document.header.documentType, documentTypes)) {
2468
+ onProgress?.({
2469
+ stage: "unsupported-document-type",
2470
+ progress: 100,
2471
+ error: `Document type ${document.header.documentType} is not supported`
2472
+ });
2473
+ throw new UnsupportedDocumentTypeError(document.header.documentType);
2474
+ }
2475
+ await reactor.getDocumentModelModule(document.header.documentType);
2476
+ onProgress?.({
2477
+ stage: "initializing",
2478
+ progress: 10
2479
+ });
2480
+ const created = await createImportedDocument(reactor, document, driveId, name, parentFolder);
2481
+ const documentId = created.documentId;
2482
+ const fileNode = created.fileNode;
2483
+ onProgress?.({
2484
+ stage: "initializing",
2485
+ progress: 20
2486
+ });
2487
+ await reactor.get(documentId);
2488
+ console.log("Document created, starting upload of operations");
2489
+ const segments = splitAtUpgradeBoundaries(document.operations);
2490
+ const totalOperations = segments.reduce((total, segment) => total + countOperations(segment.operations), 0);
2491
+ let uploadedBefore = 0;
2492
+ for (const segment of segments) {
2493
+ await uploadOperations(documentId, segment.operations, queueOperations, { onProgress: (uploadProgress) => {
2494
+ if (uploadProgress.uploadedOperations === void 0) return;
2495
+ const uploaded = uploadedBefore + uploadProgress.uploadedOperations;
2496
+ const uploadPercent = totalOperations > 0 ? uploaded / totalOperations : 0;
2497
+ onProgress?.({
2498
+ stage: "uploading",
2499
+ progress: 20 + Math.round(uploadPercent * 80),
2500
+ totalOperations,
2501
+ uploadedOperations: uploaded
2502
+ });
2503
+ } });
2504
+ uploadedBefore += countOperations(segment.operations);
2505
+ if (segment.upgradeTo !== void 0) await reactor.upgradeDocument(documentId, segment.upgradeTo);
2506
+ }
2507
+ onProgress?.({
2508
+ stage: "complete",
2509
+ progress: 100,
2510
+ fileNode
2511
+ });
2512
+ return fileNode;
2513
+ } catch (error) {
2514
+ if (!UnsupportedDocumentTypeError.isError(error)) {
2515
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
2516
+ onProgress?.({
2517
+ stage: "failed",
2518
+ progress: 100,
2519
+ error: errorMessage
2520
+ });
2521
+ }
2522
+ throw error;
2523
+ }
2754
2524
  }
2755
- /** Returns the current path without the base path */
2756
- function getPathWithoutBase(path) {
2757
- const basePath = window.ph?.basePath ?? "/";
2758
- return path.replace(basePath, basePath.endsWith("/") ? "/" : "");
2525
+ async function retryAfterDiscovery(discoveryService, documentType, file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict) {
2526
+ if (!discoveryService) return;
2527
+ try {
2528
+ await discoveryService.load(documentType);
2529
+ } catch {
2530
+ onProgress?.({
2531
+ stage: "unsupported-document-type",
2532
+ progress: 100,
2533
+ error: `Document type ${documentType} is not supported`
2534
+ });
2535
+ return;
2536
+ }
2537
+ await addFileWithProgress(file, driveId, name, parentFolder, onProgress, documentTypes, resolveConflict);
2759
2538
  }
2760
- /** Makes a URL component for a node. */
2761
- function makeNodeSlug(node) {
2762
- if (!node) return "";
2763
- const nodeName = node.name;
2764
- if (!nodeName) return slug(node.id);
2765
- return slug(`${nodeName}-${node.id}`);
2539
+ async function addFolder$1(driveId, name, parentFolder) {
2540
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2541
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to create folders");
2542
+ const reactorClient = window.ph?.reactorClient;
2543
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2544
+ await reactorClient.get(driveId);
2545
+ const folderId = generateId();
2546
+ const node = (await reactorClient.execute(driveId, "main", [addFolder({
2547
+ id: folderId,
2548
+ name,
2549
+ parentFolder
2550
+ })])).state.global.nodes.find((node) => node.id === folderId);
2551
+ if (!node || !isFolderNode(node)) throw new Error("There was an error adding folder");
2552
+ return node;
2766
2553
  }
2767
- /** Extracts the node slug from a path.
2768
- *
2769
- * The path is expected to be in the format `/d/<drive-slug>/<node-slug>`.
2770
- */
2771
- function extractNodeSlugFromPath(path) {
2772
- const currentPath = getPathWithoutBase(path);
2773
- return /^\/d\/[^/]+\/([^/]+)$/.exec(currentPath)?.[1];
2554
+ async function renameNode(driveId, nodeId, name) {
2555
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2556
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to rename documents");
2557
+ const reactorClient = window.ph?.reactorClient;
2558
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2559
+ if ((await reactorClient.execute(nodeId, "main", [setName({ name })])).header.name !== name) throw new Error("There was an error renaming the node");
2560
+ const node = (await reactorClient.execute(driveId, "main", [updateNode({
2561
+ id: nodeId,
2562
+ name
2563
+ })])).state.global.nodes.find((n) => n.id === nodeId);
2564
+ if (!node) throw new Error("There was an error renaming node in the drive");
2565
+ return node;
2774
2566
  }
2775
- /** Finds a UUID in a string, used for extracting node ids from node slugs in the URL. */
2776
- function findUuid(input) {
2777
- if (!input) return void 0;
2778
- return /\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/.exec(input)?.[0];
2567
+ async function renameDriveNode(driveId, nodeId, name) {
2568
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2569
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to rename documents");
2570
+ const reactorClient = window.ph?.reactorClient;
2571
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2572
+ if ((await reactorClient.execute(nodeId, "main", [setName({ name })])).header.name !== name) throw new Error("There was an error renaming the node");
2573
+ await reactorClient.execute(driveId, "main", [updateNode({
2574
+ id: nodeId,
2575
+ name
2576
+ })]);
2577
+ return (await reactorClient.get(driveId)).state.global.nodes.find((n) => n.id === nodeId);
2779
2578
  }
2780
- function extractNodeIdFromSlug(nodeSlug) {
2781
- return findUuid(nodeSlug);
2579
+ async function moveNodeById(args) {
2580
+ const { driveId, srcId, targetId } = args;
2581
+ if (!driveId || !srcId) return;
2582
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2583
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to move documents");
2584
+ const reactorClient = window.ph?.reactorClient;
2585
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2586
+ const targetParentFolder = t$3(targetId, [e$3(e$4), e$6(void 0)], [t(driveId), e$6(void 0)], e$6(targetId));
2587
+ if (t(targetParentFolder, srcId)) return;
2588
+ return await reactorClient.execute(driveId, "main", [moveNode({
2589
+ srcFolder: srcId,
2590
+ targetParentFolder
2591
+ })]);
2782
2592
  }
2783
- /** Extracts the drive slug from a path.
2784
- * Used for extracting drive ids from drive slugs in the URL.
2785
- * Expects the path to be in the format `/d/<drive-slug>`.
2786
- */
2787
- function extractDriveSlugFromPath(path) {
2788
- const currentPath = getPathWithoutBase(path);
2789
- return /^\/d\/([^/]+)/.exec(currentPath)?.[1] ?? "";
2593
+ async function moveNode$1(driveId, src, target) {
2594
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2595
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to move documents");
2596
+ const reactorClient = window.ph?.reactorClient;
2597
+ if (!reactorClient) throw new Error("ReactorClient not initialized");
2598
+ return await reactorClient.execute(driveId, "main", [moveNode({
2599
+ srcFolder: src.id,
2600
+ targetParentFolder: target?.id
2601
+ })]);
2790
2602
  }
2791
2603
  /**
2792
- * Creates a URL string with the given pathname while preserving existing query parameters.
2604
+ * Duplicates a document under a new id using version-aware replay.
2605
+ * Falls back gracefully when no upgrade manifest is registered for the document type.
2793
2606
  */
2794
- function createUrlWithPreservedParams(pathname) {
2795
- const search = window.location.search;
2796
- return search ? `${pathname}${search}` : pathname;
2797
- }
2798
- const drivesEventFunctions = makePHEventFunctions("drives");
2799
- /** Returns all of the drives in the reactor */
2800
- const useDrives = drivesEventFunctions.useValue;
2801
- /** Sets the drives in the reactor */
2802
- const setDrives = drivesEventFunctions.setValue;
2803
- drivesEventFunctions.addEventHandler;
2804
- const selectedNodeIdEventFunctions = makePHEventFunctions("selectedNodeId");
2805
- const useSelectedNodeId = selectedNodeIdEventFunctions.useValue;
2806
- const setSelectedNodeId = selectedNodeIdEventFunctions.setValue;
2807
- selectedNodeIdEventFunctions.addEventHandler;
2808
- /** Sets the selected node (file or folder). */
2809
- function setSelectedNode(nodeOrNodeSlug) {
2810
- const nodeSlug = typeof nodeOrNodeSlug === "string" ? nodeOrNodeSlug : makeNodeSlug(nodeOrNodeSlug);
2811
- setSelectedNodeId(extractNodeIdFromSlug(nodeSlug));
2812
- const driveSlugFromPath = extractDriveSlugFromPath(window.location.pathname);
2813
- if (!driveSlugFromPath) return;
2814
- if (!nodeSlug) {
2815
- const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}`);
2816
- if (pathname === window.location.pathname) return;
2817
- window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
2818
- return;
2819
- }
2820
- const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}/${nodeSlug}`);
2821
- if (pathname === window.location.pathname) return;
2822
- window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
2823
- }
2824
- const selectedDriveIdEventFunctions = makePHEventFunctions("selectedDriveId");
2825
- /** Returns the selected drive id */
2826
- const useSelectedDriveId = selectedDriveIdEventFunctions.useValue;
2827
- /** Sets the selected drive id */
2828
- const setSelectedDriveId = selectedDriveIdEventFunctions.setValue;
2829
- selectedDriveIdEventFunctions.addEventHandler;
2830
- /** Returns the selected drive, or undefined if no drive is selected */
2831
- function useSelectedDriveSafe() {
2832
- const selectedDriveId = useSelectedDriveId();
2833
- const selectedDrive = useDrives()?.find((drive) => drive.header.id === selectedDriveId);
2834
- const [drive, dispatch] = useDispatch(selectedDrive);
2835
- if (!selectedDrive) return [void 0, void 0];
2836
- return [drive, dispatch];
2837
- }
2838
- function setSelectedDrive(driveOrDriveSlug) {
2839
- const driveSlug = typeof driveOrDriveSlug === "string" ? driveOrDriveSlug : driveOrDriveSlug?.header.slug;
2840
- const drives = window.ph?.drives;
2841
- const driveId = (typeof driveOrDriveSlug === "object" && driveOrDriveSlug !== null ? driveOrDriveSlug : drives?.find((d) => d.header.slug === driveSlug))?.header.id;
2842
- if (!driveId && driveSlug && extractDriveSlugFromPath(window.location.pathname) === driveSlug) {
2843
- if (window.ph?.selectedDriveId) setSelectedDriveId(void 0);
2844
- deferDriveSelection(driveSlug);
2845
- return;
2846
- }
2847
- cancelPendingDriveSelection();
2848
- setSelectedDriveId(driveId);
2849
- if (!driveId) {
2850
- const pathname = resolveUrlPathname("/");
2851
- if (pathname === window.location.pathname) return;
2852
- window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
2853
- return;
2854
- }
2855
- const pathname = resolveUrlPathname(`/d/${driveSlug}`);
2856
- if (pathname === window.location.pathname) return;
2857
- window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
2607
+ async function _duplicateDocument(reactor, document, newId = generateId()) {
2608
+ const documentType = document.header.documentType;
2609
+ const { results: allModules } = await reactor.getDocumentModelModules();
2610
+ const modulesForType = allModules.filter((m) => m.documentModel.global.id === documentType);
2611
+ const reducers = {};
2612
+ for (const m of modulesForType) reducers[m.version ?? 1] = m.reducer;
2613
+ if (Object.keys(reducers).length === 0) throw new Error(`Document model module not found for type: ${documentType}`);
2614
+ const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
2615
+ let upgradeManifest;
2616
+ if (registry) try {
2617
+ upgradeManifest = registry.getUpgradeManifest(documentType);
2618
+ } catch {}
2619
+ const config = {
2620
+ reducers,
2621
+ upgradeManifest
2622
+ };
2623
+ const header = createPresignedHeader(newId, documentType);
2624
+ const duplicated = replayDocumentVersioned(document.initialState, document.operations, config, header);
2625
+ assertAuthPreservedOnDuplicate(document.header.id, document.state.auth, duplicated.state.auth);
2626
+ return duplicated;
2858
2627
  }
2859
- const DEFERRED_DRIVE_TICK_MS = 2e3;
2860
- const DEFERRED_DRIVE_MAX_WAIT_MS = 15e3;
2861
- function isInitialSyncInFlight() {
2862
- const remotes = window.ph?.reactorClientModule?.reactorModule?.syncModule?.syncManager?.list();
2863
- if (!remotes?.length) return false;
2864
- return remotes.some((remote) => {
2865
- try {
2866
- const snapshot = remote.channel.getConnectionState();
2867
- return snapshot.receivingPages || !snapshot.lastSuccessUtcMs && snapshot.state !== "error";
2868
- } catch {
2869
- return false;
2628
+ async function copyNode$1(driveId, src, target) {
2629
+ const reactor = window.ph?.reactorClientModule?.client;
2630
+ if (!reactor) return;
2631
+ const { isAllowedToCreateDocuments } = getUserPermissions();
2632
+ if (!isAllowedToCreateDocuments) throw new Error("User is not allowed to copy documents");
2633
+ const drive = await reactor.get(driveId);
2634
+ const copyNodesInput = generateNodesCopy({
2635
+ srcId: src.id,
2636
+ targetParentFolder: target?.id,
2637
+ targetName: src.name
2638
+ }, () => generateId(), drive.state.global.nodes);
2639
+ const resolvedNamesMap = /* @__PURE__ */ new Map();
2640
+ for (const copyNodeInput of copyNodesInput) {
2641
+ const node = drive.state.global.nodes.find((n) => n.id === copyNodeInput.srcId);
2642
+ if (node) {
2643
+ const resolvedName = handleTargetNameCollisions({
2644
+ nodes: drive.state.global.nodes,
2645
+ srcName: copyNodeInput.targetName || node.name,
2646
+ srcKind: isFileNode(node) ? "file" : "folder",
2647
+ targetParentFolder: copyNodeInput.targetParentFolder || null
2648
+ });
2649
+ resolvedNamesMap.set(copyNodeInput.targetId, resolvedName);
2870
2650
  }
2871
- });
2872
- }
2873
- let pendingHandler;
2874
- let pendingTimeout;
2875
- function cancelPendingDriveSelection() {
2876
- if (pendingHandler) {
2877
- window.removeEventListener("ph:drivesUpdated", pendingHandler);
2878
- pendingHandler = void 0;
2879
2651
  }
2880
- if (pendingTimeout) {
2881
- clearTimeout(pendingTimeout);
2882
- pendingTimeout = void 0;
2652
+ const fileNodesToCopy = copyNodesInput.filter((copyNodeInput) => {
2653
+ const node = drive.state.global.nodes.find((node) => node.id === copyNodeInput.srcId);
2654
+ return node !== void 0 && isFileNode(node);
2655
+ });
2656
+ for (const fileNodeToCopy of fileNodesToCopy) try {
2657
+ const duplicatedDocument = await _duplicateDocument(reactor, await reactor.get(fileNodeToCopy.srcId), fileNodeToCopy.targetId);
2658
+ const resolvedName = resolvedNamesMap.get(fileNodeToCopy.targetId);
2659
+ if (resolvedName) duplicatedDocument.header.name = resolvedName;
2660
+ await reactor.drives.addFile(driveId, duplicatedDocument, target?.id);
2661
+ } catch (e) {
2662
+ logger.error(`Error copying document ${fileNodeToCopy.srcId}: ${String(e)}`);
2883
2663
  }
2664
+ return await queueActions(drive, copyNodesInput.map((copyNodeInput) => copyNode(copyNodeInput)));
2884
2665
  }
2885
- function deferDriveSelection(driveSlug) {
2886
- cancelPendingDriveSelection();
2887
- const nodeSlug = extractNodeSlugFromPath(window.location.pathname);
2888
- const handler = () => {
2889
- if (!window.ph?.drives?.find((d) => d.header.slug === driveSlug)) return;
2890
- cancelPendingDriveSelection();
2891
- setSelectedDrive(driveSlug);
2892
- setSelectedNode(nodeSlug);
2893
- };
2894
- pendingHandler = handler;
2895
- window.addEventListener("ph:drivesUpdated", handler);
2896
- const deadline = Date.now() + DEFERRED_DRIVE_MAX_WAIT_MS;
2897
- const scheduleTick = () => {
2898
- pendingTimeout = setTimeout(() => {
2899
- if (Date.now() < deadline && isInitialSyncInFlight()) {
2900
- scheduleTick();
2901
- return;
2902
- }
2903
- cancelPendingDriveSelection();
2904
- const pathname = resolveUrlPathname("/");
2905
- if (pathname === window.location.pathname) return;
2906
- window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
2907
- }, DEFERRED_DRIVE_TICK_MS);
2908
- };
2909
- scheduleTick();
2666
+ /**
2667
+ * The operation selection of `GetDocumentOperations`, lifted into a fragment so
2668
+ * the write path can reuse `remoteOperationToLocal` on the items it selects.
2669
+ */
2670
+ const ReactorOperationFieldsFragmentDoc = import_main.gql`
2671
+ fragment ReactorOperationFields on ReactorOperation {
2672
+ index
2673
+ timestampUtcMs
2674
+ hash
2675
+ skip
2676
+ error
2677
+ deniedReason
2678
+ id
2679
+ action {
2680
+ id
2681
+ type
2682
+ timestampUtcMs
2683
+ input
2684
+ scope
2685
+ context {
2686
+ signer {
2687
+ user {
2688
+ address
2689
+ networkId
2690
+ chainId
2691
+ }
2692
+ app {
2693
+ name
2694
+ key
2695
+ }
2696
+ signatures
2697
+ }
2698
+ }
2699
+ }
2700
+ }
2701
+ `;
2702
+ import_main.gql`
2703
+ mutation MutateDocumentWithOperations(
2704
+ $documentIdentifier: String!
2705
+ $actions: [ActionInput!]!
2706
+ $sinceRevision: Int
2707
+ $scopes: [String!]
2708
+ $branch: String
2709
+ ) {
2710
+ mutateDocument: execute(
2711
+ documentIdentifier: $documentIdentifier
2712
+ actions: $actions
2713
+ branch: $branch
2714
+ ) {
2715
+ ...PHDocumentFields
2716
+ operations(
2717
+ filter: {
2718
+ sinceRevision: $sinceRevision
2719
+ scopes: $scopes
2720
+ branch: $branch
2721
+ }
2722
+ ) {
2723
+ items {
2724
+ ...ReactorOperationFields
2725
+ }
2726
+ }
2727
+ }
2728
+ }
2729
+ ${PhDocumentFieldsFragmentDoc}
2730
+ ${ReactorOperationFieldsFragmentDoc}
2731
+ `;
2732
+ DocumentChangeType.Created, DOCUMENT_CHANGE_TYPE.Created, DocumentChangeType.Deleted, DOCUMENT_CHANGE_TYPE.Deleted, DocumentChangeType.Updated, DOCUMENT_CHANGE_TYPE.Updated, DocumentChangeType.ParentAdded, DOCUMENT_CHANGE_TYPE.ParentAdded, DocumentChangeType.ParentRemoved, DOCUMENT_CHANGE_TYPE.ParentRemoved, DocumentChangeType.ChildAdded, DOCUMENT_CHANGE_TYPE.ChildAdded, DocumentChangeType.ChildRemoved, DOCUMENT_CHANGE_TYPE.ChildRemoved;
2733
+ PropagationMode.Cascade, PropagationMode.Orphan;
2734
+ const isExternalControlsEnabledEventFunctions = makePHEventFunctions("isExternalControlsEnabled");
2735
+ /** Sets whether external controls are enabled for a given editor. */
2736
+ const setIsExternalControlsEnabled = isExternalControlsEnabledEventFunctions.setValue;
2737
+ /** Gets whether external controls are enabled for a given editor. */
2738
+ const useIsExternalControlsEnabled = isExternalControlsEnabledEventFunctions.useValue;
2739
+ isExternalControlsEnabledEventFunctions.addEventHandler;
2740
+ const isDragAndDropEnabledEventFunctions = makePHEventFunctions("isDragAndDropEnabled");
2741
+ /** Sets whether drag and drop is enabled for a given app. */
2742
+ const setIsDragAndDropEnabled = isDragAndDropEnabledEventFunctions.setValue;
2743
+ /** Gets whether drag and drop is enabled for a given app. */
2744
+ const useIsDragAndDropEnabled = isDragAndDropEnabledEventFunctions.useValue;
2745
+ isDragAndDropEnabledEventFunctions.addEventHandler;
2746
+ const allowedDocumentTypesEventFunctions = makePHEventFunctions("allowedDocumentTypes");
2747
+ /** Sets the allowed document types for a given app. */
2748
+ const setAllowedDocumentTypes = allowedDocumentTypesEventFunctions.setValue;
2749
+ /** Defines the document types a drive supports.
2750
+ *
2751
+ * Defaults to all of the document types registered in the reactor.
2752
+ */
2753
+ function useAllowedDocumentTypes() {
2754
+ return allowedDocumentTypesEventFunctions.useValue();
2910
2755
  }
2756
+ allowedDocumentTypesEventFunctions.addEventHandler;
2757
+ const phAppConfigSetters = {
2758
+ allowedDocumentTypes: setAllowedDocumentTypes,
2759
+ isDragAndDropEnabled: setIsDragAndDropEnabled
2760
+ };
2761
+ const phDocumentEditorConfigSetters = { isExternalControlsEnabled: setIsExternalControlsEnabled };
2762
+ const phAppConfigHooks = {
2763
+ allowedDocumentTypes: useAllowedDocumentTypes,
2764
+ isDragAndDropEnabled: useIsDragAndDropEnabled
2765
+ };
2766
+ const phDocumentEditorConfigHooks = { isExternalControlsEnabled: useIsExternalControlsEnabled };
2767
+ const { useValue: useRouterBasename, setValue: setRouterBasename, addEventHandler: addRouterBasenameEventHandler } = makePHEventFunctions("routerBasename");
2768
+ const { useValue: useVersion, setValue: setVersion, addEventHandler: addVersionEventHandler } = makePHEventFunctions("version");
2769
+ const { useValue: useRequiresHardRefresh, setValue: setRequiresHardRefresh, addEventHandler: addRequiresHardRefreshEventHandler } = makePHEventFunctions("requiresHardRefresh");
2770
+ const { useValue: useWarnOutdatedApp, setValue: setWarnOutdatedApp, addEventHandler: addWarnOutdatedAppEventHandler } = makePHEventFunctions("warnOutdatedApp");
2771
+ const { useValue: useStudioMode, setValue: setStudioMode, addEventHandler: addStudioModeEventHandler } = makePHEventFunctions("studioMode");
2772
+ const { useValue: useBasePath, setValue: setBasePath, addEventHandler: addBasePathEventHandler } = makePHEventFunctions("basePath");
2773
+ const { useValue: useVersionCheckInterval, setValue: setVersionCheckInterval, addEventHandler: addVersionCheckIntervalEventHandler } = makePHEventFunctions("versionCheckInterval");
2774
+ const { useValue: useCliVersion, setValue: setCliVersion, addEventHandler: addCliVersionEventHandler } = makePHEventFunctions("cliVersion");
2775
+ const { useValue: useFileUploadOperationsChunkSize, setValue: setFileUploadOperationsChunkSize, addEventHandler: addFileUploadOperationsChunkSizeEventHandler } = makePHEventFunctions("fileUploadOperationsChunkSize");
2776
+ const { useValue: useIsDocumentModelSelectionSettingsEnabled, setValue: setIsDocumentModelSelectionSettingsEnabled, addEventHandler: addIsDocumentModelSelectionSettingsEnabledEventHandler } = makePHEventFunctions("isDocumentModelSelectionSettingsEnabled");
2777
+ const { useValue: useGaTrackingId, setValue: setGaTrackingId, addEventHandler: addGaTrackingIdEventHandler } = makePHEventFunctions("gaTrackingId");
2778
+ const { useValue: useDefaultDrivesUrl, setValue: setDefaultDrivesUrl, addEventHandler: addDefaultDrivesUrlEventHandler } = makePHEventFunctions("defaultDrivesUrl");
2779
+ const { useValue: useDrivesPreserveStrategy, setValue: setDrivesPreserveStrategy, addEventHandler: addDrivesPreserveStrategyEventHandler } = makePHEventFunctions("drivesPreserveStrategy");
2780
+ const { useValue: useIsLocalDrivesEnabled, setValue: setIsLocalDrivesEnabled, addEventHandler: addIsLocalDrivesEnabledEventHandler } = makePHEventFunctions("isLocalDrivesEnabled");
2781
+ const { useValue: useIsAddDriveEnabled, setValue: setIsAddDriveEnabled, addEventHandler: addIsAddDriveEnabledEventHandler } = makePHEventFunctions("isAddDriveEnabled");
2782
+ const { useValue: useIsPublicDrivesEnabled, setValue: setIsPublicDrivesEnabled, addEventHandler: addIsPublicDrivesEnabledEventHandler } = makePHEventFunctions("isPublicDrivesEnabled");
2783
+ const { useValue: useIsAddPublicDrivesEnabled, setValue: setIsAddPublicDrivesEnabled, addEventHandler: addIsAddPublicDrivesEnabledEventHandler } = makePHEventFunctions("isAddPublicDrivesEnabled");
2784
+ const { useValue: useIsDeletePublicDrivesEnabled, setValue: setIsDeletePublicDrivesEnabled, addEventHandler: addIsDeletePublicDrivesEnabledEventHandler } = makePHEventFunctions("isDeletePublicDrivesEnabled");
2785
+ const { useValue: useIsCloudDrivesEnabled, setValue: setIsCloudDrivesEnabled, addEventHandler: addIsCloudDrivesEnabledEventHandler } = makePHEventFunctions("isCloudDrivesEnabled");
2786
+ const { useValue: useIsAddCloudDrivesEnabled, setValue: setIsAddCloudDrivesEnabled, addEventHandler: addIsAddCloudDrivesEnabledEventHandler } = makePHEventFunctions("isAddCloudDrivesEnabled");
2787
+ const { useValue: useIsDeleteCloudDrivesEnabled, setValue: setIsDeleteCloudDrivesEnabled, addEventHandler: addIsDeleteCloudDrivesEnabledEventHandler } = makePHEventFunctions("isDeleteCloudDrivesEnabled");
2788
+ const { useValue: useLocalDrivesEnabled, setValue: setLocalDrivesEnabled, addEventHandler: addLocalDrivesEnabledEventHandler } = makePHEventFunctions("isLocalDrivesEnabled");
2789
+ const { useValue: useIsAddLocalDrivesEnabled, setValue: setIsAddLocalDrivesEnabled, addEventHandler: addIsAddLocalDrivesEnabledEventHandler } = makePHEventFunctions("isAddLocalDrivesEnabled");
2790
+ const { useValue: useIsDeleteLocalDrivesEnabled, setValue: setIsDeleteLocalDrivesEnabled, addEventHandler: addIsDeleteLocalDrivesEnabledEventHandler } = makePHEventFunctions("isDeleteLocalDrivesEnabled");
2791
+ const { useValue: useIsEditorDebugModeEnabled, setValue: setIsEditorDebugModeEnabled, addEventHandler: addIsEditorDebugModeEnabledEventHandler } = makePHEventFunctions("isEditorDebugModeEnabled");
2792
+ const { useValue: useIsEditorReadModeEnabled, setValue: setIsEditorReadModeEnabled, addEventHandler: addIsEditorReadModeEnabledEventHandler } = makePHEventFunctions("isEditorReadModeEnabled");
2793
+ const { useValue: useIsAnalyticsDatabaseWorkerEnabled, setValue: setIsAnalyticsDatabaseWorkerEnabled, addEventHandler: addIsAnalyticsDatabaseWorkerEnabledEventHandler } = makePHEventFunctions("isAnalyticsDatabaseWorkerEnabled");
2794
+ const { useValue: useIsDiffAnalyticsEnabled, setValue: setIsDiffAnalyticsEnabled, addEventHandler: addIsDiffAnalyticsEnabledEventHandler } = makePHEventFunctions("isDiffAnalyticsEnabled");
2795
+ const { useValue: useIsDriveAnalyticsEnabled, setValue: setIsDriveAnalyticsEnabled, addEventHandler: addIsDriveAnalyticsEnabledEventHandler } = makePHEventFunctions("isDriveAnalyticsEnabled");
2796
+ const { useValue: useRenownUrl, setValue: setRenownUrl, addEventHandler: addRenownUrlEventHandler } = makePHEventFunctions("renownUrl");
2797
+ const { useValue: useRenownNetworkId, setValue: setRenownNetworkId, addEventHandler: addRenownNetworkIdEventHandler } = makePHEventFunctions("renownNetworkId");
2798
+ const { useValue: useRenownChainId, setValue: setRenownChainId, addEventHandler: addRenownChainIdEventHandler } = makePHEventFunctions("renownChainId");
2799
+ const { useValue: useSwitchboardUrl, setValue: setSwitchboardUrl, addEventHandler: addSwitchboardUrlEventHandler } = makePHEventFunctions("switchboardUrl");
2800
+ const { useValue: useRenownAdapters, setValue: setRenownAdapters, addEventHandler: addRenownAdaptersEventHandler } = makePHEventFunctions("renownAdapters");
2801
+ const { useValue: useSentryRelease, setValue: setSentryRelease, addEventHandler: addSentryReleaseEventHandler } = makePHEventFunctions("sentryRelease");
2802
+ const { useValue: useSentryDsn, setValue: setSentryDsn, addEventHandler: addSentryDsnEventHandler } = makePHEventFunctions("sentryDsn");
2803
+ const { useValue: useSentryEnv, setValue: setSentryEnv, addEventHandler: addSentryEnvEventHandler } = makePHEventFunctions("sentryEnv");
2804
+ const { useValue: useIsSentryTracingEnabled, setValue: setIsSentryTracingEnabled, addEventHandler: addIsSentryTracingEnabledEventHandler } = makePHEventFunctions("isSentryTracingEnabled");
2805
+ const { useValue: useIsExternalProcessorsEnabled, setValue: setIsExternalProcessorsEnabled, addEventHandler: addIsExternalProcessorsEnabledEventHandler } = makePHEventFunctions("isExternalProcessorsEnabled");
2806
+ const { useValue: useIsExternalPackagesEnabled, setValue: setIsExternalPackagesEnabled, addEventHandler: addIsExternalPackagesEnabledEventHandler } = makePHEventFunctions("isExternalPackagesEnabled");
2807
+ const enabledEditorsEventFunctions = makePHEventFunctions("enabledEditors");
2808
+ /** Sets the enabled editors for Connect. */
2809
+ const setEnabledEditors = enabledEditorsEventFunctions.setValue;
2810
+ /** Gets the enabled editors for Connect. */
2811
+ const useEnabledEditors = enabledEditorsEventFunctions.useValue;
2812
+ enabledEditorsEventFunctions.addEventHandler;
2813
+ const disabledEditorsEventFunctions = makePHEventFunctions("disabledEditors");
2814
+ /** Sets the disabled editors for Connect. */
2815
+ const setDisabledEditors = disabledEditorsEventFunctions.setValue;
2816
+ /** Gets the disabled editors for Connect. */
2817
+ const useDisabledEditors = disabledEditorsEventFunctions.useValue;
2818
+ disabledEditorsEventFunctions.addEventHandler;
2819
+ const isRelationalProcessorsEnabled = makePHEventFunctions("isRelationalProcessorsEnabled");
2820
+ /** Sets the isRelationalProcessorsEnabled for Connect. */
2821
+ const setIsRelationalProcessorsEnabled = isRelationalProcessorsEnabled.setValue;
2822
+ /** Gets the isRelationalProcessorsEnabled for Connect. */
2823
+ const useIsRelationalProcessorsEnabled = isRelationalProcessorsEnabled.useValue;
2824
+ isRelationalProcessorsEnabled.addEventHandler;
2825
+ const isExternalRelationalProcessorsEnabled = makePHEventFunctions("isExternalRelationalProcessorsEnabled");
2826
+ /** Sets the isExternalRelationalProcessorsEnabled for Connect. */
2827
+ const setIsExternalRelationalProcessorsEnabled = isExternalRelationalProcessorsEnabled.setValue;
2828
+ /** Gets the isExternalRelationalProcessorsEnabled for Connect. */
2829
+ const useIsExternalRelationalProcessorsEnabled = isExternalRelationalProcessorsEnabled.useValue;
2830
+ isExternalRelationalProcessorsEnabled.addEventHandler;
2831
+ const isAnalyticsEnabledEventFunctions = makePHEventFunctions("isAnalyticsEnabled");
2832
+ /** Sets the isAnalyticsEnabled for Connect. */
2833
+ const setIsAnalyticsEnabled = isAnalyticsEnabledEventFunctions.setValue;
2834
+ /** Gets the isAnalyticsEnabled for Connect. */
2835
+ const useIsAnalyticsEnabled = isAnalyticsEnabledEventFunctions.useValue;
2836
+ isAnalyticsEnabledEventFunctions.addEventHandler;
2837
+ const isAnalyticsExternalProcessorsEnabled = makePHEventFunctions("isAnalyticsExternalProcessorsEnabled");
2838
+ /** Sets the isAnalyticsExternalProcessorsEnabled for Connect. */
2839
+ const setIsAnalyticsExternalProcessorsEnabled = isAnalyticsExternalProcessorsEnabled.setValue;
2840
+ /** Gets the isAnalyticsExternalProcessorsEnabled for Connect. */
2841
+ const useIsAnalyticsExternalProcessorsEnabled = isAnalyticsExternalProcessorsEnabled.useValue;
2842
+ isAnalyticsExternalProcessorsEnabled.addEventHandler;
2843
+ const analyticsDatabaseNameEventFunctions = makePHEventFunctions("analyticsDatabaseName");
2844
+ /** Sets the analytics database name for Connect. */
2845
+ const setAnalyticsDatabaseName = analyticsDatabaseNameEventFunctions.setValue;
2846
+ /** Gets the analytics database name for Connect. */
2847
+ const useAnalyticsDatabaseName = analyticsDatabaseNameEventFunctions.useValue;
2848
+ analyticsDatabaseNameEventFunctions.addEventHandler;
2849
+ const logLevelEventFunctions = makePHEventFunctions("logLevel");
2850
+ /** Sets the log level for Connect. */
2851
+ const setLogLevel = logLevelEventFunctions.setValue;
2852
+ /** Gets the log level for Connect. */
2853
+ const useLogLevel = logLevelEventFunctions.useValue;
2854
+ logLevelEventFunctions.addEventHandler;
2855
+ const allowListEventFunctions = makePHEventFunctions("allowList");
2856
+ /** Sets the allow list for Connect. */
2857
+ const setAllowList = allowListEventFunctions.setValue;
2858
+ /** Gets the allow list for Connect. */
2859
+ const useAllowList = allowListEventFunctions.useValue;
2860
+ allowListEventFunctions.addEventHandler;
2861
+ const nonUserConfigSetters = {
2862
+ routerBasename: setRouterBasename,
2863
+ version: setVersion,
2864
+ requiresHardRefresh: setRequiresHardRefresh,
2865
+ warnOutdatedApp: setWarnOutdatedApp,
2866
+ studioMode: setStudioMode,
2867
+ basePath: setBasePath,
2868
+ versionCheckInterval: setVersionCheckInterval,
2869
+ cliVersion: setCliVersion,
2870
+ fileUploadOperationsChunkSize: setFileUploadOperationsChunkSize,
2871
+ isDocumentModelSelectionSettingsEnabled: setIsDocumentModelSelectionSettingsEnabled,
2872
+ gaTrackingId: setGaTrackingId,
2873
+ defaultDrivesUrl: setDefaultDrivesUrl,
2874
+ drivesPreserveStrategy: setDrivesPreserveStrategy,
2875
+ isLocalDrivesEnabled: setIsLocalDrivesEnabled,
2876
+ isAddDriveEnabled: setIsAddDriveEnabled,
2877
+ isPublicDrivesEnabled: setIsPublicDrivesEnabled,
2878
+ isAddPublicDrivesEnabled: setIsAddPublicDrivesEnabled,
2879
+ isDeletePublicDrivesEnabled: setIsDeletePublicDrivesEnabled,
2880
+ isCloudDrivesEnabled: setIsCloudDrivesEnabled,
2881
+ isAddCloudDrivesEnabled: setIsAddCloudDrivesEnabled,
2882
+ isDeleteCloudDrivesEnabled: setIsDeleteCloudDrivesEnabled,
2883
+ isAddLocalDrivesEnabled: setIsAddLocalDrivesEnabled,
2884
+ isDeleteLocalDrivesEnabled: setIsDeleteLocalDrivesEnabled,
2885
+ isEditorDebugModeEnabled: setIsEditorDebugModeEnabled,
2886
+ isEditorReadModeEnabled: setIsEditorReadModeEnabled,
2887
+ isRelationalProcessorsEnabled: setIsRelationalProcessorsEnabled,
2888
+ isExternalRelationalProcessorsEnabled: setIsExternalRelationalProcessorsEnabled,
2889
+ isAnalyticsEnabled: setIsAnalyticsEnabled,
2890
+ analyticsDatabaseName: setAnalyticsDatabaseName,
2891
+ isAnalyticsExternalProcessorsEnabled: setIsAnalyticsExternalProcessorsEnabled,
2892
+ isAnalyticsDatabaseWorkerEnabled: setIsAnalyticsDatabaseWorkerEnabled,
2893
+ isDiffAnalyticsEnabled: setIsDiffAnalyticsEnabled,
2894
+ isDriveAnalyticsEnabled: setIsDriveAnalyticsEnabled,
2895
+ renownUrl: setRenownUrl,
2896
+ renownNetworkId: setRenownNetworkId,
2897
+ renownChainId: setRenownChainId,
2898
+ switchboardUrl: setSwitchboardUrl,
2899
+ renownAdapters: setRenownAdapters,
2900
+ sentryRelease: setSentryRelease,
2901
+ sentryDsn: setSentryDsn,
2902
+ sentryEnv: setSentryEnv,
2903
+ isSentryTracingEnabled: setIsSentryTracingEnabled,
2904
+ isExternalProcessorsEnabled: setIsExternalProcessorsEnabled,
2905
+ isExternalPackagesEnabled: setIsExternalPackagesEnabled,
2906
+ allowList: setAllowList,
2907
+ logLevel: setLogLevel,
2908
+ disabledEditors: setDisabledEditors,
2909
+ enabledEditors: setEnabledEditors
2910
+ };
2911
+ const phGlobalConfigSetters = {
2912
+ ...phAppConfigSetters,
2913
+ ...phDocumentEditorConfigSetters,
2914
+ ...nonUserConfigSetters
2915
+ };
2916
+ const nonUserConfigHooks = {
2917
+ routerBasename: useRouterBasename,
2918
+ version: useVersion,
2919
+ requiresHardRefresh: useRequiresHardRefresh,
2920
+ warnOutdatedApp: useWarnOutdatedApp,
2921
+ studioMode: useStudioMode,
2922
+ basePath: useBasePath,
2923
+ versionCheckInterval: useVersionCheckInterval,
2924
+ cliVersion: useCliVersion,
2925
+ fileUploadOperationsChunkSize: useFileUploadOperationsChunkSize,
2926
+ isDocumentModelSelectionSettingsEnabled: useIsDocumentModelSelectionSettingsEnabled,
2927
+ gaTrackingId: useGaTrackingId,
2928
+ defaultDrivesUrl: useDefaultDrivesUrl,
2929
+ drivesPreserveStrategy: useDrivesPreserveStrategy,
2930
+ isAddDriveEnabled: useIsAddDriveEnabled,
2931
+ isPublicDrivesEnabled: useIsPublicDrivesEnabled,
2932
+ isAddPublicDrivesEnabled: useIsAddPublicDrivesEnabled,
2933
+ isDeletePublicDrivesEnabled: useIsDeletePublicDrivesEnabled,
2934
+ isCloudDrivesEnabled: useIsCloudDrivesEnabled,
2935
+ isAddCloudDrivesEnabled: useIsAddCloudDrivesEnabled,
2936
+ isDeleteCloudDrivesEnabled: useIsDeleteCloudDrivesEnabled,
2937
+ isLocalDrivesEnabled: useIsLocalDrivesEnabled,
2938
+ isAddLocalDrivesEnabled: useIsAddLocalDrivesEnabled,
2939
+ isDeleteLocalDrivesEnabled: useIsDeleteLocalDrivesEnabled,
2940
+ isEditorDebugModeEnabled: useIsEditorDebugModeEnabled,
2941
+ isEditorReadModeEnabled: useIsEditorReadModeEnabled,
2942
+ isAnalyticsDatabaseWorkerEnabled: useIsAnalyticsDatabaseWorkerEnabled,
2943
+ isDiffAnalyticsEnabled: useIsDiffAnalyticsEnabled,
2944
+ isDriveAnalyticsEnabled: useIsDriveAnalyticsEnabled,
2945
+ renownUrl: useRenownUrl,
2946
+ renownNetworkId: useRenownNetworkId,
2947
+ renownChainId: useRenownChainId,
2948
+ switchboardUrl: useSwitchboardUrl,
2949
+ renownAdapters: useRenownAdapters,
2950
+ sentryRelease: useSentryRelease,
2951
+ sentryDsn: useSentryDsn,
2952
+ sentryEnv: useSentryEnv,
2953
+ isSentryTracingEnabled: useIsSentryTracingEnabled,
2954
+ isExternalProcessorsEnabled: useIsExternalProcessorsEnabled,
2955
+ isExternalPackagesEnabled: useIsExternalPackagesEnabled,
2956
+ allowList: useAllowList,
2957
+ isAnalyticsEnabled: useIsAnalyticsEnabled,
2958
+ isAnalyticsExternalProcessorsEnabled: useIsAnalyticsExternalProcessorsEnabled,
2959
+ isRelationalProcessorsEnabled: useIsRelationalProcessorsEnabled,
2960
+ isExternalRelationalProcessorsEnabled: useIsExternalRelationalProcessorsEnabled,
2961
+ analyticsDatabaseName: useAnalyticsDatabaseName,
2962
+ logLevel: useLogLevel,
2963
+ disabledEditors: useDisabledEditors,
2964
+ enabledEditors: useEnabledEditors
2965
+ };
2966
+ ({
2967
+ ...phAppConfigHooks,
2968
+ ...phDocumentEditorConfigHooks,
2969
+ ...nonUserConfigHooks
2970
+ });
2971
+ const attachmentServiceEventFunctions = makePHEventFunctions("attachmentService");
2972
+ attachmentServiceEventFunctions.useValue;
2973
+ attachmentServiceEventFunctions.setValue;
2974
+ attachmentServiceEventFunctions.addEventHandler;
2975
+ const featuresEventFunctions = makePHEventFunctions("features");
2976
+ featuresEventFunctions.useValue;
2977
+ featuresEventFunctions.setValue;
2978
+ featuresEventFunctions.addEventHandler;
2911
2979
  function useDropTarget() {
2912
2980
  const [isDropTarget, setIsDropTarget] = useState(false);
2913
2981
  const isDragAndDropEnabled = useIsDragAndDropEnabled();
@@ -3055,34 +3123,6 @@ revisionHistoryEventFunctions.addEventHandler;
3055
3123
  function showRevisionHistory() {
3056
3124
  setRevisionHistoryVisible(true);
3057
3125
  }
3058
- /** Sorts nodes by name. */
3059
- function sortNodesByName(nodes) {
3060
- return nodes.toSorted((a, b) => a.name.localeCompare(b.name));
3061
- }
3062
- /** Returns whether a node is a file. */
3063
- function isFileNodeKind(node) {
3064
- if (!node) return false;
3065
- return node.kind.toUpperCase() === "FILE";
3066
- }
3067
- /** Returns whether a node is a folder. */
3068
- function isFolderNodeKind(node) {
3069
- if (!node) return false;
3070
- return node.kind.toUpperCase() === "FOLDER";
3071
- }
3072
- /** Returns the nodes in the selected drive. */
3073
- function useNodesInSelectedDrive() {
3074
- const [selectedDrive] = useSelectedDriveSafe();
3075
- return selectedDrive?.state.global.nodes;
3076
- }
3077
- /** Returns the folder nodes in the selected drive. */
3078
- function useFolderNodesInSelectedDrive() {
3079
- return useNodesInSelectedDrive()?.filter((n) => isFolderNodeKind(n));
3080
- }
3081
- /** Returns the selected node. */
3082
- function useSelectedNode() {
3083
- const selectedNodeId = useSelectedNodeId();
3084
- return useNodesInSelectedDrive()?.find((n) => n.id === selectedNodeId);
3085
- }
3086
3126
  const selectedTimelineItemEventFunctions = makePHEventFunctions("selectedTimelineItem");
3087
3127
  selectedTimelineItemEventFunctions.useValue;
3088
3128
  selectedTimelineItemEventFunctions.setValue;
@@ -3096,43 +3136,32 @@ const toastEventFunctions = makePHEventFunctions("toast");
3096
3136
  const usePHToast = toastEventFunctions.useValue;
3097
3137
  toastEventFunctions.setValue;
3098
3138
  toastEventFunctions.addEventHandler;
3099
- const vetraPackageManagerFunctions = makePHEventFunctions("vetraPackageManager");
3100
- const useVetraPackageManager = vetraPackageManagerFunctions.useValue;
3101
- /** Returns all of the Vetra packages loaded by the Connect instance */
3102
- const useVetraPackages = () => {
3103
- const packageManager = useVetraPackageManager();
3104
- return useSyncExternalStore((cb) => packageManager ? packageManager.subscribe(cb) : () => {}, () => packageManager?.packages ?? []);
3105
- };
3106
- vetraPackageManagerFunctions.addEventHandler;
3107
- function useDocumentModelModules() {
3108
- return useVetraPackages().flatMap((pkg) => pkg.documentModels).filter((module, index, modules) => modules.findIndex((m) => m.documentModel.global.id === module.documentModel.global.id && m.version === module.version) === index);
3139
+ //#endregion
3140
+ //#region ../reactor-browser/dist/selected-document-CtRlEZyi.js
3141
+ /** Returns a document of a specific type, throws an error if the found document has a different type */
3142
+ function useDocumentOfType(documentId, documentType) {
3143
+ const [document, dispatch] = useDocumentById(documentId);
3144
+ const documentModelModule = useDocumentModelModuleById(documentType);
3145
+ if (!documentId || !documentType) return [];
3146
+ if (!document) throw new Error(`Document not found: ${documentId}`);
3147
+ if (!documentModelModule) throw new ModuleNotFoundError(documentType);
3148
+ if (document.header.documentType !== documentType) throw new DocumentTypeMismatchError(documentId, documentType, document.header.documentType);
3149
+ return [document, dispatch];
3109
3150
  }
3110
- /**
3111
- * Resolves a document model module by document type, mirroring the registry's
3112
- * semantics (`IDocumentModelRegistry.getModule`): with `version` omitted the
3113
- * LATEST version of the type wins (`version ?? 1` as each module's default),
3114
- * with `version` given only an exact match is returned. The reactor resolves
3115
- * modules the same way when a document is created, so metadata read through
3116
- * this hook and the version a creation actually uses cannot disagree.
3117
- */
3118
- function useDocumentModelModuleById(id, version) {
3119
- const documentModelModules = useDocumentModelModules();
3120
- if (!id || !documentModelModules) return void 0;
3121
- let latestModule;
3122
- let latestVersion = -1;
3123
- for (const module of documentModelModules) {
3124
- if (module.documentModel.global.id !== id) continue;
3125
- const moduleVersion = module.version ?? 1;
3126
- if (version !== void 0) {
3127
- if (moduleVersion === version) return module;
3128
- continue;
3129
- }
3130
- if (moduleVersion > latestVersion) {
3131
- latestVersion = moduleVersion;
3132
- latestModule = module;
3133
- }
3134
- }
3135
- return latestModule;
3151
+ /** Returns the selected document id */
3152
+ function useSelectedDocumentId() {
3153
+ const selectedNode = useSelectedNode();
3154
+ return selectedNode && isFileNode(selectedNode) ? selectedNode.id : void 0;
3155
+ }
3156
+ /** Returns the selected document. */
3157
+ function useSelectedDocumentSafe() {
3158
+ return useDocumentById(useSelectedDocumentId());
3159
+ }
3160
+ function useSelectedDocumentOfType(documentType) {
3161
+ const documentId = useSelectedDocumentId();
3162
+ if (!documentType) return [];
3163
+ if (!documentId) throw new NoSelectedDocumentError();
3164
+ return useDocumentOfType(documentId, documentType);
3136
3165
  }
3137
3166
  //#endregion
3138
3167
  //#region ../../node_modules/.pnpm/normalize-exception@4.0.1/node_modules/normalize-exception/build/src/descriptors.js
@@ -3890,16 +3919,6 @@ function useSetPHDocumentEditorConfig(config) {
3890
3919
  setIsInitialized(true);
3891
3920
  }, [config, isInitialized]);
3892
3921
  }
3893
- /** Returns a document of a specific type, throws an error if the found document has a different type */
3894
- function useDocumentOfType(documentId, documentType) {
3895
- const [document, dispatch] = useDocumentById(documentId);
3896
- const documentModelModule = useDocumentModelModuleById(documentType);
3897
- if (!documentId || !documentType) return [];
3898
- if (!document) throw new Error(`Document not found: ${documentId}`);
3899
- if (!documentModelModule) throw new ModuleNotFoundError(documentType);
3900
- if (document.header.documentType !== documentType) throw new DocumentTypeMismatchError(documentId, documentType, document.header.documentType);
3901
- return [document, dispatch];
3902
- }
3903
3922
  /**
3904
3923
  * Classifies a document's model version against the installed module
3905
3924
  * versions. Pure logic, extracted for testing.
@@ -4143,21 +4162,6 @@ function useNodeParentFolderById(id) {
4143
4162
  function useParentFolderForSelectedNode() {
4144
4163
  return useNodeParentFolderById(useSelectedNode()?.id);
4145
4164
  }
4146
- /** Returns the selected document id */
4147
- function useSelectedDocumentId() {
4148
- const selectedNode = useSelectedNode();
4149
- return selectedNode && isFileNode(selectedNode) ? selectedNode.id : void 0;
4150
- }
4151
- /** Returns the selected document. */
4152
- function useSelectedDocumentSafe() {
4153
- return useDocumentById(useSelectedDocumentId());
4154
- }
4155
- function useSelectedDocumentOfType(documentType) {
4156
- const documentId = useSelectedDocumentId();
4157
- if (!documentType) return [];
4158
- if (!documentId) throw new NoSelectedDocumentError();
4159
- return useDocumentOfType(documentId, documentType);
4160
- }
4161
4165
  const STORED_THEME_KEY = "ph:theme";
4162
4166
  const UPDATE_STORED_THEME = "ph:updateStoredTheme";
4163
4167
  const STORED_THEME_UPDATED = "ph:storedThemeUpdated";
@@ -4371,6 +4375,6 @@ function createDebouncedRefreshReactorDataClient(debounceDelayMs = DEFAULT_DEBOU
4371
4375
  createDebouncedRefreshReactorData();
4372
4376
  createDebouncedRefreshReactorDataClient();
4373
4377
  //#endregion
4374
- export { showRevisionHistory as A, t$2 as B, addFolder$1 as C, setSelectedNode as D, setSelectedDrive as E, useSelectedDriveId as F, useDocumentById as H, useSelectedDriveSafe as I, useStudioMode as L, useDragNode as M, useDropNode as N, showDeleteNodeModal as O, usePHToast as P, e$1 as R, addDocument as S, isFolderNodeKind as T, t$5 as V, useSelectedNodePath as _, useDownloadDocument as a, useTheme as b, useGetSwitchboardLink as c, useNodeParentFolderById as d, useNodesInSelectedDriveOrFolder as f, useSelectedFolder as g, useSelectedDocumentSafe as h, useDocumentVersionStatus as i, useDisabledEditors as j, showPHModal as k, useNodeActions as l, useSelectedDocumentOfType as m, preloadEditorModule as n, useEditorModules as o, useParentFolderForSelectedNode as p, useAllowedDocumentModelModules as r, useEditorModulesForDocumentType as s, getSyncStatusSync as t, useNodeById as u, useSetPHAppConfig as v, isFileNodeKind as w, useUserPermissions as x, useSetPHDocumentEditorConfig as y, e$4 as z };
4378
+ export { usePHToast as A, useSelectedDriveId as B, addFolder$1 as C, useDisabledEditors as D, showRevisionHistory as E, t$5 as F, useDocumentById as H, isFileNodeKind as I, isFolderNodeKind as L, e$1 as M, e$4 as N, useDragNode as O, t$2 as P, setSelectedDrive as R, addDocument as S, showPHModal as T, useSelectedDriveSafe as V, useSetPHDocumentEditorConfig as _, useDownloadDocument as a, useSelectedDocumentOfType as b, useGetSwitchboardLink as c, useNodeParentFolderById as d, useNodesInSelectedDriveOrFolder as f, useSetPHAppConfig as g, useSelectedNodePath as h, useDocumentVersionStatus as i, useStudioMode as j, useDropNode as k, useNodeActions as l, useSelectedFolder as m, preloadEditorModule as n, useEditorModules as o, useParentFolderForSelectedNode as p, useAllowedDocumentModelModules as r, useEditorModulesForDocumentType as s, getSyncStatusSync as t, useNodeById as u, useTheme as v, showDeleteNodeModal as w, useSelectedDocumentSafe as x, useUserPermissions as y, setSelectedNode as z };
4375
4379
 
4376
- //# sourceMappingURL=dist-Bmp6vCZK.mjs.map
4380
+ //# sourceMappingURL=dist-BzJZJOzf.mjs.map