@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 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$1 | null;
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$1 | null;
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.5",
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",