@powerhousedao/connect-core 6.2.3-dev.77 → 6.2.3-dev.78

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 (35) hide show
  1. package/dist/connect-router-11uRIT3z.d.ts.map +1 -1
  2. package/dist/index-DQ0nbYne.d.ts.map +1 -1
  3. package/dist/index.js +7 -7
  4. package/dist/{multi-reactor-CPRsFtfd.js → multi-reactor-CCMzwoMi.js} +3 -1
  5. package/dist/multi-reactor-CCMzwoMi.js.map +1 -0
  6. package/dist/{plugin-host-BSFfhXpz.js → plugin-host-HhfxwUZN.js} +2 -2
  7. package/dist/{plugin-host-BSFfhXpz.js.map → plugin-host-HhfxwUZN.js.map} +1 -1
  8. package/dist/{plugin-ui-sO7AJLHj.js → plugin-ui-W0ma6oKJ.js} +5 -5
  9. package/dist/plugin-ui-W0ma6oKJ.js.map +1 -0
  10. package/dist/plugins.js +2 -2
  11. package/dist/{router-8pekwJsk.js → router-DHL9GT3P.js} +4 -3
  12. package/dist/{router-8pekwJsk.js.map → router-DHL9GT3P.js.map} +1 -1
  13. package/dist/router.js +3 -3
  14. package/dist/{runtime-D8IBQzHM.js → runtime-D5hpzfgT.js} +3 -3
  15. package/dist/{runtime-D8IBQzHM.js.map → runtime-D5hpzfgT.js.map} +1 -1
  16. package/dist/runtime-config.js +4 -4
  17. package/dist/{runtime-flag-CJWngtxE.js → runtime-flag-U8y14Nth.js} +2 -2
  18. package/dist/{runtime-flag-CJWngtxE.js.map → runtime-flag-U8y14Nth.js.map} +1 -1
  19. package/dist/runtime.js +2 -2
  20. package/dist/{sidebar-DVQCwBYR.js → sidebar-CRv_DvBV.js} +4 -4
  21. package/dist/sidebar-CRv_DvBV.js.map +1 -0
  22. package/dist/{views-CAbBIFzO.js → views-anOyTI7u.js} +10 -4
  23. package/dist/views-anOyTI7u.js.map +1 -0
  24. package/dist/views.js +1 -1
  25. package/package.json +8 -8
  26. package/src/router/connect-router.ts +1 -0
  27. package/src/router/drive-route-loader.ts +3 -1
  28. package/src/router/route-data.ts +2 -4
  29. package/src/router/titles.ts +2 -2
  30. package/src/runtime/graphql-routable-backend.ts +9 -0
  31. package/src/views/directory-listing.tsx +12 -1
  32. package/dist/multi-reactor-CPRsFtfd.js.map +0 -1
  33. package/dist/plugin-ui-sO7AJLHj.js.map +0 -1
  34. package/dist/sidebar-DVQCwBYR.js.map +0 -1
  35. package/dist/views-CAbBIFzO.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"connect-router-11uRIT3z.d.ts","names":[],"sources":["../src/router/modals.tsx","../src/plugins/types.ts","../src/router/drive-route-loader.ts","../src/router/route-data.ts","../src/router/route-tree.ts","../src/registry.ts","../src/plugins/plugin-ui.ts","../src/router/connect-router.ts"],"mappings":";;;;;;;;;;;KAUY,gBAAgB,QAAQ,OAAO,iBAAiB;;YAGhD;;IAER,SAAS;;;;;cAMA;WACK;WACT;WACK;WACY;WACI;WACA;WACT;;;;iBA6BL,cAAc;EAAY,QAAQ;gCAAe,IAAA;;;;;;;;;;UCtChD;;EAEf,aAAa;;UAGE;EACf,yBACE,QAAQ,wBACR,KAAK,yBACF;EACL,aAAa,KAAK,gCAAgC;;KAGxC,gBAAgB,WAAW;;;KAI3B,wBACV,QAAQ,4BACL;;KAGO;EACV,YAAY;EACZ,mBAAmB;EACnB,iBAAiB;EACjB,oBAAoB;EACpB,aAAa,QAAQ;;;KAIX;;;EAGV,SAAS,eAAe;;EAExB,YAAY;;EAEZ,SAAS;;EAET,OAAO;;EAEP,iBAAiB;;EAEjB;;EAEA;;;;KAKU;EACV,QAAQ;EACR,cAAc,QAAQ,2BAA2B;;EAEjD,WAAW,QAAQ;;EAEnB;;;;KClEU;EACV,OAAO;;EAEP,WAAW;;EAEX;;EAEA;;;KAIU;EAAsB;;iBAElB,gBAAgB,gBAAgB,QAAQ;;KAS5C;EAAmB;EAAiB;;KAEpC;EAAqB;EAAmB;;KAExC;EACV,QAAQ;EACR,SAAS;EACT,iBAAiB;EACjB;;;iBAuBoB,UACpB,SAAS,qBACR;EAAU;;;;iBAYS,SACpB,SAAS,qBACR,QAAQ;;;;cCtEE;;cAEA;;;KAID;EACV,OAAO;;EAEP,QAAQ;;EAER;;;iBAIc,oBAAoB;;iBASpB,qBAAqB;;;;cCTxB;;cAEA;cACP;KAgBM,0BAA0B;KAC1B;EACV,WAAW;EACX,WAAW;EACX,UAAU,sBAAsB;EAChC,WAAW,sBAAsB;;EAEjC,YAAY,sBAAsB;;EAElC,WAAW,sBAAsB;EACjC,eAAe,sBAAsB;;;;iBAKvB,cAAc,WAAW,WAAW;;;iBAsBpC,iBAAiB,iBAAiB;;iBAqBlC,oBAAoB,iBAAiB;;;iBAsBrC,sBACd,cAAc;;;KAkCJ;EACV,OAAO;;EAEP;;EAEA;;EAEA;;;;iBAgCc;;iBAeA,qBAAqB,qBAAkB;;;iBAgBvC,sBAAsB,iBAAiB;;;KC1N3C,2BAA2B,eAAe;;KAG1C,oCACC,eACP,QAAQ,2BAA2B;;;;KCA7B;EACV,QAAQ,eAAe;EACvB,WAAW;EACX,QAAQ;EACR,OAAO;EACP,iBAAiB;EACjB;EACA;;iBAYc,qBACd,cAAc,oBACb;;;iBAyBmB,oBACpB;EAAwB;kBACvB,QAAQ;;iBAkBK,sBAAsB;;;iBA8BtB,qBACd,WAAW,UACX,KAAI;;iBA+BU,qBAAqB,WAAW;;;KClHpC;EACV,OAAO;EACP,WAAW;EACX;EACA,UAAU;EACV,aAAa,OAAO,sBAAsB;;EAE1C,mBAAmB;;EAEnB,iBAAiB;;EAEjB,WAAW;;EAEX,oBAAoB;;EAEpB,WAAW;;;EAGX,kBACa,eACP,QAAQ,2BAA2B;;EAEzC,WAAW,gBAAgB,OAAO;;EAElC;;EAEA;;;KAQU,iBAAiB,mBAAmB,YAAY,OAC1D,4BAGA,eACA;KAGU,gBAAgB,iBAAiB;KACjC,sBAAsB,KAChC;EAEI,QAAQ;;iBAEE,oBACd,SAAS,uBACR;;iBA6Ca,kBACd,eAAe,qBACf,OAAO"}
