@comapeo/core-react 9.0.2 → 10.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +1 -1
  2. package/dist/commonjs/contexts/ClientApi.d.ts +1 -3
  3. package/dist/commonjs/contexts/ClientApi.js +2 -2
  4. package/dist/commonjs/hooks/client.d.ts +74 -33
  5. package/dist/commonjs/hooks/client.js +40 -11
  6. package/dist/commonjs/hooks/documents.d.ts +42 -429
  7. package/dist/commonjs/hooks/documents.js +100 -51
  8. package/dist/commonjs/hooks/invites.d.ts +153 -55
  9. package/dist/commonjs/hooks/invites.js +69 -20
  10. package/dist/commonjs/hooks/maps.d.ts +96 -225
  11. package/dist/commonjs/hooks/maps.js +104 -37
  12. package/dist/commonjs/hooks/projects.d.ts +666 -223
  13. package/dist/commonjs/hooks/projects.js +264 -131
  14. package/dist/commonjs/index.d.ts +2 -2
  15. package/dist/commonjs/lib/map-shares-stores.d.ts +1 -1
  16. package/dist/commonjs/lib/map-shares-stores.js +2 -2
  17. package/dist/commonjs/lib/presets.d.ts +1 -3
  18. package/dist/commonjs/lib/react-query.d.ts +103 -0
  19. package/dist/commonjs/lib/react-query.js +187 -0
  20. package/dist/commonjs/lib/sync.d.ts +2 -5
  21. package/dist/commonjs/lib/sync.js +0 -1
  22. package/dist/commonjs/lib/types.d.ts +4 -6
  23. package/dist/esm/contexts/ClientApi.d.ts +1 -3
  24. package/dist/esm/contexts/ClientApi.js +1 -1
  25. package/dist/esm/hooks/client.d.ts +74 -33
  26. package/dist/esm/hooks/client.js +40 -11
  27. package/dist/esm/hooks/documents.d.ts +42 -429
  28. package/dist/esm/hooks/documents.js +100 -51
  29. package/dist/esm/hooks/invites.d.ts +153 -55
  30. package/dist/esm/hooks/invites.js +69 -20
  31. package/dist/esm/hooks/maps.d.ts +96 -225
  32. package/dist/esm/hooks/maps.js +105 -38
  33. package/dist/esm/hooks/projects.d.ts +666 -223
  34. package/dist/esm/hooks/projects.js +262 -129
  35. package/dist/esm/index.d.ts +2 -2
  36. package/dist/esm/lib/map-shares-stores.d.ts +1 -1
  37. package/dist/esm/lib/map-shares-stores.js +1 -1
  38. package/dist/esm/lib/presets.d.ts +1 -3
  39. package/dist/esm/lib/react-query.d.ts +103 -0
  40. package/dist/esm/lib/react-query.js +162 -0
  41. package/dist/esm/lib/sync.d.ts +2 -5
  42. package/dist/esm/lib/sync.js +1 -1
  43. package/dist/esm/lib/types.d.ts +4 -6
  44. package/docs/API.md +137 -81
  45. package/package.json +39 -35
  46. package/dist/commonjs/lib/react-query/client.d.ts +0 -65
  47. package/dist/commonjs/lib/react-query/client.js +0 -68
  48. package/dist/commonjs/lib/react-query/documents.d.ts +0 -1484
  49. package/dist/commonjs/lib/react-query/documents.js +0 -149
  50. package/dist/commonjs/lib/react-query/invites.d.ts +0 -88
  51. package/dist/commonjs/lib/react-query/invites.js +0 -95
  52. package/dist/commonjs/lib/react-query/maps.d.ts +0 -104
  53. package/dist/commonjs/lib/react-query/maps.js +0 -129
  54. package/dist/commonjs/lib/react-query/mutation-result.d.ts +0 -8
  55. package/dist/commonjs/lib/react-query/mutation-result.js +0 -22
  56. package/dist/commonjs/lib/react-query/projects.d.ts +0 -316
  57. package/dist/commonjs/lib/react-query/projects.js +0 -359
  58. package/dist/commonjs/lib/react-query/shared.d.ts +0 -9
  59. package/dist/commonjs/lib/react-query/shared.js +0 -23
  60. package/dist/esm/lib/react-query/client.d.ts +0 -65
  61. package/dist/esm/lib/react-query/client.js +0 -59
  62. package/dist/esm/lib/react-query/documents.d.ts +0 -1484
  63. package/dist/esm/lib/react-query/documents.js +0 -137
  64. package/dist/esm/lib/react-query/invites.d.ts +0 -88
  65. package/dist/esm/lib/react-query/invites.js +0 -85
  66. package/dist/esm/lib/react-query/maps.d.ts +0 -104
  67. package/dist/esm/lib/react-query/maps.js +0 -119
  68. package/dist/esm/lib/react-query/mutation-result.d.ts +0 -8
  69. package/dist/esm/lib/react-query/mutation-result.js +0 -19
  70. package/dist/esm/lib/react-query/projects.d.ts +0 -316
  71. package/dist/esm/lib/react-query/projects.js +0 -324
  72. package/dist/esm/lib/react-query/shared.d.ts +0 -9
  73. package/dist/esm/lib/react-query/shared.js +0 -18
