@comapeo/core-react 8.0.0 → 9.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 (43) hide show
  1. package/README.md +38 -0
  2. package/dist/commonjs/contexts/ClientApi.d.ts +5 -5
  3. package/dist/commonjs/contexts/ClientApi.js +6 -5
  4. package/dist/commonjs/contexts/ComapeoCore.d.ts +8 -0
  5. package/dist/commonjs/contexts/ComapeoCore.js +9 -0
  6. package/dist/commonjs/contexts/MapServer.d.ts +69 -0
  7. package/dist/commonjs/contexts/MapServer.js +92 -0
  8. package/dist/commonjs/contexts/MapShares.d.ts +52 -0
  9. package/dist/commonjs/contexts/MapShares.js +74 -0
  10. package/dist/commonjs/hooks/maps.d.ts +460 -3
  11. package/dist/commonjs/hooks/maps.js +261 -4
  12. package/dist/commonjs/index.d.ts +5 -2
  13. package/dist/commonjs/index.js +20 -3
  14. package/dist/commonjs/lib/http.d.ts +45 -0
  15. package/dist/commonjs/lib/http.js +103 -0
  16. package/dist/commonjs/lib/map-shares-stores.d.ts +80 -0
  17. package/dist/commonjs/lib/map-shares-stores.js +299 -0
  18. package/dist/commonjs/lib/react-query/maps.d.ts +66 -20
  19. package/dist/commonjs/lib/react-query/maps.js +113 -11
  20. package/dist/commonjs/lib/react-query/mutation-result.d.ts +8 -0
  21. package/dist/commonjs/lib/react-query/mutation-result.js +22 -0
  22. package/dist/esm/contexts/ClientApi.d.ts +5 -5
  23. package/dist/esm/contexts/ClientApi.js +6 -5
  24. package/dist/esm/contexts/ComapeoCore.d.ts +8 -0
  25. package/dist/esm/contexts/ComapeoCore.js +6 -0
  26. package/dist/esm/contexts/MapServer.d.ts +69 -0
  27. package/dist/esm/contexts/MapServer.js +86 -0
  28. package/dist/esm/contexts/MapShares.d.ts +52 -0
  29. package/dist/esm/contexts/MapShares.js +65 -0
  30. package/dist/esm/hooks/maps.d.ts +460 -3
  31. package/dist/esm/hooks/maps.js +252 -6
  32. package/dist/esm/index.d.ts +5 -2
  33. package/dist/esm/index.js +4 -2
  34. package/dist/esm/lib/http.d.ts +45 -0
  35. package/dist/esm/lib/http.js +98 -0
  36. package/dist/esm/lib/map-shares-stores.d.ts +80 -0
  37. package/dist/esm/lib/map-shares-stores.js +291 -0
  38. package/dist/esm/lib/react-query/maps.d.ts +66 -20
  39. package/dist/esm/lib/react-query/maps.js +109 -12
  40. package/dist/esm/lib/react-query/mutation-result.d.ts +8 -0
  41. package/dist/esm/lib/react-query/mutation-result.js +19 -0
  42. package/docs/API.md +567 -60
  43. package/package.json +15 -4
@@ -1,9 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useMapStyleUrl = useMapStyleUrl;
4
+ exports.useImportCustomMapFile = useImportCustomMapFile;
5
+ exports.useRemoveCustomMapFile = useRemoveCustomMapFile;
6
+ exports.useGetCustomMapInfo = useGetCustomMapInfo;
7
+ exports.useManyReceivedMapShares = useManyReceivedMapShares;
8
+ exports.useSingleReceivedMapShare = useSingleReceivedMapShare;
9
+ exports.useDownloadReceivedMapShare = useDownloadReceivedMapShare;
10
+ exports.useDeclineReceivedMapShare = useDeclineReceivedMapShare;
11
+ exports.useAbortReceivedMapShareDownload = useAbortReceivedMapShareDownload;
12
+ exports.useSendMapShare = useSendMapShare;
13
+ exports.useCancelSentMapShare = useCancelSentMapShare;
14
+ exports.useSingleSentMapShare = useSingleSentMapShare;
15
+ const constants_js_1 = require("@comapeo/map-server/constants.js");
16
+ const errors_js_1 = require("@comapeo/map-server/errors.js");
4
17
  const react_query_1 = require("@tanstack/react-query");
18
+ const react_1 = require("react");
19
+ const MapServer_js_1 = require("../contexts/MapServer.js");
20
+ const MapShares_js_1 = require("../contexts/MapShares.js");
5
21
  const maps_js_1 = require("../lib/react-query/maps.js");
