@amerged/ohmyhost-runtime 0.1.22 → 0.1.24
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/database-kysely.d.ts +5 -0
- package/dist/database-kysely.d.ts.map +1 -0
- package/dist/database-kysely.js +95 -0
- package/dist/database-kysely.js.map +1 -0
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +43 -7
- package/dist/database.js.map +1 -1
- package/dist/errors.d.ts +5 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -5
- package/dist/errors.js.map +1 -1
- package/dist/http.d.ts +4 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +31 -12
- package/dist/http.js.map +1 -1
- package/dist/mail-attachments.d.ts.map +1 -1
- package/dist/mail-attachments.js +3 -4
- package/dist/mail-attachments.js.map +1 -1
- package/dist/mail.d.ts.map +1 -1
- package/dist/mail.js +16 -11
- package/dist/mail.js.map +1 -1
- package/dist/storage-batch-stream.d.ts +31 -0
- package/dist/storage-batch-stream.d.ts.map +1 -0
- package/dist/storage-batch-stream.js +282 -0
- package/dist/storage-batch-stream.js.map +1 -0
- package/dist/storage.d.ts +11 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +167 -14
- package/dist/storage.js.map +1 -1
- package/package.json +13 -1
- package/src/packages/customer-runtime/package.json +53 -0
- package/src/packages/customer-runtime/src/database-kysely.ts +127 -0
- package/src/packages/customer-runtime/{database.ts → src/database.ts} +50 -8
- package/src/packages/customer-runtime/{errors.ts → src/errors.ts} +13 -4
- package/src/packages/customer-runtime/{http.ts → src/http.ts} +43 -10
- package/src/packages/customer-runtime/{mail-attachments.ts → src/mail-attachments.ts} +12 -4
- package/src/packages/customer-runtime/{mail.ts → src/mail.ts} +28 -14
- package/src/packages/customer-runtime/src/storage-batch-stream.ts +318 -0
- package/src/packages/customer-runtime/{storage.ts → src/storage.ts} +236 -13
- /package/src/packages/customer-runtime/{index.ts → src/index.ts} +0 -0
- /package/src/packages/customer-runtime/{mail-webhook.ts → src/mail-webhook.ts} +0 -0
package/dist/mail.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mail.js","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EACL,WAAW,EACX,eAAe,EACf,eAAe,EACf,yBAAyB,GAE1B,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"mail.js","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type StorageReadResult = Readonly<{
|
|
2
|
+
state: "not_found";
|
|
3
|
+
objectKey: string;
|
|
4
|
+
}> | Readonly<{
|
|
5
|
+
state: "found";
|
|
6
|
+
objectKey: string;
|
|
7
|
+
contentType: string;
|
|
8
|
+
contentLength: number;
|
|
9
|
+
etag: string;
|
|
10
|
+
body: ReadableStream<Uint8Array>;
|
|
11
|
+
}>;
|
|
12
|
+
export type StorageDeleteResult = Readonly<{
|
|
13
|
+
state: "completed";
|
|
14
|
+
objectKey: string;
|
|
15
|
+
deletionId: string;
|
|
16
|
+
}> | Readonly<{
|
|
17
|
+
state: "pending";
|
|
18
|
+
objectKey: string;
|
|
19
|
+
retryAt: string;
|
|
20
|
+
}> | Readonly<{
|
|
21
|
+
state: "failed";
|
|
22
|
+
objectKey: string;
|
|
23
|
+
code: "object_not_found" | "storage_gateway_unavailable";
|
|
24
|
+
retryable: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
export declare const STORAGE_BATCH_CONTENT_TYPE = "application/vnd.ohmyhost.storage-batch.v1";
|
|
27
|
+
/** Yields one bounded body at a time; completion requires the final frame and exact EOF. */
|
|
28
|
+
export declare function decodeStorageBatch(response: Response, keys: readonly string[], timeoutMilliseconds: number): AsyncIterable<StorageReadResult>;
|
|
29
|
+
/** Control JSON has its own four-MiB budget and never buffers object payloads. */
|
|
30
|
+
export declare function readStorageBatchJson(response: Response, timeoutMilliseconds: number, signal?: AbortSignal): Promise<unknown>;
|
|
31
|
+
//# sourceMappingURL=storage-batch-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-batch-stream.d.ts","sourceRoot":"","sources":["../src/storage-batch-stream.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,iBAAiB,GACzB,QAAQ,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GACnD,QAAQ,CAAC;IACP,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;CAClC,CAAC,CAAC;AACP,MAAM,MAAM,mBAAmB,GAC3B,QAAQ,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GACvE,QAAQ,CAAC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAClE,QAAQ,CAAC;IACP,KAAK,EAAE,QAAQ,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,kBAAkB,GAAG,6BAA6B,CAAC;IACzD,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC,CAAC;AACP,eAAO,MAAM,0BAA0B,8CAA8C,CAAC;AAyCtF,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,mBAAmB,EAAE,MAAM,GAC1B,aAAa,CAAC,iBAAiB,CAAC,CAyMlC;AAED,kFAAkF;AAClF,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,QAAQ,EAClB,mBAAmB,EAAE,MAAM,EAC3B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,OAAO,CAAC,CAyClB"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { CustomerRuntimeGatewayError } from "./errors.js";
|
|
2
|
+
import { exactRecord, invalidResponse } from "./http.js";
|
|
3
|
+
export const STORAGE_BATCH_CONTENT_TYPE = "application/vnd.ohmyhost.storage-batch.v1";
|
|
4
|
+
const MAX_CONTROL_BYTES = 4 * 1024 * 1024;
|
|
5
|
+
const MAX_HEADER_BYTES = 2048;
|
|
6
|
+
/** Pending reads are bounded; errors never expose provider text. */
|
|
7
|
+
async function timedRead(reader, timeoutMilliseconds, signal) {
|
|
8
|
+
let timer;
|
|
9
|
+
let abortListener;
|
|
10
|
+
try {
|
|
11
|
+
if (signal?.aborted) {
|
|
12
|
+
void reader.cancel().catch(() => undefined);
|
|
13
|
+
throw new CustomerRuntimeGatewayError("gateway_timeout", null, true);
|
|
14
|
+
}
|
|
15
|
+
return await Promise.race([
|
|
16
|
+
reader.read(),
|
|
17
|
+
new Promise((_resolve, reject) => {
|
|
18
|
+
const abort = () => {
|
|
19
|
+
reject(new CustomerRuntimeGatewayError("gateway_timeout", null, true));
|
|
20
|
+
void reader.cancel().catch(() => undefined);
|
|
21
|
+
};
|
|
22
|
+
timer = setTimeout(abort, timeoutMilliseconds);
|
|
23
|
+
if (signal !== undefined) {
|
|
24
|
+
abortListener = abort;
|
|
25
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
26
|
+
}
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof CustomerRuntimeGatewayError)
|
|
32
|
+
throw error;
|
|
33
|
+
if (signal?.aborted)
|
|
34
|
+
throw new CustomerRuntimeGatewayError("gateway_timeout", null, true);
|
|
35
|
+
throw new CustomerRuntimeGatewayError("gateway_unavailable", null, true);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
if (abortListener !== undefined)
|
|
40
|
+
signal?.removeEventListener("abort", abortListener);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Yields one bounded body at a time; completion requires the final frame and exact EOF. */
|
|
44
|
+
export function decodeStorageBatch(response, keys, timeoutMilliseconds) {
|
|
45
|
+
if (response.headers.get("content-type") !== STORAGE_BATCH_CONTENT_TYPE ||
|
|
46
|
+
response.body === null) {
|
|
47
|
+
void response.body?.cancel().catch(() => undefined);
|
|
48
|
+
invalidResponse();
|
|
49
|
+
}
|
|
50
|
+
const source = response.body.getReader();
|
|
51
|
+
let buffer = new Uint8Array();
|
|
52
|
+
let offset = 0;
|
|
53
|
+
let controlBytes = 0;
|
|
54
|
+
let started = false;
|
|
55
|
+
let finished = false;
|
|
56
|
+
let cancelled = false;
|
|
57
|
+
let released = false;
|
|
58
|
+
let activeBody;
|
|
59
|
+
function cancellationError() {
|
|
60
|
+
return new CustomerRuntimeGatewayError("gateway_request_invalid", null, false, "this storage read was cancelled; start another readMany() to read more objects");
|
|
61
|
+
}
|
|
62
|
+
function closeSource() {
|
|
63
|
+
if (released)
|
|
64
|
+
return;
|
|
65
|
+
released = true;
|
|
66
|
+
if (!finished)
|
|
67
|
+
void source.cancel().catch(() => undefined);
|
|
68
|
+
source.releaseLock();
|
|
69
|
+
}
|
|
70
|
+
async function chunk(maximum) {
|
|
71
|
+
if (cancelled)
|
|
72
|
+
throw cancellationError();
|
|
73
|
+
while (offset === buffer.byteLength) {
|
|
74
|
+
const next = await timedRead(source, timeoutMilliseconds);
|
|
75
|
+
if (cancelled)
|
|
76
|
+
throw cancellationError();
|
|
77
|
+
if (next.done || !(next.value instanceof Uint8Array))
|
|
78
|
+
invalidResponse();
|
|
79
|
+
buffer = next.value;
|
|
80
|
+
offset = 0;
|
|
81
|
+
}
|
|
82
|
+
const length = Math.min(maximum, buffer.byteLength - offset);
|
|
83
|
+
const bytes = buffer.subarray(offset, offset + length);
|
|
84
|
+
offset += length;
|
|
85
|
+
return bytes;
|
|
86
|
+
}
|
|
87
|
+
async function exactBytes(length) {
|
|
88
|
+
const bytes = new Uint8Array(length);
|
|
89
|
+
let written = 0;
|
|
90
|
+
while (written < length) {
|
|
91
|
+
const next = await chunk(length - written);
|
|
92
|
+
bytes.set(next, written);
|
|
93
|
+
written += next.byteLength;
|
|
94
|
+
}
|
|
95
|
+
return bytes;
|
|
96
|
+
}
|
|
97
|
+
async function header() {
|
|
98
|
+
const length = new DataView((await exactBytes(4)).buffer).getUint32(0);
|
|
99
|
+
controlBytes += 4 + length;
|
|
100
|
+
if (length < 1 || length > MAX_HEADER_BYTES || controlBytes > MAX_CONTROL_BYTES)
|
|
101
|
+
invalidResponse();
|
|
102
|
+
const bytes = await exactBytes(length);
|
|
103
|
+
try {
|
|
104
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return invalidResponse();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const iterator = iterate();
|
|
111
|
+
// Returning an unstarted async generator skips its finally block.
|
|
112
|
+
return {
|
|
113
|
+
[Symbol.asyncIterator]() {
|
|
114
|
+
return {
|
|
115
|
+
next: () => (cancelled ? Promise.reject(cancellationError()) : iterator.next()),
|
|
116
|
+
async return() {
|
|
117
|
+
cancelled = true;
|
|
118
|
+
activeBody?.error(cancellationError());
|
|
119
|
+
activeBody = undefined;
|
|
120
|
+
closeSource();
|
|
121
|
+
if (!started)
|
|
122
|
+
return { done: true, value: undefined };
|
|
123
|
+
return iterator.return(undefined);
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
async function* iterate() {
|
|
129
|
+
started = true;
|
|
130
|
+
let currentConsumed = true;
|
|
131
|
+
let bodyFailure;
|
|
132
|
+
try {
|
|
133
|
+
for (let index = 0; index < keys.length; index++) {
|
|
134
|
+
const objectKey = keys[index];
|
|
135
|
+
if (objectKey === undefined)
|
|
136
|
+
invalidResponse();
|
|
137
|
+
if (!currentConsumed)
|
|
138
|
+
throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false, "consume or cancel each object's body before reading the next object");
|
|
139
|
+
if (bodyFailure !== undefined)
|
|
140
|
+
throw bodyFailure;
|
|
141
|
+
const value = await header();
|
|
142
|
+
const candidate = value;
|
|
143
|
+
const record = exactRecord(value, candidate?.["state"] === "found"
|
|
144
|
+
? ["index", "objectKey", "state", "contentType", "contentLength", "etag"]
|
|
145
|
+
: ["index", "objectKey", "state"]);
|
|
146
|
+
if (record["index"] !== index || record["objectKey"] !== keys[index])
|
|
147
|
+
invalidResponse();
|
|
148
|
+
if (record["state"] === "not_found") {
|
|
149
|
+
yield Object.freeze({ state: "not_found", objectKey });
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (record["state"] !== "found" ||
|
|
153
|
+
typeof record["contentType"] !== "string" ||
|
|
154
|
+
!/^[a-z0-9][a-z0-9!#$&^_.+-]{0,63}\/[a-z0-9][a-z0-9!#$&^_.+-]{0,63}$/u.test(record["contentType"]) ||
|
|
155
|
+
!Number.isSafeInteger(record["contentLength"]) ||
|
|
156
|
+
Number(record["contentLength"]) < 0 ||
|
|
157
|
+
Number(record["contentLength"]) > 1_073_741_824 ||
|
|
158
|
+
typeof record["etag"] !== "string" ||
|
|
159
|
+
!/^[0-9a-f]{32}(?:-[1-9][0-9]{0,4})?$/u.test(record["etag"]))
|
|
160
|
+
invalidResponse();
|
|
161
|
+
let remaining = Number(record["contentLength"]);
|
|
162
|
+
currentConsumed = remaining === 0;
|
|
163
|
+
const body = new ReadableStream({
|
|
164
|
+
start(controller) {
|
|
165
|
+
if (remaining === 0)
|
|
166
|
+
controller.close();
|
|
167
|
+
else
|
|
168
|
+
activeBody = controller;
|
|
169
|
+
},
|
|
170
|
+
async pull(controller) {
|
|
171
|
+
try {
|
|
172
|
+
const bytes = await chunk(remaining);
|
|
173
|
+
remaining -= bytes.byteLength;
|
|
174
|
+
controller.enqueue(bytes);
|
|
175
|
+
if (remaining === 0) {
|
|
176
|
+
currentConsumed = true;
|
|
177
|
+
activeBody = undefined;
|
|
178
|
+
controller.close();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
bodyFailure = error;
|
|
183
|
+
currentConsumed = true;
|
|
184
|
+
activeBody = undefined;
|
|
185
|
+
controller.error(error);
|
|
186
|
+
closeSource();
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
async cancel() {
|
|
190
|
+
activeBody = undefined;
|
|
191
|
+
try {
|
|
192
|
+
while (remaining > 0)
|
|
193
|
+
remaining -= (await chunk(remaining)).byteLength;
|
|
194
|
+
currentConsumed = true;
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
bodyFailure = error;
|
|
198
|
+
currentConsumed = true;
|
|
199
|
+
closeSource();
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
}, { highWaterMark: 0 });
|
|
204
|
+
yield Object.freeze({
|
|
205
|
+
state: "found",
|
|
206
|
+
objectKey,
|
|
207
|
+
contentType: record["contentType"],
|
|
208
|
+
contentLength: Number(record["contentLength"]),
|
|
209
|
+
etag: record["etag"],
|
|
210
|
+
body,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
if (!currentConsumed)
|
|
214
|
+
throw new CustomerRuntimeGatewayError("gateway_request_invalid", null, false, "consume or cancel the last object's body before completing the read");
|
|
215
|
+
if (bodyFailure !== undefined)
|
|
216
|
+
throw bodyFailure;
|
|
217
|
+
const terminal = exactRecord(await header(), ["state", "count"]);
|
|
218
|
+
if (terminal["state"] !== "completed" ||
|
|
219
|
+
terminal["count"] !== keys.length ||
|
|
220
|
+
offset !== buffer.byteLength)
|
|
221
|
+
invalidResponse();
|
|
222
|
+
const end = await timedRead(source, timeoutMilliseconds);
|
|
223
|
+
if (!end.done)
|
|
224
|
+
invalidResponse();
|
|
225
|
+
if (cancelled)
|
|
226
|
+
throw cancellationError();
|
|
227
|
+
finished = true;
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
activeBody?.error(bodyFailure ?? cancellationError());
|
|
231
|
+
activeBody = undefined;
|
|
232
|
+
closeSource();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/** Control JSON has its own four-MiB budget and never buffers object payloads. */
|
|
237
|
+
export async function readStorageBatchJson(response, timeoutMilliseconds, signal) {
|
|
238
|
+
const declared = response.headers.get("content-length");
|
|
239
|
+
if (response.headers.get("content-type")?.split(";", 1)[0]?.trim() !== "application/json" ||
|
|
240
|
+
(declared !== null && (!/^\d+$/u.test(declared) || Number(declared) > MAX_CONTROL_BYTES)) ||
|
|
241
|
+
response.body === null) {
|
|
242
|
+
void response.body?.cancel().catch(() => undefined);
|
|
243
|
+
invalidResponse();
|
|
244
|
+
}
|
|
245
|
+
const reader = response.body.getReader();
|
|
246
|
+
const chunks = [];
|
|
247
|
+
let length = 0;
|
|
248
|
+
let finished = false;
|
|
249
|
+
try {
|
|
250
|
+
for (;;) {
|
|
251
|
+
const next = await timedRead(reader, timeoutMilliseconds, signal);
|
|
252
|
+
if (next.done) {
|
|
253
|
+
finished = true;
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
if (!(next.value instanceof Uint8Array))
|
|
257
|
+
invalidResponse();
|
|
258
|
+
length += next.value.byteLength;
|
|
259
|
+
if (length > MAX_CONTROL_BYTES)
|
|
260
|
+
invalidResponse();
|
|
261
|
+
chunks.push(next.value);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
if (!finished)
|
|
266
|
+
void reader.cancel().catch(() => undefined);
|
|
267
|
+
reader.releaseLock();
|
|
268
|
+
}
|
|
269
|
+
const bytes = new Uint8Array(length);
|
|
270
|
+
let offset = 0;
|
|
271
|
+
for (const chunk of chunks) {
|
|
272
|
+
bytes.set(chunk, offset);
|
|
273
|
+
offset += chunk.byteLength;
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
return invalidResponse();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=storage-batch-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-batch-stream.js","sourceRoot":"","sources":["../src/storage-batch-stream.ts"],"names":[],"mappings":"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"}
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type GatewayConnection } from "./http.js";
|
|
2
|
+
import { type StorageReadResult, type StorageDeleteResult } from "./storage-batch-stream.js";
|
|
3
|
+
export type { StorageReadResult, StorageDeleteResult } from "./storage-batch-stream.js";
|
|
2
4
|
export interface StorageCapability {
|
|
3
5
|
readonly operation: "GET" | "PUT";
|
|
4
6
|
readonly objectKey: string;
|
|
@@ -58,5 +60,14 @@ export declare function createPrivateStorageClient(configuration: GatewayConnect
|
|
|
58
60
|
state: "completed" | "pending";
|
|
59
61
|
transferId: string;
|
|
60
62
|
}>>;
|
|
63
|
+
readMany: (input: {
|
|
64
|
+
readonly objectKeys: readonly string[];
|
|
65
|
+
}) => Promise<AsyncIterable<StorageReadResult>>;
|
|
66
|
+
deleteMany: (input: {
|
|
67
|
+
readonly objects: readonly {
|
|
68
|
+
readonly objectKey: string;
|
|
69
|
+
readonly idempotencyKey: string;
|
|
70
|
+
}[];
|
|
71
|
+
}) => Promise<readonly StorageDeleteResult[]>;
|
|
61
72
|
}>;
|
|
62
73
|
//# sourceMappingURL=storage.d.ts.map
|
package/dist/storage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,EAQL,KAAK,iBAAiB,EACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAExF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,iBAAiB,GAAG;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnE;2BAoBQ,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC,GAAG;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;iCAoC5B,MAAM;;;;kCAqBL,MAAM;;;;;;;;0BAiBd;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;;;;oBAkBnD,kBAAkB;;;;sBAkDhB;QAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;KACxC,KAAG,OAAO,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;wBAiBZ;QAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS;YAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAC9F,KAAG,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;GAuG5C"}
|
package/dist/storage.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { CustomerRuntimeGatewayError } from "./errors.js";
|
|
2
|
-
import { exactRecord, fetchWithTimeout, invalidResponse, postGatewayJson, validateGatewayConnection, } from "./http.js";
|
|
2
|
+
import { configurationInvalid, exactRecord, fetchWithTimeout, invalidResponse, postGatewayJson, requireConfiguredUlid, validateGatewayConnection, } from "./http.js";
|
|
3
|
+
import { decodeStorageBatch, readStorageBatchJson, } from "./storage-batch-stream.js";
|
|
3
4
|
export function createPrivateStorageClient(configuration) {
|
|
4
5
|
const connection = validateGatewayConnection(configuration);
|
|
5
6
|
if (typeof configuration.capabilityFetch !== "function") {
|
|
6
|
-
|
|
7
|
+
configurationInvalid("capabilityFetch is not a function; pass (request) => fetch(request)");
|
|
7
8
|
}
|
|
8
9
|
const capabilityFetch = configuration.capabilityFetch;
|
|
9
|
-
const projectId =
|
|
10
|
-
const environmentId =
|
|
10
|
+
const projectId = requireConfiguredUlid(configuration.projectId, "projectId", "OHMYHOST_PROJECT_ID");
|
|
11
|
+
const environmentId = requireConfiguredUlid(configuration.environmentId, "environmentId", "OHMYHOST_ENVIRONMENT_ID");
|
|
11
12
|
const authenticatedBody = Object.freeze({ projectId, environmentId });
|
|
12
13
|
async function reserveUpload(input) {
|
|
13
14
|
validateStorageMutation(input.idempotencyKey, input.objectKey);
|
|
@@ -19,7 +20,7 @@ export function createPrivateStorageClient(configuration) {
|
|
|
19
20
|
}
|
|
20
21
|
const response = await postGatewayJson(connection, "/v1/uploads", { ...authenticatedBody, ...input }, 8 * 1024, input.idempotencyKey);
|
|
21
22
|
if (response.status !== 200)
|
|
22
|
-
throwStorageError(response.status, response.body);
|
|
23
|
+
throwStorageError(response.status, response.body, environmentId);
|
|
23
24
|
const record = response.body;
|
|
24
25
|
if (record?.["state"] === "completed") {
|
|
25
26
|
const completed = exactRecord(response.body, ["state", "transfer_id"]);
|
|
@@ -43,7 +44,7 @@ export function createPrivateStorageClient(configuration) {
|
|
|
43
44
|
transferId: requireUlid(transferId),
|
|
44
45
|
}, 8 * 1024);
|
|
45
46
|
if (response.status !== 200 && response.status !== 202) {
|
|
46
|
-
throwStorageError(response.status, response.body);
|
|
47
|
+
throwStorageError(response.status, response.body, environmentId);
|
|
47
48
|
}
|
|
48
49
|
const record = exactRecord(response.body, ["state", "transfer_id"]);
|
|
49
50
|
if (record["state"] !== "completed" && record["state"] !== "pending")
|
|
@@ -60,7 +61,7 @@ export function createPrivateStorageClient(configuration) {
|
|
|
60
61
|
objectKey,
|
|
61
62
|
}, 8 * 1024);
|
|
62
63
|
if (response.status !== 200)
|
|
63
|
-
throwStorageError(response.status, response.body);
|
|
64
|
+
throwStorageError(response.status, response.body, environmentId);
|
|
64
65
|
const record = exactRecord(response.body, ["state", "capability"]);
|
|
65
66
|
if (record["state"] !== "ready")
|
|
66
67
|
invalidResponse();
|
|
@@ -70,7 +71,7 @@ export function createPrivateStorageClient(configuration) {
|
|
|
70
71
|
validateStorageMutation(input.idempotencyKey, input.objectKey);
|
|
71
72
|
const response = await postGatewayJson(connection, "/v1/deletions", { ...authenticatedBody, objectKey: input.objectKey }, 8 * 1024, input.idempotencyKey);
|
|
72
73
|
if (response.status !== 200)
|
|
73
|
-
throwStorageError(response.status, response.body);
|
|
74
|
+
throwStorageError(response.status, response.body, environmentId);
|
|
74
75
|
const record = exactRecord(response.body, ["state", "deletion_id"]);
|
|
75
76
|
if (record["state"] !== "completed")
|
|
76
77
|
invalidResponse();
|
|
@@ -94,12 +95,140 @@ export function createPrivateStorageClient(configuration) {
|
|
|
94
95
|
headers: reservation.capability.requiredHeaders,
|
|
95
96
|
body: bytes,
|
|
96
97
|
}), connection.timeoutMilliseconds);
|
|
98
|
+
// The create-only PUT answers 412 when an earlier attempt already stored these bytes under
|
|
99
|
+
// this reservation; recording them is the retry's whole remaining work.
|
|
100
|
+
if (uploaded.status === 412)
|
|
101
|
+
return completeUpload(reservation.transferId);
|
|
97
102
|
if (uploaded.status < 200 || uploaded.status >= 300) {
|
|
98
|
-
throw new CustomerRuntimeGatewayError("storage_upload_rejected", uploaded.status,
|
|
103
|
+
throw new CustomerRuntimeGatewayError("storage_upload_rejected", uploaded.status, uploaded.status >= 500 || uploaded.status === 429, `the signed upload answered ${String(uploaded.status)}. For 5xx or 429, repeat upload() with the same idempotencyKey and objectKey.`);
|
|
99
104
|
}
|
|
100
105
|
return completeUpload(reservation.transferId);
|
|
101
106
|
}
|
|
102
|
-
|
|
107
|
+
async function batchRequest(path, body, signal) {
|
|
108
|
+
const serialized = JSON.stringify({ ...authenticatedBody, ...body });
|
|
109
|
+
if (new TextEncoder().encode(serialized).byteLength > 4 * 1024 * 1024)
|
|
110
|
+
invalidRequest();
|
|
111
|
+
return fetchWithTimeout(connection.fetch, new Request(new URL(path, connection.endpoint), {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: { authorization: `Bearer ${connection.key}`, "content-type": "application/json" },
|
|
114
|
+
body: serialized,
|
|
115
|
+
...(signal === undefined ? {} : { signal }),
|
|
116
|
+
}), connection.timeoutMilliseconds);
|
|
117
|
+
}
|
|
118
|
+
async function readMany(input) {
|
|
119
|
+
if (typeof input !== "object" ||
|
|
120
|
+
input === null ||
|
|
121
|
+
Object.keys(input).join(",") !== "objectKeys")
|
|
122
|
+
invalidRequest();
|
|
123
|
+
const objectKeys = validateBatchKeys(input.objectKeys);
|
|
124
|
+
const response = await batchRequest("/v1/downloads/batch", { objectKeys });
|
|
125
|
+
if (response.status !== 200)
|
|
126
|
+
throwStorageError(response.status, await readStorageBatchJson(response, connection.timeoutMilliseconds), environmentId);
|
|
127
|
+
return decodeStorageBatch(response, objectKeys, connection.timeoutMilliseconds);
|
|
128
|
+
}
|
|
129
|
+
async function deleteMany(input) {
|
|
130
|
+
if (typeof input !== "object" ||
|
|
131
|
+
input === null ||
|
|
132
|
+
Object.keys(input).join(",") !== "objects" ||
|
|
133
|
+
!Array.isArray(input.objects) ||
|
|
134
|
+
input.objects.length === 0 ||
|
|
135
|
+
input.objects.length > 4000)
|
|
136
|
+
invalidRequest();
|
|
137
|
+
const objects = input.objects.map((item) => {
|
|
138
|
+
if (typeof item !== "object" ||
|
|
139
|
+
item === null ||
|
|
140
|
+
Object.keys(item).sort().join(",") !== "idempotencyKey,objectKey" ||
|
|
141
|
+
typeof item.objectKey !== "string" ||
|
|
142
|
+
typeof item.idempotencyKey !== "string")
|
|
143
|
+
invalidRequest();
|
|
144
|
+
validateStorageMutation(item.idempotencyKey, item.objectKey);
|
|
145
|
+
return { objectKey: item.objectKey, idempotencyKey: item.idempotencyKey };
|
|
146
|
+
});
|
|
147
|
+
validateBatchKeys(objects.map((item) => item.objectKey));
|
|
148
|
+
if (new Set(objects.map((item) => item.idempotencyKey)).size !== objects.length)
|
|
149
|
+
invalidRequest();
|
|
150
|
+
const controller = new AbortController();
|
|
151
|
+
const deadline = Date.now() + connection.timeoutMilliseconds;
|
|
152
|
+
const timer = setTimeout(() => controller.abort(), connection.timeoutMilliseconds);
|
|
153
|
+
try {
|
|
154
|
+
const response = await batchRequest("/v1/deletions/batch", { objects }, controller.signal);
|
|
155
|
+
const value = await readStorageBatchJson(response, connection.timeoutMilliseconds, controller.signal);
|
|
156
|
+
if (response.status !== 200)
|
|
157
|
+
throwStorageError(response.status, value, environmentId);
|
|
158
|
+
const record = exactRecord(value, ["state", "results"]);
|
|
159
|
+
if (!Array.isArray(record["results"]) || record["results"].length !== objects.length)
|
|
160
|
+
invalidResponse();
|
|
161
|
+
const results = record["results"].map((value, index) => {
|
|
162
|
+
const candidate = value;
|
|
163
|
+
const item = exactRecord(value, candidate?.["state"] === "completed"
|
|
164
|
+
? ["object_key", "state", "deletion_id"]
|
|
165
|
+
: candidate?.["state"] === "pending"
|
|
166
|
+
? ["object_key", "state", "retry_at"]
|
|
167
|
+
: ["object_key", "state", "code", "retryable"]);
|
|
168
|
+
const requested = objects[index];
|
|
169
|
+
if (requested === undefined || item["object_key"] !== requested.objectKey)
|
|
170
|
+
invalidResponse();
|
|
171
|
+
const objectKey = requested.objectKey;
|
|
172
|
+
if (item["state"] === "completed")
|
|
173
|
+
return Object.freeze({
|
|
174
|
+
state: "completed",
|
|
175
|
+
objectKey,
|
|
176
|
+
deletionId: requireUlid(item["deletion_id"]),
|
|
177
|
+
});
|
|
178
|
+
if (item["state"] === "pending") {
|
|
179
|
+
return Object.freeze({
|
|
180
|
+
state: "pending",
|
|
181
|
+
objectKey,
|
|
182
|
+
retryAt: requireRetryAt(item["retry_at"]),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (item["state"] !== "failed" ||
|
|
186
|
+
(item["code"] !== "object_not_found" && item["code"] !== "storage_gateway_unavailable") ||
|
|
187
|
+
typeof item["retryable"] !== "boolean" ||
|
|
188
|
+
(item["code"] === "object_not_found" && item["retryable"] !== false))
|
|
189
|
+
invalidResponse();
|
|
190
|
+
return Object.freeze({
|
|
191
|
+
state: "failed",
|
|
192
|
+
objectKey,
|
|
193
|
+
code: item["code"],
|
|
194
|
+
retryable: item["retryable"],
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
if (record["state"] !==
|
|
198
|
+
(results.every((item) => item.state === "completed") ? "completed" : "partial"))
|
|
199
|
+
invalidResponse();
|
|
200
|
+
if (controller.signal.aborted || Date.now() >= deadline) {
|
|
201
|
+
controller.abort();
|
|
202
|
+
throw new CustomerRuntimeGatewayError("gateway_timeout", null, true);
|
|
203
|
+
}
|
|
204
|
+
return Object.freeze(results);
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
clearTimeout(timer);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return Object.freeze({
|
|
211
|
+
reserveUpload,
|
|
212
|
+
completeUpload,
|
|
213
|
+
createSignedRead,
|
|
214
|
+
deleteObject,
|
|
215
|
+
upload,
|
|
216
|
+
readMany,
|
|
217
|
+
deleteMany,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function validateBatchKeys(value) {
|
|
221
|
+
if (!Array.isArray(value) ||
|
|
222
|
+
value.length === 0 ||
|
|
223
|
+
value.length > 4000 ||
|
|
224
|
+
new Set(value).size !== value.length)
|
|
225
|
+
invalidRequest();
|
|
226
|
+
for (const key of value) {
|
|
227
|
+
if (typeof key !== "string")
|
|
228
|
+
invalidRequest();
|
|
229
|
+
validateObjectKey(key);
|
|
230
|
+
}
|
|
231
|
+
return Object.freeze(Array.from(value));
|
|
103
232
|
}
|
|
104
233
|
function parseCapability(value, operation, objectKey) {
|
|
105
234
|
const record = exactRecord(value, [
|
|
@@ -146,10 +275,16 @@ function exactHeaders(value) {
|
|
|
146
275
|
}
|
|
147
276
|
return Object.freeze(Object.fromEntries(entries));
|
|
148
277
|
}
|
|
149
|
-
function throwStorageError(status, body) {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
278
|
+
function throwStorageError(status, body, environmentId) {
|
|
279
|
+
const candidate = body;
|
|
280
|
+
const record = exactRecord(body, candidate?.["code"] === "storage_delete_pending"
|
|
281
|
+
? ["code", "retry_at"]
|
|
282
|
+
: candidate?.["code"] === "data_change_in_progress" ||
|
|
283
|
+
candidate?.["code"] === "storage_binding_data_changed"
|
|
284
|
+
? ["code"]
|
|
285
|
+
: typeof body === "object" && body !== null && "transfer_id" in body
|
|
286
|
+
? ["code", "transfer_id"]
|
|
287
|
+
: ["code"]);
|
|
153
288
|
const code = record["code"];
|
|
154
289
|
if (status === 401 && code === "unauthorized") {
|
|
155
290
|
throw new CustomerRuntimeGatewayError("unauthorized", status, false);
|
|
@@ -161,6 +296,16 @@ function throwStorageError(status, body) {
|
|
|
161
296
|
requireUlid(record["transfer_id"]);
|
|
162
297
|
throw new CustomerRuntimeGatewayError("storage_upload_expired", status, false);
|
|
163
298
|
}
|
|
299
|
+
if (status === 409 && code === "data_change_in_progress") {
|
|
300
|
+
throw new CustomerRuntimeGatewayError("data_change_in_progress", status, true, "a data change is running for this project; wait for that existing operation to finish, then repeat the same storage request with the same idempotency keys");
|
|
301
|
+
}
|
|
302
|
+
if (status === 409 && code === "storage_binding_data_changed") {
|
|
303
|
+
throw new CustomerRuntimeGatewayError("storage_binding_data_changed", status, false, `environment ${environmentId} now uses a different data area; create a new deployment plan and redeploy that environment. Repeating this request will not update this deployment's binding`);
|
|
304
|
+
}
|
|
305
|
+
if (status === 409 && code === "storage_delete_pending") {
|
|
306
|
+
const retryAt = requireRetryAt(record["retry_at"]);
|
|
307
|
+
throw new CustomerRuntimeGatewayError("storage_delete_pending", status, true, `a previously accepted upload or deletion is still settling; wait until ${retryAt}, then repeat deleteObject() with the same objectKey and idempotencyKey`);
|
|
308
|
+
}
|
|
164
309
|
if (status === 409 && typeof code === "string") {
|
|
165
310
|
throw new CustomerRuntimeGatewayError("storage_conflict", status, false);
|
|
166
311
|
}
|
|
@@ -172,6 +317,14 @@ function throwStorageError(status, body) {
|
|
|
172
317
|
}
|
|
173
318
|
return invalidResponse();
|
|
174
319
|
}
|
|
320
|
+
function requireRetryAt(value) {
|
|
321
|
+
if (typeof value !== "string" ||
|
|
322
|
+
!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value) ||
|
|
323
|
+
!Number.isFinite(Date.parse(value)) ||
|
|
324
|
+
new Date(value).toISOString() !== value)
|
|
325
|
+
invalidResponse();
|
|
326
|
+
return value;
|
|
327
|
+
}
|
|
175
328
|
function validateStorageMutation(idempotencyKey, objectKey) {
|
|
176
329
|
if (!/^[A-Za-z0-9._:-]{1,128}$/u.test(idempotencyKey))
|
|
177
330
|
invalidRequest();
|