@@ -31,7 +31,7 @@ exports.useExportGeoJSON = useExportGeoJSON;
31
31
  exports.useExportZipFile = useExportZipFile;
32
32
  const react_query_1 = require("@tanstack/react-query");
33
33
  const react_1 = require("react");
34
- const projects_js_1 = require("../lib/react-query/projects.js");
34
+ const react_query_js_1 = require("../lib/react-query.js");
35
35
  const sync_js_1 = require("../lib/sync.js");
36
36
  const urls_js_1 = require("../lib/urls.js");
37
37
  const client_js_1 = require("./client.js");
@@ -49,16 +49,15 @@ const client_js_1 = require("./client.js");
49
49
  * }
50
50
  * ```
51
51
  */
52
- function useProjectSettings({ projectId }) {
53
- const clientApi = (0, client_js_1.useClientApi)();
54
- const { data: projectApi } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.projectByIdQueryOptions)({
55
- projectId,
56
- clientApi,
57
- }));
58
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.projectSettingsQueryOptions)({
59
- projectApi,
60
- projectId,
61
- }));
52
+ function useProjectSettings({ projectId, }) {
53
+ const { data: projectApi } = useSingleProject({ projectId });
54
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
55
+ ...(0, react_query_js_1.baseQueryOptions)(),
56
+ queryKey: (0, react_query_js_1.getProjectSettingsQueryKey)({ projectId }),
57
+ queryFn: async () => {
58
+ return projectApi.$getProjectSettings();
59
+ },
60
+ });
62
61
  return { data, error, isRefetching };
63
62
  }
64
63
  /**
@@ -75,13 +74,14 @@ function useProjectSettings({ projectId }) {
75
74
  * }
76
75
  * ```
77
76
  */
78
- function useSingleProject({ projectId }) {
77
+ function useSingleProject({ projectId, }) {
79
78
  const clientApi = (0, client_js_1.useClientApi)();
80
79
  const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
81
- ...(0, projects_js_1.projectByIdQueryOptions)({
82
- clientApi,
83
- projectId,
84
- }),
80
+ ...(0, react_query_js_1.baseQueryOptions)(),
81
+ queryKey: (0, react_query_js_1.getProjectByIdQueryKey)({ projectId }),
82
+ queryFn: async () => {
83
+ return clientApi.getProject(projectId);
84
+ },
85
85
  // Keep project instances around indefinitely - shouldn't be a memory
86
86
  // problem because these are only lightweight proxy objects, and project
87
87
  // references are kept indefinitely on the backend anyway once they are
@@ -105,9 +105,13 @@ function useSingleProject({ projectId }) {
105
105
  */
106
106
  function useManyProjects() {
107
107
  const clientApi = (0, client_js_1.useClientApi)();
108
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.projectsQueryOptions)({
109
- clientApi,
110
- }));
108
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
109
+ ...(0, react_query_js_1.baseQueryOptions)(),
110
+ queryKey: (0, react_query_js_1.getProjectsQueryKey)(),
111
+ queryFn: async () => {
112
+ return clientApi.listProjects();
113
+ },
114
+ });
111
115
  return { data, error, isRefetching };
112
116
  }
113
117
  /**
@@ -127,11 +131,13 @@ function useManyProjects() {
127
131
  */
128
132
  function useSingleMember({ projectId, deviceId, }) {
129
133
  const { data: projectApi } = useSingleProject({ projectId });
130
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.projectMemberByIdQueryOptions)({
131
- projectApi,
132
- projectId,
133
- deviceId,
134
- }));
134
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
135
+ ...(0, react_query_js_1.baseQueryOptions)(),
136
+ queryKey: (0, react_query_js_1.getMemberByIdQueryKey)({ projectId, deviceId }),
137
+ queryFn: async () => {
138
+ return projectApi.$member.getById(deviceId);
139
+ },
140
+ });
135
141
  return { data, error, isRefetching };
136
142
  }