6
- const client_js_1 = require("./client.js");
22
+ const mutation_result_js_1 = require("../lib/react-query/mutation-result.js");
7
23
  /**
8
24
  * Get a URL that points to a StyleJSON resource served by the embedded HTTP server.
9
25
  *
@@ -30,8 +46,249 @@ const client_js_1 = require("./client.js");
30
46
  * }
31
47
  * ```
32
48
  */
33
- function useMapStyleUrl({ refreshToken, } = {}) {
34
- const clientApi = (0, client_js_1.useClientApi)();
35
- const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, maps_js_1.mapStyleJsonUrlQueryOptions)({ clientApi, refreshToken }));
49
+ function useMapStyleUrl() {
50
+ const mapServerApi = (0, MapServer_js_1.useMapServerApi)();
51
+ const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, maps_js_1.mapStyleJsonUrlQueryOptions)({ mapServerApi }));
36
52
  return { data, error, isRefetching };
37
53
  }
54
+ /**
55
+ * Import a custom SMP map file, replacing any existing custom map. The mutation
56
+ * resolves once the file is successfully uploaded and processed by the server.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * function MapImportExample() {
61
+ * const { mutate: importMap } = useImportCustomMapFile()
62
+ *
63
+ * }
64
+ * ```
65
+ */
66
+ function useImportCustomMapFile() {
67
+ const mapServerApi = (0, MapServer_js_1.useMapServerApi)();
68
+ const queryClient = (0, react_query_1.useQueryClient)();
69
+ const options = (0, maps_js_1.mapImportMutationOptions)({ mapServerApi, queryClient });
70
+ const result = (0, react_query_1.useMutation)(options);
71
+ return (0, mutation_result_js_1.filterMutationResult)(result);
72
+ }
73
+ function useRemoveCustomMapFile() {
74
+ const mapServerApi = (0, MapServer_js_1.useMapServerApi)();
75
+ const queryClient = (0, react_query_1.useQueryClient)();
76
+ const options = (0, maps_js_1.mapRemoveMutationOptions)({ mapServerApi, queryClient });
77
+ const result = (0, react_query_1.useMutation)(options);
78
+ return (0, mutation_result_js_1.filterMutationResult)(result);
79
+ }
80
+ function useGetCustomMapInfo() {
81
+ const mapServerApi = (0, MapServer_js_1.useMapServerApi)();
82
+ const { data, error, isRefetching } = (0, react_query_1.useQuery)((0, maps_js_1.mapInfoQueryOptions)({ mapServerApi, mapId: constants_js_1.CUSTOM_MAP_ID }));
83
+ return { data, error, isRefetching };
84
+ }
85
+ // ============================================
86
+ // RECEIVER HOOKS
87
+ // ============================================
88
+ /**
89
+ * Get all map shares that the device has received. Automatically updates when
90
+ * new shares arrive or share states change.
91
+ *
92
+ * IMPORTANT: This hook will not trigger a re-render when download progress
93
+ * updates, only when the status changes. This is to avoid excessive re-renders
94
+ * during downloads. Use `useSingleReceivedMapShare` to get real-time updates on
95
+ * a specific share, including download progress.
96
+ *
97
+ * @example
98
+ * ```tsx
99
+ * function MapSharesList() {
100
+ * const shares = useManyReceivedMapShares()
101
+ *
102
+ * return shares.map(share => (
103
+ * <div key={share.shareId}>
104
+ * {share.mapName} from {share.senderDeviceName} - {share.state}
105
+ * </div>
106
+ * ))
107
+ * }
108
+ * ```
109
+ */
110
+ function useManyReceivedMapShares() {
111
+ return (0, MapShares_js_1.useReceivedMapSharesState)();
112
+ }
113
+ /**
114
+ * Get a single received map share based on its shareId.
115
+ *
116
+ * @param opts.shareId ID of the map share
117
+ *
118
+ * @example
119
+ * ```tsx
120
+ * function MapShareDetail({ shareId }: { shareId: string }) {
121
+ * const share = useSingleReceivedMapShare({ shareId })
122
+ *
123
+ * return <div>{share.mapName} - {share.state}</div>
124
+ * }
125
+ * ```
126
+ */
127
+ function useSingleReceivedMapShare({ shareId }) {
128
+ const mapShare = (0, MapShares_js_1.useReceivedMapSharesState)((0, react_1.useCallback)((shares) => shares.find((s) => s.shareId === shareId), [shareId]));
129
+ if (!mapShare) {
130
+ throw new Error(`Map share with id ${shareId} not found`);
131
+ }
132
+ return mapShare;
133
+ }
134
+ /**
135
+ * Accept and download a map share that has been received. The mutate promise
136
+ * resolves once the map _starts_ downloading, before it finishes downloading.
137
+ * Use `useManyMapShares` or `useSingleMapShare` to track download progress.
138
+ *
139
+ * Throws if the share is not in `status="pending"` or if the download fails to
140
+ * start (e.g. if the shareId if invalid).
141
+ *
142
+ * @example
143
+ * ```tsx
144
+ * function AcceptButton({ shareId }: { shareId: string }) {
145
+ * const { mutate: accept } = useAcceptMapShare()
146
+ *
147
+ * return <button onClick={() => accept({ shareId })}>Accept</button>
148
+ * }
149
+ * ```
150
+ */
151
+ function useDownloadReceivedMapShare() {
152
+ const { download } = (0, MapShares_js_1.useReceivedMapSharesActions)();
153
+ const options = (0, maps_js_1.mapSharesMutationOptions)({ action: download });
154
+ const result = (0, react_query_1.useMutation)(options);
155
+ return (0, mutation_result_js_1.filterMutationResult)(result);
156
+ }
157
+ /**
158
+ * Decline a map share that has been received. Notifies the sender that the
159
+ * share was declined.
160
+ *
161
+ * Throws if the share is not with `status="pending"`
162
+ * Throws if shareId is invalid
163
+ * Throws if decline request fails (e.g. network error)
164
+ *
165
+ * @example
166
+ * ```tsx
167
+ * import { DeclineReason } from '@comapeo/core-react'
168
+ * function DeclineButton({ shareId }: { shareId: string }) {
169
+ * const { mutate: decline } = useDeclineMapShare()
170
+ *
171
+ * return (
172
+ * <button onClick={() => decline({ shareId, reason: DeclineReason.user_rejected })}>
173
+ * Decline
174
+ * </button>
175
+ * )
176
+ * }
177
+ * ```
178
+ */
179
+ function useDeclineReceivedMapShare() {
180
+ const { decline } = (0, MapShares_js_1.useReceivedMapSharesActions)();
181
+ const options = (0, maps_js_1.mapSharesMutationOptions)({ action: decline });
182
+ const result = (0, react_query_1.useMutation)(options);
183
+ return (0, mutation_result_js_1.filterMutationResult)(result);
184
+ }
185
+ /**
186
+ * Abort an in-progress map share download.
187
+ *
188
+ * Throws if the share is not in `status="downloading"`
189
+ * Throws if shareId is invalid
190
+ *
191
+ * @example
192
+ * ```tsx
193
+ * function AbortButton({ shareId }: { shareId: string }) {
194
+ * const { mutate: abort } = useAbortMapShareDownload()
195
+ *
196
+ * return <button onClick={() => abort({ shareId })}>Cancel Download</button>
197
+ * }
198
+ * ```
199
+ */
200
+ function useAbortReceivedMapShareDownload() {
201
+ const { abort } = (0, MapShares_js_1.useReceivedMapSharesActions)();
202
+ const options = (0, maps_js_1.mapSharesMutationOptions)({ action: abort });
203
+ const result = (0, react_query_1.useMutation)(options);
204
+ return (0, mutation_result_js_1.filterMutationResult)(result);
205
+ }
206
+ // ============================================
207
+ // SENDER HOOKS
208
+ // ============================================
209
+ /**
210
+ * Share a map with a device. The mutation resolves immediately after sending
211
+ * the share offer, without waiting for the recipient to accept or reject. The
212
+ * mutation resolves with the created map share object, including its ID, which
213
+ * can be used to track the share status with `useSingleSentMapShare`.
214
+ *
215
+ * @param opts.projectId Public ID of project for sending the map share: you can only send map shares to users on the same project
216
+ *
217
+ * @example
218
+ * ```tsx
219
+ * function SendMapButton({ projectId, deviceId }: { projectId: string; deviceId: string }) {
220
+ * const { mutate: send } = useSendMapShare({ projectId }, {
221
+ * onSuccess: (mapShare) => {
222
+ * console.log('Share sent with id', mapShare.shareId)
223
+ * }
224
+ * })
225
+ *
226
+ * return (
227
+ * <button onClick={() => send({ receiverDeviceId: deviceId, mapId: 'custom' })}>
228
+ * Send Map
229
+ * </button>
230
+ * )
231
+ * }
232
+ * ```
233
+ */
234
+ function useSendMapShare({ projectId }) {
235
+ const { createAndSend } = (0, MapShares_js_1.useSentMapSharesActions)();
236
+ const options = (0, maps_js_1.mapSharesMutationOptions)({ action: createAndSend, projectId });
237
+ const result = (0, react_query_1.useMutation)(options);
238
+ return (0, mutation_result_js_1.filterMutationResult)(result);
239
+ }
240
+ /**
241
+ * Cancel a map share that was previously sent. If the recipient has not yet
242
+ * started downloading the share, they will not be notified until they attempt
243
+ * to accept the share and begin downloading it. If they are already downloading
244
+ * the share, the download will be canceled before completion. If the download
245
+ * is already complete, this action will throw an error.
246
+ *
247
+ * @param opts.projectId Public ID of project to request the map share cancellation for.
248
+ *
249
+ * @example
250
+ * ```tsx
251
+ * function CancelShareButton({ projectId, shareId }: { projectId: string; shareId: string }) {
252
+ * const { mutate: cancel } = useRequestCancelMapShare({ projectId })
253
+ *
254
+ * return <button onClick={() => cancel({ shareId })}>Cancel Share</button>
255
+ * }
256
+ * ```
257
+ */
258
+ function useCancelSentMapShare() {
259
+ const { cancel } = (0, MapShares_js_1.useSentMapSharesActions)();
260
+ const options = (0, maps_js_1.mapSharesMutationOptions)({ action: cancel });
261
+ const result = (0, react_query_1.useMutation)(options);
262
+ return (0, mutation_result_js_1.filterMutationResult)(result);
263
+ }
264
+ /**
265
+ * Track the status and progress of a sent map share. Returns the current state
266
+ * of the share, updated in real-time. When the recipient starts downloading, or
267
+ * if they decline the share, then the returned share will update.
268
+ *
269
+ * Throws if no share with the specified ID is found.
270
+ *
271
+ * @param opts.shareId ID of the sent map share
272
+ *
273
+ * @example
274
+ * ```tsx
275
+ * function SentShareStatus({ shareId }: { shareId: string }) {
276
+ * const mapShare = useSingleSentMapShare({ shareId })
277
+ *
278
+ * return (<div>
279
+ * <div>Share status: {mapShare.status}</div>
280
+ * {mapShare.status === 'pending' && <div>Waiting for recipient to accept...</div>}
281
+ * {mapShare.status === 'downloading' && (<div>Download in progress: {mapShare.downloadProgress}%</div>)}
282
+ * {mapShare.status === 'declined' && <div>Share was declined by recipient</div>}
283
+ * {mapShare.status === 'canceled' && <div>Share was canceled</div>}
284
+ * </div>)
285
+ * }
286
+ * ```
287
+ */
288
+ function useSingleSentMapShare({ shareId, }) {
289
+ const mapShare = (0, MapShares_js_1.useSentMapSharesState)((0, react_1.useCallback)((shares) => shares.find((s) => s.shareId === shareId), [shareId]));
290
+ if (!mapShare) {
291
+ throw new errors_js_1.errors.MAP_SHARE_NOT_FOUND(`Sent map share with id ${shareId} not found`);
292
+ }
293
+ return mapShare;
294
+ }
@@ -1,8 +1,11 @@
1
- export { ClientApiProvider } from './contexts/ClientApi.js';
1
+ export { ComapeoCoreProvider } from './contexts/ComapeoCore.js';
2
2
  export { useClientApi, useIsArchiveDevice, useOwnDeviceInfo, useSetIsArchiveDevice, useSetOwnDeviceInfo, } from './hooks/client.js';
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
- export { useMapStyleUrl } from './hooks/maps.js';
5
+ export { useMapStyleUrl, useImportCustomMapFile, useRemoveCustomMapFile, useGetCustomMapInfo, useManyReceivedMapShares, useSingleReceivedMapShare, useDeclineReceivedMapShare, useDownloadReceivedMapShare, useAbortReceivedMapShareDownload, useSendMapShare, useCancelSentMapShare, useSingleSentMapShare, } from './hooks/maps.js';
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';
6
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';
7
9
  export { type SyncState } from './lib/sync.js';
