@comapeo/core-react 10.0.1 → 11.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.
- package/dist/commonjs/contexts/MapShares.d.ts +1 -1
- package/dist/commonjs/hooks/maps.d.ts +57 -18
- package/dist/commonjs/hooks/maps.js +58 -19
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +6 -2
- package/dist/commonjs/lib/map-shares-stores.d.ts +120 -3
- package/dist/commonjs/lib/map-shares-stores.js +170 -8
- package/dist/commonjs/lib/react-query.js +2 -2
- package/dist/esm/contexts/MapShares.d.ts +1 -1
- package/dist/esm/hooks/maps.d.ts +57 -18
- package/dist/esm/hooks/maps.js +58 -19
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/lib/map-shares-stores.d.ts +120 -3
- package/dist/esm/lib/map-shares-stores.js +166 -7
- package/dist/esm/lib/react-query.js +1 -1
- package/docs/API.md +19 -24
- package/package.json +6 -6
|
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.DeclineReason = void 0;
|
|
6
|
+
exports.InvalidStatusTransitionError = exports.MapShareCanceledError = exports.DeclineReason = exports.MapShareErrorCode = void 0;
|
|
7
|
+
exports.getErrorCode = getErrorCode;
|
|
7
8
|
exports.createReceivedMapSharesStore = createReceivedMapSharesStore;
|
|
8
9
|
exports.createSentMapSharesStore = createSentMapSharesStore;
|
|
9
10
|
const constants_js_1 = require("@comapeo/map-server/constants.js");
|
|
@@ -16,6 +17,118 @@ const react_query_js_1 = require("./react-query.js");
|
|
|
16
17
|
// functions - if the documentation comments are added inline for the store
|
|
17
18
|
// actions, they do not show for the mutate() function in hooks.
|
|
18
19
|
// ============================================
|
|
20
|
+
/**
|
|
21
|
+
* Error codes for map share operations. Use with {@link getErrorCode} to safely
|
|
22
|
+
* check the error code of an unknown error thrown by a map share mutation, or
|
|
23
|
+
* to check the `error.code` on a share in `status='error'`.
|
|
24
|
+
*
|
|
25
|
+
* ## Receiver errors
|
|
26
|
+
*
|
|
27
|
+
* **Mutation errors** (thrown by receiver hooks, check via
|
|
28
|
+
* `getErrorCode(mutation.error)`):
|
|
29
|
+
* - `MAP_SHARE_CANCELED` — the sender canceled the share
|
|
30
|
+
* - `INVALID_STATUS_TRANSITION` — the action is not valid for the share's
|
|
31
|
+
* current status (e.g. declining a share that is already downloading)
|
|
32
|
+
* - `MAP_SHARE_NOT_FOUND` — no share with the given `shareId` exists
|
|
33
|
+
* - `DOWNLOAD_NOT_FOUND` — abort was called but no download is tracked for
|
|
34
|
+
* this share
|
|
35
|
+
*
|
|
36
|
+
* **Share state errors** (on received `share.error.code` when
|
|
37
|
+
* `share.status === 'error'`):
|
|
38
|
+
* - `DOWNLOAD_ERROR` — the download failed (network, disk, or server error)
|
|
39
|
+
* - `DECLINE_CANNOT_CONNECT` — the decline was accepted locally but the sender
|
|
40
|
+
* could not be reached to notify them
|
|
41
|
+
*
|
|
42
|
+
* ## Sender errors
|
|
43
|
+
*
|
|
44
|
+
* **Mutation errors** (thrown by sender hooks, check via
|
|
45
|
+
* `getErrorCode(mutation.error)`):
|
|
46
|
+
* - `INVALID_STATUS_TRANSITION` — the action is not valid for the share's
|
|
47
|
+
* current status (e.g. canceling a share that is already canceled)
|
|
48
|
+
* - `MAP_SHARE_NOT_FOUND` — no share with the given `shareId` exists
|
|
49
|
+
*
|
|
50
|
+
* **Share state errors** (on sent `share.error.code` when
|
|
51
|
+
* `share.status === 'error'`):
|
|
52
|
+
* - `CANCEL_SHARE_NOT_CANCELABLE` — the cancel request reached the server but
|
|
53
|
+
* the share is already in a final state (e.g. completed or declined)
|
|
54
|
+
*
|
|
55
|
+
* ## Common
|
|
56
|
+
*
|
|
57
|
+
* - `UNKNOWN_ERROR` — fallback when the original error has no specific code.
|
|
58
|
+
* Can appear as both a mutation error and a share state error for either
|
|
59
|
+
* sender or receiver.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```tsx
|
|
63
|
+
* import { getErrorCode, MapShareErrorCode } from '@comapeo/core-react'
|
|
64
|
+
*
|
|
65
|
+
* // Receiver: checking a mutation error
|
|
66
|
+
* const decline = useDeclineReceivedMapShare()
|
|
67
|
+
* // ... after mutation fails:
|
|
68
|
+
* if (getErrorCode(decline.error) === MapShareErrorCode.MAP_SHARE_CANCELED) {
|
|
69
|
+
* // Show "this share was canceled by the sender"
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```tsx
|
|
75
|
+
* // Receiver: checking a share state error
|
|
76
|
+
* const share = useSingleReceivedMapShare({ shareId })
|
|
77
|
+
* if (share.status === 'error') {
|
|
78
|
+
* if (share.error.code === MapShareErrorCode.DOWNLOAD_ERROR) {
|
|
79
|
+
* // Show "download failed, try again?"
|
|
80
|
+
* }
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
exports.MapShareErrorCode = {
|
|
85
|
+
// --- Receiver mutation errors (thrown by receiver actions) ---
|
|
86
|
+
/** Receiver: the sender canceled the share before the action could complete */
|
|
87
|
+
MAP_SHARE_CANCELED: 'MAP_SHARE_CANCELED',
|
|
88
|
+
/** Receiver/Sender: the action is not valid for the share's current status */
|
|
89
|
+
INVALID_STATUS_TRANSITION: 'INVALID_STATUS_TRANSITION',
|
|
90
|
+
/** Receiver/Sender: no map share with the given `shareId` exists in the store */
|
|
91
|
+
MAP_SHARE_NOT_FOUND: 'MAP_SHARE_NOT_FOUND',
|
|
92
|
+
/** Receiver: abort was called but no download is tracked for this share */
|
|
93
|
+
DOWNLOAD_NOT_FOUND: 'DOWNLOAD_NOT_FOUND',
|
|
94
|
+
// --- Receiver share state errors (in share.error.code) ---
|
|
95
|
+
/** Receiver: the download failed due to a network, disk, or server error */
|
|
96
|
+
DOWNLOAD_ERROR: 'DOWNLOAD_ERROR',
|
|
97
|
+
/** Receiver: could not connect to the sender to notify them of the decline */
|
|
98
|
+
DECLINE_CANNOT_CONNECT: 'DECLINE_CANNOT_CONNECT',
|
|
99
|
+
// --- Sender share state errors (in share.error.code) ---
|
|
100
|
+
/** Sender: cancel failed because the share is already in a final state on the server */
|
|
101
|
+
CANCEL_SHARE_NOT_CANCELABLE: 'CANCEL_SHARE_NOT_CANCELABLE',
|
|
102
|
+
// --- Common ---
|
|
103
|
+
/** Receiver/Sender: fallback code when the original error has no specific code */
|
|
104
|
+
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Safely extract the `code` property from an unknown error. Returns `undefined`
|
|
108
|
+
* if the value is not an Error or has no string `code` property.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```tsx
|
|
112
|
+
* import { getErrorCode, MapShareErrorCode } from '@comapeo/core-react'
|
|
113
|
+
*
|
|
114
|
+
* try {
|
|
115
|
+
* await decline.mutateAsync({ shareId, reason: 'user_rejected' })
|
|
116
|
+
* } catch (e) {
|
|
117
|
+
* const code = getErrorCode(e)
|
|
118
|
+
* if (code === MapShareErrorCode.MAP_SHARE_CANCELED) {
|
|
119
|
+
* // handle cancellation
|
|
120
|
+
* }
|
|
121
|
+
* }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
function getErrorCode(error) {
|
|
125
|
+
if (error instanceof Error &&
|
|
126
|
+
'code' in error &&
|
|
127
|
+
typeof error.code === 'string') {
|
|
128
|
+
return error.code;
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
19
132
|
/** Known reasons for declining a map share */
|
|
20
133
|
exports.DeclineReason = {
|
|
21
134
|
/** User explicitly rejected the map share */
|
|
@@ -23,6 +136,32 @@ exports.DeclineReason = {
|
|
|
23
136
|
/** Device storage is full */
|
|
24
137
|
storage_full: 'storage_full',
|
|
25
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* Thrown when a receiver action (download, decline, or abort) is attempted on a
|
|
141
|
+
* map share that has been canceled by the sender. Has `code: 'MAP_SHARE_CANCELED'`.
|
|
142
|
+
*/
|
|
143
|
+
class MapShareCanceledError extends Error {
|
|
144
|
+
code = 'MAP_SHARE_CANCELED';
|
|
145
|
+
constructor(shareId) {
|
|
146
|
+
super(`Map share ${shareId} has been canceled by the sender`);
|
|
147
|
+
this.name = 'MapShareCanceledError';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.MapShareCanceledError = MapShareCanceledError;
|
|
151
|
+
/**
|
|
152
|
+
* Thrown when an action is attempted on a map share whose current status does
|
|
153
|
+
* not allow the requested transition (e.g. declining a share that is already
|
|
154
|
+
* downloading, or aborting a share that is still pending).
|
|
155
|
+
* Has `code: 'INVALID_STATUS_TRANSITION'`.
|
|
156
|
+
*/
|
|
157
|
+
class InvalidStatusTransitionError extends Error {
|
|
158
|
+
code = 'INVALID_STATUS_TRANSITION';
|
|
159
|
+
constructor(current, next) {
|
|
160
|
+
super(`Invalid status transition from ${current} to ${next}`);
|
|
161
|
+
this.name = 'InvalidStatusTransitionError';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.InvalidStatusTransitionError = InvalidStatusTransitionError;
|
|
26
165
|
/**
|
|
27
166
|
* This is like a mini zustand store. Keeping the map shares in an external
|
|
28
167
|
* store avoids unnecessary re-renders of the entire app when map shares are
|
|
@@ -143,6 +282,13 @@ function createReceivedMapSharesStore({ clientApi, mapServerApi, queryClient, })
|
|
|
143
282
|
const actions = {
|
|
144
283
|
async download({ shareId }) {
|
|
145
284
|
const mapShare = get(shareId);
|
|
285
|
+
// This path should be be impossible, because the map share only receives
|
|
286
|
+
// status updates from the receiver after the download starts, but adding
|
|
287
|
+
// for completeness, and the edge-case of the receiving trying to
|
|
288
|
+
// download() a second time.
|
|
289
|
+
if (mapShare.status === 'canceled') {
|
|
290
|
+
throw new MapShareCanceledError(shareId);
|
|
291
|
+
}
|
|
146
292
|
update(shareId, { status: 'downloading', bytesDownloaded: 0 });
|
|
147
293
|
try {
|
|
148
294
|
const downloadIdPromise = mapServerApi
|
|
@@ -184,22 +330,39 @@ function createReceivedMapSharesStore({ clientApi, mapServerApi, queryClient, })
|
|
|
184
330
|
},
|
|
185
331
|
async decline({ shareId, reason }) {
|
|
186
332
|
const mapShare = get(shareId);
|
|
187
|
-
|
|
333
|
+
if (mapShare.status === 'canceled') {
|
|
334
|
+
throw new MapShareCanceledError(shareId);
|
|
335
|
+
}
|
|
336
|
+
if (mapShare.status !== 'pending') {
|
|
337
|
+
throw new InvalidStatusTransitionError(mapShare.status, 'declined');
|
|
338
|
+
}
|
|
188
339
|
try {
|
|
189
|
-
await mapServerApi
|
|
340
|
+
await mapServerApi
|
|
341
|
+
.post(`mapShares/${shareId}/decline`, {
|
|
190
342
|
json: {
|
|
191
343
|
senderDeviceId: mapShare.senderDeviceId,
|
|
192
344
|
mapShareUrls: mapShare.mapShareUrls,
|
|
193
345
|
reason,
|
|
194
346
|
},
|
|
195
|
-
})
|
|
347
|
+
})
|
|
348
|
+
.json();
|
|
349
|
+
update(shareId, { status: 'declined', reason });
|
|
196
350
|
}
|
|
197
351
|
catch (e) {
|
|
352
|
+
const error = (0, ensure_error_1.default)(e);
|
|
353
|
+
if ('code' in error && error.code === 'MAP_SHARE_CANCELED') {
|
|
354
|
+
update(shareId, { status: 'canceled' });
|
|
355
|
+
throw new MapShareCanceledError(shareId);
|
|
356
|
+
}
|
|
198
357
|
handleError(shareId, e);
|
|
199
358
|
throw e;
|
|
200
359
|
}
|
|
201
360
|
},
|
|
202
361
|
async abort({ shareId }) {
|
|
362
|
+
const mapShare = get(shareId);
|
|
363
|
+
if (mapShare.status === 'canceled') {
|
|
364
|
+
throw new MapShareCanceledError(shareId);
|
|
365
|
+
}
|
|
203
366
|
update(shareId, { status: 'aborted' });
|
|
204
367
|
try {
|
|
205
368
|
const downloadId = await downloads.get(shareId);
|
|
@@ -229,15 +392,14 @@ function createReceivedMapSharesStore({ clientApi, mapServerApi, queryClient, })
|
|
|
229
392
|
function createSentMapSharesStore({ clientApi, mapServerApi, }) {
|
|
230
393
|
const { subscribe, getSnapshot, update, add, handleError, monitor } = createMapSharesStore({ mapServerApi });
|
|
231
394
|
const actions = {
|
|
232
|
-
async createAndSend({
|
|
395
|
+
async createAndSend({ receiverDeviceId, mapId = constants_js_1.CUSTOM_MAP_ID, }) {
|
|
233
396
|
const mapShare = await mapServerApi
|
|
234
397
|
.post('mapShares', {
|
|
235
398
|
json: { receiverDeviceId, mapId },
|
|
236
399
|
})
|
|
237
400
|
.json();
|
|
238
401
|
try {
|
|
239
|
-
|
|
240
|
-
await project.$sendMapShare(mapShare);
|
|
402
|
+
await clientApi.sendMapShare(mapShare);
|
|
241
403
|
}
|
|
242
404
|
catch (e) {
|
|
243
405
|
await mapServerApi.post(`mapShares/${mapShare.shareId}/cancel`);
|
|
@@ -279,7 +441,7 @@ const allowedStatusTransitions = {
|
|
|
279
441
|
*/
|
|
280
442
|
function assertValidStatusTransition(current, next) {
|
|
281
443
|
if (!allowedStatusTransitions[current].includes(next)) {
|
|
282
|
-
throw new
|
|
444
|
+
throw new InvalidStatusTransitionError(current, next);
|
|
283
445
|
}
|
|
284
446
|
}
|
|
285
447
|
const finalStatuses = [
|
|
@@ -23,7 +23,7 @@ exports.getDocumentsQueryKey = getDocumentsQueryKey;
|
|
|
23
23
|
exports.getManyDocumentsQueryKey = getManyDocumentsQueryKey;
|
|
24
24
|
exports.getDocumentByDocIdQueryKey = getDocumentByDocIdQueryKey;
|
|
25
25
|
exports.getDocumentByVersionIdQueryKey = getDocumentByVersionIdQueryKey;
|
|
26
|
-
const
|
|
26
|
+
const constants_js_1 = require("@comapeo/map-server/constants.js");
|
|
27
27
|
// #region Shared
|
|
28
28
|
const ROOT_QUERY_KEY = '@comapeo/core-react';
|
|
29
29
|
// Since the API is running locally, queries should run regardless of network
|
|
@@ -103,7 +103,7 @@ async function invalidateMapQueries(queryClient, { mapId }) {
|
|
|
103
103
|
queryKey: getMapQueryKey({ mapId }),
|
|
104
104
|
}),
|
|
105
105
|
queryClient.invalidateQueries({
|
|
106
|
-
queryKey: getMapQueryKey({ mapId:
|
|
106
|
+
queryKey: getMapQueryKey({ mapId: constants_js_1.DEFAULT_MAP_ID }),
|
|
107
107
|
}),
|
|
108
108
|
]);
|
|
109
109
|
}
|
|
@@ -42,7 +42,7 @@ export declare function useReceivedMapSharesState<T>(selector: (state: Array<Rec
|
|
|
42
42
|
* @internal
|
|
43
43
|
*/
|
|
44
44
|
export declare function useSentMapSharesActions(): {
|
|
45
|
-
createAndSend({
|
|
45
|
+
createAndSend({ receiverDeviceId, mapId, }: import("../lib/map-shares-stores.js").CreateAndSendMapShareOptions): Promise<import("@comapeo/map-server").MapShareState>;
|
|
46
46
|
cancel({ shareId }: import("../lib/map-shares-stores.js").CancelMapShareOptions): Promise<void>;
|
|
47
47
|
};
|
|
48
48
|
/**
|
package/dist/esm/hooks/maps.d.ts
CHANGED
|
@@ -141,6 +141,9 @@ export declare function useManyReceivedMapShares(): ReceivedMapShareState[];
|
|
|
141
141
|
*
|
|
142
142
|
* @param opts.shareId ID of the map share
|
|
143
143
|
*
|
|
144
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no received share
|
|
145
|
+
* with the given `shareId` exists.
|
|
146
|
+
*
|
|
144
147
|
* @example
|
|
145
148
|
* ```tsx
|
|
146
149
|
* function MapShareDetail({ shareId }: { shareId: string }) {
|
|
@@ -156,15 +159,28 @@ export declare function useSingleReceivedMapShare({ shareId }: {
|
|
|
156
159
|
/**
|
|
157
160
|
* Accept and download a map share that has been received. The mutate promise
|
|
158
161
|
* resolves once the map _starts_ downloading, before it finishes downloading.
|
|
159
|
-
* Use `
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
162
|
+
* Use `useManyReceivedMapShares` or `useSingleReceivedMapShare` to track
|
|
163
|
+
* download progress and final status.
|
|
164
|
+
*
|
|
165
|
+
* If the sender canceled the share before the receiver calls this, the
|
|
166
|
+
* mutation will still resolve (the download starts), but the share status will
|
|
167
|
+
* end up as `'canceled'` rather than `'completed'`. This is the only way the
|
|
168
|
+
* receiver discovers that a share has been canceled — check `share.status`
|
|
169
|
+
* after the download settles.
|
|
170
|
+
*
|
|
171
|
+
* @throws An error with code `'MAP_SHARE_CANCELED'` if the share is already
|
|
172
|
+
* known to be canceled (i.e. `status` is `'canceled'` in the store, e.g.
|
|
173
|
+
* after a previous download attempt discovered the cancellation).
|
|
174
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
175
|
+
* not in a valid state to start downloading (e.g. already downloading,
|
|
176
|
+
* completed, or declined).
|
|
177
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
178
|
+
* given `shareId` exists in the store.
|
|
163
179
|
*
|
|
164
180
|
* @example
|
|
165
181
|
* ```tsx
|
|
166
182
|
* function AcceptButton({ shareId }: { shareId: string }) {
|
|
167
|
-
* const { mutate: accept } =
|
|
183
|
+
* const { mutate: accept } = useDownloadReceivedMapShare()
|
|
168
184
|
*
|
|
169
185
|
* return <button onClick={() => accept({ shareId })}>Accept</button>
|
|
170
186
|
* }
|
|
@@ -189,17 +205,28 @@ export declare function useDownloadReceivedMapShare(): Pick<import("@tanstack/re
|
|
|
189
205
|
}, "error" | "status" | "mutate" | "reset" | "mutateAsync">;
|
|
190
206
|
/**
|
|
191
207
|
* Decline a map share that has been received. Notifies the sender that the
|
|
192
|
-
* share was declined.
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
208
|
+
* share was declined. The share status is only updated to `'declined'` after
|
|
209
|
+
* the server confirms the decline — there is no optimistic update.
|
|
210
|
+
*
|
|
211
|
+
* If the sender canceled the share before the decline reaches the server, the
|
|
212
|
+
* share status will transition to `'canceled'` (not `'error'`) and the
|
|
213
|
+
* mutation will throw a `MapShareCanceledError`.
|
|
214
|
+
*
|
|
215
|
+
* @throws An error with code `'MAP_SHARE_CANCELED'` if the share is already
|
|
216
|
+
* known to be canceled, or if the server reports that the sender canceled
|
|
217
|
+
* the share while the decline was in flight. In both cases `share.status`
|
|
218
|
+
* will be `'canceled'`.
|
|
219
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
220
|
+
* not in `status='pending'` (e.g. already downloading, completed, or
|
|
221
|
+
* declined).
|
|
222
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
223
|
+
* given `shareId` exists in the store.
|
|
197
224
|
*
|
|
198
225
|
* @example
|
|
199
226
|
* ```tsx
|
|
200
227
|
* import { DeclineReason } from '@comapeo/core-react'
|
|
201
228
|
* function DeclineButton({ shareId }: { shareId: string }) {
|
|
202
|
-
* const { mutate: decline } =
|
|
229
|
+
* const { mutate: decline } = useDeclineReceivedMapShare()
|
|
203
230
|
*
|
|
204
231
|
* return (
|
|
205
232
|
* <button onClick={() => decline({ shareId, reason: DeclineReason.user_rejected })}>
|
|
@@ -229,13 +256,20 @@ export declare function useDeclineReceivedMapShare(): Pick<import("@tanstack/rea
|
|
|
229
256
|
/**
|
|
230
257
|
* Abort an in-progress map share download.
|
|
231
258
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
259
|
+
* @throws An error with code `'MAP_SHARE_CANCELED'` if the share is already
|
|
260
|
+
* known to be canceled.
|
|
261
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
262
|
+
* not in `status='downloading'` (e.g. still pending, already completed, or
|
|
263
|
+
* declined).
|
|
264
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
265
|
+
* given `shareId` exists in the store.
|
|
266
|
+
* @throws An error with code `'DOWNLOAD_NOT_FOUND'` if no download is
|
|
267
|
+
* currently tracked for this share (e.g. the download was never started).
|
|
234
268
|
*
|
|
235
269
|
* @example
|
|
236
270
|
* ```tsx
|
|
237
271
|
* function AbortButton({ shareId }: { shareId: string }) {
|
|
238
|
-
* const { mutate: abort } =
|
|
272
|
+
* const { mutate: abort } = useAbortReceivedMapShareDownload()
|
|
239
273
|
*
|
|
240
274
|
* return <button onClick={() => abort({ shareId })}>Cancel Download</button>
|
|
241
275
|
* }
|
|
@@ -264,8 +298,6 @@ export declare function useAbortReceivedMapShareDownload(): Pick<import("@tansta
|
|
|
264
298
|
* mutation resolves with the created map share object, including its ID, which
|
|
265
299
|
* can be used to track the share status with `useSingleSentMapShare`.
|
|
266
300
|
*
|
|
267
|
-
* @param opts.projectId Public ID of project for sending the map share: you can only send map shares to users on the same project
|
|
268
|
-
*
|
|
269
301
|
* @example
|
|
270
302
|
* ```tsx
|
|
271
303
|
* function SendMapButton({ projectId, deviceId }: { projectId: string; deviceId: string }) {
|
|
@@ -274,7 +306,7 @@ export declare function useAbortReceivedMapShareDownload(): Pick<import("@tansta
|
|
|
274
306
|
* return (
|
|
275
307
|
* <button
|
|
276
308
|
* onClick={() =>
|
|
277
|
-
* send({
|
|
309
|
+
* send({ receiverDeviceId: deviceId, mapId: 'custom' }, {
|
|
278
310
|
* onSuccess: (mapShare) => {
|
|
279
311
|
* console.log('Share sent with id', mapShare.shareId)
|
|
280
312
|
* }
|
|
@@ -311,6 +343,12 @@ export declare function useSendMapShare(): Pick<import("@tanstack/react-query").
|
|
|
311
343
|
* the share, the download will be canceled before completion. If the download
|
|
312
344
|
* is already complete, this action will throw an error.
|
|
313
345
|
*
|
|
346
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
347
|
+
* not in `status='pending'` or `status='downloading'` (e.g. already
|
|
348
|
+
* completed, canceled, aborted, or declined).
|
|
349
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
350
|
+
* given `shareId` exists in the store.
|
|
351
|
+
*
|
|
314
352
|
* @param opts.projectId Public ID of project to request the map share cancellation for.
|
|
315
353
|
*
|
|
316
354
|
* @example
|
|
@@ -344,7 +382,8 @@ export declare function useCancelSentMapShare(): Pick<import("@tanstack/react-qu
|
|
|
344
382
|
* of the share, updated in real-time. When the recipient starts downloading, or
|
|
345
383
|
* if they decline the share, then the returned share will update.
|
|
346
384
|
*
|
|
347
|
-
*
|
|
385
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no sent share with
|
|
386
|
+
* the given `shareId` exists in the store.
|
|
348
387
|
*
|
|
349
388
|
* @param opts.shareId ID of the sent map share
|
|
350
389
|
*
|
package/dist/esm/hooks/maps.js
CHANGED
|
@@ -149,6 +149,9 @@ export function useManyReceivedMapShares() {
|
|
|
149
149
|
*
|
|
150
150
|
* @param opts.shareId ID of the map share
|
|
151
151
|
*
|
|
152
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no received share
|
|
153
|
+
* with the given `shareId` exists.
|
|
154
|
+
*
|
|
152
155
|
* @example
|
|
153
156
|
* ```tsx
|
|
154
157
|
* function MapShareDetail({ shareId }: { shareId: string }) {
|
|
@@ -161,22 +164,35 @@ export function useManyReceivedMapShares() {
|
|
|
161
164
|
export function useSingleReceivedMapShare({ shareId }) {
|
|
162
165
|
const mapShare = useReceivedMapSharesState(useCallback((shares) => shares.find((s) => s.shareId === shareId), [shareId]));
|
|
163
166
|
if (!mapShare) {
|
|
164
|
-
throw new
|
|
167
|
+
throw new errors.MAP_SHARE_NOT_FOUND(`Received map share with id ${shareId} not found`);
|
|
165
168
|
}
|
|
166
169
|
return mapShare;
|
|
167
170
|
}
|
|
168
171
|
/**
|
|
169
172
|
* Accept and download a map share that has been received. The mutate promise
|
|
170
173
|
* resolves once the map _starts_ downloading, before it finishes downloading.
|
|
171
|
-
* Use `
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
174
|
+
* Use `useManyReceivedMapShares` or `useSingleReceivedMapShare` to track
|
|
175
|
+
* download progress and final status.
|
|
176
|
+
*
|
|
177
|
+
* If the sender canceled the share before the receiver calls this, the
|
|
178
|
+
* mutation will still resolve (the download starts), but the share status will
|
|
179
|
+
* end up as `'canceled'` rather than `'completed'`. This is the only way the
|
|
180
|
+
* receiver discovers that a share has been canceled — check `share.status`
|
|
181
|
+
* after the download settles.
|
|
182
|
+
*
|
|
183
|
+
* @throws An error with code `'MAP_SHARE_CANCELED'` if the share is already
|
|
184
|
+
* known to be canceled (i.e. `status` is `'canceled'` in the store, e.g.
|
|
185
|
+
* after a previous download attempt discovered the cancellation).
|
|
186
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
187
|
+
* not in a valid state to start downloading (e.g. already downloading,
|
|
188
|
+
* completed, or declined).
|
|
189
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
190
|
+
* given `shareId` exists in the store.
|
|
175
191
|
*
|
|
176
192
|
* @example
|
|
177
193
|
* ```tsx
|
|
178
194
|
* function AcceptButton({ shareId }: { shareId: string }) {
|
|
179
|
-
* const { mutate: accept } =
|
|
195
|
+
* const { mutate: accept } = useDownloadReceivedMapShare()
|
|
180
196
|
*
|
|
181
197
|
* return <button onClick={() => accept({ shareId })}>Accept</button>
|
|
182
198
|
* }
|
|
@@ -193,17 +209,28 @@ export function useDownloadReceivedMapShare() {
|
|
|
193
209
|
}
|
|
194
210
|
/**
|
|
195
211
|
* Decline a map share that has been received. Notifies the sender that the
|
|
196
|
-
* share was declined.
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
212
|
+
* share was declined. The share status is only updated to `'declined'` after
|
|
213
|
+
* the server confirms the decline — there is no optimistic update.
|
|
214
|
+
*
|
|
215
|
+
* If the sender canceled the share before the decline reaches the server, the
|
|
216
|
+
* share status will transition to `'canceled'` (not `'error'`) and the
|
|
217
|
+
* mutation will throw a `MapShareCanceledError`.
|
|
218
|
+
*
|
|
219
|
+
* @throws An error with code `'MAP_SHARE_CANCELED'` if the share is already
|
|
220
|
+
* known to be canceled, or if the server reports that the sender canceled
|
|
221
|
+
* the share while the decline was in flight. In both cases `share.status`
|
|
222
|
+
* will be `'canceled'`.
|
|
223
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
224
|
+
* not in `status='pending'` (e.g. already downloading, completed, or
|
|
225
|
+
* declined).
|
|
226
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
227
|
+
* given `shareId` exists in the store.
|
|
201
228
|
*
|
|
202
229
|
* @example
|
|
203
230
|
* ```tsx
|
|
204
231
|
* import { DeclineReason } from '@comapeo/core-react'
|
|
205
232
|
* function DeclineButton({ shareId }: { shareId: string }) {
|
|
206
|
-
* const { mutate: decline } =
|
|
233
|
+
* const { mutate: decline } = useDeclineReceivedMapShare()
|
|
207
234
|
*
|
|
208
235
|
* return (
|
|
209
236
|
* <button onClick={() => decline({ shareId, reason: DeclineReason.user_rejected })}>
|
|
@@ -225,13 +252,20 @@ export function useDeclineReceivedMapShare() {
|
|
|
225
252
|
/**
|
|
226
253
|
* Abort an in-progress map share download.
|
|
227
254
|
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
255
|
+
* @throws An error with code `'MAP_SHARE_CANCELED'` if the share is already
|
|
256
|
+
* known to be canceled.
|
|
257
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
258
|
+
* not in `status='downloading'` (e.g. still pending, already completed, or
|
|
259
|
+
* declined).
|
|
260
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
261
|
+
* given `shareId` exists in the store.
|
|
262
|
+
* @throws An error with code `'DOWNLOAD_NOT_FOUND'` if no download is
|
|
263
|
+
* currently tracked for this share (e.g. the download was never started).
|
|
230
264
|
*
|
|
231
265
|
* @example
|
|
232
266
|
* ```tsx
|
|
233
267
|
* function AbortButton({ shareId }: { shareId: string }) {
|
|
234
|
-
* const { mutate: abort } =
|
|
268
|
+
* const { mutate: abort } = useAbortReceivedMapShareDownload()
|
|
235
269
|
*
|
|
236
270
|
* return <button onClick={() => abort({ shareId })}>Cancel Download</button>
|
|
237
271
|
* }
|
|
@@ -255,8 +289,6 @@ export function useAbortReceivedMapShareDownload() {
|
|
|
255
289
|
* mutation resolves with the created map share object, including its ID, which
|
|
256
290
|
* can be used to track the share status with `useSingleSentMapShare`.
|
|
257
291
|
*
|
|
258
|
-
* @param opts.projectId Public ID of project for sending the map share: you can only send map shares to users on the same project
|
|
259
|
-
*
|
|
260
292
|
* @example
|
|
261
293
|
* ```tsx
|
|
262
294
|
* function SendMapButton({ projectId, deviceId }: { projectId: string; deviceId: string }) {
|
|
@@ -265,7 +297,7 @@ export function useAbortReceivedMapShareDownload() {
|
|
|
265
297
|
* return (
|
|
266
298
|
* <button
|
|
267
299
|
* onClick={() =>
|
|
268
|
-
* send({
|
|
300
|
+
* send({ receiverDeviceId: deviceId, mapId: 'custom' }, {
|
|
269
301
|
* onSuccess: (mapShare) => {
|
|
270
302
|
* console.log('Share sent with id', mapShare.shareId)
|
|
271
303
|
* }
|
|
@@ -294,6 +326,12 @@ export function useSendMapShare() {
|
|
|
294
326
|
* the share, the download will be canceled before completion. If the download
|
|
295
327
|
* is already complete, this action will throw an error.
|
|
296
328
|
*
|
|
329
|
+
* @throws An error with code `'INVALID_STATUS_TRANSITION'` if the share is
|
|
330
|
+
* not in `status='pending'` or `status='downloading'` (e.g. already
|
|
331
|
+
* completed, canceled, aborted, or declined).
|
|
332
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no share with the
|
|
333
|
+
* given `shareId` exists in the store.
|
|
334
|
+
*
|
|
297
335
|
* @param opts.projectId Public ID of project to request the map share cancellation for.
|
|
298
336
|
*
|
|
299
337
|
* @example
|
|
@@ -319,7 +357,8 @@ export function useCancelSentMapShare() {
|
|
|
319
357
|
* of the share, updated in real-time. When the recipient starts downloading, or
|
|
320
358
|
* if they decline the share, then the returned share will update.
|
|
321
359
|
*
|
|
322
|
-
*
|
|
360
|
+
* @throws An error with code `'MAP_SHARE_NOT_FOUND'` if no sent share with
|
|
361
|
+
* the given `shareId` exists in the store.
|
|
323
362
|
*
|
|
324
363
|
* @param opts.shareId ID of the sent map share
|
|
325
364
|
*
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { useCreateDocument, useDeleteDocument, useManyDocs, usePresetsSelection,
|
|
|
4
4
|
export { useAcceptInvite, useManyInvites, useRejectInvite, useRequestCancelInvite, useSendInvite, useSingleInvite, } from './hooks/invites.js';
|
|
5
5
|
export { useMapStyleUrl, useImportCustomMapFile, useRemoveCustomMapFile, useGetCustomMapInfo, useManyReceivedMapShares, useSingleReceivedMapShare, useDeclineReceivedMapShare, useDownloadReceivedMapShare, useAbortReceivedMapShareDownload, useSendMapShare, useCancelSentMapShare, useSingleSentMapShare, } from './hooks/maps.js';
|
|
6
6
|
export type { SentMapShareState, ReceivedMapShareState, AbortMapShareOptions, CancelMapShareOptions, DeclineMapShareOptions, DownloadMapShareOptions, CreateAndSendMapShareOptions, } from './lib/map-shares-stores.js';
|
|
7
|
-
export { DeclineReason } from './lib/map-shares-stores.js';
|
|
7
|
+
export { DeclineReason, MapShareErrorCode, getErrorCode, MapShareCanceledError, InvalidStatusTransitionError, } 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
9
|
export type { SyncState } from './lib/sync.js';
|
|
10
10
|
export type { WriteableDocument, WriteableDocumentType, WriteableValue, } from './lib/types.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -3,6 +3,6 @@ export { useClientApi, useIsArchiveDevice, useOwnDeviceInfo, useSetIsArchiveDevi
|
|
|
3
3
|
export { useCreateDocument, useDeleteDocument, useManyDocs, usePresetsSelection, useSingleDocByDocId, useSingleDocByVersionId, useUpdateDocument, } from './hooks/documents.js';
|
|
4
4
|
export { useAcceptInvite, useManyInvites, useRejectInvite, useRequestCancelInvite, useSendInvite, useSingleInvite, } from './hooks/invites.js';
|
|
5
5
|
export { useMapStyleUrl, useImportCustomMapFile, useRemoveCustomMapFile, useGetCustomMapInfo, useManyReceivedMapShares, useSingleReceivedMapShare, useDeclineReceivedMapShare, useDownloadReceivedMapShare, useAbortReceivedMapShareDownload, useSendMapShare, useCancelSentMapShare, useSingleSentMapShare, } from './hooks/maps.js';
|
|
6
|
-
export { DeclineReason } from './lib/map-shares-stores.js';
|
|
6
|
+
export { DeclineReason, MapShareErrorCode, getErrorCode, MapShareCanceledError, InvalidStatusTransitionError, } from './lib/map-shares-stores.js';
|
|
7
7
|
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';
|
|
8
8
|
export { HTTPError, isHTTPError } from './lib/http.js';
|