137
143
  /**
@@ -142,15 +148,22 @@ function useSingleMember({ projectId, deviceId, }) {
142
148
  * @example
143
149
  * ```tsx
144
150
  * function BasicExample() {
145
- * const { data } = useManyMembers({ projectId: '...' })
151
+ * const activeMembers1 = useManyMembers({ projectId: '...' })
152
+ * const activeMembers2 = useManyMembers({ projectId: '...', includeLeft: false })
146
153
  *
147
- * console.log(data.role)
154
+ * const allMembers = useManyMembers({ projectId: '...', includeLeft: true })
148
155
  * }
149
156
  * ```
150
157
  */
151
- function useManyMembers({ projectId }) {
158
+ function useManyMembers({ projectId, includeLeft, }) {
152
159
  const { data: projectApi } = useSingleProject({ projectId });
153
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.projectMembersQueryOptions)({ projectApi, projectId }));
160
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
161
+ ...(0, react_query_js_1.baseQueryOptions)(),
162
+ queryKey: (0, react_query_js_1.getMembersQueryKey)({ projectId, includeLeft }),
163
+ queryFn: async () => {
164
+ return projectApi.$member.getMany({ includeLeft });
165
+ },
166
+ });
154
167
  return { data, error, isRefetching };
155
168
  }
156
169
  /**
@@ -256,14 +269,32 @@ function useAttachmentUrl({ projectId, blobId, }) {
256
269
  const blobUrl = (0, urls_js_1.getBlobUrl)({ serverOrigin, projectId, blobId });
257
270
  return { data: blobUrl, error, isRefetching };
258
271
  }
272
+ // Used as a placeholder so that we can read the server port from the $blobs.getUrl() method
273
+ const FAKE_BLOB_ID = {
274
+ type: 'photo',
275
+ variant: 'original',
276
+ name: 'name',
277
+ driveId: 'drive-id',
278
+ };
259
279
  /**
260
280
  * @internal
261
281
  * Hack to retrieve the media server origin (protocol + host).
262
282
  */
263
283
  function useMediaServerOrigin({ projectApi }) {
264
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.mediaServerOriginQueryOptions)({
265
- projectApi,
266
- }));
284
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
285
+ ...(0, react_query_js_1.baseQueryOptions)(),
286
+ // HACK: The server doesn't yet expose a method to get its origin, so we use
287
+ // the existing $blobs.getUrl() to get the origin with a fake BlobId. The origin
288
+ // is the same regardless of the blobId, so it's not necessary to include it
289
+ // as a dep for the query key.
290
+ queryKey: (0, react_query_js_1.getMediaServerOriginQueryKey)(),
291
+ queryFn: async () => {
292
+ const url = await projectApi.$blobs.getUrl(FAKE_BLOB_ID);
293
+ return new URL(url).origin;
294
+ },
295
+ staleTime: 'static',
296
+ gcTime: Infinity,
297
+ });
267
298
  return { data, error, isRefetching };
268
299
  }
269
300
  // TODO: Eventually remove in favor of this information being provided by the backend when retrieving documents
@@ -287,7 +318,18 @@ function useMediaServerOrigin({ projectApi }) {
287
318
  */
288
319
  function useDocumentCreatedBy({ projectId, originalVersionId, }) {
289
320
  const { data: projectApi } = useSingleProject({ projectId });
290
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.documentCreatedByQueryOptions)({ projectApi, projectId, originalVersionId }));
321
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
322
+ ...(0, react_query_js_1.baseQueryOptions)(),
323
+ queryKey: (0, react_query_js_1.getDocumentCreatedByQueryKey)({
324
+ projectId,
325
+ originalVersionId,
326
+ }),
327
+ queryFn: async () => {
328
+ return projectApi.$originalVersionIdToDeviceId(originalVersionId);
329
+ },
330
+ staleTime: 'static',
331
+ gcTime: Infinity,
332
+ });
291
333
  return { data, error, isRefetching };
292
334
  }
293
335
  /**
@@ -305,26 +347,50 @@ function useDocumentCreatedBy({ projectId, originalVersionId, }) {
305
347
  * }
306
348
  * ```
307
349
  */
308
- function useOwnRoleInProject({ projectId }) {
350
+ function useOwnRoleInProject({ projectId, }) {
309
351
  const { data: projectApi } = useSingleProject({ projectId });
310
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.projectOwnRoleQueryOptions)({ projectApi, projectId }));
352
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)({
353
+ ...(0, react_query_js_1.baseQueryOptions)(),
354
+ queryKey: (0, react_query_js_1.getProjectRoleQueryKey)({ projectId }),
355
+ queryFn: async () => {
356
+ return projectApi.$getOwnRole();
357
+ },
358
+ });
311
359
  return { data, error, isRefetching };
