@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.mjs CHANGED
@@ -25,9 +25,6 @@ var HttpClient = class {
25
25
  this.defaultHeaders = {
26
26
  ...config.headers
27
27
  };
28
- if (config.apiKey) {
29
- this.defaultHeaders["Authorization"] = `Bearer ${config.apiKey}`;
30
- }
31
28
  if (!this.fetch) {
32
29
  throw new Error(
33
30
  "Fetch is not available. Please provide a fetch implementation in the config."
@@ -172,294 +169,70 @@ var TokenManager = class {
172
169
  }
173
170
  };
174
171
 
175
- // src/modules/database.ts
176
- var QueryBuilder = class {
177
- constructor(table, http) {
178
- this.table = table;
179
- this.http = http;
180
- this.method = "GET";
181
- this.headers = {};
182
- this.queryParams = {};
183
- }
184
- /**
185
- * Perform a SELECT query
186
- * For mutations (insert/update/delete), this enables returning data
187
- * @param columns - Columns to select (default: '*')
188
- * @example
189
- * .select('*')
190
- * .select('id, title, content')
191
- * .select('*, users!inner(*)') // Join with users table
192
- * .select('*, profile:profiles(*)') // Join with alias
193
- * .insert({ title: 'New' }).select() // Returns inserted data
194
- */
195
- select(columns = "*") {
196
- if (this.method !== "GET") {
197
- const existingPrefer = this.headers["Prefer"] || "";
198
- const preferParts = existingPrefer ? [existingPrefer] : [];
199
- if (!preferParts.some((p) => p.includes("return="))) {
200
- preferParts.push("return=representation");
201
- }
202
- this.headers["Prefer"] = preferParts.join(",");
203
- }
204
- if (this.method === "GET" && columns) {
205
- this.queryParams.select = columns;
206
- } else if (columns !== "*") {
207
- this.queryParams.select = columns;
208
- }
209
- return this;
210
- }
211
- /**
212
- * Perform an INSERT
213
- * @param values - Single object or array of objects
214
- * @param options - { upsert: true } for upsert behavior
215
- * @example
216
- * .insert({ title: 'Hello', content: 'World' }).select()
217
- * .insert([{ title: 'Post 1' }, { title: 'Post 2' }]).select()
218
- */
219
- insert(values, options) {
220
- this.method = "POST";
221
- this.body = Array.isArray(values) ? values : [values];
222
- if (options?.upsert) {
223
- this.headers["Prefer"] = "resolution=merge-duplicates";
224
- }
225
- return this;
226
- }
227
- /**
228
- * Perform an UPDATE
229
- * @param values - Object with fields to update
230
- * @example
231
- * .update({ title: 'Updated Title' }).select()
232
- */
233
- update(values) {
234
- this.method = "PATCH";
235
- this.body = values;
236
- return this;
237
- }
238
- /**
239
- * Perform a DELETE
240
- * @example
241
- * .delete().select()
242
- */
243
- delete() {
244
- this.method = "DELETE";
245
- return this;
246
- }
247
- /**
248
- * Perform an UPSERT
249
- * @param values - Single object or array of objects
250
- * @example
251
- * .upsert({ id: 1, title: 'Hello' })
252
- */
253
- upsert(values) {
254
- return this.insert(values, { upsert: true });
255
- }
256
- // FILTERS
257
- /**
258
- * Filter by column equal to value
259
- * @example .eq('id', 123)
260
- */
261
- eq(column, value) {
262
- this.queryParams[column] = `eq.${value}`;
263
- return this;
264
- }
265
- /**
266
- * Filter by column not equal to value
267
- * @example .neq('status', 'draft')
268
- */
269
- neq(column, value) {
270
- this.queryParams[column] = `neq.${value}`;
271
- return this;
272
- }
273
- /**
274
- * Filter by column greater than value
275
- * @example .gt('age', 18)
276
- */
277
- gt(column, value) {
278
- this.queryParams[column] = `gt.${value}`;
279
- return this;
280
- }
281
- /**
282
- * Filter by column greater than or equal to value
283
- * @example .gte('price', 100)
284
- */
285
- gte(column, value) {
286
- this.queryParams[column] = `gte.${value}`;
287
- return this;
288
- }
289
- /**
290
- * Filter by column less than value
291
- * @example .lt('stock', 10)
292
- */
293
- lt(column, value) {
294
- this.queryParams[column] = `lt.${value}`;
295
- return this;
296
- }
297
- /**
298
- * Filter by column less than or equal to value
299
- * @example .lte('discount', 50)
300
- */
301
- lte(column, value) {
302
- this.queryParams[column] = `lte.${value}`;
303
- return this;
304
- }
305
- /**
306
- * Filter by pattern matching (case-sensitive)
307
- * @example .like('email', '%@gmail.com')
308
- */
309
- like(column, pattern) {
310
- this.queryParams[column] = `like.${pattern}`;
311
- return this;
312
- }
313
- /**
314
- * Filter by pattern matching (case-insensitive)
315
- * @example .ilike('name', '%john%')
316
- */
317
- ilike(column, pattern) {
318
- this.queryParams[column] = `ilike.${pattern}`;
319
- return this;
320
- }
321
- /**
322
- * Filter by checking if column is a value
323
- * @example .is('deleted_at', null)
324
- */
325
- is(column, value) {
326
- if (value === null) {
327
- this.queryParams[column] = "is.null";
328
- } else {
329
- this.queryParams[column] = `is.${value}`;
330
- }
331
- return this;
332
- }
333
- /**
334
- * Filter by checking if value is in array
335
- * @example .in('status', ['active', 'pending'])
336
- */
337
- in(column, values) {
338
- this.queryParams[column] = `in.(${values.join(",")})`;
339
- return this;
340
- }
341
- // MODIFIERS
342
- /**
343
- * Order by column
344
- * @example
345
- * .order('created_at') // ascending
346
- * .order('created_at', { ascending: false }) // descending
347
- */
348
- order(column, options) {
349
- const ascending = options?.ascending !== false;
350
- this.queryParams.order = ascending ? column : `${column}.desc`;
351
- return this;
352
- }
353
- /**
354
- * Limit the number of rows returned
355
- * @example .limit(10)
356
- */
357
- limit(count) {
358
- this.queryParams.limit = count.toString();
359
- return this;
360
- }
361
- /**
362
- * Return results from an offset
363
- * @example .offset(20)
364
- */
365
- offset(count) {
366
- this.queryParams.offset = count.toString();
367
- return this;
368
- }
369
- /**
370
- * Set a range of rows to return
371
- * @example .range(0, 9) // First 10 rows
372
- */
373
- range(from, to) {
374
- this.headers["Range"] = `${from}-${to}`;
375
- return this;
376
- }
377
- /**
378
- * Return a single object instead of array
379
- * @example .single()
380
- */
381
- single() {
382
- this.headers["Accept"] = "application/vnd.pgrst.object+json";
383
- return this;
384
- }
385
- /**
386
- * Get the total count (use with select)
387
- * @example .select('*', { count: 'exact' })
388
- */
389
- count(algorithm = "exact") {
390
- const prefer = this.headers["Prefer"] || "";
391
- this.headers["Prefer"] = prefer ? `${prefer},count=${algorithm}` : `count=${algorithm}`;
392
- return this;
393
- }
394
- /**
395
- * Execute the query and return results
396
- */
397
- async execute() {
398
- try {
399
- const path = `/api/database/records/${this.table}`;
400
- let response;
401
- switch (this.method) {
402
- case "GET":
403
- response = await this.http.get(path, {
404
- params: this.queryParams,
405
- headers: this.headers
406
- });
407
- break;
408
- case "POST":
409
- response = await this.http.post(path, this.body, {
410
- params: this.queryParams,
411
- headers: this.headers
412
- });
413
- break;
414
- case "PATCH":
415
- response = await this.http.patch(path, this.body, {
416
- params: this.queryParams,
417
- headers: this.headers
418
- });
419
- break;
420
- case "DELETE":
421
- response = await this.http.delete(path, {
422
- params: this.queryParams,
423
- headers: this.headers
424
- });
425
- break;
426
- }
427
- return { data: response, error: null };
428
- } catch (error) {
429
- return {
430
- data: null,
431
- error: error instanceof InsForgeError ? error : new InsForgeError(
432
- "Database operation failed",
433
- 500,
434
- "DATABASE_ERROR"
435
- )
436
- };
437
- }
438
- }
439
- /**
440
- * Make QueryBuilder thenable for async/await
441
- */
442
- then(onfulfilled, onrejected) {
443
- return this.execute().then(onfulfilled, onrejected);
444
- }
445
- };
172
+ // src/modules/database-postgrest.ts
173
+ import { PostgrestClient } from "@supabase/postgrest-js";
174
+ function createInsForgePostgrestFetch(httpClient, tokenManager) {
175
+ return async (input, init) => {
176
+ const url = typeof input === "string" ? input : input.toString();
177
+ const urlObj = new URL(url);
178
+ const tableName = urlObj.pathname.slice(1);
179
+ const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;
180
+ const token = tokenManager.getAccessToken();
181
+ const headers = new Headers(init?.headers);
182
+ if (token && !headers.has("Authorization")) {
183
+ headers.set("Authorization", `Bearer ${token}`);
184
+ }
185
+ const response = await fetch(insforgeUrl, {
186
+ ...init,
187
+ headers
188
+ });
189
+ return response;
190
+ };
191
+ }
446
192
  var Database = class {
447
- constructor(http) {
448
- this.http = http;
193
+ constructor(httpClient, tokenManager) {
194
+ this.postgrest = new PostgrestClient("http://dummy", {
195
+ fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
196
+ headers: {}
197
+ });
449
198
  }
450
199
  /**
451
200
  * Create a query builder for a table
452
- * @param table - The table name
201
+ *
453
202
  * @example
203
+ * // Basic query
454
204
  * const { data, error } = await client.database
455
205
  * .from('posts')
456
206
  * .select('*')
457
- * .eq('user_id', userId)
458
- * .order('created_at', { ascending: false })
459
- * .limit(10);
207
+ * .eq('user_id', userId);
208
+ *
209
+ * // With count (Supabase style!)
210
+ * const { data, error, count } = await client.database
211
+ * .from('posts')
212
+ * .select('*', { count: 'exact' })
213
+ * .range(0, 9);
214
+ *
215
+ * // Just get count, no data
216
+ * const { count } = await client.database
217
+ * .from('posts')
218
+ * .select('*', { count: 'exact', head: true });
219
+ *
220
+ * // Complex queries with OR
221
+ * const { data } = await client.database
222
+ * .from('posts')
223
+ * .select('*, users!inner(*)')
224
+ * .or('status.eq.active,status.eq.pending');
225
+ *
226
+ * // All features work:
227
+ * - Nested selects
228
+ * - Foreign key expansion
229
+ * - OR/AND/NOT conditions
230
+ * - Count with head
231
+ * - Range pagination
232
+ * - Upserts
460
233
  */
461
234
  from(table) {
462
- return new QueryBuilder(table, this.http);
235
+ return this.postgrest.from(table);
463
236
  }
464
237
  };
465
238
 
@@ -468,7 +241,7 @@ var Auth = class {
468
241
  constructor(http, tokenManager) {
469
242
  this.http = http;
470
243
  this.tokenManager = tokenManager;
471
- this.database = new Database(http);
244
+ this.database = new Database(http, tokenManager);
472
245
  this.detectOAuthCallback();
473
246
  }
474
247
  /**
@@ -639,7 +412,7 @@ var Auth = class {
639
412
  this.http.setAuthToken(session.accessToken);
640
413
  const authResponse = await this.http.get("/api/auth/sessions/current");
641
414
  const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
642
- if (profileError && profileError.statusCode !== 406) {
415
+ if (profileError && profileError.code !== "PGRST116") {
643
416
  return { data: null, error: profileError };
644
417
  }
645
418
  return {
@@ -673,7 +446,7 @@ var Auth = class {
673
446
  */
674
447
  async getProfile(userId) {
675
448
  const { data, error } = await this.database.from("users").select("*").eq("id", userId).single();
676
- if (error && error.statusCode === 406) {
449
+ if (error && error.code === "PGRST116") {
677
450
  return { data: null, error: null };
678
451
  }
679
452
  return { data, error };
@@ -720,7 +493,8 @@ var Auth = class {
720
493
  )
721
494
  };
722
495
  }
723
- return await this.database.from("users").update(profile).eq("id", session.user.id).select().single();
496
+ const { data, error } = await this.database.from("users").update(profile).eq("id", session.user.id).select().single();
497
+ return { data, error };
724
498
  }
725
499
  };
726
500
 
@@ -1036,24 +810,10 @@ var InsForgeClient = class {
1036
810
  this.http,
1037
811
  this.tokenManager
1038
812
  );
1039
- this.database = new Database(this.http);
813
+ this.database = new Database(this.http, this.tokenManager);
1040
814
  this.storage = new Storage(this.http);
1041
815
  this.ai = new AI(this.http);
1042
816
  }
1043
- /**
1044
- * Set a custom API key for authentication
1045
- * This is useful for server-to-server communication
1046
- *
1047
- * @param apiKey - The API key (should start with 'ik_')
1048
- *
1049
- * @example
1050
- * ```typescript
1051
- * client.setApiKey('ik_your_api_key_here');
1052
- * ```
1053
- */
1054
- setApiKey(apiKey) {
1055
- this.http.setAuthToken(apiKey);
1056
- }
1057
817
  /**
1058
818
  * Get the underlying HTTP client for custom requests
1059
819
  *
@@ -1088,7 +848,6 @@ export {
1088
848
  HttpClient,
1089
849
  InsForgeClient,
1090
850
  InsForgeError,
1091
- QueryBuilder,
1092
851
  Storage,
1093
852
  StorageBucket,
1094
853
  TokenManager,