@amerged/ohmyhost-runtime 0.1.37 → 0.1.39
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/README.md +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/http.d.ts +8 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +39 -11
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mail-attachment.d.ts +14 -0
- package/dist/mail-attachment.d.ts.map +1 -0
- package/dist/mail-attachment.js +186 -0
- package/dist/mail-attachment.js.map +1 -0
- package/dist/mail.d.ts +1 -0
- package/dist/mail.d.ts.map +1 -1
- package/dist/mail.js +11 -9
- package/dist/mail.js.map +1 -1
- package/dist/storage-batch-stream.d.ts.map +1 -1
- package/dist/storage-batch-stream.js +24 -27
- package/dist/storage-batch-stream.js.map +1 -1
- package/dist/storage.d.ts +2 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +43 -51
- package/dist/storage.js.map +1 -1
- package/package.json +5 -1
- package/src/packages/customer-runtime/package.json +7 -2
- package/src/packages/customer-runtime/src/errors.ts +3 -0
- package/src/packages/customer-runtime/src/http.ts +63 -11
- package/src/packages/customer-runtime/src/index.ts +1 -1
- package/src/packages/customer-runtime/src/mail-attachment.ts +238 -0
- package/src/packages/customer-runtime/src/mail.ts +12 -6
- package/src/packages/customer-runtime/src/storage-batch-stream.ts +29 -25
- package/src/packages/customer-runtime/src/storage.ts +59 -48
- package/dist/mail-attachments.d.ts +0 -8
- package/dist/mail-attachments.d.ts.map +0 -1
- package/dist/mail-attachments.js +0 -32
- package/dist/mail-attachments.js.map +0 -1
- package/src/packages/customer-runtime/src/mail-attachments.ts +0 -53
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
postGatewayJson,
|
|
8
8
|
requireConfiguredUlid,
|
|
9
9
|
validateGatewayConnection,
|
|
10
|
+
throwGatewayRelayError,
|
|
10
11
|
type GatewayConnection,
|
|
11
12
|
} from "./http.js";
|
|
12
13
|
import {
|
|
@@ -33,10 +34,12 @@ export interface StorageUploadInput {
|
|
|
33
34
|
readonly bytes: Uint8Array;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
/** Server-only private files; use global fetch for gateway and signed-object transports. */
|
|
36
38
|
export function createPrivateStorageClient(
|
|
37
39
|
configuration: GatewayConnection & {
|
|
38
40
|
readonly projectId: string;
|
|
39
41
|
readonly environmentId: string;
|
|
42
|
+
/** Global fetch for short-lived signed object URLs; explicit transports remain test seams. */
|
|
40
43
|
readonly capabilityFetch: (request: Request) => Promise<Response>;
|
|
41
44
|
},
|
|
42
45
|
) {
|
|
@@ -79,18 +82,22 @@ export function createPrivateStorageClient(
|
|
|
79
82
|
if (response.status !== 200) throwStorageError(response.status, response.body, environmentId);
|
|
80
83
|
const record = response.body as Record<string, unknown>;
|
|
81
84
|
if (record?.["state"] === "completed") {
|
|
82
|
-
const completed = exactRecord(response.body, ["state", "transfer_id"]);
|
|
85
|
+
const completed = exactRecord(response.body, ["state", "transfer_id"], response.status);
|
|
83
86
|
return Object.freeze({
|
|
84
87
|
state: "completed" as const,
|
|
85
|
-
transferId: requireUlid(completed["transfer_id"]),
|
|
88
|
+
transferId: requireUlid(completed["transfer_id"], response.status),
|
|
86
89
|
});
|
|
87
90
|
}
|
|
88
|
-
const ready = exactRecord(
|
|
89
|
-
|
|
91
|
+
const ready = exactRecord(
|
|
92
|
+
response.body,
|
|
93
|
+
["state", "transfer_id", "capability"],
|
|
94
|
+
response.status,
|
|
95
|
+
);
|
|
96
|
+
if (ready["state"] !== "ready") invalidResponse(response.status);
|
|
90
97
|
return Object.freeze({
|
|
91
98
|
state: "ready" as const,
|
|
92
|
-
transferId: requireUlid(ready["transfer_id"]),
|
|
93
|
-
capability: parseCapability(ready["capability"], "PUT", input.objectKey),
|
|
99
|
+
transferId: requireUlid(ready["transfer_id"], response.status),
|
|
100
|
+
capability: parseCapability(ready["capability"], "PUT", input.objectKey, response.status),
|
|
94
101
|
});
|
|
95
102
|
}
|
|
96
103
|
|
|
@@ -107,11 +114,12 @@ export function createPrivateStorageClient(
|
|
|
107
114
|
if (response.status !== 200 && response.status !== 202) {
|
|
108
115
|
throwStorageError(response.status, response.body, environmentId);
|
|
109
116
|
}
|
|
110
|
-
const record = exactRecord(response.body, ["state", "transfer_id"]);
|
|
111
|
-
if (record["state"] !== "completed" && record["state"] !== "pending")
|
|
117
|
+
const record = exactRecord(response.body, ["state", "transfer_id"], response.status);
|
|
118
|
+
if (record["state"] !== "completed" && record["state"] !== "pending")
|
|
119
|
+
invalidResponse(response.status);
|
|
112
120
|
return Object.freeze({
|
|
113
121
|
state: record["state"],
|
|
114
|
-
transferId: requireUlid(record["transfer_id"]),
|
|
122
|
+
transferId: requireUlid(record["transfer_id"], response.status),
|
|
115
123
|
});
|
|
116
124
|
}
|
|
117
125
|
|
|
@@ -127,9 +135,9 @@ export function createPrivateStorageClient(
|
|
|
127
135
|
8 * 1024,
|
|
128
136
|
);
|
|
129
137
|
if (response.status !== 200) throwStorageError(response.status, response.body, environmentId);
|
|
130
|
-
const record = exactRecord(response.body, ["state", "capability"]);
|
|
131
|
-
if (record["state"] !== "ready") invalidResponse();
|
|
132
|
-
return parseCapability(record["capability"], "GET", objectKey);
|
|
138
|
+
const record = exactRecord(response.body, ["state", "capability"], response.status);
|
|
139
|
+
if (record["state"] !== "ready") invalidResponse(response.status);
|
|
140
|
+
return parseCapability(record["capability"], "GET", objectKey, response.status);
|
|
133
141
|
}
|
|
134
142
|
|
|
135
143
|
async function deleteObject(input: { idempotencyKey: string; objectKey: string }) {
|
|
@@ -142,11 +150,11 @@ export function createPrivateStorageClient(
|
|
|
142
150
|
input.idempotencyKey,
|
|
143
151
|
);
|
|
144
152
|
if (response.status !== 200) throwStorageError(response.status, response.body, environmentId);
|
|
145
|
-
const record = exactRecord(response.body, ["state", "deletion_id"]);
|
|
146
|
-
if (record["state"] !== "completed") invalidResponse();
|
|
153
|
+
const record = exactRecord(response.body, ["state", "deletion_id"], response.status);
|
|
154
|
+
if (record["state"] !== "completed") invalidResponse(response.status);
|
|
147
155
|
return Object.freeze({
|
|
148
156
|
state: "completed" as const,
|
|
149
|
-
deletionId: requireUlid(record["deletion_id"]),
|
|
157
|
+
deletionId: requireUlid(record["deletion_id"], response.status),
|
|
150
158
|
});
|
|
151
159
|
}
|
|
152
160
|
|
|
@@ -257,9 +265,9 @@ export function createPrivateStorageClient(
|
|
|
257
265
|
controller.signal,
|
|
258
266
|
);
|
|
259
267
|
if (response.status !== 200) throwStorageError(response.status, value, environmentId);
|
|
260
|
-
const record = exactRecord(value, ["state", "results"]);
|
|
268
|
+
const record = exactRecord(value, ["state", "results"], response.status);
|
|
261
269
|
if (!Array.isArray(record["results"]) || record["results"].length !== objects.length)
|
|
262
|
-
invalidResponse();
|
|
270
|
+
invalidResponse(response.status);
|
|
263
271
|
const results = record["results"].map((value, index): StorageDeleteResult => {
|
|
264
272
|
const candidate = value as Record<string, unknown>;
|
|
265
273
|
const item = exactRecord(
|
|
@@ -269,22 +277,23 @@ export function createPrivateStorageClient(
|
|
|
269
277
|
: candidate?.["state"] === "pending"
|
|
270
278
|
? ["object_key", "state", "retry_at"]
|
|
271
279
|
: ["object_key", "state", "code", "retryable"],
|
|
280
|
+
response.status,
|
|
272
281
|
);
|
|
273
282
|
const requested = objects[index];
|
|
274
283
|
if (requested === undefined || item["object_key"] !== requested.objectKey)
|
|
275
|
-
invalidResponse();
|
|
284
|
+
invalidResponse(response.status);
|
|
276
285
|
const objectKey = requested.objectKey;
|
|
277
286
|
if (item["state"] === "completed")
|
|
278
287
|
return Object.freeze({
|
|
279
288
|
state: "completed",
|
|
280
289
|
objectKey,
|
|
281
|
-
deletionId: requireUlid(item["deletion_id"]),
|
|
290
|
+
deletionId: requireUlid(item["deletion_id"], response.status),
|
|
282
291
|
});
|
|
283
292
|
if (item["state"] === "pending") {
|
|
284
293
|
return Object.freeze({
|
|
285
294
|
state: "pending",
|
|
286
295
|
objectKey,
|
|
287
|
-
retryAt: requireRetryAt(item["retry_at"]),
|
|
296
|
+
retryAt: requireRetryAt(item["retry_at"], response.status),
|
|
288
297
|
});
|
|
289
298
|
}
|
|
290
299
|
if (
|
|
@@ -293,7 +302,7 @@ export function createPrivateStorageClient(
|
|
|
293
302
|
typeof item["retryable"] !== "boolean" ||
|
|
294
303
|
(item["code"] === "object_not_found" && item["retryable"] !== false)
|
|
295
304
|
)
|
|
296
|
-
invalidResponse();
|
|
305
|
+
invalidResponse(response.status);
|
|
297
306
|
return Object.freeze({
|
|
298
307
|
state: "failed",
|
|
299
308
|
objectKey,
|
|
@@ -305,10 +314,10 @@ export function createPrivateStorageClient(
|
|
|
305
314
|
record["state"] !==
|
|
306
315
|
(results.every((item) => item.state === "completed") ? "completed" : "partial")
|
|
307
316
|
)
|
|
308
|
-
invalidResponse();
|
|
317
|
+
invalidResponse(response.status);
|
|
309
318
|
if (controller.signal.aborted || Date.now() >= deadline) {
|
|
310
319
|
controller.abort();
|
|
311
|
-
throw new CustomerRuntimeGatewayError("gateway_timeout",
|
|
320
|
+
throw new CustomerRuntimeGatewayError("gateway_timeout", response.status, true);
|
|
312
321
|
}
|
|
313
322
|
return Object.freeze(results);
|
|
314
323
|
} finally {
|
|
@@ -341,16 +350,18 @@ function validateBatchKeys(value: readonly string[]): readonly string[] {
|
|
|
341
350
|
return Object.freeze(Array.from(value));
|
|
342
351
|
}
|
|
343
352
|
|
|
344
|
-
function parseCapability(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
353
|
+
function parseCapability(
|
|
354
|
+
value: unknown,
|
|
355
|
+
operation: "GET" | "PUT",
|
|
356
|
+
objectKey: string,
|
|
357
|
+
status: number,
|
|
358
|
+
) {
|
|
359
|
+
const record = exactRecord(
|
|
360
|
+
value,
|
|
361
|
+
["operation", "objectKey", "url", "expiresAt", "expectedContentLength", "requiredHeaders"],
|
|
362
|
+
status,
|
|
363
|
+
);
|
|
364
|
+
const headers = exactHeaders(record["requiredHeaders"], status);
|
|
354
365
|
if (
|
|
355
366
|
record["operation"] !== operation ||
|
|
356
367
|
record["objectKey"] !== objectKey ||
|
|
@@ -363,7 +374,7 @@ function parseCapability(value: unknown, operation: "GET" | "PUT", objectKey: st
|
|
|
363
374
|
Number(record["expectedContentLength"]) < 0 ||
|
|
364
375
|
Number(record["expectedContentLength"]) > 1_073_741_824))
|
|
365
376
|
) {
|
|
366
|
-
invalidResponse();
|
|
377
|
+
invalidResponse(status);
|
|
367
378
|
}
|
|
368
379
|
return Object.freeze({
|
|
369
380
|
operation,
|
|
@@ -376,8 +387,8 @@ function parseCapability(value: unknown, operation: "GET" | "PUT", objectKey: st
|
|
|
376
387
|
});
|
|
377
388
|
}
|
|
378
389
|
|
|
379
|
-
function exactHeaders(value: unknown): Readonly<Record<string, string>> {
|
|
380
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) invalidResponse();
|
|
390
|
+
function exactHeaders(value: unknown, status: number): Readonly<Record<string, string>> {
|
|
391
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) invalidResponse(status);
|
|
381
392
|
const entries = Object.entries(value as Record<string, unknown>);
|
|
382
393
|
if (
|
|
383
394
|
entries.length > 16 ||
|
|
@@ -390,12 +401,13 @@ function exactHeaders(value: unknown): Readonly<Record<string, string>> {
|
|
|
390
401
|
/[\r\n]/u.test(header),
|
|
391
402
|
)
|
|
392
403
|
) {
|
|
393
|
-
invalidResponse();
|
|
404
|
+
invalidResponse(status);
|
|
394
405
|
}
|
|
395
406
|
return Object.freeze(Object.fromEntries(entries) as Record<string, string>);
|
|
396
407
|
}
|
|
397
408
|
|
|
398
409
|
function throwStorageError(status: number, body: unknown, environmentId: string): never {
|
|
410
|
+
throwGatewayRelayError(status, body);
|
|
399
411
|
const candidate = body as Record<string, unknown>;
|
|
400
412
|
const record = exactRecord(
|
|
401
413
|
body,
|
|
@@ -407,6 +419,7 @@ function throwStorageError(status: number, body: unknown, environmentId: string)
|
|
|
407
419
|
: typeof body === "object" && body !== null && "transfer_id" in body
|
|
408
420
|
? ["code", "transfer_id"]
|
|
409
421
|
: ["code"],
|
|
422
|
+
status,
|
|
410
423
|
);
|
|
411
424
|
const code = record["code"];
|
|
412
425
|
if (status === 401 && code === "unauthorized") {
|
|
@@ -416,7 +429,7 @@ function throwStorageError(status: number, body: unknown, environmentId: string)
|
|
|
416
429
|
throw new CustomerRuntimeGatewayError("storage_object_not_found", status, false);
|
|
417
430
|
}
|
|
418
431
|
if (status === 409 && code === "upload_expired") {
|
|
419
|
-
requireUlid(record["transfer_id"]);
|
|
432
|
+
requireUlid(record["transfer_id"], status);
|
|
420
433
|
throw new CustomerRuntimeGatewayError("storage_upload_expired", status, false);
|
|
421
434
|
}
|
|
422
435
|
if (status === 409 && code === "data_change_in_progress") {
|
|
@@ -432,11 +445,11 @@ function throwStorageError(status: number, body: unknown, environmentId: string)
|
|
|
432
445
|
"storage_binding_data_changed",
|
|
433
446
|
status,
|
|
434
447
|
false,
|
|
435
|
-
`environment
|
|
448
|
+
`the environment's data area changed while this request ran; read the current state for environment ${environmentId} and issue a new request`,
|
|
436
449
|
);
|
|
437
450
|
}
|
|
438
451
|
if (status === 409 && code === "storage_delete_pending") {
|
|
439
|
-
const retryAt = requireRetryAt(record["retry_at"]);
|
|
452
|
+
const retryAt = requireRetryAt(record["retry_at"], status);
|
|
440
453
|
throw new CustomerRuntimeGatewayError(
|
|
441
454
|
"storage_delete_pending",
|
|
442
455
|
status,
|
|
@@ -450,20 +463,17 @@ function throwStorageError(status: number, body: unknown, environmentId: string)
|
|
|
450
463
|
if (status === 413 && typeof code === "string") {
|
|
451
464
|
throw new CustomerRuntimeGatewayError("storage_quota_exceeded", status, false);
|
|
452
465
|
}
|
|
453
|
-
|
|
454
|
-
throw new CustomerRuntimeGatewayError("gateway_unavailable", status, true);
|
|
455
|
-
}
|
|
456
|
-
return invalidResponse();
|
|
466
|
+
return invalidResponse(status);
|
|
457
467
|
}
|
|
458
468
|
|
|
459
|
-
function requireRetryAt(value: unknown): string {
|
|
469
|
+
function requireRetryAt(value: unknown, status: number): string {
|
|
460
470
|
if (
|
|
461
471
|
typeof value !== "string" ||
|
|
462
472
|
!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value) ||
|
|
463
473
|
!Number.isFinite(Date.parse(value)) ||
|
|
464
474
|
new Date(value).toISOString() !== value
|
|
465
475
|
)
|
|
466
|
-
invalidResponse();
|
|
476
|
+
invalidResponse(status);
|
|
467
477
|
return value;
|
|
468
478
|
}
|
|
469
479
|
|
|
@@ -507,8 +517,9 @@ function validSignedUrl(value: string): boolean {
|
|
|
507
517
|
}
|
|
508
518
|
}
|
|
509
519
|
|
|
510
|
-
function requireUlid(value: unknown): string {
|
|
511
|
-
if (typeof value !== "string" || !/^[0-9A-HJKMNP-TV-Z]{26}$/u.test(value))
|
|
520
|
+
function requireUlid(value: unknown, status: number | null = null): string {
|
|
521
|
+
if (typeof value !== "string" || !/^[0-9A-HJKMNP-TV-Z]{26}$/u.test(value))
|
|
522
|
+
invalidResponse(status);
|
|
512
523
|
return value;
|
|
513
524
|
}
|
|
514
525
|
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type GatewayConnection } from "./http.js";
|
|
2
|
-
/** Stream owned attachments through the private mail binding using the environment's runtime key. */
|
|
3
|
-
export declare function createMailAttachmentClient(configuration: GatewayConnection & {
|
|
4
|
-
projectId: string;
|
|
5
|
-
}): {
|
|
6
|
-
download(downloadPath: string): Promise<Response>;
|
|
7
|
-
};
|
|
8
|
-
//# sourceMappingURL=mail-attachments.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-attachments.d.ts","sourceRoot":"","sources":["../src/mail-attachments.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,WAAW,CAAC;AAEnB,qGAAqG;AACrG,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,iBAAiB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE;2BAazB,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;EA8B1D"}
|
package/dist/mail-attachments.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { validateGatewayConnection, fetchWithTimeout, requireConfiguredUlid, } from "./http.js";
|
|
2
|
-
import { CustomerRuntimeGatewayError } from "./errors.js";
|
|
3
|
-
/** Stream owned attachments through the private mail binding using the environment's runtime key. */
|
|
4
|
-
export function createMailAttachmentClient(configuration) {
|
|
5
|
-
const connection = validateGatewayConnection(configuration);
|
|
6
|
-
const projectId = requireConfiguredUlid(configuration.projectId, "projectId", "OHMYHOST_PROJECT_ID");
|
|
7
|
-
const pattern = new RegExp(`^/v1/projects/${projectId}/environments/[0-7][0-9A-HJKMNP-TV-Z]{25}/mail/messages/[0-7][0-9A-HJKMNP-TV-Z]{25}/attachments/[A-Za-z0-9_-]{1,128}$`, "u");
|
|
8
|
-
return {
|
|
9
|
-
async download(downloadPath) {
|
|
10
|
-
if (!pattern.test(downloadPath))
|
|
11
|
-
throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false);
|
|
12
|
-
const response = await fetchWithTimeout(connection.fetch, new Request(new URL(downloadPath, connection.endpoint), {
|
|
13
|
-
redirect: "manual",
|
|
14
|
-
headers: { authorization: `Bearer ${connection.key}` },
|
|
15
|
-
}), connection.timeoutMilliseconds);
|
|
16
|
-
if (response.status !== 200) {
|
|
17
|
-
await response.body?.cancel();
|
|
18
|
-
throw new CustomerRuntimeGatewayError(response.status === 410
|
|
19
|
-
? "mail_content_expired"
|
|
20
|
-
: response.status === 413
|
|
21
|
-
? "mail_attachment_too_large"
|
|
22
|
-
: response.status === 404
|
|
23
|
-
? "mail_message_not_found"
|
|
24
|
-
: response.status === 401
|
|
25
|
-
? "unauthorized"
|
|
26
|
-
: "gateway_unavailable", response.status, response.status >= 500);
|
|
27
|
-
}
|
|
28
|
-
return response;
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
//# sourceMappingURL=mail-attachments.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mail-attachments.js","sourceRoot":"","sources":["../src/mail-attachments.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,qBAAqB,GAEtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC1D,qGAAqG;AACrG,MAAM,UAAU,0BAA0B,CACxC,aAAwD;IAExD,MAAM,UAAU,GAAG,yBAAyB,CAAC,aAAa,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,qBAAqB,CACrC,aAAa,CAAC,SAAS,EACvB,WAAW,EACX,qBAAqB,CACtB,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,MAAM,CACxB,iBAAiB,SAAS,uHAAuH,EACjJ,GAAG,CACJ,CAAC;IACF,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,YAAoB;YACjC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC;gBAC7B,MAAM,IAAI,2BAA2B,CAAC,yBAAyB,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAChF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACrC,UAAU,CAAC,KAAK,EAChB,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE;gBACtD,QAAQ,EAAE,QAAQ;gBAClB,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,CAAC,GAAG,EAAE,EAAE;aACvD,CAAC,EACF,UAAU,CAAC,mBAAmB,CAC/B,CAAC;YACF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;gBAC9B,MAAM,IAAI,2BAA2B,CACnC,QAAQ,CAAC,MAAM,KAAK,GAAG;oBACrB,CAAC,CAAC,sBAAsB;oBACxB,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG;wBACvB,CAAC,CAAC,2BAA2B;wBAC7B,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG;4BACvB,CAAC,CAAC,wBAAwB;4BAC1B,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG;gCACvB,CAAC,CAAC,cAAc;gCAChB,CAAC,CAAC,qBAAqB,EAC/B,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,MAAM,IAAI,GAAG,CACvB,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
validateGatewayConnection,
|
|
3
|
-
fetchWithTimeout,
|
|
4
|
-
requireConfiguredUlid,
|
|
5
|
-
type GatewayConnection,
|
|
6
|
-
} from "./http.js";
|
|
7
|
-
import { CustomerRuntimeGatewayError } from "./errors.js";
|
|
8
|
-
/** Stream owned attachments through the private mail binding using the environment's runtime key. */
|
|
9
|
-
export function createMailAttachmentClient(
|
|
10
|
-
configuration: GatewayConnection & { projectId: string },
|
|
11
|
-
) {
|
|
12
|
-
const connection = validateGatewayConnection(configuration);
|
|
13
|
-
const projectId = requireConfiguredUlid(
|
|
14
|
-
configuration.projectId,
|
|
15
|
-
"projectId",
|
|
16
|
-
"OHMYHOST_PROJECT_ID",
|
|
17
|
-
);
|
|
18
|
-
const pattern = new RegExp(
|
|
19
|
-
`^/v1/projects/${projectId}/environments/[0-7][0-9A-HJKMNP-TV-Z]{25}/mail/messages/[0-7][0-9A-HJKMNP-TV-Z]{25}/attachments/[A-Za-z0-9_-]{1,128}$`,
|
|
20
|
-
"u",
|
|
21
|
-
);
|
|
22
|
-
return {
|
|
23
|
-
async download(downloadPath: string): Promise<Response> {
|
|
24
|
-
if (!pattern.test(downloadPath))
|
|
25
|
-
throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false);
|
|
26
|
-
const response = await fetchWithTimeout(
|
|
27
|
-
connection.fetch,
|
|
28
|
-
new Request(new URL(downloadPath, connection.endpoint), {
|
|
29
|
-
redirect: "manual",
|
|
30
|
-
headers: { authorization: `Bearer ${connection.key}` },
|
|
31
|
-
}),
|
|
32
|
-
connection.timeoutMilliseconds,
|
|
33
|
-
);
|
|
34
|
-
if (response.status !== 200) {
|
|
35
|
-
await response.body?.cancel();
|
|
36
|
-
throw new CustomerRuntimeGatewayError(
|
|
37
|
-
response.status === 410
|
|
38
|
-
? "mail_content_expired"
|
|
39
|
-
: response.status === 413
|
|
40
|
-
? "mail_attachment_too_large"
|
|
41
|
-
: response.status === 404
|
|
42
|
-
? "mail_message_not_found"
|
|
43
|
-
: response.status === 401
|
|
44
|
-
? "unauthorized"
|
|
45
|
-
: "gateway_unavailable",
|
|
46
|
-
response.status,
|
|
47
|
-
response.status >= 500,
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return response;
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
}
|