312
360
  }
313
361
  function useAddServerPeer({ projectId }) {
314
362
  const queryClient = (0, react_query_1.useQueryClient)();
315
363
  const { data: projectApi } = useSingleProject({ projectId });
316
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.addServerPeerMutationOptions)({ projectApi, projectId, queryClient }));
317
- return status === 'error'
318
- ? { error, mutate, mutateAsync, reset, status }
319
- : { error: null, mutate, mutateAsync, reset, status };
364
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
365
+ ...(0, react_query_js_1.baseMutationOptions)(),
366
+ mutationFn: async ({ baseUrl, dangerouslyAllowInsecureConnections, }) => {
367
+ return projectApi.$member.addServerPeer(baseUrl, {
368
+ dangerouslyAllowInsecureConnections,
369
+ });
370
+ },
371
+ onSuccess: () => {
372
+ queryClient.invalidateQueries({
373
+ queryKey: (0, react_query_js_1.getMembersQueryKey)({ projectId }),
374
+ });
375
+ },
376
+ }));
320
377
  }
321
378
  function useRemoveServerPeer({ projectId }) {
322
379
  const queryClient = (0, react_query_1.useQueryClient)();
323
380
  const { data: projectApi } = useSingleProject({ projectId });
324
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.removeServerPeerMutationOptions)({ projectApi, projectId, queryClient }));
325
- return status === 'error'
326
- ? { error, mutate, mutateAsync, reset, status }
327
- : { error: null, mutate, mutateAsync, reset, status };
381
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
382
+ ...(0, react_query_js_1.baseMutationOptions)(),
383
+ mutationFn: async ({ serverDeviceId, dangerouslyAllowInsecureConnections, }) => {
384
+ return projectApi.$member.removeServerPeer(serverDeviceId, {
385
+ dangerouslyAllowInsecureConnections,
386
+ });
387
+ },
388
+ onSuccess: () => {
389
+ queryClient.invalidateQueries({
390
+ queryKey: (0, react_query_js_1.getMembersQueryKey)({ projectId }),
391
+ });
392
+ },
393
+ }));
328
394
  }
329
395
  /**
330
396
  * Create a new project.
@@ -332,10 +398,19 @@ function useRemoveServerPeer({ projectId }) {
332
398
  function useCreateProject() {
333
399
  const queryClient = (0, react_query_1.useQueryClient)();
334
400
  const clientApi = (0, client_js_1.useClientApi)();
335
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.createProjectMutationOptions)({ clientApi, queryClient }));
336
- return status === 'error'
337
- ? { error, mutate, mutateAsync, reset, status }
338
- : { error: null, mutate, mutateAsync, reset, status };
401
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
402
+ ...(0, react_query_js_1.baseMutationOptions)(),
403
+ mutationFn: async (opts) => {
404
+ // Have to avoid passing `undefined` explicitly
405
+ // See https://github.com/digidem/rpc-reflector/issues/21
406
+ return opts ? clientApi.createProject(opts) : clientApi.createProject();
407
+ },
408
+ onSuccess: () => {
409
+ queryClient.invalidateQueries({
410
+ queryKey: (0, react_query_js_1.getProjectsQueryKey)(),
411
+ });
412
+ },
413
+ }));
339
414
  }
340
415
  /**
341
416
  * Leave an existing project.
@@ -343,10 +418,17 @@ function useCreateProject() {
343
418
  function useLeaveProject() {
344
419
  const queryClient = (0, react_query_1.useQueryClient)();
345
420
  const clientApi = (0, client_js_1.useClientApi)();
346
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.leaveProjectMutationOptions)({ clientApi, queryClient }));
347
- return status === 'error'
348
- ? { error, mutate, mutateAsync, reset, status }
349
- : { error: null, mutate, mutateAsync, reset, status };
421
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
422
+ ...(0, react_query_js_1.baseMutationOptions)(),
423
+ mutationFn: async ({ projectId }) => {
424
+ return clientApi.leaveProject(projectId);
425
+ },
426
+ onSuccess: () => {
427
+ queryClient.invalidateQueries({
428
+ queryKey: (0, react_query_js_1.getProjectsQueryKey)(),
429
+ });
430
+ },
431
+ }));
350
432
  }
351
433
  /**
352
434
  * Update the categories of a project using an external file.
@@ -356,14 +438,17 @@ function useLeaveProject() {
356
438
  function useImportProjectCategories({ projectId, }) {
357
439
  const queryClient = (0, react_query_1.useQueryClient)();
358
440
  const { data: projectApi } = useSingleProject({ projectId });
359
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.importProjectCategoriesMutationOptions)({
360
- queryClient,
361
- projectApi,
362
- projectId,
441
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
442
+ ...(0, react_query_js_1.baseMutationOptions)(),
443
+ mutationFn: ({ filePath }) => {
444
+ return projectApi.$importCategories({ filePath });
445
+ },
446
+ onSuccess: () => {
447
+ queryClient.invalidateQueries({
448
+ queryKey: (0, react_query_js_1.getProjectByIdQueryKey)({ projectId }),
449
+ });
450
+ },
363
451
  }));
364
- return status === 'error'
365
- ? { error, mutate, mutateAsync, reset, status }
366
- : { error: null, mutate, mutateAsync, reset, status };
367
452
  }
368
453
  /**
369
454
  * Update the configuration of a project using an external file.
@@ -374,23 +459,37 @@ function useImportProjectCategories({ projectId, }) {
374
459
  function useImportProjectConfig({ projectId }) {
375
460
  const queryClient = (0, react_query_1.useQueryClient)();
376
461
  const { data: projectApi } = useSingleProject({ projectId });
377
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.importProjectConfigMutationOptions)({ queryClient, projectApi, projectId }));
378
- return status === 'error'
379
- ? { error, mutate, mutateAsync, reset, status }
380
- : { error: null, mutate, mutateAsync, reset, status };
462
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
463
+ ...(0, react_query_js_1.baseMutationOptions)(),
464
+ mutationFn: ({ configPath }) => {
465
+ return projectApi.importConfig({ configPath });
466
+ },
467
+ onSuccess: () => {
468
+ queryClient.invalidateQueries({
469
+ queryKey: (0, react_query_js_1.getProjectByIdQueryKey)({ projectId }),
470
+ });
471
+ },
472
+ }));
381
473
  }
382
474
  /**
383
475
  * Update the settings of a project.
384
476
  *
385
477
  * @param opts.projectId Public ID of the project to apply changes to.
386
478
  */
