@insforge/sdk 1.4.1 → 1.4.3

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/README.md CHANGED
@@ -185,6 +185,31 @@ const { data, error } = await insforge.database
185
185
  .eq("id", postId);
186
186
  ```
187
187
 
188
+ #### Selecting a schema
189
+
190
+ Queries hit the `public` schema by default. Target a custom schema by chaining `.schema()` — the table name stays bare (it maps to PostgREST's `Accept-Profile`/`Content-Profile` header):
191
+
192
+ ```javascript
193
+ const { data } = await insforge.database
194
+ .schema("analytics")
195
+ .from("events")
196
+ .select("*");
197
+
198
+ await insforge.database.schema("analytics").rpc("rollup", { day: "2026-01-01" });
199
+ ```
200
+
201
+ Or set a default schema for every query when creating the client:
202
+
203
+ ```javascript
204
+ const insforge = createClient({
205
+ baseUrl: "...",
206
+ anonKey: "...",
207
+ db: { schema: "analytics" },
208
+ });
209
+ ```
210
+
211
+ The schema must be exposed by the backend, and access is still gated by grants + RLS like `public`. Older backends that don't expose the schema return PostgREST `PGRST106` rather than silently falling back.
212
+
188
213
  ### File Storage
189
214
 
190
215
  ```javascript
@@ -366,6 +391,11 @@ import { createBrowserClient } from "@insforge/sdk/ssr";
366
391
  export const insforge = createBrowserClient();
367
392
  ```
368
393
 
394
+ `createBrowserClient()` is for Client Components that consume an existing SSR
395
+ session. Its TypeScript surface does not include auth mutations such as
396
+ `signInWithPassword()`, `signUp()`, or `signOut()`. Run auth mutations on the
397
+ server so the app can write server-owned auth cookies.
398
+
369
399
  ```typescript
370
400
  // app/lib/insforge/server.ts
371
401
  import { cookies } from "next/headers";
@@ -383,18 +413,126 @@ import { createRefreshAuthRouter } from "@insforge/sdk/ssr";
383
413
  export const { POST } = createRefreshAuthRouter();
384
414
  ```
385
415
 
386
- For server-owned refresh cookies, run sign-in in a Route Handler or Server Action and use `setAuthCookies()` from `@insforge/sdk/ssr` with the framework cookie writer. In Next.js Route Handlers, pass `response.cookies`:
416
+ For sign-in, sign-up, and sign-out, use `createAuthActions()` in a Server
417
+ Action file. Server Actions are stable in Next.js 14+. Do not return raw auth
418
+ responses from Server Actions; return only the user or app-specific safe fields
419
+ so access and refresh tokens stay server-owned.
387
420
 
388
421
  ```typescript
389
- import { NextResponse } from "next/server";
390
- import { setAuthCookies } from "@insforge/sdk/ssr";
422
+ // app/actions.ts
423
+ "use server";
391
424
 
