@scalemule/nextjs 0.1.3 → 0.1.4
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 +66 -2
- package/dist/index.d.ts +66 -2
- package/dist/index.js +70 -0
- package/dist/index.mjs +70 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { MoneyClient } from '@scalemule/money';
|
|
4
4
|
export { MoneyClient, MoneyClientConfig, createMoneyClient } from '@scalemule/money';
|
|
5
|
-
import { RealtimeService, StorageService, PhotoService, VideoService, ApiError as ApiError$1 } from '@scalemule/sdk';
|
|
5
|
+
import { RealtimeService, StorageService, PhotoService, VideoService, ApiError as ApiError$1, FileStatus } from '@scalemule/sdk';
|
|
6
6
|
import { ScaleMuleClient } from './client.mjs';
|
|
7
7
|
export { ClientConfig, RequestOptions, createClient } from './client.mjs';
|
|
8
8
|
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';
|
|
@@ -268,6 +268,70 @@ interface UseMediaReturn {
|
|
|
268
268
|
*/
|
|
269
269
|
declare function useMedia(): UseMediaReturn;
|
|
270
270
|
|
|
271
|
+
interface UseFileStatusOptions {
|
|
272
|
+
/** Storage file_id to read status for. */
|
|
273
|
+
fileId: string | null | undefined;
|
|
274
|
+
/**
|
|
275
|
+
* Optional poll interval in milliseconds. If set, the hook re-fetches
|
|
276
|
+
* status every `pollIntervalMs`. Useful while waiting for transcode /
|
|
277
|
+
* optimization to complete. Pass `null` (default) for a one-shot read.
|
|
278
|
+
*
|
|
279
|
+
* Polling stops automatically once `scan.status === 'clean'` AND the
|
|
280
|
+
* caller's expected pipeline is done (`urls.optimized` returns 200 for
|
|
281
|
+
* images, `urls.hls` returns 200 for videos). Today the hook can only
|
|
282
|
+
* detect scan clean — broader pipeline-done detection lands when Phase 3
|
|
283
|
+
* enriches the optimize/transcode response fields.
|
|
284
|
+
*/
|
|
285
|
+
pollIntervalMs?: number | null;
|
|
286
|
+
/**
|
|
287
|
+
* Disable the hook (don't fetch). Useful when `fileId` is conditional.
|
|
288
|
+
*/
|
|
289
|
+
disabled?: boolean;
|
|
290
|
+
}
|
|
291
|
+
interface UseFileStatusReturn {
|
|
292
|
+
/** The latest status response, or null on first render / disabled. */
|
|
293
|
+
status: FileStatus | null;
|
|
294
|
+
/** True while a fetch is in flight. */
|
|
295
|
+
loading: boolean;
|
|
296
|
+
/** Last error, or null. */
|
|
297
|
+
error: ApiError$1 | null;
|
|
298
|
+
/**
|
|
299
|
+
* Convenience: scan is clean. For images/videos, this means the file
|
|
300
|
+
* is *safe to render*; the optimized / HLS variants may still be
|
|
301
|
+
* processing. The caller should attempt the constructed URLs and
|
|
302
|
+
* fall back to `urls.original` if the pipeline-specific URL 404s.
|
|
303
|
+
*/
|
|
304
|
+
isReady: boolean;
|
|
305
|
+
/** Force-refresh the status. Promise resolves when the new state is committed. */
|
|
306
|
+
refresh: () => Promise<void>;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Subscribes to {@link FileStatus} for a single file. Today this is a
|
|
310
|
+
* pull-only hook — single fetch by default, optional polling.
|
|
311
|
+
*
|
|
312
|
+
* Phase 3 of the realtime-chat media pipeline ADR will add a push variant
|
|
313
|
+
* for chat surfaces — `useFileStatus({ messageId })` will subscribe to
|
|
314
|
+
* `file.status` events on the existing per-conversation realtime channel
|
|
315
|
+
* via the `scalemule-chat` translation bridge (P5'). Until that lands,
|
|
316
|
+
* customers using this hook from chat surfaces should pass `pollIntervalMs`
|
|
317
|
+
* in the 1–3 second range while a media pipeline is expected to be running,
|
|
318
|
+
* then drop the polling once `isReady` is true.
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* ```tsx
|
|
322
|
+
* function ChatImage({ fileId }: { fileId: string }) {
|
|
323
|
+
* const { status, isReady } = useFileStatus({
|
|
324
|
+
* fileId,
|
|
325
|
+
* pollIntervalMs: 2000,
|
|
326
|
+
* });
|
|
327
|
+
* if (!isReady) return <div>Scanning…</div>;
|
|
328
|
+
* const src = status?.urls.optimized ?? status?.urls.original;
|
|
329
|
+
* return <img src={src} />;
|
|
330
|
+
* }
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
declare function useFileStatus(options: UseFileStatusOptions): UseFileStatusReturn;
|
|
334
|
+
|
|
271
335
|
declare const useMoney: typeof useMoneyClient;
|
|
272
336
|
|
|
273
337
|
/**
|
|
@@ -751,4 +815,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
751
815
|
error: (message: string, data?: unknown) => void;
|
|
752
816
|
};
|
|
753
817
|
|
|
754
|
-
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, ScaleMuleProvider, type ScaleMuleProviderProps, UseAnalyticsOptions, UseAnalyticsReturn, UseAuthReturn, UseBillingReturn, UseContentReturn, type UseFeatureFlagsOptions, type UseFeatureFlagsReturn, type UseFeedbackOptions, type UseFeedbackResult, 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, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
818
|
+
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, 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
|
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { MoneyClient } from '@scalemule/money';
|
|
4
4
|
export { MoneyClient, MoneyClientConfig, createMoneyClient } from '@scalemule/money';
|
|
5
|
-
import { RealtimeService, StorageService, PhotoService, VideoService, ApiError as ApiError$1 } from '@scalemule/sdk';
|
|
5
|
+
import { RealtimeService, StorageService, PhotoService, VideoService, ApiError as ApiError$1, FileStatus } from '@scalemule/sdk';
|
|
6
6
|
import { ScaleMuleClient } from './client.js';
|
|
7
7
|
export { ClientConfig, RequestOptions, createClient } from './client.js';
|
|
8
8
|
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';
|
|
@@ -268,6 +268,70 @@ interface UseMediaReturn {
|
|
|
268
268
|
*/
|
|
269
269
|
declare function useMedia(): UseMediaReturn;
|
|
270
270
|
|
|
271
|
+
interface UseFileStatusOptions {
|
|
272
|
+
/** Storage file_id to read status for. */
|
|
273
|
+
fileId: string | null | undefined;
|
|
274
|
+
/**
|
|
275
|
+
* Optional poll interval in milliseconds. If set, the hook re-fetches
|
|
276
|
+
* status every `pollIntervalMs`. Useful while waiting for transcode /
|
|
277
|
+
* optimization to complete. Pass `null` (default) for a one-shot read.
|
|
278
|
+
*
|
|
279
|
+
* Polling stops automatically once `scan.status === 'clean'` AND the
|
|
280
|
+
* caller's expected pipeline is done (`urls.optimized` returns 200 for
|
|
281
|
+
* images, `urls.hls` returns 200 for videos). Today the hook can only
|
|
282
|
+
* detect scan clean — broader pipeline-done detection lands when Phase 3
|
|
283
|
+
* enriches the optimize/transcode response fields.
|
|
284
|
+
*/
|
|
285
|
+
pollIntervalMs?: number | null;
|
|
286
|
+
/**
|
|
287
|
+
* Disable the hook (don't fetch). Useful when `fileId` is conditional.
|
|
288
|
+
*/
|
|
289
|
+
disabled?: boolean;
|
|
290
|
+
}
|
|
291
|
+
interface UseFileStatusReturn {
|
|
292
|
+
/** The latest status response, or null on first render / disabled. */
|
|
293
|
+
status: FileStatus | null;
|
|
294
|
+
/** True while a fetch is in flight. */
|
|
295
|
+
loading: boolean;
|
|
296
|
+
/** Last error, or null. */
|
|
297
|
+
error: ApiError$1 | null;
|
|
298
|
+
/**
|
|
299
|
+
* Convenience: scan is clean. For images/videos, this means the file
|
|
300
|
+
* is *safe to render*; the optimized / HLS variants may still be
|
|
301
|
+
* processing. The caller should attempt the constructed URLs and
|
|
302
|
+
* fall back to `urls.original` if the pipeline-specific URL 404s.
|
|
303
|
+
*/
|
|
304
|
+
isReady: boolean;
|
|
305
|
+
/** Force-refresh the status. Promise resolves when the new state is committed. */
|
|
306
|
+
refresh: () => Promise<void>;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Subscribes to {@link FileStatus} for a single file. Today this is a
|
|
310
|
+
* pull-only hook — single fetch by default, optional polling.
|
|
311
|
+
*
|
|
312
|
+
* Phase 3 of the realtime-chat media pipeline ADR will add a push variant
|
|
313
|
+
* for chat surfaces — `useFileStatus({ messageId })` will subscribe to
|
|
314
|
+
* `file.status` events on the existing per-conversation realtime channel
|
|
315
|
+
* via the `scalemule-chat` translation bridge (P5'). Until that lands,
|
|
316
|
+
* customers using this hook from chat surfaces should pass `pollIntervalMs`
|
|
317
|
+
* in the 1–3 second range while a media pipeline is expected to be running,
|
|
318
|
+
* then drop the polling once `isReady` is true.
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* ```tsx
|
|
322
|
+
* function ChatImage({ fileId }: { fileId: string }) {
|
|
323
|
+
* const { status, isReady } = useFileStatus({
|
|
324
|
+
* fileId,
|
|
325
|
+
* pollIntervalMs: 2000,
|
|
326
|
+
* });
|
|
327
|
+
* if (!isReady) return <div>Scanning…</div>;
|
|
328
|
+
* const src = status?.urls.optimized ?? status?.urls.original;
|
|
329
|
+
* return <img src={src} />;
|
|
330
|
+
* }
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
declare function useFileStatus(options: UseFileStatusOptions): UseFileStatusReturn;
|
|
334
|
+
|
|
271
335
|
declare const useMoney: typeof useMoneyClient;
|
|
272
336
|
|
|
273
337
|
/**
|
|
@@ -751,4 +815,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
751
815
|
error: (message: string, data?: unknown) => void;
|
|
752
816
|
};
|
|
753
817
|
|
|
754
|
-
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, ScaleMuleProvider, type ScaleMuleProviderProps, UseAnalyticsOptions, UseAnalyticsReturn, UseAuthReturn, UseBillingReturn, UseContentReturn, type UseFeatureFlagsOptions, type UseFeatureFlagsReturn, type UseFeedbackOptions, type UseFeedbackResult, 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, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
818
|
+
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, 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
|
@@ -2707,6 +2707,31 @@ var StorageService = class extends ServiceModule {
|
|
|
2707
2707
|
async getInfo(fileId, options) {
|
|
2708
2708
|
return this._get(`/files/${fileId}/info`, options);
|
|
2709
2709
|
}
|
|
2710
|
+
/**
|
|
2711
|
+
* Aggregate status for a file — single call returns scan + reserved
|
|
2712
|
+
* optimize/transcode slots + the canonical view URL paths for image
|
|
2713
|
+
* (transform endpoint) and video (HLS playlist) MIME types.
|
|
2714
|
+
*
|
|
2715
|
+
* Foundational primitive for the chat / progressive media read side.
|
|
2716
|
+
* `useFileStatus()` (in `@scalemule/nextjs`) consumes this for both
|
|
2717
|
+
* first-paint and refresh-on-demand scenarios.
|
|
2718
|
+
*
|
|
2719
|
+
* `optimize` and `transcode` are reserved for Phase 3 enrichment. Until
|
|
2720
|
+
* the photo/video services expose internal status endpoints, callers
|
|
2721
|
+
* should attempt the constructed URLs directly to discover readiness
|
|
2722
|
+
* (404 means the pipeline is still running).
|
|
2723
|
+
*
|
|
2724
|
+
* @example
|
|
2725
|
+
* ```ts
|
|
2726
|
+
* const r = await client.storage.getFileStatus(fileId);
|
|
2727
|
+
* if (r.data?.scan.status === 'clean' && r.data.urls.optimized) {
|
|
2728
|
+
* // image: try transform URL for an optimized variant
|
|
2729
|
+
* }
|
|
2730
|
+
* ```
|
|
2731
|
+
*/
|
|
2732
|
+
async getFileStatus(fileId, options) {
|
|
2733
|
+
return this._get(`/files/${fileId}/status`, options);
|
|
2734
|
+
}
|
|
2710
2735
|
/**
|
|
2711
2736
|
* Get a signed view URL for inline display (img src, thumbnails).
|
|
2712
2737
|
* Returns CloudFront signed URL (fast, ~1us) or S3 presigned fallback.
|
|
@@ -8961,6 +8986,50 @@ function useMedia() {
|
|
|
8961
8986
|
);
|
|
8962
8987
|
return { upload, cancelUpload, error, uploading };
|
|
8963
8988
|
}
|
|
8989
|
+
function useFileStatus(options) {
|
|
8990
|
+
const { storage } = useScaleMule();
|
|
8991
|
+
const { fileId, pollIntervalMs = null, disabled = false } = options;
|
|
8992
|
+
const [status, setStatus] = react.useState(null);
|
|
8993
|
+
const [loading, setLoading] = react.useState(false);
|
|
8994
|
+
const [error, setError] = react.useState(null);
|
|
8995
|
+
const requestSeqRef = react.useRef(0);
|
|
8996
|
+
const fetchStatus = react.useCallback(async () => {
|
|
8997
|
+
if (!fileId || disabled) return;
|
|
8998
|
+
const seq = ++requestSeqRef.current;
|
|
8999
|
+
setLoading(true);
|
|
9000
|
+
setError(null);
|
|
9001
|
+
try {
|
|
9002
|
+
const r = await storage.getFileStatus(fileId);
|
|
9003
|
+
if (seq !== requestSeqRef.current) return;
|
|
9004
|
+
if (r.error || !r.data) {
|
|
9005
|
+
setError(r.error);
|
|
9006
|
+
return;
|
|
9007
|
+
}
|
|
9008
|
+
setStatus(r.data);
|
|
9009
|
+
} catch (err) {
|
|
9010
|
+
if (seq !== requestSeqRef.current) return;
|
|
9011
|
+
setError(err);
|
|
9012
|
+
} finally {
|
|
9013
|
+
if (seq === requestSeqRef.current) {
|
|
9014
|
+
setLoading(false);
|
|
9015
|
+
}
|
|
9016
|
+
}
|
|
9017
|
+
}, [storage, fileId, disabled]);
|
|
9018
|
+
react.useEffect(() => {
|
|
9019
|
+
void fetchStatus();
|
|
9020
|
+
}, [fetchStatus]);
|
|
9021
|
+
react.useEffect(() => {
|
|
9022
|
+
if (!pollIntervalMs || disabled || !fileId) return;
|
|
9023
|
+
const isClean = status?.scan.status === "clean";
|
|
9024
|
+
if (isClean) return;
|
|
9025
|
+
const id = setInterval(() => {
|
|
9026
|
+
void fetchStatus();
|
|
9027
|
+
}, pollIntervalMs);
|
|
9028
|
+
return () => clearInterval(id);
|
|
9029
|
+
}, [pollIntervalMs, disabled, fileId, status?.scan.status, fetchStatus]);
|
|
9030
|
+
const isReady = status?.scan.status === "clean";
|
|
9031
|
+
return { status, loading, error, isReady, refresh: fetchStatus };
|
|
9032
|
+
}
|
|
8964
9033
|
|
|
8965
9034
|
// src/hooks/useMoney.ts
|
|
8966
9035
|
var useMoney = useMoneyClient;
|
|
@@ -10771,6 +10840,7 @@ exports.useBilling = useBilling;
|
|
|
10771
10840
|
exports.useContent = useContent;
|
|
10772
10841
|
exports.useFeatureFlags = useFeatureFlags;
|
|
10773
10842
|
exports.useFeedback = useFeedback;
|
|
10843
|
+
exports.useFileStatus = useFileStatus;
|
|
10774
10844
|
exports.useMedia = useMedia;
|
|
10775
10845
|
exports.useMoney = useMoney;
|
|
10776
10846
|
exports.useMoneyClient = useMoneyClient;
|
package/dist/index.mjs
CHANGED
|
@@ -2706,6 +2706,31 @@ var StorageService = class extends ServiceModule {
|
|
|
2706
2706
|
async getInfo(fileId, options) {
|
|
2707
2707
|
return this._get(`/files/${fileId}/info`, options);
|
|
2708
2708
|
}
|
|
2709
|
+
/**
|
|
2710
|
+
* Aggregate status for a file — single call returns scan + reserved
|
|
2711
|
+
* optimize/transcode slots + the canonical view URL paths for image
|
|
2712
|
+
* (transform endpoint) and video (HLS playlist) MIME types.
|
|
2713
|
+
*
|
|
2714
|
+
* Foundational primitive for the chat / progressive media read side.
|
|
2715
|
+
* `useFileStatus()` (in `@scalemule/nextjs`) consumes this for both
|
|
2716
|
+
* first-paint and refresh-on-demand scenarios.
|
|
2717
|
+
*
|
|
2718
|
+
* `optimize` and `transcode` are reserved for Phase 3 enrichment. Until
|
|
2719
|
+
* the photo/video services expose internal status endpoints, callers
|
|
2720
|
+
* should attempt the constructed URLs directly to discover readiness
|
|
2721
|
+
* (404 means the pipeline is still running).
|
|
2722
|
+
*
|
|
2723
|
+
* @example
|
|
2724
|
+
* ```ts
|
|
2725
|
+
* const r = await client.storage.getFileStatus(fileId);
|
|
2726
|
+
* if (r.data?.scan.status === 'clean' && r.data.urls.optimized) {
|
|
2727
|
+
* // image: try transform URL for an optimized variant
|
|
2728
|
+
* }
|
|
2729
|
+
* ```
|
|
2730
|
+
*/
|
|
2731
|
+
async getFileStatus(fileId, options) {
|
|
2732
|
+
return this._get(`/files/${fileId}/status`, options);
|
|
2733
|
+
}
|
|
2709
2734
|
/**
|
|
2710
2735
|
* Get a signed view URL for inline display (img src, thumbnails).
|
|
2711
2736
|
* Returns CloudFront signed URL (fast, ~1us) or S3 presigned fallback.
|
|
@@ -8960,6 +8985,50 @@ function useMedia() {
|
|
|
8960
8985
|
);
|
|
8961
8986
|
return { upload, cancelUpload, error, uploading };
|
|
8962
8987
|
}
|
|
8988
|
+
function useFileStatus(options) {
|
|
8989
|
+
const { storage } = useScaleMule();
|
|
8990
|
+
const { fileId, pollIntervalMs = null, disabled = false } = options;
|
|
8991
|
+
const [status, setStatus] = useState(null);
|
|
8992
|
+
const [loading, setLoading] = useState(false);
|
|
8993
|
+
const [error, setError] = useState(null);
|
|
8994
|
+
const requestSeqRef = useRef(0);
|
|
8995
|
+
const fetchStatus = useCallback(async () => {
|
|
8996
|
+
if (!fileId || disabled) return;
|
|
8997
|
+
const seq = ++requestSeqRef.current;
|
|
8998
|
+
setLoading(true);
|
|
8999
|
+
setError(null);
|
|
9000
|
+
try {
|
|
9001
|
+
const r = await storage.getFileStatus(fileId);
|
|
9002
|
+
if (seq !== requestSeqRef.current) return;
|
|
9003
|
+
if (r.error || !r.data) {
|
|
9004
|
+
setError(r.error);
|
|
9005
|
+
return;
|
|
9006
|
+
}
|
|
9007
|
+
setStatus(r.data);
|
|
9008
|
+
} catch (err) {
|
|
9009
|
+
if (seq !== requestSeqRef.current) return;
|
|
9010
|
+
setError(err);
|
|
9011
|
+
} finally {
|
|
9012
|
+
if (seq === requestSeqRef.current) {
|
|
9013
|
+
setLoading(false);
|
|
9014
|
+
}
|
|
9015
|
+
}
|
|
9016
|
+
}, [storage, fileId, disabled]);
|
|
9017
|
+
useEffect(() => {
|
|
9018
|
+
void fetchStatus();
|
|
9019
|
+
}, [fetchStatus]);
|
|
9020
|
+
useEffect(() => {
|
|
9021
|
+
if (!pollIntervalMs || disabled || !fileId) return;
|
|
9022
|
+
const isClean = status?.scan.status === "clean";
|
|
9023
|
+
if (isClean) return;
|
|
9024
|
+
const id = setInterval(() => {
|
|
9025
|
+
void fetchStatus();
|
|
9026
|
+
}, pollIntervalMs);
|
|
9027
|
+
return () => clearInterval(id);
|
|
9028
|
+
}, [pollIntervalMs, disabled, fileId, status?.scan.status, fetchStatus]);
|
|
9029
|
+
const isReady = status?.scan.status === "clean";
|
|
9030
|
+
return { status, loading, error, isReady, refresh: fetchStatus };
|
|
9031
|
+
}
|
|
8963
9032
|
|
|
8964
9033
|
// src/hooks/useMoney.ts
|
|
8965
9034
|
var useMoney = useMoneyClient;
|
|
@@ -10746,4 +10815,4 @@ function createSafeLogger(prefix) {
|
|
|
10746
10815
|
};
|
|
10747
10816
|
}
|
|
10748
10817
|
|
|
10749
|
-
export { FeedbackWidget, ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
|
10818
|
+
export { FeedbackWidget, ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/nextjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@scalemule/money": "^0.0.1",
|
|
56
|
-
"@scalemule/sdk": "^0.0.
|
|
56
|
+
"@scalemule/sdk": "^0.0.41"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"next": ">=14.0.0",
|