@insforge/sdk 0.0.25 → 0.0.26

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 ADDED
@@ -0,0 +1,971 @@
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
+ AI: () => AI,
24
+ Auth: () => Auth,
25
+ Database: () => Database,
26
+ HttpClient: () => HttpClient,
27
+ InsForgeClient: () => InsForgeClient,
28
+ InsForgeError: () => InsForgeError,
29
+ Storage: () => Storage,
30
+ StorageBucket: () => StorageBucket,
31
+ TokenManager: () => TokenManager,
32
+ createClient: () => createClient,
33
+ default: () => index_default
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/types.ts
38
+ var InsForgeError = class _InsForgeError extends Error {
39
+ constructor(message, statusCode, error, nextActions) {
40
+ super(message);
41
+ this.name = "InsForgeError";
42
+ this.statusCode = statusCode;
43
+ this.error = error;
44
+ this.nextActions = nextActions;
45
+ }
46
+ static fromApiError(apiError) {
47
+ return new _InsForgeError(
48
+ apiError.message,
49
+ apiError.statusCode,
50
+ apiError.error,
51
+ apiError.nextActions
52
+ );
53
+ }
54
+ };
55
+
56
+ // src/lib/http-client.ts
57
+ var HttpClient = class {
58
+ constructor(config) {
59
+ this.baseUrl = config.baseUrl || "http://localhost:7130";
60
+ this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
61
+ this.defaultHeaders = {
62
+ ...config.headers
63
+ };
64
+ if (!this.fetch) {
65
+ throw new Error(
66
+ "Fetch is not available. Please provide a fetch implementation in the config."
67
+ );
68
+ }
69
+ }
70
+ buildUrl(path, params) {
71
+ const url = new URL(path, this.baseUrl);
72
+ if (params) {
73
+ Object.entries(params).forEach(([key, value]) => {
74
+ if (key === "select") {
75
+ let normalizedValue = value.replace(/\s+/g, " ").trim();
76
+ normalizedValue = normalizedValue.replace(/\s*\(\s*/g, "(").replace(/\s*\)\s*/g, ")").replace(/\(\s+/g, "(").replace(/\s+\)/g, ")").replace(/,\s+(?=[^()]*\))/g, ",");
77
+ url.searchParams.append(key, normalizedValue);
78
+ } else {
79
+ url.searchParams.append(key, value);
80
+ }
81
+ });
82
+ }
83
+ return url.toString();
84
+ }
85
+ async request(method, path, options = {}) {
86
+ const { params, headers = {}, body, ...fetchOptions } = options;
87
+ const url = this.buildUrl(path, params);
88
+ const requestHeaders = {
89
+ ...this.defaultHeaders
90
+ };
91
+ let processedBody;
92
+ if (body !== void 0) {
93
+ if (typeof FormData !== "undefined" && body instanceof FormData) {
94
+ processedBody = body;
95
+ } else {
96
+ if (method !== "GET") {
97
+ requestHeaders["Content-Type"] = "application/json;charset=UTF-8";
98
+ }
99
+ processedBody = JSON.stringify(body);
100
+ }
101
+ }
102
+ Object.assign(requestHeaders, headers);
103
+ const response = await this.fetch(url, {
104
+ method,
105
+ headers: requestHeaders,
106
+ body: processedBody,
107
+ ...fetchOptions
108
+ });
109
+ if (response.status === 204) {
110
+ return void 0;
111
+ }
112
+ let data;
113
+ const contentType = response.headers.get("content-type");
114
+ if (contentType?.includes("json")) {
115
+ data = await response.json();
116
+ } else {
117
+ data = await response.text();
118
+ }
119
+ if (!response.ok) {
120
+ if (data && typeof data === "object" && "error" in data) {
121
+ throw InsForgeError.fromApiError(data);
122
+ }
123
+ throw new InsForgeError(
124
+ `Request failed: ${response.statusText}`,
125
+ response.status,
126
+ "REQUEST_FAILED"
127
+ );
128
+ }
129
+ return data;
130
+ }
131
+ get(path, options) {
132
+ return this.request("GET", path, options);
133
+ }
134
+ post(path, body, options) {
135
+ return this.request("POST", path, { ...options, body });
136
+ }
137
+ put(path, body, options) {
138
+ return this.request("PUT", path, { ...options, body });
139
+ }
140
+ patch(path, body, options) {
141
+ return this.request("PATCH", path, { ...options, body });
142
+ }
143
+ delete(path, options) {
144
+ return this.request("DELETE", path, options);
145
+ }
146
+ setAuthToken(token) {
147
+ if (token) {
148
+ this.defaultHeaders["Authorization"] = `Bearer ${token}`;
149
+ } else {
150
+ delete this.defaultHeaders["Authorization"];
151
+ }
152
+ }
153
+ getHeaders() {
154
+ return { ...this.defaultHeaders };
155
+ }
156
+ };
157
+
158
+ // src/lib/token-manager.ts
159
+ var TOKEN_KEY = "insforge-auth-token";
160
+ var USER_KEY = "insforge-auth-user";
161
+ var TokenManager = class {
162
+ constructor(storage) {
163
+ if (storage) {
164
+ this.storage = storage;
165
+ } else if (typeof window !== "undefined" && window.localStorage) {
166
+ this.storage = window.localStorage;
167
+ } else {
168
+ const store = /* @__PURE__ */ new Map();
169
+ this.storage = {
170
+ getItem: (key) => store.get(key) || null,
171
+ setItem: (key, value) => {
172
+ store.set(key, value);
173
+ },
174
+ removeItem: (key) => {
175
+ store.delete(key);
176
+ }
177
+ };
178
+ }
179
+ }
180
+ saveSession(session) {
181
+ this.storage.setItem(TOKEN_KEY, session.accessToken);
182
+ this.storage.setItem(USER_KEY, JSON.stringify(session.user));
183
+ }
184
+ getSession() {
185
+ const token = this.storage.getItem(TOKEN_KEY);
186
+ const userStr = this.storage.getItem(USER_KEY);
187
+ if (!token || !userStr) {
188
+ return null;
189
+ }
190
+ try {
191
+ const user = JSON.parse(userStr);
192
+ return { accessToken: token, user };
193
+ } catch {
194
+ this.clearSession();
195
+ return null;
196
+ }
197
+ }
198
+ getAccessToken() {
199
+ const token = this.storage.getItem(TOKEN_KEY);
200
+ return typeof token === "string" ? token : null;
201
+ }
202
+ clearSession() {
203
+ this.storage.removeItem(TOKEN_KEY);
204
+ this.storage.removeItem(USER_KEY);
205
+ }
206
+ };
207
+
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
+ }
228
+ var Database = class {
229
+ constructor(httpClient, tokenManager) {
230
+ this.postgrest = new import_postgrest_js.PostgrestClient("http://dummy", {
231
+ fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
232
+ headers: {}
233
+ });
234
+ }
235
+ /**
236
+ * Create a query builder for a table
237
+ *
238
+ * @example
239
+ * // Basic query
240
+ * const { data, error } = await client.database
241
+ * .from('posts')
242
+ * .select('*')
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
269
+ */
270
+ from(table) {
271
+ return this.postgrest.from(table);
272
+ }
273
+ };
274
+
275
+ // src/modules/auth.ts
276
+ var Auth = class {
277
+ constructor(http, tokenManager) {
278
+ this.http = http;
279
+ this.tokenManager = tokenManager;
280
+ this.database = new Database(http, tokenManager);
281
+ this.detectOAuthCallback();
282
+ }
283
+ /**
284
+ * Automatically detect and handle OAuth callback parameters in the URL
285
+ * This runs on initialization to seamlessly complete the OAuth flow
286
+ * Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
287
+ */
288
+ detectOAuthCallback() {
289
+ if (typeof window === "undefined") return;
290
+ try {
291
+ const params = new URLSearchParams(window.location.search);
292
+ const accessToken = params.get("access_token");
293
+ const userId = params.get("user_id");
294
+ const email = params.get("email");
295
+ const name = params.get("name");
296
+ if (accessToken && userId && email) {
297
+ const session = {
298
+ accessToken,
299
+ user: {
300
+ id: userId,
301
+ email,
302
+ name: name || "",
303
+ // These fields are not provided by backend OAuth callback
304
+ // They'll be populated when calling getCurrentUser()
305
+ emailVerified: false,
306
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
307
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
308
+ }
309
+ };
310
+ this.tokenManager.saveSession(session);
311
+ this.http.setAuthToken(accessToken);
312
+ const url = new URL(window.location.href);
313
+ url.searchParams.delete("access_token");
314
+ url.searchParams.delete("user_id");
315
+ url.searchParams.delete("email");
316
+ url.searchParams.delete("name");
317
+ if (params.has("error")) {
318
+ url.searchParams.delete("error");
319
+ }
320
+ window.history.replaceState({}, document.title, url.toString());
321
+ }
322
+ } catch (error) {
323
+ console.debug("OAuth callback detection skipped:", error);
324
+ }
325
+ }
326
+ /**
327
+ * Sign up a new user
328
+ */
329
+ async signUp(request) {
330
+ try {
331
+ const response = await this.http.post("/api/auth/users", request);
332
+ const session = {
333
+ accessToken: response.accessToken,
334
+ user: response.user
335
+ };
336
+ this.tokenManager.saveSession(session);
337
+ this.http.setAuthToken(response.accessToken);
338
+ return {
339
+ data: response,
340
+ error: null
341
+ };
342
+ } catch (error) {
343
+ if (error instanceof InsForgeError) {
344
+ return { data: null, error };
345
+ }
346
+ return {
347
+ data: null,
348
+ error: new InsForgeError(
349
+ error instanceof Error ? error.message : "An unexpected error occurred during sign up",
350
+ 500,
351
+ "UNEXPECTED_ERROR"
352
+ )
353
+ };
354
+ }
355
+ }
356
+ /**
357
+ * Sign in with email and password
358
+ */
359
+ async signInWithPassword(request) {
360
+ try {
361
+ const response = await this.http.post("/api/auth/sessions", request);
362
+ const session = {
363
+ accessToken: response.accessToken,
364
+ user: response.user
365
+ };
366
+ this.tokenManager.saveSession(session);
367
+ this.http.setAuthToken(response.accessToken);
368
+ return {
369
+ data: response,
370
+ error: null
371
+ };
372
+ } catch (error) {
373
+ if (error instanceof InsForgeError) {
374
+ return { data: null, error };
375
+ }
376
+ return {
377
+ data: null,
378
+ error: new InsForgeError(
379
+ "An unexpected error occurred during sign in",
380
+ 500,
381
+ "UNEXPECTED_ERROR"
382
+ )
383
+ };
384
+ }
385
+ }
386
+ /**
387
+ * Sign in with OAuth provider
388
+ */
389
+ async signInWithOAuth(options) {
390
+ try {
391
+ const { provider, redirectTo, skipBrowserRedirect } = options;
392
+ const params = redirectTo ? { redirect_uri: redirectTo } : void 0;
393
+ const endpoint = `/api/auth/oauth/${provider}`;
394
+ const response = await this.http.get(endpoint, { params });
395
+ if (typeof window !== "undefined" && !skipBrowserRedirect) {
396
+ window.location.href = response.authUrl;
397
+ return { data: {}, error: null };
398
+ }
399
+ return {
400
+ data: {
401
+ url: response.authUrl,
402
+ provider
403
+ },
404
+ error: null
405
+ };
406
+ } catch (error) {
407
+ if (error instanceof InsForgeError) {
408
+ return { data: {}, error };
409
+ }
410
+ return {
411
+ data: {},
412
+ error: new InsForgeError(
413
+ "An unexpected error occurred during OAuth initialization",
414
+ 500,
415
+ "UNEXPECTED_ERROR"
416
+ )
417
+ };
418
+ }
419
+ }
420
+ /**
421
+ * Sign out the current user
422
+ */
423
+ async signOut() {
424
+ try {
425
+ this.tokenManager.clearSession();
426
+ this.http.setAuthToken(null);
427
+ return { error: null };
428
+ } catch (error) {
429
+ return {
430
+ error: new InsForgeError(
431
+ "Failed to sign out",
432
+ 500,
433
+ "SIGNOUT_ERROR"
434
+ )
435
+ };
436
+ }
437
+ }
438
+ /**
439
+ * Get the current user with full profile information
440
+ * Returns both auth info (id, email, role) and profile data (nickname, avatar_url, bio, etc.)
441
+ */
442
+ async getCurrentUser() {
443
+ try {
444
+ const session = this.tokenManager.getSession();
445
+ if (!session?.accessToken) {
446
+ return { data: null, error: null };
447
+ }
448
+ this.http.setAuthToken(session.accessToken);
449
+ const authResponse = await this.http.get("/api/auth/sessions/current");
450
+ const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
451
+ if (profileError && profileError.code !== "PGRST116") {
452
+ return { data: null, error: profileError };
453
+ }
454
+ return {
455
+ data: {
456
+ user: authResponse.user,
457
+ profile
458
+ },
459
+ error: null
460
+ };
461
+ } catch (error) {
462
+ if (error instanceof InsForgeError && error.statusCode === 401) {
463
+ await this.signOut();
464
+ return { data: null, error: null };
465
+ }
466
+ if (error instanceof InsForgeError) {
467
+ return { data: null, error };
468
+ }
469
+ return {
470
+ data: null,
471
+ error: new InsForgeError(
472
+ "An unexpected error occurred while fetching user",
473
+ 500,
474
+ "UNEXPECTED_ERROR"
475
+ )
476
+ };
477
+ }
478
+ }
479
+ /**
480
+ * Get any user's profile by ID
481
+ * Returns profile information from the users table (nickname, avatar_url, bio, etc.)
482
+ */
483
+ async getProfile(userId) {
484
+ const { data, error } = await this.database.from("users").select("*").eq("id", userId).single();
485
+ if (error && error.code === "PGRST116") {
486
+ return { data: null, error: null };
487
+ }
488
+ return { data, error };
489
+ }
490
+ /**
491
+ * Get the current session (only session data, no API call)
492
+ * Returns the stored JWT token and basic user info from local storage
493
+ */
494
+ getCurrentSession() {
495
+ try {
496
+ const session = this.tokenManager.getSession();
497
+ if (session?.accessToken) {
498
+ this.http.setAuthToken(session.accessToken);
499
+ return { data: { session }, error: null };
500
+ }
501
+ return { data: { session: null }, error: null };
502
+ } catch (error) {
503
+ if (error instanceof InsForgeError) {
504
+ return { data: { session: null }, error };
505
+ }
506
+ return {
507
+ data: { session: null },
508
+ error: new InsForgeError(
509
+ "An unexpected error occurred while getting session",
510
+ 500,
511
+ "UNEXPECTED_ERROR"
512
+ )
513
+ };
514
+ }
515
+ }
516
+ /**
517
+ * Set/Update the current user's profile
518
+ * Updates profile information in the users table (nickname, avatar_url, bio, etc.)
519
+ */
520
+ async setProfile(profile) {
521
+ const session = this.tokenManager.getSession();
522
+ if (!session?.user?.id) {
523
+ return {
524
+ data: null,
525
+ error: new InsForgeError(
526
+ "No authenticated user found",
527
+ 401,
528
+ "UNAUTHENTICATED"
529
+ )
530
+ };
531
+ }
532
+ const { data, error } = await this.database.from("users").update(profile).eq("id", session.user.id).select().single();
533
+ return { data, error };
534
+ }
535
+ };
536
+
537
+ // src/modules/storage.ts
538
+ var StorageBucket = class {
539
+ constructor(bucketName, http) {
540
+ this.bucketName = bucketName;
541
+ this.http = http;
542
+ }
543
+ /**
544
+ * Upload a file with a specific key
545
+ * @param path - The object key/path
546
+ * @param file - File or Blob to upload
547
+ */
548
+ async upload(path, file) {
549
+ try {
550
+ const formData = new FormData();
551
+ formData.append("file", file);
552
+ const response = await this.http.request(
553
+ "PUT",
554
+ `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`,
555
+ {
556
+ body: formData,
557
+ headers: {
558
+ // Don't set Content-Type, let browser set multipart boundary
559
+ }
560
+ }
561
+ );
562
+ return { data: response, error: null };
563
+ } catch (error) {
564
+ return {
565
+ data: null,
566
+ error: error instanceof InsForgeError ? error : new InsForgeError(
567
+ "Upload failed",
568
+ 500,
569
+ "STORAGE_ERROR"
570
+ )
571
+ };
572
+ }
573
+ }
574
+ /**
575
+ * Upload a file with auto-generated key
576
+ * @param file - File or Blob to upload
577
+ */
578
+ async uploadAuto(file) {
579
+ try {
580
+ const formData = new FormData();
581
+ formData.append("file", file);
582
+ const response = await this.http.request(
583
+ "POST",
584
+ `/api/storage/buckets/${this.bucketName}/objects`,
585
+ {
586
+ body: formData,
587
+ headers: {
588
+ // Don't set Content-Type, let browser set multipart boundary
589
+ }
590
+ }
591
+ );
592
+ return { data: response, error: null };
593
+ } catch (error) {
594
+ return {
595
+ data: null,
596
+ error: error instanceof InsForgeError ? error : new InsForgeError(
597
+ "Upload failed",
598
+ 500,
599
+ "STORAGE_ERROR"
600
+ )
601
+ };
602
+ }
603
+ }
604
+ /**
605
+ * Download a file
606
+ * @param path - The object key/path
607
+ * Returns the file as a Blob
608
+ */
609
+ async download(path) {
610
+ try {
611
+ const url = `${this.http.baseUrl}/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`;
612
+ const response = await this.http.fetch(url, {
613
+ method: "GET",
614
+ headers: this.http.getHeaders()
615
+ });
616
+ if (!response.ok) {
617
+ try {
618
+ const error = await response.json();
619
+ throw InsForgeError.fromApiError(error);
620
+ } catch {
621
+ throw new InsForgeError(
622
+ `Download failed: ${response.statusText}`,
623
+ response.status,
624
+ "STORAGE_ERROR"
625
+ );
626
+ }
627
+ }
628
+ const blob = await response.blob();
629
+ return { data: blob, error: null };
630
+ } catch (error) {
631
+ return {
632
+ data: null,
633
+ error: error instanceof InsForgeError ? error : new InsForgeError(
634
+ "Download failed",
635
+ 500,
636
+ "STORAGE_ERROR"
637
+ )
638
+ };
639
+ }
640
+ }
641
+ /**
642
+ * Get public URL for a file
643
+ * @param path - The object key/path
644
+ */
645
+ getPublicUrl(path) {
646
+ return `${this.http.baseUrl}/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`;
647
+ }
648
+ /**
649
+ * List objects in the bucket
650
+ * @param prefix - Filter by key prefix
651
+ * @param search - Search in file names
652
+ * @param limit - Maximum number of results (default: 100, max: 1000)
653
+ * @param offset - Number of results to skip
654
+ */
655
+ async list(options) {
656
+ try {
657
+ const params = {};
658
+ if (options?.prefix) params.prefix = options.prefix;
659
+ if (options?.search) params.search = options.search;
660
+ if (options?.limit) params.limit = options.limit.toString();
661
+ if (options?.offset) params.offset = options.offset.toString();
662
+ const response = await this.http.get(
663
+ `/api/storage/buckets/${this.bucketName}/objects`,
664
+ { params }
665
+ );
666
+ return { data: response, error: null };
667
+ } catch (error) {
668
+ return {
669
+ data: null,
670
+ error: error instanceof InsForgeError ? error : new InsForgeError(
671
+ "List failed",
672
+ 500,
673
+ "STORAGE_ERROR"
674
+ )
675
+ };
676
+ }
677
+ }
678
+ /**
679
+ * Delete a file
680
+ * @param path - The object key/path
681
+ */
682
+ async remove(path) {
683
+ try {
684
+ const response = await this.http.delete(
685
+ `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`
686
+ );
687
+ return { data: response, error: null };
688
+ } catch (error) {
689
+ return {
690
+ data: null,
691
+ error: error instanceof InsForgeError ? error : new InsForgeError(
692
+ "Delete failed",
693
+ 500,
694
+ "STORAGE_ERROR"
695
+ )
696
+ };
697
+ }
698
+ }
699
+ };
700
+ var Storage = class {
701
+ constructor(http) {
702
+ this.http = http;
703
+ }
704
+ /**
705
+ * Get a bucket instance for operations
706
+ * @param bucketName - Name of the bucket
707
+ */
708
+ from(bucketName) {
709
+ return new StorageBucket(bucketName, this.http);
710
+ }
711
+ };
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 - OpenAI-like response format
732
+ *
733
+ * @example
734
+ * ```typescript
735
+ * // Non-streaming
736
+ * const completion = await client.ai.chat.completions.create({
737
+ * model: 'gpt-4',
738
+ * messages: [{ role: 'user', content: 'Hello!' }]
739
+ * });
740
+ * console.log(completion.choices[0].message.content);
741
+ *
742
+ * // With images
743
+ * const response = await client.ai.chat.completions.create({
744
+ * model: 'gpt-4-vision',
745
+ * messages: [{
746
+ * role: 'user',
747
+ * content: 'What is in this image?',
748
+ * images: [{ url: 'https://example.com/image.jpg' }]
749
+ * }]
750
+ * });
751
+ *
752
+ * // Streaming - returns async iterable
753
+ * const stream = await client.ai.chat.completions.create({
754
+ * model: 'gpt-4',
755
+ * messages: [{ role: 'user', content: 'Tell me a story' }],
756
+ * stream: true
757
+ * });
758
+ *
759
+ * for await (const chunk of stream) {
760
+ * if (chunk.choices[0]?.delta?.content) {
761
+ * process.stdout.write(chunk.choices[0].delta.content);
762
+ * }
763
+ * }
764
+ * ```
765
+ */
766
+ async create(params) {
767
+ const backendParams = {
768
+ model: params.model,
769
+ messages: params.messages,
770
+ temperature: params.temperature,
771
+ maxTokens: params.maxTokens,
772
+ topP: params.topP,
773
+ stream: params.stream
774
+ };
775
+ if (params.stream) {
776
+ const headers = this.http.getHeaders();
777
+ headers["Content-Type"] = "application/json";
778
+ const response2 = await this.http.fetch(
779
+ `${this.http.baseUrl}/api/ai/chat/completion`,
780
+ {
781
+ method: "POST",
782
+ headers,
783
+ body: JSON.stringify(backendParams)
784
+ }
785
+ );
786
+ if (!response2.ok) {
787
+ const error = await response2.json();
788
+ throw new Error(error.error || "Stream request failed");
789
+ }
790
+ return this.parseSSEStream(response2, params.model);
791
+ }
792
+ const response = await this.http.post("/api/ai/chat/completion", backendParams);
793
+ const content = response.content || response.response || response.message || response.text || "";
794
+ return {
795
+ id: response.id || `chatcmpl-${Date.now()}`,
796
+ object: "chat.completion",
797
+ created: Math.floor(Date.now() / 1e3),
798
+ model: params.model,
799
+ choices: [{
800
+ index: 0,
801
+ message: {
802
+ role: "assistant",
803
+ content
804
+ },
805
+ finish_reason: "stop"
806
+ }],
807
+ usage: response.usage || {
808
+ prompt_tokens: 0,
809
+ completion_tokens: 0,
810
+ total_tokens: 0
811
+ }
812
+ };
813
+ }
814
+ /**
815
+ * Parse SSE stream into async iterable of OpenAI-like chunks
816
+ */
817
+ async *parseSSEStream(response, model) {
818
+ const reader = response.body.getReader();
819
+ const decoder = new TextDecoder();
820
+ let buffer = "";
821
+ try {
822
+ while (true) {
823
+ const { done, value } = await reader.read();
824
+ if (done) break;
825
+ buffer += decoder.decode(value, { stream: true });
826
+ const lines = buffer.split("\n");
827
+ buffer = lines.pop() || "";
828
+ for (const line of lines) {
829
+ if (line.startsWith("data: ")) {
830
+ const dataStr = line.slice(6).trim();
831
+ if (dataStr) {
832
+ try {
833
+ const data = JSON.parse(dataStr);
834
+ if (data.chunk || data.content) {
835
+ yield {
836
+ id: `chatcmpl-${Date.now()}`,
837
+ object: "chat.completion.chunk",
838
+ created: Math.floor(Date.now() / 1e3),
839
+ model,
840
+ choices: [{
841
+ index: 0,
842
+ delta: {
843
+ content: data.chunk || data.content
844
+ },
845
+ finish_reason: data.done ? "stop" : null
846
+ }]
847
+ };
848
+ }
849
+ if (data.done) {
850
+ reader.releaseLock();
851
+ return;
852
+ }
853
+ } catch (e) {
854
+ console.warn("Failed to parse SSE data:", dataStr);
855
+ }
856
+ }
857
+ }
858
+ }
859
+ }
860
+ } finally {
861
+ reader.releaseLock();
862
+ }
863
+ }
864
+ };
865
+ var Images = class {
866
+ constructor(http) {
867
+ this.http = http;
868
+ }
869
+ /**
870
+ * Generate images - OpenAI-like response format
871
+ *
872
+ * @example
873
+ * ```typescript
874
+ * // Text-to-image
875
+ * const response = await client.ai.images.generate({
876
+ * model: 'dall-e-3',
877
+ * prompt: 'A sunset over mountains',
878
+ * n: 1,
879
+ * size: '1024x1024'
880
+ * });
881
+ * console.log(response.images[0].url);
882
+ *
883
+ * // Image-to-image (with input images)
884
+ * const response = await client.ai.images.generate({
885
+ * model: 'stable-diffusion-xl',
886
+ * prompt: 'Transform this into a watercolor painting',
887
+ * images: [
888
+ * { url: 'https://example.com/input.jpg' },
889
+ * // or base64-encoded Data URI:
890
+ * { url: 'data:image/jpeg;base64,/9j/4AAQ...' }
891
+ * ]
892
+ * });
893
+ * ```
894
+ */
895
+ async generate(params) {
896
+ const backendParams = {
897
+ model: params.model,
898
+ prompt: params.prompt,
899
+ numImages: params.n || 1,
900
+ size: params.size,
901
+ quality: params.quality,
902
+ style: params.style,
903
+ responseFormat: params.response_format
904
+ };
905
+ const response = await this.http.post("/api/ai/image/generation", backendParams);
906
+ const images = response.images || response.data || [];
907
+ return {
908
+ created: Math.floor(Date.now() / 1e3),
909
+ data: images.map((img) => ({
910
+ url: img.url || img,
911
+ b64_json: img.b64_json,
912
+ revised_prompt: img.revised_prompt
913
+ }))
914
+ };
915
+ }
916
+ };
917
+
918
+ // src/client.ts
919
+ var InsForgeClient = class {
920
+ constructor(config = {}) {
921
+ this.http = new HttpClient(config);
922
+ this.tokenManager = new TokenManager(config.storage);
923
+ this.auth = new Auth(
924
+ this.http,
925
+ this.tokenManager
926
+ );
927
+ this.database = new Database(this.http, this.tokenManager);
928
+ this.storage = new Storage(this.http);
929
+ this.ai = new AI(this.http);
930
+ }
931
+ /**
932
+ * Get the underlying HTTP client for custom requests
933
+ *
934
+ * @example
935
+ * ```typescript
936
+ * const httpClient = client.getHttpClient();
937
+ * const customData = await httpClient.get('/api/custom-endpoint');
938
+ * ```
939
+ */
940
+ getHttpClient() {
941
+ return this.http;
942
+ }
943
+ /**
944
+ * Future modules will be added here:
945
+ * - database: Database operations
946
+ * - storage: File storage operations
947
+ * - functions: Serverless functions
948
+ * - tables: Table management
949
+ * - metadata: Backend metadata
950
+ */
951
+ };
952
+
953
+ // src/index.ts
954
+ function createClient(config) {
955
+ return new InsForgeClient(config);
956
+ }
957
+ var index_default = InsForgeClient;
958
+ // Annotate the CommonJS export names for ESM import in node:
959
+ 0 && (module.exports = {
960
+ AI,
961
+ Auth,
962
+ Database,
963
+ HttpClient,
964
+ InsForgeClient,
965
+ InsForgeError,
966
+ Storage,
967
+ StorageBucket,
968
+ TokenManager,
969
+ createClient
970
+ });
971
+ //# sourceMappingURL=index.js.map