@sequenceholdings/storage 0.1.2 → 0.1.3

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/dist/crc32c.js CHANGED
@@ -1,76 +1,18 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Crc32c = void 0;
4
- exports.crc32c = crc32c;
5
- /**
6
- * CRC32C (Castagnoli), the checksum GCS records for every object. Digests use
7
- * GCS's encoding: base64 of the big-endian uint32, as in `x-goog-hash: crc32c=`
8
- * and the object resource's `crc32c` field.
9
- *
10
- * Slicing-by-8 over eight 256-entry tables: one table lookup per input byte,
11
- * eight bytes per loop iteration. Pure TypeScript so the SDK runs unchanged in
12
- * browsers, Artifact sandboxes and Node without a native dependency.
13
- */
14
- const CASTAGNOLI_REFLECTED = 0x82f63b78;
15
- function buildTables() {
16
- const tables = Array.from({ length: 8 }, () => new Uint32Array(256));
17
- const [base] = tables;
18
- for (let n = 0; n < 256; n++) {
19
- let c = n;
20
- for (let k = 0; k < 8; k++)
21
- c = c & 1 ? (c >>> 1) ^ CASTAGNOLI_REFLECTED : c >>> 1;
22
- base[n] = c;
23
- }
24
- for (let n = 0; n < 256; n++) {
25
- let c = base[n];
26
- for (let k = 1; k < 8; k++) {
27
- c = base[c & 0xff] ^ (c >>> 8);
28
- tables[k][n] = c;
29
- }
30
- }
31
- return tables;
32
- }
33
- const [T0, T1, T2, T3, T4, T5, T6, T7] = buildTables();
34
- /** Incremental CRC32C: `update` any split of the input, then `digest`. */
35
- class Crc32c {
36
- #crc = 0xffffffff;
37
- update(bytes) {
38
- let crc = this.#crc;
39
- let i = 0;
40
- const end8 = bytes.length - (bytes.length % 8);
41
- for (; i < end8; i += 8) {
42
- const low = crc ^
43
- (bytes[i] |
44
- (bytes[i + 1] << 8) |
45
- (bytes[i + 2] << 16) |
46
- (bytes[i + 3] << 24));
47
- crc =
48
- T7[low & 0xff] ^
49
- T6[(low >>> 8) & 0xff] ^
50
- T5[(low >>> 16) & 0xff] ^
51
- T4[low >>> 24] ^
52
- T3[bytes[i + 4]] ^
53
- T2[bytes[i + 5]] ^
54
- T1[bytes[i + 6]] ^
55
- T0[bytes[i + 7]];
56
- }
57
- for (; i < bytes.length; i++)
58
- crc = T0[(crc ^ bytes[i]) & 0xff] ^ (crc >>> 8);
59
- this.#crc = crc;
60
- return this;
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
61
7
  }
62
- /** The checksum of everything passed to `update` so far, as a uint32. */
63
- value() {
64
- return (this.#crc ^ 0xffffffff) >>> 0;
65
- }
66
- /** The checksum in GCS's encoding. Does not reset; `update` may continue. */
67
- digest() {
68
- const value = this.value();
69
- return btoa(String.fromCharCode(value >>> 24, (value >>> 16) & 0xff, (value >>> 8) & 0xff, value & 0xff));
70
- }
71
- }
72
- exports.Crc32c = Crc32c;
73
- /** One-shot CRC32C of `bytes` in GCS's base64 encoding. */
74
- function crc32c(bytes) {
75
- return new Crc32c().update(bytes).digest();
76
- }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
18
+ __exportStar(require("@sequenceholdings/platform/storage"), exports);
package/dist/index.d.ts CHANGED
@@ -1,6 +1,2 @@
1
- export * from './contracts.js';
2
- export * from './paths.js';
3
- export * from './client.js';
4
- export * from './transfer.js';
5
- export * from './crc32c.js';
6
- export * from './scope.js';
1
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
2
+ export * from "@sequenceholdings/platform/storage";
package/dist/index.js CHANGED
@@ -14,9 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./contracts.js"), exports);
18
- __exportStar(require("./paths.js"), exports);
19
- __exportStar(require("./client.js"), exports);
20
- __exportStar(require("./transfer.js"), exports);
21
- __exportStar(require("./crc32c.js"), exports);
22
- __exportStar(require("./scope.js"), exports);
17
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
18
+ __exportStar(require("@sequenceholdings/platform/storage"), exports);
package/dist/paths.d.ts CHANGED
@@ -1,4 +1,2 @@
1
- export declare const MAX_STORAGE_DEPTH = 16;
2
- /** Case-sensitive, NFC names. Paths never undergo URL decoding or traversal resolution. */
3
- export declare function normalizeStorageName(name: string): string;
4
- export declare function splitStoragePath(path: string): string[];
1
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
2
+ export * from "@sequenceholdings/platform/storage";
package/dist/paths.js CHANGED
@@ -1,28 +1,18 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MAX_STORAGE_DEPTH = void 0;
4
- exports.normalizeStorageName = normalizeStorageName;
5
- exports.splitStoragePath = splitStoragePath;
6
- // Leave room for role and group rewrites under OpenFGA’s 25-node resolve limit.
7
- // The maximum inherited chain is covered by authz/model.fga.yaml.
8
- exports.MAX_STORAGE_DEPTH = 16;
9
- /** Case-sensitive, NFC names. Paths never undergo URL decoding or traversal resolution. */
10
- function normalizeStorageName(name) {
11
- const normalized = name.normalize('NFC');
12
- if (!normalized ||
13
- normalized !== normalized.trim() ||
14
- normalized === '.' ||
15
- normalized === '..' ||
16
- /[\/\\\u0000-\u001f\u007f]/u.test(normalized) ||
17
- new TextEncoder().encode(normalized).byteLength > 255)
18
- throw new Error('Names must be 1–255 UTF-8 bytes, without separators, control characters, or surrounding whitespace');
19
- return normalized;
20
- }
21
- function splitStoragePath(path) {
22
- const parts = path.split('/');
23
- if (parts.length > exports.MAX_STORAGE_DEPTH ||
24
- new TextEncoder().encode(path).byteLength > 4096) {
25
- throw new Error(`Path exceeds the ${exports.MAX_STORAGE_DEPTH}-level or 4096-byte limit`);
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
26
7
  }
27
- return parts.map(normalizeStorageName);
28
- }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
18
+ __exportStar(require("@sequenceholdings/platform/storage"), exports);
package/dist/scope.d.ts CHANGED
@@ -1,15 +1,2 @@
1
- import { z } from 'zod';
2
- /** Maximum consumer reach. This declaration never grants resource permissions. */
3
- export declare const storageScopesSchema: z.ZodRecord<z.ZodUUID, z.ZodEnum<{
4
- viewer: "viewer";
5
- editor: "editor";
6
- admin: "admin";
7
- }>>;
8
- export type StorageScopes = z.infer<typeof storageScopesSchema>;
9
- export declare function readStorageScopes(manifest: unknown): StorageScopes;
10
- /** Catalog discovery and workspace provisioning are not delegated to consumers. */
11
- export declare function storageScopeAllows({ scopes, method, pathname, }: {
12
- scopes: StorageScopes;
13
- method: string;
14
- pathname: string;
15
- }): boolean;
1
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
2
+ export * from "@sequenceholdings/platform/storage";
package/dist/scope.js CHANGED
@@ -1,42 +1,18 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.storageScopesSchema = void 0;
4
- exports.readStorageScopes = readStorageScopes;
5
- exports.storageScopeAllows = storageScopeAllows;
6
- const zod_1 = require("zod");
7
- /** Maximum consumer reach. This declaration never grants resource permissions. */
8
- exports.storageScopesSchema = zod_1.z
9
- .record(zod_1.z.uuid(), zod_1.z.enum(['viewer', 'editor', 'admin']))
10
- .refine((value) => Object.keys(value).length <= 64, 'At most 64 workspace bindings');
11
- function readStorageScopes(manifest) {
12
- const parsed = zod_1.z
13
- .object({
14
- capabilities: zod_1.z
15
- .object({ storage: exports.storageScopesSchema.optional() })
16
- .optional(),
17
- })
18
- .safeParse(manifest);
19
- return parsed.success ? (parsed.data.capabilities?.storage ?? {}) : {};
20
- }
21
- /** Catalog discovery and workspace provisioning are not delegated to consumers. */
22
- function storageScopeAllows({ scopes, method, pathname, }) {
23
- const match = /^\/api\/storage\/workspaces\/([0-9a-f-]{36})(\/.*)?$/.exec(pathname);
24
- if (!match)
25
- return false;
26
- const role = scopes[match[1]];
27
- if (!role)
28
- return false;
29
- const suffix = match[2] ?? '';
30
- const upper = method.toUpperCase();
31
- if (suffix === '/owner' || (!suffix && upper !== 'GET'))
32
- return false;
33
- if (suffix.endsWith('/access'))
34
- return role === 'admin';
35
- if (suffix.endsWith('/purge') ||
36
- (/\/versions\/[0-9a-f-]+$/.test(suffix) && upper === 'DELETE') ||
37
- suffix.endsWith('/retry'))
38
- return role === 'admin';
39
- if (upper === 'GET' || (upper === 'POST' && suffix.endsWith('/download')))
40
- return true;
41
- return role === 'editor' || role === 'admin';
42
- }
17
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
18
+ __exportStar(require("@sequenceholdings/platform/storage"), exports);
@@ -1,34 +1,2 @@
1
- export type StorageUploadSource = Blob | ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>;
2
- export interface StorageTransferOptions {
3
- signal?: AbortSignal;
4
- onProgress?: (uploadedBytes: number) => void;
5
- fetch?: typeof fetch;
6
- /** Multiples of 256 KiB, between 256 KiB and 32 MiB. Defaults to 8 MiB. */
7
- chunkBytes?: number;
8
- /** Use one request for a small Blob. Large/streaming inputs remain chunked. */
9
- method?: 'simple' | 'resumable';
10
- }
11
- export interface StorageTransferResult {
12
- /**
13
- * CRC32C of the whole source as this call read it from byte zero, in GCS's
14
- * encoding. Pass it to upload completion so the server can compare it with
15
- * the stored object.
16
- */
17
- crc32c: string;
18
- }
19
- export declare class StorageTransferError extends Error {
20
- readonly status?: number | undefined;
21
- constructor(message: string, status?: number | undefined);
22
- }
23
- /**
24
- * Resume a session with the original source, starting at byte zero. The
25
- * acknowledged prefix is read again (and discarded with bounded memory) so the
26
- * returned CRC32C covers the whole object, not just the bytes this call sent.
27
- * Session URLs are bearer credentials: never persist them in logs or telemetry.
28
- */
29
- export declare function transferStorageUpload({ uploadUrl, source, size, maxBytes, ...options }: StorageTransferOptions & {
30
- uploadUrl: string;
31
- source: StorageUploadSource;
32
- size?: number;
33
- maxBytes: number;
34
- }): Promise<StorageTransferResult>;
1
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
2
+ export * from "@sequenceholdings/platform/storage";
package/dist/transfer.js CHANGED
@@ -1,265 +1,18 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StorageTransferError = void 0;
4
- exports.transferStorageUpload = transferStorageUpload;
5
- /** GCS sequential resumable transfer. No Atlas endpoint receives file bytes. */
6
- const crc32c_js_1 = require("./crc32c.js");
7
- class StorageTransferError extends Error {
8
- status;
9
- constructor(message, status) {
10
- super(message);
11
- this.status = status;
12
- this.name = 'StorageTransferError';
13
- }
14
- }
15
- exports.StorageTransferError = StorageTransferError;
16
- /** One dotless bucket label: Google's certificate covers `*.storage.googleapis.com` only. */
17
- const BUCKET_HOST = /^[a-z0-9][a-z0-9_-]{1,61}[a-z0-9]\.storage\.googleapis\.com$/;
18
- /**
19
- * A session URI is a bearer credential, so bytes go only to GCS's resumable
20
- * endpoints: the JSON API on the shared host, or an XML session on a bucket's
21
- * own host (Atlas issues those to agent sandboxes, whose egress allows only
22
- * their deployment's bucket host). The resumable protocol is the same on both.
23
- */
24
- function checkedUploadUrl(value) {
25
- const url = new URL(value);
26
- const jsonSession = url.hostname === 'storage.googleapis.com' && url.pathname.startsWith('/upload/');
27
- const bucketHostSession = BUCKET_HOST.test(url.hostname) && url.pathname !== '/';
28
- if (url.protocol !== 'https:' ||
29
- !(jsonSession || bucketHostSession) ||
30
- !url.searchParams.has('upload_id') ||
31
- url.port ||
32
- url.username ||
33
- url.password) {
34
- throw new StorageTransferError('Invalid storage upload destination');
35
- }
36
- return url.href;
37
- }
38
- async function* bytes(source) {
39
- if (source instanceof Blob || source instanceof ReadableStream) {
40
- const reader = (source instanceof Blob ? source.stream() : source).getReader();
41
- try {
42
- for (;;) {
43
- const part = await reader.read();
44
- if (part.done)
45
- return;
46
- yield part.value;
47
- }
48
- }
49
- finally {
50
- await reader.cancel().catch(() => { });
51
- reader.releaseLock();
52
- }
53
- }
54
- else {
55
- yield* source;
56
- }
57
- }
58
- /**
59
- * Retain at most two fixed-size chunks, independent of total file size. Every
60
- * source byte is hashed as it is read, including the acknowledged prefix a
61
- * resume skips: the digest describes the object the source says it is, so a
62
- * source that yields different bytes on re-read cannot match what GCS stored.
63
- */
64
- async function* chunks(source, size, skip, hash, signal) {
65
- let buffer = new Uint8Array(size);
66
- let used = 0;
67
- for await (const input of bytes(source)) {
68
- signal?.throwIfAborted();
69
- hash.update(input);
70
- let position = Math.min(skip, input.byteLength);
71
- skip -= position;
72
- while (position < input.byteLength) {
73
- const length = Math.min(size - used, input.byteLength - position);
74
- buffer.set(input.subarray(position, position + length), used);
75
- used += length;
76
- position += length;
77
- if (used === size) {
78
- yield buffer;
79
- buffer = new Uint8Array(size);
80
- used = 0;
81
- }
82
- }
83
- }
84
- if (skip)
85
- throw new StorageTransferError('Upload source is shorter than the saved offset');
86
- if (used)
87
- yield buffer.subarray(0, used);
88
- }
89
- function receivedOffset(response) {
90
- const range = response.headers.get('Range');
91
- if (!range)
92
- return 0;
93
- const match = /^bytes=0-(\d+)$/.exec(range);
94
- const offset = match ? Number(match[1]) + 1 : NaN;
95
- if (!Number.isSafeInteger(offset) || offset < 1)
96
- throw new StorageTransferError('Storage returned an invalid upload offset');
97
- return offset;
98
- }
99
- // GCS uses 308 for upload progress. Fetch treats it as a redirect; Google's
100
- // no-308 protocol preserves the acknowledgement without following a Location.
101
- function incomplete(response) {
102
- return (response.status === 308 ||
103
- response.headers.get('X-Http-Status-Code-Override') === '308');
104
- }
105
- function retryable(status) {
106
- return status === 408 || status === 429 || status >= 500;
107
- }
108
- async function delay(attempt, signal) {
109
- signal?.throwIfAborted();
110
- await new Promise((resolve, reject) => {
111
- const timer = setTimeout(() => {
112
- signal?.removeEventListener('abort', abort);
113
- resolve();
114
- }, Math.min(250 * 2 ** attempt, 4000));
115
- const abort = () => {
116
- clearTimeout(timer);
117
- reject(signal?.reason ?? new Error('Upload cancelled'));
118
- };
119
- signal?.addEventListener('abort', abort, { once: true });
120
- });
121
- }
122
- async function digest(source, signal) {
123
- const hash = new crc32c_js_1.Crc32c();
124
- for await (const input of bytes(source)) {
125
- signal?.throwIfAborted();
126
- hash.update(input);
127
- }
128
- return hash.digest();
129
- }
130
- /**
131
- * Resume a session with the original source, starting at byte zero. The
132
- * acknowledged prefix is read again (and discarded with bounded memory) so the
133
- * returned CRC32C covers the whole object, not just the bytes this call sent.
134
- * Session URLs are bearer credentials: never persist them in logs or telemetry.
135
- */
136
- async function transferStorageUpload({ uploadUrl, source, size, maxBytes, ...options }) {
137
- const url = checkedUploadUrl(uploadUrl);
138
- const fetcher = options.fetch ?? globalThis.fetch;
139
- const total = source instanceof Blob ? source.size : size;
140
- if (total !== undefined && (!Number.isSafeInteger(total) || total < 0 || total > maxBytes))
141
- throw new StorageTransferError(`Upload source is ${total} bytes, above the ${maxBytes}-byte reservation`);
142
- let chunkBytes = options.chunkBytes ?? 8 * 1024 * 1024;
143
- if (chunkBytes < 262144 ||
144
- chunkBytes > 32 * 1024 * 1024 ||
145
- chunkBytes % 262144)
146
- throw new StorageTransferError('Invalid upload chunk size');
147
- if (options.method === 'simple' &&
148
- source instanceof Blob &&
149
- source.size <= 32 * 1024 * 1024)
150
- chunkBytes = Math.max(262144, Math.ceil(source.size / 262144) * 262144);
151
- async function probe() {
152
- for (let attempt = 0;; attempt++) {
153
- let response;
154
- try {
155
- response = await fetcher(url, {
156
- method: 'PUT',
157
- headers: {
158
- 'X-GUploader-No-308': 'yes',
159
- 'Content-Range': `bytes */${total ?? '*'}`,
160
- },
161
- body: new Uint8Array(),
162
- signal: options.signal,
163
- redirect: 'error',
164
- });
165
- }
166
- catch {
167
- options.signal?.throwIfAborted();
168
- if (attempt >= 4)
169
- throw new StorageTransferError('Upload status is unavailable; resume this session later');
170
- await delay(attempt, options.signal);
171
- continue;
172
- }
173
- if (response.ok && !incomplete(response))
174
- return { offset: total ?? 0, complete: true };
175
- if (incomplete(response))
176
- return { offset: receivedOffset(response), complete: false };
177
- if (!retryable(response.status) || attempt >= 4)
178
- throw new StorageTransferError('Upload session is unavailable or expired', response.status);
179
- await delay(attempt, options.signal);
180
- }
181
- }
182
- const initial = await probe();
183
- if (initial.complete) {
184
- if (total !== undefined)
185
- options.onProgress?.(total);
186
- // An earlier call finalized the object; nothing is sent, but the checksum
187
- // must still describe the source so completion can compare it.
188
- return { crc32c: await digest(source, options.signal) };
189
- }
190
- let offset = initial.offset;
191
- if (offset > maxBytes || (total !== undefined && offset > total))
192
- throw new StorageTransferError(`Upload session offset is ${offset} bytes, past the source${total === undefined ? '' : ` of ${total} bytes`} and the ${maxBytes}-byte reservation`);
193
- options.onProgress?.(offset);
194
- const hash = new crc32c_js_1.Crc32c();
195
- const iterable = chunks(source, chunkBytes, offset, hash, options.signal);
196
- const iterator = iterable[Symbol.asyncIterator]();
197
- try {
198
- let current = await iterator.next();
199
- for (;;) {
200
- const next = current.done ? current : await iterator.next();
201
- const chunk = current.done ? new Uint8Array() : current.value;
202
- const end = offset + chunk.byteLength;
203
- const last = Boolean(next.done);
204
- if (total === undefined && end > maxBytes)
205
- throw new StorageTransferError(`Upload stream exceeds its ${maxBytes}-byte reservation; declare \`size\` when starting the upload to send a larger file`);
206
- if (end > maxBytes ||
207
- (total !== undefined && (end > total || (last && end !== total))))
208
- throw new StorageTransferError(`Upload source does not match its reserved size: session offset ${offset} bytes, read ${end} bytes, reservation ${maxBytes} bytes${total === undefined ? '' : `, declared ${total} bytes`}`);
209
- const length = total ?? (last ? end : '*');
210
- let acknowledged = offset;
211
- for (let attempt = 0;; attempt++) {
212
- options.signal?.throwIfAborted();
213
- let response;
214
- try {
215
- response = await fetcher(url, {
216
- method: 'PUT',
217
- signal: options.signal,
218
- redirect: 'error',
219
- headers: {
220
- 'X-GUploader-No-308': 'yes',
221
- 'Content-Range': chunk.byteLength
222
- ? `bytes ${acknowledged}-${end - 1}/${length}`
223
- : `bytes */${length}`,
224
- },
225
- body: new Uint8Array(chunk.subarray(acknowledged - offset)),
226
- });
227
- }
228
- catch {
229
- options.signal?.throwIfAborted();
230
- }
231
- if (response?.ok && !incomplete(response)) {
232
- if (!last)
233
- throw new StorageTransferError('Storage completed before the source ended');
234
- options.onProgress?.(end);
235
- return { crc32c: hash.digest() };
236
- }
237
- if (response && !incomplete(response) && !retryable(response.status))
238
- throw new StorageTransferError('Storage rejected the upload chunk', response.status);
239
- const status = response && incomplete(response)
240
- ? { offset: receivedOffset(response), complete: false }
241
- : await probe();
242
- if (status.complete) {
243
- if (!last)
244
- throw new StorageTransferError('Storage completed before the source ended');
245
- options.onProgress?.(end);
246
- return { crc32c: hash.digest() };
247
- }
248
- if (status.offset < acknowledged || status.offset > end)
249
- throw new StorageTransferError('Storage returned an inconsistent upload offset');
250
- acknowledged = status.offset;
251
- options.onProgress?.(acknowledged);
252
- if (acknowledged === end && !last)
253
- break;
254
- if (attempt >= 4)
255
- throw new StorageTransferError('Upload interrupted; resume this session to continue');
256
- await delay(attempt, options.signal);
257
- }
258
- offset = end;
259
- current = next;
260
- }
261
- }
262
- finally {
263
- await iterator.return(undefined);
264
- }
265
- }
17
+ /** Runtime compatibility export; implementation lives in the platform SDK. */
18
+ __exportStar(require("@sequenceholdings/platform/storage"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sequenceholdings/storage",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Atlas workspace storage contracts and streaming client",
5
5
  "license": "UNLICENSED",
6
6
  "type": "commonjs",
@@ -18,7 +18,8 @@
18
18
  "README.md"
19
19
  ],
20
20
  "dependencies": {
21
- "zod": "^4.1.13"
21
+ "zod": "^4.1.13",
22
+ "@sequenceholdings/platform": "0.1.0"
22
23
  },
23
24
  "devDependencies": {
24
25
  "typescript": "^5.3.3",