387
- function useUpdateProjectSettings({ projectId }) {
479
+ function useUpdateProjectSettings({ projectId, }) {
388
480
  const queryClient = (0, react_query_1.useQueryClient)();
389
481
  const { data: projectApi } = useSingleProject({ projectId });
390
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.updateProjectSettingsMutationOptions)({ projectApi, queryClient }));
391
- return status === 'error'
392
- ? { error, mutate, mutateAsync, reset, status }
393
- : { error: null, mutate, mutateAsync, reset, status };
482
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
483
+ ...(0, react_query_js_1.baseMutationOptions)(),
484
+ mutationFn: async (value) => {
485
+ return projectApi.$setProjectSettings(value);
486
+ },
487
+ onSuccess: () => {
488
+ queryClient.invalidateQueries({
489
+ queryKey: (0, react_query_js_1.getProjectsQueryKey)(),
490
+ });
491
+ },
492
+ }));
394
493
  }
395
494
  /**
396
495
  * Change a project member's role.
@@ -409,10 +508,20 @@ function useUpdateProjectSettings({ projectId }) {
409
508
  function useChangeMemberRole({ projectId }) {
410
509
  const queryClient = (0, react_query_1.useQueryClient)();
411
510
  const { data: projectApi } = useSingleProject({ projectId });
412
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.changeMemberRoleMutationOptions)({ projectApi, projectId, queryClient }));
413
- return status === 'error'
414
- ? { error, mutate, mutateAsync, reset, status }
415
- : { error: null, mutate, mutateAsync, reset, status };
511
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
512
+ ...(0, react_query_js_1.baseMutationOptions)(),
513
+ mutationFn: async ({ deviceId, roleId, }) => {
514
+ return projectApi.$member.assignRole(deviceId, roleId);
515
+ },
516
+ onSuccess: () => {
517
+ queryClient.invalidateQueries({
518
+ queryKey: (0, react_query_js_1.getMembersQueryKey)({ projectId }),
519
+ });
520
+ queryClient.invalidateQueries({
521
+ queryKey: (0, react_query_js_1.getProjectRoleQueryKey)({ projectId }),
522
+ });
523
+ },
524
+ }));
416
525
  }
417
526
  /**
418
527
  * Remove a member from a project, providing an optional reason for removal.
@@ -436,48 +545,64 @@ function useChangeMemberRole({ projectId }) {
436
545
  function useRemoveMember({ projectId }) {
437
546
  const queryClient = (0, react_query_1.useQueryClient)();
438
547
  const { data: projectApi } = useSingleProject({ projectId });
439
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.removeProjectMemberMutationOptions)({ projectId, projectApi, queryClient }));
440
- return status === 'error'
441
- ? { error, mutate, mutateAsync, reset, status }
442
- : { error: null, mutate, mutateAsync, reset, status };
548
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
549
+ ...(0, react_query_js_1.baseMutationOptions)(),
550
+ mutationFn: async ({ deviceId, reason, }) => {
551
+ // Have to avoid passing `undefined` explicitly
552
+ // See https://github.com/digidem/rpc-reflector/issues/21
553
+ return reason
554
+ ? projectApi.$member.remove(deviceId, { reason })
555
+ : projectApi.$member.remove(deviceId);
556
+ },
557
+ onSuccess: () => {
558
+ queryClient.invalidateQueries({
559
+ queryKey: (0, react_query_js_1.getMembersQueryKey)({ projectId }),
560
+ });
561
+ },
562
+ }));
443
563
  }
444
564
  /**
445
565
  * Set up listener for changes to your own role in a project.
446
566
  * It is necessary to use this if you want the project role-related read hooks to update
447
567
  * based on role change events that are received in the background.
448
568
  *
449
- * @param opts.listener Optional listener to invoke when role changes
569
+ *
450
570
  *
451
571
  * @example
452
572
  * ```tsx
453
- * function SomeComponent({ projectId }: { projectId: string }) {
573
+ * function ListenerComponent({ projectId }: { projectId: string }) {
574
+ * // Set up the listener
454
575
  * useProjectOwnRoleChangeListener({ projectId })
455
576
  * }
456
- * ```
457
577
  *
458
- * @example
459
- * ```tsx
460
- * function ComponentWithListener({ projectId }: { projectId: string }) {
461
- * useProjectOwnRoleChangeListener({
462
- * projectId,
463
- * listener: (event) => {
464
- * // Handle role change, e.g., navigate to default project
465
- * console.log('New role:', event.role)
578
+ * // Handle role change events separately
579
+ * function EventHandlerComponent() {
580
+ * const { data: projectApi } = useSingleProject({ projectId })
581
+ *
582
+ * useEffect(() => {
583
+ * function handleRoleChangeEvent(event) {
584
+ * // Do something with event...
466
585
  * }
467
- * })
586
+ *
587
+ * projectApi.addListener('own-role-change', handleRoleChangeEvent)
588
+ *
589
+ * return () => {
590
+ * projectApi.removeListener('own-role-change', handleRoleChangeEvent)
591
+ * }
592
+ * }, [projectApi])
468
593
  * }
469
594
  * ```
470
595
  */
