@scalemule/nextjs 0.1.5 → 0.1.7
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 +175 -122
- package/dist/index.d.ts +175 -122
- package/dist/index.js +14 -4
- package/dist/index.mjs +14 -4
- package/package.json +3 -2
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, 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,12 @@ interface ScaleMuleContextValue {
|
|
|
22
164
|
photo: PhotoService;
|
|
23
165
|
/** Base SDK video service — exposed for `useMedia()` and `video.uploadViaStorage()` */
|
|
24
166
|
video: VideoService;
|
|
167
|
+
/**
|
|
168
|
+
* Default media policy for `useMedia()` calls. Set via
|
|
169
|
+
* `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
|
|
170
|
+
* Undefined falls back to `useMedia()`'s built-in `safe_visible` default.
|
|
171
|
+
*/
|
|
172
|
+
mediaPolicy?: MediaPolicy;
|
|
25
173
|
/** Current authenticated user */
|
|
26
174
|
user: User | null;
|
|
27
175
|
/** Set the current user */
|
|
@@ -29,9 +177,9 @@ interface ScaleMuleContextValue {
|
|
|
29
177
|
/** Whether the SDK is initializing */
|
|
30
178
|
initializing: boolean;
|
|
31
179
|
/** Last error */
|
|
32
|
-
error: ApiError | null;
|
|
180
|
+
error: ApiError$1 | null;
|
|
33
181
|
/** Set error */
|
|
34
|
-
setError: (error: ApiError | null) => void;
|
|
182
|
+
setError: (error: ApiError$1 | null) => void;
|
|
35
183
|
/** Analytics proxy URL (when set, SDK sends events here instead of ScaleMule) */
|
|
36
184
|
analyticsProxyUrl?: string;
|
|
37
185
|
/** Auth proxy URL (when set, auth operations route through this proxy) */
|
|
@@ -56,11 +204,27 @@ interface ScaleMuleProviderProps extends ScaleMuleConfig {
|
|
|
56
204
|
/** Called when user logs out */
|
|
57
205
|
onLogout?: () => void;
|
|
58
206
|
/** Called on authentication error */
|
|
59
|
-
onAuthError?: (error: ApiError) => void;
|
|
207
|
+
onAuthError?: (error: ApiError$1) => void;
|
|
60
208
|
/** Server-evaluated flag values to bootstrap the client (eliminates loading flash) */
|
|
61
209
|
bootstrapFlags?: Record<string, unknown>;
|
|
210
|
+
/**
|
|
211
|
+
* Default media-pipeline policy applied to `useMedia()` calls when no
|
|
212
|
+
* per-call `policy` override is given. Five modes — see
|
|
213
|
+
* `docs/MEDIA-UPLOADS.md` and the {@link import('./hooks/useMedia').MediaPolicy} type.
|
|
214
|
+
*
|
|
215
|
+
* The platform stores the per-app policy in
|
|
216
|
+
* `application_storage_settings.media_policy` (Phase 4 / P3, live in
|
|
217
|
+
* prod). That endpoint is `MemberOnly` admin-auth, so end-user-context
|
|
218
|
+
* provider can't fetch it directly — apps that want policy-driven
|
|
219
|
+
* defaults should declare the value here, mirroring whatever the
|
|
220
|
+
* platform admin set.
|
|
221
|
+
*
|
|
222
|
+
* Default: undefined → `useMedia()` falls back to its built-in
|
|
223
|
+
* `safe_visible` default.
|
|
224
|
+
*/
|
|
225
|
+
mediaPolicy?: MediaPolicy;
|
|
62
226
|
}
|
|
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;
|
|
227
|
+
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
228
|
declare function useScaleMule(): ScaleMuleContextValue;
|
|
65
229
|
declare function useScaleMuleClient(): ScaleMuleClient;
|
|
66
230
|
declare function useMoneyClient(): MoneyClient;
|
|
@@ -158,117 +322,6 @@ interface UseContentOptions {
|
|
|
158
322
|
*/
|
|
159
323
|
declare function useContent(options?: UseContentOptions): UseContentReturn;
|
|
160
324
|
|
|
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
|
-
interface UseMediaUploadOptions {
|
|
189
|
-
/** Whether the resulting storage object should be public-readable.
|
|
190
|
-
* Default: `false` (private). Public is opt-in for surfaces that
|
|
191
|
-
* genuinely need it (avatars, public listings). Chat / DM uploads
|
|
192
|
-
* should always be private. */
|
|
193
|
-
is_public?: boolean;
|
|
194
|
-
/** Display filename (sanitized server-side). */
|
|
195
|
-
filename?: string;
|
|
196
|
-
/** Custom metadata attached to the file. */
|
|
197
|
-
metadata?: Record<string, unknown>;
|
|
198
|
-
/** Upload progress callback (0-100). */
|
|
199
|
-
onProgress?: (percent: number) => void;
|
|
200
|
-
/** AbortSignal for cancellation. */
|
|
201
|
-
signal?: AbortSignal;
|
|
202
|
-
/** Force a non-photo path even for image MIME types — useful for
|
|
203
|
-
* generic file uploads where you don't want the photo optimizer
|
|
204
|
-
* to register the file. Default: `false`. */
|
|
205
|
-
skipPhotoRegister?: boolean;
|
|
206
|
-
}
|
|
207
|
-
interface UseMediaReturn {
|
|
208
|
-
/** Upload a file. MIME-aware: images go through photo register +
|
|
209
|
-
* optimization; everything else goes through generic storage. */
|
|
210
|
-
upload: (file: File | Blob, options?: UseMediaUploadOptions) => Promise<MediaUploadResult>;
|
|
211
|
-
/** Cancel an upload by its `file_id`. Deletes the storage object so
|
|
212
|
-
* it doesn't orphan in S3 — useful when a chat composer accepts a
|
|
213
|
-
* file but the user removes it before sending. Idempotent. */
|
|
214
|
-
cancelUpload: (fileId: string) => Promise<void>;
|
|
215
|
-
/** Last error from `upload` or `cancelUpload`. */
|
|
216
|
-
error: ApiError$1 | null;
|
|
217
|
-
/** True while an upload is in progress. */
|
|
218
|
-
uploading: boolean;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Opinionated, MIME-aware media upload hook.
|
|
222
|
-
*
|
|
223
|
-
* `useMedia()` is the canonical upload primitive for chat / progressive
|
|
224
|
-
* media use. It branches by MIME type:
|
|
225
|
-
* - `image/*` → `client.photo.uploadViaStorage()` — upload to storage,
|
|
226
|
-
* then register with the photo service so the on-demand transform
|
|
227
|
-
* endpoint resolves to optimized variants. The returned
|
|
228
|
-
* `optimized_url_promise` resolves once the optimizer finishes.
|
|
229
|
-
* - everything else → `client.storage.uploadPrivate()` — a private,
|
|
230
|
-
* uncompressed, fail-closed upload to generic storage.
|
|
231
|
-
*
|
|
232
|
-
* **Default visibility is `is_public: false`.** Public is opt-in per call.
|
|
233
|
-
* `useMedia()` does not expose `is_public` via app-level config — visibility
|
|
234
|
-
* is always an explicit per-call surface choice.
|
|
235
|
-
*
|
|
236
|
-
* Compared to `useContent()`:
|
|
237
|
-
* - `useContent()` is a thin wrapper over generic storage and does not
|
|
238
|
-
* register photos / videos with their typed services. Use it for plain
|
|
239
|
-
* file uploads where you don't need optimization or transcoding.
|
|
240
|
-
* - `useMedia()` defaults to private + no compression, integrates with the
|
|
241
|
-
* typed media services automatically, and is the right primitive for
|
|
242
|
-
* anything chat- or media-shaped.
|
|
243
|
-
*
|
|
244
|
-
* @example
|
|
245
|
-
* ```tsx
|
|
246
|
-
* 'use client';
|
|
247
|
-
*
|
|
248
|
-
* import { useMedia, ScaleMuleMedia } from '@scalemule/nextjs';
|
|
249
|
-
*
|
|
250
|
-
* function ChatComposer({ onAttach }) {
|
|
251
|
-
* const { upload, uploading } = useMedia();
|
|
252
|
-
*
|
|
253
|
-
* async function handlePick(file: File) {
|
|
254
|
-
* const result = await upload(file);
|
|
255
|
-
* onAttach({
|
|
256
|
-
* file_id: result.file_id,
|
|
257
|
-
* mime_type: result.mime_type,
|
|
258
|
-
* optimized_url_promise: result.optimized_url_promise,
|
|
259
|
-
* });
|
|
260
|
-
* }
|
|
261
|
-
*
|
|
262
|
-
* return <input type="file" disabled={uploading}
|
|
263
|
-
* onChange={(e) => e.target.files?.[0] && handlePick(e.target.files[0])} />;
|
|
264
|
-
* }
|
|
265
|
-
* ```
|
|
266
|
-
*
|
|
267
|
-
* See `docs/MEDIA-UPLOADS.md` in the platform repo for the decision
|
|
268
|
-
* tree and the full anti-patterns list.
|
|
269
|
-
*/
|
|
270
|
-
declare function useMedia(): UseMediaReturn;
|
|
271
|
-
|
|
272
325
|
interface UseFileStatusOptions {
|
|
273
326
|
/** Storage file_id to read status for. */
|
|
274
327
|
fileId: string | null | undefined;
|
|
@@ -295,7 +348,7 @@ interface UseFileStatusReturn {
|
|
|
295
348
|
/** True while a fetch is in flight. */
|
|
296
349
|
loading: boolean;
|
|
297
350
|
/** Last error, or null. */
|
|
298
|
-
error: ApiError
|
|
351
|
+
error: ApiError | null;
|
|
299
352
|
/**
|
|
300
353
|
* Convenience: scan is clean. For images/videos, this means the file
|
|
301
354
|
* is *safe to render*; the optimized / HLS variants may still be
|
|
@@ -555,7 +608,7 @@ interface UseFeatureFlagsOptions {
|
|
|
555
608
|
interface UseFeatureFlagsReturn {
|
|
556
609
|
flags: Record<string, FeatureFlagEvaluation>;
|
|
557
610
|
loading: boolean;
|
|
558
|
-
error: ApiError | null;
|
|
611
|
+
error: ApiError$1 | null;
|
|
559
612
|
refresh: () => Promise<void>;
|
|
560
613
|
isEnabled: (flagKey: string, fallback?: boolean) => boolean;
|
|
561
614
|
getFlag: <T = unknown>(flagKey: string, fallback?: T) => T;
|
|
@@ -582,7 +635,7 @@ interface UsePushNotificationsReturn {
|
|
|
582
635
|
/** Whether an operation is in progress */
|
|
583
636
|
isLoading: boolean;
|
|
584
637
|
/** Last error */
|
|
585
|
-
error: ApiError | null;
|
|
638
|
+
error: ApiError$1 | null;
|
|
586
639
|
/** Request permission and subscribe to push notifications */
|
|
587
640
|
subscribe: () => Promise<void>;
|
|
588
641
|
/** Unsubscribe from push notifications */
|
|
@@ -683,7 +736,7 @@ interface UseFeedbackResult {
|
|
|
683
736
|
/** End-user's own feedback items for the current tenant. Empty when not signed in. */
|
|
684
737
|
items: FeedbackItem[];
|
|
685
738
|
loading: boolean;
|
|
686
|
-
error: ApiError | null;
|
|
739
|
+
error: ApiError$1 | null;
|
|
687
740
|
/** Submit a new feedback item. Returns the persisted item on success. */
|
|
688
741
|
submit: (input: FeedbackItemInput) => Promise<FeedbackItem>;
|
|
689
742
|
/** Re-fetch the list. */
|
|
@@ -895,4 +948,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
895
948
|
error: (message: string, data?: unknown) => void;
|
|
896
949
|
};
|
|
897
950
|
|
|
898
|
-
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 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 };
|
|
951
|
+
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, 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,12 @@ interface ScaleMuleContextValue {
|
|
|
22
164
|
photo: PhotoService;
|
|
23
165
|
/** Base SDK video service — exposed for `useMedia()` and `video.uploadViaStorage()` */
|
|
24
166
|
video: VideoService;
|
|
167
|
+
/**
|
|
168
|
+
* Default media policy for `useMedia()` calls. Set via
|
|
169
|
+
* `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
|
|
170
|
+
* Undefined falls back to `useMedia()`'s built-in `safe_visible` default.
|
|
171
|
+
*/
|
|
172
|
+
mediaPolicy?: MediaPolicy;
|
|
25
173
|
/** Current authenticated user */
|
|
26
174
|
user: User | null;
|
|
27
175
|
/** Set the current user */
|
|
@@ -29,9 +177,9 @@ interface ScaleMuleContextValue {
|
|
|
29
177
|
/** Whether the SDK is initializing */
|
|
30
178
|
initializing: boolean;
|
|
31
179
|
/** Last error */
|
|
32
|
-
error: ApiError | null;
|
|
180
|
+
error: ApiError$1 | null;
|
|
33
181
|
/** Set error */
|
|
34
|
-
setError: (error: ApiError | null) => void;
|
|
182
|
+
setError: (error: ApiError$1 | null) => void;
|
|
35
183
|
/** Analytics proxy URL (when set, SDK sends events here instead of ScaleMule) */
|
|
36
184
|
analyticsProxyUrl?: string;
|
|
37
185
|
/** Auth proxy URL (when set, auth operations route through this proxy) */
|
|
@@ -56,11 +204,27 @@ interface ScaleMuleProviderProps extends ScaleMuleConfig {
|
|
|
56
204
|
/** Called when user logs out */
|
|
57
205
|
onLogout?: () => void;
|
|
58
206
|
/** Called on authentication error */
|
|
59
|
-
onAuthError?: (error: ApiError) => void;
|
|
207
|
+
onAuthError?: (error: ApiError$1) => void;
|
|
60
208
|
/** Server-evaluated flag values to bootstrap the client (eliminates loading flash) */
|
|
61
209
|
bootstrapFlags?: Record<string, unknown>;
|
|
210
|
+
/**
|
|
211
|
+
* Default media-pipeline policy applied to `useMedia()` calls when no
|
|
212
|
+
* per-call `policy` override is given. Five modes — see
|
|
213
|
+
* `docs/MEDIA-UPLOADS.md` and the {@link import('./hooks/useMedia').MediaPolicy} type.
|
|
214
|
+
*
|
|
215
|
+
* The platform stores the per-app policy in
|
|
216
|
+
* `application_storage_settings.media_policy` (Phase 4 / P3, live in
|
|
217
|
+
* prod). That endpoint is `MemberOnly` admin-auth, so end-user-context
|
|
218
|
+
* provider can't fetch it directly — apps that want policy-driven
|
|
219
|
+
* defaults should declare the value here, mirroring whatever the
|
|
220
|
+
* platform admin set.
|
|
221
|
+
*
|
|
222
|
+
* Default: undefined → `useMedia()` falls back to its built-in
|
|
223
|
+
* `safe_visible` default.
|
|
224
|
+
*/
|
|
225
|
+
mediaPolicy?: MediaPolicy;
|
|
62
226
|
}
|
|
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;
|
|
227
|
+
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
228
|
declare function useScaleMule(): ScaleMuleContextValue;
|
|
65
229
|
declare function useScaleMuleClient(): ScaleMuleClient;
|
|
66
230
|
declare function useMoneyClient(): MoneyClient;
|
|
@@ -158,117 +322,6 @@ interface UseContentOptions {
|
|
|
158
322
|
*/
|
|
159
323
|
declare function useContent(options?: UseContentOptions): UseContentReturn;
|
|
160
324
|
|
|
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
|
-
interface UseMediaUploadOptions {
|
|
189
|
-
/** Whether the resulting storage object should be public-readable.
|
|
190
|
-
* Default: `false` (private). Public is opt-in for surfaces that
|
|
191
|
-
* genuinely need it (avatars, public listings). Chat / DM uploads
|
|
192
|
-
* should always be private. */
|
|
193
|
-
is_public?: boolean;
|
|
194
|
-
/** Display filename (sanitized server-side). */
|
|
195
|
-
filename?: string;
|
|
196
|
-
/** Custom metadata attached to the file. */
|
|
197
|
-
metadata?: Record<string, unknown>;
|
|
198
|
-
/** Upload progress callback (0-100). */
|
|
199
|
-
onProgress?: (percent: number) => void;
|
|
200
|
-
/** AbortSignal for cancellation. */
|
|
201
|
-
signal?: AbortSignal;
|
|
202
|
-
/** Force a non-photo path even for image MIME types — useful for
|
|
203
|
-
* generic file uploads where you don't want the photo optimizer
|
|
204
|
-
* to register the file. Default: `false`. */
|
|
205
|
-
skipPhotoRegister?: boolean;
|
|
206
|
-
}
|
|
207
|
-
interface UseMediaReturn {
|
|
208
|
-
/** Upload a file. MIME-aware: images go through photo register +
|
|
209
|
-
* optimization; everything else goes through generic storage. */
|
|
210
|
-
upload: (file: File | Blob, options?: UseMediaUploadOptions) => Promise<MediaUploadResult>;
|
|
211
|
-
/** Cancel an upload by its `file_id`. Deletes the storage object so
|
|
212
|
-
* it doesn't orphan in S3 — useful when a chat composer accepts a
|
|
213
|
-
* file but the user removes it before sending. Idempotent. */
|
|
214
|
-
cancelUpload: (fileId: string) => Promise<void>;
|
|
215
|
-
/** Last error from `upload` or `cancelUpload`. */
|
|
216
|
-
error: ApiError$1 | null;
|
|
217
|
-
/** True while an upload is in progress. */
|
|
218
|
-
uploading: boolean;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Opinionated, MIME-aware media upload hook.
|
|
222
|
-
*
|
|
223
|
-
* `useMedia()` is the canonical upload primitive for chat / progressive
|
|
224
|
-
* media use. It branches by MIME type:
|
|
225
|
-
* - `image/*` → `client.photo.uploadViaStorage()` — upload to storage,
|
|
226
|
-
* then register with the photo service so the on-demand transform
|
|
227
|
-
* endpoint resolves to optimized variants. The returned
|
|
228
|
-
* `optimized_url_promise` resolves once the optimizer finishes.
|
|
229
|
-
* - everything else → `client.storage.uploadPrivate()` — a private,
|
|
230
|
-
* uncompressed, fail-closed upload to generic storage.
|
|
231
|
-
*
|
|
232
|
-
* **Default visibility is `is_public: false`.** Public is opt-in per call.
|
|
233
|
-
* `useMedia()` does not expose `is_public` via app-level config — visibility
|
|
234
|
-
* is always an explicit per-call surface choice.
|
|
235
|
-
*
|
|
236
|
-
* Compared to `useContent()`:
|
|
237
|
-
* - `useContent()` is a thin wrapper over generic storage and does not
|
|
238
|
-
* register photos / videos with their typed services. Use it for plain
|
|
239
|
-
* file uploads where you don't need optimization or transcoding.
|
|
240
|
-
* - `useMedia()` defaults to private + no compression, integrates with the
|
|
241
|
-
* typed media services automatically, and is the right primitive for
|
|
242
|
-
* anything chat- or media-shaped.
|
|
243
|
-
*
|
|
244
|
-
* @example
|
|
245
|
-
* ```tsx
|
|
246
|
-
* 'use client';
|
|
247
|
-
*
|
|
248
|
-
* import { useMedia, ScaleMuleMedia } from '@scalemule/nextjs';
|
|
249
|
-
*
|
|
250
|
-
* function ChatComposer({ onAttach }) {
|
|
251
|
-
* const { upload, uploading } = useMedia();
|
|
252
|
-
*
|
|
253
|
-
* async function handlePick(file: File) {
|
|
254
|
-
* const result = await upload(file);
|
|
255
|
-
* onAttach({
|
|
256
|
-
* file_id: result.file_id,
|
|
257
|
-
* mime_type: result.mime_type,
|
|
258
|
-
* optimized_url_promise: result.optimized_url_promise,
|
|
259
|
-
* });
|
|
260
|
-
* }
|
|
261
|
-
*
|
|
262
|
-
* return <input type="file" disabled={uploading}
|
|
263
|
-
* onChange={(e) => e.target.files?.[0] && handlePick(e.target.files[0])} />;
|
|
264
|
-
* }
|
|
265
|
-
* ```
|
|
266
|
-
*
|
|
267
|
-
* See `docs/MEDIA-UPLOADS.md` in the platform repo for the decision
|
|
268
|
-
* tree and the full anti-patterns list.
|
|
269
|
-
*/
|
|
270
|
-
declare function useMedia(): UseMediaReturn;
|
|
271
|
-
|
|
272
325
|
interface UseFileStatusOptions {
|
|
273
326
|
/** Storage file_id to read status for. */
|
|
274
327
|
fileId: string | null | undefined;
|
|
@@ -295,7 +348,7 @@ interface UseFileStatusReturn {
|
|
|
295
348
|
/** True while a fetch is in flight. */
|
|
296
349
|
loading: boolean;
|
|
297
350
|
/** Last error, or null. */
|
|
298
|
-
error: ApiError
|
|
351
|
+
error: ApiError | null;
|
|
299
352
|
/**
|
|
300
353
|
* Convenience: scan is clean. For images/videos, this means the file
|
|
301
354
|
* is *safe to render*; the optimized / HLS variants may still be
|
|
@@ -555,7 +608,7 @@ interface UseFeatureFlagsOptions {
|
|
|
555
608
|
interface UseFeatureFlagsReturn {
|
|
556
609
|
flags: Record<string, FeatureFlagEvaluation>;
|
|
557
610
|
loading: boolean;
|
|
558
|
-
error: ApiError | null;
|
|
611
|
+
error: ApiError$1 | null;
|
|
559
612
|
refresh: () => Promise<void>;
|
|
560
613
|
isEnabled: (flagKey: string, fallback?: boolean) => boolean;
|
|
561
614
|
getFlag: <T = unknown>(flagKey: string, fallback?: T) => T;
|
|
@@ -582,7 +635,7 @@ interface UsePushNotificationsReturn {
|
|
|
582
635
|
/** Whether an operation is in progress */
|
|
583
636
|
isLoading: boolean;
|
|
584
637
|
/** Last error */
|
|
585
|
-
error: ApiError | null;
|
|
638
|
+
error: ApiError$1 | null;
|
|
586
639
|
/** Request permission and subscribe to push notifications */
|
|
587
640
|
subscribe: () => Promise<void>;
|
|
588
641
|
/** Unsubscribe from push notifications */
|
|
@@ -683,7 +736,7 @@ interface UseFeedbackResult {
|
|
|
683
736
|
/** End-user's own feedback items for the current tenant. Empty when not signed in. */
|
|
684
737
|
items: FeedbackItem[];
|
|
685
738
|
loading: boolean;
|
|
686
|
-
error: ApiError | null;
|
|
739
|
+
error: ApiError$1 | null;
|
|
687
740
|
/** Submit a new feedback item. Returns the persisted item on success. */
|
|
688
741
|
submit: (input: FeedbackItemInput) => Promise<FeedbackItem>;
|
|
689
742
|
/** Re-fetch the list. */
|
|
@@ -895,4 +948,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
895
948
|
error: (message: string, data?: unknown) => void;
|
|
896
949
|
};
|
|
897
950
|
|
|
898
|
-
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 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 };
|
|
951
|
+
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
|
@@ -7445,7 +7445,8 @@ function ScaleMuleProvider({
|
|
|
7445
7445
|
onLogin,
|
|
7446
7446
|
onLogout,
|
|
7447
7447
|
onAuthError,
|
|
7448
|
-
bootstrapFlags
|
|
7448
|
+
bootstrapFlags,
|
|
7449
|
+
mediaPolicy
|
|
7449
7450
|
}) {
|
|
7450
7451
|
const [user, setUser] = React.useState(null);
|
|
7451
7452
|
const [initializing, setInitializing] = React.useState(true);
|
|
@@ -7584,6 +7585,7 @@ function ScaleMuleProvider({
|
|
|
7584
7585
|
storage: baseClient.storage,
|
|
7585
7586
|
photo: baseClient.photo,
|
|
7586
7587
|
video: baseClient.video,
|
|
7588
|
+
mediaPolicy,
|
|
7587
7589
|
user,
|
|
7588
7590
|
setUser: handleSetUser,
|
|
7589
7591
|
initializing,
|
|
@@ -7598,7 +7600,7 @@ function ScaleMuleProvider({
|
|
|
7598
7600
|
accountSwitcherPrivacy,
|
|
7599
7601
|
bootstrapFlags
|
|
7600
7602
|
}),
|
|
7601
|
-
[client, money$1, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags]
|
|
7603
|
+
[client, money$1, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags, mediaPolicy]
|
|
7602
7604
|
);
|
|
7603
7605
|
return /* @__PURE__ */ jsxRuntime.jsx(ScaleMuleContext.Provider, { value, children });
|
|
7604
7606
|
}
|
|
@@ -8897,7 +8899,7 @@ function useContent(options = {}) {
|
|
|
8897
8899
|
);
|
|
8898
8900
|
}
|
|
8899
8901
|
function useMedia() {
|
|
8900
|
-
const { storage, photo, video } = useScaleMule();
|
|
8902
|
+
const { storage, photo, video, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
8901
8903
|
const [uploading, setUploading] = React.useState(false);
|
|
8902
8904
|
const [error, setError] = React.useState(null);
|
|
8903
8905
|
const upload = React.useCallback(
|
|
@@ -8906,6 +8908,8 @@ function useMedia() {
|
|
|
8906
8908
|
setError(null);
|
|
8907
8909
|
const isPublic = options?.is_public ?? false;
|
|
8908
8910
|
const mimeType = file.type || "application/octet-stream";
|
|
8911
|
+
const policy = options?.policy ?? providerDefaultPolicy ?? "safe_visible";
|
|
8912
|
+
const gateOnPipeline = policy === "safe_public" || policy === "moderated" || policy === "compliance";
|
|
8909
8913
|
const sharedOpts = {
|
|
8910
8914
|
filename: options?.filename,
|
|
8911
8915
|
metadata: options?.metadata,
|
|
@@ -8918,6 +8922,9 @@ function useMedia() {
|
|
|
8918
8922
|
if (r2.error || !r2.data) {
|
|
8919
8923
|
throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
|
|
8920
8924
|
}
|
|
8925
|
+
if (gateOnPipeline) {
|
|
8926
|
+
await r2.data.optimized_url_promise;
|
|
8927
|
+
}
|
|
8921
8928
|
return {
|
|
8922
8929
|
file_id: r2.data.file_id,
|
|
8923
8930
|
photo_id: r2.data.photo_id,
|
|
@@ -8933,6 +8940,9 @@ function useMedia() {
|
|
|
8933
8940
|
if (r2.error || !r2.data) {
|
|
8934
8941
|
throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
|
|
8935
8942
|
}
|
|
8943
|
+
if (gateOnPipeline) {
|
|
8944
|
+
await r2.data.hls_url_promise;
|
|
8945
|
+
}
|
|
8936
8946
|
return {
|
|
8937
8947
|
file_id: r2.data.file_id,
|
|
8938
8948
|
photo_id: null,
|
|
@@ -8985,7 +8995,7 @@ function useMedia() {
|
|
|
8985
8995
|
setUploading(false);
|
|
8986
8996
|
}
|
|
8987
8997
|
},
|
|
8988
|
-
[storage, photo]
|
|
8998
|
+
[storage, photo, video, providerDefaultPolicy]
|
|
8989
8999
|
);
|
|
8990
9000
|
const cancelUpload = React.useCallback(
|
|
8991
9001
|
async (fileId) => {
|
package/dist/index.mjs
CHANGED
|
@@ -7425,7 +7425,8 @@ function ScaleMuleProvider({
|
|
|
7425
7425
|
onLogin,
|
|
7426
7426
|
onLogout,
|
|
7427
7427
|
onAuthError,
|
|
7428
|
-
bootstrapFlags
|
|
7428
|
+
bootstrapFlags,
|
|
7429
|
+
mediaPolicy
|
|
7429
7430
|
}) {
|
|
7430
7431
|
const [user, setUser] = useState(null);
|
|
7431
7432
|
const [initializing, setInitializing] = useState(true);
|
|
@@ -7564,6 +7565,7 @@ function ScaleMuleProvider({
|
|
|
7564
7565
|
storage: baseClient.storage,
|
|
7565
7566
|
photo: baseClient.photo,
|
|
7566
7567
|
video: baseClient.video,
|
|
7568
|
+
mediaPolicy,
|
|
7567
7569
|
user,
|
|
7568
7570
|
setUser: handleSetUser,
|
|
7569
7571
|
initializing,
|
|
@@ -7578,7 +7580,7 @@ function ScaleMuleProvider({
|
|
|
7578
7580
|
accountSwitcherPrivacy,
|
|
7579
7581
|
bootstrapFlags
|
|
7580
7582
|
}),
|
|
7581
|
-
[client, money, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags]
|
|
7583
|
+
[client, money, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags, mediaPolicy]
|
|
7582
7584
|
);
|
|
7583
7585
|
return /* @__PURE__ */ jsx(ScaleMuleContext.Provider, { value, children });
|
|
7584
7586
|
}
|
|
@@ -8877,7 +8879,7 @@ function useContent(options = {}) {
|
|
|
8877
8879
|
);
|
|
8878
8880
|
}
|
|
8879
8881
|
function useMedia() {
|
|
8880
|
-
const { storage, photo, video } = useScaleMule();
|
|
8882
|
+
const { storage, photo, video, mediaPolicy: providerDefaultPolicy } = useScaleMule();
|
|
8881
8883
|
const [uploading, setUploading] = useState(false);
|
|
8882
8884
|
const [error, setError] = useState(null);
|
|
8883
8885
|
const upload = useCallback(
|
|
@@ -8886,6 +8888,8 @@ function useMedia() {
|
|
|
8886
8888
|
setError(null);
|
|
8887
8889
|
const isPublic = options?.is_public ?? false;
|
|
8888
8890
|
const mimeType = file.type || "application/octet-stream";
|
|
8891
|
+
const policy = options?.policy ?? providerDefaultPolicy ?? "safe_visible";
|
|
8892
|
+
const gateOnPipeline = policy === "safe_public" || policy === "moderated" || policy === "compliance";
|
|
8889
8893
|
const sharedOpts = {
|
|
8890
8894
|
filename: options?.filename,
|
|
8891
8895
|
metadata: options?.metadata,
|
|
@@ -8898,6 +8902,9 @@ function useMedia() {
|
|
|
8898
8902
|
if (r2.error || !r2.data) {
|
|
8899
8903
|
throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
|
|
8900
8904
|
}
|
|
8905
|
+
if (gateOnPipeline) {
|
|
8906
|
+
await r2.data.optimized_url_promise;
|
|
8907
|
+
}
|
|
8901
8908
|
return {
|
|
8902
8909
|
file_id: r2.data.file_id,
|
|
8903
8910
|
photo_id: r2.data.photo_id,
|
|
@@ -8913,6 +8920,9 @@ function useMedia() {
|
|
|
8913
8920
|
if (r2.error || !r2.data) {
|
|
8914
8921
|
throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
|
|
8915
8922
|
}
|
|
8923
|
+
if (gateOnPipeline) {
|
|
8924
|
+
await r2.data.hls_url_promise;
|
|
8925
|
+
}
|
|
8916
8926
|
return {
|
|
8917
8927
|
file_id: r2.data.file_id,
|
|
8918
8928
|
photo_id: null,
|
|
@@ -8965,7 +8975,7 @@ function useMedia() {
|
|
|
8965
8975
|
setUploading(false);
|
|
8966
8976
|
}
|
|
8967
8977
|
},
|
|
8968
|
-
[storage, photo]
|
|
8978
|
+
[storage, photo, video, providerDefaultPolicy]
|
|
8969
8979
|
);
|
|
8970
8980
|
const cancelUpload = useCallback(
|
|
8971
8981
|
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.7",
|
|
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,7 +49,8 @@
|
|
|
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",
|