diff --git a/docs/API.md b/docs/API.md index 483fa0a..24d1706 100644 --- a/docs/API.md +++ b/docs/API.md @@ -29,6 +29,8 @@ - [useConnectSyncServers](#useconnectsyncservers) - [useDisconnectSyncServers](#usedisconnectsyncservers) - [useSetAutostopDataSyncTimeout](#usesetautostopdatasynctimeout) +- [useExportGeoJSON](#useexportgeojson) +- [useExportZipFile](#useexportzipfile) - [useSingleDocByDocId](#usesingledocbydocid) - [useSingleDocByVersionId](#usesingledocbyversionid) - [useManyDocs](#usemanydocs) @@ -547,6 +549,32 @@ Provides the progress of data sync for sync-enabled connected peers | ---------- | ---------- | | `useSetAutostopDataSyncTimeout` | `({ projectId, }: { projectId: string; }) => { error: Error; mutate: UseMutateFunction; mutateAsync: UseMutateAsyncFunction; reset: () => void; status: "error"; } or { ...; }` | +### useExportGeoJSON + +Creates a GeoJson file with all the observations and/or tracks in the project. + +| Function | Type | +| ---------- | ---------- | +| `useExportGeoJSON` | `({ projectId }: { projectId: string; }) => { error: Error; mutate: UseMutateFunction; mutateAsync: UseMutateAsyncFunction<...>; reset: () => void; status: "error...` | + +Parameters: + +* `opts.projectId`: Public ID of the project to apply changes to. + + +### useExportZipFile + +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). + +| Function | Type | +| ---------- | ---------- | +| `useExportZipFile` | `({ projectId }: { projectId: string; }) => { error: Error; mutate: UseMutateFunction; mutateAsync: UseMutateAsyncFunction<...>...` | + +Parameters: + +* `opts.projectId`: Public ID of the project to apply changes to. + + ### useSingleDocByDocId Retrieve a single document from the database based on the document's document ID. diff --git a/package-lock.json b/package-lock.json index f669a45..1278ce4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "4.2.1", "license": "MIT", "devDependencies": { - "@comapeo/core": "3.1.2", + "@comapeo/core": "3.2.0", "@comapeo/ipc": "3.0.0", "@comapeo/schema": "1.6.0", "@eslint/compat": "1.2.9", @@ -43,7 +43,7 @@ "vitest": "3.1.4" }, "peerDependencies": { - "@comapeo/core": "^3.1.0", + "@comapeo/core": "^3.2.0", "@comapeo/ipc": "^3.0.0", "@comapeo/schema": "*", "@tanstack/react-query": "^5", @@ -190,14 +190,14 @@ } }, "node_modules/@comapeo/core": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@comapeo/core/-/core-3.1.2.tgz", - "integrity": "sha512-RBxegjQwGLt2fdsZPf3zRdsqBBVZBtvf+IiC6Od4z9vVm41Vgs4xeTcgMSDXGIQ5IhajbqLsnSHv0iklRwO5Ag==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@comapeo/core/-/core-3.2.0.tgz", + "integrity": "sha512-N26J6MqzntnP1M0h7F2ZhvcE4Qnho8vy5j0K5H0FjnADKimoDp2rWew/9c0+MdHQm7h9jgW3mqdYUTJ3GQDSXA==", "dev": true, "license": "MIT", "dependencies": { "@comapeo/fallback-smp": "^1.0.0", - "@comapeo/schema": "1.5.0", + "@comapeo/schema": "1.6.0", "@digidem/types": "^2.3.0", "@fastify/error": "^3.4.1", "@fastify/type-provider-typebox": "^4.1.0", @@ -248,20 +248,8 @@ "varint": "^6.0.0", "ws": "^8.18.0", "xstate": "^5.19.2", - "yauzl-promise": "^4.0.0" - } - }, - "node_modules/@comapeo/core/node_modules/@comapeo/schema": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@comapeo/schema/-/schema-1.5.0.tgz", - "integrity": "sha512-MIT9BSo34ffUKn6kZuBf10Xs3/7FZ2tVwXLi+Oi5DiOuTEI1r03DAI9XzGTqU2FsnPkza+dc5h6aaBB/ZuOsrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@comapeo/geometry": "^1.1.1", - "compact-encoding": "^2.12.0", - "protobufjs": "^7.2.5", - "type-fest": "^4.26.0" + "yauzl-promise": "^4.0.0", + "zip-stream-promise": "^1.0.2" } }, "node_modules/@comapeo/core/node_modules/corestore": { @@ -2825,6 +2813,28 @@ "@types/node": "*" } }, + "node_modules/@types/compress-commons": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/compress-commons/-/compress-commons-7.0.1.tgz", + "integrity": "sha512-2MNs8Qv4HRZIYAmDhUqBkPTU6qj4hqB4eKczIw68e899FXY0NMVjGZsi8B3i50HsbVaTe8q9GgTIqVbhbS9aHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/crc32-stream": "*", + "@types/node": "*", + "@types/readable-stream": "*" + } + }, + "node_modules/@types/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-DTag28dyA2A3yVTijkx5dfrTCE+5RC+XdWthkQOl2CCCdptgm/3rqwJsNdN5mljOKylf0mYv9KZl4FRaa2X8qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -2886,6 +2896,24 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/readable-stream": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.18.tgz", + "integrity": "sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/streamx": { "version": "2.9.5", "resolved": "https://registry.npmjs.org/@types/streamx/-/streamx-2.9.5.tgz", @@ -2903,6 +2931,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/zip-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/zip-stream/-/zip-stream-7.0.0.tgz", + "integrity": "sha512-lU8b0uAYlw8U7gnQ0tgH91DMMX99Gdh7350YDtBEKW0A2LB6NIFub7Bep3oaEuqiiyEYMOZtUShrmgyWcxy/+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/compress-commons": "*", + "@types/node": "*", + "@types/readable-stream": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.32.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", @@ -11012,6 +11052,77 @@ "engines": { "node": ">= 14" } + }, + "node_modules/zip-stream-promise": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/zip-stream-promise/-/zip-stream-promise-1.0.2.tgz", + "integrity": "sha512-bGIB91TYzyjQPxMk69n+5W7gtvz5QMo/OgtQDQZYj9uocpRce67pR/oyosSdj65/G4ews32vYN+1XGTbGRXnAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^22.15.18", + "@types/zip-stream": "^7.0.0", + "zip-stream": "^7.0.2" + } + }, + "node_modules/zip-stream-promise/node_modules/compress-commons": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-7.0.0.tgz", + "integrity": "sha512-8WWFRMWaa37dwjWCxDcmdx6sxfjQTAEQ6s96BWqX9WYC6Mgg95EvwPYS/7QGX3txkst7TD1jIL2HCY9AixLGfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^7.0.1", + "is-stream": "^4.0.0", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/zip-stream-promise/node_modules/crc32-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-7.0.1.tgz", + "integrity": "sha512-IBWsY8xznyQrcHn8h4bC8/4ErNke5elzgG8GcqF4RFPw6aHkWWRc7Tgw6upjaTX/CT/yQgqYENkxYsTYN+hW2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/zip-stream-promise/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream-promise/node_modules/zip-stream": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-7.0.2.tgz", + "integrity": "sha512-g1TjcvzTXLWwDDyZSdC+w7tNdeNCq/qA8Amm8kxGBldyW2yxtSHHlYinxTRvlcaE4Tt3l1ZPsWSA+P9sn20MRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "compress-commons": "^7.0.0", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">=18" + } } } } diff --git a/package.json b/package.json index fe841a6..4394c7c 100644 --- a/package.json +++ b/package.json @@ -57,14 +57,14 @@ "types": "tsc" }, "peerDependencies": { - "@comapeo/core": "^3.1.0", + "@comapeo/core": "^3.2.0", "@comapeo/ipc": "^3.0.0", "@comapeo/schema": "*", "@tanstack/react-query": "^5", "react": "^18 || ^19" }, "devDependencies": { - "@comapeo/core": "3.1.2", + "@comapeo/core": "3.2.0", "@comapeo/ipc": "3.0.0", "@comapeo/schema": "1.6.0", "@eslint/compat": "1.2.9", diff --git a/src/hooks/projects.ts b/src/hooks/projects.ts index 1cd995d..d94fdc4 100644 --- a/src/hooks/projects.ts +++ b/src/hooks/projects.ts @@ -19,6 +19,8 @@ import { createProjectMutationOptions, disconnectSyncServersMutationOptions, documentCreatedByQueryOptions, + exportGeoJSONMutationOptions, + exportZipFileMutationOptions, iconUrlQueryOptions, importProjectConfigMutationOptions, leaveProjectMutationOptions, @@ -610,3 +612,37 @@ export function useSetAutostopDataSyncTimeout({ ? { error, mutate, mutateAsync, reset, status } : { error: null, mutate, mutateAsync, reset, status } } + +/** + * Creates a GeoJson file with all the observations and/or tracks in the project. + * + * @param opts.projectId Public ID of the project to apply changes to. + */ +export function useExportGeoJSON({ projectId }: { projectId: string }) { + const { data: projectApi } = useSingleProject({ projectId }) + + const { error, mutate, mutateAsync, reset, status } = useMutation( + exportGeoJSONMutationOptions({ projectApi }), + ) + + return status === 'error' + ? { error, mutate, mutateAsync, reset, status } + : { error: null, mutate, mutateAsync, reset, status } +} + +/** + * 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). + * + * @param opts.projectId Public ID of the project to apply changes to. + */ +export function useExportZipFile({ projectId }: { projectId: string }) { + const { data: projectApi } = useSingleProject({ projectId }) + + const { error, mutate, mutateAsync, reset, status } = useMutation( + exportZipFileMutationOptions({ projectApi }), + ) + + return status === 'error' + ? { error, mutate, mutateAsync, reset, status } + : { error: null, mutate, mutateAsync, reset, status } +} diff --git a/src/index.ts b/src/index.ts index 1946574..9e62853 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,6 +48,8 @@ export { useStopSync, useSyncState, useUpdateProjectSettings, + useExportGeoJSON, + useExportZipFile, } from './hooks/projects.js' export { type SyncState } from './lib/sync.js' export { diff --git a/src/lib/react-query/projects.ts b/src/lib/react-query/projects.ts index 1e739c4..fa9705a 100644 --- a/src/lib/react-query/projects.ts +++ b/src/lib/react-query/projects.ts @@ -517,3 +517,52 @@ export function setAutostopDataSyncTimeoutMutationOptions({ }, } satisfies UseMutationOptions } + +export function exportGeoJSONMutationOptions({ + projectApi, +}: { + projectApi: MapeoProjectApi +}) { + return { + ...baseMutationOptions(), + mutationFn: async (opts) => { + return projectApi.exportGeoJSONFile(opts.path, opts.exportOptions) + }, + } satisfies UseMutationOptions< + string, + Error, + { + path: string + exportOptions: { + observations?: boolean + tracks?: boolean + lang?: string + } + } + > +} + +export function exportZipFileMutationOptions({ + projectApi, +}: { + projectApi: MapeoProjectApi +}) { + return { + ...baseMutationOptions(), + mutationFn: async (opts) => { + return projectApi.exportZipFile(opts.path, opts.exportOptions) + }, + } satisfies UseMutationOptions< + string, + Error, + { + path: string + exportOptions: { + observations?: boolean + tracks?: boolean + lang?: string + attachments?: boolean + } + } + > +}