@renderinc/sdk 0.2.1 → 0.4.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/README.md +159 -42
- package/dist/experimental/experimental.d.ts +2 -2
- package/dist/experimental/experimental.d.ts.map +1 -1
- package/dist/experimental/experimental.js +4 -4
- package/dist/experimental/object/api.d.ts +2 -1
- package/dist/experimental/object/api.d.ts.map +1 -1
- package/dist/experimental/object/api.js +20 -3
- package/dist/experimental/object/client.d.ts +11 -5
- package/dist/experimental/object/client.d.ts.map +1 -1
- package/dist/experimental/object/client.js +78 -13
- package/dist/experimental/object/e2e-helpers.d.ts +3 -0
- package/dist/experimental/object/e2e-helpers.d.ts.map +1 -0
- package/dist/experimental/object/e2e-helpers.js +70 -0
- package/dist/experimental/object/index.d.ts +1 -1
- package/dist/experimental/object/index.d.ts.map +1 -1
- package/dist/experimental/object/types.d.ts +18 -0
- package/dist/experimental/object/types.d.ts.map +1 -1
- package/dist/generated/schema.d.ts +167 -28
- package/dist/generated/schema.d.ts.map +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +3 -1
- package/dist/workflows/client/client.d.ts +7 -3
- package/dist/workflows/client/client.d.ts.map +1 -1
- package/dist/workflows/client/client.js +96 -15
- package/dist/workflows/client/index.d.ts +2 -0
- package/dist/workflows/client/index.d.ts.map +1 -1
- package/dist/workflows/client/index.js +5 -1
- package/dist/workflows/client/sse.d.ts +0 -7
- package/dist/workflows/client/sse.d.ts.map +1 -1
- package/dist/workflows/client/sse.js +1 -71
- package/dist/workflows/client/task-run-promise.d.ts +12 -0
- package/dist/workflows/client/task-run-promise.d.ts.map +1 -0
- package/dist/workflows/client/task-run-promise.js +22 -0
- package/dist/workflows/client/task-run-result.d.ts +10 -0
- package/dist/workflows/client/task-run-result.d.ts.map +1 -0
- package/dist/workflows/client/task-run-result.js +18 -0
- package/dist/workflows/client/types.d.ts +2 -0
- package/dist/workflows/client/types.d.ts.map +1 -1
- package/dist/workflows/uds.d.ts +1 -0
- package/dist/workflows/uds.d.ts.map +1 -1
- package/dist/workflows/uds.js +30 -2
- package/dist/workflows/workflows.d.ts +19 -0
- package/dist/workflows/workflows.d.ts.map +1 -0
- package/dist/workflows/workflows.js +51 -0
- package/package.json +5 -1
- package/CHANGELOG.md +0 -33
- package/biome.json +0 -84
- package/examples/client/main.ts +0 -42
- package/examples/client/package-lock.json +0 -601
- package/examples/client/package.json +0 -16
- package/examples/client/tsconfig.json +0 -17
- package/examples/task/main.ts +0 -90
- package/examples/task/package-lock.json +0 -584
- package/examples/task/package.json +0 -16
- package/examples/task/tsconfig.json +0 -17
- package/src/errors.test.ts +0 -75
- package/src/errors.ts +0 -73
- package/src/experimental/experimental.ts +0 -56
- package/src/experimental/index.ts +0 -24
- package/src/experimental/object/api.ts +0 -91
- package/src/experimental/object/client.test.ts +0 -138
- package/src/experimental/object/client.ts +0 -317
- package/src/experimental/object/index.ts +0 -22
- package/src/experimental/object/types.test.ts +0 -87
- package/src/experimental/object/types.ts +0 -131
- package/src/generated/schema.ts +0 -12937
- package/src/index.ts +0 -7
- package/src/render.ts +0 -35
- package/src/utils/create-api-client.ts +0 -13
- package/src/utils/get-base-url.test.ts +0 -58
- package/src/utils/get-base-url.ts +0 -16
- package/src/version.ts +0 -37
- package/src/workflows/client/client.test.ts +0 -68
- package/src/workflows/client/client.ts +0 -142
- package/src/workflows/client/create-client.ts +0 -17
- package/src/workflows/client/index.ts +0 -3
- package/src/workflows/client/sse.ts +0 -95
- package/src/workflows/client/types.ts +0 -56
- package/src/workflows/executor.ts +0 -124
- package/src/workflows/index.ts +0 -7
- package/src/workflows/registry.test.ts +0 -76
- package/src/workflows/registry.ts +0 -88
- package/src/workflows/runner.ts +0 -38
- package/src/workflows/schema.ts +0 -348
- package/src/workflows/task.ts +0 -117
- package/src/workflows/types.test.ts +0 -52
- package/src/workflows/types.ts +0 -89
- package/src/workflows/uds.ts +0 -139
- package/test-types.ts +0 -14
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -23
- package/vitest.config.ts +0 -8
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import type { Client } from "openapi-fetch";
|
|
2
|
-
import { RenderError } from "../../errors.js";
|
|
3
|
-
import type { paths } from "../../generated/schema.js";
|
|
4
|
-
import type {
|
|
5
|
-
DeleteObjectInput,
|
|
6
|
-
GetObjectInput,
|
|
7
|
-
ObjectData,
|
|
8
|
-
ObjectScope,
|
|
9
|
-
PutObjectInput,
|
|
10
|
-
PutObjectResult,
|
|
11
|
-
Region,
|
|
12
|
-
ScopedDeleteObjectInput,
|
|
13
|
-
ScopedGetObjectInput,
|
|
14
|
-
ScopedPutObjectInput,
|
|
15
|
-
} from "./types.js";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Layer 3: High-Level Object Client
|
|
19
|
-
*
|
|
20
|
-
* User-facing API that abstracts presigned URLs completely.
|
|
21
|
-
* Provides simple put/get/delete operations that handle the
|
|
22
|
-
* two-step presigned URL flow internally.
|
|
23
|
-
*/
|
|
24
|
-
export class ObjectClient {
|
|
25
|
-
constructor(private readonly apiClient: Client<paths>) {}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Upload an object to storage
|
|
29
|
-
*
|
|
30
|
-
* @param input - Upload parameters including object identifier and data
|
|
31
|
-
* @returns Result with optional ETag
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```typescript
|
|
35
|
-
* // Upload a Buffer
|
|
36
|
-
* const data = Buffer.from("binary content");
|
|
37
|
-
* await objectClient.put({
|
|
38
|
-
* ownerId: "tea-xxxxx",
|
|
39
|
-
* region: "oregon",
|
|
40
|
-
* key: "path/to/file.png",
|
|
41
|
-
* data,
|
|
42
|
-
* contentType: "image/png"
|
|
43
|
-
* });
|
|
44
|
-
*
|
|
45
|
-
* // Upload from stream
|
|
46
|
-
* const stream = createReadStream("/path/to/file.zip");
|
|
47
|
-
* const stats = statSync("/path/to/file.zip");
|
|
48
|
-
* await objectClient.put({
|
|
49
|
-
* ownerId: "tea-xxxxx",
|
|
50
|
-
* region: "oregon",
|
|
51
|
-
* key: "file.zip",
|
|
52
|
-
* data: stream,
|
|
53
|
-
* size: stats.size
|
|
54
|
-
* });
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
async put(input: PutObjectInput): Promise<PutObjectResult> {
|
|
58
|
-
// Resolve and validate size
|
|
59
|
-
const size = this.resolveSize(input);
|
|
60
|
-
|
|
61
|
-
// Step 1: Get presigned upload URL from Render API
|
|
62
|
-
const { data, error } = await this.apiClient.PUT("/blobs/{ownerId}/{region}/{key}", {
|
|
63
|
-
params: {
|
|
64
|
-
path: {
|
|
65
|
-
ownerId: input.ownerId,
|
|
66
|
-
region: input.region as Region,
|
|
67
|
-
key: input.key,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
body: { sizeBytes: size },
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
if (error) {
|
|
74
|
-
throw new RenderError(`Failed to get upload URL: ${error.message || "Unknown error"}`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Step 2: Upload to storage via presigned URL
|
|
78
|
-
const headers: Record<string, string> = {
|
|
79
|
-
"Content-Length": size.toString(),
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
if (input.contentType) {
|
|
83
|
-
headers["Content-Type"] = input.contentType;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const response = await fetch(data.url, {
|
|
87
|
-
method: "PUT",
|
|
88
|
-
headers,
|
|
89
|
-
body: input.data,
|
|
90
|
-
duplex: "half",
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
if (!response.ok) {
|
|
94
|
-
throw new RenderError(`Upload failed: ${response.status} ${response.statusText}`);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
etag: response.headers.get("ETag") ?? undefined,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Download an object from storage
|
|
104
|
-
*
|
|
105
|
-
* @param input - Download parameters including object identifier
|
|
106
|
-
* @returns Object data with content
|
|
107
|
-
*
|
|
108
|
-
* @example
|
|
109
|
-
* ```typescript
|
|
110
|
-
* const obj = await objectClient.get({
|
|
111
|
-
* ownerId: "tea-xxxxx",
|
|
112
|
-
* region: "oregon",
|
|
113
|
-
* key: "path/to/file.png"
|
|
114
|
-
* });
|
|
115
|
-
*
|
|
116
|
-
* console.log(obj.size); // Size in bytes
|
|
117
|
-
* console.log(obj.contentType); // MIME type if available
|
|
118
|
-
* // obj.data is a Buffer
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
async get(input: GetObjectInput): Promise<ObjectData> {
|
|
122
|
-
// Step 1: Get presigned download URL from Render API
|
|
123
|
-
const { data, error } = await this.apiClient.GET("/blobs/{ownerId}/{region}/{key}", {
|
|
124
|
-
params: {
|
|
125
|
-
path: {
|
|
126
|
-
ownerId: input.ownerId,
|
|
127
|
-
region: input.region as Region,
|
|
128
|
-
key: input.key,
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
if (error) {
|
|
134
|
-
throw new RenderError(`Failed to get download URL: ${error.message || "Unknown error"}`);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Step 2: Download from storage via presigned URL
|
|
138
|
-
const response = await fetch(data.url);
|
|
139
|
-
|
|
140
|
-
if (!response.ok) {
|
|
141
|
-
throw new RenderError(`Download failed: ${response.status} ${response.statusText}`);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
145
|
-
const buffer = Buffer.from(arrayBuffer);
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
data: buffer,
|
|
149
|
-
size: buffer.byteLength,
|
|
150
|
-
contentType: response.headers.get("Content-Type") ?? undefined,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Delete an object from storage
|
|
156
|
-
*
|
|
157
|
-
* @param input - Delete parameters including object identifier
|
|
158
|
-
*
|
|
159
|
-
* @example
|
|
160
|
-
* ```typescript
|
|
161
|
-
* await objectClient.delete({
|
|
162
|
-
* ownerId: "tea-xxxxx",
|
|
163
|
-
* region: "oregon",
|
|
164
|
-
* key: "path/to/file.png"
|
|
165
|
-
* });
|
|
166
|
-
* ```
|
|
167
|
-
*/
|
|
168
|
-
async delete(input: DeleteObjectInput): Promise<void> {
|
|
169
|
-
// DELETE goes directly to Render API (no presigned URL)
|
|
170
|
-
const { error } = await this.apiClient.DELETE("/blobs/{ownerId}/{region}/{key}", {
|
|
171
|
-
params: {
|
|
172
|
-
path: {
|
|
173
|
-
ownerId: input.ownerId,
|
|
174
|
-
region: input.region as Region,
|
|
175
|
-
key: input.key,
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
if (error) {
|
|
181
|
-
throw new RenderError(`Failed to delete object: ${error.message || "Unknown error"}`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Create a scoped object client for a specific owner and region
|
|
187
|
-
*
|
|
188
|
-
* @param scope - Owner ID and region to scope operations to
|
|
189
|
-
* @returns Scoped object client that doesn't require ownerId/region on each call
|
|
190
|
-
*
|
|
191
|
-
* @example
|
|
192
|
-
* ```typescript
|
|
193
|
-
* const scoped = objectClient.scoped({
|
|
194
|
-
* ownerId: "tea-xxxxx",
|
|
195
|
-
* region: "oregon"
|
|
196
|
-
* });
|
|
197
|
-
*
|
|
198
|
-
* // Subsequent calls only need the key
|
|
199
|
-
* await scoped.put({ key: "file.png", data: buffer });
|
|
200
|
-
* await scoped.get({ key: "file.png" });
|
|
201
|
-
* await scoped.delete({ key: "file.png" });
|
|
202
|
-
* ```
|
|
203
|
-
*/
|
|
204
|
-
scoped(scope: ObjectScope): ScopedObjectClient {
|
|
205
|
-
return new ScopedObjectClient(this.apiClient, scope);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Resolve and validate the size for a put operation
|
|
210
|
-
*
|
|
211
|
-
* - For Buffer/Uint8Array: auto-calculate size, validate if provided
|
|
212
|
-
* - For streams/strings: require explicit size
|
|
213
|
-
*/
|
|
214
|
-
private resolveSize(input: PutObjectInput): number {
|
|
215
|
-
if (Buffer.isBuffer(input.data) || input.data instanceof Uint8Array) {
|
|
216
|
-
const actualSize = input.data.byteLength;
|
|
217
|
-
|
|
218
|
-
if (input.size !== undefined && input.size !== actualSize) {
|
|
219
|
-
throw new RenderError(
|
|
220
|
-
`Size mismatch: provided size ${input.size} does not match actual size ${actualSize}`,
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return actualSize;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// For Readable streams or strings, size must be provided
|
|
228
|
-
if (input.size === undefined) {
|
|
229
|
-
throw new RenderError(
|
|
230
|
-
"Size is required for stream and string inputs. Provide the size parameter.",
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (input.size <= 0) {
|
|
235
|
-
throw new RenderError("Size must be a positive integer");
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return input.size;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Scoped Object Client
|
|
244
|
-
*
|
|
245
|
-
* Pre-configured client for a specific owner and region.
|
|
246
|
-
* Eliminates the need to specify ownerId and region on every operation.
|
|
247
|
-
*/
|
|
248
|
-
export class ScopedObjectClient {
|
|
249
|
-
private readonly objectClient: ObjectClient;
|
|
250
|
-
|
|
251
|
-
constructor(
|
|
252
|
-
apiClient: Client<paths>,
|
|
253
|
-
private readonly scope: ObjectScope,
|
|
254
|
-
) {
|
|
255
|
-
this.objectClient = new ObjectClient(apiClient);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Upload an object to storage using scoped owner and region
|
|
260
|
-
*
|
|
261
|
-
* @param input - Upload parameters (key and data only)
|
|
262
|
-
* @returns Result with optional ETag
|
|
263
|
-
*
|
|
264
|
-
* @example
|
|
265
|
-
* ```typescript
|
|
266
|
-
* const scoped = objectClient.scoped({ ownerId: "tea-xxxxx", region: "oregon" });
|
|
267
|
-
* await scoped.put({
|
|
268
|
-
* key: "file.png",
|
|
269
|
-
* data: Buffer.from("content"),
|
|
270
|
-
* contentType: "image/png"
|
|
271
|
-
* });
|
|
272
|
-
* ```
|
|
273
|
-
*/
|
|
274
|
-
async put(input: ScopedPutObjectInput): Promise<PutObjectResult> {
|
|
275
|
-
return this.objectClient.put({
|
|
276
|
-
...this.scope,
|
|
277
|
-
...input,
|
|
278
|
-
} as PutObjectInput);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Download an object from storage using scoped owner and region
|
|
283
|
-
*
|
|
284
|
-
* @param input - Download parameters (key only)
|
|
285
|
-
* @returns Object data with content
|
|
286
|
-
*
|
|
287
|
-
* @example
|
|
288
|
-
* ```typescript
|
|
289
|
-
* const scoped = objectClient.scoped({ ownerId: "tea-xxxxx", region: "oregon" });
|
|
290
|
-
* const obj = await scoped.get({ key: "file.png" });
|
|
291
|
-
* ```
|
|
292
|
-
*/
|
|
293
|
-
async get(input: ScopedGetObjectInput): Promise<ObjectData> {
|
|
294
|
-
return this.objectClient.get({
|
|
295
|
-
...this.scope,
|
|
296
|
-
...input,
|
|
297
|
-
} as GetObjectInput);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Delete an object from storage using scoped owner and region
|
|
302
|
-
*
|
|
303
|
-
* @param input - Delete parameters (key only)
|
|
304
|
-
*
|
|
305
|
-
* @example
|
|
306
|
-
* ```typescript
|
|
307
|
-
* const scoped = objectClient.scoped({ ownerId: "tea-xxxxx", region: "oregon" });
|
|
308
|
-
* await scoped.delete({ key: "file.png" });
|
|
309
|
-
* ```
|
|
310
|
-
*/
|
|
311
|
-
async delete(input: ScopedDeleteObjectInput): Promise<void> {
|
|
312
|
-
return this.objectClient.delete({
|
|
313
|
-
...this.scope,
|
|
314
|
-
...input,
|
|
315
|
-
} as DeleteObjectInput);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// Object storage client exports
|
|
2
|
-
export { ObjectApi } from "./api.js";
|
|
3
|
-
export { ObjectClient, ScopedObjectClient } from "./client.js";
|
|
4
|
-
// Type exports
|
|
5
|
-
export type {
|
|
6
|
-
DeleteObjectInput,
|
|
7
|
-
GetObjectInput,
|
|
8
|
-
ObjectData,
|
|
9
|
-
ObjectIdentifier,
|
|
10
|
-
ObjectScope,
|
|
11
|
-
PresignedDownloadUrl,
|
|
12
|
-
PresignedUploadUrl,
|
|
13
|
-
PutObjectInput,
|
|
14
|
-
PutObjectInputBuffer,
|
|
15
|
-
PutObjectInputStream,
|
|
16
|
-
PutObjectResult,
|
|
17
|
-
ScopedDeleteObjectInput,
|
|
18
|
-
ScopedGetObjectInput,
|
|
19
|
-
ScopedPutObjectInput,
|
|
20
|
-
} from "./types.js";
|
|
21
|
-
// Re-export the Region enum (both type and value)
|
|
22
|
-
export { Region } from "./types.js";
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import type { Readable } from "node:stream";
|
|
2
|
-
import type {
|
|
3
|
-
DeleteObjectInput,
|
|
4
|
-
GetObjectInput,
|
|
5
|
-
ObjectIdentifier,
|
|
6
|
-
ObjectScope,
|
|
7
|
-
PutObjectInput,
|
|
8
|
-
PutObjectInputBuffer,
|
|
9
|
-
PutObjectInputStream,
|
|
10
|
-
ScopedDeleteObjectInput,
|
|
11
|
-
ScopedGetObjectInput,
|
|
12
|
-
ScopedPutObjectInput,
|
|
13
|
-
} from "./types.js";
|
|
14
|
-
|
|
15
|
-
describe("PutObjectInput discriminated union", () => {
|
|
16
|
-
it("accepts buffer variant", () => {
|
|
17
|
-
const input: PutObjectInput = {
|
|
18
|
-
ownerId: "tea-123",
|
|
19
|
-
region: "frankfurt",
|
|
20
|
-
key: "test.txt",
|
|
21
|
-
data: Buffer.from("hello"),
|
|
22
|
-
};
|
|
23
|
-
expectTypeOf(input).toMatchTypeOf<PutObjectInput>();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("accepts stream variant with required size", () => {
|
|
27
|
-
const input: PutObjectInput = {
|
|
28
|
-
ownerId: "tea-123",
|
|
29
|
-
region: "frankfurt",
|
|
30
|
-
key: "test.txt",
|
|
31
|
-
data: {} as Readable,
|
|
32
|
-
size: 100,
|
|
33
|
-
};
|
|
34
|
-
expectTypeOf(input).toMatchTypeOf<PutObjectInput>();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("union includes both variants", () => {
|
|
38
|
-
expectTypeOf<PutObjectInput>().toMatchTypeOf<PutObjectInputBuffer | PutObjectInputStream>();
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe("ObjectIdentifier type", () => {
|
|
43
|
-
it("requires tea- prefix on ownerId", () => {
|
|
44
|
-
expectTypeOf<ObjectIdentifier["ownerId"]>().toEqualTypeOf<`tea-${string}`>();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("has required key property", () => {
|
|
48
|
-
expectTypeOf<ObjectIdentifier>().toHaveProperty("key");
|
|
49
|
-
expectTypeOf<ObjectIdentifier["key"]>().toEqualTypeOf<string>();
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe("Scoped types omit ObjectScope fields", () => {
|
|
54
|
-
it("ScopedPutObjectInput omits ownerId and region", () => {
|
|
55
|
-
expectTypeOf<ScopedPutObjectInput>().not.toHaveProperty("ownerId");
|
|
56
|
-
expectTypeOf<ScopedPutObjectInput>().not.toHaveProperty("region");
|
|
57
|
-
expectTypeOf<ScopedPutObjectInput>().toHaveProperty("key");
|
|
58
|
-
expectTypeOf<ScopedPutObjectInput>().toHaveProperty("data");
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("ScopedGetObjectInput omits ownerId and region", () => {
|
|
62
|
-
expectTypeOf<ScopedGetObjectInput>().not.toHaveProperty("ownerId");
|
|
63
|
-
expectTypeOf<ScopedGetObjectInput>().not.toHaveProperty("region");
|
|
64
|
-
expectTypeOf<ScopedGetObjectInput>().toHaveProperty("key");
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("ScopedDeleteObjectInput omits ownerId and region", () => {
|
|
68
|
-
expectTypeOf<ScopedDeleteObjectInput>().not.toHaveProperty("ownerId");
|
|
69
|
-
expectTypeOf<ScopedDeleteObjectInput>().not.toHaveProperty("region");
|
|
70
|
-
expectTypeOf<ScopedDeleteObjectInput>().toHaveProperty("key");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("ObjectScope has ownerId and region", () => {
|
|
74
|
-
expectTypeOf<ObjectScope>().toHaveProperty("ownerId");
|
|
75
|
-
expectTypeOf<ObjectScope>().toHaveProperty("region");
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe("GetObjectInput and DeleteObjectInput extend ObjectIdentifier", () => {
|
|
80
|
-
it("GetObjectInput matches ObjectIdentifier", () => {
|
|
81
|
-
expectTypeOf<GetObjectInput>().toMatchTypeOf<ObjectIdentifier>();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("DeleteObjectInput matches ObjectIdentifier", () => {
|
|
85
|
-
expectTypeOf<DeleteObjectInput>().toMatchTypeOf<ObjectIdentifier>();
|
|
86
|
-
});
|
|
87
|
-
});
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import type { Readable } from "node:stream";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Supported regions for object storage
|
|
5
|
-
*/
|
|
6
|
-
export type Region = "frankfurt" | "oregon" | "ohio" | "singapore" | "virginia";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Base identifier for a storage object
|
|
10
|
-
*/
|
|
11
|
-
export interface ObjectIdentifier {
|
|
12
|
-
/** Owner ID (workspace team ID) in format tea-xxxxx */
|
|
13
|
-
ownerId: `tea-${string}`;
|
|
14
|
-
/** Region where the object is stored */
|
|
15
|
-
region: Region | string;
|
|
16
|
-
/** Object key (path) for the object */
|
|
17
|
-
key: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Base options for putting an object
|
|
22
|
-
*/
|
|
23
|
-
interface PutObjectInputBase extends ObjectIdentifier {
|
|
24
|
-
/** MIME type of the content (optional, will be auto-detected if not provided) */
|
|
25
|
-
contentType?: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Put object input for Buffer, Uint8Array, or string data
|
|
30
|
-
* Size is optional and will be auto-calculated
|
|
31
|
-
*/
|
|
32
|
-
export interface PutObjectInputBuffer extends PutObjectInputBase {
|
|
33
|
-
/** Binary data as Buffer, Uint8Array, or string */
|
|
34
|
-
data: Buffer | Uint8Array | string;
|
|
35
|
-
/** Size in bytes (optional, auto-calculated for Buffer/Uint8Array) */
|
|
36
|
-
size?: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Put object input for readable streams
|
|
41
|
-
* Size is required for streams
|
|
42
|
-
*/
|
|
43
|
-
export interface PutObjectInputStream extends PutObjectInputBase {
|
|
44
|
-
/** Readable stream */
|
|
45
|
-
data: Readable;
|
|
46
|
-
/** Size in bytes (required for streams) */
|
|
47
|
-
size: number;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Input for uploading an object
|
|
52
|
-
* Discriminated union: size is optional for Buffer/Uint8Array, required for streams
|
|
53
|
-
*/
|
|
54
|
-
export type PutObjectInput = PutObjectInputBuffer | PutObjectInputStream;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Input for downloading an object
|
|
58
|
-
*/
|
|
59
|
-
export interface GetObjectInput extends ObjectIdentifier {}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Input for deleting an object
|
|
63
|
-
*/
|
|
64
|
-
export interface DeleteObjectInput extends ObjectIdentifier {}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Presigned URL for uploading
|
|
68
|
-
*/
|
|
69
|
-
export interface PresignedUploadUrl {
|
|
70
|
-
/** Presigned upload URL */
|
|
71
|
-
url: string;
|
|
72
|
-
/** Expiration timestamp */
|
|
73
|
-
expiresAt: Date;
|
|
74
|
-
/** Maximum size allowed for upload */
|
|
75
|
-
maxSizeBytes: number;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Presigned URL for downloading
|
|
80
|
-
*/
|
|
81
|
-
export interface PresignedDownloadUrl {
|
|
82
|
-
/** Presigned download URL */
|
|
83
|
-
url: string;
|
|
84
|
-
/** Expiration timestamp */
|
|
85
|
-
expiresAt: Date;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Downloaded object data
|
|
90
|
-
*/
|
|
91
|
-
export interface ObjectData {
|
|
92
|
-
/** Binary content */
|
|
93
|
-
data: Buffer;
|
|
94
|
-
/** MIME type if available */
|
|
95
|
-
contentType?: string;
|
|
96
|
-
/** Size in bytes */
|
|
97
|
-
size: number;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Result from uploading an object
|
|
102
|
-
*/
|
|
103
|
-
export interface PutObjectResult {
|
|
104
|
-
/** ETag from storage provider */
|
|
105
|
-
etag?: string;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Scope configuration for scoped object client
|
|
110
|
-
*/
|
|
111
|
-
export interface ObjectScope {
|
|
112
|
-
/** Owner ID (workspace team ID) in format tea-xxxxx */
|
|
113
|
-
ownerId: `tea-${string}`;
|
|
114
|
-
/** Region where the object is stored */
|
|
115
|
-
region: Region | string;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Scoped input for uploading an object (without ownerId/region)
|
|
120
|
-
*/
|
|
121
|
-
export type ScopedPutObjectInput = Omit<PutObjectInput, keyof ObjectScope>;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Scoped input for downloading an object (without ownerId/region)
|
|
125
|
-
*/
|
|
126
|
-
export type ScopedGetObjectInput = Omit<GetObjectInput, keyof ObjectScope>;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Scoped input for deleting an object (without ownerId/region)
|
|
130
|
-
*/
|
|
131
|
-
export type ScopedDeleteObjectInput = Omit<DeleteObjectInput, keyof ObjectScope>;
|