392
- const response = NextResponse.json({ user: data.user });
393
- setAuthCookies(response.cookies, {
394
- accessToken: data.accessToken,
395
- refreshToken: data.refreshToken,
396
- });
397
- return response;
425
+ import { cookies } from "next/headers";
426
+ import { createAuthActions } from "@insforge/sdk/ssr";
427
+
428
+ export async function signIn(formData: FormData) {
429
+ const auth = createAuthActions({ cookies: await cookies() });
430
+
431
+ const { data, error } = await auth.signInWithPassword({
432
+ email: String(formData.get("email")),
433
+ password: String(formData.get("password")),
434
+ });
435
+
436
+ return { user: data?.user ?? null, error };
437
+ }
438
+ ```
439
+
440
+ For OAuth in SSR apps, start and finish the flow on the server. Store the PKCE
441
+ verifier in an httpOnly app cookie and exchange the callback code with
442
+ `createAuthActions()`:
443
+
444
+ ```typescript
445
+ // app/actions.ts
446
+ "use server";
447
+
448
+ import { cookies } from "next/headers";
449
+ import { redirect } from "next/navigation";
450
+ import { createAuthActions } from "@insforge/sdk/ssr";
451
+
452
+ export async function signInWithGoogle() {
453
+ const cookieStore = await cookies();
454
+ const auth = createAuthActions({ cookies: cookieStore });
455
+ const { data, error } = await auth.signInWithOAuth("google", {
456
+ redirectTo: new URL(
457
+ "/api/auth/callback",
458
+ process.env.NEXT_PUBLIC_APP_URL
459
+ ).toString(),
460
+ skipBrowserRedirect: true,
461
+ });
462
+
463
+ if (error || !data.url || !data.codeVerifier) {
464
+ throw new Error(error?.message ?? "OAuth init failed");
465
+ }
466
+
467
+ cookieStore.set("insforge_code_verifier", data.codeVerifier, {
468
+ httpOnly: true,
469
+ secure: process.env.NODE_ENV === "production",
470
+ sameSite: "lax",
471
+ path: "/",
472
+ maxAge: 600,
473
+ });
474
+
475
+ redirect(data.url);
476
+ }
477
+ ```
478
+
479
+ ```typescript
480
+ // app/api/auth/callback/route.ts
481
+ import { cookies } from "next/headers";
482
+ import { NextResponse, type NextRequest } from "next/server";
483
+ import { createAuthActions } from "@insforge/sdk/ssr";
484
+
485
+ export async function GET(request: NextRequest) {
486
+ const code = request.nextUrl.searchParams.get("insforge_code");
487
+ const verifier = (await cookies()).get("insforge_code_verifier")?.value;
488
+ if (!code || !verifier) {
489
+ return NextResponse.redirect(new URL("/login?error=oauth", request.url));
490
+ }
491
+
492
+ const response = NextResponse.redirect(new URL("/dashboard", request.url));
493
+ const auth = createAuthActions({
494
+ requestCookies: request.cookies,
495
+ responseCookies: response.cookies,
496
+ });
497
+ const { error } = await auth.exchangeOAuthCode(code, verifier);
498
+ if (error) {
499
+ return NextResponse.redirect(new URL("/login?error=oauth", request.url));
500
+ }
501
+
502
+ response.cookies.delete("insforge_code_verifier");
503
+ return response;
504
+ }
505
+ ```
506
+
507
+ SSR browser clients do not exchange OAuth callbacks automatically. OAuth
508
+ callbacks must be completed on the server so the refresh token lands in the
509
+ httpOnly app cookie.
510
+
511
+ For Route Handlers, pass request cookies for reading the current session and
512
+ response cookies for writing the next session:
513
+
514
+ ```typescript
515
+ // app/api/auth/sign-out/route.ts
516
+ import { NextResponse, type NextRequest } from "next/server";
517
+ import { createAuthActions } from "@insforge/sdk/ssr";
518
+
519
+ export async function POST(request: NextRequest) {
520
+ const response = NextResponse.json({ ok: true });
521
+ const auth = createAuthActions({
522
+ requestCookies: request.cookies,
523
+ responseCookies: response.cookies,
524
+ });
525
+
526
+ const { error } = await auth.signOut();
527
+ if (error) {
528
+ return NextResponse.json(
529
+ { error: error.error, message: error.message },
530
+ { status: error.statusCode }
531
+ );
532
+ }
533
+
534
+ return response;
535
+ }
398
536
  ```
399
537
 
400
538
  If your refresh route needs custom side effects:
package/SDK-REFERENCE.md CHANGED
@@ -59,6 +59,10 @@ const insforge = createBrowserClient({
59
59
 
60
60
  The browser client reads the access-token cookie, uses it for Database, Storage, Functions, and Realtime, and calls the refresh route when the access token is missing or near expiry.
61
61
 
62
+ The browser client consumes an existing SSR session. Its TypeScript surface does
63
+ not include auth mutations such as `signInWithPassword()`, `signUp()`, or
64
+ `signOut()`.
65
+
62
66
  ### `createServerClient()`
63
67
 
64
68
  ```typescript
@@ -81,34 +85,40 @@ import { createRefreshAuthRouter } from "@insforge/sdk/ssr";
81
85
  export const { POST } = createRefreshAuthRouter();
82
86
  ```
83
87
 
84
- For server-owned refresh cookies, sign-in should also run through a Route Handler or Server Action that can set cookies:
88
+ For server-owned refresh cookies, sign-in, sign-up, and sign-out should run
89
+ through a Server Action or Route Handler that can set cookies. Do not return
90
+ raw auth responses from Server Actions; return only the user or app-specific
91
+ safe fields.
85
92
 
86
93
  ```typescript
87
- import { NextResponse } from "next/server";
88
- import { createServerClient, setAuthCookies } from "@insforge/sdk/ssr";
94
+ // app/actions.ts
95
+ "use server";
89
96
 
