@semapps/activitypub-components 0.6.7 → 0.7.0

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/dist/index.cjs.js CHANGED
@@ -8,10 +8,10 @@ var $583VT$muistylesmakeStyles = require("@mui/styles/makeStyles");
8
8
  var $583VT$muiiconsmaterialSend = require("@mui/icons-material/Send");
9
9
  var $583VT$semappssemanticdataprovider = require("@semapps/semantic-data-provider");
10
10
  var $583VT$semappsauthprovider = require("@semapps/auth-provider");
11
+ var $583VT$reactquery = require("react-query");
11
12
  var $583VT$tiptapcore = require("@tiptap/core");
12
13
  var $583VT$tiptapextensionmention = require("@tiptap/extension-mention");
13
14
  var $583VT$semappsfieldcomponents = require("@semapps/field-components");
14
- var $583VT$reactquery = require("react-query");
15
15
  var $583VT$tiptapreact = require("@tiptap/react");
16
16
  var $583VT$tippyjs = require("tippy.js");
17
17
 
@@ -28,9 +28,9 @@ $parcel$export(module.exports, "CommentsField", () => $2e5504cc4159ca8d$export$2
28
28
  $parcel$export(module.exports, "CollectionList", () => $505d598a33288aad$export$2e2bcd8739ae039);
29
29
  $parcel$export(module.exports, "ReferenceCollectionField", () => $b0c94a9bdea99da5$export$2e2bcd8739ae039);
30
30
  $parcel$export(module.exports, "useCollection", () => $5ca5f7e9fc1c3544$export$2e2bcd8739ae039);
31
- $parcel$export(module.exports, "useInbox", () => $97664763db3c0a46$export$2e2bcd8739ae039);
32
- $parcel$export(module.exports, "useNodeinfo", () => $30fd77858150739b$export$2e2bcd8739ae039);
33
- $parcel$export(module.exports, "useOutbox", () => $decfdd34cc00b80e$export$2e2bcd8739ae039);
31
+ $parcel$export(module.exports, "useInbox", () => $486f741c94cd8f74$export$2e2bcd8739ae039);
32
+ $parcel$export(module.exports, "useNodeinfo", () => $59fc2d2cba62bd8e$export$2e2bcd8739ae039);
33
+ $parcel$export(module.exports, "useOutbox", () => $456aea3814dded7d$export$2e2bcd8739ae039);
34
34
  $parcel$export(module.exports, "useWebfinger", () => $5b61553556e35016$export$2e2bcd8739ae039);
35
35
  $parcel$export(module.exports, "useMentions", () => $968ea07fb81eda0b$export$2e2bcd8739ae039);
36
36
  $parcel$export(module.exports, "ACTIVITY_TYPES", () => $ebea823cebb2f44b$export$1ec8e53e7d982d22);
@@ -108,102 +108,365 @@ const $ebea823cebb2f44b$export$4d8d554031975581 = "https://www.w3.org/ns/activit
108
108
 
109
109
 
110
110
 
111
- const $decfdd34cc00b80e$var$useOutbox = ()=>{
111
+
112
+
113
+
114
+ const $03510abb28fd3d8a$export$e57ff0f701c44363 = (value)=>{
115
+ // If the field is null-ish, we suppose there are no values.
116
+ if (value === null || value === undefined) return [];
117
+ // Return as is.
118
+ if (Array.isArray(value)) return value;
119
+ // Single value is made an array.
120
+ return [
121
+ value
122
+ ];
123
+ };
124
+ var $03510abb28fd3d8a$export$2e2bcd8739ae039 = {
125
+ arrayOf: $03510abb28fd3d8a$export$e57ff0f701c44363
126
+ };
127
+ const $03510abb28fd3d8a$export$34aed805e991a647 = (iterable, predicate)=>{
128
+ const seen = new Set();
129
+ return iterable.filter((item)=>{
130
+ const key = predicate(item);
131
+ if (seen.has(key)) return false;
132
+ seen.add(key);
133
+ return true;
134
+ });
135
+ };
136
+
137
+
138
+ const $5ca5f7e9fc1c3544$var$useItemsFromPages = (pages, dereferenceItems)=>{
139
+ const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
140
+ const items = (0, $583VT$react.useMemo)(()=>pages.flatMap((p)=>(0, $03510abb28fd3d8a$export$e57ff0f701c44363)(p.orderedItems || p.items)), [
141
+ pages
142
+ ]);
143
+ // We will force dereference, if some items are not URI string references.
144
+ const shouldDereference = (0, $583VT$react.useMemo)(()=>{
145
+ return dereferenceItems || items.some((item)=>typeof item !== "string");
146
+ }, [
147
+ dereferenceItems,
148
+ items
149
+ ]);
150
+ // Dereference all items, if necessary (even if shouldDereference is false, the hook needs to be called).
151
+ const itemQueries = (0, $583VT$reactquery.useQueries)(!shouldDereference ? [] : items.filter((item)=>typeof item === "string").map((itemUri)=>({
152
+ queryKey: [
153
+ "resource",
154
+ itemUri
155
+ ],
156
+ queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
157
+ staleTime: Infinity
158
+ })));
159
+ if (!shouldDereference) return {
160
+ loadedItems: items,
161
+ isLoading: false,
162
+ isFetching: false
163
+ };
164
+ // Put all loaded items together (might be dereferenced already, so concatenate).
165
+ const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
166
+ return itemQuery.isSuccess && itemQuery.data || [];
167
+ }));
168
+ const errors = itemQueries.filter((q)=>q.error);
169
+ return {
170
+ loadedItems: loadedItems,
171
+ isLoading: itemQueries.some((q)=>q.isLoading),
172
+ isFetching: itemQueries.some((q)=>q.isFetching),
173
+ errors: errors.length > 0 ? errors : undefined
174
+ };
175
+ };
176
+ /**
177
+ * Subscribe a collection. Supports pagination.
178
+ * @param predicateOrUrl The collection URI or the predicate to get the collection URI from the identity (webId).
179
+ * @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
180
+ */ const $5ca5f7e9fc1c3544$var$useCollection = (predicateOrUrl, options = {})=>{
181
+ const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
112
182
  const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
113
- const outboxUrl = (0, $583VT$react.useMemo)(()=>{
114
- if (identity?.webIdData) return identity?.webIdData?.outbox;
183
+ const [totalItems, setTotalItems] = (0, $583VT$react.useState)();
184
+ const queryClient = (0, $583VT$reactquery.useQueryClient)();
185
+ const [hasLiveUpdates, setHasLiveUpdates] = (0, $583VT$react.useState)({
186
+ status: "connecting"
187
+ });
188
+ const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
189
+ // Get collectionUrl from webId predicate or URL.
190
+ const collectionUrl = (0, $583VT$react.useMemo)(()=>{
191
+ if (predicateOrUrl) {
192
+ if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
193
+ if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
194
+ }
195
+ return undefined;
196
+ // throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
115
197
  }, [
116
- identity
198
+ identity,
199
+ predicateOrUrl
117
200
  ]);
118
- const sparqlEndpoint = (0, $583VT$react.useMemo)(()=>{
119
- if (identity?.webIdData) return identity?.webIdData?.endpoints?.["void:sparqlEndpoint"] || `${identity?.id}/sparql`;
201
+ // Fetch page of collection item references (if pageParam provided)
202
+ // or default to `collectionUrl` (which should give you the first page).
203
+ const fetchCollection = (0, $583VT$react.useCallback)(async ({ pageParam: nextPageUrl })=>{
204
+ // Fetch page or first page (collectionUrl)
205
+ let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
206
+ if (json.totalItems) setTotalItems(json.totalItems);
207
+ // If first page, handle this here.
208
+ if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
209
+ if (json.first?.items) {
210
+ if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
211
+ ({ json: json } = await dataProvider.fetch(json.first?.next));
212
+ else json = json.first;
213
+ } else // Fetch the first page
214
+ ({ json: json } = await dataProvider.fetch(json.first));
215
+ }
216
+ return json;
120
217
  }, [
121
- identity
218
+ dataProvider,
219
+ collectionUrl,
220
+ identity,
221
+ setTotalItems
122
222
  ]);
123
- // Post an activity to the logged user's outbox and return its URI
124
- const post = (0, $583VT$react.useCallback)(async (activity)=>{
125
- if (!outboxUrl) throw new Error("Cannot post to outbox before user identity is loaded. Please use the loaded argument of useOutbox");
126
- const token = localStorage.getItem("token");
127
- const { headers: headers } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(outboxUrl, {
128
- method: "POST",
129
- body: JSON.stringify({
130
- "@context": "https://www.w3.org/ns/activitystreams",
131
- ...activity
132
- }),
133
- headers: new Headers({
134
- "Content-Type": "application/ld+json",
135
- Authorization: `Bearer ${token}`
136
- })
223
+ // Use infiniteQuery to handle pagination, fetching, etc.
224
+ const { data: pageData, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $583VT$reactquery.useInfiniteQuery)([
225
+ "collection",
226
+ {
227
+ collectionUrl: collectionUrl
228
+ }
229
+ ], fetchCollection, {
230
+ enabled: !!(collectionUrl && identity?.id),
231
+ getNextPageParam: (lastPage)=>lastPage.next,
232
+ getPreviousPageParam: (firstPage)=>firstPage.prev
233
+ });
234
+ // Put all items together in a list (and dereference, if required).
235
+ const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $5ca5f7e9fc1c3544$var$useItemsFromPages(pageData?.pages ?? [], dereferenceItems);
236
+ const allErrors = (0, $03510abb28fd3d8a$export$e57ff0f701c44363)(collectionError).concat((0, $03510abb28fd3d8a$export$e57ff0f701c44363)(itemErrors));
237
+ const addItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
238
+ queryClient.setQueryData([
239
+ "collection",
240
+ {
241
+ collectionUrl: collectionUrl
242
+ }
243
+ ], (oldData)=>{
244
+ if (!oldData) return oldData;
245
+ setTotalItems(totalItems && totalItems + 1);
246
+ // Destructure, so react knows, it needs to re-render the pages.
247
+ const pages = [
248
+ ...oldData.pages
249
+ ];
250
+ const firstPageItems = pages?.[0]?.orderedItems || pages?.[0]?.items || [];
251
+ firstPageItems.unshift(item);
252
+ oldData.pages = pages;
253
+ return oldData;
137
254
  });
138
- return headers.get("Location");
255
+ if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
256
+ "collection",
257
+ {
258
+ collectionUrl: collectionUrl
259
+ }
260
+ ], {
261
+ active: true,
262
+ exact: true
263
+ }), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
139
264
  }, [
140
- outboxUrl
265
+ queryClient,
266
+ collectionUrl
141
267
  ]);
142
- const fetch = (0, $583VT$react.useCallback)(async ()=>{
143
- if (!sparqlEndpoint || !outboxUrl) return;
144
- const token = localStorage.getItem("token");
145
- const blankNodesQuery = (0, $583VT$semappssemanticdataprovider.buildBlankNodesQuery)([
146
- "as:object"
147
- ]);
148
- const query = `
149
- PREFIX as: <https://www.w3.org/ns/activitystreams#>
150
- CONSTRUCT {
151
- ?s1 ?p1 ?o1 .
152
- ${blankNodesQuery.construct}
153
- }
154
- WHERE {
155
- <${outboxUrl}> as:items ?s1 .
156
- ?s1 ?p1 ?o1 .
157
- ${blankNodesQuery.where}
158
- }
159
- `;
160
- const { json: json } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(sparqlEndpoint, {
161
- method: "POST",
162
- body: query,
163
- headers: new Headers({
164
- Accept: "application/ld+json",
165
- Authorization: token ? `Bearer ${token}` : undefined
166
- })
268
+ const removeItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
269
+ queryClient.setQueryData([
270
+ "collection",
271
+ {
272
+ collectionUrl: collectionUrl
273
+ }
274
+ ], (oldData)=>{
275
+ if (!oldData) return oldData;
276
+ setTotalItems(totalItems && totalItems - 1);
277
+ // Destructure, so react knows, it needs to re-render the pages array.
278
+ const pages = [
279
+ ...oldData.pages
280
+ ];
281
+ // Find the item in all pages and remove the item to be removed (either item.id or just item)
282
+ pages.forEach((page)=>{
283
+ if (page.orderedItems) page.orderedItems = page.orderedItems.filter((i)=>(i.id || i) !== (item.id || item));
284
+ else if (page.items) page.items = page.items.filter((i)=>(i.id || i) !== (item?.id || item));
285
+ });
286
+ oldData.pages = pages;
287
+ return oldData;
167
288
  });
168
- if (json["@graph"]) return json["@graph"];
169
- return null;
289
+ if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
290
+ "collection",
291
+ {
292
+ collectionUrl: collectionUrl
293
+ }
294
+ ], {
295
+ active: true,
296
+ exact: true
297
+ }), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
298
+ }, [
299
+ queryClient,
300
+ collectionUrl
301
+ ]);
302
+ // Live Updates
303
+ (0, $583VT$react.useEffect)(()=>{
304
+ if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
305
+ (0, $583VT$semappssemanticdataprovider.getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((webSocket)=>{
306
+ webSocket.addEventListener("message", (e)=>{
307
+ const data = JSON.parse(e.data);
308
+ if (data.type === "Add") addItem(data.object, true);
309
+ else if (data.type === "Remove") removeItem(data.object, true);
310
+ });
311
+ webSocket.addEventListener("error", (e)=>{
312
+ setHasLiveUpdates({
313
+ status: "error",
314
+ error: e
315
+ });
316
+ // TODO: Retry after a while
317
+ });
318
+ webSocket.addEventListener("close", (e)=>{
319
+ if (!hasLiveUpdates.error) setHasLiveUpdates({
320
+ ...hasLiveUpdates,
321
+ status: "closed"
322
+ });
323
+ });
324
+ setHasLiveUpdates({
325
+ status: "connected",
326
+ webSocket: webSocket
327
+ });
328
+ }).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
170
329
  }, [
171
- sparqlEndpoint,
172
- outboxUrl
330
+ collectionUrl,
331
+ liveUpdates,
332
+ dataProvider
173
333
  ]);
174
334
  return {
175
- post: post,
176
- fetch: fetch,
177
- url: outboxUrl,
178
- loaded: !!outboxUrl,
179
- owner: identity?.id
335
+ items: items,
336
+ totalItems: totalItems,
337
+ error: allErrors.length > 0 && allErrors,
338
+ refetch: refetch,
339
+ fetchNextPage: fetchNextPage,
340
+ addItem: addItem,
341
+ removeItem: removeItem,
342
+ hasNextPage: hasNextPage,
343
+ isLoading: isLoadingPage || isLoadingItems,
344
+ isFetching: isFetchingPage || isFetchingItems,
345
+ isFetchingNextPage: isFetchingNextPage,
346
+ url: collectionUrl,
347
+ hasLiveUpdates: hasLiveUpdates
180
348
  };
181
349
  };
182
- var $decfdd34cc00b80e$export$2e2bcd8739ae039 = $decfdd34cc00b80e$var$useOutbox;
350
+ var $5ca5f7e9fc1c3544$export$2e2bcd8739ae039 = $5ca5f7e9fc1c3544$var$useCollection;
183
351
 
184
352
 
185
353
 
186
354
 
187
- // Fix a bug in the current version of the mention extension
188
- // (The { id, label } object is located inside the id property)
189
- // See https://github.com/ueberdosis/tiptap/pull/1322
190
- const $9b1343b281972d72$var$CustomMention = (0, ($parcel$interopDefault($583VT$tiptapextensionmention))).extend({
191
- renderHTML ({ node: node, HTMLAttributes: HTMLAttributes }) {
192
- return [
193
- "span",
194
- (0, $583VT$tiptapcore.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
195
- `@${node.attrs.id.label}`
196
- ];
197
- },
198
- addAttributes () {
199
- return {
200
- label: {
201
- default: null,
202
- parseHTML: (element)=>{
203
- return {
204
- label: element.getAttribute("data-mention-label")
205
- };
206
- },
355
+ /**
356
+ * Hook used internally by useInbox and useOutbox. This is not exported.
357
+ * @param webSocket WebSocket which allow to listen to the inbox or outbox
358
+ * @param existingActivities Partial list of activities already received in the inbox and outbox
359
+ */ const $5e70f9d0635e25dd$var$useAwaitActivity = (webSocket, existingActivities)=>{
360
+ const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
361
+ // TODO Allow to pass an object, and automatically dereference it if required, like on the @semapps/activitypub matchActivity util
362
+ return (0, $583VT$react.useCallback)((matchActivity, options = {})=>{
363
+ const { timeout: timeout = 30000, checkExistingActivities: checkExistingActivities = false } = options;
364
+ return new Promise((resolve, reject)=>{
365
+ if (webSocket) {
366
+ const onMessage = (event)=>{
367
+ const data = JSON.parse(event.data);
368
+ if (data.type === "Add") dataProvider.fetch(data.object).then(({ json: json })=>{
369
+ if (matchActivity(json)) {
370
+ webSocket.removeEventListener("message", onMessage);
371
+ return resolve(json);
372
+ }
373
+ });
374
+ };
375
+ webSocket.addEventListener("message", onMessage);
376
+ // TODO reconnect if connection closed
377
+ webSocket.addEventListener("error", (e)=>{
378
+ reject(e);
379
+ });
380
+ webSocket.addEventListener("close", (e)=>{
381
+ reject(new Error(`${e.reason} (Code: ${e.code})`));
382
+ });
383
+ // If a list of activities is already loaded, verify if there is a match
384
+ if (existingActivities && checkExistingActivities) for (const a of existingActivities){
385
+ if (typeof a !== "string") {
386
+ if (matchActivity(a)) {
387
+ webSocket.removeEventListener("message", onMessage);
388
+ return resolve(a);
389
+ }
390
+ }
391
+ }
392
+ setTimeout(()=>{
393
+ webSocket.removeEventListener("message", onMessage);
394
+ reject(new Error("Timeout"));
395
+ }, timeout);
396
+ } else throw new Error("WebSocket is not initialized !");
397
+ });
398
+ }, [
399
+ webSocket,
400
+ existingActivities,
401
+ dataProvider
402
+ ]);
403
+ };
404
+ var $5e70f9d0635e25dd$export$2e2bcd8739ae039 = $5e70f9d0635e25dd$var$useAwaitActivity;
405
+
406
+
407
+ /**
408
+ * Hook to fetch and post to the outbox of the logged user.
409
+ * Returns the same data as the useCollection hooks, plus:
410
+ * - `post`: a function to post a new activity in the user's outbox
411
+ * - `awaitActivity`: a function to wait for a certain activity to be posted
412
+ * - `owner`: the WebID of the outbox's owner
413
+ * See https://semapps.org/docs/frontend/activitypub-components#useoutbox for usage
414
+ * @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
415
+ */ const $456aea3814dded7d$var$useOutbox = (options = {})=>{
416
+ const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
417
+ const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
418
+ const { url: url, hasLiveUpdates: hasLiveUpdates, items: items, ...rest } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)("outbox", options);
419
+ const awaitActivity = (0, $5e70f9d0635e25dd$export$2e2bcd8739ae039)(hasLiveUpdates.webSocket, items);
420
+ // Post an activity to the logged user's outbox and return its URI
421
+ const post = (0, $583VT$react.useCallback)(async (activity)=>{
422
+ if (!url) throw new Error("Cannot post to outbox before user identity is loaded. Please use the isLoading argument of useOutbox");
423
+ const { headers: headers } = await dataProvider.fetch(url, {
424
+ method: "POST",
425
+ body: JSON.stringify({
426
+ "@context": "https://www.w3.org/ns/activitystreams",
427
+ ...activity
428
+ })
429
+ });
430
+ return headers.get("Location");
431
+ }, [
432
+ url,
433
+ dataProvider
434
+ ]);
435
+ return {
436
+ url: url,
437
+ hasLiveUpdates: hasLiveUpdates,
438
+ items: items,
439
+ post: post,
440
+ awaitActivity: awaitActivity,
441
+ owner: identity?.id,
442
+ ...rest
443
+ };
444
+ };
445
+ var $456aea3814dded7d$export$2e2bcd8739ae039 = $456aea3814dded7d$var$useOutbox;
446
+
447
+
448
+
449
+
450
+ // Fix a bug in the current version of the mention extension
451
+ // (The { id, label } object is located inside the id property)
452
+ // See https://github.com/ueberdosis/tiptap/pull/1322
453
+ const $9b1343b281972d72$var$CustomMention = (0, ($parcel$interopDefault($583VT$tiptapextensionmention))).extend({
454
+ renderHTML ({ node: node, HTMLAttributes: HTMLAttributes }) {
455
+ return [
456
+ "span",
457
+ (0, $583VT$tiptapcore.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
458
+ `@${node.attrs.id.label}`
459
+ ];
460
+ },
461
+ addAttributes () {
462
+ return {
463
+ label: {
464
+ default: null,
465
+ parseHTML: (element)=>{
466
+ return {
467
+ label: element.getAttribute("data-mention-label")
468
+ };
469
+ },
207
470
  renderHTML: (attributes)=>{
208
471
  if (!attributes.id.label) return {};
209
472
  return {
@@ -284,7 +547,7 @@ const $703eba3e46be7ee5$var$PostCommentForm = ({ context: context, placeholder:
284
547
  const userDataModel = (0, $583VT$semappssemanticdataprovider.useDataModel)(userResource);
285
548
  const classes = $703eba3e46be7ee5$var$useStyles();
286
549
  const notify = (0, $583VT$reactadmin.useNotify)();
287
- const outbox = (0, $decfdd34cc00b80e$export$2e2bcd8739ae039)();
550
+ const outbox = (0, $456aea3814dded7d$export$2e2bcd8739ae039)();
288
551
  const [expanded, setExpanded] = (0, $583VT$react.useState)(false);
289
552
  const [openAuth, setOpenAuth] = (0, $583VT$react.useState)(false);
290
553
  const onSubmit = (0, $583VT$react.useCallback)(async (values)=>{
@@ -544,186 +807,9 @@ var $d68cd57b2d06b6d5$export$2e2bcd8739ae039 = $d68cd57b2d06b6d5$var$CommentsLis
544
807
 
545
808
 
546
809
 
547
-
548
-
549
-
550
- const $03510abb28fd3d8a$export$e57ff0f701c44363 = (value)=>{
551
- // If the field is null-ish, we suppose there are no values.
552
- if (value === null || value === undefined) return [];
553
- // Return as is.
554
- if (Array.isArray(value)) return value;
555
- // Single value is made an array.
556
- return [
557
- value
558
- ];
559
- };
560
- var $03510abb28fd3d8a$export$2e2bcd8739ae039 = {
561
- arrayOf: $03510abb28fd3d8a$export$e57ff0f701c44363
562
- };
563
- const $03510abb28fd3d8a$export$34aed805e991a647 = (iterable, predicate)=>{
564
- const seen = new Set();
565
- return iterable.filter((item)=>{
566
- const key = predicate(item);
567
- if (seen.has(key)) return false;
568
- seen.add(key);
569
- return true;
570
- });
571
- };
572
-
573
-
574
- const $2b75a2f49c9ef165$var$useItemsFromPagesAndNotifications = (pages, notifications, dereferenceItems)=>{
575
- const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
576
- // Add all items from pages and process notifications (possibly new and deleted items).
577
- const items = (0, $583VT$react.useMemo)(()=>{
578
- const addItems = notifications.map((n)=>n.type === "Add").map((n)=>n.object);
579
- const removeItems = notifications.map((n)=>n.type === "Remove").map((n)=>n.object.id || n.object);
580
- const currentItems = !pages ? [] : pages.flatMap((p)=>(0, $03510abb28fd3d8a$export$e57ff0f701c44363)(p.orderedItems || p.items));
581
- const currentAndNew = currentItems.concat(addItems);
582
- return currentAndNew// Filter out removed items.
583
- .filter((item)=>!removeItems.some((r)=>(r.id ?? r) === (item.id ?? item)))// Filter duplicates.
584
- .filter((item)=>currentAndNew.some((i2)=>(i2.id ?? i2) === (item.id ?? item)));
585
- }, pages, notifications);
586
- if (!dereferenceItems) return {
587
- loadedItems: items,
588
- isLoading: false,
589
- isFetching: false
590
- };
591
- // Dereference all items, if they are not yet.
592
- const itemQueries = (0, $583VT$reactquery.useQueries)(items.filter((item)=>typeof item === "string").map((itemUri)=>({
593
- queryKey: [
594
- "resource",
595
- itemUri
596
- ],
597
- queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
598
- staleTime: Infinity
599
- })));
600
- // Put all loaded items together (might be dereferenced already, so concatenate).
601
- const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
602
- return itemQuery.isSuccess && itemQuery.data || [];
603
- }));
604
- console.log("loadedItems", loadedItems.length, "total", items.length);
605
- const errors = itemQueries.filter((q)=>q.error);
606
- return {
607
- loadedItems: loadedItems,
608
- isLoading: itemQueries.some((q)=>q.isLoading),
609
- isFetching: itemQueries.some((q)=>q.isFetching),
610
- errors: errors.length > 0 && errors
611
- };
612
- };
613
- const $2b75a2f49c9ef165$var$useCollection = (predicateOrUrl, options = {})=>{
614
- const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
615
- const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
616
- const [totalItems, setTotalItems] = (0, $583VT$react.useState)();
617
- const [notifications, setNotifications] = (0, $583VT$react.useState)([]);
618
- const [hasLiveUpdates, setHasLiveUpdates] = (0, $583VT$react.useState)({
619
- status: "disconnected",
620
- error: undefined
621
- });
622
- const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
623
- // Get collectionUrl from webId predicate or URL.
624
- const collectionUrl = (0, $583VT$react.useMemo)(()=>{
625
- if (predicateOrUrl) {
626
- if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
627
- if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
628
- }
629
- return undefined;
630
- // throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
631
- }, [
632
- identity,
633
- predicateOrUrl
634
- ]);
635
- // Fetch page of collection item references (if pageParam provided)
636
- // or default to `collectionUrl` (which should give you the first page).
637
- const fetchCollection = (0, $583VT$react.useCallback)(async ({ pageParam: nextPageUrl })=>{
638
- // Fetch page or first page (collectionUrl)
639
- let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
640
- if (json.totalItems) setTotalItems(json.totalItems);
641
- // If first page, handle this here.
642
- if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
643
- if (json.first?.items) {
644
- if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
645
- ({ json: json } = await dataProvider.fetch(json.first?.next));
646
- else json = json.first;
647
- } else // Fetch the first page
648
- ({ json: json } = await dataProvider.fetch(json.first));
649
- }
650
- return json;
651
- }, [
652
- dataProvider,
653
- collectionUrl,
654
- identity,
655
- setTotalItems
656
- ]);
657
- // Use infiniteQuery to handle pagination, fetching, etc.
658
- const { data: data, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $583VT$reactquery.useInfiniteQuery)([
659
- "collection",
660
- {
661
- collectionUrl: collectionUrl
662
- }
663
- ], fetchCollection, {
664
- enabled: !!(collectionUrl && identity?.id),
665
- getNextPageParam: (lastPage)=>lastPage.next,
666
- getPreviousPageParam: (firstPage)=>firstPage.prev
667
- });
668
- // Put all items together in a list.
669
- const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $2b75a2f49c9ef165$var$useItemsFromPagesAndNotifications(data?.pages, notifications, dereferenceItems);
670
- // Notifications have been processed after hook call, so reset.
671
- // useEffect(() => {
672
- // setNotifications([]);
673
- // }, [notifications])
674
- // Live Updates
675
- (0, $583VT$react.useEffect)(()=>{
676
- if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
677
- (0, $583VT$semappssemanticdataprovider.getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((webSocket)=>{
678
- webSocket.addEventListener("message", (e)=>{
679
- if (e.data && e.data.type === "Add" || e.data.type === "Remove") setNotifications([
680
- ...notifications,
681
- e.data
682
- ]);
683
- });
684
- webSocket.addEventListener("error", (e)=>{
685
- setHasLiveUpdates({
686
- status: "error",
687
- error: e
688
- });
689
- // TODO: Retry after a while
690
- });
691
- webSocket.addEventListener("close", (e)=>{
692
- setHasLiveUpdates({
693
- ...hasLiveUpdates,
694
- status: "disconnected"
695
- });
696
- });
697
- setHasLiveUpdates({
698
- status: "connected"
699
- });
700
- }).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
701
- }, [
702
- collectionUrl,
703
- liveUpdates,
704
- dataProvider.fetch
705
- ]);
706
- const allErrors = (0, $03510abb28fd3d8a$export$e57ff0f701c44363)(collectionError).concat((0, $03510abb28fd3d8a$export$e57ff0f701c44363)(itemErrors));
707
- return {
708
- items: items,
709
- totalItems: totalItems,
710
- error: allErrors.length > 0 && allErrors,
711
- refetch: refetch,
712
- fetchNextPage: fetchNextPage,
713
- hasNextPage: hasNextPage,
714
- isLoading: isLoadingPage || isLoadingItems,
715
- isFetching: isFetchingPage || isFetchingItems,
716
- isFetchingNextPage: isFetchingNextPage,
717
- url: collectionUrl,
718
- hasLiveUpdates: hasLiveUpdates
719
- };
720
- };
721
- var $2b75a2f49c9ef165$export$2e2bcd8739ae039 = $2b75a2f49c9ef165$var$useCollection;
722
-
723
-
724
810
  const $2e5504cc4159ca8d$var$CommentsField = ({ source: source, context: context, helperText: helperText, placeholder: placeholder, userResource: userResource, mentions: mentions })=>{
725
811
  const record = (0, $583VT$reactadmin.useRecordContext)();
726
- const { items: comments, loading: loading, addItem: addItem, removeItem: removeItem } = (0, $2b75a2f49c9ef165$export$2e2bcd8739ae039)(record.replies);
812
+ const { items: comments, loading: loading, addItem: addItem, removeItem: removeItem } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)(record.replies);
727
813
  if (!userResource) throw new Error("No userResource defined for CommentsField");
728
814
  return /*#__PURE__*/ (0, $583VT$reactjsxruntime.jsxs)((0, $583VT$reactjsxruntime.Fragment), {
729
815
  children: [
@@ -759,7 +845,7 @@ var $2e5504cc4159ca8d$export$2e2bcd8739ae039 = $2e5504cc4159ca8d$var$CommentsFie
759
845
 
760
846
  const $505d598a33288aad$var$CollectionList = ({ collectionUrl: collectionUrl, resource: resource, children: children })=>{
761
847
  if ((0, ($parcel$interopDefault($583VT$react))).Children.count(children) !== 1) throw new Error("<CollectionList> only accepts a single child");
762
- const { items: actorsUris } = (0, $2b75a2f49c9ef165$export$2e2bcd8739ae039)(collectionUrl);
848
+ const { items: actorsUris } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)(collectionUrl);
763
849
  const { data: data, isLoading: isLoading, isFetching: isFetching } = (0, $583VT$reactadmin.useGetMany)(resource, {
764
850
  ids: Array.isArray(actorsUris) ? actorsUris : [
765
851
  actorsUris
@@ -802,302 +888,49 @@ var $b0c94a9bdea99da5$export$2e2bcd8739ae039 = $b0c94a9bdea99da5$var$ReferenceCo
802
888
 
803
889
 
804
890
 
805
-
806
- const $5ca5f7e9fc1c3544$var$useItemsFromPages = (pages, dereferenceItems)=>{
807
- const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
808
- const items = (0, $583VT$react.useMemo)(()=>pages.flatMap((p)=>(0, $03510abb28fd3d8a$export$e57ff0f701c44363)(p.orderedItems || p.items)), [
809
- pages
810
- ]);
811
- // We will force dereference, if some items are not URI string references.
812
- const shouldDereference = (0, $583VT$react.useMemo)(()=>{
813
- return dereferenceItems || items.some((item)=>typeof item !== "string");
814
- }, [
815
- dereferenceItems,
816
- items
817
- ]);
818
- // Dereference all items, if necessary (even if shouldDereference is false, the hook needs to be called).
819
- const itemQueries = (0, $583VT$reactquery.useQueries)(!shouldDereference ? [] : items.filter((item)=>typeof item === "string").map((itemUri)=>({
820
- queryKey: [
821
- "resource",
822
- itemUri
823
- ],
824
- queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
825
- staleTime: Infinity
826
- })));
827
- if (!shouldDereference) return {
828
- loadedItems: items,
829
- isLoading: false,
830
- isFetching: false
831
- };
832
- // Put all loaded items together (might be dereferenced already, so concatenate).
833
- const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
834
- return itemQuery.isSuccess && itemQuery.data || [];
835
- }));
836
- const errors = itemQueries.filter((q)=>q.error);
837
- return {
838
- loadedItems: loadedItems,
839
- isLoading: itemQueries.some((q)=>q.isLoading),
840
- isFetching: itemQueries.some((q)=>q.isFetching),
841
- errors: errors.length > 0 ? errors : undefined
842
- };
843
- };
844
891
  /**
845
- * Subscribe a collection. Supports pagination.
846
- * @param predicateOrUrl The collection URI or the predicate to get the collection URI from the identity (webId).
892
+ * Hook to fetch the inbox of the logged user.
893
+ * Returns the same data as the useCollection hooks, plus:
894
+ * - `awaitActivity`: a function to wait for a certain activity to be received
895
+ * - `owner`: the WebID of the inbox's owner
896
+ * See https://semapps.org/docs/frontend/activitypub-components#useinbox for usage
847
897
  * @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
848
- */ const $5ca5f7e9fc1c3544$var$useCollection = (predicateOrUrl, options = {})=>{
849
- const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
898
+ */ const $486f741c94cd8f74$var$useInbox = (options = {})=>{
850
899
  const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
851
- const [totalItems, setTotalItems] = (0, $583VT$react.useState)();
852
- const queryClient = (0, $583VT$reactquery.useQueryClient)();
853
- const [hasLiveUpdates, setHasLiveUpdates] = (0, $583VT$react.useState)({
854
- status: "connecting"
855
- });
856
- const dataProvider = (0, $583VT$reactadmin.useDataProvider)();
857
- // Get collectionUrl from webId predicate or URL.
858
- const collectionUrl = (0, $583VT$react.useMemo)(()=>{
859
- if (predicateOrUrl) {
860
- if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
861
- if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
862
- }
863
- return undefined;
864
- // throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
865
- }, [
866
- identity,
867
- predicateOrUrl
868
- ]);
869
- // Fetch page of collection item references (if pageParam provided)
870
- // or default to `collectionUrl` (which should give you the first page).
871
- const fetchCollection = (0, $583VT$react.useCallback)(async ({ pageParam: nextPageUrl })=>{
872
- // Fetch page or first page (collectionUrl)
873
- let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
874
- if (json.totalItems) setTotalItems(json.totalItems);
875
- // If first page, handle this here.
876
- if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
877
- if (json.first?.items) {
878
- if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
879
- ({ json: json } = await dataProvider.fetch(json.first?.next));
880
- else json = json.first;
881
- } else // Fetch the first page
882
- ({ json: json } = await dataProvider.fetch(json.first));
883
- }
884
- return json;
885
- }, [
886
- dataProvider,
887
- collectionUrl,
888
- identity,
889
- setTotalItems
890
- ]);
891
- // Use infiniteQuery to handle pagination, fetching, etc.
892
- const { data: pageData, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $583VT$reactquery.useInfiniteQuery)([
893
- "collection",
894
- {
895
- collectionUrl: collectionUrl
896
- }
897
- ], fetchCollection, {
898
- enabled: !!(collectionUrl && identity?.id),
899
- getNextPageParam: (lastPage)=>lastPage.next,
900
- getPreviousPageParam: (firstPage)=>firstPage.prev
901
- });
902
- // Put all items together in a list (and dereference, if required).
903
- const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $5ca5f7e9fc1c3544$var$useItemsFromPages(pageData?.pages ?? [], dereferenceItems);
904
- const allErrors = (0, $03510abb28fd3d8a$export$e57ff0f701c44363)(collectionError).concat((0, $03510abb28fd3d8a$export$e57ff0f701c44363)(itemErrors));
905
- const addItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
906
- queryClient.setQueryData([
907
- "collection",
908
- {
909
- collectionUrl: collectionUrl
910
- }
911
- ], (oldData)=>{
912
- if (!oldData) return oldData;
913
- setTotalItems(totalItems && totalItems + 1);
914
- // Destructure, so react knows, it needs to re-render the pages.
915
- const pages = [
916
- ...oldData.pages
917
- ];
918
- const firstPageItems = pages?.[0]?.orderedItems || pages?.[0]?.items || [];
919
- firstPageItems.unshift(item);
920
- oldData.pages = pages;
921
- return oldData;
922
- });
923
- if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
924
- "collection",
925
- {
926
- collectionUrl: collectionUrl
927
- }
928
- ], {
929
- active: true,
930
- exact: true
931
- }), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
932
- }, [
933
- queryClient,
934
- collectionUrl
935
- ]);
936
- const removeItem = (0, $583VT$react.useCallback)((item, shouldRefetch = true)=>{
937
- queryClient.setQueryData([
938
- "collection",
939
- {
940
- collectionUrl: collectionUrl
941
- }
942
- ], (oldData)=>{
943
- if (!oldData) return oldData;
944
- setTotalItems(totalItems && totalItems - 1);
945
- // Destructure, so react knows, it needs to re-render the pages array.
946
- const pages = [
947
- ...oldData.pages
948
- ];
949
- // Find the item in all pages and remove the item to be removed (either item.id or just item)
950
- pages.forEach((page)=>{
951
- if (page.orderedItems) page.orderedItems = page.orderedItems.filter((i)=>(i.id || i) !== (item.id || item));
952
- else if (page.items) page.items = page.items.filter((i)=>(i.id || i) !== (item?.id || item));
953
- });
954
- oldData.pages = pages;
955
- return oldData;
956
- });
957
- if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
958
- "collection",
959
- {
960
- collectionUrl: collectionUrl
961
- }
962
- ], {
963
- active: true,
964
- exact: true
965
- }), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
966
- }, [
967
- queryClient,
968
- collectionUrl
969
- ]);
970
- // Live Updates
971
- (0, $583VT$react.useEffect)(()=>{
972
- if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
973
- (0, $583VT$semappssemanticdataprovider.getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((webSocket)=>{
974
- webSocket.addEventListener("message", (e)=>{
975
- const data = JSON.parse(e.data);
976
- if (data && data.type === "Add") addItem(data.object, true);
977
- else if (data && data.type === "Remove") removeItem(data.object, true);
978
- });
979
- webSocket.addEventListener("error", (e)=>{
980
- setHasLiveUpdates({
981
- status: "error",
982
- error: e
983
- });
984
- // TODO: Retry after a while
985
- });
986
- webSocket.addEventListener("close", (e)=>{
987
- if (!hasLiveUpdates.error) setHasLiveUpdates({
988
- ...hasLiveUpdates,
989
- status: "closed"
990
- });
991
- });
992
- setHasLiveUpdates({
993
- status: "connected"
994
- });
995
- }).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
996
- }, [
997
- collectionUrl,
998
- liveUpdates,
999
- dataProvider
1000
- ]);
900
+ const { items: items, url: url, hasLiveUpdates: hasLiveUpdates, ...rest } = (0, $5ca5f7e9fc1c3544$export$2e2bcd8739ae039)("inbox", options);
901
+ const awaitActivity = (0, $5e70f9d0635e25dd$export$2e2bcd8739ae039)(hasLiveUpdates.webSocket);
1001
902
  return {
1002
903
  items: items,
1003
- totalItems: totalItems,
1004
- error: allErrors.length > 0 && allErrors,
1005
- refetch: refetch,
1006
- fetchNextPage: fetchNextPage,
1007
- addItem: addItem,
1008
- removeItem: removeItem,
1009
- hasNextPage: hasNextPage,
1010
- isLoading: isLoadingPage || isLoadingItems,
1011
- isFetching: isFetchingPage || isFetchingItems,
1012
- isFetchingNextPage: isFetchingNextPage,
1013
- url: collectionUrl,
1014
- hasLiveUpdates: hasLiveUpdates
904
+ url: url,
905
+ hasLiveUpdates: hasLiveUpdates,
906
+ awaitActivity: awaitActivity,
907
+ owner: identity?.id,
908
+ ...rest
1015
909
  };
1016
910
  };
1017
- var $5ca5f7e9fc1c3544$export$2e2bcd8739ae039 = $5ca5f7e9fc1c3544$var$useCollection;
1018
-
1019
-
1020
-
1021
-
1022
-
1023
- const $97664763db3c0a46$var$useInbox = ()=>{
1024
- const { data: identity } = (0, $583VT$reactadmin.useGetIdentity)();
1025
- const inboxUrl = (0, $583VT$react.useMemo)(()=>{
1026
- if (identity?.webIdData) return identity?.webIdData?.inbox;
1027
- }, [
1028
- identity
1029
- ]);
1030
- const sparqlEndpoint = (0, $583VT$react.useMemo)(()=>{
1031
- if (identity?.webIdData) return identity?.webIdData?.endpoints?.["void:sparqlEndpoint"] || `${identity?.id}/sparql`;
1032
- }, [
1033
- identity
1034
- ]);
1035
- const fetch = (0, $583VT$react.useCallback)(async ({ filters: filters })=>{
1036
- if (!sparqlEndpoint || !inboxUrl) return;
1037
- const token = localStorage.getItem("token");
1038
- const blankNodesQuery = (0, $583VT$semappssemanticdataprovider.buildBlankNodesQuery)([
1039
- "as:object"
1040
- ]);
1041
- let filtersWhereQuery = "";
1042
- if (filters) Object.keys(filters).forEach((predicate)=>{
1043
- if (filters[predicate]) {
1044
- const object = filters[predicate].startsWith("http") ? `<${filters[predicate]}>` : filters[predicate];
1045
- filtersWhereQuery += `?s1 ${predicate} ${object} .`;
1046
- }
1047
- });
1048
- const query = `
1049
- PREFIX as: <https://www.w3.org/ns/activitystreams#>
1050
- CONSTRUCT {
1051
- ?s1 ?p1 ?o1 .
1052
- ${blankNodesQuery.construct}
1053
- }
1054
- WHERE {
1055
- <${inboxUrl}> as:items ?s1 .
1056
- ?s1 ?p1 ?o1 .
1057
- FILTER( (isIRI(?s1)) ) .
1058
- ${filtersWhereQuery}
1059
- ${blankNodesQuery.where}
1060
- }
1061
- `;
1062
- const { json: json } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(sparqlEndpoint, {
1063
- method: "POST",
1064
- body: query,
1065
- headers: new Headers({
1066
- Accept: "application/ld+json",
1067
- Authorization: token ? `Bearer ${token}` : undefined
1068
- })
1069
- });
1070
- if (json["@graph"]) return json["@graph"];
1071
- return null;
1072
- }, [
1073
- sparqlEndpoint,
1074
- inboxUrl
1075
- ]);
1076
- return {
1077
- fetch: fetch,
1078
- url: inboxUrl,
1079
- owner: identity?.id
1080
- };
1081
- };
1082
- var $97664763db3c0a46$export$2e2bcd8739ae039 = $97664763db3c0a46$var$useInbox;
911
+ var $486f741c94cd8f74$export$2e2bcd8739ae039 = $486f741c94cd8f74$var$useInbox;
1083
912
 
1084
913
 
1085
914
 
1086
915
 
1087
- const $30fd77858150739b$var$useNodeinfo = (host, rel = "http://nodeinfo.diaspora.software/ns/schema/2.1")=>{
916
+ const $59fc2d2cba62bd8e$var$useNodeinfo = (host, rel = "http://nodeinfo.diaspora.software/ns/schema/2.1")=>{
1088
917
  const [schema, setSchema] = (0, $583VT$react.useState)();
1089
918
  (0, $583VT$react.useEffect)(()=>{
1090
919
  (async ()=>{
1091
- const protocol = host.includes(":") ? "http" : "https"; // If the host has a port, we are likely on HTTP
1092
- const nodeinfoUrl = `${protocol}://${host}/.well-known/nodeinfo`;
1093
- try {
1094
- const { json: links } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(nodeinfoUrl);
1095
- // Accept any version of the nodeinfo protocol
1096
- const link = links?.links?.find((l)=>l.rel === rel);
1097
- const { json: json } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(link.href);
1098
- setSchema(json);
1099
- } catch (e) {
1100
- // Do nothing if nodeinfo can't be fetched
920
+ if (host && rel) {
921
+ const protocol = host.includes(":") ? "http" : "https"; // If the host has a port, we are likely on HTTP
922
+ const nodeinfoUrl = `${protocol}://${host}/.well-known/nodeinfo`;
923
+ try {
924
+ const { json: links } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(nodeinfoUrl);
925
+ // Accept any version of the nodeinfo protocol
926
+ const link = links?.links?.find((l)=>l.rel === rel);
927
+ if (link) {
928
+ const { json: json } = await (0, $583VT$reactadmin.fetchUtils).fetchJson(link.href);
929
+ setSchema(json);
930
+ }
931
+ } catch (e) {
932
+ // Do nothing if nodeinfo can't be fetched
933
+ }
1101
934
  }
1102
935
  })();
1103
936
  }, [
@@ -1107,7 +940,7 @@ const $30fd77858150739b$var$useNodeinfo = (host, rel = "http://nodeinfo.diaspora
1107
940
  ]);
1108
941
  return schema;
1109
942
  };
1110
- var $30fd77858150739b$export$2e2bcd8739ae039 = $30fd77858150739b$var$useNodeinfo;
943
+ var $59fc2d2cba62bd8e$export$2e2bcd8739ae039 = $59fc2d2cba62bd8e$var$useNodeinfo;
1111
944
 
1112
945
 
1113
946