@vaiftechnologies/vaif-client 0.1.1 → 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.
@@ -1,3 +1,166 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ RealtimeChannel: () => RealtimeChannel,
24
+ VaifAI: () => VaifAI,
25
+ VaifAdmin: () => VaifAdmin,
26
+ VaifApiKeys: () => VaifApiKeys,
27
+ VaifAuth: () => VaifAuth,
28
+ VaifAuthError: () => VaifAuthError,
29
+ VaifClient: () => VaifClient,
30
+ VaifConflictError: () => VaifConflictError,
31
+ VaifDatabase: () => VaifDatabase,
32
+ VaifError: () => VaifError,
33
+ VaifFunctions: () => VaifFunctions,
34
+ VaifIntegrations: () => VaifIntegrations,
35
+ VaifNetworkError: () => VaifNetworkError,
36
+ VaifNotFoundError: () => VaifNotFoundError,
37
+ VaifProjects: () => VaifProjects,
38
+ VaifRateLimitError: () => VaifRateLimitError,
39
+ VaifRealtime: () => VaifRealtime,
40
+ VaifSchema: () => VaifSchema,
41
+ VaifStorage: () => VaifStorage,
42
+ VaifTimeoutError: () => VaifTimeoutError,
43
+ VaifTypeGen: () => VaifTypeGen,
44
+ VaifValidationError: () => VaifValidationError,
45
+ createClient: () => createClient,
46
+ createTypeGen: () => createTypeGen,
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
56
+ });
57
+ module.exports = __toCommonJS(index_exports);
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
+
1
164
  // src/lib/database.ts
