@resultdev/sdk 0.2.0 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # @resultdev/sdk
2
2
 
3
+ ## 0.3.1
4
+
5
+ - A missing `baseUrl` now throws `MISSING_BASE_URL` at client construction
6
+ instead of silently falling back to a localhost dev URL. The fallback made
7
+ deployed sites whose `NEXT_PUBLIC_BACKEND_URL` was undefined in the
8
+ browser bundle (for example when the env var is read through an imported
9
+ `process` module, which defeats build-time inlining) call `localhost` from
10
+ production pages, which surfaced as Chrome's "access other apps and
11
+ services on this device" permission prompt. The error's fix hint names the
12
+ env var and the inlining rule.
13
+
14
+ ## 0.3.0
15
+
16
+ Reliability release: every fix here comes from live verification against a
17
+ freshly provisioned backend.
18
+
19
+ - Functions: `invoke()` now goes through the main host's `/functions/{slug}`
20
+ route by default. The legacy subhosting fast-path was retired upstream and
21
+ broke browser calls entirely (its preflight 404s surfaced as
22
+ `TypeError: Failed to fetch`). The main route works from browsers with
23
+ correct CORS. In-process dispatch inside deployments is unchanged, and an
24
+ explicit `functionsUrl` is still honored (now with fallback to the main
25
+ route on network failure, not just 404).
26
+ - Realtime: incoming `meta.channel` had a transport prefix
27
+ (`realtime:chat:1` for a subscription to `chat:1`), so the natural
28
+ `msg.meta.channel === channel` filter silently dropped every message. The
29
+ SDK now strips the prefix before delivery; presence join/leave tracking is
30
+ fixed by the same change.
31
+ - Realtime docs: payload fields arrive spread onto the message (not under a
32
+ `payload` key), and the sender receives its own broadcast; dedupe with
33
+ `meta.messageId`.
34
+ - AI: streaming responses now surface web-search/file citations
35
+ (`chunk.choices[0].delta.annotations`, trailing chunk) and token usage
36
+ (`chunk.usage`). Both were silently dropped before.
37
+ - AI: deterministic bad requests fail fast with specific errors instead of
38
+ an opaque upstream 4xx after a round trip: unsupported audio formats
39
+ (browser MediaRecorder webm/opus included) and audio input on `openai/*`
40
+ models. Upstream provider errors on image/audio requests now name
41
+ `google/gemini-2.5-flash` as the verified multimodal model.
42
+ - Docs: session model documented on `auth` (httpOnly cookie + in-memory
43
+ token; localStorage is empty by design), verified model names in every AI
44
+ example, return shapes clarified across modules.
45
+
3
46
  ## 0.2.0
4
47
 
5
48
  The SDK is now built fully first-party instead of wrapping a bundled
@@ -1,4 +1,4 @@
1
- import { e as AuthSession, U as UserSchema, a as ResultConfig, G as AuthRefreshResponse, C as ChatCompletionRequest, B as ToolCall, H as Annotation, I as ImageGenerationRequest, j as EmbeddingsRequest, J as EmbeddingObject, h as CreateUserRequest, K as CreateUserResponse, o as ResultError, g as CreateSessionRequest, L as CreateSessionResponse, l as OAuthProvidersSchema, M as RefreshSessionResponse, N as GetProfileResponse, Q as SendVerificationEmailRequest, V as VerifyEmailRequest, W as VerifyEmailResponse, X as SendResetPasswordEmailRequest, Y as ExchangeResetPasswordTokenRequest, Z as ExchangeResetPasswordTokenResponse, _ as ResetPasswordResponse, $ as GetPublicAuthConfigResponse, S as SendRawEmailRequest, q as SendEmailResponse, v as SubscribeResponse, r as SocketMessage, P as PresenceMember, u as StorageFileSchema, a0 as ListObjectsResponseSchema, i as DeleteObjectsResponse, A as Analytics, w as Support } from './types-CbsaMttt.cjs';
1
+ import { e as AuthSession, U as UserSchema, a as ResultConfig, G as AuthRefreshResponse, C as ChatCompletionRequest, B as ToolCall, H as Annotation, I as ImageGenerationRequest, j as EmbeddingsRequest, J as EmbeddingObject, h as CreateUserRequest, K as CreateUserResponse, o as ResultError, g as CreateSessionRequest, L as CreateSessionResponse, l as OAuthProvidersSchema, M as RefreshSessionResponse, N as GetProfileResponse, Q as SendVerificationEmailRequest, V as VerifyEmailRequest, W as VerifyEmailResponse, X as SendResetPasswordEmailRequest, Y as ExchangeResetPasswordTokenRequest, Z as ExchangeResetPasswordTokenResponse, _ as ResetPasswordResponse, $ as GetPublicAuthConfigResponse, S as SendRawEmailRequest, q as SendEmailResponse, v as SubscribeResponse, r as SocketMessage, P as PresenceMember, u as StorageFileSchema, a0 as ListObjectsResponseSchema, i as DeleteObjectsResponse, A as Analytics, w as Support } from './types-BmU3deRO.js';
2
2
  import * as _supabase_postgrest_js from '@supabase/postgrest-js';
