@vaiftechnologies/vaif-client 0.1.2 → 0.2.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/index.cjs CHANGED
@@ -25,21 +25,142 @@ __export(index_exports, {
25
25
  VaifAdmin: () => VaifAdmin,
26
26
  VaifApiKeys: () => VaifApiKeys,
27
27
  VaifAuth: () => VaifAuth,
28
+ VaifAuthError: () => VaifAuthError,
28
29
  VaifClient: () => VaifClient,
30
+ VaifConflictError: () => VaifConflictError,
29
31
  VaifDatabase: () => VaifDatabase,
32
+ VaifError: () => VaifError,
30
33
  VaifFunctions: () => VaifFunctions,
31
34
  VaifIntegrations: () => VaifIntegrations,
35
+ VaifNetworkError: () => VaifNetworkError,
36
+ VaifNotFoundError: () => VaifNotFoundError,
32
37
  VaifProjects: () => VaifProjects,
38
+ VaifRateLimitError: () => VaifRateLimitError,
33
39
  VaifRealtime: () => VaifRealtime,
34
40
  VaifSchema: () => VaifSchema,
35
41
  VaifStorage: () => VaifStorage,
42
+ VaifTimeoutError: () => VaifTimeoutError,
36
43
  VaifTypeGen: () => VaifTypeGen,
44
+ VaifValidationError: () => VaifValidationError,
37
45
  createClient: () => createClient,
38
46
  createTypeGen: () => createTypeGen,
39
- createVaifClient: () => createClient
47
+ createVaifClient: () => createClient,
48
+ isVaifAuthError: () => isVaifAuthError,
49
+ isVaifConflictError: () => isVaifConflictError,
50
+ isVaifError: () => isVaifError,
51
+ isVaifNetworkError: () => isVaifNetworkError,
52
+ isVaifNotFoundError: () => isVaifNotFoundError,
53
+ isVaifRateLimitError: () => isVaifRateLimitError,
54
+ isVaifTimeoutError: () => isVaifTimeoutError,
55
+ isVaifValidationError: () => isVaifValidationError
40
56
  });
41
57
  module.exports = __toCommonJS(index_exports);
42
58
 
