@powerhousedao/reactor-browser 6.2.3-dev.3 → 6.2.3-dev.5

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 (36) hide show
  1. package/dist/{attachment-service-CdwHrbDH.d.ts → attachment-service-D3EhiAJ7.d.ts} +43 -8
  2. package/dist/attachment-service-D3EhiAJ7.d.ts.map +1 -0
  3. package/dist/{document-by-id-BSZqTN66.js → document-by-id-B4FIzG1w.js} +4 -2
  4. package/dist/{document-by-id-BSZqTN66.js.map → document-by-id-B4FIzG1w.js.map} +1 -1
  5. package/dist/{document-model-modules-DfQBNGc-.js → document-model-modules-bTP87nyr.js} +35 -35
  6. package/dist/{document-model-modules-DfQBNGc-.js.map → document-model-modules-bTP87nyr.js.map} +1 -1
  7. package/dist/{document-operations-Bgo6A6W2.js → document-operations-WeE6wIDt.js} +67 -9
  8. package/dist/document-operations-WeE6wIDt.js.map +1 -0
  9. package/dist/{global-BggszP4X.d.ts → global-OuINvEGT.d.ts} +2 -2
  10. package/dist/{global-BggszP4X.d.ts.map → global-OuINvEGT.d.ts.map} +1 -1
  11. package/dist/{index-CkJNhsQo.d.ts → index-B33TKEqp.d.ts} +4 -3
  12. package/dist/{index-CkJNhsQo.d.ts.map → index-B33TKEqp.d.ts.map} +1 -1
  13. package/dist/index.d.ts +42 -5
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +42 -11
  16. package/dist/index.js.map +1 -1
  17. package/dist/{relational-D4sxGPz7.js → relational-D1RB45sA.js} +2 -2
  18. package/dist/{relational-D4sxGPz7.js.map → relational-D1RB45sA.js.map} +1 -1
  19. package/dist/{renown-BIEv6bSI.js → renown-rqK8sokh.js} +20 -5
  20. package/dist/renown-rqK8sokh.js.map +1 -0
  21. package/dist/src/ai/index.js +2 -2
  22. package/dist/src/analytics/index.js +1 -1
  23. package/dist/src/graphql-client/entry.d.ts +3 -3
  24. package/dist/src/graphql-client/entry.js +4 -4
  25. package/dist/src/relational/index.js +1 -1
  26. package/dist/src/renown/index.d.ts +2 -2
  27. package/dist/src/renown/index.js +2 -2
  28. package/dist/src/rpc/index.d.ts.map +1 -1
  29. package/dist/src/rpc/index.js +2 -0
  30. package/dist/src/rpc/index.js.map +1 -1
  31. package/dist/{switchboard-D4-_jwk-.js → switchboard-CaXQ4-5Q.js} +4 -4
  32. package/dist/{switchboard-D4-_jwk-.js.map → switchboard-CaXQ4-5Q.js.map} +1 -1
  33. package/package.json +9 -9
  34. package/dist/attachment-service-CdwHrbDH.d.ts.map +0 -1
  35. package/dist/document-operations-Bgo6A6W2.js.map +0 -1
  36. package/dist/renown-BIEv6bSI.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"document-model-modules-DfQBNGc-.js","names":[],"sources":["../src/errors.ts","../src/graphql-client/auth.ts","../src/utils/url.ts","../src/hooks/drives.ts","../src/hooks/set-selected-node.ts","../src/hooks/selected-drive.ts","../src/utils/nodes.ts","../src/hooks/items-in-selected-drive.ts","../src/hooks/selected-node.ts","../src/hooks/vetra-packages.ts","../src/hooks/document-model-modules.ts"],"sourcesContent":["export class UnsupportedDocumentTypeError extends Error {\n constructor(documentType: string) {\n super(`Document type ${documentType} is not supported`);\n this.name = \"UnsupportedDocumentTypeError\";\n }\n\n static isError(error: unknown): error is UnsupportedDocumentTypeError {\n return (\n Error.isError(error) && error.name === \"UnsupportedDocumentTypeError\"\n );\n }\n}\n\nexport class DocumentModelNotFoundError extends Error {\n readonly documentType: string;\n readonly name = \"DocumentModelNotFoundError\";\n\n constructor(documentType: string) {\n super(`Document model module for type ${documentType} not found`);\n this.documentType = documentType;\n }\n\n static isError(error: unknown): error is DocumentModelNotFoundError {\n return Error.isError(error) && error.name === \"DocumentModelNotFoundError\";\n }\n}\n\nexport class DocumentTypeMismatchError extends Error {\n constructor(documentId: string, expectedType: string, actualType: string) {\n super(\n `Document ${documentId} is not of type ${expectedType}. Actual type: ${actualType}`,\n );\n }\n}\n\nexport class NoSelectedDocumentError extends Error {\n constructor() {\n super(\n \"There is no selected document. Did you mean to call 'useSelectedDocumentSafe' instead?\",\n );\n }\n}\n","import type { SdkFunctionWrapper } from \"../graphql/gen/schema.js\";\n\n/**\n * Resolves the bearer token to send with a request.\n *\n * Returning `undefined` (or an empty string) means \"send this request\n * anonymously\": open Switchboards must keep serving reads to logged-out users.\n */\nexport type BearerTokenProvider = () => Promise<string | undefined>;\n\n/** Lifetime requested for an ambient Renown token, in seconds. */\nconst ambientTokenExpiresInSeconds = 600;\n\n/**\n * The default token provider: the token of the currently logged-in Renown user.\n *\n * It is deliberately resolved from `window.ph` on every call rather than\n * captured at construction time, so a client built before login starts sending\n * the token as soon as there is one.\n *\n * The token is requested WITHOUT an `aud` claim - the Switchboard verifier\n * rejects tokens that carry an audience.\n */\nexport async function ambientRenownTokenProvider(): Promise<\n string | undefined\n> {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n const renown = window.ph?.renown;\n if (!renown?.user) {\n return undefined;\n }\n\n return renown.getBearerToken({ expiresIn: ambientTokenExpiresInSeconds });\n}\n\n/**\n * Builds the SDK middleware that authenticates every request.\n *\n * The token is resolved per request and never cached, so a login, a logout or\n * an expiry between two calls is picked up by the next one. When no token is\n * available the request goes out unauthenticated.\n */\nexport function makeAuthMiddleware(\n tokenProvider: BearerTokenProvider,\n): SdkFunctionWrapper {\n return async (action) => {\n const token = await tokenProvider();\n if (!token) {\n return action();\n }\n\n return action({ authorization: `Bearer ${token}` });\n };\n}\n","import type {\n DocumentDriveDocument,\n Node,\n} from \"@powerhousedao/shared/document-drive\";\nimport slug from \"slug\";\n\n// Returns url with base path plus provided path\nexport function resolveUrlPathname(path: string) {\n return new URL(\n path.replace(/^\\/+/, \"\"),\n window.location.origin + (window.ph?.basePath ?? \"/\"),\n ).pathname;\n}\n\n/** Returns the current path without the base path */\nexport function getPathWithoutBase(path: string) {\n const basePath = window.ph?.basePath ?? \"/\";\n return path.replace(basePath, basePath.endsWith(\"/\") ? \"/\" : \"\");\n}\n\n/** Makes a URL component for a drive. */\nexport function makeDriveUrlComponent(\n drive: DocumentDriveDocument | undefined,\n) {\n if (!drive) return \"\";\n return `/d/${slug(drive.header.slug)}`;\n}\n\n/** Makes a URL component for a node. */\nexport function makeNodeSlug(node: Node | undefined) {\n if (!node) return \"\";\n const nodeName = node.name;\n if (!nodeName) return slug(node.id);\n return slug(`${nodeName}-${node.id}`);\n}\n\n/** Extracts the node slug from a path.\n *\n * The path is expected to be in the format `/d/<drive-slug>/<node-slug>`.\n */\nexport function extractNodeSlugFromPath(path: string) {\n const currentPath = getPathWithoutBase(path);\n const match = /^\\/d\\/[^/]+\\/([^/]+)$/.exec(currentPath);\n return match?.[1];\n}\n\n/** Finds a UUID in a string, used for extracting node ids from node slugs in the URL. */\nexport function findUuid(input: string | undefined) {\n if (!input) return undefined;\n const uuidRegex =\n /\\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\\b/;\n const match = uuidRegex.exec(input);\n return match?.[0];\n}\n\nexport function extractNodeIdFromSlug(nodeSlug: string | undefined) {\n const nodeId = findUuid(nodeSlug);\n return nodeId;\n}\n\nexport function extractNodeIdFromPath(path: string) {\n const nodeSlug = extractNodeSlugFromPath(path);\n const nodeId = extractNodeIdFromSlug(nodeSlug);\n return nodeId;\n}\n\n/** Extracts the drive slug from a path.\n * Used for extracting drive ids from drive slugs in the URL.\n * Expects the path to be in the format `/d/<drive-slug>`.\n */\nexport function extractDriveSlugFromPath(path: string) {\n const currentPath = getPathWithoutBase(path);\n const match = /^\\/d\\/([^/]+)/.exec(currentPath);\n return match?.[1] ?? \"\";\n}\n\nexport function extractDriveIdFromSlug(driveSlug: string | undefined) {\n const driveId = findUuid(driveSlug);\n return driveId;\n}\n\nexport function extractDriveIdFromPath(path: string) {\n const driveSlug = extractDriveSlugFromPath(path);\n const driveId = extractDriveIdFromSlug(driveSlug);\n return driveId;\n}\n\n/**\n * Creates a URL string with the given pathname while preserving existing query parameters.\n */\nexport function createUrlWithPreservedParams(pathname: string): string {\n const search = window.location.search;\n return search ? `${pathname}${search}` : pathname;\n}\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type { SetPHGlobalValue, UsePHGlobalValue } from \"../types/global.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\n\nconst drivesEventFunctions = makePHEventFunctions(\"drives\");\n\n/** Returns all of the drives in the reactor */\nexport const useDrives: UsePHGlobalValue<DocumentDriveDocument[]> =\n drivesEventFunctions.useValue;\n\n/** Sets the drives in the reactor */\nexport const setDrives: SetPHGlobalValue<DocumentDriveDocument[]> =\n drivesEventFunctions.setValue;\n\n/** Adds an event handler for the drives */\nexport const addDrivesEventHandler = drivesEventFunctions.addEventHandler;\n","import type { Node } from \"@powerhousedao/shared/document-drive\";\nimport {\n createUrlWithPreservedParams,\n extractDriveSlugFromPath,\n extractNodeIdFromSlug,\n extractNodeSlugFromPath,\n makeNodeSlug,\n resolveUrlPathname,\n} from \"../utils/url.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\n\nconst selectedNodeIdEventFunctions = makePHEventFunctions(\"selectedNodeId\");\nexport const useSelectedNodeId = selectedNodeIdEventFunctions.useValue;\nconst setSelectedNodeId = selectedNodeIdEventFunctions.setValue;\nexport const addSelectedNodeIdEventHandler =\n selectedNodeIdEventFunctions.addEventHandler;\n\n/** Sets the selected node (file or folder). */\nexport function setSelectedNode(nodeOrNodeSlug: Node | string | undefined) {\n const nodeSlug =\n typeof nodeOrNodeSlug === \"string\"\n ? nodeOrNodeSlug\n : makeNodeSlug(nodeOrNodeSlug);\n const nodeId = extractNodeIdFromSlug(nodeSlug);\n setSelectedNodeId(nodeId);\n const driveSlugFromPath = extractDriveSlugFromPath(window.location.pathname);\n if (!driveSlugFromPath) {\n return;\n }\n if (!nodeSlug) {\n const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}`);\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n return;\n }\n const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}/${nodeSlug}`);\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n}\n\nexport function addResetSelectedNodeEventHandler() {\n window.addEventListener(\"ph:selectedDriveIdUpdated\", () => {\n setSelectedNodeId(undefined);\n });\n}\n\nexport function addSetSelectedNodeOnPopStateEventHandler() {\n window.addEventListener(\"popstate\", () => {\n const pathname = window.location.pathname;\n const nodeSlug = extractNodeSlugFromPath(pathname);\n // The slug embeds the id (`<name>-<uuid>`); compare ids, not slug vs id.\n const nodeId = extractNodeIdFromSlug(nodeSlug);\n const selectedNodeId = window.ph?.selectedNodeId;\n if (nodeId !== selectedNodeId) {\n setSelectedNode(nodeSlug);\n }\n });\n}\n","import type { DocumentDispatch } from \"@powerhousedao/reactor-browser\";\nimport type {\n DocumentDriveAction,\n DocumentDriveDocument,\n} from \"@powerhousedao/shared/document-drive\";\nimport {\n createUrlWithPreservedParams,\n extractDriveIdFromPath,\n extractDriveSlugFromPath,\n extractNodeSlugFromPath,\n resolveUrlPathname,\n} from \"../utils/url.js\";\nimport { useDispatch } from \"./dispatch.js\";\nimport { useDrives } from \"./drives.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\nimport { setSelectedNode } from \"./set-selected-node.js\";\n\nconst selectedDriveIdEventFunctions = makePHEventFunctions(\"selectedDriveId\");\n\n/** Returns the selected drive id */\nexport const useSelectedDriveId = selectedDriveIdEventFunctions.useValue;\n\n/** Sets the selected drive id */\nexport const setSelectedDriveId = selectedDriveIdEventFunctions.setValue;\n\n/** Adds an event handler for the selected drive id */\nexport const addSelectedDriveIdEventHandler =\n selectedDriveIdEventFunctions.addEventHandler;\n\n/** Returns the selected drive */\nexport function useSelectedDrive() {\n const drive = useSelectedDriveSafe();\n if (!drive[0]) {\n throw new Error(\n \"There is no drive selected. Did you mean to call 'useSelectedDriveSafe'?\",\n );\n }\n\n return drive;\n}\n\n/** Returns the selected drive, or undefined if no drive is selected */\nexport function useSelectedDriveSafe() {\n const selectedDriveId = useSelectedDriveId();\n const drives = useDrives();\n const selectedDrive = drives?.find(\n (drive) => drive.header.id === selectedDriveId,\n );\n\n const [drive, dispatch] = useDispatch(selectedDrive);\n if (!selectedDrive) {\n return [undefined, undefined] as const;\n }\n return [drive, dispatch] as [\n DocumentDriveDocument,\n DocumentDispatch<DocumentDriveAction>,\n ];\n}\n\nexport function setSelectedDrive(\n driveOrDriveSlug: string | DocumentDriveDocument | undefined,\n) {\n const driveSlug =\n typeof driveOrDriveSlug === \"string\"\n ? driveOrDriveSlug\n : driveOrDriveSlug?.header.slug;\n\n // A full drive document is selected directly — a just-created drive\n // navigates before the collection refresh. Slugs go through the lookup.\n const drives = window.ph?.drives;\n const drive =\n typeof driveOrDriveSlug === \"object\" && driveOrDriveSlug !== null\n ? driveOrDriveSlug\n : drives?.find((d) => d.header.slug === driveSlug);\n const driveId = drive?.header.id;\n\n // A URL-pinned slug with no matching drive: the deep link may predate\n // remote drive registration, so defer instead of rewriting the URL.\n if (\n !driveId &&\n driveSlug &&\n extractDriveSlugFromPath(window.location.pathname) === driveSlug\n ) {\n // Clear the previous selection so a stale drive doesn't render against\n // the new URL; the selected node resets with it, the URL is untouched.\n if (window.ph?.selectedDriveId) {\n setSelectedDriveId(undefined);\n }\n deferDriveSelection(driveSlug);\n return;\n }\n\n // Any resolved selection supersedes a pending deferred lookup.\n cancelPendingDriveSelection();\n\n setSelectedDriveId(driveId);\n\n if (!driveId) {\n const pathname = resolveUrlPathname(\"/\");\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n return;\n }\n const pathname = resolveUrlPathname(`/d/${driveSlug}`);\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n}\n\n// Tick between unresolved-slug checks; re-armed while a sync is in flight.\nconst DEFERRED_DRIVE_TICK_MS = 2_000;\n// Hard cap so a wedged remote can't pin the deep link forever.\nconst DEFERRED_DRIVE_MAX_WAIT_MS = 15_000;\n\n// True while any sync remote has not completed its first successful pull —\n// a drive may still be on its way in, so the deferred lookup keeps waiting.\nfunction isInitialSyncInFlight(): boolean {\n const remotes =\n window.ph?.reactorClientModule?.reactorModule?.syncModule?.syncManager?.list();\n if (!remotes?.length) {\n return false;\n }\n return remotes.some((remote) => {\n try {\n const snapshot = remote.channel.getConnectionState();\n return (\n snapshot.receivingPages ||\n (!snapshot.lastSuccessUtcMs && snapshot.state !== \"error\")\n );\n } catch {\n return false;\n }\n });\n}\n\nlet pendingHandler: (() => void) | undefined;\nlet pendingTimeout: ReturnType<typeof setTimeout> | undefined;\n\nfunction cancelPendingDriveSelection() {\n if (pendingHandler) {\n window.removeEventListener(\"ph:drivesUpdated\", pendingHandler);\n pendingHandler = undefined;\n }\n if (pendingTimeout) {\n clearTimeout(pendingTimeout);\n pendingTimeout = undefined;\n }\n}\n\n// Re-runs the slug lookup on each drives update until it resolves, then\n// restores the URL-pinned node. Unresolved slugs redirect once syncs settle.\nfunction deferDriveSelection(driveSlug: string) {\n cancelPendingDriveSelection();\n\n // Capture the node pinned in the deep link before setSelectedDrive\n // rewrites the URL to /d/<driveSlug>, dropping the node segment.\n const nodeSlug = extractNodeSlugFromPath(window.location.pathname);\n const handler = () => {\n const drive = window.ph?.drives?.find((d) => d.header.slug === driveSlug);\n if (!drive) {\n return;\n }\n cancelPendingDriveSelection();\n setSelectedDrive(driveSlug);\n setSelectedNode(nodeSlug);\n };\n pendingHandler = handler;\n window.addEventListener(\"ph:drivesUpdated\", handler);\n\n const deadline = Date.now() + DEFERRED_DRIVE_MAX_WAIT_MS;\n const scheduleTick = () => {\n pendingTimeout = setTimeout(() => {\n if (Date.now() < deadline && isInitialSyncInFlight()) {\n scheduleTick();\n return;\n }\n cancelPendingDriveSelection();\n const pathname = resolveUrlPathname(\"/\");\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(\n null,\n \"\",\n createUrlWithPreservedParams(pathname),\n );\n }, DEFERRED_DRIVE_TICK_MS);\n };\n scheduleTick();\n}\n\nexport function addSetSelectedDriveOnPopStateEventHandler() {\n window.addEventListener(\"popstate\", () => {\n const pathname = window.location.pathname;\n const driveId = extractDriveIdFromPath(pathname);\n const selectedDriveId = window.ph?.selectedDriveId;\n if (driveId !== selectedDriveId) {\n setSelectedDrive(driveId);\n }\n });\n}\n","import type {\n FileNode,\n FolderNode,\n Node,\n} from \"@powerhousedao/shared/document-drive\";\n\n/** Sorts nodes by name. */\nexport function sortNodesByName<T extends Node>(nodes: T[]) {\n return nodes.toSorted((a, b) => a.name.localeCompare(b.name));\n}\n\n/** Returns whether a node is a file. */\nexport function isFileNodeKind(\n node: Node | null | undefined,\n): node is FileNode {\n if (!node) return false;\n return node.kind.toUpperCase() === \"FILE\";\n}\n\n/** Returns whether a node is a folder. */\nexport function isFolderNodeKind(\n node: Node | null | undefined,\n): node is FolderNode {\n if (!node) return false;\n return node.kind.toUpperCase() === \"FOLDER\";\n}\n","import type {\n FileNode,\n FolderNode,\n} from \"@powerhousedao/shared/document-drive\";\nimport type {\n DocumentModelDocument,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport { isFileNodeKind, isFolderNodeKind } from \"../utils/nodes.js\";\nimport { useDocumentsByIds } from \"./document-by-id.js\";\nimport { useSelectedDriveSafe } from \"./selected-drive.js\";\n\n/** Returns the nodes in the selected drive. */\nexport function useNodesInSelectedDrive() {\n const [selectedDrive] = useSelectedDriveSafe();\n return selectedDrive?.state.global.nodes;\n}\n\n/** Returns the file nodes in the selected drive. */\nexport function useFileNodesInSelectedDrive(): FileNode[] | undefined {\n const nodes = useNodesInSelectedDrive();\n return nodes?.filter((n) => isFileNodeKind(n));\n}\n\n/** Returns the folder nodes in the selected drive. */\nexport function useFolderNodesInSelectedDrive(): FolderNode[] | undefined {\n const nodes = useNodesInSelectedDrive();\n return nodes?.filter((n) => isFolderNodeKind(n));\n}\n\n/** Returns the documents in the selected drive. */\nexport function useDocumentsInSelectedDrive(): PHDocument[] | undefined {\n const fileNodes = useFileNodesInSelectedDrive();\n const fileNodeIds = fileNodes?.map((node) => node.id);\n return useDocumentsByIds(fileNodeIds);\n}\n\n/** Returns the document types supported by the selected drive, as defined by the document model documents present in the drive */\nexport function useDocumentTypesInSelectedDrive() {\n const documentsInSelectedDrive = useDocumentsInSelectedDrive();\n const documentModelDocumentsInSelectedDrive =\n documentsInSelectedDrive?.filter(isDocumentModelDocument);\n const documentTypesFromDocumentModelDocuments =\n documentModelDocumentsInSelectedDrive?.map((doc) => doc.state.global.id);\n return documentTypesFromDocumentModelDocuments;\n}\n\nfunction isDocumentModelDocument(\n document: PHDocument,\n): document is DocumentModelDocument {\n return document.header.documentType === \"powerhouse/document-model\";\n}\n","import type { Node } from \"@powerhousedao/shared/document-drive\";\nimport { useNodesInSelectedDrive } from \"./items-in-selected-drive.js\";\nimport { useSelectedNodeId } from \"./set-selected-node.js\";\n\nexport {\n addResetSelectedNodeEventHandler,\n addSelectedNodeIdEventHandler,\n addSetSelectedNodeOnPopStateEventHandler,\n setSelectedNode,\n} from \"./set-selected-node.js\";\n\n/** Returns the selected node. */\nexport function useSelectedNode(): Node | undefined {\n const selectedNodeId = useSelectedNodeId();\n const nodes = useNodesInSelectedDrive();\n return nodes?.find((n) => n.id === selectedNodeId);\n}\n","import type { DocumentModelLib } from \"document-model\";\nimport { useSyncExternalStore } from \"react\";\nimport {\n isDuplicateManifestError,\n isDuplicateModuleError,\n} from \"../reactor-interop.js\";\nimport type { IPackageManager } from \"../types/vetra.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\n\nconst vetraPackageManagerFunctions = makePHEventFunctions(\n \"vetraPackageManager\",\n);\n\nexport const useVetraPackageManager = vetraPackageManagerFunctions.useValue;\n\nconst EMPTY_VETRA_PACKAGES: DocumentModelLib[] = [];\nconst noPackageManagerUnsubscribe = () => {};\n\n/**\n * Returns all of the Vetra packages loaded by the Connect instance.\n *\n * The snapshot and subscription must keep stable identity while no package\n * manager is registered: `useSyncExternalStore` loops when the snapshot\n * changes on every read, which a fresh `[]` does.\n */\nexport const useVetraPackages = () => {\n const packageManager = useVetraPackageManager();\n\n return useSyncExternalStore(\n (cb) =>\n packageManager\n ? packageManager.subscribe(cb)\n : noPackageManagerUnsubscribe,\n () => packageManager?.packages ?? EMPTY_VETRA_PACKAGES,\n );\n};\n\n/** Adds the Vetra package manager event handler */\nexport const addVetraPackageManagerEventHandler =\n vetraPackageManagerFunctions.addEventHandler;\n\n/** Sets the Vetra package manager and registers its packages */\nexport function setVetraPackageManager(packageManager: IPackageManager) {\n vetraPackageManagerFunctions.setValue(packageManager);\n updateReactorClientDocumentModels(packageManager.packages);\n updateReactorClientUpgradeManifests(packageManager.packages);\n packageManager.subscribe(({ packages }) => {\n updateReactorClientDocumentModels(packages);\n updateReactorClientUpgradeManifests(packages);\n });\n}\n\nfunction updateReactorClientDocumentModels(packages: DocumentModelLib[]) {\n const documentModelModules = packages\n .flatMap((pkg) => pkg.documentModels)\n .filter(\n (module, index, modules) =>\n // dedupe by documentType and version\n modules.findIndex(\n (m) =>\n m.documentModel.global.id === module.documentModel.global.id &&\n (m.version ?? 1) === (module.version ?? 1),\n ) === index,\n );\n\n const registry =\n window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;\n if (!registry || documentModelModules.length === 0) return;\n\n const results = registry.registerModules(...documentModelModules);\n const duplicateTypes = new Set<string>();\n for (const result of results) {\n if (result.status === \"error\") {\n if (isDuplicateModuleError(result.error)) {\n duplicateTypes.add(result.item.documentModel.global.id);\n } else {\n console.error(\n \"Failed to register document model module:\",\n result.error,\n );\n }\n }\n }\n if (duplicateTypes.size > 0) {\n // unregisterModules is type-scoped, so replace the whole version family\n // with the incoming package's modules: re-registering only the duplicated\n // items would purge any new version that registered successfully above.\n registry.unregisterModules(...duplicateTypes);\n registry.registerModules(\n ...documentModelModules.filter((module) =>\n duplicateTypes.has(module.documentModel.global.id),\n ),\n );\n }\n}\n\nfunction updateReactorClientUpgradeManifests(packages: DocumentModelLib[]) {\n const upgradeManifests = packages\n .flatMap((pkg) => pkg.upgradeManifests)\n .filter((u) => u !== undefined);\n\n const registry =\n window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;\n if (!registry || upgradeManifests.length === 0) return;\n\n const results = registry.registerUpgradeManifests(...upgradeManifests);\n const duplicates = [];\n for (const result of results) {\n if (result.status === \"error\") {\n if (isDuplicateManifestError(result.error)) {\n duplicates.push(result);\n } else {\n console.error(\"Failed to register upgrade manifest:\", result.error);\n }\n }\n }\n if (duplicates.length > 0) {\n const duplicateTypes = duplicates\n .map((r) => r.item.documentType)\n .filter((t): t is string => !!t);\n registry.unregisterUpgradeManifests(...duplicateTypes);\n registry.registerUpgradeManifests(...duplicates.map((r) => r.item));\n }\n}\n","import type { DocumentModelModule } from \"document-model\";\nimport { useVetraPackages } from \"./vetra-packages.js\";\n\nexport function useDocumentModelModules(): DocumentModelModule[] | undefined {\n const vetraPackages = useVetraPackages();\n return vetraPackages\n .flatMap((pkg) => pkg.documentModels)\n .filter(\n (module, index, modules) =>\n // deduplicate by documentType and version\n modules.findIndex(\n (m) =>\n m.documentModel.global.id === module.documentModel.global.id &&\n m.version === module.version,\n ) === index,\n );\n}\n\n/**\n * Resolves a document model module by document type, mirroring the registry's\n * semantics (`IDocumentModelRegistry.getModule`): with `version` omitted the\n * LATEST version of the type wins (`version ?? 1` as each module's default),\n * with `version` given only an exact match is returned. The reactor resolves\n * modules the same way when a document is created, so metadata read through\n * this hook and the version a creation actually uses cannot disagree.\n */\nexport function useDocumentModelModuleById(\n id: string | null | undefined,\n version?: number,\n): DocumentModelModule | undefined {\n const documentModelModules = useDocumentModelModules();\n if (!id || !documentModelModules) return undefined;\n\n let latestModule: DocumentModelModule | undefined;\n let latestVersion = -1;\n for (const module of documentModelModules) {\n if (module.documentModel.global.id !== id) continue;\n const moduleVersion = module.version ?? 1;\n if (version !== undefined) {\n if (moduleVersion === version) return module;\n continue;\n }\n if (moduleVersion > latestVersion) {\n latestVersion = moduleVersion;\n latestModule = module;\n }\n }\n return latestModule;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"document-model-modules-bTP87nyr.js","names":[],"sources":["../src/graphql-client/auth.ts","../src/errors.ts","../src/utils/url.ts","../src/hooks/drives.ts","../src/hooks/set-selected-node.ts","../src/hooks/selected-drive.ts","../src/utils/nodes.ts","../src/hooks/items-in-selected-drive.ts","../src/hooks/selected-node.ts","../src/hooks/vetra-packages.ts","../src/hooks/document-model-modules.ts"],"sourcesContent":["import type { SdkFunctionWrapper } from \"../graphql/gen/schema.js\";\n\n/**\n * Resolves the bearer token to send with a request.\n *\n * Returning `undefined` (or an empty string) means \"send this request\n * anonymously\": open Switchboards must keep serving reads to logged-out users.\n */\nexport type BearerTokenProvider = () => Promise<string | undefined>;\n\n/** Lifetime requested for an ambient Renown token, in seconds. */\nconst ambientTokenExpiresInSeconds = 600;\n\n/**\n * The default token provider: the token of the currently logged-in Renown user.\n *\n * It is deliberately resolved from `window.ph` on every call rather than\n * captured at construction time, so a client built before login starts sending\n * the token as soon as there is one.\n *\n * The token is requested WITHOUT an `aud` claim - the Switchboard verifier\n * rejects tokens that carry an audience.\n */\nexport async function ambientRenownTokenProvider(): Promise<\n string | undefined\n> {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n const renown = window.ph?.renown;\n if (!renown?.user) {\n return undefined;\n }\n\n return renown.getBearerToken({ expiresIn: ambientTokenExpiresInSeconds });\n}\n\n/**\n * Builds the SDK middleware that authenticates every request.\n *\n * The token is resolved per request and never cached, so a login, a logout or\n * an expiry between two calls is picked up by the next one. When no token is\n * available the request goes out unauthenticated.\n */\nexport function makeAuthMiddleware(\n tokenProvider: BearerTokenProvider,\n): SdkFunctionWrapper {\n return async (action) => {\n const token = await tokenProvider();\n if (!token) {\n return action();\n }\n\n return action({ authorization: `Bearer ${token}` });\n };\n}\n","export class UnsupportedDocumentTypeError extends Error {\n constructor(documentType: string) {\n super(`Document type ${documentType} is not supported`);\n this.name = \"UnsupportedDocumentTypeError\";\n }\n\n static isError(error: unknown): error is UnsupportedDocumentTypeError {\n return (\n Error.isError(error) && error.name === \"UnsupportedDocumentTypeError\"\n );\n }\n}\n\nexport class DocumentModelNotFoundError extends Error {\n readonly documentType: string;\n readonly name = \"DocumentModelNotFoundError\";\n\n constructor(documentType: string) {\n super(`Document model module for type ${documentType} not found`);\n this.documentType = documentType;\n }\n\n static isError(error: unknown): error is DocumentModelNotFoundError {\n return Error.isError(error) && error.name === \"DocumentModelNotFoundError\";\n }\n}\n\nexport class DocumentTypeMismatchError extends Error {\n constructor(documentId: string, expectedType: string, actualType: string) {\n super(\n `Document ${documentId} is not of type ${expectedType}. Actual type: ${actualType}`,\n );\n }\n}\n\nexport class NoSelectedDocumentError extends Error {\n constructor() {\n super(\n \"There is no selected document. Did you mean to call 'useSelectedDocumentSafe' instead?\",\n );\n }\n}\n","import type {\n DocumentDriveDocument,\n Node,\n} from \"@powerhousedao/shared/document-drive\";\nimport slug from \"slug\";\n\n// Returns url with base path plus provided path\nexport function resolveUrlPathname(path: string) {\n return new URL(\n path.replace(/^\\/+/, \"\"),\n window.location.origin + (window.ph?.basePath ?? \"/\"),\n ).pathname;\n}\n\n/** Returns the current path without the base path */\nexport function getPathWithoutBase(path: string) {\n const basePath = window.ph?.basePath ?? \"/\";\n return path.replace(basePath, basePath.endsWith(\"/\") ? \"/\" : \"\");\n}\n\n/** Makes a URL component for a drive. */\nexport function makeDriveUrlComponent(\n drive: DocumentDriveDocument | undefined,\n) {\n if (!drive) return \"\";\n return `/d/${slug(drive.header.slug)}`;\n}\n\n/** Makes a URL component for a node. */\nexport function makeNodeSlug(node: Node | undefined) {\n if (!node) return \"\";\n const nodeName = node.name;\n if (!nodeName) return slug(node.id);\n return slug(`${nodeName}-${node.id}`);\n}\n\n/** Extracts the node slug from a path.\n *\n * The path is expected to be in the format `/d/<drive-slug>/<node-slug>`.\n */\nexport function extractNodeSlugFromPath(path: string) {\n const currentPath = getPathWithoutBase(path);\n const match = /^\\/d\\/[^/]+\\/([^/]+)$/.exec(currentPath);\n return match?.[1];\n}\n\n/** Finds a UUID in a string, used for extracting node ids from node slugs in the URL. */\nexport function findUuid(input: string | undefined) {\n if (!input) return undefined;\n const uuidRegex =\n /\\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\\b/;\n const match = uuidRegex.exec(input);\n return match?.[0];\n}\n\nexport function extractNodeIdFromSlug(nodeSlug: string | undefined) {\n const nodeId = findUuid(nodeSlug);\n return nodeId;\n}\n\nexport function extractNodeIdFromPath(path: string) {\n const nodeSlug = extractNodeSlugFromPath(path);\n const nodeId = extractNodeIdFromSlug(nodeSlug);\n return nodeId;\n}\n\n/** Extracts the drive slug from a path.\n * Used for extracting drive ids from drive slugs in the URL.\n * Expects the path to be in the format `/d/<drive-slug>`.\n */\nexport function extractDriveSlugFromPath(path: string) {\n const currentPath = getPathWithoutBase(path);\n const match = /^\\/d\\/([^/]+)/.exec(currentPath);\n return match?.[1] ?? \"\";\n}\n\nexport function extractDriveIdFromSlug(driveSlug: string | undefined) {\n const driveId = findUuid(driveSlug);\n return driveId;\n}\n\nexport function extractDriveIdFromPath(path: string) {\n const driveSlug = extractDriveSlugFromPath(path);\n const driveId = extractDriveIdFromSlug(driveSlug);\n return driveId;\n}\n\n/**\n * Creates a URL string with the given pathname while preserving existing query parameters.\n */\nexport function createUrlWithPreservedParams(pathname: string): string {\n const search = window.location.search;\n return search ? `${pathname}${search}` : pathname;\n}\n","import type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport type { SetPHGlobalValue, UsePHGlobalValue } from \"../types/global.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\n\nconst drivesEventFunctions = makePHEventFunctions(\"drives\");\n\n/** Returns all of the drives in the reactor */\nexport const useDrives: UsePHGlobalValue<DocumentDriveDocument[]> =\n drivesEventFunctions.useValue;\n\n/** Sets the drives in the reactor */\nexport const setDrives: SetPHGlobalValue<DocumentDriveDocument[]> =\n drivesEventFunctions.setValue;\n\n/** Adds an event handler for the drives */\nexport const addDrivesEventHandler = drivesEventFunctions.addEventHandler;\n","import type { Node } from \"@powerhousedao/shared/document-drive\";\nimport {\n createUrlWithPreservedParams,\n extractDriveSlugFromPath,\n extractNodeIdFromSlug,\n extractNodeSlugFromPath,\n makeNodeSlug,\n resolveUrlPathname,\n} from \"../utils/url.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\n\nconst selectedNodeIdEventFunctions = makePHEventFunctions(\"selectedNodeId\");\nexport const useSelectedNodeId = selectedNodeIdEventFunctions.useValue;\nconst setSelectedNodeId = selectedNodeIdEventFunctions.setValue;\nexport const addSelectedNodeIdEventHandler =\n selectedNodeIdEventFunctions.addEventHandler;\n\n/** Sets the selected node (file or folder). */\nexport function setSelectedNode(nodeOrNodeSlug: Node | string | undefined) {\n const nodeSlug =\n typeof nodeOrNodeSlug === \"string\"\n ? nodeOrNodeSlug\n : makeNodeSlug(nodeOrNodeSlug);\n const nodeId = extractNodeIdFromSlug(nodeSlug);\n setSelectedNodeId(nodeId);\n const driveSlugFromPath = extractDriveSlugFromPath(window.location.pathname);\n if (!driveSlugFromPath) {\n return;\n }\n if (!nodeSlug) {\n const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}`);\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n return;\n }\n const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}/${nodeSlug}`);\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n}\n\nexport function addResetSelectedNodeEventHandler() {\n window.addEventListener(\"ph:selectedDriveIdUpdated\", () => {\n setSelectedNodeId(undefined);\n });\n}\n\nexport function addSetSelectedNodeOnPopStateEventHandler() {\n window.addEventListener(\"popstate\", () => {\n const pathname = window.location.pathname;\n const nodeSlug = extractNodeSlugFromPath(pathname);\n // The slug embeds the id (`<name>-<uuid>`); compare ids, not slug vs id.\n const nodeId = extractNodeIdFromSlug(nodeSlug);\n const selectedNodeId = window.ph?.selectedNodeId;\n if (nodeId !== selectedNodeId) {\n setSelectedNode(nodeSlug);\n }\n });\n}\n","import type { DocumentDispatch } from \"@powerhousedao/reactor-browser\";\nimport type {\n DocumentDriveAction,\n DocumentDriveDocument,\n} from \"@powerhousedao/shared/document-drive\";\nimport {\n createUrlWithPreservedParams,\n extractDriveIdFromPath,\n extractDriveSlugFromPath,\n extractNodeSlugFromPath,\n resolveUrlPathname,\n} from \"../utils/url.js\";\nimport { useDispatch } from \"./dispatch.js\";\nimport { useDrives } from \"./drives.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\nimport { setSelectedNode } from \"./set-selected-node.js\";\n\nconst selectedDriveIdEventFunctions = makePHEventFunctions(\"selectedDriveId\");\n\n/** Returns the selected drive id */\nexport const useSelectedDriveId = selectedDriveIdEventFunctions.useValue;\n\n/** Sets the selected drive id */\nexport const setSelectedDriveId = selectedDriveIdEventFunctions.setValue;\n\n/** Adds an event handler for the selected drive id */\nexport const addSelectedDriveIdEventHandler =\n selectedDriveIdEventFunctions.addEventHandler;\n\n/** Returns the selected drive */\nexport function useSelectedDrive() {\n const drive = useSelectedDriveSafe();\n if (!drive[0]) {\n throw new Error(\n \"There is no drive selected. Did you mean to call 'useSelectedDriveSafe'?\",\n );\n }\n\n return drive;\n}\n\n/** Returns the selected drive, or undefined if no drive is selected */\nexport function useSelectedDriveSafe() {\n const selectedDriveId = useSelectedDriveId();\n const drives = useDrives();\n const selectedDrive = drives?.find(\n (drive) => drive.header.id === selectedDriveId,\n );\n\n const [drive, dispatch] = useDispatch(selectedDrive);\n if (!selectedDrive) {\n return [undefined, undefined] as const;\n }\n return [drive, dispatch] as [\n DocumentDriveDocument,\n DocumentDispatch<DocumentDriveAction>,\n ];\n}\n\nexport function setSelectedDrive(\n driveOrDriveSlug: string | DocumentDriveDocument | undefined,\n) {\n const driveSlug =\n typeof driveOrDriveSlug === \"string\"\n ? driveOrDriveSlug\n : driveOrDriveSlug?.header.slug;\n\n // A full drive document is selected directly — a just-created drive\n // navigates before the collection refresh. Slugs go through the lookup.\n const drives = window.ph?.drives;\n const drive =\n typeof driveOrDriveSlug === \"object\" && driveOrDriveSlug !== null\n ? driveOrDriveSlug\n : drives?.find((d) => d.header.slug === driveSlug);\n const driveId = drive?.header.id;\n\n // A URL-pinned slug with no matching drive: the deep link may predate\n // remote drive registration, so defer instead of rewriting the URL.\n if (\n !driveId &&\n driveSlug &&\n extractDriveSlugFromPath(window.location.pathname) === driveSlug\n ) {\n // Clear the previous selection so a stale drive doesn't render against\n // the new URL; the selected node resets with it, the URL is untouched.\n if (window.ph?.selectedDriveId) {\n setSelectedDriveId(undefined);\n }\n deferDriveSelection(driveSlug);\n return;\n }\n\n // Any resolved selection supersedes a pending deferred lookup.\n cancelPendingDriveSelection();\n\n setSelectedDriveId(driveId);\n\n if (!driveId) {\n const pathname = resolveUrlPathname(\"/\");\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n return;\n }\n const pathname = resolveUrlPathname(`/d/${driveSlug}`);\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(null, \"\", createUrlWithPreservedParams(pathname));\n}\n\n// Tick between unresolved-slug checks; re-armed while a sync is in flight.\nconst DEFERRED_DRIVE_TICK_MS = 2_000;\n// Hard cap so a wedged remote can't pin the deep link forever.\nconst DEFERRED_DRIVE_MAX_WAIT_MS = 15_000;\n\n// True while any sync remote has not completed its first successful pull —\n// a drive may still be on its way in, so the deferred lookup keeps waiting.\nfunction isInitialSyncInFlight(): boolean {\n const remotes =\n window.ph?.reactorClientModule?.reactorModule?.syncModule?.syncManager?.list();\n if (!remotes?.length) {\n return false;\n }\n return remotes.some((remote) => {\n try {\n const snapshot = remote.channel.getConnectionState();\n return (\n snapshot.receivingPages ||\n (!snapshot.lastSuccessUtcMs && snapshot.state !== \"error\")\n );\n } catch {\n return false;\n }\n });\n}\n\nlet pendingHandler: (() => void) | undefined;\nlet pendingTimeout: ReturnType<typeof setTimeout> | undefined;\n\nfunction cancelPendingDriveSelection() {\n if (pendingHandler) {\n window.removeEventListener(\"ph:drivesUpdated\", pendingHandler);\n pendingHandler = undefined;\n }\n if (pendingTimeout) {\n clearTimeout(pendingTimeout);\n pendingTimeout = undefined;\n }\n}\n\n// Re-runs the slug lookup on each drives update until it resolves, then\n// restores the URL-pinned node. Unresolved slugs redirect once syncs settle.\nfunction deferDriveSelection(driveSlug: string) {\n cancelPendingDriveSelection();\n\n // Capture the node pinned in the deep link before setSelectedDrive\n // rewrites the URL to /d/<driveSlug>, dropping the node segment.\n const nodeSlug = extractNodeSlugFromPath(window.location.pathname);\n const handler = () => {\n const drive = window.ph?.drives?.find((d) => d.header.slug === driveSlug);\n if (!drive) {\n return;\n }\n cancelPendingDriveSelection();\n setSelectedDrive(driveSlug);\n setSelectedNode(nodeSlug);\n };\n pendingHandler = handler;\n window.addEventListener(\"ph:drivesUpdated\", handler);\n\n const deadline = Date.now() + DEFERRED_DRIVE_MAX_WAIT_MS;\n const scheduleTick = () => {\n pendingTimeout = setTimeout(() => {\n if (Date.now() < deadline && isInitialSyncInFlight()) {\n scheduleTick();\n return;\n }\n cancelPendingDriveSelection();\n const pathname = resolveUrlPathname(\"/\");\n if (pathname === window.location.pathname) {\n return;\n }\n window.history.pushState(\n null,\n \"\",\n createUrlWithPreservedParams(pathname),\n );\n }, DEFERRED_DRIVE_TICK_MS);\n };\n scheduleTick();\n}\n\nexport function addSetSelectedDriveOnPopStateEventHandler() {\n window.addEventListener(\"popstate\", () => {\n const pathname = window.location.pathname;\n const driveId = extractDriveIdFromPath(pathname);\n const selectedDriveId = window.ph?.selectedDriveId;\n if (driveId !== selectedDriveId) {\n setSelectedDrive(driveId);\n }\n });\n}\n","import type {\n FileNode,\n FolderNode,\n Node,\n} from \"@powerhousedao/shared/document-drive\";\n\n/** Sorts nodes by name. */\nexport function sortNodesByName<T extends Node>(nodes: T[]) {\n return nodes.toSorted((a, b) => a.name.localeCompare(b.name));\n}\n\n/** Returns whether a node is a file. */\nexport function isFileNodeKind(\n node: Node | null | undefined,\n): node is FileNode {\n if (!node) return false;\n return node.kind.toUpperCase() === \"FILE\";\n}\n\n/** Returns whether a node is a folder. */\nexport function isFolderNodeKind(\n node: Node | null | undefined,\n): node is FolderNode {\n if (!node) return false;\n return node.kind.toUpperCase() === \"FOLDER\";\n}\n","import type {\n FileNode,\n FolderNode,\n} from \"@powerhousedao/shared/document-drive\";\nimport type {\n DocumentModelDocument,\n PHDocument,\n} from \"@powerhousedao/shared/document-model\";\nimport { isFileNodeKind, isFolderNodeKind } from \"../utils/nodes.js\";\nimport { useDocumentsByIds } from \"./document-by-id.js\";\nimport { useSelectedDriveSafe } from \"./selected-drive.js\";\n\n/** Returns the nodes in the selected drive. */\nexport function useNodesInSelectedDrive() {\n const [selectedDrive] = useSelectedDriveSafe();\n return selectedDrive?.state.global.nodes;\n}\n\n/** Returns the file nodes in the selected drive. */\nexport function useFileNodesInSelectedDrive(): FileNode[] | undefined {\n const nodes = useNodesInSelectedDrive();\n return nodes?.filter((n) => isFileNodeKind(n));\n}\n\n/** Returns the folder nodes in the selected drive. */\nexport function useFolderNodesInSelectedDrive(): FolderNode[] | undefined {\n const nodes = useNodesInSelectedDrive();\n return nodes?.filter((n) => isFolderNodeKind(n));\n}\n\n/** Returns the documents in the selected drive. */\nexport function useDocumentsInSelectedDrive(): PHDocument[] | undefined {\n const fileNodes = useFileNodesInSelectedDrive();\n const fileNodeIds = fileNodes?.map((node) => node.id);\n return useDocumentsByIds(fileNodeIds);\n}\n\n/** Returns the document types supported by the selected drive, as defined by the document model documents present in the drive */\nexport function useDocumentTypesInSelectedDrive() {\n const documentsInSelectedDrive = useDocumentsInSelectedDrive();\n const documentModelDocumentsInSelectedDrive =\n documentsInSelectedDrive?.filter(isDocumentModelDocument);\n const documentTypesFromDocumentModelDocuments =\n documentModelDocumentsInSelectedDrive?.map((doc) => doc.state.global.id);\n return documentTypesFromDocumentModelDocuments;\n}\n\nfunction isDocumentModelDocument(\n document: PHDocument,\n): document is DocumentModelDocument {\n return document.header.documentType === \"powerhouse/document-model\";\n}\n","import type { Node } from \"@powerhousedao/shared/document-drive\";\nimport { useNodesInSelectedDrive } from \"./items-in-selected-drive.js\";\nimport { useSelectedNodeId } from \"./set-selected-node.js\";\n\nexport {\n addResetSelectedNodeEventHandler,\n addSelectedNodeIdEventHandler,\n addSetSelectedNodeOnPopStateEventHandler,\n setSelectedNode,\n} from \"./set-selected-node.js\";\n\n/** Returns the selected node. */\nexport function useSelectedNode(): Node | undefined {\n const selectedNodeId = useSelectedNodeId();\n const nodes = useNodesInSelectedDrive();\n return nodes?.find((n) => n.id === selectedNodeId);\n}\n","import type { DocumentModelLib } from \"document-model\";\nimport { useSyncExternalStore } from \"react\";\nimport {\n isDuplicateManifestError,\n isDuplicateModuleError,\n} from \"../reactor-interop.js\";\nimport type { IPackageManager } from \"../types/vetra.js\";\nimport { makePHEventFunctions } from \"./make-ph-event-functions.js\";\n\nconst vetraPackageManagerFunctions = makePHEventFunctions(\n \"vetraPackageManager\",\n);\n\nexport const useVetraPackageManager = vetraPackageManagerFunctions.useValue;\n\nconst EMPTY_VETRA_PACKAGES: DocumentModelLib[] = [];\nconst noPackageManagerUnsubscribe = () => {};\n\n/**\n * Returns all of the Vetra packages loaded by the Connect instance.\n *\n * The snapshot and subscription must keep stable identity while no package\n * manager is registered: `useSyncExternalStore` loops when the snapshot\n * changes on every read, which a fresh `[]` does.\n */\nexport const useVetraPackages = () => {\n const packageManager = useVetraPackageManager();\n\n return useSyncExternalStore(\n (cb) =>\n packageManager\n ? packageManager.subscribe(cb)\n : noPackageManagerUnsubscribe,\n () => packageManager?.packages ?? EMPTY_VETRA_PACKAGES,\n );\n};\n\n/** Adds the Vetra package manager event handler */\nexport const addVetraPackageManagerEventHandler =\n vetraPackageManagerFunctions.addEventHandler;\n\n/** Sets the Vetra package manager and registers its packages */\nexport function setVetraPackageManager(packageManager: IPackageManager) {\n vetraPackageManagerFunctions.setValue(packageManager);\n updateReactorClientDocumentModels(packageManager.packages);\n updateReactorClientUpgradeManifests(packageManager.packages);\n packageManager.subscribe(({ packages }) => {\n updateReactorClientDocumentModels(packages);\n updateReactorClientUpgradeManifests(packages);\n });\n}\n\nfunction updateReactorClientDocumentModels(packages: DocumentModelLib[]) {\n const documentModelModules = packages\n .flatMap((pkg) => pkg.documentModels)\n .filter(\n (module, index, modules) =>\n // dedupe by documentType and version\n modules.findIndex(\n (m) =>\n m.documentModel.global.id === module.documentModel.global.id &&\n (m.version ?? 1) === (module.version ?? 1),\n ) === index,\n );\n\n const registry =\n window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;\n if (!registry || documentModelModules.length === 0) return;\n\n const results = registry.registerModules(...documentModelModules);\n const duplicateTypes = new Set<string>();\n for (const result of results) {\n if (result.status === \"error\") {\n if (isDuplicateModuleError(result.error)) {\n duplicateTypes.add(result.item.documentModel.global.id);\n } else {\n console.error(\n \"Failed to register document model module:\",\n result.error,\n );\n }\n }\n }\n if (duplicateTypes.size > 0) {\n // unregisterModules is type-scoped, so replace the whole version family\n // with the incoming package's modules: re-registering only the duplicated\n // items would purge any new version that registered successfully above.\n registry.unregisterModules(...duplicateTypes);\n registry.registerModules(\n ...documentModelModules.filter((module) =>\n duplicateTypes.has(module.documentModel.global.id),\n ),\n );\n }\n}\n\nfunction updateReactorClientUpgradeManifests(packages: DocumentModelLib[]) {\n const upgradeManifests = packages\n .flatMap((pkg) => pkg.upgradeManifests)\n .filter((u) => u !== undefined);\n\n const registry =\n window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;\n if (!registry || upgradeManifests.length === 0) return;\n\n const results = registry.registerUpgradeManifests(...upgradeManifests);\n const duplicates = [];\n for (const result of results) {\n if (result.status === \"error\") {\n if (isDuplicateManifestError(result.error)) {\n duplicates.push(result);\n } else {\n console.error(\"Failed to register upgrade manifest:\", result.error);\n }\n }\n }\n if (duplicates.length > 0) {\n const duplicateTypes = duplicates\n .map((r) => r.item.documentType)\n .filter((t): t is string => !!t);\n registry.unregisterUpgradeManifests(...duplicateTypes);\n registry.registerUpgradeManifests(...duplicates.map((r) => r.item));\n }\n}\n","import type { DocumentModelModule } from \"document-model\";\nimport { useVetraPackages } from \"./vetra-packages.js\";\n\nexport function useDocumentModelModules(): DocumentModelModule[] | undefined {\n const vetraPackages = useVetraPackages();\n return vetraPackages\n .flatMap((pkg) => pkg.documentModels)\n .filter(\n (module, index, modules) =>\n // deduplicate by documentType and version\n modules.findIndex(\n (m) =>\n m.documentModel.global.id === module.documentModel.global.id &&\n m.version === module.version,\n ) === index,\n );\n}\n\n/**\n * Resolves a document model module by document type, mirroring the registry's\n * semantics (`IDocumentModelRegistry.getModule`): with `version` omitted the\n * LATEST version of the type wins (`version ?? 1` as each module's default),\n * with `version` given only an exact match is returned. The reactor resolves\n * modules the same way when a document is created, so metadata read through\n * this hook and the version a creation actually uses cannot disagree.\n */\nexport function useDocumentModelModuleById(\n id: string | null | undefined,\n version?: number,\n): DocumentModelModule | undefined {\n const documentModelModules = useDocumentModelModules();\n if (!id || !documentModelModules) return undefined;\n\n let latestModule: DocumentModelModule | undefined;\n let latestVersion = -1;\n for (const module of documentModelModules) {\n if (module.documentModel.global.id !== id) continue;\n const moduleVersion = module.version ?? 1;\n if (version !== undefined) {\n if (moduleVersion === version) return module;\n continue;\n }\n if (moduleVersion > latestVersion) {\n latestVersion = moduleVersion;\n latestModule = module;\n }\n }\n return latestModule;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { S as uploadOperations, a as setDocumentCache, b as queueActions, g as DOCUMENT_CHANGE_TYPE, i as addDocumentCacheEventHandler, p as DocumentCache, x as queueOperations } from "./document-by-id-BSZqTN66.js";
2
- import { C as addResetSelectedNodeEventHandler, D as addDrivesEventHandler, H as ambientRenownTokenProvider, T as addSetSelectedNodeOnPopStateEventHandler, U as makeAuthMiddleware, W as DocumentModelNotFoundError, _ as addSetSelectedDriveOnPopStateEventHandler, g as addSelectedDriveIdEventHandler, i as setVetraPackageManager, q as UnsupportedDocumentTypeError, r as addVetraPackageManagerEventHandler, w as addSelectedNodeIdEventHandler, x as useSelectedDriveId } from "./document-model-modules-DfQBNGc-.js";
1
+ import { S as uploadOperations, a as setDocumentCache, b as queueActions, g as DOCUMENT_CHANGE_TYPE, i as addDocumentCacheEventHandler, p as DocumentCache, x as queueOperations } from "./document-by-id-B4FIzG1w.js";
2
+ import { C as addResetSelectedNodeEventHandler, D as addDrivesEventHandler, G as UnsupportedDocumentTypeError, H as DocumentModelNotFoundError, K as ambientRenownTokenProvider, T as addSetSelectedNodeOnPopStateEventHandler, _ as addSetSelectedDriveOnPopStateEventHandler, g as addSelectedDriveIdEventHandler, i as setVetraPackageManager, q as makeAuthMiddleware, r as addVetraPackageManagerEventHandler, w as addSelectedNodeIdEventHandler, x as useSelectedDriveId } from "./document-model-modules-bTP87nyr.js";
3
3
  import { t as makePHEventFunctions } from "./make-ph-event-functions-DBq3iWYn.js";
4
4
  import { a as PhDocumentFieldsFragmentDoc, n as DocumentChangeType, o as PropagationMode, r as DocumentChangesDocument, t as createClient$1 } from "./client-D66jVnot.js";
5
5
  import { f as addLoadingEventHandler, t as addRenownEventHandler } from "./renown-BHxwP7xU.js";
@@ -1285,6 +1285,30 @@ var SubgraphSdkRegistry = class {
1285
1285
  //#endregion
1286
1286
  //#region src/graphql-client/subscriptions.ts
1287
1287
  /**
1288
+ * The 4403 close reasons a Switchboard refuses a handshake with.
1289
+ *
1290
+ * Mirrors `WS_AUTH_CLOSE_REASONS` in `@powerhousedao/reactor-api`
1291
+ * (`src/graphql/gateway/types.ts`). This package does not depend on that one,
1292
+ * so the strings are duplicated and are a wire contract: change them on both
1293
+ * sides or not at all.
1294
+ */
1295
+ const authCloseReasons = ["authentication-required", "bearer-rejected"];
1296
+ /** graphql-ws's own `isLikeCloseEvent`, which it does not export. */
1297
+ function isLikeCloseEvent(value) {
1298
+ return typeof value === "object" && value !== null && "code" in value && "reason" in value;
1299
+ }
1300
+ /**
1301
+ * Whether a socket failure is the Switchboard refusing the credentials sent.
1302
+ *
1303
+ * Keyed on the close reason, not the code: both refusals close 4403, because
1304
+ * `connectionParams` is resolved per connect and a reconnect carrying a fresh
1305
+ * token genuinely succeeds. What the reason adds is that *this* attempt cannot
1306
+ * be fixed by repeating it.
1307
+ */
1308
+ function isAuthRefusalClose(error) {
1309
+ return isLikeCloseEvent(error) && authCloseReasons.includes(error.reason);
1310
+ }
1311
+ /**
1288
1312
  * Opens one `documentChanges` subscription and feeds every event to `onEvent`.
1289
1313
  *
1290
1314
  * The subscription is a firehose: no `search` argument, so the server sends
@@ -1297,7 +1321,8 @@ var SubgraphSdkRegistry = class {
1297
1321
  function startDocumentChangesSubscription(options) {
1298
1322
  const client = createClient({
1299
1323
  url: options.wsUrl,
1300
- connectionParams: options.connectionParams
1324
+ connectionParams: options.connectionParams,
1325
+ shouldRetry: (errOrCloseEvent) => isLikeCloseEvent(errOrCloseEvent) && !isAuthRefusalClose(errOrCloseEvent)
1301
1326
  });
1302
1327
  const unsubscribe = client.subscribe({
1303
1328
  operationName: "DocumentChanges",
@@ -1380,6 +1405,8 @@ var GraphQLReactorClient = class {
1380
1405
  realtimeStarted = false;
1381
1406
  realtimeGeneration = 0;
1382
1407
  realtimeErrorLogged = false;
1408
+ /** Whether the last socket died because the Switchboard refused its credentials. */
1409
+ realtimeRefusedCredentials = false;
1383
1410
  constructor(options) {
1384
1411
  this.tokenProvider = options.tokenProvider ?? ambientRenownTokenProvider;
1385
1412
  this.documentModels = [...options.documentModels ?? []];
@@ -1612,10 +1639,13 @@ var GraphQLReactorClient = class {
1612
1639
  * Gives up on a failed socket so that a later subscriber can try again.
1613
1640
  *
1614
1641
  * `graphql-ws` retries on its own and only reports here once it has given up,
1615
- * or once the server refused the subscription outright - which is what an
1616
- * auth-enabled Switchboard does to an anonymous subscriber. Keeping the dead
1617
- * stop function would make every later `subscribe` a no-op, so realtime would
1618
- * stay off for the life of the page even after the user signs in.
1642
+ * or once the Switchboard refused the credentials the socket carried - which
1643
+ * `shouldRetry` declines to retry at all. Keeping the dead stop function
1644
+ * would make every later `subscribe` a no-op, so realtime would stay off for
1645
+ * the life of the page even after the user signs in.
1646
+ *
1647
+ * Why it died is recorded: a refusal is undone by a credential change and
1648
+ * nothing else, and {@link notifyCredentialsChanged} acts only on that.
1619
1649
  *
1620
1650
  * The generation stamp discards a report from a socket that has already been
1621
1651
  * replaced or disposed.
@@ -1623,12 +1653,40 @@ var GraphQLReactorClient = class {
1623
1653
  handleRealtimeFailure(generation, error) {
1624
1654
  if (generation !== this.realtimeGeneration) return;
1625
1655
  this.teardownRealtime();
1656
+ this.realtimeRefusedCredentials = isAuthRefusalClose(error);
1626
1657
  this.logRealtimeError(error);
1627
1658
  }
1659
+ /**
1660
+ * Reopens realtime after a sign-in, a sign-out or a token swap.
1661
+ *
1662
+ * Call it whenever the credentials this client authenticates with change.
1663
+ *
1664
+ * A live socket is replaced. `connectionParams` are resolved once, when the
1665
+ * socket opens, so a socket keeps presenting the credentials it was opened
1666
+ * with until something closes it - and a sign-out closes nothing. That left
1667
+ * a signed-out tab still receiving the previous identity's document changes,
1668
+ * on a shared machine, for as long as the socket happened to survive.
1669
+ *
1670
+ * A refused socket is reopened, for the same reason from the other side:
1671
+ * otherwise it stays closed until an unrelated component happens to
1672
+ * `subscribe`, so signing in leaves realtime off with nothing said - the
1673
+ * state `handleRealtimeFailure` resets to avoid.
1674
+ *
1675
+ * A socket that died for any other reason is left alone: a network failure
1676
+ * is not something a new token fixes, and reopening one here would turn a
1677
+ * credential change into a reconnect loop.
1678
+ */
1679
+ notifyCredentialsChanged() {
1680
+ if (!this.realtimeStarted && !this.realtimeRefusedCredentials) return;
1681
+ this.teardownRealtime();
1682
+ if (this.listeners.length === 0) return;
1683
+ this.startRealtime();
1684
+ }
1628
1685
  /** Closes the socket and lets a later subscriber open a new one. */
1629
1686
  teardownRealtime() {
1630
1687
  this.realtimeGeneration += 1;
1631
1688
  this.realtimeStarted = false;
1689
+ this.realtimeRefusedCredentials = false;
1632
1690
  this.stopRealtime?.();
1633
1691
  this.stopRealtime = void 0;
1634
1692
  }
@@ -2540,6 +2598,6 @@ function useDocumentOperations(documentId) {
2540
2598
  };
2541
2599
  }
2542
2600
  //#endregion
2543
- export { addDefaultDrivesUrlEventHandler as $, useIsAddLocalDrivesEnabled as $n, makeAuthConnectionParams as $r, setEnabledEditors as $t, useReactorClientModule as A, getDocumentExtension as Ai, setRenownUrl as An, useSentryRelease as Ar, addRenownAdaptersEventHandler as At, useDragNode as B, closePHModal as Bi, setWarnOutdatedApp as Bn, phAppConfigHooks as Br, addSwitchboardUrlEventHandler as Bt, addReactorClientModuleEventHandler as C, addFileWithProgress as Ci, setIsRelationalProcessorsEnabled as Cn, useRenownChainId as Cr, addIsExternalRelationalProcessorsEnabledEventHandler as Ct, useModelRegistry as D, exportFile as Di, setRenownAdapters as Dn, useRouterBasename as Dr, addIsSentryTracingEnabledEventHandler as Dt, useDatabase as E, deleteNode as Ei, setLogLevel as En, useRequiresHardRefresh as Er, addIsRelationalProcessorsEnabledEventHandler as Et, usePackageDiscoveryService as F, setPreferredEditorOnNode as Fi, setSentryRelease as Fn, useWarnOutdatedApp as Fr, addRouterBasenameEventHandler as Ft, useFeatures as G, usePHModal as Gi, useDefaultDrivesUrl as Gn, setIsDragAndDropEnabled as Gr, phGlobalConfigSetters as Gt, useDropTarget as H, showCreateDocumentModal as Hi, useAnalyticsDatabaseName as Hn, phDocumentEditorConfigHooks as Hr, addVersionEventHandler as Ht, addGraphQLReactorClientEventHandler as I, upgradeDocument as Ii, setStudioMode as In, addAllowedDocumentTypesEventHandler as Ir, addSentryDsnEventHandler as It, useAttachmentService as J, useEnabledEditors as Jn, useIsDragAndDropEnabled as Jr, setBasePath as Jt, addAttachmentServiceEventHandler as K, useDisabledEditors as Kn, setIsExternalControlsEnabled as Kr, setAllowList as Kt, setGraphQLReactorClient as L, getUserPermissions as Li, setSwitchboardUrl as Ln, addIsDragAndDropEnabledEventHandler as Lr, addSentryEnvEventHandler as Lt, useSyncList as M, moveNode$1 as Mi, setRouterBasename as Mn, useSwitchboardUrl as Mr, addRenownNetworkIdEventHandler as Mt, addPackageDiscoveryServiceEventHandler as N, renameDriveNode as Ni, setSentryDsn as Nn, useVersion as Nr, addRenownUrlEventHandler as Nt, usePGlite as O, extractInitialState as Oi, setRenownChainId as On, useSentryDsn as Or, addLocalDrivesEnabledEventHandler as Ot, setPackageDiscoveryService as P, renameNode as Pi, setSentryEnv as Pn, useVersionCheckInterval as Pr, addRequiresHardRefreshEventHandler as Pt, addCliVersionEventHandler as Q, useIsAddDriveEnabled as Qn, viewFilterInputFromViewFilter as Qr, setDrivesPreserveStrategy as Qt, useGraphQLReactorClient as R, isDocumentTypeSupported as Ri, setVersion as Rn, addIsExternalControlsEnabledEventHandler as Rr, addSentryReleaseEventHandler as Rt, addReactorClientEventHandler as S, addDocument as Si, setIsPublicDrivesEnabled as Sn, useRenownAdapters as Sr, addIsExternalProcessorsEnabledEventHandler as St, setReactorClientModule as T, copyNode$1 as Ti, setLocalDrivesEnabled as Tn, useRenownUrl as Tr, addIsPublicDrivesEnabledEventHandler as Tt, addFeaturesEventHandler as U, showDeleteNodeModal as Ui, useBasePath as Un, phDocumentEditorConfigSetters as Ur, addWarnOutdatedAppEventHandler as Ut, useDropNode as V, setPHModal as Vi, useAllowList as Vn, phAppConfigSetters as Vr, addVersionCheckIntervalEventHandler as Vt, setFeatures as W, showPHModal as Wi, useCliVersion as Wn, setAllowedDocumentTypes as Wr, phGlobalConfigHooks as Wt, addAnalyticsDatabaseNameEventHandler as X, useGaTrackingId as Xn, GraphQLReactorClient as Xr, setDefaultDrivesUrl as Xt, addAllowListEventHandler as Y, useFileUploadOperationsChunkSize as Yn, useIsExternalControlsEnabled as Yr, setCliVersion as Yt, addBasePathEventHandler as Z, useIsAddCloudDrivesEnabled as Zn, isGraphQLReactorClient as Zr, setDisabledEditors as Zt, addRevisionHistoryVisibleEventHandler as _, buildPulledDocument as _i, setIsEditorReadModeEnabled as _n, useIsPublicDrivesEnabled as _r, addIsDocumentModelSelectionSettingsEnabledEventHandler as _t, addPHEventHandlers as a, StaticPackageManager as ai, setIsAddPublicDrivesEnabled as an, useIsDeleteCloudDrivesEnabled as ar, addIsAddCloudDrivesEnabledEventHandler as at, showRevisionHistory as b, hasRevisionConflict as bi, setIsExternalRelationalProcessorsEnabled as bn, useLocalDrivesEnabled as br, addIsEditorReadModeEnabledEventHandler as bt, addToastEventHandler as c, prepareSignedActions as ci, setIsAnalyticsExternalProcessorsEnabled as cn, useIsDiffAnalyticsEnabled as cr, addIsAddPublicDrivesEnabledEventHandler as ct, addSelectedTimelineRevisionEventHandler as d, MutateDocumentWithOperationsDocument as di, setIsDeleteLocalDrivesEnabled as dn, useIsEditorDebugModeEnabled as dr, addIsAnalyticsExternalProcessorsEnabledEventHandler as dt, startDocumentChangesSubscription as ei, setFileUploadOperationsChunkSize as en, useIsAddPublicDrivesEnabled as er, addDisabledEditorsEventHandler as et, setSelectedTimelineRevision as f, ReactorOperationFieldsFragmentDoc as fi, setIsDeletePublicDrivesEnabled as fn, useIsEditorReadModeEnabled as fr, addIsCloudDrivesEnabledEventHandler as ft, useSelectedTimelineItem as g, ConflictError as gi, setIsEditorDebugModeEnabled as gn, useIsLocalDrivesEnabled as gr, addIsDiffAnalyticsEnabledEventHandler as gt, setSelectedTimelineItem as h, revisionMapFromRevisionsList as hi, setIsDriveAnalyticsEnabled as hn, useIsExternalRelationalProcessorsEnabled as hr, addIsDeletePublicDrivesEnabledEventHandler as ht, useSwitchboardClient as i, subgraphUrlFromGraphqlUrl as ii, setIsAddLocalDrivesEnabled as in, useIsCloudDrivesEnabled as ir, addGaTrackingIdEventHandler as it, useSync as j, loadFile as ji, setRequiresHardRefresh as jn, useStudioMode as jr, addRenownChainIdEventHandler as jt, useReactorClient as k, fetchDocumentOperations as ki, setRenownNetworkId as kn, useSentryEnv as kr, addLogLevelEventHandler as kt, setPHToast as l, signStampedAction as li, setIsCloudDrivesEnabled as ln, useIsDocumentModelSelectionSettingsEnabled as lr, addIsAnalyticsDatabaseWorkerEnabledEventHandler as lt, addSelectedTimelineItemEventHandler as m, phDocumentFromMutation as mi, setIsDocumentModelSelectionSettingsEnabled as mn, useIsExternalProcessorsEnabled as mr, addIsDeleteLocalDrivesEnabledEventHandler as mt, GraphQLReactorProvider as n, SubgraphSdkRegistry as ni, setIsAddCloudDrivesEnabled as nn, useIsAnalyticsEnabled as nr, addEnabledEditorsEventHandler as nt, callEventHandlerRegisterFunctions as o, packageFromDocumentModels as oi, setIsAnalyticsDatabaseWorkerEnabled as on, useIsDeleteLocalDrivesEnabled as or, addIsAddDriveEnabledEventHandler as ot, useSelectedTimelineRevision as p, phDocumentFromGetDocument as pi, setIsDiffAnalyticsEnabled as pn, useIsExternalPackagesEnabled as pr, addIsDeleteCloudDrivesEnabledEventHandler as pt, setAttachmentService as q, useDrivesPreserveStrategy as qn, useAllowedDocumentTypes as qr, setAnalyticsDatabaseName as qt, ensurePHEventHandlers as r, describeGraphQLDocument as ri, setIsAddDriveEnabled as rn, useIsAnalyticsExternalProcessorsEnabled as rr, addFileUploadOperationsChunkSizeEventHandler as rt, commonGlobalEventHandlerFunctions as s, resolveDocumentModelModule as si, setIsAnalyticsEnabled as sn, useIsDeletePublicDrivesEnabled as sr, addIsAddLocalDrivesEnabledEventHandler as st, useDocumentOperations as t, subscriptionsUrlFromGraphqlUrl as ti, setGaTrackingId as tn, useIsAnalyticsDatabaseWorkerEnabled as tr, addDrivesPreserveStrategyEventHandler as tt, usePHToast as u, stampAction as ui, setIsDeleteCloudDrivesEnabled as un, useIsDriveAnalyticsEnabled as ur, addIsAnalyticsEnabledEventHandler as ut, hideRevisionHistory as v, convertRemoteOperations as vi, setIsExternalPackagesEnabled as vn, useIsRelationalProcessorsEnabled as vr, addIsDriveAnalyticsEnabledEventHandler as vt, setReactorClient as w, addFolder$1 as wi, setIsSentryTracingEnabled as wn, useRenownNetworkId as wr, addIsLocalDrivesEnabledEventHandler as wt, useRevisionHistoryVisible as x, screamingSnakeToCamel as xi, setIsLocalDrivesEnabled as xn, useLogLevel as xr, addIsExternalPackagesEnabledEventHandler as xt, setRevisionHistoryVisible as y, extractRevisionMap as yi, setIsExternalProcessorsEnabled as yn, useIsSentryTracingEnabled as yr, addIsEditorDebugModeEnabledEventHandler as yt, addDraggingNodeEventHandler as z, addModalEventHandler as zi, setVersionCheckInterval as zn, isExternalControlsEnabledEventFunctions as zr, addStudioModeEventHandler as zt };
2601
+ export { addDefaultDrivesUrlEventHandler as $, useIsAddLocalDrivesEnabled as $n, isAuthRefusalClose as $r, setEnabledEditors as $t, useReactorClientModule as A, fetchDocumentOperations as Ai, setRenownUrl as An, useSentryRelease as Ar, addRenownAdaptersEventHandler as At, useDragNode as B, addModalEventHandler as Bi, setWarnOutdatedApp as Bn, phAppConfigHooks as Br, addSwitchboardUrlEventHandler as Bt, addReactorClientModuleEventHandler as C, addDocument as Ci, setIsRelationalProcessorsEnabled as Cn, useRenownChainId as Cr, addIsExternalRelationalProcessorsEnabledEventHandler as Ct, useModelRegistry as D, deleteNode as Di, setRenownAdapters as Dn, useRouterBasename as Dr, addIsSentryTracingEnabledEventHandler as Dt, useDatabase as E, copyNode$1 as Ei, setLogLevel as En, useRequiresHardRefresh as Er, addIsRelationalProcessorsEnabledEventHandler as Et, usePackageDiscoveryService as F, renameNode as Fi, setSentryRelease as Fn, useWarnOutdatedApp as Fr, addRouterBasenameEventHandler as Ft, useFeatures as G, showPHModal as Gi, useDefaultDrivesUrl as Gn, setIsDragAndDropEnabled as Gr, phGlobalConfigSetters as Gt, useDropTarget as H, setPHModal as Hi, useAnalyticsDatabaseName as Hn, phDocumentEditorConfigHooks as Hr, addVersionEventHandler as Ht, addGraphQLReactorClientEventHandler as I, setPreferredEditorOnNode as Ii, setStudioMode as In, addAllowedDocumentTypesEventHandler as Ir, addSentryDsnEventHandler as It, useAttachmentService as J, useEnabledEditors as Jn, useIsDragAndDropEnabled as Jr, setBasePath as Jt, addAttachmentServiceEventHandler as K, usePHModal as Ki, useDisabledEditors as Kn, setIsExternalControlsEnabled as Kr, setAllowList as Kt, setGraphQLReactorClient as L, upgradeDocument as Li, setSwitchboardUrl as Ln, addIsDragAndDropEnabledEventHandler as Lr, addSentryEnvEventHandler as Lt, useSyncList as M, loadFile as Mi, setRouterBasename as Mn, useSwitchboardUrl as Mr, addRenownNetworkIdEventHandler as Mt, addPackageDiscoveryServiceEventHandler as N, moveNode$1 as Ni, setSentryDsn as Nn, useVersion as Nr, addRenownUrlEventHandler as Nt, usePGlite as O, exportFile as Oi, setRenownChainId as On, useSentryDsn as Or, addLocalDrivesEnabledEventHandler as Ot, setPackageDiscoveryService as P, renameDriveNode as Pi, setSentryEnv as Pn, useVersionCheckInterval as Pr, addRequiresHardRefreshEventHandler as Pt, addCliVersionEventHandler as Q, useIsAddDriveEnabled as Qn, viewFilterInputFromViewFilter as Qr, setDrivesPreserveStrategy as Qt, useGraphQLReactorClient as R, getUserPermissions as Ri, setVersion as Rn, addIsExternalControlsEnabledEventHandler as Rr, addSentryReleaseEventHandler as Rt, addReactorClientEventHandler as S, screamingSnakeToCamel as Si, setIsPublicDrivesEnabled as Sn, useRenownAdapters as Sr, addIsExternalProcessorsEnabledEventHandler as St, setReactorClientModule as T, addFolder$1 as Ti, setLocalDrivesEnabled as Tn, useRenownUrl as Tr, addIsPublicDrivesEnabledEventHandler as Tt, addFeaturesEventHandler as U, showCreateDocumentModal as Ui, useBasePath as Un, phDocumentEditorConfigSetters as Ur, addWarnOutdatedAppEventHandler as Ut, useDropNode as V, closePHModal as Vi, useAllowList as Vn, phAppConfigSetters as Vr, addVersionCheckIntervalEventHandler as Vt, setFeatures as W, showDeleteNodeModal as Wi, useCliVersion as Wn, setAllowedDocumentTypes as Wr, phGlobalConfigHooks as Wt, addAnalyticsDatabaseNameEventHandler as X, useGaTrackingId as Xn, GraphQLReactorClient as Xr, setDefaultDrivesUrl as Xt, addAllowListEventHandler as Y, useFileUploadOperationsChunkSize as Yn, useIsExternalControlsEnabled as Yr, setCliVersion as Yt, addBasePathEventHandler as Z, useIsAddCloudDrivesEnabled as Zn, isGraphQLReactorClient as Zr, setDisabledEditors as Zt, addRevisionHistoryVisibleEventHandler as _, ConflictError as _i, setIsEditorReadModeEnabled as _n, useIsPublicDrivesEnabled as _r, addIsDocumentModelSelectionSettingsEnabledEventHandler as _t, addPHEventHandlers as a, subgraphUrlFromGraphqlUrl as ai, setIsAddPublicDrivesEnabled as an, useIsDeleteCloudDrivesEnabled as ar, addIsAddCloudDrivesEnabledEventHandler as at, showRevisionHistory as b, extractRevisionMap as bi, setIsExternalRelationalProcessorsEnabled as bn, useLocalDrivesEnabled as br, addIsEditorReadModeEnabledEventHandler as bt, addToastEventHandler as c, resolveDocumentModelModule as ci, setIsAnalyticsExternalProcessorsEnabled as cn, useIsDiffAnalyticsEnabled as cr, addIsAddPublicDrivesEnabledEventHandler as ct, addSelectedTimelineRevisionEventHandler as d, stampAction as di, setIsDeleteLocalDrivesEnabled as dn, useIsEditorDebugModeEnabled as dr, addIsAnalyticsExternalProcessorsEnabledEventHandler as dt, makeAuthConnectionParams as ei, setFileUploadOperationsChunkSize as en, useIsAddPublicDrivesEnabled as er, addDisabledEditorsEventHandler as et, setSelectedTimelineRevision as f, MutateDocumentWithOperationsDocument as fi, setIsDeletePublicDrivesEnabled as fn, useIsEditorReadModeEnabled as fr, addIsCloudDrivesEnabledEventHandler as ft, useSelectedTimelineItem as g, revisionMapFromRevisionsList as gi, setIsEditorDebugModeEnabled as gn, useIsLocalDrivesEnabled as gr, addIsDiffAnalyticsEnabledEventHandler as gt, setSelectedTimelineItem as h, phDocumentFromMutation as hi, setIsDriveAnalyticsEnabled as hn, useIsExternalRelationalProcessorsEnabled as hr, addIsDeletePublicDrivesEnabledEventHandler as ht, useSwitchboardClient as i, describeGraphQLDocument as ii, setIsAddLocalDrivesEnabled as in, useIsCloudDrivesEnabled as ir, addGaTrackingIdEventHandler as it, useSync as j, getDocumentExtension as ji, setRequiresHardRefresh as jn, useStudioMode as jr, addRenownChainIdEventHandler as jt, useReactorClient as k, extractInitialState as ki, setRenownNetworkId as kn, useSentryEnv as kr, addLogLevelEventHandler as kt, setPHToast as l, prepareSignedActions as li, setIsCloudDrivesEnabled as ln, useIsDocumentModelSelectionSettingsEnabled as lr, addIsAnalyticsDatabaseWorkerEnabledEventHandler as lt, addSelectedTimelineItemEventHandler as m, phDocumentFromGetDocument as mi, setIsDocumentModelSelectionSettingsEnabled as mn, useIsExternalProcessorsEnabled as mr, addIsDeleteLocalDrivesEnabledEventHandler as mt, GraphQLReactorProvider as n, subscriptionsUrlFromGraphqlUrl as ni, setIsAddCloudDrivesEnabled as nn, useIsAnalyticsEnabled as nr, addEnabledEditorsEventHandler as nt, callEventHandlerRegisterFunctions as o, StaticPackageManager as oi, setIsAnalyticsDatabaseWorkerEnabled as on, useIsDeleteLocalDrivesEnabled as or, addIsAddDriveEnabledEventHandler as ot, useSelectedTimelineRevision as p, ReactorOperationFieldsFragmentDoc as pi, setIsDiffAnalyticsEnabled as pn, useIsExternalPackagesEnabled as pr, addIsDeleteCloudDrivesEnabledEventHandler as pt, setAttachmentService as q, useDrivesPreserveStrategy as qn, useAllowedDocumentTypes as qr, setAnalyticsDatabaseName as qt, ensurePHEventHandlers as r, SubgraphSdkRegistry as ri, setIsAddDriveEnabled as rn, useIsAnalyticsExternalProcessorsEnabled as rr, addFileUploadOperationsChunkSizeEventHandler as rt, commonGlobalEventHandlerFunctions as s, packageFromDocumentModels as si, setIsAnalyticsEnabled as sn, useIsDeletePublicDrivesEnabled as sr, addIsAddLocalDrivesEnabledEventHandler as st, useDocumentOperations as t, startDocumentChangesSubscription as ti, setGaTrackingId as tn, useIsAnalyticsDatabaseWorkerEnabled as tr, addDrivesPreserveStrategyEventHandler as tt, usePHToast as u, signStampedAction as ui, setIsDeleteCloudDrivesEnabled as un, useIsDriveAnalyticsEnabled as ur, addIsAnalyticsEnabledEventHandler as ut, hideRevisionHistory as v, buildPulledDocument as vi, setIsExternalPackagesEnabled as vn, useIsRelationalProcessorsEnabled as vr, addIsDriveAnalyticsEnabledEventHandler as vt, setReactorClient as w, addFileWithProgress as wi, setIsSentryTracingEnabled as wn, useRenownNetworkId as wr, addIsLocalDrivesEnabledEventHandler as wt, useRevisionHistoryVisible as x, hasRevisionConflict as xi, setIsLocalDrivesEnabled as xn, useLogLevel as xr, addIsExternalPackagesEnabledEventHandler as xt, setRevisionHistoryVisible as y, convertRemoteOperations as yi, setIsExternalProcessorsEnabled as yn, useIsSentryTracingEnabled as yr, addIsEditorDebugModeEnabledEventHandler as yt, addDraggingNodeEventHandler as z, isDocumentTypeSupported as zi, setVersionCheckInterval as zn, isExternalControlsEnabledEventFunctions as zr, addStudioModeEventHandler as zt };
2544
2602
 
2545
- //# sourceMappingURL=document-operations-Bgo6A6W2.js.map
2603
+ //# sourceMappingURL=document-operations-WeE6wIDt.js.map