471
- function useProjectOwnRoleChangeListener({ projectId, listener, }) {
596
+ function useProjectOwnRoleChangeListener({ projectId, }) {
472
597
  const queryClient = (0, react_query_1.useQueryClient)();
473
598
  const { data: projectApi } = useSingleProject({ projectId });
474
599
  (0, react_1.useEffect)(() => {
475
600
  function invalidateCache() {
476
601
  queryClient.invalidateQueries({
477
- queryKey: (0, projects_js_1.getMembersQueryKey)({ projectId }),
602
+ queryKey: (0, react_query_js_1.getMembersQueryKey)({ projectId }),
478
603
  });
479
604
  queryClient.invalidateQueries({
480
- queryKey: (0, projects_js_1.getProjectRoleQueryKey)({ projectId }),
605
+ queryKey: (0, react_query_js_1.getProjectRoleQueryKey)({ projectId }),
481
606
  });
482
607
  }
483
608
  projectApi.addListener('own-role-change', invalidateCache);
@@ -485,16 +610,6 @@ function useProjectOwnRoleChangeListener({ projectId, listener, }) {
485
610
  projectApi.removeListener('own-role-change', invalidateCache);
486
611
  };
487
612
  }, [projectApi, queryClient, projectId]);
488
- (0, react_1.useEffect)(() => {
489
- if (listener) {
490
- projectApi.addListener('own-role-change', listener);
491
- }
492
- return () => {
493
- if (listener) {
494
- projectApi.removeListener('own-role-change', listener);
495
- }
496
- };
497
- }, [projectApi, listener]);
498
613
  }
499
614
  /**
500
615
  * Create a blob for a project.
@@ -503,10 +618,12 @@ function useProjectOwnRoleChangeListener({ projectId, listener, }) {
503
618
  */
504
619
  function useCreateBlob({ projectId }) {
505
620
  const { data: projectApi } = useSingleProject({ projectId });
506
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.createBlobMutationOptions)({ projectApi }));
507
- return status === 'error'
508
- ? { error, mutate, mutateAsync, reset, status }
509
- : { error: null, mutate, mutateAsync, reset, status };
621
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
622
+ ...(0, react_query_js_1.baseMutationOptions)(),
623
+ mutationFn: async ({ original, preview, thumbnail, metadata, }) => {
624
+ return projectApi.$blobs.create({ original, preview, thumbnail }, metadata);
625
+ },
626
+ }));
510
627
  }
