@syncular/transport-http 0.0.1-106 → 0.0.1-109
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/index.d.ts.map +1 -1
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/transport-options.test.ts +48 -0
- package/src/index.ts +99 -0
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAGV,aAAa,EAGd,MAAM,gBAAgB,CAAC;AAExB,OAAO,YAAY,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAE7C,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AA+BxB,wBAAsB,MAAM,CAAC,CAAC,EAC5B,OAAO,EAAE,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAC9C,OAAO,CAAC,CAAC,CAAC,CAMZ;AA6BD,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;OAGG;IACH,aAAa,CAAC,EAAE,iBAAiB,CAAC;CACnC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAGV,aAAa,EAGd,MAAM,gBAAgB,CAAC;AAExB,OAAO,YAAY,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAE7C,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AA+BxB,wBAAsB,MAAM,CAAC,CAAC,EAC5B,OAAO,EAAE,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAC9C,OAAO,CAAC,CAAC,CAAC,CAMZ;AA6BD,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;OAGG;IACH,aAAa,CAAC,EAAE,iBAAiB,CAAC;CACnC;AA0BD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,UAAU,CA2BlE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CACjC,eAAe,EAAE,UAAU,GAAG,aAAa,GAC1C,aAAa,CA6Lf"}
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,25 @@ async function executeWithAuthRetry(execute, options) {
|
|
|
54
54
|
}
|
|
55
55
|
return execute(options.signal);
|
|
56
56
|
}
|
|
57
|
+
function resolveRequestUrl(baseUrl, path) {
|
|
58
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
59
|
+
const isAbsolute = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(baseUrl);
|
|
60
|
+
if (isAbsolute) {
|
|
61
|
+
return new URL(normalizedPath, baseUrl).toString();
|
|
62
|
+
}
|
|
63
|
+
if (typeof location === 'undefined') {
|
|
64
|
+
return `${baseUrl.replace(/\/$/, '')}${normalizedPath}`;
|
|
65
|
+
}
|
|
66
|
+
return new URL(`${baseUrl.replace(/\/$/, '')}${normalizedPath}`, location.origin).toString();
|
|
67
|
+
}
|
|
68
|
+
function bytesToReadableStream(bytes) {
|
|
69
|
+
return new ReadableStream({
|
|
70
|
+
start(controller) {
|
|
71
|
+
controller.enqueue(bytes);
|
|
72
|
+
controller.close();
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
57
76
|
/**
|
|
58
77
|
* Create a typed API client for the full Syncular API.
|
|
59
78
|
*
|
|
@@ -124,6 +143,7 @@ export function createHttpTransport(clientOrOptions) {
|
|
|
124
143
|
const client = 'GET' in clientOrOptions
|
|
125
144
|
? clientOrOptions
|
|
126
145
|
: createApiClient(clientOrOptions);
|
|
146
|
+
const transportOptions = 'GET' in clientOrOptions ? undefined : clientOrOptions;
|
|
127
147
|
// Create blob operations using the typed OpenAPI client
|
|
128
148
|
const blobs = {
|
|
129
149
|
async initiateUpload(args) {
|
|
@@ -182,6 +202,55 @@ export function createHttpTransport(clientOrOptions) {
|
|
|
182
202
|
}
|
|
183
203
|
return new Uint8Array(await data.arrayBuffer());
|
|
184
204
|
},
|
|
205
|
+
async fetchSnapshotChunkStream(request, options) {
|
|
206
|
+
if (!transportOptions) {
|
|
207
|
+
const bytes = await this.fetchSnapshotChunk(request, options);
|
|
208
|
+
return bytesToReadableStream(bytes);
|
|
209
|
+
}
|
|
210
|
+
const fetchImpl = transportOptions.fetch ?? globalThis.fetch;
|
|
211
|
+
const requestUrl = resolveRequestUrl(transportOptions.baseUrl, `/sync/snapshot-chunks/${encodeURIComponent(request.chunkId)}`);
|
|
212
|
+
const performRequest = async (signal) => {
|
|
213
|
+
const headers = new Headers();
|
|
214
|
+
const extraHeaders = await transportOptions.getHeaders?.();
|
|
215
|
+
if (extraHeaders) {
|
|
216
|
+
for (const [key, value] of Object.entries(extraHeaders)) {
|
|
217
|
+
headers.set(key, value);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (!headers.has('x-syncular-transport-path')) {
|
|
221
|
+
headers.set('x-syncular-transport-path', transportOptions.transportPath ?? 'direct');
|
|
222
|
+
}
|
|
223
|
+
return fetchImpl(requestUrl, {
|
|
224
|
+
method: 'GET',
|
|
225
|
+
headers,
|
|
226
|
+
...(signal ? { signal } : {}),
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
let response = await performRequest(options?.signal);
|
|
230
|
+
if ((response.status === 401 || response.status === 403) &&
|
|
231
|
+
options?.onAuthError) {
|
|
232
|
+
const shouldRetry = await options.onAuthError();
|
|
233
|
+
if (shouldRetry) {
|
|
234
|
+
response = await performRequest(options.signal);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
let reason = response.statusText || 'Request failed';
|
|
239
|
+
try {
|
|
240
|
+
const maybeJson = (await response.json());
|
|
241
|
+
reason = getErrorMessage(maybeJson) || reason;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// ignore parse failures
|
|
245
|
+
}
|
|
246
|
+
throw new SyncTransportError(`Snapshot chunk download failed: ${reason}`, response.status);
|
|
247
|
+
}
|
|
248
|
+
if (!response.body) {
|
|
249
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
250
|
+
return bytesToReadableStream(bytes);
|
|
251
|
+
}
|
|
252
|
+
return response.body;
|
|
253
|
+
},
|
|
185
254
|
// Include blob operations
|
|
186
255
|
blobs,
|
|
187
256
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -147,4 +147,52 @@ describe('createHttpTransport SyncTransportOptions', () => {
|
|
|
147
147
|
expect(seenSignals[0]).toBe(controller.signal);
|
|
148
148
|
expect(seenSignals[1]).toBe(controller.signal);
|
|
149
149
|
});
|
|
150
|
+
|
|
151
|
+
it('streams snapshot chunk fetch with auth retry support', async () => {
|
|
152
|
+
let requestCount = 0;
|
|
153
|
+
let authErrorCount = 0;
|
|
154
|
+
|
|
155
|
+
const transport = createHttpTransport({
|
|
156
|
+
baseUrl: 'http://localhost',
|
|
157
|
+
fetch: async () => {
|
|
158
|
+
requestCount += 1;
|
|
159
|
+
if (requestCount === 1) {
|
|
160
|
+
return new Response(JSON.stringify({ error: 'UNAUTHENTICATED' }), {
|
|
161
|
+
status: 401,
|
|
162
|
+
headers: { 'content-type': 'application/json' },
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return new Response(new Uint8Array([9, 8, 7]), {
|
|
167
|
+
status: 200,
|
|
168
|
+
headers: { 'content-type': 'application/octet-stream' },
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const stream = await transport.fetchSnapshotChunkStream?.(
|
|
174
|
+
{ chunkId: 'chunk-2' },
|
|
175
|
+
{
|
|
176
|
+
onAuthError: async () => {
|
|
177
|
+
authErrorCount += 1;
|
|
178
|
+
return true;
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
expect(stream).toBeDefined();
|
|
184
|
+
const reader = stream!.getReader();
|
|
185
|
+
const collected: number[] = [];
|
|
186
|
+
while (true) {
|
|
187
|
+
const { done, value } = await reader.read();
|
|
188
|
+
if (done) break;
|
|
189
|
+
if (!value) continue;
|
|
190
|
+
collected.push(...value);
|
|
191
|
+
}
|
|
192
|
+
reader.releaseLock();
|
|
193
|
+
|
|
194
|
+
expect(collected).toEqual([9, 8, 7]);
|
|
195
|
+
expect(requestCount).toBe(2);
|
|
196
|
+
expect(authErrorCount).toBe(1);
|
|
197
|
+
});
|
|
150
198
|
});
|
package/src/index.ts
CHANGED
|
@@ -104,6 +104,30 @@ export interface ClientOptions {
|
|
|
104
104
|
transportPath?: SyncTransportPath;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
function resolveRequestUrl(baseUrl: string, path: string): string {
|
|
108
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
109
|
+
const isAbsolute = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(baseUrl);
|
|
110
|
+
if (isAbsolute) {
|
|
111
|
+
return new URL(normalizedPath, baseUrl).toString();
|
|
112
|
+
}
|
|
113
|
+
if (typeof location === 'undefined') {
|
|
114
|
+
return `${baseUrl.replace(/\/$/, '')}${normalizedPath}`;
|
|
115
|
+
}
|
|
116
|
+
return new URL(
|
|
117
|
+
`${baseUrl.replace(/\/$/, '')}${normalizedPath}`,
|
|
118
|
+
location.origin
|
|
119
|
+
).toString();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function bytesToReadableStream(bytes: Uint8Array): ReadableStream<Uint8Array> {
|
|
123
|
+
return new ReadableStream<Uint8Array>({
|
|
124
|
+
start(controller) {
|
|
125
|
+
controller.enqueue(bytes);
|
|
126
|
+
controller.close();
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
107
131
|
/**
|
|
108
132
|
* Create a typed API client for the full Syncular API.
|
|
109
133
|
*
|
|
@@ -183,6 +207,8 @@ export function createHttpTransport(
|
|
|
183
207
|
'GET' in clientOrOptions
|
|
184
208
|
? clientOrOptions
|
|
185
209
|
: createApiClient(clientOrOptions);
|
|
210
|
+
const transportOptions =
|
|
211
|
+
'GET' in clientOrOptions ? undefined : clientOrOptions;
|
|
186
212
|
|
|
187
213
|
// Create blob operations using the typed OpenAPI client
|
|
188
214
|
const blobs: SyncTransportBlobs = {
|
|
@@ -289,6 +315,79 @@ export function createHttpTransport(
|
|
|
289
315
|
return new Uint8Array(await (data as Blob).arrayBuffer());
|
|
290
316
|
},
|
|
291
317
|
|
|
318
|
+
async fetchSnapshotChunkStream(
|
|
319
|
+
request: { chunkId: string },
|
|
320
|
+
options?: SyncTransportOptions
|
|
321
|
+
): Promise<ReadableStream<Uint8Array>> {
|
|
322
|
+
if (!transportOptions) {
|
|
323
|
+
const bytes = await this.fetchSnapshotChunk(request, options);
|
|
324
|
+
return bytesToReadableStream(bytes);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const fetchImpl = transportOptions.fetch ?? globalThis.fetch;
|
|
328
|
+
const requestUrl = resolveRequestUrl(
|
|
329
|
+
transportOptions.baseUrl,
|
|
330
|
+
`/sync/snapshot-chunks/${encodeURIComponent(request.chunkId)}`
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
const performRequest = async (
|
|
334
|
+
signal?: AbortSignal
|
|
335
|
+
): Promise<Response> => {
|
|
336
|
+
const headers = new Headers();
|
|
337
|
+
const extraHeaders = await transportOptions.getHeaders?.();
|
|
338
|
+
if (extraHeaders) {
|
|
339
|
+
for (const [key, value] of Object.entries(extraHeaders)) {
|
|
340
|
+
headers.set(key, value);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (!headers.has('x-syncular-transport-path')) {
|
|
344
|
+
headers.set(
|
|
345
|
+
'x-syncular-transport-path',
|
|
346
|
+
transportOptions.transportPath ?? 'direct'
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
return fetchImpl(requestUrl, {
|
|
350
|
+
method: 'GET',
|
|
351
|
+
headers,
|
|
352
|
+
...(signal ? { signal } : {}),
|
|
353
|
+
});
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
let response = await performRequest(options?.signal);
|
|
357
|
+
if (
|
|
358
|
+
(response.status === 401 || response.status === 403) &&
|
|
359
|
+
options?.onAuthError
|
|
360
|
+
) {
|
|
361
|
+
const shouldRetry = await options.onAuthError();
|
|
362
|
+
if (shouldRetry) {
|
|
363
|
+
response = await performRequest(options.signal);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (!response.ok) {
|
|
368
|
+
let reason = response.statusText || 'Request failed';
|
|
369
|
+
try {
|
|
370
|
+
const maybeJson = (await response.json()) as
|
|
371
|
+
| { error?: unknown; message?: unknown }
|
|
372
|
+
| undefined;
|
|
373
|
+
reason = getErrorMessage(maybeJson) || reason;
|
|
374
|
+
} catch {
|
|
375
|
+
// ignore parse failures
|
|
376
|
+
}
|
|
377
|
+
throw new SyncTransportError(
|
|
378
|
+
`Snapshot chunk download failed: ${reason}`,
|
|
379
|
+
response.status
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (!response.body) {
|
|
384
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
385
|
+
return bytesToReadableStream(bytes);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return response.body as ReadableStream<Uint8Array>;
|
|
389
|
+
},
|
|
390
|
+
|
|
292
391
|
// Include blob operations
|
|
293
392
|
blobs,
|
|
294
393
|
};
|