@scalemule/nextjs 0.1.6 → 0.1.8
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 +177 -153
- package/dist/index.d.ts +177 -153
- package/dist/index.js +109 -5
- package/dist/index.mjs +109 -5
- package/package.json +4 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,14 +1,156 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, FileStatus } from '@scalemule/sdk';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
import { ReactNode, ReactElement } from 'react';
|
|
4
5
|
import { MoneyClient } from '@scalemule/money';
|
|
5
6
|
export { MoneyClient, MoneyClientConfig, createMoneyClient } from '@scalemule/money';
|
|
6
|
-
import { RealtimeService, StorageService, PhotoService, VideoService, ApiError as ApiError$1, FileStatus } from '@scalemule/sdk';
|
|
7
7
|
import { ScaleMuleClient } from './client.mjs';
|
|
8
8
|
export { ClientConfig, RequestOptions, createClient } from './client.mjs';
|
|
9
|
-
import { S as ScaleMuleConfig, U as User, L as LoginResponse, A as ApiError, a as UseAuthReturn, b as UseBillingReturn, c as ListFilesParams, d as UseContentReturn, e as UseUserReturn, f as UseAnalyticsOptions, g as UseAnalyticsReturn } from './index-BIIUrnPr.mjs';
|
|
9
|
+
import { S as ScaleMuleConfig, U as User, L as LoginResponse, A as ApiError$1, a as UseAuthReturn, b as UseBillingReturn, c as ListFilesParams, d as UseContentReturn, e as UseUserReturn, f as UseAnalyticsOptions, g as UseAnalyticsReturn } from './index-BIIUrnPr.mjs';
|
|
10
10
|
export { h as AccountBalance, i as AnalyticsEvent, j as ApiResponse, B as BatchTrackRequest, k as BillingPayment, l as BillingPayout, m as BillingRefund, n as BillingTransaction, C as ChangeEmailRequest, o as ChangePasswordRequest, p as ClientContext, q as ConnectedAccount, D as DeviceFingerprint, r as DeviceInfo, E as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, K as KnownAccountInfo, s as LinkedAccount, t as ListFilesResponse, u as LoginDeviceInfo, v as LoginRequest, w as LoginResponseWithMFA, x as LoginRiskInfo, M as MFAChallengeResponse, y as MFAMethod, z as MFASMSSetupResponse, G as MFASetupRequest, H as MFAStatus, I as MFATOTPSetupResponse, J as MFAVerifyRequest, O as OAuthCallbackRequest, N as OAuthCallbackResponse, P as OAuthConfig, Q as OAuthProvider, R as OAuthStartResponse, T as PageViewData, V as PayoutSchedule, W as PhoneLoginRequest, X as PhoneSendCodeRequest, Y as PhoneVerifyRequest, Z as Profile, _ as RefreshResponse, $ as RegisterRequest, a0 as ResetPasswordRequest, a1 as ScaleMuleApiError, a2 as ScaleMuleEnvironment, a3 as Session, a4 as SignedUploadCompleteRequest, a5 as SignedUploadRequest, a6 as SignedUploadResponse, a7 as SignedUploadUrl, a8 as StorageAdapter, a9 as StorageFile, aa as TrackEventResponse, ab as TransactionSummary, ac as UTMParams, ad as UpdateProfileRequest, ae as UploadOptions, af as UploadResponse, ag as VerifyEmailRequest } from './index-BIIUrnPr.mjs';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Result of a single {@link useMedia} upload call.
|
|
14
|
+
*
|
|
15
|
+
* The shape is normalized regardless of MIME type — `optimized_url_promise`
|
|
16
|
+
* resolves on image uploads after the photo optimizer finishes; for non-image
|
|
17
|
+
* uploads it resolves to `null` immediately. (Video / audio branches will
|
|
18
|
+
* populate `hls_url_promise` in later phases — today they fall through to
|
|
19
|
+
* generic storage and that field stays `null`.)
|
|
20
|
+
*/
|
|
21
|
+
interface MediaUploadResult {
|
|
22
|
+
/** Storage file_id — store this in chat-attachment metadata. */
|
|
23
|
+
file_id: string;
|
|
24
|
+
/** Photo service id — null for non-image uploads or when register() failed. */
|
|
25
|
+
photo_id: string | null;
|
|
26
|
+
/** Short-lived signed URL to the original bytes (private uploads) or
|
|
27
|
+
* a public CDN URL (when caller passed `is_public: true`). */
|
|
28
|
+
original_view_url: string | null;
|
|
29
|
+
/** Resolves once the photo optimizer finishes. `null` for non-image
|
|
30
|
+
* MIME types or when register() failed. */
|
|
31
|
+
optimized_url_promise: Promise<string | null>;
|
|
32
|
+
/** Resolves once the video transcoder finishes (Phase 2 / S5b). `null` today. */
|
|
33
|
+
hls_url_promise: Promise<string | null>;
|
|
34
|
+
/** The file's MIME type — preserved from the input File / Blob. */
|
|
35
|
+
mime_type: string;
|
|
36
|
+
/** Whether the resulting storage object is public-readable. */
|
|
37
|
+
is_public: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Per-app media-pipeline policy. Drives release-gating + processing
|
|
41
|
+
* behavior. **Orthogonal to `is_public`.** See
|
|
42
|
+
* `docs/MEDIA-UPLOADS.md` and ADR-2026-04-26 for the full taxonomy.
|
|
43
|
+
*
|
|
44
|
+
* Today's behavior (Phase 4 v1):
|
|
45
|
+
* - `fast_trusted` / `safe_visible` (default): upload promise resolves
|
|
46
|
+
* as soon as the file is uploaded + registered. The post-processing
|
|
47
|
+
* (scan, optimize, transcode) runs async; callers can observe via
|
|
48
|
+
* `useFileStatus`.
|
|
49
|
+
* - `safe_public` / `moderated`: upload promise *waits* for the
|
|
50
|
+
* optimized image variant (image MIME) or HLS playlist (video MIME)
|
|
51
|
+
* to become ready before resolving. Acts as the release-gate for
|
|
52
|
+
* UGC-style apps that should not publish raw bytes.
|
|
53
|
+
* - `compliance`: today behaves as `safe_public`; Phase 4+ adds the
|
|
54
|
+
* audit-log + signed-with-purpose URL semantics.
|
|
55
|
+
*/
|
|
56
|
+
type MediaPolicy = 'fast_trusted' | 'safe_visible' | 'safe_public' | 'moderated' | 'compliance';
|
|
57
|
+
interface UseMediaUploadOptions {
|
|
58
|
+
/** Whether the resulting storage object should be public-readable.
|
|
59
|
+
* Default: `false` (private). Public is opt-in for surfaces that
|
|
60
|
+
* genuinely need it (avatars, public listings). Chat / DM uploads
|
|
61
|
+
* should always be private. */
|
|
62
|
+
is_public?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Per-call media-policy override. Defaults to `safe_visible` (visible
|
|
65
|
+
* immediately at original fidelity; optimized variants swap in async).
|
|
66
|
+
* Set to `safe_public` to make the upload promise *await* the optimized
|
|
67
|
+
* variant (image) or HLS playlist (video) before resolving — useful for
|
|
68
|
+
* broadcast / UGC apps that gate publication on processing complete.
|
|
69
|
+
*
|
|
70
|
+
* The per-app default lives in `application_storage_settings.media_policy`
|
|
71
|
+
* (Phase 4 / P3, live in prod 2026-04-26). Reading the per-app default
|
|
72
|
+
* into `useMedia` defaults lands in a follow-up; today the option is
|
|
73
|
+
* caller-provided per call.
|
|
74
|
+
*/
|
|
75
|
+
policy?: MediaPolicy;
|
|
76
|
+
/** Display filename (sanitized server-side). */
|
|
77
|
+
filename?: string;
|
|
78
|
+
/** Custom metadata attached to the file. */
|
|
79
|
+
metadata?: Record<string, unknown>;
|
|
80
|
+
/** Upload progress callback (0-100). */
|
|
81
|
+
onProgress?: (percent: number) => void;
|
|
82
|
+
/** AbortSignal for cancellation. */
|
|
83
|
+
signal?: AbortSignal;
|
|
84
|
+
/** Force a non-photo path even for image MIME types — useful for
|
|
85
|
+
* generic file uploads where you don't want the photo optimizer
|
|
86
|
+
* to register the file. Default: `false`. */
|
|
87
|
+
skipPhotoRegister?: boolean;
|
|
88
|
+
}
|
|
89
|
+
interface UseMediaReturn {
|
|
90
|
+
/** Upload a file. MIME-aware: images go through photo register +
|
|
91
|
+
* optimization; everything else goes through generic storage. */
|
|
92
|
+
upload: (file: File | Blob, options?: UseMediaUploadOptions) => Promise<MediaUploadResult>;
|
|
93
|
+
/** Cancel an upload by its `file_id`. Deletes the storage object so
|
|
94
|
+
* it doesn't orphan in S3 — useful when a chat composer accepts a
|
|
95
|
+
* file but the user removes it before sending. Idempotent. */
|
|
96
|
+
cancelUpload: (fileId: string) => Promise<void>;
|
|
97
|
+
/** Last error from `upload` or `cancelUpload`. */
|
|
98
|
+
error: ApiError | null;
|
|
99
|
+
/** True while an upload is in progress. */
|
|
100
|
+
uploading: boolean;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Opinionated, MIME-aware media upload hook.
|
|
104
|
+
*
|
|
105
|
+
* `useMedia()` is the canonical upload primitive for chat / progressive
|
|
106
|
+
* media use. It branches by MIME type:
|
|
107
|
+
* - `image/*` → `client.photo.uploadViaStorage()` — upload to storage,
|
|
108
|
+
* then register with the photo service so the on-demand transform
|
|
109
|
+
* endpoint resolves to optimized variants. The returned
|
|
110
|
+
* `optimized_url_promise` resolves once the optimizer finishes.
|
|
111
|
+
* - everything else → `client.storage.uploadPrivate()` — a private,
|
|
112
|
+
* uncompressed, fail-closed upload to generic storage.
|
|
113
|
+
*
|
|
114
|
+
* **Default visibility is `is_public: false`.** Public is opt-in per call.
|
|
115
|
+
* `useMedia()` does not expose `is_public` via app-level config — visibility
|
|
116
|
+
* is always an explicit per-call surface choice.
|
|
117
|
+
*
|
|
118
|
+
* Compared to `useContent()`:
|
|
119
|
+
* - `useContent()` is a thin wrapper over generic storage and does not
|
|
120
|
+
* register photos / videos with their typed services. Use it for plain
|
|
121
|
+
* file uploads where you don't need optimization or transcoding.
|
|
122
|
+
* - `useMedia()` defaults to private + no compression, integrates with the
|
|
123
|
+
* typed media services automatically, and is the right primitive for
|
|
124
|
+
* anything chat- or media-shaped.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```tsx
|
|
128
|
+
* 'use client';
|
|
129
|
+
*
|
|
130
|
+
* import { useMedia, ScaleMuleMedia } from '@scalemule/nextjs';
|
|
131
|
+
*
|
|
132
|
+
* function ChatComposer({ onAttach }) {
|
|
133
|
+
* const { upload, uploading } = useMedia();
|
|
134
|
+
*
|
|
135
|
+
* async function handlePick(file: File) {
|
|
136
|
+
* const result = await upload(file);
|
|
137
|
+
* onAttach({
|
|
138
|
+
* file_id: result.file_id,
|
|
139
|
+
* mime_type: result.mime_type,
|
|
140
|
+
* optimized_url_promise: result.optimized_url_promise,
|
|
141
|
+
* });
|
|
142
|
+
* }
|
|
143
|
+
*
|
|
144
|
+
* return <input type="file" disabled={uploading}
|
|
145
|
+
* onChange={(e) => e.target.files?.[0] && handlePick(e.target.files[0])} />;
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* See `docs/MEDIA-UPLOADS.md` in the platform repo for the decision
|
|
150
|
+
* tree and the full anti-patterns list.
|
|
151
|
+
*/
|
|
152
|
+
declare function useMedia(): UseMediaReturn;
|
|
153
|
+
|
|
12
154
|
interface ScaleMuleContextValue {
|
|
13
155
|
/** The API client instance */
|
|
14
156
|
client: ScaleMuleClient;
|
|
@@ -22,6 +164,14 @@ interface ScaleMuleContextValue {
|
|
|
22
164
|
photo: PhotoService;
|
|
23
165
|
/** Base SDK video service — exposed for `useMedia()` and `video.uploadViaStorage()` */
|
|
24
166
|
video: VideoService;
|
|
167
|
+
/** Base SDK audio service — exposed for `useMedia()` and `audio.uploadViaStorage()` */
|
|
168
|
+
audio: AudioService;
|
|
169
|
+
/**
|
|
170
|
+
* Default media policy for `useMedia()` calls. Set via
|
|
171
|
+
* `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
|
|
172
|
+
* Undefined falls back to `useMedia()`'s built-in `safe_visible` default.
|
|
173
|
+
*/
|
|
174
|
+
mediaPolicy?: MediaPolicy;
|
|
25
175
|
/** Current authenticated user */
|
|
26
176
|
user: User | null;
|
|
27
177
|
/** Set the current user */
|
|
@@ -29,9 +179,9 @@ interface ScaleMuleContextValue {
|
|
|
29
179
|
/** Whether the SDK is initializing */
|
|
30
180
|
initializing: boolean;
|
|
31
181
|
/** Last error */
|
|
32
|
-
error: ApiError | null;
|
|
182
|
+
error: ApiError$1 | null;
|
|
33
183
|
/** Set error */
|
|
34
|
-
setError: (error: ApiError | null) => void;
|
|
184
|
+
setError: (error: ApiError$1 | null) => void;
|
|
35
185
|
/** Analytics proxy URL (when set, SDK sends events here instead of ScaleMule) */
|
|
36
186
|
analyticsProxyUrl?: string;
|
|
37
187
|
/** Auth proxy URL (when set, auth operations route through this proxy) */
|
|
@@ -56,11 +206,27 @@ interface ScaleMuleProviderProps extends ScaleMuleConfig {
|
|
|
56
206
|
/** Called when user logs out */
|
|
57
207
|
onLogout?: () => void;
|
|
58
208
|
/** Called on authentication error */
|
|
59
|
-
onAuthError?: (error: ApiError) => void;
|
|
209
|
+
onAuthError?: (error: ApiError$1) => void;
|
|
60
210
|
/** Server-evaluated flag values to bootstrap the client (eliminates loading flash) */
|
|
61
211
|
bootstrapFlags?: Record<string, unknown>;
|
|
212
|
+
/**
|
|
213
|
+
* Default media-pipeline policy applied to `useMedia()` calls when no
|
|
214
|
+
* per-call `policy` override is given. Five modes — see
|
|
215
|
+
* `docs/MEDIA-UPLOADS.md` and the {@link import('./hooks/useMedia').MediaPolicy} type.
|
|
216
|
+
*
|
|
217
|
+
* The platform stores the per-app policy in
|
|
218
|
+
* `application_storage_settings.media_policy` (Phase 4 / P3, live in
|
|
219
|
+
* prod). That endpoint is `MemberOnly` admin-auth, so end-user-context
|
|
220
|
+
* provider can't fetch it directly — apps that want policy-driven
|
|
221
|
+
* defaults should declare the value here, mirroring whatever the
|
|
222
|
+
* platform admin set.
|
|
223
|
+
*
|
|
224
|
+
* Default: undefined → `useMedia()` falls back to its built-in
|
|
225
|
+
* `safe_visible` default.
|
|
226
|
+
*/
|
|
227
|
+
mediaPolicy?: MediaPolicy;
|
|
62
228
|
}
|
|
63
|
-
declare function ScaleMuleProvider({ apiKey, applicationId, environment, gatewayUrl, debug, storage, analyticsProxyUrl, authProxyUrl, publishableKey, enableAccountSwitcher, accountSwitcherPrivacy, children, onLogin, onLogout, onAuthError, bootstrapFlags, }: ScaleMuleProviderProps): react_jsx_runtime.JSX.Element;
|
|
229
|
+
declare function ScaleMuleProvider({ apiKey, applicationId, environment, gatewayUrl, debug, storage, analyticsProxyUrl, authProxyUrl, publishableKey, enableAccountSwitcher, accountSwitcherPrivacy, children, onLogin, onLogout, onAuthError, bootstrapFlags, mediaPolicy, }: ScaleMuleProviderProps): react_jsx_runtime.JSX.Element;
|
|
64
230
|
declare function useScaleMule(): ScaleMuleContextValue;
|
|
65
231
|
declare function useScaleMuleClient(): ScaleMuleClient;
|
|
66
232
|
declare function useMoneyClient(): MoneyClient;
|
|
@@ -158,148 +324,6 @@ interface UseContentOptions {
|
|
|
158
324
|
*/
|
|
159
325
|
declare function useContent(options?: UseContentOptions): UseContentReturn;
|
|
160
326
|
|
|
161
|
-
/**
|
|
162
|
-
* Result of a single {@link useMedia} upload call.
|
|
163
|
-
*
|
|
164
|
-
* The shape is normalized regardless of MIME type — `optimized_url_promise`
|
|
165
|
-
* resolves on image uploads after the photo optimizer finishes; for non-image
|
|
166
|
-
* uploads it resolves to `null` immediately. (Video / audio branches will
|
|
167
|
-
* populate `hls_url_promise` in later phases — today they fall through to
|
|
168
|
-
* generic storage and that field stays `null`.)
|
|
169
|
-
*/
|
|
170
|
-
interface MediaUploadResult {
|
|
171
|
-
/** Storage file_id — store this in chat-attachment metadata. */
|
|
172
|
-
file_id: string;
|
|
173
|
-
/** Photo service id — null for non-image uploads or when register() failed. */
|
|
174
|
-
photo_id: string | null;
|
|
175
|
-
/** Short-lived signed URL to the original bytes (private uploads) or
|
|
176
|
-
* a public CDN URL (when caller passed `is_public: true`). */
|
|
177
|
-
original_view_url: string | null;
|
|
178
|
-
/** Resolves once the photo optimizer finishes. `null` for non-image
|
|
179
|
-
* MIME types or when register() failed. */
|
|
180
|
-
optimized_url_promise: Promise<string | null>;
|
|
181
|
-
/** Resolves once the video transcoder finishes (Phase 2 / S5b). `null` today. */
|
|
182
|
-
hls_url_promise: Promise<string | null>;
|
|
183
|
-
/** The file's MIME type — preserved from the input File / Blob. */
|
|
184
|
-
mime_type: string;
|
|
185
|
-
/** Whether the resulting storage object is public-readable. */
|
|
186
|
-
is_public: boolean;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Per-app media-pipeline policy. Drives release-gating + processing
|
|
190
|
-
* behavior. **Orthogonal to `is_public`.** See
|
|
191
|
-
* `docs/MEDIA-UPLOADS.md` and ADR-2026-04-26 for the full taxonomy.
|
|
192
|
-
*
|
|
193
|
-
* Today's behavior (Phase 4 v1):
|
|
194
|
-
* - `fast_trusted` / `safe_visible` (default): upload promise resolves
|
|
195
|
-
* as soon as the file is uploaded + registered. The post-processing
|
|
196
|
-
* (scan, optimize, transcode) runs async; callers can observe via
|
|
197
|
-
* `useFileStatus`.
|
|
198
|
-
* - `safe_public` / `moderated`: upload promise *waits* for the
|
|
199
|
-
* optimized image variant (image MIME) or HLS playlist (video MIME)
|
|
200
|
-
* to become ready before resolving. Acts as the release-gate for
|
|
201
|
-
* UGC-style apps that should not publish raw bytes.
|
|
202
|
-
* - `compliance`: today behaves as `safe_public`; Phase 4+ adds the
|
|
203
|
-
* audit-log + signed-with-purpose URL semantics.
|
|
204
|
-
*/
|
|
205
|
-
type MediaPolicy = 'fast_trusted' | 'safe_visible' | 'safe_public' | 'moderated' | 'compliance';
|
|
206
|
-
interface UseMediaUploadOptions {
|
|
207
|
-
/** Whether the resulting storage object should be public-readable.
|
|
208
|
-
* Default: `false` (private). Public is opt-in for surfaces that
|
|
209
|
-
* genuinely need it (avatars, public listings). Chat / DM uploads
|
|
210
|
-
* should always be private. */
|
|
211
|
-
is_public?: boolean;
|
|
212
|
-
/**
|
|
213
|
-
* Per-call media-policy override. Defaults to `safe_visible` (visible
|
|
214
|
-
* immediately at original fidelity; optimized variants swap in async).
|
|
215
|
-
* Set to `safe_public` to make the upload promise *await* the optimized
|
|
216
|
-
* variant (image) or HLS playlist (video) before resolving — useful for
|
|
217
|
-
* broadcast / UGC apps that gate publication on processing complete.
|
|
218
|
-
*
|
|
219
|
-
* The per-app default lives in `application_storage_settings.media_policy`
|
|
220
|
-
* (Phase 4 / P3, live in prod 2026-04-26). Reading the per-app default
|
|
221
|
-
* into `useMedia` defaults lands in a follow-up; today the option is
|
|
222
|
-
* caller-provided per call.
|
|
223
|
-
*/
|
|
224
|
-
policy?: MediaPolicy;
|
|
225
|
-
/** Display filename (sanitized server-side). */
|
|
226
|
-
filename?: string;
|
|
227
|
-
/** Custom metadata attached to the file. */
|
|
228
|
-
metadata?: Record<string, unknown>;
|
|
229
|
-
/** Upload progress callback (0-100). */
|
|
230
|
-
onProgress?: (percent: number) => void;
|
|
231
|
-
/** AbortSignal for cancellation. */
|
|
232
|
-
signal?: AbortSignal;
|
|
233
|
-
/** Force a non-photo path even for image MIME types — useful for
|
|
234
|
-
* generic file uploads where you don't want the photo optimizer
|
|
235
|
-
* to register the file. Default: `false`. */
|
|
236
|
-
skipPhotoRegister?: boolean;
|
|
237
|
-
}
|
|
238
|
-
interface UseMediaReturn {
|
|
239
|
-
/** Upload a file. MIME-aware: images go through photo register +
|
|
240
|
-
* optimization; everything else goes through generic storage. */
|
|
241
|
-
upload: (file: File | Blob, options?: UseMediaUploadOptions) => Promise<MediaUploadResult>;
|
|
242
|
-
/** Cancel an upload by its `file_id`. Deletes the storage object so
|
|
243
|
-
* it doesn't orphan in S3 — useful when a chat composer accepts a
|
|
244
|
-
* file but the user removes it before sending. Idempotent. */
|
|
245
|
-
cancelUpload: (fileId: string) => Promise<void>;
|
|
246
|
-
/** Last error from `upload` or `cancelUpload`. */
|
|
247
|
-
error: ApiError$1 | null;
|
|
248
|
-
/** True while an upload is in progress. */
|
|
249
|
-
uploading: boolean;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Opinionated, MIME-aware media upload hook.
|
|
253
|
-
*
|
|
254
|
-
* `useMedia()` is the canonical upload primitive for chat / progressive
|
|
255
|
-
* media use. It branches by MIME type:
|
|
256
|
-
* - `image/*` → `client.photo.uploadViaStorage()` — upload to storage,
|
|
257
|
-
* then register with the photo service so the on-demand transform
|
|
258
|
-
* endpoint resolves to optimized variants. The returned
|
|
259
|
-
* `optimized_url_promise` resolves once the optimizer finishes.
|
|
260
|
-
* - everything else → `client.storage.uploadPrivate()` — a private,
|
|
261
|
-
* uncompressed, fail-closed upload to generic storage.
|
|
262
|
-
*
|
|
263
|
-
* **Default visibility is `is_public: false`.** Public is opt-in per call.
|
|
264
|
-
* `useMedia()` does not expose `is_public` via app-level config — visibility
|
|
265
|
-
* is always an explicit per-call surface choice.
|
|
266
|
-
*
|
|
267
|
-
* Compared to `useContent()`:
|
|
268
|
-
* - `useContent()` is a thin wrapper over generic storage and does not
|
|
269
|
-
* register photos / videos with their typed services. Use it for plain
|
|
270
|
-
* file uploads where you don't need optimization or transcoding.
|
|
271
|
-
* - `useMedia()` defaults to private + no compression, integrates with the
|
|
272
|
-
* typed media services automatically, and is the right primitive for
|
|
273
|
-
* anything chat- or media-shaped.
|
|
274
|
-
*
|
|
275
|
-
* @example
|
|
276
|
-
* ```tsx
|
|
277
|
-
* 'use client';
|
|
278
|
-
*
|
|
279
|
-
* import { useMedia, ScaleMuleMedia } from '@scalemule/nextjs';
|
|
280
|
-
*
|
|
281
|
-
* function ChatComposer({ onAttach }) {
|
|
282
|
-
* const { upload, uploading } = useMedia();
|
|
283
|
-
*
|
|
284
|
-
* async function handlePick(file: File) {
|
|
285
|
-
* const result = await upload(file);
|
|
286
|
-
* onAttach({
|
|
287
|
-
* file_id: result.file_id,
|
|
288
|
-
* mime_type: result.mime_type,
|
|
289
|
-
* optimized_url_promise: result.optimized_url_promise,
|
|
290
|
-
* });
|
|
291
|
-
* }
|
|
292
|
-
*
|
|
293
|
-
* return <input type="file" disabled={uploading}
|
|
294
|
-
* onChange={(e) => e.target.files?.[0] && handlePick(e.target.files[0])} />;
|
|
295
|
-
* }
|
|
296
|
-
* ```
|
|
297
|
-
*
|
|
298
|
-
* See `docs/MEDIA-UPLOADS.md` in the platform repo for the decision
|
|
299
|
-
* tree and the full anti-patterns list.
|
|
300
|
-
*/
|
|
301
|
-
declare function useMedia(): UseMediaReturn;
|
|
302
|
-
|
|
303
327
|
interface UseFileStatusOptions {
|
|
304
328
|
/** Storage file_id to read status for. */
|
|
305
329
|
fileId: string | null | undefined;
|
|
@@ -326,7 +350,7 @@ interface UseFileStatusReturn {
|
|
|
326
350
|
/** True while a fetch is in flight. */
|
|
327
351
|
loading: boolean;
|
|
328
352
|
/** Last error, or null. */
|
|
329
|
-
error: ApiError
|
|
353
|
+
error: ApiError | null;
|
|
330
354
|
/**
|
|
331
355
|
* Convenience: scan is clean. For images/videos, this means the file
|
|
332
356
|
* is *safe to render*; the optimized / HLS variants may still be
|
|
@@ -586,7 +610,7 @@ interface UseFeatureFlagsOptions {
|
|
|
586
610
|
interface UseFeatureFlagsReturn {
|
|
587
611
|
flags: Record<string, FeatureFlagEvaluation>;
|
|
588
612
|
loading: boolean;
|
|
589
|
-
error: ApiError | null;
|
|
613
|
+
error: ApiError$1 | null;
|
|
590
614
|
refresh: () => Promise<void>;
|
|
591
615
|
isEnabled: (flagKey: string, fallback?: boolean) => boolean;
|
|
592
616
|
getFlag: <T = unknown>(flagKey: string, fallback?: T) => T;
|
|
@@ -613,7 +637,7 @@ interface UsePushNotificationsReturn {
|
|
|
613
637
|
/** Whether an operation is in progress */
|
|
614
638
|
isLoading: boolean;
|
|
615
639
|
/** Last error */
|
|
616
|
-
error: ApiError | null;
|
|
640
|
+
error: ApiError$1 | null;
|
|
617
641
|
/** Request permission and subscribe to push notifications */
|
|
618
642
|
subscribe: () => Promise<void>;
|
|
619
643
|
/** Unsubscribe from push notifications */
|
|
@@ -714,7 +738,7 @@ interface UseFeedbackResult {
|
|
|
714
738
|
/** End-user's own feedback items for the current tenant. Empty when not signed in. */
|
|
715
739
|
items: FeedbackItem[];
|
|
716
740
|
loading: boolean;
|
|
717
|
-
error: ApiError | null;
|
|
741
|
+
error: ApiError$1 | null;
|
|
718
742
|
/** Submit a new feedback item. Returns the persisted item on success. */
|
|
719
743
|
submit: (input: FeedbackItemInput) => Promise<FeedbackItem>;
|
|
720
744
|
/** Re-fetch the list. */
|
|
@@ -926,4 +950,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
926
950
|
error: (message: string, data?: unknown) => void;
|
|
927
951
|
};
|
|
928
952
|
|
|
929
|
-
export { ApiError, 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 };
|
|
953
|
+
export { ApiError$1 as ApiError, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,156 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, FileStatus } from '@scalemule/sdk';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
import { ReactNode, ReactElement } from 'react';
|
|
4
5
|
import { MoneyClient } from '@scalemule/money';
|
|
5
6
|
export { MoneyClient, MoneyClientConfig, createMoneyClient } from '@scalemule/money';
|
|
6
|
-
import { RealtimeService, StorageService, PhotoService, VideoService, ApiError as ApiError$1, FileStatus } from '@scalemule/sdk';
|
|
7
7
|
import { ScaleMuleClient } from './client.js';
|
|
8
8
|
export { ClientConfig, RequestOptions, createClient } from './client.js';
|
|
9
|
-
import { S as ScaleMuleConfig, U as User, L as LoginResponse, A as ApiError, a as UseAuthReturn, b as UseBillingReturn, c as ListFilesParams, d as UseContentReturn, e as UseUserReturn, f as UseAnalyticsOptions, g as UseAnalyticsReturn } from './index-BIIUrnPr.js';
|
|
9
|
+
import { S as ScaleMuleConfig, U as User, L as LoginResponse, A as ApiError$1, a as UseAuthReturn, b as UseBillingReturn, c as ListFilesParams, d as UseContentReturn, e as UseUserReturn, f as UseAnalyticsOptions, g as UseAnalyticsReturn } from './index-BIIUrnPr.js';
|
|
10
10
|
export { h as AccountBalance, i as AnalyticsEvent, j as ApiResponse, B as BatchTrackRequest, k as BillingPayment, l as BillingPayout, m as BillingRefund, n as BillingTransaction, C as ChangeEmailRequest, o as ChangePasswordRequest, p as ClientContext, q as ConnectedAccount, D as DeviceFingerprint, r as DeviceInfo, E as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, K as KnownAccountInfo, s as LinkedAccount, t as ListFilesResponse, u as LoginDeviceInfo, v as LoginRequest, w as LoginResponseWithMFA, x as LoginRiskInfo, M as MFAChallengeResponse, y as MFAMethod, z as MFASMSSetupResponse, G as MFASetupRequest, H as MFAStatus, I as MFATOTPSetupResponse, J as MFAVerifyRequest, O as OAuthCallbackRequest, N as OAuthCallbackResponse, P as OAuthConfig, Q as OAuthProvider, R as OAuthStartResponse, T as PageViewData, V as PayoutSchedule, W as PhoneLoginRequest, X as PhoneSendCodeRequest, Y as PhoneVerifyRequest, Z as Profile, _ as RefreshResponse, $ as RegisterRequest, a0 as ResetPasswordRequest, a1 as ScaleMuleApiError, a2 as ScaleMuleEnvironment, a3 as Session, a4 as SignedUploadCompleteRequest, a5 as SignedUploadRequest, a6 as SignedUploadResponse, a7 as SignedUploadUrl, a8 as StorageAdapter, a9 as StorageFile, aa as TrackEventResponse, ab as TransactionSummary, ac as UTMParams, ad as UpdateProfileRequest, ae as UploadOptions, af as UploadResponse, ag as VerifyEmailRequest } from './index-BIIUrnPr.js';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Result of a single {@link useMedia} upload call.
|
|
14
|
+
*
|
|
15
|
+
* The shape is normalized regardless of MIME type — `optimized_url_promise`
|
|
16
|
+
* resolves on image uploads after the photo optimizer finishes; for non-image
|
|
17
|
+
* uploads it resolves to `null` immediately. (Video / audio branches will
|
|
18
|
+
* populate `hls_url_promise` in later phases — today they fall through to
|
|
19
|
+
* generic storage and that field stays `null`.)
|
|
20
|
+
*/
|
|
21
|
+
interface MediaUploadResult {
|
|
22
|
+
/** Storage file_id — store this in chat-attachment metadata. */
|
|
23
|
+
file_id: string;
|
|
24
|
+
/** Photo service id — null for non-image uploads or when register() failed. */
|
|
25
|
+
photo_id: string | null;
|
|
26
|
+
/** Short-lived signed URL to the original bytes (private uploads) or
|
|
27
|
+
* a public CDN URL (when caller passed `is_public: true`). */
|
|
28
|
+
original_view_url: string | null;
|
|
29
|
+
/** Resolves once the photo optimizer finishes. `null` for non-image
|
|
30
|
+
* MIME types or when register() failed. */
|
|
31
|
+
optimized_url_promise: Promise<string | null>;
|
|
32
|
+
/** Resolves once the video transcoder finishes (Phase 2 / S5b). `null` today. */
|
|
33
|
+
hls_url_promise: Promise<string | null>;
|
|
34
|
+
/** The file's MIME type — preserved from the input File / Blob. */
|
|
35
|
+
mime_type: string;
|
|
36
|
+
/** Whether the resulting storage object is public-readable. */
|
|
37
|
+
is_public: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Per-app media-pipeline policy. Drives release-gating + processing
|
|
41
|
+
* behavior. **Orthogonal to `is_public`.** See
|
|
42
|
+
* `docs/MEDIA-UPLOADS.md` and ADR-2026-04-26 for the full taxonomy.
|
|
43
|
+
*
|
|
44
|
+
* Today's behavior (Phase 4 v1):
|
|
45
|
+
* - `fast_trusted` / `safe_visible` (default): upload promise resolves
|
|
46
|
+
* as soon as the file is uploaded + registered. The post-processing
|
|
47
|
+
* (scan, optimize, transcode) runs async; callers can observe via
|
|
48
|
+
* `useFileStatus`.
|
|
49
|
+
* - `safe_public` / `moderated`: upload promise *waits* for the
|
|
50
|
+
* optimized image variant (image MIME) or HLS playlist (video MIME)
|
|
51
|
+
* to become ready before resolving. Acts as the release-gate for
|
|
52
|
+
* UGC-style apps that should not publish raw bytes.
|
|
53
|
+
* - `compliance`: today behaves as `safe_public`; Phase 4+ adds the
|
|
54
|
+
* audit-log + signed-with-purpose URL semantics.
|
|
55
|
+
*/
|
|
56
|
+
type MediaPolicy = 'fast_trusted' | 'safe_visible' | 'safe_public' | 'moderated' | 'compliance';
|
|
57
|
+
interface UseMediaUploadOptions {
|
|
58
|
+
/** Whether the resulting storage object should be public-readable.
|
|
59
|
+
* Default: `false` (private). Public is opt-in for surfaces that
|
|
60
|
+
* genuinely need it (avatars, public listings). Chat / DM uploads
|
|
61
|
+
* should always be private. */
|
|
62
|
+
is_public?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Per-call media-policy override. Defaults to `safe_visible` (visible
|
|
65
|
+
* immediately at original fidelity; optimized variants swap in async).
|
|
66
|
+
* Set to `safe_public` to make the upload promise *await* the optimized
|
|
67
|
+
* variant (image) or HLS playlist (video) before resolving — useful for
|
|
68
|
+
* broadcast / UGC apps that gate publication on processing complete.
|
|
69
|
+
*
|
|
70
|
+
* The per-app default lives in `application_storage_settings.media_policy`
|
|
71
|
+
* (Phase 4 / P3, live in prod 2026-04-26). Reading the per-app default
|
|
72
|
+
* into `useMedia` defaults lands in a follow-up; today the option is
|
|
73
|
+
* caller-provided per call.
|
|
74
|
+
*/
|
|
75
|
+
policy?: MediaPolicy;
|
|
76
|
+
/** Display filename (sanitized server-side). */
|
|
77
|
+
filename?: string;
|
|
78
|
+
/** Custom metadata attached to the file. */
|
|
79
|
+
metadata?: Record<string, unknown>;
|
|
80
|
+
/** Upload progress callback (0-100). */
|
|
81
|
+
onProgress?: (percent: number) => void;
|
|
82
|
+
/** AbortSignal for cancellation. */
|
|
83
|
+
signal?: AbortSignal;
|
|
84
|
+
/** Force a non-photo path even for image MIME types — useful for
|
|
85
|
+
* generic file uploads where you don't want the photo optimizer
|
|
86
|
+
* to register the file. Default: `false`. */
|
|
87
|
+
skipPhotoRegister?: boolean;
|
|
88
|
+
}
|
|
89
|
+
interface UseMediaReturn {
|
|
90
|
+
/** Upload a file. MIME-aware: images go through photo register +
|
|
91
|
+
* optimization; everything else goes through generic storage. */
|
|
92
|
+
upload: (file: File | Blob, options?: UseMediaUploadOptions) => Promise<MediaUploadResult>;
|
|
93
|
+
/** Cancel an upload by its `file_id`. Deletes the storage object so
|
|
94
|
+
* it doesn't orphan in S3 — useful when a chat composer accepts a
|
|
95
|
+
* file but the user removes it before sending. Idempotent. */
|
|
96
|
+
cancelUpload: (fileId: string) => Promise<void>;
|
|
97
|
+
/** Last error from `upload` or `cancelUpload`. */
|
|
98
|
+
error: ApiError | null;
|
|
99
|
+
/** True while an upload is in progress. */
|
|
100
|
+
uploading: boolean;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Opinionated, MIME-aware media upload hook.
|
|
104
|
+
*
|
|
105
|
+
* `useMedia()` is the canonical upload primitive for chat / progressive
|
|
106
|
+
* media use. It branches by MIME type:
|
|
107
|
+
* - `image/*` → `client.photo.uploadViaStorage()` — upload to storage,
|
|
108
|
+
* then register with the photo service so the on-demand transform
|
|
109
|
+
* endpoint resolves to optimized variants. The returned
|
|
110
|
+
* `optimized_url_promise` resolves once the optimizer finishes.
|
|
111
|
+
* - everything else → `client.storage.uploadPrivate()` — a private,
|
|
112
|
+
* uncompressed, fail-closed upload to generic storage.
|
|
113
|
+
*
|
|
114
|
+
* **Default visibility is `is_public: false`.** Public is opt-in per call.
|
|
115
|
+
* `useMedia()` does not expose `is_public` via app-level config — visibility
|
|
116
|
+
* is always an explicit per-call surface choice.
|
|
117
|
+
*
|
|
118
|
+
* Compared to `useContent()`:
|
|
119
|
+
* - `useContent()` is a thin wrapper over generic storage and does not
|
|
120
|
+
* register photos / videos with their typed services. Use it for plain
|
|
121
|
+
* file uploads where you don't need optimization or transcoding.
|
|
122
|
+
* - `useMedia()` defaults to private + no compression, integrates with the
|
|
123
|
+
* typed media services automatically, and is the right primitive for
|
|
124
|
+
* anything chat- or media-shaped.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```tsx
|
|
128
|
+
* 'use client';
|
|
129
|
+
*
|
|
130
|
+
* import { useMedia, ScaleMuleMedia } from '@scalemule/nextjs';
|
|
131
|
+
*
|
|
132
|
+
* function ChatComposer({ onAttach }) {
|
|
133
|
+
* const { upload, uploading } = useMedia();
|
|
134
|
+
*
|
|
135
|
+
* async function handlePick(file: File) {
|
|
136
|
+
* const result = await upload(file);
|
|
137
|
+
* onAttach({
|
|
138
|
+
* file_id: result.file_id,
|
|
139
|
+
* mime_type: result.mime_type,
|
|
140
|
+
* optimized_url_promise: result.optimized_url_promise,
|
|
141
|
+
* });
|
|
142
|
+
* }
|
|
143
|
+
*
|
|
144
|
+
* return <input type="file" disabled={uploading}
|
|
145
|
+
* onChange={(e) => e.target.files?.[0] && handlePick(e.target.files[0])} />;
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* See `docs/MEDIA-UPLOADS.md` in the platform repo for the decision
|
|
150
|
+
* tree and the full anti-patterns list.
|
|
151
|
+
*/
|
|
152
|
+
declare function useMedia(): UseMediaReturn;
|
|
153
|
+
|
|
12
154
|
interface ScaleMuleContextValue {
|
|
13
155
|
/** The API client instance */
|
|
14
156
|
client: ScaleMuleClient;
|
|
@@ -22,6 +164,14 @@ interface ScaleMuleContextValue {
|
|
|
22
164
|
photo: PhotoService;
|
|
23
165
|
/** Base SDK video service — exposed for `useMedia()` and `video.uploadViaStorage()` */
|
|
24
166
|
video: VideoService;
|
|
167
|
+
/** Base SDK audio service — exposed for `useMedia()` and `audio.uploadViaStorage()` */
|
|
168
|
+
audio: AudioService;
|
|
169
|
+
/**
|
|
170
|
+
* Default media policy for `useMedia()` calls. Set via
|
|
171
|
+
* `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
|
|
172
|
+
* Undefined falls back to `useMedia()`'s built-in `safe_visible` default.
|
|
173
|
+
*/
|
|
174
|
+
mediaPolicy?: MediaPolicy;
|
|
25
175
|
/** Current authenticated user */
|
|
26
176
|
user: User | null;
|
|
27
177
|
/** Set the current user */
|
|
@@ -29,9 +179,9 @@ interface ScaleMuleContextValue {
|
|
|
29
179
|
/** Whether the SDK is initializing */
|
|
30
180
|
initializing: boolean;
|
|
31
181
|
/** Last error */
|
|
32
|
-
error: ApiError | null;
|
|
182
|
+
error: ApiError$1 | null;
|
|
33
183
|
/** Set error */
|
|
34
|
-
setError: (error: ApiError | null) => void;
|
|
184
|
+
setError: (error: ApiError$1 | null) => void;
|
|
35
185
|
/** Analytics proxy URL (when set, SDK sends events here instead of ScaleMule) */
|
|
36
186
|
analyticsProxyUrl?: string;
|
|
37
187
|
/** Auth proxy URL (when set, auth operations route through this proxy) */
|
|
@@ -56,11 +206,27 @@ interface ScaleMuleProviderProps extends ScaleMuleConfig {
|
|
|
56
206
|
/** Called when user logs out */
|
|
57
207
|
onLogout?: () => void;
|
|
58
208
|
/** Called on authentication error */
|
|
59
|
-
onAuthError?: (error: ApiError) => void;
|
|
209
|
+
onAuthError?: (error: ApiError$1) => void;
|
|
60
210
|
/** Server-evaluated flag values to bootstrap the client (eliminates loading flash) */
|
|
61
211
|
bootstrapFlags?: Record<string, unknown>;
|
|
212
|
+
/**
|
|
213
|
+
* Default media-pipeline policy applied to `useMedia()` calls when no
|
|
214
|
+
* per-call `policy` override is given. Five modes — see
|
|
215
|
+
* `docs/MEDIA-UPLOADS.md` and the {@link import('./hooks/useMedia').MediaPolicy} type.
|
|
216
|
+
*
|
|
217
|
+
* The platform stores the per-app policy in
|
|
218
|
+
* `application_storage_settings.media_policy` (Phase 4 / P3, live in
|
|
219
|
+
* prod). That endpoint is `MemberOnly` admin-auth, so end-user-context
|
|
220
|
+
* provider can't fetch it directly — apps that want policy-driven
|
|
221
|
+
* defaults should declare the value here, mirroring whatever the
|
|
222
|
+
* platform admin set.
|
|
223
|
+
*
|
|
224
|
+
* Default: undefined → `useMedia()` falls back to its built-in
|
|
225
|
+
* `safe_visible` default.
|
|
226
|
+
*/
|
|
227
|
+
mediaPolicy?: MediaPolicy;
|
|
62
228
|
}
|
|
63
|
-
declare function ScaleMuleProvider({ apiKey, applicationId, environment, gatewayUrl, debug, storage, analyticsProxyUrl, authProxyUrl, publishableKey, enableAccountSwitcher, accountSwitcherPrivacy, children, onLogin, onLogout, onAuthError, bootstrapFlags, }: ScaleMuleProviderProps): react_jsx_runtime.JSX.Element;
|
|
229
|
+
declare function ScaleMuleProvider({ apiKey, applicationId, environment, gatewayUrl, debug, storage, analyticsProxyUrl, authProxyUrl, publishableKey, enableAccountSwitcher, accountSwitcherPrivacy, children, onLogin, onLogout, onAuthError, bootstrapFlags, mediaPolicy, }: ScaleMuleProviderProps): react_jsx_runtime.JSX.Element;
|
|
64
230
|
declare function useScaleMule(): ScaleMuleContextValue;
|
|
65
231
|
declare function useScaleMuleClient(): ScaleMuleClient;
|
|
66
232
|
declare function useMoneyClient(): MoneyClient;
|
|
@@ -158,148 +324,6 @@ interface UseContentOptions {
|
|
|
158
324
|
*/
|
|
159
325
|
declare function useContent(options?: UseContentOptions): UseContentReturn;
|
|
160
326
|
|
|
161
|
-
/**
|
|
162
|
-
* Result of a single {@link useMedia} upload call.
|
|
163
|
-
*
|
|
164
|
-
* The shape is normalized regardless of MIME type — `optimized_url_promise`
|
|
165
|
-
* resolves on image uploads after the photo optimizer finishes; for non-image
|
|
166
|
-
* uploads it resolves to `null` immediately. (Video / audio branches will
|
|
167
|
-
* populate `hls_url_promise` in later phases — today they fall through to
|
|
168
|
-
* generic storage and that field stays `null`.)
|
|
169
|
-
*/
|
|
170
|
-
interface MediaUploadResult {
|
|
171
|
-
/** Storage file_id — store this in chat-attachment metadata. */
|
|
172
|
-
file_id: string;
|
|
173
|
-
/** Photo service id — null for non-image uploads or when register() failed. */
|
|
174
|
-
photo_id: string | null;
|
|
175
|
-
/** Short-lived signed URL to the original bytes (private uploads) or
|
|
176
|
-
* a public CDN URL (when caller passed `is_public: true`). */
|
|
177
|
-
original_view_url: string | null;
|
|
178
|
-
/** Resolves once the photo optimizer finishes. `null` for non-image
|
|
179
|
-
* MIME types or when register() failed. */
|
|
180
|
-
optimized_url_promise: Promise<string | null>;
|
|
181
|
-
/** Resolves once the video transcoder finishes (Phase 2 / S5b). `null` today. */
|
|
182
|
-
hls_url_promise: Promise<string | null>;
|
|
183
|
-
/** The file's MIME type — preserved from the input File / Blob. */
|
|
184
|
-
mime_type: string;
|
|
185
|
-
/** Whether the resulting storage object is public-readable. */
|
|
186
|
-
is_public: boolean;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Per-app media-pipeline policy. Drives release-gating + processing
|
|
190
|
-
* behavior. **Orthogonal to `is_public`.** See
|
|
191
|
-
* `docs/MEDIA-UPLOADS.md` and ADR-2026-04-26 for the full taxonomy.
|
|
192
|
-
*
|
|
193
|
-
* Today's behavior (Phase 4 v1):
|
|
194
|
-
* - `fast_trusted` / `safe_visible` (default): upload promise resolves
|
|
195
|
-
* as soon as the file is uploaded + registered. The post-processing
|
|
196
|
-
* (scan, optimize, transcode) runs async; callers can observe via
|
|
197
|
-
* `useFileStatus`.
|
|
198
|
-
* - `safe_public` / `moderated`: upload promise *waits* for the
|
|
199
|
-
* optimized image variant (image MIME) or HLS playlist (video MIME)
|
|
200
|
-
* to become ready before resolving. Acts as the release-gate for
|
|
201
|
-
* UGC-style apps that should not publish raw bytes.
|
|
202
|
-
* - `compliance`: today behaves as `safe_public`; Phase 4+ adds the
|
|
203
|
-
* audit-log + signed-with-purpose URL semantics.
|
|
204
|
-
*/
|
|
205
|
-
type MediaPolicy = 'fast_trusted' | 'safe_visible' | 'safe_public' | 'moderated' | 'compliance';
|
|
206
|
-
interface UseMediaUploadOptions {
|
|
207
|
-
/** Whether the resulting storage object should be public-readable.
|
|
208
|
-
* Default: `false` (private). Public is opt-in for surfaces that
|
|
209
|
-
* genuinely need it (avatars, public listings). Chat / DM uploads
|
|
210
|
-
* should always be private. */
|
|
211
|
-
is_public?: boolean;
|
|
212
|
-
/**
|
|
213
|
-
* Per-call media-policy override. Defaults to `safe_visible` (visible
|
|
214
|
-
* immediately at original fidelity; optimized variants swap in async).
|
|
215
|
-
* Set to `safe_public` to make the upload promise *await* the optimized
|
|
216
|
-
* variant (image) or HLS playlist (video) before resolving — useful for
|
|
217
|
-
* broadcast / UGC apps that gate publication on processing complete.
|
|
218
|
-
*
|
|
219
|
-
* The per-app default lives in `application_storage_settings.media_policy`
|
|
220
|
-
* (Phase 4 / P3, live in prod 2026-04-26). Reading the per-app default
|
|
221
|
-
* into `useMedia` defaults lands in a follow-up; today the option is
|
|
222
|
-
* caller-provided per call.
|
|
223
|
-
*/
|
|
224
|
-
policy?: MediaPolicy;
|
|
225
|
-
/** Display filename (sanitized server-side). */
|
|
226
|
-
filename?: string;
|
|
227
|
-
/** Custom metadata attached to the file. */
|
|
228
|
-
metadata?: Record<string, unknown>;
|
|
229
|
-
/** Upload progress callback (0-100). */
|
|
230
|
-
onProgress?: (percent: number) => void;
|
|
231
|
-
/** AbortSignal for cancellation. */
|
|
232
|
-
signal?: AbortSignal;
|
|
233
|
-
/** Force a non-photo path even for image MIME types — useful for
|
|
234
|
-
* generic file uploads where you don't want the photo optimizer
|
|
235
|
-
* to register the file. Default: `false`. */
|
|
236
|
-
skipPhotoRegister?: boolean;
|
|
237
|
-
}
|
|
238
|
-
interface UseMediaReturn {
|
|
239
|
-
/** Upload a file. MIME-aware: images go through photo register +
|
|
240
|
-
* optimization; everything else goes through generic storage. */
|
|
241
|
-
upload: (file: File | Blob, options?: UseMediaUploadOptions) => Promise<MediaUploadResult>;
|
|
242
|
-
/** Cancel an upload by its `file_id`. Deletes the storage object so
|
|
243
|
-
* it doesn't orphan in S3 — useful when a chat composer accepts a
|
|
244
|
-
* file but the user removes it before sending. Idempotent. */
|
|
245
|
-
cancelUpload: (fileId: string) => Promise<void>;
|
|
246
|
-
/** Last error from `upload` or `cancelUpload`. */
|
|
247
|
-
error: ApiError$1 | null;
|
|
248
|
-
/** True while an upload is in progress. */
|
|
249
|
-
uploading: boolean;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Opinionated, MIME-aware media upload hook.
|
|
253
|
-
*
|
|
254
|
-
* `useMedia()` is the canonical upload primitive for chat / progressive
|
|
255
|
-
* media use. It branches by MIME type:
|
|
256
|
-
* - `image/*` → `client.photo.uploadViaStorage()` — upload to storage,
|
|
257
|
-
* then register with the photo service so the on-demand transform
|
|
258
|
-
* endpoint resolves to optimized variants. The returned
|
|
259
|
-
* `optimized_url_promise` resolves once the optimizer finishes.
|
|
260
|
-
* - everything else → `client.storage.uploadPrivate()` — a private,
|
|
261
|
-
* uncompressed, fail-closed upload to generic storage.
|
|
262
|
-
*
|
|
263
|
-
* **Default visibility is `is_public: false`.** Public is opt-in per call.
|
|
264
|
-
* `useMedia()` does not expose `is_public` via app-level config — visibility
|
|
265
|
-
* is always an explicit per-call surface choice.
|
|
266
|
-
*
|
|
267
|
-
* Compared to `useContent()`:
|
|
268
|
-
* - `useContent()` is a thin wrapper over generic storage and does not
|
|
269
|
-
* register photos / videos with their typed services. Use it for plain
|
|
270
|
-
* file uploads where you don't need optimization or transcoding.
|
|
271
|
-
* - `useMedia()` defaults to private + no compression, integrates with the
|
|
272
|
-
* typed media services automatically, and is the right primitive for
|
|
273
|
-
* anything chat- or media-shaped.
|
|
274
|
-
*
|
|
275
|
-
* @example
|
|
276
|
-
* ```tsx
|
|
277
|
-
* 'use client';
|
|
278
|
-
*
|
|
279
|
-
* import { useMedia, ScaleMuleMedia } from '@scalemule/nextjs';
|
|
280
|
-
*
|
|
281
|
-
* function ChatComposer({ onAttach }) {
|
|
282
|
-
* const { upload, uploading } = useMedia();
|
|
283
|
-
*
|
|
284
|
-
* async function handlePick(file: File) {
|
|
285
|
-
* const result = await upload(file);
|
|
286
|
-
* onAttach({
|
|
287
|
-
* file_id: result.file_id,
|
|
288
|
-
* mime_type: result.mime_type,
|
|
289
|
-
* optimized_url_promise: result.optimized_url_promise,
|
|
290
|
-
* });
|
|
291
|
-
* }
|
|
292
|
-
*
|
|
293
|
-
* return <input type="file" disabled={uploading}
|
|
294
|
-
* onChange={(e) => e.target.files?.[0] && handlePick(e.target.files[0])} />;
|
|
295
|
-
* }
|
|
296
|
-
* ```
|
|
297
|
-
*
|
|
298
|
-
* See `docs/MEDIA-UPLOADS.md` in the platform repo for the decision
|
|
299
|
-
* tree and the full anti-patterns list.
|
|
300
|
-
*/
|
|
301
|
-
declare function useMedia(): UseMediaReturn;
|
|
302
|
-
|
|
303
327
|
interface UseFileStatusOptions {
|
|
304
328
|
/** Storage file_id to read status for. */
|
|
305
329
|
fileId: string | null | undefined;
|
|
@@ -326,7 +350,7 @@ interface UseFileStatusReturn {
|
|
|
326
350
|
/** True while a fetch is in flight. */
|
|
327
351
|
loading: boolean;
|
|
328
352
|
/** Last error, or null. */
|
|
329
|
-
error: ApiError
|
|
353
|
+
error: ApiError | null;
|
|
330
354
|
/**
|
|
331
355
|
* Convenience: scan is clean. For images/videos, this means the file
|
|
332
356
|
* is *safe to render*; the optimized / HLS variants may still be
|
|
@@ -586,7 +610,7 @@ interface UseFeatureFlagsOptions {
|
|
|
586
610
|
interface UseFeatureFlagsReturn {
|
|
587
611
|
flags: Record<string, FeatureFlagEvaluation>;
|
|
588
612
|
loading: boolean;
|
|
589
|
-
error: ApiError | null;
|
|
613
|
+
error: ApiError$1 | null;
|
|
590
614
|
refresh: () => Promise<void>;
|
|
591
615
|
isEnabled: (flagKey: string, fallback?: boolean) => boolean;
|
|
592
616
|
getFlag: <T = unknown>(flagKey: string, fallback?: T) => T;
|
|
@@ -613,7 +637,7 @@ interface UsePushNotificationsReturn {
|
|
|
613
637
|
/** Whether an operation is in progress */
|
|
614
638
|
isLoading: boolean;
|
|
615
639
|
/** Last error */
|
|
616
|
-
error: ApiError | null;
|
|
640
|
+
error: ApiError$1 | null;
|
|
617
641
|
/** Request permission and subscribe to push notifications */
|
|
618
642
|
subscribe: () => Promise<void>;
|
|
619
643
|
/** Unsubscribe from push notifications */
|
|
@@ -714,7 +738,7 @@ interface UseFeedbackResult {
|
|
|
714
738
|
/** End-user's own feedback items for the current tenant. Empty when not signed in. */
|
|
715
739
|
items: FeedbackItem[];
|
|
716
740
|
loading: boolean;
|
|
717
|
-
error: ApiError | null;
|
|
741
|
+
error: ApiError$1 | null;
|
|
718
742
|
/** Submit a new feedback item. Returns the persisted item on success. */
|
|
719
743
|
submit: (input: FeedbackItemInput) => Promise<FeedbackItem>;
|
|
720
744
|
/** Re-fetch the list. */
|
|
@@ -926,4 +950,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
926
950
|
error: (message: string, data?: unknown) => void;
|
|
927
951
|
};
|
|
928
952
|
|
|
929
|
-
export { ApiError, 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 };
|
|
953
|
+
export { ApiError$1 as ApiError, 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 };
|
package/dist/index.js
CHANGED
|
@@ -2727,6 +2727,25 @@ var StorageService = class extends ServiceModule {
|
|
|
2727
2727
|
async getInfo(fileId, options) {
|
|
2728
2728
|
return this._get(`/files/${fileId}/info`, options);
|
|
2729
2729
|
}
|
|
2730
|
+
/**
|
|
2731
|
+
* Get the calling app's storage + media settings — content policy,
|
|
2732
|
+
* retention, max upload size, and the per-app `media_policy`.
|
|
2733
|
+
*
|
|
2734
|
+
* `media_policy` drives release-gating in the SDK upload helpers:
|
|
2735
|
+
* `fast_trusted` / `safe_visible` resolve immediately on upload; the
|
|
2736
|
+
* `safe_public` / `moderated` / `compliance` modes await pipeline
|
|
2737
|
+
* completion before resolving the upload promise.
|
|
2738
|
+
*/
|
|
2739
|
+
async getSettings(options) {
|
|
2740
|
+
return this._get("/settings", options);
|
|
2741
|
+
}
|
|
2742
|
+
/**
|
|
2743
|
+
* Update the calling app's storage + media settings. Admin-only on the
|
|
2744
|
+
* platform side (callers without the right role get 403).
|
|
2745
|
+
*/
|
|
2746
|
+
async updateSettings(settings, options) {
|
|
2747
|
+
return this.put("/settings", settings, options);
|
|
2748
|
+
}
|
|
2730
2749
|
/**
|
|
2731
2750
|
* Aggregate status for a file — single call returns scan + reserved
|
|
2732
2751
|
* optimize/transcode slots + the canonical view URL paths for image
|
|
@@ -5678,6 +5697,72 @@ var PhotoService = class extends ServiceModule {
|
|
|
5678
5697
|
return this.get(id);
|
|
5679
5698
|
}
|
|
5680
5699
|
};
|
|
5700
|
+
var AudioService = class extends ServiceModule {
|
|
5701
|
+
/**
|
|
5702
|
+
* @param storage Required for {@link uploadViaStorage}. Wired up by the
|
|
5703
|
+
* top-level {@link ScaleMule} constructor — most call sites should not
|
|
5704
|
+
* instantiate `AudioService` directly.
|
|
5705
|
+
*/
|
|
5706
|
+
constructor(client, storage) {
|
|
5707
|
+
super(client);
|
|
5708
|
+
this.storage = storage;
|
|
5709
|
+
this.basePath = "/v1/audios";
|
|
5710
|
+
}
|
|
5711
|
+
/**
|
|
5712
|
+
* Register a storage-uploaded audio asset with the audio service.
|
|
5713
|
+
* Idempotent — re-calling with the same `file_id` returns the existing
|
|
5714
|
+
* record.
|
|
5715
|
+
*/
|
|
5716
|
+
async register(args, options) {
|
|
5717
|
+
return this.post("/register", { file_id: args.fileId, sm_user_id: args.userId }, options);
|
|
5718
|
+
}
|
|
5719
|
+
/**
|
|
5720
|
+
* Upload a file to storage (browser → S3 direct, private, uncompressed)
|
|
5721
|
+
* and register it with the audio service.
|
|
5722
|
+
*
|
|
5723
|
+
* Mirrors `photo.uploadViaStorage()` / `video.uploadViaStorage()`. If
|
|
5724
|
+
* `register()` fails after a successful storage upload, the file is *not*
|
|
5725
|
+
* lost — the returned `file_id` is still valid as a generic private storage
|
|
5726
|
+
* file. The SDK logs a warning and returns `audio_id: null`.
|
|
5727
|
+
*/
|
|
5728
|
+
async uploadViaStorage(file, uploadOptions, requestOptions) {
|
|
5729
|
+
const uploadResult = await this.storage.uploadPrivate(file, {
|
|
5730
|
+
filename: uploadOptions?.filename,
|
|
5731
|
+
metadata: uploadOptions?.metadata,
|
|
5732
|
+
onProgress: uploadOptions?.onProgress,
|
|
5733
|
+
signal: uploadOptions?.signal
|
|
5734
|
+
});
|
|
5735
|
+
if (uploadResult.error || !uploadResult.data) {
|
|
5736
|
+
return { data: null, error: uploadResult.error };
|
|
5737
|
+
}
|
|
5738
|
+
const fileInfo = uploadResult.data;
|
|
5739
|
+
const fileId = fileInfo.id;
|
|
5740
|
+
const originalViewUrl = fileInfo.url ?? null;
|
|
5741
|
+
const registerResult = await this.register({ fileId, userId: uploadOptions?.userId }, requestOptions);
|
|
5742
|
+
if (registerResult.error || !registerResult.data) {
|
|
5743
|
+
console.warn(
|
|
5744
|
+
"[scalemule-sdk] audio.register() failed after storage upload; typed audio metadata unavailable.",
|
|
5745
|
+
registerResult.error
|
|
5746
|
+
);
|
|
5747
|
+
return {
|
|
5748
|
+
data: {
|
|
5749
|
+
file_id: fileId,
|
|
5750
|
+
audio_id: null,
|
|
5751
|
+
original_view_url: originalViewUrl
|
|
5752
|
+
},
|
|
5753
|
+
error: null
|
|
5754
|
+
};
|
|
5755
|
+
}
|
|
5756
|
+
return {
|
|
5757
|
+
data: {
|
|
5758
|
+
file_id: fileId,
|
|
5759
|
+
audio_id: registerResult.data.audio_id,
|
|
5760
|
+
original_view_url: originalViewUrl
|
|
5761
|
+
},
|
|
5762
|
+
error: null
|
|
5763
|
+
};
|
|
5764
|
+
}
|
|
5765
|
+
};
|
|
5681
5766
|
var DeadLetterApi = class extends ServiceModule {
|
|
5682
5767
|
constructor() {
|
|
5683
5768
|
super(...arguments);
|
|
@@ -6497,6 +6582,7 @@ var ScaleMule = class {
|
|
|
6497
6582
|
this.graph = new GraphService(this._client);
|
|
6498
6583
|
this.functions = new FunctionsService(this._client);
|
|
6499
6584
|
this.photo = new PhotoService(this._client, this.storage);
|
|
6585
|
+
this.audio = new AudioService(this._client, this.storage);
|
|
6500
6586
|
this.flagContent = new FlagContentService(this._client);
|
|
6501
6587
|
this.creatorMaker = new CreatorMakerService(this._client);
|
|
6502
6588
|
this.compliance = new ComplianceService(this._client);
|
|
@@ -7445,7 +7531,8 @@ function ScaleMuleProvider({
|
|
|
7445
7531
|
onLogin,
|
|
7446
7532
|
onLogout,
|
|
7447
7533
|
onAuthError,
|
|
7448
|
-
bootstrapFlags
|
|
7534
|
+
bootstrapFlags,
|
|
7535
|
+
mediaPolicy
|
|
7449
7536
|
}) {
|
|
7450
7537
|
const [user, setUser] = React.useState(null);
|
|
7451
7538
|
const [initializing, setInitializing] = React.useState(true);
|
|
@@ -7584,6 +7671,8 @@ function ScaleMuleProvider({
|
|
|
7584
7671
|
storage: baseClient.storage,
|
|
7585
7672
|
photo: baseClient.photo,
|
|
7586
7673
|
video: baseClient.video,
|
|
7674
|
+
audio: baseClient.audio,
|
|
7675
|
+
mediaPolicy,
|
|
7587
7676
|
user,
|
|
7588
7677
|
setUser: handleSetUser,
|
|
7589
7678
|
initializing,
|
|
@@ -7598,7 +7687,7 @@ function ScaleMuleProvider({
|
|
|
7598
7687
|
accountSwitcherPrivacy,
|
|
7599
7688
|
bootstrapFlags
|
|
7600
7689
|
}),
|
|
7601
|
-
[client, money$1, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags]
|
|
7690
|
+
[client, money$1, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags, mediaPolicy]
|
|
7602
7691
|
);
|
|
7603
7692
|
return /* @__PURE__ */ jsxRuntime.jsx(ScaleMuleContext.Provider, { value, children });
|
|
7604
7693
|
}
|
|
@@ -8897,7 +8986,7 @@ function useContent(options = {}) {
|
|
|
8897
8986
|
);
|
|
8898
8987
|
}
|
|
8899
8988
|
function useMedia() {
|
|
8900
|
-
const { storage, photo, video } = useScaleMule();
|
|
8989
|
+
const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
8901
8990
|
const [uploading, setUploading] = React.useState(false);
|
|
8902
8991
|
const [error, setError] = React.useState(null);
|
|
8903
8992
|
const upload = React.useCallback(
|
|
@@ -8906,7 +8995,7 @@ function useMedia() {
|
|
|
8906
8995
|
setError(null);
|
|
8907
8996
|
const isPublic = options?.is_public ?? false;
|
|
8908
8997
|
const mimeType = file.type || "application/octet-stream";
|
|
8909
|
-
const policy = options?.policy ?? "safe_visible";
|
|
8998
|
+
const policy = options?.policy ?? providerDefaultPolicy ?? "safe_visible";
|
|
8910
8999
|
const gateOnPipeline = policy === "safe_public" || policy === "moderated" || policy === "compliance";
|
|
8911
9000
|
const sharedOpts = {
|
|
8912
9001
|
filename: options?.filename,
|
|
@@ -8951,6 +9040,21 @@ function useMedia() {
|
|
|
8951
9040
|
is_public: false
|
|
8952
9041
|
};
|
|
8953
9042
|
}
|
|
9043
|
+
if (mimeType.startsWith("audio/") && !isPublic) {
|
|
9044
|
+
const r2 = await audio.uploadViaStorage(file, sharedOpts);
|
|
9045
|
+
if (r2.error || !r2.data) {
|
|
9046
|
+
throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
|
|
9047
|
+
}
|
|
9048
|
+
return {
|
|
9049
|
+
file_id: r2.data.file_id,
|
|
9050
|
+
photo_id: null,
|
|
9051
|
+
original_view_url: r2.data.original_view_url,
|
|
9052
|
+
optimized_url_promise: Promise.resolve(null),
|
|
9053
|
+
hls_url_promise: Promise.resolve(null),
|
|
9054
|
+
mime_type: mimeType,
|
|
9055
|
+
is_public: false
|
|
9056
|
+
};
|
|
9057
|
+
}
|
|
8954
9058
|
if (mimeType.startsWith("image/") && isPublic) {
|
|
8955
9059
|
const r2 = await storage.upload(file, {
|
|
8956
9060
|
...sharedOpts,
|
|
@@ -8993,7 +9097,7 @@ function useMedia() {
|
|
|
8993
9097
|
setUploading(false);
|
|
8994
9098
|
}
|
|
8995
9099
|
},
|
|
8996
|
-
[storage, photo]
|
|
9100
|
+
[storage, photo, video, audio, providerDefaultPolicy]
|
|
8997
9101
|
);
|
|
8998
9102
|
const cancelUpload = React.useCallback(
|
|
8999
9103
|
async (fileId) => {
|
package/dist/index.mjs
CHANGED
|
@@ -2707,6 +2707,25 @@ var StorageService = class extends ServiceModule {
|
|
|
2707
2707
|
async getInfo(fileId, options) {
|
|
2708
2708
|
return this._get(`/files/${fileId}/info`, options);
|
|
2709
2709
|
}
|
|
2710
|
+
/**
|
|
2711
|
+
* Get the calling app's storage + media settings — content policy,
|
|
2712
|
+
* retention, max upload size, and the per-app `media_policy`.
|
|
2713
|
+
*
|
|
2714
|
+
* `media_policy` drives release-gating in the SDK upload helpers:
|
|
2715
|
+
* `fast_trusted` / `safe_visible` resolve immediately on upload; the
|
|
2716
|
+
* `safe_public` / `moderated` / `compliance` modes await pipeline
|
|
2717
|
+
* completion before resolving the upload promise.
|
|
2718
|
+
*/
|
|
2719
|
+
async getSettings(options) {
|
|
2720
|
+
return this._get("/settings", options);
|
|
2721
|
+
}
|
|
2722
|
+
/**
|
|
2723
|
+
* Update the calling app's storage + media settings. Admin-only on the
|
|
2724
|
+
* platform side (callers without the right role get 403).
|
|
2725
|
+
*/
|
|
2726
|
+
async updateSettings(settings, options) {
|
|
2727
|
+
return this.put("/settings", settings, options);
|
|
2728
|
+
}
|
|
2710
2729
|
/**
|
|
2711
2730
|
* Aggregate status for a file — single call returns scan + reserved
|
|
2712
2731
|
* optimize/transcode slots + the canonical view URL paths for image
|
|
@@ -5658,6 +5677,72 @@ var PhotoService = class extends ServiceModule {
|
|
|
5658
5677
|
return this.get(id);
|
|
5659
5678
|
}
|
|
5660
5679
|
};
|
|
5680
|
+
var AudioService = class extends ServiceModule {
|
|
5681
|
+
/**
|
|
5682
|
+
* @param storage Required for {@link uploadViaStorage}. Wired up by the
|
|
5683
|
+
* top-level {@link ScaleMule} constructor — most call sites should not
|
|
5684
|
+
* instantiate `AudioService` directly.
|
|
5685
|
+
*/
|
|
5686
|
+
constructor(client, storage) {
|
|
5687
|
+
super(client);
|
|
5688
|
+
this.storage = storage;
|
|
5689
|
+
this.basePath = "/v1/audios";
|
|
5690
|
+
}
|
|
5691
|
+
/**
|
|
5692
|
+
* Register a storage-uploaded audio asset with the audio service.
|
|
5693
|
+
* Idempotent — re-calling with the same `file_id` returns the existing
|
|
5694
|
+
* record.
|
|
5695
|
+
*/
|
|
5696
|
+
async register(args, options) {
|
|
5697
|
+
return this.post("/register", { file_id: args.fileId, sm_user_id: args.userId }, options);
|
|
5698
|
+
}
|
|
5699
|
+
/**
|
|
5700
|
+
* Upload a file to storage (browser → S3 direct, private, uncompressed)
|
|
5701
|
+
* and register it with the audio service.
|
|
5702
|
+
*
|
|
5703
|
+
* Mirrors `photo.uploadViaStorage()` / `video.uploadViaStorage()`. If
|
|
5704
|
+
* `register()` fails after a successful storage upload, the file is *not*
|
|
5705
|
+
* lost — the returned `file_id` is still valid as a generic private storage
|
|
5706
|
+
* file. The SDK logs a warning and returns `audio_id: null`.
|
|
5707
|
+
*/
|
|
5708
|
+
async uploadViaStorage(file, uploadOptions, requestOptions) {
|
|
5709
|
+
const uploadResult = await this.storage.uploadPrivate(file, {
|
|
5710
|
+
filename: uploadOptions?.filename,
|
|
5711
|
+
metadata: uploadOptions?.metadata,
|
|
5712
|
+
onProgress: uploadOptions?.onProgress,
|
|
5713
|
+
signal: uploadOptions?.signal
|
|
5714
|
+
});
|
|
5715
|
+
if (uploadResult.error || !uploadResult.data) {
|
|
5716
|
+
return { data: null, error: uploadResult.error };
|
|
5717
|
+
}
|
|
5718
|
+
const fileInfo = uploadResult.data;
|
|
5719
|
+
const fileId = fileInfo.id;
|
|
5720
|
+
const originalViewUrl = fileInfo.url ?? null;
|
|
5721
|
+
const registerResult = await this.register({ fileId, userId: uploadOptions?.userId }, requestOptions);
|
|
5722
|
+
if (registerResult.error || !registerResult.data) {
|
|
5723
|
+
console.warn(
|
|
5724
|
+
"[scalemule-sdk] audio.register() failed after storage upload; typed audio metadata unavailable.",
|
|
5725
|
+
registerResult.error
|
|
5726
|
+
);
|
|
5727
|
+
return {
|
|
5728
|
+
data: {
|
|
5729
|
+
file_id: fileId,
|
|
5730
|
+
audio_id: null,
|
|
5731
|
+
original_view_url: originalViewUrl
|
|
5732
|
+
},
|
|
5733
|
+
error: null
|
|
5734
|
+
};
|
|
5735
|
+
}
|
|
5736
|
+
return {
|
|
5737
|
+
data: {
|
|
5738
|
+
file_id: fileId,
|
|
5739
|
+
audio_id: registerResult.data.audio_id,
|
|
5740
|
+
original_view_url: originalViewUrl
|
|
5741
|
+
},
|
|
5742
|
+
error: null
|
|
5743
|
+
};
|
|
5744
|
+
}
|
|
5745
|
+
};
|
|
5661
5746
|
var DeadLetterApi = class extends ServiceModule {
|
|
5662
5747
|
constructor() {
|
|
5663
5748
|
super(...arguments);
|
|
@@ -6477,6 +6562,7 @@ var ScaleMule = class {
|
|
|
6477
6562
|
this.graph = new GraphService(this._client);
|
|
6478
6563
|
this.functions = new FunctionsService(this._client);
|
|
6479
6564
|
this.photo = new PhotoService(this._client, this.storage);
|
|
6565
|
+
this.audio = new AudioService(this._client, this.storage);
|
|
6480
6566
|
this.flagContent = new FlagContentService(this._client);
|
|
6481
6567
|
this.creatorMaker = new CreatorMakerService(this._client);
|
|
6482
6568
|
this.compliance = new ComplianceService(this._client);
|
|
@@ -7425,7 +7511,8 @@ function ScaleMuleProvider({
|
|
|
7425
7511
|
onLogin,
|
|
7426
7512
|
onLogout,
|
|
7427
7513
|
onAuthError,
|
|
7428
|
-
bootstrapFlags
|
|
7514
|
+
bootstrapFlags,
|
|
7515
|
+
mediaPolicy
|
|
7429
7516
|
}) {
|
|
7430
7517
|
const [user, setUser] = useState(null);
|
|
7431
7518
|
const [initializing, setInitializing] = useState(true);
|
|
@@ -7564,6 +7651,8 @@ function ScaleMuleProvider({
|
|
|
7564
7651
|
storage: baseClient.storage,
|
|
7565
7652
|
photo: baseClient.photo,
|
|
7566
7653
|
video: baseClient.video,
|
|
7654
|
+
audio: baseClient.audio,
|
|
7655
|
+
mediaPolicy,
|
|
7567
7656
|
user,
|
|
7568
7657
|
setUser: handleSetUser,
|
|
7569
7658
|
initializing,
|
|
@@ -7578,7 +7667,7 @@ function ScaleMuleProvider({
|
|
|
7578
7667
|
accountSwitcherPrivacy,
|
|
7579
7668
|
bootstrapFlags
|
|
7580
7669
|
}),
|
|
7581
|
-
[client, money, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags]
|
|
7670
|
+
[client, money, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags, mediaPolicy]
|
|
7582
7671
|
);
|
|
7583
7672
|
return /* @__PURE__ */ jsx(ScaleMuleContext.Provider, { value, children });
|
|
7584
7673
|
}
|
|
@@ -8877,7 +8966,7 @@ function useContent(options = {}) {
|
|
|
8877
8966
|
);
|
|
8878
8967
|
}
|
|
8879
8968
|
function useMedia() {
|
|
8880
|
-
const { storage, photo, video } = useScaleMule();
|
|
8969
|
+
const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
8881
8970
|
const [uploading, setUploading] = useState(false);
|
|
8882
8971
|
const [error, setError] = useState(null);
|
|
8883
8972
|
const upload = useCallback(
|
|
@@ -8886,7 +8975,7 @@ function useMedia() {
|
|
|
8886
8975
|
setError(null);
|
|
8887
8976
|
const isPublic = options?.is_public ?? false;
|
|
8888
8977
|
const mimeType = file.type || "application/octet-stream";
|
|
8889
|
-
const policy = options?.policy ?? "safe_visible";
|
|
8978
|
+
const policy = options?.policy ?? providerDefaultPolicy ?? "safe_visible";
|
|
8890
8979
|
const gateOnPipeline = policy === "safe_public" || policy === "moderated" || policy === "compliance";
|
|
8891
8980
|
const sharedOpts = {
|
|
8892
8981
|
filename: options?.filename,
|
|
@@ -8931,6 +9020,21 @@ function useMedia() {
|
|
|
8931
9020
|
is_public: false
|
|
8932
9021
|
};
|
|
8933
9022
|
}
|
|
9023
|
+
if (mimeType.startsWith("audio/") && !isPublic) {
|
|
9024
|
+
const r2 = await audio.uploadViaStorage(file, sharedOpts);
|
|
9025
|
+
if (r2.error || !r2.data) {
|
|
9026
|
+
throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
|
|
9027
|
+
}
|
|
9028
|
+
return {
|
|
9029
|
+
file_id: r2.data.file_id,
|
|
9030
|
+
photo_id: null,
|
|
9031
|
+
original_view_url: r2.data.original_view_url,
|
|
9032
|
+
optimized_url_promise: Promise.resolve(null),
|
|
9033
|
+
hls_url_promise: Promise.resolve(null),
|
|
9034
|
+
mime_type: mimeType,
|
|
9035
|
+
is_public: false
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
8934
9038
|
if (mimeType.startsWith("image/") && isPublic) {
|
|
8935
9039
|
const r2 = await storage.upload(file, {
|
|
8936
9040
|
...sharedOpts,
|
|
@@ -8973,7 +9077,7 @@ function useMedia() {
|
|
|
8973
9077
|
setUploading(false);
|
|
8974
9078
|
}
|
|
8975
9079
|
},
|
|
8976
|
-
[storage, photo]
|
|
9080
|
+
[storage, photo, video, audio, providerDefaultPolicy]
|
|
8977
9081
|
);
|
|
8978
9082
|
const cancelUpload = useCallback(
|
|
8979
9083
|
async (fileId) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/nextjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
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",
|
|
@@ -49,11 +49,12 @@
|
|
|
49
49
|
"test:watch": "vitest",
|
|
50
50
|
"type-check": "tsc --noEmit",
|
|
51
51
|
"lint": "tsc --noEmit",
|
|
52
|
-
"clean": "rm -rf dist"
|
|
52
|
+
"clean": "rm -rf dist",
|
|
53
|
+
"prepublishOnly": "node -e \"const v=require('./package.json').version; if(!/^0\\.(0|1)\\.\\d+$/.test(v)){console.error('ERR: SDK '+v+' violates patch-only policy (0.0.x or 0.1.x only). See CONTRIBUTING.md SDK versioning section.');process.exit(1)}\""
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
55
56
|
"@scalemule/money": "^0.0.1",
|
|
56
|
-
"@scalemule/sdk": "^0.0.
|
|
57
|
+
"@scalemule/sdk": "^0.0.43"
|
|
57
58
|
},
|
|
58
59
|
"peerDependencies": {
|
|
59
60
|
"next": ">=14.0.0",
|