@insforge/sdk 0.0.20 → 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
@@ -20,12 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AI: () => AI,
23
24
  Auth: () => Auth,
24
25
  Database: () => Database,
25
26
  HttpClient: () => HttpClient,
26
27
  InsForgeClient: () => InsForgeClient,
27
28
  InsForgeError: () => InsForgeError,
28
- QueryBuilder: () => QueryBuilder,
29
29
  Storage: () => Storage,
30
30
  StorageBucket: () => StorageBucket,
31
31
  TokenManager: () => TokenManager,
@@ -61,9 +61,6 @@ var HttpClient = class {
61
61
  this.defaultHeaders = {
62
62
  ...config.headers
63
63
  };
64
- if (config.apiKey) {
65
- this.defaultHeaders["Authorization"] = `Bearer ${config.apiKey}`;
66
- }
67
64
  if (!this.fetch) {
68
65
  throw new Error(
69
66
  "Fetch is not available. Please provide a fetch implementation in the config."
@@ -208,294 +205,70 @@ var TokenManager = class {
208
205
  }
209
206
  };
210
207
 
211
- // src/modules/database.ts
212
- var QueryBuilder = class {
213
- constructor(table, http) {
214
- this.table = table;
215
- this.http = http;
216
- this.method = "GET";
217
- this.headers = {};
218
- this.queryParams = {};
219
- }
220
- /**
221
- * Perform a SELECT query
222
- * For mutations (insert/update/delete), this enables returning data
223
- * @param columns - Columns to select (default: '*')
224
- * @example
225
- * .select('*')
226
- * .select('id, title, content')
227
- * .select('*, users!inner(*)') // Join with users table
228
- * .select('*, profile:profiles(*)') // Join with alias
229
- * .insert({ title: 'New' }).select() // Returns inserted data
230
- */
231
- select(columns = "*") {
232
- if (this.method !== "GET") {
233
- const existingPrefer = this.headers["Prefer"] || "";
234
- const preferParts = existingPrefer ? [existingPrefer] : [];
235
- if (!preferParts.some((p) => p.includes("return="))) {
236
- preferParts.push("return=representation");
237
- }
238
- this.headers["Prefer"] = preferParts.join(",");
239
- }
240
- if (this.method === "GET" && columns) {
241
- this.queryParams.select = columns;
242
- } else if (columns !== "*") {
243
- this.queryParams.select = columns;
244
- }
245
- return this;
246
- }
247
- /**
248
- * Perform an INSERT
249
- * @param values - Single object or array of objects
250
- * @param options - { upsert: true } for upsert behavior
251
- * @example
252
- * .insert({ title: 'Hello', content: 'World' }).select()
253
- * .insert([{ title: 'Post 1' }, { title: 'Post 2' }]).select()
254
- */
255
- insert(values, options) {
256
- this.method = "POST";
257
- this.body = Array.isArray(values) ? values : [values];
258
- if (options?.upsert) {
259
- this.headers["Prefer"] = "resolution=merge-duplicates";
260
- }
261
- return this;
262
- }
263
- /**
264
- * Perform an UPDATE
265
- * @param values - Object with fields to update
266
- * @example
267
- * .update({ title: 'Updated Title' }).select()
268
- */
269
- update(values) {
270
- this.method = "PATCH";
271
- this.body = values;
272
- return this;
273
- }
274
- /**
275
- * Perform a DELETE
276
- * @example
277
- * .delete().select()
278
- */
279
- delete() {
280
- this.method = "DELETE";
281
- return this;
282
- }
283
- /**
284
- * Perform an UPSERT
285
- * @param values - Single object or array of objects
286
- * @example
287
- * .upsert({ id: 1, title: 'Hello' })
288
- */
289
- upsert(values) {
290
- return this.insert(values, { upsert: true });
291
- }
292
- // FILTERS
293
- /**
294
- * Filter by column equal to value
295
- * @example .eq('id', 123)
296
- */
297
- eq(column, value) {
298
- this.queryParams[column] = `eq.${value}`;
299
- return this;
300
- }
301
- /**
302
- * Filter by column not equal to value
303
- * @example .neq('status', 'draft')
304
- */
305
- neq(column, value) {
306
- this.queryParams[column] = `neq.${value}`;
307
- return this;
308
- }
309
- /**
310
- * Filter by column greater than value
311
- * @example .gt('age', 18)
312
- */
313
- gt(column, value) {
314
- this.queryParams[column] = `gt.${value}`;
315
- return this;
316
- }
317
- /**
318
- * Filter by column greater than or equal to value
319
- * @example .gte('price', 100)
320
- */
321
- gte(column, value) {
322
- this.queryParams[column] = `gte.${value}`;
323
- return this;
324
- }
325
- /**
326
- * Filter by column less than value
327
- * @example .lt('stock', 10)
328
- */
329
- lt(column, value) {
330
- this.queryParams[column] = `lt.${value}`;
331
- return this;
332
- }
333
- /**
334
- * Filter by column less than or equal to value
335
- * @example .lte('discount', 50)
336
- */
337
- lte(column, value) {
338
- this.queryParams[column] = `lte.${value}`;
339
- return this;
340
- }
341
- /**
342
- * Filter by pattern matching (case-sensitive)
343
- * @example .like('email', '%@gmail.com')
344
- */
345
- like(column, pattern) {
346
- this.queryParams[column] = `like.${pattern}`;
347
- return this;
348
- }
349
- /**
350
- * Filter by pattern matching (case-insensitive)
351
- * @example .ilike('name', '%john%')
352
- */
353
- ilike(column, pattern) {
354
- this.queryParams[column] = `ilike.${pattern}`;
355
- return this;
356
- }
357
- /**
358
- * Filter by checking if column is a value
359
- * @example .is('deleted_at', null)
360
- */
361
- is(column, value) {
362
- if (value === null) {
363
- this.queryParams[column] = "is.null";
364
- } else {
365
- this.queryParams[column] = `is.${value}`;
366
- }
367
- return this;
368
- }
369
- /**
370
- * Filter by checking if value is in array
371
- * @example .in('status', ['active', 'pending'])
372
- */
373
- in(column, values) {
374
- this.queryParams[column] = `in.(${values.join(",")})`;
375
- return this;
376
- }
377
- // MODIFIERS
378
- /**
379
- * Order by column
380
- * @example
381
- * .order('created_at') // ascending
382
- * .order('created_at', { ascending: false }) // descending
383
- */
384
- order(column, options) {
385
- const ascending = options?.ascending !== false;
386
- this.queryParams.order = ascending ? column : `${column}.desc`;
387
- return this;
388
- }
389
- /**
390
- * Limit the number of rows returned
391
- * @example .limit(10)
392
- */
393
- limit(count) {
394
- this.queryParams.limit = count.toString();
395
- return this;
396
- }
397
- /**
398
- * Return results from an offset
399
- * @example .offset(20)
400
- */
401
- offset(count) {
402
- this.queryParams.offset = count.toString();
403
- return this;
404
- }
405
- /**
406
- * Set a range of rows to return
407
- * @example .range(0, 9) // First 10 rows
408
- */
409
- range(from, to) {
410
- this.headers["Range"] = `${from}-${to}`;
411
- return this;
412
- }
413
- /**
414
- * Return a single object instead of array
415
- * @example .single()
416
- */
417
- single() {
418
- this.headers["Accept"] = "application/vnd.pgrst.object+json";
419
- return this;
420
- }
421
- /**
422
- * Get the total count (use with select)
423
- * @example .select('*', { count: 'exact' })
424
- */
425
- count(algorithm = "exact") {
426
- const prefer = this.headers["Prefer"] || "";
427
- this.headers["Prefer"] = prefer ? `${prefer},count=${algorithm}` : `count=${algorithm}`;
428
- return this;
429
- }
430
- /**
431
- * Execute the query and return results
432
- */
433
- async execute() {
434
- try {
435
- const path = `/api/database/records/${this.table}`;
436
- let response;
437
- switch (this.method) {
438
- case "GET":
439
- response = await this.http.get(path, {
440
- params: this.queryParams,
441
- headers: this.headers
442
- });
443
- break;
444
- case "POST":
445
- response = await this.http.post(path, this.body, {
446
- params: this.queryParams,
447
- headers: this.headers
448
- });
449
- break;
450
- case "PATCH":
451
- response = await this.http.patch(path, this.body, {
452
- params: this.queryParams,
453
- headers: this.headers
454
- });
455
- break;
456
- case "DELETE":
457
- response = await this.http.delete(path, {
458
- params: this.queryParams,
459
- headers: this.headers
460
- });
461
- break;
462
- }
463
- return { data: response, error: null };
464
- } catch (error) {
465
- return {
466
- data: null,
467
- error: error instanceof InsForgeError ? error : new InsForgeError(
468
- "Database operation failed",
469
- 500,
470
- "DATABASE_ERROR"
471
- )
472
- };
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}`);
473
220
  }
474
- }
475
- /**
476
- * Make QueryBuilder thenable for async/await
477
- */
478
- then(onfulfilled, onrejected) {
479
- return this.execute().then(onfulfilled, onrejected);
480
- }
481
- };
221
+ const response = await fetch(insforgeUrl, {
222
+ ...init,
223
+ headers
224
+ });
225
+ return response;
226
+ };
227
+ }
482
228
  var Database = class {
483
- constructor(http) {
484
- 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
+ });
485
234
  }
486
235
  /**
487
236
  * Create a query builder for a table
488
- * @param table - The table name
237
+ *
489
238
  * @example
239
+ * // Basic query
490
240
  * const { data, error } = await client.database
491
241
  * .from('posts')
492
242
  * .select('*')
493
- * .eq('user_id', userId)
494
- * .order('created_at', { ascending: false })
495
- * .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
496
269
  */
497
270
  from(table) {
498
- return new QueryBuilder(table, this.http);
271
+ return this.postgrest.from(table);
499
272
  }
500
273
  };
501
274
 
@@ -504,7 +277,7 @@ var Auth = class {
504
277
  constructor(http, tokenManager) {
505
278
  this.http = http;
506
279
  this.tokenManager = tokenManager;
507
- this.database = new Database(http);
280
+ this.database = new Database(http, tokenManager);
508
281
  this.detectOAuthCallback();
509
282
  }
510
283
  /**
@@ -675,7 +448,7 @@ var Auth = class {
675
448
  this.http.setAuthToken(session.accessToken);
676
449
  const authResponse = await this.http.get("/api/auth/sessions/current");
677
450
  const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
678
- if (profileError && profileError.statusCode !== 406) {
451
+ if (profileError && profileError.code !== "PGRST116") {
679
452
  return { data: null, error: profileError };
680
453
  }
681
454
  return {
@@ -709,7 +482,7 @@ var Auth = class {
709
482
  */
710
483
  async getProfile(userId) {
711
484
  const { data, error } = await this.database.from("users").select("*").eq("id", userId).single();
712
- if (error && error.statusCode === 406) {
485
+ if (error && error.code === "PGRST116") {
713
486
  return { data: null, error: null };
714
487
  }
715
488
  return { data, error };
@@ -756,7 +529,8 @@ var Auth = class {
756
529
  )
757
530
  };
758
531
  }
759
- 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 };
760
534
  }
761
535
  };
762
536
 
@@ -936,6 +710,133 @@ var Storage = class {
936
710
  }
937
711
  };
938
712
 
713
+ // src/modules/ai.ts
714
+ var AI = class {
715
+ constructor(http) {
716
+ this.http = http;
717
+ this.chat = new Chat(http);
718
+ this.images = new Images(http);
719
+ }
720
+ };
721
+ var Chat = class {
722
+ constructor(http) {
723
+ this.completions = new ChatCompletions(http);
724
+ }
725
+ };
726
+ var ChatCompletions = class {
727
+ constructor(http) {
728
+ this.http = http;
729
+ }
730
+ /**
731
+ * Create a chat completion
732
+ *
733
+ * @example
734
+ * ```typescript
735
+ * // Non-streaming
736
+ * const response = await client.ai.chat.completions.create({
737
+ * model: 'gpt-4',
738
+ * messages: [{ role: 'user', content: 'Hello!' }]
739
+ * });
740
+ * console.log(response.response);
741
+ *
742
+ * // Streaming - returns async iterable
743
+ * const stream = await client.ai.chat.completions.create({
744
+ * model: 'gpt-4',
745
+ * messages: [{ role: 'user', content: 'Tell me a story' }],
746
+ * stream: true
747
+ * });
748
+ *
749
+ * for await (const event of stream) {
750
+ * if (event.chunk) {
751
+ * process.stdout.write(event.chunk);
752
+ * }
753
+ * if (event.done) {
754
+ * console.log('Stream complete!');
755
+ * }
756
+ * }
757
+ * ```
758
+ */
759
+ async create(params) {
760
+ if (params.stream) {
761
+ const headers = this.http.getHeaders();
762
+ headers["Content-Type"] = "application/json";
763
+ const response = await this.http.fetch(
764
+ `${this.http.baseUrl}/api/ai/chat/completion`,
765
+ {
766
+ method: "POST",
767
+ headers,
768
+ body: JSON.stringify(params)
769
+ }
770
+ );
771
+ if (!response.ok) {
772
+ const error = await response.json();
773
+ throw new Error(error.error || "Stream request failed");
774
+ }
775
+ return this.parseSSEStream(response);
776
+ }
777
+ return this.http.post("/api/ai/chat/completion", params);
778
+ }
779
+ /**
780
+ * Parse SSE stream into async iterable of parsed events
781
+ * Users don't need to handle SSE parsing themselves
782
+ */
783
+ async *parseSSEStream(response) {
784
+ const reader = response.body.getReader();
785
+ const decoder = new TextDecoder();
786
+ let buffer = "";
787
+ try {
788
+ while (true) {
789
+ const { done, value } = await reader.read();
790
+ if (done) break;
791
+ buffer += decoder.decode(value, { stream: true });
792
+ const lines = buffer.split("\n");
793
+ buffer = lines.pop() || "";
794
+ for (const line of lines) {
795
+ if (line.startsWith("data: ")) {
796
+ const dataStr = line.slice(6).trim();
797
+ if (dataStr) {
798
+ try {
799
+ const data = JSON.parse(dataStr);
800
+ yield data;
801
+ if (data.done) {
802
+ reader.releaseLock();
803
+ return;
804
+ }
805
+ } catch (e) {
806
+ console.warn("Failed to parse SSE data:", dataStr);
807
+ }
808
+ }
809
+ }
810
+ }
811
+ }
812
+ } finally {
813
+ reader.releaseLock();
814
+ }
815
+ }
816
+ };
817
+ var Images = class {
818
+ constructor(http) {
819
+ this.http = http;
820
+ }
821
+ /**
822
+ * Generate images
823
+ *
824
+ * @example
825
+ * ```typescript
826
+ * const response = await client.ai.images.generate({
827
+ * model: 'dall-e-3',
828
+ * prompt: 'A sunset over mountains',
829
+ * numImages: 1,
830
+ * size: '1024x1024'
831
+ * });
832
+ * console.log(response.images[0].url);
833
+ * ```
834
+ */
835
+ async generate(params) {
836
+ return this.http.post("/api/ai/image/generation", params);
837
+ }
838
+ };
839
+
939
840
  // src/client.ts
940
841
  var InsForgeClient = class {
941
842
  constructor(config = {}) {
@@ -945,22 +846,9 @@ var InsForgeClient = class {
945
846
  this.http,
946
847
  this.tokenManager
947
848
  );
948
- this.database = new Database(this.http);
849
+ this.database = new Database(this.http, this.tokenManager);
949
850
  this.storage = new Storage(this.http);
950
- }
951
- /**
952
- * Set a custom API key for authentication
953
- * This is useful for server-to-server communication
954
- *
955
- * @param apiKey - The API key (should start with 'ik_')
956
- *
957
- * @example
958
- * ```typescript
959
- * client.setApiKey('ik_your_api_key_here');
960
- * ```
961
- */
962
- setApiKey(apiKey) {
963
- this.http.setAuthToken(apiKey);
851
+ this.ai = new AI(this.http);
964
852
  }
965
853
  /**
966
854
  * Get the underlying HTTP client for custom requests
@@ -991,12 +879,12 @@ function createClient(config) {
991
879
  var index_default = InsForgeClient;
992
880
  // Annotate the CommonJS export names for ESM import in node:
993
881
  0 && (module.exports = {
882
+ AI,
994
883
  Auth,
995
884
  Database,
996
885
  HttpClient,
997
886
  InsForgeClient,
998
887
  InsForgeError,
999
- QueryBuilder,
1000
888
  Storage,
1001
889
  StorageBucket,
1002
890
  TokenManager,