@comapeo/core-react 6.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/hooks/projects.d.ts +28 -4
- package/dist/commonjs/hooks/projects.js +16 -10
- package/dist/commonjs/lib/react-query/projects.d.ts +11 -63
- package/dist/commonjs/lib/react-query/projects.js +28 -29
- package/dist/commonjs/lib/urls.d.ts +12 -0
- package/dist/commonjs/lib/urls.js +62 -0
- package/dist/esm/hooks/projects.d.ts +28 -4
- package/dist/esm/hooks/projects.js +17 -11
- package/dist/esm/lib/react-query/projects.d.ts +11 -63
- package/dist/esm/lib/react-query/projects.js +26 -25
- package/dist/esm/lib/urls.d.ts +12 -0
- package/dist/esm/lib/urls.js +58 -0
- package/package.json +1 -1
|
@@ -626,7 +626,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
626
626
|
mutate: import("@tanstack/react-query").UseMutateFunction<string, Error, {
|
|
627
627
|
path: string;
|
|
628
628
|
exportOptions: {
|
|
629
|
-
observations
|
|
629
|
+
observations
|
|
630
|
+
/**
|
|
631
|
+
* Update the settings of a project.
|
|
632
|
+
*
|
|
633
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
634
|
+
*/
|
|
635
|
+
?: boolean;
|
|
630
636
|
tracks?: boolean;
|
|
631
637
|
lang?: string;
|
|
632
638
|
};
|
|
@@ -634,7 +640,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
634
640
|
mutateAsync: import("@tanstack/react-query").UseMutateAsyncFunction<string, Error, {
|
|
635
641
|
path: string;
|
|
636
642
|
exportOptions: {
|
|
637
|
-
observations
|
|
643
|
+
observations
|
|
644
|
+
/**
|
|
645
|
+
* Update the settings of a project.
|
|
646
|
+
*
|
|
647
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
648
|
+
*/
|
|
649
|
+
?: boolean;
|
|
638
650
|
tracks?: boolean;
|
|
639
651
|
lang?: string;
|
|
640
652
|
};
|
|
@@ -646,7 +658,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
646
658
|
mutate: import("@tanstack/react-query").UseMutateFunction<string, Error, {
|
|
647
659
|
path: string;
|
|
648
660
|
exportOptions: {
|
|
649
|
-
observations
|
|
661
|
+
observations
|
|
662
|
+
/**
|
|
663
|
+
* Update the settings of a project.
|
|
664
|
+
*
|
|
665
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
666
|
+
*/
|
|
667
|
+
?: boolean;
|
|
650
668
|
tracks?: boolean;
|
|
651
669
|
lang?: string;
|
|
652
670
|
};
|
|
@@ -654,7 +672,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
654
672
|
mutateAsync: import("@tanstack/react-query").UseMutateAsyncFunction<string, Error, {
|
|
655
673
|
path: string;
|
|
656
674
|
exportOptions: {
|
|
657
|
-
observations
|
|
675
|
+
observations
|
|
676
|
+
/**
|
|
677
|
+
* Update the settings of a project.
|
|
678
|
+
*
|
|
679
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
680
|
+
*/
|
|
681
|
+
?: boolean;
|
|
658
682
|
tracks?: boolean;
|
|
659
683
|
lang?: string;
|
|
660
684
|
};
|
|
@@ -29,6 +29,7 @@ const react_query_1 = require("@tanstack/react-query");
|
|
|
29
29
|
const react_1 = require("react");
|
|
30
30
|
const projects_js_1 = require("../lib/react-query/projects.js");
|
|
31
31
|
const sync_js_1 = require("../lib/sync.js");
|
|
32
|
+
const urls_js_1 = require("../lib/urls.js");
|
|
32
33
|
const client_js_1 = require("./client.js");
|
|
33
34
|
/**
|
|
34
35
|
* Retrieve the project settings for a project.
|
|
@@ -185,13 +186,10 @@ function useManyMembers({ projectId }) {
|
|
|
185
186
|
*/
|
|
186
187
|
function useIconUrl({ projectId, iconId, ...mimeBasedOpts }) {
|
|
187
188
|
const { data: projectApi } = useSingleProject({ projectId });
|
|
188
|
-
const { data, error, isRefetching } = (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
iconId,
|
|
193
|
-
}));
|
|
194
|
-
return { data, error, isRefetching };
|
|
189
|
+
const { data: port, error, isRefetching } = useMediaServerPort({ projectApi });
|
|
190
|
+
const baseUrl = `http://127.0.0.1:${port}`;
|
|
191
|
+
const iconUrl = (0, urls_js_1.getIconUrl)(baseUrl, iconId, mimeBasedOpts);
|
|
192
|
+
return { data: iconUrl, error, isRefetching };
|
|
195
193
|
}
|
|
196
194
|
/**
|
|
197
195
|
* Retrieve a URL that points to a desired blob resource.
|
|
@@ -246,10 +244,18 @@ function useIconUrl({ projectId, iconId, ...mimeBasedOpts }) {
|
|
|
246
244
|
*/
|
|
247
245
|
function useAttachmentUrl({ projectId, blobId, }) {
|
|
248
246
|
const { data: projectApi } = useSingleProject({ projectId });
|
|
249
|
-
const { data, error, isRefetching } = (
|
|
247
|
+
const { data: port, error, isRefetching } = useMediaServerPort({ projectApi });
|
|
248
|
+
const baseUrl = `http://127.0.0.1:${port}`;
|
|
249
|
+
const blobUrl = (0, urls_js_1.getBlobUrl)(baseUrl, blobId);
|
|
250
|
+
return { data: blobUrl, error, isRefetching };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* @internal
|
|
254
|
+
* Hack to retrieve the media server port.
|
|
255
|
+
*/
|
|
256
|
+
function useMediaServerPort({ projectApi }) {
|
|
257
|
+
const { data, error, isRefetching } = (0, react_query_1.useSuspenseQuery)((0, projects_js_1.mediaServerPortQueryOptions)({
|
|
250
258
|
projectApi,
|
|
251
|
-
projectId,
|
|
252
|
-
blobId,
|
|
253
259
|
}));
|
|
254
260
|
return { data, error, isRefetching };
|
|
255
261
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BlobApi
|
|
1
|
+
import type { BlobApi } from '@comapeo/core' with { 'resolution-mode': 'import' };
|
|
2
2
|
import type { MapeoClientApi, MapeoProjectApi } from '@comapeo/ipc' with { 'resolution-mode': 'import' };
|
|
3
3
|
import type { ProjectSettings } from '@comapeo/schema' with { 'resolution-mode': 'import' };
|
|
4
4
|
import { type QueryClient, type UnusedSkipTokenOptions } from '@tanstack/react-query';
|
|
@@ -19,27 +19,16 @@ export declare function getMemberByIdQueryKey({ projectId, deviceId, }: {
|
|
|
19
19
|
projectId: string;
|
|
20
20
|
deviceId: string;
|
|
21
21
|
}): readonly ["@comapeo/core-react", "projects", string, "members", string];
|
|
22
|
-
export declare function getIconUrlQueryKey({ projectId, iconId, ...mimeBasedOpts }: {
|
|
23
|
-
projectId: string;
|
|
24
|
-
iconId: string;
|
|
25
|
-
} & (IconApi.BitmapOpts | IconApi.SvgOpts)): readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
26
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/png">;
|
|
27
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant, {
|
|
28
|
-
mimeType: "image/png";
|
|
29
|
-
}>["pixelDensity"];
|
|
30
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
31
|
-
} | {
|
|
32
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/svg+xml">;
|
|
33
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
34
|
-
}];
|
|
35
22
|
export declare function getDocumentCreatedByQueryKey({ projectId, originalVersionId, }: {
|
|
36
23
|
projectId: string;
|
|
37
24
|
originalVersionId: string;
|
|
38
25
|
}): readonly ["@comapeo/core-react", "projects", string, "document_created_by", string];
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
/**
|
|
27
|
+
* We call this within a project hook, because that's the only place the API is
|
|
28
|
+
* exposed right now, but it is the same for all projects, so no need for
|
|
29
|
+
* scoping the query key to the project
|
|
30
|
+
*/
|
|
31
|
+
export declare function getMediaServerPortQueryKey(): readonly ["@comapeo/core-react", "media_server_port"];
|
|
43
32
|
export declare function projectsQueryOptions({ clientApi, }: {
|
|
44
33
|
clientApi: MapeoClientApi;
|
|
45
34
|
}): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<import("@comapeo/core/dist/mapeo-manager.js", { with: { "resolution-mode": "import" } }).ListedProject[], Error, import("@comapeo/core/dist/mapeo-manager.js", { with: { "resolution-mode": "import" } }).ListedProject[], readonly ["@comapeo/core-react", "projects"]>, "queryFn"> & {
|
|
@@ -99,45 +88,6 @@ export declare function projectOwnRoleQueryOptions({ projectApi, projectId, }: {
|
|
|
99
88
|
[dataTagErrorSymbol]: Error;
|
|
100
89
|
};
|
|
101
90
|
};
|
|
102
|
-
export declare function iconUrlQueryOptions({ projectApi, projectId, iconId, ...mimeBasedOpts }: {
|
|
103
|
-
projectApi: MapeoProjectApi;
|
|
104
|
-
projectId: string;
|
|
105
|
-
iconId: Parameters<MapeoProjectApi['$icons']['getIconUrl']>[0];
|
|
106
|
-
} & (IconApi.BitmapOpts | IconApi.SvgOpts)): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<string, Error, string, readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
107
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/png">;
|
|
108
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant, {
|
|
109
|
-
mimeType: "image/png";
|
|
110
|
-
}>["pixelDensity"];
|
|
111
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
112
|
-
} | {
|
|
113
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/svg+xml">;
|
|
114
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
115
|
-
}]>, "queryFn"> & {
|
|
116
|
-
queryFn?: import("@tanstack/react-query").QueryFunction<string, readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
117
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/png">;
|
|
118
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant, {
|
|
119
|
-
mimeType: "image/png";
|
|
120
|
-
}>["pixelDensity"];
|
|
121
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
122
|
-
} | {
|
|
123
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/svg+xml">;
|
|
124
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
125
|
-
}], never> | undefined;
|
|
126
|
-
} & {
|
|
127
|
-
queryKey: readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
128
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/png">;
|
|
129
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant, {
|
|
130
|
-
mimeType: "image/png";
|
|
131
|
-
}>["pixelDensity"];
|
|
132
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
133
|
-
} | {
|
|
134
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).IconVariant["mimeType"], "image/svg+xml">;
|
|
135
|
-
size: import("@comapeo/core/dist/icon-api.js", { with: { "resolution-mode": "import" } }).ValidSizes;
|
|
136
|
-
}] & {
|
|
137
|
-
[dataTagSymbol]: string;
|
|
138
|
-
[dataTagErrorSymbol]: Error;
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
91
|
export declare function documentCreatedByQueryOptions({ projectApi, projectId, originalVersionId, }: {
|
|
142
92
|
projectApi: MapeoProjectApi;
|
|
143
93
|
projectId: string;
|
|
@@ -150,14 +100,12 @@ export declare function documentCreatedByQueryOptions({ projectApi, projectId, o
|
|
|
150
100
|
[dataTagErrorSymbol]: Error;
|
|
151
101
|
};
|
|
152
102
|
};
|
|
153
|
-
export declare function
|
|
103
|
+
export declare function mediaServerPortQueryOptions({ projectApi, }: {
|
|
154
104
|
projectApi: MapeoProjectApi;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<string, Error, string, readonly ["@comapeo/core-react", "projects", string, "attachments", import("@comapeo/core/dist/types.js", { with: { "resolution-mode": "import" } }).BlobId]>, "queryFn"> & {
|
|
158
|
-
queryFn?: import("@tanstack/react-query").QueryFunction<string, readonly ["@comapeo/core-react", "projects", string, "attachments", import("@comapeo/core/dist/types.js", { with: { "resolution-mode": "import" } }).BlobId], never> | undefined;
|
|
105
|
+
}): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<string, Error, string, readonly ["@comapeo/core-react", "media_server_port"]>, "queryFn"> & {
|
|
106
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<string, readonly ["@comapeo/core-react", "media_server_port"], never> | undefined;
|
|
159
107
|
} & {
|
|
160
|
-
queryKey: readonly ["@comapeo/core-react", "
|
|
108
|
+
queryKey: readonly ["@comapeo/core-react", "media_server_port"] & {
|
|
161
109
|
[dataTagSymbol]: string;
|
|
162
110
|
[dataTagErrorSymbol]: Error;
|
|
163
111
|
};
|
|
@@ -6,18 +6,16 @@ exports.getProjectSettingsQueryKey = getProjectSettingsQueryKey;
|
|
|
6
6
|
exports.getProjectRoleQueryKey = getProjectRoleQueryKey;
|
|
7
7
|
exports.getMembersQueryKey = getMembersQueryKey;
|
|
8
8
|
exports.getMemberByIdQueryKey = getMemberByIdQueryKey;
|
|
9
|
-
exports.getIconUrlQueryKey = getIconUrlQueryKey;
|
|
10
9
|
exports.getDocumentCreatedByQueryKey = getDocumentCreatedByQueryKey;
|
|
11
|
-
exports.
|
|
10
|
+
exports.getMediaServerPortQueryKey = getMediaServerPortQueryKey;
|
|
12
11
|
exports.projectsQueryOptions = projectsQueryOptions;
|
|
13
12
|
exports.projectByIdQueryOptions = projectByIdQueryOptions;
|
|
14
13
|
exports.projectSettingsQueryOptions = projectSettingsQueryOptions;
|
|
15
14
|
exports.projectMembersQueryOptions = projectMembersQueryOptions;
|
|
16
15
|
exports.projectMemberByIdQueryOptions = projectMemberByIdQueryOptions;
|
|
17
16
|
exports.projectOwnRoleQueryOptions = projectOwnRoleQueryOptions;
|
|
18
|
-
exports.iconUrlQueryOptions = iconUrlQueryOptions;
|
|
19
17
|
exports.documentCreatedByQueryOptions = documentCreatedByQueryOptions;
|
|
20
|
-
exports.
|
|
18
|
+
exports.mediaServerPortQueryOptions = mediaServerPortQueryOptions;
|
|
21
19
|
exports.addServerPeerMutationOptions = addServerPeerMutationOptions;
|
|
22
20
|
exports.removeServerPeerMutationOptions = removeServerPeerMutationOptions;
|
|
23
21
|
exports.createProjectMutationOptions = createProjectMutationOptions;
|
|
@@ -52,16 +50,6 @@ function getMembersQueryKey({ projectId }) {
|
|
|
52
50
|
function getMemberByIdQueryKey({ projectId, deviceId, }) {
|
|
53
51
|
return [shared_js_1.ROOT_QUERY_KEY, 'projects', projectId, 'members', deviceId];
|
|
54
52
|
}
|
|
55
|
-
function getIconUrlQueryKey({ projectId, iconId, ...mimeBasedOpts }) {
|
|
56
|
-
return [
|
|
57
|
-
shared_js_1.ROOT_QUERY_KEY,
|
|
58
|
-
'projects',
|
|
59
|
-
projectId,
|
|
60
|
-
'icons',
|
|
61
|
-
iconId,
|
|
62
|
-
mimeBasedOpts,
|
|
63
|
-
];
|
|
64
|
-
}
|
|
65
53
|
function getDocumentCreatedByQueryKey({ projectId, originalVersionId, }) {
|
|
66
54
|
return [
|
|
67
55
|
shared_js_1.ROOT_QUERY_KEY,
|
|
@@ -71,8 +59,13 @@ function getDocumentCreatedByQueryKey({ projectId, originalVersionId, }) {
|
|
|
71
59
|
originalVersionId,
|
|
72
60
|
];
|
|
73
61
|
}
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
/**
|
|
63
|
+
* We call this within a project hook, because that's the only place the API is
|
|
64
|
+
* exposed right now, but it is the same for all projects, so no need for
|
|
65
|
+
* scoping the query key to the project
|
|
66
|
+
*/
|
|
67
|
+
function getMediaServerPortQueryKey() {
|
|
68
|
+
return [shared_js_1.ROOT_QUERY_KEY, 'media_server_port'];
|
|
76
69
|
}
|
|
77
70
|
function projectsQueryOptions({ clientApi, }) {
|
|
78
71
|
return (0, react_query_1.queryOptions)({
|
|
@@ -128,15 +121,6 @@ function projectOwnRoleQueryOptions({ projectApi, projectId, }) {
|
|
|
128
121
|
},
|
|
129
122
|
});
|
|
130
123
|
}
|
|
131
|
-
function iconUrlQueryOptions({ projectApi, projectId, iconId, ...mimeBasedOpts }) {
|
|
132
|
-
return (0, react_query_1.queryOptions)({
|
|
133
|
-
...(0, shared_js_1.baseQueryOptions)(),
|
|
134
|
-
queryKey: getIconUrlQueryKey({ ...mimeBasedOpts, projectId, iconId }),
|
|
135
|
-
queryFn: async () => {
|
|
136
|
-
return projectApi.$icons.getIconUrl(iconId, mimeBasedOpts);
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
124
|
function documentCreatedByQueryOptions({ projectApi, projectId, originalVersionId, }) {
|
|
141
125
|
return (0, react_query_1.queryOptions)({
|
|
142
126
|
...(0, shared_js_1.baseQueryOptions)(),
|
|
@@ -147,16 +131,31 @@ function documentCreatedByQueryOptions({ projectApi, projectId, originalVersionI
|
|
|
147
131
|
queryFn: async () => {
|
|
148
132
|
return projectApi.$originalVersionIdToDeviceId(originalVersionId);
|
|
149
133
|
},
|
|
134
|
+
staleTime: 'static',
|
|
135
|
+
gcTime: Infinity,
|
|
150
136
|
});
|
|
151
137
|
}
|
|
152
|
-
|
|
138
|
+
// Used as a placeholder so that we can read the server port from the $blobs.getUrl() method
|
|
139
|
+
const FAKE_BLOB_ID = {
|
|
140
|
+
type: 'photo',
|
|
141
|
+
variant: 'original',
|
|
142
|
+
name: 'name',
|
|
143
|
+
driveId: 'drive-id',
|
|
144
|
+
};
|
|
145
|
+
function mediaServerPortQueryOptions({ projectApi, }) {
|
|
153
146
|
return (0, react_query_1.queryOptions)({
|
|
154
147
|
...(0, shared_js_1.baseQueryOptions)(),
|
|
155
|
-
|
|
148
|
+
// HACK: The server doesn't yet expose a method to get its port, so we use
|
|
149
|
+
// the existing $blobs.getUrl() to get the port with a fake BlobId. The port
|
|
150
|
+
// is the same regardless of the blobId, so it's not necessary to include it
|
|
151
|
+
// as a dep for the query key.
|
|
152
|
+
queryKey: getMediaServerPortQueryKey(),
|
|
156
153
|
queryFn: async () => {
|
|
157
|
-
|
|
158
|
-
return
|
|
154
|
+
const url = await projectApi.$blobs.getUrl(FAKE_BLOB_ID);
|
|
155
|
+
return new URL(url).port;
|
|
159
156
|
},
|
|
157
|
+
staleTime: 'static',
|
|
158
|
+
gcTime: Infinity,
|
|
160
159
|
});
|
|
161
160
|
}
|
|
162
161
|
function addServerPeerMutationOptions({ projectApi, projectId, queryClient, }) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BlobApi, IconApi } from '@comapeo/core';
|
|
2
|
+
/**
|
|
3
|
+
* Get a url for a blob based on its BlobId
|
|
4
|
+
*/
|
|
5
|
+
export declare function getBlobUrl(baseUrl: string, blobId: BlobApi.BlobId): string;
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} iconId
|
|
8
|
+
* @param {BitmapOpts | SvgOpts} opts
|
|
9
|
+
*
|
|
10
|
+
* @returns {Promise<string>}
|
|
11
|
+
*/
|
|
12
|
+
export declare function getIconUrl(baseUrl: string, iconId: string, opts: IconApi.BitmapOpts | IconApi.SvgOpts): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// TODO: Move these into a separate "@comapeo/asset-server" module which can
|
|
3
|
+
// export them to be imported directly in a client.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.getBlobUrl = getBlobUrl;
|
|
6
|
+
exports.getIconUrl = getIconUrl;
|
|
7
|
+
const MIME_TO_EXTENSION = {
|
|
8
|
+
'image/png': '.png',
|
|
9
|
+
'image/svg+xml': '.svg',
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Get a url for a blob based on its BlobId
|
|
13
|
+
*/
|
|
14
|
+
function getBlobUrl(baseUrl, blobId) {
|
|
15
|
+
const { driveId, type, variant, name } = blobId;
|
|
16
|
+
if (!baseUrl.endsWith('/')) {
|
|
17
|
+
baseUrl += '/';
|
|
18
|
+
}
|
|
19
|
+
return baseUrl + `${driveId}/${type}/${variant}/${name}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} iconId
|
|
23
|
+
* @param {BitmapOpts | SvgOpts} opts
|
|
24
|
+
*
|
|
25
|
+
* @returns {Promise<string>}
|
|
26
|
+
*/
|
|
27
|
+
function getIconUrl(baseUrl, iconId, opts) {
|
|
28
|
+
if (!baseUrl.endsWith('/')) {
|
|
29
|
+
baseUrl += '/';
|
|
30
|
+
}
|
|
31
|
+
const mimeExtension = MIME_TO_EXTENSION[opts.mimeType];
|
|
32
|
+
const pixelDensity = opts.mimeType === 'image/svg+xml' ||
|
|
33
|
+
// if the pixel density is 1, we can omit the density suffix in the resulting url
|
|
34
|
+
// and assume the pixel density is 1 for applicable mime types when using the url
|
|
35
|
+
opts.pixelDensity === 1
|
|
36
|
+
? undefined
|
|
37
|
+
: opts.pixelDensity;
|
|
38
|
+
return (baseUrl +
|
|
39
|
+
constructIconPath({
|
|
40
|
+
pixelDensity,
|
|
41
|
+
size: opts.size,
|
|
42
|
+
extension: mimeExtension,
|
|
43
|
+
iconId,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* General purpose path builder for an icon
|
|
48
|
+
*/
|
|
49
|
+
function constructIconPath({ size, pixelDensity, iconId, extension, }) {
|
|
50
|
+
if (iconId.length === 0 || size.length === 0 || extension.length === 0) {
|
|
51
|
+
throw new Error('iconId, size, and extension cannot be empty strings');
|
|
52
|
+
}
|
|
53
|
+
let result = `${iconId}/${size}`;
|
|
54
|
+
if (typeof pixelDensity === 'number') {
|
|
55
|
+
if (pixelDensity < 1) {
|
|
56
|
+
throw new Error('pixelDensity must be a positive number');
|
|
57
|
+
}
|
|
58
|
+
result += `@${pixelDensity}x`;
|
|
59
|
+
}
|
|
60
|
+
result += extension.startsWith('.') ? extension : '.' + extension;
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
@@ -626,7 +626,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
626
626
|
mutate: import("@tanstack/react-query").UseMutateFunction<string, Error, {
|
|
627
627
|
path: string;
|
|
628
628
|
exportOptions: {
|
|
629
|
-
observations
|
|
629
|
+
observations
|
|
630
|
+
/**
|
|
631
|
+
* Update the settings of a project.
|
|
632
|
+
*
|
|
633
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
634
|
+
*/
|
|
635
|
+
?: boolean;
|
|
630
636
|
tracks?: boolean;
|
|
631
637
|
lang?: string;
|
|
632
638
|
};
|
|
@@ -634,7 +640,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
634
640
|
mutateAsync: import("@tanstack/react-query").UseMutateAsyncFunction<string, Error, {
|
|
635
641
|
path: string;
|
|
636
642
|
exportOptions: {
|
|
637
|
-
observations
|
|
643
|
+
observations
|
|
644
|
+
/**
|
|
645
|
+
* Update the settings of a project.
|
|
646
|
+
*
|
|
647
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
648
|
+
*/
|
|
649
|
+
?: boolean;
|
|
638
650
|
tracks?: boolean;
|
|
639
651
|
lang?: string;
|
|
640
652
|
};
|
|
@@ -646,7 +658,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
646
658
|
mutate: import("@tanstack/react-query").UseMutateFunction<string, Error, {
|
|
647
659
|
path: string;
|
|
648
660
|
exportOptions: {
|
|
649
|
-
observations
|
|
661
|
+
observations
|
|
662
|
+
/**
|
|
663
|
+
* Update the settings of a project.
|
|
664
|
+
*
|
|
665
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
666
|
+
*/
|
|
667
|
+
?: boolean;
|
|
650
668
|
tracks?: boolean;
|
|
651
669
|
lang?: string;
|
|
652
670
|
};
|
|
@@ -654,7 +672,13 @@ export declare function useExportGeoJSON({ projectId }: {
|
|
|
654
672
|
mutateAsync: import("@tanstack/react-query").UseMutateAsyncFunction<string, Error, {
|
|
655
673
|
path: string;
|
|
656
674
|
exportOptions: {
|
|
657
|
-
observations
|
|
675
|
+
observations
|
|
676
|
+
/**
|
|
677
|
+
* Update the settings of a project.
|
|
678
|
+
*
|
|
679
|
+
* @param opts.projectId Public ID of the project to apply changes to.
|
|
680
|
+
*/
|
|
681
|
+
?: boolean;
|
|
658
682
|
tracks?: boolean;
|
|
659
683
|
lang?: string;
|
|
660
684
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useMutation, useQueryClient, useSuspenseQuery, } from '@tanstack/react-query';
|
|
2
2
|
import { useSyncExternalStore } from 'react';
|
|
3
|
-
import { addServerPeerMutationOptions,
|
|
3
|
+
import { addServerPeerMutationOptions, connectSyncServersMutationOptions, createBlobMutationOptions, createProjectMutationOptions, disconnectSyncServersMutationOptions, documentCreatedByQueryOptions, exportGeoJSONMutationOptions, exportZipFileMutationOptions, importProjectConfigMutationOptions, leaveProjectMutationOptions, mediaServerPortQueryOptions, projectByIdQueryOptions, projectMemberByIdQueryOptions, projectMembersQueryOptions, projectOwnRoleQueryOptions, projectSettingsQueryOptions, projectsQueryOptions, removeServerPeerMutationOptions, setAutostopDataSyncTimeoutMutationOptions, startSyncMutationOptions, stopSyncMutationOptions, updateProjectSettingsMutationOptions, } from '../lib/react-query/projects.js';
|
|
4
4
|
import { SyncStore } from '../lib/sync.js';
|
|
5
|
+
import { getBlobUrl, getIconUrl } from '../lib/urls.js';
|
|
5
6
|
import { useClientApi } from './client.js';
|
|
6
7
|
/**
|
|
7
8
|
* Retrieve the project settings for a project.
|
|
@@ -158,13 +159,10 @@ export function useManyMembers({ projectId }) {
|
|
|
158
159
|
*/
|
|
159
160
|
export function useIconUrl({ projectId, iconId, ...mimeBasedOpts }) {
|
|
160
161
|
const { data: projectApi } = useSingleProject({ projectId });
|
|
161
|
-
const { data, error, isRefetching } =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
iconId,
|
|
166
|
-
}));
|
|
167
|
-
return { data, error, isRefetching };
|
|
162
|
+
const { data: port, error, isRefetching } = useMediaServerPort({ projectApi });
|
|
163
|
+
const baseUrl = `http://127.0.0.1:${port}`;
|
|
164
|
+
const iconUrl = getIconUrl(baseUrl, iconId, mimeBasedOpts);
|
|
165
|
+
return { data: iconUrl, error, isRefetching };
|
|
168
166
|
}
|
|
169
167
|
/**
|
|
170
168
|
* Retrieve a URL that points to a desired blob resource.
|
|
@@ -219,10 +217,18 @@ export function useIconUrl({ projectId, iconId, ...mimeBasedOpts }) {
|
|
|
219
217
|
*/
|
|
220
218
|
export function useAttachmentUrl({ projectId, blobId, }) {
|
|
221
219
|
const { data: projectApi } = useSingleProject({ projectId });
|
|
222
|
-
const { data, error, isRefetching } =
|
|
220
|
+
const { data: port, error, isRefetching } = useMediaServerPort({ projectApi });
|
|
221
|
+
const baseUrl = `http://127.0.0.1:${port}`;
|
|
222
|
+
const blobUrl = getBlobUrl(baseUrl, blobId);
|
|
223
|
+
return { data: blobUrl, error, isRefetching };
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* @internal
|
|
227
|
+
* Hack to retrieve the media server port.
|
|
228
|
+
*/
|
|
229
|
+
function useMediaServerPort({ projectApi }) {
|
|
230
|
+
const { data, error, isRefetching } = useSuspenseQuery(mediaServerPortQueryOptions({
|
|
223
231
|
projectApi,
|
|
224
|
-
projectId,
|
|
225
|
-
blobId,
|
|
226
232
|
}));
|
|
227
233
|
return { data, error, isRefetching };
|
|
228
234
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BlobApi
|
|
1
|
+
import type { BlobApi } from '@comapeo/core' with { 'resolution-mode': 'import' };
|
|
2
2
|
import type { MapeoClientApi, MapeoProjectApi } from '@comapeo/ipc' with { 'resolution-mode': 'import' };
|
|
3
3
|
import type { ProjectSettings } from '@comapeo/schema' with { 'resolution-mode': 'import' };
|
|
4
4
|
import { type QueryClient, type UnusedSkipTokenOptions } from '@tanstack/react-query';
|
|
@@ -19,27 +19,16 @@ export declare function getMemberByIdQueryKey({ projectId, deviceId, }: {
|
|
|
19
19
|
projectId: string;
|
|
20
20
|
deviceId: string;
|
|
21
21
|
}): readonly ["@comapeo/core-react", "projects", string, "members", string];
|
|
22
|
-
export declare function getIconUrlQueryKey({ projectId, iconId, ...mimeBasedOpts }: {
|
|
23
|
-
projectId: string;
|
|
24
|
-
iconId: string;
|
|
25
|
-
} & (IconApi.BitmapOpts | IconApi.SvgOpts)): readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
26
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/png">;
|
|
27
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant, {
|
|
28
|
-
mimeType: "image/png";
|
|
29
|
-
}>["pixelDensity"];
|
|
30
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
31
|
-
} | {
|
|
32
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/svg+xml">;
|
|
33
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
34
|
-
}];
|
|
35
22
|
export declare function getDocumentCreatedByQueryKey({ projectId, originalVersionId, }: {
|
|
36
23
|
projectId: string;
|
|
37
24
|
originalVersionId: string;
|
|
38
25
|
}): readonly ["@comapeo/core-react", "projects", string, "document_created_by", string];
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
/**
|
|
27
|
+
* We call this within a project hook, because that's the only place the API is
|
|
28
|
+
* exposed right now, but it is the same for all projects, so no need for
|
|
29
|
+
* scoping the query key to the project
|
|
30
|
+
*/
|
|
31
|
+
export declare function getMediaServerPortQueryKey(): readonly ["@comapeo/core-react", "media_server_port"];
|
|
43
32
|
export declare function projectsQueryOptions({ clientApi, }: {
|
|
44
33
|
clientApi: MapeoClientApi;
|
|
45
34
|
}): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<import("@comapeo/core/dist/mapeo-manager.js").ListedProject[], Error, import("@comapeo/core/dist/mapeo-manager.js").ListedProject[], readonly ["@comapeo/core-react", "projects"]>, "queryFn"> & {
|
|
@@ -99,45 +88,6 @@ export declare function projectOwnRoleQueryOptions({ projectApi, projectId, }: {
|
|
|
99
88
|
[dataTagErrorSymbol]: Error;
|
|
100
89
|
};
|
|
101
90
|
};
|
|
102
|
-
export declare function iconUrlQueryOptions({ projectApi, projectId, iconId, ...mimeBasedOpts }: {
|
|
103
|
-
projectApi: MapeoProjectApi;
|
|
104
|
-
projectId: string;
|
|
105
|
-
iconId: Parameters<MapeoProjectApi['$icons']['getIconUrl']>[0];
|
|
106
|
-
} & (IconApi.BitmapOpts | IconApi.SvgOpts)): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<string, Error, string, readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
107
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/png">;
|
|
108
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant, {
|
|
109
|
-
mimeType: "image/png";
|
|
110
|
-
}>["pixelDensity"];
|
|
111
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
112
|
-
} | {
|
|
113
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/svg+xml">;
|
|
114
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
115
|
-
}]>, "queryFn"> & {
|
|
116
|
-
queryFn?: import("@tanstack/react-query").QueryFunction<string, readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
117
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/png">;
|
|
118
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant, {
|
|
119
|
-
mimeType: "image/png";
|
|
120
|
-
}>["pixelDensity"];
|
|
121
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
122
|
-
} | {
|
|
123
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/svg+xml">;
|
|
124
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
125
|
-
}], never> | undefined;
|
|
126
|
-
} & {
|
|
127
|
-
queryKey: readonly ["@comapeo/core-react", "projects", string, "icons", string, {
|
|
128
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/png">;
|
|
129
|
-
pixelDensity: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant, {
|
|
130
|
-
mimeType: "image/png";
|
|
131
|
-
}>["pixelDensity"];
|
|
132
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
133
|
-
} | {
|
|
134
|
-
mimeType: Extract<import("@comapeo/core/dist/icon-api.js").IconVariant["mimeType"], "image/svg+xml">;
|
|
135
|
-
size: import("@comapeo/core/dist/icon-api.js").ValidSizes;
|
|
136
|
-
}] & {
|
|
137
|
-
[dataTagSymbol]: string;
|
|
138
|
-
[dataTagErrorSymbol]: Error;
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
91
|
export declare function documentCreatedByQueryOptions({ projectApi, projectId, originalVersionId, }: {
|
|
142
92
|
projectApi: MapeoProjectApi;
|
|
143
93
|
projectId: string;
|
|
@@ -150,14 +100,12 @@ export declare function documentCreatedByQueryOptions({ projectApi, projectId, o
|
|
|
150
100
|
[dataTagErrorSymbol]: Error;
|
|
151
101
|
};
|
|
152
102
|
};
|
|
153
|
-
export declare function
|
|
103
|
+
export declare function mediaServerPortQueryOptions({ projectApi, }: {
|
|
154
104
|
projectApi: MapeoProjectApi;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<string, Error, string, readonly ["@comapeo/core-react", "projects", string, "attachments", import("@comapeo/core/dist/types.js").BlobId]>, "queryFn"> & {
|
|
158
|
-
queryFn?: import("@tanstack/react-query").QueryFunction<string, readonly ["@comapeo/core-react", "projects", string, "attachments", import("@comapeo/core/dist/types.js").BlobId], never> | undefined;
|
|
105
|
+
}): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<string, Error, string, readonly ["@comapeo/core-react", "media_server_port"]>, "queryFn"> & {
|
|
106
|
+
queryFn?: import("@tanstack/react-query").QueryFunction<string, readonly ["@comapeo/core-react", "media_server_port"], never> | undefined;
|
|
159
107
|
} & {
|
|
160
|
-
queryKey: readonly ["@comapeo/core-react", "
|
|
108
|
+
queryKey: readonly ["@comapeo/core-react", "media_server_port"] & {
|
|
161
109
|
[dataTagSymbol]: string;
|
|
162
110
|
[dataTagErrorSymbol]: Error;
|
|
163
111
|
};
|
|
@@ -18,16 +18,6 @@ export function getMembersQueryKey({ projectId }) {
|
|
|
18
18
|
export function getMemberByIdQueryKey({ projectId, deviceId, }) {
|
|
19
19
|
return [ROOT_QUERY_KEY, 'projects', projectId, 'members', deviceId];
|
|
20
20
|
}
|
|
21
|
-
export function getIconUrlQueryKey({ projectId, iconId, ...mimeBasedOpts }) {
|
|
22
|
-
return [
|
|
23
|
-
ROOT_QUERY_KEY,
|
|
24
|
-
'projects',
|
|
25
|
-
projectId,
|
|
26
|
-
'icons',
|
|
27
|
-
iconId,
|
|
28
|
-
mimeBasedOpts,
|
|
29
|
-
];
|
|
30
|
-
}
|
|
31
21
|
export function getDocumentCreatedByQueryKey({ projectId, originalVersionId, }) {
|
|
32
22
|
return [
|
|
33
23
|
ROOT_QUERY_KEY,
|
|
@@ -37,8 +27,13 @@ export function getDocumentCreatedByQueryKey({ projectId, originalVersionId, })
|
|
|
37
27
|
originalVersionId,
|
|
38
28
|
];
|
|
39
29
|
}
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
/**
|
|
31
|
+
* We call this within a project hook, because that's the only place the API is
|
|
32
|
+
* exposed right now, but it is the same for all projects, so no need for
|
|
33
|
+
* scoping the query key to the project
|
|
34
|
+
*/
|
|
35
|
+
export function getMediaServerPortQueryKey() {
|
|
36
|
+
return [ROOT_QUERY_KEY, 'media_server_port'];
|
|
42
37
|
}
|
|
43
38
|
export function projectsQueryOptions({ clientApi, }) {
|
|
44
39
|
return queryOptions({
|
|
@@ -94,15 +89,6 @@ export function projectOwnRoleQueryOptions({ projectApi, projectId, }) {
|
|
|
94
89
|
},
|
|
95
90
|
});
|
|
96
91
|
}
|
|
97
|
-
export function iconUrlQueryOptions({ projectApi, projectId, iconId, ...mimeBasedOpts }) {
|
|
98
|
-
return queryOptions({
|
|
99
|
-
...baseQueryOptions(),
|
|
100
|
-
queryKey: getIconUrlQueryKey({ ...mimeBasedOpts, projectId, iconId }),
|
|
101
|
-
queryFn: async () => {
|
|
102
|
-
return projectApi.$icons.getIconUrl(iconId, mimeBasedOpts);
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
92
|
export function documentCreatedByQueryOptions({ projectApi, projectId, originalVersionId, }) {
|
|
107
93
|
return queryOptions({
|
|
108
94
|
...baseQueryOptions(),
|
|
@@ -113,16 +99,31 @@ export function documentCreatedByQueryOptions({ projectApi, projectId, originalV
|
|
|
113
99
|
queryFn: async () => {
|
|
114
100
|
return projectApi.$originalVersionIdToDeviceId(originalVersionId);
|
|
115
101
|
},
|
|
102
|
+
staleTime: 'static',
|
|
103
|
+
gcTime: Infinity,
|
|
116
104
|
});
|
|
117
105
|
}
|
|
118
|
-
|
|
106
|
+
// Used as a placeholder so that we can read the server port from the $blobs.getUrl() method
|
|
107
|
+
const FAKE_BLOB_ID = {
|
|
108
|
+
type: 'photo',
|
|
109
|
+
variant: 'original',
|
|
110
|
+
name: 'name',
|
|
111
|
+
driveId: 'drive-id',
|
|
112
|
+
};
|
|
113
|
+
export function mediaServerPortQueryOptions({ projectApi, }) {
|
|
119
114
|
return queryOptions({
|
|
120
115
|
...baseQueryOptions(),
|
|
121
|
-
|
|
116
|
+
// HACK: The server doesn't yet expose a method to get its port, so we use
|
|
117
|
+
// the existing $blobs.getUrl() to get the port with a fake BlobId. The port
|
|
118
|
+
// is the same regardless of the blobId, so it's not necessary to include it
|
|
119
|
+
// as a dep for the query key.
|
|
120
|
+
queryKey: getMediaServerPortQueryKey(),
|
|
122
121
|
queryFn: async () => {
|
|
123
|
-
|
|
124
|
-
return
|
|
122
|
+
const url = await projectApi.$blobs.getUrl(FAKE_BLOB_ID);
|
|
123
|
+
return new URL(url).port;
|
|
125
124
|
},
|
|
125
|
+
staleTime: 'static',
|
|
126
|
+
gcTime: Infinity,
|
|
126
127
|
});
|
|
127
128
|
}
|
|
128
129
|
export function addServerPeerMutationOptions({ projectApi, projectId, queryClient, }) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BlobApi, IconApi } from '@comapeo/core';
|
|
2
|
+
/**
|
|
3
|
+
* Get a url for a blob based on its BlobId
|
|
4
|
+
*/
|
|
5
|
+
export declare function getBlobUrl(baseUrl: string, blobId: BlobApi.BlobId): string;
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} iconId
|
|
8
|
+
* @param {BitmapOpts | SvgOpts} opts
|
|
9
|
+
*
|
|
10
|
+
* @returns {Promise<string>}
|
|
11
|
+
*/
|
|
12
|
+
export declare function getIconUrl(baseUrl: string, iconId: string, opts: IconApi.BitmapOpts | IconApi.SvgOpts): string;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// TODO: Move these into a separate "@comapeo/asset-server" module which can
|
|
2
|
+
// export them to be imported directly in a client.
|
|
3
|
+
const MIME_TO_EXTENSION = {
|
|
4
|
+
'image/png': '.png',
|
|
5
|
+
'image/svg+xml': '.svg',
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Get a url for a blob based on its BlobId
|
|
9
|
+
*/
|
|
10
|
+
export function getBlobUrl(baseUrl, blobId) {
|
|
11
|
+
const { driveId, type, variant, name } = blobId;
|
|
12
|
+
if (!baseUrl.endsWith('/')) {
|
|
13
|
+
baseUrl += '/';
|
|
14
|
+
}
|
|
15
|
+
return baseUrl + `${driveId}/${type}/${variant}/${name}`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} iconId
|
|
19
|
+
* @param {BitmapOpts | SvgOpts} opts
|
|
20
|
+
*
|
|
21
|
+
* @returns {Promise<string>}
|
|
22
|
+
*/
|
|
23
|
+
export function getIconUrl(baseUrl, iconId, opts) {
|
|
24
|
+
if (!baseUrl.endsWith('/')) {
|
|
25
|
+
baseUrl += '/';
|
|
26
|
+
}
|
|
27
|
+
const mimeExtension = MIME_TO_EXTENSION[opts.mimeType];
|
|
28
|
+
const pixelDensity = opts.mimeType === 'image/svg+xml' ||
|
|
29
|
+
// if the pixel density is 1, we can omit the density suffix in the resulting url
|
|
30
|
+
// and assume the pixel density is 1 for applicable mime types when using the url
|
|
31
|
+
opts.pixelDensity === 1
|
|
32
|
+
? undefined
|
|
33
|
+
: opts.pixelDensity;
|
|
34
|
+
return (baseUrl +
|
|
35
|
+
constructIconPath({
|
|
36
|
+
pixelDensity,
|
|
37
|
+
size: opts.size,
|
|
38
|
+
extension: mimeExtension,
|
|
39
|
+
iconId,
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* General purpose path builder for an icon
|
|
44
|
+
*/
|
|
45
|
+
function constructIconPath({ size, pixelDensity, iconId, extension, }) {
|
|
46
|
+
if (iconId.length === 0 || size.length === 0 || extension.length === 0) {
|
|
47
|
+
throw new Error('iconId, size, and extension cannot be empty strings');
|
|
48
|
+
}
|
|
49
|
+
let result = `${iconId}/${size}`;
|
|
50
|
+
if (typeof pixelDensity === 'number') {
|
|
51
|
+
if (pixelDensity < 1) {
|
|
52
|
+
throw new Error('pixelDensity must be a positive number');
|
|
53
|
+
}
|
|
54
|
+
result += `@${pixelDensity}x`;
|
|
55
|
+
}
|
|
56
|
+
result += extension.startsWith('.') ? extension : '.' + extension;
|
|
57
|
+
return result;
|
|
58
|
+
}
|