@insforge/sdk 1.2.10 → 1.3.0-ssr.1

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.
@@ -0,0 +1,1121 @@
1
+ import { UserSchema, ErrorCode, 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 } from '@insforge/shared-schemas';
2
+ import * as _supabase_postgrest_js from '@supabase/postgrest-js';
3
+
4
+ /**
5
+ * InsForge SDK Types - only SDK-specific types here
6
+ * Use @insforge/shared-schemas directly for API types
7
+ */
8
+
9
+ type InsForgeErrorCode = ErrorCode | (string & {});
10
+ interface InsForgeConfig {
11
+ /**
12
+ * The base URL of the InsForge backend API
13
+ * @default "http://localhost:7130"
14
+ */
15
+ baseUrl?: string;
16
+ /**
17
+ * Anonymous API key (optional)
18
+ * Used for public/unauthenticated requests when no user token is set
19
+ */
20
+ anonKey?: string;
21
+ /**
22
+ * Edge Function Token (optional)
23
+ * Use this when running in edge functions/serverless with a user's JWT token
24
+ * This token will be used for all authenticated requests
25
+ */
26
+ edgeFunctionToken?: string;
27
+ /**
28
+ * Direct URL to Deno Subhosting functions (optional)
29
+ * When provided, SDK will try this URL first for function invocations.
30
+ * Falls back to proxy URL if subhosting returns 404.
31
+ * @example "https://{appKey}.functions.insforge.app"
32
+ */
33
+ functionsUrl?: string;
34
+ /**
35
+ * Custom fetch implementation (useful for Node.js environments)
36
+ */
37
+ fetch?: typeof fetch;
38
+ /**
39
+ * Enable server-side auth mode (SSR/Node runtime)
40
+ * In this mode auth endpoints use `client_type=mobile` and refresh_token body flow.
41
+ *
42
+ * @deprecated Use `createServerClient()`, `createBrowserClient()`, and
43
+ * `updateSession()` from `@insforge/sdk/ssr` for SSR apps.
44
+ * @default false
45
+ */
46
+ isServerMode?: boolean;
47
+ /**
48
+ * Custom headers to include with every request
49
+ */
50
+ headers?: Record<string, string>;
51
+ /**
52
+ * Enable debug logging for HTTP requests and responses.
53
+ * When true, request/response details are logged to the console.
54
+ * Can also be a custom log function for advanced use cases.
55
+ * @default false
56
+ */
57
+ debug?: boolean | ((message: string, ...args: any[]) => void);
58
+ /**
59
+ * Request timeout in milliseconds.
60
+ * Requests that exceed this duration will be aborted.
61
+ * Set to 0 to disable timeout.
62
+ * @default 30000
63
+ */
64
+ timeout?: number;
65
+ /**
66
+ * Maximum number of retry attempts for failed requests.
67
+ * Retries are triggered on network errors and server errors (5xx).
68
+ * Client errors (4xx) are never retried.
69
+ * Set to 0 to disable retries.
70
+ * @default 3
71
+ */
72
+ retryCount?: number;
73
+ /**
74
+ * Initial delay in milliseconds before the first retry.
75
+ * The delay doubles with each subsequent attempt (exponential backoff)
76
+ * with ±15% jitter to prevent thundering herd.
77
+ * @default 500
78
+ */
79
+ retryDelay?: number;
80
+ }
81
+ interface AuthSession {
82
+ user: UserSchema;
83
+ accessToken: string;
84
+ expiresAt?: Date;
85
+ }
86
+ interface AuthRefreshResponse {
87
+ user: UserSchema;
88
+ accessToken: string;
89
+ csrfToken?: string;
90
+ refreshToken?: string;
91
+ }
92
+ interface ApiError {
93
+ error: InsForgeErrorCode;
94
+ message: string;
95
+ statusCode: number;
96
+ nextActions?: string;
97
+ }
98
+ declare class InsForgeError extends Error {
99
+ statusCode: number;
100
+ error: InsForgeErrorCode;
101
+ nextActions?: string;
102
+ constructor(message: string, statusCode: number, error: InsForgeErrorCode, nextActions?: string);
103
+ static fromApiError(apiError: ApiError): InsForgeError;
104
+ }
105
+
106
+ type LogFunction = (message: string, ...args: any[]) => void;
107
+ /**
108
+ * Debug logger for the InsForge SDK.
109
+ * Logs HTTP request/response details with automatic redaction of sensitive data.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * // Enable via SDK config
114
+ * const client = new InsForgeClient({ debug: true });
115
+ *
116
+ * // Or with a custom log function
117
+ * const client = new InsForgeClient({
118
+ * debug: (msg) => myLogger.info(msg)
119
+ * });
120
+ * ```
121
+ */
122
+ declare class Logger {
123
+ /** Whether debug logging is currently enabled */
124
+ enabled: boolean;
125
+ private customLog;
126
+ /**
127
+ * Creates a new Logger instance.
128
+ * @param debug - Set to true to enable console logging, or pass a custom log function
129
+ */
130
+ constructor(debug?: boolean | LogFunction);
131
+ /**
132
+ * Logs a debug message at the info level.
133
+ * @param message - The message to log
134
+ * @param args - Additional arguments to pass to the log function
135
+ */
136
+ log(message: string, ...args: any[]): void;
137
+ /**
138
+ * Logs a debug message at the warning level.
139
+ * @param message - The message to log
140
+ * @param args - Additional arguments to pass to the log function
141
+ */
142
+ warn(message: string, ...args: any[]): void;
143
+ /**
144
+ * Logs a debug message at the error level.
145
+ * @param message - The message to log
146
+ * @param args - Additional arguments to pass to the log function
147
+ */
148
+ error(message: string, ...args: any[]): void;
149
+ /**
150
+ * Logs an outgoing HTTP request with method, URL, headers, and body.
151
+ * Sensitive headers and body fields are automatically redacted.
152
+ * @param method - HTTP method (GET, POST, etc.)
153
+ * @param url - The full request URL
154
+ * @param headers - Request headers (sensitive values will be redacted)
155
+ * @param body - Request body (sensitive fields will be masked)
156
+ */
157
+ logRequest(method: string, url: string, headers?: Record<string, string>, body?: any): void;
158
+ /**
159
+ * Logs an incoming HTTP response with method, URL, status, duration, and body.
160
+ * Error responses (4xx/5xx) are logged at the error level.
161
+ * @param method - HTTP method (GET, POST, etc.)
162
+ * @param url - The full request URL
163
+ * @param status - HTTP response status code
164
+ * @param durationMs - Request duration in milliseconds
165
+ * @param body - Response body (sensitive fields will be masked, large bodies truncated)
166
+ */
167
+ logResponse(method: string, url: string, status: number, durationMs: number, body?: any): void;
168
+ }
169
+
170
+ /**
171
+ * Token Manager for InsForge SDK
172
+ *
173
+ * Memory-only token storage.
174
+ */
175
+
176
+ declare class TokenManager {
177
+ private accessToken;
178
+ private user;
179
+ onTokenChange: (() => void) | null;
180
+ constructor();
181
+ /**
182
+ * Save session in memory
183
+ */
184
+ saveSession(session: AuthSession): void;
185
+ /**
186
+ * Get current session
187
+ */
188
+ getSession(): AuthSession | null;
189
+ /**
190
+ * Get access token
191
+ */
192
+ getAccessToken(): string | null;
193
+ /**
194
+ * Set access token
195
+ */
196
+ setAccessToken(token: string): void;
197
+ /**
198
+ * Get user
199
+ */
200
+ getUser(): UserSchema | null;
201
+ /**
202
+ * Set user
203
+ */
204
+ setUser(user: UserSchema): void;
205
+ /**
206
+ * Clear in-memory session
207
+ */
208
+ clearSession(): void;
209
+ }
210
+
211
+ type JsonRequestBody = Record<string, unknown> | unknown[] | null;
212
+ interface RequestOptions extends Omit<RequestInit, 'body'> {
213
+ params?: Record<string, string>;
214
+ body?: RequestInit['body'] | JsonRequestBody;
215
+ /** Allow retrying non-idempotent requests (POST, PATCH). Off by default to prevent duplicate writes. */
216
+ idempotent?: boolean;
217
+ /** Disable automatic access-token refresh for auth/control-flow requests. */
218
+ skipAuthRefresh?: boolean;
219
+ }
220
+ /**
221
+ * HTTP client with built-in retry, timeout, and exponential backoff support.
222
+ * Handles authentication, request serialization, and error normalization.
223
+ */
224
+ declare class HttpClient {
225
+ readonly baseUrl: string;
226
+ readonly fetch: typeof fetch;
227
+ private readonly config;
228
+ private defaultHeaders;
229
+ private anonKey;
230
+ private userToken;
231
+ private logger;
232
+ private isRefreshing;
233
+ private refreshPromise;
234
+ private tokenManager;
235
+ private refreshToken;
236
+ private timeout;
237
+ private retryCount;
238
+ private retryDelay;
239
+ /**
240
+ * Creates a new HttpClient instance.
241
+ * @param config - SDK configuration including baseUrl, timeout, retry settings, and fetch implementation.
242
+ * @param tokenManager - Token manager for session persistence.
243
+ * @param logger - Optional logger instance for request/response debugging.
244
+ */
245
+ constructor(config: InsForgeConfig, tokenManager?: TokenManager, logger?: Logger);
246
+ /**
247
+ * Builds a full URL from a path and optional query parameters.
248
+ * Normalizes PostgREST select parameters for proper syntax.
249
+ */
250
+ private buildUrl;
251
+ /** Checks if an HTTP status code is eligible for retry (5xx server errors). */
252
+ private isRetryableStatus;
253
+ /**
254
+ * Computes the delay before the next retry using exponential backoff with jitter.
255
+ * @param attempt - The current retry attempt number (1-based).
256
+ * @returns Delay in milliseconds.
257
+ */
258
+ private computeRetryDelay;
259
+ private shouldRefreshAccessToken;
260
+ private fetchWithRetry;
261
+ /**
262
+ * Performs an HTTP request with automatic retry and timeout handling.
263
+ * Retries on network errors and 5xx server errors with exponential backoff.
264
+ * Client errors (4xx) and timeouts are thrown immediately without retry.
265
+ * @param method - HTTP method (GET, POST, PUT, PATCH, DELETE).
266
+ * @param path - API path relative to the base URL.
267
+ * @param options - Optional request configuration including headers, body, and query params.
268
+ * @returns Parsed response data.
269
+ * @throws {InsForgeError} On timeout, network failure, or HTTP error responses.
270
+ */
271
+ private handleRequest;
272
+ request<T>(method: string, path: string, options?: RequestOptions): Promise<T>;
273
+ /**
274
+ * Performs an SDK-configured fetch and returns the raw Response.
275
+ * This is used by clients such as postgrest-js that need to own response
276
+ * parsing while still sharing SDK auth and refresh behavior.
277
+ */
278
+ rawFetch(input: RequestInfo | URL, init?: RequestInit, options?: {
279
+ skipAuthRefresh?: boolean;
280
+ }): Promise<Response>;
281
+ /** Performs a GET request. */
282
+ get<T>(path: string, options?: RequestOptions): Promise<T>;
283
+ /** Performs a POST request with an optional JSON body. */
284
+ post<T>(path: string, body?: any, options?: RequestOptions): Promise<T>;
285
+ /** Performs a PUT request with an optional JSON body. */
286
+ put<T>(path: string, body?: any, options?: RequestOptions): Promise<T>;
287
+ /** Performs a PATCH request with an optional JSON body. */
288
+ patch<T>(path: string, body?: any, options?: RequestOptions): Promise<T>;
289
+ /** Performs a DELETE request. */
290
+ delete<T>(path: string, options?: RequestOptions): Promise<T>;
291
+ /** Sets or clears the user authentication token for subsequent requests. */
292
+ setAuthToken(token: string | null): void;
293
+ setRefreshToken(token: string | null): void;
294
+ /** Returns the current default headers including the authorization header if set. */
295
+ getHeaders(): Record<string, string>;
296
+ refreshAccessToken(): Promise<AuthRefreshResponse>;
297
+ private refreshAndSaveSession;
298
+ private clearAuthSession;
299
+ }
300
+
301
+ /**
302
+ * Auth module for InsForge SDK
303
+ * Handles authentication, sessions, profiles, and email verification
304
+ */
305
+
306
+ interface AuthOptions {
307
+ isServerMode?: boolean;
308
+ }
309
+ declare class Auth {
310
+ private http;
311
+ private tokenManager;
312
+ private options;
313
+ private authCallbackHandled;
314
+ constructor(http: HttpClient, tokenManager: TokenManager, options?: AuthOptions);
315
+ private isServerMode;
316
+ /**
317
+ * Save session from API response
318
+ * Handles token storage, CSRF token, and HTTP auth header
319
+ */
320
+ private saveSessionFromResponse;
321
+ /**
322
+ * Detect and handle OAuth callback parameters in URL
323
+ * Supports PKCE flow (insforge_code)
324
+ */
325
+ private detectAuthCallback;
326
+ signUp(request: CreateUserRequest): Promise<{
327
+ data: CreateUserResponse | null;
328
+ error: InsForgeError | null;
329
+ }>;
330
+ signInWithPassword(request: CreateSessionRequest): Promise<{
331
+ data: CreateSessionResponse | null;
332
+ error: InsForgeError | null;
333
+ }>;
334
+ signOut(): Promise<{
335
+ error: InsForgeError | null;
336
+ }>;
337
+ /**
338
+ * Sign in with OAuth provider using PKCE flow
339
+ */
340
+ signInWithOAuth(options: {
341
+ provider: OAuthProvidersSchema | string;
342
+ redirectTo?: string;
343
+ skipBrowserRedirect?: boolean;
344
+ }): Promise<{
345
+ data: {
346
+ url?: string;
347
+ provider?: string;
348
+ codeVerifier?: string;
349
+ };
350
+ error: InsForgeError | null;
351
+ }>;
352
+ /**
353
+ * Exchange OAuth authorization code for tokens (PKCE flow)
354
+ * Called automatically on initialization when insforge_code is in URL
355
+ */
356
+ exchangeOAuthCode(code: string, codeVerifier?: string): Promise<{
357
+ data: CreateSessionResponse | null;
358
+ error: InsForgeError | null;
359
+ }>;
360
+ /**
361
+ * Sign in with an ID token from a native SDK (Google One Tap, etc.)
362
+ * Use this for native mobile apps or Google One Tap on web.
363
+ *
364
+ * @param credentials.provider - The identity provider (currently only 'google' is supported)
365
+ * @param credentials.token - The ID token from the native SDK
366
+ */
367
+ signInWithIdToken(credentials: {
368
+ provider: 'google';
369
+ token: string;
370
+ }): Promise<{
371
+ data: CreateSessionResponse | null;
372
+ error: InsForgeError | null;
373
+ }>;
374
+ /**
375
+ * Refresh the current auth session.
376
+ *
377
+ * Browser mode:
378
+ * - Uses httpOnly refresh cookie and optional CSRF header.
379
+ *
380
+ * Legacy server mode (`isServerMode: true`):
381
+ * - Uses mobile auth flow and requires `refreshToken` in request body.
382
+ *
383
+ * SSR apps should prefer `createRefreshAuthRouter()` / `refreshAuth()` from
384
+ * `@insforge/sdk/ssr`.
385
+ */
386
+ refreshSession(options?: {
387
+ refreshToken?: string;
388
+ }): Promise<{
389
+ data: RefreshSessionResponse | null;
390
+ error: InsForgeError | null;
391
+ }>;
392
+ /**
393
+ * Get current user, automatically waits for pending OAuth callback
394
+ */
395
+ getCurrentUser(): Promise<{
396
+ data: {
397
+ user: UserSchema | null;
398
+ };
399
+ error: InsForgeError | null;
400
+ }>;
401
+ getProfile(userId: string): Promise<{
402
+ data: GetProfileResponse | null;
403
+ error: InsForgeError | null;
404
+ }>;
405
+ setProfile(profile: Record<string, unknown>): Promise<{
406
+ data: GetProfileResponse | null;
407
+ error: InsForgeError | null;
408
+ }>;
409
+ resendVerificationEmail(request: SendVerificationEmailRequest): Promise<{
410
+ data: {
411
+ success: boolean;
412
+ message: string;
413
+ } | null;
414
+ error: InsForgeError | null;
415
+ }>;
416
+ verifyEmail(request: VerifyEmailRequest): Promise<{
417
+ data: VerifyEmailResponse | null;
418
+ error: InsForgeError | null;
419
+ }>;
420
+ sendResetPasswordEmail(request: SendResetPasswordEmailRequest): Promise<{
421
+ data: {
422
+ success: boolean;
423
+ message: string;
424
+ } | null;
425
+ error: InsForgeError | null;
426
+ }>;
427
+ exchangeResetPasswordToken(request: ExchangeResetPasswordTokenRequest): Promise<{
428
+ data: ExchangeResetPasswordTokenResponse | null;
429
+ error: InsForgeError | null;
430
+ }>;
431
+ resetPassword(request: {
432
+ newPassword: string;
433
+ otp: string;
434
+ }): Promise<{
435
+ data: ResetPasswordResponse | null;
436
+ error: InsForgeError | null;
437
+ }>;
438
+ getPublicAuthConfig(): Promise<{
439
+ data: GetPublicAuthConfigResponse | null;
440
+ error: InsForgeError | null;
441
+ }>;
442
+ }
443
+
444
+ /**
445
+ * Database client using postgrest-js
446
+ * Drop-in replacement with FULL PostgREST capabilities
447
+ */
448
+ declare class Database {
449
+ private postgrest;
450
+ constructor(httpClient: HttpClient);
451
+ /**
452
+ * Create a query builder for a table
453
+ *
454
+ * @example
455
+ * // Basic query
456
+ * const { data, error } = await client.database
457
+ * .from('posts')
458
+ * .select('*')
459
+ * .eq('user_id', userId);
460
+ *
461
+ * // With count (Supabase style!)
462
+ * const { data, error, count } = await client.database
463
+ * .from('posts')
464
+ * .select('*', { count: 'exact' })
465
+ * .range(0, 9);
466
+ *
467
+ * // Just get count, no data
468
+ * const { count } = await client.database
469
+ * .from('posts')
470
+ * .select('*', { count: 'exact', head: true });
471
+ *
472
+ * // Complex queries with OR
473
+ * const { data } = await client.database
474
+ * .from('posts')
475
+ * .select('*, users!inner(*)')
476
+ * .or('status.eq.active,status.eq.pending');
477
+ *
478
+ * // All features work:
479
+ * - Nested selects
480
+ * - Foreign key expansion
481
+ * - OR/AND/NOT conditions
482
+ * - Count with head
483
+ * - Range pagination
484
+ * - Upserts
485
+ */
486
+ from(table: string): _supabase_postgrest_js.PostgrestQueryBuilder<any, any, any, string, unknown>;
487
+ /**
488
+ * Call a PostgreSQL function (RPC)
489
+ *
490
+ * @example
491
+ * // Call a function with parameters
492
+ * const { data, error } = await client.database
493
+ * .rpc('get_user_stats', { user_id: 123 });
494
+ *
495
+ * // Call a function with no parameters
496
+ * const { data, error } = await client.database
497
+ * .rpc('get_all_active_users');
498
+ *
499
+ * // With options (head, count, get)
500
+ * const { data, count } = await client.database
501
+ * .rpc('search_posts', { query: 'hello' }, { count: 'exact' });
502
+ */
503
+ rpc(fn: string, args?: Record<string, unknown>, options?: {
504
+ head?: boolean;
505
+ get?: boolean;
506
+ count?: 'exact' | 'planned' | 'estimated';
507
+ }): _supabase_postgrest_js.PostgrestFilterBuilder<any, any, any, any, string, null, "RPC">;
508
+ }
509
+
510
+ /**
511
+ * Storage module for InsForge SDK
512
+ * Handles file uploads, downloads, and bucket management
513
+ */
514
+
515
+ interface StorageResponse<T> {
516
+ data: T | null;
517
+ error: InsForgeError | null;
518
+ }
519
+ /**
520
+ * Storage bucket operations
521
+ */
522
+ declare class StorageBucket {
523
+ private bucketName;
524
+ private http;
525
+ constructor(bucketName: string, http: HttpClient);
526
+ /**
527
+ * Upload a file with a specific key
528
+ * Uses the upload strategy from backend (direct or presigned)
529
+ * @param path - The object key/path
530
+ * @param file - File or Blob to upload
531
+ */
532
+ upload(path: string, file: File | Blob): Promise<StorageResponse<StorageFileSchema>>;
533
+ /**
534
+ * Upload a file with auto-generated key
535
+ * Uses the upload strategy from backend (direct or presigned)
536
+ * @param file - File or Blob to upload
537
+ */
538
+ uploadAuto(file: File | Blob): Promise<StorageResponse<StorageFileSchema>>;
539
+ /**
540
+ * Internal method to handle presigned URL uploads
541
+ */
542
+ private uploadWithPresignedUrl;
543
+ /**
544
+ * Download a file
545
+ * Uses the download strategy from backend (direct or presigned)
546
+ * @param path - The object key/path
547
+ * Returns the file as a Blob
548
+ */
549
+ download(path: string): Promise<{
550
+ data: Blob | null;
551
+ error: InsForgeError | null;
552
+ }>;
553
+ /**
554
+ * Get public URL for a file
555
+ * @param path - The object key/path
556
+ */
557
+ getPublicUrl(path: string): string;
558
+ /**
559
+ * List objects in the bucket
560
+ * @param prefix - Filter by key prefix
561
+ * @param search - Search in file names
562
+ * @param limit - Maximum number of results (default: 100, max: 1000)
563
+ * @param offset - Number of results to skip
564
+ */
565
+ list(options?: {
566
+ prefix?: string;
567
+ search?: string;
568
+ limit?: number;
569
+ offset?: number;
570
+ }): Promise<StorageResponse<ListObjectsResponseSchema>>;
571
+ /**
572
+ * Delete a file
573
+ * @param path - The object key/path
574
+ */
575
+ remove(path: string): Promise<StorageResponse<{
576
+ message: string;
577
+ }>>;
578
+ }
579
+ /**
580
+ * Storage module for file operations
581
+ */
582
+ declare class Storage {
583
+ private http;
584
+ constructor(http: HttpClient);
585
+ /**
586
+ * Get a bucket instance for operations
587
+ * @param bucketName - Name of the bucket
588
+ */
589
+ from(bucketName: string): StorageBucket;
590
+ }
591
+
592
+ /**
593
+ * AI Module for Insforge SDK
594
+ * Response format roughly matches OpenAI SDK for compatibility
595
+ *
596
+ * The backend handles all the complexity of different AI providers
597
+ * and returns a unified format. This SDK transforms responses to match OpenAI-like format.
598
+ */
599
+
600
+ declare class AI {
601
+ private http;
602
+ readonly chat: Chat;
603
+ readonly images: Images;
604
+ readonly embeddings: Embeddings;
605
+ constructor(http: HttpClient);
606
+ }
607
+ declare class Chat {
608
+ readonly completions: ChatCompletions;
609
+ constructor(http: HttpClient);
610
+ }
611
+ declare class ChatCompletions {
612
+ private http;
613
+ constructor(http: HttpClient);
614
+ /**
615
+ * Create a chat completion - OpenAI-like response format
616
+ *
617
+ * @example
618
+ * ```typescript
619
+ * // Non-streaming
620
+ * const completion = await client.ai.chat.completions.create({
621
+ * model: 'gpt-4',
622
+ * messages: [{ role: 'user', content: 'Hello!' }]
623
+ * });
624
+ * console.log(completion.choices[0].message.content);
625
+ *
626
+ * // With images (OpenAI-compatible format)
627
+ * const response = await client.ai.chat.completions.create({
628
+ * model: 'gpt-4-vision',
629
+ * messages: [{
630
+ * role: 'user',
631
+ * content: [
632
+ * { type: 'text', text: 'What is in this image?' },
633
+ * { type: 'image_url', image_url: { url: 'https://example.com/image.jpg' } }
634
+ * ]
635
+ * }]
636
+ * });
637
+ *
638
+ * // With PDF files
639
+ * const pdfResponse = await client.ai.chat.completions.create({
640
+ * model: 'anthropic/claude-3.5-sonnet',
641
+ * messages: [{
642
+ * role: 'user',
643
+ * content: [
644
+ * { type: 'text', text: 'Summarize this document' },
645
+ * { type: 'file', file: { filename: 'doc.pdf', file_data: 'https://example.com/doc.pdf' } }
646
+ * ]
647
+ * }],
648
+ * fileParser: { enabled: true, pdf: { engine: 'mistral-ocr' } }
649
+ * });
650
+ *
651
+ * // With web search
652
+ * const searchResponse = await client.ai.chat.completions.create({
653
+ * model: 'openai/gpt-4',
654
+ * messages: [{ role: 'user', content: 'What are the latest news about AI?' }],
655
+ * webSearch: { enabled: true, maxResults: 5 }
656
+ * });
657
+ * // Access citations from response.choices[0].message.annotations
658
+ *
659
+ * // With thinking/reasoning mode (Anthropic models)
660
+ * const thinkingResponse = await client.ai.chat.completions.create({
661
+ * model: 'anthropic/claude-3.5-sonnet',
662
+ * messages: [{ role: 'user', content: 'Solve this complex math problem...' }],
663
+ * thinking: true
664
+ * });
665
+ *
666
+ * // Streaming - returns async iterable
667
+ * const stream = await client.ai.chat.completions.create({
668
+ * model: 'gpt-4',
669
+ * messages: [{ role: 'user', content: 'Tell me a story' }],
670
+ * stream: true
671
+ * });
672
+ *
673
+ * for await (const chunk of stream) {
674
+ * if (chunk.choices[0]?.delta?.content) {
675
+ * process.stdout.write(chunk.choices[0].delta.content);
676
+ * }
677
+ * }
678
+ * ```
679
+ */
680
+ create(params: ChatCompletionRequest): Promise<any>;
681
+ /**
682
+ * Parse SSE stream into async iterable of OpenAI-like chunks
683
+ */
684
+ private parseSSEStream;
685
+ }
686
+ declare class Embeddings {
687
+ private http;
688
+ constructor(http: HttpClient);
689
+ /**
690
+ * Create embeddings for text input - OpenAI-like response format
691
+ *
692
+ * @example
693
+ * ```typescript
694
+ * // Single text input
695
+ * const response = await client.ai.embeddings.create({
696
+ * model: 'openai/text-embedding-3-small',
697
+ * input: 'Hello world'
698
+ * });
699
+ * console.log(response.data[0].embedding); // number[]
700
+ *
701
+ * // Multiple text inputs
702
+ * const response = await client.ai.embeddings.create({
703
+ * model: 'openai/text-embedding-3-small',
704
+ * input: ['Hello world', 'Goodbye world']
705
+ * });
706
+ * response.data.forEach((item, i) => {
707
+ * console.log(`Embedding ${i}:`, item.embedding.slice(0, 5)); // First 5 dimensions
708
+ * });
709
+ *
710
+ * // With custom dimensions (if supported by model)
711
+ * const response = await client.ai.embeddings.create({
712
+ * model: 'openai/text-embedding-3-small',
713
+ * input: 'Hello world',
714
+ * dimensions: 256
715
+ * });
716
+ *
717
+ * // With base64 encoding format
718
+ * const response = await client.ai.embeddings.create({
719
+ * model: 'openai/text-embedding-3-small',
720
+ * input: 'Hello world',
721
+ * encoding_format: 'base64'
722
+ * });
723
+ * ```
724
+ */
725
+ create(params: EmbeddingsRequest): Promise<any>;
726
+ }
727
+ declare class Images {
728
+ private http;
729
+ constructor(http: HttpClient);
730
+ /**
731
+ * Generate images - OpenAI-like response format
732
+ *
733
+ * @example
734
+ * ```typescript
735
+ * // Text-to-image
736
+ * const response = await client.ai.images.generate({
737
+ * model: 'dall-e-3',
738
+ * prompt: 'A sunset over mountains',
739
+ * });
740
+ * console.log(response.images[0].url);
741
+ *
742
+ * // Image-to-image (with input images)
743
+ * const response = await client.ai.images.generate({
744
+ * model: 'stable-diffusion-xl',
745
+ * prompt: 'Transform this into a watercolor painting',
746
+ * images: [
747
+ * { url: 'https://example.com/input.jpg' },
748
+ * // or base64-encoded Data URI:
749
+ * { url: 'data:image/jpeg;base64,/9j/4AAQ...' }
750
+ * ]
751
+ * });
752
+ * ```
753
+ */
754
+ generate(params: ImageGenerationRequest): Promise<any>;
755
+ }
756
+
757
+ interface FunctionInvokeOptions {
758
+ /**
759
+ * The body of the request
760
+ */
761
+ body?: any;
762
+ /**
763
+ * Custom headers to send with the request
764
+ */
765
+ headers?: Record<string, string>;
766
+ /**
767
+ * HTTP method (default: POST)
768
+ */
769
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
770
+ }
771
+ /**
772
+ * Edge Functions client for invoking serverless functions.
773
+ *
774
+ * @example
775
+ * ```typescript
776
+ * const { data, error } = await client.functions.invoke('hello-world', {
777
+ * body: { name: 'World' }
778
+ * });
779
+ * ```
780
+ */
781
+ declare class Functions {
782
+ private http;
783
+ private functionsUrl;
784
+ constructor(http: HttpClient, functionsUrl?: string);
785
+ /**
786
+ * Derive the subhosting URL from the base URL.
787
+ * Base URL pattern: https://{appKey}.{region}.insforge.app
788
+ * Functions URL: https://{appKey}.functions.insforge.app
789
+ * Only applies to .insforge.app domains.
790
+ */
791
+ private static deriveSubhostingUrl;
792
+ /**
793
+ * Build a Request for in-process dispatch. The host is a non-routable
794
+ * placeholder; the router only reads pathname.
795
+ */
796
+ private buildInProcessRequest;
797
+ /**
798
+ * Invoke an Edge Function.
799
+ *
800
+ * Dispatch order:
801
+ * 1. If `globalThis.__insforge_dispatch__` is present, call it in-process.
802
+ * This avoids Deno Subhosting's 508 Loop Detected when one bundled
803
+ * function invokes another inside the same deployment.
804
+ * 2. Otherwise, try the configured subhosting URL.
805
+ * 3. On 404 from subhosting, fall back to the proxy path.
806
+ *
807
+ * @param slug The function slug to invoke
808
+ * @param options Request options
809
+ */
810
+ invoke<T = any>(slug: string, options?: FunctionInvokeOptions): Promise<{
811
+ data: T | null;
812
+ error: InsForgeError | null;
813
+ }>;
814
+ }
815
+
816
+ type ConnectionState = 'disconnected' | 'connecting' | 'connected';
817
+ type EventCallback<T = unknown> = (payload: T) => void;
818
+ /**
819
+ * Realtime module for subscribing to channels and handling real-time events
820
+ *
821
+ * @example
822
+ * ```typescript
823
+ * const { realtime } = client;
824
+ *
825
+ * // Connect to the realtime server
826
+ * await realtime.connect();
827
+ *
828
+ * // Subscribe to a channel
829
+ * const response = await realtime.subscribe('orders:123');
830
+ * if (!response.ok) {
831
+ * console.error('Failed to subscribe:', response.error);
832
+ * }
833
+ *
834
+ * // Listen for specific events
835
+ * realtime.on('order_updated', (payload) => {
836
+ * console.log('Order updated:', payload);
837
+ * });
838
+ *
839
+ * // Listen for connection events
840
+ * realtime.on('connect', () => console.log('Connected!'));
841
+ * realtime.on('connect_error', (err) => console.error('Connection failed:', err));
842
+ * realtime.on('disconnect', (reason) => console.log('Disconnected:', reason));
843
+ * realtime.on('error', (error) => console.error('Realtime error:', error));
844
+ *
845
+ * // Publish a message to a channel
846
+ * await realtime.publish('orders:123', 'status_changed', { status: 'shipped' });
847
+ *
848
+ * // Unsubscribe and disconnect when done
849
+ * realtime.unsubscribe('orders:123');
850
+ * realtime.disconnect();
851
+ * ```
852
+ */
853
+ declare class Realtime {
854
+ private baseUrl;
855
+ private tokenManager;
856
+ private socket;
857
+ private connectPromise;
858
+ private subscribedChannels;
859
+ private eventListeners;
860
+ private anonKey?;
861
+ constructor(baseUrl: string, tokenManager: TokenManager, anonKey?: string);
862
+ private notifyListeners;
863
+ /**
864
+ * Connect to the realtime server
865
+ * @returns Promise that resolves when connected
866
+ */
867
+ connect(): Promise<void>;
868
+ /**
869
+ * Disconnect from the realtime server
870
+ */
871
+ disconnect(): void;
872
+ /**
873
+ * Handle token changes (e.g., after auth refresh)
874
+ * Updates socket auth so reconnects use the new token
875
+ * If connected, triggers reconnect to apply new token immediately
876
+ */
877
+ private onTokenChange;
878
+ /**
879
+ * Check if connected to the realtime server
880
+ */
881
+ get isConnected(): boolean;
882
+ /**
883
+ * Get the current connection state
884
+ */
885
+ get connectionState(): ConnectionState;
886
+ /**
887
+ * Get the socket ID (if connected)
888
+ */
889
+ get socketId(): string | undefined;
890
+ /**
891
+ * Subscribe to a channel
892
+ *
893
+ * Automatically connects if not already connected.
894
+ *
895
+ * @param channel - Channel name (e.g., 'orders:123', 'broadcast')
896
+ * @returns Promise with the subscription response
897
+ */
898
+ subscribe(channel: string): Promise<SubscribeResponse>;
899
+ /**
900
+ * Unsubscribe from a channel (fire-and-forget)
901
+ *
902
+ * @param channel - Channel name to unsubscribe from
903
+ */
904
+ unsubscribe(channel: string): void;
905
+ /**
906
+ * Publish a message to a channel
907
+ *
908
+ * @param channel - Channel name
909
+ * @param event - Event name
910
+ * @param payload - Message payload
911
+ */
912
+ publish<T = unknown>(channel: string, event: string, payload: T): Promise<void>;
913
+ /**
914
+ * Listen for events
915
+ *
916
+ * Reserved event names:
917
+ * - 'connect' - Fired when connected to the server
918
+ * - 'connect_error' - Fired when connection fails (payload: Error)
919
+ * - 'disconnect' - Fired when disconnected (payload: reason string)
920
+ * - 'error' - Fired when a realtime error occurs (payload: RealtimeErrorPayload)
921
+ *
922
+ * All other events receive a `SocketMessage` payload with metadata.
923
+ *
924
+ * @param event - Event name to listen for
925
+ * @param callback - Callback function when event is received
926
+ */
927
+ on<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
928
+ /**
929
+ * Remove a listener for a specific event
930
+ *
931
+ * @param event - Event name
932
+ * @param callback - The callback function to remove
933
+ */
934
+ off<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
935
+ /**
936
+ * Listen for an event only once, then automatically remove the listener
937
+ *
938
+ * @param event - Event name to listen for
939
+ * @param callback - Callback function when event is received
940
+ */
941
+ once<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
942
+ /**
943
+ * Get all currently subscribed channels
944
+ *
945
+ * @returns Array of channel names
946
+ */
947
+ getSubscribedChannels(): string[];
948
+ }
949
+
950
+ /**
951
+ * Emails client for sending custom emails
952
+ *
953
+ * @example
954
+ * ```typescript
955
+ * // Send a simple email
956
+ * const { data, error } = await client.emails.send({
957
+ * to: 'user@example.com',
958
+ * subject: 'Welcome!',
959
+ * html: '<h1>Welcome to our platform</h1>'
960
+ * });
961
+ *
962
+ * if (error) {
963
+ * console.error('Failed to send:', error.message);
964
+ * return;
965
+ * }
966
+ * // Email sent successfully - data is {} (empty object)
967
+ *
968
+ * // Send to multiple recipients with CC
969
+ * const { data, error } = await client.emails.send({
970
+ * to: ['user1@example.com', 'user2@example.com'],
971
+ * cc: 'manager@example.com',
972
+ * subject: 'Team Update',
973
+ * html: '<p>Here is the latest update...</p>',
974
+ * replyTo: 'support@example.com'
975
+ * });
976
+ * ```
977
+ */
978
+ declare class Emails {
979
+ private http;
980
+ constructor(http: HttpClient);
981
+ /**
982
+ * Send a custom HTML email
983
+ * @param options Email options including recipients, subject, and HTML content
984
+ */
985
+ send(options: SendRawEmailRequest): Promise<{
986
+ data: SendEmailResponse | null;
987
+ error: InsForgeError | null;
988
+ }>;
989
+ }
990
+
991
+ interface PaymentsResponse<T> {
992
+ data: T | null;
993
+ error: InsForgeError | null;
994
+ }
995
+ /**
996
+ * Payments client for runtime Stripe payment flows.
997
+ *
998
+ * These methods are safe to call from generated app frontends with the current
999
+ * user token or anon key. Admin-only Stripe key/catalog APIs are intentionally
1000
+ * not exposed here.
1001
+ */
1002
+ declare class Payments {
1003
+ private http;
1004
+ constructor(http: HttpClient);
1005
+ /**
1006
+ * Create a Stripe Checkout Session through the InsForge backend.
1007
+ *
1008
+ * @example
1009
+ * ```typescript
1010
+ * const { data, error } = await client.payments.createCheckoutSession('test', {
1011
+ * mode: 'payment',
1012
+ * lineItems: [{ stripePriceId: 'price_123', quantity: 1 }],
1013
+ * successUrl: `${window.location.origin}/success`,
1014
+ * cancelUrl: `${window.location.origin}/pricing`
1015
+ * });
1016
+ *
1017
+ * if (!error && data.checkoutSession.url) {
1018
+ * window.location.assign(data.checkoutSession.url);
1019
+ * }
1020
+ * ```
1021
+ */
1022
+ createCheckoutSession(environment: StripeEnvironment, request: CreateCheckoutSessionBody): Promise<PaymentsResponse<CreateCheckoutSessionResponse>>;
1023
+ /**
1024
+ * Create a Stripe Billing Portal Session for a mapped billing subject.
1025
+ */
1026
+ createCustomerPortalSession(environment: StripeEnvironment, request: CreateCustomerPortalSessionBody): Promise<PaymentsResponse<CreateCustomerPortalSessionResponse>>;
1027
+ }
1028
+
1029
+ /**
1030
+ * Main InsForge SDK Client
1031
+ *
1032
+ * @example
1033
+ * ```typescript
1034
+ * import { InsForgeClient } from '@insforge/sdk';
1035
+ *
1036
+ * const client = new InsForgeClient({
1037
+ * baseUrl: 'http://localhost:7130'
1038
+ * });
1039
+ *
1040
+ * // Authentication
1041
+ * const { data, error } = await client.auth.signUp({
1042
+ * email: 'user@example.com',
1043
+ * password: 'password123',
1044
+ * name: 'John Doe'
1045
+ * });
1046
+ *
1047
+ * // Database operations
1048
+ * const { data, error } = await client.database
1049
+ * .from('posts')
1050
+ * .select('*')
1051
+ * .eq('user_id', session.user.id)
1052
+ * .order('created_at', { ascending: false })
1053
+ * .limit(10);
1054
+ *
1055
+ * // Insert data
1056
+ * const { data: newPost } = await client.database
1057
+ * .from('posts')
1058
+ * .insert({ title: 'Hello', content: 'World' })
1059
+ * .single();
1060
+ *
1061
+ * // Invoke edge functions
1062
+ * const { data, error } = await client.functions.invoke('my-function', {
1063
+ * body: { message: 'Hello from SDK' }
1064
+ * });
1065
+ *
1066
+ * // Enable debug logging
1067
+ * const debugClient = new InsForgeClient({
1068
+ * baseUrl: 'http://localhost:7130',
1069
+ * debug: true
1070
+ * });
1071
+ * ```
1072
+ */
1073
+ declare class InsForgeClient {
1074
+ private http;
1075
+ private tokenManager;
1076
+ readonly auth: Auth;
1077
+ readonly database: Database;
1078
+ readonly storage: Storage;
1079
+ readonly ai: AI;
1080
+ readonly functions: Functions;
1081
+ readonly realtime: Realtime;
1082
+ readonly emails: Emails;
1083
+ readonly payments: Payments;
1084
+ constructor(config?: InsForgeConfig);
1085
+ /**
1086
+ * Get the underlying HTTP client for custom requests
1087
+ *
1088
+ * @example
1089
+ * ```typescript
1090
+ * const httpClient = client.getHttpClient();
1091
+ * const customData = await httpClient.get('/api/custom-endpoint');
1092
+ * ```
1093
+ */
1094
+ getHttpClient(): HttpClient;
1095
+ /**
1096
+ * Set the access token used by every SDK surface. Updates both the HTTP
1097
+ * client (database / storage / functions / AI / emails) and the realtime
1098
+ * token manager (which fires `onTokenChange` to reconnect the WebSocket
1099
+ * with the new bearer). Pass `null` to clear.
1100
+ *
1101
+ * Use this when an external auth provider (Better Auth, Clerk, Auth0,
1102
+ * WorkOS, Kinde, Stytch, …) issues the JWT and you need to keep the
1103
+ * long-lived InsForge client in sync. Without this, you'd have to call
1104
+ * `client.getHttpClient().setAuthToken(token)` AND reach into the private
1105
+ * `client.realtime.tokenManager.setAccessToken(token)` separately —
1106
+ * forgetting the second one silently breaks realtime auth.
1107
+ *
1108
+ * @example
1109
+ * ```typescript
1110
+ * // Refresh a third-party-issued JWT periodically
1111
+ * const { token } = await fetch('/api/insforge-token').then((r) => r.json());
1112
+ * client.setAccessToken(token);
1113
+ *
1114
+ * // Sign-out
1115
+ * client.setAccessToken(null);
1116
+ * ```
1117
+ */
1118
+ setAccessToken(token: string | null): void;
1119
+ }
1120
+
1121
+ export { type AuthSession as A, type ConnectionState as C, Database as D, Emails as E, Functions as F, HttpClient as H, InsForgeClient as I, Logger as L, Payments as P, Realtime as R, Storage as S, TokenManager as T, type InsForgeConfig as a, type ApiError as b, type InsForgeErrorCode as c, InsForgeError as d, Auth as e, StorageBucket as f, type StorageResponse as g, AI as h, type FunctionInvokeOptions as i, type PaymentsResponse as j, type EventCallback as k, type AuthRefreshResponse as l };