90
- export async function POST(request: Request) {
91
- const client = createServerClient();
92
- const { data, error } = await client.auth.signInWithPassword(
93
- await request.json(),
94
- );
95
- if (error || !data?.accessToken) {
96
- return Response.json(error, { status: error?.statusCode ?? 400 });
97
- }
97
+ import { cookies } from "next/headers";
98
+ import { createAuthActions } from "@insforge/sdk/ssr";
98
99
 
99
- const response = NextResponse.json({
100
- accessToken: data.accessToken,
101
- user: data.user,
102
- });
103
- setAuthCookies(response.cookies, {
104
- accessToken: data.accessToken,
105
- refreshToken: data.refreshToken,
100
+ export async function signIn(formData: FormData) {
101
+ const auth = createAuthActions({ cookies: await cookies() });
102
+
103
+ const { data, error } = await auth.signInWithPassword({
104
+ email: String(formData.get("email")),
105
+ password: String(formData.get("password")),
106
106
  });
107
107
 
108
- return response;
108
+ return { user: data?.user ?? null, error };
109
109
  }
110
110
  ```
111
111
 
112
+ In Route Handlers, pass `requestCookies` and `responseCookies` to the same
113
+ helper when request and response cookie stores are separate.
114
+
115
+ For OAuth, initiate and exchange on the server. Use
116
+ `createAuthActions().signInWithOAuth(provider, { redirectTo, skipBrowserRedirect: true })`
117
+ in a Server Action, store the returned `codeVerifier` in an httpOnly app cookie,
118
+ redirect to `data.url`, then call `createAuthActions().exchangeOAuthCode(code,
119
+ codeVerifier)` from the callback Route Handler. SSR browser clients do not
120
+ auto-exchange OAuth callbacks.
121
+
112
122
  Use `refreshAuth()` directly when the route needs app-specific logic:
113
123
 
114
124
  ```typescript
@@ -1,6 +1,7 @@
1
- import { A as AuthSession, I as InsForgeConfig, e as AuthRefreshResponse, d as InsForgeError } from './types-NjykhyRq.mjs';
1
+ import { A as AuthSession, I as InsForgeConfig, e as AuthRefreshResponse, d as InsForgeError } from './types-MKmYAYeg.mjs';
2
2
  import { UserSchema, CreateUserRequest, CreateUserResponse, CreateSessionRequest, CreateSessionResponse, OAuthProvidersSchema, RefreshSessionResponse, GetProfileResponse, SendVerificationEmailRequest, VerifyEmailRequest, VerifyEmailResponse, SendResetPasswordEmailRequest, ExchangeResetPasswordTokenRequest, ExchangeResetPasswordTokenResponse, ResetPasswordResponse, GetPublicAuthConfigResponse, StorageFileSchema, ListObjectsResponseSchema, ChatCompletionRequest, ImageGenerationRequest, EmbeddingsRequest, SubscribeResponse, SocketMessage, SendRawEmailRequest, SendEmailResponse, StripeEnvironment, CreateCheckoutSessionBody, CreateCheckoutSessionResponse, CreateCustomerPortalSessionBody, CreateCustomerPortalSessionResponse, RazorpayEnvironment, CreateRazorpayOrderBody, CreateRazorpayOrderResponse, VerifyRazorpayOrderBody, VerifyRazorpayOrderResponse, CreateRazorpaySubscriptionBody, CreateRazorpaySubscriptionResponse, VerifyRazorpaySubscriptionBody, VerifyRazorpaySubscriptionResponse, CancelRazorpaySubscriptionBodyInput, CancelRazorpaySubscriptionResponse, PauseRazorpaySubscriptionResponse, ResumeRazorpaySubscriptionResponse } from '@insforge/shared-schemas';
3
3
  import * as _supabase_postgrest_js from '@supabase/postgrest-js';
4
+ import { PostgrestClient } from '@supabase/postgrest-js';
4
5
 
5
6
  type LogFunction = (message: string, ...args: any[]) => void;
6
7
  /**
@@ -204,6 +205,7 @@ declare class HttpClient {
204
205
 
205
206
  interface AuthOptions {
206
207
  isServerMode?: boolean;
208
+ detectOAuthCallback?: boolean;
207
209
  }
208
210
  type OAuthSignInOptions = {
209
211
  redirectTo: string;
@@ -361,7 +363,22 @@ declare class Auth {
361
363
  */
362
364
  declare class Database {
363
365
  private postgrest;
364
- constructor(httpClient: HttpClient);
366
+ constructor(httpClient: HttpClient, defaultSchema?: string);
367
+ /**
368
+ * Select a non-default Postgres schema for the chained query. Maps to
369
+ * PostgREST's `Accept-Profile` (reads) / `Content-Profile` (writes) header.
370
+ * The schema must be exposed by the backend.
371
+ *
372
+ * @example
373
+ * const { data } = await client.database
374
+ * .schema('analytics')
375
+ * .from('events')
376
+ * .select('*');
377
+ *
378
+ * @example
379
+ * await client.database.schema('analytics').rpc('rollup', { day: '2026-01-01' });
380
+ */
381
+ schema(schemaName: string): PostgrestClient<any, any, string, any>;
365
382
  /**
366
383
  * Create a query builder for a table
367
384
  *
@@ -1,6 +1,7 @@
1
- import { A as AuthSession, I as InsForgeConfig, e as AuthRefreshResponse, d as InsForgeError } from './types-NjykhyRq.js';
1
+ import { A as AuthSession, I as InsForgeConfig, e as AuthRefreshResponse, d as InsForgeError } from './types-MKmYAYeg.js';
2
2
  import { UserSchema, CreateUserRequest, CreateUserResponse, CreateSessionRequest, CreateSessionResponse, OAuthProvidersSchema, RefreshSessionResponse, GetProfileResponse, SendVerificationEmailRequest, VerifyEmailRequest, VerifyEmailResponse, SendResetPasswordEmailRequest, ExchangeResetPasswordTokenRequest, ExchangeResetPasswordTokenResponse, ResetPasswordResponse, GetPublicAuthConfigResponse, StorageFileSchema, ListObjectsResponseSchema, ChatCompletionRequest, ImageGenerationRequest, EmbeddingsRequest, SubscribeResponse, SocketMessage, SendRawEmailRequest, SendEmailResponse, StripeEnvironment, CreateCheckoutSessionBody, CreateCheckoutSessionResponse, CreateCustomerPortalSessionBody, CreateCustomerPortalSessionResponse, RazorpayEnvironment, CreateRazorpayOrderBody, CreateRazorpayOrderResponse, VerifyRazorpayOrderBody, VerifyRazorpayOrderResponse, CreateRazorpaySubscriptionBody, CreateRazorpaySubscriptionResponse, VerifyRazorpaySubscriptionBody, VerifyRazorpaySubscriptionResponse, CancelRazorpaySubscriptionBodyInput, CancelRazorpaySubscriptionResponse, PauseRazorpaySubscriptionResponse, ResumeRazorpaySubscriptionResponse } from '@insforge/shared-schemas';
3
3
  import * as _supabase_postgrest_js from '@supabase/postgrest-js';
4
+ import { PostgrestClient } from '@supabase/postgrest-js';
4
5
 
5
6
  type LogFunction = (message: string, ...args: any[]) => void;
6
7
  /**
@@ -204,6 +205,7 @@ declare class HttpClient {
204
205
 
205
206
  interface AuthOptions {
206
207
  isServerMode?: boolean;
208
+ detectOAuthCallback?: boolean;
207
209
  }
208
210
  type OAuthSignInOptions = {
209
211
  redirectTo: string;
@@ -361,7 +363,22 @@ declare class Auth {
361
363
  */
362
364
  declare class Database {
363
365
  private postgrest;
364
- constructor(httpClient: HttpClient);
366
+ constructor(httpClient: HttpClient, defaultSchema?: string);
367
+ /**
368
+ * Select a non-default Postgres schema for the chained query. Maps to
369
+ * PostgREST's `Accept-Profile` (reads) / `Content-Profile` (writes) header.
370
+ * The schema must be exposed by the backend.
371
+ *
372
+ * @example
373
+ * const { data } = await client.database
374
+ * .schema('analytics')
375
+ * .from('events')
376
+ * .select('*');
377
+ *
378
+ * @example
379
+ * await client.database.schema('analytics').rpc('rollup', { day: '2026-01-01' });
380
+ */
381
+ schema(schemaName: string): PostgrestClient<any, any, string, any>;
365
382
  /**
366
383
  * Create a query builder for a table
367
384
  *
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { I as InsForgeClient } from './client-hYdj36T6.mjs';
2
- export { c as AI, A as Auth, C as ConnectionState, D as Database, E as Emails, f as EventCallback, d as FunctionInvokeOptions, F as Functions, H as HttpClient, L as Logger, P as Payments, e as PaymentsResponse, R as Realtime, S as Storage, a as StorageBucket, b as StorageResponse, T as TokenManager } from './client-hYdj36T6.mjs';
3
- import { I as InsForgeConfig, a as InsForgeAdminConfig } from './types-NjykhyRq.mjs';
4
- export { b as ApiError, A as AuthSession, d as InsForgeError, c as InsForgeErrorCode } from './types-NjykhyRq.mjs';
1
+ import { I as InsForgeClient } from './client-B6eZHolm.mjs';
2
+ export { c as AI, A as Auth, C as ConnectionState, D as Database, E as Emails, f as EventCallback, d as FunctionInvokeOptions, F as Functions, H as HttpClient, L as Logger, P as Payments, e as PaymentsResponse, R as Realtime, S as Storage, a as StorageBucket, b as StorageResponse, T as TokenManager } from './client-B6eZHolm.mjs';
3
+ import { I as InsForgeConfig, a as InsForgeAdminConfig } from './types-MKmYAYeg.mjs';
4
+ export { b as ApiError, A as AuthSession, d as InsForgeError, c as InsForgeErrorCode } from './types-MKmYAYeg.mjs';
5
5
  export { AuthErrorResponse, CreateSessionRequest, CreateUserRequest, RealtimeErrorPayload, SendRawEmailRequest as SendEmailOptions, SendEmailResponse, SocketMessage, SubscribeResponse, UserSchema } from '@insforge/shared-schemas';
6
6
  import '@supabase/postgrest-js';
7
7
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { I as InsForgeClient } from './client-DoWwzWnh.js';
2
- export { c as AI, A as Auth, C as ConnectionState, D as Database, E as Emails, f as EventCallback, d as FunctionInvokeOptions, F as Functions, H as HttpClient, L as Logger, P as Payments, e as PaymentsResponse, R as Realtime, S as Storage, a as StorageBucket, b as StorageResponse, T as TokenManager } from './client-DoWwzWnh.js';
3
- import { I as InsForgeConfig, a as InsForgeAdminConfig } from './types-NjykhyRq.js';
4
- export { b as ApiError, A as AuthSession, d as InsForgeError, c as InsForgeErrorCode } from './types-NjykhyRq.js';
1
+ import { I as InsForgeClient } from './client-DUmOm_3W.js';
2
+ export { c as AI, A as Auth, C as ConnectionState, D as Database, E as Emails, f as EventCallback, d as FunctionInvokeOptions, F as Functions, H as HttpClient, L as Logger, P as Payments, e as PaymentsResponse, R as Realtime, S as Storage, a as StorageBucket, b as StorageResponse, T as TokenManager } from './client-DUmOm_3W.js';
3
+ import { I as InsForgeConfig, a as InsForgeAdminConfig } from './types-MKmYAYeg.js';
4
+ export { b as ApiError, A as AuthSession, d as InsForgeError, c as InsForgeErrorCode } from './types-MKmYAYeg.js';
5
5
  export { AuthErrorResponse, CreateSessionRequest, CreateUserRequest, RealtimeErrorPayload, SendRawEmailRequest as SendEmailOptions, SendEmailResponse, SocketMessage, SubscribeResponse, UserSchema } from '@insforge/shared-schemas';
6
6
  import '@supabase/postgrest-js';
7
7
 
package/dist/index.js CHANGED
@@ -885,19 +885,32 @@ var HttpClient = class {
885
885
 
886
886
  // src/modules/auth/helpers.ts
887
887
  var PKCE_VERIFIER_KEY = "insforge_pkce_verifier";
888
+ async function getWebCrypto() {
889
+ const webCrypto = globalThis.crypto;
890
+ if (typeof webCrypto?.getRandomValues === "function" && webCrypto.subtle) {
891
+ return webCrypto;
892
+ }
893
+ if (typeof process !== "undefined" && process.versions?.node) {
894
+ const { webcrypto } = await import("crypto");
895
+ return webcrypto;
896
+ }
897
+ throw new Error("Web Crypto API is not available in this environment");
898
+ }
888
899
  function base64UrlEncode(buffer) {
889
900
  const base64 = btoa(String.fromCharCode(...buffer));
890
901
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
891
902
  }
892
- function generateCodeVerifier() {
903
+ async function generateCodeVerifier() {
904
+ const webCrypto = await getWebCrypto();
893
905
  const array = new Uint8Array(32);
894
- crypto.getRandomValues(array);
906
+ webCrypto.getRandomValues(array);
895
907
  return base64UrlEncode(array);
896
908
  }
897
909
  async function generateCodeChallenge(verifier) {
910
+ const webCrypto = await getWebCrypto();
898
911
  const encoder = new TextEncoder();
899
912
  const data = encoder.encode(verifier);
900
- const hash = await crypto.subtle.digest("SHA-256", data);
913
+ const hash = await webCrypto.subtle.digest("SHA-256", data);
901
914
  return base64UrlEncode(new Uint8Array(hash));
902
915
  }
903
916
  function storePkceVerifier(verifier) {
@@ -944,7 +957,7 @@ var Auth = class {
944
957
  this.http = http;
945
958
  this.tokenManager = tokenManager;
946
959
  this.options = options;
947
- this.authCallbackHandled = this.detectAuthCallback();
960
+ this.authCallbackHandled = options.detectOAuthCallback === false ? Promise.resolve() : this.detectAuthCallback();
948
961
  }
949
962
  isServerMode() {
950
963
  return !!this.options.isServerMode;
@@ -1041,10 +1054,16 @@ var Auth = class {
1041
1054
  async signOut() {
1042
1055
  try {
1043
1056
  try {
1057
+ const serverMode = this.isServerMode();
1058
+ const csrfToken = !serverMode ? getCsrfToken() : null;
1044
1059
  await this.http.post(
1045
- this.isServerMode() ? "/api/auth/logout?client_type=mobile" : "/api/auth/logout",
1060
+ serverMode ? "/api/auth/logout?client_type=mobile" : "/api/auth/logout",
1046
1061
  void 0,
1047
- { credentials: "include", skipAuthRefresh: true }
1062
+ {
1063
+ credentials: "include",
1064
+ skipAuthRefresh: true,
1065
+ ...csrfToken ? { headers: { "X-CSRF-Token": csrfToken } } : {}
1066
+ }
1048
1067
  );
1049
1068
  } catch {
1050
1069
  }
@@ -1090,7 +1109,7 @@ var Auth = class {
1090
1109
  }
1091
1110
  const { provider } = signInOptions;
1092
1111
  const providerKey = encodeURIComponent(provider.toLowerCase());
1093
- const codeVerifier = generateCodeVerifier();
1112
+ const codeVerifier = await generateCodeVerifier();
1094
1113
  const codeChallenge = await generateCodeChallenge(codeVerifier);
1095
1114
  storePkceVerifier(codeVerifier);
1096
1115
  const params = {
@@ -1450,12 +1469,30 @@ function createInsForgePostgrestFetch(httpClient) {
1450
1469
  };
1451
1470
  }
1452
1471
  var Database = class {
1453
- constructor(httpClient) {
1472
+ constructor(httpClient, defaultSchema) {
1454
1473
  this.postgrest = new import_postgrest_js.PostgrestClient("http://dummy", {
1455
1474
  fetch: createInsForgePostgrestFetch(httpClient),
1456
- headers: {}
1475
+ headers: {},
1476
+ ...defaultSchema ? { schema: defaultSchema } : {}
1457
1477
  });
1458
1478
  }
1479
+ /**
1480
+ * Select a non-default Postgres schema for the chained query. Maps to
1481
+ * PostgREST's `Accept-Profile` (reads) / `Content-Profile` (writes) header.
1482
+ * The schema must be exposed by the backend.
1483
+ *
1484
+ * @example
1485
+ * const { data } = await client.database
1486
+ * .schema('analytics')
1487
+ * .from('events')
1488
+ * .select('*');
1489
+ *
1490
+ * @example
1491
+ * await client.database.schema('analytics').rpc('rollup', { day: '2026-01-01' });
1492
+ */
1493
+ schema(schemaName) {
1494
+ return this.postgrest.schema(schemaName);
1495
+ }
1459
1496
  /**
1460
1497
  * Create a query builder for a table
1461
1498
  *
@@ -2812,9 +2849,10 @@ var InsForgeClient = class {
2812
2849
  this.tokenManager.setAccessToken(accessToken);
2813
2850
  }
2814
2851
  this.auth = new Auth(this.http, this.tokenManager, {
2815
- isServerMode: config.isServerMode ?? !!accessToken
2852
+ isServerMode: config.isServerMode ?? !!accessToken,
2853
+ detectOAuthCallback: config.auth?.detectOAuthCallback
2816
2854
  });
2817
- this.database = new Database(this.http);
2855
+ this.database = new Database(this.http, config.db?.schema);
2818
2856
  this.storage = new Storage(this.http);
2819
2857
  this.ai = new AI(this.http);
2820
2858
  this.functions = new Functions(this.http, config.functionsUrl);