1
+ {"version":3,"file":"connect-router-11uRIT3z.d.ts","names":[],"sources":["../src/router/modals.tsx","../src/plugins/types.ts","../src/router/drive-route-loader.ts","../src/router/route-data.ts","../src/router/route-tree.ts","../src/registry.ts","../src/plugins/plugin-ui.ts","../src/router/connect-router.ts"],"mappings":";;;;;;;;;;;KAUY,gBAAgB,QAAQ,OAAO,iBAAiB;;YAGhD;;IAER,SAAS;;;;;cAMA;WACK;WACT;WACK;WACY;WACI;WACA;WACT;;;;iBA6BL,cAAc;EAAY,QAAQ;gCAAe,IAAA;;;;;;;;;;UCtChD;;EAEf,aAAa;;UAGE;EACf,yBACE,QAAQ,wBACR,KAAK,yBACF;EACL,aAAa,KAAK,gCAAgC;;KAGxC,gBAAgB,WAAW;;;KAI3B,wBACV,QAAQ,4BACL;;KAGO;EACV,YAAY;EACZ,mBAAmB;EACnB,iBAAiB;EACjB,oBAAoB;EACpB,aAAa,QAAQ;;;KAIX;;;EAGV,SAAS,eAAe;;EAExB,YAAY;;EAEZ,SAAS;;EAET,OAAO;;EAEP,iBAAiB;;EAEjB;;EAEA;;;;KAKU;EACV,QAAQ;EACR,cAAc,QAAQ,2BAA2B;;EAEjD,WAAW,QAAQ;;EAEnB;;;;KCjEU;EACV,OAAO;;EAEP,WAAW;;EAEX;;EAEA;;;KAIU;EAAsB;;iBAElB,gBAAgB,gBAAgB,QAAQ;;KAS5C;EAAmB;EAAiB;;KAEpC;EAAqB;EAAmB;;KAExC;EACV,QAAQ;EACR,SAAS;EACT,iBAAiB;EACjB;;;iBAuBoB,UACpB,SAAS,qBACR;EAAU;;;;iBAYS,SACpB,SAAS,qBACR,QAAQ;;;;cCvEE;;cAEA;;;KAID;EACV,OAAO;;EAEP,QAAQ;;EAER;;;iBAIc,oBAAoB;;iBASpB,qBAAqB;;;;cCTxB;;cAEA;cACP;KAgBM,0BAA0B;KAC1B;EACV,WAAW;EACX,WAAW;EACX,UAAU,sBAAsB;EAChC,WAAW,sBAAsB;;EAEjC,YAAY,sBAAsB;;EAElC,WAAW,sBAAsB;EACjC,eAAe,sBAAsB;;;;iBAKvB,cAAc,WAAW,WAAW;;;iBAsBpC,iBAAiB,iBAAiB;;iBAqBlC,oBAAoB,iBAAiB;;;iBAsBrC,sBACd,cAAc;;;KAkCJ;EACV,OAAO;;EAEP;;EAEA;;EAEA;;;;iBAgCc;;iBAeA,qBAAqB,qBAAkB;;;iBAgBvC,sBAAsB,iBAAiB;;;KC1N3C,2BAA2B,eAAe;;KAG1C,oCACC,eACP,QAAQ,2BAA2B;;;;KCA7B;EACV,QAAQ,eAAe;EACvB,WAAW;EACX,QAAQ;EACR,OAAO;EACP,iBAAiB;EACjB;EACA;;iBAYc,qBACd,cAAc,oBACb;;;iBAyBmB,oBACpB;EAAwB;kBACvB,QAAQ;;iBAkBK,sBAAsB;;;iBA8BtB,qBACd,WAAW,UACX,KAAI;;iBA+BU,qBAAqB,WAAW;;;KClHpC;EACV,OAAO;EACP,WAAW;EACX;EACA,UAAU;EACV,aAAa,OAAO,sBAAsB;;EAE1C,mBAAmB;;EAEnB,iBAAiB;;EAEjB,WAAW;;EAEX,oBAAoB;;EAEpB,WAAW;;;EAGX,kBACa,eACP,QAAQ,2BAA2B;;EAEzC,WAAW,gBAAgB,OAAO;;EAElC;;EAEA;;;KAQU,iBAAiB,mBAAmB,YAAY,OAC1D,4BAGA,eACA;KAGU,gBAAgB,iBAAiB;KACjC,sBAAsB,KAChC;EAEI,QAAQ;;iBAEE,oBACd,SAAS,uBACR;;iBA6Ca,kBACd,eAAe,qBACf,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"index-DQ0nbYne.d.ts","names":[],"sources":["../src/views/content.tsx","../src/views/directory-listing.tsx","../src/views/document-history.tsx","../src/views/document-json.tsx","../src/views/editor-host.tsx","../src/views/home.tsx","../src/views/index-table.tsx","../src/views/layout.tsx","../src/views/not-found-page.tsx","../src/views/modals.tsx","../src/views/route-views.tsx","../src/views/settings.tsx","../src/views/settings-packages.tsx","../src/views/theme-toggle.tsx"],"mappings":";;;;;;;iBAoBgB,eAAe;EAAc,UAAU;gCAAY,IAAA;;;iBAgCnD,2CAAW,IAAA;;iBAkCX,wCAAQ,IAAA;;;;iBCHR,mBAAmB,OAAO,QAAQ,YAAY,+EAAc,IAAA,UAAA,SAAA,aAAA,6CAAA,SAAA,6BAAA,+CAAA,8CAAA;;;;cCrE/D;;iBAmHG,kBAAkB,YAAY,gDAAiB,IAAA;;;;iBC1F/C,eAAe,YAAY,gDAAiB,IAAA;;;;KClChD,sBAAsB;EAChC;EACA;IAAY;IAAoB;;;KA8CtB;;EAEV;;EAEA;EACA,UAAU;;;iBAII,aACd,WACA,OACA,YACC,8CAAe,IAAA;;;;iBC1BF,0CAAU,IAAA;;;;iBCrCV,eAAe;;;;iBCuBf,wCAAQ,IAAA;;iBAgBR,0CAAU,IAAA;;;iBA8BV,0CAAU,IAAA;;;;iBCpEV,eAAe;EAAe;gCAAoB,IAAA;iBAyBlD,oBAAoB;EAAe;gCAAmB,IAAA;;;;;iBCmEtD,mDAAmB,IAAA;;iBAiGnB,0CAAU,IAAA;;iBAuCV,+CAAe,IAAA;;iBAqCf,2DAA2B,IAAA;;iBA0C3B,+DAA+B,IAAA;;iBAiC/B,+DAA+B,IAAA;;iBAgC/B,sDAAsB,IAAA;;;;iBCrXtB,iBAAiB,OAAO,SAAS,kDAAmB,IAAA;;;;iBC2BpD,gDAAgB,IAAA;;iBA+ChB,6CAAa,IAAA;;;;iBCyDb,2CAAW,IAAA;;;;iBCnIX,cAAc;EAAe;gCAAoB,IAAA"}
1
+ {"version":3,"file":"index-DQ0nbYne.d.ts","names":[],"sources":["../src/views/content.tsx","../src/views/directory-listing.tsx","../src/views/document-history.tsx","../src/views/document-json.tsx","../src/views/editor-host.tsx","../src/views/home.tsx","../src/views/index-table.tsx","../src/views/layout.tsx","../src/views/not-found-page.tsx","../src/views/modals.tsx","../src/views/route-views.tsx","../src/views/settings.tsx","../src/views/settings-packages.tsx","../src/views/theme-toggle.tsx"],"mappings":";;;;;;;iBAoBgB,eAAe;EAAc,UAAU;gCAAY,IAAA;;;iBAgCnD,2CAAW,IAAA;;iBAkCX,wCAAQ,IAAA;;;;iBCFR,mBAAmB,OAAO,QAAQ,YAAY,+EAAc,IAAA,UAAA,SAAA,aAAA,6CAAA,SAAA,6BAAA,+CAAA,8CAAA;;;;cCtE/D;;iBAmHG,kBAAkB,YAAY,gDAAiB,IAAA;;;;iBC1F/C,eAAe,YAAY,gDAAiB,IAAA;;;;KClChD,sBAAsB;EAChC;EACA;IAAY;IAAoB;;;KA8CtB;;EAEV;;EAEA;EACA,UAAU;;;iBAII,aACd,WACA,OACA,YACC,8CAAe,IAAA;;;;iBC1BF,0CAAU,IAAA;;;;iBCrCV,eAAe;;;;iBCuBf,wCAAQ,IAAA;;iBAgBR,0CAAU,IAAA;;;iBA8BV,0CAAU,IAAA;;;;iBCpEV,eAAe;EAAe;gCAAoB,IAAA;iBAyBlD,oBAAoB;EAAe;gCAAmB,IAAA;;;;;iBCmEtD,mDAAmB,IAAA;;iBAiGnB,0CAAU,IAAA;;iBAuCV,+CAAe,IAAA;;iBAqCf,2DAA2B,IAAA;;iBA0C3B,+DAA+B,IAAA;;iBAiC/B,+DAA+B,IAAA;;iBAgC/B,sDAAsB,IAAA;;;;iBCrXtB,iBAAiB,OAAO,SAAS,kDAAmB,IAAA;;;;iBC2BpD,gDAAgB,IAAA;;iBA+ChB,6CAAa,IAAA;;;;iBCyDb,2CAAW,IAAA;;;;iBCnIX,cAAc;EAAe;gCAAoB,IAAA"}
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import { C as DocumentJson, D as formatModified, E as DirectoryListing, S as EditorHost, T as HISTORY_PAGE_SIZE, _ as ThemeToggle, a as DriveNotFoundPage, b as DriveLayout, c as CoreLayout, d as CreateDocumentModal, f as DeleteItemModal, g as LoginModal, h as DriveAuthRequiredModal, i as CoreRouteError, l as CoreRoot, m as DownloadDocumentWithErrorsModal, n as AppearanceTab, o as NotFoundPage, p as DocumentVersionUnsupportedModal, r as CoreSettingsPage, s as CoreHeader, t as PackagesTab, u as ConfirmDocumentUpgradeModal, v as DriveIndex, w as DocumentHistory, x as NodeView, y as DocumentView } from "./views-CAbBIFzO.js";
2
- import { c as CoreNotFound, d as isCoreView, f as isDriveNotFound, i as mergeConnectPluginUi, l as coreModals, m as loadNode, n as getConnectPluginUi, o as resetConnectPluginUi, p as loadDrive, r as loadConnectPluginUi, s as CoreError, t as applyConnectPluginUi, u as coreView } from "./plugin-ui-sO7AJLHj.js";
1
+ import { C as DocumentJson, D as formatModified, E as DirectoryListing, S as EditorHost, T as HISTORY_PAGE_SIZE, _ as ThemeToggle, a as DriveNotFoundPage, b as DriveLayout, c as CoreLayout, d as CreateDocumentModal, f as DeleteItemModal, g as LoginModal, h as DriveAuthRequiredModal, i as CoreRouteError, l as CoreRoot, m as DownloadDocumentWithErrorsModal, n as AppearanceTab, o as NotFoundPage, p as DocumentVersionUnsupportedModal, r as CoreSettingsPage, s as CoreHeader, t as PackagesTab, u as ConfirmDocumentUpgradeModal, v as DriveIndex, w as DocumentHistory, x as NodeView, y as DocumentView } from "./views-anOyTI7u.js";
2
+ import { c as CoreNotFound, d as isCoreView, f as isDriveNotFound, i as mergeConnectPluginUi, l as coreModals, m as loadNode, n as getConnectPluginUi, o as resetConnectPluginUi, p as loadDrive, r as loadConnectPluginUi, s as CoreError, t as applyConnectPluginUi, u as coreView } from "./plugin-ui-W0ma6oKJ.js";
3
3
  import { a as connectRoutesSettled, c as registerPackageRoutes, f as CORE_MODAL_VIEWS, h as useModalFrame, i as connectRoutes, l as removeConnectRoutes, m as ModalDialog, n as HOME_ROUTE_ID, o as holdConnectRoutes, p as ModalOutlet, r as addConnectRoutes, s as registerConnectRoutes, t as APP_ROUTE_ID } from "./route-tree-D0aszMrk.js";
4
- import { C as ContentOutlet, E as useIsColdStart, S as CONTENT_VIEW_ID, T as DrivePending, _ as useForgetSettingsOpenedFrom, a as DRIVE_ROUTE_ID, b as driveTitle, c as useDriveRouteIds, d as redirectToSettingsTab, f as setSettingsRoute, g as showsSettingsTab, h as settingsTitle, i as useCreateDocumentTarget, l as SETTINGS_ROUTE_ID, m as settingsTabsOf, n as useNavRoutes, o as NODE_ROUTE_ID, p as settingsTabs, r as useSidebarMode, s as useDriveRouteData, t as navRoutes, u as keepOpenedFrom, v as useSettingsTabs, w as DRIVE_PENDING_MS, x as notFoundTitle, y as appTitle } from "./sidebar-DVQCwBYR.js";
5
- import { i as registerConnectPlugins, n as knownPlugins, t as applyComposition } from "./plugin-host-BSFfhXpz.js";
6
- import { _ as PERF_STORAGE_KEY, a as createConnectRouter, b as markRouterNavigations, c as GLOBAL_SEARCH_PARAMS, d as parseConnectSearch, f as stringifyConnectSearch, g as connectScrollRestoration, h as bindConnectScroll, i as bindConnectRouter, l as connectSearchMiddlewares, m as validateDriveSearch, n as disposeConnectAppRouter, o as createConnectNavigation, p as validateConnectSearch, r as getConnectAppRouter, s as FEATURE_FLAG_PARAM_PREFIX, t as ConnectCoreApp, u as definedSearch, v as ROUTER_MEASURES, x as routerPerfEnabled, y as markNavigationClick } from "./router-8pekwJsk.js";
4
+ import { C as ContentOutlet, E as useIsColdStart, S as CONTENT_VIEW_ID, T as DrivePending, _ as useForgetSettingsOpenedFrom, a as DRIVE_ROUTE_ID, b as driveTitle, c as useDriveRouteIds, d as redirectToSettingsTab, f as setSettingsRoute, g as showsSettingsTab, h as settingsTitle, i as useCreateDocumentTarget, l as SETTINGS_ROUTE_ID, m as settingsTabsOf, n as useNavRoutes, o as NODE_ROUTE_ID, p as settingsTabs, r as useSidebarMode, s as useDriveRouteData, t as navRoutes, u as keepOpenedFrom, v as useSettingsTabs, w as DRIVE_PENDING_MS, x as notFoundTitle, y as appTitle } from "./sidebar-CRv_DvBV.js";
5
+ import { i as registerConnectPlugins, n as knownPlugins, t as applyComposition } from "./plugin-host-HhfxwUZN.js";
6
+ import { _ as PERF_STORAGE_KEY, a as createConnectRouter, b as markRouterNavigations, c as GLOBAL_SEARCH_PARAMS, d as parseConnectSearch, f as stringifyConnectSearch, g as connectScrollRestoration, h as bindConnectScroll, i as bindConnectRouter, l as connectSearchMiddlewares, m as validateDriveSearch, n as disposeConnectAppRouter, o as createConnectNavigation, p as validateConnectSearch, r as getConnectAppRouter, s as FEATURE_FLAG_PARAM_PREFIX, t as ConnectCoreApp, u as definedSearch, v as ROUTER_MEASURES, x as routerPerfEnabled, y as markNavigationClick } from "./router-DHL9GT3P.js";
7
7
  import { getRuntimeConfig, loadRuntimeConfig, primeRuntimeConfig } from "./runtime-config.js";
8
8
  import { n as isPluginActive, t as getActivePluginModules } from "./plugins-x1XqLPzp.js";
9
- import { n as resolveRuntimeFlag, t as isRuntimeFlagEnabled } from "./runtime-flag-CJWngtxE.js";
10
- import { a as planReactorClient, c as resolveReactorClientMode, d as isReactorWorkerEnabled, f as resolveReactorWorkerEnabled, i as getAppDrives, l as REACTOR_WORKER_QUERY_KEY, n as getConnectPHStore, o as refreshAppDrives, p as isMultiReactorEnabled, r as createAppReactorClient, s as selectAppReactorClient, t as loadLocalPackage, u as REACTOR_WORKER_STORAGE_KEY } from "./runtime-D8IBQzHM.js";
9
+ import { n as resolveRuntimeFlag, t as isRuntimeFlagEnabled } from "./runtime-flag-U8y14Nth.js";
10
+ import { a as planReactorClient, c as resolveReactorClientMode, d as isReactorWorkerEnabled, f as resolveReactorWorkerEnabled, i as getAppDrives, l as REACTOR_WORKER_QUERY_KEY, n as getConnectPHStore, o as refreshAppDrives, p as isMultiReactorEnabled, r as createAppReactorClient, s as selectAppReactorClient, t as loadLocalPackage, u as REACTOR_WORKER_STORAGE_KEY } from "./runtime-D5hpzfgT.js";
11
11
  import { getIsEmbedded, useIsEmbedded } from "./embedded.js";
12
12
  export { APP_ROUTE_ID, AppearanceTab, CONTENT_VIEW_ID, CORE_MODAL_VIEWS, ConfirmDocumentUpgradeModal, ConnectCoreApp, ContentOutlet, CoreError, CoreHeader, CoreLayout, CoreNotFound, CoreRoot, CoreRouteError, CoreSettingsPage, CreateDocumentModal, DRIVE_PENDING_MS, DRIVE_ROUTE_ID, DeleteItemModal, DirectoryListing, DocumentHistory, DocumentJson, DocumentVersionUnsupportedModal, DocumentView, DownloadDocumentWithErrorsModal, DriveAuthRequiredModal, DriveIndex, DriveLayout, DriveNotFoundPage, DrivePending, EditorHost, FEATURE_FLAG_PARAM_PREFIX, GLOBAL_SEARCH_PARAMS, HISTORY_PAGE_SIZE, HOME_ROUTE_ID, LoginModal, ModalDialog, ModalOutlet, NODE_ROUTE_ID, NodeView, NotFoundPage, PERF_STORAGE_KEY, PackagesTab, REACTOR_WORKER_QUERY_KEY, REACTOR_WORKER_STORAGE_KEY, ROUTER_MEASURES, SETTINGS_ROUTE_ID, ThemeToggle, addConnectRoutes, appTitle, applyComposition, applyConnectPluginUi, bindConnectRouter, bindConnectScroll, connectRoutes, connectRoutesSettled, connectScrollRestoration, connectSearchMiddlewares, coreModals, coreView, createAppReactorClient, createConnectNavigation, createConnectRouter, definedSearch, disposeConnectAppRouter, driveTitle, formatModified, getActivePluginModules, getAppDrives, getConnectAppRouter, getConnectPHStore, getConnectPluginUi, getIsEmbedded, getRuntimeConfig, holdConnectRoutes, isCoreView, isDriveNotFound, isMultiReactorEnabled, isPluginActive, isReactorWorkerEnabled, isRuntimeFlagEnabled, keepOpenedFrom, knownPlugins, loadConnectPluginUi, loadDrive, loadLocalPackage, loadNode, loadRuntimeConfig, markNavigationClick, markRouterNavigations, mergeConnectPluginUi, navRoutes, notFoundTitle, parseConnectSearch, planReactorClient, primeRuntimeConfig, redirectToSettingsTab, refreshAppDrives, registerConnectPlugins, registerConnectRoutes, registerPackageRoutes, removeConnectRoutes, resetConnectPluginUi, resolveReactorClientMode, resolveReactorWorkerEnabled, resolveRuntimeFlag, routerPerfEnabled, selectAppReactorClient, setSettingsRoute, settingsTabs, settingsTabsOf, settingsTitle, showsSettingsTab, stringifyConnectSearch, useCreateDocumentTarget, useDriveRouteData, useDriveRouteIds, useForgetSettingsOpenedFrom, useIsColdStart, useIsEmbedded, useModalFrame, useNavRoutes, useSettingsTabs, useSidebarMode, validateConnectSearch, validateDriveSearch };
@@ -66,7 +66,9 @@ function createGraphQLRoutableBackend(options) {
66
66
  find: findIsServableOverGraphQL,
67
67
  pointInTimeViews: false
68
68
  },
69
+ drives: gql.read.drives,
69
70
  get: async (identifier, view, signal) => drives.learn(await gql.get(identifier, view, signal)),
71
+ getMany: async (ids, view, signal) => (await gql.getMany(ids, view, signal)).map((document) => drives.learn(document)),
70
72
  getOperations: (identifier, view, filter, paging, signal) => gql.getOperations(identifier, view, filter, paging, signal),
71
73
  find: async (search, view, paging, signal) => drives.learnPage(await gql.find(search, view, paging, signal)),
72
74
  isServed: (identifier, view, signal) => gql.isServed(identifier, view, signal),
@@ -214,4 +216,4 @@ async function buildMultiReactorClient(params) {
214
216
  //#endregion
215
217
  export { ConnectRoutingClient, LOCAL_BACKEND_NAME, PLACE_ON_LOCAL, PLACE_ON_REMOTE, REMOTE_BACKEND_NAME, buildMultiReactorClient, createGraphQLRoutableBackend, deriveSwitchboardGraphqlUrl, localFacts, localReach };
216
218
 
217
- //# sourceMappingURL=multi-reactor-CPRsFtfd.js.map
219
+ //# sourceMappingURL=multi-reactor-CCMzwoMi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-reactor-CCMzwoMi.js","names":[],"sources":["../src/runtime/graphql-routable-backend.ts","../src/runtime/multi-reactor.ts"],"sourcesContent":["import {\n JOB_NOT_FOUND_ERROR_NAME,\n JobStatus,\n type PagedResults,\n type ReactorInfo,\n type ViewFilter,\n} from \"@powerhousedao/reactor\";\nimport {\n DRIVE_DOCUMENT_TYPES,\n findIsServableOverGraphQL,\n GraphQLReactorClient,\n type DriveIdCall,\n type GraphQLReactorClientOptions,\n} from \"@powerhousedao/reactor-browser\";\nimport type { IRoutableBackend } from \"@powerhousedao/reactor-router\";\nimport type { Action, PHDocument } from \"@powerhousedao/shared/document-model\";\n\nconst REMOTE_INFO_QUERY = /* GraphQL */ `\n query RemoteReactorInfo {\n inspection {\n info {\n storage {\n engine\n persistence\n durable\n selfHeal\n }\n workflows\n syncChannels\n }\n }\n }\n`;\n\ntype RemoteReactorInfo = {\n inspection: { info: Omit<ReactorInfo, \"access\"> };\n};\n\n/** Ids and slugs of documents this backend answered as drives, by drive id. */\nclass KnownDrives {\n private readonly ids = new Map<string, string>();\n\n learn<T extends PHDocument>(document: T): T {\n const { id, slug, documentType } = document.header;\n if ((DRIVE_DOCUMENT_TYPES as readonly string[]).includes(documentType)) {\n this.ids.set(id, id);\n if (slug) {\n this.ids.set(slug, id);\n }\n }\n return document;\n }\n\n learnPage<T extends PHDocument>(page: PagedResults<T>): PagedResults<T> {\n for (const document of page.results) {\n this.learn(document);\n }\n return page;\n }\n\n driveOf(identifier: string | undefined): string | undefined {\n return identifier === undefined ? undefined : this.ids.get(identifier);\n }\n\n /** Names a drive only when this backend proved it is one. */\n driveIdFor = (call: DriveIdCall): string | undefined => {\n switch (call.method) {\n case \"create\":\n case \"find\":\n return this.driveOf(call.parentId);\n case \"execute\":\n case \"deleteDocument\":\n return this.driveOf(call.documentId);\n case \"executeBatch\":\n for (const job of call.jobs ?? []) {\n const drive = this.driveOf(job.documentId);\n if (drive !== undefined) {\n return drive;\n }\n }\n return undefined;\n }\n };\n}\n\nexport type GraphQLRoutableBackendOptions = Omit<\n GraphQLReactorClientOptions,\n \"driveIdFor\"\n>;\n\nexport type GraphQLRoutableBackend = {\n readonly backend: IRoutableBackend;\n /** The Switchboard's own facts, from its inspection subgraph. */\n info(): Promise<ReactorInfo>;\n /** Reopens the realtime socket on the new credentials. */\n notifyCredentialsChanged(): void;\n};\n\n/** A Switchboard as a router backend; members GraphQL cannot serve are absent. */\nexport function createGraphQLRoutableBackend(\n options: GraphQLRoutableBackendOptions,\n): GraphQLRoutableBackend {\n const drives = new KnownDrives();\n const gql = new GraphQLReactorClient({\n ...options,\n driveIdFor: drives.driveIdFor,\n });\n const backend: IRoutableBackend = {\n supports: { find: findIsServableOverGraphQL, pointInTimeViews: false },\n drives: gql.read.drives,\n get: async <TDocument extends PHDocument>(\n identifier: string,\n view?: ViewFilter,\n signal?: AbortSignal,\n ) => drives.learn(await gql.get<TDocument>(identifier, view, signal)),\n getMany: async <TDocument extends PHDocument>(\n ids: string[],\n view?: ViewFilter,\n signal?: AbortSignal,\n ) =>\n (await gql.getMany<TDocument>(ids, view, signal)).map((document) =>\n drives.learn(document),\n ),\n getOperations: (identifier, view, filter, paging, signal) =>\n gql.getOperations(identifier, view, filter, paging, signal),\n find: async (search, view, paging, signal) =>\n drives.learnPage(await gql.find(search, view, paging, signal)),\n isServed: (identifier, view, signal) =>\n gql.isServed(identifier, view, signal),\n getOutgoingRelationships: (source, type, view, paging, signal) =>\n gql.getOutgoingRelationships(source, type, view, paging, signal),\n getIncomingRelationships: (target, type, view, paging, signal) =>\n gql.getIncomingRelationships(target, type, view, paging, signal),\n getOutgoingRelationshipEdges: (source, type, view, paging, signal) =>\n gql.getOutgoingRelationshipEdges(source, type, view, paging, signal),\n getIncomingRelationshipEdges: (target, type, view, paging, signal) =>\n gql.getIncomingRelationshipEdges(target, type, view, paging, signal),\n subscribe: (search, callback, view) =>\n gql.subscribe(search, callback, view),\n getCreateSignaturePolicy: () => gql.getCreateSignaturePolicy(),\n getCreateProtocolVersions: (parent, signal) =>\n gql.getCreateProtocolVersions(parent, signal),\n create: async <TDocument extends PHDocument = PHDocument>(\n document: PHDocument,\n parent?: string,\n signal?: AbortSignal,\n ) => drives.learn(await gql.create<TDocument>(document, parent, signal)),\n execute: async <TDocument extends PHDocument>(\n identifier: string,\n branch: string,\n actions: Action[],\n signal?: AbortSignal,\n ) =>\n drives.learn(\n await gql.execute<TDocument>(identifier, branch, actions, signal),\n ),\n executeBatch: (request, signal) => gql.executeBatch(request, signal),\n deleteDocument: (identifier, propagate, signal) =>\n gql.deleteDocument(identifier, propagate, signal),\n setPreferredEditor: (identifier, editor, branch, signal) =>\n gql.setPreferredEditor(identifier, editor, branch, signal),\n getJob: async (jobId, signal) => {\n const job = await gql.getJob(jobId, signal);\n return job?.status === JobStatus.FAILED &&\n job.error?.name === JOB_NOT_FOUND_ERROR_NAME\n ? undefined\n : job;\n },\n waitForJob: (job, signal) => gql.waitForJob(job, signal),\n };\n return {\n backend,\n info: async () => {\n const result = await gql.request<RemoteReactorInfo>(REMOTE_INFO_QUERY);\n return {\n ...result.inspection.info,\n access: { admin: false, sql: false },\n };\n },\n notifyCredentialsChanged: () => gql.notifyCredentialsChanged(),\n };\n}\n","import {\n createReactorInspector,\n type ReactorInfo,\n} from \"@powerhousedao/reactor\";\nimport type {\n BrowserReactorClientModule,\n WorkerReactorClientModule,\n} from \"@powerhousedao/reactor-browser\";\nimport {\n FanInPartialFailureError,\n fromReactorClient,\n RoutingReactorClient,\n type CollectionRequirementsInput,\n type ReactorReach,\n type RoutableBackendConfig,\n type RouterDiagnostic,\n type RoutingClientOptions,\n} from \"@powerhousedao/reactor-router\";\nimport type {\n DocumentModelModule,\n ISigner,\n} from \"@powerhousedao/shared/document-model\";\nimport { logger } from \"document-model\";\nimport {\n createGraphQLRoutableBackend,\n type GraphQLRoutableBackend,\n} from \"./graphql-routable-backend.js\";\n\nexport { createGraphQLRoutableBackend } from \"./graphql-routable-backend.js\";\nexport type {\n GraphQLRoutableBackend,\n GraphQLRoutableBackendOptions,\n} from \"./graphql-routable-backend.js\";\n\nexport const LOCAL_BACKEND_NAME = \"connect-local\";\nexport const REMOTE_BACKEND_NAME = \"switchboard-remote\";\n\nexport type LocalReactorModule =\n | BrowserReactorClientModule\n | WorkerReactorClientModule;\n\nconst REMOTE_REACH: ReactorReach = Object.freeze({\n hosting: \"remote\",\n inspection: \"none\",\n});\n\n/** Only the tab's reactor is inspectable here, so new collections land on it. */\nexport const PLACE_ON_LOCAL: CollectionRequirementsInput = Object.freeze({\n inspectable: true,\n});\n\nexport function localReach(kind: LocalReactorModule[\"kind\"]): ReactorReach {\n return kind === \"worker\"\n ? { hosting: \"worker\", inspection: \"rpc\" }\n : { hosting: \"in-process\", inspection: \"direct\" };\n}\n\n/** Read at every refresh, never kept: a rebuilt reactor reports its own. */\nexport function localFacts(\n module: LocalReactorModule,\n): () => Promise<ReactorInfo> {\n if (module.kind === \"worker\") {\n return () => module.inspector.info();\n }\n return async () => {\n const reactorModule = module.reactorModule;\n if (!reactorModule) {\n throw new Error(\"The in-tab reactor exposes no module to inspect\");\n }\n return createReactorInspector(reactorModule).info();\n };\n}\n\n/** `<origin>[/<prefix>]/d/<slug>` -> `<origin>[/<prefix>]/graphql`. */\nexport function deriveSwitchboardGraphqlUrl(\n remoteDriveUrl: string,\n): string | undefined {\n let parsed: URL;\n try {\n parsed = new URL(remoteDriveUrl);\n } catch {\n return undefined;\n }\n const prefix = /^(.*)\\/d\\/[^/]+\\/?$/.exec(parsed.pathname)?.[1];\n return prefix === undefined ? undefined : `${parsed.origin}${prefix}/graphql`;\n}\n\n/** The loaded document models, or a getter that reads the current ones. */\nexport type LoadedDocumentModels =\n | readonly DocumentModelModule[]\n | (() => readonly DocumentModelModule[]);\n\nexport type MultiReactorParams = {\n /** The local module, built and ready. Undefined builds a REMOTE-ONLY router\n * (no local backend → no local reactor, no PGlite): the `remote` client. */\n module: LocalReactorModule | undefined;\n remoteGraphqlUrl: string;\n /** Signs routed writes; unsigned (anonymous) without one. */\n signer?: ISigner;\n /** Signing models when the local module exposes no registry; the router asks the local reactor (or, remote-only, the loaded set). */\n documentModelModules: LoadedDocumentModels;\n onDiagnostic?: RouterDiagnostic;\n};\n\n/** Remote-only placement: the Switchboard serves every collection. (It offers\n * no inspection surface over GraphQL, so PLACE_ON_LOCAL's `inspectable`\n * requirement must NOT apply, or no backend would be eligible.) */\nexport const PLACE_ON_REMOTE: CollectionRequirementsInput = Object.freeze({});\n\n/**\n * The local answer stands when only the Switchboard could not answer -- but\n * only when there IS a local backend. Remote-only has nothing to fall back to,\n * so its errors surface. Installed as the router's `answerFailedIdCheck`, so\n * the facade and `write.isDocumentIdTaken` both apply it.\n */\nfunction localIdCheckAnswer(\n documentId: string,\n error: unknown,\n): boolean | undefined {\n if (!failedOnlyOnRemote(error)) {\n return undefined;\n }\n logger.warn(\n \"The Switchboard could not say whether @id is taken; using the local reactor's answer: @error\",\n documentId,\n error,\n );\n return false;\n}\n\n/** The router Connect installs, with Connect's handling of credentials and id checks. */\nexport class ConnectRoutingClient extends RoutingReactorClient {\n private readonly remote: GraphQLRoutableBackend;\n\n constructor(\n backends: readonly RoutableBackendConfig[],\n options: RoutingClientOptions,\n remote: GraphQLRoutableBackend,\n hasLocal: boolean,\n ) {\n super(backends, {\n ...options,\n answerFailedIdCheck: hasLocal\n ? localIdCheckAnswer\n : options.answerFailedIdCheck,\n });\n this.remote = remote;\n }\n\n /** Renown's sign-in and sign-out call this on whatever client is installed. */\n notifyCredentialsChanged(): void {\n this.remote.notifyCredentialsChanged();\n }\n}\n\nfunction failedOnlyOnRemote(error: unknown): boolean {\n return (\n error instanceof FanInPartialFailureError &&\n error.failures.every((failure) => failure.backend === REMOTE_BACKEND_NAME)\n );\n}\n\n/**\n * Build the Connect routing client. With a local `module` it is the router\n * over the tab's reactor (primary) and the Switchboard; WITHOUT one it is the\n * `remote` client — a remote-only router whose single backend is the\n * Switchboard, so no local reactor (and no PGlite) is built. Either way the\n * result is a full IReactorClient the app graph consumes unchanged.\n */\nexport async function buildMultiReactorClient(\n params: MultiReactorParams,\n): Promise<ConnectRoutingClient> {\n const module = params.module;\n const registry = module?.reactorModule?.documentModelRegistry;\n const loaded = params.documentModelModules;\n const loadedModules = typeof loaded === \"function\" ? loaded : () => loaded;\n const remote = createGraphQLRoutableBackend({\n url: params.remoteGraphqlUrl,\n documentModels: () => registry?.getAllModules() ?? loadedModules(),\n });\n const remoteBackend: RoutableBackendConfig = {\n name: REMOTE_BACKEND_NAME,\n backend: remote.backend,\n facts: () => remote.info(),\n reach: REMOTE_REACH,\n refusesMisroutes: false,\n };\n const backends: RoutableBackendConfig[] = module\n ? [\n {\n name: LOCAL_BACKEND_NAME,\n backend: fromReactorClient(module.client),\n facts: localFacts(module),\n reach: localReach(module.kind),\n refusesMisroutes: false,\n },\n remoteBackend,\n ]\n : [remoteBackend];\n const router = new ConnectRoutingClient(\n backends,\n {\n // Remote-only: the Switchboard is primary and serves every collection;\n // with a local reactor, new collections land on it (inspectable).\n primaryBackend: module ? LOCAL_BACKEND_NAME : REMOTE_BACKEND_NAME,\n defaultRequirements: module ? PLACE_ON_LOCAL : PLACE_ON_REMOTE,\n signer: params.signer,\n onDiagnostic: params.onDiagnostic,\n // The Switchboard serves no models over GraphQL; remote-only uses the loaded set.\n documentModelModules: module ? undefined : loadedModules,\n },\n remote,\n Boolean(module),\n );\n await router.refreshFacts();\n return router;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { O as __exportAll } from "./views-CAbBIFzO.js";
1
+ import { O as __exportAll } from "./views-anOyTI7u.js";
2
2
  import { t as getConnectRegistry } from "./registry-DCZHBP7M.js";
3
3
  import { resolveOrder, runTransformHook } from "@powerhousedao/host-core/plugins";
4
4
  //#region src/plugins/plugin-host.ts
@@ -57,4 +57,4 @@ async function applyComposition(config) {
57
57
  //#endregion
58
58
  export { registerConnectPlugins as i, knownPlugins as n, plugin_host_exports as r, applyComposition as t };
59
59
 
60
- //# sourceMappingURL=plugin-host-BSFfhXpz.js.map
60
+ //# sourceMappingURL=plugin-host-HhfxwUZN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-host-BSFfhXpz.js","names":[],"sources":["../src/plugins/plugin-host.ts"],"sourcesContent":["import {\n resolveOrder,\n runTransformHook,\n} from \"@powerhousedao/host-core/plugins\";\nimport type { PHConnectRuntimeConfig } from \"@powerhousedao/shared/clis\";\nimport type { ConnectPluginDefinitions } from \"../registry.js\";\nimport { getConnectRegistry } from \"../registry.js\";\nimport type {\n ConnectPlugin,\n ConnectPluginContext,\n ConnectPluginDefinition,\n} from \"./types.js\";\n\nexport type { ConnectPluginContext } from \"./types.js\";\n\n// ConnectCore's plugin pipeline (rewire plan R3). It runs only when the served\n// config carries a `composition`; presence is activation.\n\ntype PluginDefinitions = ConnectPluginDefinitions;\ntype PluginLoader = () => Promise<PluginDefinitions>;\n\n/** Makes plugin modules known by specifier; a loader runs when a composition applies. */\nexport function registerConnectPlugins(\n plugins: PluginDefinitions | PluginLoader,\n) {\n const registry = getConnectRegistry();\n if (typeof plugins === \"function\") registry.pluginLoaders.push(plugins);\n else Object.assign(registry.plugins, plugins);\n}\n\n/** Every plugin module made known, its loaders run. */\nexport async function knownPlugins(): Promise<PluginDefinitions> {\n const registry = getConnectRegistry();\n const pending = registry.pluginLoaders;\n registry.pluginLoaders = [];\n for (const loaded of await Promise.all(pending.map((load) => load()))) {\n Object.assign(registry.plugins, loaded);\n }\n return registry.plugins;\n}\n\n/** The slices of known plugins absent from the composition, zeroed. */\nfunction zeroAbsentSlices(\n config: PHConnectRuntimeConfig,\n present: ReadonlySet<string>,\n plugins: PluginDefinitions,\n): PHConnectRuntimeConfig {\n let out = { ...config };\n for (const [module, definition] of Object.entries(plugins)) {\n if (!present.has(module) && definition.whenAbsent) {\n out = definition.whenAbsent(out);\n }\n }\n return out;\n}\n\nconst LOG = \"[connect:plugins]\";\n\n/** Applies the composition to the served config; pure, and logs the plan and\n * each hook it fires to the console. */\nexport async function applyComposition(\n config: PHConnectRuntimeConfig,\n): Promise<PHConnectRuntimeConfig> {\n const composition = config.composition;\n if (!composition) return config;\n\n const definitions = await knownPlugins();\n const present = new Set(composition.map((entry) => entry.module));\n const plugins: ConnectPlugin[] = [];\n\n console.info(\n `${LOG} resolving composition — ${composition.length} entr${composition.length === 1 ? \"y\" : \"ies\"}`,\n );\n for (const entry of composition) {\n const definition: ConnectPluginDefinition | undefined =\n definitions[entry.module];\n if (!definition) {\n console.warn(\n `${LOG} ✗ ${entry.module} — unknown (external plugin loading not wired); SKIPPED`,\n );\n continue;\n }\n const plugin = definition.create(entry.config ?? {});\n plugins.push(plugin);\n const cfgKeys = Object.keys(entry.config ?? {});\n console.info(\n `${LOG} ✓ ${plugin.name} (${entry.module})` +\n (cfgKeys.length ? ` config: {${cfgKeys.join(\", \")}}` : \"\"),\n );\n }\n\n const ordered = resolveOrder(plugins);\n const ctx: ConnectPluginContext = { entryConfig: {} };\n const ran = ordered\n .filter((p) => p.hooks?.transformConnectConfig)\n .map((p) => p.name);\n console.info(\n `${LOG} hook transformConnectConfig → ${ran.length ? ran.join(\", \") : \"(none)\"}`,\n );\n return runTransformHook<PHConnectRuntimeConfig, ConnectPluginContext>(\n \"transformConnectConfig\",\n ordered,\n ctx,\n zeroAbsentSlices(config, present, definitions),\n );\n}\n"],"mappings":";;;;;;;;;;AAsBA,SAAgB,uBACd,SACA;CACA,MAAM,WAAW,mBAAmB;CACpC,IAAI,OAAO,YAAY,YAAY,SAAS,cAAc,KAAK,OAAO;MACjE,OAAO,OAAO,SAAS,SAAS,OAAO;AAC9C;;AAGA,eAAsB,eAA2C;CAC/D,MAAM,WAAW,mBAAmB;CACpC,MAAM,UAAU,SAAS;CACzB,SAAS,gBAAgB,CAAC;CAC1B,KAAK,MAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,KAAK,SAAS,KAAK,CAAC,CAAC,GAClE,OAAO,OAAO,SAAS,SAAS,MAAM;CAExC,OAAO,SAAS;AAClB;;AAGA,SAAS,iBACP,QACA,SACA,SACwB;CACxB,IAAI,MAAM,EAAE,GAAG,OAAO;CACtB,KAAK,MAAM,CAAC,QAAQ,eAAe,OAAO,QAAQ,OAAO,GACvD,IAAI,CAAC,QAAQ,IAAI,MAAM,KAAK,WAAW,YACrC,MAAM,WAAW,WAAW,GAAG;CAGnC,OAAO;AACT;AAEA,MAAM,MAAM;;;AAIZ,eAAsB,iBACpB,QACiC;CACjC,MAAM,cAAc,OAAO;CAC3B,IAAI,CAAC,aAAa,OAAO;CAEzB,MAAM,cAAc,MAAM,aAAa;CACvC,MAAM,UAAU,IAAI,IAAI,YAAY,KAAK,UAAU,MAAM,MAAM,CAAC;CAChE,MAAM,UAA2B,CAAC;CAElC,QAAQ,KACN,GAAG,IAAI,2BAA2B,YAAY,OAAO,OAAO,YAAY,WAAW,IAAI,MAAM,OAC/F;CACA,KAAK,MAAM,SAAS,aAAa;EAC/B,MAAM,aACJ,YAAY,MAAM;EACpB,IAAI,CAAC,YAAY;GACf,QAAQ,KACN,GAAG,IAAI,OAAO,MAAM,OAAO,wDAC7B;GACA;EACF;EACA,MAAM,SAAS,WAAW,OAAO,MAAM,UAAU,CAAC,CAAC;EACnD,QAAQ,KAAK,MAAM;EACnB,MAAM,UAAU,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC;EAC9C,QAAQ,KACN,GAAG,IAAI,OAAO,OAAO,KAAK,IAAI,MAAM,OAAO,MACxC,QAAQ,SAAS,aAAa,QAAQ,KAAK,IAAI,EAAE,KAAK,GAC3D;CACF;CAEA,MAAM,UAAU,aAAa,OAAO;CACpC,MAAM,MAA4B,EAAE,aAAa,CAAC,EAAE;CACpD,MAAM,MAAM,QACT,QAAQ,MAAM,EAAE,OAAO,sBAAsB,CAAC,CAC9C,KAAK,MAAM,EAAE,IAAI;CACpB,QAAQ,KACN,GAAG,IAAI,iCAAiC,IAAI,SAAS,IAAI,KAAK,IAAI,IAAI,UACxE;CACA,OAAO,iBACL,0BACA,SACA,KACA,iBAAiB,QAAQ,SAAS,WAAW,CAC/C;AACF"}
1
+ {"version":3,"file":"plugin-host-HhfxwUZN.js","names":[],"sources":["../src/plugins/plugin-host.ts"],"sourcesContent":["import {\n resolveOrder,\n runTransformHook,\n} from \"@powerhousedao/host-core/plugins\";\nimport type { PHConnectRuntimeConfig } from \"@powerhousedao/shared/clis\";\nimport type { ConnectPluginDefinitions } from \"../registry.js\";\nimport { getConnectRegistry } from \"../registry.js\";\nimport type {\n ConnectPlugin,\n ConnectPluginContext,\n ConnectPluginDefinition,\n} from \"./types.js\";\n\nexport type { ConnectPluginContext } from \"./types.js\";\n\n// ConnectCore's plugin pipeline (rewire plan R3). It runs only when the served\n// config carries a `composition`; presence is activation.\n\ntype PluginDefinitions = ConnectPluginDefinitions;\ntype PluginLoader = () => Promise<PluginDefinitions>;\n\n/** Makes plugin modules known by specifier; a loader runs when a composition applies. */\nexport function registerConnectPlugins(\n plugins: PluginDefinitions | PluginLoader,\n) {\n const registry = getConnectRegistry();\n if (typeof plugins === \"function\") registry.pluginLoaders.push(plugins);\n else Object.assign(registry.plugins, plugins);\n}\n\n/** Every plugin module made known, its loaders run. */\nexport async function knownPlugins(): Promise<PluginDefinitions> {\n const registry = getConnectRegistry();\n const pending = registry.pluginLoaders;\n registry.pluginLoaders = [];\n for (const loaded of await Promise.all(pending.map((load) => load()))) {\n Object.assign(registry.plugins, loaded);\n }\n return registry.plugins;\n}\n\n/** The slices of known plugins absent from the composition, zeroed. */\nfunction zeroAbsentSlices(\n config: PHConnectRuntimeConfig,\n present: ReadonlySet<string>,\n plugins: PluginDefinitions,\n): PHConnectRuntimeConfig {\n let out = { ...config };\n for (const [module, definition] of Object.entries(plugins)) {\n if (!present.has(module) && definition.whenAbsent) {\n out = definition.whenAbsent(out);\n }\n }\n return out;\n}\n\nconst LOG = \"[connect:plugins]\";\n\n/** Applies the composition to the served config; pure, and logs the plan and\n * each hook it fires to the console. */\nexport async function applyComposition(\n config: PHConnectRuntimeConfig,\n): Promise<PHConnectRuntimeConfig> {\n const composition = config.composition;\n if (!composition) return config;\n\n const definitions = await knownPlugins();\n const present = new Set(composition.map((entry) => entry.module));\n const plugins: ConnectPlugin[] = [];\n\n console.info(\n `${LOG} resolving composition — ${composition.length} entr${composition.length === 1 ? \"y\" : \"ies\"}`,\n );\n for (const entry of composition) {\n const definition: ConnectPluginDefinition | undefined =\n definitions[entry.module];\n if (!definition) {\n console.warn(\n `${LOG} ✗ ${entry.module} — unknown (external plugin loading not wired); SKIPPED`,\n );\n continue;\n }\n const plugin = definition.create(entry.config ?? {});\n plugins.push(plugin);\n const cfgKeys = Object.keys(entry.config ?? {});\n console.info(\n `${LOG} ✓ ${plugin.name} (${entry.module})` +\n (cfgKeys.length ? ` config: {${cfgKeys.join(\", \")}}` : \"\"),\n );\n }\n\n const ordered = resolveOrder(plugins);\n const ctx: ConnectPluginContext = { entryConfig: {} };\n const ran = ordered\n .filter((p) => p.hooks?.transformConnectConfig)\n .map((p) => p.name);\n console.info(\n `${LOG} hook transformConnectConfig → ${ran.length ? ran.join(\", \") : \"(none)\"}`,\n );\n return runTransformHook<PHConnectRuntimeConfig, ConnectPluginContext>(\n \"transformConnectConfig\",\n ordered,\n ctx,\n zeroAbsentSlices(config, present, definitions),\n );\n}\n"],"mappings":";;;;;;;;;;AAsBA,SAAgB,uBACd,SACA;CACA,MAAM,WAAW,mBAAmB;CACpC,IAAI,OAAO,YAAY,YAAY,SAAS,cAAc,KAAK,OAAO;MACjE,OAAO,OAAO,SAAS,SAAS,OAAO;AAC9C;;AAGA,eAAsB,eAA2C;CAC/D,MAAM,WAAW,mBAAmB;CACpC,MAAM,UAAU,SAAS;CACzB,SAAS,gBAAgB,CAAC;CAC1B,KAAK,MAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,KAAK,SAAS,KAAK,CAAC,CAAC,GAClE,OAAO,OAAO,SAAS,SAAS,MAAM;CAExC,OAAO,SAAS;AAClB;;AAGA,SAAS,iBACP,QACA,SACA,SACwB;CACxB,IAAI,MAAM,EAAE,GAAG,OAAO;CACtB,KAAK,MAAM,CAAC,QAAQ,eAAe,OAAO,QAAQ,OAAO,GACvD,IAAI,CAAC,QAAQ,IAAI,MAAM,KAAK,WAAW,YACrC,MAAM,WAAW,WAAW,GAAG;CAGnC,OAAO;AACT;AAEA,MAAM,MAAM;;;AAIZ,eAAsB,iBACpB,QACiC;CACjC,MAAM,cAAc,OAAO;CAC3B,IAAI,CAAC,aAAa,OAAO;CAEzB,MAAM,cAAc,MAAM,aAAa;CACvC,MAAM,UAAU,IAAI,IAAI,YAAY,KAAK,UAAU,MAAM,MAAM,CAAC;CAChE,MAAM,UAA2B,CAAC;CAElC,QAAQ,KACN,GAAG,IAAI,2BAA2B,YAAY,OAAO,OAAO,YAAY,WAAW,IAAI,MAAM,OAC/F;CACA,KAAK,MAAM,SAAS,aAAa;EAC/B,MAAM,aACJ,YAAY,MAAM;EACpB,IAAI,CAAC,YAAY;GACf,QAAQ,KACN,GAAG,IAAI,OAAO,MAAM,OAAO,wDAC7B;GACA;EACF;EACA,MAAM,SAAS,WAAW,OAAO,MAAM,UAAU,CAAC,CAAC;EACnD,QAAQ,KAAK,MAAM;EACnB,MAAM,UAAU,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC;EAC9C,QAAQ,KACN,GAAG,IAAI,OAAO,OAAO,KAAK,IAAI,MAAM,OAAO,MACxC,QAAQ,SAAS,aAAa,QAAQ,KAAK,IAAI,EAAE,KAAK,GAC3D;CACF;CAEA,MAAM,UAAU,aAAa,OAAO;CACpC,MAAM,MAA4B,EAAE,aAAa,CAAC,EAAE;CACpD,MAAM,MAAM,QACT,QAAQ,MAAM,EAAE,OAAO,sBAAsB,CAAC,CAC9C,KAAK,MAAM,EAAE,IAAI;CACpB,QAAQ,KACN,GAAG,IAAI,iCAAiC,IAAI,SAAS,IAAI,KAAK,IAAI,IAAI,UACxE;CACA,OAAO,iBACL,0BACA,SACA,KACA,iBAAiB,QAAQ,SAAS,WAAW,CAC/C;AACF"}
@@ -1,8 +1,8 @@
1
- import { O as __exportAll } from "./views-CAbBIFzO.js";
1
+ import { O as __exportAll } from "./views-anOyTI7u.js";
2
2
  import { t as getConnectRegistry } from "./registry-DCZHBP7M.js";
3
3
  import { f as CORE_MODAL_VIEWS, l as removeConnectRoutes, r as addConnectRoutes, u as resolveConnectRoutes } from "./route-tree-D0aszMrk.js";
4
- import { n as knownPlugins } from "./plugin-host-BSFfhXpz.js";
5
- import { findDriveBySlugOrId, makeDriveSlug, makeNodeSlug, resolveDriveRoute } from "@powerhousedao/reactor-browser";
4
+ import { n as knownPlugins } from "./plugin-host-HhfxwUZN.js";
5
+ import { findDriveBySlugOrId, makeDriveSlug, makeNodeSlug, peekDriveNode, resolveDriveRoute } from "@powerhousedao/reactor-browser";
6
6
  import { lazyRouteComponent, notFound, redirect } from "@tanstack/react-router";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  //#region src/router/drive-route-loader.ts
@@ -58,7 +58,7 @@ function canonicalParams(store, data) {
58
58
  const drive = findDriveBySlugOrId(store, data.driveId);
59
59
  if (!drive) return void 0;
60
60
  if (!data.nodeId) return { driveSlug: makeDriveSlug(drive) };
61
- const node = drive.state.global.nodes.find((n) => n.id === data.nodeId);
61
+ const node = peekDriveNode(drive.header.id, data.nodeId, store);
62
62
  if (!node) return void 0;
63
63
  return {
64
64
  driveSlug: makeDriveSlug(drive),
@@ -197,4 +197,4 @@ function resetConnectPluginUi(routeTree) {
197
197
  //#endregion
198
198
  export { plugin_ui_exports as a, CoreNotFound as c, isCoreView as d, isDriveNotFound as f, mergeConnectPluginUi as i, coreModals as l, loadNode as m, getConnectPluginUi as n, resetConnectPluginUi as o, loadDrive as p, loadConnectPluginUi as r, CoreError as s, applyConnectPluginUi as t, coreView as u };
199
199
 
200
- //# sourceMappingURL=plugin-ui-sO7AJLHj.js.map
200
+ //# sourceMappingURL=plugin-ui-W0ma6oKJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-ui-W0ma6oKJ.js","names":[],"sources":["../src/router/drive-route-loader.ts","../src/router/core-views.tsx","../src/plugins/plugin-ui.ts"],"sourcesContent":["// The drive routes' loaders. Server-safe: they read everything from router context.\nimport type { DriveArrivals, PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n findDriveBySlugOrId,\n makeDriveSlug,\n makeNodeSlug,\n peekDriveNode,\n resolveDriveRoute,\n} from \"@powerhousedao/reactor-browser\";\nimport { notFound, redirect } from \"@tanstack/react-router\";\n\nexport type ConnectRouterContext = {\n store: PHStore;\n /** Without it the drive route never waits for drives to arrive. */\n arrivals?: DriveArrivals;\n /** Ends every document title; \"Connect\" without one. */\n appName?: string;\n /** Rendering the loading shell: a layout shows its pendingComponent in place of its page. */\n shell?: boolean;\n};\n\n/** A missing drive's not-found data. */\nexport type DriveNotFoundData = { driveSlug: string };\n\nexport function isDriveNotFound(data: unknown): data is DriveNotFoundData {\n return (\n typeof data === \"object\" &&\n data !== null &&\n typeof (data as { driveSlug?: unknown }).driveSlug === \"string\"\n );\n}\n\n/** What the drive routes resolved their params to. */\nexport type DriveRouteData = { driveId: string; nodeId?: string };\n\nexport type DriveRouteParams = { driveSlug: string; nodeSlug?: string };\n\nexport type DriveLoaderOptions = {\n params: DriveRouteParams;\n context: ConnectRouterContext;\n abortController: AbortController;\n preload: boolean;\n};\n\nfunction resolve(options: DriveLoaderOptions, params: DriveRouteParams) {\n return resolveDriveRoute({\n store: options.context.store,\n arrivals: options.context.arrivals,\n driveSlug: params.driveSlug,\n nodeSlug: params.nodeSlug,\n signal: options.abortController.signal,\n preload: options.preload,\n });\n}\n\n// At the drive layout, so the 404 takes the drive's place in the layout.\nfunction driveNotFound(driveSlug: string) {\n return notFound({\n routeId: \"/_app/d/$driveSlug\" as never,\n data: { driveSlug } satisfies DriveNotFoundData,\n });\n}\n\n/** The drive layout's loader: the drive, or not found once arrivals settle. */\nexport async function loadDrive(\n options: DriveLoaderOptions,\n): Promise<{ driveId: string }> {\n const { driveSlug } = options.params;\n const result = await resolve(options, { driveSlug });\n if (result.kind === \"drive-not-found\") {\n // oxlint-disable-next-line typescript/only-throw-error -- router control flow\n throw driveNotFound(driveSlug);\n }\n return { driveId: result.driveId };\n}\n\n/** The node route's loader: the drive and the open node. An id or an old name\n * in the URL becomes the current slugs; a missing node leads to its drive. */\nexport async function loadNode(\n options: DriveLoaderOptions,\n): Promise<DriveRouteData> {\n const { params, context, preload } = options;\n const result = await resolve(options, params);\n switch (result.kind) {\n case \"drive\": {\n const data: DriveRouteData = result.nodeId\n ? { driveId: result.driveId, nodeId: result.nodeId }\n : { driveId: result.driveId };\n const canonical = canonicalParams(context.store, data);\n // An id, an old name or an old drive id in the URL becomes the current slugs.\n if (\n !preload &&\n canonical &&\n (canonical.driveSlug !== params.driveSlug ||\n canonical.nodeSlug !== (params.nodeSlug || undefined))\n ) {\n // oxlint-disable-next-line typescript/only-throw-error -- router control flow\n throw redirectTo(canonical);\n }\n return data;\n }\n case \"drive-not-found\":\n // oxlint-disable-next-line typescript/only-throw-error -- router control flow\n throw driveNotFound(params.driveSlug);\n case \"node-not-found\":\n // oxlint-disable-next-line typescript/only-throw-error -- router control flow\n throw redirectTo({\n driveSlug:\n canonicalParams(context.store, { driveId: result.driveId })\n ?.driveSlug ?? params.driveSlug,\n nodeSlug: undefined,\n });\n }\n}\n\n// The slugs links write for `data`; unknown while the drive is unlisted.\nfunction canonicalParams(\n store: PHStore,\n data: DriveRouteData,\n): DriveRouteParams | undefined {\n const drive = findDriveBySlugOrId(store, data.driveId);\n if (!drive) return undefined;\n if (!data.nodeId) return { driveSlug: makeDriveSlug(drive) };\n // resolveDriveRoute cached the node it resolved.\n const node = peekDriveNode(drive.header.id, data.nodeId, store);\n if (!node) return undefined;\n return { driveSlug: makeDriveSlug(drive), nodeSlug: makeNodeSlug(node) };\n}\n\n// In place, with the URL's search params and history state (the opened-from index).\nfunction redirectTo(params: DriveRouteParams) {\n return redirect({\n to: \"/d/$driveSlug/{-$nodeSlug}\",\n params,\n search: true,\n state: true,\n replace: true,\n });\n}\n","// The router's one edge to core's views: views never import this module, so\n// loading them lazily makes no import cycle.\nimport type {\n ErrorRouteComponent,\n NotFoundRouteProps,\n RouteComponent,\n} from \"@tanstack/react-router\";\nimport { lazyRouteComponent } from \"@tanstack/react-router\";\nimport type { ComponentType } from \"react\";\nimport { isDriveNotFound } from \"./drive-route-loader.js\";\nimport type { ConnectModals } from \"./modals.js\";\nimport { CORE_MODAL_VIEWS } from \"./modals.js\";\n\n// Core's views load only when a page shows one.\nconst views = () => import(\"@powerhousedao/connect-core/views\");\n\nconst CORE_VIEW = Symbol.for(\"@powerhousedao/connect-core/core-view\");\n\n/** One of core's views, loaded with the route that shows it. */\nexport function coreView(name: keyof Awaited<ReturnType<typeof views>>) {\n return Object.assign(lazyRouteComponent(views, name), {\n [CORE_VIEW]: true,\n }) as RouteComponent;\n}\n\n/** Whether a route's component is one of core's views, which a plugin's UI replaces. */\nexport function isCoreView(component: unknown) {\n return (\n typeof component === \"function\" &&\n (component as { [CORE_VIEW]?: true })[CORE_VIEW] === true\n );\n}\n\nconst NotFoundPage = coreView(\"NotFoundPage\");\nconst DriveNotFoundPage = coreView(\"DriveNotFoundPage\") as ComponentType<{\n driveSlug: string;\n}>;\n\n/** Core's not-found page; a missing drive's names the drive. */\nexport function CoreNotFound({ data }: Partial<NotFoundRouteProps>) {\n return isDriveNotFound(data) ? (\n <DriveNotFoundPage driveSlug={data.driveSlug} />\n ) : (\n <NotFoundPage />\n );\n}\n\n/** Core's view of a route's loader or render error. */\nexport const CoreError = coreView(\"CoreRouteError\") as ErrorRouteComponent;\n\n/** Core's modals, loaded when one opens. */\nexport const coreModals: ConnectModals = Object.fromEntries(\n Object.entries(CORE_MODAL_VIEWS).map(([type, name]) => [\n type,\n coreView(name),\n ]),\n);\n","import type { AnyRoute, ErrorRouteComponent } from \"@tanstack/react-router\";\nimport type { ComponentType } from \"react\";\nimport type { ConnectRouteRegistration } from \"../registry.js\";\nimport { getConnectRegistry } from \"../registry.js\";\nimport type { ConnectModals } from \"../router/modals.js\";\nimport { isCoreView } from \"../router/core-views.js\";\nimport {\n addConnectRoutes,\n removeConnectRoutes,\n resolveConnectRoutes,\n} from \"../router/route-tree.js\";\nimport { knownPlugins } from \"./plugin-host.js\";\nimport type { ConnectPluginUi, ConnectRouteUi } from \"./types.js\";\n\n/** The active plugins' UI; a later plugin's routes and modals win. */\nexport type ConnectPluginUiSet = {\n routes: Record<string, ConnectRouteUi>;\n addRoutes: ConnectRouteRegistration[];\n modals: ConnectModals;\n roots: ComponentType[];\n errorComponent?: ErrorRouteComponent;\n commonEditors: boolean;\n consent: boolean;\n};\n\nconst NO_UI: ConnectPluginUiSet = {\n routes: {},\n addRoutes: [],\n modals: {},\n roots: [],\n commonEditors: false,\n consent: false,\n};\n\nexport function mergeConnectPluginUi(\n uis: readonly ConnectPluginUi[],\n): ConnectPluginUiSet {\n const set: ConnectPluginUiSet = {\n routes: {},\n addRoutes: [],\n modals: {},\n roots: [],\n commonEditors: false,\n consent: false,\n };\n for (const ui of uis) {\n for (const [id, route] of Object.entries(ui.routes ?? {})) {\n set.routes[id] = { ...set.routes[id], ...route };\n }\n if (ui.addRoutes) set.addRoutes.push(ui.addRoutes);\n Object.assign(set.modals, ui.modals);\n if (ui.Root) set.roots.push(ui.Root);\n set.errorComponent = ui.errorComponent ?? set.errorComponent;\n set.commonEditors ||= ui.commonEditors ?? false;\n set.consent ||= ui.consent ?? false;\n }\n return set;\n}\n\n/** Loads the UI of the plugins `composition` names, or of every known plugin\n * without one (classic Connect), and keeps it for `getConnectPluginUi`. */\nexport async function loadConnectPluginUi(\n composition: readonly { module: string }[] | undefined,\n): Promise<ConnectPluginUiSet> {\n const definitions = await knownPlugins();\n const modules = composition\n ? composition.map((entry) => entry.module)\n : Object.keys(definitions);\n const uis = await Promise.all(\n modules.map(\n (module) => definitions[module]?.ui?.() ?? Promise.resolve(undefined),\n ),\n );\n const set = mergeConnectPluginUi(\n uis.filter((ui): ui is ConnectPluginUi => !!ui),\n );\n getConnectRegistry().ui = set;\n return set;\n}\n\n/** The active plugins' UI; none until `loadRuntimeConfig` has loaded it. */\nexport function getConnectPluginUi(): ConnectPluginUiSet {\n return getConnectRegistry().ui ?? NO_UI;\n}\n\ntype RouteOptions = Record<string, unknown> & { id?: string; path?: string };\n\nconst ROOT_ID = \"__root__\";\n\nfunction forEachRoute(\n route: AnyRoute,\n visit: (route: AnyRoute, id: string) => void,\n parentId?: string,\n) {\n const options = route.options as unknown as RouteOptions;\n const segment = options.id ?? options.path;\n const own =\n parentId === undefined || segment === undefined\n ? ROOT_ID\n : `${parentId === ROOT_ID ? \"\" : parentId}/${segment.replace(/^\\//, \"\")}`;\n visit(route, own);\n for (const child of (route.children ?? []) as AnyRoute[]) {\n forEachRoute(child, visit, own);\n }\n}\n\ntype Applied = { originals: Map<AnyRoute, RouteOptions>; added: AnyRoute[] };\nconst appliedTo = new WeakMap<AnyRoute, Applied>();\n\n/** Sets `ui`'s route options on the tree's routes that still show core's view,\n * and adds its routes; `resetConnectPluginUi` undoes both. */\nexport function applyConnectPluginUi(\n routeTree: AnyRoute,\n ui: ConnectPluginUiSet = getConnectPluginUi(),\n) {\n resetConnectPluginUi(routeTree);\n const applied: Applied = { originals: new Map(), added: [] };\n forEachRoute(routeTree, (route, id) => {\n const routeUi = ui.routes[id];\n const options = route.options as unknown as RouteOptions;\n if (!routeUi || !isCoreView(options.component)) return;\n const { staticData, ...views } = routeUi;\n const keys = [...Object.keys(views), ...(staticData ? [\"staticData\"] : [])];\n applied.originals.set(\n route,\n Object.fromEntries(keys.map((key) => [key, options[key]])),\n );\n Object.assign(options, views);\n if (staticData) {\n options.staticData = {\n ...(options.staticData as object | undefined),\n ...staticData,\n };\n }\n });\n for (const registration of ui.addRoutes) {\n const routes = resolveConnectRoutes(registration, routeTree);\n addConnectRoutes(routes);\n applied.added.push(...routes);\n }\n appliedTo.set(routeTree, applied);\n}\n\n/** Restores the routes `applyConnectPluginUi` changed and removes the ones it added. */\nexport function resetConnectPluginUi(routeTree: AnyRoute) {\n const applied = appliedTo.get(routeTree);\n if (!applied) return;\n for (const [route, originals] of applied.originals) {\n Object.assign(route.options, originals);\n }\n removeConnectRoutes(applied.added);\n appliedTo.delete(routeTree);\n}\n"],"mappings":"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"}
package/dist/plugins.js CHANGED
@@ -1,4 +1,4 @@
1
- import { i as mergeConnectPluginUi, n as getConnectPluginUi, o as resetConnectPluginUi, r as loadConnectPluginUi, t as applyConnectPluginUi } from "./plugin-ui-sO7AJLHj.js";
2
- import { i as registerConnectPlugins, n as knownPlugins, t as applyComposition } from "./plugin-host-BSFfhXpz.js";
1
+ import { i as mergeConnectPluginUi, n as getConnectPluginUi, o as resetConnectPluginUi, r as loadConnectPluginUi, t as applyConnectPluginUi } from "./plugin-ui-W0ma6oKJ.js";
2
+ import { i as registerConnectPlugins, n as knownPlugins, t as applyComposition } from "./plugin-host-HhfxwUZN.js";
3
3
  import { n as isPluginActive, t as getActivePluginModules } from "./plugins-x1XqLPzp.js";
4
4
  export { applyComposition, applyConnectPluginUi, getActivePluginModules, getConnectPluginUi, isPluginActive, knownPlugins, loadConnectPluginUi, mergeConnectPluginUi, registerConnectPlugins, resetConnectPluginUi };
@@ -1,7 +1,7 @@
1
1
  import { t as getConnectRegistry } from "./registry-DCZHBP7M.js";
2
- import { c as CoreNotFound, n as getConnectPluginUi, s as CoreError, t as applyConnectPluginUi } from "./plugin-ui-sO7AJLHj.js";
2
+ import { c as CoreNotFound, n as getConnectPluginUi, s as CoreError, t as applyConnectPluginUi } from "./plugin-ui-W0ma6oKJ.js";
3
3
  import { i as connectRoutes, r as addConnectRoutes, u as resolveConnectRoutes } from "./route-tree-D0aszMrk.js";
4
- import { S as CONTENT_VIEW_ID, b as driveTitle, f as setSettingsRoute, p as settingsTabs, u as keepOpenedFrom } from "./sidebar-DVQCwBYR.js";
4
+ import { S as CONTENT_VIEW_ID, b as driveTitle, f as setSettingsRoute, p as settingsTabs, u as keepOpenedFrom } from "./sidebar-CRv_DvBV.js";
5
5
  import { FEATURE_FLAG_PARAM_PREFIX, GLOBAL_SEARCH_PARAMS, OPENED_FROM_STATE_KEY, PHStoreProvider, REVISION_HISTORY_PAGE_PARAM, REVISION_HISTORY_PARAM, applySearchUpdate, createDriveArrivals, findDriveBySlugOrId, getPHStoreSubscribe, isRoutedModal, isSettingsTarget, makeDriveSlug, modalFromSearch, openedFromIndex, parseRevisionHistoryPage, resolveSearchUpdate, searchParamsToString } from "@powerhousedao/reactor-browser";
6
6
  import { RouterProvider, createRouter, retainSearchParams, useRouterState } from "@tanstack/react-router";
7
7
  import { useMemo } from "react";
@@ -424,6 +424,7 @@ function bindConnectRouter(connectRouter, store) {
424
424
  }),
425
425
  router.subscribe("onResolved", syncModal),
426
426
  getPHStoreSubscribe(store, "drives")(retitle),
427
+ getPHStoreSubscribe(store, "driveNodes")(retitle),
427
428
  markRouterNavigations(router)
428
429
  ];
429
430
  const unbindScroll = bindConnectScroll(router, CONTENT_VIEW_ID);
@@ -488,4 +489,4 @@ function ConnectCoreApp(props) {
488
489
  //#endregion
489
490
  export { PERF_STORAGE_KEY as _, createConnectRouter as a, markRouterNavigations as b, GLOBAL_SEARCH_PARAMS as c, parseConnectSearch as d, stringifyConnectSearch as f, connectScrollRestoration as g, bindConnectScroll as h, bindConnectRouter as i, connectSearchMiddlewares as l, validateDriveSearch as m, disposeConnectAppRouter as n, createConnectNavigation as o, validateConnectSearch as p, getConnectAppRouter as r, FEATURE_FLAG_PARAM_PREFIX as s, ConnectCoreApp as t, definedSearch as u, ROUTER_MEASURES as v, routerPerfEnabled as x, markNavigationClick as y };
490
491
 
491
- //# sourceMappingURL=router-8pekwJsk.js.map
492
+ //# sourceMappingURL=router-DHL9GT3P.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"router-8pekwJsk.js","names":[],"sources":["../src/router/perf-marks.ts","../src/router/scroll.ts","../src/router/search.ts","../src/router/navigation.ts","../src/router/connect-router.ts","../src/router/app-router.ts","../src/router/core-app.tsx"],"sourcesContent":["import type { AnyRouter } from \"@tanstack/react-router\";\n\n/** `localStorage[PERF_STORAGE_KEY] = \"1\"` or `?perf=1` turns the marks on in production. */\nexport const PERF_STORAGE_KEY = \"ph:perf\";\n\n/** The measures each navigation writes, as the bench reads them. */\nexport const ROUTER_MEASURES = {\n /** `navigation.open` to the router starting the navigation. */\n click: \"nav click\",\n /** Route loaders, until the router commits the matches. */\n loader: \"nav loader\",\n /** The commit until React has rendered it. */\n commit: \"nav commit\",\n /** The click (or the navigation's start) to the next frame after render. */\n total: \"nav total\",\n} as const;\n\n// Chrome's Performance panel shows these as \"Connect › Router\".\nconst DETAIL = {\n devtools: { dataType: \"track-entry\", track: \"Router\", trackGroup: \"Connect\" },\n} as const;\n\nlet marking = 0;\nlet clickedAt: number | undefined;\n\n/** On in dev builds; elsewhere only with the runtime flag. */\nexport function routerPerfEnabled(dev = !!import.meta.env?.DEV) {\n if (dev) return true;\n try {\n return (\n new URLSearchParams(location.search).get(\"perf\") === \"1\" ||\n localStorage.getItem(PERF_STORAGE_KEY) === \"1\"\n );\n } catch {\n return false;\n }\n}\n\n/** Marks a navigation's click; a no-op unless a router is being marked. */\nexport function markNavigationClick() {\n if (!marking) return;\n clickedAt = performance.now();\n performance.mark(\"nav:click\", { detail: DETAIL });\n}\n\nfunction measure(name: string, start: number | undefined, end: number) {\n if (start === undefined) return;\n performance.measure(name, { start, end, detail: DETAIL });\n}\n\n/** Writes each navigation's phases as performance measures; returns the unsubscribe. */\nexport function markRouterNavigations(\n router: Pick<AnyRouter, \"subscribe\">,\n enabled = routerPerfEnabled(),\n) {\n if (!enabled) return () => {};\n marking++;\n let generation = 0;\n let clicked: number | undefined;\n let navigated: number | undefined;\n let loading: number | undefined;\n let loaded: number | undefined;\n const unsubscribes = [\n router.subscribe(\"onBeforeNavigate\", () => {\n generation++;\n navigated = performance.now();\n clicked = clickedAt;\n clickedAt = undefined;\n measure(ROUTER_MEASURES.click, clicked, navigated);\n loading = loaded = undefined;\n }),\n router.subscribe(\"onBeforeLoad\", () => {\n loading = performance.now();\n }),\n router.subscribe(\"onLoad\", () => {\n loaded = performance.now();\n measure(ROUTER_MEASURES.loader, loading, loaded);\n }),\n router.subscribe(\"onRendered\", () => {\n measure(ROUTER_MEASURES.commit, loaded, performance.now());\n const current = generation;\n const start = clicked ?? navigated;\n // The frame after render, as close to paint as a script sees.\n requestAnimationFrame(() =>\n setTimeout(() => {\n if (current === generation) {\n measure(ROUTER_MEASURES.total, start, performance.now());\n }\n }),\n );\n }),\n ];\n return () => {\n marking--;\n for (const unsubscribe of unsubscribes) unsubscribe();\n };\n}\n","import type {\n AnyRouter,\n ParsedLocation,\n RouterHistory,\n} from \"@tanstack/react-router\";\n\ntype ScrollRouter = Pick<AnyRouter, \"subscribe\" | \"_scroll\" | \"options\"> & {\n history: RouterHistory;\n};\n\nconst TRAVERSALS = new Set([\"BACK\", \"FORWARD\", \"GO\"]);\nconst traversals = new WeakMap<object, { traversal: boolean }>();\n\n/** The router's `scrollRestoration`: on for back/forward only; other\n * navigations reset the content view in `bindConnectScroll`. */\nexport function connectScrollRestoration() {\n // The first load restores a reloaded page's scroll.\n const state = { traversal: true };\n const restore = ({ location }: { location: ParsedLocation }) =>\n state.traversal || !!location.hash;\n traversals.set(restore, state);\n return restore;\n}\n\n/** Tracks history actions, and resets a scrolled content view on new views. */\nexport function bindConnectScroll(router: ScrollRouter, contentViewId: string) {\n const state = traversals.get(router.options.scrollRestoration as object);\n if (!state) return () => {};\n const unsubscribeHistory = router.history.subscribe(({ action }) => {\n state.traversal = TRAVERSALS.has(action.type);\n });\n if (typeof document === \"undefined\") return unsubscribeHistory;\n\n // Read in the scroll event, where layout is clean, not at navigation.\n let scrolledView: Element | undefined;\n let windowScrolled = false;\n const onScroll = (event: Event) => {\n const target = event.target;\n if (target === document) {\n windowScrolled = window.scrollY > 0 || window.scrollX > 0;\n } else if (target instanceof Element && target.id === contentViewId) {\n scrolledView = target.scrollTop > 0 ? target : undefined;\n }\n };\n document.addEventListener(\"scroll\", onScroll, {\n capture: true,\n passive: true,\n });\n\n let resetScroll = true;\n const unsubscribes = [\n unsubscribeHistory,\n // The navigation's `resetScroll`, before the router clears it on render.\n router.subscribe(\"onBeforeRouteMount\", () => {\n resetScroll = router._scroll.n;\n }),\n router.subscribe(\"onRendered\", ({ toLocation }) => {\n if (state.traversal || toLocation.hash || !resetScroll) return;\n if (scrolledView?.isConnected) scrolledView.scrollTo(0, 0);\n if (windowScrolled) window.scrollTo(0, 0);\n scrolledView = undefined;\n windowScrolled = false;\n }),\n ];\n return () => {\n document.removeEventListener(\"scroll\", onScroll, { capture: true });\n for (const unsubscribe of unsubscribes) unsubscribe();\n };\n}\n","import {\n FEATURE_FLAG_PARAM_PREFIX,\n GLOBAL_SEARCH_PARAMS,\n parseRevisionHistoryPage,\n REVISION_HISTORY_PAGE_PARAM,\n REVISION_HISTORY_PARAM,\n searchParamsToString,\n} from \"@powerhousedao/reactor-browser\";\nimport type { SearchMiddleware } from \"@tanstack/react-router\";\nimport { retainSearchParams } from \"@tanstack/react-router\";\n\n// Shared with reactor-browser's fallback navigation.\nexport { FEATURE_FLAG_PARAM_PREFIX, GLOBAL_SEARCH_PARAMS };\n\n/** Connect's query params: plain strings, as in the URL. */\nexport type ConnectSearch = Record<string, string | undefined>;\n\nconst retainFeatureFlags: SearchMiddleware<ConnectSearch> = ({\n search,\n next,\n}) => {\n const result = { ...next(search) };\n for (const [key, value] of Object.entries(search)) {\n if (key.startsWith(FEATURE_FLAG_PARAM_PREFIX) && !(key in result)) {\n result[key] = value;\n }\n }\n return result;\n};\n\n/** The root route's middlewares; they apply to every navigation and redirect. */\nexport const connectSearchMiddlewares: SearchMiddleware<ConnectSearch>[] = [\n retainSearchParams<ConnectSearch>([...GLOBAL_SEARCH_PARAMS]),\n retainFeatureFlags,\n];\n\n/** Lets every param through; routes add none of their own. */\nexport function validateConnectSearch(\n search: Record<string, unknown>,\n): ConnectSearch {\n return search as ConnectSearch;\n}\n\n/** Parses a query string into plain string values, unlike the JSON default. */\nexport function parseConnectSearch(searchStr: string): ConnectSearch {\n return Object.fromEntries(new URLSearchParams(searchStr));\n}\n\n/** Writes plain `key=value` pairs, so other readers of the URL see strings. */\nexport function stringifyConnectSearch(search: Record<string, unknown>) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(search)) {\n if (value === undefined || value === null) continue;\n params.set(key, typeof value === \"string\" ? value : JSON.stringify(value));\n }\n const searchStr = searchParamsToString(params);\n return searchStr ? `?${searchStr}` : \"\";\n}\n\n/** The drive route's params: `?history` opens the document's revision history,\n * and `historyPage` (a positive integer; 1 is dropped) pages it. */\nexport function validateDriveSearch(\n search: Record<string, unknown>,\n): ConnectSearch {\n const result = { ...search } as ConnectSearch;\n if (result[REVISION_HISTORY_PARAM] === undefined) return result;\n result[REVISION_HISTORY_PARAM] = \"\";\n const page = parseRevisionHistoryPage(result[REVISION_HISTORY_PAGE_PARAM]);\n if (page > 1) result[REVISION_HISTORY_PAGE_PARAM] = String(page);\n // Undefined, not deleted: a route's search is merged over its parent's.\n else result[REVISION_HISTORY_PAGE_PARAM] = undefined;\n return result;\n}\n\n/** The defined values of `search`, for callers that take plain records. */\nexport function definedSearch(search: object): Record<string, string> {\n const record: Record<string, string> = {};\n for (const [key, value] of Object.entries(search)) {\n if (typeof value === \"string\") record[key] = value;\n else if (value !== undefined && value !== null) {\n record[key] = JSON.stringify(value);\n }\n }\n return record;\n}\n","import type {\n PHDriveTarget,\n PHNavigation,\n PHNavigationTarget,\n PHSettingsTarget,\n SetSearchParams,\n} from \"@powerhousedao/reactor-browser\";\nimport {\n applySearchUpdate,\n findDriveBySlugOrId,\n isSettingsTarget,\n makeDriveSlug,\n OPENED_FROM_STATE_KEY,\n openedFromIndex,\n resolveSearchUpdate,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n AnyRouter,\n HistoryState,\n MakeRouteMatchUnion,\n} from \"@tanstack/react-router\";\nimport { useRouterState } from \"@tanstack/react-router\";\nimport { useMemo } from \"react\";\nimport type { ConnectRouterBundle } from \"./connect-router.js\";\nimport { markNavigationClick } from \"./perf-marks.js\";\nimport { definedSearch } from \"./search.js\";\nimport { keepOpenedFrom, settingsTabs } from \"./settings.js\";\n\n// Hover intent: a pointer passing over cards doesn't preload each of them.\nconst PRELOAD_DELAY_MS = 50;\n\n/** The PH navigation backed by `router`; its hooks take the router directly,\n * so they work outside the RouterProvider. */\nexport function createConnectNavigation(\n connectRouter: ConnectRouterBundle,\n): PHNavigation & { dispose(): void } {\n const { router, homeRoute, nodeRoute, settingsRoute } = connectRouter;\n // Settings tabs can come from a project's routes, unknown to Connect's types.\n const anyRouter = router as unknown as AnyRouter;\n\n // A listed drive is addressed by its canonical slug, whatever form came in.\n const driveParams = (target: PHDriveTarget) => {\n const drive = findDriveBySlugOrId(\n router.options.context.store,\n target.driveSlug,\n );\n return {\n driveSlug: drive ? makeDriveSlug(drive) : target.driveSlug,\n nodeSlug: target.nodeSlug || undefined,\n };\n };\n\n // `true` is the first tab, so the URL names a tab without a redirect.\n const settingsPath = ({ settings }: PHSettingsTarget) => {\n const tab =\n settings === true ? settingsTabs(anyRouter).at(0)?.id : settings;\n return tab ? `${settingsRoute.fullPath}/${tab}` : settingsRoute.fullPath;\n };\n\n // In-document writes keep the entry's state, so its opened-from index too.\n const setSearch: PHNavigation[\"setSearch\"] = (update, options) => {\n void router.navigate({\n to: \".\",\n search: (prev) => applySearchUpdate({}, update(definedSearch(prev))),\n state: true,\n replace: options?.replace,\n resetScroll: false,\n });\n };\n\n const showsSettings = () =>\n router.state.matches.some((match) => match.routeId === settingsRoute.id);\n\n // A push remembers the entry it leaves; a replace keeps what that one had,\n // as does a move between settings tabs.\n const openedFromState = (\n replace: boolean | undefined,\n target: PHNavigationTarget | undefined,\n ) => {\n const { state } = router.history.location;\n const next =\n replace || (isSettingsTarget(target) && showsSettings())\n ? keepOpenedFrom(state)\n : ({\n [OPENED_FROM_STATE_KEY]: state.__TSR_index,\n } as unknown as HistoryState);\n return () => next;\n };\n\n const targetKey = (target: PHNavigationTarget | undefined) => {\n if (!target) return homeRoute.id;\n if (isSettingsTarget(target)) return settingsPath(target);\n const { driveSlug, nodeSlug } = driveParams(target);\n return JSON.stringify([driveSlug, nodeSlug ?? \"\"]);\n };\n let keyedMatches: readonly MakeRouteMatchUnion[] | undefined;\n let matchesKey: string | undefined;\n const currentKey = (matches: readonly MakeRouteMatchUnion[]) => {\n if (matches === keyedMatches) return matchesKey;\n keyedMatches = matches;\n const drive = matches.find((match) => match.routeId === nodeRoute.id);\n const settings = matches.some(\n (match) => match.routeId === settingsRoute.id,\n );\n if (drive) {\n matchesKey = targetKey(drive.params as PHDriveTarget);\n } else if (settings) {\n // A tab's key is its path, as settingsPath builds it.\n matchesKey = matches.at(-1)?.fullPath.replace(/\\/$/, \"\");\n } else {\n matchesKey = matches.find(\n (match) => match.routeId === homeRoute.id,\n )?.routeId;\n }\n return matchesKey;\n };\n\n // Hrefs depend only on the target and the global params of the current search.\n const hrefs = new Map<string, string>();\n let hrefsSearch: string | undefined;\n\n const setSearchParams: SetSearchParams = (update, options) =>\n setSearch((prev) => resolveSearchUpdate(prev, update), options);\n\n let preloadTimer: ReturnType<typeof setTimeout> | undefined;\n return {\n location: () => router.history.location,\n // The root route's middlewares add the global params to `search`.\n open: (target, options) => {\n markNavigationClick();\n const search = applySearchUpdate({}, options?.search ?? {});\n const replace = options?.replace;\n const state = openedFromState(replace, target);\n if (!target) {\n void router.navigate({\n to: homeRoute.fullPath,\n search,\n replace,\n state,\n });\n return;\n }\n if (isSettingsTarget(target)) {\n void anyRouter.navigate({\n to: settingsPath(target),\n search,\n replace,\n state,\n });\n return;\n }\n void router.navigate({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n search,\n replace,\n state,\n });\n },\n // The public href, base path included; global params as `open` keeps them.\n hrefFor: (target) => {\n const { searchStr } = router.latestLocation;\n if (searchStr !== hrefsSearch) {\n hrefs.clear();\n hrefsSearch = searchStr;\n }\n const key = targetKey(target);\n let href = hrefs.get(key);\n if (href === undefined) {\n const location = !target\n ? router.buildLocation({ to: homeRoute.fullPath, search: {} })\n : isSettingsTarget(target)\n ? anyRouter.buildLocation({ to: settingsPath(target), search: {} })\n : router.buildLocation({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n search: {},\n });\n href = location.publicHref;\n hrefs.set(key, href);\n }\n return href;\n },\n // One key per shown matches, so each link's selector is a string compare.\n useIsCurrent: (target) => {\n // The settings page itself is current on any of its tabs.\n const anyTab = isSettingsTarget(target) && target.settings === true;\n const key = anyTab ? `${settingsRoute.fullPath}/` : targetKey(target);\n return useRouterState({\n router,\n select: (state) => {\n const current = currentKey(state.matches);\n return anyTab ? !!current?.startsWith(key) : current === key;\n },\n });\n },\n preload: (target) => {\n clearTimeout(preloadTimer);\n if (!target) return;\n preloadTimer = setTimeout(() => {\n const preloading = isSettingsTarget(target)\n ? anyRouter.preloadRoute({ to: settingsPath(target) })\n : router.preloadRoute({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n });\n preloading.catch(() => undefined);\n }, PRELOAD_DELAY_MS);\n },\n setSearch,\n // The presented matches' params, else the location's.\n useSearchParams() {\n const search = useRouterState({\n router,\n select: (state) =>\n state.matches.at(-1)?.search ?? state.location.search,\n });\n return useMemo(() => definedSearch(search), [search]);\n },\n useSetSearchParams: () => setSearchParams,\n closeOpened: () => {\n const { state } = router.history.location;\n const from = openedFromIndex(state, state.__TSR_index);\n if (from === undefined) return false;\n router.history.go(from - state.__TSR_index);\n return true;\n },\n dispose: () => clearTimeout(preloadTimer),\n };\n}\n","import type { DriveArrivals, PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n getPHStoreSubscribe,\n isRoutedModal,\n modalFromSearch,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n AnyRoute,\n ErrorRouteComponent,\n NotFoundRouteComponent,\n RouteComponent,\n Router,\n RouterHistory,\n} from \"@tanstack/react-router\";\nimport { createRouter } from \"@tanstack/react-router\";\nimport type { ErrorInfo, PropsWithChildren, ReactElement } from \"react\";\nimport type { ConnectPluginUiSet } from \"../plugins/plugin-ui.js\";\nimport { applyConnectPluginUi } from \"../plugins/plugin-ui.js\";\nimport { markRouterNavigations } from \"./perf-marks.js\";\nimport { bindConnectScroll, connectScrollRestoration } from \"./scroll.js\";\nimport type { DriveRouteData } from \"./drive-route-loader.js\";\nimport type { ConnectRootRoute, ConnectRoutes } from \"./route-tree.js\";\nimport { createConnectNavigation } from \"./navigation.js\";\nimport { CoreError, CoreNotFound } from \"./core-views.js\";\nimport { CONTENT_VIEW_ID } from \"./route-components.js\";\nimport { addConnectRoutes, connectRoutes } from \"./route-tree.js\";\nimport { setSettingsRoute } from \"./settings.js\";\nimport { parseConnectSearch, stringifyConnectSearch } from \"./search.js\";\nimport { driveTitle } from \"./titles.js\";\n\nexport type ConnectRouterOptions = {\n store: PHStore;\n arrivals?: DriveArrivals;\n basepath?: string;\n history?: RouterHistory;\n InnerWrap?: (props: PropsWithChildren) => ReactElement;\n /** Shown while a route's loader or chunks are pending, after the router's `pendingMs`. */\n pendingComponent?: RouteComponent;\n /** Any route's loader or render error; the plugins', else core's error view. */\n errorComponent?: ErrorRouteComponent;\n /** The active plugins' UI, set on the routes that show core's views. */\n pluginUi?: ConnectPluginUiSet;\n /** Loaders' notFound(), e.g. a missing drive's; core's page by default. */\n notFoundComponent?: NotFoundRouteComponent;\n /** The tree to route with: `@powerhousedao/connect/route-tree`, core's or a project's. */\n routeTree: AnyRoute;\n /** Code routes added to the file routes; see `addConnectRoutes`. A function\n * receives the tree's core routes to attach to. */\n routes?:\n | readonly AnyRoute[]\n | ((routes: ConnectRoutes) => readonly AnyRoute[]);\n /** Reports a route's loader or render error; logged by default. */\n onCatch?: (error: unknown, info?: ErrorInfo) => void;\n /** Ends every document title; \"Connect\" without one. */\n appName?: string;\n /** Renders the loading shell: layouts show their pendingComponent, not their page. */\n shell?: boolean;\n};\n\nfunction reportRouteError(error: unknown, info?: ErrorInfo) {\n console.error(error, info?.componentStack ?? \"\");\n}\n\n/** The router over `TRouteTree`; a project's generated tree registers its own. */\nexport type ConnectRouterFor<TRouteTree extends AnyRoute> = Router<\n TRouteTree,\n \"never\",\n false,\n RouterHistory,\n Record<string, any>\n>;\n// Written out, not inferred; see ConnectRootRoute.\nexport type ConnectRouter = ConnectRouterFor<ConnectRootRoute>;\nexport type ConnectRouterBundle = Pick<\n ConnectRoutes,\n \"homeRoute\" | \"driveRoute\" | \"nodeRoute\" | \"settingsRoute\"\n> & { router: ConnectRouter };\n\nexport function createConnectRouter(\n options: ConnectRouterOptions,\n): ConnectRouterBundle {\n const { routeTree, homeRoute, driveRoute, nodeRoute, settingsRoute } =\n connectRoutes(options.routeTree);\n if (options.pluginUi) applyConnectPluginUi(routeTree, options.pluginUi);\n if (options.routes) {\n addConnectRoutes(\n typeof options.routes === \"function\"\n ? options.routes(connectRoutes(routeTree))\n : options.routes,\n );\n }\n setSettingsRoute(settingsRoute);\n const router = createRouter({\n routeTree,\n basepath: options.basepath,\n history: options.history,\n context: {\n store: options.store,\n arrivals: options.arrivals,\n appName: options.appName,\n shell: options.shell,\n },\n parseSearch: parseConnectSearch,\n stringifySearch: stringifyConnectSearch,\n scrollRestoration: connectScrollRestoration(),\n scrollToTopSelectors: [`#${CONTENT_VIEW_ID}`],\n InnerWrap: options.InnerWrap,\n defaultPendingComponent: options.pendingComponent,\n defaultErrorComponent:\n options.errorComponent ?? options.pluginUi?.errorComponent ?? CoreError,\n // Not per route: a route's notFoundComponent mounts a boundary that\n // re-renders on every navigation.\n defaultNotFoundComponent: options.notFoundComponent ?? CoreNotFound,\n defaultOnCatch: options.onCatch ?? reportRouteError,\n });\n return { router, homeRoute, driveRoute, nodeRoute, settingsRoute };\n}\n\nfunction writeSelection(store: PHStore, data: DriveRouteData | undefined) {\n // Drive first: a new drive resets the node.\n store.selectedDriveId = data?.driveId;\n store.selectedNodeId = data?.nodeId;\n}\n\n/** Makes `router` the store's navigation and writes the selection it commits. */\nexport function bindConnectRouter(\n connectRouter: ConnectRouterBundle,\n store: PHStore,\n) {\n const { router, nodeRoute } = connectRouter;\n\n // Only committed matches select; pending ones keep the open view.\n const commitSelection = () => {\n const matches = router.state.matches;\n const drive = matches.find((match) => match.routeId === nodeRoute.id);\n if (drive) {\n if (drive.status === \"success\" && drive.loaderData) {\n writeSelection(store, drive.loaderData);\n } else if (matches.some((match) => match.status === \"notFound\")) {\n // The drive's 404 page shows no drive.\n writeSelection(store, undefined);\n }\n return;\n }\n // Any other page (home, settings, a project's, a 404) shows no drive.\n const shown = matches.at(-1)?.status;\n if (shown === \"success\" || shown === \"notFound\") {\n writeSelection(store, undefined);\n }\n };\n\n // A routed modal is the URL's: the store holds what the location names,\n // unless a confirmation is open over it.\n const syncModal = () => {\n const routed = modalFromSearch(router.state.location.search);\n if (store.modal && !isRoutedModal(store.modal)) return;\n if (routed) {\n if (JSON.stringify(store.modal) !== JSON.stringify(routed)) {\n store.modal = routed;\n }\n } else if (isRoutedModal(store.modal)) {\n store.modal = undefined;\n }\n };\n\n // Set once, before the first render; selection setters navigate from the start.\n const navigation = createConnectNavigation(connectRouter);\n store.navigation = navigation;\n\n // The node route's head reads names from the store; a rename re-runs it.\n const shownTitle = () => {\n const node = router.state.matches.find((m) => m.routeId === nodeRoute.id);\n return driveTitle(store, node?.loaderData, router.options.context.appName);\n };\n let title = shownTitle();\n const retitle = () => {\n const next = shownTitle();\n if (next === title) return;\n title = next;\n void router.invalidate({ filter: (m) => m.routeId === nodeRoute.id });\n };\n\n // Before mount, so the view and scroll restoration see the new selection.\n const unsubscribes = [\n router.subscribe(\"onBeforeRouteMount\", commitSelection),\n router.subscribe(\"onResolved\", commitSelection),\n router.subscribe(\"onResolved\", () => {\n title = shownTitle();\n }),\n router.subscribe(\"onResolved\", syncModal),\n getPHStoreSubscribe(store, \"drives\")(retitle),\n markRouterNavigations(router),\n ];\n const unbindScroll = bindConnectScroll(router, CONTENT_VIEW_ID);\n commitSelection();\n syncModal();\n\n return () => {\n navigation.dispose();\n unbindScroll();\n for (const unsubscribe of unsubscribes) unsubscribe();\n if (store.navigation === navigation) store.navigation = undefined;\n };\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport { createDriveArrivals } from \"@powerhousedao/reactor-browser\";\nimport { getConnectPluginUi } from \"../plugins/plugin-ui.js\";\nimport { getConnectRegistry } from \"../registry.js\";\nimport type {\n ConnectRouterBundle,\n ConnectRouterOptions,\n} from \"./connect-router.js\";\nimport { bindConnectRouter, createConnectRouter } from \"./connect-router.js\";\nimport { resolveConnectRoutes } from \"./route-tree.js\";\n\nexport type ConnectAppRouterOptions = Omit<\n ConnectRouterOptions,\n \"store\" | \"arrivals\"\n>;\n\n/** The app's one router over `store`; created, and made the store's navigation,\n * on first use. Registered routes join `options.routes`. */\nexport function getConnectAppRouter(\n store: PHStore,\n options: () => ConnectAppRouterOptions,\n): ConnectRouterBundle {\n const registry = getConnectRegistry();\n const current = registry.app;\n if (current) {\n if (import.meta.env?.DEV && current.store !== store) {\n throw new Error(\"Connect's router is already bound to another PH store\");\n }\n return current.bundle;\n }\n const { routes, ...rest } = options();\n const bundle = createConnectRouter({\n store,\n arrivals: createDriveArrivals(store),\n pluginUi: getConnectPluginUi(),\n ...rest,\n routes: (tree) => [\n ...(routes ? resolveConnectRoutes(routes, tree.routeTree) : []),\n ...registry.routes.flatMap((entry) => {\n entry.added = [\n ...resolveConnectRoutes(entry.registration, tree.routeTree),\n ];\n return entry.added;\n }),\n ],\n });\n registry.app = { store, bundle, unbind: bindConnectRouter(bundle, store) };\n return bundle;\n}\n\n/** Stops the app's router writing the selection, e.g. on HMR. */\nexport function disposeConnectAppRouter() {\n const registry = getConnectRegistry();\n registry.app?.unbind();\n registry.app = undefined;\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport { PHStoreProvider } from \"@powerhousedao/reactor-browser\";\nimport type { AnyRoute } from \"@tanstack/react-router\";\nimport { RouterProvider } from \"@tanstack/react-router\";\nimport type { ConnectAppRouterOptions } from \"./app-router.js\";\nimport { getConnectAppRouter } from \"./app-router.js\";\n\n/** A core-only app: `routeTree`'s views over `store`. */\nexport function ConnectCoreApp(props: {\n store: PHStore;\n routeTree: AnyRoute;\n basepath?: string;\n options?: () => Omit<ConnectAppRouterOptions, \"routeTree\">;\n}) {\n const { router } = getConnectAppRouter(props.store, () => ({\n basepath: props.basepath,\n ...props.options?.(),\n routeTree: props.routeTree,\n }));\n return (\n <PHStoreProvider store={props.store}>\n <RouterProvider router={router} />\n </PHStoreProvider>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"router-DHL9GT3P.js","names":[],"sources":["../src/router/perf-marks.ts","../src/router/scroll.ts","../src/router/search.ts","../src/router/navigation.ts","../src/router/connect-router.ts","../src/router/app-router.ts","../src/router/core-app.tsx"],"sourcesContent":["import type { AnyRouter } from \"@tanstack/react-router\";\n\n/** `localStorage[PERF_STORAGE_KEY] = \"1\"` or `?perf=1` turns the marks on in production. */\nexport const PERF_STORAGE_KEY = \"ph:perf\";\n\n/** The measures each navigation writes, as the bench reads them. */\nexport const ROUTER_MEASURES = {\n /** `navigation.open` to the router starting the navigation. */\n click: \"nav click\",\n /** Route loaders, until the router commits the matches. */\n loader: \"nav loader\",\n /** The commit until React has rendered it. */\n commit: \"nav commit\",\n /** The click (or the navigation's start) to the next frame after render. */\n total: \"nav total\",\n} as const;\n\n// Chrome's Performance panel shows these as \"Connect › Router\".\nconst DETAIL = {\n devtools: { dataType: \"track-entry\", track: \"Router\", trackGroup: \"Connect\" },\n} as const;\n\nlet marking = 0;\nlet clickedAt: number | undefined;\n\n/** On in dev builds; elsewhere only with the runtime flag. */\nexport function routerPerfEnabled(dev = !!import.meta.env?.DEV) {\n if (dev) return true;\n try {\n return (\n new URLSearchParams(location.search).get(\"perf\") === \"1\" ||\n localStorage.getItem(PERF_STORAGE_KEY) === \"1\"\n );\n } catch {\n return false;\n }\n}\n\n/** Marks a navigation's click; a no-op unless a router is being marked. */\nexport function markNavigationClick() {\n if (!marking) return;\n clickedAt = performance.now();\n performance.mark(\"nav:click\", { detail: DETAIL });\n}\n\nfunction measure(name: string, start: number | undefined, end: number) {\n if (start === undefined) return;\n performance.measure(name, { start, end, detail: DETAIL });\n}\n\n/** Writes each navigation's phases as performance measures; returns the unsubscribe. */\nexport function markRouterNavigations(\n router: Pick<AnyRouter, \"subscribe\">,\n enabled = routerPerfEnabled(),\n) {\n if (!enabled) return () => {};\n marking++;\n let generation = 0;\n let clicked: number | undefined;\n let navigated: number | undefined;\n let loading: number | undefined;\n let loaded: number | undefined;\n const unsubscribes = [\n router.subscribe(\"onBeforeNavigate\", () => {\n generation++;\n navigated = performance.now();\n clicked = clickedAt;\n clickedAt = undefined;\n measure(ROUTER_MEASURES.click, clicked, navigated);\n loading = loaded = undefined;\n }),\n router.subscribe(\"onBeforeLoad\", () => {\n loading = performance.now();\n }),\n router.subscribe(\"onLoad\", () => {\n loaded = performance.now();\n measure(ROUTER_MEASURES.loader, loading, loaded);\n }),\n router.subscribe(\"onRendered\", () => {\n measure(ROUTER_MEASURES.commit, loaded, performance.now());\n const current = generation;\n const start = clicked ?? navigated;\n // The frame after render, as close to paint as a script sees.\n requestAnimationFrame(() =>\n setTimeout(() => {\n if (current === generation) {\n measure(ROUTER_MEASURES.total, start, performance.now());\n }\n }),\n );\n }),\n ];\n return () => {\n marking--;\n for (const unsubscribe of unsubscribes) unsubscribe();\n };\n}\n","import type {\n AnyRouter,\n ParsedLocation,\n RouterHistory,\n} from \"@tanstack/react-router\";\n\ntype ScrollRouter = Pick<AnyRouter, \"subscribe\" | \"_scroll\" | \"options\"> & {\n history: RouterHistory;\n};\n\nconst TRAVERSALS = new Set([\"BACK\", \"FORWARD\", \"GO\"]);\nconst traversals = new WeakMap<object, { traversal: boolean }>();\n\n/** The router's `scrollRestoration`: on for back/forward only; other\n * navigations reset the content view in `bindConnectScroll`. */\nexport function connectScrollRestoration() {\n // The first load restores a reloaded page's scroll.\n const state = { traversal: true };\n const restore = ({ location }: { location: ParsedLocation }) =>\n state.traversal || !!location.hash;\n traversals.set(restore, state);\n return restore;\n}\n\n/** Tracks history actions, and resets a scrolled content view on new views. */\nexport function bindConnectScroll(router: ScrollRouter, contentViewId: string) {\n const state = traversals.get(router.options.scrollRestoration as object);\n if (!state) return () => {};\n const unsubscribeHistory = router.history.subscribe(({ action }) => {\n state.traversal = TRAVERSALS.has(action.type);\n });\n if (typeof document === \"undefined\") return unsubscribeHistory;\n\n // Read in the scroll event, where layout is clean, not at navigation.\n let scrolledView: Element | undefined;\n let windowScrolled = false;\n const onScroll = (event: Event) => {\n const target = event.target;\n if (target === document) {\n windowScrolled = window.scrollY > 0 || window.scrollX > 0;\n } else if (target instanceof Element && target.id === contentViewId) {\n scrolledView = target.scrollTop > 0 ? target : undefined;\n }\n };\n document.addEventListener(\"scroll\", onScroll, {\n capture: true,\n passive: true,\n });\n\n let resetScroll = true;\n const unsubscribes = [\n unsubscribeHistory,\n // The navigation's `resetScroll`, before the router clears it on render.\n router.subscribe(\"onBeforeRouteMount\", () => {\n resetScroll = router._scroll.n;\n }),\n router.subscribe(\"onRendered\", ({ toLocation }) => {\n if (state.traversal || toLocation.hash || !resetScroll) return;\n if (scrolledView?.isConnected) scrolledView.scrollTo(0, 0);\n if (windowScrolled) window.scrollTo(0, 0);\n scrolledView = undefined;\n windowScrolled = false;\n }),\n ];\n return () => {\n document.removeEventListener(\"scroll\", onScroll, { capture: true });\n for (const unsubscribe of unsubscribes) unsubscribe();\n };\n}\n","import {\n FEATURE_FLAG_PARAM_PREFIX,\n GLOBAL_SEARCH_PARAMS,\n parseRevisionHistoryPage,\n REVISION_HISTORY_PAGE_PARAM,\n REVISION_HISTORY_PARAM,\n searchParamsToString,\n} from \"@powerhousedao/reactor-browser\";\nimport type { SearchMiddleware } from \"@tanstack/react-router\";\nimport { retainSearchParams } from \"@tanstack/react-router\";\n\n// Shared with reactor-browser's fallback navigation.\nexport { FEATURE_FLAG_PARAM_PREFIX, GLOBAL_SEARCH_PARAMS };\n\n/** Connect's query params: plain strings, as in the URL. */\nexport type ConnectSearch = Record<string, string | undefined>;\n\nconst retainFeatureFlags: SearchMiddleware<ConnectSearch> = ({\n search,\n next,\n}) => {\n const result = { ...next(search) };\n for (const [key, value] of Object.entries(search)) {\n if (key.startsWith(FEATURE_FLAG_PARAM_PREFIX) && !(key in result)) {\n result[key] = value;\n }\n }\n return result;\n};\n\n/** The root route's middlewares; they apply to every navigation and redirect. */\nexport const connectSearchMiddlewares: SearchMiddleware<ConnectSearch>[] = [\n retainSearchParams<ConnectSearch>([...GLOBAL_SEARCH_PARAMS]),\n retainFeatureFlags,\n];\n\n/** Lets every param through; routes add none of their own. */\nexport function validateConnectSearch(\n search: Record<string, unknown>,\n): ConnectSearch {\n return search as ConnectSearch;\n}\n\n/** Parses a query string into plain string values, unlike the JSON default. */\nexport function parseConnectSearch(searchStr: string): ConnectSearch {\n return Object.fromEntries(new URLSearchParams(searchStr));\n}\n\n/** Writes plain `key=value` pairs, so other readers of the URL see strings. */\nexport function stringifyConnectSearch(search: Record<string, unknown>) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(search)) {\n if (value === undefined || value === null) continue;\n params.set(key, typeof value === \"string\" ? value : JSON.stringify(value));\n }\n const searchStr = searchParamsToString(params);\n return searchStr ? `?${searchStr}` : \"\";\n}\n\n/** The drive route's params: `?history` opens the document's revision history,\n * and `historyPage` (a positive integer; 1 is dropped) pages it. */\nexport function validateDriveSearch(\n search: Record<string, unknown>,\n): ConnectSearch {\n const result = { ...search } as ConnectSearch;\n if (result[REVISION_HISTORY_PARAM] === undefined) return result;\n result[REVISION_HISTORY_PARAM] = \"\";\n const page = parseRevisionHistoryPage(result[REVISION_HISTORY_PAGE_PARAM]);\n if (page > 1) result[REVISION_HISTORY_PAGE_PARAM] = String(page);\n // Undefined, not deleted: a route's search is merged over its parent's.\n else result[REVISION_HISTORY_PAGE_PARAM] = undefined;\n return result;\n}\n\n/** The defined values of `search`, for callers that take plain records. */\nexport function definedSearch(search: object): Record<string, string> {\n const record: Record<string, string> = {};\n for (const [key, value] of Object.entries(search)) {\n if (typeof value === \"string\") record[key] = value;\n else if (value !== undefined && value !== null) {\n record[key] = JSON.stringify(value);\n }\n }\n return record;\n}\n","import type {\n PHDriveTarget,\n PHNavigation,\n PHNavigationTarget,\n PHSettingsTarget,\n SetSearchParams,\n} from \"@powerhousedao/reactor-browser\";\nimport {\n applySearchUpdate,\n findDriveBySlugOrId,\n isSettingsTarget,\n makeDriveSlug,\n OPENED_FROM_STATE_KEY,\n openedFromIndex,\n resolveSearchUpdate,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n AnyRouter,\n HistoryState,\n MakeRouteMatchUnion,\n} from \"@tanstack/react-router\";\nimport { useRouterState } from \"@tanstack/react-router\";\nimport { useMemo } from \"react\";\nimport type { ConnectRouterBundle } from \"./connect-router.js\";\nimport { markNavigationClick } from \"./perf-marks.js\";\nimport { definedSearch } from \"./search.js\";\nimport { keepOpenedFrom, settingsTabs } from \"./settings.js\";\n\n// Hover intent: a pointer passing over cards doesn't preload each of them.\nconst PRELOAD_DELAY_MS = 50;\n\n/** The PH navigation backed by `router`; its hooks take the router directly,\n * so they work outside the RouterProvider. */\nexport function createConnectNavigation(\n connectRouter: ConnectRouterBundle,\n): PHNavigation & { dispose(): void } {\n const { router, homeRoute, nodeRoute, settingsRoute } = connectRouter;\n // Settings tabs can come from a project's routes, unknown to Connect's types.\n const anyRouter = router as unknown as AnyRouter;\n\n // A listed drive is addressed by its canonical slug, whatever form came in.\n const driveParams = (target: PHDriveTarget) => {\n const drive = findDriveBySlugOrId(\n router.options.context.store,\n target.driveSlug,\n );\n return {\n driveSlug: drive ? makeDriveSlug(drive) : target.driveSlug,\n nodeSlug: target.nodeSlug || undefined,\n };\n };\n\n // `true` is the first tab, so the URL names a tab without a redirect.\n const settingsPath = ({ settings }: PHSettingsTarget) => {\n const tab =\n settings === true ? settingsTabs(anyRouter).at(0)?.id : settings;\n return tab ? `${settingsRoute.fullPath}/${tab}` : settingsRoute.fullPath;\n };\n\n // In-document writes keep the entry's state, so its opened-from index too.\n const setSearch: PHNavigation[\"setSearch\"] = (update, options) => {\n void router.navigate({\n to: \".\",\n search: (prev) => applySearchUpdate({}, update(definedSearch(prev))),\n state: true,\n replace: options?.replace,\n resetScroll: false,\n });\n };\n\n const showsSettings = () =>\n router.state.matches.some((match) => match.routeId === settingsRoute.id);\n\n // A push remembers the entry it leaves; a replace keeps what that one had,\n // as does a move between settings tabs.\n const openedFromState = (\n replace: boolean | undefined,\n target: PHNavigationTarget | undefined,\n ) => {\n const { state } = router.history.location;\n const next =\n replace || (isSettingsTarget(target) && showsSettings())\n ? keepOpenedFrom(state)\n : ({\n [OPENED_FROM_STATE_KEY]: state.__TSR_index,\n } as unknown as HistoryState);\n return () => next;\n };\n\n const targetKey = (target: PHNavigationTarget | undefined) => {\n if (!target) return homeRoute.id;\n if (isSettingsTarget(target)) return settingsPath(target);\n const { driveSlug, nodeSlug } = driveParams(target);\n return JSON.stringify([driveSlug, nodeSlug ?? \"\"]);\n };\n let keyedMatches: readonly MakeRouteMatchUnion[] | undefined;\n let matchesKey: string | undefined;\n const currentKey = (matches: readonly MakeRouteMatchUnion[]) => {\n if (matches === keyedMatches) return matchesKey;\n keyedMatches = matches;\n const drive = matches.find((match) => match.routeId === nodeRoute.id);\n const settings = matches.some(\n (match) => match.routeId === settingsRoute.id,\n );\n if (drive) {\n matchesKey = targetKey(drive.params as PHDriveTarget);\n } else if (settings) {\n // A tab's key is its path, as settingsPath builds it.\n matchesKey = matches.at(-1)?.fullPath.replace(/\\/$/, \"\");\n } else {\n matchesKey = matches.find(\n (match) => match.routeId === homeRoute.id,\n )?.routeId;\n }\n return matchesKey;\n };\n\n // Hrefs depend only on the target and the global params of the current search.\n const hrefs = new Map<string, string>();\n let hrefsSearch: string | undefined;\n\n const setSearchParams: SetSearchParams = (update, options) =>\n setSearch((prev) => resolveSearchUpdate(prev, update), options);\n\n let preloadTimer: ReturnType<typeof setTimeout> | undefined;\n return {\n location: () => router.history.location,\n // The root route's middlewares add the global params to `search`.\n open: (target, options) => {\n markNavigationClick();\n const search = applySearchUpdate({}, options?.search ?? {});\n const replace = options?.replace;\n const state = openedFromState(replace, target);\n if (!target) {\n void router.navigate({\n to: homeRoute.fullPath,\n search,\n replace,\n state,\n });\n return;\n }\n if (isSettingsTarget(target)) {\n void anyRouter.navigate({\n to: settingsPath(target),\n search,\n replace,\n state,\n });\n return;\n }\n void router.navigate({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n search,\n replace,\n state,\n });\n },\n // The public href, base path included; global params as `open` keeps them.\n hrefFor: (target) => {\n const { searchStr } = router.latestLocation;\n if (searchStr !== hrefsSearch) {\n hrefs.clear();\n hrefsSearch = searchStr;\n }\n const key = targetKey(target);\n let href = hrefs.get(key);\n if (href === undefined) {\n const location = !target\n ? router.buildLocation({ to: homeRoute.fullPath, search: {} })\n : isSettingsTarget(target)\n ? anyRouter.buildLocation({ to: settingsPath(target), search: {} })\n : router.buildLocation({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n search: {},\n });\n href = location.publicHref;\n hrefs.set(key, href);\n }\n return href;\n },\n // One key per shown matches, so each link's selector is a string compare.\n useIsCurrent: (target) => {\n // The settings page itself is current on any of its tabs.\n const anyTab = isSettingsTarget(target) && target.settings === true;\n const key = anyTab ? `${settingsRoute.fullPath}/` : targetKey(target);\n return useRouterState({\n router,\n select: (state) => {\n const current = currentKey(state.matches);\n return anyTab ? !!current?.startsWith(key) : current === key;\n },\n });\n },\n preload: (target) => {\n clearTimeout(preloadTimer);\n if (!target) return;\n preloadTimer = setTimeout(() => {\n const preloading = isSettingsTarget(target)\n ? anyRouter.preloadRoute({ to: settingsPath(target) })\n : router.preloadRoute({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n });\n preloading.catch(() => undefined);\n }, PRELOAD_DELAY_MS);\n },\n setSearch,\n // The presented matches' params, else the location's.\n useSearchParams() {\n const search = useRouterState({\n router,\n select: (state) =>\n state.matches.at(-1)?.search ?? state.location.search,\n });\n return useMemo(() => definedSearch(search), [search]);\n },\n useSetSearchParams: () => setSearchParams,\n closeOpened: () => {\n const { state } = router.history.location;\n const from = openedFromIndex(state, state.__TSR_index);\n if (from === undefined) return false;\n router.history.go(from - state.__TSR_index);\n return true;\n },\n dispose: () => clearTimeout(preloadTimer),\n };\n}\n","import type { DriveArrivals, PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n getPHStoreSubscribe,\n isRoutedModal,\n modalFromSearch,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n AnyRoute,\n ErrorRouteComponent,\n NotFoundRouteComponent,\n RouteComponent,\n Router,\n RouterHistory,\n} from \"@tanstack/react-router\";\nimport { createRouter } from \"@tanstack/react-router\";\nimport type { ErrorInfo, PropsWithChildren, ReactElement } from \"react\";\nimport type { ConnectPluginUiSet } from \"../plugins/plugin-ui.js\";\nimport { applyConnectPluginUi } from \"../plugins/plugin-ui.js\";\nimport { markRouterNavigations } from \"./perf-marks.js\";\nimport { bindConnectScroll, connectScrollRestoration } from \"./scroll.js\";\nimport type { DriveRouteData } from \"./drive-route-loader.js\";\nimport type { ConnectRootRoute, ConnectRoutes } from \"./route-tree.js\";\nimport { createConnectNavigation } from \"./navigation.js\";\nimport { CoreError, CoreNotFound } from \"./core-views.js\";\nimport { CONTENT_VIEW_ID } from \"./route-components.js\";\nimport { addConnectRoutes, connectRoutes } from \"./route-tree.js\";\nimport { setSettingsRoute } from \"./settings.js\";\nimport { parseConnectSearch, stringifyConnectSearch } from \"./search.js\";\nimport { driveTitle } from \"./titles.js\";\n\nexport type ConnectRouterOptions = {\n store: PHStore;\n arrivals?: DriveArrivals;\n basepath?: string;\n history?: RouterHistory;\n InnerWrap?: (props: PropsWithChildren) => ReactElement;\n /** Shown while a route's loader or chunks are pending, after the router's `pendingMs`. */\n pendingComponent?: RouteComponent;\n /** Any route's loader or render error; the plugins', else core's error view. */\n errorComponent?: ErrorRouteComponent;\n /** The active plugins' UI, set on the routes that show core's views. */\n pluginUi?: ConnectPluginUiSet;\n /** Loaders' notFound(), e.g. a missing drive's; core's page by default. */\n notFoundComponent?: NotFoundRouteComponent;\n /** The tree to route with: `@powerhousedao/connect/route-tree`, core's or a project's. */\n routeTree: AnyRoute;\n /** Code routes added to the file routes; see `addConnectRoutes`. A function\n * receives the tree's core routes to attach to. */\n routes?:\n | readonly AnyRoute[]\n | ((routes: ConnectRoutes) => readonly AnyRoute[]);\n /** Reports a route's loader or render error; logged by default. */\n onCatch?: (error: unknown, info?: ErrorInfo) => void;\n /** Ends every document title; \"Connect\" without one. */\n appName?: string;\n /** Renders the loading shell: layouts show their pendingComponent, not their page. */\n shell?: boolean;\n};\n\nfunction reportRouteError(error: unknown, info?: ErrorInfo) {\n console.error(error, info?.componentStack ?? \"\");\n}\n\n/** The router over `TRouteTree`; a project's generated tree registers its own. */\nexport type ConnectRouterFor<TRouteTree extends AnyRoute> = Router<\n TRouteTree,\n \"never\",\n false,\n RouterHistory,\n Record<string, any>\n>;\n// Written out, not inferred; see ConnectRootRoute.\nexport type ConnectRouter = ConnectRouterFor<ConnectRootRoute>;\nexport type ConnectRouterBundle = Pick<\n ConnectRoutes,\n \"homeRoute\" | \"driveRoute\" | \"nodeRoute\" | \"settingsRoute\"\n> & { router: ConnectRouter };\n\nexport function createConnectRouter(\n options: ConnectRouterOptions,\n): ConnectRouterBundle {\n const { routeTree, homeRoute, driveRoute, nodeRoute, settingsRoute } =\n connectRoutes(options.routeTree);\n if (options.pluginUi) applyConnectPluginUi(routeTree, options.pluginUi);\n if (options.routes) {\n addConnectRoutes(\n typeof options.routes === \"function\"\n ? options.routes(connectRoutes(routeTree))\n : options.routes,\n );\n }\n setSettingsRoute(settingsRoute);\n const router = createRouter({\n routeTree,\n basepath: options.basepath,\n history: options.history,\n context: {\n store: options.store,\n arrivals: options.arrivals,\n appName: options.appName,\n shell: options.shell,\n },\n parseSearch: parseConnectSearch,\n stringifySearch: stringifyConnectSearch,\n scrollRestoration: connectScrollRestoration(),\n scrollToTopSelectors: [`#${CONTENT_VIEW_ID}`],\n InnerWrap: options.InnerWrap,\n defaultPendingComponent: options.pendingComponent,\n defaultErrorComponent:\n options.errorComponent ?? options.pluginUi?.errorComponent ?? CoreError,\n // Not per route: a route's notFoundComponent mounts a boundary that\n // re-renders on every navigation.\n defaultNotFoundComponent: options.notFoundComponent ?? CoreNotFound,\n defaultOnCatch: options.onCatch ?? reportRouteError,\n });\n return { router, homeRoute, driveRoute, nodeRoute, settingsRoute };\n}\n\nfunction writeSelection(store: PHStore, data: DriveRouteData | undefined) {\n // Drive first: a new drive resets the node.\n store.selectedDriveId = data?.driveId;\n store.selectedNodeId = data?.nodeId;\n}\n\n/** Makes `router` the store's navigation and writes the selection it commits. */\nexport function bindConnectRouter(\n connectRouter: ConnectRouterBundle,\n store: PHStore,\n) {\n const { router, nodeRoute } = connectRouter;\n\n // Only committed matches select; pending ones keep the open view.\n const commitSelection = () => {\n const matches = router.state.matches;\n const drive = matches.find((match) => match.routeId === nodeRoute.id);\n if (drive) {\n if (drive.status === \"success\" && drive.loaderData) {\n writeSelection(store, drive.loaderData);\n } else if (matches.some((match) => match.status === \"notFound\")) {\n // The drive's 404 page shows no drive.\n writeSelection(store, undefined);\n }\n return;\n }\n // Any other page (home, settings, a project's, a 404) shows no drive.\n const shown = matches.at(-1)?.status;\n if (shown === \"success\" || shown === \"notFound\") {\n writeSelection(store, undefined);\n }\n };\n\n // A routed modal is the URL's: the store holds what the location names,\n // unless a confirmation is open over it.\n const syncModal = () => {\n const routed = modalFromSearch(router.state.location.search);\n if (store.modal && !isRoutedModal(store.modal)) return;\n if (routed) {\n if (JSON.stringify(store.modal) !== JSON.stringify(routed)) {\n store.modal = routed;\n }\n } else if (isRoutedModal(store.modal)) {\n store.modal = undefined;\n }\n };\n\n // Set once, before the first render; selection setters navigate from the start.\n const navigation = createConnectNavigation(connectRouter);\n store.navigation = navigation;\n\n // The node route's head reads names from the store; a rename re-runs it.\n const shownTitle = () => {\n const node = router.state.matches.find((m) => m.routeId === nodeRoute.id);\n return driveTitle(store, node?.loaderData, router.options.context.appName);\n };\n let title = shownTitle();\n const retitle = () => {\n const next = shownTitle();\n if (next === title) return;\n title = next;\n void router.invalidate({ filter: (m) => m.routeId === nodeRoute.id });\n };\n\n // Before mount, so the view and scroll restoration see the new selection.\n const unsubscribes = [\n router.subscribe(\"onBeforeRouteMount\", commitSelection),\n router.subscribe(\"onResolved\", commitSelection),\n router.subscribe(\"onResolved\", () => {\n title = shownTitle();\n }),\n router.subscribe(\"onResolved\", syncModal),\n getPHStoreSubscribe(store, \"drives\")(retitle),\n getPHStoreSubscribe(store, \"driveNodes\")(retitle),\n markRouterNavigations(router),\n ];\n const unbindScroll = bindConnectScroll(router, CONTENT_VIEW_ID);\n commitSelection();\n syncModal();\n\n return () => {\n navigation.dispose();\n unbindScroll();\n for (const unsubscribe of unsubscribes) unsubscribe();\n if (store.navigation === navigation) store.navigation = undefined;\n };\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport { createDriveArrivals } from \"@powerhousedao/reactor-browser\";\nimport { getConnectPluginUi } from \"../plugins/plugin-ui.js\";\nimport { getConnectRegistry } from \"../registry.js\";\nimport type {\n ConnectRouterBundle,\n ConnectRouterOptions,\n} from \"./connect-router.js\";\nimport { bindConnectRouter, createConnectRouter } from \"./connect-router.js\";\nimport { resolveConnectRoutes } from \"./route-tree.js\";\n\nexport type ConnectAppRouterOptions = Omit<\n ConnectRouterOptions,\n \"store\" | \"arrivals\"\n>;\n\n/** The app's one router over `store`; created, and made the store's navigation,\n * on first use. Registered routes join `options.routes`. */\nexport function getConnectAppRouter(\n store: PHStore,\n options: () => ConnectAppRouterOptions,\n): ConnectRouterBundle {\n const registry = getConnectRegistry();\n const current = registry.app;\n if (current) {\n if (import.meta.env?.DEV && current.store !== store) {\n throw new Error(\"Connect's router is already bound to another PH store\");\n }\n return current.bundle;\n }\n const { routes, ...rest } = options();\n const bundle = createConnectRouter({\n store,\n arrivals: createDriveArrivals(store),\n pluginUi: getConnectPluginUi(),\n ...rest,\n routes: (tree) => [\n ...(routes ? resolveConnectRoutes(routes, tree.routeTree) : []),\n ...registry.routes.flatMap((entry) => {\n entry.added = [\n ...resolveConnectRoutes(entry.registration, tree.routeTree),\n ];\n return entry.added;\n }),\n ],\n });\n registry.app = { store, bundle, unbind: bindConnectRouter(bundle, store) };\n return bundle;\n}\n\n/** Stops the app's router writing the selection, e.g. on HMR. */\nexport function disposeConnectAppRouter() {\n const registry = getConnectRegistry();\n registry.app?.unbind();\n registry.app = undefined;\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport { PHStoreProvider } from \"@powerhousedao/reactor-browser\";\nimport type { AnyRoute } from \"@tanstack/react-router\";\nimport { RouterProvider } from \"@tanstack/react-router\";\nimport type { ConnectAppRouterOptions } from \"./app-router.js\";\nimport { getConnectAppRouter } from \"./app-router.js\";\n\n/** A core-only app: `routeTree`'s views over `store`. */\nexport function ConnectCoreApp(props: {\n store: PHStore;\n routeTree: AnyRoute;\n basepath?: string;\n options?: () => Omit<ConnectAppRouterOptions, \"routeTree\">;\n}) {\n const { router } = getConnectAppRouter(props.store, () => ({\n basepath: props.basepath,\n ...props.options?.(),\n routeTree: props.routeTree,\n }));\n return (\n <PHStoreProvider store={props.store}>\n <RouterProvider router={router} />\n </PHStoreProvider>\n );\n}\n"],"mappings":"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"}
package/dist/router.js CHANGED
@@ -1,5 +1,5 @@
1
- import { c as CoreNotFound, d as isCoreView, f as isDriveNotFound, l as coreModals, m as loadNode, p as loadDrive, s as CoreError, u as coreView } from "./plugin-ui-sO7AJLHj.js";
1
+ import { c as CoreNotFound, d as isCoreView, f as isDriveNotFound, l as coreModals, m as loadNode, p as loadDrive, s as CoreError, u as coreView } from "./plugin-ui-W0ma6oKJ.js";
2
2
  import { a as connectRoutesSettled, c as registerPackageRoutes, f as CORE_MODAL_VIEWS, h as useModalFrame, i as connectRoutes, l as removeConnectRoutes, m as ModalDialog, n as HOME_ROUTE_ID, o as holdConnectRoutes, p as ModalOutlet, r as addConnectRoutes, s as registerConnectRoutes, t as APP_ROUTE_ID } from "./route-tree-D0aszMrk.js";
3
- import { C as ContentOutlet, E as useIsColdStart, S as CONTENT_VIEW_ID, T as DrivePending, _ as useForgetSettingsOpenedFrom, a as DRIVE_ROUTE_ID, b as driveTitle, c as useDriveRouteIds, d as redirectToSettingsTab, f as setSettingsRoute, g as showsSettingsTab, h as settingsTitle, i as useCreateDocumentTarget, l as SETTINGS_ROUTE_ID, m as settingsTabsOf, n as useNavRoutes, o as NODE_ROUTE_ID, p as settingsTabs, r as useSidebarMode, s as useDriveRouteData, t as navRoutes, u as keepOpenedFrom, v as useSettingsTabs, w as DRIVE_PENDING_MS, x as notFoundTitle, y as appTitle } from "./sidebar-DVQCwBYR.js";
4
- import { _ as PERF_STORAGE_KEY, a as createConnectRouter, b as markRouterNavigations, c as GLOBAL_SEARCH_PARAMS, d as parseConnectSearch, f as stringifyConnectSearch, g as connectScrollRestoration, h as bindConnectScroll, i as bindConnectRouter, l as connectSearchMiddlewares, m as validateDriveSearch, n as disposeConnectAppRouter, o as createConnectNavigation, p as validateConnectSearch, r as getConnectAppRouter, s as FEATURE_FLAG_PARAM_PREFIX, t as ConnectCoreApp, u as definedSearch, v as ROUTER_MEASURES, x as routerPerfEnabled, y as markNavigationClick } from "./router-8pekwJsk.js";
3
+ import { C as ContentOutlet, E as useIsColdStart, S as CONTENT_VIEW_ID, T as DrivePending, _ as useForgetSettingsOpenedFrom, a as DRIVE_ROUTE_ID, b as driveTitle, c as useDriveRouteIds, d as redirectToSettingsTab, f as setSettingsRoute, g as showsSettingsTab, h as settingsTitle, i as useCreateDocumentTarget, l as SETTINGS_ROUTE_ID, m as settingsTabsOf, n as useNavRoutes, o as NODE_ROUTE_ID, p as settingsTabs, r as useSidebarMode, s as useDriveRouteData, t as navRoutes, u as keepOpenedFrom, v as useSettingsTabs, w as DRIVE_PENDING_MS, x as notFoundTitle, y as appTitle } from "./sidebar-CRv_DvBV.js";
4
+ import { _ as PERF_STORAGE_KEY, a as createConnectRouter, b as markRouterNavigations, c as GLOBAL_SEARCH_PARAMS, d as parseConnectSearch, f as stringifyConnectSearch, g as connectScrollRestoration, h as bindConnectScroll, i as bindConnectRouter, l as connectSearchMiddlewares, m as validateDriveSearch, n as disposeConnectAppRouter, o as createConnectNavigation, p as validateConnectSearch, r as getConnectAppRouter, s as FEATURE_FLAG_PARAM_PREFIX, t as ConnectCoreApp, u as definedSearch, v as ROUTER_MEASURES, x as routerPerfEnabled, y as markNavigationClick } from "./router-DHL9GT3P.js";
5
5
  export { APP_ROUTE_ID, CONTENT_VIEW_ID, CORE_MODAL_VIEWS, ConnectCoreApp, ContentOutlet, CoreError, CoreNotFound, DRIVE_PENDING_MS, DRIVE_ROUTE_ID, DrivePending, FEATURE_FLAG_PARAM_PREFIX, GLOBAL_SEARCH_PARAMS, HOME_ROUTE_ID, ModalDialog, ModalOutlet, NODE_ROUTE_ID, PERF_STORAGE_KEY, ROUTER_MEASURES, SETTINGS_ROUTE_ID, addConnectRoutes, appTitle, bindConnectRouter, bindConnectScroll, connectRoutes, connectRoutesSettled, connectScrollRestoration, connectSearchMiddlewares, coreModals, coreView, createConnectNavigation, createConnectRouter, definedSearch, disposeConnectAppRouter, driveTitle, getConnectAppRouter, holdConnectRoutes, isCoreView, isDriveNotFound, keepOpenedFrom, loadDrive, loadNode, markNavigationClick, markRouterNavigations, navRoutes, notFoundTitle, parseConnectSearch, redirectToSettingsTab, registerConnectRoutes, registerPackageRoutes, removeConnectRoutes, routerPerfEnabled, setSettingsRoute, settingsTabs, settingsTabsOf, settingsTitle, showsSettingsTab, stringifyConnectSearch, useCreateDocumentTarget, useDriveRouteData, useDriveRouteIds, useForgetSettingsOpenedFrom, useIsColdStart, useModalFrame, useNavRoutes, useSettingsTabs, useSidebarMode, validateConnectSearch, validateDriveSearch };
@@ -1,5 +1,5 @@
1
1
  import { getRuntimeConfig } from "./runtime-config.js";
2
- import { n as resolveRuntimeFlag, t as isRuntimeFlagEnabled } from "./runtime-flag-CJWngtxE.js";
2
+ import { n as resolveRuntimeFlag, t as isRuntimeFlagEnabled } from "./runtime-flag-U8y14Nth.js";
3
3
  import { bindPHStoreToWindow, createPHStore, getActivePHStore, getDrives, getPHStore, refreshReactorDataClient, setDrives, setFullReactorClient } from "@powerhousedao/reactor-browser";
4
4
  import { logger } from "document-model";
5
5
  //#region src/runtime/multi-reactor-flag.ts
@@ -48,7 +48,7 @@ function resolveReactorClientMode() {
48
48
  }
49
49
  //#endregion
50
50
  //#region src/runtime/app-reactor-client.ts
51
- const loadMultiReactor = () => import("./multi-reactor-CPRsFtfd.js");
51
+ const loadMultiReactor = () => import("./multi-reactor-CCMzwoMi.js");
52
52
  function planReactorClient(mode = resolveReactorClientMode()) {
53
53
  const needsLocalReactor = mode !== "remote";
54
54
  return {
@@ -186,4 +186,4 @@ function loadLocalPackage(source) {
186
186
  //#endregion
187
187
  export { planReactorClient as a, resolveReactorClientMode as c, isReactorWorkerEnabled as d, resolveReactorWorkerEnabled as f, getAppDrives as i, REACTOR_WORKER_QUERY_KEY as l, getConnectPHStore as n, refreshAppDrives as o, isMultiReactorEnabled as p, createAppReactorClient as r, selectAppReactorClient as s, loadLocalPackage as t, REACTOR_WORKER_STORAGE_KEY as u };
188
188
 
189
- //# sourceMappingURL=runtime-D8IBQzHM.js.map
189
+ //# sourceMappingURL=runtime-D5hpzfgT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-D8IBQzHM.js","names":[],"sources":["../src/runtime/multi-reactor-flag.ts","../src/runtime/reactor-worker-flag.ts","../src/runtime/reactor-client-mode.ts","../src/runtime/app-reactor-client.ts","../src/runtime/ph-store.ts","../src/runtime/local-package.ts"],"sourcesContent":["import { getRuntimeConfig } from \"./runtime-config.js\";\n\n// Config only: the flag is in the worker fingerprint, so a per-tab value would split tabs.\nexport function isMultiReactorEnabled(): boolean {\n return getRuntimeConfig().connect.instance?.multiReactor ?? false;\n}\n","import { getRuntimeConfig } from \"./runtime-config.js\";\nimport {\n isRuntimeFlagEnabled,\n resolveRuntimeFlag,\n type RuntimeFlagInput,\n} from \"./runtime-flag.js\";\n\nexport const REACTOR_WORKER_QUERY_KEY = \"reactorWorker\";\nexport const REACTOR_WORKER_STORAGE_KEY = \"ph:reactorWorker\";\n\nexport type ReactorWorkerFlagInput = RuntimeFlagInput;\n\nexport function resolveReactorWorkerEnabled(\n input: ReactorWorkerFlagInput,\n): boolean {\n return resolveRuntimeFlag(input);\n}\n\nexport function isReactorWorkerEnabled(): boolean {\n return isRuntimeFlagEnabled({\n queryKey: REACTOR_WORKER_QUERY_KEY,\n storageKey: REACTOR_WORKER_STORAGE_KEY,\n readConfigFlag: () =>\n getRuntimeConfig().connect.instance?.reactorWorker ?? false,\n });\n}\n","import type { PHReactorClientMode } from \"@powerhousedao/shared/clis\";\nimport { getRuntimeConfig } from \"./runtime-config.js\";\nimport { isMultiReactorEnabled } from \"./multi-reactor-flag.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\n\n/**\n * Which of the four reactor clients Connect boots. Standardized by the\n * multi-reactor work; this resolves the single selector Connect acts on:\n *\n * in-process | worker | remote | router\n *\n * Precedence: an explicit `?reactorClient=` query override (handy for a quick\n * check), then the served `connect.instance.reactorClient` (projected from the\n * host's reactor backends), then the LEGACY booleans — so a config that only\n * sets reactorWorker/multiReactor behaves exactly as before.\n *\n * `remote` is the only mode that builds NO local reactor (no PGlite): it is a\n * pure client to a remote Switchboard. `router` keeps the local reactor and\n * adds remote backends; `worker`/`in-process` are the local reactor alone.\n */\nexport type ReactorClientMode = PHReactorClientMode;\n\nconst MODES: ReadonlySet<string> = new Set([\n \"in-process\",\n \"worker\",\n \"remote\",\n \"router\",\n]);\n\nfunction fromQuery(): ReactorClientMode | undefined {\n if (typeof window === \"undefined\") return undefined;\n try {\n const value = new URLSearchParams(window.location.search).get(\n \"reactorClient\",\n );\n return value && MODES.has(value) ? (value as ReactorClientMode) : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function resolveReactorClientMode(): ReactorClientMode {\n const override = fromQuery();\n if (override) return override;\n const configured = getRuntimeConfig().connect.instance?.reactorClient;\n if (configured && MODES.has(configured)) return configured;\n // Legacy fallback — unchanged behaviour for configs without reactorClient.\n if (isMultiReactorEnabled()) return \"router\";\n if (isReactorWorkerEnabled()) return \"worker\";\n return \"in-process\";\n}\n","import type { IReactorClient } from \"@powerhousedao/reactor\";\nimport {\n getDrives,\n refreshReactorDataClient,\n setDrives,\n setFullReactorClient,\n getPHStore,\n} from \"@powerhousedao/reactor-browser\";\nimport type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type { ISigner } from \"@powerhousedao/shared/document-model\";\nimport { logger } from \"document-model\";\nimport type * as MultiReactor from \"./multi-reactor.js\";\nimport type {\n LoadedDocumentModels,\n LocalReactorModule,\n} from \"./multi-reactor.js\";\nimport type { ReactorClientMode } from \"./reactor-client-mode.js\";\nimport { resolveReactorClientMode } from \"./reactor-client-mode.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\n\ntype MultiReactorModule = typeof MultiReactor;\n\nexport type AppReactorClientParams = {\n mode: ReactorClientMode;\n /** Built, and ready (the worker has started up). Undefined in `remote`\n * mode, where no local reactor is built. */\n module: LocalReactorModule | undefined;\n remoteDriveUrl: string | undefined;\n /** Signs routed writes; unsigned (anonymous) without one. */\n signer?: ISigner;\n documentModelModules: LoadedDocumentModels;\n loadRouter?: () => Promise<MultiReactorModule>;\n};\n\nconst loadMultiReactor = (): Promise<MultiReactorModule> =>\n import(\"./multi-reactor.js\");\n\n/** What a mode builds in the tab; `remote` builds no local reactor (no PGlite). */\nexport type ReactorClientPlan = {\n mode: ReactorClientMode;\n /** `router`: the local reactor plus remote backends. */\n multiReactor: boolean;\n needsLocalReactor: boolean;\n /** The local reactor runs in the shared worker. */\n localAsWorker: boolean;\n};\n\nexport function planReactorClient(\n mode: ReactorClientMode = resolveReactorClientMode(),\n): ReactorClientPlan {\n const needsLocalReactor = mode !== \"remote\";\n return {\n mode,\n multiReactor: mode === \"router\",\n needsLocalReactor,\n localAsWorker:\n needsLocalReactor &&\n (mode === \"worker\" || (mode === \"router\" && isReactorWorkerEnabled())),\n };\n}\n\n/** Builds the tab's reactor, e.g. Connect's PGlite or worker reactor. */\nexport type LocalReactorFactory = (\n plan: ReactorClientPlan,\n) => Promise<LocalReactorModule>;\n\nexport type CreateAppReactorClientOptions = Omit<\n AppReactorClientParams,\n \"mode\" | \"module\"\n> & {\n plan?: ReactorClientPlan;\n /** Called only when the plan needs a local reactor. */\n localReactor?: LocalReactorFactory;\n};\n\n/** Builds the local reactor the plan needs, then selects the app's client. */\nexport async function createAppReactorClient(\n options: CreateAppReactorClientOptions,\n) {\n const { localReactor, ...params } = options;\n const plan = options.plan ?? planReactorClient();\n let module: LocalReactorModule | undefined;\n if (plan.needsLocalReactor) {\n if (!localReactor) {\n throw new Error(\n `reactorClient mode \"${plan.mode}\" needs a local reactor; pass localReactor`,\n );\n }\n module = await localReactor(plan);\n }\n const client = await selectAppReactorClient({\n ...params,\n mode: plan.mode,\n module,\n });\n return { plan, module, client };\n}\n\n/**\n * Pick the client for the resolved mode:\n * - `in-process` / `worker`: the local client, router module never loaded.\n * - `router`: the local reactor plus remote backends.\n * - `remote`: a remote-only router — a full IReactorClient that proxies to\n * the Switchboard over GraphQL with NO local reactor (no PGlite).\n */\nexport async function selectAppReactorClient(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (params.mode === \"remote\") {\n setFullReactorClient(undefined);\n const remote = await buildRemoteOnly(params);\n setFullReactorClient(remote);\n return remote;\n }\n if (params.mode !== \"router\") {\n if (getPHStore()?.fullReactorClient) {\n setFullReactorClient(undefined);\n }\n return requireModule(params).client;\n }\n setFullReactorClient(undefined);\n const routed = await buildRouter(params);\n setFullReactorClient(routed);\n return routed ?? requireModule(params).client;\n}\n\nfunction requireModule(params: AppReactorClientParams): LocalReactorModule {\n if (!params.module) {\n throw new Error(\n `reactorClient mode \"${params.mode}\" needs a local reactor, but none was built`,\n );\n }\n return params.module;\n}\n\n/** A Switchboard that cannot answer must not fail boot: list the tab's drives. */\nexport async function getAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<DocumentDriveDocument[]> {\n if (client === local) {\n return getDrives(local);\n }\n try {\n return await getDrives(client);\n } catch (error) {\n logger.warn(\n \"Could not list drives through the router; listing the local reactor's: @error\",\n error,\n );\n return getDrives(local);\n }\n}\n\nexport async function refreshAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<void> {\n if (client === local) {\n return refreshReactorDataClient(client);\n }\n setDrives(await getAppDrives(client, local));\n}\n\nasync function buildRouter(\n params: AppReactorClientParams,\n): Promise<IReactorClient | undefined> {\n if (!params.remoteDriveUrl) {\n logger.warn(\n \"multiReactor is on but no remote drive URL is configured; using the local reactor only\",\n );\n return undefined;\n }\n let multiReactor: MultiReactorModule;\n try {\n multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n } catch (error) {\n logger.error(\"Could not load the multi-reactor router: @error\", error);\n return undefined;\n }\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n logger.warn(\n \"multiReactor is on but the remote drive URL @url does not parse; using the local reactor only\",\n params.remoteDriveUrl,\n );\n return undefined;\n }\n logger.info(\"Multi-reactor routing to @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: requireModule(params),\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n\n/**\n * The `remote` mode: a remote-only router — a full IReactorClient that proxies\n * to the Switchboard over GraphQL with NO local backend, so no local reactor\n * and no PGlite are ever built. A missing/unparseable remote URL is a hard\n * config error here (unlike `router`, there is no local reactor to fall back\n * to).\n */\nasync function buildRemoteOnly(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (!params.remoteDriveUrl) {\n throw new Error(\n 'reactorClient \"remote\" needs a remote drive URL — declare a remote backend / default drive the client can proxy to',\n );\n }\n const multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n throw new Error(\n `reactorClient \"remote\": the remote drive URL \"${params.remoteDriveUrl}\" does not resolve to a Switchboard GraphQL endpoint`,\n );\n }\n logger.info(\"Remote reactor client → @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: undefined,\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n bindPHStoreToWindow,\n createPHStore,\n getActivePHStore,\n} from \"@powerhousedao/reactor-browser\";\n\n/** The app's PH store: the active one, else a new one bound to `window.ph`.\n * Values set on `window.ph` before carry over. */\nexport function getConnectPHStore(): PHStore {\n const active = getActivePHStore();\n if (active) return active;\n const store = createPHStore();\n bindPHStoreToWindow(store);\n return store;\n}\n","import type { DocumentModelLib } from \"document-model\";\n\n/** A module namespace, as `import * as pkg` or Vite HMR hands it over. */\nexport type ModuleNamespace = Record<string, any> & {\n [Symbol.toStringTag]: \"Module\";\n};\n\nexport type LocalPackage = DocumentModelLib<any> | ModuleNamespace;\n\n/** The package itself, or a loader (`() => import(\"./index.js\")`) that keeps it off the boot path. */\nexport type LocalPackageSource = LocalPackage | (() => Promise<LocalPackage>);\n\n/** Starts loading the project's package; a loader runs once, here. */\nexport function loadLocalPackage(\n source: LocalPackageSource | undefined,\n): DocumentModelLib | Promise<DocumentModelLib> | undefined {\n const pkg = (typeof source === \"function\" ? source() : source) as\n | DocumentModelLib\n | Promise<DocumentModelLib>\n | undefined;\n // Consumers await it; this only stops an early rejection being reported as unhandled.\n if (pkg instanceof Promise) pkg.catch(() => undefined);\n return pkg;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime-D5hpzfgT.js","names":[],"sources":["../src/runtime/multi-reactor-flag.ts","../src/runtime/reactor-worker-flag.ts","../src/runtime/reactor-client-mode.ts","../src/runtime/app-reactor-client.ts","../src/runtime/ph-store.ts","../src/runtime/local-package.ts"],"sourcesContent":["import { getRuntimeConfig } from \"./runtime-config.js\";\n\n// Config only: the flag is in the worker fingerprint, so a per-tab value would split tabs.\nexport function isMultiReactorEnabled(): boolean {\n return getRuntimeConfig().connect.instance?.multiReactor ?? false;\n}\n","import { getRuntimeConfig } from \"./runtime-config.js\";\nimport {\n isRuntimeFlagEnabled,\n resolveRuntimeFlag,\n type RuntimeFlagInput,\n} from \"./runtime-flag.js\";\n\nexport const REACTOR_WORKER_QUERY_KEY = \"reactorWorker\";\nexport const REACTOR_WORKER_STORAGE_KEY = \"ph:reactorWorker\";\n\nexport type ReactorWorkerFlagInput = RuntimeFlagInput;\n\nexport function resolveReactorWorkerEnabled(\n input: ReactorWorkerFlagInput,\n): boolean {\n return resolveRuntimeFlag(input);\n}\n\nexport function isReactorWorkerEnabled(): boolean {\n return isRuntimeFlagEnabled({\n queryKey: REACTOR_WORKER_QUERY_KEY,\n storageKey: REACTOR_WORKER_STORAGE_KEY,\n readConfigFlag: () =>\n getRuntimeConfig().connect.instance?.reactorWorker ?? false,\n });\n}\n","import type { PHReactorClientMode } from \"@powerhousedao/shared/clis\";\nimport { getRuntimeConfig } from \"./runtime-config.js\";\nimport { isMultiReactorEnabled } from \"./multi-reactor-flag.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\n\n/**\n * Which of the four reactor clients Connect boots. Standardized by the\n * multi-reactor work; this resolves the single selector Connect acts on:\n *\n * in-process | worker | remote | router\n *\n * Precedence: an explicit `?reactorClient=` query override (handy for a quick\n * check), then the served `connect.instance.reactorClient` (projected from the\n * host's reactor backends), then the LEGACY booleans — so a config that only\n * sets reactorWorker/multiReactor behaves exactly as before.\n *\n * `remote` is the only mode that builds NO local reactor (no PGlite): it is a\n * pure client to a remote Switchboard. `router` keeps the local reactor and\n * adds remote backends; `worker`/`in-process` are the local reactor alone.\n */\nexport type ReactorClientMode = PHReactorClientMode;\n\nconst MODES: ReadonlySet<string> = new Set([\n \"in-process\",\n \"worker\",\n \"remote\",\n \"router\",\n]);\n\nfunction fromQuery(): ReactorClientMode | undefined {\n if (typeof window === \"undefined\") return undefined;\n try {\n const value = new URLSearchParams(window.location.search).get(\n \"reactorClient\",\n );\n return value && MODES.has(value) ? (value as ReactorClientMode) : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function resolveReactorClientMode(): ReactorClientMode {\n const override = fromQuery();\n if (override) return override;\n const configured = getRuntimeConfig().connect.instance?.reactorClient;\n if (configured && MODES.has(configured)) return configured;\n // Legacy fallback — unchanged behaviour for configs without reactorClient.\n if (isMultiReactorEnabled()) return \"router\";\n if (isReactorWorkerEnabled()) return \"worker\";\n return \"in-process\";\n}\n","import type { IReactorClient } from \"@powerhousedao/reactor\";\nimport {\n getDrives,\n refreshReactorDataClient,\n setDrives,\n setFullReactorClient,\n getPHStore,\n} from \"@powerhousedao/reactor-browser\";\nimport type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type { ISigner } from \"@powerhousedao/shared/document-model\";\nimport { logger } from \"document-model\";\nimport type * as MultiReactor from \"./multi-reactor.js\";\nimport type {\n LoadedDocumentModels,\n LocalReactorModule,\n} from \"./multi-reactor.js\";\nimport type { ReactorClientMode } from \"./reactor-client-mode.js\";\nimport { resolveReactorClientMode } from \"./reactor-client-mode.js\";\nimport { isReactorWorkerEnabled } from \"./reactor-worker-flag.js\";\n\ntype MultiReactorModule = typeof MultiReactor;\n\nexport type AppReactorClientParams = {\n mode: ReactorClientMode;\n /** Built, and ready (the worker has started up). Undefined in `remote`\n * mode, where no local reactor is built. */\n module: LocalReactorModule | undefined;\n remoteDriveUrl: string | undefined;\n /** Signs routed writes; unsigned (anonymous) without one. */\n signer?: ISigner;\n documentModelModules: LoadedDocumentModels;\n loadRouter?: () => Promise<MultiReactorModule>;\n};\n\nconst loadMultiReactor = (): Promise<MultiReactorModule> =>\n import(\"./multi-reactor.js\");\n\n/** What a mode builds in the tab; `remote` builds no local reactor (no PGlite). */\nexport type ReactorClientPlan = {\n mode: ReactorClientMode;\n /** `router`: the local reactor plus remote backends. */\n multiReactor: boolean;\n needsLocalReactor: boolean;\n /** The local reactor runs in the shared worker. */\n localAsWorker: boolean;\n};\n\nexport function planReactorClient(\n mode: ReactorClientMode = resolveReactorClientMode(),\n): ReactorClientPlan {\n const needsLocalReactor = mode !== \"remote\";\n return {\n mode,\n multiReactor: mode === \"router\",\n needsLocalReactor,\n localAsWorker:\n needsLocalReactor &&\n (mode === \"worker\" || (mode === \"router\" && isReactorWorkerEnabled())),\n };\n}\n\n/** Builds the tab's reactor, e.g. Connect's PGlite or worker reactor. */\nexport type LocalReactorFactory = (\n plan: ReactorClientPlan,\n) => Promise<LocalReactorModule>;\n\nexport type CreateAppReactorClientOptions = Omit<\n AppReactorClientParams,\n \"mode\" | \"module\"\n> & {\n plan?: ReactorClientPlan;\n /** Called only when the plan needs a local reactor. */\n localReactor?: LocalReactorFactory;\n};\n\n/** Builds the local reactor the plan needs, then selects the app's client. */\nexport async function createAppReactorClient(\n options: CreateAppReactorClientOptions,\n) {\n const { localReactor, ...params } = options;\n const plan = options.plan ?? planReactorClient();\n let module: LocalReactorModule | undefined;\n if (plan.needsLocalReactor) {\n if (!localReactor) {\n throw new Error(\n `reactorClient mode \"${plan.mode}\" needs a local reactor; pass localReactor`,\n );\n }\n module = await localReactor(plan);\n }\n const client = await selectAppReactorClient({\n ...params,\n mode: plan.mode,\n module,\n });\n return { plan, module, client };\n}\n\n/**\n * Pick the client for the resolved mode:\n * - `in-process` / `worker`: the local client, router module never loaded.\n * - `router`: the local reactor plus remote backends.\n * - `remote`: a remote-only router — a full IReactorClient that proxies to\n * the Switchboard over GraphQL with NO local reactor (no PGlite).\n */\nexport async function selectAppReactorClient(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (params.mode === \"remote\") {\n setFullReactorClient(undefined);\n const remote = await buildRemoteOnly(params);\n setFullReactorClient(remote);\n return remote;\n }\n if (params.mode !== \"router\") {\n if (getPHStore()?.fullReactorClient) {\n setFullReactorClient(undefined);\n }\n return requireModule(params).client;\n }\n setFullReactorClient(undefined);\n const routed = await buildRouter(params);\n setFullReactorClient(routed);\n return routed ?? requireModule(params).client;\n}\n\nfunction requireModule(params: AppReactorClientParams): LocalReactorModule {\n if (!params.module) {\n throw new Error(\n `reactorClient mode \"${params.mode}\" needs a local reactor, but none was built`,\n );\n }\n return params.module;\n}\n\n/** A Switchboard that cannot answer must not fail boot: list the tab's drives. */\nexport async function getAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<DocumentDriveDocument[]> {\n if (client === local) {\n return getDrives(local);\n }\n try {\n return await getDrives(client);\n } catch (error) {\n logger.warn(\n \"Could not list drives through the router; listing the local reactor's: @error\",\n error,\n );\n return getDrives(local);\n }\n}\n\nexport async function refreshAppDrives(\n client: IReactorClient,\n local: IReactorClient,\n): Promise<void> {\n if (client === local) {\n return refreshReactorDataClient(client);\n }\n setDrives(await getAppDrives(client, local));\n}\n\nasync function buildRouter(\n params: AppReactorClientParams,\n): Promise<IReactorClient | undefined> {\n if (!params.remoteDriveUrl) {\n logger.warn(\n \"multiReactor is on but no remote drive URL is configured; using the local reactor only\",\n );\n return undefined;\n }\n let multiReactor: MultiReactorModule;\n try {\n multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n } catch (error) {\n logger.error(\"Could not load the multi-reactor router: @error\", error);\n return undefined;\n }\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n logger.warn(\n \"multiReactor is on but the remote drive URL @url does not parse; using the local reactor only\",\n params.remoteDriveUrl,\n );\n return undefined;\n }\n logger.info(\"Multi-reactor routing to @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: requireModule(params),\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n\n/**\n * The `remote` mode: a remote-only router — a full IReactorClient that proxies\n * to the Switchboard over GraphQL with NO local backend, so no local reactor\n * and no PGlite are ever built. A missing/unparseable remote URL is a hard\n * config error here (unlike `router`, there is no local reactor to fall back\n * to).\n */\nasync function buildRemoteOnly(\n params: AppReactorClientParams,\n): Promise<IReactorClient> {\n if (!params.remoteDriveUrl) {\n throw new Error(\n 'reactorClient \"remote\" needs a remote drive URL — declare a remote backend / default drive the client can proxy to',\n );\n }\n const multiReactor = await (params.loadRouter ?? loadMultiReactor)();\n const remoteGraphqlUrl = multiReactor.deriveSwitchboardGraphqlUrl(\n params.remoteDriveUrl,\n );\n if (!remoteGraphqlUrl) {\n throw new Error(\n `reactorClient \"remote\": the remote drive URL \"${params.remoteDriveUrl}\" does not resolve to a Switchboard GraphQL endpoint`,\n );\n }\n logger.info(\"Remote reactor client → @url\", remoteGraphqlUrl);\n return multiReactor.buildMultiReactorClient({\n module: undefined,\n remoteGraphqlUrl,\n signer: params.signer,\n documentModelModules: params.documentModelModules,\n });\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n bindPHStoreToWindow,\n createPHStore,\n getActivePHStore,\n} from \"@powerhousedao/reactor-browser\";\n\n/** The app's PH store: the active one, else a new one bound to `window.ph`.\n * Values set on `window.ph` before carry over. */\nexport function getConnectPHStore(): PHStore {\n const active = getActivePHStore();\n if (active) return active;\n const store = createPHStore();\n bindPHStoreToWindow(store);\n return store;\n}\n","import type { DocumentModelLib } from \"document-model\";\n\n/** A module namespace, as `import * as pkg` or Vite HMR hands it over. */\nexport type ModuleNamespace = Record<string, any> & {\n [Symbol.toStringTag]: \"Module\";\n};\n\nexport type LocalPackage = DocumentModelLib<any> | ModuleNamespace;\n\n/** The package itself, or a loader (`() => import(\"./index.js\")`) that keeps it off the boot path. */\nexport type LocalPackageSource = LocalPackage | (() => Promise<LocalPackage>);\n\n/** Starts loading the project's package; a loader runs once, here. */\nexport function loadLocalPackage(\n source: LocalPackageSource | undefined,\n): DocumentModelLib | Promise<DocumentModelLib> | undefined {\n const pkg = (typeof source === \"function\" ? source() : source) as\n | DocumentModelLib\n | Promise<DocumentModelLib>\n | undefined;\n // Consumers await it; this only stops an early rejection being reported as unhandled.\n if (pkg instanceof Promise) pkg.catch(() => undefined);\n return pkg;\n}\n"],"mappings":"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"}