@syncular/transport-http 0.0.2-2 → 0.0.3-12

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 CHANGED
@@ -16,6 +16,13 @@ import { createHttpTransport } from '@syncular/transport-http';
16
16
  const transport = createHttpTransport({
17
17
  baseUrl: 'https://api.example.com',
18
18
  getHeaders: () => ({ Authorization: `Bearer ${token}` }),
19
+ authLifecycle: {
20
+ onAuthExpired: ({ operation, status }) => {
21
+ console.warn('Auth expired', operation, status);
22
+ },
23
+ refreshToken: async () => auth.refreshToken(),
24
+ retryWithFreshToken: ({ refreshResult }) => refreshResult,
25
+ },
19
26
  });
20
27
  ```
21
28
 
package/dist/index.d.ts CHANGED
@@ -3,10 +3,10 @@
3
3
  *
4
4
  * Provides typed API clients using openapi-fetch with auto-generated types.
5
5
  */
6
- import type { SyncTransport } from '@syncular/core';
6
+ import type { SyncAuthLifecycle, SyncTransport } from '@syncular/core';
7
7
  import createClient from 'openapi-fetch';
8
8
  import type { paths } from './generated/api';
9
- export type { SyncTransport, SyncTransportBlobs, SyncTransportOptions, } from '@syncular/core';
9
+ export type { SyncAuthErrorContext, SyncAuthLifecycle, SyncAuthOperation, SyncTransport, SyncTransportBlobs, SyncTransportOptions, } from '@syncular/core';
10
10
  export declare function unwrap<T>(promise: Promise<{
11
11
  data?: T;
12
12
  error?: unknown;
@@ -18,6 +18,8 @@ export interface ClientOptions {
18
18
  baseUrl: string;
19
19
  /** Function to get headers for requests (e.g., for auth tokens) */
20
20
  getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
21
+ /** Shared auth lifecycle for all transport operations. */
22
+ authLifecycle?: SyncAuthLifecycle;
21
23
  /** Custom fetch implementation (defaults to globalThis.fetch) */
22
24
  fetch?: typeof globalThis.fetch;
23
25
  /**
@@ -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;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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,iBAAiB,EAIjB,aAAa,EAGd,MAAM,gBAAgB,CAAC;AAExB,OAAO,YAAY,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAE7C,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,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;AAmCD,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,0DAA0D;IAC1D,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,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,CA0Pf"}
package/dist/index.js CHANGED
@@ -40,19 +40,16 @@ export async function unwrap(promise) {
40
40
  }
41
41
  return data;
42
42
  }
43
- async function executeWithAuthRetry(execute, options) {
43
+ async function executeWithAuthRetry(execute, options, operation, resolveAuthRetry) {
44
44
  const first = await execute(options?.signal);
45
45
  if (first.response.status !== 401 && first.response.status !== 403) {
46
46
  return first;
47
47
  }
48
- if (!options?.onAuthError) {
49
- return first;
50
- }
51
- const shouldRetry = await options.onAuthError();
48
+ const shouldRetry = await resolveAuthRetry({ operation, status: first.response.status }, options);
52
49
  if (!shouldRetry) {
53
50
  return first;
54
51
  }
55
- return execute(options.signal);
52
+ return execute(options?.signal);
56
53
  }
57
54
  function resolveRequestUrl(baseUrl, path) {
58
55
  const normalizedPath = path.startsWith('/') ? path : `/${path}`;
@@ -144,21 +141,51 @@ export function createHttpTransport(clientOrOptions) {
144
141
  ? clientOrOptions
145
142
  : createApiClient(clientOrOptions);
146
143
  const transportOptions = 'GET' in clientOrOptions ? undefined : clientOrOptions;
144
+ const defaultAuthLifecycle = transportOptions?.authLifecycle;
145
+ let refreshInFlight = null;
146
+ const runRefreshSingleFlight = async (lifecycle, context) => {
147
+ if (!lifecycle.refreshToken)
148
+ return false;
149
+ if (!refreshInFlight) {
150
+ refreshInFlight = Promise.resolve(lifecycle.refreshToken(context))
151
+ .then((result) => Boolean(result))
152
+ .finally(() => {
153
+ refreshInFlight = null;
154
+ });
155
+ }
156
+ return refreshInFlight;
157
+ };
158
+ const resolveAuthRetry = async (context, options) => {
159
+ if (options?.onAuthError) {
160
+ return Boolean(await options.onAuthError());
161
+ }
162
+ const lifecycle = options?.authLifecycle ?? defaultAuthLifecycle;
163
+ if (!lifecycle)
164
+ return false;
165
+ await lifecycle.onAuthExpired?.(context);
166
+ const refreshResult = await runRefreshSingleFlight(lifecycle, context);
167
+ if (lifecycle.retryWithFreshToken) {
168
+ return Boolean(await lifecycle.retryWithFreshToken({ ...context, refreshResult }));
169
+ }
170
+ return refreshResult;
171
+ };
147
172
  // Create blob operations using the typed OpenAPI client
148
173
  const blobs = {
149
174
  async initiateUpload(args) {
150
- const { data, error, response } = await client.POST('/sync/blobs/upload', {
175
+ const { data, error, response } = await executeWithAuthRetry((signal) => client.POST('/sync/blobs/upload', {
151
176
  body: args,
152
- });
177
+ ...(signal ? { signal } : {}),
178
+ }), undefined, 'blobInitiateUpload', resolveAuthRetry);
153
179
  if (error || !data) {
154
180
  throw new SyncTransportError(`Blob upload init failed: ${getErrorMessage(error) || response.statusText}`, response.status);
155
181
  }
156
182
  return data;
157
183
  },
158
184
  async completeUpload(hash) {
159
- const { data, error } = await client.POST('/sync/blobs/{hash}/complete', {
185
+ const { data, error } = await executeWithAuthRetry((signal) => client.POST('/sync/blobs/{hash}/complete', {
160
186
  params: { path: { hash } },
161
- });
187
+ ...(signal ? { signal } : {}),
188
+ }), undefined, 'blobCompleteUpload', resolveAuthRetry);
162
189
  if (error || !data) {
163
190
  return {
164
191
  ok: false,
@@ -168,9 +195,10 @@ export function createHttpTransport(clientOrOptions) {
168
195
  return data;
169
196
  },
170
197
  async getDownloadUrl(hash) {
171
- const { data, error, response } = await client.GET('/sync/blobs/{hash}/url', {
198
+ const { data, error, response } = await executeWithAuthRetry((signal) => client.GET('/sync/blobs/{hash}/url', {
172
199
  params: { path: { hash } },
173
- });
200
+ ...(signal ? { signal } : {}),
201
+ }), undefined, 'blobGetDownloadUrl', resolveAuthRetry);
174
202
  if (error || !data) {
175
203
  throw new SyncTransportError(`Get download URL failed: ${getErrorMessage(error) || response.statusText}`, response.status);
176
204
  }
@@ -185,7 +213,7 @@ export function createHttpTransport(clientOrOptions) {
185
213
  const { data, error, response } = await executeWithAuthRetry((signal) => client.POST('/sync', {
186
214
  body: request,
187
215
  ...(signal ? { signal } : {}),
188
- }), transportOptions);
216
+ }), transportOptions, 'sync', resolveAuthRetry);
189
217
  if (error || !data) {
190
218
  throw new SyncTransportError(`Sync failed: ${getErrorMessage(error) || response.statusText}`, response.status);
191
219
  }
@@ -196,7 +224,7 @@ export function createHttpTransport(clientOrOptions) {
196
224
  params: { path: { chunkId: request.chunkId } },
197
225
  parseAs: 'blob',
198
226
  ...(signal ? { signal } : {}),
199
- }), transportOptions);
227
+ }), transportOptions, 'snapshotChunk', resolveAuthRetry);
200
228
  if (error || !data) {
201
229
  throw new SyncTransportError(`Snapshot chunk download failed: ${getErrorMessage(error) || response.statusText}`, response.status);
202
230
  }
@@ -227,11 +255,13 @@ export function createHttpTransport(clientOrOptions) {
227
255
  });
228
256
  };
229
257
  let response = await performRequest(options?.signal);
230
- if ((response.status === 401 || response.status === 403) &&
231
- options?.onAuthError) {
232
- const shouldRetry = await options.onAuthError();
258
+ if (response.status === 401 || response.status === 403) {
259
+ const shouldRetry = await resolveAuthRetry({
260
+ operation: 'snapshotChunkStream',
261
+ status: response.status,
262
+ }, options);
233
263
  if (shouldRetry) {
234
- response = await performRequest(options.signal);
264
+ response = await performRequest(options?.signal);
235
265
  }
236
266
  }
237
267
  if (!response.ok) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/transport-http",
3
- "version": "0.0.2-2",
3
+ "version": "0.0.3-12",
4
4
  "description": "HTTP transport for Syncular client-server communication",
5
5
  "license": "MIT",
6
6
  "author": "Benjamin Kniffler",
@@ -43,7 +43,7 @@
43
43
  "release": "bunx syncular-publish"
44
44
  },
45
45
  "dependencies": {
46
- "@syncular/core": "0.0.2-2",
46
+ "@syncular/core": "0.0.3-12",
47
47
  "openapi-fetch": "^0.17.0"
48
48
  },
49
49
  "devDependencies": {
@@ -195,4 +195,195 @@ describe('createHttpTransport SyncTransportOptions', () => {
195
195
  expect(requestCount).toBe(2);
196
196
  expect(authErrorCount).toBe(1);
197
197
  });
198
+
199
+ it('supports auth lifecycle callbacks on 401/403', async () => {
200
+ let requestCount = 0;
201
+ let authExpiredCount = 0;
202
+ let refreshCount = 0;
203
+ let retryCount = 0;
204
+
205
+ const transport = createHttpTransport({
206
+ baseUrl: 'http://localhost',
207
+ authLifecycle: {
208
+ onAuthExpired: async (context) => {
209
+ authExpiredCount += 1;
210
+ expect(context.operation).toBe('sync');
211
+ expect(context.status).toBe(401);
212
+ },
213
+ refreshToken: async (context) => {
214
+ refreshCount += 1;
215
+ expect(context.operation).toBe('sync');
216
+ expect(context.status).toBe(401);
217
+ return true;
218
+ },
219
+ retryWithFreshToken: async (context) => {
220
+ retryCount += 1;
221
+ expect(context.operation).toBe('sync');
222
+ expect(context.status).toBe(401);
223
+ expect(context.refreshResult).toBe(true);
224
+ return context.refreshResult;
225
+ },
226
+ },
227
+ fetch: async () => {
228
+ requestCount += 1;
229
+ if (requestCount === 1) {
230
+ return new Response(JSON.stringify({ error: 'UNAUTHENTICATED' }), {
231
+ status: 401,
232
+ headers: { 'content-type': 'application/json' },
233
+ });
234
+ }
235
+ return new Response(
236
+ JSON.stringify({ ok: true, pull: { ok: true, subscriptions: [] } }),
237
+ {
238
+ status: 200,
239
+ headers: { 'content-type': 'application/json' },
240
+ }
241
+ );
242
+ },
243
+ });
244
+
245
+ const response = await transport.sync({
246
+ clientId: 'client-1',
247
+ pull: { limitCommits: 10, subscriptions: [] },
248
+ });
249
+
250
+ expect(response.ok).toBe(true);
251
+ expect(requestCount).toBe(2);
252
+ expect(authExpiredCount).toBe(1);
253
+ expect(refreshCount).toBe(1);
254
+ expect(retryCount).toBe(1);
255
+ });
256
+
257
+ it('deduplicates concurrent token refresh requests', async () => {
258
+ let requestCount = 0;
259
+ let refreshCount = 0;
260
+
261
+ const transport = createHttpTransport({
262
+ baseUrl: 'http://localhost',
263
+ authLifecycle: {
264
+ refreshToken: async () => {
265
+ refreshCount += 1;
266
+ await new Promise((resolve) => setTimeout(resolve, 5));
267
+ return true;
268
+ },
269
+ },
270
+ fetch: async () => {
271
+ requestCount += 1;
272
+ if (requestCount <= 2) {
273
+ return new Response(JSON.stringify({ error: 'UNAUTHENTICATED' }), {
274
+ status: 401,
275
+ headers: { 'content-type': 'application/json' },
276
+ });
277
+ }
278
+ return new Response(
279
+ JSON.stringify({ ok: true, pull: { ok: true, subscriptions: [] } }),
280
+ {
281
+ status: 200,
282
+ headers: { 'content-type': 'application/json' },
283
+ }
284
+ );
285
+ },
286
+ });
287
+
288
+ const [first, second] = await Promise.all([
289
+ transport.sync({
290
+ clientId: 'client-a',
291
+ pull: { limitCommits: 10, subscriptions: [] },
292
+ }),
293
+ transport.sync({
294
+ clientId: 'client-b',
295
+ pull: { limitCommits: 10, subscriptions: [] },
296
+ }),
297
+ ]);
298
+
299
+ expect(first.ok).toBe(true);
300
+ expect(second.ok).toBe(true);
301
+ expect(refreshCount).toBe(1);
302
+ expect(requestCount).toBe(4);
303
+ });
304
+
305
+ it('prioritizes per-call onAuthError over shared auth lifecycle', async () => {
306
+ let legacyCount = 0;
307
+ let refreshCount = 0;
308
+
309
+ const transport = createHttpTransport({
310
+ baseUrl: 'http://localhost',
311
+ authLifecycle: {
312
+ refreshToken: async () => {
313
+ refreshCount += 1;
314
+ return true;
315
+ },
316
+ },
317
+ fetch: async () =>
318
+ new Response(JSON.stringify({ error: 'UNAUTHENTICATED' }), {
319
+ status: 401,
320
+ headers: { 'content-type': 'application/json' },
321
+ }),
322
+ });
323
+
324
+ await expect(
325
+ transport.sync(
326
+ {
327
+ clientId: 'client-1',
328
+ pull: { limitCommits: 10, subscriptions: [] },
329
+ },
330
+ {
331
+ onAuthError: async () => {
332
+ legacyCount += 1;
333
+ return false;
334
+ },
335
+ }
336
+ )
337
+ ).rejects.toMatchObject({ status: 401 });
338
+
339
+ expect(legacyCount).toBe(1);
340
+ expect(refreshCount).toBe(0);
341
+ });
342
+
343
+ it('retries streamed snapshot chunk fetch via shared auth lifecycle', async () => {
344
+ let requestCount = 0;
345
+ let refreshCount = 0;
346
+
347
+ const transport = createHttpTransport({
348
+ baseUrl: 'http://localhost',
349
+ authLifecycle: {
350
+ refreshToken: async () => {
351
+ refreshCount += 1;
352
+ return true;
353
+ },
354
+ },
355
+ fetch: async () => {
356
+ requestCount += 1;
357
+ if (requestCount === 1) {
358
+ return new Response(JSON.stringify({ error: 'UNAUTHENTICATED' }), {
359
+ status: 401,
360
+ headers: { 'content-type': 'application/json' },
361
+ });
362
+ }
363
+ return new Response(new Uint8Array([5, 4, 3]), {
364
+ status: 200,
365
+ headers: { 'content-type': 'application/octet-stream' },
366
+ });
367
+ },
368
+ });
369
+
370
+ const stream = await transport.fetchSnapshotChunkStream?.({
371
+ chunkId: 'chunk-shared-auth',
372
+ });
373
+ expect(stream).toBeDefined();
374
+
375
+ const reader = stream!.getReader();
376
+ const collected: number[] = [];
377
+ while (true) {
378
+ const { done, value } = await reader.read();
379
+ if (done) break;
380
+ if (!value) continue;
381
+ collected.push(...value);
382
+ }
383
+ reader.releaseLock();
384
+
385
+ expect(collected).toEqual([5, 4, 3]);
386
+ expect(refreshCount).toBe(1);
387
+ expect(requestCount).toBe(2);
388
+ });
198
389
  });
package/src/index.ts CHANGED
@@ -5,6 +5,9 @@
5
5
  */
6
6
 
7
7
  import type {
8
+ SyncAuthErrorContext,
9
+ SyncAuthLifecycle,
10
+ SyncAuthOperation,
8
11
  SyncCombinedRequest,
9
12
  SyncCombinedResponse,
10
13
  SyncTransport,
@@ -16,6 +19,9 @@ import createClient from 'openapi-fetch';
16
19
  import type { paths } from './generated/api';
17
20
 
18
21
  export type {
22
+ SyncAuthErrorContext,
23
+ SyncAuthLifecycle,
24
+ SyncAuthOperation,
19
25
  SyncTransport,
20
26
  SyncTransportBlobs,
21
27
  SyncTransportOptions,
@@ -66,24 +72,30 @@ type ApiResult<T> = {
66
72
  response: Response;
67
73
  };
68
74
 
75
+ type ResolveAuthRetry = (
76
+ context: SyncAuthErrorContext,
77
+ options?: SyncTransportOptions
78
+ ) => Promise<boolean>;
79
+
69
80
  async function executeWithAuthRetry<T>(
70
81
  execute: (signal?: AbortSignal) => Promise<ApiResult<T>>,
71
- options?: SyncTransportOptions
82
+ options: SyncTransportOptions | undefined,
83
+ operation: SyncAuthOperation,
84
+ resolveAuthRetry: ResolveAuthRetry
72
85
  ): Promise<ApiResult<T>> {
73
86
  const first = await execute(options?.signal);
74
87
  if (first.response.status !== 401 && first.response.status !== 403) {
75
88
  return first;
76
89
  }
77
- if (!options?.onAuthError) {
78
- return first;
79
- }
80
-
81
- const shouldRetry = await options.onAuthError();
90
+ const shouldRetry = await resolveAuthRetry(
91
+ { operation, status: first.response.status },
92
+ options
93
+ );
82
94
  if (!shouldRetry) {
83
95
  return first;
84
96
  }
85
97
 
86
- return execute(options.signal);
98
+ return execute(options?.signal);
87
99
  }
88
100
 
89
101
  // Re-export useful types from the generated API
@@ -95,6 +107,8 @@ export interface ClientOptions {
95
107
  baseUrl: string;
96
108
  /** Function to get headers for requests (e.g., for auth tokens) */
97
109
  getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
110
+ /** Shared auth lifecycle for all transport operations. */
111
+ authLifecycle?: SyncAuthLifecycle;
98
112
  /** Custom fetch implementation (defaults to globalThis.fetch) */
99
113
  fetch?: typeof globalThis.fetch;
100
114
  /**
@@ -209,15 +223,58 @@ export function createHttpTransport(
209
223
  : createApiClient(clientOrOptions);
210
224
  const transportOptions =
211
225
  'GET' in clientOrOptions ? undefined : clientOrOptions;
226
+ const defaultAuthLifecycle = transportOptions?.authLifecycle;
227
+
228
+ let refreshInFlight: Promise<boolean> | null = null;
229
+
230
+ const runRefreshSingleFlight = async (
231
+ lifecycle: SyncAuthLifecycle,
232
+ context: SyncAuthErrorContext
233
+ ): Promise<boolean> => {
234
+ if (!lifecycle.refreshToken) return false;
235
+
236
+ if (!refreshInFlight) {
237
+ refreshInFlight = Promise.resolve(lifecycle.refreshToken(context))
238
+ .then((result) => Boolean(result))
239
+ .finally(() => {
240
+ refreshInFlight = null;
241
+ });
242
+ }
243
+
244
+ return refreshInFlight;
245
+ };
246
+
247
+ const resolveAuthRetry: ResolveAuthRetry = async (context, options) => {
248
+ if (options?.onAuthError) {
249
+ return Boolean(await options.onAuthError());
250
+ }
251
+
252
+ const lifecycle = options?.authLifecycle ?? defaultAuthLifecycle;
253
+ if (!lifecycle) return false;
254
+
255
+ await lifecycle.onAuthExpired?.(context);
256
+
257
+ const refreshResult = await runRefreshSingleFlight(lifecycle, context);
258
+ if (lifecycle.retryWithFreshToken) {
259
+ return Boolean(
260
+ await lifecycle.retryWithFreshToken({ ...context, refreshResult })
261
+ );
262
+ }
263
+ return refreshResult;
264
+ };
212
265
 
213
266
  // Create blob operations using the typed OpenAPI client
214
267
  const blobs: SyncTransportBlobs = {
215
268
  async initiateUpload(args) {
216
- const { data, error, response } = await client.POST(
217
- '/sync/blobs/upload',
218
- {
219
- body: args,
220
- }
269
+ const { data, error, response } = await executeWithAuthRetry(
270
+ (signal) =>
271
+ client.POST('/sync/blobs/upload', {
272
+ body: args,
273
+ ...(signal ? { signal } : {}),
274
+ }),
275
+ undefined,
276
+ 'blobInitiateUpload',
277
+ resolveAuthRetry
221
278
  );
222
279
 
223
280
  if (error || !data) {
@@ -231,9 +288,16 @@ export function createHttpTransport(
231
288
  },
232
289
 
233
290
  async completeUpload(hash) {
234
- const { data, error } = await client.POST('/sync/blobs/{hash}/complete', {
235
- params: { path: { hash } },
236
- });
291
+ const { data, error } = await executeWithAuthRetry(
292
+ (signal) =>
293
+ client.POST('/sync/blobs/{hash}/complete', {
294
+ params: { path: { hash } },
295
+ ...(signal ? { signal } : {}),
296
+ }),
297
+ undefined,
298
+ 'blobCompleteUpload',
299
+ resolveAuthRetry
300
+ );
237
301
 
238
302
  if (error || !data) {
239
303
  return {
@@ -246,11 +310,15 @@ export function createHttpTransport(
246
310
  },
247
311
 
248
312
  async getDownloadUrl(hash) {
249
- const { data, error, response } = await client.GET(
250
- '/sync/blobs/{hash}/url',
251
- {
252
- params: { path: { hash } },
253
- }
313
+ const { data, error, response } = await executeWithAuthRetry(
314
+ (signal) =>
315
+ client.GET('/sync/blobs/{hash}/url', {
316
+ params: { path: { hash } },
317
+ ...(signal ? { signal } : {}),
318
+ }),
319
+ undefined,
320
+ 'blobGetDownloadUrl',
321
+ resolveAuthRetry
254
322
  );
255
323
 
256
324
  if (error || !data) {
@@ -278,7 +346,9 @@ export function createHttpTransport(
278
346
  body: request,
279
347
  ...(signal ? { signal } : {}),
280
348
  }),
281
- transportOptions
349
+ transportOptions,
350
+ 'sync',
351
+ resolveAuthRetry
282
352
  );
283
353
 
284
354
  if (error || !data) {
@@ -302,7 +372,9 @@ export function createHttpTransport(
302
372
  parseAs: 'blob',
303
373
  ...(signal ? { signal } : {}),
304
374
  }),
305
- transportOptions
375
+ transportOptions,
376
+ 'snapshotChunk',
377
+ resolveAuthRetry
306
378
  );
307
379
 
308
380
  if (error || !data) {
@@ -354,13 +426,16 @@ export function createHttpTransport(
354
426
  };
355
427
 
356
428
  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();
429
+ if (response.status === 401 || response.status === 403) {
430
+ const shouldRetry = await resolveAuthRetry(
431
+ {
432
+ operation: 'snapshotChunkStream',
433
+ status: response.status,
434
+ },
435
+ options
436
+ );
362
437
  if (shouldRetry) {
363
- response = await performRequest(options.signal);
438
+ response = await performRequest(options?.signal);
364
439
  }
365
440
  }
366
441