59
+ // src/errors.ts
60
+ var VaifError = class _VaifError extends Error {
61
+ constructor(message, options) {
62
+ super(message);
63
+ this.name = "VaifError";
64
+ this.code = options.code;
65
+ this.statusCode = options.statusCode;
66
+ this.requestId = options.requestId;
67
+ this.details = options.details;
68
+ const ErrorWithCapture = Error;
69
+ if (ErrorWithCapture.captureStackTrace) {
70
+ ErrorWithCapture.captureStackTrace(this, _VaifError);
71
+ }
72
+ }
73
+ toJSON() {
74
+ return {
75
+ name: this.name,
76
+ message: this.message,
77
+ code: this.code,
78
+ statusCode: this.statusCode,
79
+ requestId: this.requestId,
80
+ details: this.details
81
+ };
82
+ }
83
+ };
84
+ var VaifAuthError = class extends VaifError {
85
+ constructor(message, options) {
86
+ super(message, {
87
+ code: options?.code ?? "AUTH_ERROR",
88
+ statusCode: options?.statusCode ?? 401,
89
+ requestId: options?.requestId
90
+ });
91
+ this.name = "VaifAuthError";
92
+ }
93
+ };
94
+ var VaifValidationError = class extends VaifError {
95
+ constructor(message, options) {
96
+ super(message, {
97
+ code: "VALIDATION_ERROR",
98
+ statusCode: 400,
99
+ requestId: options?.requestId,
100
+ details: options?.details ?? options?.fieldErrors
101
+ });
102
+ this.name = "VaifValidationError";
103
+ this.fieldErrors = options?.fieldErrors;
104
+ }
105
+ };
106
+ var VaifNetworkError = class extends VaifError {
107
+ constructor(message, cause) {
108
+ super(message, { code: "NETWORK_ERROR" });
109
+ this.name = "VaifNetworkError";
110
+ this.cause = cause;
111
+ }
112
+ };
113
+ var VaifRateLimitError = class extends VaifError {
114
+ constructor(message, retryAfter) {
115
+ super(message, { code: "RATE_LIMITED", statusCode: 429 });
116
+ this.name = "VaifRateLimitError";
117
+ this.retryAfter = retryAfter;
118
+ }
119
+ };
120
+ var VaifNotFoundError = class extends VaifError {
121
+ constructor(message, requestId) {
122
+ super(message, { code: "NOT_FOUND", statusCode: 404, requestId });
123
+ this.name = "VaifNotFoundError";
124
+ }
125
+ };
126
+ var VaifConflictError = class extends VaifError {
127
+ constructor(message, requestId) {
128
+ super(message, { code: "CONFLICT", statusCode: 409, requestId });
129
+ this.name = "VaifConflictError";
130
+ }
131
+ };
132
+ var VaifTimeoutError = class extends VaifNetworkError {
133
+ constructor(message, timeoutMs) {
134
+ super(message);
135
+ this.name = "VaifTimeoutError";
136
+ this.timeoutMs = timeoutMs;
137
+ }
138
+ };
139
+ function isVaifError(error) {
140
+ return error instanceof VaifError;
141
+ }
142
+ function isVaifAuthError(error) {
143
+ return error instanceof VaifAuthError;
144
+ }
145
+ function isVaifValidationError(error) {
146
+ return error instanceof VaifValidationError;
147
+ }
148
+ function isVaifNetworkError(error) {
149
+ return error instanceof VaifNetworkError;
150
+ }
151
+ function isVaifRateLimitError(error) {
152
+ return error instanceof VaifRateLimitError;
153
+ }
154
+ function isVaifNotFoundError(error) {
155
+ return error instanceof VaifNotFoundError;
156
+ }
157
+ function isVaifConflictError(error) {
158
+ return error instanceof VaifConflictError;
159
+ }
160
+ function isVaifTimeoutError(error) {
161
+ return error instanceof VaifTimeoutError;
162
+ }
163
+
43
164
  // src/lib/database.ts
