@powerhousedao/reactor-browser 6.2.2-dev.8 → 6.2.2-dev.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +341 -0
- package/dist/attachment-service-LwpgZ358.d.ts +1057 -0
- package/dist/attachment-service-LwpgZ358.d.ts.map +1 -0
- package/dist/{client-u13cr-Vg.js → client-B8ezRmBB.js} +30 -3
- package/dist/client-B8ezRmBB.js.map +1 -0
- package/dist/client-BIHN_UyR.d.ts +14 -0
- package/dist/client-BIHN_UyR.d.ts.map +1 -0
- package/dist/{client-_Gh2Uf0E.js → client-D66jVnot.js} +79 -13
- package/dist/client-D66jVnot.js.map +1 -0
- package/dist/{document-by-id-dLYFX-xz.js → document-by-id-BSZqTN66.js} +81 -51
- package/dist/document-by-id-BSZqTN66.js.map +1 -0
- package/dist/document-model-modules-DMIR-uSD.js +411 -0
- package/dist/document-model-modules-DMIR-uSD.js.map +1 -0
- package/dist/document-operations-BO-SlTDw.js +2539 -0
- package/dist/document-operations-BO-SlTDw.js.map +1 -0
- package/dist/global-1rvI8VdA.d.ts +400 -0
- package/dist/global-1rvI8VdA.d.ts.map +1 -0
- package/dist/index-BE3wBHLP.d.ts +349 -0
- package/dist/index-BE3wBHLP.d.ts.map +1 -0
- package/dist/index-BIVDXw3K.d.ts +144 -0
- package/dist/index-BIVDXw3K.d.ts.map +1 -0
- package/dist/index.d.ts +313 -715
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +611 -1696
- package/dist/index.js.map +1 -1
- package/dist/{inspector-proxy-CvQDDxmT.d.ts → inspector-proxy-6h5VKAwt.d.ts} +4 -2
- package/dist/inspector-proxy-6h5VKAwt.d.ts.map +1 -0
- package/dist/{make-ph-event-functions-BHoLPif5.js → make-ph-event-functions-DBq3iWYn.js} +1 -1
- package/dist/{make-ph-event-functions-BHoLPif5.js.map → make-ph-event-functions-DBq3iWYn.js.map} +1 -1
- package/dist/{index-DS4W07Y8.d.ts → pglite-CntadC_p-9NDG14dS.d.ts} +2 -142
- package/dist/pglite-CntadC_p-9NDG14dS.d.ts.map +1 -0
- package/dist/{relational-Dj06-YkI.js → relational-D4sxGPz7.js} +2 -2
- package/dist/{relational-Dj06-YkI.js.map → relational-D4sxGPz7.js.map} +1 -1
- package/dist/renown-BHxwP7xU.js +97 -0
- package/dist/renown-BHxwP7xU.js.map +1 -0
- package/dist/{renown-D-1c_Bvx.js → renown-BIEv6bSI.js} +523 -57
- package/dist/renown-BIEv6bSI.js.map +1 -0
- package/dist/selected-document-xFBNPc9Q.js +42 -0
- package/dist/selected-document-xFBNPc9Q.js.map +1 -0
- package/dist/src/ai/index.d.ts +369 -0
- package/dist/src/ai/index.d.ts.map +1 -0
- package/dist/src/ai/index.js +1296 -0
- package/dist/src/ai/index.js.map +1 -0
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/analytics/index.js.map +1 -1
- package/dist/src/graphql/client.d.ts +3 -2
- package/dist/src/graphql/client.js +1 -1
- package/dist/src/graphql-client/entry.d.ts +4 -0
- package/dist/src/graphql-client/entry.js +4 -0
- package/dist/src/relational/index.d.ts +1 -1
- package/dist/src/relational/index.js +1 -1
- package/dist/src/renown/index.d.ts +2 -2
- package/dist/src/renown/index.js +3 -2
- package/dist/src/rpc/index.d.ts +6 -3
- package/dist/src/rpc/index.d.ts.map +1 -1
- package/dist/src/rpc/index.js +41 -10
- package/dist/src/rpc/index.js.map +1 -1
- package/dist/store-BJYcr_FL.js +37 -0
- package/dist/store-BJYcr_FL.js.map +1 -0
- package/dist/{types-CPV0Cnsy.d.ts → types-6vDzbRRS.d.ts} +1 -1
- package/dist/{types-CPV0Cnsy.d.ts.map → types-6vDzbRRS.d.ts.map} +1 -1
- package/dist/{client-09xv0Dq6.d.ts → types-Dcv1ZLoW.d.ts} +87 -19
- package/dist/types-Dcv1ZLoW.d.ts.map +1 -0
- package/package.json +26 -10
- package/dist/client-09xv0Dq6.d.ts.map +0 -1
- package/dist/client-_Gh2Uf0E.js.map +0 -1
- package/dist/client-u13cr-Vg.js.map +0 -1
- package/dist/document-by-id-dLYFX-xz.js.map +0 -1
- package/dist/index-D3bV5rcl.d.ts +0 -216
- package/dist/index-D3bV5rcl.d.ts.map +0 -1
- package/dist/index-DS4W07Y8.d.ts.map +0 -1
- package/dist/inspector-proxy-CvQDDxmT.d.ts.map +0 -1
- package/dist/renown-D-1c_Bvx.js.map +0 -1
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { _ as isDuplicateManifestError, n as useDocumentsByIds, r as useDispatch, v as isDuplicateModuleError } from "./document-by-id-BSZqTN66.js";
|
|
2
|
+
import { t as makePHEventFunctions } from "./make-ph-event-functions-DBq3iWYn.js";
|
|
3
|
+
import { useSyncExternalStore } from "react";
|
|
4
|
+
import slug from "slug";
|
|
5
|
+
//#region src/errors.ts
|
|
6
|
+
var UnsupportedDocumentTypeError = class extends Error {
|
|
7
|
+
constructor(documentType) {
|
|
8
|
+
super(`Document type ${documentType} is not supported`);
|
|
9
|
+
this.name = "UnsupportedDocumentTypeError";
|
|
10
|
+
}
|
|
11
|
+
static isError(error) {
|
|
12
|
+
return Error.isError(error) && error.name === "UnsupportedDocumentTypeError";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var DocumentModelNotFoundError = class extends Error {
|
|
16
|
+
documentType;
|
|
17
|
+
name = "DocumentModelNotFoundError";
|
|
18
|
+
constructor(documentType) {
|
|
19
|
+
super(`Document model module for type ${documentType} not found`);
|
|
20
|
+
this.documentType = documentType;
|
|
21
|
+
}
|
|
22
|
+
static isError(error) {
|
|
23
|
+
return Error.isError(error) && error.name === "DocumentModelNotFoundError";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var DocumentTypeMismatchError = class extends Error {
|
|
27
|
+
constructor(documentId, expectedType, actualType) {
|
|
28
|
+
super(`Document ${documentId} is not of type ${expectedType}. Actual type: ${actualType}`);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var NoSelectedDocumentError = class extends Error {
|
|
32
|
+
constructor() {
|
|
33
|
+
super("There is no selected document. Did you mean to call 'useSelectedDocumentSafe' instead?");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/graphql-client/auth.ts
|
|
38
|
+
/** Lifetime requested for an ambient Renown token, in seconds. */
|
|
39
|
+
const ambientTokenExpiresInSeconds = 600;
|
|
40
|
+
/**
|
|
41
|
+
* The default token provider: the token of the currently logged-in Renown user.
|
|
42
|
+
*
|
|
43
|
+
* It is deliberately resolved from `window.ph` on every call rather than
|
|
44
|
+
* captured at construction time, so a client built before login starts sending
|
|
45
|
+
* the token as soon as there is one.
|
|
46
|
+
*
|
|
47
|
+
* The token is requested WITHOUT an `aud` claim - the Switchboard verifier
|
|
48
|
+
* rejects tokens that carry an audience.
|
|
49
|
+
*/
|
|
50
|
+
async function ambientRenownTokenProvider() {
|
|
51
|
+
if (typeof window === "undefined") return;
|
|
52
|
+
const renown = window.ph?.renown;
|
|
53
|
+
if (!renown?.user) return;
|
|
54
|
+
return renown.getBearerToken({ expiresIn: ambientTokenExpiresInSeconds });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Builds the SDK middleware that authenticates every request.
|
|
58
|
+
*
|
|
59
|
+
* The token is resolved per request and never cached, so a login, a logout or
|
|
60
|
+
* an expiry between two calls is picked up by the next one. When no token is
|
|
61
|
+
* available the request goes out unauthenticated.
|
|
62
|
+
*/
|
|
63
|
+
function makeAuthMiddleware(tokenProvider) {
|
|
64
|
+
return async (action) => {
|
|
65
|
+
const token = await tokenProvider();
|
|
66
|
+
if (!token) return action();
|
|
67
|
+
return action({ authorization: `Bearer ${token}` });
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/utils/url.ts
|
|
72
|
+
function resolveUrlPathname(path) {
|
|
73
|
+
return new URL(path.replace(/^\/+/, ""), window.location.origin + (window.ph?.basePath ?? "/")).pathname;
|
|
74
|
+
}
|
|
75
|
+
/** Returns the current path without the base path */
|
|
76
|
+
function getPathWithoutBase(path) {
|
|
77
|
+
const basePath = window.ph?.basePath ?? "/";
|
|
78
|
+
return path.replace(basePath, basePath.endsWith("/") ? "/" : "");
|
|
79
|
+
}
|
|
80
|
+
/** Makes a URL component for a drive. */
|
|
81
|
+
function makeDriveUrlComponent(drive) {
|
|
82
|
+
if (!drive) return "";
|
|
83
|
+
return `/d/${slug(drive.header.slug)}`;
|
|
84
|
+
}
|
|
85
|
+
/** Makes a URL component for a node. */
|
|
86
|
+
function makeNodeSlug(node) {
|
|
87
|
+
if (!node) return "";
|
|
88
|
+
const nodeName = node.name;
|
|
89
|
+
if (!nodeName) return slug(node.id);
|
|
90
|
+
return slug(`${nodeName}-${node.id}`);
|
|
91
|
+
}
|
|
92
|
+
/** Extracts the node slug from a path.
|
|
93
|
+
*
|
|
94
|
+
* The path is expected to be in the format `/d/<drive-slug>/<node-slug>`.
|
|
95
|
+
*/
|
|
96
|
+
function extractNodeSlugFromPath(path) {
|
|
97
|
+
const currentPath = getPathWithoutBase(path);
|
|
98
|
+
return /^\/d\/[^/]+\/([^/]+)$/.exec(currentPath)?.[1];
|
|
99
|
+
}
|
|
100
|
+
/** Finds a UUID in a string, used for extracting node ids from node slugs in the URL. */
|
|
101
|
+
function findUuid(input) {
|
|
102
|
+
if (!input) return void 0;
|
|
103
|
+
return /\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/.exec(input)?.[0];
|
|
104
|
+
}
|
|
105
|
+
function extractNodeIdFromSlug(nodeSlug) {
|
|
106
|
+
return findUuid(nodeSlug);
|
|
107
|
+
}
|
|
108
|
+
function extractNodeIdFromPath(path) {
|
|
109
|
+
return extractNodeIdFromSlug(extractNodeSlugFromPath(path));
|
|
110
|
+
}
|
|
111
|
+
/** Extracts the drive slug from a path.
|
|
112
|
+
* Used for extracting drive ids from drive slugs in the URL.
|
|
113
|
+
* Expects the path to be in the format `/d/<drive-slug>`.
|
|
114
|
+
*/
|
|
115
|
+
function extractDriveSlugFromPath(path) {
|
|
116
|
+
const currentPath = getPathWithoutBase(path);
|
|
117
|
+
return /^\/d\/([^/]+)/.exec(currentPath)?.[1] ?? "";
|
|
118
|
+
}
|
|
119
|
+
function extractDriveIdFromSlug(driveSlug) {
|
|
120
|
+
return findUuid(driveSlug);
|
|
121
|
+
}
|
|
122
|
+
function extractDriveIdFromPath(path) {
|
|
123
|
+
return extractDriveIdFromSlug(extractDriveSlugFromPath(path));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Creates a URL string with the given pathname while preserving existing query parameters.
|
|
127
|
+
*/
|
|
128
|
+
function createUrlWithPreservedParams(pathname) {
|
|
129
|
+
const search = window.location.search;
|
|
130
|
+
return search ? `${pathname}${search}` : pathname;
|
|
131
|
+
}
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/hooks/drives.ts
|
|
134
|
+
const drivesEventFunctions = makePHEventFunctions("drives");
|
|
135
|
+
/** Returns all of the drives in the reactor */
|
|
136
|
+
const useDrives = drivesEventFunctions.useValue;
|
|
137
|
+
/** Sets the drives in the reactor */
|
|
138
|
+
const setDrives = drivesEventFunctions.setValue;
|
|
139
|
+
/** Adds an event handler for the drives */
|
|
140
|
+
const addDrivesEventHandler = drivesEventFunctions.addEventHandler;
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/hooks/set-selected-node.ts
|
|
143
|
+
const selectedNodeIdEventFunctions = makePHEventFunctions("selectedNodeId");
|
|
144
|
+
const useSelectedNodeId = selectedNodeIdEventFunctions.useValue;
|
|
145
|
+
const setSelectedNodeId = selectedNodeIdEventFunctions.setValue;
|
|
146
|
+
const addSelectedNodeIdEventHandler = selectedNodeIdEventFunctions.addEventHandler;
|
|
147
|
+
/** Sets the selected node (file or folder). */
|
|
148
|
+
function setSelectedNode(nodeOrNodeSlug) {
|
|
149
|
+
const nodeSlug = typeof nodeOrNodeSlug === "string" ? nodeOrNodeSlug : makeNodeSlug(nodeOrNodeSlug);
|
|
150
|
+
setSelectedNodeId(extractNodeIdFromSlug(nodeSlug));
|
|
151
|
+
const driveSlugFromPath = extractDriveSlugFromPath(window.location.pathname);
|
|
152
|
+
if (!driveSlugFromPath) return;
|
|
153
|
+
if (!nodeSlug) {
|
|
154
|
+
const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}`);
|
|
155
|
+
if (pathname === window.location.pathname) return;
|
|
156
|
+
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const pathname = resolveUrlPathname(`/d/${driveSlugFromPath}/${nodeSlug}`);
|
|
160
|
+
if (pathname === window.location.pathname) return;
|
|
161
|
+
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
162
|
+
}
|
|
163
|
+
function addResetSelectedNodeEventHandler() {
|
|
164
|
+
window.addEventListener("ph:selectedDriveIdUpdated", () => {
|
|
165
|
+
setSelectedNodeId(void 0);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
function addSetSelectedNodeOnPopStateEventHandler() {
|
|
169
|
+
window.addEventListener("popstate", () => {
|
|
170
|
+
const pathname = window.location.pathname;
|
|
171
|
+
const nodeSlug = extractNodeSlugFromPath(pathname);
|
|
172
|
+
if (extractNodeIdFromSlug(nodeSlug) !== window.ph?.selectedNodeId) setSelectedNode(nodeSlug);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
//#region src/hooks/selected-drive.ts
|
|
177
|
+
const selectedDriveIdEventFunctions = makePHEventFunctions("selectedDriveId");
|
|
178
|
+
/** Returns the selected drive id */
|
|
179
|
+
const useSelectedDriveId = selectedDriveIdEventFunctions.useValue;
|
|
180
|
+
/** Sets the selected drive id */
|
|
181
|
+
const setSelectedDriveId = selectedDriveIdEventFunctions.setValue;
|
|
182
|
+
/** Adds an event handler for the selected drive id */
|
|
183
|
+
const addSelectedDriveIdEventHandler = selectedDriveIdEventFunctions.addEventHandler;
|
|
184
|
+
/** Returns the selected drive */
|
|
185
|
+
function useSelectedDrive() {
|
|
186
|
+
const drive = useSelectedDriveSafe();
|
|
187
|
+
if (!drive[0]) throw new Error("There is no drive selected. Did you mean to call 'useSelectedDriveSafe'?");
|
|
188
|
+
return drive;
|
|
189
|
+
}
|
|
190
|
+
/** Returns the selected drive, or undefined if no drive is selected */
|
|
191
|
+
function useSelectedDriveSafe() {
|
|
192
|
+
const selectedDriveId = useSelectedDriveId();
|
|
193
|
+
const selectedDrive = useDrives()?.find((drive) => drive.header.id === selectedDriveId);
|
|
194
|
+
const [drive, dispatch] = useDispatch(selectedDrive);
|
|
195
|
+
if (!selectedDrive) return [void 0, void 0];
|
|
196
|
+
return [drive, dispatch];
|
|
197
|
+
}
|
|
198
|
+
function setSelectedDrive(driveOrDriveSlug) {
|
|
199
|
+
const driveSlug = typeof driveOrDriveSlug === "string" ? driveOrDriveSlug : driveOrDriveSlug?.header.slug;
|
|
200
|
+
const drives = window.ph?.drives;
|
|
201
|
+
const driveId = (typeof driveOrDriveSlug === "object" && driveOrDriveSlug !== null ? driveOrDriveSlug : drives?.find((d) => d.header.slug === driveSlug))?.header.id;
|
|
202
|
+
if (!driveId && driveSlug && extractDriveSlugFromPath(window.location.pathname) === driveSlug) {
|
|
203
|
+
if (window.ph?.selectedDriveId) setSelectedDriveId(void 0);
|
|
204
|
+
deferDriveSelection(driveSlug);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
cancelPendingDriveSelection();
|
|
208
|
+
setSelectedDriveId(driveId);
|
|
209
|
+
if (!driveId) {
|
|
210
|
+
const pathname = resolveUrlPathname("/");
|
|
211
|
+
if (pathname === window.location.pathname) return;
|
|
212
|
+
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const pathname = resolveUrlPathname(`/d/${driveSlug}`);
|
|
216
|
+
if (pathname === window.location.pathname) return;
|
|
217
|
+
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
218
|
+
}
|
|
219
|
+
const DEFERRED_DRIVE_TICK_MS = 2e3;
|
|
220
|
+
const DEFERRED_DRIVE_MAX_WAIT_MS = 15e3;
|
|
221
|
+
function isInitialSyncInFlight() {
|
|
222
|
+
const remotes = window.ph?.reactorClientModule?.reactorModule?.syncModule?.syncManager?.list();
|
|
223
|
+
if (!remotes?.length) return false;
|
|
224
|
+
return remotes.some((remote) => {
|
|
225
|
+
try {
|
|
226
|
+
const snapshot = remote.channel.getConnectionState();
|
|
227
|
+
return snapshot.receivingPages || !snapshot.lastSuccessUtcMs && snapshot.state !== "error";
|
|
228
|
+
} catch {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
let pendingHandler;
|
|
234
|
+
let pendingTimeout;
|
|
235
|
+
function cancelPendingDriveSelection() {
|
|
236
|
+
if (pendingHandler) {
|
|
237
|
+
window.removeEventListener("ph:drivesUpdated", pendingHandler);
|
|
238
|
+
pendingHandler = void 0;
|
|
239
|
+
}
|
|
240
|
+
if (pendingTimeout) {
|
|
241
|
+
clearTimeout(pendingTimeout);
|
|
242
|
+
pendingTimeout = void 0;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function deferDriveSelection(driveSlug) {
|
|
246
|
+
cancelPendingDriveSelection();
|
|
247
|
+
const nodeSlug = extractNodeSlugFromPath(window.location.pathname);
|
|
248
|
+
const handler = () => {
|
|
249
|
+
if (!window.ph?.drives?.find((d) => d.header.slug === driveSlug)) return;
|
|
250
|
+
cancelPendingDriveSelection();
|
|
251
|
+
setSelectedDrive(driveSlug);
|
|
252
|
+
setSelectedNode(nodeSlug);
|
|
253
|
+
};
|
|
254
|
+
pendingHandler = handler;
|
|
255
|
+
window.addEventListener("ph:drivesUpdated", handler);
|
|
256
|
+
const deadline = Date.now() + DEFERRED_DRIVE_MAX_WAIT_MS;
|
|
257
|
+
const scheduleTick = () => {
|
|
258
|
+
pendingTimeout = setTimeout(() => {
|
|
259
|
+
if (Date.now() < deadline && isInitialSyncInFlight()) {
|
|
260
|
+
scheduleTick();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
cancelPendingDriveSelection();
|
|
264
|
+
const pathname = resolveUrlPathname("/");
|
|
265
|
+
if (pathname === window.location.pathname) return;
|
|
266
|
+
window.history.pushState(null, "", createUrlWithPreservedParams(pathname));
|
|
267
|
+
}, DEFERRED_DRIVE_TICK_MS);
|
|
268
|
+
};
|
|
269
|
+
scheduleTick();
|
|
270
|
+
}
|
|
271
|
+
function addSetSelectedDriveOnPopStateEventHandler() {
|
|
272
|
+
window.addEventListener("popstate", () => {
|
|
273
|
+
const pathname = window.location.pathname;
|
|
274
|
+
const driveId = extractDriveIdFromPath(pathname);
|
|
275
|
+
if (driveId !== window.ph?.selectedDriveId) setSelectedDrive(driveId);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/utils/nodes.ts
|
|
280
|
+
/** Sorts nodes by name. */
|
|
281
|
+
function sortNodesByName(nodes) {
|
|
282
|
+
return nodes.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
283
|
+
}
|
|
284
|
+
/** Returns whether a node is a file. */
|
|
285
|
+
function isFileNodeKind(node) {
|
|
286
|
+
if (!node) return false;
|
|
287
|
+
return node.kind.toUpperCase() === "FILE";
|
|
288
|
+
}
|
|
289
|
+
/** Returns whether a node is a folder. */
|
|
290
|
+
function isFolderNodeKind(node) {
|
|
291
|
+
if (!node) return false;
|
|
292
|
+
return node.kind.toUpperCase() === "FOLDER";
|
|
293
|
+
}
|
|
294
|
+
//#endregion
|
|
295
|
+
//#region src/hooks/items-in-selected-drive.ts
|
|
296
|
+
/** Returns the nodes in the selected drive. */
|
|
297
|
+
function useNodesInSelectedDrive() {
|
|
298
|
+
const [selectedDrive] = useSelectedDriveSafe();
|
|
299
|
+
return selectedDrive?.state.global.nodes;
|
|
300
|
+
}
|
|
301
|
+
/** Returns the file nodes in the selected drive. */
|
|
302
|
+
function useFileNodesInSelectedDrive() {
|
|
303
|
+
return useNodesInSelectedDrive()?.filter((n) => isFileNodeKind(n));
|
|
304
|
+
}
|
|
305
|
+
/** Returns the folder nodes in the selected drive. */
|
|
306
|
+
function useFolderNodesInSelectedDrive() {
|
|
307
|
+
return useNodesInSelectedDrive()?.filter((n) => isFolderNodeKind(n));
|
|
308
|
+
}
|
|
309
|
+
/** Returns the documents in the selected drive. */
|
|
310
|
+
function useDocumentsInSelectedDrive() {
|
|
311
|
+
const fileNodeIds = useFileNodesInSelectedDrive()?.map((node) => node.id);
|
|
312
|
+
return useDocumentsByIds(fileNodeIds);
|
|
313
|
+
}
|
|
314
|
+
/** Returns the document types supported by the selected drive, as defined by the document model documents present in the drive */
|
|
315
|
+
function useDocumentTypesInSelectedDrive() {
|
|
316
|
+
return (useDocumentsInSelectedDrive()?.filter(isDocumentModelDocument))?.map((doc) => doc.state.global.id);
|
|
317
|
+
}
|
|
318
|
+
function isDocumentModelDocument(document) {
|
|
319
|
+
return document.header.documentType === "powerhouse/document-model";
|
|
320
|
+
}
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region src/hooks/selected-node.ts
|
|
323
|
+
/** Returns the selected node. */
|
|
324
|
+
function useSelectedNode() {
|
|
325
|
+
const selectedNodeId = useSelectedNodeId();
|
|
326
|
+
return useNodesInSelectedDrive()?.find((n) => n.id === selectedNodeId);
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/hooks/vetra-packages.ts
|
|
330
|
+
const vetraPackageManagerFunctions = makePHEventFunctions("vetraPackageManager");
|
|
331
|
+
const useVetraPackageManager = vetraPackageManagerFunctions.useValue;
|
|
332
|
+
/** Returns all of the Vetra packages loaded by the Connect instance */
|
|
333
|
+
const useVetraPackages = () => {
|
|
334
|
+
const packageManager = useVetraPackageManager();
|
|
335
|
+
return useSyncExternalStore((cb) => packageManager ? packageManager.subscribe(cb) : () => {}, () => packageManager?.packages ?? []);
|
|
336
|
+
};
|
|
337
|
+
/** Adds the Vetra package manager event handler */
|
|
338
|
+
const addVetraPackageManagerEventHandler = vetraPackageManagerFunctions.addEventHandler;
|
|
339
|
+
/** Sets the Vetra package manager and registers its packages */
|
|
340
|
+
function setVetraPackageManager(packageManager) {
|
|
341
|
+
vetraPackageManagerFunctions.setValue(packageManager);
|
|
342
|
+
updateReactorClientDocumentModels(packageManager.packages);
|
|
343
|
+
updateReactorClientUpgradeManifests(packageManager.packages);
|
|
344
|
+
packageManager.subscribe(({ packages }) => {
|
|
345
|
+
updateReactorClientDocumentModels(packages);
|
|
346
|
+
updateReactorClientUpgradeManifests(packages);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
function updateReactorClientDocumentModels(packages) {
|
|
350
|
+
const documentModelModules = packages.flatMap((pkg) => pkg.documentModels).filter((module, index, modules) => modules.findIndex((m) => m.documentModel.global.id === module.documentModel.global.id && (m.version ?? 1) === (module.version ?? 1)) === index);
|
|
351
|
+
const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
|
|
352
|
+
if (!registry || documentModelModules.length === 0) return;
|
|
353
|
+
const results = registry.registerModules(...documentModelModules);
|
|
354
|
+
const duplicateTypes = /* @__PURE__ */ new Set();
|
|
355
|
+
for (const result of results) if (result.status === "error") if (isDuplicateModuleError(result.error)) duplicateTypes.add(result.item.documentModel.global.id);
|
|
356
|
+
else console.error("Failed to register document model module:", result.error);
|
|
357
|
+
if (duplicateTypes.size > 0) {
|
|
358
|
+
registry.unregisterModules(...duplicateTypes);
|
|
359
|
+
registry.registerModules(...documentModelModules.filter((module) => duplicateTypes.has(module.documentModel.global.id)));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function updateReactorClientUpgradeManifests(packages) {
|
|
363
|
+
const upgradeManifests = packages.flatMap((pkg) => pkg.upgradeManifests).filter((u) => u !== void 0);
|
|
364
|
+
const registry = window.ph?.reactorClientModule?.reactorModule?.documentModelRegistry;
|
|
365
|
+
if (!registry || upgradeManifests.length === 0) return;
|
|
366
|
+
const results = registry.registerUpgradeManifests(...upgradeManifests);
|
|
367
|
+
const duplicates = [];
|
|
368
|
+
for (const result of results) if (result.status === "error") if (isDuplicateManifestError(result.error)) duplicates.push(result);
|
|
369
|
+
else console.error("Failed to register upgrade manifest:", result.error);
|
|
370
|
+
if (duplicates.length > 0) {
|
|
371
|
+
const duplicateTypes = duplicates.map((r) => r.item.documentType).filter((t) => !!t);
|
|
372
|
+
registry.unregisterUpgradeManifests(...duplicateTypes);
|
|
373
|
+
registry.registerUpgradeManifests(...duplicates.map((r) => r.item));
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/hooks/document-model-modules.ts
|
|
378
|
+
function useDocumentModelModules() {
|
|
379
|
+
return useVetraPackages().flatMap((pkg) => pkg.documentModels).filter((module, index, modules) => modules.findIndex((m) => m.documentModel.global.id === module.documentModel.global.id && m.version === module.version) === index);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Resolves a document model module by document type, mirroring the registry's
|
|
383
|
+
* semantics (`IDocumentModelRegistry.getModule`): with `version` omitted the
|
|
384
|
+
* LATEST version of the type wins (`version ?? 1` as each module's default),
|
|
385
|
+
* with `version` given only an exact match is returned. The reactor resolves
|
|
386
|
+
* modules the same way when a document is created, so metadata read through
|
|
387
|
+
* this hook and the version a creation actually uses cannot disagree.
|
|
388
|
+
*/
|
|
389
|
+
function useDocumentModelModuleById(id, version) {
|
|
390
|
+
const documentModelModules = useDocumentModelModules();
|
|
391
|
+
if (!id || !documentModelModules) return void 0;
|
|
392
|
+
let latestModule;
|
|
393
|
+
let latestVersion = -1;
|
|
394
|
+
for (const module of documentModelModules) {
|
|
395
|
+
if (module.documentModel.global.id !== id) continue;
|
|
396
|
+
const moduleVersion = module.version ?? 1;
|
|
397
|
+
if (version !== void 0) {
|
|
398
|
+
if (moduleVersion === version) return module;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (moduleVersion > latestVersion) {
|
|
402
|
+
latestVersion = moduleVersion;
|
|
403
|
+
latestModule = module;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return latestModule;
|
|
407
|
+
}
|
|
408
|
+
//#endregion
|
|
409
|
+
export { createUrlWithPreservedParams as A, makeNodeSlug as B, addResetSelectedNodeEventHandler as C, addDrivesEventHandler as D, setSelectedNode as E, extractNodeIdFromSlug as F, DocumentTypeMismatchError as G, ambientRenownTokenProvider as H, extractNodeSlugFromPath as I, NoSelectedDocumentError as K, findUuid as L, extractDriveIdFromSlug as M, extractDriveSlugFromPath as N, setDrives as O, extractNodeIdFromPath as P, getPathWithoutBase as R, useSelectedDriveSafe as S, addSetSelectedNodeOnPopStateEventHandler as T, makeAuthMiddleware as U, resolveUrlPathname as V, DocumentModelNotFoundError as W, addSetSelectedDriveOnPopStateEventHandler as _, useVetraPackageManager as a, useSelectedDrive as b, useDocumentTypesInSelectedDrive as c, useFolderNodesInSelectedDrive as d, useNodesInSelectedDrive as f, addSelectedDriveIdEventHandler as g, sortNodesByName as h, setVetraPackageManager as i, extractDriveIdFromPath as j, useDrives as k, useDocumentsInSelectedDrive as l, isFolderNodeKind as m, useDocumentModelModules as n, useVetraPackages as o, isFileNodeKind as p, UnsupportedDocumentTypeError as q, addVetraPackageManagerEventHandler as r, useSelectedNode as s, useDocumentModelModuleById as t, useFileNodesInSelectedDrive as u, setSelectedDrive as v, addSelectedNodeIdEventHandler as w, useSelectedDriveId as x, setSelectedDriveId as y, makeDriveUrlComponent as z };
|
|
410
|
+
|
|
411
|
+
//# sourceMappingURL=document-model-modules-DMIR-uSD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-model-modules-DMIR-uSD.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\n/** Returns all of the Vetra packages loaded by the Connect instance */\nexport const useVetraPackages = () => {\n const packageManager = useVetraPackageManager();\n\n return useSyncExternalStore(\n (cb) => (packageManager ? packageManager.subscribe(cb) : () => {}),\n () => packageManager?.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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"}
|