@insforge/sdk 1.4.3 → 1.4.5-beta.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.
package/SDK-REFERENCE.md CHANGED
@@ -9,11 +9,11 @@ npm install @insforge/sdk
9
9
  ## Initialize
10
10
 
11
11
  ```javascript
12
- import { createClient } from "@insforge/sdk";
12
+ import { createClient } from '@insforge/sdk';
13
13
 
14
14
  const insforge = createClient({
15
- baseUrl: "http://localhost:7130",
16
- anonKey: "your-anon-key",
15
+ baseUrl: 'http://localhost:7130',
16
+ anonKey: 'your-anon-key',
17
17
  });
18
18
  ```
19
19
 
@@ -22,10 +22,10 @@ const insforge = createClient({
22
22
  ## Admin Client
23
23
 
24
24
  ```typescript
25
- import { createAdminClient } from "@insforge/sdk";
25
+ import { createAdminClient } from '@insforge/sdk';
26
26
 
27
27
  const admin = createAdminClient({
28
- baseUrl: "http://localhost:7130",
28
+ baseUrl: 'http://localhost:7130',
29
29
  apiKey: process.env.INSFORGE_API_KEY!,
30
30
  });
31
31
  ```
@@ -50,10 +50,10 @@ Default cookies:
50
50
  ### `createBrowserClient()`
51
51
 
52
52
  ```typescript
53
- import { createBrowserClient } from "@insforge/sdk/ssr";
53
+ import { createBrowserClient } from '@insforge/sdk/ssr';
54
54
 
55
55
  const insforge = createBrowserClient({
56
- refreshUrl: "/api/auth/refresh", // default
56
+ refreshUrl: '/api/auth/refresh', // default
57
57
  });
58
58
  ```
59
59
 
@@ -66,8 +66,8 @@ not include auth mutations such as `signInWithPassword()`, `signUp()`, or
66
66
  ### `createServerClient()`
67
67
 
68
68
  ```typescript
69
- import { cookies } from "next/headers";
70
- import { createServerClient } from "@insforge/sdk/ssr";
69
+ import { cookies } from 'next/headers';
70
+ import { createServerClient } from '@insforge/sdk/ssr';
71
71
 
72
72
  const insforge = createServerClient({
73
73
  cookies: await cookies(),
@@ -80,7 +80,7 @@ The server client reads only the access-token cookie and passes it as the per-re
80
80
 
81
81
  ```typescript
82
82
  // app/api/auth/refresh/route.ts
83
- import { createRefreshAuthRouter } from "@insforge/sdk/ssr";
83
+ import { createRefreshAuthRouter } from '@insforge/sdk/ssr';
84
84
 
85
85
  export const { POST } = createRefreshAuthRouter();
86
86
  ```
@@ -92,17 +92,17 @@ safe fields.
92
92
 
93
93
  ```typescript
94
94
  // app/actions.ts
95
- "use server";
95
+ 'use server';
96
96
 
97
- import { cookies } from "next/headers";
98
- import { createAuthActions } from "@insforge/sdk/ssr";
97
+ import { cookies } from 'next/headers';
98
+ import { createAuthActions } from '@insforge/sdk/ssr';
99
99
 
100
100
  export async function signIn(formData: FormData) {
101
101
  const auth = createAuthActions({ cookies: await cookies() });
102
102
 
103
103
  const { data, error } = await auth.signInWithPassword({
104
- email: String(formData.get("email")),
105
- password: String(formData.get("password")),
104
+ email: String(formData.get('email')),
105
+ password: String(formData.get('password')),
106
106
  });
107
107
 
108
108
  return { user: data?.user ?? null, error };
@@ -122,7 +122,7 @@ auto-exchange OAuth callbacks.
122
122
  Use `refreshAuth()` directly when the route needs app-specific logic:
123
123
 
124
124
  ```typescript
125
- import { refreshAuth } from "@insforge/sdk/ssr";
125
+ import { refreshAuth } from '@insforge/sdk/ssr';
126
126
 
127
127
  export async function POST(request: Request) {
128
128
  await beforeRefresh(request);
@@ -140,8 +140,8 @@ bundling the full SDK client.
140
140
 
141
141
  ```typescript
142
142
  // proxy.ts on Next.js 16+, middleware.ts on Next.js 15 and earlier
143
- import { NextResponse, type NextRequest } from "next/server";
144
- import { updateSession } from "@insforge/sdk/ssr/middleware";
143
+ import { NextResponse, type NextRequest } from 'next/server';
144
+ import { updateSession } from '@insforge/sdk/ssr/middleware';
145
145
 
146
146
  export async function proxy(request: NextRequest) {
147
147
  const response = NextResponse.next({ request });
@@ -171,7 +171,7 @@ The SDK automatically detects and handles OAuth callback parameters when initial
171
171
  ```javascript
172
172
  // Just initialize the client - OAuth is handled automatically
173
173
  const insforge = createClient({
174
- baseUrl: "http://localhost:7130",
174
+ baseUrl: 'http://localhost:7130',
175
175
  });
176
176
 
177
177
  // If the URL contains OAuth callback parameters like:
@@ -192,10 +192,10 @@ const { data } = await insforge.auth.getCurrentUser();
192
192
 
193
193
  ```javascript
194
194
  await insforge.auth.signUp({
195
- email: "user@example.com",
196
- password: "password123",
197
- name: "John Doe", // optional
198
- redirectTo: "http://localhost:3000/sign-in", // optional, recommended for link-based verification
195
+ email: 'user@example.com',
196
+ password: 'password123',
197
+ name: 'John Doe', // optional
198
+ redirectTo: 'http://localhost:3000/sign-in', // optional, recommended for link-based verification
199
199
  });
200
200
  // Response: { data: { user, accessToken }, error }
201
201
  // user: { id, email, name, emailVerified, createdAt, updatedAt }
@@ -215,8 +215,8 @@ Recommended: use your sign-in page as `redirectTo`, then show a success message
215
215
 
216
216
  ```javascript
217
217
  await insforge.auth.signInWithPassword({
218
- email: "user@example.com",
219
- password: "password123",
218
+ email: 'user@example.com',
219
+ password: 'password123',
220
220
  });
221
221
  // Response: { data: { user, accessToken }, error }
222
222
  // user: { id, email, name, emailVerified, createdAt, updatedAt }
@@ -226,9 +226,9 @@ await insforge.auth.signInWithPassword({
226
226
  ### `signInWithOAuth()`
227
227
 
228
228
  ```javascript
229
- await insforge.auth.signInWithOAuth("google", {
230
- redirectTo: "http://localhost:3000/dashboard",
231
- additionalParams: { prompt: "select_account" }, // optional provider-specific OAuth params
229
+ await insforge.auth.signInWithOAuth('google', {
230
+ redirectTo: 'http://localhost:3000/dashboard',
231
+ additionalParams: { prompt: 'select_account' }, // optional provider-specific OAuth params
232
232
  skipBrowserRedirect: true, // optional, returns URL instead of redirecting
233
233
  });
234
234
  // Response: { data: { url, provider }, error }
@@ -280,10 +280,10 @@ await insforge.auth.getProfile(userId);
280
280
 
281
281
  ```javascript
282
282
  await insforge.auth.setProfile({
283
- nickname: "JohnDoe",
284
- avatar_url: "https://...",
285
- bio: "Software developer",
286
- birthday: "1990-01-01",
283
+ nickname: 'JohnDoe',
284
+ avatar_url: 'https://...',
285
+ bio: 'Software developer',
286
+ birthday: '1990-01-01',
287
287
  });
288
288
  // Response: { data: profile, error }
289
289
  // Updates current user's profile in users table
@@ -302,8 +302,8 @@ await insforge.auth.getPublicAuthConfig();
302
302
 
303
303
  ```javascript
304
304
  await insforge.auth.resendVerificationEmail({
305
- email: "user@example.com",
306
- redirectTo: "http://localhost:3000/sign-in", // optional, recommended for link-based verification
305
+ email: 'user@example.com',
306
+ redirectTo: 'http://localhost:3000/sign-in', // optional, recommended for link-based verification
307
307
  });
308
308
  // Response: { data: { success, message }, error }
309
309
  ```
@@ -312,8 +312,8 @@ await insforge.auth.resendVerificationEmail({
312
312
 
313
313
  ```javascript
314
314
  await insforge.auth.verifyEmail({
315
- email: "user@example.com",
316
- otp: "123456",
315
+ email: 'user@example.com',
316
+ otp: '123456',
317
317
  });
318
318
  // Response: { data: { user, accessToken, csrfToken?, refreshToken? }, error }
319
319
  // POST /api/auth/email/verify is code-only
@@ -328,8 +328,8 @@ await insforge.auth.verifyEmail({
328
328
 
329
329
  ```javascript
330
330
  await insforge.auth.sendResetPasswordEmail({
331
- email: "user@example.com",
332
- redirectTo: "http://localhost:3000/reset-password", // optional, recommended for link-based reset
331
+ email: 'user@example.com',
332
+ redirectTo: 'http://localhost:3000/reset-password', // optional, recommended for link-based reset
333
333
  });
334
334
  // Response: { data: { success, message }, error }
335
335
  ```
@@ -338,8 +338,8 @@ await insforge.auth.sendResetPasswordEmail({
338
338
 
339
339
  ```javascript
340
340
  await insforge.auth.exchangeResetPasswordToken({
341
- email: "user@example.com",
342
- code: "123456",
341
+ email: 'user@example.com',
342
+ code: '123456',
343
343
  });
344
344
  // Response: { data: { token, expiresAt }, error }
345
345
  ```
@@ -348,8 +348,8 @@ await insforge.auth.exchangeResetPasswordToken({
348
348
 
349
349
  ```javascript
350
350
  await insforge.auth.resetPassword({
351
- newPassword: "newSecurePassword123",
352
- otp: "reset-token",
351
+ newPassword: 'newSecurePassword123',
352
+ otp: 'reset-token',
353
353
  });
354
354
  // Response: { data: { message }, error }
355
355
  // Browser reset links use GET /api/auth/email/reset-password-link first,
@@ -401,16 +401,13 @@ Payments methods are provider-scoped and intended for generated app frontends. T
401
401
  ### `stripe.createCheckoutSession()`
402
402
 
403
403
  ```javascript
404
- const { data, error } = await insforge.payments.stripe.createCheckoutSession(
405
- "test",
406
- {
407
- mode: "payment",
408
- lineItems: [{ priceId: "price_123", quantity: 1 }],
409
- successUrl: "https://example.com/success",
410
- cancelUrl: "https://example.com/pricing",
411
- idempotencyKey: "cart_123", // optional, recommended for retry-safe checkout creation
412
- },
413
- );
404
+ const { data, error } = await insforge.payments.stripe.createCheckoutSession('test', {
405
+ mode: 'payment',
406
+ lineItems: [{ priceId: 'price_123', quantity: 1 }],
407
+ successUrl: 'https://example.com/success',
408
+ cancelUrl: 'https://example.com/pricing',
409
+ idempotencyKey: 'cart_123', // optional, recommended for retry-safe checkout creation
410
+ });
414
411
 
415
412
  if (!error && data?.checkoutSession.url) {
416
413
  window.location.assign(data.checkoutSession.url);
@@ -420,23 +417,22 @@ if (!error && data?.checkoutSession.url) {
420
417
  For one-time payments, `subject` is optional. For subscription checkout, `subject` is required because subscriptions represent ongoing entitlement for an app-defined billing owner.
421
418
 
422
419
  ```javascript
423
- await insforge.payments.stripe.createCheckoutSession("test", {
424
- mode: "subscription",
425
- subject: { type: "team", id: "team_123" },
426
- lineItems: [{ priceId: "price_monthly_123", quantity: 1 }],
427
- successUrl: "https://example.com/billing/success",
428
- cancelUrl: "https://example.com/billing",
420
+ await insforge.payments.stripe.createCheckoutSession('test', {
421
+ mode: 'subscription',
422
+ subject: { type: 'team', id: 'team_123' },
423
+ lineItems: [{ priceId: 'price_monthly_123', quantity: 1 }],
424
+ successUrl: 'https://example.com/billing/success',
425
+ cancelUrl: 'https://example.com/billing',
429
426
  });
430
427
  ```
431
428
 
432
429
  ### `stripe.createCustomerPortalSession()`
433
430
 
434
431
  ```javascript
435
- const { data, error } =
436
- await insforge.payments.stripe.createCustomerPortalSession("test", {
437
- subject: { type: "team", id: "team_123" },
438
- returnUrl: "https://example.com/billing",
439
- });
432
+ const { data, error } = await insforge.payments.stripe.createCustomerPortalSession('test', {
433
+ subject: { type: 'team', id: 'team_123' },
434
+ returnUrl: 'https://example.com/billing',
435
+ });
440
436
 
441
437
  if (!error && data?.customerPortalSession.url) {
442
438
  window.location.assign(data.customerPortalSession.url);
@@ -450,20 +446,20 @@ Customer portal sessions require an authenticated user and an existing Stripe cu
450
446
  Razorpay uses Checkout.js instead of a hosted redirect URL. Create an order through InsForge, pass `checkoutOptions` into Razorpay Checkout.js, then verify the signed payment response.
451
447
 
452
448
  ```javascript
453
- const { data, error } = await insforge.payments.razorpay.createOrder("test", {
449
+ const { data, error } = await insforge.payments.razorpay.createOrder('test', {
454
450
  amount: 200000,
455
- currency: "INR",
456
- receipt: "cart_123",
457
- subject: { type: "team", id: "team_123" },
458
- customerName: "Ada Lovelace",
459
- customerEmail: "ada@example.com",
451
+ currency: 'INR',
452
+ receipt: 'cart_123',
453
+ subject: { type: 'team', id: 'team_123' },
454
+ customerName: 'Ada Lovelace',
455
+ customerEmail: 'ada@example.com',
460
456
  });
461
457
 
462
458
  if (!error && data) {
463
459
  const checkout = new Razorpay({
464
460
  ...data.checkoutOptions,
465
461
  handler: async (response) => {
466
- await insforge.payments.razorpay.verifyOrder("test", {
462
+ await insforge.payments.razorpay.verifyOrder('test', {
467
463
  orderId: response.razorpay_order_id,
468
464
  paymentId: response.razorpay_payment_id,
469
465
  signature: response.razorpay_signature,
@@ -478,22 +474,19 @@ if (!error && data) {
478
474
  ### `razorpay.createSubscription()`
479
475
 
480
476
  ```javascript
481
- const { data, error } = await insforge.payments.razorpay.createSubscription(
482
- "test",
483
- {
484
- planId: "plan_123",
485
- totalCount: 12,
486
- subject: { type: "team", id: "team_123" },
487
- customerName: "Ada Lovelace",
488
- customerEmail: "ada@example.com",
489
- },
490
- );
477
+ const { data, error } = await insforge.payments.razorpay.createSubscription('test', {
478
+ planId: 'plan_123',
479
+ totalCount: 12,
480
+ subject: { type: 'team', id: 'team_123' },
481
+ customerName: 'Ada Lovelace',
482
+ customerEmail: 'ada@example.com',
483
+ });
491
484
 
492
485
  if (!error && data) {
493
486
  const checkout = new Razorpay({
494
487
  ...data.checkoutOptions,
495
488
  handler: async (response) => {
496
- await insforge.payments.razorpay.verifySubscription("test", {
489
+ await insforge.payments.razorpay.verifySubscription('test', {
497
490
  subscriptionId: response.razorpay_subscription_id,
498
491
  paymentId: response.razorpay_payment_id,
499
492
  signature: response.razorpay_signature,
@@ -508,7 +501,7 @@ if (!error && data) {
508
501
  ### `razorpay.cancelSubscription()`
509
502
 
510
503
  ```javascript
511
- await insforge.payments.razorpay.cancelSubscription("test", "sub_123", {
504
+ await insforge.payments.razorpay.cancelSubscription('test', 'sub_123', {
512
505
  cancelAtCycleEnd: false,
513
506
  });
514
507
  ```
@@ -516,8 +509,8 @@ await insforge.payments.razorpay.cancelSubscription("test", "sub_123", {
516
509
  ### `razorpay.pauseSubscription()` / `razorpay.resumeSubscription()`
517
510
 
518
511
  ```javascript
519
- await insforge.payments.razorpay.pauseSubscription("test", "sub_123");
520
- await insforge.payments.razorpay.resumeSubscription("test", "sub_123");
512
+ await insforge.payments.razorpay.pauseSubscription('test', 'sub_123');
513
+ await insforge.payments.razorpay.resumeSubscription('test', 'sub_123');
521
514
  ```
522
515
 
523
516
  Razorpay webhook setup is manual in the Razorpay dashboard. Configure keys and copy the webhook URL, secret, and recommended events from the InsForge payments settings UI.
@@ -531,7 +524,7 @@ Razorpay webhook setup is manual in the Razorpay dashboard. Configure keys and c
531
524
  Create a query builder for a table:
532
525
 
533
526
  ```javascript
534
- const query = insforge.database.from("posts");
527
+ const query = insforge.database.from('posts');
535
528
  // Returns a PostgREST query builder with all Supabase features
536
529
  ```
537
530
 
@@ -539,29 +532,27 @@ const query = insforge.database.from("posts");
539
532
 
540
533
  ```javascript
541
534
  // Basic select
542
- await insforge.database.from("posts").select(); // Default: '*'
535
+ await insforge.database.from('posts').select(); // Default: '*'
543
536
 
544
537
  // Select specific columns
545
- await insforge.database.from("posts").select("id, title, created_at");
538
+ await insforge.database.from('posts').select('id, title, created_at');
546
539
 
547
540
  // With filters
548
541
  await insforge.database
549
- .from("posts")
542
+ .from('posts')
550
543
  .select()
551
- .eq("user_id", "123")
552
- .order("created_at", { ascending: false })
544
+ .eq('user_id', '123')
545
+ .order('created_at', { ascending: false })
553
546
  .limit(10);
554
547
 
555
548
  // With joins (PostgREST syntax)
556
- await insforge.database.from("posts").select("*, users!inner(*)"); // Inner join with users table
549
+ await insforge.database.from('posts').select('*, users!inner(*)'); // Inner join with users table
557
550
 
558
551
  // Join with specific columns
559
- await insforge.database
560
- .from("posts")
561
- .select("id, title, users(nickname, avatar_url)");
552
+ await insforge.database.from('posts').select('id, title, users(nickname, avatar_url)');
562
553
 
563
554
  // Aliased joins
564
- await insforge.database.from("posts").select("*, author:users(*)"); // Alias users as author
555
+ await insforge.database.from('posts').select('*, author:users(*)'); // Alias users as author
565
556
  // Response: { data: [...], error }
566
557
  ```
567
558
 
@@ -569,25 +560,19 @@ await insforge.database.from("posts").select("*, author:users(*)"); // Alias use
569
560
 
570
561
  ```javascript
571
562
  // Single record - use .select() to return inserted data
572
- await insforge.database
573
- .from("posts")
574
- .insert({ title: "Hello", content: "World" })
575
- .select();
563
+ await insforge.database.from('posts').insert({ title: 'Hello', content: 'World' }).select();
576
564
 
577
565
  // Multiple records
578
566
  await insforge.database
579
- .from("posts")
567
+ .from('posts')
580
568
  .insert([
581
- { title: "Post 1", content: "Content 1" },
582
- { title: "Post 2", content: "Content 2" },
569
+ { title: 'Post 1', content: 'Content 1' },
570
+ { title: 'Post 2', content: 'Content 2' },
583
571
  ])
584
572
  .select();
585
573
 
586
574
  // Upsert
587
- await insforge.database
588
- .from("posts")
589
- .upsert({ id: "123", title: "Updated or New" })
590
- .select();
575
+ await insforge.database.from('posts').upsert({ id: '123', title: 'Updated or New' }).select();
591
576
  // Response: { data: [...], error }
592
577
 
593
578
  // Note: Without .select(), mutations return { data: null, error }
@@ -596,18 +581,14 @@ await insforge.database
596
581
  ### UPDATE Operations
597
582
 
598
583
  ```javascript
599
- await insforge.database
600
- .from("posts")
601
- .update({ title: "Updated Title" })
602
- .eq("id", "123")
603
- .select();
584
+ await insforge.database.from('posts').update({ title: 'Updated Title' }).eq('id', '123').select();
604
585
  // Response: { data: [...], error }
605
586
  ```
606
587
 
607
588
  ### DELETE Operations
608
589
 
609
590
  ```javascript
610
- await insforge.database.from("posts").delete().eq("id", "123").select();
591
+ await insforge.database.from('posts').delete().eq('id', '123').select();
611
592
  // Response: { data: [...], error }
612
593
  ```
613
594
 
@@ -635,28 +616,25 @@ await insforge.database.from("posts").delete().eq("id", "123").select();
635
616
 
636
617
  ```javascript
637
618
  // Simple OR: status = 'active' OR status = 'pending'
638
- await insforge.database
639
- .from("posts")
640
- .select()
641
- .or("status.eq.active,status.eq.pending");
619
+ await insforge.database.from('posts').select().or('status.eq.active,status.eq.pending');
642
620
 
643
621
  // OR with other filters (implicit AND)
644
622
  await insforge.database
645
- .from("posts")
623
+ .from('posts')
646
624
  .select()
647
- .eq("user_id", "123") // AND
648
- .or("status.eq.draft,status.eq.published"); // OR
625
+ .eq('user_id', '123') // AND
626
+ .or('status.eq.draft,status.eq.published'); // OR
649
627
 
650
628
  // Complex OR with NOT
651
- await insforge.database.from("users").select().or("age.lt.18,age.gt.65");
629
+ await insforge.database.from('users').select().or('age.lt.18,age.gt.65');
652
630
  // age < 18 OR age > 65
653
631
 
654
632
  // Combining AND and OR
655
633
  await insforge.database
656
- .from("products")
634
+ .from('products')
657
635
  .select()
658
- .eq("category", "electronics")
659
- .or("price.lt.100,rating.gte.4.5");
636
+ .eq('category', 'electronics')
637
+ .or('price.lt.100,rating.gte.4.5');
660
638
  // category = 'electronics' AND (price < 100 OR rating >= 4.5)
661
639
  ```
662
640
 
@@ -678,13 +656,13 @@ Use with `select()` to get counts:
678
656
  ```javascript
679
657
  // Get exact count with data
680
658
  const { data, count, error } = await insforge.database
681
- .from("posts")
682
- .select("*", { count: "exact" });
659
+ .from('posts')
660
+ .select('*', { count: 'exact' });
683
661
 
684
662
  // Get count without data (HEAD request)
685
663
  const { count, error } = await insforge.database
686
- .from("posts")
687
- .select("*", { count: "exact", head: true });
664
+ .from('posts')
665
+ .select('*', { count: 'exact', head: true });
688
666
 
689
667
  // Count strategies:
690
668
  // 'exact' - Accurate but slower for large tables
@@ -698,26 +676,26 @@ All methods return the query builder for chaining:
698
676
 
699
677
  ```javascript
700
678
  const { data, error } = await insforge.database
701
- .from("posts")
702
- .select("id, title, content")
703
- .eq("status", "published")
704
- .gte("likes", 100)
705
- .order("created_at", { ascending: false })
679
+ .from('posts')
680
+ .select('id, title, content')
681
+ .eq('status', 'published')
682
+ .gte('likes', 100)
683
+ .order('created_at', { ascending: false })
706
684
  .limit(10);
707
685
 
708
686
  // With count (Supabase-style)
709
687
  const { data, error, count } = await insforge.database
710
- .from("posts")
711
- .select("*", { count: "exact" }) // Request exact count
712
- .eq("status", "published")
688
+ .from('posts')
689
+ .select('*', { count: 'exact' }) // Request exact count
690
+ .eq('status', 'published')
713
691
  .range(0, 9); // Get first 10
714
692
  // Returns: data (array), error (PostgrestError), count (number)
715
693
 
716
694
  // Count without data (head request)
717
695
  const { count, error } = await insforge.database
718
- .from("posts")
719
- .select("*", { count: "exact", head: true })
720
- .eq("status", "published");
696
+ .from('posts')
697
+ .select('*', { count: 'exact', head: true })
698
+ .eq('status', 'published');
721
699
  // Returns only count, no data
722
700
  ```
723
701
 
@@ -726,14 +704,14 @@ const { count, error } = await insforge.database
726
704
  ### `storage.from()`
727
705
 
728
706
  ```javascript
729
- const bucket = insforge.storage.from("avatars");
707
+ const bucket = insforge.storage.from('avatars');
730
708
  // Returns StorageBucket instance for file operations
731
709
  ```
732
710
 
733
711
  ### `bucket.upload()`
734
712
 
735
713
  ```javascript
736
- await bucket.upload("path/file.jpg", file);
714
+ await bucket.upload('path/file.jpg', file);
737
715
  // Response: { data: StorageFileSchema, error }
738
716
  // data: { bucket, key, size, mimeType, uploadedAt, url }
739
717
  ```
@@ -749,14 +727,14 @@ await bucket.uploadAuto(file);
749
727
  ### `bucket.download()`
750
728
 
751
729
  ```javascript
752
- await bucket.download("path/file.jpg");
730
+ await bucket.download('path/file.jpg');
753
731
  // Response: { data: Blob, error }
754
732
  ```
755
733
 
756
734
  ### `bucket.list()`
757
735
 
758
736
  ```javascript
759
- await bucket.list({ prefix: "users/", limit: 10 });
737
+ await bucket.list({ prefix: 'users/', limit: 10 });
760
738
  // Response: { data: ListObjectsResponseSchema, error }
761
739
  // data: { bucketName, objects[], pagination }
762
740
  ```
@@ -764,14 +742,14 @@ await bucket.list({ prefix: "users/", limit: 10 });
764
742
  ### `bucket.remove()`
765
743
 
766
744
  ```javascript
767
- await bucket.remove("path/file.jpg");
745
+ await bucket.remove('path/file.jpg');
768
746
  // Response: { data: { message }, error }
769
747
  ```
770
748
 
771
749
  ### `bucket.getPublicUrl()`
772
750
 
773
751
  ```javascript
774
- bucket.getPublicUrl("path/file.jpg");
752
+ bucket.getPublicUrl('path/file.jpg');
775
753
  // Returns: string URL (no API call)
776
754
  ```
777
755
 
@@ -785,10 +763,10 @@ Create AI chat completions with support for both streaming and non-streaming res
785
763
 
786
764
  ```javascript
787
765
  const completion = await insforge.ai.chat.completions.create({
788
- model: "anthropic/claude-3.5-haiku",
766
+ model: 'anthropic/claude-3.5-haiku',
789
767
  messages: [
790
- { role: "system", content: "You are a helpful assistant" },
791
- { role: "user", content: "Hello, how are you?" },
768
+ { role: 'system', content: 'You are a helpful assistant' },
769
+ { role: 'user', content: 'Hello, how are you?' },
792
770
  ],
793
771
  temperature: 0.7,
794
772
  maxTokens: 500,
@@ -805,8 +783,8 @@ console.log(completion.choices[0].message.content);
805
783
  ```javascript
806
784
  // Returns an async iterable of OpenAI-like chunks for real-time streaming
807
785
  const stream = await insforge.ai.chat.completions.create({
808
- model: "anthropic/claude-3.5-haiku",
809
- messages: [{ role: "user", content: "Tell me a story" }],
786
+ model: 'anthropic/claude-3.5-haiku',
787
+ messages: [{ role: 'user', content: 'Tell me a story' }],
810
788
  stream: true,
811
789
  });
812
790
 
@@ -835,8 +813,8 @@ Generate images using AI models.
835
813
  ```javascript
836
814
  // Text-to-image
837
815
  const image = await insforge.ai.images.generate({
838
- model: "google/gemini-3-pro-image-preview",
839
- prompt: "A serene landscape with mountains at sunset",
816
+ model: 'google/gemini-3-pro-image-preview',
817
+ prompt: 'A serene landscape with mountains at sunset',
840
818
  });
841
819
  // Returns an OpenAI-like image object directly (not a { data, error } envelope):
842
820
  // image.data[i].b64_json - base64-encoded image (no `data:` URI prefix)
@@ -846,9 +824,9 @@ const base64Png = image.data[0].b64_json;
846
824
 
847
825
  // Image-to-image — pass source images as URLs or base64 data URIs
848
826
  const edited = await insforge.ai.images.generate({
849
- model: "google/gemini-3-pro-image-preview",
850
- prompt: "Turn this into a watercolor painting",
851
- images: [{ url: "https://example.com/input.jpg" }],
827
+ model: 'google/gemini-3-pro-image-preview',
828
+ prompt: 'Turn this into a watercolor painting',
829
+ images: [{ url: 'https://example.com/input.jpg' }],
852
830
  });
853
831
  ```
854
832
 
@@ -866,8 +844,8 @@ Create embeddings for one or more text inputs.
866
844
 
867
845
  ```javascript
868
846
  const embeddings = await insforge.ai.embeddings.create({
869
- model: "openai/text-embedding-3-small",
870
- input: "Hello world", // or string[] for batch input
847
+ model: 'openai/text-embedding-3-small',
848
+ input: 'Hello world', // or string[] for batch input
871
849
  });
872
850
  // Returns an OpenAI-like embeddings object directly (not a { data, error } envelope):
873
851
  // embeddings.data[i].embedding - the vector (number[]) for input i
@@ -886,27 +864,27 @@ console.log(embeddings.data[0].embedding);
886
864
  ### Complete AI Example
887
865
 
888
866
  ```javascript
889
- import { createClient } from "@insforge/sdk";
867
+ import { createClient } from '@insforge/sdk';
890
868
 
891
869
  const insforge = createClient({
892
- baseUrl: "http://localhost:7130",
870
+ baseUrl: 'http://localhost:7130',
893
871
  });
894
872
 
895
873
  // Chat completion
896
874
  const chat = await insforge.ai.chat.completions.create({
897
- model: "anthropic/claude-3.5-haiku",
898
- messages: [{ role: "user", content: "What is the capital of France?" }],
875
+ model: 'anthropic/claude-3.5-haiku',
876
+ messages: [{ role: 'user', content: 'What is the capital of France?' }],
899
877
  });
900
878
  console.log(chat.choices[0].message.content); // "The capital of France is Paris."
901
879
 
902
880
  // Streaming chat
903
881
  const stream = await insforge.ai.chat.completions.create({
904
- model: "anthropic/claude-3.5-haiku",
905
- messages: [{ role: "user", content: "Write a haiku about coding" }],
882
+ model: 'anthropic/claude-3.5-haiku',
883
+ messages: [{ role: 'user', content: 'Write a haiku about coding' }],
906
884
  stream: true,
907
885
  });
908
886
 
909
- let fullResponse = "";
887
+ let fullResponse = '';
910
888
  for await (const chunk of stream) {
911
889
  const delta = chunk.choices[0]?.delta?.content;
912
890
  if (delta) {
@@ -917,15 +895,15 @@ for await (const chunk of stream) {
917
895
 
918
896
  // Image generation
919
897
  const image = await insforge.ai.images.generate({
920
- model: "google/gemini-3-pro-image-preview",
921
- prompt: "A futuristic city with flying cars",
898
+ model: 'google/gemini-3-pro-image-preview',
899
+ prompt: 'A futuristic city with flying cars',
922
900
  });
923
901
  const base64Png = image.data[0].b64_json; // base64-encoded image
924
902
 
925
903
  // Embeddings
926
904
  const embeddings = await insforge.ai.embeddings.create({
927
- model: "openai/text-embedding-3-small",
928
- input: "Vectorize this sentence",
905
+ model: 'openai/text-embedding-3-small',
906
+ input: 'Vectorize this sentence',
929
907
  });
930
908
  console.log(embeddings.data[0].embedding); // number[]
931
909
  ```
@@ -943,7 +921,7 @@ import type {
943
921
  ListObjectsResponseSchema,
944
922
  PublicOAuthProvider,
945
923
  GetPublicEmailAuthConfigResponse,
946
- } from "@insforge/shared-schemas";
924
+ } from '@insforge/shared-schemas';
947
925
 
948
926
  // Database response type
949
927
  interface DatabaseResponse<T> {