@ogcio/building-blocks-sdk 0.2.84 → 0.2.86
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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/client/clients/messaging/index.d.ts +8 -0
- package/dist/client/clients/messaging/index.d.ts.map +1 -1
- package/dist/client/clients/messaging/index.js +7 -1
- package/dist/client/clients/messaging/index.js.map +1 -1
- package/dist/client/clients/messaging/schema.d.ts +154 -0
- package/dist/client/clients/messaging/schema.d.ts.map +1 -1
- package/dist/client/clients/messaging/support.d.ts +125 -0
- package/dist/client/clients/messaging/support.d.ts.map +1 -0
- package/dist/client/clients/messaging/support.js +20 -0
- package/dist/client/clients/messaging/support.js.map +1 -0
- package/dist/client/clients/profile/citizen.d.ts.map +1 -1
- package/dist/client/clients/profile/index.d.ts +7 -79
- package/dist/client/clients/profile/index.d.ts.map +1 -1
- package/dist/client/clients/profile/index.js +13 -20
- package/dist/client/clients/profile/index.js.map +1 -1
- package/dist/client/clients/profile/organisation.d.ts.map +1 -1
- package/dist/client/clients/profile/schema.d.ts +1 -89
- package/dist/client/clients/profile/schema.d.ts.map +1 -1
- package/dist/client/clients/upload/index.d.ts +23 -0
- package/dist/client/clients/upload/index.d.ts.map +1 -1
- package/dist/client/clients/upload/index.js +26 -36
- package/dist/client/clients/upload/index.js.map +1 -1
- package/dist/client/clients/upload/schema.d.ts +321 -0
- package/dist/client/clients/upload/schema.d.ts.map +1 -1
- package/dist/client/clients/upload/shared.d.ts +47 -0
- package/dist/client/clients/upload/shared.d.ts.map +1 -0
- package/dist/client/clients/upload/shared.js +72 -0
- package/dist/client/clients/upload/shared.js.map +1 -0
- package/dist/client/clients/upload/support.d.ts +239 -0
- package/dist/client/clients/upload/support.d.ts.map +1 -0
- package/dist/client/clients/upload/support.js +73 -0
- package/dist/client/clients/upload/support.js.map +1 -0
- package/dist/client/utils/client-utils.d.ts +9 -0
- package/dist/client/utils/client-utils.d.ts.map +1 -1
- package/dist/client/utils/client-utils.js +43 -0
- package/dist/client/utils/client-utils.js.map +1 -1
- package/package.json +1 -1
- package/src/client/clients/messaging/index.ts +20 -1
- package/src/client/clients/messaging/open-api-definition.json +355 -0
- package/src/client/clients/messaging/schema.ts +154 -0
- package/src/client/clients/messaging/support.ts +27 -0
- package/src/client/clients/profile/index.ts +33 -35
- package/src/client/clients/profile/open-api-definition.json +3 -163
- package/src/client/clients/profile/schema.ts +1 -89
- package/src/client/clients/upload/index.ts +56 -37
- package/src/client/clients/upload/open-api-definition.json +621 -41
- package/src/client/clients/upload/schema.ts +321 -0
- package/src/client/clients/upload/shared.ts +122 -0
- package/src/client/clients/upload/support.ts +127 -0
- package/src/client/utils/client-utils.ts +59 -0
|
@@ -143,6 +143,155 @@ export interface paths {
|
|
|
143
143
|
patch?: never;
|
|
144
144
|
trace?: never;
|
|
145
145
|
};
|
|
146
|
+
"/api/v1/support/files/": {
|
|
147
|
+
parameters: {
|
|
148
|
+
query?: never;
|
|
149
|
+
header?: never;
|
|
150
|
+
path?: never;
|
|
151
|
+
cookie?: never;
|
|
152
|
+
};
|
|
153
|
+
get?: never;
|
|
154
|
+
put?: never;
|
|
155
|
+
post: {
|
|
156
|
+
parameters: {
|
|
157
|
+
query?: never;
|
|
158
|
+
header?: never;
|
|
159
|
+
path?: never;
|
|
160
|
+
cookie?: never;
|
|
161
|
+
};
|
|
162
|
+
requestBody?: {
|
|
163
|
+
content: {
|
|
164
|
+
"multipart/form-data": unknown | unknown;
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
responses: {
|
|
168
|
+
/** @description Default Response */
|
|
169
|
+
201: {
|
|
170
|
+
headers: {
|
|
171
|
+
[name: string]: unknown;
|
|
172
|
+
};
|
|
173
|
+
content: {
|
|
174
|
+
"application/json": {
|
|
175
|
+
data: {
|
|
176
|
+
id: string;
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
/** @description Default Response */
|
|
182
|
+
"4XX": {
|
|
183
|
+
headers: {
|
|
184
|
+
[name: string]: unknown;
|
|
185
|
+
};
|
|
186
|
+
content: {
|
|
187
|
+
"application/json": {
|
|
188
|
+
code: string;
|
|
189
|
+
detail: string;
|
|
190
|
+
requestId: string;
|
|
191
|
+
name: string;
|
|
192
|
+
validation?: unknown;
|
|
193
|
+
validationContext?: string;
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
/** @description Default Response */
|
|
198
|
+
"5XX": {
|
|
199
|
+
headers: {
|
|
200
|
+
[name: string]: unknown;
|
|
201
|
+
};
|
|
202
|
+
content: {
|
|
203
|
+
"application/json": {
|
|
204
|
+
code: string;
|
|
205
|
+
detail: string;
|
|
206
|
+
requestId: string;
|
|
207
|
+
name: string;
|
|
208
|
+
validation?: unknown;
|
|
209
|
+
validationContext?: string;
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
delete?: never;
|
|
216
|
+
options?: never;
|
|
217
|
+
head?: never;
|
|
218
|
+
patch?: never;
|
|
219
|
+
trace?: never;
|
|
220
|
+
};
|
|
221
|
+
"/api/v1/support/files/download-batch": {
|
|
222
|
+
parameters: {
|
|
223
|
+
query?: never;
|
|
224
|
+
header?: never;
|
|
225
|
+
path?: never;
|
|
226
|
+
cookie?: never;
|
|
227
|
+
};
|
|
228
|
+
get?: never;
|
|
229
|
+
put?: never;
|
|
230
|
+
post: {
|
|
231
|
+
parameters: {
|
|
232
|
+
query?: never;
|
|
233
|
+
header?: never;
|
|
234
|
+
path?: never;
|
|
235
|
+
cookie?: never;
|
|
236
|
+
};
|
|
237
|
+
requestBody: {
|
|
238
|
+
content: {
|
|
239
|
+
"application/json": {
|
|
240
|
+
fileIds: string[];
|
|
241
|
+
userId: string;
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
responses: {
|
|
246
|
+
/** @description Multipart mixed response containing requested files */
|
|
247
|
+
200: {
|
|
248
|
+
headers: {
|
|
249
|
+
[name: string]: unknown;
|
|
250
|
+
};
|
|
251
|
+
content: {
|
|
252
|
+
"multipart/mixed": string;
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
/** @description Default Response */
|
|
256
|
+
"4XX": {
|
|
257
|
+
headers: {
|
|
258
|
+
[name: string]: unknown;
|
|
259
|
+
};
|
|
260
|
+
content: {
|
|
261
|
+
"application/json": {
|
|
262
|
+
code: string;
|
|
263
|
+
detail: string;
|
|
264
|
+
requestId: string;
|
|
265
|
+
name: string;
|
|
266
|
+
validation?: unknown;
|
|
267
|
+
validationContext?: string;
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
/** @description Default Response */
|
|
272
|
+
"5XX": {
|
|
273
|
+
headers: {
|
|
274
|
+
[name: string]: unknown;
|
|
275
|
+
};
|
|
276
|
+
content: {
|
|
277
|
+
"application/json": {
|
|
278
|
+
code: string;
|
|
279
|
+
detail: string;
|
|
280
|
+
requestId: string;
|
|
281
|
+
name: string;
|
|
282
|
+
validation?: unknown;
|
|
283
|
+
validationContext?: string;
|
|
284
|
+
};
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
delete?: never;
|
|
290
|
+
options?: never;
|
|
291
|
+
head?: never;
|
|
292
|
+
patch?: never;
|
|
293
|
+
trace?: never;
|
|
294
|
+
};
|
|
146
295
|
"/api/v1/metadata/": {
|
|
147
296
|
parameters: {
|
|
148
297
|
query?: never;
|
|
@@ -377,6 +526,93 @@ export interface paths {
|
|
|
377
526
|
patch?: never;
|
|
378
527
|
trace?: never;
|
|
379
528
|
};
|
|
529
|
+
"/api/v1/support/metadata/": {
|
|
530
|
+
parameters: {
|
|
531
|
+
query?: never;
|
|
532
|
+
header?: never;
|
|
533
|
+
path?: never;
|
|
534
|
+
cookie?: never;
|
|
535
|
+
};
|
|
536
|
+
get: {
|
|
537
|
+
parameters: {
|
|
538
|
+
query?: {
|
|
539
|
+
userId?: string;
|
|
540
|
+
organizationId?: string;
|
|
541
|
+
};
|
|
542
|
+
header?: never;
|
|
543
|
+
path?: never;
|
|
544
|
+
cookie?: never;
|
|
545
|
+
};
|
|
546
|
+
requestBody?: never;
|
|
547
|
+
responses: {
|
|
548
|
+
/** @description Default Response */
|
|
549
|
+
200: {
|
|
550
|
+
headers: {
|
|
551
|
+
[name: string]: unknown;
|
|
552
|
+
};
|
|
553
|
+
content: {
|
|
554
|
+
"application/json": {
|
|
555
|
+
data: {
|
|
556
|
+
fileName: string;
|
|
557
|
+
id?: string;
|
|
558
|
+
key: string;
|
|
559
|
+
ownerId: string;
|
|
560
|
+
fileSize: number;
|
|
561
|
+
mimeType: string;
|
|
562
|
+
createdAt: string;
|
|
563
|
+
lastScan: string;
|
|
564
|
+
/** @default false */
|
|
565
|
+
deleted: boolean;
|
|
566
|
+
infected: boolean;
|
|
567
|
+
infectionDescription?: string;
|
|
568
|
+
antivirusDbVersion?: string;
|
|
569
|
+
expiresAt?: string;
|
|
570
|
+
}[];
|
|
571
|
+
};
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
/** @description Default Response */
|
|
575
|
+
"4XX": {
|
|
576
|
+
headers: {
|
|
577
|
+
[name: string]: unknown;
|
|
578
|
+
};
|
|
579
|
+
content: {
|
|
580
|
+
"application/json": {
|
|
581
|
+
code: string;
|
|
582
|
+
detail: string;
|
|
583
|
+
requestId: string;
|
|
584
|
+
name: string;
|
|
585
|
+
validation?: unknown;
|
|
586
|
+
validationContext?: string;
|
|
587
|
+
};
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
/** @description Default Response */
|
|
591
|
+
"5XX": {
|
|
592
|
+
headers: {
|
|
593
|
+
[name: string]: unknown;
|
|
594
|
+
};
|
|
595
|
+
content: {
|
|
596
|
+
"application/json": {
|
|
597
|
+
code: string;
|
|
598
|
+
detail: string;
|
|
599
|
+
requestId: string;
|
|
600
|
+
name: string;
|
|
601
|
+
validation?: unknown;
|
|
602
|
+
validationContext?: string;
|
|
603
|
+
};
|
|
604
|
+
};
|
|
605
|
+
};
|
|
606
|
+
};
|
|
607
|
+
};
|
|
608
|
+
put?: never;
|
|
609
|
+
post?: never;
|
|
610
|
+
delete?: never;
|
|
611
|
+
options?: never;
|
|
612
|
+
head?: never;
|
|
613
|
+
patch?: never;
|
|
614
|
+
trace?: never;
|
|
615
|
+
};
|
|
380
616
|
"/api/v1/permissions/": {
|
|
381
617
|
parameters: {
|
|
382
618
|
query?: never;
|
|
@@ -569,6 +805,91 @@ export interface paths {
|
|
|
569
805
|
patch?: never;
|
|
570
806
|
trace?: never;
|
|
571
807
|
};
|
|
808
|
+
"/api/v1/support/permissions/": {
|
|
809
|
+
parameters: {
|
|
810
|
+
query?: never;
|
|
811
|
+
header?: never;
|
|
812
|
+
path?: never;
|
|
813
|
+
cookie?: never;
|
|
814
|
+
};
|
|
815
|
+
get?: never;
|
|
816
|
+
put?: never;
|
|
817
|
+
post: {
|
|
818
|
+
parameters: {
|
|
819
|
+
query?: never;
|
|
820
|
+
header?: never;
|
|
821
|
+
path?: never;
|
|
822
|
+
cookie?: never;
|
|
823
|
+
};
|
|
824
|
+
requestBody?: {
|
|
825
|
+
content: {
|
|
826
|
+
"application/json": {
|
|
827
|
+
fileId: string;
|
|
828
|
+
userId: string;
|
|
829
|
+
} | {
|
|
830
|
+
fileId: string;
|
|
831
|
+
userIds: string[];
|
|
832
|
+
};
|
|
833
|
+
};
|
|
834
|
+
};
|
|
835
|
+
responses: {
|
|
836
|
+
/** @description Default Response */
|
|
837
|
+
201: {
|
|
838
|
+
headers: {
|
|
839
|
+
[name: string]: unknown;
|
|
840
|
+
};
|
|
841
|
+
content: {
|
|
842
|
+
"application/json": {
|
|
843
|
+
data: {
|
|
844
|
+
fileId: string;
|
|
845
|
+
userId: string;
|
|
846
|
+
} | {
|
|
847
|
+
fileId: string;
|
|
848
|
+
userIds: string[];
|
|
849
|
+
};
|
|
850
|
+
};
|
|
851
|
+
};
|
|
852
|
+
};
|
|
853
|
+
/** @description Default Response */
|
|
854
|
+
"4XX": {
|
|
855
|
+
headers: {
|
|
856
|
+
[name: string]: unknown;
|
|
857
|
+
};
|
|
858
|
+
content: {
|
|
859
|
+
"application/json": {
|
|
860
|
+
code: string;
|
|
861
|
+
detail: string;
|
|
862
|
+
requestId: string;
|
|
863
|
+
name: string;
|
|
864
|
+
validation?: unknown;
|
|
865
|
+
validationContext?: string;
|
|
866
|
+
};
|
|
867
|
+
};
|
|
868
|
+
};
|
|
869
|
+
/** @description Default Response */
|
|
870
|
+
"5XX": {
|
|
871
|
+
headers: {
|
|
872
|
+
[name: string]: unknown;
|
|
873
|
+
};
|
|
874
|
+
content: {
|
|
875
|
+
"application/json": {
|
|
876
|
+
code: string;
|
|
877
|
+
detail: string;
|
|
878
|
+
requestId: string;
|
|
879
|
+
name: string;
|
|
880
|
+
validation?: unknown;
|
|
881
|
+
validationContext?: string;
|
|
882
|
+
};
|
|
883
|
+
};
|
|
884
|
+
};
|
|
885
|
+
};
|
|
886
|
+
};
|
|
887
|
+
delete?: never;
|
|
888
|
+
options?: never;
|
|
889
|
+
head?: never;
|
|
890
|
+
patch?: never;
|
|
891
|
+
trace?: never;
|
|
892
|
+
};
|
|
572
893
|
}
|
|
573
894
|
export type webhooks = Record<string, never>;
|
|
574
895
|
export interface components {
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type createClient from "openapi-fetch";
|
|
2
|
+
import { buildStreamingMultipart } from "../../utils/client-utils.js";
|
|
3
|
+
import type { paths } from "./schema.js";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_TIMEOUT_MS = 120000; // 120 seconds
|
|
6
|
+
|
|
7
|
+
export async function uploadFile(params: {
|
|
8
|
+
file: File;
|
|
9
|
+
expirationDate?: string;
|
|
10
|
+
options?: { timeoutMs?: number };
|
|
11
|
+
client: ReturnType<typeof createClient<paths>>;
|
|
12
|
+
path: "/api/v1/support/files/" | "/api/v1/files/";
|
|
13
|
+
}): Promise<{
|
|
14
|
+
error?: {
|
|
15
|
+
code: string;
|
|
16
|
+
detail: string;
|
|
17
|
+
requestId: string;
|
|
18
|
+
name: string;
|
|
19
|
+
validation?: unknown;
|
|
20
|
+
validationContext?: string;
|
|
21
|
+
};
|
|
22
|
+
data?: { uploadId?: string };
|
|
23
|
+
}> {
|
|
24
|
+
const { file, expirationDate, options, client, path } = params;
|
|
25
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
26
|
+
try {
|
|
27
|
+
const { error, data } = await client.POST(path, {
|
|
28
|
+
body: {
|
|
29
|
+
file,
|
|
30
|
+
expirationDate,
|
|
31
|
+
},
|
|
32
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
33
|
+
bodySerializer: (body: unknown) => {
|
|
34
|
+
const parsed = body as { file: File; expirationDate?: string };
|
|
35
|
+
const formData = new FormData();
|
|
36
|
+
if (parsed.expirationDate) {
|
|
37
|
+
formData.set("expirationDate", parsed.expirationDate);
|
|
38
|
+
}
|
|
39
|
+
formData.set("file", parsed.file);
|
|
40
|
+
return formData;
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return { error, data: { uploadId: data?.data.id } };
|
|
45
|
+
} catch (e: unknown) {
|
|
46
|
+
const err = e as Error & { name?: string };
|
|
47
|
+
if (
|
|
48
|
+
err?.name === "AbortError" ||
|
|
49
|
+
err?.constructor?.name === "DOMException"
|
|
50
|
+
) {
|
|
51
|
+
return {
|
|
52
|
+
error: {
|
|
53
|
+
name: "TimeoutError",
|
|
54
|
+
detail: "Upload aborted after reaching timeout",
|
|
55
|
+
requestId: "",
|
|
56
|
+
code: "TIMEOUT_ERROR",
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function uploadStreamFile(params: {
|
|
65
|
+
file: ReadableStream<Uint8Array> | Blob;
|
|
66
|
+
filename: string;
|
|
67
|
+
mimeType: string;
|
|
68
|
+
expirationDate?: string;
|
|
69
|
+
options?: { timeoutMs?: number };
|
|
70
|
+
client: ReturnType<typeof createClient<paths>>;
|
|
71
|
+
path: "/api/v1/support/files/" | "/api/v1/files/";
|
|
72
|
+
}): Promise<{
|
|
73
|
+
error?: {
|
|
74
|
+
code: string;
|
|
75
|
+
detail: string;
|
|
76
|
+
requestId: string;
|
|
77
|
+
name: string;
|
|
78
|
+
validation?: unknown;
|
|
79
|
+
validationContext?: string;
|
|
80
|
+
};
|
|
81
|
+
data?: { uploadId?: string };
|
|
82
|
+
}> {
|
|
83
|
+
const { file, filename, mimeType, expirationDate, options, client, path } =
|
|
84
|
+
params;
|
|
85
|
+
|
|
86
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
87
|
+
try {
|
|
88
|
+
const stream = file instanceof Blob ? file.stream() : file;
|
|
89
|
+
const { body, contentType } = buildStreamingMultipart(
|
|
90
|
+
stream,
|
|
91
|
+
filename,
|
|
92
|
+
mimeType,
|
|
93
|
+
expirationDate,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const { error, data } = await client.POST(path, {
|
|
97
|
+
body: {} as never,
|
|
98
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
99
|
+
headers: { "content-type": contentType },
|
|
100
|
+
bodySerializer: () => body,
|
|
101
|
+
duplex: "half",
|
|
102
|
+
} as unknown as Parameters<typeof client.POST>[1]);
|
|
103
|
+
|
|
104
|
+
return { error, data: { uploadId: data?.data.id } };
|
|
105
|
+
} catch (e: unknown) {
|
|
106
|
+
const err = e as Error & { name?: string };
|
|
107
|
+
if (
|
|
108
|
+
err?.name === "AbortError" ||
|
|
109
|
+
err?.constructor?.name === "DOMException"
|
|
110
|
+
) {
|
|
111
|
+
return {
|
|
112
|
+
error: {
|
|
113
|
+
name: "TimeoutError",
|
|
114
|
+
detail: "Upload aborted after reaching timeout",
|
|
115
|
+
requestId: "",
|
|
116
|
+
code: "TIMEOUT_ERROR",
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type createClient from "openapi-fetch";
|
|
2
|
+
import type { Logger } from "../../../types/index.js";
|
|
3
|
+
import {
|
|
4
|
+
formatError,
|
|
5
|
+
formatResponse,
|
|
6
|
+
throwIfEmpty,
|
|
7
|
+
} from "../../utils/client-utils.js";
|
|
8
|
+
import type { paths } from "./schema.js";
|
|
9
|
+
import { uploadFile, uploadStreamFile } from "./shared.js";
|
|
10
|
+
|
|
11
|
+
export class UploadSupport {
|
|
12
|
+
constructor(
|
|
13
|
+
private readonly client: ReturnType<typeof createClient<paths>>,
|
|
14
|
+
private readonly serviceName: string,
|
|
15
|
+
private readonly logger: Logger | undefined,
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
async getSharedFilesForUser(
|
|
19
|
+
query: paths["/api/v1/support/metadata/"]["get"]["parameters"]["query"],
|
|
20
|
+
) {
|
|
21
|
+
const { userId, organizationId } = query || {};
|
|
22
|
+
|
|
23
|
+
return this.client
|
|
24
|
+
.GET("/api/v1/support/metadata/", {
|
|
25
|
+
params: { query: { userId, organizationId } },
|
|
26
|
+
})
|
|
27
|
+
.then(
|
|
28
|
+
(response) => formatResponse(response, this.serviceName, this.logger),
|
|
29
|
+
(reason) => formatError(reason, this.serviceName, this.logger),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async getFiles(
|
|
34
|
+
params: paths["/api/v1/support/files/download-batch"]["post"]["requestBody"]["content"]["application/json"],
|
|
35
|
+
) {
|
|
36
|
+
throwIfEmpty(params.userId);
|
|
37
|
+
try {
|
|
38
|
+
const {
|
|
39
|
+
error,
|
|
40
|
+
data,
|
|
41
|
+
response: { headers, status },
|
|
42
|
+
} = await this.client.POST("/api/v1/support/files/download-batch", {
|
|
43
|
+
body: params,
|
|
44
|
+
parseAs: "stream",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
error,
|
|
49
|
+
data,
|
|
50
|
+
headers: Object.fromEntries(headers.entries()),
|
|
51
|
+
status,
|
|
52
|
+
};
|
|
53
|
+
} catch (e) {
|
|
54
|
+
return {
|
|
55
|
+
error: e,
|
|
56
|
+
data: null,
|
|
57
|
+
headers: null,
|
|
58
|
+
status: 500,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async uploadFile(
|
|
64
|
+
file: File,
|
|
65
|
+
expirationDate?: string,
|
|
66
|
+
options?: { timeoutMs?: number },
|
|
67
|
+
): Promise<{
|
|
68
|
+
error?: {
|
|
69
|
+
code: string;
|
|
70
|
+
detail: string;
|
|
71
|
+
requestId: string;
|
|
72
|
+
name: string;
|
|
73
|
+
validation?: unknown;
|
|
74
|
+
validationContext?: string;
|
|
75
|
+
};
|
|
76
|
+
data?: { uploadId?: string };
|
|
77
|
+
}> {
|
|
78
|
+
return uploadFile({
|
|
79
|
+
file,
|
|
80
|
+
expirationDate,
|
|
81
|
+
options,
|
|
82
|
+
client: this.client,
|
|
83
|
+
path: "/api/v1/support/files/",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async uploadStreamFile(
|
|
88
|
+
file: ReadableStream<Uint8Array> | Blob,
|
|
89
|
+
filename: string,
|
|
90
|
+
mimeType: string,
|
|
91
|
+
expirationDate?: string,
|
|
92
|
+
options?: { timeoutMs?: number },
|
|
93
|
+
): Promise<{
|
|
94
|
+
error?: {
|
|
95
|
+
code: string;
|
|
96
|
+
detail: string;
|
|
97
|
+
requestId: string;
|
|
98
|
+
name: string;
|
|
99
|
+
validation?: unknown;
|
|
100
|
+
validationContext?: string;
|
|
101
|
+
};
|
|
102
|
+
data?: { uploadId?: string };
|
|
103
|
+
}> {
|
|
104
|
+
return uploadStreamFile({
|
|
105
|
+
file,
|
|
106
|
+
filename,
|
|
107
|
+
mimeType,
|
|
108
|
+
expirationDate,
|
|
109
|
+
options,
|
|
110
|
+
client: this.client,
|
|
111
|
+
path: "/api/v1/support/files/",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
shareFile(fileId: string, ...userIds: string[]) {
|
|
116
|
+
throwIfEmpty(fileId);
|
|
117
|
+
throwIfEmpty(userIds);
|
|
118
|
+
return this.client
|
|
119
|
+
.POST("/api/v1/support/permissions/", {
|
|
120
|
+
body: { fileId, userIds },
|
|
121
|
+
})
|
|
122
|
+
.then(
|
|
123
|
+
(response) => formatResponse(response, this.serviceName, this.logger),
|
|
124
|
+
(reason) => formatError(reason, this.serviceName, this.logger),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -163,3 +163,62 @@ export function throwIfEmpty(input: string | string[]): void {
|
|
|
163
163
|
throw Error("Parameter cannot be an empty string or array!");
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Builds a streaming multipart/form-data body from a ReadableStream without
|
|
169
|
+
* buffering the file content in memory. The returned ReadableStream pipes the
|
|
170
|
+
* file chunks directly into the multipart envelope as they are read.
|
|
171
|
+
*/
|
|
172
|
+
export function buildStreamingMultipart(
|
|
173
|
+
stream: ReadableStream<Uint8Array>,
|
|
174
|
+
filename: string,
|
|
175
|
+
mimeType: string,
|
|
176
|
+
expirationDate?: string,
|
|
177
|
+
): { body: ReadableStream<Uint8Array>; contentType: string } {
|
|
178
|
+
const boundary = `----FormBoundary${crypto.randomUUID().replace(/-/g, "")}`;
|
|
179
|
+
const encoder = new TextEncoder();
|
|
180
|
+
// Sanitize filename to prevent Content-Disposition header injection
|
|
181
|
+
const safeFilename = filename.replace(/["\\\r\n]/g, "_");
|
|
182
|
+
|
|
183
|
+
const parts: (Uint8Array | ReadableStream<Uint8Array>)[] = [];
|
|
184
|
+
|
|
185
|
+
if (expirationDate) {
|
|
186
|
+
parts.push(
|
|
187
|
+
encoder.encode(
|
|
188
|
+
`--${boundary}\r\nContent-Disposition: form-data; name="expirationDate"\r\n\r\n${expirationDate}\r\n`,
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
parts.push(
|
|
194
|
+
encoder.encode(
|
|
195
|
+
`--${boundary}\r\nContent-Disposition: form-data; name="file"; filename="${safeFilename}"\r\nContent-Type: ${mimeType}\r\n\r\n`,
|
|
196
|
+
),
|
|
197
|
+
);
|
|
198
|
+
parts.push(stream);
|
|
199
|
+
parts.push(encoder.encode(`\r\n--${boundary}--\r\n`));
|
|
200
|
+
|
|
201
|
+
const body = new ReadableStream<Uint8Array>({
|
|
202
|
+
async start(controller) {
|
|
203
|
+
for (const part of parts) {
|
|
204
|
+
if (part instanceof Uint8Array) {
|
|
205
|
+
controller.enqueue(part);
|
|
206
|
+
} else {
|
|
207
|
+
const reader = part.getReader();
|
|
208
|
+
try {
|
|
209
|
+
while (true) {
|
|
210
|
+
const { done, value } = await reader.read();
|
|
211
|
+
if (done) break;
|
|
212
|
+
controller.enqueue(value);
|
|
213
|
+
}
|
|
214
|
+
} finally {
|
|
215
|
+
reader.releaseLock();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
controller.close();
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return { body, contentType: `multipart/form-data; boundary=${boundary}` };
|
|
224
|
+
}
|