3
3
  import { PostgrestClient } from '@supabase/postgrest-js';
4
4
 
@@ -248,9 +248,13 @@ interface ChatCompletionChunk {
248
248
  delta: {
249
249
  content?: string;
250
250
  tool_calls?: ToolCall[];
251
+ /** Web-search/file citations; arrives in a trailing chunk. */
252
+ annotations?: Annotation[];
251
253
  };
252
254
  finish_reason: "tool_calls" | null;
253
255
  }[];
256
+ /** Token usage; arrives in a trailing chunk with empty choices. */
257
+ usage?: ChatCompletionUsage;
254
258
  }
255
259
  interface EmbeddingsResult {
256
260
  object: "list";
@@ -293,14 +297,16 @@ declare class ChatCompletions {
293
297
  * ```typescript
294
298
  * // Non-streaming
295
299
  * const completion = await client.ai.chat.completions.create({
296
- * model: 'gpt-4',
300
+ * model: 'openai/gpt-4o-mini',
297
301
  * messages: [{ role: 'user', content: 'Hello!' }]
298
302
  * });
299
303
  * console.log(completion.choices[0].message.content);
300
304
  *
301
- * // With images (OpenAI-compatible format)
305
+ * // With images. google/gemini-2.5-flash is the verified multimodal
306
+ * // model (openai/gpt-4o and gpt-4o-mini also accept images, but audio
307
+ * // requires gemini). URLs and base64 data URIs both work.
302
308
  * const response = await client.ai.chat.completions.create({
303
- * model: 'gpt-4-vision',
309
+ * model: 'google/gemini-2.5-flash',
304
310
  * messages: [{
305
311
  * role: 'user',
306
312
  * content: [
@@ -310,37 +316,32 @@ declare class ChatCompletions {
310
316
  * }]
311
317
  * });
312
318
  *
313
- * // With PDF files
314
- * const pdfResponse = await client.ai.chat.completions.create({
315
- * model: 'anthropic/claude-3.5-sonnet',
319
+ * // With audio. Base64 data in wav/mp3/aiff/aac/ogg/flac/m4a only -
320
+ * // browser MediaRecorder's webm/opus is rejected; record PCM via the
321
+ * // Web Audio API and encode a 16 kHz mono WAV instead.
322
+ * const audioResponse = await client.ai.chat.completions.create({
323
+ * model: 'google/gemini-2.5-flash',
316
324
  * messages: [{
317
325
  * role: 'user',
318
326
  * content: [
319
- * { type: 'text', text: 'Summarize this document' },
320
- * { type: 'file', file: { filename: 'doc.pdf', file_data: 'https://example.com/doc.pdf' } }
327
+ * { type: 'text', text: 'Transcribe this recording' },
328
+ * { type: 'input_audio', input_audio: { data: base64Wav, format: 'wav' } }
321
329
  * ]
322
- * }],
323
- * fileParser: { enabled: true, pdf: { engine: 'mistral-ocr' } }
330
+ * }]
324
331
  * });
325
332
  *
326
- * // With web search
333
+ * // With web search. Non-streaming: citations arrive on
334
+ * // response.choices[0].message.annotations. Streaming: they arrive in a
335
+ * // trailing chunk as chunk.choices[0].delta.annotations.
327
336
  * const searchResponse = await client.ai.chat.completions.create({
328
- * model: 'openai/gpt-4',
337
+ * model: 'openai/gpt-4o-mini',
329
338
  * messages: [{ role: 'user', content: 'What are the latest news about AI?' }],
330
339
  * webSearch: { enabled: true, maxResults: 5 }
331
340
  * });
332
- * // Access citations from response.choices[0].message.annotations
333
- *
334
- * // With thinking/reasoning mode (Anthropic models)
335
- * const thinkingResponse = await client.ai.chat.completions.create({
336
- * model: 'anthropic/claude-3.5-sonnet',
337
- * messages: [{ role: 'user', content: 'Solve this complex math problem...' }],
338
- * thinking: true
339
- * });
340
341
  *
341
342
  * // Streaming - returns async iterable
342
343
  * const stream = await client.ai.chat.completions.create({
343
- * model: 'gpt-4',
344
+ * model: 'openai/gpt-4o-mini',
344
345
  * messages: [{ role: 'user', content: 'Tell me a story' }],
345
346
  * stream: true
346
347
  * });
@@ -452,6 +453,16 @@ type OAuthSignInOptions = {
452
453
  type OAuthSignInLegacyOptions = OAuthSignInOptions & {
453
454
  provider: OAuthProvidersSchema | string;
454
455
  };
456
+ /**
457
+ * Authentication client.
458
+ *
459
+ * Session model: the refresh token lives in an httpOnly cookie set by the
460
+ * backend (plus a CSRF cookie); the access token is held in memory and
461
+ * refreshed from that cookie. Nothing auth-related is written to
462
+ * localStorage, so an empty localStorage does NOT mean the user is signed
463
+ * out. Check state with getCurrentUser() or onAuthStateChange(), never by
464
+ * reading browser storage.
465
+ */
455
466
  declare class Auth {
456
467
  private http;
457
468
  private tokenManager;
@@ -748,10 +759,10 @@ declare class Functions {
748
759
  private functionsUrl;
749
760
  constructor(http: HttpClient, functionsUrl?: string);
750
761
  /**
751
- * Derive the subhosting URL from the base URL.
752
- * Rewrites the backend base URL to its functions subhosting URL
762
+ * Derive the legacy subhosting URL from the base URL
753
763
  * ({appKey}.{region}.<domain> -> {appKey}.functions.<domain>).
754
- * Only applies to platform-hosted backends.
764
+ * Only used to recognize when a configured functionsUrl still points at
765
+ * the local deployment, so in-process dispatch can short-circuit it.
755
766
  */
756
767
  private static deriveSubhostingUrl;
757
768
  /**
@@ -763,11 +774,13 @@ declare class Functions {
763
774
  * Invoke an Edge Function.
764
775
  *
765
776
  * Dispatch order:
766
- * 1. If the platform's in-process dispatch hook is present, call it directly.
767
- * This avoids Deno Subhosting's 508 Loop Detected when one bundled
768
- * function invokes another inside the same deployment.
769
- * 2. Otherwise, try the configured subhosting URL.
770
- * 3. On 404 from subhosting, fall back to the proxy path.
777
+ * 1. If the platform's in-process dispatch hook is present and no foreign
778
+ * functionsUrl is configured, call it directly (function-to-function
779
+ * calls inside the same deployment).
780
+ * 2. If a custom functionsUrl is configured, try it; fall back to the
781
+ * proxy path on 404 or network failure.
782
+ * 3. Otherwise, invoke through the main host's /functions/{slug} proxy.
783
+ * This route works from browsers too (correct CORS).
771
784
  *
772
785
  * @param slug The function slug to invoke
773
786
  * @param options Request options
@@ -811,7 +824,24 @@ declare class Realtime {
811
824
  get socketId(): string | undefined;
812
825
  subscribe(channel: string): Promise<SubscribeResponse>;
813
826
  unsubscribe(channel: string): void;
827
+ /**
828
+ * Publish an event to a channel.
829
+ *
830
+ * Delivery notes (verified against a live backend):
831
+ * - Payload fields arrive spread onto the received message itself, next to
832
+ * `meta` - not nested under a `payload` key. Publishing `{ text: "hi" }`
833
+ * means receivers read `msg.text`.
834
+ * - The sender receives its own message too. Deduplicate with
835
+ * `msg.meta.messageId` (or `msg.meta.senderId`) if you also update local
836
+ * state optimistically.
837
+ */
814
838
  publish<T = unknown>(channel: string, event: string, payload: T): Promise<void>;
839
+ /**
840
+ * Listen for an event by name, across all subscribed channels.
841
+ * Filter by channel inside the callback: `msg.meta.channel` always matches
842
+ * the exact name passed to subscribe() (the SDK strips the server's
843
+ * transport prefix before delivery).
844
+ */
815
845
  on<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
816
846
  off<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
817
847
  once<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
@@ -966,7 +996,7 @@ type AccessTokenChangeEvent = typeof AuthChangeEvent.SIGNED_IN | typeof AuthChan
966
996
  * import { ResultClient } from '@resultdev/sdk';
967
997
  *
968
998
  * const client = new ResultClient({
969
- * baseUrl: 'http://localhost:7130'
999
+ * baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!
970
1000
  * });
971
1001
  *
972
1002
  * // Authentication
@@ -997,7 +1027,7 @@ type AccessTokenChangeEvent = typeof AuthChangeEvent.SIGNED_IN | typeof AuthChan
997
1027
  *
998
1028
  * // Enable debug logging
999
1029
  * const debugClient = new ResultClient({
1000
- * baseUrl: 'http://localhost:7130',
1030
+ * baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!,
1001
1031
  * debug: true
1002
1032
  * });
1003
1033
  * ```
@@ -1,4 +1,4 @@
1
- import { e as AuthSession, U as UserSchema, a as ResultConfig, G as AuthRefreshResponse, C as ChatCompletionRequest, B as ToolCall, H as Annotation, I as ImageGenerationRequest, j as EmbeddingsRequest, J as EmbeddingObject, h as CreateUserRequest, K as CreateUserResponse, o as ResultError, g as CreateSessionRequest, L as CreateSessionResponse, l as OAuthProvidersSchema, M as RefreshSessionResponse, N as GetProfileResponse, Q as SendVerificationEmailRequest, V as VerifyEmailRequest, W as VerifyEmailResponse, X as SendResetPasswordEmailRequest, Y as ExchangeResetPasswordTokenRequest, Z as ExchangeResetPasswordTokenResponse, _ as ResetPasswordResponse, $ as GetPublicAuthConfigResponse, S as SendRawEmailRequest, q as SendEmailResponse, v as SubscribeResponse, r as SocketMessage, P as PresenceMember, u as StorageFileSchema, a0 as ListObjectsResponseSchema, i as DeleteObjectsResponse, A as Analytics, w as Support } from './types-CbsaMttt.js';
1
+ import { e as AuthSession, U as UserSchema, a as ResultConfig, G as AuthRefreshResponse, C as ChatCompletionRequest, B as ToolCall, H as Annotation, I as ImageGenerationRequest, j as EmbeddingsRequest, J as EmbeddingObject, h as CreateUserRequest, K as CreateUserResponse, o as ResultError, g as CreateSessionRequest, L as CreateSessionResponse, l as OAuthProvidersSchema, M as RefreshSessionResponse, N as GetProfileResponse, Q as SendVerificationEmailRequest, V as VerifyEmailRequest, W as VerifyEmailResponse, X as SendResetPasswordEmailRequest, Y as ExchangeResetPasswordTokenRequest, Z as ExchangeResetPasswordTokenResponse, _ as ResetPasswordResponse, $ as GetPublicAuthConfigResponse, S as SendRawEmailRequest, q as SendEmailResponse, v as SubscribeResponse, r as SocketMessage, P as PresenceMember, u as StorageFileSchema, a0 as ListObjectsResponseSchema, i as DeleteObjectsResponse, A as Analytics, w as Support } from './types-BmU3deRO.cjs';
2
2
  import * as _supabase_postgrest_js from '@supabase/postgrest-js';
3
3
  import { PostgrestClient } from '@supabase/postgrest-js';
4
4
 
@@ -248,9 +248,13 @@ interface ChatCompletionChunk {
248
248
  delta: {
249
249
  content?: string;
250
250
  tool_calls?: ToolCall[];
251
+ /** Web-search/file citations; arrives in a trailing chunk. */
252
+ annotations?: Annotation[];
251
253
  };
252
254
  finish_reason: "tool_calls" | null;
253
255
  }[];
256
+ /** Token usage; arrives in a trailing chunk with empty choices. */
257
+ usage?: ChatCompletionUsage;
254
258
  }
255
259
  interface EmbeddingsResult {
256
260
  object: "list";
@@ -293,14 +297,16 @@ declare class ChatCompletions {
293
297
  * ```typescript
294
298
  * // Non-streaming
295
299
  * const completion = await client.ai.chat.completions.create({
296
- * model: 'gpt-4',
300
+ * model: 'openai/gpt-4o-mini',
297
301
  * messages: [{ role: 'user', content: 'Hello!' }]
298
302
  * });
299
303
  * console.log(completion.choices[0].message.content);
300
304
  *
301
- * // With images (OpenAI-compatible format)
305
+ * // With images. google/gemini-2.5-flash is the verified multimodal
306
+ * // model (openai/gpt-4o and gpt-4o-mini also accept images, but audio
307
+ * // requires gemini). URLs and base64 data URIs both work.
302
308
  * const response = await client.ai.chat.completions.create({
303
- * model: 'gpt-4-vision',
309
+ * model: 'google/gemini-2.5-flash',
304
310
  * messages: [{
305
311
  * role: 'user',
306
312
  * content: [
@@ -310,37 +316,32 @@ declare class ChatCompletions {
310
316
  * }]
311
317
  * });
312
318
  *
313
- * // With PDF files
314
- * const pdfResponse = await client.ai.chat.completions.create({
315
- * model: 'anthropic/claude-3.5-sonnet',
319
+ * // With audio. Base64 data in wav/mp3/aiff/aac/ogg/flac/m4a only -
320
+ * // browser MediaRecorder's webm/opus is rejected; record PCM via the
321
+ * // Web Audio API and encode a 16 kHz mono WAV instead.
322
+ * const audioResponse = await client.ai.chat.completions.create({
323
+ * model: 'google/gemini-2.5-flash',
316
324
  * messages: [{
317
325
  * role: 'user',
318
326
  * content: [
319
- * { type: 'text', text: 'Summarize this document' },
320
- * { type: 'file', file: { filename: 'doc.pdf', file_data: 'https://example.com/doc.pdf' } }
327
+ * { type: 'text', text: 'Transcribe this recording' },
328
+ * { type: 'input_audio', input_audio: { data: base64Wav, format: 'wav' } }
321
329
  * ]
322
- * }],
323
- * fileParser: { enabled: true, pdf: { engine: 'mistral-ocr' } }
330
+ * }]
324
331
  * });
325
332
  *
326
- * // With web search
333
+ * // With web search. Non-streaming: citations arrive on
334
+ * // response.choices[0].message.annotations. Streaming: they arrive in a
335
+ * // trailing chunk as chunk.choices[0].delta.annotations.
327
336
  * const searchResponse = await client.ai.chat.completions.create({
328
- * model: 'openai/gpt-4',
337
+ * model: 'openai/gpt-4o-mini',
329
338
  * messages: [{ role: 'user', content: 'What are the latest news about AI?' }],
330
339
  * webSearch: { enabled: true, maxResults: 5 }
331
340
  * });
332
- * // Access citations from response.choices[0].message.annotations
333
- *
334
- * // With thinking/reasoning mode (Anthropic models)
335
- * const thinkingResponse = await client.ai.chat.completions.create({
336
- * model: 'anthropic/claude-3.5-sonnet',
337
- * messages: [{ role: 'user', content: 'Solve this complex math problem...' }],
338
- * thinking: true
339
- * });
340
341
  *
341
342
  * // Streaming - returns async iterable
342
343
  * const stream = await client.ai.chat.completions.create({
343
- * model: 'gpt-4',
344
+ * model: 'openai/gpt-4o-mini',
344
345
  * messages: [{ role: 'user', content: 'Tell me a story' }],
345
346
  * stream: true
346
347
  * });
@@ -452,6 +453,16 @@ type OAuthSignInOptions = {
452
453
  type OAuthSignInLegacyOptions = OAuthSignInOptions & {
453
454
  provider: OAuthProvidersSchema | string;
454
455
  };
456
+ /**
457
+ * Authentication client.
458
+ *
459
+ * Session model: the refresh token lives in an httpOnly cookie set by the
460
+ * backend (plus a CSRF cookie); the access token is held in memory and
461
+ * refreshed from that cookie. Nothing auth-related is written to
462
+ * localStorage, so an empty localStorage does NOT mean the user is signed
463
+ * out. Check state with getCurrentUser() or onAuthStateChange(), never by
464
+ * reading browser storage.
465
+ */
455
466
  declare class Auth {
456
467
  private http;
457
468
  private tokenManager;
@@ -748,10 +759,10 @@ declare class Functions {
748
759
  private functionsUrl;
749
760
  constructor(http: HttpClient, functionsUrl?: string);
750
761
  /**
751
- * Derive the subhosting URL from the base URL.
752
- * Rewrites the backend base URL to its functions subhosting URL
762
+ * Derive the legacy subhosting URL from the base URL
753
763
  * ({appKey}.{region}.<domain> -> {appKey}.functions.<domain>).
754
- * Only applies to platform-hosted backends.
764
+ * Only used to recognize when a configured functionsUrl still points at
765
+ * the local deployment, so in-process dispatch can short-circuit it.
755
766
  */
756
767
  private static deriveSubhostingUrl;
757
768
  /**
@@ -763,11 +774,13 @@ declare class Functions {
763
774
  * Invoke an Edge Function.
764
775
  *
765
776
  * Dispatch order:
766
- * 1. If the platform's in-process dispatch hook is present, call it directly.
767
- * This avoids Deno Subhosting's 508 Loop Detected when one bundled
768
- * function invokes another inside the same deployment.
769
- * 2. Otherwise, try the configured subhosting URL.
770
- * 3. On 404 from subhosting, fall back to the proxy path.
777
+ * 1. If the platform's in-process dispatch hook is present and no foreign
778
+ * functionsUrl is configured, call it directly (function-to-function
779
+ * calls inside the same deployment).
780
+ * 2. If a custom functionsUrl is configured, try it; fall back to the
781
+ * proxy path on 404 or network failure.
782
+ * 3. Otherwise, invoke through the main host's /functions/{slug} proxy.
783
+ * This route works from browsers too (correct CORS).
771
784
  *
772
785
  * @param slug The function slug to invoke
773
786
  * @param options Request options
@@ -811,7 +824,24 @@ declare class Realtime {
811
824
  get socketId(): string | undefined;
812
825
  subscribe(channel: string): Promise<SubscribeResponse>;
813
826
  unsubscribe(channel: string): void;
827
+ /**
828
+ * Publish an event to a channel.
829
+ *
830
+ * Delivery notes (verified against a live backend):
831
+ * - Payload fields arrive spread onto the received message itself, next to
832
+ * `meta` - not nested under a `payload` key. Publishing `{ text: "hi" }`
833
+ * means receivers read `msg.text`.
834
+ * - The sender receives its own message too. Deduplicate with
835
+ * `msg.meta.messageId` (or `msg.meta.senderId`) if you also update local
836
+ * state optimistically.
837
+ */
814
838
  publish<T = unknown>(channel: string, event: string, payload: T): Promise<void>;
839
+ /**
840
+ * Listen for an event by name, across all subscribed channels.
841
+ * Filter by channel inside the callback: `msg.meta.channel` always matches
842
+ * the exact name passed to subscribe() (the SDK strips the server's
843
+ * transport prefix before delivery).
844
+ */
815
845
  on<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
816
846
  off<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
817
847
  once<T = SocketMessage>(event: string, callback: EventCallback<T>): void;
@@ -966,7 +996,7 @@ type AccessTokenChangeEvent = typeof AuthChangeEvent.SIGNED_IN | typeof AuthChan
966
996
  * import { ResultClient } from '@resultdev/sdk';
967
997
  *
968
998
  * const client = new ResultClient({
969
- * baseUrl: 'http://localhost:7130'
999
+ * baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!
970
1000
  * });
971
1001
  *
972
1002
  * // Authentication
@@ -997,7 +1027,7 @@ type AccessTokenChangeEvent = typeof AuthChangeEvent.SIGNED_IN | typeof AuthChan
997
1027
  *
998
1028
  * // Enable debug logging
999
1029
  * const debugClient = new ResultClient({
1000
- * baseUrl: 'http://localhost:7130',
1030
+ * baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!,
1001
1031
  * debug: true
1002
1032
  * });
1003
1033
  * ```