@markwharton/pwa-core 3.4.2 → 4.0.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/dist/client.d.ts CHANGED
@@ -2,9 +2,17 @@
2
2
  * pwa-core/client - Browser-side API client utilities
3
3
  *
4
4
  * This module has NO Node.js dependencies and is designed for browser use.
5
+ *
6
+ * Supports two auth strategies via a single API surface:
7
+ * - Token (Bearer): initApiClient() — sends Authorization header
8
+ * - Session (Cookie): initSessionApiClient() — sends credentials: 'include'
9
+ *
10
+ * All api* functions (apiCall, apiGet, apiPost, etc.) work with whichever
11
+ * strategy was initialized. The sessionApi* names are deprecated aliases.
5
12
  */
6
13
  /**
7
- * API response wrapper for safe calls
14
+ * API response wrapper for safe calls.
15
+ * @deprecated Use ApiResponse — will be removed in next major version.
8
16
  */
9
17
  export interface ApiResponse<T> {
10
18
  ok: boolean;
@@ -13,7 +21,7 @@ export interface ApiResponse<T> {
13
21
  error?: string;
14
22
  }
15
23
  /**
16
- * Configuration for initApiClient
24
+ * Configuration for initApiClient (Bearer token auth)
17
25
  */
18
26
  export interface ApiClientConfig {
19
27
  /** Function that returns the current auth token (or null) */
@@ -24,7 +32,7 @@ export interface ApiClientConfig {
24
32
  timeout?: number;
25
33
  }
26
34
  /**
27
- * Configuration for initSessionApiClient
35
+ * Configuration for initSessionApiClient (cookie auth)
28
36
  */
29
37
  export interface SessionApiClientConfig {
30
38
  /** Optional callback for 401 responses (e.g., redirect to login) */
@@ -81,7 +89,7 @@ export declare class ApiError extends Error {
81
89
  isServerError(): boolean;
82
90
  }
83
91
  /**
84
- * Initializes the API client with token retrieval and optional configuration.
92
+ * Initializes the API client with Bearer token authentication.
85
93
  * Call once at application startup.
86
94
  * @param config - Client configuration
87
95
  * @example
@@ -92,6 +100,18 @@ export declare class ApiError extends Error {
92
100
  * });
93
101
  */
94
102
  export declare function initApiClient(config: ApiClientConfig): void;
103
+ /**
104
+ * Initializes the session-based API client.
105
+ * Uses cookies (credentials: 'include') instead of Bearer tokens.
106
+ * After calling this, use apiCall/apiGet/apiPost etc. (same functions as token auth).
107
+ * @param config - Client configuration
108
+ * @example
109
+ * initSessionApiClient({
110
+ * onUnauthenticated: () => window.location.href = '/login',
111
+ * timeout: 60000
112
+ * });
113
+ */
114
+ export declare function initSessionApiClient(config: SessionApiClientConfig): void;
95
115
  /**
96
116
  * Extract a user-friendly error message from an API error.
97
117
  * Use in catch blocks to convert errors to displayable strings.
@@ -108,6 +128,7 @@ export declare function initApiClient(config: ApiClientConfig): void;
108
128
  export declare function getApiErrorMessage(error: unknown, fallback: string): string;
109
129
  /**
110
130
  * Makes an authenticated API call. Throws ApiError on non-2xx responses.
131
+ * Works with both token (Bearer) and session (cookie) auth strategies.
111
132
  * @typeParam T - The expected response data type
112
133
  * @param url - The API endpoint URL
113
134
  * @param options - Optional fetch options (method, body, headers)
@@ -198,88 +219,6 @@ export declare function apiCallVoid(url: string, options?: RequestInit): Promise
198
219
  * }
199
220
  */
200
221
  export declare function apiCallSafe<T>(url: string, options?: RequestInit): Promise<ApiResponse<T>>;
201
- /**
202
- * Initializes the session-based API client.
203
- * Uses cookies (credentials: 'include') instead of Bearer tokens.
204
- * @param config - Client configuration
205
- * @example
206
- * initSessionApiClient({
207
- * onUnauthenticated: () => window.location.href = '/login',
208
- * timeout: 60000
209
- * });
210
- */
211
- export declare function initSessionApiClient(config: SessionApiClientConfig): void;
212
- /**
213
- * Makes a cookie-authenticated API call. Throws ApiError on non-2xx responses.
214
- * Uses credentials: 'include' to send session cookies.
215
- * @typeParam T - The expected response data type
216
- * @param url - The API endpoint URL
217
- * @param options - Optional fetch options (method, body, headers)
218
- * @returns The parsed JSON response
219
- * @throws ApiError on non-2xx HTTP status or timeout
220
- * @example
221
- * const user = await sessionApiCall<User>('/api/auth/me');
222
- */
223
- export declare function sessionApiCall<T>(url: string, options?: RequestInit): Promise<T>;
224
- /**
225
- * Makes a cookie-authenticated GET request.
226
- * @typeParam T - The expected response data type
227
- * @param url - The API endpoint URL
228
- * @returns The parsed JSON response
229
- * @throws ApiError on non-2xx HTTP status
230
- */
231
- export declare function sessionApiGet<T>(url: string): Promise<T>;
232
- /**
233
- * Makes a cookie-authenticated POST request.
234
- * @typeParam T - The expected response data type
235
- * @param url - The API endpoint URL
236
- * @param body - Optional request body (will be JSON stringified)
237
- * @returns The parsed JSON response
238
- * @throws ApiError on non-2xx HTTP status
239
- */
240
- export declare function sessionApiPost<T>(url: string, body?: unknown): Promise<T>;
241
- /**
242
- * Makes a cookie-authenticated PUT request.
243
- * @typeParam T - The expected response data type
244
- * @param url - The API endpoint URL
245
- * @param body - Optional request body (will be JSON stringified)
246
- * @returns The parsed JSON response
247
- * @throws ApiError on non-2xx HTTP status
248
- */
249
- export declare function sessionApiPut<T>(url: string, body?: unknown): Promise<T>;
250
- /**
251
- * Makes a cookie-authenticated PATCH request.
252
- * @typeParam T - The expected response data type
253
- * @param url - The API endpoint URL
254
- * @param body - Optional request body (will be JSON stringified)
255
- * @returns The parsed JSON response
256
- * @throws ApiError on non-2xx HTTP status
257
- */
258
- export declare function sessionApiPatch<T>(url: string, body?: unknown): Promise<T>;
259
- /**
260
- * Makes a cookie-authenticated DELETE request.
261
- * @typeParam T - The expected response data type
262
- * @param url - The API endpoint URL
263
- * @returns The parsed JSON response
264
- * @throws ApiError on non-2xx HTTP status
265
- */
266
- export declare function sessionApiDelete<T>(url: string): Promise<T>;
267
- /**
268
- * Makes a cookie-authenticated API call with Result-style error handling.
269
- * Unlike sessionApiCall, this never throws - errors are returned in the response.
270
- * @typeParam T - The expected response data type
271
- * @param url - The API endpoint URL
272
- * @param options - Optional fetch options (method, body, headers)
273
- * @returns ApiResponse with ok, status, data (on success), or error (on failure)
274
- */
275
- export declare function sessionApiCallSafe<T>(url: string, options?: RequestInit): Promise<ApiResponse<T>>;
276
- /**
277
- * Makes a cookie-authenticated API call expecting no response body.
278
- * @param url - The API endpoint URL
279
- * @param options - Optional fetch options (method, body, headers)
280
- * @throws ApiError on non-2xx HTTP status or timeout
281
- */
282
- export declare function sessionApiCallVoid(url: string, options?: RequestInit): Promise<void>;
283
222
  /**
284
223
  * Checks if an HTTP status code indicates a retryable error.
285
224
  * @param status - The HTTP status code (or undefined for network errors)
@@ -289,8 +228,9 @@ export declare function sessionApiCallVoid(url: string, options?: RequestInit):
289
228
  */
290
229
  export declare function isRetryableStatus(status: number | undefined): boolean;
291
230
  /**
292
- * Makes a cookie-authenticated API call with exponential backoff retry.
231
+ * Makes an authenticated API call with exponential backoff retry.
293
232
  * Retries on retryable status codes (408, 425, 429, 5xx, network errors).
233
+ * Works with both token and session auth strategies.
294
234
  * @typeParam T - The expected response data type
295
235
  * @param url - The API endpoint URL
296
236
  * @param options - Optional fetch options
@@ -299,9 +239,27 @@ export declare function isRetryableStatus(status: number | undefined): boolean;
299
239
  * @returns The parsed JSON response
300
240
  * @throws ApiError if all retries fail
301
241
  * @example
302
- * const result = await sessionApiCallWithRetry<AuthResponse>('/api/auth/verify', {
242
+ * const result = await apiCallWithRetry<AuthResponse>('/api/auth/verify', {
303
243
  * method: 'POST',
304
244
  * body: JSON.stringify({ token })
305
245
  * });
306
246
  */
307
- export declare function sessionApiCallWithRetry<T>(url: string, options?: RequestInit, maxRetries?: number, initialDelayMs?: number): Promise<T>;
247
+ export declare function apiCallWithRetry<T>(url: string, options?: RequestInit, maxRetries?: number, initialDelayMs?: number): Promise<T>;
248
+ /** @deprecated Use apiCall after initSessionApiClient */
249
+ export declare const sessionApiCall: typeof apiCall;
250
+ /** @deprecated Use apiGet after initSessionApiClient */
251
+ export declare const sessionApiGet: typeof apiGet;
252
+ /** @deprecated Use apiPost after initSessionApiClient */
253
+ export declare const sessionApiPost: typeof apiPost;
254
+ /** @deprecated Use apiPut after initSessionApiClient */
255
+ export declare const sessionApiPut: typeof apiPut;
256
+ /** @deprecated Use apiPatch after initSessionApiClient */
257
+ export declare const sessionApiPatch: typeof apiPatch;
258
+ /** @deprecated Use apiDelete after initSessionApiClient */
259
+ export declare const sessionApiDelete: typeof apiDelete;
260
+ /** @deprecated Use apiCallSafe after initSessionApiClient */
261
+ export declare const sessionApiCallSafe: typeof apiCallSafe;
262
+ /** @deprecated Use apiCallVoid after initSessionApiClient */
263
+ export declare const sessionApiCallVoid: typeof apiCallVoid;
264
+ /** @deprecated Use apiCallWithRetry after initSessionApiClient */
265
+ export declare const sessionApiCallWithRetry: typeof apiCallWithRetry;
package/dist/client.js CHANGED
@@ -3,10 +3,18 @@
3
3
  * pwa-core/client - Browser-side API client utilities
4
4
  *
5
5
  * This module has NO Node.js dependencies and is designed for browser use.
6
+ *
7
+ * Supports two auth strategies via a single API surface:
8
+ * - Token (Bearer): initApiClient() — sends Authorization header
9
+ * - Session (Cookie): initSessionApiClient() — sends credentials: 'include'
10
+ *
11
+ * All api* functions (apiCall, apiGet, apiPost, etc.) work with whichever
12
+ * strategy was initialized. The sessionApi* names are deprecated aliases.
6
13
  */
7
14
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ApiError = void 0;
15
+ exports.sessionApiCallWithRetry = exports.sessionApiCallVoid = exports.sessionApiCallSafe = exports.sessionApiDelete = exports.sessionApiPatch = exports.sessionApiPut = exports.sessionApiPost = exports.sessionApiGet = exports.sessionApiCall = exports.ApiError = void 0;
9
16
  exports.initApiClient = initApiClient;
17
+ exports.initSessionApiClient = initSessionApiClient;
10
18
  exports.getApiErrorMessage = getApiErrorMessage;
11
19
  exports.apiCall = apiCall;
12
20
  exports.apiGet = apiGet;
@@ -16,17 +24,8 @@ exports.apiPatch = apiPatch;
16
24
  exports.apiDelete = apiDelete;
17
25
  exports.apiCallVoid = apiCallVoid;
18
26
  exports.apiCallSafe = apiCallSafe;
19
- exports.initSessionApiClient = initSessionApiClient;
20
- exports.sessionApiCall = sessionApiCall;
21
- exports.sessionApiGet = sessionApiGet;
22
- exports.sessionApiPost = sessionApiPost;
23
- exports.sessionApiPut = sessionApiPut;
24
- exports.sessionApiPatch = sessionApiPatch;
25
- exports.sessionApiDelete = sessionApiDelete;
26
- exports.sessionApiCallSafe = sessionApiCallSafe;
27
- exports.sessionApiCallVoid = sessionApiCallVoid;
28
27
  exports.isRetryableStatus = isRetryableStatus;
29
- exports.sessionApiCallWithRetry = sessionApiCallWithRetry;
28
+ exports.apiCallWithRetry = apiCallWithRetry;
30
29
  // =============================================================================
31
30
  // ApiError Class
32
31
  // =============================================================================
@@ -92,29 +91,35 @@ class ApiError extends Error {
92
91
  }
93
92
  }
94
93
  exports.ApiError = ApiError;
95
- // =============================================================================
96
- // Module State
97
- // =============================================================================
98
- // Token getter function - set by consuming app
99
- let getToken = null;
100
- // Callback for 401 responses (e.g., redirect to login)
101
- let onUnauthorized = null;
102
- // Request timeout in milliseconds (default: 30 seconds)
103
- let requestTimeout = 30000;
94
+ let clientState = null;
104
95
  // =============================================================================
105
96
  // Internal Helpers
106
97
  // =============================================================================
107
- /** Prepare headers with optional auth token */
108
- function prepareHeaders(options) {
109
- const token = getToken?.();
98
+ /** Get the active client state or throw */
99
+ function getState() {
100
+ if (!clientState) {
101
+ throw new Error('API client not initialized. Call initApiClient() or initSessionApiClient() first.');
102
+ }
103
+ return clientState;
104
+ }
105
+ /** Prepare headers and fetch options based on auth strategy */
106
+ function prepareFetchOptions(options) {
107
+ const state = getState();
110
108
  const headers = {
111
109
  'Content-Type': 'application/json',
112
110
  ...options.headers
113
111
  };
114
- if (token) {
115
- headers['Authorization'] = `Bearer ${token}`;
112
+ const fetchOptions = { ...options };
113
+ if (state.strategy === 'token') {
114
+ const token = state.getToken?.();
115
+ if (token) {
116
+ headers['Authorization'] = `Bearer ${token}`;
117
+ }
116
118
  }
117
- return headers;
119
+ else {
120
+ fetchOptions.credentials = 'include';
121
+ }
122
+ return { headers, fetchOptions };
118
123
  }
119
124
  /** Extract error message from failed response */
120
125
  async function extractErrorMessage(response) {
@@ -126,10 +131,10 @@ async function extractErrorMessage(response) {
126
131
  return 'Request failed';
127
132
  }
128
133
  }
129
- /** Handle 401 unauthorized callback */
134
+ /** Handle 401 unauthorized/unauthenticated callback */
130
135
  function handleUnauthorized(status) {
131
- if (status === 401 && onUnauthorized) {
132
- onUnauthorized();
136
+ if (status === 401 && clientState?.onUnauthorized) {
137
+ clientState.onUnauthorized();
133
138
  }
134
139
  }
135
140
  /** Handle catch block for throwing API functions */
@@ -143,10 +148,10 @@ function handleApiError(error) {
143
148
  throw error;
144
149
  }
145
150
  // =============================================================================
146
- // Public API
151
+ // Initialization
147
152
  // =============================================================================
148
153
  /**
149
- * Initializes the API client with token retrieval and optional configuration.
154
+ * Initializes the API client with Bearer token authentication.
150
155
  * Call once at application startup.
151
156
  * @param config - Client configuration
152
157
  * @example
@@ -157,10 +162,34 @@ function handleApiError(error) {
157
162
  * });
158
163
  */
159
164
  function initApiClient(config) {
160
- getToken = config.getToken;
161
- onUnauthorized = config.onUnauthorized ?? null;
162
- requestTimeout = config.timeout ?? 30000;
165
+ clientState = {
166
+ strategy: 'token',
167
+ getToken: config.getToken,
168
+ onUnauthorized: config.onUnauthorized,
169
+ timeout: config.timeout ?? 30000,
170
+ };
163
171
  }
172
+ /**
173
+ * Initializes the session-based API client.
174
+ * Uses cookies (credentials: 'include') instead of Bearer tokens.
175
+ * After calling this, use apiCall/apiGet/apiPost etc. (same functions as token auth).
176
+ * @param config - Client configuration
177
+ * @example
178
+ * initSessionApiClient({
179
+ * onUnauthenticated: () => window.location.href = '/login',
180
+ * timeout: 60000
181
+ * });
182
+ */
183
+ function initSessionApiClient(config) {
184
+ clientState = {
185
+ strategy: 'session',
186
+ onUnauthorized: config.onUnauthenticated,
187
+ timeout: config.timeout ?? 30000,
188
+ };
189
+ }
190
+ // =============================================================================
191
+ // Public API — Works with both token and session strategies
192
+ // =============================================================================
164
193
  /**
165
194
  * Extract a user-friendly error message from an API error.
166
195
  * Use in catch blocks to convert errors to displayable strings.
@@ -185,6 +214,7 @@ function getApiErrorMessage(error, fallback) {
185
214
  }
186
215
  /**
187
216
  * Makes an authenticated API call. Throws ApiError on non-2xx responses.
217
+ * Works with both token (Bearer) and session (cookie) auth strategies.
188
218
  * @typeParam T - The expected response data type
189
219
  * @param url - The API endpoint URL
190
220
  * @param options - Optional fetch options (method, body, headers)
@@ -194,12 +224,13 @@ function getApiErrorMessage(error, fallback) {
194
224
  * const user = await apiCall<User>('/api/users/123');
195
225
  */
196
226
  async function apiCall(url, options = {}) {
197
- const headers = prepareHeaders(options);
227
+ const state = getState();
228
+ const { headers, fetchOptions } = prepareFetchOptions(options);
198
229
  const controller = new AbortController();
199
- const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
230
+ const timeoutId = setTimeout(() => controller.abort(), state.timeout);
200
231
  try {
201
232
  const response = await fetch(url, {
202
- ...options,
233
+ ...fetchOptions,
203
234
  headers,
204
235
  signal: controller.signal
205
236
  });
@@ -304,12 +335,13 @@ async function apiDelete(url) {
304
335
  * await apiCallVoid('/api/action', { method: 'POST' });
305
336
  */
306
337
  async function apiCallVoid(url, options = {}) {
307
- const headers = prepareHeaders(options);
338
+ const state = getState();
339
+ const { headers, fetchOptions } = prepareFetchOptions(options);
308
340
  const controller = new AbortController();
309
- const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
341
+ const timeoutId = setTimeout(() => controller.abort(), state.timeout);
310
342
  try {
311
343
  const response = await fetch(url, {
312
- ...options,
344
+ ...fetchOptions,
313
345
  headers,
314
346
  signal: controller.signal
315
347
  });
@@ -343,12 +375,13 @@ async function apiCallVoid(url, options = {}) {
343
375
  * }
344
376
  */
345
377
  async function apiCallSafe(url, options = {}) {
346
- const headers = prepareHeaders(options);
378
+ const state = getState();
379
+ const { headers, fetchOptions } = prepareFetchOptions(options);
347
380
  const controller = new AbortController();
348
- const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
381
+ const timeoutId = setTimeout(() => controller.abort(), state.timeout);
349
382
  try {
350
383
  const response = await fetch(url, {
351
- ...options,
384
+ ...fetchOptions,
352
385
  headers,
353
386
  signal: controller.signal
354
387
  });
@@ -372,211 +405,6 @@ async function apiCallSafe(url, options = {}) {
372
405
  }
373
406
  }
374
407
  // =============================================================================
375
- // Session API Client (cookie-based auth)
376
- // =============================================================================
377
- // Session API client state
378
- let sessionOnUnauthenticated = null;
379
- let sessionRequestTimeout = 30000;
380
- /**
381
- * Initializes the session-based API client.
382
- * Uses cookies (credentials: 'include') instead of Bearer tokens.
383
- * @param config - Client configuration
384
- * @example
385
- * initSessionApiClient({
386
- * onUnauthenticated: () => window.location.href = '/login',
387
- * timeout: 60000
388
- * });
389
- */
390
- function initSessionApiClient(config) {
391
- sessionOnUnauthenticated = config.onUnauthenticated ?? null;
392
- sessionRequestTimeout = config.timeout ?? 30000;
393
- }
394
- /** Handle 401 unauthenticated callback for session API */
395
- function handleUnauthenticated(status) {
396
- if (status === 401 && sessionOnUnauthenticated) {
397
- sessionOnUnauthenticated();
398
- }
399
- }
400
- /**
401
- * Makes a cookie-authenticated API call. Throws ApiError on non-2xx responses.
402
- * Uses credentials: 'include' to send session cookies.
403
- * @typeParam T - The expected response data type
404
- * @param url - The API endpoint URL
405
- * @param options - Optional fetch options (method, body, headers)
406
- * @returns The parsed JSON response
407
- * @throws ApiError on non-2xx HTTP status or timeout
408
- * @example
409
- * const user = await sessionApiCall<User>('/api/auth/me');
410
- */
411
- async function sessionApiCall(url, options = {}) {
412
- const headers = {
413
- 'Content-Type': 'application/json',
414
- ...options.headers
415
- };
416
- const controller = new AbortController();
417
- const timeoutId = setTimeout(() => controller.abort(), sessionRequestTimeout);
418
- try {
419
- const response = await fetch(url, {
420
- ...options,
421
- headers,
422
- credentials: 'include',
423
- signal: controller.signal
424
- });
425
- if (!response.ok) {
426
- handleUnauthenticated(response.status);
427
- const errorMessage = await extractErrorMessage(response);
428
- throw new ApiError(response.status, errorMessage);
429
- }
430
- const text = await response.text();
431
- if (!text) {
432
- throw new ApiError(response.status, 'Empty response body');
433
- }
434
- return JSON.parse(text);
435
- }
436
- catch (error) {
437
- handleApiError(error);
438
- }
439
- finally {
440
- clearTimeout(timeoutId);
441
- }
442
- }
443
- /**
444
- * Makes a cookie-authenticated GET request.
445
- * @typeParam T - The expected response data type
446
- * @param url - The API endpoint URL
447
- * @returns The parsed JSON response
448
- * @throws ApiError on non-2xx HTTP status
449
- */
450
- async function sessionApiGet(url) {
451
- return sessionApiCall(url, { method: 'GET' });
452
- }
453
- /**
454
- * Makes a cookie-authenticated POST request.
455
- * @typeParam T - The expected response data type
456
- * @param url - The API endpoint URL
457
- * @param body - Optional request body (will be JSON stringified)
458
- * @returns The parsed JSON response
459
- * @throws ApiError on non-2xx HTTP status
460
- */
461
- async function sessionApiPost(url, body) {
462
- return sessionApiCall(url, {
463
- method: 'POST',
464
- body: body ? JSON.stringify(body) : undefined
465
- });
466
- }
467
- /**
468
- * Makes a cookie-authenticated PUT request.
469
- * @typeParam T - The expected response data type
470
- * @param url - The API endpoint URL
471
- * @param body - Optional request body (will be JSON stringified)
472
- * @returns The parsed JSON response
473
- * @throws ApiError on non-2xx HTTP status
474
- */
475
- async function sessionApiPut(url, body) {
476
- return sessionApiCall(url, {
477
- method: 'PUT',
478
- body: body ? JSON.stringify(body) : undefined
479
- });
480
- }
481
- /**
482
- * Makes a cookie-authenticated PATCH request.
483
- * @typeParam T - The expected response data type
484
- * @param url - The API endpoint URL
485
- * @param body - Optional request body (will be JSON stringified)
486
- * @returns The parsed JSON response
487
- * @throws ApiError on non-2xx HTTP status
488
- */
489
- async function sessionApiPatch(url, body) {
490
- return sessionApiCall(url, {
491
- method: 'PATCH',
492
- body: body ? JSON.stringify(body) : undefined
493
- });
494
- }
495
- /**
496
- * Makes a cookie-authenticated DELETE request.
497
- * @typeParam T - The expected response data type
498
- * @param url - The API endpoint URL
499
- * @returns The parsed JSON response
500
- * @throws ApiError on non-2xx HTTP status
501
- */
502
- async function sessionApiDelete(url) {
503
- return sessionApiCall(url, { method: 'DELETE' });
504
- }
505
- /**
506
- * Makes a cookie-authenticated API call with Result-style error handling.
507
- * Unlike sessionApiCall, this never throws - errors are returned in the response.
508
- * @typeParam T - The expected response data type
509
- * @param url - The API endpoint URL
510
- * @param options - Optional fetch options (method, body, headers)
511
- * @returns ApiResponse with ok, status, data (on success), or error (on failure)
512
- */
513
- async function sessionApiCallSafe(url, options = {}) {
514
- const headers = {
515
- 'Content-Type': 'application/json',
516
- ...options.headers
517
- };
518
- const controller = new AbortController();
519
- const timeoutId = setTimeout(() => controller.abort(), sessionRequestTimeout);
520
- try {
521
- const response = await fetch(url, {
522
- ...options,
523
- headers,
524
- credentials: 'include',
525
- signal: controller.signal
526
- });
527
- if (!response.ok) {
528
- handleUnauthenticated(response.status);
529
- const errorMessage = await extractErrorMessage(response);
530
- return { ok: false, status: response.status, error: errorMessage };
531
- }
532
- const text = await response.text();
533
- const data = text ? JSON.parse(text) : undefined;
534
- return { ok: true, status: response.status, data };
535
- }
536
- catch (error) {
537
- if (error instanceof Error && error.name === 'AbortError') {
538
- return { ok: false, status: 0, error: 'Request timeout' };
539
- }
540
- return { ok: false, status: 0, error: 'Network error' };
541
- }
542
- finally {
543
- clearTimeout(timeoutId);
544
- }
545
- }
546
- /**
547
- * Makes a cookie-authenticated API call expecting no response body.
548
- * @param url - The API endpoint URL
549
- * @param options - Optional fetch options (method, body, headers)
550
- * @throws ApiError on non-2xx HTTP status or timeout
551
- */
552
- async function sessionApiCallVoid(url, options = {}) {
553
- const headers = {
554
- 'Content-Type': 'application/json',
555
- ...options.headers
556
- };
557
- const controller = new AbortController();
558
- const timeoutId = setTimeout(() => controller.abort(), sessionRequestTimeout);
559
- try {
560
- const response = await fetch(url, {
561
- ...options,
562
- headers,
563
- credentials: 'include',
564
- signal: controller.signal
565
- });
566
- if (!response.ok) {
567
- handleUnauthenticated(response.status);
568
- const errorMessage = await extractErrorMessage(response);
569
- throw new ApiError(response.status, errorMessage);
570
- }
571
- }
572
- catch (error) {
573
- handleApiError(error);
574
- }
575
- finally {
576
- clearTimeout(timeoutId);
577
- }
578
- }
579
- // =============================================================================
580
408
  // Retryable Request Helper
581
409
  // =============================================================================
582
410
  /**
@@ -596,8 +424,9 @@ function isRetryableStatus(status) {
596
424
  return false;
597
425
  }
598
426
  /**
599
- * Makes a cookie-authenticated API call with exponential backoff retry.
427
+ * Makes an authenticated API call with exponential backoff retry.
600
428
  * Retries on retryable status codes (408, 425, 429, 5xx, network errors).
429
+ * Works with both token and session auth strategies.
601
430
  * @typeParam T - The expected response data type
602
431
  * @param url - The API endpoint URL
603
432
  * @param options - Optional fetch options
@@ -606,16 +435,16 @@ function isRetryableStatus(status) {
606
435
  * @returns The parsed JSON response
607
436
  * @throws ApiError if all retries fail
608
437
  * @example
609
- * const result = await sessionApiCallWithRetry<AuthResponse>('/api/auth/verify', {
438
+ * const result = await apiCallWithRetry<AuthResponse>('/api/auth/verify', {
610
439
  * method: 'POST',
611
440
  * body: JSON.stringify({ token })
612
441
  * });
613
442
  */
614
- async function sessionApiCallWithRetry(url, options, maxRetries = 3, initialDelayMs = 1000) {
443
+ async function apiCallWithRetry(url, options, maxRetries = 3, initialDelayMs = 1000) {
615
444
  let lastError;
616
445
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
617
446
  try {
618
- return await sessionApiCall(url, options);
447
+ return await apiCall(url, options);
619
448
  }
620
449
  catch (error) {
621
450
  lastError = error;
@@ -630,3 +459,24 @@ async function sessionApiCallWithRetry(url, options, maxRetries = 3, initialDela
630
459
  }
631
460
  throw lastError;
632
461
  }
462
+ // =============================================================================
463
+ // Deprecated Aliases — Use apiCall/apiGet/apiPost etc. after initSessionApiClient
464
+ // =============================================================================
465
+ /** @deprecated Use apiCall after initSessionApiClient */
466
+ exports.sessionApiCall = apiCall;
467
+ /** @deprecated Use apiGet after initSessionApiClient */
468
+ exports.sessionApiGet = apiGet;
469
+ /** @deprecated Use apiPost after initSessionApiClient */
470
+ exports.sessionApiPost = apiPost;
471
+ /** @deprecated Use apiPut after initSessionApiClient */
472
+ exports.sessionApiPut = apiPut;
473
+ /** @deprecated Use apiPatch after initSessionApiClient */
474
+ exports.sessionApiPatch = apiPatch;
475
+ /** @deprecated Use apiDelete after initSessionApiClient */
476
+ exports.sessionApiDelete = apiDelete;
477
+ /** @deprecated Use apiCallSafe after initSessionApiClient */
478
+ exports.sessionApiCallSafe = apiCallSafe;
479
+ /** @deprecated Use apiCallVoid after initSessionApiClient */
480
+ exports.sessionApiCallVoid = apiCallVoid;
481
+ /** @deprecated Use apiCallWithRetry after initSessionApiClient */
482
+ exports.sessionApiCallWithRetry = apiCallWithRetry;