511
628
  const PROJECT_SYNC_STORE_MAP = new WeakMap();
512
629
  function useSyncStore({ projectId }) {
@@ -556,38 +673,50 @@ function useDataSyncProgress({ projectId, }) {
556
673
  }
557
674
  function useStartSync({ projectId }) {
558
675
  const { data: projectApi } = useSingleProject({ projectId });
559
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.startSyncMutationOptions)({ projectApi }));
560
- return status === 'error'
561
- ? { error, mutate, mutateAsync, reset, status }
562
- : { error: null, mutate, mutateAsync, reset, status };
676
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
677
+ ...(0, react_query_js_1.baseMutationOptions)(),
678
+ mutationFn: async (opts) => {
679
+ // Have to avoid passing `undefined` explicitly
680
+ // See https://github.com/digidem/rpc-reflector/issues/21
681
+ return opts ? projectApi.$sync.start(opts) : projectApi.$sync.start();
682
+ },
683
+ }));
563
684
  }
564
685
  function useStopSync({ projectId }) {
565
686
  const { data: projectApi } = useSingleProject({ projectId });
566
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.stopSyncMutationOptions)({ projectApi }));
567
- return status === 'error'
568
- ? { error, mutate, mutateAsync, reset, status }
569
- : { error: null, mutate, mutateAsync, reset, status };
687
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
688
+ ...(0, react_query_js_1.baseMutationOptions)(),
689
+ mutationFn: async () => {
690
+ return projectApi.$sync.stop();
691
+ },
692
+ }));
570
693
  }
571
694
  function useConnectSyncServers({ projectId }) {
572
695
  const { data: projectApi } = useSingleProject({ projectId });
573
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.connectSyncServersMutationOptions)({ projectApi }));
574
- return status === 'error'
575
- ? { error, mutate, mutateAsync, reset, status }
576
- : { error: null, mutate, mutateAsync, reset, status };
696
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
697
+ ...(0, react_query_js_1.baseMutationOptions)(),
698
+ mutationFn: async () => {
699
+ return projectApi.$sync.connectServers();
700
+ },
701
+ }));
577
702
  }
578
703
  function useDisconnectSyncServers({ projectId }) {
579
704
  const { data: projectApi } = useSingleProject({ projectId });
580
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.disconnectSyncServersMutationOptions)({ projectApi }));
581
- return status === 'error'
582
- ? { error, mutate, mutateAsync, reset, status }
583
- : { error: null, mutate, mutateAsync, reset, status };
705
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
706
+ ...(0, react_query_js_1.baseMutationOptions)(),
707
+ mutationFn: async () => {
708
+ return projectApi.$sync.disconnectServers();
709
+ },
710
+ }));
584
711
  }
585
712
  function useSetAutostopDataSyncTimeout({ projectId, }) {
586
713
  const { data: projectApi } = useSingleProject({ projectId });
587
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.setAutostopDataSyncTimeoutMutationOptions)({ projectApi }));
588
- return status === 'error'
589
- ? { error, mutate, mutateAsync, reset, status }
590
- : { error: null, mutate, mutateAsync, reset, status };
714
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
715
+ ...(0, react_query_js_1.baseMutationOptions)(),
716
+ mutationFn: async ({ after }) => {
717
+ return projectApi.$sync.setAutostopDataSyncTimeout(after);
718
+ },
719
+ }));
591
720
  }
592
721
  /**
593
722
  * Creates a GeoJson file with all the observations and/or tracks in the project.
@@ -596,10 +725,12 @@ function useSetAutostopDataSyncTimeout({ projectId, }) {
596
725
  */
597
726
  function useExportGeoJSON({ projectId }) {
598
727
  const { data: projectApi } = useSingleProject({ projectId });
599
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.exportGeoJSONMutationOptions)({ projectApi }));
600
- return status === 'error'
601
- ? { error, mutate, mutateAsync, reset, status }
602
- : { error: null, mutate, mutateAsync, reset, status };
728
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
729
+ ...(0, react_query_js_1.baseMutationOptions)(),
730
+ mutationFn: async (opts) => {
731
+ return projectApi.exportGeoJSONFile(opts.path, opts.exportOptions);
732
+ },
733
+ }));
603
734
  }
604
735
  /**
605
736
  * Creates a zip file containing a GeoJson file with all the observations and/or tracks in the project and all associated attachments (photos and audio).
@@ -608,8 +739,10 @@ function useExportGeoJSON({ projectId }) {
608
739
  */
