@scalemule/nextjs 0.1.9 → 0.1.10
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 +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +72 -19
- package/dist/index.mjs +72 -19
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -216,13 +216,13 @@ interface ScaleMuleProviderProps extends ScaleMuleConfig {
|
|
|
216
216
|
*
|
|
217
217
|
* The platform stores the per-app policy in
|
|
218
218
|
* `application_storage_settings.media_policy` (Phase 4 / P3, live in
|
|
219
|
-
* prod).
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* platform admin set.
|
|
219
|
+
* prod). On boot, the provider fetches `GET /v1/storage/policy` (a
|
|
220
|
+
* lightweight `EndUserOnly` endpoint added in `@scalemule/sdk@0.0.45`)
|
|
221
|
+
* and uses the returned policy as the effective default.
|
|
223
222
|
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
223
|
+
* Passing this prop overrides the auto-fetched value — useful for
|
|
224
|
+
* tests or when an app needs to force a specific mode regardless of
|
|
225
|
+
* platform config.
|
|
226
226
|
*/
|
|
227
227
|
mediaPolicy?: MediaPolicy;
|
|
228
228
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -216,13 +216,13 @@ interface ScaleMuleProviderProps extends ScaleMuleConfig {
|
|
|
216
216
|
*
|
|
217
217
|
* The platform stores the per-app policy in
|
|
218
218
|
* `application_storage_settings.media_policy` (Phase 4 / P3, live in
|
|
219
|
-
* prod).
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* platform admin set.
|
|
219
|
+
* prod). On boot, the provider fetches `GET /v1/storage/policy` (a
|
|
220
|
+
* lightweight `EndUserOnly` endpoint added in `@scalemule/sdk@0.0.45`)
|
|
221
|
+
* and uses the returned policy as the effective default.
|
|
223
222
|
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
223
|
+
* Passing this prop overrides the auto-fetched value — useful for
|
|
224
|
+
* tests or when an app needs to force a specific mode regardless of
|
|
225
|
+
* platform config.
|
|
226
226
|
*/
|
|
227
227
|
mediaPolicy?: MediaPolicy;
|
|
228
228
|
}
|
package/dist/index.js
CHANGED
|
@@ -7569,6 +7569,28 @@ function ScaleMuleProvider({
|
|
|
7569
7569
|
debug
|
|
7570
7570
|
});
|
|
7571
7571
|
}, [apiKey, applicationId, environment, resolvedGatewayUrl, debug]);
|
|
7572
|
+
const [fetchedPolicy, setFetchedPolicy] = React.useState(void 0);
|
|
7573
|
+
React.useEffect(() => {
|
|
7574
|
+
if (mediaPolicy) return;
|
|
7575
|
+
let mounted = true;
|
|
7576
|
+
void (async () => {
|
|
7577
|
+
try {
|
|
7578
|
+
const fn = baseClient.storage.getPolicy;
|
|
7579
|
+
if (typeof fn !== "function") return;
|
|
7580
|
+
const r = await fn.call(baseClient.storage);
|
|
7581
|
+
if (!mounted) return;
|
|
7582
|
+
const v = r?.data?.media_policy;
|
|
7583
|
+
if (v === "fast_trusted" || v === "safe_visible" || v === "safe_public" || v === "moderated" || v === "compliance") {
|
|
7584
|
+
setFetchedPolicy(v);
|
|
7585
|
+
}
|
|
7586
|
+
} catch {
|
|
7587
|
+
}
|
|
7588
|
+
})();
|
|
7589
|
+
return () => {
|
|
7590
|
+
mounted = false;
|
|
7591
|
+
};
|
|
7592
|
+
}, [baseClient, mediaPolicy]);
|
|
7593
|
+
const effectiveMediaPolicy = mediaPolicy ?? fetchedPolicy;
|
|
7572
7594
|
React.useEffect(() => {
|
|
7573
7595
|
const token = client.getSessionToken();
|
|
7574
7596
|
if (token) {
|
|
@@ -7672,7 +7694,7 @@ function ScaleMuleProvider({
|
|
|
7672
7694
|
photo: baseClient.photo,
|
|
7673
7695
|
video: baseClient.video,
|
|
7674
7696
|
audio: baseClient.audio,
|
|
7675
|
-
mediaPolicy,
|
|
7697
|
+
mediaPolicy: effectiveMediaPolicy,
|
|
7676
7698
|
user,
|
|
7677
7699
|
setUser: handleSetUser,
|
|
7678
7700
|
initializing,
|
|
@@ -7687,7 +7709,7 @@ function ScaleMuleProvider({
|
|
|
7687
7709
|
accountSwitcherPrivacy,
|
|
7688
7710
|
bootstrapFlags
|
|
7689
7711
|
}),
|
|
7690
|
-
[client, money$1, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags,
|
|
7712
|
+
[client, money$1, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags, effectiveMediaPolicy]
|
|
7691
7713
|
);
|
|
7692
7714
|
return /* @__PURE__ */ jsxRuntime.jsx(ScaleMuleContext.Provider, { value, children });
|
|
7693
7715
|
}
|
|
@@ -9103,10 +9125,13 @@ function useMedia() {
|
|
|
9103
9125
|
async (fileId) => {
|
|
9104
9126
|
setError(null);
|
|
9105
9127
|
try {
|
|
9106
|
-
const
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9128
|
+
const [, storageResult] = await Promise.all([
|
|
9129
|
+
photo.delete(fileId).catch(() => void 0),
|
|
9130
|
+
storage.delete(fileId)
|
|
9131
|
+
]);
|
|
9132
|
+
if (storageResult.error) {
|
|
9133
|
+
if (storageResult.error.status === 404) return;
|
|
9134
|
+
throw storageResult.error;
|
|
9110
9135
|
}
|
|
9111
9136
|
} catch (err) {
|
|
9112
9137
|
const e = err;
|
|
@@ -9114,7 +9139,7 @@ function useMedia() {
|
|
|
9114
9139
|
throw e;
|
|
9115
9140
|
}
|
|
9116
9141
|
},
|
|
9117
|
-
[storage]
|
|
9142
|
+
[storage, photo]
|
|
9118
9143
|
);
|
|
9119
9144
|
return { upload, cancelUpload, error, uploading };
|
|
9120
9145
|
}
|
|
@@ -9171,13 +9196,26 @@ function useFileStatus(options) {
|
|
|
9171
9196
|
}, [fetchStatus]);
|
|
9172
9197
|
React.useEffect(() => {
|
|
9173
9198
|
if (!pollIntervalMs || disabled || !fileId) return;
|
|
9174
|
-
const
|
|
9175
|
-
if (
|
|
9199
|
+
const scan = status?.scan.status;
|
|
9200
|
+
if (scan === "threat" || scan === "quarantined" || scan === "error") return;
|
|
9201
|
+
const optimizePending = status?.optimize != null && status.optimize.status !== "done";
|
|
9202
|
+
const transcodePending = status?.transcode != null && status.transcode.status !== "done";
|
|
9203
|
+
const pipelinePending = optimizePending || transcodePending;
|
|
9204
|
+
const isSettled = scan === "clean" && !pipelinePending;
|
|
9205
|
+
if (isSettled) return;
|
|
9176
9206
|
const id = setInterval(() => {
|
|
9177
9207
|
void fetchStatus();
|
|
9178
9208
|
}, pollIntervalMs);
|
|
9179
9209
|
return () => clearInterval(id);
|
|
9180
|
-
}, [
|
|
9210
|
+
}, [
|
|
9211
|
+
pollIntervalMs,
|
|
9212
|
+
disabled,
|
|
9213
|
+
fileId,
|
|
9214
|
+
status?.scan.status,
|
|
9215
|
+
status?.optimize,
|
|
9216
|
+
status?.transcode,
|
|
9217
|
+
fetchStatus
|
|
9218
|
+
]);
|
|
9181
9219
|
React.useEffect(() => {
|
|
9182
9220
|
if (!conversationId || !fileId || disabled) return;
|
|
9183
9221
|
const channel = conversationChannel(conversationKind, conversationId);
|
|
@@ -9212,33 +9250,48 @@ function ScaleMuleMedia(props) {
|
|
|
9212
9250
|
renderBlocked,
|
|
9213
9251
|
renderOverride
|
|
9214
9252
|
} = props;
|
|
9253
|
+
const { gatewayUrl } = useScaleMule();
|
|
9215
9254
|
const { status, isReady } = useFileStatus({
|
|
9216
9255
|
fileId,
|
|
9217
9256
|
pollIntervalMs,
|
|
9218
9257
|
conversationId,
|
|
9219
9258
|
conversationKind
|
|
9220
9259
|
});
|
|
9260
|
+
const absoluteUrl = React__namespace.useCallback(
|
|
9261
|
+
(url) => {
|
|
9262
|
+
if (!url) return null;
|
|
9263
|
+
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("blob:") || url.startsWith("data:")) {
|
|
9264
|
+
return url;
|
|
9265
|
+
}
|
|
9266
|
+
if (!gatewayUrl) return url;
|
|
9267
|
+
const base = gatewayUrl.endsWith("/") ? gatewayUrl.slice(0, -1) : gatewayUrl;
|
|
9268
|
+
const path = url.startsWith("/") ? url : `/${url}`;
|
|
9269
|
+
return `${base}${path}`;
|
|
9270
|
+
},
|
|
9271
|
+
[gatewayUrl]
|
|
9272
|
+
);
|
|
9221
9273
|
const isImage = mimeType.startsWith("image/");
|
|
9222
9274
|
const isVideo = mimeType.startsWith("video/");
|
|
9223
9275
|
const isAudio = mimeType.startsWith("audio/");
|
|
9224
9276
|
const src = React.useMemo(() => {
|
|
9225
9277
|
const scan = status?.scan.status;
|
|
9226
9278
|
if (scan === "threat" || scan === "quarantined") return null;
|
|
9227
|
-
if (status
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
if (
|
|
9233
|
-
return null;
|
|
9234
|
-
}, [status,
|
|
9279
|
+
if (!status) {
|
|
9280
|
+
return blobPreview ?? null;
|
|
9281
|
+
}
|
|
9282
|
+
if (isImage && status.urls.optimized) return absoluteUrl(status.urls.optimized);
|
|
9283
|
+
if (isVideo && status.urls.hls) return absoluteUrl(status.urls.hls);
|
|
9284
|
+
if (status.urls.original) return absoluteUrl(status.urls.original);
|
|
9285
|
+
return blobPreview ?? null;
|
|
9286
|
+
}, [status, isImage, isVideo, blobPreview, absoluteUrl]);
|
|
9235
9287
|
const renderState = React.useMemo(() => {
|
|
9236
9288
|
const scan = status?.scan.status;
|
|
9237
9289
|
if (scan === "threat" || scan === "quarantined") return "blocked";
|
|
9290
|
+
if (status?.urls.original) return "ready";
|
|
9238
9291
|
if (isReady) return "ready";
|
|
9239
9292
|
if (blobPreview) return "preview";
|
|
9240
9293
|
return "pending";
|
|
9241
|
-
}, [status?.scan.status, isReady, blobPreview]);
|
|
9294
|
+
}, [status?.scan.status, status?.urls.original, isReady, blobPreview]);
|
|
9242
9295
|
const videoRef = React__namespace.useRef(null);
|
|
9243
9296
|
React.useEffect(() => {
|
|
9244
9297
|
if (!isVideo) return;
|
package/dist/index.mjs
CHANGED
|
@@ -7549,6 +7549,28 @@ function ScaleMuleProvider({
|
|
|
7549
7549
|
debug
|
|
7550
7550
|
});
|
|
7551
7551
|
}, [apiKey, applicationId, environment, resolvedGatewayUrl, debug]);
|
|
7552
|
+
const [fetchedPolicy, setFetchedPolicy] = useState(void 0);
|
|
7553
|
+
useEffect(() => {
|
|
7554
|
+
if (mediaPolicy) return;
|
|
7555
|
+
let mounted = true;
|
|
7556
|
+
void (async () => {
|
|
7557
|
+
try {
|
|
7558
|
+
const fn = baseClient.storage.getPolicy;
|
|
7559
|
+
if (typeof fn !== "function") return;
|
|
7560
|
+
const r = await fn.call(baseClient.storage);
|
|
7561
|
+
if (!mounted) return;
|
|
7562
|
+
const v = r?.data?.media_policy;
|
|
7563
|
+
if (v === "fast_trusted" || v === "safe_visible" || v === "safe_public" || v === "moderated" || v === "compliance") {
|
|
7564
|
+
setFetchedPolicy(v);
|
|
7565
|
+
}
|
|
7566
|
+
} catch {
|
|
7567
|
+
}
|
|
7568
|
+
})();
|
|
7569
|
+
return () => {
|
|
7570
|
+
mounted = false;
|
|
7571
|
+
};
|
|
7572
|
+
}, [baseClient, mediaPolicy]);
|
|
7573
|
+
const effectiveMediaPolicy = mediaPolicy ?? fetchedPolicy;
|
|
7552
7574
|
useEffect(() => {
|
|
7553
7575
|
const token = client.getSessionToken();
|
|
7554
7576
|
if (token) {
|
|
@@ -7652,7 +7674,7 @@ function ScaleMuleProvider({
|
|
|
7652
7674
|
photo: baseClient.photo,
|
|
7653
7675
|
video: baseClient.video,
|
|
7654
7676
|
audio: baseClient.audio,
|
|
7655
|
-
mediaPolicy,
|
|
7677
|
+
mediaPolicy: effectiveMediaPolicy,
|
|
7656
7678
|
user,
|
|
7657
7679
|
setUser: handleSetUser,
|
|
7658
7680
|
initializing,
|
|
@@ -7667,7 +7689,7 @@ function ScaleMuleProvider({
|
|
|
7667
7689
|
accountSwitcherPrivacy,
|
|
7668
7690
|
bootstrapFlags
|
|
7669
7691
|
}),
|
|
7670
|
-
[client, money, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags,
|
|
7692
|
+
[client, money, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags, effectiveMediaPolicy]
|
|
7671
7693
|
);
|
|
7672
7694
|
return /* @__PURE__ */ jsx(ScaleMuleContext.Provider, { value, children });
|
|
7673
7695
|
}
|
|
@@ -9083,10 +9105,13 @@ function useMedia() {
|
|
|
9083
9105
|
async (fileId) => {
|
|
9084
9106
|
setError(null);
|
|
9085
9107
|
try {
|
|
9086
|
-
const
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9108
|
+
const [, storageResult] = await Promise.all([
|
|
9109
|
+
photo.delete(fileId).catch(() => void 0),
|
|
9110
|
+
storage.delete(fileId)
|
|
9111
|
+
]);
|
|
9112
|
+
if (storageResult.error) {
|
|
9113
|
+
if (storageResult.error.status === 404) return;
|
|
9114
|
+
throw storageResult.error;
|
|
9090
9115
|
}
|
|
9091
9116
|
} catch (err) {
|
|
9092
9117
|
const e = err;
|
|
@@ -9094,7 +9119,7 @@ function useMedia() {
|
|
|
9094
9119
|
throw e;
|
|
9095
9120
|
}
|
|
9096
9121
|
},
|
|
9097
|
-
[storage]
|
|
9122
|
+
[storage, photo]
|
|
9098
9123
|
);
|
|
9099
9124
|
return { upload, cancelUpload, error, uploading };
|
|
9100
9125
|
}
|
|
@@ -9151,13 +9176,26 @@ function useFileStatus(options) {
|
|
|
9151
9176
|
}, [fetchStatus]);
|
|
9152
9177
|
useEffect(() => {
|
|
9153
9178
|
if (!pollIntervalMs || disabled || !fileId) return;
|
|
9154
|
-
const
|
|
9155
|
-
if (
|
|
9179
|
+
const scan = status?.scan.status;
|
|
9180
|
+
if (scan === "threat" || scan === "quarantined" || scan === "error") return;
|
|
9181
|
+
const optimizePending = status?.optimize != null && status.optimize.status !== "done";
|
|
9182
|
+
const transcodePending = status?.transcode != null && status.transcode.status !== "done";
|
|
9183
|
+
const pipelinePending = optimizePending || transcodePending;
|
|
9184
|
+
const isSettled = scan === "clean" && !pipelinePending;
|
|
9185
|
+
if (isSettled) return;
|
|
9156
9186
|
const id = setInterval(() => {
|
|
9157
9187
|
void fetchStatus();
|
|
9158
9188
|
}, pollIntervalMs);
|
|
9159
9189
|
return () => clearInterval(id);
|
|
9160
|
-
}, [
|
|
9190
|
+
}, [
|
|
9191
|
+
pollIntervalMs,
|
|
9192
|
+
disabled,
|
|
9193
|
+
fileId,
|
|
9194
|
+
status?.scan.status,
|
|
9195
|
+
status?.optimize,
|
|
9196
|
+
status?.transcode,
|
|
9197
|
+
fetchStatus
|
|
9198
|
+
]);
|
|
9161
9199
|
useEffect(() => {
|
|
9162
9200
|
if (!conversationId || !fileId || disabled) return;
|
|
9163
9201
|
const channel = conversationChannel(conversationKind, conversationId);
|
|
@@ -9192,33 +9230,48 @@ function ScaleMuleMedia(props) {
|
|
|
9192
9230
|
renderBlocked,
|
|
9193
9231
|
renderOverride
|
|
9194
9232
|
} = props;
|
|
9233
|
+
const { gatewayUrl } = useScaleMule();
|
|
9195
9234
|
const { status, isReady } = useFileStatus({
|
|
9196
9235
|
fileId,
|
|
9197
9236
|
pollIntervalMs,
|
|
9198
9237
|
conversationId,
|
|
9199
9238
|
conversationKind
|
|
9200
9239
|
});
|
|
9240
|
+
const absoluteUrl = React.useCallback(
|
|
9241
|
+
(url) => {
|
|
9242
|
+
if (!url) return null;
|
|
9243
|
+
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("blob:") || url.startsWith("data:")) {
|
|
9244
|
+
return url;
|
|
9245
|
+
}
|
|
9246
|
+
if (!gatewayUrl) return url;
|
|
9247
|
+
const base = gatewayUrl.endsWith("/") ? gatewayUrl.slice(0, -1) : gatewayUrl;
|
|
9248
|
+
const path = url.startsWith("/") ? url : `/${url}`;
|
|
9249
|
+
return `${base}${path}`;
|
|
9250
|
+
},
|
|
9251
|
+
[gatewayUrl]
|
|
9252
|
+
);
|
|
9201
9253
|
const isImage = mimeType.startsWith("image/");
|
|
9202
9254
|
const isVideo = mimeType.startsWith("video/");
|
|
9203
9255
|
const isAudio = mimeType.startsWith("audio/");
|
|
9204
9256
|
const src = useMemo(() => {
|
|
9205
9257
|
const scan = status?.scan.status;
|
|
9206
9258
|
if (scan === "threat" || scan === "quarantined") return null;
|
|
9207
|
-
if (status
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
if (
|
|
9213
|
-
return null;
|
|
9214
|
-
}, [status,
|
|
9259
|
+
if (!status) {
|
|
9260
|
+
return blobPreview ?? null;
|
|
9261
|
+
}
|
|
9262
|
+
if (isImage && status.urls.optimized) return absoluteUrl(status.urls.optimized);
|
|
9263
|
+
if (isVideo && status.urls.hls) return absoluteUrl(status.urls.hls);
|
|
9264
|
+
if (status.urls.original) return absoluteUrl(status.urls.original);
|
|
9265
|
+
return blobPreview ?? null;
|
|
9266
|
+
}, [status, isImage, isVideo, blobPreview, absoluteUrl]);
|
|
9215
9267
|
const renderState = useMemo(() => {
|
|
9216
9268
|
const scan = status?.scan.status;
|
|
9217
9269
|
if (scan === "threat" || scan === "quarantined") return "blocked";
|
|
9270
|
+
if (status?.urls.original) return "ready";
|
|
9218
9271
|
if (isReady) return "ready";
|
|
9219
9272
|
if (blobPreview) return "preview";
|
|
9220
9273
|
return "pending";
|
|
9221
|
-
}, [status?.scan.status, isReady, blobPreview]);
|
|
9274
|
+
}, [status?.scan.status, status?.urls.original, isReady, blobPreview]);
|
|
9222
9275
|
const videoRef = React.useRef(null);
|
|
9223
9276
|
useEffect(() => {
|
|
9224
9277
|
if (!isVideo) return;
|
package/package.json
CHANGED