@semapps/activitypub-components 0.6.7 → 0.8.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 +413 -545
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +215 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +420 -552
- package/dist/index.es.js.map +1 -1
- package/package.json +6 -6
package/dist/index.es.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {jsxs as $85cNH$jsxs, Fragment as $85cNH$Fragment, jsx as $85cNH$jsx} from "react/jsx-runtime";
|
|
2
|
-
import $85cNH$react, {useState as $85cNH$useState, useCallback as $85cNH$useCallback, useMemo as $85cNH$useMemo, useEffect as $85cNH$useEffect, forwardRef as $85cNH$forwardRef, useImperativeHandle as $85cNH$useImperativeHandle} from "react";
|
|
3
|
-
import {useRecordContext as $85cNH$useRecordContext, useGetIdentity as $85cNH$useGetIdentity, useNotify as $85cNH$useNotify, Form as $85cNH$Form,
|
|
2
|
+
import $85cNH$react, {useState as $85cNH$useState, useCallback as $85cNH$useCallback, useMemo as $85cNH$useMemo, useRef as $85cNH$useRef, useEffect as $85cNH$useEffect, forwardRef as $85cNH$forwardRef, useImperativeHandle as $85cNH$useImperativeHandle} from "react";
|
|
3
|
+
import {useRecordContext as $85cNH$useRecordContext, useGetIdentity as $85cNH$useGetIdentity, useNotify as $85cNH$useNotify, Form as $85cNH$Form, useDataProvider as $85cNH$useDataProvider, TextField as $85cNH$TextField, DateField as $85cNH$DateField, RichTextField as $85cNH$RichTextField, useGetMany as $85cNH$useGetMany, useList as $85cNH$useList, ListContextProvider as $85cNH$ListContextProvider, fetchUtils as $85cNH$fetchUtils, useGetList as $85cNH$useGetList} from "react-admin";
|
|
4
4
|
import {RichTextInput as $85cNH$RichTextInput, DefaultEditorOptions as $85cNH$DefaultEditorOptions} from "ra-input-rich-text";
|
|
5
5
|
import $85cNH$tiptapextensionplaceholder from "@tiptap/extension-placeholder";
|
|
6
6
|
import {Box as $85cNH$Box, Avatar as $85cNH$Avatar, Button as $85cNH$Button, Typography as $85cNH$Typography, CircularProgress as $85cNH$CircularProgress} from "@mui/material";
|
|
7
7
|
import $85cNH$muistylesmakeStyles from "@mui/styles/makeStyles";
|
|
8
8
|
import $85cNH$muiiconsmaterialSend from "@mui/icons-material/Send";
|
|
9
|
-
import {useDataModel as $85cNH$useDataModel,
|
|
9
|
+
import {useDataModel as $85cNH$useDataModel, getOrCreateWsChannel as $85cNH$getOrCreateWsChannel} from "@semapps/semantic-data-provider";
|
|
10
10
|
import {AuthDialog as $85cNH$AuthDialog} from "@semapps/auth-provider";
|
|
11
|
+
import {useQueries as $85cNH$useQueries, useQueryClient as $85cNH$useQueryClient, useInfiniteQuery as $85cNH$useInfiniteQuery} from "react-query";
|
|
11
12
|
import {mergeAttributes as $85cNH$mergeAttributes} from "@tiptap/core";
|
|
12
13
|
import $85cNH$tiptapextensionmention from "@tiptap/extension-mention";
|
|
13
14
|
import {ReferenceField as $85cNH$ReferenceField, AvatarWithLabelField as $85cNH$AvatarWithLabelField} from "@semapps/field-components";
|
|
14
|
-
import {useQueries as $85cNH$useQueries, useInfiniteQuery as $85cNH$useInfiniteQuery, useQueryClient as $85cNH$useQueryClient} from "react-query";
|
|
15
15
|
import {ReactRenderer as $85cNH$ReactRenderer} from "@tiptap/react";
|
|
16
16
|
import $85cNH$tippyjs from "tippy.js";
|
|
17
17
|
|
|
@@ -86,78 +86,376 @@ const $338f387df48a40d7$export$4d8d554031975581 = "https://www.w3.org/ns/activit
|
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
const $577f4953dfa5de4f$export$e57ff0f701c44363 = (value)=>{
|
|
93
|
+
// If the field is null-ish, we suppose there are no values.
|
|
94
|
+
if (value === null || value === undefined) return [];
|
|
95
|
+
// Return as is.
|
|
96
|
+
if (Array.isArray(value)) return value;
|
|
97
|
+
// Single value is made an array.
|
|
98
|
+
return [
|
|
99
|
+
value
|
|
100
|
+
];
|
|
101
|
+
};
|
|
102
|
+
var $577f4953dfa5de4f$export$2e2bcd8739ae039 = {
|
|
103
|
+
arrayOf: $577f4953dfa5de4f$export$e57ff0f701c44363
|
|
104
|
+
};
|
|
105
|
+
const $577f4953dfa5de4f$export$34aed805e991a647 = (iterable, predicate)=>{
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
return iterable.filter((item)=>{
|
|
108
|
+
const key = predicate(item);
|
|
109
|
+
if (seen.has(key)) return false;
|
|
110
|
+
seen.add(key);
|
|
111
|
+
return true;
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
const $8281f3ce3b9d6123$var$useItemsFromPages = (pages, dereferenceItems)=>{
|
|
117
|
+
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
118
|
+
const items = (0, $85cNH$useMemo)(()=>pages.flatMap((p)=>(0, $577f4953dfa5de4f$export$e57ff0f701c44363)(p.orderedItems || p.items)), [
|
|
119
|
+
pages
|
|
120
|
+
]);
|
|
121
|
+
// We will force dereference, if some items are not URI string references.
|
|
122
|
+
const shouldDereference = (0, $85cNH$useMemo)(()=>{
|
|
123
|
+
return dereferenceItems || items.some((item)=>typeof item !== "string");
|
|
124
|
+
}, [
|
|
125
|
+
dereferenceItems,
|
|
126
|
+
items
|
|
127
|
+
]);
|
|
128
|
+
// Dereference all items, if necessary (even if shouldDereference is false, the hook needs to be called).
|
|
129
|
+
const itemQueries = (0, $85cNH$useQueries)(!shouldDereference ? [] : items.filter((item)=>typeof item === "string").map((itemUri)=>({
|
|
130
|
+
queryKey: [
|
|
131
|
+
"resource",
|
|
132
|
+
itemUri
|
|
133
|
+
],
|
|
134
|
+
queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
|
|
135
|
+
staleTime: Infinity
|
|
136
|
+
})));
|
|
137
|
+
if (!shouldDereference) return {
|
|
138
|
+
loadedItems: items,
|
|
139
|
+
isLoading: false,
|
|
140
|
+
isFetching: false
|
|
141
|
+
};
|
|
142
|
+
// Put all loaded items together (might be dereferenced already, so concatenate).
|
|
143
|
+
const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
|
|
144
|
+
return itemQuery.isSuccess && itemQuery.data || [];
|
|
145
|
+
}));
|
|
146
|
+
const errors = itemQueries.filter((q)=>q.error);
|
|
147
|
+
return {
|
|
148
|
+
loadedItems: loadedItems,
|
|
149
|
+
isLoading: itemQueries.some((q)=>q.isLoading),
|
|
150
|
+
isFetching: itemQueries.some((q)=>q.isFetching),
|
|
151
|
+
errors: errors.length > 0 ? errors : undefined
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Subscribe a collection. Supports pagination.
|
|
156
|
+
* @param predicateOrUrl The collection URI or the predicate to get the collection URI from the identity (webId).
|
|
157
|
+
* @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
|
|
158
|
+
*/ const $8281f3ce3b9d6123$var$useCollection = (predicateOrUrl, options = {})=>{
|
|
159
|
+
const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
|
|
90
160
|
const { data: identity } = (0, $85cNH$useGetIdentity)();
|
|
91
|
-
const
|
|
92
|
-
|
|
161
|
+
const [totalItems, setTotalItems] = (0, $85cNH$useState)();
|
|
162
|
+
const queryClient = (0, $85cNH$useQueryClient)();
|
|
163
|
+
const [hasLiveUpdates, setHasLiveUpdates] = (0, $85cNH$useState)({
|
|
164
|
+
status: "connecting"
|
|
165
|
+
});
|
|
166
|
+
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
167
|
+
const webSocketRef = (0, $85cNH$useRef)(null);
|
|
168
|
+
// Get collectionUrl from webId predicate or URL.
|
|
169
|
+
const collectionUrl = (0, $85cNH$useMemo)(()=>{
|
|
170
|
+
if (predicateOrUrl) {
|
|
171
|
+
if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
|
|
172
|
+
if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
175
|
+
// throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
|
|
93
176
|
}, [
|
|
94
|
-
identity
|
|
177
|
+
identity,
|
|
178
|
+
predicateOrUrl
|
|
95
179
|
]);
|
|
96
|
-
|
|
97
|
-
|
|
180
|
+
// Fetch page of collection item references (if pageParam provided)
|
|
181
|
+
// or default to `collectionUrl` (which should give you the first page).
|
|
182
|
+
const fetchCollection = (0, $85cNH$useCallback)(async ({ pageParam: nextPageUrl })=>{
|
|
183
|
+
// Fetch page or first page (collectionUrl)
|
|
184
|
+
let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
|
|
185
|
+
if (json.totalItems) setTotalItems(json.totalItems);
|
|
186
|
+
// If first page, handle this here.
|
|
187
|
+
if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
|
|
188
|
+
if (json.first?.items) {
|
|
189
|
+
if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
|
|
190
|
+
({ json: json } = await dataProvider.fetch(json.first?.next));
|
|
191
|
+
else json = json.first;
|
|
192
|
+
} else // Fetch the first page
|
|
193
|
+
({ json: json } = await dataProvider.fetch(json.first));
|
|
194
|
+
}
|
|
195
|
+
return json;
|
|
196
|
+
}, [
|
|
197
|
+
dataProvider,
|
|
198
|
+
collectionUrl,
|
|
199
|
+
identity,
|
|
200
|
+
setTotalItems
|
|
201
|
+
]);
|
|
202
|
+
// Use infiniteQuery to handle pagination, fetching, etc.
|
|
203
|
+
const { data: pageData, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $85cNH$useInfiniteQuery)([
|
|
204
|
+
"collection",
|
|
205
|
+
{
|
|
206
|
+
collectionUrl: collectionUrl
|
|
207
|
+
}
|
|
208
|
+
], fetchCollection, {
|
|
209
|
+
enabled: !!(collectionUrl && identity?.id),
|
|
210
|
+
getNextPageParam: (lastPage)=>lastPage.next,
|
|
211
|
+
getPreviousPageParam: (firstPage)=>firstPage.prev
|
|
212
|
+
});
|
|
213
|
+
// Put all items together in a list (and dereference, if required).
|
|
214
|
+
const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $8281f3ce3b9d6123$var$useItemsFromPages(pageData?.pages ?? [], dereferenceItems);
|
|
215
|
+
const allErrors = (0, $577f4953dfa5de4f$export$e57ff0f701c44363)(collectionError).concat((0, $577f4953dfa5de4f$export$e57ff0f701c44363)(itemErrors));
|
|
216
|
+
const addItem = (0, $85cNH$useCallback)((item, shouldRefetch = true)=>{
|
|
217
|
+
queryClient.setQueryData([
|
|
218
|
+
"collection",
|
|
219
|
+
{
|
|
220
|
+
collectionUrl: collectionUrl
|
|
221
|
+
}
|
|
222
|
+
], (oldData)=>{
|
|
223
|
+
if (!oldData) return oldData;
|
|
224
|
+
setTotalItems(totalItems && totalItems + 1);
|
|
225
|
+
// Destructure, so react knows, it needs to re-render the pages.
|
|
226
|
+
const pages = [
|
|
227
|
+
...oldData.pages
|
|
228
|
+
];
|
|
229
|
+
const firstPageItems = pages?.[0]?.orderedItems || pages?.[0]?.items || [];
|
|
230
|
+
firstPageItems.unshift(item);
|
|
231
|
+
oldData.pages = pages;
|
|
232
|
+
return oldData;
|
|
233
|
+
});
|
|
234
|
+
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
235
|
+
"collection",
|
|
236
|
+
{
|
|
237
|
+
collectionUrl: collectionUrl
|
|
238
|
+
}
|
|
239
|
+
], {
|
|
240
|
+
active: true,
|
|
241
|
+
exact: true
|
|
242
|
+
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
243
|
+
}, [
|
|
244
|
+
queryClient,
|
|
245
|
+
collectionUrl
|
|
246
|
+
]);
|
|
247
|
+
const removeItem = (0, $85cNH$useCallback)((item, shouldRefetch = true)=>{
|
|
248
|
+
queryClient.setQueryData([
|
|
249
|
+
"collection",
|
|
250
|
+
{
|
|
251
|
+
collectionUrl: collectionUrl
|
|
252
|
+
}
|
|
253
|
+
], (oldData)=>{
|
|
254
|
+
if (!oldData) return oldData;
|
|
255
|
+
setTotalItems(totalItems && totalItems - 1);
|
|
256
|
+
// Destructure, so react knows, it needs to re-render the pages array.
|
|
257
|
+
const pages = [
|
|
258
|
+
...oldData.pages
|
|
259
|
+
];
|
|
260
|
+
// Find the item in all pages and remove the item to be removed (either item.id or just item)
|
|
261
|
+
pages.forEach((page)=>{
|
|
262
|
+
if (page.orderedItems) page.orderedItems = page.orderedItems.filter((i)=>(i.id || i) !== (item.id || item));
|
|
263
|
+
else if (page.items) page.items = page.items.filter((i)=>(i.id || i) !== (item?.id || item));
|
|
264
|
+
});
|
|
265
|
+
oldData.pages = pages;
|
|
266
|
+
return oldData;
|
|
267
|
+
});
|
|
268
|
+
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
269
|
+
"collection",
|
|
270
|
+
{
|
|
271
|
+
collectionUrl: collectionUrl
|
|
272
|
+
}
|
|
273
|
+
], {
|
|
274
|
+
active: true,
|
|
275
|
+
exact: true
|
|
276
|
+
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
277
|
+
}, [
|
|
278
|
+
queryClient,
|
|
279
|
+
collectionUrl
|
|
280
|
+
]);
|
|
281
|
+
// Live Updates
|
|
282
|
+
(0, $85cNH$useEffect)(()=>{
|
|
283
|
+
if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
|
|
284
|
+
(0, $85cNH$getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((ws)=>{
|
|
285
|
+
webSocketRef.current = ws; // Keep a ref to the webSocket so that it can be used elsewhere
|
|
286
|
+
webSocketRef.current.addEventListener("message", (e)=>{
|
|
287
|
+
const data = JSON.parse(e.data);
|
|
288
|
+
if (data.type === "Add") addItem(data.object, true);
|
|
289
|
+
else if (data.type === "Remove") removeItem(data.object, true);
|
|
290
|
+
});
|
|
291
|
+
webSocketRef.current.addEventListener("error", (e)=>{
|
|
292
|
+
setHasLiveUpdates({
|
|
293
|
+
status: "error",
|
|
294
|
+
error: e
|
|
295
|
+
});
|
|
296
|
+
// TODO: Retry after a while
|
|
297
|
+
});
|
|
298
|
+
webSocketRef.current.addEventListener("close", (e)=>{
|
|
299
|
+
if (!hasLiveUpdates.error) setHasLiveUpdates({
|
|
300
|
+
...hasLiveUpdates,
|
|
301
|
+
status: "closed"
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
setHasLiveUpdates({
|
|
305
|
+
status: "connected"
|
|
306
|
+
});
|
|
307
|
+
}).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
|
|
308
|
+
}, [
|
|
309
|
+
collectionUrl,
|
|
310
|
+
liveUpdates,
|
|
311
|
+
dataProvider,
|
|
312
|
+
webSocketRef
|
|
313
|
+
]);
|
|
314
|
+
const awaitWebSocketConnection = (0, $85cNH$useCallback)((options = {})=>{
|
|
315
|
+
const { timeout: timeout = 30000 } = options;
|
|
316
|
+
return new Promise((resolve, reject)=>{
|
|
317
|
+
if (webSocketRef?.current) resolve(webSocketRef);
|
|
318
|
+
else {
|
|
319
|
+
const timeoutId = setTimeout(()=>{
|
|
320
|
+
reject(`No WebSocket connection found within ${Math.round(timeout / 1000)}s`);
|
|
321
|
+
}, timeout);
|
|
322
|
+
const intervalId = setInterval(()=>{
|
|
323
|
+
if (webSocketRef?.current) {
|
|
324
|
+
clearInterval(intervalId);
|
|
325
|
+
clearTimeout(timeoutId);
|
|
326
|
+
resolve(webSocketRef);
|
|
327
|
+
} else console.log("WebSocket is not initialized yet, waiting...");
|
|
328
|
+
}, 100);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
98
331
|
}, [
|
|
99
|
-
|
|
332
|
+
webSocketRef
|
|
100
333
|
]);
|
|
334
|
+
return {
|
|
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,
|
|
348
|
+
awaitWebSocketConnection: awaitWebSocketConnection,
|
|
349
|
+
webSocketRef: webSocketRef
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
var $8281f3ce3b9d6123$export$2e2bcd8739ae039 = $8281f3ce3b9d6123$var$useCollection;
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Hook used internally by useInbox and useOutbox. This is not exported.
|
|
359
|
+
* @param awaitWebSocketConnection Promise returning the WebSocket which allow to listen to the inbox or outbox
|
|
360
|
+
* @param existingActivities Partial list of activities already received in the inbox and outbox
|
|
361
|
+
*/ const $600ca419166a1ded$var$useAwaitActivity = (awaitWebSocketConnection, existingActivities)=>{
|
|
362
|
+
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
363
|
+
// TODO Allow to pass an object, and automatically dereference it if required, like on the @semapps/activitypub matchActivity util
|
|
364
|
+
return (0, $85cNH$useCallback)((matchActivity, options = {})=>{
|
|
365
|
+
const { timeout: timeout = 30000, checkExistingActivities: checkExistingActivities = false } = options;
|
|
366
|
+
return new Promise((resolve, reject)=>{
|
|
367
|
+
awaitWebSocketConnection().then((webSocketRef)=>{
|
|
368
|
+
const onMessage = (event)=>{
|
|
369
|
+
const data = JSON.parse(event.data);
|
|
370
|
+
if (data.type === "Add") dataProvider.fetch(data.object).then(({ json: json })=>{
|
|
371
|
+
if (matchActivity(json)) {
|
|
372
|
+
removeListeners();
|
|
373
|
+
return resolve(json);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
};
|
|
377
|
+
const onError = (e)=>{
|
|
378
|
+
// TODO reconnect if connection closed
|
|
379
|
+
removeListeners();
|
|
380
|
+
reject(e);
|
|
381
|
+
};
|
|
382
|
+
const onClose = (e)=>{
|
|
383
|
+
removeListeners();
|
|
384
|
+
reject(new Error(`${e.reason} (Code: ${e.code})`));
|
|
385
|
+
};
|
|
386
|
+
const removeListeners = ()=>{
|
|
387
|
+
webSocketRef.current?.removeEventListener("message", onMessage);
|
|
388
|
+
webSocketRef.current?.removeEventListener("error", onError);
|
|
389
|
+
webSocketRef.current?.removeEventListener("close", onClose);
|
|
390
|
+
};
|
|
391
|
+
webSocketRef.current?.addEventListener("message", onMessage);
|
|
392
|
+
webSocketRef.current?.addEventListener("error", onError);
|
|
393
|
+
webSocketRef.current?.addEventListener("close", onClose);
|
|
394
|
+
// If a list of activities is already loaded, verify if there is a match
|
|
395
|
+
if (existingActivities && checkExistingActivities) for (const a of existingActivities){
|
|
396
|
+
if (typeof a !== "string") {
|
|
397
|
+
if (matchActivity(a)) {
|
|
398
|
+
removeListeners();
|
|
399
|
+
return resolve(a);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
setTimeout(()=>{
|
|
404
|
+
removeListeners();
|
|
405
|
+
reject(new Error("Timeout"));
|
|
406
|
+
}, timeout);
|
|
407
|
+
}).catch((e)=>{
|
|
408
|
+
reject(e);
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
}, [
|
|
412
|
+
awaitWebSocketConnection,
|
|
413
|
+
existingActivities,
|
|
414
|
+
dataProvider
|
|
415
|
+
]);
|
|
416
|
+
};
|
|
417
|
+
var $600ca419166a1ded$export$2e2bcd8739ae039 = $600ca419166a1ded$var$useAwaitActivity;
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Hook to fetch and post to the outbox of the logged user.
|
|
422
|
+
* Returns the same data as the useCollection hooks, plus:
|
|
423
|
+
* - `post`: a function to post a new activity in the user's outbox
|
|
424
|
+
* - `awaitActivity`: a function to wait for a certain activity to be posted
|
|
425
|
+
* - `owner`: the WebID of the outbox's owner
|
|
426
|
+
* See https://semapps.org/docs/frontend/activitypub-components#useoutbox for usage
|
|
427
|
+
* @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
|
|
428
|
+
*/ const $4d1d40fdbcd30589$var$useOutbox = (options = {})=>{
|
|
429
|
+
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
430
|
+
const { data: identity } = (0, $85cNH$useGetIdentity)();
|
|
431
|
+
const { url: url, items: items, awaitWebSocketConnection: awaitWebSocketConnection, ...rest } = (0, $8281f3ce3b9d6123$export$2e2bcd8739ae039)("outbox", options);
|
|
432
|
+
const awaitActivity = (0, $600ca419166a1ded$export$2e2bcd8739ae039)(awaitWebSocketConnection, items);
|
|
101
433
|
// Post an activity to the logged user's outbox and return its URI
|
|
102
434
|
const post = (0, $85cNH$useCallback)(async (activity)=>{
|
|
103
|
-
if (!
|
|
104
|
-
const
|
|
105
|
-
const { headers: headers } = await (0, $85cNH$fetchUtils).fetchJson(outboxUrl, {
|
|
435
|
+
if (!url) throw new Error("Cannot post to outbox before user identity is loaded. Please use the isLoading argument of useOutbox");
|
|
436
|
+
const { headers: headers } = await dataProvider.fetch(url, {
|
|
106
437
|
method: "POST",
|
|
107
438
|
body: JSON.stringify({
|
|
108
439
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
109
440
|
...activity
|
|
110
|
-
}),
|
|
111
|
-
headers: new Headers({
|
|
112
|
-
"Content-Type": "application/ld+json",
|
|
113
|
-
Authorization: `Bearer ${token}`
|
|
114
441
|
})
|
|
115
442
|
});
|
|
116
443
|
return headers.get("Location");
|
|
117
444
|
}, [
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const fetch = (0, $85cNH$useCallback)(async ()=>{
|
|
121
|
-
if (!sparqlEndpoint || !outboxUrl) return;
|
|
122
|
-
const token = localStorage.getItem("token");
|
|
123
|
-
const blankNodesQuery = (0, $85cNH$buildBlankNodesQuery)([
|
|
124
|
-
"as:object"
|
|
125
|
-
]);
|
|
126
|
-
const query = `
|
|
127
|
-
PREFIX as: <https://www.w3.org/ns/activitystreams#>
|
|
128
|
-
CONSTRUCT {
|
|
129
|
-
?s1 ?p1 ?o1 .
|
|
130
|
-
${blankNodesQuery.construct}
|
|
131
|
-
}
|
|
132
|
-
WHERE {
|
|
133
|
-
<${outboxUrl}> as:items ?s1 .
|
|
134
|
-
?s1 ?p1 ?o1 .
|
|
135
|
-
${blankNodesQuery.where}
|
|
136
|
-
}
|
|
137
|
-
`;
|
|
138
|
-
const { json: json } = await (0, $85cNH$fetchUtils).fetchJson(sparqlEndpoint, {
|
|
139
|
-
method: "POST",
|
|
140
|
-
body: query,
|
|
141
|
-
headers: new Headers({
|
|
142
|
-
Accept: "application/ld+json",
|
|
143
|
-
Authorization: token ? `Bearer ${token}` : undefined
|
|
144
|
-
})
|
|
145
|
-
});
|
|
146
|
-
if (json["@graph"]) return json["@graph"];
|
|
147
|
-
return null;
|
|
148
|
-
}, [
|
|
149
|
-
sparqlEndpoint,
|
|
150
|
-
outboxUrl
|
|
445
|
+
url,
|
|
446
|
+
dataProvider
|
|
151
447
|
]);
|
|
152
448
|
return {
|
|
449
|
+
url: url,
|
|
450
|
+
items: items,
|
|
451
|
+
awaitWebSocketConnection: awaitWebSocketConnection,
|
|
153
452
|
post: post,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
owner: identity?.id
|
|
453
|
+
awaitActivity: awaitActivity,
|
|
454
|
+
owner: identity?.id,
|
|
455
|
+
...rest
|
|
158
456
|
};
|
|
159
457
|
};
|
|
160
|
-
var $
|
|
458
|
+
var $4d1d40fdbcd30589$export$2e2bcd8739ae039 = $4d1d40fdbcd30589$var$useOutbox;
|
|
161
459
|
|
|
162
460
|
|
|
163
461
|
|
|
@@ -262,7 +560,7 @@ const $3c17312a40ebf1ed$var$PostCommentForm = ({ context: context, placeholder:
|
|
|
262
560
|
const userDataModel = (0, $85cNH$useDataModel)(userResource);
|
|
263
561
|
const classes = $3c17312a40ebf1ed$var$useStyles();
|
|
264
562
|
const notify = (0, $85cNH$useNotify)();
|
|
265
|
-
const outbox = (0, $
|
|
563
|
+
const outbox = (0, $4d1d40fdbcd30589$export$2e2bcd8739ae039)();
|
|
266
564
|
const [expanded, setExpanded] = (0, $85cNH$useState)(false);
|
|
267
565
|
const [openAuth, setOpenAuth] = (0, $85cNH$useState)(false);
|
|
268
566
|
const onSubmit = (0, $85cNH$useCallback)(async (values)=>{
|
|
@@ -487,221 +785,44 @@ const $be88b298220210d1$var$CommentsList = ({ comments: comments, userResource:
|
|
|
487
785
|
}),
|
|
488
786
|
"\xa0\u2022\xa0",
|
|
489
787
|
/*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$DateField), {
|
|
490
|
-
record: comment,
|
|
491
|
-
variant: "body2",
|
|
492
|
-
source: "published",
|
|
493
|
-
showTime: true
|
|
494
|
-
})
|
|
495
|
-
]
|
|
496
|
-
}),
|
|
497
|
-
/*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$RichTextField), {
|
|
498
|
-
record: comment,
|
|
499
|
-
variant: "body1",
|
|
500
|
-
source: "content",
|
|
501
|
-
className: classes.content
|
|
502
|
-
})
|
|
503
|
-
]
|
|
504
|
-
})
|
|
505
|
-
]
|
|
506
|
-
}, comment.id)),
|
|
507
|
-
loading && /*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$Box), {
|
|
508
|
-
minHeight: 200,
|
|
509
|
-
children: /*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$Box), {
|
|
510
|
-
alignItems: "center",
|
|
511
|
-
className: classes.loading,
|
|
512
|
-
children: /*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$CircularProgress), {
|
|
513
|
-
size: 60,
|
|
514
|
-
thickness: 6
|
|
515
|
-
})
|
|
516
|
-
})
|
|
517
|
-
})
|
|
518
|
-
]
|
|
519
|
-
});
|
|
520
|
-
};
|
|
521
|
-
var $be88b298220210d1$export$2e2bcd8739ae039 = $be88b298220210d1$var$CommentsList;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const $577f4953dfa5de4f$export$e57ff0f701c44363 = (value)=>{
|
|
529
|
-
// If the field is null-ish, we suppose there are no values.
|
|
530
|
-
if (value === null || value === undefined) return [];
|
|
531
|
-
// Return as is.
|
|
532
|
-
if (Array.isArray(value)) return value;
|
|
533
|
-
// Single value is made an array.
|
|
534
|
-
return [
|
|
535
|
-
value
|
|
536
|
-
];
|
|
537
|
-
};
|
|
538
|
-
var $577f4953dfa5de4f$export$2e2bcd8739ae039 = {
|
|
539
|
-
arrayOf: $577f4953dfa5de4f$export$e57ff0f701c44363
|
|
540
|
-
};
|
|
541
|
-
const $577f4953dfa5de4f$export$34aed805e991a647 = (iterable, predicate)=>{
|
|
542
|
-
const seen = new Set();
|
|
543
|
-
return iterable.filter((item)=>{
|
|
544
|
-
const key = predicate(item);
|
|
545
|
-
if (seen.has(key)) return false;
|
|
546
|
-
seen.add(key);
|
|
547
|
-
return true;
|
|
548
|
-
});
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
const $c1e897431d8c5742$var$useItemsFromPagesAndNotifications = (pages, notifications, dereferenceItems)=>{
|
|
553
|
-
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
554
|
-
// Add all items from pages and process notifications (possibly new and deleted items).
|
|
555
|
-
const items = (0, $85cNH$useMemo)(()=>{
|
|
556
|
-
const addItems = notifications.map((n)=>n.type === "Add").map((n)=>n.object);
|
|
557
|
-
const removeItems = notifications.map((n)=>n.type === "Remove").map((n)=>n.object.id || n.object);
|
|
558
|
-
const currentItems = !pages ? [] : pages.flatMap((p)=>(0, $577f4953dfa5de4f$export$e57ff0f701c44363)(p.orderedItems || p.items));
|
|
559
|
-
const currentAndNew = currentItems.concat(addItems);
|
|
560
|
-
return currentAndNew// Filter out removed items.
|
|
561
|
-
.filter((item)=>!removeItems.some((r)=>(r.id ?? r) === (item.id ?? item)))// Filter duplicates.
|
|
562
|
-
.filter((item)=>currentAndNew.some((i2)=>(i2.id ?? i2) === (item.id ?? item)));
|
|
563
|
-
}, pages, notifications);
|
|
564
|
-
if (!dereferenceItems) return {
|
|
565
|
-
loadedItems: items,
|
|
566
|
-
isLoading: false,
|
|
567
|
-
isFetching: false
|
|
568
|
-
};
|
|
569
|
-
// Dereference all items, if they are not yet.
|
|
570
|
-
const itemQueries = (0, $85cNH$useQueries)(items.filter((item)=>typeof item === "string").map((itemUri)=>({
|
|
571
|
-
queryKey: [
|
|
572
|
-
"resource",
|
|
573
|
-
itemUri
|
|
574
|
-
],
|
|
575
|
-
queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
|
|
576
|
-
staleTime: Infinity
|
|
577
|
-
})));
|
|
578
|
-
// Put all loaded items together (might be dereferenced already, so concatenate).
|
|
579
|
-
const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
|
|
580
|
-
return itemQuery.isSuccess && itemQuery.data || [];
|
|
581
|
-
}));
|
|
582
|
-
console.log("loadedItems", loadedItems.length, "total", items.length);
|
|
583
|
-
const errors = itemQueries.filter((q)=>q.error);
|
|
584
|
-
return {
|
|
585
|
-
loadedItems: loadedItems,
|
|
586
|
-
isLoading: itemQueries.some((q)=>q.isLoading),
|
|
587
|
-
isFetching: itemQueries.some((q)=>q.isFetching),
|
|
588
|
-
errors: errors.length > 0 && errors
|
|
589
|
-
};
|
|
590
|
-
};
|
|
591
|
-
const $c1e897431d8c5742$var$useCollection = (predicateOrUrl, options = {})=>{
|
|
592
|
-
const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
|
|
593
|
-
const { data: identity } = (0, $85cNH$useGetIdentity)();
|
|
594
|
-
const [totalItems, setTotalItems] = (0, $85cNH$useState)();
|
|
595
|
-
const [notifications, setNotifications] = (0, $85cNH$useState)([]);
|
|
596
|
-
const [hasLiveUpdates, setHasLiveUpdates] = (0, $85cNH$useState)({
|
|
597
|
-
status: "disconnected",
|
|
598
|
-
error: undefined
|
|
599
|
-
});
|
|
600
|
-
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
601
|
-
// Get collectionUrl from webId predicate or URL.
|
|
602
|
-
const collectionUrl = (0, $85cNH$useMemo)(()=>{
|
|
603
|
-
if (predicateOrUrl) {
|
|
604
|
-
if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
|
|
605
|
-
if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
|
|
606
|
-
}
|
|
607
|
-
return undefined;
|
|
608
|
-
// throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
|
|
609
|
-
}, [
|
|
610
|
-
identity,
|
|
611
|
-
predicateOrUrl
|
|
612
|
-
]);
|
|
613
|
-
// Fetch page of collection item references (if pageParam provided)
|
|
614
|
-
// or default to `collectionUrl` (which should give you the first page).
|
|
615
|
-
const fetchCollection = (0, $85cNH$useCallback)(async ({ pageParam: nextPageUrl })=>{
|
|
616
|
-
// Fetch page or first page (collectionUrl)
|
|
617
|
-
let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
|
|
618
|
-
if (json.totalItems) setTotalItems(json.totalItems);
|
|
619
|
-
// If first page, handle this here.
|
|
620
|
-
if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
|
|
621
|
-
if (json.first?.items) {
|
|
622
|
-
if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
|
|
623
|
-
({ json: json } = await dataProvider.fetch(json.first?.next));
|
|
624
|
-
else json = json.first;
|
|
625
|
-
} else // Fetch the first page
|
|
626
|
-
({ json: json } = await dataProvider.fetch(json.first));
|
|
627
|
-
}
|
|
628
|
-
return json;
|
|
629
|
-
}, [
|
|
630
|
-
dataProvider,
|
|
631
|
-
collectionUrl,
|
|
632
|
-
identity,
|
|
633
|
-
setTotalItems
|
|
634
|
-
]);
|
|
635
|
-
// Use infiniteQuery to handle pagination, fetching, etc.
|
|
636
|
-
const { data: data, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $85cNH$useInfiniteQuery)([
|
|
637
|
-
"collection",
|
|
638
|
-
{
|
|
639
|
-
collectionUrl: collectionUrl
|
|
640
|
-
}
|
|
641
|
-
], fetchCollection, {
|
|
642
|
-
enabled: !!(collectionUrl && identity?.id),
|
|
643
|
-
getNextPageParam: (lastPage)=>lastPage.next,
|
|
644
|
-
getPreviousPageParam: (firstPage)=>firstPage.prev
|
|
645
|
-
});
|
|
646
|
-
// Put all items together in a list.
|
|
647
|
-
const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $c1e897431d8c5742$var$useItemsFromPagesAndNotifications(data?.pages, notifications, dereferenceItems);
|
|
648
|
-
// Notifications have been processed after hook call, so reset.
|
|
649
|
-
// useEffect(() => {
|
|
650
|
-
// setNotifications([]);
|
|
651
|
-
// }, [notifications])
|
|
652
|
-
// Live Updates
|
|
653
|
-
(0, $85cNH$useEffect)(()=>{
|
|
654
|
-
if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
|
|
655
|
-
(0, $85cNH$getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((webSocket)=>{
|
|
656
|
-
webSocket.addEventListener("message", (e)=>{
|
|
657
|
-
if (e.data && e.data.type === "Add" || e.data.type === "Remove") setNotifications([
|
|
658
|
-
...notifications,
|
|
659
|
-
e.data
|
|
660
|
-
]);
|
|
661
|
-
});
|
|
662
|
-
webSocket.addEventListener("error", (e)=>{
|
|
663
|
-
setHasLiveUpdates({
|
|
664
|
-
status: "error",
|
|
665
|
-
error: e
|
|
666
|
-
});
|
|
667
|
-
// TODO: Retry after a while
|
|
668
|
-
});
|
|
669
|
-
webSocket.addEventListener("close", (e)=>{
|
|
670
|
-
setHasLiveUpdates({
|
|
671
|
-
...hasLiveUpdates,
|
|
672
|
-
status: "disconnected"
|
|
673
|
-
});
|
|
674
|
-
});
|
|
675
|
-
setHasLiveUpdates({
|
|
676
|
-
status: "connected"
|
|
677
|
-
});
|
|
678
|
-
}).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
|
|
679
|
-
}, [
|
|
680
|
-
collectionUrl,
|
|
681
|
-
liveUpdates,
|
|
682
|
-
dataProvider.fetch
|
|
683
|
-
]);
|
|
684
|
-
const allErrors = (0, $577f4953dfa5de4f$export$e57ff0f701c44363)(collectionError).concat((0, $577f4953dfa5de4f$export$e57ff0f701c44363)(itemErrors));
|
|
685
|
-
return {
|
|
686
|
-
items: items,
|
|
687
|
-
totalItems: totalItems,
|
|
688
|
-
error: allErrors.length > 0 && allErrors,
|
|
689
|
-
refetch: refetch,
|
|
690
|
-
fetchNextPage: fetchNextPage,
|
|
691
|
-
hasNextPage: hasNextPage,
|
|
692
|
-
isLoading: isLoadingPage || isLoadingItems,
|
|
693
|
-
isFetching: isFetchingPage || isFetchingItems,
|
|
694
|
-
isFetchingNextPage: isFetchingNextPage,
|
|
695
|
-
url: collectionUrl,
|
|
696
|
-
hasLiveUpdates: hasLiveUpdates
|
|
697
|
-
};
|
|
788
|
+
record: comment,
|
|
789
|
+
variant: "body2",
|
|
790
|
+
source: "published",
|
|
791
|
+
showTime: true
|
|
792
|
+
})
|
|
793
|
+
]
|
|
794
|
+
}),
|
|
795
|
+
/*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$RichTextField), {
|
|
796
|
+
record: comment,
|
|
797
|
+
variant: "body1",
|
|
798
|
+
source: "content",
|
|
799
|
+
className: classes.content
|
|
800
|
+
})
|
|
801
|
+
]
|
|
802
|
+
})
|
|
803
|
+
]
|
|
804
|
+
}, comment.id)),
|
|
805
|
+
loading && /*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$Box), {
|
|
806
|
+
minHeight: 200,
|
|
807
|
+
children: /*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$Box), {
|
|
808
|
+
alignItems: "center",
|
|
809
|
+
className: classes.loading,
|
|
810
|
+
children: /*#__PURE__*/ (0, $85cNH$jsx)((0, $85cNH$CircularProgress), {
|
|
811
|
+
size: 60,
|
|
812
|
+
thickness: 6
|
|
813
|
+
})
|
|
814
|
+
})
|
|
815
|
+
})
|
|
816
|
+
]
|
|
817
|
+
});
|
|
698
818
|
};
|
|
699
|
-
var $
|
|
819
|
+
var $be88b298220210d1$export$2e2bcd8739ae039 = $be88b298220210d1$var$CommentsList;
|
|
820
|
+
|
|
700
821
|
|
|
701
822
|
|
|
702
823
|
const $7ce737d4a1c88e63$var$CommentsField = ({ source: source, context: context, helperText: helperText, placeholder: placeholder, userResource: userResource, mentions: mentions })=>{
|
|
703
824
|
const record = (0, $85cNH$useRecordContext)();
|
|
704
|
-
const { items: comments, loading: loading, addItem: addItem, removeItem: removeItem } = (0, $
|
|
825
|
+
const { items: comments, loading: loading, addItem: addItem, removeItem: removeItem } = (0, $8281f3ce3b9d6123$export$2e2bcd8739ae039)(record.replies);
|
|
705
826
|
if (!userResource) throw new Error("No userResource defined for CommentsField");
|
|
706
827
|
return /*#__PURE__*/ (0, $85cNH$jsxs)((0, $85cNH$Fragment), {
|
|
707
828
|
children: [
|
|
@@ -737,7 +858,7 @@ var $7ce737d4a1c88e63$export$2e2bcd8739ae039 = $7ce737d4a1c88e63$var$CommentsFie
|
|
|
737
858
|
|
|
738
859
|
const $d3be168cd1e7aaae$var$CollectionList = ({ collectionUrl: collectionUrl, resource: resource, children: children })=>{
|
|
739
860
|
if ((0, $85cNH$react).Children.count(children) !== 1) throw new Error("<CollectionList> only accepts a single child");
|
|
740
|
-
const { items: actorsUris } = (0, $
|
|
861
|
+
const { items: actorsUris } = (0, $8281f3ce3b9d6123$export$2e2bcd8739ae039)(collectionUrl);
|
|
741
862
|
const { data: data, isLoading: isLoading, isFetching: isFetching } = (0, $85cNH$useGetMany)(resource, {
|
|
742
863
|
ids: Array.isArray(actorsUris) ? actorsUris : [
|
|
743
864
|
actorsUris
|
|
@@ -780,302 +901,49 @@ var $ea214512ab1a2e8f$export$2e2bcd8739ae039 = $ea214512ab1a2e8f$var$ReferenceCo
|
|
|
780
901
|
|
|
781
902
|
|
|
782
903
|
|
|
783
|
-
|
|
784
|
-
const $8281f3ce3b9d6123$var$useItemsFromPages = (pages, dereferenceItems)=>{
|
|
785
|
-
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
786
|
-
const items = (0, $85cNH$useMemo)(()=>pages.flatMap((p)=>(0, $577f4953dfa5de4f$export$e57ff0f701c44363)(p.orderedItems || p.items)), [
|
|
787
|
-
pages
|
|
788
|
-
]);
|
|
789
|
-
// We will force dereference, if some items are not URI string references.
|
|
790
|
-
const shouldDereference = (0, $85cNH$useMemo)(()=>{
|
|
791
|
-
return dereferenceItems || items.some((item)=>typeof item !== "string");
|
|
792
|
-
}, [
|
|
793
|
-
dereferenceItems,
|
|
794
|
-
items
|
|
795
|
-
]);
|
|
796
|
-
// Dereference all items, if necessary (even if shouldDereference is false, the hook needs to be called).
|
|
797
|
-
const itemQueries = (0, $85cNH$useQueries)(!shouldDereference ? [] : items.filter((item)=>typeof item === "string").map((itemUri)=>({
|
|
798
|
-
queryKey: [
|
|
799
|
-
"resource",
|
|
800
|
-
itemUri
|
|
801
|
-
],
|
|
802
|
-
queryFn: async ()=>(await dataProvider.fetch(itemUri)).json,
|
|
803
|
-
staleTime: Infinity
|
|
804
|
-
})));
|
|
805
|
-
if (!shouldDereference) return {
|
|
806
|
-
loadedItems: items,
|
|
807
|
-
isLoading: false,
|
|
808
|
-
isFetching: false
|
|
809
|
-
};
|
|
810
|
-
// Put all loaded items together (might be dereferenced already, so concatenate).
|
|
811
|
-
const loadedItems = items.filter((item)=>typeof item !== "string").concat(itemQueries.flatMap((itemQuery)=>{
|
|
812
|
-
return itemQuery.isSuccess && itemQuery.data || [];
|
|
813
|
-
}));
|
|
814
|
-
const errors = itemQueries.filter((q)=>q.error);
|
|
815
|
-
return {
|
|
816
|
-
loadedItems: loadedItems,
|
|
817
|
-
isLoading: itemQueries.some((q)=>q.isLoading),
|
|
818
|
-
isFetching: itemQueries.some((q)=>q.isFetching),
|
|
819
|
-
errors: errors.length > 0 ? errors : undefined
|
|
820
|
-
};
|
|
821
|
-
};
|
|
822
904
|
/**
|
|
823
|
-
*
|
|
824
|
-
*
|
|
905
|
+
* Hook to fetch the inbox of the logged user.
|
|
906
|
+
* Returns the same data as the useCollection hooks, plus:
|
|
907
|
+
* - `awaitActivity`: a function to wait for a certain activity to be received
|
|
908
|
+
* - `owner`: the WebID of the inbox's owner
|
|
909
|
+
* See https://semapps.org/docs/frontend/activitypub-components#useinbox for usage
|
|
825
910
|
* @param {UseCollectionOptions} options Defaults to `{ dereferenceItems: false, liveUpdates: true }`
|
|
826
|
-
*/ const $
|
|
827
|
-
const { dereferenceItems: dereferenceItems = false, liveUpdates: liveUpdates = true } = options;
|
|
911
|
+
*/ const $cc1d1cd0e97c63a2$var$useInbox = (options = {})=>{
|
|
828
912
|
const { data: identity } = (0, $85cNH$useGetIdentity)();
|
|
829
|
-
const
|
|
830
|
-
const
|
|
831
|
-
const [hasLiveUpdates, setHasLiveUpdates] = (0, $85cNH$useState)({
|
|
832
|
-
status: "connecting"
|
|
833
|
-
});
|
|
834
|
-
const dataProvider = (0, $85cNH$useDataProvider)();
|
|
835
|
-
// Get collectionUrl from webId predicate or URL.
|
|
836
|
-
const collectionUrl = (0, $85cNH$useMemo)(()=>{
|
|
837
|
-
if (predicateOrUrl) {
|
|
838
|
-
if (predicateOrUrl.startsWith("http")) return predicateOrUrl;
|
|
839
|
-
if (identity?.webIdData) return identity?.webIdData?.[predicateOrUrl];
|
|
840
|
-
}
|
|
841
|
-
return undefined;
|
|
842
|
-
// throw new Error(`No URL available for useCollection: ${predicateOrUrl}.`);
|
|
843
|
-
}, [
|
|
844
|
-
identity,
|
|
845
|
-
predicateOrUrl
|
|
846
|
-
]);
|
|
847
|
-
// Fetch page of collection item references (if pageParam provided)
|
|
848
|
-
// or default to `collectionUrl` (which should give you the first page).
|
|
849
|
-
const fetchCollection = (0, $85cNH$useCallback)(async ({ pageParam: nextPageUrl })=>{
|
|
850
|
-
// Fetch page or first page (collectionUrl)
|
|
851
|
-
let { json: json } = await dataProvider.fetch(nextPageUrl || collectionUrl);
|
|
852
|
-
if (json.totalItems) setTotalItems(json.totalItems);
|
|
853
|
-
// If first page, handle this here.
|
|
854
|
-
if ((json.type === "OrderedCollection" || json.type === "Collection") && json.first) {
|
|
855
|
-
if (json.first?.items) {
|
|
856
|
-
if (json.first?.items.length === 0 && json.first?.next) // Special case where the first property is an object without items
|
|
857
|
-
({ json: json } = await dataProvider.fetch(json.first?.next));
|
|
858
|
-
else json = json.first;
|
|
859
|
-
} else // Fetch the first page
|
|
860
|
-
({ json: json } = await dataProvider.fetch(json.first));
|
|
861
|
-
}
|
|
862
|
-
return json;
|
|
863
|
-
}, [
|
|
864
|
-
dataProvider,
|
|
865
|
-
collectionUrl,
|
|
866
|
-
identity,
|
|
867
|
-
setTotalItems
|
|
868
|
-
]);
|
|
869
|
-
// Use infiniteQuery to handle pagination, fetching, etc.
|
|
870
|
-
const { data: pageData, error: collectionError, fetchNextPage: fetchNextPage, refetch: refetch, hasNextPage: hasNextPage, isLoading: isLoadingPage, isFetching: isFetchingPage, isFetchingNextPage: isFetchingNextPage } = (0, $85cNH$useInfiniteQuery)([
|
|
871
|
-
"collection",
|
|
872
|
-
{
|
|
873
|
-
collectionUrl: collectionUrl
|
|
874
|
-
}
|
|
875
|
-
], fetchCollection, {
|
|
876
|
-
enabled: !!(collectionUrl && identity?.id),
|
|
877
|
-
getNextPageParam: (lastPage)=>lastPage.next,
|
|
878
|
-
getPreviousPageParam: (firstPage)=>firstPage.prev
|
|
879
|
-
});
|
|
880
|
-
// Put all items together in a list (and dereference, if required).
|
|
881
|
-
const { loadedItems: items, isLoading: isLoadingItems, isFetching: isFetchingItems, errors: itemErrors } = $8281f3ce3b9d6123$var$useItemsFromPages(pageData?.pages ?? [], dereferenceItems);
|
|
882
|
-
const allErrors = (0, $577f4953dfa5de4f$export$e57ff0f701c44363)(collectionError).concat((0, $577f4953dfa5de4f$export$e57ff0f701c44363)(itemErrors));
|
|
883
|
-
const addItem = (0, $85cNH$useCallback)((item, shouldRefetch = true)=>{
|
|
884
|
-
queryClient.setQueryData([
|
|
885
|
-
"collection",
|
|
886
|
-
{
|
|
887
|
-
collectionUrl: collectionUrl
|
|
888
|
-
}
|
|
889
|
-
], (oldData)=>{
|
|
890
|
-
if (!oldData) return oldData;
|
|
891
|
-
setTotalItems(totalItems && totalItems + 1);
|
|
892
|
-
// Destructure, so react knows, it needs to re-render the pages.
|
|
893
|
-
const pages = [
|
|
894
|
-
...oldData.pages
|
|
895
|
-
];
|
|
896
|
-
const firstPageItems = pages?.[0]?.orderedItems || pages?.[0]?.items || [];
|
|
897
|
-
firstPageItems.unshift(item);
|
|
898
|
-
oldData.pages = pages;
|
|
899
|
-
return oldData;
|
|
900
|
-
});
|
|
901
|
-
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
902
|
-
"collection",
|
|
903
|
-
{
|
|
904
|
-
collectionUrl: collectionUrl
|
|
905
|
-
}
|
|
906
|
-
], {
|
|
907
|
-
active: true,
|
|
908
|
-
exact: true
|
|
909
|
-
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
910
|
-
}, [
|
|
911
|
-
queryClient,
|
|
912
|
-
collectionUrl
|
|
913
|
-
]);
|
|
914
|
-
const removeItem = (0, $85cNH$useCallback)((item, shouldRefetch = true)=>{
|
|
915
|
-
queryClient.setQueryData([
|
|
916
|
-
"collection",
|
|
917
|
-
{
|
|
918
|
-
collectionUrl: collectionUrl
|
|
919
|
-
}
|
|
920
|
-
], (oldData)=>{
|
|
921
|
-
if (!oldData) return oldData;
|
|
922
|
-
setTotalItems(totalItems && totalItems - 1);
|
|
923
|
-
// Destructure, so react knows, it needs to re-render the pages array.
|
|
924
|
-
const pages = [
|
|
925
|
-
...oldData.pages
|
|
926
|
-
];
|
|
927
|
-
// Find the item in all pages and remove the item to be removed (either item.id or just item)
|
|
928
|
-
pages.forEach((page)=>{
|
|
929
|
-
if (page.orderedItems) page.orderedItems = page.orderedItems.filter((i)=>(i.id || i) !== (item.id || item));
|
|
930
|
-
else if (page.items) page.items = page.items.filter((i)=>(i.id || i) !== (item?.id || item));
|
|
931
|
-
});
|
|
932
|
-
oldData.pages = pages;
|
|
933
|
-
return oldData;
|
|
934
|
-
});
|
|
935
|
-
if (shouldRefetch) setTimeout(()=>queryClient.refetchQueries([
|
|
936
|
-
"collection",
|
|
937
|
-
{
|
|
938
|
-
collectionUrl: collectionUrl
|
|
939
|
-
}
|
|
940
|
-
], {
|
|
941
|
-
active: true,
|
|
942
|
-
exact: true
|
|
943
|
-
}), typeof shouldRefetch === "number" ? shouldRefetch : 2000);
|
|
944
|
-
}, [
|
|
945
|
-
queryClient,
|
|
946
|
-
collectionUrl
|
|
947
|
-
]);
|
|
948
|
-
// Live Updates
|
|
949
|
-
(0, $85cNH$useEffect)(()=>{
|
|
950
|
-
if (liveUpdates && collectionUrl) // Create ws that listens to collectionUri changes
|
|
951
|
-
(0, $85cNH$getOrCreateWsChannel)(dataProvider.fetch, collectionUrl).then((webSocket)=>{
|
|
952
|
-
webSocket.addEventListener("message", (e)=>{
|
|
953
|
-
const data = JSON.parse(e.data);
|
|
954
|
-
if (data && data.type === "Add") addItem(data.object, true);
|
|
955
|
-
else if (data && data.type === "Remove") removeItem(data.object, true);
|
|
956
|
-
});
|
|
957
|
-
webSocket.addEventListener("error", (e)=>{
|
|
958
|
-
setHasLiveUpdates({
|
|
959
|
-
status: "error",
|
|
960
|
-
error: e
|
|
961
|
-
});
|
|
962
|
-
// TODO: Retry after a while
|
|
963
|
-
});
|
|
964
|
-
webSocket.addEventListener("close", (e)=>{
|
|
965
|
-
if (!hasLiveUpdates.error) setHasLiveUpdates({
|
|
966
|
-
...hasLiveUpdates,
|
|
967
|
-
status: "closed"
|
|
968
|
-
});
|
|
969
|
-
});
|
|
970
|
-
setHasLiveUpdates({
|
|
971
|
-
status: "connected"
|
|
972
|
-
});
|
|
973
|
-
}).catch(()=>{}); // If it fails, we won't receive live updates. But that's okay.
|
|
974
|
-
}, [
|
|
975
|
-
collectionUrl,
|
|
976
|
-
liveUpdates,
|
|
977
|
-
dataProvider
|
|
978
|
-
]);
|
|
913
|
+
const { url: url, items: items, awaitWebSocketConnection: awaitWebSocketConnection, ...rest } = (0, $8281f3ce3b9d6123$export$2e2bcd8739ae039)("inbox", options);
|
|
914
|
+
const awaitActivity = (0, $600ca419166a1ded$export$2e2bcd8739ae039)(awaitWebSocketConnection, items);
|
|
979
915
|
return {
|
|
916
|
+
url: url,
|
|
980
917
|
items: items,
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
addItem: addItem,
|
|
986
|
-
removeItem: removeItem,
|
|
987
|
-
hasNextPage: hasNextPage,
|
|
988
|
-
isLoading: isLoadingPage || isLoadingItems,
|
|
989
|
-
isFetching: isFetchingPage || isFetchingItems,
|
|
990
|
-
isFetchingNextPage: isFetchingNextPage,
|
|
991
|
-
url: collectionUrl,
|
|
992
|
-
hasLiveUpdates: hasLiveUpdates
|
|
993
|
-
};
|
|
994
|
-
};
|
|
995
|
-
var $8281f3ce3b9d6123$export$2e2bcd8739ae039 = $8281f3ce3b9d6123$var$useCollection;
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
const $542b37cc25b8ccca$var$useInbox = ()=>{
|
|
1002
|
-
const { data: identity } = (0, $85cNH$useGetIdentity)();
|
|
1003
|
-
const inboxUrl = (0, $85cNH$useMemo)(()=>{
|
|
1004
|
-
if (identity?.webIdData) return identity?.webIdData?.inbox;
|
|
1005
|
-
}, [
|
|
1006
|
-
identity
|
|
1007
|
-
]);
|
|
1008
|
-
const sparqlEndpoint = (0, $85cNH$useMemo)(()=>{
|
|
1009
|
-
if (identity?.webIdData) return identity?.webIdData?.endpoints?.["void:sparqlEndpoint"] || `${identity?.id}/sparql`;
|
|
1010
|
-
}, [
|
|
1011
|
-
identity
|
|
1012
|
-
]);
|
|
1013
|
-
const fetch = (0, $85cNH$useCallback)(async ({ filters: filters })=>{
|
|
1014
|
-
if (!sparqlEndpoint || !inboxUrl) return;
|
|
1015
|
-
const token = localStorage.getItem("token");
|
|
1016
|
-
const blankNodesQuery = (0, $85cNH$buildBlankNodesQuery)([
|
|
1017
|
-
"as:object"
|
|
1018
|
-
]);
|
|
1019
|
-
let filtersWhereQuery = "";
|
|
1020
|
-
if (filters) Object.keys(filters).forEach((predicate)=>{
|
|
1021
|
-
if (filters[predicate]) {
|
|
1022
|
-
const object = filters[predicate].startsWith("http") ? `<${filters[predicate]}>` : filters[predicate];
|
|
1023
|
-
filtersWhereQuery += `?s1 ${predicate} ${object} .`;
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
const query = `
|
|
1027
|
-
PREFIX as: <https://www.w3.org/ns/activitystreams#>
|
|
1028
|
-
CONSTRUCT {
|
|
1029
|
-
?s1 ?p1 ?o1 .
|
|
1030
|
-
${blankNodesQuery.construct}
|
|
1031
|
-
}
|
|
1032
|
-
WHERE {
|
|
1033
|
-
<${inboxUrl}> as:items ?s1 .
|
|
1034
|
-
?s1 ?p1 ?o1 .
|
|
1035
|
-
FILTER( (isIRI(?s1)) ) .
|
|
1036
|
-
${filtersWhereQuery}
|
|
1037
|
-
${blankNodesQuery.where}
|
|
1038
|
-
}
|
|
1039
|
-
`;
|
|
1040
|
-
const { json: json } = await (0, $85cNH$fetchUtils).fetchJson(sparqlEndpoint, {
|
|
1041
|
-
method: "POST",
|
|
1042
|
-
body: query,
|
|
1043
|
-
headers: new Headers({
|
|
1044
|
-
Accept: "application/ld+json",
|
|
1045
|
-
Authorization: token ? `Bearer ${token}` : undefined
|
|
1046
|
-
})
|
|
1047
|
-
});
|
|
1048
|
-
if (json["@graph"]) return json["@graph"];
|
|
1049
|
-
return null;
|
|
1050
|
-
}, [
|
|
1051
|
-
sparqlEndpoint,
|
|
1052
|
-
inboxUrl
|
|
1053
|
-
]);
|
|
1054
|
-
return {
|
|
1055
|
-
fetch: fetch,
|
|
1056
|
-
url: inboxUrl,
|
|
1057
|
-
owner: identity?.id
|
|
918
|
+
awaitWebSocketConnection: awaitWebSocketConnection,
|
|
919
|
+
awaitActivity: awaitActivity,
|
|
920
|
+
owner: identity?.id,
|
|
921
|
+
...rest
|
|
1058
922
|
};
|
|
1059
923
|
};
|
|
1060
|
-
var $
|
|
924
|
+
var $cc1d1cd0e97c63a2$export$2e2bcd8739ae039 = $cc1d1cd0e97c63a2$var$useInbox;
|
|
1061
925
|
|
|
1062
926
|
|
|
1063
927
|
|
|
1064
928
|
|
|
1065
|
-
const $
|
|
929
|
+
const $6a227ddc2fd92a7a$var$useNodeinfo = (host, rel = "http://nodeinfo.diaspora.software/ns/schema/2.1")=>{
|
|
1066
930
|
const [schema, setSchema] = (0, $85cNH$useState)();
|
|
1067
931
|
(0, $85cNH$useEffect)(()=>{
|
|
1068
932
|
(async ()=>{
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
933
|
+
if (host && rel) {
|
|
934
|
+
const protocol = host.includes(":") ? "http" : "https"; // If the host has a port, we are likely on HTTP
|
|
935
|
+
const nodeinfoUrl = `${protocol}://${host}/.well-known/nodeinfo`;
|
|
936
|
+
try {
|
|
937
|
+
const { json: links } = await (0, $85cNH$fetchUtils).fetchJson(nodeinfoUrl);
|
|
938
|
+
// Accept any version of the nodeinfo protocol
|
|
939
|
+
const link = links?.links?.find((l)=>l.rel === rel);
|
|
940
|
+
if (link) {
|
|
941
|
+
const { json: json } = await (0, $85cNH$fetchUtils).fetchJson(link.href);
|
|
942
|
+
setSchema(json);
|
|
943
|
+
}
|
|
944
|
+
} catch (e) {
|
|
945
|
+
// Do nothing if nodeinfo can't be fetched
|
|
946
|
+
}
|
|
1079
947
|
}
|
|
1080
948
|
})();
|
|
1081
949
|
}, [
|
|
@@ -1085,7 +953,7 @@ const $641e93142bcf5435$var$useNodeinfo = (host, rel = "http://nodeinfo.diaspora
|
|
|
1085
953
|
]);
|
|
1086
954
|
return schema;
|
|
1087
955
|
};
|
|
1088
|
-
var $
|
|
956
|
+
var $6a227ddc2fd92a7a$export$2e2bcd8739ae039 = $6a227ddc2fd92a7a$var$useNodeinfo;
|
|
1089
957
|
|
|
1090
958
|
|
|
1091
959
|
|
|
@@ -1279,5 +1147,5 @@ var $51cccd331ea8b13d$export$2e2bcd8739ae039 = $51cccd331ea8b13d$var$useMentions
|
|
|
1279
1147
|
|
|
1280
1148
|
|
|
1281
1149
|
|
|
1282
|
-
export {$7ce737d4a1c88e63$export$2e2bcd8739ae039 as CommentsField, $d3be168cd1e7aaae$export$2e2bcd8739ae039 as CollectionList, $ea214512ab1a2e8f$export$2e2bcd8739ae039 as ReferenceCollectionField, $8281f3ce3b9d6123$export$2e2bcd8739ae039 as useCollection, $
|
|
1150
|
+
export {$7ce737d4a1c88e63$export$2e2bcd8739ae039 as CommentsField, $d3be168cd1e7aaae$export$2e2bcd8739ae039 as CollectionList, $ea214512ab1a2e8f$export$2e2bcd8739ae039 as ReferenceCollectionField, $8281f3ce3b9d6123$export$2e2bcd8739ae039 as useCollection, $cc1d1cd0e97c63a2$export$2e2bcd8739ae039 as useInbox, $6a227ddc2fd92a7a$export$2e2bcd8739ae039 as useNodeinfo, $4d1d40fdbcd30589$export$2e2bcd8739ae039 as useOutbox, $2514c63dc8f4867c$export$2e2bcd8739ae039 as useWebfinger, $51cccd331ea8b13d$export$2e2bcd8739ae039 as useMentions, $338f387df48a40d7$export$1ec8e53e7d982d22 as ACTIVITY_TYPES, $338f387df48a40d7$export$9649665d7ccb0dc2 as ACTOR_TYPES, $338f387df48a40d7$export$c49cfb2681596b20 as OBJECT_TYPES, $338f387df48a40d7$export$4d8d554031975581 as PUBLIC_URI};
|
|
1283
1151
|
//# sourceMappingURL=index.es.js.map
|