realtime-avatar 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NQJK3QD7.js → chunk-2V333KRZ.js} +1 -1
- package/dist/{chunk-QC5BVIUO.js → chunk-OMOEUVO5.js} +1 -1
- package/dist/express.js +2 -2
- package/dist/hono.js +2 -2
- package/dist/index.js +1 -1
- package/dist/nextjs.js +2 -2
- package/dist/react-native.js +140 -2
- package/dist/react.js +140 -2
- package/dist/server.js +1 -1
- package/dist/tanstack-start.js +2 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-
|
|
1
|
+
import { RealtimeAvatar, isQueued, RealtimeAvatarHttpError } from './chunk-2V333KRZ.js';
|
|
2
2
|
|
|
3
3
|
// ../proxy/src/config.ts
|
|
4
4
|
var json = (body, status = 200) => new Response(JSON.stringify(body), {
|
package/dist/express.js
CHANGED
package/dist/hono.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, isQueued, verifyTranscript } from './chunk-
|
|
1
|
+
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, isQueued, verifyTranscript } from './chunk-2V333KRZ.js';
|
package/dist/nextjs.js
CHANGED
package/dist/react-native.js
CHANGED
|
@@ -131,6 +131,43 @@ function timeoutSetter(fn, ms) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
// ../client/src/errors.ts
|
|
134
|
+
var RealtimeAvatarApiError = class _RealtimeAvatarApiError extends Error {
|
|
135
|
+
constructor(message, status, body, response, metadata = {}) {
|
|
136
|
+
super(message);
|
|
137
|
+
this.status = status;
|
|
138
|
+
this.body = body;
|
|
139
|
+
this.response = response;
|
|
140
|
+
this.name = "RealtimeAvatarApiError";
|
|
141
|
+
this.code = metadata.code;
|
|
142
|
+
this.retryable = metadata.retryable;
|
|
143
|
+
this.billingUrl = metadata.billingUrl;
|
|
144
|
+
this.rawMessage = metadata.rawMessage ?? null;
|
|
145
|
+
}
|
|
146
|
+
status;
|
|
147
|
+
body;
|
|
148
|
+
response;
|
|
149
|
+
code;
|
|
150
|
+
retryable;
|
|
151
|
+
billingUrl;
|
|
152
|
+
/** Debug detail returned by the API. Do not render directly in user-facing UI. */
|
|
153
|
+
rawMessage;
|
|
154
|
+
get isBillingRequired() {
|
|
155
|
+
return this.status === 402 || this.code === "insufficient_credits" || this.code === "spend_limit_exceeded";
|
|
156
|
+
}
|
|
157
|
+
static async fromResponse(response) {
|
|
158
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
159
|
+
const body = contentType.includes("application/json") ? await response.clone().json().catch(() => null) : await response.clone().text().catch(() => "");
|
|
160
|
+
const rawMessage = (extractErrorMessage(body) ?? response.statusText) || null;
|
|
161
|
+
const metadata = extractErrorMetadata(body, response.status, rawMessage);
|
|
162
|
+
return new _RealtimeAvatarApiError(
|
|
163
|
+
metadata.message,
|
|
164
|
+
response.status,
|
|
165
|
+
body,
|
|
166
|
+
response,
|
|
167
|
+
metadata
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
134
171
|
var RealtimeAvatarCapacityError = class extends Error {
|
|
135
172
|
constructor(message, busy) {
|
|
136
173
|
super(message);
|
|
@@ -151,6 +188,107 @@ var RealtimeAvatarCapacityError = class extends Error {
|
|
|
151
188
|
return this.busy.recommended_retry_ms;
|
|
152
189
|
}
|
|
153
190
|
};
|
|
191
|
+
function extractErrorMessage(body) {
|
|
192
|
+
if (!body || typeof body !== "object") return typeof body === "string" && body ? body : null;
|
|
193
|
+
const record = body;
|
|
194
|
+
const detail = readMessageValue(record.detail);
|
|
195
|
+
if (detail) return detail;
|
|
196
|
+
const error = readMessageValue(record.error);
|
|
197
|
+
if (error) return error;
|
|
198
|
+
const message = readMessageValue(record.message);
|
|
199
|
+
if (message) return message;
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
function normalizeRealtimeAvatarError(input) {
|
|
203
|
+
const status = input.status ?? 0;
|
|
204
|
+
const rawCode = input.code?.trim() || null;
|
|
205
|
+
const rawMessage = input.message?.trim() || "";
|
|
206
|
+
const blob = `${rawCode ?? ""} ${rawMessage}`.toLowerCase();
|
|
207
|
+
if (rawCode === "insufficient_credits" || rawCode === "spend_limit_exceeded" || status === 402) {
|
|
208
|
+
return {
|
|
209
|
+
code: rawCode ?? "billing_required",
|
|
210
|
+
message: rawMessage && !hasInternalDetail(rawMessage) ? rawMessage : "Add credits to continue using realtime avatars.",
|
|
211
|
+
retryable: false
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (status === 401) {
|
|
215
|
+
return { code: "unauthorized", message: "Authentication is required to use Realtime Avatar.", retryable: false };
|
|
216
|
+
}
|
|
217
|
+
if (status === 403) {
|
|
218
|
+
return { code: "forbidden", message: "This API key does not have access to that action.", retryable: false };
|
|
219
|
+
}
|
|
220
|
+
if (status === 404 || blob.includes("unknown avatar_id") || blob.includes("avatar not found")) {
|
|
221
|
+
return { code: "not_found", message: "We could not find that avatar or resource.", retryable: false };
|
|
222
|
+
}
|
|
223
|
+
if (status === 409) {
|
|
224
|
+
return { code: "conflict", message: "That request is already in progress. Try again in a moment.", retryable: true };
|
|
225
|
+
}
|
|
226
|
+
if (status === 429) {
|
|
227
|
+
return { code: "rate_limited", message: "Too many realtime requests. Please slow down and retry.", retryable: true };
|
|
228
|
+
}
|
|
229
|
+
if (isWarmingMessage(blob)) {
|
|
230
|
+
return { code: "service_unavailable", message: "Realtime Avatar is warming up. Try again in a moment.", retryable: true };
|
|
231
|
+
}
|
|
232
|
+
if (status === 400 || status === 422) {
|
|
233
|
+
return { code: "invalid_request", message: userSafeMessage(rawMessage) ?? "Check the request and try again.", retryable: false };
|
|
234
|
+
}
|
|
235
|
+
if (status >= 500) {
|
|
236
|
+
return { code: "service_unavailable", message: "Realtime Avatar is temporarily unavailable. Try again in a moment.", retryable: true };
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
code: isPublicErrorCode(rawCode) ? rawCode : "request_failed",
|
|
240
|
+
message: userSafeMessage(rawMessage) ?? "Realtime Avatar request failed. Try again.",
|
|
241
|
+
retryable: status === 0 || status >= 500
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function extractErrorMetadata(body, status, rawMessage) {
|
|
245
|
+
if (!body || typeof body !== "object") {
|
|
246
|
+
const normalized2 = normalizeRealtimeAvatarError({ status, message: rawMessage });
|
|
247
|
+
return { ...normalized2, rawMessage };
|
|
248
|
+
}
|
|
249
|
+
const record = body;
|
|
250
|
+
const code = typeof record.code === "string" ? record.code : null;
|
|
251
|
+
const normalized = normalizeRealtimeAvatarError({ status, code, message: rawMessage });
|
|
252
|
+
return {
|
|
253
|
+
code: normalized.code,
|
|
254
|
+
retryable: typeof record.retryable === "boolean" ? record.retryable : normalized.retryable,
|
|
255
|
+
...typeof record.billingUrl === "string" ? { billingUrl: record.billingUrl } : {},
|
|
256
|
+
rawMessage,
|
|
257
|
+
message: normalized.message
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
261
|
+
"billing_required",
|
|
262
|
+
"invalid_request",
|
|
263
|
+
"unauthorized",
|
|
264
|
+
"forbidden",
|
|
265
|
+
"not_found",
|
|
266
|
+
"conflict",
|
|
267
|
+
"rate_limited",
|
|
268
|
+
"service_unavailable",
|
|
269
|
+
"request_failed",
|
|
270
|
+
"network_error"
|
|
271
|
+
]);
|
|
272
|
+
function isPublicErrorCode(code) {
|
|
273
|
+
return Boolean(code && PUBLIC_ERROR_CODES.has(code));
|
|
274
|
+
}
|
|
275
|
+
function readMessageValue(value) {
|
|
276
|
+
if (typeof value === "string") return value.trim() || null;
|
|
277
|
+
if (!value || typeof value !== "object") return null;
|
|
278
|
+
const record = value;
|
|
279
|
+
return readMessageValue(record.message) ?? readMessageValue(record.error) ?? readMessageValue(record.detail);
|
|
280
|
+
}
|
|
281
|
+
function userSafeMessage(message) {
|
|
282
|
+
if (!message || hasInternalDetail(message)) return null;
|
|
283
|
+
return message.length > 180 ? `${message.slice(0, 177)}...` : message;
|
|
284
|
+
}
|
|
285
|
+
function isWarmingMessage(blob) {
|
|
286
|
+
return blob.includes("warming") || blob.includes("not ready") || blob.includes("starting up");
|
|
287
|
+
}
|
|
288
|
+
var MACHINE_SHAPED = /[_=<>{}\[\]|\\$`]|\w+\.\w+\.\w|\S:\d|\w\(\)|^\s*(?:at|File)\b/mu;
|
|
289
|
+
function hasInternalDetail(message) {
|
|
290
|
+
return MACHINE_SHAPED.test(message);
|
|
291
|
+
}
|
|
154
292
|
function splitCallTranscript(all, localIdentity) {
|
|
155
293
|
if (!localIdentity) return { user: [], agent: all };
|
|
156
294
|
const user = [];
|
|
@@ -1697,6 +1835,7 @@ function useSessionLifecycle(input) {
|
|
|
1697
1835
|
if (!active || connected || connectWatchdogMs <= 0) return;
|
|
1698
1836
|
if (grantState.status !== "ready" || !grantState.grant) return;
|
|
1699
1837
|
if (recovery.kind === "failed" || recovery.kind === "ended") return;
|
|
1838
|
+
if (recovery.kind === "in-place-reconnecting") return;
|
|
1700
1839
|
const timer = window.setTimeout(() => {
|
|
1701
1840
|
releaseRef.current("disconnected");
|
|
1702
1841
|
setRecovery({ kind: "reconnecting", attempt: attemptRef.current });
|
|
@@ -2389,8 +2528,7 @@ function createProxyClient(options) {
|
|
|
2389
2528
|
return { status: "busy", busy };
|
|
2390
2529
|
}
|
|
2391
2530
|
if (!response.ok) {
|
|
2392
|
-
|
|
2393
|
-
throw new Error(`realtime-avatar: proxy refused the call (${response.status}) ${detail}`.trim());
|
|
2531
|
+
throw await RealtimeAvatarApiError.fromResponse(response);
|
|
2394
2532
|
}
|
|
2395
2533
|
return { status: "ready", grant: await response.json() };
|
|
2396
2534
|
},
|
package/dist/react.js
CHANGED
|
@@ -90,6 +90,43 @@ function timeoutSetter(fn, ms) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
// ../client/src/errors.ts
|
|
93
|
+
var RealtimeAvatarApiError = class _RealtimeAvatarApiError extends Error {
|
|
94
|
+
constructor(message, status, body, response, metadata = {}) {
|
|
95
|
+
super(message);
|
|
96
|
+
this.status = status;
|
|
97
|
+
this.body = body;
|
|
98
|
+
this.response = response;
|
|
99
|
+
this.name = "RealtimeAvatarApiError";
|
|
100
|
+
this.code = metadata.code;
|
|
101
|
+
this.retryable = metadata.retryable;
|
|
102
|
+
this.billingUrl = metadata.billingUrl;
|
|
103
|
+
this.rawMessage = metadata.rawMessage ?? null;
|
|
104
|
+
}
|
|
105
|
+
status;
|
|
106
|
+
body;
|
|
107
|
+
response;
|
|
108
|
+
code;
|
|
109
|
+
retryable;
|
|
110
|
+
billingUrl;
|
|
111
|
+
/** Debug detail returned by the API. Do not render directly in user-facing UI. */
|
|
112
|
+
rawMessage;
|
|
113
|
+
get isBillingRequired() {
|
|
114
|
+
return this.status === 402 || this.code === "insufficient_credits" || this.code === "spend_limit_exceeded";
|
|
115
|
+
}
|
|
116
|
+
static async fromResponse(response) {
|
|
117
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
118
|
+
const body = contentType.includes("application/json") ? await response.clone().json().catch(() => null) : await response.clone().text().catch(() => "");
|
|
119
|
+
const rawMessage = (extractErrorMessage(body) ?? response.statusText) || null;
|
|
120
|
+
const metadata = extractErrorMetadata(body, response.status, rawMessage);
|
|
121
|
+
return new _RealtimeAvatarApiError(
|
|
122
|
+
metadata.message,
|
|
123
|
+
response.status,
|
|
124
|
+
body,
|
|
125
|
+
response,
|
|
126
|
+
metadata
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
93
130
|
var RealtimeAvatarCapacityError = class extends Error {
|
|
94
131
|
constructor(message, busy) {
|
|
95
132
|
super(message);
|
|
@@ -110,6 +147,107 @@ var RealtimeAvatarCapacityError = class extends Error {
|
|
|
110
147
|
return this.busy.recommended_retry_ms;
|
|
111
148
|
}
|
|
112
149
|
};
|
|
150
|
+
function extractErrorMessage(body) {
|
|
151
|
+
if (!body || typeof body !== "object") return typeof body === "string" && body ? body : null;
|
|
152
|
+
const record = body;
|
|
153
|
+
const detail = readMessageValue(record.detail);
|
|
154
|
+
if (detail) return detail;
|
|
155
|
+
const error = readMessageValue(record.error);
|
|
156
|
+
if (error) return error;
|
|
157
|
+
const message = readMessageValue(record.message);
|
|
158
|
+
if (message) return message;
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
function normalizeRealtimeAvatarError(input) {
|
|
162
|
+
const status = input.status ?? 0;
|
|
163
|
+
const rawCode = input.code?.trim() || null;
|
|
164
|
+
const rawMessage = input.message?.trim() || "";
|
|
165
|
+
const blob = `${rawCode ?? ""} ${rawMessage}`.toLowerCase();
|
|
166
|
+
if (rawCode === "insufficient_credits" || rawCode === "spend_limit_exceeded" || status === 402) {
|
|
167
|
+
return {
|
|
168
|
+
code: rawCode ?? "billing_required",
|
|
169
|
+
message: rawMessage && !hasInternalDetail(rawMessage) ? rawMessage : "Add credits to continue using realtime avatars.",
|
|
170
|
+
retryable: false
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (status === 401) {
|
|
174
|
+
return { code: "unauthorized", message: "Authentication is required to use Realtime Avatar.", retryable: false };
|
|
175
|
+
}
|
|
176
|
+
if (status === 403) {
|
|
177
|
+
return { code: "forbidden", message: "This API key does not have access to that action.", retryable: false };
|
|
178
|
+
}
|
|
179
|
+
if (status === 404 || blob.includes("unknown avatar_id") || blob.includes("avatar not found")) {
|
|
180
|
+
return { code: "not_found", message: "We could not find that avatar or resource.", retryable: false };
|
|
181
|
+
}
|
|
182
|
+
if (status === 409) {
|
|
183
|
+
return { code: "conflict", message: "That request is already in progress. Try again in a moment.", retryable: true };
|
|
184
|
+
}
|
|
185
|
+
if (status === 429) {
|
|
186
|
+
return { code: "rate_limited", message: "Too many realtime requests. Please slow down and retry.", retryable: true };
|
|
187
|
+
}
|
|
188
|
+
if (isWarmingMessage(blob)) {
|
|
189
|
+
return { code: "service_unavailable", message: "Realtime Avatar is warming up. Try again in a moment.", retryable: true };
|
|
190
|
+
}
|
|
191
|
+
if (status === 400 || status === 422) {
|
|
192
|
+
return { code: "invalid_request", message: userSafeMessage(rawMessage) ?? "Check the request and try again.", retryable: false };
|
|
193
|
+
}
|
|
194
|
+
if (status >= 500) {
|
|
195
|
+
return { code: "service_unavailable", message: "Realtime Avatar is temporarily unavailable. Try again in a moment.", retryable: true };
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
code: isPublicErrorCode(rawCode) ? rawCode : "request_failed",
|
|
199
|
+
message: userSafeMessage(rawMessage) ?? "Realtime Avatar request failed. Try again.",
|
|
200
|
+
retryable: status === 0 || status >= 500
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function extractErrorMetadata(body, status, rawMessage) {
|
|
204
|
+
if (!body || typeof body !== "object") {
|
|
205
|
+
const normalized2 = normalizeRealtimeAvatarError({ status, message: rawMessage });
|
|
206
|
+
return { ...normalized2, rawMessage };
|
|
207
|
+
}
|
|
208
|
+
const record = body;
|
|
209
|
+
const code = typeof record.code === "string" ? record.code : null;
|
|
210
|
+
const normalized = normalizeRealtimeAvatarError({ status, code, message: rawMessage });
|
|
211
|
+
return {
|
|
212
|
+
code: normalized.code,
|
|
213
|
+
retryable: typeof record.retryable === "boolean" ? record.retryable : normalized.retryable,
|
|
214
|
+
...typeof record.billingUrl === "string" ? { billingUrl: record.billingUrl } : {},
|
|
215
|
+
rawMessage,
|
|
216
|
+
message: normalized.message
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
220
|
+
"billing_required",
|
|
221
|
+
"invalid_request",
|
|
222
|
+
"unauthorized",
|
|
223
|
+
"forbidden",
|
|
224
|
+
"not_found",
|
|
225
|
+
"conflict",
|
|
226
|
+
"rate_limited",
|
|
227
|
+
"service_unavailable",
|
|
228
|
+
"request_failed",
|
|
229
|
+
"network_error"
|
|
230
|
+
]);
|
|
231
|
+
function isPublicErrorCode(code) {
|
|
232
|
+
return Boolean(code && PUBLIC_ERROR_CODES.has(code));
|
|
233
|
+
}
|
|
234
|
+
function readMessageValue(value) {
|
|
235
|
+
if (typeof value === "string") return value.trim() || null;
|
|
236
|
+
if (!value || typeof value !== "object") return null;
|
|
237
|
+
const record = value;
|
|
238
|
+
return readMessageValue(record.message) ?? readMessageValue(record.error) ?? readMessageValue(record.detail);
|
|
239
|
+
}
|
|
240
|
+
function userSafeMessage(message) {
|
|
241
|
+
if (!message || hasInternalDetail(message)) return null;
|
|
242
|
+
return message.length > 180 ? `${message.slice(0, 177)}...` : message;
|
|
243
|
+
}
|
|
244
|
+
function isWarmingMessage(blob) {
|
|
245
|
+
return blob.includes("warming") || blob.includes("not ready") || blob.includes("starting up");
|
|
246
|
+
}
|
|
247
|
+
var MACHINE_SHAPED = /[_=<>{}\[\]|\\$`]|\w+\.\w+\.\w|\S:\d|\w\(\)|^\s*(?:at|File)\b/mu;
|
|
248
|
+
function hasInternalDetail(message) {
|
|
249
|
+
return MACHINE_SHAPED.test(message);
|
|
250
|
+
}
|
|
113
251
|
function splitCallTranscript(all, localIdentity) {
|
|
114
252
|
if (!localIdentity) return { user: [], agent: all };
|
|
115
253
|
const user = [];
|
|
@@ -1920,6 +2058,7 @@ function useSessionLifecycle(input) {
|
|
|
1920
2058
|
if (!active || connected || connectWatchdogMs <= 0) return;
|
|
1921
2059
|
if (grantState.status !== "ready" || !grantState.grant) return;
|
|
1922
2060
|
if (recovery.kind === "failed" || recovery.kind === "ended") return;
|
|
2061
|
+
if (recovery.kind === "in-place-reconnecting") return;
|
|
1923
2062
|
const timer = window.setTimeout(() => {
|
|
1924
2063
|
releaseRef.current("disconnected");
|
|
1925
2064
|
setRecovery({ kind: "reconnecting", attempt: attemptRef.current });
|
|
@@ -2694,8 +2833,7 @@ function createProxyClient(options) {
|
|
|
2694
2833
|
return { status: "busy", busy };
|
|
2695
2834
|
}
|
|
2696
2835
|
if (!response.ok) {
|
|
2697
|
-
|
|
2698
|
-
throw new Error(`realtime-avatar: proxy refused the call (${response.status}) ${detail}`.trim());
|
|
2836
|
+
throw await RealtimeAvatarApiError.fromResponse(response);
|
|
2699
2837
|
}
|
|
2700
2838
|
return { status: "ready", grant: await response.json() };
|
|
2701
2839
|
},
|
package/dist/server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, isQueued, verifyTranscript } from './chunk-
|
|
1
|
+
export { RealtimeAvatar, RealtimeAvatarError, RealtimeAvatarHttpError, isQueued, verifyTranscript } from './chunk-2V333KRZ.js';
|
package/dist/tanstack-start.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "realtime-avatar",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Realtime Avatar SDK. `realtime-avatar` and the route adapters hold your API key and are server-only; `realtime-avatar/react`, `/browser` and `/tools` never can — importing a server entry into a browser build throws at bundle time.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "The Influence Company",
|