@sequenceholdings/storage 0.1.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 +91 -0
- package/dist/client.d.ts +453 -0
- package/dist/client.js +298 -0
- package/dist/contracts.d.ts +244 -0
- package/dist/contracts.js +186 -0
- package/dist/crc32c.d.ts +11 -0
- package/dist/crc32c.js +76 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +22 -0
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +28 -0
- package/dist/scope.d.ts +15 -0
- package/dist/scope.js +42 -0
- package/dist/transfer.d.ts +34 -0
- package/dist/transfer.js +257 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Atlas storage client
|
|
2
|
+
|
|
3
|
+
Typed Workspaces V2 metadata and direct-to-GCS sequential resumable transfers.
|
|
4
|
+
Initial release is pending publication and public-contract review.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { createStorageClient } from '@sequenceholdings/storage'
|
|
8
|
+
|
|
9
|
+
const storage = createStorageClient({ baseUrl: atlasUrl, getToken: authenticatedToken })
|
|
10
|
+
const workspace = storage.workspace(workspaceId)
|
|
11
|
+
const result = await workspace.uploads.put({
|
|
12
|
+
path: 'reports/quarterly.pdf', parentId: null,
|
|
13
|
+
contentType: 'application/pdf',
|
|
14
|
+
}, fileBlob, { onProgress: uploadedBytes => console.log(uploadedBytes) })
|
|
15
|
+
// Store result.fileId (and optionally result.versionId) in your application's data model.
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`uploads.start` returns an upload ID before transfer. Keep that ID for
|
|
19
|
+
`uploads.resume(id, originalSource)`. Source can be a Blob, Web ReadableStream or
|
|
20
|
+
Node async iterable. The client retains fixed-size chunks, probes GCS offsets and
|
|
21
|
+
retries transient failures. Supply `size` when known (up to 50 GiB); a stream without
|
|
22
|
+
one reserves 1 GiB and fails once it exceeds that. Pass `signal` to stop transfer, then
|
|
23
|
+
either resume or `uploads.abort(id)` to release the reservation. When `put` fails after
|
|
24
|
+
starting a session it aborts the session for you; pass `{ keepSessionOnFailure: true }`
|
|
25
|
+
to keep it and `resume` later. `put` generates an `idempotencyKey` unless you pass
|
|
26
|
+
one and reuses it whenever it resends `start`, which `start` itself does after a
|
|
27
|
+
timeout, a lost reply or a 5xx: the server replays a start that committed, so it
|
|
28
|
+
never leaves an unnamed session holding one of your 20 pending uploads per
|
|
29
|
+
workspace. Small Blobs can use
|
|
30
|
+
`{ method: 'simple' }`; sequential resumable is the default. Parallel multipart is
|
|
31
|
+
not included. Do not log the session URL: it is a bearer credential.
|
|
32
|
+
|
|
33
|
+
`resume` and `put` compute a CRC32C over the whole source as they read it (from
|
|
34
|
+
byte zero, including the prefix a resume skips) and send it on completion; Atlas
|
|
35
|
+
aborts the session with `409` if the stored object differs, which is how a resume
|
|
36
|
+
with a source that yields different bytes is caught. If you transfer bytes yourself
|
|
37
|
+
with `transferStorageUpload`, pass its result: `uploads.complete(id, { crc32c })`.
|
|
38
|
+
`Crc32c` (incremental `update(bytes)` / `digest()`) and `crc32c(bytes)` are exported
|
|
39
|
+
for producers that want to declare `checksum` at start. The completion field is
|
|
40
|
+
optional today and becomes required once in-repo consumers ship this SDK.
|
|
41
|
+
|
|
42
|
+
Replace a file by supplying `fileId` and its `expectedRevision`. Concurrent stale
|
|
43
|
+
replacement fails with `409`; reload before retrying. Completion is idempotent.
|
|
44
|
+
While a just-committed permission change is still being applied, Atlas answers
|
|
45
|
+
`503 permissions_pending`; while other changes hold the workspace, `503
|
|
46
|
+
storage_busy`. The client retries both on reads, upload `start`/`complete`/`abort`,
|
|
47
|
+
`createFolder` and manifest `apply` (replay-safe) for ~10 seconds; other mutations are not retried,
|
|
48
|
+
because the change may already have been applied, so refresh before repeating one.
|
|
49
|
+
`createFolder` sends an `idempotencyKey` (generated per call, or pass
|
|
50
|
+
`{ idempotencyKey }` to cover your own retries), so a resend returns the folder
|
|
51
|
+
it already created instead of `409`. `createStorageClient` bounds each metadata request with `requestTimeoutMs`
|
|
52
|
+
(default 30 s, `0` disables); a timeout surfaces as `request_timeout`.
|
|
53
|
+
`versions`, `restoreVersion` and `deleteVersion` manage immutable history. Restore
|
|
54
|
+
creates a new revision without copying bytes. `update` renames/moves metadata while
|
|
55
|
+
preserving file IDs. `trash`/`restore` are reversible; `purge` and workspace `delete`
|
|
56
|
+
return durable receipts from `operations` (yours by default; `{ scope: 'workspace' }`
|
|
57
|
+
lists everyone's for workspace Admins). Poll these until `succeeded`; failed runs
|
|
58
|
+
requeue automatically, and `retryOperation` restarts one marked `failed` after
|
|
59
|
+
correcting its cause.
|
|
60
|
+
|
|
61
|
+
In an Artifact, use the trusted host's Blob transfer bridge:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { createArtifactStorageClient } from '@sequenceholdings/artifact-studio'
|
|
65
|
+
const workspace = createArtifactStorageClient().workspace(workspaceId)
|
|
66
|
+
await workspace.uploads.put(input, file, {
|
|
67
|
+
onProgress: ({ uploadedBytes }) => updateProgress(uploadedBytes),
|
|
68
|
+
})
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Declare `capabilities.storage` as a map from workspace UUID to `viewer`, `editor`
|
|
72
|
+
or `admin`. The declaration only limits reach; the caller also needs resource
|
|
73
|
+
permissions. A folder-only grant is sufficient for that folder's resources.
|
|
74
|
+
|
|
75
|
+
In a Managed Function, use invocation headers, never a caller-supplied token or URL:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { createFunctionStorageClient } from '@sequenceholdings/managed-functions'
|
|
79
|
+
const storage = createFunctionStorageClient({ baseUrl: configuredAtlasUrl, headers: req.headers })
|
|
80
|
+
const file = await storage.workspace(workspaceId).getNode(fileId)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
User mode is the default. `{ mode: 'service' }` explicitly selects the manifest's
|
|
84
|
+
attached platform service account, which needs its own storage grants. Declare
|
|
85
|
+
`service_account`, `capabilities.storage` and hosted network egress to your Atlas
|
|
86
|
+
host and `storage.googleapis.com`. Delegation expires after 15 minutes; resume in a
|
|
87
|
+
fresh invocation when necessary. Signed download leases expire after 60 seconds.
|
|
88
|
+
|
|
89
|
+
For local integration use the normal local Atlas environment, `seq-studio storage`
|
|
90
|
+
and `functions deploy -e local`. File references in ORM remain application-owned;
|
|
91
|
+
there is no automatic row-to-file authorization or deletion cascade.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type CompleteStorageUpload, type StartStorageUpload, type StorageOperationScope, type WorkspaceManifest, type updateNodeSchema, type updateStorageAccessSchema } from './contracts.js';
|
|
3
|
+
import { type StorageUploadSource, type StorageTransferOptions } from './transfer.js';
|
|
4
|
+
export declare const STORAGE_TOKEN_HEADER = "x-sequence-storage-token";
|
|
5
|
+
export declare const STORAGE_SERVICE_TOKEN_HEADER = "x-sequence-storage-token-service";
|
|
6
|
+
export interface StorageTransport {
|
|
7
|
+
request(method: string, path: string, body?: unknown): Promise<unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface StorageListOptions {
|
|
10
|
+
cursor?: string;
|
|
11
|
+
limit?: number;
|
|
12
|
+
q?: string;
|
|
13
|
+
sort?: 'name' | 'newest';
|
|
14
|
+
}
|
|
15
|
+
export declare class StorageApiError extends Error {
|
|
16
|
+
readonly status: number;
|
|
17
|
+
readonly code: string;
|
|
18
|
+
constructor(status: number, code: string, message: string);
|
|
19
|
+
}
|
|
20
|
+
/** Backoff for replay-safe requests (see `replayable`). */
|
|
21
|
+
export interface StoragePermissionsRetry {
|
|
22
|
+
/** Total attempts including the first; 1 disables retrying. */
|
|
23
|
+
attempts?: number;
|
|
24
|
+
/** Ceiling of the first backoff; each later retry doubles it. */
|
|
25
|
+
baseDelayMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export declare const storageDownloadSchema: z.ZodObject<{
|
|
28
|
+
url: z.ZodURL;
|
|
29
|
+
expiresAt: z.ZodString;
|
|
30
|
+
preview: z.ZodBoolean;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
/** Supply a transport for an Artifact bridge, or use createStorageClient for HTTP. */
|
|
33
|
+
export declare function storageClient(transport: StorageTransport, { permissionsRetry, }?: {
|
|
34
|
+
permissionsRetry?: StoragePermissionsRetry;
|
|
35
|
+
}): {
|
|
36
|
+
capabilities: () => Promise<{
|
|
37
|
+
canProvision: boolean;
|
|
38
|
+
uploadMethods: string[];
|
|
39
|
+
}>;
|
|
40
|
+
list: (options?: StorageListOptions) => Promise<{
|
|
41
|
+
items: {
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
description: string;
|
|
45
|
+
environment: string;
|
|
46
|
+
state: "active" | "trashed" | "purging";
|
|
47
|
+
revision: number;
|
|
48
|
+
createdAt: string;
|
|
49
|
+
role: "viewer" | "editor" | "admin" | "owner";
|
|
50
|
+
quotaBytes: number;
|
|
51
|
+
usedBytes: number;
|
|
52
|
+
reservedBytes: number;
|
|
53
|
+
}[];
|
|
54
|
+
nextCursor: string | null;
|
|
55
|
+
}>;
|
|
56
|
+
shared: (options?: StorageListOptions & {
|
|
57
|
+
trash?: boolean;
|
|
58
|
+
}) => Promise<{
|
|
59
|
+
items: {
|
|
60
|
+
id: string;
|
|
61
|
+
workspaceId: string;
|
|
62
|
+
parentId: string | null;
|
|
63
|
+
name: string;
|
|
64
|
+
kind: "file" | "folder";
|
|
65
|
+
state: "active" | "trashed" | "purging";
|
|
66
|
+
restricted: boolean;
|
|
67
|
+
revision: number;
|
|
68
|
+
currentVersionId: string | null;
|
|
69
|
+
metadata: Record<string, string>;
|
|
70
|
+
createdAt: string;
|
|
71
|
+
updatedAt: string;
|
|
72
|
+
role: "viewer" | "editor" | "admin";
|
|
73
|
+
size: number | null;
|
|
74
|
+
contentType: string | null;
|
|
75
|
+
}[];
|
|
76
|
+
nextCursor: string | null;
|
|
77
|
+
}>;
|
|
78
|
+
apply: (manifest: WorkspaceManifest) => Promise<{
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
description: string;
|
|
82
|
+
environment: string;
|
|
83
|
+
state: "active" | "trashed" | "purging";
|
|
84
|
+
revision: number;
|
|
85
|
+
createdAt: string;
|
|
86
|
+
role: "viewer" | "editor" | "admin" | "owner";
|
|
87
|
+
quotaBytes: number;
|
|
88
|
+
usedBytes: number;
|
|
89
|
+
reservedBytes: number;
|
|
90
|
+
}>;
|
|
91
|
+
workspace(id: string): {
|
|
92
|
+
get: () => Promise<{
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
description: string;
|
|
96
|
+
environment: string;
|
|
97
|
+
state: "active" | "trashed" | "purging";
|
|
98
|
+
revision: number;
|
|
99
|
+
createdAt: string;
|
|
100
|
+
role: "viewer" | "editor" | "admin" | "owner";
|
|
101
|
+
quotaBytes: number;
|
|
102
|
+
usedBytes: number;
|
|
103
|
+
reservedBytes: number;
|
|
104
|
+
}>;
|
|
105
|
+
delete: (expectedRevision: number) => Promise<{
|
|
106
|
+
id: string;
|
|
107
|
+
workspaceId: string;
|
|
108
|
+
targetId: string | null;
|
|
109
|
+
kind: "purge" | "delete_version";
|
|
110
|
+
status: "queued" | "running" | "succeeded" | "failed";
|
|
111
|
+
completed: number;
|
|
112
|
+
total: number;
|
|
113
|
+
error: string | null;
|
|
114
|
+
createdAt: string;
|
|
115
|
+
updatedAt: string;
|
|
116
|
+
canRetry: boolean;
|
|
117
|
+
}>;
|
|
118
|
+
list: (options?: StorageListOptions & {
|
|
119
|
+
parentId?: string | null;
|
|
120
|
+
trash?: boolean;
|
|
121
|
+
}) => Promise<{
|
|
122
|
+
items: {
|
|
123
|
+
id: string;
|
|
124
|
+
workspaceId: string;
|
|
125
|
+
parentId: string | null;
|
|
126
|
+
name: string;
|
|
127
|
+
kind: "file" | "folder";
|
|
128
|
+
state: "active" | "trashed" | "purging";
|
|
129
|
+
restricted: boolean;
|
|
130
|
+
revision: number;
|
|
131
|
+
currentVersionId: string | null;
|
|
132
|
+
metadata: Record<string, string>;
|
|
133
|
+
createdAt: string;
|
|
134
|
+
updatedAt: string;
|
|
135
|
+
role: "viewer" | "editor" | "admin";
|
|
136
|
+
size: number | null;
|
|
137
|
+
contentType: string | null;
|
|
138
|
+
}[];
|
|
139
|
+
nextCursor: string | null;
|
|
140
|
+
}>;
|
|
141
|
+
getNode: (id: string) => Promise<{
|
|
142
|
+
id: string;
|
|
143
|
+
workspaceId: string;
|
|
144
|
+
parentId: string | null;
|
|
145
|
+
name: string;
|
|
146
|
+
kind: "file" | "folder";
|
|
147
|
+
state: "active" | "trashed" | "purging";
|
|
148
|
+
restricted: boolean;
|
|
149
|
+
revision: number;
|
|
150
|
+
currentVersionId: string | null;
|
|
151
|
+
metadata: Record<string, string>;
|
|
152
|
+
createdAt: string;
|
|
153
|
+
updatedAt: string;
|
|
154
|
+
role: "viewer" | "editor" | "admin";
|
|
155
|
+
size: number | null;
|
|
156
|
+
contentType: string | null;
|
|
157
|
+
}>;
|
|
158
|
+
/**
|
|
159
|
+
* Keyed like upload start, so every resend (storage_busy,
|
|
160
|
+
* permissions_pending, a lost reply) returns the one folder it made.
|
|
161
|
+
* Pass `idempotencyKey` to extend that across your own retries.
|
|
162
|
+
*/
|
|
163
|
+
createFolder: (name: string, parentId?: string | null, { idempotencyKey, }?: {
|
|
164
|
+
idempotencyKey?: string;
|
|
165
|
+
}) => Promise<{
|
|
166
|
+
id: string;
|
|
167
|
+
workspaceId: string;
|
|
168
|
+
parentId: string | null;
|
|
169
|
+
name: string;
|
|
170
|
+
kind: "file" | "folder";
|
|
171
|
+
state: "active" | "trashed" | "purging";
|
|
172
|
+
restricted: boolean;
|
|
173
|
+
revision: number;
|
|
174
|
+
currentVersionId: string | null;
|
|
175
|
+
metadata: Record<string, string>;
|
|
176
|
+
createdAt: string;
|
|
177
|
+
updatedAt: string;
|
|
178
|
+
role: "viewer" | "editor" | "admin";
|
|
179
|
+
size: number | null;
|
|
180
|
+
contentType: string | null;
|
|
181
|
+
}>;
|
|
182
|
+
update: (id: string, input: z.input<typeof updateNodeSchema>) => Promise<{
|
|
183
|
+
id: string;
|
|
184
|
+
workspaceId: string;
|
|
185
|
+
parentId: string | null;
|
|
186
|
+
name: string;
|
|
187
|
+
kind: "file" | "folder";
|
|
188
|
+
state: "active" | "trashed" | "purging";
|
|
189
|
+
restricted: boolean;
|
|
190
|
+
revision: number;
|
|
191
|
+
currentVersionId: string | null;
|
|
192
|
+
metadata: Record<string, string>;
|
|
193
|
+
createdAt: string;
|
|
194
|
+
updatedAt: string;
|
|
195
|
+
role: "viewer" | "editor" | "admin";
|
|
196
|
+
size: number | null;
|
|
197
|
+
contentType: string | null;
|
|
198
|
+
}>;
|
|
199
|
+
trash: (id: string, expectedRevision: number) => Promise<{
|
|
200
|
+
id: string;
|
|
201
|
+
workspaceId: string;
|
|
202
|
+
parentId: string | null;
|
|
203
|
+
name: string;
|
|
204
|
+
kind: "file" | "folder";
|
|
205
|
+
state: "active" | "trashed" | "purging";
|
|
206
|
+
restricted: boolean;
|
|
207
|
+
revision: number;
|
|
208
|
+
currentVersionId: string | null;
|
|
209
|
+
metadata: Record<string, string>;
|
|
210
|
+
createdAt: string;
|
|
211
|
+
updatedAt: string;
|
|
212
|
+
role: "viewer" | "editor" | "admin";
|
|
213
|
+
size: number | null;
|
|
214
|
+
contentType: string | null;
|
|
215
|
+
}>;
|
|
216
|
+
restore: (id: string, expectedRevision: number) => Promise<{
|
|
217
|
+
id: string;
|
|
218
|
+
workspaceId: string;
|
|
219
|
+
parentId: string | null;
|
|
220
|
+
name: string;
|
|
221
|
+
kind: "file" | "folder";
|
|
222
|
+
state: "active" | "trashed" | "purging";
|
|
223
|
+
restricted: boolean;
|
|
224
|
+
revision: number;
|
|
225
|
+
currentVersionId: string | null;
|
|
226
|
+
metadata: Record<string, string>;
|
|
227
|
+
createdAt: string;
|
|
228
|
+
updatedAt: string;
|
|
229
|
+
role: "viewer" | "editor" | "admin";
|
|
230
|
+
size: number | null;
|
|
231
|
+
contentType: string | null;
|
|
232
|
+
}>;
|
|
233
|
+
purge: (id: string, expectedRevision: number) => Promise<{
|
|
234
|
+
id: string;
|
|
235
|
+
workspaceId: string;
|
|
236
|
+
targetId: string | null;
|
|
237
|
+
kind: "purge" | "delete_version";
|
|
238
|
+
status: "queued" | "running" | "succeeded" | "failed";
|
|
239
|
+
completed: number;
|
|
240
|
+
total: number;
|
|
241
|
+
error: string | null;
|
|
242
|
+
createdAt: string;
|
|
243
|
+
updatedAt: string;
|
|
244
|
+
canRetry: boolean;
|
|
245
|
+
}>;
|
|
246
|
+
download: (id: string, options?: {
|
|
247
|
+
versionId?: string;
|
|
248
|
+
preview?: boolean;
|
|
249
|
+
}) => Promise<{
|
|
250
|
+
url: string;
|
|
251
|
+
expiresAt: string;
|
|
252
|
+
preview: boolean;
|
|
253
|
+
}>;
|
|
254
|
+
versions: (id: string, options?: {
|
|
255
|
+
before?: number;
|
|
256
|
+
limit?: number;
|
|
257
|
+
}) => Promise<{
|
|
258
|
+
items: {
|
|
259
|
+
id: string;
|
|
260
|
+
fileId: string;
|
|
261
|
+
revision: number;
|
|
262
|
+
size: number;
|
|
263
|
+
checksum: string;
|
|
264
|
+
contentType: string;
|
|
265
|
+
createdAt: string;
|
|
266
|
+
createdBy: string;
|
|
267
|
+
state: "active" | "purging";
|
|
268
|
+
}[];
|
|
269
|
+
nextRevision: number | null;
|
|
270
|
+
}>;
|
|
271
|
+
restoreVersion: (id: string, versionId: string, expectedRevision: number) => Promise<{
|
|
272
|
+
id: string;
|
|
273
|
+
fileId: string;
|
|
274
|
+
revision: number;
|
|
275
|
+
size: number;
|
|
276
|
+
checksum: string;
|
|
277
|
+
contentType: string;
|
|
278
|
+
createdAt: string;
|
|
279
|
+
createdBy: string;
|
|
280
|
+
state: "active" | "purging";
|
|
281
|
+
}>;
|
|
282
|
+
deleteVersion: (id: string, versionId: string, expectedRevision: number) => Promise<{
|
|
283
|
+
id: string;
|
|
284
|
+
workspaceId: string;
|
|
285
|
+
targetId: string | null;
|
|
286
|
+
kind: "purge" | "delete_version";
|
|
287
|
+
status: "queued" | "running" | "succeeded" | "failed";
|
|
288
|
+
completed: number;
|
|
289
|
+
total: number;
|
|
290
|
+
error: string | null;
|
|
291
|
+
createdAt: string;
|
|
292
|
+
updatedAt: string;
|
|
293
|
+
canRetry: boolean;
|
|
294
|
+
}>;
|
|
295
|
+
access: (id?: string) => Promise<{
|
|
296
|
+
revision: number;
|
|
297
|
+
restricted: boolean;
|
|
298
|
+
grants: {
|
|
299
|
+
type: "user" | "group" | "organization" | "service_account";
|
|
300
|
+
id: string;
|
|
301
|
+
role: "viewer" | "editor" | "admin";
|
|
302
|
+
}[];
|
|
303
|
+
owner: string | null;
|
|
304
|
+
inherited: boolean;
|
|
305
|
+
workspaceAdminOverride: true;
|
|
306
|
+
displayNames: Record<string, string>;
|
|
307
|
+
}>;
|
|
308
|
+
setAccess: (input: z.input<typeof updateStorageAccessSchema>, id?: string) => Promise<{
|
|
309
|
+
revision: number;
|
|
310
|
+
restricted: boolean;
|
|
311
|
+
grants: {
|
|
312
|
+
type: "user" | "group" | "organization" | "service_account";
|
|
313
|
+
id: string;
|
|
314
|
+
role: "viewer" | "editor" | "admin";
|
|
315
|
+
}[];
|
|
316
|
+
owner: string | null;
|
|
317
|
+
inherited: boolean;
|
|
318
|
+
workspaceAdminOverride: true;
|
|
319
|
+
displayNames: Record<string, string>;
|
|
320
|
+
}>;
|
|
321
|
+
transferOwner: (principal: {
|
|
322
|
+
type: "user" | "service_account";
|
|
323
|
+
id: string;
|
|
324
|
+
}, expectedRevision: number) => Promise<{
|
|
325
|
+
revision: number;
|
|
326
|
+
restricted: boolean;
|
|
327
|
+
grants: {
|
|
328
|
+
type: "user" | "group" | "organization" | "service_account";
|
|
329
|
+
id: string;
|
|
330
|
+
role: "viewer" | "editor" | "admin";
|
|
331
|
+
}[];
|
|
332
|
+
owner: string | null;
|
|
333
|
+
inherited: boolean;
|
|
334
|
+
workspaceAdminOverride: true;
|
|
335
|
+
displayNames: Record<string, string>;
|
|
336
|
+
}>;
|
|
337
|
+
operations: (options?: {
|
|
338
|
+
before?: string;
|
|
339
|
+
limit?: number;
|
|
340
|
+
scope?: StorageOperationScope;
|
|
341
|
+
}) => Promise<{
|
|
342
|
+
items: {
|
|
343
|
+
id: string;
|
|
344
|
+
workspaceId: string;
|
|
345
|
+
targetId: string | null;
|
|
346
|
+
kind: "purge" | "delete_version";
|
|
347
|
+
status: "queued" | "running" | "succeeded" | "failed";
|
|
348
|
+
completed: number;
|
|
349
|
+
total: number;
|
|
350
|
+
error: string | null;
|
|
351
|
+
createdAt: string;
|
|
352
|
+
updatedAt: string;
|
|
353
|
+
canRetry: boolean;
|
|
354
|
+
}[];
|
|
355
|
+
nextCursor: string | null;
|
|
356
|
+
}>;
|
|
357
|
+
retryOperation: (id: string) => Promise<{
|
|
358
|
+
id: string;
|
|
359
|
+
workspaceId: string;
|
|
360
|
+
targetId: string | null;
|
|
361
|
+
kind: "purge" | "delete_version";
|
|
362
|
+
status: "queued" | "running" | "succeeded" | "failed";
|
|
363
|
+
completed: number;
|
|
364
|
+
total: number;
|
|
365
|
+
error: string | null;
|
|
366
|
+
createdAt: string;
|
|
367
|
+
updatedAt: string;
|
|
368
|
+
canRetry: boolean;
|
|
369
|
+
}>;
|
|
370
|
+
uploads: {
|
|
371
|
+
start: (input: StartStorageUpload) => Promise<{
|
|
372
|
+
id: string;
|
|
373
|
+
fileId: string;
|
|
374
|
+
uploadUrl: string | null;
|
|
375
|
+
expiresAt: string;
|
|
376
|
+
state: "pending" | "complete" | "aborted";
|
|
377
|
+
versionId: string | null;
|
|
378
|
+
maxBytes: number;
|
|
379
|
+
}>;
|
|
380
|
+
get: (id: string) => Promise<{
|
|
381
|
+
id: string;
|
|
382
|
+
fileId: string;
|
|
383
|
+
uploadUrl: string | null;
|
|
384
|
+
expiresAt: string;
|
|
385
|
+
state: "pending" | "complete" | "aborted";
|
|
386
|
+
versionId: string | null;
|
|
387
|
+
maxBytes: number;
|
|
388
|
+
}>;
|
|
389
|
+
/** `resume` passes the CRC32C it computed; pass your own when transferring bytes yourself. */
|
|
390
|
+
complete: (id: string, input?: CompleteStorageUpload) => Promise<{
|
|
391
|
+
id: string;
|
|
392
|
+
fileId: string;
|
|
393
|
+
uploadUrl: string | null;
|
|
394
|
+
expiresAt: string;
|
|
395
|
+
state: "pending" | "complete" | "aborted";
|
|
396
|
+
versionId: string | null;
|
|
397
|
+
maxBytes: number;
|
|
398
|
+
}>;
|
|
399
|
+
abort: (id: string) => Promise<{
|
|
400
|
+
id: string;
|
|
401
|
+
fileId: string;
|
|
402
|
+
uploadUrl: string | null;
|
|
403
|
+
expiresAt: string;
|
|
404
|
+
state: "pending" | "complete" | "aborted";
|
|
405
|
+
versionId: string | null;
|
|
406
|
+
maxBytes: number;
|
|
407
|
+
}>;
|
|
408
|
+
resume(id: string, source: StorageUploadSource, options?: StorageTransferOptions & {
|
|
409
|
+
size?: number;
|
|
410
|
+
}): Promise<{
|
|
411
|
+
id: string;
|
|
412
|
+
fileId: string;
|
|
413
|
+
uploadUrl: string | null;
|
|
414
|
+
expiresAt: string;
|
|
415
|
+
state: "pending" | "complete" | "aborted";
|
|
416
|
+
versionId: string | null;
|
|
417
|
+
maxBytes: number;
|
|
418
|
+
}>;
|
|
419
|
+
/**
|
|
420
|
+
* Start, transfer and complete in one call. A failure after the session
|
|
421
|
+
* starts aborts it (best effort) to release its reservation; pass
|
|
422
|
+
* `keepSessionOnFailure` to keep it for a manual `resume`.
|
|
423
|
+
*/
|
|
424
|
+
put(input: Omit<StartStorageUpload, "idempotencyKey"> & {
|
|
425
|
+
/** Defaults to a fresh key per put, reused across its start retries. */
|
|
426
|
+
idempotencyKey?: string;
|
|
427
|
+
}, source: StorageUploadSource, { keepSessionOnFailure, ...options }?: StorageTransferOptions & {
|
|
428
|
+
keepSessionOnFailure?: boolean;
|
|
429
|
+
}): Promise<{
|
|
430
|
+
id: string;
|
|
431
|
+
fileId: string;
|
|
432
|
+
uploadUrl: string | null;
|
|
433
|
+
expiresAt: string;
|
|
434
|
+
state: "pending" | "complete" | "aborted";
|
|
435
|
+
versionId: string | null;
|
|
436
|
+
maxBytes: number;
|
|
437
|
+
}>;
|
|
438
|
+
};
|
|
439
|
+
};
|
|
440
|
+
};
|
|
441
|
+
export type StorageClient = ReturnType<typeof storageClient>;
|
|
442
|
+
export declare function createStorageClient({ baseUrl, getToken, getHeaders, fetch: fetcher, permissionsRetry, requestTimeoutMs, }: {
|
|
443
|
+
baseUrl: string;
|
|
444
|
+
getToken?: () => string | Promise<string>;
|
|
445
|
+
getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
446
|
+
fetch?: typeof fetch;
|
|
447
|
+
permissionsRetry?: StoragePermissionsRetry;
|
|
448
|
+
/**
|
|
449
|
+
* Per metadata request, including reading the reply; 0 disables it. Byte
|
|
450
|
+
* transfer goes to the provider directly and is not bounded by this.
|
|
451
|
+
*/
|
|
452
|
+
requestTimeoutMs?: number;
|
|
453
|
+
}): StorageClient;
|