@modelrelay/sdk 0.2.0 → 0.4.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ModelRelay TypeScript SDK
2
2
 
3
- Typed client for browsers and Node.js that wraps the ModelRelay API. It exchanges publishable keys for frontend tokens, starts Stripe Checkout for end users, and proxies chat completions with SSE handling.
3
+ Typed client for Node.js that wraps the ModelRelay API for **consuming** LLM/usage endpoints. Use secret API keys or bearer tokens issued by your backend; publishable-key frontend token flows have been removed.
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,21 +14,12 @@ bun add @modelrelay/sdk
14
14
  ```ts
15
15
  import { ModelRelay } from "@modelrelay/sdk";
16
16
 
17
- // Use a publishable key for client-side apps.
17
+ // Use a secret key or bearer token from your backend.
18
18
  const mr = new ModelRelay({
19
- key: "mr_pk_...",
20
- endUser: { id: "user-123" } // required when using publishable keys
19
+ key: "mr_sk_..."
21
20
  });
22
21
 
23
- // 1. Start an end-user Stripe checkout.
24
- await mr.billing.checkout({
25
- endUserId: "user-123",
26
- planId: "pro-plan",
27
- successUrl: window.location.origin + "/success",
28
- cancelUrl: window.location.origin + "/cancel"
29
- });
30
-
31
- // 2. Stream chat completions (publishable keys are exchanged for a frontend token automatically).
22
+ // Stream chat completions.
32
23
  const stream = await mr.chat.completions.create({
33
24
  model: "grok-4-1-fast-reasoning",
34
25
  messages: [{ role: "user", content: "Hello" }]
@@ -41,18 +32,9 @@ for await (const event of stream) {
41
32
  }
42
33
  ```
43
34
 
44
- ### Manual frontend token exchange
45
-
46
- If you need to mint the token yourself (e.g., to store in your app state):
47
-
48
- ```ts
49
- const token = await mr.auth.frontendToken({ userId: "user-123" });
50
- const chat = new ModelRelay({ token: token.token });
51
- ```
52
-
53
35
  ### Server-side usage
54
36
 
55
- Provide a secret API key or bearer token instead of a publishable key:
37
+ Provide a secret API key or bearer token:
56
38
 