609
740
  function useExportZipFile({ projectId }) {
610
741
  const { data: projectApi } = useSingleProject({ projectId });
611
- const { error, mutate, mutateAsync, reset, status } = (0, react_query_1.useMutation)((0, projects_js_1.exportZipFileMutationOptions)({ projectApi }));
612
- return status === 'error'
613
- ? { error, mutate, mutateAsync, reset, status }
614
- : { error: null, mutate, mutateAsync, reset, status };
742
+ return (0, react_query_js_1.filterMutationResult)((0, react_query_1.useMutation)({
743
+ ...(0, react_query_js_1.baseMutationOptions)(),
744
+ mutationFn: async (opts) => {
745
+ return projectApi.exportZipFile(opts.path, opts.exportOptions);
746
+ },
747
+ }));
615
748
  }
@@ -6,6 +6,6 @@ export { useMapStyleUrl, useImportCustomMapFile, useRemoveCustomMapFile, useGetC
6
6
  export type { SentMapShareState, ReceivedMapShareState, AbortMapShareOptions, CancelMapShareOptions, DeclineMapShareOptions, DownloadMapShareOptions, CreateAndSendMapShareOptions, } from './lib/map-shares-stores.js';
7
7
  export { DeclineReason } from './lib/map-shares-stores.js';
8
8
  export { useAddServerPeer, useAttachmentUrl, useConnectSyncServers, useCreateBlob, useCreateProject, useDataSyncProgress, useDisconnectSyncServers, useDocumentCreatedBy, useIconUrl, useImportProjectCategories, useImportProjectConfig, useLeaveProject, useManyMembers, useManyProjects, useOwnRoleInProject, useProjectOwnRoleChangeListener, useProjectSettings, useRemoveServerPeer, useRemoveMember, useSetAutostopDataSyncTimeout, useSingleMember, useSingleProject, useStartSync, useStopSync, useSyncState, useUpdateProjectSettings, useChangeMemberRole, useExportGeoJSON, useExportZipFile, } from './hooks/projects.js';
9
- export { type SyncState } from './lib/sync.js';
10
- export { type WriteableDocument, type WriteableDocumentType, type WriteableValue, } from './lib/types.js';
9
+ export type { SyncState } from './lib/sync.js';
10
+ export type { WriteableDocument, WriteableDocumentType, WriteableValue, } from './lib/types.js';
11
11
  export { HTTPError, isHTTPError } from './lib/http.js';
@@ -1,7 +1,7 @@
1
1
  import type { MapShare } from '@comapeo/core';
2
2
  import type { MapeoClientApi } from '@comapeo/ipc';
3
3
  import { type MapShareState as ServerMapShareState } from '@comapeo/map-server';
4
- import { type QueryClient } from '@tanstack/react-query';
4
+ import type { QueryClient } from '@tanstack/react-query';
5
5
  import type { Simplify } from 'type-fest';
6
6
  import type { MapServerApi } from '../contexts/MapServer.js';
7
7
  type DistributedIntersection<T, U> = U extends unknown ? Simplify<T & U> : never;
@@ -9,7 +9,7 @@ exports.createSentMapSharesStore = createSentMapSharesStore;
9
9
  const constants_js_1 = require("@comapeo/map-server/constants.js");
10
10
  const errors_js_1 = require("@comapeo/map-server/errors.js");
11
11
  const ensure_error_1 = __importDefault(require("ensure-error"));
12
- const maps_js_1 = require("./react-query/maps.js");
12
+ const react_query_js_1 = require("./react-query.js");
13
13
  // ============================================
14
14
  // ACTION OPTIONS TYPES
15
15
  // These are defined here so that VSCode tooltips work for the mutation
@@ -169,7 +169,7 @@ function createReceivedMapSharesStore({ clientApi, mapServerApi, queryClient, })
169
169
  downloads.delete(shareId);
170
170
  // Invalidate map queries when download completes to trigger reload of map
171
171
  if (stateUpdate.status === 'completed') {
172
- return (0, maps_js_1.invalidateMapQueries)(queryClient, {
172
+ return (0, react_query_js_1.invalidateMapQueries)(queryClient, {
173
173
  mapId: mapShare.mapId,
174
174
  });
175
175
  }
@@ -1,4 +1,2 @@
1
- import type { Preset } from '@comapeo/schema' with {
2
- 'resolution-mode': 'import'
3
- };
1
+ import type { Preset } from '@comapeo/core/schema.js';
4
2
  export declare function getPresetsSelection(presets: Array<Preset>, orderedPresetIds?: Array<string>): Array<Preset>;