@modelrelay/sdk 0.19.0 → 0.21.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/dist/index.cjs CHANGED
@@ -96,7 +96,13 @@ var ErrorCodes = {
96
96
  SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE",
97
97
  INVALID_INPUT: "INVALID_INPUT",
98
98
  PAYMENT_REQUIRED: "PAYMENT_REQUIRED",
99
- METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED"
99
+ METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED",
100
+ /** No tiers configured for the project - create a tier first. */
101
+ NO_TIERS: "NO_TIERS",
102
+ /** No free tier available for auto-provisioning - create a free tier or use checkout flow. */
103
+ NO_FREE_TIER: "NO_FREE_TIER",
104
+ /** Email required for auto-provisioning a new customer. */
105
+ EMAIL_REQUIRED: "EMAIL_REQUIRED"
100
106
  };
101
107
  var ModelRelayError = class extends Error {
102
108
  constructor(message, opts) {
@@ -165,6 +171,36 @@ var APIError = class extends ModelRelayError {
165
171
  isUnavailable() {
166
172
  return this.code === ErrorCodes.SERVICE_UNAVAILABLE;
167
173
  }
174
+ /**
175
+ * Returns true if the error indicates no tiers are configured.
176
+ * To resolve: create at least one tier in your project dashboard.
177
+ */
178
+ isNoTiers() {
179
+ return this.code === ErrorCodes.NO_TIERS;
180
+ }
181
+ /**
182
+ * Returns true if the error indicates no free tier is available for auto-provisioning.
183
+ * To resolve: either create a free tier for automatic customer creation,
184
+ * or use the checkout flow to create paying customers first.
185
+ */
186
+ isNoFreeTier() {
187
+ return this.code === ErrorCodes.NO_FREE_TIER;
188
+ }
189
+ /**
190
+ * Returns true if email is required for auto-provisioning a new customer.
191
+ * To resolve: provide the 'email' field in FrontendTokenRequest.
192
+ */
193
+ isEmailRequired() {
194
+ return this.code === ErrorCodes.EMAIL_REQUIRED;
195
+ }
196
+ /**
197
+ * Returns true if this is a customer provisioning error (NO_TIERS, NO_FREE_TIER, or EMAIL_REQUIRED).
198
+ * These errors occur when calling frontendToken() with a customer that doesn't exist
199
+ * and automatic provisioning cannot complete.
200
+ */
201
+ isProvisioningError() {
202
+ return this.isNoTiers() || this.isNoFreeTier() || this.isEmailRequired();
203
+ }
168
204
  };
169
205
  async function parseErrorResponse(response, retries) {
170
206
  const requestId = response.headers.get("X-ModelRelay-Chat-Request-Id") || response.headers.get("X-Request-Id") || void 0;
@@ -234,20 +270,47 @@ var AuthClient = class {
234
270
  this.customer = cfg.customer;
235
271
  }
236
272
  /**
237
- * Exchange a publishable key for a short-lived frontend token.
273
+ * Exchange a publishable key for a short-lived frontend token for an existing customer.
238
274
  * Tokens are cached until they are close to expiry.
275
+ *
276
+ * Use this method when the customer already exists in the system.
277
+ * For auto-provisioning new customers, use frontendTokenAutoProvision instead.
239
278
  */
240
279
  async frontendToken(request) {
241
- const publishableKey = request?.publishableKey || (isPublishableKey(this.apiKey) ? this.apiKey : void 0);
242
- if (!publishableKey) {
243
- throw new ConfigError("publishable key required to issue frontend tokens");
280
+ if (!request.publishableKey?.trim()) {
281
+ throw new ConfigError("publishableKey is required");
244
282
  }
245
- const customerId = request?.customerId || this.customer?.id;
246
- if (!customerId) {
247
- throw new ConfigError("customerId is required to mint a frontend token");
283
+ if (!request.customerId?.trim()) {
284
+ throw new ConfigError("customerId is required");
248
285
  }
249
- const deviceId = request?.deviceId || this.customer?.deviceId;
250
- const ttlSeconds = request?.ttlSeconds ?? this.customer?.ttlSeconds;
286
+ return this.sendFrontendTokenRequest(request);
287
+ }
288
+ /**
289
+ * Exchange a publishable key for a frontend token, creating the customer if needed.
290
+ * The customer will be auto-provisioned on the project's free tier.
291
+ * Tokens are cached until they are close to expiry.
292
+ *
293
+ * Use this method when the customer may not exist and should be created automatically.
294
+ * The email is required for auto-provisioning.
295
+ */
296
+ async frontendTokenAutoProvision(request) {
297
+ if (!request.publishableKey?.trim()) {
298
+ throw new ConfigError("publishableKey is required");
299
+ }
300
+ if (!request.customerId?.trim()) {
301
+ throw new ConfigError("customerId is required");
302
+ }
303
+ if (!request.email?.trim()) {
304
+ throw new ConfigError("email is required for auto-provisioning");
305
+ }
306
+ return this.sendFrontendTokenRequest(request);
307
+ }
308
+ /**
309
+ * Internal method to send frontend token requests.
310
+ */
311
+ async sendFrontendTokenRequest(request) {
312
+ const { publishableKey, customerId, deviceId, ttlSeconds } = request;
313
+ const email = "email" in request ? request.email : void 0;
251
314
  const cacheKey = `${publishableKey}:${customerId}:${deviceId || ""}`;
252
315
  const cached = this.cachedFrontend.get(cacheKey);
253
316
  if (cached && isTokenReusable(cached)) {
@@ -263,6 +326,9 @@ var AuthClient = class {
263
326
  if (typeof ttlSeconds === "number" && ttlSeconds > 0) {
264
327
  payload.ttl_seconds = ttlSeconds;
265
328
  }
329
+ if (email) {
330
+ payload.email = email;
331
+ }
266
332
  const response = await this.http.json(
267
333
  "/auth/frontend-token",
268
334
  {
@@ -290,10 +356,15 @@ var AuthClient = class {
290
356
  throw new ConfigError("API key or token is required");
291
357
  }
292
358
  if (isPublishableKey(this.apiKey)) {
359
+ const resolvedCustomerId = customerId || overrides?.id || this.customer?.id;
360
+ if (!resolvedCustomerId) {
361
+ throw new ConfigError("customerId is required to mint a frontend token");
362
+ }
293
363
  const token = await this.frontendToken({
294
- customerId: customerId || overrides?.id,
295
- deviceId: overrides?.deviceId,
296
- ttlSeconds: overrides?.ttlSeconds
364
+ publishableKey: this.apiKey,
365
+ customerId: resolvedCustomerId,
366
+ deviceId: overrides?.deviceId || this.customer?.deviceId,
367
+ ttlSeconds: overrides?.ttlSeconds ?? this.customer?.ttlSeconds
297
368
  });
298
369
  return createAccessTokenAuth(token.token);
299
370
  }
@@ -347,7 +418,7 @@ function isTokenReusable(token) {
347
418
  // package.json
348
419
  var package_default = {
349
420
  name: "@modelrelay/sdk",
350
- version: "0.19.0",
421
+ version: "0.21.0",
351
422
  description: "TypeScript SDK for the ModelRelay API",
352
423
  type: "module",
353
424
  main: "dist/index.cjs",
package/dist/index.d.cts CHANGED
@@ -180,10 +180,35 @@ interface FrontendCustomer {
180
180
  deviceId?: string;
181
181
  ttlSeconds?: number;
182
182
  }
183
+ /**
184
+ * Request for fetching a frontend token for an existing customer.
185
+ * Use this when the customer already exists in the system.
186
+ */
183
187
  interface FrontendTokenRequest {
184
- publishableKey?: string;
188
+ /** Publishable key (mr_pk_*) - required for authentication. */
189
+ publishableKey: string;
190
+ /** Customer identifier - required to issue a token for this customer. */
185
191
  customerId: string;
192
+ /** Optional device identifier for tracking/rate limiting. */
186
193
  deviceId?: string;
194
+ /** Optional TTL in seconds for the issued token. */
195
+ ttlSeconds?: number;
196
+ }
197
+ /**
198
+ * Request for fetching a frontend token with auto-provisioning.
199
+ * Use this when the customer may not exist and should be created on the free tier.
200
+ * The email is required for auto-provisioning.
201
+ */
202
+ interface FrontendTokenAutoProvisionRequest {
203
+ /** Publishable key (mr_pk_*) - required for authentication. */
204
+ publishableKey: string;
205
+ /** Customer identifier - required to issue a token for this customer. */
206
+ customerId: string;
207
+ /** Email address - required for auto-provisioning a new customer. */
208
+ email: string;
209
+ /** Optional device identifier for tracking/rate limiting. */
210
+ deviceId?: string;
211
+ /** Optional TTL in seconds for the issued token. */
187
212
  ttlSeconds?: number;
188
213
  }
189
214
  interface FrontendToken {
@@ -640,10 +665,26 @@ declare class AuthClient {
640
665
  private cachedFrontend;
641
666
  constructor(http: HTTPClient, cfg: AuthConfig);
642
667
  /**
643
- * Exchange a publishable key for a short-lived frontend token.
668
+ * Exchange a publishable key for a short-lived frontend token for an existing customer.
644
669
  * Tokens are cached until they are close to expiry.
670
+ *
671
+ * Use this method when the customer already exists in the system.
672
+ * For auto-provisioning new customers, use frontendTokenAutoProvision instead.
645
673
  */
646
- frontendToken(request?: Partial<FrontendTokenRequest>): Promise<FrontendToken>;
674
+ frontendToken(request: FrontendTokenRequest): Promise<FrontendToken>;
675
+ /**
676
+ * Exchange a publishable key for a frontend token, creating the customer if needed.
677
+ * The customer will be auto-provisioned on the project's free tier.
678
+ * Tokens are cached until they are close to expiry.
679
+ *
680
+ * Use this method when the customer may not exist and should be created automatically.
681
+ * The email is required for auto-provisioning.
682
+ */
683
+ frontendTokenAutoProvision(request: FrontendTokenAutoProvisionRequest): Promise<FrontendToken>;
684
+ /**
685
+ * Internal method to send frontend token requests.
686
+ */
687
+ private sendFrontendTokenRequest;
647
688
  /**
648
689
  * Determine the correct auth headers for chat completions.
649
690
  * Publishable keys are automatically exchanged for frontend tokens.
@@ -977,6 +1018,12 @@ declare const ErrorCodes: {
977
1018
  readonly INVALID_INPUT: "INVALID_INPUT";
978
1019
  readonly PAYMENT_REQUIRED: "PAYMENT_REQUIRED";
979
1020
  readonly METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED";
1021
+ /** No tiers configured for the project - create a tier first. */
1022
+ readonly NO_TIERS: "NO_TIERS";
1023
+ /** No free tier available for auto-provisioning - create a free tier or use checkout flow. */
1024
+ readonly NO_FREE_TIER: "NO_FREE_TIER";
1025
+ /** Email required for auto-provisioning a new customer. */
1026
+ readonly EMAIL_REQUIRED: "EMAIL_REQUIRED";
980
1027
  };
981
1028
  type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
982
1029
  type ErrorCategory = "config" | "transport" | "api";
@@ -1032,6 +1079,28 @@ declare class APIError extends ModelRelayError {
1032
1079
  isForbidden(): boolean;
1033
1080
  /** Returns true if the error is a service unavailable error. */
1034
1081
  isUnavailable(): boolean;
1082
+ /**
1083
+ * Returns true if the error indicates no tiers are configured.
1084
+ * To resolve: create at least one tier in your project dashboard.
1085
+ */
1086
+ isNoTiers(): boolean;
1087
+ /**
1088
+ * Returns true if the error indicates no free tier is available for auto-provisioning.
1089
+ * To resolve: either create a free tier for automatic customer creation,
1090
+ * or use the checkout flow to create paying customers first.
1091
+ */
1092
+ isNoFreeTier(): boolean;
1093
+ /**
1094
+ * Returns true if email is required for auto-provisioning a new customer.
1095
+ * To resolve: provide the 'email' field in FrontendTokenRequest.
1096
+ */
1097
+ isEmailRequired(): boolean;
1098
+ /**
1099
+ * Returns true if this is a customer provisioning error (NO_TIERS, NO_FREE_TIER, or EMAIL_REQUIRED).
1100
+ * These errors occur when calling frontendToken() with a customer that doesn't exist
1101
+ * and automatic provisioning cannot complete.
1102
+ */
1103
+ isProvisioningError(): boolean;
1035
1104
  }
1036
1105
  declare function parseErrorResponse(response: Response, retries?: RetryMetadata): Promise<APIError>;
1037
1106
 
@@ -1461,4 +1530,4 @@ declare class ModelRelay {
1461
1530
  constructor(options: ModelRelayOptions);
1462
1531
  }
1463
1532
 
1464
- export { type APIChatResponse, type APIChatUsage, type APICheckoutSession, type APICustomerRef, APIError, type APIFrontendToken, type APIKey, AuthClient, type AuthHeaders, ChatClient, type ChatCompletionCreateParams, type ChatCompletionEvent, type ChatCompletionResponse, ChatCompletionsStream, type ChatEventType, type ChatMessage, type CheckoutSession, type CheckoutSessionRequest, type CodeExecConfig, ConfigError, type Customer, type CustomerClaimRequest, type CustomerCreateRequest, type CustomerMetadata, type CustomerUpsertRequest, CustomersClient, DEFAULT_BASE_URL, DEFAULT_CLIENT_HEADER, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, type ErrorCategory, type ErrorCode, ErrorCodes, type FieldError, type FrontendCustomer, type FrontendToken, type FrontendTokenRequest, type FunctionCall, type FunctionCallDelta, type FunctionTool, type HttpRequestMetrics, type JsonSchemaOptions, type KnownStopReason, type MessageDeltaData, type MessageStartData, type MessageStopData, type MetricsCallbacks, type ModelId, ModelRelay, type ModelRelayBaseOptions, ModelRelayError, type ModelRelayKeyOptions, type ModelRelayOptions, type ModelRelayOptionsLegacy, type ModelRelayTokenOptions, type NonEmptyArray, type PriceInterval, type Project, type ProviderId, type RequestContext, type ResponseFormat, type ResponseFormatType, ResponseFormatTypes, type ResponseJSONSchemaFormat, type RetryConfig, type RetryMetadata, type RetryOptions, SDK_VERSION, type Schema, type StopReason, StopReasons, type StreamFirstTokenMetrics, type StructuredJSONEvent, type StructuredJSONRecordType, StructuredJSONStream, type SubscriptionStatus, type Tier, type TierCheckoutRequest, type TierCheckoutSession, TiersClient, type TokenUsageMetrics, type Tool, ToolArgsError, type ToolCall, ToolCallAccumulator, type ToolCallDelta, type ToolChoice, type ToolChoiceType, ToolChoiceTypes, type ToolExecutionResult, type ToolHandler, ToolRegistry, type ToolType, ToolTypes, type TraceCallbacks, TransportError, type TransportErrorKind, type Usage, type UsageSummary, type WebSearchConfig, type WebToolMode, WebToolModes, type XSearchConfig, type ZodLikeSchema, assistantMessageWithToolCalls, createAccessTokenAuth, createApiKeyAuth, createAssistantMessage, createFunctionCall, createFunctionTool, createFunctionToolFromSchema, createRetryMessages, createSystemMessage, createToolCall, createUsage, createUserMessage, createWebTool, executeWithRetry, firstToolCall, formatToolErrorForModel, getRetryableErrors, hasRetryableErrors, hasToolCalls, isPublishableKey, mergeMetrics, mergeTrace, modelToString, normalizeModelId, normalizeStopReason, parseErrorResponse, parseToolArgs, parseToolArgsRaw, respondToToolCall, stopReasonToString, toolChoiceAuto, toolChoiceNone, toolChoiceRequired, toolResultMessage, tryParseToolArgs, zodToJsonSchema };
1533
+ export { type APIChatResponse, type APIChatUsage, type APICheckoutSession, type APICustomerRef, APIError, type APIFrontendToken, type APIKey, AuthClient, type AuthHeaders, ChatClient, type ChatCompletionCreateParams, type ChatCompletionEvent, type ChatCompletionResponse, ChatCompletionsStream, type ChatEventType, type ChatMessage, type CheckoutSession, type CheckoutSessionRequest, type CodeExecConfig, ConfigError, type Customer, type CustomerClaimRequest, type CustomerCreateRequest, type CustomerMetadata, type CustomerUpsertRequest, CustomersClient, DEFAULT_BASE_URL, DEFAULT_CLIENT_HEADER, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, type ErrorCategory, type ErrorCode, ErrorCodes, type FieldError, type FrontendCustomer, type FrontendToken, type FrontendTokenAutoProvisionRequest, type FrontendTokenRequest, type FunctionCall, type FunctionCallDelta, type FunctionTool, type HttpRequestMetrics, type JsonSchemaOptions, type KnownStopReason, type MessageDeltaData, type MessageStartData, type MessageStopData, type MetricsCallbacks, type ModelId, ModelRelay, type ModelRelayBaseOptions, ModelRelayError, type ModelRelayKeyOptions, type ModelRelayOptions, type ModelRelayOptionsLegacy, type ModelRelayTokenOptions, type NonEmptyArray, type PriceInterval, type Project, type ProviderId, type RequestContext, type ResponseFormat, type ResponseFormatType, ResponseFormatTypes, type ResponseJSONSchemaFormat, type RetryConfig, type RetryMetadata, type RetryOptions, SDK_VERSION, type Schema, type StopReason, StopReasons, type StreamFirstTokenMetrics, type StructuredJSONEvent, type StructuredJSONRecordType, StructuredJSONStream, type SubscriptionStatus, type Tier, type TierCheckoutRequest, type TierCheckoutSession, TiersClient, type TokenUsageMetrics, type Tool, ToolArgsError, type ToolCall, ToolCallAccumulator, type ToolCallDelta, type ToolChoice, type ToolChoiceType, ToolChoiceTypes, type ToolExecutionResult, type ToolHandler, ToolRegistry, type ToolType, ToolTypes, type TraceCallbacks, TransportError, type TransportErrorKind, type Usage, type UsageSummary, type WebSearchConfig, type WebToolMode, WebToolModes, type XSearchConfig, type ZodLikeSchema, assistantMessageWithToolCalls, createAccessTokenAuth, createApiKeyAuth, createAssistantMessage, createFunctionCall, createFunctionTool, createFunctionToolFromSchema, createRetryMessages, createSystemMessage, createToolCall, createUsage, createUserMessage, createWebTool, executeWithRetry, firstToolCall, formatToolErrorForModel, getRetryableErrors, hasRetryableErrors, hasToolCalls, isPublishableKey, mergeMetrics, mergeTrace, modelToString, normalizeModelId, normalizeStopReason, parseErrorResponse, parseToolArgs, parseToolArgsRaw, respondToToolCall, stopReasonToString, toolChoiceAuto, toolChoiceNone, toolChoiceRequired, toolResultMessage, tryParseToolArgs, zodToJsonSchema };
package/dist/index.d.ts CHANGED
@@ -180,10 +180,35 @@ interface FrontendCustomer {
180
180
  deviceId?: string;
181
181
  ttlSeconds?: number;
182
182
  }
183
+ /**
184
+ * Request for fetching a frontend token for an existing customer.
185
+ * Use this when the customer already exists in the system.
186
+ */
183
187
  interface FrontendTokenRequest {
184
- publishableKey?: string;
188
+ /** Publishable key (mr_pk_*) - required for authentication. */
189
+ publishableKey: string;
190
+ /** Customer identifier - required to issue a token for this customer. */
185
191
  customerId: string;
192
+ /** Optional device identifier for tracking/rate limiting. */
186
193
  deviceId?: string;
194
+ /** Optional TTL in seconds for the issued token. */
195
+ ttlSeconds?: number;
196
+ }
197
+ /**
198
+ * Request for fetching a frontend token with auto-provisioning.
199
+ * Use this when the customer may not exist and should be created on the free tier.
200
+ * The email is required for auto-provisioning.
201
+ */
202
+ interface FrontendTokenAutoProvisionRequest {
203
+ /** Publishable key (mr_pk_*) - required for authentication. */
204
+ publishableKey: string;
205
+ /** Customer identifier - required to issue a token for this customer. */
206
+ customerId: string;
207
+ /** Email address - required for auto-provisioning a new customer. */
208
+ email: string;
209
+ /** Optional device identifier for tracking/rate limiting. */
210
+ deviceId?: string;
211
+ /** Optional TTL in seconds for the issued token. */
187
212
  ttlSeconds?: number;
188
213
  }
189
214
  interface FrontendToken {
@@ -640,10 +665,26 @@ declare class AuthClient {
640
665
  private cachedFrontend;
641
666
  constructor(http: HTTPClient, cfg: AuthConfig);
642
667
  /**
643
- * Exchange a publishable key for a short-lived frontend token.
668
+ * Exchange a publishable key for a short-lived frontend token for an existing customer.
644
669
  * Tokens are cached until they are close to expiry.
670
+ *
671
+ * Use this method when the customer already exists in the system.
672
+ * For auto-provisioning new customers, use frontendTokenAutoProvision instead.
645
673
  */
646
- frontendToken(request?: Partial<FrontendTokenRequest>): Promise<FrontendToken>;
674
+ frontendToken(request: FrontendTokenRequest): Promise<FrontendToken>;
675
+ /**
676
+ * Exchange a publishable key for a frontend token, creating the customer if needed.
677
+ * The customer will be auto-provisioned on the project's free tier.
678
+ * Tokens are cached until they are close to expiry.
679
+ *
680
+ * Use this method when the customer may not exist and should be created automatically.
681
+ * The email is required for auto-provisioning.
682
+ */
683
+ frontendTokenAutoProvision(request: FrontendTokenAutoProvisionRequest): Promise<FrontendToken>;
684
+ /**
685
+ * Internal method to send frontend token requests.
686
+ */
687
+ private sendFrontendTokenRequest;
647
688
  /**
648
689
  * Determine the correct auth headers for chat completions.
649
690
  * Publishable keys are automatically exchanged for frontend tokens.
@@ -977,6 +1018,12 @@ declare const ErrorCodes: {
977
1018
  readonly INVALID_INPUT: "INVALID_INPUT";
978
1019
  readonly PAYMENT_REQUIRED: "PAYMENT_REQUIRED";
979
1020
  readonly METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED";
1021
+ /** No tiers configured for the project - create a tier first. */
1022
+ readonly NO_TIERS: "NO_TIERS";
1023
+ /** No free tier available for auto-provisioning - create a free tier or use checkout flow. */
1024
+ readonly NO_FREE_TIER: "NO_FREE_TIER";
1025
+ /** Email required for auto-provisioning a new customer. */
1026
+ readonly EMAIL_REQUIRED: "EMAIL_REQUIRED";
980
1027
  };
981
1028
  type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
982
1029
  type ErrorCategory = "config" | "transport" | "api";
@@ -1032,6 +1079,28 @@ declare class APIError extends ModelRelayError {
1032
1079
  isForbidden(): boolean;
1033
1080
  /** Returns true if the error is a service unavailable error. */
1034
1081
  isUnavailable(): boolean;
1082
+ /**
1083
+ * Returns true if the error indicates no tiers are configured.
1084
+ * To resolve: create at least one tier in your project dashboard.
1085
+ */
1086
+ isNoTiers(): boolean;
1087
+ /**
1088
+ * Returns true if the error indicates no free tier is available for auto-provisioning.
1089
+ * To resolve: either create a free tier for automatic customer creation,
1090
+ * or use the checkout flow to create paying customers first.
1091
+ */
1092
+ isNoFreeTier(): boolean;
1093
+ /**
1094
+ * Returns true if email is required for auto-provisioning a new customer.
1095
+ * To resolve: provide the 'email' field in FrontendTokenRequest.
1096
+ */
1097
+ isEmailRequired(): boolean;
1098
+ /**
1099
+ * Returns true if this is a customer provisioning error (NO_TIERS, NO_FREE_TIER, or EMAIL_REQUIRED).
1100
+ * These errors occur when calling frontendToken() with a customer that doesn't exist
1101
+ * and automatic provisioning cannot complete.
1102
+ */
1103
+ isProvisioningError(): boolean;
1035
1104
  }
1036
1105
  declare function parseErrorResponse(response: Response, retries?: RetryMetadata): Promise<APIError>;
1037
1106
 
@@ -1461,4 +1530,4 @@ declare class ModelRelay {
1461
1530
  constructor(options: ModelRelayOptions);
1462
1531
  }
1463
1532
 
1464
- export { type APIChatResponse, type APIChatUsage, type APICheckoutSession, type APICustomerRef, APIError, type APIFrontendToken, type APIKey, AuthClient, type AuthHeaders, ChatClient, type ChatCompletionCreateParams, type ChatCompletionEvent, type ChatCompletionResponse, ChatCompletionsStream, type ChatEventType, type ChatMessage, type CheckoutSession, type CheckoutSessionRequest, type CodeExecConfig, ConfigError, type Customer, type CustomerClaimRequest, type CustomerCreateRequest, type CustomerMetadata, type CustomerUpsertRequest, CustomersClient, DEFAULT_BASE_URL, DEFAULT_CLIENT_HEADER, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, type ErrorCategory, type ErrorCode, ErrorCodes, type FieldError, type FrontendCustomer, type FrontendToken, type FrontendTokenRequest, type FunctionCall, type FunctionCallDelta, type FunctionTool, type HttpRequestMetrics, type JsonSchemaOptions, type KnownStopReason, type MessageDeltaData, type MessageStartData, type MessageStopData, type MetricsCallbacks, type ModelId, ModelRelay, type ModelRelayBaseOptions, ModelRelayError, type ModelRelayKeyOptions, type ModelRelayOptions, type ModelRelayOptionsLegacy, type ModelRelayTokenOptions, type NonEmptyArray, type PriceInterval, type Project, type ProviderId, type RequestContext, type ResponseFormat, type ResponseFormatType, ResponseFormatTypes, type ResponseJSONSchemaFormat, type RetryConfig, type RetryMetadata, type RetryOptions, SDK_VERSION, type Schema, type StopReason, StopReasons, type StreamFirstTokenMetrics, type StructuredJSONEvent, type StructuredJSONRecordType, StructuredJSONStream, type SubscriptionStatus, type Tier, type TierCheckoutRequest, type TierCheckoutSession, TiersClient, type TokenUsageMetrics, type Tool, ToolArgsError, type ToolCall, ToolCallAccumulator, type ToolCallDelta, type ToolChoice, type ToolChoiceType, ToolChoiceTypes, type ToolExecutionResult, type ToolHandler, ToolRegistry, type ToolType, ToolTypes, type TraceCallbacks, TransportError, type TransportErrorKind, type Usage, type UsageSummary, type WebSearchConfig, type WebToolMode, WebToolModes, type XSearchConfig, type ZodLikeSchema, assistantMessageWithToolCalls, createAccessTokenAuth, createApiKeyAuth, createAssistantMessage, createFunctionCall, createFunctionTool, createFunctionToolFromSchema, createRetryMessages, createSystemMessage, createToolCall, createUsage, createUserMessage, createWebTool, executeWithRetry, firstToolCall, formatToolErrorForModel, getRetryableErrors, hasRetryableErrors, hasToolCalls, isPublishableKey, mergeMetrics, mergeTrace, modelToString, normalizeModelId, normalizeStopReason, parseErrorResponse, parseToolArgs, parseToolArgsRaw, respondToToolCall, stopReasonToString, toolChoiceAuto, toolChoiceNone, toolChoiceRequired, toolResultMessage, tryParseToolArgs, zodToJsonSchema };
1533
+ export { type APIChatResponse, type APIChatUsage, type APICheckoutSession, type APICustomerRef, APIError, type APIFrontendToken, type APIKey, AuthClient, type AuthHeaders, ChatClient, type ChatCompletionCreateParams, type ChatCompletionEvent, type ChatCompletionResponse, ChatCompletionsStream, type ChatEventType, type ChatMessage, type CheckoutSession, type CheckoutSessionRequest, type CodeExecConfig, ConfigError, type Customer, type CustomerClaimRequest, type CustomerCreateRequest, type CustomerMetadata, type CustomerUpsertRequest, CustomersClient, DEFAULT_BASE_URL, DEFAULT_CLIENT_HEADER, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, type ErrorCategory, type ErrorCode, ErrorCodes, type FieldError, type FrontendCustomer, type FrontendToken, type FrontendTokenAutoProvisionRequest, type FrontendTokenRequest, type FunctionCall, type FunctionCallDelta, type FunctionTool, type HttpRequestMetrics, type JsonSchemaOptions, type KnownStopReason, type MessageDeltaData, type MessageStartData, type MessageStopData, type MetricsCallbacks, type ModelId, ModelRelay, type ModelRelayBaseOptions, ModelRelayError, type ModelRelayKeyOptions, type ModelRelayOptions, type ModelRelayOptionsLegacy, type ModelRelayTokenOptions, type NonEmptyArray, type PriceInterval, type Project, type ProviderId, type RequestContext, type ResponseFormat, type ResponseFormatType, ResponseFormatTypes, type ResponseJSONSchemaFormat, type RetryConfig, type RetryMetadata, type RetryOptions, SDK_VERSION, type Schema, type StopReason, StopReasons, type StreamFirstTokenMetrics, type StructuredJSONEvent, type StructuredJSONRecordType, StructuredJSONStream, type SubscriptionStatus, type Tier, type TierCheckoutRequest, type TierCheckoutSession, TiersClient, type TokenUsageMetrics, type Tool, ToolArgsError, type ToolCall, ToolCallAccumulator, type ToolCallDelta, type ToolChoice, type ToolChoiceType, ToolChoiceTypes, type ToolExecutionResult, type ToolHandler, ToolRegistry, type ToolType, ToolTypes, type TraceCallbacks, TransportError, type TransportErrorKind, type Usage, type UsageSummary, type WebSearchConfig, type WebToolMode, WebToolModes, type XSearchConfig, type ZodLikeSchema, assistantMessageWithToolCalls, createAccessTokenAuth, createApiKeyAuth, createAssistantMessage, createFunctionCall, createFunctionTool, createFunctionToolFromSchema, createRetryMessages, createSystemMessage, createToolCall, createUsage, createUserMessage, createWebTool, executeWithRetry, firstToolCall, formatToolErrorForModel, getRetryableErrors, hasRetryableErrors, hasToolCalls, isPublishableKey, mergeMetrics, mergeTrace, modelToString, normalizeModelId, normalizeStopReason, parseErrorResponse, parseToolArgs, parseToolArgsRaw, respondToToolCall, stopReasonToString, toolChoiceAuto, toolChoiceNone, toolChoiceRequired, toolResultMessage, tryParseToolArgs, zodToJsonSchema };
package/dist/index.js CHANGED
@@ -10,7 +10,13 @@ var ErrorCodes = {
10
10
  SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE",
11
11
  INVALID_INPUT: "INVALID_INPUT",
12
12
  PAYMENT_REQUIRED: "PAYMENT_REQUIRED",
13
- METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED"
13
+ METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED",
14
+ /** No tiers configured for the project - create a tier first. */
15
+ NO_TIERS: "NO_TIERS",
16
+ /** No free tier available for auto-provisioning - create a free tier or use checkout flow. */
17
+ NO_FREE_TIER: "NO_FREE_TIER",
18
+ /** Email required for auto-provisioning a new customer. */
19
+ EMAIL_REQUIRED: "EMAIL_REQUIRED"
14
20
  };
15
21
  var ModelRelayError = class extends Error {
16
22
  constructor(message, opts) {
@@ -79,6 +85,36 @@ var APIError = class extends ModelRelayError {
79
85
  isUnavailable() {
80
86
  return this.code === ErrorCodes.SERVICE_UNAVAILABLE;
81
87
  }
88
+ /**
89
+ * Returns true if the error indicates no tiers are configured.
90
+ * To resolve: create at least one tier in your project dashboard.
91
+ */
92
+ isNoTiers() {
93
+ return this.code === ErrorCodes.NO_TIERS;
94
+ }
95
+ /**
96
+ * Returns true if the error indicates no free tier is available for auto-provisioning.
97
+ * To resolve: either create a free tier for automatic customer creation,
98
+ * or use the checkout flow to create paying customers first.
99
+ */
100
+ isNoFreeTier() {
101
+ return this.code === ErrorCodes.NO_FREE_TIER;
102
+ }
103
+ /**
104
+ * Returns true if email is required for auto-provisioning a new customer.
105
+ * To resolve: provide the 'email' field in FrontendTokenRequest.
106
+ */
107
+ isEmailRequired() {
108
+ return this.code === ErrorCodes.EMAIL_REQUIRED;
109
+ }
110
+ /**
111
+ * Returns true if this is a customer provisioning error (NO_TIERS, NO_FREE_TIER, or EMAIL_REQUIRED).
112
+ * These errors occur when calling frontendToken() with a customer that doesn't exist
113
+ * and automatic provisioning cannot complete.
114
+ */
115
+ isProvisioningError() {
116
+ return this.isNoTiers() || this.isNoFreeTier() || this.isEmailRequired();
117
+ }
82
118
  };
83
119
  async function parseErrorResponse(response, retries) {
84
120
  const requestId = response.headers.get("X-ModelRelay-Chat-Request-Id") || response.headers.get("X-Request-Id") || void 0;
@@ -148,20 +184,47 @@ var AuthClient = class {
148
184
  this.customer = cfg.customer;
149
185
  }
150
186
  /**
151
- * Exchange a publishable key for a short-lived frontend token.
187
+ * Exchange a publishable key for a short-lived frontend token for an existing customer.
152
188
  * Tokens are cached until they are close to expiry.
189
+ *
190
+ * Use this method when the customer already exists in the system.
191
+ * For auto-provisioning new customers, use frontendTokenAutoProvision instead.
153
192
  */
154
193
  async frontendToken(request) {
155
- const publishableKey = request?.publishableKey || (isPublishableKey(this.apiKey) ? this.apiKey : void 0);
156
- if (!publishableKey) {
157
- throw new ConfigError("publishable key required to issue frontend tokens");
194
+ if (!request.publishableKey?.trim()) {
195
+ throw new ConfigError("publishableKey is required");
158
196
  }
159
- const customerId = request?.customerId || this.customer?.id;
160
- if (!customerId) {
161
- throw new ConfigError("customerId is required to mint a frontend token");
197
+ if (!request.customerId?.trim()) {
198
+ throw new ConfigError("customerId is required");
162
199
  }
163
- const deviceId = request?.deviceId || this.customer?.deviceId;
164
- const ttlSeconds = request?.ttlSeconds ?? this.customer?.ttlSeconds;
200
+ return this.sendFrontendTokenRequest(request);
201
+ }
202
+ /**
203
+ * Exchange a publishable key for a frontend token, creating the customer if needed.
204
+ * The customer will be auto-provisioned on the project's free tier.
205
+ * Tokens are cached until they are close to expiry.
206
+ *
207
+ * Use this method when the customer may not exist and should be created automatically.
208
+ * The email is required for auto-provisioning.
209
+ */
210
+ async frontendTokenAutoProvision(request) {
211
+ if (!request.publishableKey?.trim()) {
212
+ throw new ConfigError("publishableKey is required");
213
+ }
214
+ if (!request.customerId?.trim()) {
215
+ throw new ConfigError("customerId is required");
216
+ }
217
+ if (!request.email?.trim()) {
218
+ throw new ConfigError("email is required for auto-provisioning");
219
+ }
220
+ return this.sendFrontendTokenRequest(request);
221
+ }
222
+ /**
223
+ * Internal method to send frontend token requests.
224
+ */
225
+ async sendFrontendTokenRequest(request) {
226
+ const { publishableKey, customerId, deviceId, ttlSeconds } = request;
227
+ const email = "email" in request ? request.email : void 0;
165
228
  const cacheKey = `${publishableKey}:${customerId}:${deviceId || ""}`;
166
229
  const cached = this.cachedFrontend.get(cacheKey);
167
230
  if (cached && isTokenReusable(cached)) {
@@ -177,6 +240,9 @@ var AuthClient = class {
177
240
  if (typeof ttlSeconds === "number" && ttlSeconds > 0) {
178
241
  payload.ttl_seconds = ttlSeconds;
179
242
  }
243
+ if (email) {
244
+ payload.email = email;
245
+ }
180
246
  const response = await this.http.json(
181
247
  "/auth/frontend-token",
182
248
  {
@@ -204,10 +270,15 @@ var AuthClient = class {
204
270
  throw new ConfigError("API key or token is required");
205
271
  }
206
272
  if (isPublishableKey(this.apiKey)) {
273
+ const resolvedCustomerId = customerId || overrides?.id || this.customer?.id;
274
+ if (!resolvedCustomerId) {
275
+ throw new ConfigError("customerId is required to mint a frontend token");
276
+ }
207
277
  const token = await this.frontendToken({
208
- customerId: customerId || overrides?.id,
209
- deviceId: overrides?.deviceId,
210
- ttlSeconds: overrides?.ttlSeconds
278
+ publishableKey: this.apiKey,
279
+ customerId: resolvedCustomerId,
280
+ deviceId: overrides?.deviceId || this.customer?.deviceId,
281
+ ttlSeconds: overrides?.ttlSeconds ?? this.customer?.ttlSeconds
211
282
  });
212
283
  return createAccessTokenAuth(token.token);
213
284
  }
@@ -261,7 +332,7 @@ function isTokenReusable(token) {
261
332
  // package.json
262
333
  var package_default = {
263
334
  name: "@modelrelay/sdk",
264
- version: "0.19.0",
335
+ version: "0.21.0",
265
336
  description: "TypeScript SDK for the ModelRelay API",
266
337
  type: "module",
267
338
  main: "dist/index.cjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelrelay/sdk",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "description": "TypeScript SDK for the ModelRelay API",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",