@insforge/sdk 0.0.21 → 0.0.22

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.js CHANGED
@@ -26,7 +26,6 @@ __export(index_exports, {
26
26
  HttpClient: () => HttpClient,
27
27
  InsForgeClient: () => InsForgeClient,
28
28
  InsForgeError: () => InsForgeError,
29
- QueryBuilder: () => QueryBuilder,
30
29
  Storage: () => Storage,
31
30
  StorageBucket: () => StorageBucket,
32
31
  TokenManager: () => TokenManager,
@@ -62,9 +61,6 @@ var HttpClient = class {
62
61
  this.defaultHeaders = {
63
62
  ...config.headers
64
63
  };
65
- if (config.apiKey) {
66
- this.defaultHeaders["Authorization"] = `Bearer ${config.apiKey}`;
67
- }
68
64
  if (!this.fetch) {
69
65
  throw new Error(
70
66
  "Fetch is not available. Please provide a fetch implementation in the config."
@@ -209,294 +205,70 @@ var TokenManager = class {
209
205
  }
210
206
  };
211
207
 
212
- // src/modules/database.ts
213
- var QueryBuilder = class {
214
- constructor(table, http) {
215
- this.table = table;
216
- this.http = http;
217
- this.method = "GET";
218
- this.headers = {};
219
- this.queryParams = {};
220
- }
221
- /**
222
- * Perform a SELECT query
223
- * For mutations (insert/update/delete), this enables returning data
224
- * @param columns - Columns to select (default: '*')
225
- * @example
226
- * .select('*')
227
- * .select('id, title, content')
228
- * .select('*, users!inner(*)') // Join with users table
229
- * .select('*, profile:profiles(*)') // Join with alias
230
- * .insert({ title: 'New' }).select() // Returns inserted data
231
- */
232
- select(columns = "*") {
233
- if (this.method !== "GET") {
234
- const existingPrefer = this.headers["Prefer"] || "";
235
- const preferParts = existingPrefer ? [existingPrefer] : [];
236
- if (!preferParts.some((p) => p.includes("return="))) {
237
- preferParts.push("return=representation");
238
- }
239
- this.headers["Prefer"] = preferParts.join(",");
240
- }
241
- if (this.method === "GET" && columns) {
242
- this.queryParams.select = columns;
243
- } else if (columns !== "*") {
244
- this.queryParams.select = columns;
245
- }
246
- return this;
247
- }
248
- /**
249
- * Perform an INSERT
250
- * @param values - Single object or array of objects
251
- * @param options - { upsert: true } for upsert behavior
252
- * @example
253
- * .insert({ title: 'Hello', content: 'World' }).select()
254
- * .insert([{ title: 'Post 1' }, { title: 'Post 2' }]).select()
255
- */
256
- insert(values, options) {
257
- this.method = "POST";
258
- this.body = Array.isArray(values) ? values : [values];
259
- if (options?.upsert) {
260
- this.headers["Prefer"] = "resolution=merge-duplicates";
261
- }
262
- return this;
263
- }
264
- /**
265
- * Perform an UPDATE
266
- * @param values - Object with fields to update
267
- * @example
268
- * .update({ title: 'Updated Title' }).select()
269
- */
270
- update(values) {
271
- this.method = "PATCH";
272
- this.body = values;
273
- return this;
274
- }
275
- /**
276
- * Perform a DELETE
277
- * @example
278
- * .delete().select()
279
- */
280
- delete() {
281
- this.method = "DELETE";
282
- return this;
283
- }
284
- /**
285
- * Perform an UPSERT
286
- * @param values - Single object or array of objects
287
- * @example
288
- * .upsert({ id: 1, title: 'Hello' })
289
- */
290
- upsert(values) {
291
- return this.insert(values, { upsert: true });
292
- }
293
- // FILTERS
294
- /**
295
- * Filter by column equal to value
296
- * @example .eq('id', 123)
297
- */
298
- eq(column, value) {
299
- this.queryParams[column] = `eq.${value}`;
300
- return this;
301
- }
302
- /**
303
- * Filter by column not equal to value
304
- * @example .neq('status', 'draft')
305
- */
306
- neq(column, value) {
307
- this.queryParams[column] = `neq.${value}`;
308
- return this;
309
- }
310
- /**
311
- * Filter by column greater than value
312
- * @example .gt('age', 18)
313
- */
314
- gt(column, value) {
315
- this.queryParams[column] = `gt.${value}`;
316
- return this;
317
- }
318
- /**
319
- * Filter by column greater than or equal to value
320
- * @example .gte('price', 100)
321
- */
322
- gte(column, value) {
323
- this.queryParams[column] = `gte.${value}`;
324
- return this;
325
- }
326
- /**
327
- * Filter by column less than value
328
- * @example .lt('stock', 10)
329
- */
330
- lt(column, value) {
331
- this.queryParams[column] = `lt.${value}`;
332
- return this;
333
- }
334
- /**
335
- * Filter by column less than or equal to value
336
- * @example .lte('discount', 50)
337
- */
338
- lte(column, value) {
339
- this.queryParams[column] = `lte.${value}`;
340
- return this;
341
- }
342
- /**
343
- * Filter by pattern matching (case-sensitive)
344
- * @example .like('email', '%@gmail.com')
345
- */
346
- like(column, pattern) {
347
- this.queryParams[column] = `like.${pattern}`;
348
- return this;
349
- }
350
- /**
351
- * Filter by pattern matching (case-insensitive)
352
- * @example .ilike('name', '%john%')
353
- */
354
- ilike(column, pattern) {
355
- this.queryParams[column] = `ilike.${pattern}`;
356
- return this;
357
- }
358
- /**
359
- * Filter by checking if column is a value
360
- * @example .is('deleted_at', null)
361
- */
362
- is(column, value) {
363
- if (value === null) {
364
- this.queryParams[column] = "is.null";
365
- } else {
366
- this.queryParams[column] = `is.${value}`;
367
- }
368
- return this;
369
- }
370
- /**
371
- * Filter by checking if value is in array
372
- * @example .in('status', ['active', 'pending'])
373
- */
374
- in(column, values) {
375
- this.queryParams[column] = `in.(${values.join(",")})`;
376
- return this;
377
- }
378
- // MODIFIERS
379
- /**
380
- * Order by column
381
- * @example
382
- * .order('created_at') // ascending
383
- * .order('created_at', { ascending: false }) // descending
384
- */
385
- order(column, options) {
386
- const ascending = options?.ascending !== false;
387
- this.queryParams.order = ascending ? column : `${column}.desc`;
388
- return this;
389
- }
390
- /**
391
- * Limit the number of rows returned
392
- * @example .limit(10)
393
- */
394
- limit(count) {
395
- this.queryParams.limit = count.toString();
396
- return this;
397
- }
398
- /**
399
- * Return results from an offset
400
- * @example .offset(20)
401
- */
402
- offset(count) {
403
- this.queryParams.offset = count.toString();
404
- return this;
405
- }
406
- /**
407
- * Set a range of rows to return
408
- * @example .range(0, 9) // First 10 rows
409
- */
410
- range(from, to) {
411
- this.headers["Range"] = `${from}-${to}`;
412
- return this;
413
- }
414
- /**
415
- * Return a single object instead of array
416
- * @example .single()
417
- */
418
- single() {
419
- this.headers["Accept"] = "application/vnd.pgrst.object+json";
420
- return this;
421
- }
422
- /**
423
- * Get the total count (use with select)
424
- * @example .select('*', { count: 'exact' })
425
- */
426
- count(algorithm = "exact") {
427
- const prefer = this.headers["Prefer"] || "";
428
- this.headers["Prefer"] = prefer ? `${prefer},count=${algorithm}` : `count=${algorithm}`;
429
- return this;
430
- }
431
- /**
432
- * Execute the query and return results
433
- */
434
- async execute() {
435
- try {
436
- const path = `/api/database/records/${this.table}`;
437
- let response;
438
- switch (this.method) {
439
- case "GET":
440
- response = await this.http.get(path, {
441
- params: this.queryParams,
442
- headers: this.headers
443
- });
444
- break;
445
- case "POST":
446
- response = await this.http.post(path, this.body, {
447
- params: this.queryParams,
448
- headers: this.headers
449
- });
450
- break;
451
- case "PATCH":
452
- response = await this.http.patch(path, this.body, {
453
- params: this.queryParams,
454
- headers: this.headers
455
- });
456
- break;
457
- case "DELETE":
458
- response = await this.http.delete(path, {
459
- params: this.queryParams,
460
- headers: this.headers
461
- });
462
- break;
463
- }
464
- return { data: response, error: null };
465
- } catch (error) {
466
- return {
467
- data: null,
468
- error: error instanceof InsForgeError ? error : new InsForgeError(
469
- "Database operation failed",
470
- 500,
471
- "DATABASE_ERROR"
472
- )
473
- };
474
- }
475
- }
476
- /**
477
- * Make QueryBuilder thenable for async/await
478
- */
479
- then(onfulfilled, onrejected) {
480
- return this.execute().then(onfulfilled, onrejected);
481
- }
482
- };
208
+ // src/modules/database-postgrest.ts
209
+ var import_postgrest_js = require("@supabase/postgrest-js");
210
+ function createInsForgePostgrestFetch(httpClient, tokenManager) {
211
+ return async (input, init) => {
212
+ const url = typeof input === "string" ? input : input.toString();
213
+ const urlObj = new URL(url);
214
+ const tableName = urlObj.pathname.slice(1);
215
+ const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;
216
+ const token = tokenManager.getAccessToken();
217
+ const headers = new Headers(init?.headers);
218
+ if (token && !headers.has("Authorization")) {
219
+ headers.set("Authorization", `Bearer ${token}`);
220
+ }
221
+ const response = await fetch(insforgeUrl, {
222
+ ...init,
223
+ headers
224
+ });
225
+ return response;
226
+ };
227
+ }
483
228
  var Database = class {
484
- constructor(http) {
485
- this.http = http;
229
+ constructor(httpClient, tokenManager) {
230
+ this.postgrest = new import_postgrest_js.PostgrestClient("http://dummy", {
231
+ fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
232
+ headers: {}
233
+ });
486
234
  }
487
235
  /**
488
236
  * Create a query builder for a table
489
- * @param table - The table name
237
+ *
490
238
  * @example
239
+ * // Basic query
491
240
  * const { data, error } = await client.database
492
241
  * .from('posts')
493
242
  * .select('*')
494
- * .eq('user_id', userId)
495
- * .order('created_at', { ascending: false })
496
- * .limit(10);
243
+ * .eq('user_id', userId);
244
+ *
245
+ * // With count (Supabase style!)
246
+ * const { data, error, count } = await client.database
247
+ * .from('posts')
248
+ * .select('*', { count: 'exact' })
249
+ * .range(0, 9);
250
+ *
251
+ * // Just get count, no data
252
+ * const { count } = await client.database
253
+ * .from('posts')
254
+ * .select('*', { count: 'exact', head: true });
255
+ *
256
+ * // Complex queries with OR
257
+ * const { data } = await client.database
258
+ * .from('posts')
259
+ * .select('*, users!inner(*)')
260
+ * .or('status.eq.active,status.eq.pending');
261
+ *
262
+ * // All features work:
263
+ * - Nested selects
264
+ * - Foreign key expansion
265
+ * - OR/AND/NOT conditions
266
+ * - Count with head
267
+ * - Range pagination
268
+ * - Upserts
497
269
  */
498
270
  from(table) {
499
- return new QueryBuilder(table, this.http);
271
+ return this.postgrest.from(table);
500
272
  }
501
273
  };
502
274
 
@@ -505,7 +277,7 @@ var Auth = class {
505
277
  constructor(http, tokenManager) {
506
278
  this.http = http;
507
279
  this.tokenManager = tokenManager;
508
- this.database = new Database(http);
280
+ this.database = new Database(http, tokenManager);
509
281
  this.detectOAuthCallback();
510
282
  }
511
283
  /**
@@ -676,7 +448,7 @@ var Auth = class {
676
448
  this.http.setAuthToken(session.accessToken);
677
449
  const authResponse = await this.http.get("/api/auth/sessions/current");
678
450
  const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
679
- if (profileError && profileError.statusCode !== 406) {
451
+ if (profileError && profileError.code !== "PGRST116") {
680
452
  return { data: null, error: profileError };
681
453
  }
682
454
  return {
@@ -710,7 +482,7 @@ var Auth = class {
710
482
  */
711
483
  async getProfile(userId) {
712
484
  const { data, error } = await this.database.from("users").select("*").eq("id", userId).single();
713
- if (error && error.statusCode === 406) {
485
+ if (error && error.code === "PGRST116") {
714
486
  return { data: null, error: null };
715
487
  }
716
488
  return { data, error };
@@ -757,7 +529,8 @@ var Auth = class {
757
529
  )
758
530
  };
759
531
  }
760
- return await this.database.from("users").update(profile).eq("id", session.user.id).select().single();
532
+ const { data, error } = await this.database.from("users").update(profile).eq("id", session.user.id).select().single();
533
+ return { data, error };
761
534
  }
762
535
  };
763
536
 
@@ -1073,24 +846,10 @@ var InsForgeClient = class {
1073
846
  this.http,
1074
847
  this.tokenManager
1075
848
  );
1076
- this.database = new Database(this.http);
849
+ this.database = new Database(this.http, this.tokenManager);
1077
850
  this.storage = new Storage(this.http);
1078
851
  this.ai = new AI(this.http);
1079
852
  }
1080
- /**
1081
- * Set a custom API key for authentication
1082
- * This is useful for server-to-server communication
1083
- *
1084
- * @param apiKey - The API key (should start with 'ik_')
1085
- *
1086
- * @example
1087
- * ```typescript
1088
- * client.setApiKey('ik_your_api_key_here');
1089
- * ```
1090
- */
1091
- setApiKey(apiKey) {
1092
- this.http.setAuthToken(apiKey);
1093
- }
1094
853
  /**
1095
854
  * Get the underlying HTTP client for custom requests
1096
855
  *
@@ -1126,7 +885,6 @@ var index_default = InsForgeClient;
1126
885
  HttpClient,
1127
886
  InsForgeClient,
1128
887
  InsForgeError,
1129
- QueryBuilder,
1130
888
  Storage,
1131
889
  StorageBucket,
1132
890
  TokenManager,