44
165
  var VaifDatabase = class {
45
166
  constructor(client) {
@@ -48,6 +169,9 @@ var VaifDatabase = class {
48
169
  /**
49
170
  * Start a query on a table
50
171
  *
172
+ * @param table - Table name to query
173
+ * @returns A query builder for chaining operations
174
+ *
51
175
  * @example
52
176
  * ```typescript
53
177
  * const users = await vaif.db.from('users').select('*').execute();
@@ -59,6 +183,10 @@ var VaifDatabase = class {
59
183
  /**
60
184
  * Execute raw SQL query (admin only)
61
185
  *
186
+ * @param sql - SQL query string with $1, $2, etc. parameter placeholders
187
+ * @param params - Parameter values for the query
188
+ * @returns Query result with typed rows
189
+ *
62
190
  * @example
63
191
  * ```typescript
64
192
  * const result = await vaif.db.raw('SELECT * FROM users WHERE id = $1', [userId]);
@@ -86,7 +214,16 @@ var VaifDatabase = class {
86
214
  };
87
215
  }
88
216
  /**
89
- * Execute a function (stored procedure)
217
+ * Execute a stored procedure (RPC call)
218
+ *
219
+ * @param functionName - Name of the database function to call
220
+ * @param params - Parameters to pass to the function
221
+ * @returns Query result with the function's return value
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * const result = await vaif.db.rpc('get_user_stats', { userId: '123' });
226
+ * ```
90
227
  */
91
228
  async rpc(functionName, params) {
92
229
  const response = await this.client.request(`/db/rpc/${functionName}`, {
@@ -175,72 +312,85 @@ var QueryBuilder = class {
175
312
  this.onConflictUpdate = data;
176
313
  return this;
177
314
  }
178
- // Filter methods
315
+ /** Filter by equality (column = value) */
179
316
  eq(column, value) {
180
317
  this.addFilter(column, this.negateNext ? "neq" : "eq", value);
181
318
  this.negateNext = false;
182
319
  return this;
183
320
  }
321
+ /** Filter by inequality (column != value) */
184
322
  neq(column, value) {
185
323
  this.addFilter(column, this.negateNext ? "eq" : "neq", value);
186
324
  this.negateNext = false;
187
325
  return this;
188
326
  }
327
+ /** Filter by greater than (column > value) */
189
328
  gt(column, value) {
190
329
  this.addFilter(column, this.negateNext ? "lte" : "gt", value);
191
330
  this.negateNext = false;
192
331
  return this;
193
332
  }
333
+ /** Filter by greater than or equal (column >= value) */
194
334
  gte(column, value) {
195
335
  this.addFilter(column, this.negateNext ? "lt" : "gte", value);
196
336
  this.negateNext = false;
197
337
  return this;
198
338
  }
339
+ /** Filter by less than (column < value) */
199
340
  lt(column, value) {
200
341
  this.addFilter(column, this.negateNext ? "gte" : "lt", value);
201
342
  this.negateNext = false;
202
343
  return this;
203
344
  }
345
+ /** Filter by less than or equal (column <= value) */
204
346
  lte(column, value) {
205
347
  this.addFilter(column, this.negateNext ? "gt" : "lte", value);
206
348
  this.negateNext = false;
207
349
  return this;
208
350
  }
351
+ /** Filter by pattern matching (case-sensitive LIKE) */
209
352
  like(column, pattern) {
210
353
  this.addFilter(column, this.negateNext ? "nlike" : "like", pattern);
211
354
  this.negateNext = false;
212
355
  return this;
213
356
  }
357
+ /** Filter by pattern matching (case-insensitive ILIKE) */
214
358
  ilike(column, pattern) {
215
359
  this.addFilter(column, this.negateNext ? "nilike" : "ilike", pattern);
216
360
  this.negateNext = false;
217
361
  return this;
218
362
  }
363
+ /** Filter by IS (null/boolean checks) */
219
364
  is(column, value) {
220
365
  this.addFilter(column, this.negateNext ? "isnot" : "is", value);
221
366
  this.negateNext = false;
222
367
  return this;
223
368
  }
369
+ /** Filter by inclusion in an array of values */
224
370
  in(column, values) {
225
371
  this.addFilter(column, this.negateNext ? "nin" : "in", values);
226
372
  this.negateNext = false;
227
373
  return this;
228
374
  }
375
+ /** Filter by array containment (@>) */
229
376
  contains(column, value) {
230
377
  this.addFilter(column, "cs", value);
231
378
  this.negateNext = false;
232
379
  return this;
233
380
  }
381
+ /** Filter by array being contained by (<@) */
234
382
  containedBy(column, value) {
235
383
  this.addFilter(column, "cd", value);
236
384
  this.negateNext = false;
237
385
  return this;
238
386
  }
387
+ /** Filter by array overlap (&&) */
239
388
  overlaps(column, value) {
240
389
  this.addFilter(column, "ov", value);
241
390
  this.negateNext = false;
242
391
  return this;
243
392
  }
393
+ /** Full-text search filter */
244
394
  textSearch(column, query, options) {
245
395
  this.addFilter(column, "fts", query, options?.config);
246
396
  this.negateNext = false;
@@ -1916,6 +2066,63 @@ var VaifAI = class {
1916
2066
  }
1917
2067
  return { data: response.data, error: null };
1918
2068
  }
2069
+ /**
2070
+ * Get Copilot observability metrics for the current project
2071
+ *
2072
+ * @example
2073
+ * ```typescript
2074
+ * const { data, error } = await vaif.ai.getCopilotMetrics({ range: '24h' });
2075
+ * console.log(`Success rate: ${data.summary.successRate}%`);
2076
+ * console.log(`Total tokens: ${data.summary.totalTokens}`);
2077
+ * ```
2078
+ */
2079
+ async getCopilotMetrics(options = {}) {
2080
+ const config = this.client.getConfig();
2081
+ const range = options.range ?? "24h";
2082
+ const response = await this.client.request(
2083
+ `/copilot/metrics/${config.projectId}?range=${range}`,
2084
+ { method: "GET" }
2085
+ );
2086
+ if (response.error) {
2087
+ return {
2088
+ data: null,
2089
+ error: {
2090
+ message: response.error.message,
2091
+ code: response.error.code,
2092
+ status: response.status
2093
+ }
2094
+ };
2095
+ }
2096
+ return { data: response.data, error: null };
2097
+ }
2098
+ /**
2099
+ * Get Copilot observability metrics for an organization
2100
+ *
2101
+ * @example
2102
+ * ```typescript
2103
+ * const { data, error } = await vaif.ai.getCopilotOrgMetrics(orgId, { range: '7d' });
2104
+ * console.log(`Total requests: ${data.summary.totalRequests}`);
2105
+ * console.log(`Projects: ${data.summary.uniqueProjects}`);
2106
+ * ```
2107
+ */
2108
+ async getCopilotOrgMetrics(orgId, options = {}) {
2109
+ const range = options.range ?? "24h";
2110
+ const response = await this.client.request(
2111
+ `/copilot/metrics/org/${orgId}?range=${range}`,
2112
+ { method: "GET" }
2113
+ );
2114
+ if (response.error) {
2115
+ return {
2116
+ data: null,
2117
+ error: {
2118
+ message: response.error.message,
2119
+ code: response.error.code,
2120
+ status: response.status
2121
+ }
2122
+ };
2123
+ }
2124
+ return { data: response.data, error: null };
2125
+ }
1919
2126
  };
1920
2127
 
1921
2128
  // src/lib/schema.ts
@@ -3271,6 +3478,14 @@ var VaifIntegrations = class {
3271
3478
  var DEFAULT_API_URL = "https://api.vaif.studio";
3272
3479
  var DEFAULT_REALTIME_URL = "wss://realtime.vaif.studio";
3273
3480
  var DEFAULT_TIMEOUT = 3e4;
3481
+ var DEFAULT_RETRY = {
3482
+ maxRetries: 3,
3483
+ retryDelay: 1e3,
3484
+ maxRetryDelay: 3e4,
3485
+ backoffMultiplier: 2,
3486
+ retryOn: [429, 500, 502, 503, 504],
3487
+ retryOnNetworkError: true
3488
+ };
3274
3489
  var memoryStorage = {
3275
3490
  data: /* @__PURE__ */ new Map(),
3276
3491
  getItem(key) {
@@ -3288,6 +3503,18 @@ var browserStorage = typeof window !== "undefined" && window.localStorage ? {
3288
3503
  setItem: (key, value) => window.localStorage.setItem(key, value),
3289
3504
  removeItem: (key) => window.localStorage.removeItem(key)
3290
3505
  } : null;
3506
+ function calculateRetryDelay(attempt, config) {
3507
+ const exponentialDelay = config.retryDelay * Math.pow(config.backoffMultiplier, attempt);
3508
+ const cappedDelay = Math.min(exponentialDelay, config.maxRetryDelay);
3509
+ const jitter = 0.5 + Math.random();
3510
+ return Math.floor(cappedDelay * jitter);
3511
+ }
3512
+ function isRetryableStatus(status, config) {
3513
+ return config.retryOn.includes(status);
3514
+ }
3515
+ function sleep(ms) {
3516
+ return new Promise((resolve) => setTimeout(resolve, ms));
3517
+ }
3291
3518
  function createClient(options) {
3292
3519
  return new VaifClient(options);
3293
3520
  }
@@ -3297,10 +3524,10 @@ var VaifClient = class {
3297
3524
  const isAdminClient = options.baseUrl || options.accessToken;
3298
3525
  if (!isAdminClient) {
3299
3526
  if (!options.projectId) {
3300
- throw new Error("projectId is required");
3527
+ throw new VaifError("projectId is required", { code: "INVALID_CONFIG" });
3301
3528
  }
3302
3529
  if (!options.apiKey) {
3303
- throw new Error("apiKey is required");
3530
+ throw new VaifError("apiKey is required", { code: "INVALID_CONFIG" });
3304
3531
  }
3305
3532
  }
3306
3533
  this.config = {
@@ -3314,7 +3541,13 @@ var VaifClient = class {
3314
3541
  debug: options.debug ?? false,
3315
3542
  autoRefreshToken: options.autoRefreshToken ?? true,
3316
3543
  persistSession: options.persistSession ?? true,
3317
- storage: options.storage ?? browserStorage ?? memoryStorage
3544
+ storage: options.storage ?? browserStorage ?? memoryStorage,
3545
+ retry: {
3546
+ ...DEFAULT_RETRY,
3547
+ ...options.retry,
3548
+ retryOn: options.retry?.retryOn ?? DEFAULT_RETRY.retryOn
3549
+ },
3550
+ interceptors: options.interceptors ?? {}
3318
3551
  };
3319
3552
  if (options.accessToken) {
3320
3553
  this.accessToken = options.accessToken;
@@ -3333,120 +3566,228 @@ var VaifClient = class {
3333
3566
  this.integrations = new VaifIntegrations(this);
3334
3567
  this.restoreSession();
3335
3568
  }
3336
- /**
3337
- * Get current configuration
3338
- */
3569
+ /** Get current configuration */
3339
3570
  getConfig() {
3340
3571
  return this.config;
3341
3572
  }
3342
- /**
3343
- * Set access token for authenticated requests
3344
- */
3573
+ /** Set access token for authenticated requests */
3345
3574
  setAccessToken(token) {
3346
3575
  this.accessToken = token;
3347
3576
  }
3348
- /**
3349
- * Get current access token
3350
- */
3577
+ /** Get current access token */
3351
3578
  getAccessToken() {
3352
3579
  return this.accessToken;
3353
3580
  }
3354
3581
  /**
3355
- * Make an authenticated API request
3582
+ * Make an authenticated API request with automatic retry and interceptors
3583
+ *
3584
+ * @param path - API path (relative to base URL)
3585
+ * @param options - Request options (method, body, params, etc.)
3586
+ * @returns Typed API response with data, error, status, and headers
3356
3587
  */
3357
3588
  async request(path, options = {}) {
3358
- const url = new URL(path, this.config.apiUrl);
3359
- if (options.params) {
3360
- Object.entries(options.params).forEach(([key, value]) => {
3361
- if (value !== void 0) {
3362
- url.searchParams.set(key, String(value));
3589
+ const { retry, interceptors } = this.config;
3590
+ for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {
3591
+ const startTime = Date.now();
3592
+ const url = new URL(path, this.config.apiUrl);
3593
+ if (options.params) {
3594
+ Object.entries(options.params).forEach(([key, value]) => {
3595
+ if (value !== void 0) {
3596
+ url.searchParams.set(key, String(value));
3597
+ }
3598
+ });
3599
+ }
3600
+ const headers = {
3601
+ "Content-Type": "application/json",
3602
+ ...this.config.headers,
3603
+ ...options.headers
3604
+ };
3605
+ if (this.config.projectId) {
3606
+ headers["X-Project-ID"] = this.config.projectId;
3607
+ }
3608
+ if (this.config.apiKey) {
3609
+ headers[this.config.apiKeyHeader] = this.config.apiKey;
3610
+ }
3611
+ if (this.accessToken) {
3612
+ headers.Authorization = `Bearer ${this.accessToken}`;
3613
+ }
3614
+ let requestContext = {
3615
+ url: url.toString(),
3616
+ path,
3617
+ method: options.method ?? "GET",
3618
+ headers: { ...headers },
3619
+ body: options.body && options.method !== "GET" ? JSON.stringify(options.body) : void 0,
3620
+ attempt
3621
+ };
3622
+ if (interceptors.onRequest) {
3623
+ try {
3624
+ const modified = await interceptors.onRequest(requestContext);
3625
+ if (modified) {
3626
+ requestContext = modified;
3627
+ }
3628
+ } catch {
3363
3629
  }
3364
- });
3365
- }
3366
- const headers = {
3367
- "Content-Type": "application/json",
3368
- ...this.config.headers,
3369
- ...options.headers
3370
- };
3371
- if (this.config.projectId) {
3372
- headers["X-Project-ID"] = this.config.projectId;
3373
- }
3374
- if (this.config.apiKey) {
3375
- headers[this.config.apiKeyHeader] = this.config.apiKey;
3376
- }
3377
- if (this.accessToken) {
3378
- headers.Authorization = `Bearer ${this.accessToken}`;
3379
- }
3380
- const fetchOptions = {
3381
- method: options.method ?? "GET",
3382
- headers,
3383
- signal: options.signal
3384
- };
3385
- if (options.body && options.method !== "GET") {
3386
- fetchOptions.body = JSON.stringify(options.body);
3387
- }
3388
- const timeoutMs = options.timeout ?? this.config.timeout;
3389
- const timeoutController = new AbortController();
3390
- const timeoutId = setTimeout(() => timeoutController.abort(), timeoutMs);
3391
- if (options.signal) {
3392
- options.signal.addEventListener("abort", () => timeoutController.abort());
3393
- }
3394
- fetchOptions.signal = timeoutController.signal;
3395
- try {
3396
- if (this.config.debug) {
3397
- console.log(`[VAIF] ${options.method ?? "GET"} ${url.toString()}`);
3398
3630
  }
3399
- const response = await fetch(url.toString(), fetchOptions);
3400
- clearTimeout(timeoutId);
3401
- const contentType = response.headers.get("content-type");
3402
- let data = null;
3403
- let error = null;
3404
- if (contentType?.includes("application/json")) {
3405
- const json = await response.json();
3406
- if (response.ok) {
3407
- data = json;
3408
- } else {
3631
+ const fetchOptions = {
3632
+ method: requestContext.method,
3633
+ headers: requestContext.headers,
3634
+ signal: options.signal
3635
+ };
3636
+ if (requestContext.body) {
3637
+ fetchOptions.body = requestContext.body;
3638
+ }
3639
+ const timeoutMs = options.timeout ?? this.config.timeout;
3640
+ const timeoutController = new AbortController();
3641
+ const timeoutId = setTimeout(() => timeoutController.abort(), timeoutMs);
3642
+ if (options.signal) {
3643
+ options.signal.addEventListener("abort", () => timeoutController.abort());
3644
+ }
3645
+ fetchOptions.signal = timeoutController.signal;
3646
+ try {
3647
+ if (this.config.debug) {
3648
+ console.log(`[VAIF] ${requestContext.method} ${requestContext.url} (attempt ${attempt + 1})`);
3649
+ }
3650
+ const response = await fetch(requestContext.url, fetchOptions);
3651
+ clearTimeout(timeoutId);
3652
+ const durationMs = Date.now() - startTime;
3653
+ const contentType = response.headers.get("content-type");
3654
+ let data = null;
3655
+ let error = null;
3656
+ if (contentType?.includes("application/json")) {
3657
+ const json = await response.json();
3658
+ if (response.ok) {
3659
+ data = json;
3660
+ } else {
3661
+ error = {
3662
+ message: json.message ?? json.error ?? "Request failed",
3663
+ code: json.code,
3664
+ status: response.status,
3665
+ details: json.details,
3666
+ requestId: response.headers.get("x-request-id") ?? void 0
3667
+ };
3668
+ }
3669
+ } else if (!response.ok) {
3409
3670
  error = {
3410
- message: json.message ?? json.error ?? "Request failed",
3411
- code: json.code,
3412
- status: response.status,
3413
- details: json.details,
3414
- requestId: response.headers.get("x-request-id") ?? void 0
3671
+ message: `Request failed with status ${response.status}`,
3672
+ status: response.status
3415
3673
  };
3416
3674
  }
3417
- } else if (!response.ok) {
3418
- error = {
3419
- message: `Request failed with status ${response.status}`,
3420
- status: response.status
3675
+ const responseHeaders = {};
3676
+ response.headers.forEach((value, key) => {
3677
+ responseHeaders[key] = value;
3678
+ });
3679
+ if (error && attempt < retry.maxRetries && isRetryableStatus(response.status, retry)) {
3680
+ if (interceptors.onError) {
3681
+ try {
3682
+ await interceptors.onError({
3683
+ request: requestContext,
3684
+ error: new VaifError(error.message, {
3685
+ code: error.code ?? "REQUEST_ERROR",
3686
+ statusCode: response.status
3687
+ }),
3688
+ durationMs,
3689
+ willRetry: true
3690
+ });
3691
+ } catch {
3692
+ }
3693
+ }
3694
+ const delay = calculateRetryDelay(attempt, retry);
3695
+ if (this.config.debug) {
3696
+ console.log(`[VAIF] Retrying in ${delay}ms (attempt ${attempt + 2}/${retry.maxRetries + 1})`);
3697
+ }
3698
+ await sleep(delay);
3699
+ continue;
3700
+ }
3701
+ if (!error && interceptors.onResponse) {
3702
+ try {
3703
+ await interceptors.onResponse({
3704
+ request: requestContext,
3705
+ data,
3706
+ status: response.status,
3707
+ headers: responseHeaders,
3708
+ durationMs
3709
+ });
3710
+ } catch {
3711
+ }
3712
+ }
3713
+ if (error && interceptors.onError) {
3714
+ try {
3715
+ await interceptors.onError({
3716
+ request: requestContext,
3717
+ error: new VaifError(error.message, {
3718
+ code: error.code ?? "REQUEST_ERROR",
3719
+ statusCode: response.status
3720
+ }),
3721
+ durationMs,
3722
+ willRetry: false
3723
+ });
3724
+ } catch {
3725
+ }
3726
+ }
3727
+ return {
3728
+ data,
3729
+ error,
3730
+ status: response.status,
3731
+ headers: responseHeaders
3732
+ };
3733
+ } catch (err) {
3734
+ clearTimeout(timeoutId);
3735
+ const durationMs = Date.now() - startTime;
3736
+ const isTimeout = err instanceof Error && err.name === "AbortError";
3737
+ const isNetworkError = !isTimeout;
3738
+ if (isNetworkError && retry.retryOnNetworkError && attempt < retry.maxRetries) {
3739
+ if (interceptors.onError) {
3740
+ try {
3741
+ await interceptors.onError({
3742
+ request: requestContext,
3743
+ error: err instanceof Error ? err : new Error(String(err)),
3744
+ durationMs,
3745
+ willRetry: true
3746
+ });
3747
+ } catch {
3748
+ }
3749
+ }
3750
+ const delay = calculateRetryDelay(attempt, retry);
3751
+ if (this.config.debug) {
3752
+ console.log(`[VAIF] Network error, retrying in ${delay}ms`);
3753
+ }
3754
+ await sleep(delay);
3755
+ continue;
3756
+ }
3757
+ const error = {
3758
+ message: err instanceof Error ? isTimeout ? "Request timed out" : err.message : "Unknown error",
3759
+ code: isTimeout ? "TIMEOUT" : "NETWORK_ERROR"
3760
+ };
3761
+ if (interceptors.onError) {
3762
+ try {
3763
+ await interceptors.onError({
3764
+ request: requestContext,
3765
+ error: isTimeout ? new VaifTimeoutError("Request timed out", timeoutMs) : new VaifNetworkError(
3766
+ err instanceof Error ? err.message : "Network error",
3767
+ err instanceof Error ? err : void 0
3768
+ ),
3769
+ durationMs,
3770
+ willRetry: false
3771
+ });
3772
+ } catch {
3773
+ }
3774
+ }
3775
+ return {
3776
+ data: null,
3777
+ error,
3778
+ status: 0,
3779
+ headers: {}
3421
3780
  };
3422
3781
  }
3423
- const responseHeaders = {};
3424
- response.headers.forEach((value, key) => {
3425
- responseHeaders[key] = value;
3426
- });
3427
- return {
3428
- data,
3429
- error,
3430
- status: response.status,
3431
- headers: responseHeaders
3432
- };
3433
- } catch (err) {
3434
- clearTimeout(timeoutId);
3435
- const error = {
3436
- message: err instanceof Error ? err.name === "AbortError" ? "Request timed out" : err.message : "Unknown error",
3437
- code: err instanceof Error && err.name === "AbortError" ? "TIMEOUT" : "NETWORK_ERROR"
3438
- };
3439
- return {
3440
- data: null,
3441
- error,
3442
- status: 0,
3443
- headers: {}
3444
- };
3445
3782
  }
3783
+ return {
3784
+ data: null,
3785
+ error: { message: "Max retries exceeded", code: "MAX_RETRIES" },
3786
+ status: 0,
3787
+ headers: {}
3788
+ };
3446
3789
  }
3447
- /**
3448
- * Restore session from storage
3449
- */
3790
+ /** Restore session from storage */
3450
3791
  async restoreSession() {
3451
3792
  if (!this.config.persistSession) return;
3452
3793
  try {
@@ -3462,9 +3803,7 @@ var VaifClient = class {
3462
3803
  } catch {
3463
3804
  }
3464
3805
  }
3465
- /**
3466
- * Log debug messages
3467
- */
3806
+ /** Log debug messages */
3468
3807
  debug(...args) {
3469
3808
  if (this.config.debug) {
3470
3809
  console.log("[VAIF]", ...args);
@@ -3478,16 +3817,32 @@ var VaifClient = class {
3478
3817
  VaifAdmin,
3479
3818
  VaifApiKeys,
3480
3819
  VaifAuth,
3820
+ VaifAuthError,
3481
3821
  VaifClient,
3822
+ VaifConflictError,
3482
3823
  VaifDatabase,
3824
+ VaifError,
3483
3825
  VaifFunctions,
3484
3826
  VaifIntegrations,
3827
+ VaifNetworkError,
3828
+ VaifNotFoundError,
3485
3829
  VaifProjects,
3830
+ VaifRateLimitError,
3486
3831
  VaifRealtime,
3487
3832
  VaifSchema,
3488
3833
  VaifStorage,
3834
+ VaifTimeoutError,
3489
3835
  VaifTypeGen,
3836
+ VaifValidationError,
3490
3837
  createClient,
3491
3838
  createTypeGen,
3492
- createVaifClient
3839
+ createVaifClient,
3840
+ isVaifAuthError,
3841
+ isVaifConflictError,
3842
+ isVaifError,
3843
+ isVaifNetworkError,
3844
+ isVaifNotFoundError,
3845
+ isVaifRateLimitError,
3846
+ isVaifTimeoutError,
3847
+ isVaifValidationError
3493
3848
  });