8
10
  export { type WriteableDocument, type WriteableDocumentType, type WriteableValue, } from './lib/types.js';
11
+ export { HTTPError, isHTTPError } from './lib/http.js';
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useExportZipFile = exports.useExportGeoJSON = exports.useChangeMemberRole = exports.useUpdateProjectSettings = exports.useSyncState = exports.useStopSync = exports.useStartSync = exports.useSingleProject = exports.useSingleMember = exports.useSetAutostopDataSyncTimeout = exports.useRemoveMember = exports.useRemoveServerPeer = exports.useProjectSettings = exports.useProjectOwnRoleChangeListener = exports.useOwnRoleInProject = exports.useManyProjects = exports.useManyMembers = exports.useLeaveProject = exports.useImportProjectConfig = exports.useImportProjectCategories = exports.useIconUrl = exports.useDocumentCreatedBy = exports.useDisconnectSyncServers = exports.useDataSyncProgress = exports.useCreateProject = exports.useCreateBlob = exports.useConnectSyncServers = exports.useAttachmentUrl = exports.useAddServerPeer = exports.useMapStyleUrl = exports.useSingleInvite = exports.useSendInvite = exports.useRequestCancelInvite = exports.useRejectInvite = exports.useManyInvites = exports.useAcceptInvite = exports.useUpdateDocument = exports.useSingleDocByVersionId = exports.useSingleDocByDocId = exports.usePresetsSelection = exports.useManyDocs = exports.useDeleteDocument = exports.useCreateDocument = exports.useSetOwnDeviceInfo = exports.useSetIsArchiveDevice = exports.useOwnDeviceInfo = exports.useIsArchiveDevice = exports.useClientApi = exports.ClientApiProvider = void 0;
4
- var ClientApi_js_1 = require("./contexts/ClientApi.js");
5
- Object.defineProperty(exports, "ClientApiProvider", { enumerable: true, get: function () { return ClientApi_js_1.ClientApiProvider; } });
3
+ exports.useRemoveServerPeer = exports.useProjectSettings = exports.useProjectOwnRoleChangeListener = exports.useOwnRoleInProject = exports.useManyProjects = exports.useManyMembers = exports.useLeaveProject = exports.useImportProjectConfig = exports.useImportProjectCategories = exports.useIconUrl = exports.useDocumentCreatedBy = exports.useDisconnectSyncServers = exports.useDataSyncProgress = exports.useCreateProject = exports.useCreateBlob = exports.useConnectSyncServers = exports.useAttachmentUrl = exports.useAddServerPeer = exports.DeclineReason = exports.useSingleSentMapShare = exports.useCancelSentMapShare = exports.useSendMapShare = exports.useAbortReceivedMapShareDownload = exports.useDownloadReceivedMapShare = exports.useDeclineReceivedMapShare = exports.useSingleReceivedMapShare = exports.useManyReceivedMapShares = exports.useGetCustomMapInfo = exports.useRemoveCustomMapFile = exports.useImportCustomMapFile = exports.useMapStyleUrl = exports.useSingleInvite = exports.useSendInvite = exports.useRequestCancelInvite = exports.useRejectInvite = exports.useManyInvites = exports.useAcceptInvite = exports.useUpdateDocument = exports.useSingleDocByVersionId = exports.useSingleDocByDocId = exports.usePresetsSelection = exports.useManyDocs = exports.useDeleteDocument = exports.useCreateDocument = exports.useSetOwnDeviceInfo = exports.useSetIsArchiveDevice = exports.useOwnDeviceInfo = exports.useIsArchiveDevice = exports.useClientApi = exports.ComapeoCoreProvider = void 0;
4
+ exports.isHTTPError = exports.HTTPError = exports.useExportZipFile = exports.useExportGeoJSON = exports.useChangeMemberRole = exports.useUpdateProjectSettings = exports.useSyncState = exports.useStopSync = exports.useStartSync = exports.useSingleProject = exports.useSingleMember = exports.useSetAutostopDataSyncTimeout = exports.useRemoveMember = void 0;
5
+ var ComapeoCore_js_1 = require("./contexts/ComapeoCore.js");
6
+ Object.defineProperty(exports, "ComapeoCoreProvider", { enumerable: true, get: function () { return ComapeoCore_js_1.ComapeoCoreProvider; } });
6
7
  var client_js_1 = require("./hooks/client.js");
