@scalemule/nextjs 0.1.12 → 0.1.14
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.d.mts +37 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +215 -12
- package/dist/index.mjs +215 -13
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -324,6 +324,42 @@ interface UseContentOptions {
|
|
|
324
324
|
*/
|
|
325
325
|
declare function useContent(options?: UseContentOptions): UseContentReturn;
|
|
326
326
|
|
|
327
|
+
interface AudioFile {
|
|
328
|
+
audio_id: string;
|
|
329
|
+
file_id: string;
|
|
330
|
+
filename: string;
|
|
331
|
+
mime_type: string;
|
|
332
|
+
size_bytes: number;
|
|
333
|
+
status: string;
|
|
334
|
+
codec: string | null;
|
|
335
|
+
bit_rate_kbps: number | null;
|
|
336
|
+
duration_ms: number | null;
|
|
337
|
+
created_at: string;
|
|
338
|
+
original_view_url: string | null;
|
|
339
|
+
transcoded_url: string | null;
|
|
340
|
+
waveform_peaks?: unknown;
|
|
341
|
+
}
|
|
342
|
+
interface UseAudioUploadOptions {
|
|
343
|
+
filename?: string;
|
|
344
|
+
metadata?: Record<string, unknown>;
|
|
345
|
+
onProgress?: (progress: number) => void;
|
|
346
|
+
signal?: AbortSignal;
|
|
347
|
+
}
|
|
348
|
+
interface AudioUploadResult {
|
|
349
|
+
file_id: string;
|
|
350
|
+
audio_id: string | null;
|
|
351
|
+
original_view_url: string | null;
|
|
352
|
+
transcoded_url_promise: Promise<string | null>;
|
|
353
|
+
}
|
|
354
|
+
interface UseAudioReturn {
|
|
355
|
+
upload: (file: File | Blob, opts?: UseAudioUploadOptions) => Promise<AudioUploadResult>;
|
|
356
|
+
list: () => Promise<AudioFile[]>;
|
|
357
|
+
remove: (fileId: string) => Promise<void>;
|
|
358
|
+
error: ApiError | null;
|
|
359
|
+
loading: boolean;
|
|
360
|
+
}
|
|
361
|
+
declare function useAudio(): UseAudioReturn;
|
|
362
|
+
|
|
327
363
|
/**
|
|
328
364
|
* Conversation kinds recognized by the chat realtime channel naming scheme.
|
|
329
365
|
* Matches `broadcast_to_conversation` in `ms/scalemule-chat/src/realtime.rs`.
|
|
@@ -996,4 +1032,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
996
1032
|
error: (message: string, data?: unknown) => void;
|
|
997
1033
|
};
|
|
998
1034
|
|
|
999
|
-
export { ApiError$1 as ApiError, 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, 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, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -324,6 +324,42 @@ interface UseContentOptions {
|
|
|
324
324
|
*/
|
|
325
325
|
declare function useContent(options?: UseContentOptions): UseContentReturn;
|
|
326
326
|
|
|
327
|
+
interface AudioFile {
|
|
328
|
+
audio_id: string;
|
|
329
|
+
file_id: string;
|
|
330
|
+
filename: string;
|
|
331
|
+
mime_type: string;
|
|
332
|
+
size_bytes: number;
|
|
333
|
+
status: string;
|
|
334
|
+
codec: string | null;
|
|
335
|
+
bit_rate_kbps: number | null;
|
|
336
|
+
duration_ms: number | null;
|
|
337
|
+
created_at: string;
|
|
338
|
+
original_view_url: string | null;
|
|
339
|
+
transcoded_url: string | null;
|
|
340
|
+
waveform_peaks?: unknown;
|
|
341
|
+
}
|
|
342
|
+
interface UseAudioUploadOptions {
|
|
343
|
+
filename?: string;
|
|
344
|
+
metadata?: Record<string, unknown>;
|
|
345
|
+
onProgress?: (progress: number) => void;
|
|
346
|
+
signal?: AbortSignal;
|
|
347
|
+
}
|
|
348
|
+
interface AudioUploadResult {
|
|
349
|
+
file_id: string;
|
|
350
|
+
audio_id: string | null;
|
|
351
|
+
original_view_url: string | null;
|
|
352
|
+
transcoded_url_promise: Promise<string | null>;
|
|
353
|
+
}
|
|
354
|
+
interface UseAudioReturn {
|
|
355
|
+
upload: (file: File | Blob, opts?: UseAudioUploadOptions) => Promise<AudioUploadResult>;
|
|
356
|
+
list: () => Promise<AudioFile[]>;
|
|
357
|
+
remove: (fileId: string) => Promise<void>;
|
|
358
|
+
error: ApiError | null;
|
|
359
|
+
loading: boolean;
|
|
360
|
+
}
|
|
361
|
+
declare function useAudio(): UseAudioReturn;
|
|
362
|
+
|
|
327
363
|
/**
|
|
328
364
|
* Conversation kinds recognized by the chat realtime channel naming scheme.
|
|
329
365
|
* Matches `broadcast_to_conversation` in `ms/scalemule-chat/src/realtime.rs`.
|
|
@@ -996,4 +1032,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
996
1032
|
error: (message: string, data?: unknown) => void;
|
|
997
1033
|
};
|
|
998
1034
|
|
|
999
|
-
export { ApiError$1 as ApiError, 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, 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, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -2242,14 +2242,25 @@ var StorageService = class extends ServiceModule {
|
|
|
2242
2242
|
},
|
|
2243
2243
|
requestOpts
|
|
2244
2244
|
);
|
|
2245
|
-
|
|
2246
|
-
telemetry?.emit(sessionId, "upload.completed", {
|
|
2247
|
-
file_id,
|
|
2248
|
-
size_bytes: file.size,
|
|
2249
|
-
duration_ms: Date.now() - directStart
|
|
2250
|
-
});
|
|
2245
|
+
return { data: null, error: completeResult.error };
|
|
2251
2246
|
}
|
|
2252
|
-
|
|
2247
|
+
telemetry?.emit(sessionId, "upload.completed", {
|
|
2248
|
+
file_id,
|
|
2249
|
+
size_bytes: file.size,
|
|
2250
|
+
duration_ms: Date.now() - directStart
|
|
2251
|
+
});
|
|
2252
|
+
const d = completeResult.data;
|
|
2253
|
+
return {
|
|
2254
|
+
data: {
|
|
2255
|
+
id: d.file_id,
|
|
2256
|
+
filename: d.filename,
|
|
2257
|
+
content_type: d.content_type,
|
|
2258
|
+
size_bytes: d.size_bytes,
|
|
2259
|
+
url: d.url,
|
|
2260
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2261
|
+
},
|
|
2262
|
+
error: null
|
|
2263
|
+
};
|
|
2253
2264
|
}
|
|
2254
2265
|
// --------------------------------------------------------------------------
|
|
2255
2266
|
// Multipart Upload
|
|
@@ -4458,15 +4469,19 @@ var BillingService = class extends ServiceModule {
|
|
|
4458
4469
|
return this.retiredSurface(`/v1/money/billing/payments/${id}/sync`);
|
|
4459
4470
|
}
|
|
4460
4471
|
// --------------------------------------------------------------------------
|
|
4461
|
-
//
|
|
4472
|
+
// Removed aliases (Phase 6 — billing-v2 retirement)
|
|
4473
|
+
//
|
|
4474
|
+
// These were soft-deprecated wrappers in earlier SDK versions. They now
|
|
4475
|
+
// throw at runtime so any caller still using them gets an immediate signal.
|
|
4476
|
+
// Replacements: createSubscription → subscribe(); getInvoices → listInvoices().
|
|
4462
4477
|
// --------------------------------------------------------------------------
|
|
4463
|
-
/** @
|
|
4478
|
+
/** @removed Use subscribe() instead. */
|
|
4464
4479
|
async createSubscription(data) {
|
|
4465
|
-
|
|
4480
|
+
throw new Error("BillingService.createSubscription was removed in Phase 6. Use subscribe() instead.");
|
|
4466
4481
|
}
|
|
4467
|
-
/** @
|
|
4482
|
+
/** @removed Use listInvoices() instead. */
|
|
4468
4483
|
async getInvoices(params) {
|
|
4469
|
-
|
|
4484
|
+
throw new Error("BillingService.getInvoices was removed in Phase 6. Use listInvoices() instead.");
|
|
4470
4485
|
}
|
|
4471
4486
|
};
|
|
4472
4487
|
var AnalyticsService = class extends ServiceModule {
|
|
@@ -9021,6 +9036,193 @@ function useContent(options = {}) {
|
|
|
9021
9036
|
]
|
|
9022
9037
|
);
|
|
9023
9038
|
}
|
|
9039
|
+
var AUDIO_POLL_INTERVAL_MS = 1e3;
|
|
9040
|
+
var AUDIO_POLL_MAX_ATTEMPTS = 30;
|
|
9041
|
+
function isAudioFile(file) {
|
|
9042
|
+
return file.content_type.startsWith("audio/");
|
|
9043
|
+
}
|
|
9044
|
+
function toStorageBackedAudioFile(file) {
|
|
9045
|
+
return {
|
|
9046
|
+
audio_id: file.id,
|
|
9047
|
+
file_id: file.id,
|
|
9048
|
+
filename: file.filename,
|
|
9049
|
+
mime_type: file.content_type,
|
|
9050
|
+
size_bytes: file.size_bytes,
|
|
9051
|
+
status: "pending_transcode",
|
|
9052
|
+
codec: null,
|
|
9053
|
+
bit_rate_kbps: null,
|
|
9054
|
+
duration_ms: null,
|
|
9055
|
+
created_at: file.created_at,
|
|
9056
|
+
original_view_url: file.url ?? null,
|
|
9057
|
+
transcoded_url: null
|
|
9058
|
+
};
|
|
9059
|
+
}
|
|
9060
|
+
function isNotFoundError(error) {
|
|
9061
|
+
if (!error || typeof error !== "object") {
|
|
9062
|
+
return false;
|
|
9063
|
+
}
|
|
9064
|
+
const candidate = error;
|
|
9065
|
+
return candidate.status === 404 || candidate.statusCode === 404 || candidate.response?.status === 404 || candidate.code === "not_found" || candidate.message?.toLowerCase().includes("not found") === true;
|
|
9066
|
+
}
|
|
9067
|
+
function isAbortError(error) {
|
|
9068
|
+
return error instanceof DOMException && error.name === "AbortError" || !!error && typeof error === "object" && "name" in error && error.name === "AbortError";
|
|
9069
|
+
}
|
|
9070
|
+
async function waitForPollInterval(signal) {
|
|
9071
|
+
if (signal?.aborted) {
|
|
9072
|
+
return false;
|
|
9073
|
+
}
|
|
9074
|
+
return new Promise((resolve) => {
|
|
9075
|
+
const timeoutId = window.setTimeout(() => {
|
|
9076
|
+
cleanup();
|
|
9077
|
+
resolve(true);
|
|
9078
|
+
}, AUDIO_POLL_INTERVAL_MS);
|
|
9079
|
+
const onAbort = () => {
|
|
9080
|
+
cleanup();
|
|
9081
|
+
resolve(false);
|
|
9082
|
+
};
|
|
9083
|
+
const cleanup = () => {
|
|
9084
|
+
window.clearTimeout(timeoutId);
|
|
9085
|
+
signal?.removeEventListener("abort", onAbort);
|
|
9086
|
+
};
|
|
9087
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
9088
|
+
});
|
|
9089
|
+
}
|
|
9090
|
+
function useAudio() {
|
|
9091
|
+
const { client, audio } = useScaleMule();
|
|
9092
|
+
const [loading, setLoading] = React.useState(false);
|
|
9093
|
+
const [error, setError] = React.useState(null);
|
|
9094
|
+
const pollTranscodedUrl = React.useCallback(
|
|
9095
|
+
async (audioId, signal) => {
|
|
9096
|
+
for (let attempt = 0; attempt < AUDIO_POLL_MAX_ATTEMPTS; attempt++) {
|
|
9097
|
+
if (signal?.aborted) {
|
|
9098
|
+
return null;
|
|
9099
|
+
}
|
|
9100
|
+
try {
|
|
9101
|
+
const details = await client.get(`/v1/audios/${audioId}`);
|
|
9102
|
+
if (details.status === "ready" && details.url) {
|
|
9103
|
+
return details.url;
|
|
9104
|
+
}
|
|
9105
|
+
if (details.status === "failed") {
|
|
9106
|
+
return null;
|
|
9107
|
+
}
|
|
9108
|
+
} catch (err) {
|
|
9109
|
+
if (isAbortError(err) || signal?.aborted) {
|
|
9110
|
+
return null;
|
|
9111
|
+
}
|
|
9112
|
+
if (!isNotFoundError(err)) {
|
|
9113
|
+
throw err;
|
|
9114
|
+
}
|
|
9115
|
+
}
|
|
9116
|
+
if (!await waitForPollInterval(signal)) {
|
|
9117
|
+
return null;
|
|
9118
|
+
}
|
|
9119
|
+
}
|
|
9120
|
+
return null;
|
|
9121
|
+
},
|
|
9122
|
+
[client]
|
|
9123
|
+
);
|
|
9124
|
+
const upload = React.useCallback(
|
|
9125
|
+
async (file, opts) => {
|
|
9126
|
+
setLoading(true);
|
|
9127
|
+
setError(null);
|
|
9128
|
+
try {
|
|
9129
|
+
const result = await audio.uploadViaStorage(file, {
|
|
9130
|
+
filename: opts?.filename,
|
|
9131
|
+
metadata: opts?.metadata,
|
|
9132
|
+
onProgress: opts?.onProgress,
|
|
9133
|
+
signal: opts?.signal
|
|
9134
|
+
});
|
|
9135
|
+
if (result.error || !result.data) {
|
|
9136
|
+
throw result.error ?? { code: "upload_error", message: "Audio upload failed" };
|
|
9137
|
+
}
|
|
9138
|
+
return {
|
|
9139
|
+
file_id: result.data.file_id,
|
|
9140
|
+
audio_id: result.data.audio_id,
|
|
9141
|
+
original_view_url: result.data.original_view_url,
|
|
9142
|
+
transcoded_url_promise: result.data.audio_id ? pollTranscodedUrl(result.data.audio_id, opts?.signal) : Promise.resolve(null)
|
|
9143
|
+
};
|
|
9144
|
+
} catch (err) {
|
|
9145
|
+
const apiError = err;
|
|
9146
|
+
setError(apiError);
|
|
9147
|
+
throw err;
|
|
9148
|
+
} finally {
|
|
9149
|
+
setLoading(false);
|
|
9150
|
+
}
|
|
9151
|
+
},
|
|
9152
|
+
[audio, pollTranscodedUrl]
|
|
9153
|
+
);
|
|
9154
|
+
const list = React.useCallback(async () => {
|
|
9155
|
+
setLoading(true);
|
|
9156
|
+
setError(null);
|
|
9157
|
+
try {
|
|
9158
|
+
const response = await client.get("/v1/storage/my-files");
|
|
9159
|
+
const audioFiles = response.files.filter(isAudioFile);
|
|
9160
|
+
const enriched = await Promise.all(
|
|
9161
|
+
audioFiles.map(async (file) => {
|
|
9162
|
+
try {
|
|
9163
|
+
const details = await client.get(`/v1/audios/${file.id}`);
|
|
9164
|
+
return {
|
|
9165
|
+
audio_id: details.id,
|
|
9166
|
+
file_id: file.id,
|
|
9167
|
+
filename: file.filename,
|
|
9168
|
+
mime_type: file.content_type,
|
|
9169
|
+
size_bytes: details.size_bytes ?? file.size_bytes,
|
|
9170
|
+
status: details.status,
|
|
9171
|
+
codec: details.codec,
|
|
9172
|
+
bit_rate_kbps: details.bit_rate_kbps ?? null,
|
|
9173
|
+
duration_ms: details.duration_ms ?? null,
|
|
9174
|
+
created_at: details.created_at,
|
|
9175
|
+
original_view_url: file.url ?? null,
|
|
9176
|
+
transcoded_url: details.url ?? null,
|
|
9177
|
+
waveform_peaks: details.waveform_peaks
|
|
9178
|
+
};
|
|
9179
|
+
} catch {
|
|
9180
|
+
return toStorageBackedAudioFile(file);
|
|
9181
|
+
}
|
|
9182
|
+
})
|
|
9183
|
+
);
|
|
9184
|
+
return enriched;
|
|
9185
|
+
} catch (err) {
|
|
9186
|
+
const apiError = err;
|
|
9187
|
+
setError(apiError);
|
|
9188
|
+
throw err;
|
|
9189
|
+
} finally {
|
|
9190
|
+
setLoading(false);
|
|
9191
|
+
}
|
|
9192
|
+
}, [client]);
|
|
9193
|
+
const remove = React.useCallback(
|
|
9194
|
+
async (fileId) => {
|
|
9195
|
+
setLoading(true);
|
|
9196
|
+
setError(null);
|
|
9197
|
+
try {
|
|
9198
|
+
const [audioDeleteResult, storageDeleteResult] = await Promise.allSettled([
|
|
9199
|
+
client.delete(`/v1/audios/${fileId}`),
|
|
9200
|
+
client.delete(`/v1/storage/files/${fileId}`)
|
|
9201
|
+
]);
|
|
9202
|
+
if (storageDeleteResult.status === "rejected" && !isNotFoundError(storageDeleteResult.reason)) {
|
|
9203
|
+
throw storageDeleteResult.reason ?? new Error("Storage delete failed");
|
|
9204
|
+
}
|
|
9205
|
+
if (audioDeleteResult.status === "rejected" && !isNotFoundError(audioDeleteResult.reason)) {
|
|
9206
|
+
console.warn("Audio record delete failed after storage delete", audioDeleteResult.reason);
|
|
9207
|
+
}
|
|
9208
|
+
} catch (err) {
|
|
9209
|
+
const apiError = err;
|
|
9210
|
+
setError(apiError);
|
|
9211
|
+
throw err;
|
|
9212
|
+
} finally {
|
|
9213
|
+
setLoading(false);
|
|
9214
|
+
}
|
|
9215
|
+
},
|
|
9216
|
+
[client]
|
|
9217
|
+
);
|
|
9218
|
+
return {
|
|
9219
|
+
upload,
|
|
9220
|
+
list,
|
|
9221
|
+
remove,
|
|
9222
|
+
error,
|
|
9223
|
+
loading
|
|
9224
|
+
};
|
|
9225
|
+
}
|
|
9024
9226
|
function useMedia() {
|
|
9025
9227
|
const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
9026
9228
|
const [uploading, setUploading] = React.useState(false);
|
|
@@ -11246,6 +11448,7 @@ exports.normalizePhone = normalizePhone;
|
|
|
11246
11448
|
exports.phoneCountries = phoneCountries;
|
|
11247
11449
|
exports.sanitizeForLog = sanitizeForLog;
|
|
11248
11450
|
exports.useAnalytics = useAnalytics;
|
|
11451
|
+
exports.useAudio = useAudio;
|
|
11249
11452
|
exports.useAuth = useAuth;
|
|
11250
11453
|
exports.useBilling = useBilling;
|
|
11251
11454
|
exports.useContent = useContent;
|
package/dist/index.mjs
CHANGED
|
@@ -2222,14 +2222,25 @@ var StorageService = class extends ServiceModule {
|
|
|
2222
2222
|
},
|
|
2223
2223
|
requestOpts
|
|
2224
2224
|
);
|
|
2225
|
-
|
|
2226
|
-
telemetry?.emit(sessionId, "upload.completed", {
|
|
2227
|
-
file_id,
|
|
2228
|
-
size_bytes: file.size,
|
|
2229
|
-
duration_ms: Date.now() - directStart
|
|
2230
|
-
});
|
|
2225
|
+
return { data: null, error: completeResult.error };
|
|
2231
2226
|
}
|
|
2232
|
-
|
|
2227
|
+
telemetry?.emit(sessionId, "upload.completed", {
|
|
2228
|
+
file_id,
|
|
2229
|
+
size_bytes: file.size,
|
|
2230
|
+
duration_ms: Date.now() - directStart
|
|
2231
|
+
});
|
|
2232
|
+
const d = completeResult.data;
|
|
2233
|
+
return {
|
|
2234
|
+
data: {
|
|
2235
|
+
id: d.file_id,
|
|
2236
|
+
filename: d.filename,
|
|
2237
|
+
content_type: d.content_type,
|
|
2238
|
+
size_bytes: d.size_bytes,
|
|
2239
|
+
url: d.url,
|
|
2240
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2241
|
+
},
|
|
2242
|
+
error: null
|
|
2243
|
+
};
|
|
2233
2244
|
}
|
|
2234
2245
|
// --------------------------------------------------------------------------
|
|
2235
2246
|
// Multipart Upload
|
|
@@ -4438,15 +4449,19 @@ var BillingService = class extends ServiceModule {
|
|
|
4438
4449
|
return this.retiredSurface(`/v1/money/billing/payments/${id}/sync`);
|
|
4439
4450
|
}
|
|
4440
4451
|
// --------------------------------------------------------------------------
|
|
4441
|
-
//
|
|
4452
|
+
// Removed aliases (Phase 6 — billing-v2 retirement)
|
|
4453
|
+
//
|
|
4454
|
+
// These were soft-deprecated wrappers in earlier SDK versions. They now
|
|
4455
|
+
// throw at runtime so any caller still using them gets an immediate signal.
|
|
4456
|
+
// Replacements: createSubscription → subscribe(); getInvoices → listInvoices().
|
|
4442
4457
|
// --------------------------------------------------------------------------
|
|
4443
|
-
/** @
|
|
4458
|
+
/** @removed Use subscribe() instead. */
|
|
4444
4459
|
async createSubscription(data) {
|
|
4445
|
-
|
|
4460
|
+
throw new Error("BillingService.createSubscription was removed in Phase 6. Use subscribe() instead.");
|
|
4446
4461
|
}
|
|
4447
|
-
/** @
|
|
4462
|
+
/** @removed Use listInvoices() instead. */
|
|
4448
4463
|
async getInvoices(params) {
|
|
4449
|
-
|
|
4464
|
+
throw new Error("BillingService.getInvoices was removed in Phase 6. Use listInvoices() instead.");
|
|
4450
4465
|
}
|
|
4451
4466
|
};
|
|
4452
4467
|
var AnalyticsService = class extends ServiceModule {
|
|
@@ -9001,6 +9016,193 @@ function useContent(options = {}) {
|
|
|
9001
9016
|
]
|
|
9002
9017
|
);
|
|
9003
9018
|
}
|
|
9019
|
+
var AUDIO_POLL_INTERVAL_MS = 1e3;
|
|
9020
|
+
var AUDIO_POLL_MAX_ATTEMPTS = 30;
|
|
9021
|
+
function isAudioFile(file) {
|
|
9022
|
+
return file.content_type.startsWith("audio/");
|
|
9023
|
+
}
|
|
9024
|
+
function toStorageBackedAudioFile(file) {
|
|
9025
|
+
return {
|
|
9026
|
+
audio_id: file.id,
|
|
9027
|
+
file_id: file.id,
|
|
9028
|
+
filename: file.filename,
|
|
9029
|
+
mime_type: file.content_type,
|
|
9030
|
+
size_bytes: file.size_bytes,
|
|
9031
|
+
status: "pending_transcode",
|
|
9032
|
+
codec: null,
|
|
9033
|
+
bit_rate_kbps: null,
|
|
9034
|
+
duration_ms: null,
|
|
9035
|
+
created_at: file.created_at,
|
|
9036
|
+
original_view_url: file.url ?? null,
|
|
9037
|
+
transcoded_url: null
|
|
9038
|
+
};
|
|
9039
|
+
}
|
|
9040
|
+
function isNotFoundError(error) {
|
|
9041
|
+
if (!error || typeof error !== "object") {
|
|
9042
|
+
return false;
|
|
9043
|
+
}
|
|
9044
|
+
const candidate = error;
|
|
9045
|
+
return candidate.status === 404 || candidate.statusCode === 404 || candidate.response?.status === 404 || candidate.code === "not_found" || candidate.message?.toLowerCase().includes("not found") === true;
|
|
9046
|
+
}
|
|
9047
|
+
function isAbortError(error) {
|
|
9048
|
+
return error instanceof DOMException && error.name === "AbortError" || !!error && typeof error === "object" && "name" in error && error.name === "AbortError";
|
|
9049
|
+
}
|
|
9050
|
+
async function waitForPollInterval(signal) {
|
|
9051
|
+
if (signal?.aborted) {
|
|
9052
|
+
return false;
|
|
9053
|
+
}
|
|
9054
|
+
return new Promise((resolve) => {
|
|
9055
|
+
const timeoutId = window.setTimeout(() => {
|
|
9056
|
+
cleanup();
|
|
9057
|
+
resolve(true);
|
|
9058
|
+
}, AUDIO_POLL_INTERVAL_MS);
|
|
9059
|
+
const onAbort = () => {
|
|
9060
|
+
cleanup();
|
|
9061
|
+
resolve(false);
|
|
9062
|
+
};
|
|
9063
|
+
const cleanup = () => {
|
|
9064
|
+
window.clearTimeout(timeoutId);
|
|
9065
|
+
signal?.removeEventListener("abort", onAbort);
|
|
9066
|
+
};
|
|
9067
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
9068
|
+
});
|
|
9069
|
+
}
|
|
9070
|
+
function useAudio() {
|
|
9071
|
+
const { client, audio } = useScaleMule();
|
|
9072
|
+
const [loading, setLoading] = useState(false);
|
|
9073
|
+
const [error, setError] = useState(null);
|
|
9074
|
+
const pollTranscodedUrl = useCallback(
|
|
9075
|
+
async (audioId, signal) => {
|
|
9076
|
+
for (let attempt = 0; attempt < AUDIO_POLL_MAX_ATTEMPTS; attempt++) {
|
|
9077
|
+
if (signal?.aborted) {
|
|
9078
|
+
return null;
|
|
9079
|
+
}
|
|
9080
|
+
try {
|
|
9081
|
+
const details = await client.get(`/v1/audios/${audioId}`);
|
|
9082
|
+
if (details.status === "ready" && details.url) {
|
|
9083
|
+
return details.url;
|
|
9084
|
+
}
|
|
9085
|
+
if (details.status === "failed") {
|
|
9086
|
+
return null;
|
|
9087
|
+
}
|
|
9088
|
+
} catch (err) {
|
|
9089
|
+
if (isAbortError(err) || signal?.aborted) {
|
|
9090
|
+
return null;
|
|
9091
|
+
}
|
|
9092
|
+
if (!isNotFoundError(err)) {
|
|
9093
|
+
throw err;
|
|
9094
|
+
}
|
|
9095
|
+
}
|
|
9096
|
+
if (!await waitForPollInterval(signal)) {
|
|
9097
|
+
return null;
|
|
9098
|
+
}
|
|
9099
|
+
}
|
|
9100
|
+
return null;
|
|
9101
|
+
},
|
|
9102
|
+
[client]
|
|
9103
|
+
);
|
|
9104
|
+
const upload = useCallback(
|
|
9105
|
+
async (file, opts) => {
|
|
9106
|
+
setLoading(true);
|
|
9107
|
+
setError(null);
|
|
9108
|
+
try {
|
|
9109
|
+
const result = await audio.uploadViaStorage(file, {
|
|
9110
|
+
filename: opts?.filename,
|
|
9111
|
+
metadata: opts?.metadata,
|
|
9112
|
+
onProgress: opts?.onProgress,
|
|
9113
|
+
signal: opts?.signal
|
|
9114
|
+
});
|
|
9115
|
+
if (result.error || !result.data) {
|
|
9116
|
+
throw result.error ?? { code: "upload_error", message: "Audio upload failed" };
|
|
9117
|
+
}
|
|
9118
|
+
return {
|
|
9119
|
+
file_id: result.data.file_id,
|
|
9120
|
+
audio_id: result.data.audio_id,
|
|
9121
|
+
original_view_url: result.data.original_view_url,
|
|
9122
|
+
transcoded_url_promise: result.data.audio_id ? pollTranscodedUrl(result.data.audio_id, opts?.signal) : Promise.resolve(null)
|
|
9123
|
+
};
|
|
9124
|
+
} catch (err) {
|
|
9125
|
+
const apiError = err;
|
|
9126
|
+
setError(apiError);
|
|
9127
|
+
throw err;
|
|
9128
|
+
} finally {
|
|
9129
|
+
setLoading(false);
|
|
9130
|
+
}
|
|
9131
|
+
},
|
|
9132
|
+
[audio, pollTranscodedUrl]
|
|
9133
|
+
);
|
|
9134
|
+
const list = useCallback(async () => {
|
|
9135
|
+
setLoading(true);
|
|
9136
|
+
setError(null);
|
|
9137
|
+
try {
|
|
9138
|
+
const response = await client.get("/v1/storage/my-files");
|
|
9139
|
+
const audioFiles = response.files.filter(isAudioFile);
|
|
9140
|
+
const enriched = await Promise.all(
|
|
9141
|
+
audioFiles.map(async (file) => {
|
|
9142
|
+
try {
|
|
9143
|
+
const details = await client.get(`/v1/audios/${file.id}`);
|
|
9144
|
+
return {
|
|
9145
|
+
audio_id: details.id,
|
|
9146
|
+
file_id: file.id,
|
|
9147
|
+
filename: file.filename,
|
|
9148
|
+
mime_type: file.content_type,
|
|
9149
|
+
size_bytes: details.size_bytes ?? file.size_bytes,
|
|
9150
|
+
status: details.status,
|
|
9151
|
+
codec: details.codec,
|
|
9152
|
+
bit_rate_kbps: details.bit_rate_kbps ?? null,
|
|
9153
|
+
duration_ms: details.duration_ms ?? null,
|
|
9154
|
+
created_at: details.created_at,
|
|
9155
|
+
original_view_url: file.url ?? null,
|
|
9156
|
+
transcoded_url: details.url ?? null,
|
|
9157
|
+
waveform_peaks: details.waveform_peaks
|
|
9158
|
+
};
|
|
9159
|
+
} catch {
|
|
9160
|
+
return toStorageBackedAudioFile(file);
|
|
9161
|
+
}
|
|
9162
|
+
})
|
|
9163
|
+
);
|
|
9164
|
+
return enriched;
|
|
9165
|
+
} catch (err) {
|
|
9166
|
+
const apiError = err;
|
|
9167
|
+
setError(apiError);
|
|
9168
|
+
throw err;
|
|
9169
|
+
} finally {
|
|
9170
|
+
setLoading(false);
|
|
9171
|
+
}
|
|
9172
|
+
}, [client]);
|
|
9173
|
+
const remove = useCallback(
|
|
9174
|
+
async (fileId) => {
|
|
9175
|
+
setLoading(true);
|
|
9176
|
+
setError(null);
|
|
9177
|
+
try {
|
|
9178
|
+
const [audioDeleteResult, storageDeleteResult] = await Promise.allSettled([
|
|
9179
|
+
client.delete(`/v1/audios/${fileId}`),
|
|
9180
|
+
client.delete(`/v1/storage/files/${fileId}`)
|
|
9181
|
+
]);
|
|
9182
|
+
if (storageDeleteResult.status === "rejected" && !isNotFoundError(storageDeleteResult.reason)) {
|
|
9183
|
+
throw storageDeleteResult.reason ?? new Error("Storage delete failed");
|
|
9184
|
+
}
|
|
9185
|
+
if (audioDeleteResult.status === "rejected" && !isNotFoundError(audioDeleteResult.reason)) {
|
|
9186
|
+
console.warn("Audio record delete failed after storage delete", audioDeleteResult.reason);
|
|
9187
|
+
}
|
|
9188
|
+
} catch (err) {
|
|
9189
|
+
const apiError = err;
|
|
9190
|
+
setError(apiError);
|
|
9191
|
+
throw err;
|
|
9192
|
+
} finally {
|
|
9193
|
+
setLoading(false);
|
|
9194
|
+
}
|
|
9195
|
+
},
|
|
9196
|
+
[client]
|
|
9197
|
+
);
|
|
9198
|
+
return {
|
|
9199
|
+
upload,
|
|
9200
|
+
list,
|
|
9201
|
+
remove,
|
|
9202
|
+
error,
|
|
9203
|
+
loading
|
|
9204
|
+
};
|
|
9205
|
+
}
|
|
9004
9206
|
function useMedia() {
|
|
9005
9207
|
const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
9006
9208
|
const [uploading, setUploading] = useState(false);
|
|
@@ -11206,4 +11408,4 @@ function createSafeLogger(prefix) {
|
|
|
11206
11408
|
};
|
|
11207
11409
|
}
|
|
11208
11410
|
|
|
11209
|
-
export { FeedbackWidget, ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleMedia, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
11411
|
+
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 };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/nextjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "ScaleMule SDK for Next.js applications - authentication, storage, and user management",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@scalemule/money": "^0.0.1",
|
|
57
|
-
"@scalemule/sdk": "
|
|
57
|
+
"@scalemule/sdk": "^0.0.47"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"next": ">=14.0.0",
|