57
39
  ```ts
58
40
  const mr = new ModelRelay({ key: "mr_sk_..." });
@@ -72,15 +54,115 @@ console.log(completion.content.join(""));
72
54
 
73
55
  - **Environments**: `environment: "production" | "staging" | "sandbox"` or override `baseUrl`.
74
56
  - **Auth**: pass a secret/publishable `key` or a bearer `token`. Publishable keys mint frontend tokens automatically.
75
- - **Timeouts & retries**: `timeoutMs` (default 60s, set `0` to disable) and `retry` (`{ maxAttempts, baseBackoffMs, maxBackoffMs, retryPost }` or `false` to disable).
57
+ - **Timeouts & retries**: `connectTimeoutMs` (default 5s per attempt) and `timeoutMs` (default 60s overall; set `0` to disable). Per-call overrides available on `chat.completions.create`. `retry` config (`{ maxAttempts, baseBackoffMs, maxBackoffMs, retryPost }` or `false`) controls exponential backoff with jitter.
76
58
  - **Headers & metadata**: `defaultHeaders` are sent with every request; `defaultMetadata` merges into every chat request and can be overridden per-call via `metadata`.
77
59
  - **Client header**: set `clientHeader` to override the telemetry header (defaults to `modelrelay-ts/<version>`).
78
60
 
61
+ ### Timeouts & retry examples
62
+
63
+ ```ts
64
+ // Shorten connect + request timeouts globally
65
+ const mr = new ModelRelay({
66
+ key: "mr_sk_...",
67
+ connectTimeoutMs: 3_000,
68
+ timeoutMs: 20_000,
69
+ retry: { maxAttempts: 4, baseBackoffMs: 200, maxBackoffMs: 2_000 }
70
+ });
71
+
72
+ // Per-call overrides (blocking)
73
+ await mr.chat.completions.create(
74
+ { model: "grok-4-1-fast-reasoning", messages: [{ role: "user", content: "Hi" }], stream: false },
75
+ { timeoutMs: 5_000, retry: false }
76
+ );
77
+
78
+ // Streaming: keep connect timeout but disable request timeout
79
+ const stream = await mr.chat.completions.create(
80
+ { model: "grok-4-1-fast-reasoning", messages: [{ role: "user", content: "Hi" }] },
81
+ { connectTimeoutMs: 2_000 } // request timeout is already disabled for streams by default
82
+ );
83
+ ```
84
+
85
+ ### Typed models, providers, and stop reasons
86
+
87
+ - Models and providers use string literal unions with an `Other` escape hatch: pass `{ other: "my-provider" }` or `{ other: "custom/model-x" }` to preserve custom IDs while benefiting from autocomplete on known values (e.g., `Models.OpenAIGpt4o`, `Providers.Anthropic`).
88
+ - Stop reasons are parsed into the `StopReason` union (e.g., `StopReasons.EndTurn`); unknown values surface as `{ other: "<raw>" }`.
89
+ - Usage backfills `totalTokens` when providers omit it, ensuring consistent accounting.
90
+
91
+ ### Telemetry & metrics hooks
92
+
93
+ Provide lightweight callbacks to observe latency and usage without extra deps:
94
+
95
+ ```ts
96
+ const calls: string[] = [];
97
+ const mr = new ModelRelay({
98
+ key: "mr_sk_...",
99
+ metrics: {
100
+ httpRequest: (m) => calls.push(`http ${m.context.path} ${m.status} ${m.latencyMs}ms`),
101
+ streamFirstToken: (m) => calls.push(`first-token ${m.latencyMs}ms`),
102
+ usage: (m) => calls.push(`usage ${m.usage.totalTokens}`)
103
+ },
104
+ trace: {
105
+ streamEvent: ({ event }) => calls.push(`event ${event.type}`),
106
+ requestFinish: ({ status, latencyMs }) => calls.push(`finished ${status} in ${latencyMs}`)
107
+ }
108
+ });
109
+
110
+ // Per-call overrides
111
+ await mr.chat.completions.create(
112
+ { model: "echo-1", messages: [{ role: "user", content: "hi" }] },
113
+ { metrics: { usage: console.log }, trace: { streamEvent: console.debug } }
114
+ );
115
+ ```
116
+
117
+ ### Error categories
118
+
119
+ - **ConfigError**: missing key/token, invalid base URL, or request validation issues.
120
+ - **TransportError**: network/connect/request/timeout failures (`kind` is one of `connect | timeout | request | other`), includes retry metadata when retries were attempted.
121
+ - **APIError**: Non-2xx responses with `status`, `code`, `fields`, `requestId`, and optional `retries` metadata.
122
+
79
123
  ## API surface
80
124
 
81
- - `auth.frontendToken()` — exchange publishable keys for short-lived frontend tokens (cached until expiry).
82
125
  - `chat.completions.create(params, options?)`
83
126
  - Supports streaming (default) or blocking JSON (`stream: false`).
84
127
  - Accepts per-call `requestId`, `headers`, `metadata`, `timeoutMs`, and `retry` overrides.
85
- - `billing.checkout()` — start an end-user Stripe Checkout session.
86
128
  - `apiKeys.list() | create() | delete(id)` — manage API keys when using secret keys or bearer tokens.
129
+ - `customers` — manage customers with a secret key (see below).
130
+
131
+ ## Backend Customer Management
132
+
133
+ Use a secret key (`mr_sk_*`) to manage customers from your backend:
134
+
135
+ ```ts
136
+ import { ModelRelay } from "@modelrelay/sdk";
137
+
138
+ const mr = new ModelRelay({ key: "mr_sk_..." });
139
+
140
+ // Create or update a customer (upsert by external_id)
141
+ const customer = await mr.customers.upsert({
142
+ tier_id: "your-tier-uuid",
143
+ external_id: "github-user-12345", // your app's user ID
144
+ email: "user@example.com",
145
+ });
146
+
147
+ // List all customers
148
+ const customers = await mr.customers.list();
149
+
150
+ // Get a specific customer
151
+ const customer = await mr.customers.get("customer-uuid");
152
+
153
+ // Create a checkout session for subscription billing
154
+ const session = await mr.customers.createCheckoutSession("customer-uuid", {
155
+ success_url: "https://myapp.com/billing/success",
156
+ cancel_url: "https://myapp.com/billing/cancel",
157
+ });
158
+ // Redirect user to session.url to complete payment
159
+
160
+ // Check subscription status
161
+ const status = await mr.customers.getSubscription("customer-uuid");
162
+ if (status.active) {
163
+ // Grant access
164
+ }
165
+
166
+ // Delete a customer
167
+ await mr.customers.delete("customer-uuid");
168
+ ```