7
8
  Object.defineProperty(exports, "useClientApi", { enumerable: true, get: function () { return client_js_1.useClientApi; } });
8
9
  Object.defineProperty(exports, "useIsArchiveDevice", { enumerable: true, get: function () { return client_js_1.useIsArchiveDevice; } });
@@ -26,6 +27,19 @@ Object.defineProperty(exports, "useSendInvite", { enumerable: true, get: functio
26
27
  Object.defineProperty(exports, "useSingleInvite", { enumerable: true, get: function () { return invites_js_1.useSingleInvite; } });
27
28
  var maps_js_1 = require("./hooks/maps.js");
28
29
  Object.defineProperty(exports, "useMapStyleUrl", { enumerable: true, get: function () { return maps_js_1.useMapStyleUrl; } });
30
+ Object.defineProperty(exports, "useImportCustomMapFile", { enumerable: true, get: function () { return maps_js_1.useImportCustomMapFile; } });
31
+ Object.defineProperty(exports, "useRemoveCustomMapFile", { enumerable: true, get: function () { return maps_js_1.useRemoveCustomMapFile; } });
32
+ Object.defineProperty(exports, "useGetCustomMapInfo", { enumerable: true, get: function () { return maps_js_1.useGetCustomMapInfo; } });
33
+ Object.defineProperty(exports, "useManyReceivedMapShares", { enumerable: true, get: function () { return maps_js_1.useManyReceivedMapShares; } });
34
+ Object.defineProperty(exports, "useSingleReceivedMapShare", { enumerable: true, get: function () { return maps_js_1.useSingleReceivedMapShare; } });
35
+ Object.defineProperty(exports, "useDeclineReceivedMapShare", { enumerable: true, get: function () { return maps_js_1.useDeclineReceivedMapShare; } });
36
+ Object.defineProperty(exports, "useDownloadReceivedMapShare", { enumerable: true, get: function () { return maps_js_1.useDownloadReceivedMapShare; } });
37
+ Object.defineProperty(exports, "useAbortReceivedMapShareDownload", { enumerable: true, get: function () { return maps_js_1.useAbortReceivedMapShareDownload; } });
38
+ Object.defineProperty(exports, "useSendMapShare", { enumerable: true, get: function () { return maps_js_1.useSendMapShare; } });
39
+ Object.defineProperty(exports, "useCancelSentMapShare", { enumerable: true, get: function () { return maps_js_1.useCancelSentMapShare; } });
40
+ Object.defineProperty(exports, "useSingleSentMapShare", { enumerable: true, get: function () { return maps_js_1.useSingleSentMapShare; } });
41
+ var map_shares_stores_js_1 = require("./lib/map-shares-stores.js");
42
+ Object.defineProperty(exports, "DeclineReason", { enumerable: true, get: function () { return map_shares_stores_js_1.DeclineReason; } });
29
43
  var projects_js_1 = require("./hooks/projects.js");
30
44
  Object.defineProperty(exports, "useAddServerPeer", { enumerable: true, get: function () { return projects_js_1.useAddServerPeer; } });
31
45
  Object.defineProperty(exports, "useAttachmentUrl", { enumerable: true, get: function () { return projects_js_1.useAttachmentUrl; } });
@@ -56,3 +70,6 @@ Object.defineProperty(exports, "useUpdateProjectSettings", { enumerable: true, g
56
70
  Object.defineProperty(exports, "useChangeMemberRole", { enumerable: true, get: function () { return projects_js_1.useChangeMemberRole; } });
57
71
  Object.defineProperty(exports, "useExportGeoJSON", { enumerable: true, get: function () { return projects_js_1.useExportGeoJSON; } });
58
72
  Object.defineProperty(exports, "useExportZipFile", { enumerable: true, get: function () { return projects_js_1.useExportZipFile; } });
73
+ var http_js_1 = require("./lib/http.js");
74
+ Object.defineProperty(exports, "HTTPError", { enumerable: true, get: function () { return http_js_1.HTTPError; } });
75
+ Object.defineProperty(exports, "isHTTPError", { enumerable: true, get: function () { return http_js_1.isHTTPError; } });
@@ -0,0 +1,45 @@
1
+ import type { JsonValue } from 'type-fest';
2
+ type HttpInit = RequestInit & {
3
+ json?: JsonValue;
4
+ };
5
+ type ResponsePromise = Promise<Response> & {
6
+ json<T = unknown>(): Promise<T>;
7
+ text(): Promise<string>;
8
+ };
9
+ type Input = string | URL;
10
+ /**
11
+ * http - A minimal fetch wrapper to reduce some boilerplate.
12
+ *
13
+ * @example
14
+ * ```js
15
+ * import { createHttp } from './http.js'
16
+ * const http = createHttp(myCustomFetch)
17
+ *
18
+ * const data = await http.get('https://api.example.com/items').json()
19
+ * await http.post('https://api.example.com/items', { json: { name: 'foo' } }).json()
20
+ * ```
21
+ */
22
+ declare function createHttp(fetchFn?: (input: string | URL, init?: RequestInit) => Promise<Response>): Record<"head" | "get" | "post" | "put" | "patch" | "delete", (input: Input, options?: HttpInit) => ResponsePromise>;
23
+ type HTTPErrorObject = {
24
+ message?: string;
25
+ code?: string;
26
+ [key: string]: unknown;
27
+ };
28
+ /**
29
+ * HTTPError - Custom error class to represent HTTP errors with additional context.
30
+ */
31
+ declare class HTTPError extends Error {
32
+ readonly response: Response;
33
+ readonly status: number;
34
+ readonly code: string;
35
+ [key: string]: unknown;
36
+ constructor(response: Response, { method, url, ...body }: {
37
+ method: string;
38
+ url: string;
39
+ } & HTTPErrorObject);
40
+ }
41
+ /**
42
+ * Type guard to check if an error is an instance of HTTPError.
43
+ */
44
+ declare function isHTTPError(error: unknown): error is HTTPError;
45
+ export { createHttp, HTTPError, isHTTPError };
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HTTPError = void 0;
4
+ exports.createHttp = createHttp;
5
+ exports.isHTTPError = isHTTPError;
6
+ const requestMethods = [
7
+ 'get',
8
+ 'post',
9
+ 'put',
10
+ 'patch',
11
+ 'head',
12
+ 'delete',
13
+ ];
14
+ /**
15
+ * http - A minimal fetch wrapper to reduce some boilerplate.
16
+ *
17
+ * @example
18
+ * ```js
19
+ * import { createHttp } from './http.js'
20
+ * const http = createHttp(myCustomFetch)
21
+ *
22
+ * const data = await http.get('https://api.example.com/items').json()
23
+ * await http.post('https://api.example.com/items', { json: { name: 'foo' } }).json()
24
+ * ```
25
+ */
26
+ function createHttp(fetchFn = globalThis.fetch) {
27
+ const alias = (method) => (input, options = {}) => {
28
+ const { json, headers, ...rest } = options;
29
+ const h = new Headers(headers);
30
+ if (json !== undefined) {
31
+ rest.body = JSON.stringify(json);
32
+ if (!h.has('content-type'))
33
+ h.set('content-type', 'application/json');
34
+ }
35
+ if (!h.has('accept'))
36
+ h.set('accept', 'application/json');
37
+ const responsePromise = fetchFn(input, {
38
+ ...rest,
39
+ method,
40
+ headers: h,
41
+ }).then((response) => {
42
+ if (!response.ok)
43
+ throw new HTTPError(response, { method, url: input.toString() });
44
+ return response;
45
+ });
46
+ responsePromise.json = () => responsePromise
47
+ .catch((e) => {
48
+ // For http errors, parse the body as json to get the error details, but rethrow other errors (e.g. network errors)
49
+ if (isHTTPError(e))
50
+ return e.response;
51
+ throw e;
52
+ })
53
+ .then(async (r) => {
54
+ if (r.status === 204)
55
+ return '';
56
+ const text = await r.text();
57
+ const parsed = text === '' ? '' : JSON.parse(text);
58
+ if (r.ok)
59
+ return parsed;
60
+ throw new HTTPError(r, {
61
+ method: options.method ?? 'GET',
62
+ url: input.toString(),
63
+ ...parsed,
64
+ });
65
+ });
66
+ responsePromise.text = () => responsePromise.then((r) => r.text());
67
+ return responsePromise;
68
+ };
69
+ const http = {};
70
+ for (const method of requestMethods) {
71
+ http[method] = alias(upperCase(method));
72
+ }
73
+ return http;
74
+ }
75
+ /**
76
+ * HTTPError - Custom error class to represent HTTP errors with additional context.
77
+ */
78
+ class HTTPError extends Error {
79
+ response;
80
+ status;
81
+ code = 'UNKNOWN_ERROR';
82
+ constructor(response, { method, url, ...body }) {
83
+ const status = response.status || 500;
84
+ const message = body.message || `Request failed with ${status}: ${method} ${url}`;
85
+ super(message);
86
+ Object.assign(this, body);
87
+ // override status in body with status from response
88
+ this.status = status;
89
+ this.name = 'HTTPError';
90
+ this.response = response;
91
+ }
92
+ }
93
+ exports.HTTPError = HTTPError;
94
+ /**
95
+ * Type guard to check if an error is an instance of HTTPError.
96
+ */
97
+ function isHTTPError(error) {
98
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
+ return error instanceof HTTPError || error?.name === HTTPError.name;
100
+ }
101
+ function upperCase(str) {
102
+ return str.toUpperCase();
103
+ }
@@ -0,0 +1,80 @@
1
+ import type { MapShare } from '@comapeo/core';
2
+ import type { MapeoClientApi } from '@comapeo/ipc';
3
+ import { type MapShareState as ServerMapShareState } from '@comapeo/map-server';
4
+ import { type QueryClient } from '@tanstack/react-query';
5
+ import type { Simplify } from 'type-fest';
6
+ import type { MapServerApi } from '../contexts/MapServer.js';
7
+ type DistributedIntersection<T, U> = U extends unknown ? Simplify<T & U> : never;
8
+ export type ReceivedMapShareState = DistributedIntersection<Simplify<MapShare>, ServerMapShareState>;
9
+ export type SentMapShareState = ServerMapShareState;
10
+ export type ReceivedMapSharesStore = ReturnType<typeof createReceivedMapSharesStore>;
11
+ export type SentMapSharesStore = ReturnType<typeof createSentMapSharesStore>;
12
+ /** Known reasons for declining a map share */
13
+ export declare const DeclineReason: {
14
+ /** User explicitly rejected the map share */
15
+ readonly user_rejected: "user_rejected";
16
+ /** Device storage is full */
17
+ readonly storage_full: "storage_full";
18
+ };
19
+ /** Options for downloading a received map share */
20
+ export type DownloadMapShareOptions = {
21
+ /** ID of the map share to download */
22
+ shareId: string;
23
+ };
24
+ /** Options for declining a received map share */
25
+ export type DeclineMapShareOptions = {
26
+ /** ID of the map share to decline */
27
+ shareId: string;
28
+ /** Reason for declining (e.g., 'user_rejected', 'storage_full') */
29
+ reason: (typeof DeclineReason)[keyof typeof DeclineReason] | (string & {});
30
+ };
31
+ /** Options for aborting an in-progress map share download */
32
+ export type AbortMapShareOptions = {
33
+ /** ID of the map share download to abort */
34
+ shareId: string;
35
+ };
36
+ /** Options for creating and sending a map share */
37
+ export type CreateAndSendMapShareOptions = {
38
+ /** Public ID of the project to send the share on behalf of */
39
+ projectId: string;
40
+ /** Device ID of the recipient */
41
+ receiverDeviceId: string;
42
+ /** ID of the map to share - not needed until we support multiple maps */
43
+ mapId?: string;
44
+ };
45
+ /** Options for canceling a sent map share */
46
+ export type CancelMapShareOptions = {
47
+ /** ID of the map share to cancel */
48
+ shareId: string;
49
+ };
50
+ /**
51
+ * Store and actions for received map shares.
52
+ */
53
+ export declare function createReceivedMapSharesStore({ clientApi, mapServerApi, queryClient, }: {
54
+ clientApi: MapeoClientApi;
55
+ mapServerApi: MapServerApi;
56
+ queryClient: QueryClient;
57
+ }): {
58
+ subscribe: (listener: () => void) => () => boolean;
59
+ getSnapshot: () => ReceivedMapShareState[];
60
+ actions: {
61
+ download({ shareId }: DownloadMapShareOptions): Promise<void>;
62
+ decline({ shareId, reason }: DeclineMapShareOptions): Promise<void>;
63
+ abort({ shareId }: AbortMapShareOptions): Promise<void>;
64
+ };
65
+ };
66
+ /**
67
+ * Store and actions for sent map share.
68
+ */
69
+ export declare function createSentMapSharesStore({ clientApi, mapServerApi, }: {
70
+ clientApi: MapeoClientApi;
71
+ mapServerApi: MapServerApi;
72
+ }): {
73
+ subscribe: (listener: () => void) => () => boolean;
74
+ getSnapshot: () => ServerMapShareState[];
75
+ actions: {
76
+ createAndSend({ projectId, receiverDeviceId, mapId, }: CreateAndSendMapShareOptions): Promise<ServerMapShareState>;
77
+ cancel({ shareId }: CancelMapShareOptions): Promise<void>;
78
+ };
79
+ };
80
+ export {};