@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/LICENSE +21 -0
- package/README.md +554 -0
- package/dist/index.cjs +458 -103
- package/dist/index.d.cts +564 -62
- package/dist/index.d.ts +564 -62
- package/dist/index.js +441 -102
- package/package.json +3 -4
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
|
|
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
|
-
|
|
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
|
|
3527
|
+
throw new VaifError("projectId is required", { code: "INVALID_CONFIG" });
|
|
3301
3528
|
}
|
|
3302
3529
|
if (!options.apiKey) {
|
|
3303
|
-
throw new
|
|
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
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
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
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
if (
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
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:
|
|
3411
|
-
|
|
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
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
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
|
});
|