@scalemule/nextjs 0.1.17 → 0.1.19
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 +3 -1
- package/dist/client.d.mts +13 -1
- package/dist/client.d.ts +13 -1
- package/dist/client.js +32 -0
- package/dist/client.mjs +32 -0
- package/dist/index.d.mts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +94 -3
- package/dist/index.mjs +94 -4
- package/dist/server/auth.js +130 -21
- package/dist/server/auth.mjs +130 -21
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +808 -658
- package/dist/server/index.mjs +809 -659
- package/dist/server/webhook-handler.d.mts +1 -1
- package/dist/server/webhook-handler.d.ts +1 -1
- package/package.json +2 -2
- package/dist/index-DTWyUcyd.d.mts +0 -919
- package/dist/index-DTWyUcyd.d.ts +0 -919
- package/dist/ledvery-CxPzZpxP.d.mts +0 -44
- package/dist/ledvery-CxPzZpxP.d.ts +0 -44
- package/dist/server/ledvery.d.mts +0 -1
- package/dist/server/ledvery.d.ts +0 -1
- package/dist/server/ledvery.js +0 -336
- package/dist/server/ledvery.mjs +0 -333
- package/dist/webhook-handler-C07AK4QB.d.ts +0 -782
- package/dist/webhook-handler-CUp_A0_p.d.mts +0 -782
package/README.md
CHANGED
|
@@ -34,6 +34,8 @@ This creates all auth endpoints automatically:
|
|
|
34
34
|
|
|
35
35
|
API keys never reach the browser. Session tokens are HTTP-only cookies.
|
|
36
36
|
|
|
37
|
+
Need the cookie/header lifecycle or the proxy-vs-direct decision tree? See [`docs/AUTH_PROXY_PATTERN.md`](./docs/AUTH_PROXY_PATTERN.md).
|
|
38
|
+
|
|
37
39
|
## Environment Variables
|
|
38
40
|
|
|
39
41
|
```bash
|
|
@@ -295,7 +297,7 @@ export const { GET, POST, DELETE, PATCH } = createAuthRoutes({
|
|
|
295
297
|
|
|
296
298
|
```ts
|
|
297
299
|
// Read CSRF token from cookie and include in requests
|
|
298
|
-
const csrfToken = document.cookie.match(/
|
|
300
|
+
const csrfToken = document.cookie.match(/sm_csrf=([^;]+)/)?.[1]
|
|
299
301
|
|
|
300
302
|
fetch('/api/auth/login', {
|
|
301
303
|
method: 'POST',
|
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a8 as StorageAdapter } from './index-DTWyUcyd.mjs';
|
|
1
|
+
import { a8 as StorageAdapter, A as ApiError } from './index-DTWyUcyd.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* ScaleMule API Client
|
|
@@ -38,6 +38,12 @@ interface ClientConfig {
|
|
|
38
38
|
enableAccountSwitcher?: boolean;
|
|
39
39
|
/** Privacy level for account switcher */
|
|
40
40
|
accountSwitcherPrivacy?: 'full' | 'masked' | 'minimal';
|
|
41
|
+
/** Optional: Callback when a 401 auto-refresh starts. */
|
|
42
|
+
onRefreshStart?: () => void;
|
|
43
|
+
/** Optional: Callback when a 401 auto-refresh finishes. */
|
|
44
|
+
onRefreshEnd?: () => void;
|
|
45
|
+
/** Optional: Callback when an automatic 401 refresh fails. */
|
|
46
|
+
onAutoRefreshFailed?: (error: ApiError) => void;
|
|
41
47
|
}
|
|
42
48
|
interface RequestOptions extends RequestInit {
|
|
43
49
|
/** Skip adding auth headers (for public endpoints) */
|
|
@@ -48,6 +54,8 @@ interface RequestOptions extends RequestInit {
|
|
|
48
54
|
retries?: number;
|
|
49
55
|
/** Skip retries */
|
|
50
56
|
skipRetry?: boolean;
|
|
57
|
+
/** Internal flag to prevent infinite refresh loops */
|
|
58
|
+
isAutoRefresh?: boolean;
|
|
51
59
|
}
|
|
52
60
|
/**
|
|
53
61
|
* ScaleMule API Client
|
|
@@ -69,6 +77,10 @@ declare class ScaleMuleClient {
|
|
|
69
77
|
private sessionGate;
|
|
70
78
|
private resolveSessionGate;
|
|
71
79
|
private workspaceId;
|
|
80
|
+
private refreshPromise;
|
|
81
|
+
private onRefreshStart?;
|
|
82
|
+
private onRefreshEnd?;
|
|
83
|
+
private onAutoRefreshFailed?;
|
|
72
84
|
constructor(config: ClientConfig);
|
|
73
85
|
/**
|
|
74
86
|
* Sync offline queue when coming back online
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a8 as StorageAdapter } from './index-DTWyUcyd.js';
|
|
1
|
+
import { a8 as StorageAdapter, A as ApiError } from './index-DTWyUcyd.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* ScaleMule API Client
|
|
@@ -38,6 +38,12 @@ interface ClientConfig {
|
|
|
38
38
|
enableAccountSwitcher?: boolean;
|
|
39
39
|
/** Privacy level for account switcher */
|
|
40
40
|
accountSwitcherPrivacy?: 'full' | 'masked' | 'minimal';
|
|
41
|
+
/** Optional: Callback when a 401 auto-refresh starts. */
|
|
42
|
+
onRefreshStart?: () => void;
|
|
43
|
+
/** Optional: Callback when a 401 auto-refresh finishes. */
|
|
44
|
+
onRefreshEnd?: () => void;
|
|
45
|
+
/** Optional: Callback when an automatic 401 refresh fails. */
|
|
46
|
+
onAutoRefreshFailed?: (error: ApiError) => void;
|
|
41
47
|
}
|
|
42
48
|
interface RequestOptions extends RequestInit {
|
|
43
49
|
/** Skip adding auth headers (for public endpoints) */
|
|
@@ -48,6 +54,8 @@ interface RequestOptions extends RequestInit {
|
|
|
48
54
|
retries?: number;
|
|
49
55
|
/** Skip retries */
|
|
50
56
|
skipRetry?: boolean;
|
|
57
|
+
/** Internal flag to prevent infinite refresh loops */
|
|
58
|
+
isAutoRefresh?: boolean;
|
|
51
59
|
}
|
|
52
60
|
/**
|
|
53
61
|
* ScaleMule API Client
|
|
@@ -69,6 +77,10 @@ declare class ScaleMuleClient {
|
|
|
69
77
|
private sessionGate;
|
|
70
78
|
private resolveSessionGate;
|
|
71
79
|
private workspaceId;
|
|
80
|
+
private refreshPromise;
|
|
81
|
+
private onRefreshStart?;
|
|
82
|
+
private onRefreshEnd?;
|
|
83
|
+
private onAutoRefreshFailed?;
|
|
72
84
|
constructor(config: ClientConfig);
|
|
73
85
|
/**
|
|
74
86
|
* Sync offline queue when coming back online
|
package/dist/client.js
CHANGED
|
@@ -278,6 +278,7 @@ var ScaleMuleClient = class {
|
|
|
278
278
|
this.sessionGate = null;
|
|
279
279
|
this.resolveSessionGate = null;
|
|
280
280
|
this.workspaceId = null;
|
|
281
|
+
this.refreshPromise = null;
|
|
281
282
|
this.apiKey = config.apiKey;
|
|
282
283
|
this.applicationId = config.applicationId || null;
|
|
283
284
|
this.gatewayUrl = resolveGatewayUrl(config);
|
|
@@ -285,6 +286,9 @@ var ScaleMuleClient = class {
|
|
|
285
286
|
this.storage = config.storage || createDefaultStorage();
|
|
286
287
|
this.enableRateLimitQueue = config.enableRateLimitQueue || false;
|
|
287
288
|
this.enableOfflineQueue = config.enableOfflineQueue || false;
|
|
289
|
+
this.onRefreshStart = config.onRefreshStart;
|
|
290
|
+
this.onRefreshEnd = config.onRefreshEnd;
|
|
291
|
+
this.onAutoRefreshFailed = config.onAutoRefreshFailed;
|
|
288
292
|
if (this.enableRateLimitQueue) {
|
|
289
293
|
this.rateLimitQueue = new RateLimitQueue();
|
|
290
294
|
}
|
|
@@ -503,6 +507,10 @@ var ScaleMuleClient = class {
|
|
|
503
507
|
signal: controller.signal
|
|
504
508
|
});
|
|
505
509
|
clearTimeout(timeoutId);
|
|
510
|
+
const rotatedToken = response.headers.get("x-rotated-session-token");
|
|
511
|
+
if (rotatedToken && this.sessionToken && this.userId) {
|
|
512
|
+
this.setSession(rotatedToken, this.userId);
|
|
513
|
+
}
|
|
506
514
|
const text = await response.text();
|
|
507
515
|
let responseData = null;
|
|
508
516
|
try {
|
|
@@ -512,6 +520,30 @@ var ScaleMuleClient = class {
|
|
|
512
520
|
if (!response.ok) {
|
|
513
521
|
const rawError = responseData?.error;
|
|
514
522
|
const error = rawError && typeof rawError === "object" ? rawError : { code: `HTTP_${response.status}`, message: typeof rawError === "string" ? rawError : responseData?.message || text || response.statusText };
|
|
523
|
+
if (response.status === 401 && this.sessionToken && !options.isAutoRefresh) {
|
|
524
|
+
if (this.debug) console.log("[ScaleMule] 401 received, attempting auto-refresh...");
|
|
525
|
+
if (!this.refreshPromise) {
|
|
526
|
+
this.onRefreshStart?.();
|
|
527
|
+
this.refreshPromise = this.post("/api/auth/refresh", {}, { isAutoRefresh: true });
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
await this.refreshPromise;
|
|
531
|
+
if (this.debug) console.log("[ScaleMule] Auto-refresh succeeded, retrying original request...");
|
|
532
|
+
attempt--;
|
|
533
|
+
if (this.sessionToken) {
|
|
534
|
+
headers.set("Authorization", `Bearer ${this.sessionToken}`);
|
|
535
|
+
}
|
|
536
|
+
continue;
|
|
537
|
+
} catch (refreshErr) {
|
|
538
|
+
if (this.debug) console.error("[ScaleMule] Auto-refresh failed:", refreshErr);
|
|
539
|
+
const refreshApiError = refreshErr instanceof ScaleMuleApiError ? { code: refreshErr.code, message: refreshErr.message, field: refreshErr.field } : { code: "REFRESH_FAILED", message: "Auto-refresh failed" };
|
|
540
|
+
this.onAutoRefreshFailed?.(refreshApiError);
|
|
541
|
+
throw new ScaleMuleApiError(error);
|
|
542
|
+
} finally {
|
|
543
|
+
this.refreshPromise = null;
|
|
544
|
+
this.onRefreshEnd?.();
|
|
545
|
+
}
|
|
546
|
+
}
|
|
515
547
|
if (attempt < maxRetries && RETRYABLE_STATUS_CODES.has(response.status)) {
|
|
516
548
|
lastError = error;
|
|
517
549
|
const delay = getBackoffDelay(attempt);
|
package/dist/client.mjs
CHANGED
|
@@ -276,6 +276,7 @@ var ScaleMuleClient = class {
|
|
|
276
276
|
this.sessionGate = null;
|
|
277
277
|
this.resolveSessionGate = null;
|
|
278
278
|
this.workspaceId = null;
|
|
279
|
+
this.refreshPromise = null;
|
|
279
280
|
this.apiKey = config.apiKey;
|
|
280
281
|
this.applicationId = config.applicationId || null;
|
|
281
282
|
this.gatewayUrl = resolveGatewayUrl(config);
|
|
@@ -283,6 +284,9 @@ var ScaleMuleClient = class {
|
|
|
283
284
|
this.storage = config.storage || createDefaultStorage();
|
|
284
285
|
this.enableRateLimitQueue = config.enableRateLimitQueue || false;
|
|
285
286
|
this.enableOfflineQueue = config.enableOfflineQueue || false;
|
|
287
|
+
this.onRefreshStart = config.onRefreshStart;
|
|
288
|
+
this.onRefreshEnd = config.onRefreshEnd;
|
|
289
|
+
this.onAutoRefreshFailed = config.onAutoRefreshFailed;
|
|
286
290
|
if (this.enableRateLimitQueue) {
|
|
287
291
|
this.rateLimitQueue = new RateLimitQueue();
|
|
288
292
|
}
|
|
@@ -501,6 +505,10 @@ var ScaleMuleClient = class {
|
|
|
501
505
|
signal: controller.signal
|
|
502
506
|
});
|
|
503
507
|
clearTimeout(timeoutId);
|
|
508
|
+
const rotatedToken = response.headers.get("x-rotated-session-token");
|
|
509
|
+
if (rotatedToken && this.sessionToken && this.userId) {
|
|
510
|
+
this.setSession(rotatedToken, this.userId);
|
|
511
|
+
}
|
|
504
512
|
const text = await response.text();
|
|
505
513
|
let responseData = null;
|
|
506
514
|
try {
|
|
@@ -510,6 +518,30 @@ var ScaleMuleClient = class {
|
|
|
510
518
|
if (!response.ok) {
|
|
511
519
|
const rawError = responseData?.error;
|
|
512
520
|
const error = rawError && typeof rawError === "object" ? rawError : { code: `HTTP_${response.status}`, message: typeof rawError === "string" ? rawError : responseData?.message || text || response.statusText };
|
|
521
|
+
if (response.status === 401 && this.sessionToken && !options.isAutoRefresh) {
|
|
522
|
+
if (this.debug) console.log("[ScaleMule] 401 received, attempting auto-refresh...");
|
|
523
|
+
if (!this.refreshPromise) {
|
|
524
|
+
this.onRefreshStart?.();
|
|
525
|
+
this.refreshPromise = this.post("/api/auth/refresh", {}, { isAutoRefresh: true });
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
await this.refreshPromise;
|
|
529
|
+
if (this.debug) console.log("[ScaleMule] Auto-refresh succeeded, retrying original request...");
|
|
530
|
+
attempt--;
|
|
531
|
+
if (this.sessionToken) {
|
|
532
|
+
headers.set("Authorization", `Bearer ${this.sessionToken}`);
|
|
533
|
+
}
|
|
534
|
+
continue;
|
|
535
|
+
} catch (refreshErr) {
|
|
536
|
+
if (this.debug) console.error("[ScaleMule] Auto-refresh failed:", refreshErr);
|
|
537
|
+
const refreshApiError = refreshErr instanceof ScaleMuleApiError ? { code: refreshErr.code, message: refreshErr.message, field: refreshErr.field } : { code: "REFRESH_FAILED", message: "Auto-refresh failed" };
|
|
538
|
+
this.onAutoRefreshFailed?.(refreshApiError);
|
|
539
|
+
throw new ScaleMuleApiError(error);
|
|
540
|
+
} finally {
|
|
541
|
+
this.refreshPromise = null;
|
|
542
|
+
this.onRefreshEnd?.();
|
|
543
|
+
}
|
|
544
|
+
}
|
|
513
545
|
if (attempt < maxRetries && RETRYABLE_STATUS_CODES.has(response.status)) {
|
|
514
546
|
lastError = error;
|
|
515
547
|
const delay = getBackoffDelay(attempt);
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, FileStatus } from '@scalemule/sdk';
|
|
2
|
+
import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, TtsService, TtsJobStatus, FileStatus } from '@scalemule/sdk';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { ReactNode, ReactElement } from 'react';
|
|
5
5
|
import { MoneyClient } from '@scalemule/money';
|
|
@@ -166,6 +166,8 @@ interface ScaleMuleContextValue {
|
|
|
166
166
|
video: VideoService;
|
|
167
167
|
/** Base SDK audio service — exposed for `useMedia()` and `audio.uploadViaStorage()` */
|
|
168
168
|
audio: AudioService;
|
|
169
|
+
/** Base SDK TTS service — exposed for `useTtsJob()` and direct narration requests */
|
|
170
|
+
tts: TtsService;
|
|
169
171
|
/**
|
|
170
172
|
* Default media policy for `useMedia()` calls. Set via
|
|
171
173
|
* `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
|
|
@@ -360,6 +362,18 @@ interface UseAudioReturn {
|
|
|
360
362
|
}
|
|
361
363
|
declare function useAudio(): UseAudioReturn;
|
|
362
364
|
|
|
365
|
+
interface UseTtsJobOptions {
|
|
366
|
+
enabled?: boolean;
|
|
367
|
+
pollIntervalMs?: number;
|
|
368
|
+
}
|
|
369
|
+
interface UseTtsJobReturn {
|
|
370
|
+
job: TtsJobStatus | null;
|
|
371
|
+
loading: boolean;
|
|
372
|
+
error: ApiError | null;
|
|
373
|
+
refresh: () => Promise<TtsJobStatus | null>;
|
|
374
|
+
}
|
|
375
|
+
declare function useTtsJob(jobId: string | null | undefined, options?: UseTtsJobOptions): UseTtsJobReturn;
|
|
376
|
+
|
|
363
377
|
/**
|
|
364
378
|
* Conversation kinds recognized by the chat realtime channel naming scheme.
|
|
365
379
|
* Matches `broadcast_to_conversation` in `ms/scalemule-chat/src/realtime.rs`.
|
|
@@ -1032,4 +1046,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
1032
1046
|
error: (message: string, data?: unknown) => void;
|
|
1033
1047
|
};
|
|
1034
1048
|
|
|
1035
|
-
export { ApiError$1 as ApiError, type AudioFile, type AudioUploadResult, type ConversationKind, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, type FeedbackItem, type FeedbackItemInput, type FeedbackPriority, type FeedbackStatus, type FeedbackType, FeedbackWidget, type FeedbackWidgetConfig, type FeedbackWidgetProps, ListFilesParams, LoginResponse, type MediaPolicy, type MediaUploadResult, type PasswordValidationResult, type PhoneCountry, type PhoneValidationResult, type RealtimeEvent, type RealtimeMessage, type RealtimeStatus, ScaleMuleClient, ScaleMuleConfig, ScaleMuleMedia, type ScaleMuleMediaProps, ScaleMuleProvider, type ScaleMuleProviderProps, UseAnalyticsOptions, UseAnalyticsReturn, type UseAudioReturn, type UseAudioUploadOptions, UseAuthReturn, UseBillingReturn, UseContentReturn, type UseFeatureFlagsOptions, type UseFeatureFlagsReturn, type UseFeedbackOptions, type UseFeedbackResult, type UseFileStatusOptions, type UseFileStatusReturn, type UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UseMediaReturn, type UseMediaUploadOptions, type UsePushNotificationsOptions, type UsePushNotificationsReturn, type UseRealtimeOptions, type UseRealtimeReturn, type UseShareOptions, type UseShareReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAudio, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
1049
|
+
export { ApiError$1 as ApiError, type AudioFile, type AudioUploadResult, type ConversationKind, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, type FeedbackItem, type FeedbackItemInput, type FeedbackPriority, type FeedbackStatus, type FeedbackType, FeedbackWidget, type FeedbackWidgetConfig, type FeedbackWidgetProps, ListFilesParams, LoginResponse, type MediaPolicy, type MediaUploadResult, type PasswordValidationResult, type PhoneCountry, type PhoneValidationResult, type RealtimeEvent, type RealtimeMessage, type RealtimeStatus, ScaleMuleClient, ScaleMuleConfig, ScaleMuleMedia, type ScaleMuleMediaProps, ScaleMuleProvider, type ScaleMuleProviderProps, UseAnalyticsOptions, UseAnalyticsReturn, type UseAudioReturn, type UseAudioUploadOptions, UseAuthReturn, UseBillingReturn, UseContentReturn, type UseFeatureFlagsOptions, type UseFeatureFlagsReturn, type UseFeedbackOptions, type UseFeedbackResult, type UseFileStatusOptions, type UseFileStatusReturn, type UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UseMediaReturn, type UseMediaUploadOptions, type UsePushNotificationsOptions, type UsePushNotificationsReturn, type UseRealtimeOptions, type UseRealtimeReturn, type UseShareOptions, type UseShareReturn, type UseTtsJobOptions, type UseTtsJobReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAudio, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useTtsJob, useUser, validateForm, validators };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, FileStatus } from '@scalemule/sdk';
|
|
2
|
+
import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, TtsService, TtsJobStatus, FileStatus } from '@scalemule/sdk';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { ReactNode, ReactElement } from 'react';
|
|
5
5
|
import { MoneyClient } from '@scalemule/money';
|
|
@@ -166,6 +166,8 @@ interface ScaleMuleContextValue {
|
|
|
166
166
|
video: VideoService;
|
|
167
167
|
/** Base SDK audio service — exposed for `useMedia()` and `audio.uploadViaStorage()` */
|
|
168
168
|
audio: AudioService;
|
|
169
|
+
/** Base SDK TTS service — exposed for `useTtsJob()` and direct narration requests */
|
|
170
|
+
tts: TtsService;
|
|
169
171
|
/**
|
|
170
172
|
* Default media policy for `useMedia()` calls. Set via
|
|
171
173
|
* `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
|
|
@@ -360,6 +362,18 @@ interface UseAudioReturn {
|
|
|
360
362
|
}
|
|
361
363
|
declare function useAudio(): UseAudioReturn;
|
|
362
364
|
|
|
365
|
+
interface UseTtsJobOptions {
|
|
366
|
+
enabled?: boolean;
|
|
367
|
+
pollIntervalMs?: number;
|
|
368
|
+
}
|
|
369
|
+
interface UseTtsJobReturn {
|
|
370
|
+
job: TtsJobStatus | null;
|
|
371
|
+
loading: boolean;
|
|
372
|
+
error: ApiError | null;
|
|
373
|
+
refresh: () => Promise<TtsJobStatus | null>;
|
|
374
|
+
}
|
|
375
|
+
declare function useTtsJob(jobId: string | null | undefined, options?: UseTtsJobOptions): UseTtsJobReturn;
|
|
376
|
+
|
|
363
377
|
/**
|
|
364
378
|
* Conversation kinds recognized by the chat realtime channel naming scheme.
|
|
365
379
|
* Matches `broadcast_to_conversation` in `ms/scalemule-chat/src/realtime.rs`.
|
|
@@ -1032,4 +1046,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
1032
1046
|
error: (message: string, data?: unknown) => void;
|
|
1033
1047
|
};
|
|
1034
1048
|
|
|
1035
|
-
export { ApiError$1 as ApiError, type AudioFile, type AudioUploadResult, type ConversationKind, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, type FeedbackItem, type FeedbackItemInput, type FeedbackPriority, type FeedbackStatus, type FeedbackType, FeedbackWidget, type FeedbackWidgetConfig, type FeedbackWidgetProps, ListFilesParams, LoginResponse, type MediaPolicy, type MediaUploadResult, type PasswordValidationResult, type PhoneCountry, type PhoneValidationResult, type RealtimeEvent, type RealtimeMessage, type RealtimeStatus, ScaleMuleClient, ScaleMuleConfig, ScaleMuleMedia, type ScaleMuleMediaProps, ScaleMuleProvider, type ScaleMuleProviderProps, UseAnalyticsOptions, UseAnalyticsReturn, type UseAudioReturn, type UseAudioUploadOptions, UseAuthReturn, UseBillingReturn, UseContentReturn, type UseFeatureFlagsOptions, type UseFeatureFlagsReturn, type UseFeedbackOptions, type UseFeedbackResult, type UseFileStatusOptions, type UseFileStatusReturn, type UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UseMediaReturn, type UseMediaUploadOptions, type UsePushNotificationsOptions, type UsePushNotificationsReturn, type UseRealtimeOptions, type UseRealtimeReturn, type UseShareOptions, type UseShareReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAudio, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
1049
|
+
export { ApiError$1 as ApiError, type AudioFile, type AudioUploadResult, type ConversationKind, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, type FeedbackItem, type FeedbackItemInput, type FeedbackPriority, type FeedbackStatus, type FeedbackType, FeedbackWidget, type FeedbackWidgetConfig, type FeedbackWidgetProps, ListFilesParams, LoginResponse, type MediaPolicy, type MediaUploadResult, type PasswordValidationResult, type PhoneCountry, type PhoneValidationResult, type RealtimeEvent, type RealtimeMessage, type RealtimeStatus, ScaleMuleClient, ScaleMuleConfig, ScaleMuleMedia, type ScaleMuleMediaProps, ScaleMuleProvider, type ScaleMuleProviderProps, UseAnalyticsOptions, UseAnalyticsReturn, type UseAudioReturn, type UseAudioUploadOptions, UseAuthReturn, UseBillingReturn, UseContentReturn, type UseFeatureFlagsOptions, type UseFeatureFlagsReturn, type UseFeedbackOptions, type UseFeedbackResult, type UseFileStatusOptions, type UseFileStatusReturn, type UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UseMediaReturn, type UseMediaUploadOptions, type UsePushNotificationsOptions, type UsePushNotificationsReturn, type UseRealtimeOptions, type UseRealtimeReturn, type UseShareOptions, type UseShareReturn, type UseTtsJobOptions, type UseTtsJobReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAudio, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useTtsJob, useUser, validateForm, validators };
|
package/dist/index.js
CHANGED
|
@@ -7023,6 +7023,7 @@ var ScaleMuleClient2 = class {
|
|
|
7023
7023
|
this.sessionGate = null;
|
|
7024
7024
|
this.resolveSessionGate = null;
|
|
7025
7025
|
this.workspaceId = null;
|
|
7026
|
+
this.refreshPromise = null;
|
|
7026
7027
|
this.apiKey = config.apiKey;
|
|
7027
7028
|
this.applicationId = config.applicationId || null;
|
|
7028
7029
|
this.gatewayUrl = resolveGatewayUrl(config);
|
|
@@ -7030,6 +7031,9 @@ var ScaleMuleClient2 = class {
|
|
|
7030
7031
|
this.storage = config.storage || createDefaultStorage2();
|
|
7031
7032
|
this.enableRateLimitQueue = config.enableRateLimitQueue || false;
|
|
7032
7033
|
this.enableOfflineQueue = config.enableOfflineQueue || false;
|
|
7034
|
+
this.onRefreshStart = config.onRefreshStart;
|
|
7035
|
+
this.onRefreshEnd = config.onRefreshEnd;
|
|
7036
|
+
this.onAutoRefreshFailed = config.onAutoRefreshFailed;
|
|
7033
7037
|
if (this.enableRateLimitQueue) {
|
|
7034
7038
|
this.rateLimitQueue = new RateLimitQueue2();
|
|
7035
7039
|
}
|
|
@@ -7248,6 +7252,10 @@ var ScaleMuleClient2 = class {
|
|
|
7248
7252
|
signal: controller.signal
|
|
7249
7253
|
});
|
|
7250
7254
|
clearTimeout(timeoutId);
|
|
7255
|
+
const rotatedToken = response.headers.get("x-rotated-session-token");
|
|
7256
|
+
if (rotatedToken && this.sessionToken && this.userId) {
|
|
7257
|
+
this.setSession(rotatedToken, this.userId);
|
|
7258
|
+
}
|
|
7251
7259
|
const text = await response.text();
|
|
7252
7260
|
let responseData = null;
|
|
7253
7261
|
try {
|
|
@@ -7257,6 +7265,30 @@ var ScaleMuleClient2 = class {
|
|
|
7257
7265
|
if (!response.ok) {
|
|
7258
7266
|
const rawError = responseData?.error;
|
|
7259
7267
|
const error = rawError && typeof rawError === "object" ? rawError : { code: `HTTP_${response.status}`, message: typeof rawError === "string" ? rawError : responseData?.message || text || response.statusText };
|
|
7268
|
+
if (response.status === 401 && this.sessionToken && !options.isAutoRefresh) {
|
|
7269
|
+
if (this.debug) console.log("[ScaleMule] 401 received, attempting auto-refresh...");
|
|
7270
|
+
if (!this.refreshPromise) {
|
|
7271
|
+
this.onRefreshStart?.();
|
|
7272
|
+
this.refreshPromise = this.post("/api/auth/refresh", {}, { isAutoRefresh: true });
|
|
7273
|
+
}
|
|
7274
|
+
try {
|
|
7275
|
+
await this.refreshPromise;
|
|
7276
|
+
if (this.debug) console.log("[ScaleMule] Auto-refresh succeeded, retrying original request...");
|
|
7277
|
+
attempt--;
|
|
7278
|
+
if (this.sessionToken) {
|
|
7279
|
+
headers.set("Authorization", `Bearer ${this.sessionToken}`);
|
|
7280
|
+
}
|
|
7281
|
+
continue;
|
|
7282
|
+
} catch (refreshErr) {
|
|
7283
|
+
if (this.debug) console.error("[ScaleMule] Auto-refresh failed:", refreshErr);
|
|
7284
|
+
const refreshApiError = refreshErr instanceof ScaleMuleApiError ? { code: refreshErr.code, message: refreshErr.message, field: refreshErr.field } : { code: "REFRESH_FAILED", message: "Auto-refresh failed" };
|
|
7285
|
+
this.onAutoRefreshFailed?.(refreshApiError);
|
|
7286
|
+
throw new ScaleMuleApiError(error);
|
|
7287
|
+
} finally {
|
|
7288
|
+
this.refreshPromise = null;
|
|
7289
|
+
this.onRefreshEnd?.();
|
|
7290
|
+
}
|
|
7291
|
+
}
|
|
7260
7292
|
if (attempt < maxRetries && RETRYABLE_STATUS_CODES3.has(response.status)) {
|
|
7261
7293
|
lastError = error;
|
|
7262
7294
|
const delay = getBackoffDelay2(attempt);
|
|
@@ -7772,6 +7804,7 @@ function ScaleMuleProvider({
|
|
|
7772
7804
|
photo: baseClient.photo,
|
|
7773
7805
|
video: baseClient.video,
|
|
7774
7806
|
audio: baseClient.audio,
|
|
7807
|
+
tts: baseClient.tts,
|
|
7775
7808
|
mediaPolicy: effectiveMediaPolicy,
|
|
7776
7809
|
user,
|
|
7777
7810
|
setUser: handleSetUser,
|
|
@@ -9160,7 +9193,7 @@ function useAudio() {
|
|
|
9160
9193
|
return null;
|
|
9161
9194
|
}
|
|
9162
9195
|
try {
|
|
9163
|
-
const details = await client.get(`/v1/
|
|
9196
|
+
const details = await client.get(`/v1/audio/${audioId}`);
|
|
9164
9197
|
if (details.status === "ready" && details.url) {
|
|
9165
9198
|
return details.url;
|
|
9166
9199
|
}
|
|
@@ -9222,7 +9255,7 @@ function useAudio() {
|
|
|
9222
9255
|
const enriched = await Promise.all(
|
|
9223
9256
|
audioFiles.map(async (file) => {
|
|
9224
9257
|
try {
|
|
9225
|
-
const details = await client.get(`/v1/
|
|
9258
|
+
const details = await client.get(`/v1/audio/${file.id}`);
|
|
9226
9259
|
return {
|
|
9227
9260
|
audio_id: details.id,
|
|
9228
9261
|
file_id: file.id,
|
|
@@ -9258,7 +9291,7 @@ function useAudio() {
|
|
|
9258
9291
|
setError(null);
|
|
9259
9292
|
try {
|
|
9260
9293
|
const [audioDeleteResult, storageDeleteResult] = await Promise.allSettled([
|
|
9261
|
-
client.delete(`/v1/
|
|
9294
|
+
client.delete(`/v1/audio/${fileId}`),
|
|
9262
9295
|
client.delete(`/v1/storage/files/${fileId}`)
|
|
9263
9296
|
]);
|
|
9264
9297
|
if (storageDeleteResult.status === "rejected" && !isNotFoundError(storageDeleteResult.reason)) {
|
|
@@ -9285,6 +9318,63 @@ function useAudio() {
|
|
|
9285
9318
|
loading
|
|
9286
9319
|
};
|
|
9287
9320
|
}
|
|
9321
|
+
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
9322
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["ready", "failed"]);
|
|
9323
|
+
function useTtsJob(jobId, options) {
|
|
9324
|
+
const { tts } = useScaleMule();
|
|
9325
|
+
const [job, setJob] = React.useState(null);
|
|
9326
|
+
const [loading, setLoading] = React.useState(false);
|
|
9327
|
+
const [error, setError] = React.useState(null);
|
|
9328
|
+
const refresh = React.useCallback(async () => {
|
|
9329
|
+
if (!jobId) {
|
|
9330
|
+
setJob(null);
|
|
9331
|
+
return null;
|
|
9332
|
+
}
|
|
9333
|
+
setLoading(true);
|
|
9334
|
+
setError(null);
|
|
9335
|
+
try {
|
|
9336
|
+
const result = await tts.getJob(jobId);
|
|
9337
|
+
if (!result) {
|
|
9338
|
+
const apiError = { code: "tts_job_error", message: "Failed to load TTS job", status: 500 };
|
|
9339
|
+
setError(apiError);
|
|
9340
|
+
return null;
|
|
9341
|
+
}
|
|
9342
|
+
if (result.error || !result.data) {
|
|
9343
|
+
const apiError = result.error ?? { code: "tts_job_error", message: "Failed to load TTS job", status: 500 };
|
|
9344
|
+
setError(apiError);
|
|
9345
|
+
return null;
|
|
9346
|
+
}
|
|
9347
|
+
setJob(result.data);
|
|
9348
|
+
return result.data;
|
|
9349
|
+
} finally {
|
|
9350
|
+
setLoading(false);
|
|
9351
|
+
}
|
|
9352
|
+
}, [jobId, tts]);
|
|
9353
|
+
React.useEffect(() => {
|
|
9354
|
+
if (!jobId || options?.enabled === false) {
|
|
9355
|
+
setJob(null);
|
|
9356
|
+
setLoading(false);
|
|
9357
|
+
return;
|
|
9358
|
+
}
|
|
9359
|
+
let cancelled = false;
|
|
9360
|
+
let timeoutId = null;
|
|
9361
|
+
const poll = async () => {
|
|
9362
|
+
const next = await refresh();
|
|
9363
|
+
if (cancelled || !next || TERMINAL_STATUSES.has(next.status)) {
|
|
9364
|
+
return;
|
|
9365
|
+
}
|
|
9366
|
+
timeoutId = window.setTimeout(poll, options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
9367
|
+
};
|
|
9368
|
+
poll();
|
|
9369
|
+
return () => {
|
|
9370
|
+
cancelled = true;
|
|
9371
|
+
if (timeoutId != null) {
|
|
9372
|
+
window.clearTimeout(timeoutId);
|
|
9373
|
+
}
|
|
9374
|
+
};
|
|
9375
|
+
}, [jobId, options?.enabled, options?.pollIntervalMs, refresh]);
|
|
9376
|
+
return { job, loading, error, refresh };
|
|
9377
|
+
}
|
|
9288
9378
|
function useMedia() {
|
|
9289
9379
|
const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
9290
9380
|
const [uploading, setUploading] = React.useState(false);
|
|
@@ -11525,6 +11615,7 @@ exports.useRealtime = useRealtime;
|
|
|
11525
11615
|
exports.useScaleMule = useScaleMule;
|
|
11526
11616
|
exports.useScaleMuleClient = useScaleMuleClient;
|
|
11527
11617
|
exports.useShare = useShare;
|
|
11618
|
+
exports.useTtsJob = useTtsJob;
|
|
11528
11619
|
exports.useUser = useUser;
|
|
11529
11620
|
exports.validateForm = validateForm;
|
|
11530
11621
|
exports.validators = validators;
|
package/dist/index.mjs
CHANGED
|
@@ -7003,6 +7003,7 @@ var ScaleMuleClient2 = class {
|
|
|
7003
7003
|
this.sessionGate = null;
|
|
7004
7004
|
this.resolveSessionGate = null;
|
|
7005
7005
|
this.workspaceId = null;
|
|
7006
|
+
this.refreshPromise = null;
|
|
7006
7007
|
this.apiKey = config.apiKey;
|
|
7007
7008
|
this.applicationId = config.applicationId || null;
|
|
7008
7009
|
this.gatewayUrl = resolveGatewayUrl(config);
|
|
@@ -7010,6 +7011,9 @@ var ScaleMuleClient2 = class {
|
|
|
7010
7011
|
this.storage = config.storage || createDefaultStorage2();
|
|
7011
7012
|
this.enableRateLimitQueue = config.enableRateLimitQueue || false;
|
|
7012
7013
|
this.enableOfflineQueue = config.enableOfflineQueue || false;
|
|
7014
|
+
this.onRefreshStart = config.onRefreshStart;
|
|
7015
|
+
this.onRefreshEnd = config.onRefreshEnd;
|
|
7016
|
+
this.onAutoRefreshFailed = config.onAutoRefreshFailed;
|
|
7013
7017
|
if (this.enableRateLimitQueue) {
|
|
7014
7018
|
this.rateLimitQueue = new RateLimitQueue2();
|
|
7015
7019
|
}
|
|
@@ -7228,6 +7232,10 @@ var ScaleMuleClient2 = class {
|
|
|
7228
7232
|
signal: controller.signal
|
|
7229
7233
|
});
|
|
7230
7234
|
clearTimeout(timeoutId);
|
|
7235
|
+
const rotatedToken = response.headers.get("x-rotated-session-token");
|
|
7236
|
+
if (rotatedToken && this.sessionToken && this.userId) {
|
|
7237
|
+
this.setSession(rotatedToken, this.userId);
|
|
7238
|
+
}
|
|
7231
7239
|
const text = await response.text();
|
|
7232
7240
|
let responseData = null;
|
|
7233
7241
|
try {
|
|
@@ -7237,6 +7245,30 @@ var ScaleMuleClient2 = class {
|
|
|
7237
7245
|
if (!response.ok) {
|
|
7238
7246
|
const rawError = responseData?.error;
|
|
7239
7247
|
const error = rawError && typeof rawError === "object" ? rawError : { code: `HTTP_${response.status}`, message: typeof rawError === "string" ? rawError : responseData?.message || text || response.statusText };
|
|
7248
|
+
if (response.status === 401 && this.sessionToken && !options.isAutoRefresh) {
|
|
7249
|
+
if (this.debug) console.log("[ScaleMule] 401 received, attempting auto-refresh...");
|
|
7250
|
+
if (!this.refreshPromise) {
|
|
7251
|
+
this.onRefreshStart?.();
|
|
7252
|
+
this.refreshPromise = this.post("/api/auth/refresh", {}, { isAutoRefresh: true });
|
|
7253
|
+
}
|
|
7254
|
+
try {
|
|
7255
|
+
await this.refreshPromise;
|
|
7256
|
+
if (this.debug) console.log("[ScaleMule] Auto-refresh succeeded, retrying original request...");
|
|
7257
|
+
attempt--;
|
|
7258
|
+
if (this.sessionToken) {
|
|
7259
|
+
headers.set("Authorization", `Bearer ${this.sessionToken}`);
|
|
7260
|
+
}
|
|
7261
|
+
continue;
|
|
7262
|
+
} catch (refreshErr) {
|
|
7263
|
+
if (this.debug) console.error("[ScaleMule] Auto-refresh failed:", refreshErr);
|
|
7264
|
+
const refreshApiError = refreshErr instanceof ScaleMuleApiError ? { code: refreshErr.code, message: refreshErr.message, field: refreshErr.field } : { code: "REFRESH_FAILED", message: "Auto-refresh failed" };
|
|
7265
|
+
this.onAutoRefreshFailed?.(refreshApiError);
|
|
7266
|
+
throw new ScaleMuleApiError(error);
|
|
7267
|
+
} finally {
|
|
7268
|
+
this.refreshPromise = null;
|
|
7269
|
+
this.onRefreshEnd?.();
|
|
7270
|
+
}
|
|
7271
|
+
}
|
|
7240
7272
|
if (attempt < maxRetries && RETRYABLE_STATUS_CODES3.has(response.status)) {
|
|
7241
7273
|
lastError = error;
|
|
7242
7274
|
const delay = getBackoffDelay2(attempt);
|
|
@@ -7752,6 +7784,7 @@ function ScaleMuleProvider({
|
|
|
7752
7784
|
photo: baseClient.photo,
|
|
7753
7785
|
video: baseClient.video,
|
|
7754
7786
|
audio: baseClient.audio,
|
|
7787
|
+
tts: baseClient.tts,
|
|
7755
7788
|
mediaPolicy: effectiveMediaPolicy,
|
|
7756
7789
|
user,
|
|
7757
7790
|
setUser: handleSetUser,
|
|
@@ -9140,7 +9173,7 @@ function useAudio() {
|
|
|
9140
9173
|
return null;
|
|
9141
9174
|
}
|
|
9142
9175
|
try {
|
|
9143
|
-
const details = await client.get(`/v1/
|
|
9176
|
+
const details = await client.get(`/v1/audio/${audioId}`);
|
|
9144
9177
|
if (details.status === "ready" && details.url) {
|
|
9145
9178
|
return details.url;
|
|
9146
9179
|
}
|
|
@@ -9202,7 +9235,7 @@ function useAudio() {
|
|
|
9202
9235
|
const enriched = await Promise.all(
|
|
9203
9236
|
audioFiles.map(async (file) => {
|
|
9204
9237
|
try {
|
|
9205
|
-
const details = await client.get(`/v1/
|
|
9238
|
+
const details = await client.get(`/v1/audio/${file.id}`);
|
|
9206
9239
|
return {
|
|
9207
9240
|
audio_id: details.id,
|
|
9208
9241
|
file_id: file.id,
|
|
@@ -9238,7 +9271,7 @@ function useAudio() {
|
|
|
9238
9271
|
setError(null);
|
|
9239
9272
|
try {
|
|
9240
9273
|
const [audioDeleteResult, storageDeleteResult] = await Promise.allSettled([
|
|
9241
|
-
client.delete(`/v1/
|
|
9274
|
+
client.delete(`/v1/audio/${fileId}`),
|
|
9242
9275
|
client.delete(`/v1/storage/files/${fileId}`)
|
|
9243
9276
|
]);
|
|
9244
9277
|
if (storageDeleteResult.status === "rejected" && !isNotFoundError(storageDeleteResult.reason)) {
|
|
@@ -9265,6 +9298,63 @@ function useAudio() {
|
|
|
9265
9298
|
loading
|
|
9266
9299
|
};
|
|
9267
9300
|
}
|
|
9301
|
+
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
9302
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["ready", "failed"]);
|
|
9303
|
+
function useTtsJob(jobId, options) {
|
|
9304
|
+
const { tts } = useScaleMule();
|
|
9305
|
+
const [job, setJob] = useState(null);
|
|
9306
|
+
const [loading, setLoading] = useState(false);
|
|
9307
|
+
const [error, setError] = useState(null);
|
|
9308
|
+
const refresh = useCallback(async () => {
|
|
9309
|
+
if (!jobId) {
|
|
9310
|
+
setJob(null);
|
|
9311
|
+
return null;
|
|
9312
|
+
}
|
|
9313
|
+
setLoading(true);
|
|
9314
|
+
setError(null);
|
|
9315
|
+
try {
|
|
9316
|
+
const result = await tts.getJob(jobId);
|
|
9317
|
+
if (!result) {
|
|
9318
|
+
const apiError = { code: "tts_job_error", message: "Failed to load TTS job", status: 500 };
|
|
9319
|
+
setError(apiError);
|
|
9320
|
+
return null;
|
|
9321
|
+
}
|
|
9322
|
+
if (result.error || !result.data) {
|
|
9323
|
+
const apiError = result.error ?? { code: "tts_job_error", message: "Failed to load TTS job", status: 500 };
|
|
9324
|
+
setError(apiError);
|
|
9325
|
+
return null;
|
|
9326
|
+
}
|
|
9327
|
+
setJob(result.data);
|
|
9328
|
+
return result.data;
|
|
9329
|
+
} finally {
|
|
9330
|
+
setLoading(false);
|
|
9331
|
+
}
|
|
9332
|
+
}, [jobId, tts]);
|
|
9333
|
+
useEffect(() => {
|
|
9334
|
+
if (!jobId || options?.enabled === false) {
|
|
9335
|
+
setJob(null);
|
|
9336
|
+
setLoading(false);
|
|
9337
|
+
return;
|
|
9338
|
+
}
|
|
9339
|
+
let cancelled = false;
|
|
9340
|
+
let timeoutId = null;
|
|
9341
|
+
const poll = async () => {
|
|
9342
|
+
const next = await refresh();
|
|
9343
|
+
if (cancelled || !next || TERMINAL_STATUSES.has(next.status)) {
|
|
9344
|
+
return;
|
|
9345
|
+
}
|
|
9346
|
+
timeoutId = window.setTimeout(poll, options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
9347
|
+
};
|
|
9348
|
+
poll();
|
|
9349
|
+
return () => {
|
|
9350
|
+
cancelled = true;
|
|
9351
|
+
if (timeoutId != null) {
|
|
9352
|
+
window.clearTimeout(timeoutId);
|
|
9353
|
+
}
|
|
9354
|
+
};
|
|
9355
|
+
}, [jobId, options?.enabled, options?.pollIntervalMs, refresh]);
|
|
9356
|
+
return { job, loading, error, refresh };
|
|
9357
|
+
}
|
|
9268
9358
|
function useMedia() {
|
|
9269
9359
|
const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
9270
9360
|
const [uploading, setUploading] = useState(false);
|
|
@@ -11470,4 +11560,4 @@ function createSafeLogger(prefix) {
|
|
|
11470
11560
|
};
|
|
11471
11561
|
}
|
|
11472
11562
|
|
|
11473
|
-
export { FeedbackWidget, ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleMedia, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAudio, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
11563
|
+
export { FeedbackWidget, ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleMedia, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAudio, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useTtsJob, useUser, validateForm, validators };
|