@ogcio/building-blocks-sdk 0.2.85 → 0.2.87

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 (34) hide show
  1. package/.azure/pipeline.yaml +15 -14
  2. package/.release-please-manifest.json +1 -1
  3. package/CHANGELOG.md +14 -0
  4. package/dist/client/clients/messaging/index.d.ts.map +1 -1
  5. package/dist/client/clients/messaging/schema.d.ts +167 -0
  6. package/dist/client/clients/messaging/schema.d.ts.map +1 -1
  7. package/dist/client/clients/messaging/support.d.ts +122 -0
  8. package/dist/client/clients/messaging/support.d.ts.map +1 -1
  9. package/dist/client/clients/messaging/support.js +7 -0
  10. package/dist/client/clients/messaging/support.js.map +1 -1
  11. package/dist/client/clients/upload/index.d.ts +15 -0
  12. package/dist/client/clients/upload/index.d.ts.map +1 -1
  13. package/dist/client/clients/upload/index.js +19 -35
  14. package/dist/client/clients/upload/index.js.map +1 -1
  15. package/dist/client/clients/upload/shared.d.ts +47 -0
  16. package/dist/client/clients/upload/shared.d.ts.map +1 -0
  17. package/dist/client/clients/upload/shared.js +72 -0
  18. package/dist/client/clients/upload/shared.js.map +1 -0
  19. package/dist/client/clients/upload/support.d.ts +15 -0
  20. package/dist/client/clients/upload/support.d.ts.map +1 -1
  21. package/dist/client/clients/upload/support.js +19 -35
  22. package/dist/client/clients/upload/support.js.map +1 -1
  23. package/dist/client/utils/client-utils.d.ts +9 -0
  24. package/dist/client/utils/client-utils.d.ts.map +1 -1
  25. package/dist/client/utils/client-utils.js +43 -0
  26. package/dist/client/utils/client-utils.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/client/clients/messaging/open-api-definition.json +337 -0
  29. package/src/client/clients/messaging/schema.ts +167 -0
  30. package/src/client/clients/messaging/support.ts +13 -0
  31. package/src/client/clients/upload/index.ts +35 -36
  32. package/src/client/clients/upload/shared.ts +122 -0
  33. package/src/client/clients/upload/support.ts +35 -36
  34. package/src/client/utils/client-utils.ts +59 -0
@@ -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
+ }
@@ -6,6 +6,7 @@ import {
6
6
  throwIfEmpty,
7
7
  } from "../../utils/client-utils.js";
8
8
  import type { paths } from "./schema.js";
9
+ import { uploadFile, uploadStreamFile } from "./shared.js";
9
10
 
10
11
  export class UploadSupport {
11
12
  constructor(
@@ -74,43 +75,41 @@ export class UploadSupport {
74
75
  };
75
76
  data?: { uploadId?: string };
76
77
  }> {
77
- const timeoutMs = options?.timeoutMs ?? 120000; // default 120s
78
- try {
79
- const { error, data } = await this.client.POST("/api/v1/support/files/", {
80
- body: {
81
- file,
82
- expirationDate,
83
- },
84
- signal: AbortSignal.timeout(timeoutMs),
85
- bodySerializer: (body: unknown) => {
86
- const parsed = body as { file: File; expirationDate?: string };
87
- const formData = new FormData();
88
- if (parsed.expirationDate) {
89
- formData.set("expirationDate", parsed.expirationDate);
90
- }
91
- formData.set("file", parsed.file);
92
- return formData;
93
- },
94
- });
78
+ return uploadFile({
79
+ file,
80
+ expirationDate,
81
+ options,
82
+ client: this.client,
83
+ path: "/api/v1/support/files/",
84
+ });
85
+ }
95
86
 
96
- return { error, data: { uploadId: data?.data.id } };
97
- } catch (e: unknown) {
98
- const err = e as Error & { name?: string };
99
- if (
100
- err?.name === "AbortError" ||
101
- err?.constructor?.name === "DOMException"
102
- ) {
103
- return {
104
- error: {
105
- name: "TimeoutError",
106
- detail: "Upload aborted after reaching timeout",
107
- requestId: "",
108
- code: "TIMEOUT_ERROR",
109
- },
110
- };
111
- }
112
- throw err;
113
- }
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
+ });
114
113
  }
115
114
 
116
115
  shareFile(fileId: string, ...userIds: string[]) {
@@ -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
+ }