2
165
  var VaifDatabase = class {
3
166
  constructor(client) {
@@ -6,6 +169,9 @@ var VaifDatabase = class {
6
169
  /**
7
170
  * Start a query on a table
8
171
  *
172
+ * @param table - Table name to query
173
+ * @returns A query builder for chaining operations
174
+ *
9
175
  * @example
10
176
  * ```typescript
11
177
  * const users = await vaif.db.from('users').select('*').execute();
@@ -17,6 +183,10 @@ var VaifDatabase = class {
17
183
  /**
18
184
  * Execute raw SQL query (admin only)
19
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
+ *
20
190
  * @example
21
191
  * ```typescript
22
192
  * const result = await vaif.db.raw('SELECT * FROM users WHERE id = $1', [userId]);
@@ -44,7 +214,16 @@ var VaifDatabase = class {
44
214
  };
45
215
  }
46
216
  /**
47
- * 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
+ * ```
48
227
  */
49
228
  async rpc(functionName, params) {
50
229
  const response = await this.client.request(`/db/rpc/${functionName}`, {
@@ -133,72 +312,85 @@ var QueryBuilder = class {
133
312
  this.onConflictUpdate = data;
134
313
  return this;
135
314
  }
136
- // Filter methods
315
+ /** Filter by equality (column = value) */
137
316
  eq(column, value) {
138
317
  this.addFilter(column, this.negateNext ? "neq" : "eq", value);
139
318
  this.negateNext = false;
140
319
  return this;
141
320
  }
321
+ /** Filter by inequality (column != value) */
142
322
  neq(column, value) {
143
323
  this.addFilter(column, this.negateNext ? "eq" : "neq", value);
144
324
  this.negateNext = false;
145
325
  return this;
146
326
  }
327
+ /** Filter by greater than (column > value) */
147
328
  gt(column, value) {
148
329
  this.addFilter(column, this.negateNext ? "lte" : "gt", value);
149
330
  this.negateNext = false;
150
331
  return this;
151
332
  }
333
+ /** Filter by greater than or equal (column >= value) */
152
334
  gte(column, value) {
153
335
  this.addFilter(column, this.negateNext ? "lt" : "gte", value);
154
336
  this.negateNext = false;
155
337
  return this;
156
338
  }
339
+ /** Filter by less than (column < value) */
157
340
  lt(column, value) {
158
341
  this.addFilter(column, this.negateNext ? "gte" : "lt", value);
159
342
  this.negateNext = false;
160
343
  return this;
161
344
  }
345
+ /** Filter by less than or equal (column <= value) */
162
346
  lte(column, value) {
163
347
  this.addFilter(column, this.negateNext ? "gt" : "lte", value);
164
348
  this.negateNext = false;
165
349
  return this;
166
350
  }
351
+ /** Filter by pattern matching (case-sensitive LIKE) */
167
352
  like(column, pattern) {
168
353
  this.addFilter(column, this.negateNext ? "nlike" : "like", pattern);
169
354
  this.negateNext = false;
170
355
  return this;
171
356
  }
357
+ /** Filter by pattern matching (case-insensitive ILIKE) */
172
358
  ilike(column, pattern) {
173
359
  this.addFilter(column, this.negateNext ? "nilike" : "ilike", pattern);
174
360
  this.negateNext = false;
175
361
  return this;
176
362
  }
363
+ /** Filter by IS (null/boolean checks) */
177
364
  is(column, value) {
178
365
  this.addFilter(column, this.negateNext ? "isnot" : "is", value);
179
366
  this.negateNext = false;
180
367
  return this;
181
368
  }
369
+ /** Filter by inclusion in an array of values */
182
370
  in(column, values) {
183
371
  this.addFilter(column, this.negateNext ? "nin" : "in", values);
184
372
  this.negateNext = false;
185
373
  return this;
186
374
  }
375
+ /** Filter by array containment (@>) */
187
376
  contains(column, value) {
188
377
  this.addFilter(column, "cs", value);
189
378
  this.negateNext = false;
190
379
  return this;
191
380
  }
381
+ /** Filter by array being contained by (<@) */
192
382
  containedBy(column, value) {
193
383
  this.addFilter(column, "cd", value);
194
384
  this.negateNext = false;
195
385
  return this;
196
386
  }
387
+ /** Filter by array overlap (&&) */
197
388
  overlaps(column, value) {
198
389
  this.addFilter(column, "ov", value);
199
390
  this.negateNext = false;
200
391
  return this;
201
392
  }
393
+ /** Full-text search filter */
202
394
  textSearch(column, query, options) {
203
395
  this.addFilter(column, "fts", query, options?.config);
204
396
  this.negateNext = false;
@@ -1813,6 +2005,42 @@ var VaifAI = class {
1813
2005
  }
1814
2006
  return { data: response.data, error: null };
1815
2007
  }
2008
+ /**
2009
+ * Generate a plan for schema or other tasks using AI
2010
+ *
2011
+ * @example
2012
+ * ```typescript
2013
+ * const { data, error } = await vaif.ai.generatePlan({
2014
+ * projectId: 'your-project-id',
2015
+ * prompt: 'Create a users table with email and password',
2016
+ * taskType: 'plan_schema',
2017
+ * mode: 'balanced'
2018
+ * });
2019
+ * ```
2020
+ */
2021
+ async generatePlan(request) {
2022
+ const response = await this.client.request("/ai/plan", {
2023
+ method: "POST",
2024
+ body: request
2025
+ });
2026
+ if (response.error) {
2027
+ return {
2028
+ ok: false,
2029
+ plan: { steps: [] },
2030
+ costEstimateCents: 0,
2031
+ error: {
2032
+ message: response.error.message,
2033
+ code: response.error.code,
2034
+ status: response.status
2035
+ }
2036
+ };
2037
+ }
2038
+ return response.data ?? {
2039
+ ok: false,
2040
+ plan: { steps: [] },
2041
+ costEstimateCents: 0
2042
+ };
2043
+ }
1816
2044
  /**
1817
2045
  * Generate SQL migration from schema diff
1818
2046
  */
@@ -1838,6 +2066,260 @@ var VaifAI = class {
1838
2066
  }
1839
2067
  return { data: response.data, error: null };
1840
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
+ }
2126
+ };
2127
+
2128
+ // src/lib/schema.ts
2129
+ var VaifSchema = class {
2130
+ constructor(client) {
2131
+ this.client = client;
2132
+ }
2133
+ /**
2134
+ * Preview schema changes without applying them
2135
+ *
2136
+ * @example
2137
+ * ```typescript
2138
+ * const result = await vaif.schema.preview({
2139
+ * projectId: 'your-project-id',
2140
+ * definition: {
2141
+ * tables: [
2142
+ * { name: 'users', columns: [{ name: 'id', type: 'uuid', primaryKey: true }] }
2143
+ * ]
2144
+ * }
2145
+ * });
2146
+ *
2147
+ * if (result.ok) {
2148
+ * console.log('Plan steps:', result.plan);
2149
+ * console.log('SQL:', result.upSql);
2150
+ * }
2151
+ * ```
2152
+ */
2153
+ async preview(request) {
2154
+ const response = await this.client.request(
2155
+ "/schema-engine/preview",
2156
+ {
2157
+ method: "POST",
2158
+ body: request
2159
+ }
2160
+ );
2161
+ if (response.error) {
2162
+ return {
2163
+ ok: false,
2164
+ projectSchema: "",
2165
+ plan: [],
2166
+ upSql: "",
2167
+ downSql: "",
2168
+ warnings: [],
2169
+ error: {
2170
+ message: response.error.message,
2171
+ code: response.error.code,
2172
+ status: response.status,
2173
+ details: response.error.details
2174
+ }
2175
+ };
2176
+ }
2177
+ return response.data ?? {
2178
+ ok: false,
2179
+ projectSchema: "",
2180
+ plan: [],
2181
+ upSql: "",
2182
+ downSql: "",
2183
+ warnings: []
2184
+ };
2185
+ }
2186
+ /**
2187
+ * Apply schema changes to the database
2188
+ *
2189
+ * @example
2190
+ * ```typescript
2191
+ * const result = await vaif.schema.apply({
2192
+ * projectId: 'your-project-id',
2193
+ * definition: {
2194
+ * tables: [
2195
+ * { name: 'users', columns: [{ name: 'id', type: 'uuid', primaryKey: true }] }
2196
+ * ]
2197
+ * },
2198
+ * migrationName: 'add_users_table'
2199
+ * });
2200
+ *
2201
+ * if (result.ok) {
2202
+ * console.log('Applied:', result.appliedSteps, 'steps');
2203
+ * }
2204
+ * ```
2205
+ */
2206
+ async apply(request) {
2207
+ const response = await this.client.request(
2208
+ "/schema-engine/apply",
2209
+ {
2210
+ method: "POST",
2211
+ body: request
2212
+ }
2213
+ );
2214
+ if (response.error) {
2215
+ return {
2216
+ ok: false,
2217
+ projectSchema: "",
2218
+ migration: {
2219
+ id: "",
2220
+ name: "",
2221
+ status: "failed",
2222
+ appliedAt: ""
2223
+ },
2224
+ appliedSteps: 0,
2225
+ error: {
2226
+ message: response.error.message,
2227
+ code: response.error.code,
2228
+ status: response.status,
2229
+ details: response.error.details
2230
+ }
2231
+ };
2232
+ }
2233
+ return response.data ?? {
2234
+ ok: false,
2235
+ projectSchema: "",
2236
+ migration: {
2237
+ id: "",
2238
+ name: "",
2239
+ status: "failed",
2240
+ appliedAt: ""
2241
+ },
2242
+ appliedSteps: 0
2243
+ };
2244
+ }
2245
+ /**
2246
+ * Introspect current database schema
2247
+ *
2248
+ * @example
2249
+ * ```typescript
2250
+ * const result = await vaif.schema.introspect('your-project-id');
2251
+ *
2252
+ * if (result.ok) {
2253
+ * console.log('Tables:', result.tables);
2254
+ * }
2255
+ * ```
2256
+ */
2257
+ async introspect(projectId, envId) {
2258
+ const params = {};
2259
+ if (envId) {
2260
+ params.envId = envId;
2261
+ }
2262
+ const response = await this.client.request(
2263
+ `/schema-engine/introspect/${projectId}`,
2264
+ { params }
2265
+ );
2266
+ if (response.error) {
2267
+ return {
2268
+ ok: false,
2269
+ schemaExists: false,
2270
+ tables: [],
2271
+ error: {
2272
+ message: response.error.message,
2273
+ code: response.error.code,
2274
+ status: response.status
2275
+ }
2276
+ };
2277
+ }
2278
+ return response.data ?? {
2279
+ ok: false,
2280
+ schemaExists: false,
2281
+ tables: []
2282
+ };
2283
+ }
2284
+ /**
2285
+ * Get migration history for a project
2286
+ *
2287
+ * @example
2288
+ * ```typescript
2289
+ * const result = await vaif.schema.getMigrations('your-project-id');
2290
+ *
2291
+ * if (result.ok) {
2292
+ * for (const migration of result.migrations) {
2293
+ * console.log(migration.name, migration.status);
2294
+ * }
2295
+ * }
2296
+ * ```
2297
+ */
2298
+ async getMigrations(projectId, options) {
2299
+ const params = {};
2300
+ if (options?.limit) {
2301
+ params.limit = String(options.limit);
2302
+ }
2303
+ const response = await this.client.request(
2304
+ `/schema-engine/migrations/project/${projectId}`,
2305
+ { params }
2306
+ );
2307
+ if (response.error) {
2308
+ return {
2309
+ ok: false,
2310
+ migrations: [],
2311
+ error: {
2312
+ message: response.error.message,
2313
+ code: response.error.code,
2314
+ status: response.status
2315
+ }
2316
+ };
2317
+ }
2318
+ return response.data ?? {
2319
+ ok: false,
2320
+ migrations: []
2321
+ };
2322
+ }
1841
2323
  };
1842
2324
 
1843
2325
  // src/lib/typegen.ts
@@ -1958,7 +2440,7 @@ var VaifTypeGen = class {
1958
2440
  lines.push("");
1959
2441
  }
1960
2442
  }
1961
- let filteredTables = dbSchema.tables.filter((t) => {
2443
+ const filteredTables = dbSchema.tables.filter((t) => {
1962
2444
  if (tables.length > 0 && !tables.includes(t.name)) return false;
1963
2445
  if (excludeTables.includes(t.name)) return false;
1964
2446
  return true;
@@ -2050,7 +2532,7 @@ var VaifTypeGen = class {
2050
2532
  lines.push("");
2051
2533
  }
2052
2534
  }
2053
- let filteredTables = (schema.tables || []).filter((t) => {
2535
+ const filteredTables = (schema.tables || []).filter((t) => {
2054
2536
  if (tables.length > 0 && !tables.includes(t.name)) return false;
2055
2537
  if (excludeTables.includes(t.name)) return false;
2056
2538
  return true;
@@ -2442,55 +2924,631 @@ var VaifAdmin = class {
2442
2924
  }
2443
2925
  };
2444
2926
 
2445
- // src/lib/client.ts
2446
- var DEFAULT_API_URL = "https://api.vaif.studio";
2447
- var DEFAULT_REALTIME_URL = "wss://realtime.vaif.studio";
2448
- var DEFAULT_TIMEOUT = 3e4;
2449
- var memoryStorage = {
2450
- data: /* @__PURE__ */ new Map(),
2451
- getItem(key) {
2452
- return this.data.get(key) ?? null;
2453
- },
2454
- setItem(key, value) {
2455
- this.data.set(key, value);
2456
- },
2457
- removeItem(key) {
2458
- this.data.delete(key);
2927
+ // src/lib/projects.ts
2928
+ var VaifProjects = class {
2929
+ constructor(client) {
2930
+ this.client = client;
2459
2931
  }
2460
- };
2461
- var browserStorage = typeof window !== "undefined" && window.localStorage ? {
2462
- getItem: (key) => window.localStorage.getItem(key),
2463
- setItem: (key, value) => window.localStorage.setItem(key, value),
2464
- removeItem: (key) => window.localStorage.removeItem(key)
2465
- } : null;
2466
- function createClient(options) {
2467
- return new VaifClient(options);
2468
- }
2469
- var VaifClient = class {
2470
- constructor(options) {
2471
- this.accessToken = null;
2472
- const isAdminClient = options.baseUrl || options.accessToken;
2473
- if (!isAdminClient) {
2474
- if (!options.projectId) {
2475
- throw new Error("projectId is required");
2476
- }
2477
- if (!options.apiKey) {
2478
- throw new Error("apiKey is required");
2479
- }
2932
+ /**
2933
+ * List all projects the user has access to
2934
+ */
2935
+ async list(options) {
2936
+ const params = {};
2937
+ if (options?.orgId) {
2938
+ params.orgId = options.orgId;
2480
2939
  }
2481
- this.config = {
2482
- projectId: options.projectId ?? "",
2483
- apiKey: options.apiKey ?? "",
2484
- apiKeyHeader: options.apiKeyHeader ?? "apikey",
2485
- apiUrl: options.baseUrl ?? options.apiUrl ?? DEFAULT_API_URL,
2486
- realtimeUrl: options.realtimeUrl ?? DEFAULT_REALTIME_URL,
2487
- timeout: options.timeout ?? DEFAULT_TIMEOUT,
2488
- headers: options.headers ?? {},
2489
- debug: options.debug ?? false,
2490
- autoRefreshToken: options.autoRefreshToken ?? true,
2491
- persistSession: options.persistSession ?? true,
2492
- storage: options.storage ?? browserStorage ?? memoryStorage
2493
- };
2940
+ const response = await this.client.request("/projects", { params });
2941
+ if (response.error) {
2942
+ throw new Error(response.error.message);
2943
+ }
2944
+ return response.data ?? [];
2945
+ }
2946
+ /**
2947
+ * Get a specific project by ID
2948
+ */
2949
+ async get(projectId) {
2950
+ const response = await this.client.request(
2951
+ `/projects/${projectId}`
2952
+ );
2953
+ if (response.error) {
2954
+ throw new Error(response.error.message);
2955
+ }
2956
+ return response.data ?? { project: {}, environments: [] };
2957
+ }
2958
+ /**
2959
+ * Create a new project
2960
+ */
2961
+ async create(options) {
2962
+ const response = await this.client.request(
2963
+ "/projects",
2964
+ {
2965
+ method: "POST",
2966
+ body: options
2967
+ }
2968
+ );
2969
+ if (response.error) {
2970
+ throw new Error(response.error.message);
2971
+ }
2972
+ return response.data ?? { project: {}, environments: [] };
2973
+ }
2974
+ /**
2975
+ * Update a project
2976
+ */
2977
+ async update(projectId, options) {
2978
+ const response = await this.client.request(
2979
+ `/projects/${projectId}`,
2980
+ {
2981
+ method: "PATCH",
2982
+ body: options
2983
+ }
2984
+ );
2985
+ if (response.error) {
2986
+ throw new Error(response.error.message);
2987
+ }
2988
+ return response.data ?? { project: {} };
2989
+ }
2990
+ /**
2991
+ * Delete a project
2992
+ */
2993
+ async delete(projectId) {
2994
+ const response = await this.client.request(
2995
+ `/projects/${projectId}`,
2996
+ {
2997
+ method: "DELETE"
2998
+ }
2999
+ );
3000
+ if (response.error) {
3001
+ throw new Error(response.error.message);
3002
+ }
3003
+ }
3004
+ /**
3005
+ * List API keys for a project
3006
+ */
3007
+ async listApiKeys(projectId) {
3008
+ const response = await this.client.request(
3009
+ `/projects/${projectId}/api-keys`
3010
+ );
3011
+ if (response.error) {
3012
+ throw new Error(response.error.message);
3013
+ }
3014
+ return response.data?.keys ?? [];
3015
+ }
3016
+ /**
3017
+ * Alias for listApiKeys
3018
+ */
3019
+ async getApiKeys(projectId) {
3020
+ return this.listApiKeys(projectId);
3021
+ }
3022
+ /**
3023
+ * Create an API key for a project
3024
+ */
3025
+ async createApiKey(projectId, options) {
3026
+ const response = await this.client.request(
3027
+ `/projects/${projectId}/api-keys`,
3028
+ {
3029
+ method: "POST",
3030
+ body: options ?? {}
3031
+ }
3032
+ );
3033
+ if (response.error) {
3034
+ throw new Error(response.error.message);
3035
+ }
3036
+ return response.data ?? { apiKeyId: "", apiKey: "" };
3037
+ }
3038
+ /**
3039
+ * Revoke an API key
3040
+ */
3041
+ async revokeApiKey(projectId, keyId) {
3042
+ const response = await this.client.request(
3043
+ `/projects/${projectId}/api-keys/${keyId}/revoke`,
3044
+ {
3045
+ method: "POST"
3046
+ }
3047
+ );
3048
+ if (response.error) {
3049
+ throw new Error(response.error.message);
3050
+ }
3051
+ }
3052
+ /**
3053
+ * Rotate an API key (revoke and create new)
3054
+ */
3055
+ async rotateApiKey(projectId, keyId) {
3056
+ const response = await this.client.request(
3057
+ `/projects/${projectId}/api-keys/${keyId}/rotate`,
3058
+ {
3059
+ method: "POST"
3060
+ }
3061
+ );
3062
+ if (response.error) {
3063
+ throw new Error(response.error.message);
3064
+ }
3065
+ return response.data ?? { apiKeyId: "", apiKey: "" };
3066
+ }
3067
+ // Project Settings Methods
3068
+ /**
3069
+ * Get project settings
3070
+ */
3071
+ async getSettings(projectId) {
3072
+ const response = await this.client.request(
3073
+ `/projects/${projectId}/settings`
3074
+ );
3075
+ if (response.error) {
3076
+ throw new Error(response.error.message);
3077
+ }
3078
+ return response.data ?? {};
3079
+ }
3080
+ /**
3081
+ * Get compute settings
3082
+ */
3083
+ async getComputeSettings(projectId) {
3084
+ const response = await this.client.request(
3085
+ `/projects/${projectId}/settings/compute`
3086
+ );
3087
+ if (response.error) {
3088
+ throw new Error(response.error.message);
3089
+ }
3090
+ return response.data ?? {
3091
+ tier: "starter",
3092
+ diskSize: 1,
3093
+ region: "us-east-1",
3094
+ autoScaling: false,
3095
+ maxInstances: 1
3096
+ };
3097
+ }
3098
+ /**
3099
+ * Update compute settings
3100
+ */
3101
+ async updateComputeSettings(projectId, settings) {
3102
+ const response = await this.client.request(
3103
+ `/projects/${projectId}/settings/compute`,
3104
+ {
3105
+ method: "PATCH",
3106
+ body: settings
3107
+ }
3108
+ );
3109
+ if (response.error) {
3110
+ throw new Error(response.error.message);
3111
+ }
3112
+ return response.data ?? {};
3113
+ }
3114
+ /**
3115
+ * Get API settings
3116
+ */
3117
+ async getApiSettings(projectId) {
3118
+ const response = await this.client.request(
3119
+ `/projects/${projectId}/settings/api`
3120
+ );
3121
+ if (response.error) {
3122
+ throw new Error(response.error.message);
3123
+ }
3124
+ return response.data ?? {
3125
+ apiVersion: "v1",
3126
+ rateLimit: 100,
3127
+ corsEnabled: true,
3128
+ corsOrigins: ["*"],
3129
+ customDomain: ""
3130
+ };
3131
+ }
3132
+ /**
3133
+ * Update API settings
3134
+ */
3135
+ async updateApiSettings(projectId, settings) {
3136
+ const response = await this.client.request(
3137
+ `/projects/${projectId}/settings/api`,
3138
+ {
3139
+ method: "PATCH",
3140
+ body: settings
3141
+ }
3142
+ );
3143
+ if (response.error) {
3144
+ throw new Error(response.error.message);
3145
+ }
3146
+ return response.data ?? {};
3147
+ }
3148
+ /**
3149
+ * Get JWT settings
3150
+ */
3151
+ async getJwtSettings(projectId) {
3152
+ const response = await this.client.request(
3153
+ `/projects/${projectId}/settings/jwt`
3154
+ );
3155
+ if (response.error) {
3156
+ throw new Error(response.error.message);
3157
+ }
3158
+ return response.data ?? {
3159
+ algorithm: "HS256",
3160
+ accessTokenExpiry: 3600,
3161
+ refreshTokenExpiry: 604800,
3162
+ refreshTokenEnabled: true,
3163
+ rotateOnUse: true,
3164
+ secretHint: "********",
3165
+ lastRotated: null
3166
+ };
3167
+ }
3168
+ /**
3169
+ * Update JWT settings
3170
+ */
3171
+ async updateJwtSettings(projectId, settings) {
3172
+ const response = await this.client.request(
3173
+ `/projects/${projectId}/settings/jwt`,
3174
+ {
3175
+ method: "PATCH",
3176
+ body: settings
3177
+ }
3178
+ );
3179
+ if (response.error) {
3180
+ throw new Error(response.error.message);
3181
+ }
3182
+ return response.data ?? {};
3183
+ }
3184
+ /**
3185
+ * Rotate JWT secret
3186
+ */
3187
+ async rotateJwtSecret(projectId) {
3188
+ const response = await this.client.request(
3189
+ `/projects/${projectId}/settings/jwt/rotate`,
3190
+ {
3191
+ method: "POST"
3192
+ }
3193
+ );
3194
+ if (response.error) {
3195
+ throw new Error(response.error.message);
3196
+ }
3197
+ return response.data ?? { secretHint: "", lastRotated: "" };
3198
+ }
3199
+ /**
3200
+ * Get addons configuration
3201
+ */
3202
+ async getAddons(projectId) {
3203
+ const response = await this.client.request(
3204
+ `/projects/${projectId}/settings/addons`
3205
+ );
3206
+ if (response.error) {
3207
+ throw new Error(response.error.message);
3208
+ }
3209
+ return response.data ?? {
3210
+ enabledAddons: [],
3211
+ currentTier: "free"
3212
+ };
3213
+ }
3214
+ /**
3215
+ * Update addons configuration
3216
+ */
3217
+ async updateAddons(projectId, enabledAddons) {
3218
+ const response = await this.client.request(
3219
+ `/projects/${projectId}/settings/addons`,
3220
+ {
3221
+ method: "PATCH",
3222
+ body: { enabledAddons }
3223
+ }
3224
+ );
3225
+ if (response.error) {
3226
+ throw new Error(response.error.message);
3227
+ }
3228
+ return response.data ?? {};
3229
+ }
3230
+ };
3231
+
3232
+ // src/lib/apiKeys.ts
3233
+ var VaifApiKeys = class {
3234
+ constructor(client) {
3235
+ this.client = client;
3236
+ }
3237
+ /**
3238
+ * List API keys for a project
3239
+ */
3240
+ async list(projectId) {
3241
+ const response = await this.client.request(
3242
+ `/projects/${projectId}/api-keys`
3243
+ );
3244
+ if (response.error) {
3245
+ throw new Error(response.error.message);
3246
+ }
3247
+ const keys = response.data?.keys ?? [];
3248
+ return keys.map((key) => ({
3249
+ ...key,
3250
+ keyHint: key.keyHint || `vaif_${key.id.slice(0, 8)}...`,
3251
+ permissions: key.scopes || key.permissions || ["read"]
3252
+ }));
3253
+ }
3254
+ /**
3255
+ * Create a new API key
3256
+ */
3257
+ async create(options) {
3258
+ const { projectId, ...body } = options;
3259
+ const requestBody = { ...body };
3260
+ if (options.permissions && !options.scopes) {
3261
+ const scopeMap = {
3262
+ read: "crud",
3263
+ write: "crud",
3264
+ admin: "crud",
3265
+ functions: "functions",
3266
+ storage: "storage",
3267
+ realtime: "realtime"
3268
+ };
3269
+ requestBody.scopes = options.permissions.map((p) => scopeMap[p] || p).filter((v, i, a) => a.indexOf(v) === i);
3270
+ }
3271
+ if (options.expiresIn && options.expiresIn !== "never") {
3272
+ const durationMatch = options.expiresIn.match(/^(\d+)([dmy])$/);
3273
+ if (durationMatch) {
3274
+ const amount = parseInt(durationMatch[1], 10);
3275
+ const unit = durationMatch[2];
3276
+ const now = /* @__PURE__ */ new Date();
3277
+ switch (unit) {
3278
+ case "d":
3279
+ now.setDate(now.getDate() + amount);
3280
+ break;
3281
+ case "m":
3282
+ now.setMonth(now.getMonth() + amount);
3283
+ break;
3284
+ case "y":
3285
+ now.setFullYear(now.getFullYear() + amount);
3286
+ break;
3287
+ }
3288
+ requestBody.expiresAt = now.toISOString();
3289
+ }
3290
+ }
3291
+ const response = await this.client.request(
3292
+ `/projects/${projectId}/api-keys`,
3293
+ {
3294
+ method: "POST",
3295
+ body: requestBody
3296
+ }
3297
+ );
3298
+ if (response.error) {
3299
+ throw new Error(response.error.message);
3300
+ }
3301
+ return {
3302
+ id: response.data?.apiKeyId ?? "",
3303
+ key: response.data?.apiKey ?? "",
3304
+ name: options.name ?? null,
3305
+ permissions: options.permissions ?? ["read"],
3306
+ expiresAt: requestBody.expiresAt ?? null
3307
+ };
3308
+ }
3309
+ /**
3310
+ * Revoke an API key
3311
+ */
3312
+ async revoke(keyId, projectId) {
3313
+ if (!projectId) {
3314
+ throw new Error("projectId is required to revoke an API key");
3315
+ }
3316
+ const response = await this.client.request(
3317
+ `/projects/${projectId}/api-keys/${keyId}/revoke`,
3318
+ {
3319
+ method: "POST"
3320
+ }
3321
+ );
3322
+ if (response.error) {
3323
+ throw new Error(response.error.message);
3324
+ }
3325
+ }
3326
+ /**
3327
+ * Rotate an API key
3328
+ */
3329
+ async rotate(keyId, projectId) {
3330
+ const response = await this.client.request(
3331
+ `/projects/${projectId}/api-keys/${keyId}/rotate`,
3332
+ {
3333
+ method: "POST"
3334
+ }
3335
+ );
3336
+ if (response.error) {
3337
+ throw new Error(response.error.message);
3338
+ }
3339
+ return {
3340
+ id: response.data?.apiKeyId ?? "",
3341
+ key: response.data?.apiKey ?? "",
3342
+ name: null,
3343
+ permissions: [],
3344
+ expiresAt: null
3345
+ };
3346
+ }
3347
+ /**
3348
+ * Update an API key
3349
+ */
3350
+ async update(projectId, keyId, options) {
3351
+ const response = await this.client.request(
3352
+ `/projects/${projectId}/api-keys/${keyId}`,
3353
+ {
3354
+ method: "PATCH",
3355
+ body: options
3356
+ }
3357
+ );
3358
+ if (response.error) {
3359
+ throw new Error(response.error.message);
3360
+ }
3361
+ return response.data?.apiKey ?? {};
3362
+ }
3363
+ };
3364
+
3365
+ // src/lib/integrations.ts
3366
+ var VaifIntegrations = class {
3367
+ constructor(client) {
3368
+ this.client = client;
3369
+ }
3370
+ /**
3371
+ * List integrations for a project
3372
+ */
3373
+ async list(projectId) {
3374
+ const response = await this.client.request(
3375
+ `/integrations/subscriptions/project/${projectId}`
3376
+ );
3377
+ if (response.error) {
3378
+ throw new Error(response.error.message);
3379
+ }
3380
+ return (response.data?.subscriptions ?? []).map((sub) => ({
3381
+ ...sub,
3382
+ enabled: !sub.updatedAt || true
3383
+ // Default to enabled if no explicit disabled state
3384
+ }));
3385
+ }
3386
+ /**
3387
+ * Create a new integration
3388
+ */
3389
+ async create(options) {
3390
+ const response = await this.client.request(
3391
+ "/integrations/subscriptions",
3392
+ {
3393
+ method: "POST",
3394
+ body: options
3395
+ }
3396
+ );
3397
+ if (response.error) {
3398
+ throw new Error(response.error.message);
3399
+ }
3400
+ return response.data?.subscription ?? {};
3401
+ }
3402
+ /**
3403
+ * Update an integration
3404
+ */
3405
+ async update(integrationId, options) {
3406
+ const response = await this.client.request(
3407
+ `/integrations/subscriptions/${integrationId}`,
3408
+ {
3409
+ method: "PATCH",
3410
+ body: options
3411
+ }
3412
+ );
3413
+ if (response.error) {
3414
+ throw new Error(response.error.message);
3415
+ }
3416
+ return response.data?.subscription ?? {};
3417
+ }
3418
+ /**
3419
+ * Delete an integration
3420
+ */
3421
+ async delete(integrationId) {
3422
+ const response = await this.client.request(
3423
+ `/integrations/subscriptions/${integrationId}`,
3424
+ {
3425
+ method: "DELETE"
3426
+ }
3427
+ );
3428
+ if (response.error) {
3429
+ throw new Error(response.error.message);
3430
+ }
3431
+ }
3432
+ /**
3433
+ * Test an integration
3434
+ */
3435
+ async test(integrationId) {
3436
+ const response = await this.client.request(
3437
+ `/integrations/subscriptions/${integrationId}/test`,
3438
+ {
3439
+ method: "POST"
3440
+ }
3441
+ );
3442
+ if (response.error) {
3443
+ throw new Error(response.error.message);
3444
+ }
3445
+ }
3446
+ /**
3447
+ * Get webhook deliveries for an integration
3448
+ */
3449
+ async getDeliveries(integrationId) {
3450
+ const response = await this.client.request(
3451
+ `/integrations/deliveries/subscription/${integrationId}`
3452
+ );
3453
+ if (response.error) {
3454
+ throw new Error(response.error.message);
3455
+ }
3456
+ return response.data?.deliveries ?? [];
3457
+ }
3458
+ /**
3459
+ * Get failed deliveries (DLQ) for a project
3460
+ */
3461
+ async getFailedDeliveries(projectId, limit) {
3462
+ const params = {};
3463
+ if (limit) {
3464
+ params.limit = String(limit);
3465
+ }
3466
+ const response = await this.client.request(
3467
+ `/integrations/dlq/project/${projectId}`,
3468
+ { params }
3469
+ );
3470
+ if (response.error) {
3471
+ throw new Error(response.error.message);
3472
+ }
3473
+ return response.data?.deliveries ?? [];
3474
+ }
3475
+ };
3476
+
3477
+ // src/lib/client.ts
3478
+ var DEFAULT_API_URL = "https://api.vaif.studio";
3479
+ var DEFAULT_REALTIME_URL = "wss://realtime.vaif.studio";
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
+ };
3489
+ var memoryStorage = {
3490
+ data: /* @__PURE__ */ new Map(),
3491
+ getItem(key) {
3492
+ return this.data.get(key) ?? null;
3493
+ },
3494
+ setItem(key, value) {
3495
+ this.data.set(key, value);
3496
+ },
3497
+ removeItem(key) {
3498
+ this.data.delete(key);
3499
+ }
3500
+ };
3501
+ var browserStorage = typeof window !== "undefined" && window.localStorage ? {
3502
+ getItem: (key) => window.localStorage.getItem(key),
3503
+ setItem: (key, value) => window.localStorage.setItem(key, value),
3504
+ removeItem: (key) => window.localStorage.removeItem(key)
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
+ }
3518
+ function createClient(options) {
3519
+ return new VaifClient(options);
3520
+ }
3521
+ var VaifClient = class {
3522
+ constructor(options) {
3523
+ this.accessToken = null;
3524
+ const isAdminClient = options.baseUrl || options.accessToken;
3525
+ if (!isAdminClient) {
3526
+ if (!options.projectId) {
3527
+ throw new VaifError("projectId is required", { code: "INVALID_CONFIG" });
3528
+ }
3529
+ if (!options.apiKey) {
3530
+ throw new VaifError("apiKey is required", { code: "INVALID_CONFIG" });
3531
+ }
3532
+ }
3533
+ this.config = {
3534
+ projectId: options.projectId ?? "",
3535
+ apiKey: options.apiKey ?? "",
3536
+ apiKeyHeader: options.apiKeyHeader ?? "apikey",
3537
+ apiUrl: options.baseUrl ?? options.apiUrl ?? DEFAULT_API_URL,
3538
+ realtimeUrl: options.realtimeUrl ?? DEFAULT_REALTIME_URL,
3539
+ timeout: options.timeout ?? DEFAULT_TIMEOUT,
3540
+ headers: options.headers ?? {},
3541
+ debug: options.debug ?? false,
3542
+ autoRefreshToken: options.autoRefreshToken ?? true,
3543
+ persistSession: options.persistSession ?? true,
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 ?? {}
3551
+ };
2494
3552
  if (options.accessToken) {
2495
3553
  this.accessToken = options.accessToken;
2496
3554
  }
@@ -2500,124 +3558,236 @@ var VaifClient = class {
2500
3558
  this.functions = new VaifFunctions(this);
2501
3559
  this.auth = new VaifAuth(this);
2502
3560
  this.ai = new VaifAI(this);
3561
+ this.schema = new VaifSchema(this);
2503
3562
  this.typegen = new VaifTypeGen(this);
2504
3563
  this.admin = new VaifAdmin(this);
3564
+ this.projects = new VaifProjects(this);
3565
+ this.apiKeys = new VaifApiKeys(this);
3566
+ this.integrations = new VaifIntegrations(this);
2505
3567
  this.restoreSession();
2506
3568
  }
2507
- /**
2508
- * Get current configuration
2509
- */
3569
+ /** Get current configuration */
2510
3570
  getConfig() {
2511
3571
  return this.config;
2512
3572
  }
2513
- /**
2514
- * Set access token for authenticated requests
2515
- */
3573
+ /** Set access token for authenticated requests */
2516
3574
  setAccessToken(token) {
2517
3575
  this.accessToken = token;
2518
3576
  }
2519
- /**
2520
- * Get current access token
2521
- */
3577
+ /** Get current access token */
2522
3578
  getAccessToken() {
2523
3579
  return this.accessToken;
2524
3580
  }
2525
3581
  /**
2526
- * 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
2527
3587
  */
2528
3588
  async request(path, options = {}) {
2529
- const url = new URL(path, this.config.apiUrl);
2530
- if (options.params) {
2531
- Object.entries(options.params).forEach(([key, value]) => {
2532
- if (value !== void 0) {
2533
- 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 {
2534
3629
  }
2535
- });
2536
- }
2537
- const headers = {
2538
- "Content-Type": "application/json",
2539
- ...this.config.headers,
2540
- ...options.headers
2541
- };
2542
- if (this.config.projectId) {
2543
- headers["X-Project-ID"] = this.config.projectId;
2544
- }
2545
- if (this.config.apiKey) {
2546
- headers[this.config.apiKeyHeader] = this.config.apiKey;
2547
- }
2548
- if (this.accessToken) {
2549
- headers.Authorization = `Bearer ${this.accessToken}`;
2550
- }
2551
- const fetchOptions = {
2552
- method: options.method ?? "GET",
2553
- headers,
2554
- signal: options.signal
2555
- };
2556
- if (options.body && options.method !== "GET") {
2557
- fetchOptions.body = JSON.stringify(options.body);
2558
- }
2559
- const timeoutMs = options.timeout ?? this.config.timeout;
2560
- const timeoutController = new AbortController();
2561
- const timeoutId = setTimeout(() => timeoutController.abort(), timeoutMs);
2562
- if (options.signal) {
2563
- options.signal.addEventListener("abort", () => timeoutController.abort());
2564
- }
2565
- fetchOptions.signal = timeoutController.signal;
2566
- try {
2567
- if (this.config.debug) {
2568
- console.log(`[VAIF] ${options.method ?? "GET"} ${url.toString()}`);
2569
3630
  }
2570
- const response = await fetch(url.toString(), fetchOptions);
2571
- clearTimeout(timeoutId);
2572
- const contentType = response.headers.get("content-type");
2573
- let data = null;
2574
- let error = null;
2575
- if (contentType?.includes("application/json")) {
2576
- const json = await response.json();
2577
- if (response.ok) {
2578
- data = json;
2579
- } 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) {
2580
3670
  error = {
2581
- message: json.message ?? json.error ?? "Request failed",
2582
- code: json.code,
2583
- status: response.status,
2584
- details: json.details,
2585
- requestId: response.headers.get("x-request-id") ?? void 0
3671
+ message: `Request failed with status ${response.status}`,
3672
+ status: response.status
2586
3673
  };
2587
3674
  }
2588
- } else if (!response.ok) {
2589
- error = {
2590
- message: `Request failed with status ${response.status}`,
2591
- 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: {}
2592
3780
  };
2593
3781
  }
2594
- const responseHeaders = {};
2595
- response.headers.forEach((value, key) => {
2596
- responseHeaders[key] = value;
2597
- });
2598
- return {
2599
- data,
2600
- error,
2601
- status: response.status,
2602
- headers: responseHeaders
2603
- };
2604
- } catch (err) {
2605
- clearTimeout(timeoutId);
2606
- const error = {
2607
- message: err instanceof Error ? err.name === "AbortError" ? "Request timed out" : err.message : "Unknown error",
2608
- code: err instanceof Error && err.name === "AbortError" ? "TIMEOUT" : "NETWORK_ERROR"
2609
- };
2610
- return {
2611
- data: null,
2612
- error,
2613
- status: 0,
2614
- headers: {}
2615
- };
2616
3782
  }
3783
+ return {
3784
+ data: null,
3785
+ error: { message: "Max retries exceeded", code: "MAX_RETRIES" },
3786
+ status: 0,
3787
+ headers: {}
3788
+ };
2617
3789
  }
2618
- /**
2619
- * Restore session from storage
2620
- */
3790
+ /** Restore session from storage */
2621
3791
  async restoreSession() {
2622
3792
  if (!this.config.persistSession) return;
2623
3793
  try {
@@ -2633,27 +3803,46 @@ var VaifClient = class {
2633
3803
  } catch {
2634
3804
  }
2635
3805
  }
2636
- /**
2637
- * Log debug messages
2638
- */
3806
+ /** Log debug messages */
2639
3807
  debug(...args) {
2640
3808
  if (this.config.debug) {
2641
3809
  console.log("[VAIF]", ...args);
2642
3810
  }
2643
3811
  }
2644
3812
  };
2645
- export {
3813
+ // Annotate the CommonJS export names for ESM import in node:
3814
+ 0 && (module.exports = {
2646
3815
  RealtimeChannel,
2647
3816
  VaifAI,
2648
3817
  VaifAdmin,
3818
+ VaifApiKeys,
2649
3819
  VaifAuth,
3820
+ VaifAuthError,
2650
3821
  VaifClient,
3822
+ VaifConflictError,
2651
3823
  VaifDatabase,
3824
+ VaifError,
2652
3825
  VaifFunctions,
3826
+ VaifIntegrations,
3827
+ VaifNetworkError,
3828
+ VaifNotFoundError,
3829
+ VaifProjects,
3830
+ VaifRateLimitError,
2653
3831
  VaifRealtime,
3832
+ VaifSchema,
2654
3833
  VaifStorage,
3834
+ VaifTimeoutError,
2655
3835
  VaifTypeGen,
3836
+ VaifValidationError,
2656
3837
  createClient,
2657
3838
  createTypeGen,
2658
- createClient as createVaifClient
2659
- };
3839
+ createVaifClient,
3840
+ isVaifAuthError,
3841
+ isVaifConflictError,
3842
+ isVaifError,
3843
+ isVaifNetworkError,
3844
+ isVaifNotFoundError,
3845
+ isVaifRateLimitError,
3846
+ isVaifTimeoutError,
3847
+ isVaifValidationError
3848
+ });