@scalemule/nextjs 0.1.24 → 0.1.26
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/client.d.mts +14 -1
- package/dist/client.d.ts +14 -1
- package/dist/client.js +22 -1
- package/dist/client.mjs +22 -1
- package/dist/{index-DTWyUcyd.d.mts → index-zQloSkpW.d.mts} +5 -1
- package/dist/{index-DTWyUcyd.d.ts → index-zQloSkpW.d.ts} +5 -1
- package/dist/index.d.mts +94 -20
- package/dist/index.d.ts +94 -20
- package/dist/index.js +395 -485
- package/dist/index.mjs +394 -485
- package/dist/server/index.d.mts +3 -3
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.js +7 -9
- package/dist/server/index.mjs +7 -9
- package/dist/server/ledvery.js +1 -5
- package/dist/server/ledvery.mjs +1 -5
- package/dist/server/webhook-handler.d.mts +2 -2
- package/dist/server/webhook-handler.d.ts +2 -2
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{webhook-handler-DsxJS_He.d.mts → webhook-handler-C_bKDevj.d.mts} +1 -1
- package/dist/{webhook-handler-CTx4Uh8u.d.ts → webhook-handler-D4uulN2T.d.ts} +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -560,6 +560,7 @@ var ScaleMuleClient = class {
|
|
|
560
560
|
this.anonymousId = null;
|
|
561
561
|
this.sessionPool = /* @__PURE__ */ new Map();
|
|
562
562
|
this.knownAccounts = /* @__PURE__ */ new Map();
|
|
563
|
+
this.refreshPromise = null;
|
|
563
564
|
this.apiKey = config.apiKey;
|
|
564
565
|
this.applicationId = config.applicationId || null;
|
|
565
566
|
this.baseUrl = config.baseUrl || GATEWAY_URLS[config.environment || "prod"];
|
|
@@ -578,6 +579,9 @@ var ScaleMuleClient = class {
|
|
|
578
579
|
this.multiSessionEnabled = config.enableMultiSession || false;
|
|
579
580
|
this.accountSwitcherEnabled = config.enableAccountSwitcher || false;
|
|
580
581
|
this.accountSwitcherPrivacy = config.accountSwitcherPrivacy || "full";
|
|
582
|
+
this.onRefreshStart = config.onRefreshStart;
|
|
583
|
+
this.onRefreshEnd = config.onRefreshEnd;
|
|
584
|
+
this.onAutoRefreshFailed = config.onAutoRefreshFailed;
|
|
581
585
|
}
|
|
582
586
|
// --------------------------------------------------------------------------
|
|
583
587
|
// Session Management
|
|
@@ -863,34 +867,28 @@ var ScaleMuleClient = class {
|
|
|
863
867
|
const method = (init.method || "GET").toUpperCase();
|
|
864
868
|
const timeout = init.timeout || this.defaultTimeout;
|
|
865
869
|
const maxRetries = init.skipRetry ? 0 : init.retries ?? this.maxRetries;
|
|
866
|
-
const
|
|
867
|
-
"x-api-key": this.apiKey,
|
|
868
|
-
"User-Agent": `ScaleMule-SDK-TypeScript/${SDK_VERSION}`,
|
|
869
|
-
...init.headers
|
|
870
|
-
};
|
|
871
|
-
if (!init.skipAuth && this.sessionToken) {
|
|
872
|
-
headers["Authorization"] = `Bearer ${this.sessionToken}`;
|
|
873
|
-
}
|
|
874
|
-
if (this.workspaceId) {
|
|
875
|
-
headers["x-sm-workspace-id"] = this.workspaceId;
|
|
876
|
-
}
|
|
877
|
-
if (!this.sessionToken && this.anonymousId) {
|
|
878
|
-
headers["x-anonymous-id"] = this.anonymousId;
|
|
879
|
-
}
|
|
880
|
-
let bodyStr;
|
|
881
|
-
if (init.body !== void 0 && init.body !== null) {
|
|
882
|
-
bodyStr = typeof init.body === "string" ? init.body : JSON.stringify(init.body);
|
|
883
|
-
if (!headers["Content-Type"]) {
|
|
884
|
-
headers["Content-Type"] = "application/json";
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
if (this.debug) {
|
|
888
|
-
console.log(`[ScaleMule] ${method} ${path}`);
|
|
889
|
-
}
|
|
890
|
-
const idempotencyKey = method === "POST" ? generateIdempotencyKey() : void 0;
|
|
870
|
+
const bodyStr = init.body ? JSON.stringify(init.body) : void 0;
|
|
891
871
|
let lastError = null;
|
|
872
|
+
let idempotencyKey = null;
|
|
892
873
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
893
|
-
|
|
874
|
+
const headers = {
|
|
875
|
+
"x-api-key": this.apiKey,
|
|
876
|
+
"User-Agent": `ScaleMule-SDK-TypeScript/${SDK_VERSION}`,
|
|
877
|
+
...init.headers
|
|
878
|
+
};
|
|
879
|
+
if (!init.skipAuth && this.sessionToken) {
|
|
880
|
+
headers["Authorization"] = `Bearer ${this.sessionToken}`;
|
|
881
|
+
}
|
|
882
|
+
if (this.workspaceId) {
|
|
883
|
+
headers["x-sm-workspace-id"] = this.workspaceId;
|
|
884
|
+
}
|
|
885
|
+
if (!this.sessionToken && this.anonymousId) {
|
|
886
|
+
headers["x-anonymous-id"] = this.anonymousId;
|
|
887
|
+
}
|
|
888
|
+
if (attempt > 0 && (method === "POST" || method === "PUT" || method === "PATCH")) {
|
|
889
|
+
if (!idempotencyKey) {
|
|
890
|
+
idempotencyKey = generateIdempotencyKey();
|
|
891
|
+
}
|
|
894
892
|
headers["x-idempotency-key"] = idempotencyKey;
|
|
895
893
|
}
|
|
896
894
|
const controller = new AbortController();
|
|
@@ -910,6 +908,10 @@ var ScaleMuleClient = class {
|
|
|
910
908
|
signal: controller.signal
|
|
911
909
|
});
|
|
912
910
|
clearTimeout(timeoutId);
|
|
911
|
+
const rotatedToken = response.headers.get("x-rotated-session-token");
|
|
912
|
+
if (rotatedToken && this.sessionToken && this.userId) {
|
|
913
|
+
this.setSession(rotatedToken, this.userId);
|
|
914
|
+
}
|
|
913
915
|
if (this.rateLimitQueue) {
|
|
914
916
|
this.rateLimitQueue.updateFromHeaders(response.headers);
|
|
915
917
|
}
|
|
@@ -932,6 +934,45 @@ var ScaleMuleClient = class {
|
|
|
932
934
|
status: response.status,
|
|
933
935
|
details: responseData?.error?.details || responseData?.details
|
|
934
936
|
};
|
|
937
|
+
if (response.status === 401 && this.sessionToken && !init.isAutoRefresh) {
|
|
938
|
+
if (this.debug) console.log("[ScaleMule] 401 received, attempting auto-refresh...");
|
|
939
|
+
let isPrimaryRefresh = false;
|
|
940
|
+
if (!this.refreshPromise) {
|
|
941
|
+
isPrimaryRefresh = true;
|
|
942
|
+
this.onRefreshStart?.();
|
|
943
|
+
this.refreshPromise = this.auth?.refreshSession ? this.auth.refreshSession() : this.post("/auth/refresh", {}, { isAutoRefresh: true });
|
|
944
|
+
}
|
|
945
|
+
const currentRefreshPromise = this.refreshPromise;
|
|
946
|
+
try {
|
|
947
|
+
const refreshResult = await currentRefreshPromise;
|
|
948
|
+
if (!refreshResult || refreshResult.error) {
|
|
949
|
+
if (this.debug) console.log("[ScaleMule] Auto-refresh failed:", refreshResult?.error);
|
|
950
|
+
const apiError = refreshResult?.error || {
|
|
951
|
+
code: "refresh_failed",
|
|
952
|
+
message: "Auto-refresh failed",
|
|
953
|
+
status: 400
|
|
954
|
+
};
|
|
955
|
+
init.onAutoRefreshFailed?.(apiError);
|
|
956
|
+
this.onAutoRefreshFailed?.(apiError);
|
|
957
|
+
return { data: null, error };
|
|
958
|
+
}
|
|
959
|
+
if (this.debug) console.log("[ScaleMule] Auto-refresh succeeded, retrying original request...");
|
|
960
|
+
const newToken = refreshResult.data?.session_token || refreshResult.data?.access_token;
|
|
961
|
+
if (newToken) {
|
|
962
|
+
this.sessionToken = newToken;
|
|
963
|
+
if (this.userId) {
|
|
964
|
+
await this.storage.setItem(SESSION_STORAGE_KEY, newToken);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
attempt--;
|
|
968
|
+
continue;
|
|
969
|
+
} finally {
|
|
970
|
+
if (isPrimaryRefresh && this.refreshPromise === currentRefreshPromise) {
|
|
971
|
+
this.refreshPromise = null;
|
|
972
|
+
this.onRefreshEnd?.();
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
935
976
|
if (response.status === 429) {
|
|
936
977
|
const retryAfter = response.headers.get("Retry-After");
|
|
937
978
|
if (retryAfter) {
|
|
@@ -5715,7 +5756,7 @@ var AudioService = class extends ServiceModule {
|
|
|
5715
5756
|
constructor(client, storage) {
|
|
5716
5757
|
super(client);
|
|
5717
5758
|
this.storage = storage;
|
|
5718
|
-
this.basePath = "/v1/
|
|
5759
|
+
this.basePath = "/v1/audio";
|
|
5719
5760
|
}
|
|
5720
5761
|
/**
|
|
5721
5762
|
* Register a storage-uploaded audio asset with the audio service.
|
|
@@ -5772,6 +5813,32 @@ var AudioService = class extends ServiceModule {
|
|
|
5772
5813
|
};
|
|
5773
5814
|
}
|
|
5774
5815
|
};
|
|
5816
|
+
var TtsService = class extends ServiceModule {
|
|
5817
|
+
constructor() {
|
|
5818
|
+
super(...arguments);
|
|
5819
|
+
this.basePath = "/v1/tts";
|
|
5820
|
+
}
|
|
5821
|
+
async synthesize(params, options) {
|
|
5822
|
+
return this.post(
|
|
5823
|
+
"/synthesize",
|
|
5824
|
+
{
|
|
5825
|
+
text: params.text,
|
|
5826
|
+
voice: params.voice,
|
|
5827
|
+
model: params.model,
|
|
5828
|
+
provider: params.provider,
|
|
5829
|
+
async: params.async,
|
|
5830
|
+
access_mode: params.accessMode
|
|
5831
|
+
},
|
|
5832
|
+
options
|
|
5833
|
+
);
|
|
5834
|
+
}
|
|
5835
|
+
async getJob(id, options) {
|
|
5836
|
+
return this._get(`/jobs/${id}`, options);
|
|
5837
|
+
}
|
|
5838
|
+
async listVoices(params, options) {
|
|
5839
|
+
return this._get(this.withQuery("/voices", { provider: params?.provider }), options);
|
|
5840
|
+
}
|
|
5841
|
+
};
|
|
5775
5842
|
var DeadLetterApi = class extends ServiceModule {
|
|
5776
5843
|
constructor() {
|
|
5777
5844
|
super(...arguments);
|
|
@@ -6592,6 +6659,7 @@ var ScaleMule = class {
|
|
|
6592
6659
|
this.functions = new FunctionsService(this._client);
|
|
6593
6660
|
this.photo = new PhotoService(this._client, this.storage);
|
|
6594
6661
|
this.audio = new AudioService(this._client, this.storage);
|
|
6662
|
+
this.tts = new TtsService(this._client);
|
|
6595
6663
|
this.flagContent = new FlagContentService(this._client);
|
|
6596
6664
|
this.creatorMaker = new CreatorMakerService(this._client);
|
|
6597
6665
|
this.compliance = new ComplianceService(this._client);
|
|
@@ -7158,6 +7226,24 @@ var ScaleMuleClient2 = class {
|
|
|
7158
7226
|
console.log("[ScaleMule] Session set for user:", userId);
|
|
7159
7227
|
}
|
|
7160
7228
|
}
|
|
7229
|
+
/**
|
|
7230
|
+
* Token-only setter for member-auth surfaces.
|
|
7231
|
+
*
|
|
7232
|
+
* Unlike `setSession(token, userId)`, this does NOT persist a userId or
|
|
7233
|
+
* write to local storage — useful when the host platform owns identity
|
|
7234
|
+
* (e.g. ScaleMule's member dashboards use `MemberAuthProvider` and the
|
|
7235
|
+
* token comes from a `${env}_member_access_token` cookie). The token is
|
|
7236
|
+
* applied in-memory and used as a `Bearer` Authorization header on
|
|
7237
|
+
* subsequent requests.
|
|
7238
|
+
*
|
|
7239
|
+
* Pass `null` to clear without touching userId/storage.
|
|
7240
|
+
*/
|
|
7241
|
+
setSessionToken(token) {
|
|
7242
|
+
this.sessionToken = token;
|
|
7243
|
+
if (this.debug) {
|
|
7244
|
+
console.log("[ScaleMule] Session token", token ? "set (token-only)" : "cleared (token-only)");
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7161
7247
|
/**
|
|
7162
7248
|
* Clear session on logout
|
|
7163
7249
|
*/
|
|
@@ -7222,6 +7308,8 @@ var ScaleMuleClient2 = class {
|
|
|
7222
7308
|
console.log(`[ScaleMule] ${options.method || "GET"} ${path}`);
|
|
7223
7309
|
}
|
|
7224
7310
|
let lastError = null;
|
|
7311
|
+
const MAX_REFRESH_ATTEMPTS = 1;
|
|
7312
|
+
let refreshAttempts = 0;
|
|
7225
7313
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
7226
7314
|
const controller = new AbortController();
|
|
7227
7315
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
@@ -7245,7 +7333,8 @@ var ScaleMuleClient2 = class {
|
|
|
7245
7333
|
if (!response.ok) {
|
|
7246
7334
|
const rawError = responseData?.error;
|
|
7247
7335
|
const error = rawError && typeof rawError === "object" ? rawError : { code: `HTTP_${response.status}`, message: typeof rawError === "string" ? rawError : responseData?.message || text || response.statusText };
|
|
7248
|
-
if (response.status === 401 && this.sessionToken && !options.isAutoRefresh) {
|
|
7336
|
+
if (response.status === 401 && this.sessionToken && !options.isAutoRefresh && refreshAttempts < MAX_REFRESH_ATTEMPTS) {
|
|
7337
|
+
refreshAttempts++;
|
|
7249
7338
|
if (this.debug) console.log("[ScaleMule] 401 received, attempting auto-refresh...");
|
|
7250
7339
|
if (!this.refreshPromise) {
|
|
7251
7340
|
this.onRefreshStart?.();
|
|
@@ -7614,8 +7703,12 @@ function ScaleMuleProvider({
|
|
|
7614
7703
|
onLogout,
|
|
7615
7704
|
onAuthError,
|
|
7616
7705
|
bootstrapFlags,
|
|
7617
|
-
mediaPolicy
|
|
7706
|
+
mediaPolicy,
|
|
7707
|
+
getToken,
|
|
7708
|
+
userResolver,
|
|
7709
|
+
memberTokenPollMs
|
|
7618
7710
|
}) {
|
|
7711
|
+
const memberMode = typeof getToken === "function";
|
|
7619
7712
|
const [user, setUser] = useState(null);
|
|
7620
7713
|
const [initializing, setInitializing] = useState(true);
|
|
7621
7714
|
const [error, setError] = useState(null);
|
|
@@ -7632,9 +7725,13 @@ function ScaleMuleProvider({
|
|
|
7632
7725
|
gatewayUrl: resolvedGatewayUrl,
|
|
7633
7726
|
debug,
|
|
7634
7727
|
storage,
|
|
7635
|
-
|
|
7728
|
+
// Make outbound API calls wait for the first token to land in any
|
|
7729
|
+
// mode where the provider is responsible for populating the
|
|
7730
|
+
// session asynchronously: auth-proxy fetch, or member-mode
|
|
7731
|
+
// getToken() callback. Resolved in the init effect below.
|
|
7732
|
+
pendingSessionInit: !!authProxyUrl || memberMode
|
|
7636
7733
|
}),
|
|
7637
|
-
[apiKey, applicationId, environment, resolvedGatewayUrl, debug, storage, authProxyUrl]
|
|
7734
|
+
[apiKey, applicationId, environment, resolvedGatewayUrl, debug, storage, authProxyUrl, memberMode]
|
|
7638
7735
|
);
|
|
7639
7736
|
const money = useMemo(
|
|
7640
7737
|
() => createMoneyClient({
|
|
@@ -7656,8 +7753,10 @@ function ScaleMuleProvider({
|
|
|
7656
7753
|
});
|
|
7657
7754
|
}, [apiKey, applicationId, environment, resolvedGatewayUrl, debug]);
|
|
7658
7755
|
const [fetchedPolicy, setFetchedPolicy] = useState(void 0);
|
|
7756
|
+
const [tokenVersion, setTokenVersion] = useState(0);
|
|
7659
7757
|
useEffect(() => {
|
|
7660
7758
|
if (mediaPolicy) return;
|
|
7759
|
+
if (memberMode && tokenVersion === 0) return;
|
|
7661
7760
|
let mounted = true;
|
|
7662
7761
|
void (async () => {
|
|
7663
7762
|
try {
|
|
@@ -7675,7 +7774,7 @@ function ScaleMuleProvider({
|
|
|
7675
7774
|
return () => {
|
|
7676
7775
|
mounted = false;
|
|
7677
7776
|
};
|
|
7678
|
-
}, [baseClient, mediaPolicy]);
|
|
7777
|
+
}, [baseClient, mediaPolicy, memberMode, tokenVersion]);
|
|
7679
7778
|
const effectiveMediaPolicy = mediaPolicy ?? fetchedPolicy;
|
|
7680
7779
|
useEffect(() => {
|
|
7681
7780
|
const token = client.getSessionToken();
|
|
@@ -7693,6 +7792,43 @@ function ScaleMuleProvider({
|
|
|
7693
7792
|
try {
|
|
7694
7793
|
await client.initialize();
|
|
7695
7794
|
const cachedUser = getCachedUser();
|
|
7795
|
+
if (memberMode) {
|
|
7796
|
+
try {
|
|
7797
|
+
const token = await Promise.resolve(getToken()) ?? null;
|
|
7798
|
+
if (mounted) {
|
|
7799
|
+
if (token) {
|
|
7800
|
+
client.setSessionToken(token);
|
|
7801
|
+
baseClient.setAccessToken(token);
|
|
7802
|
+
money.setAccessToken(token);
|
|
7803
|
+
} else {
|
|
7804
|
+
client.setSessionToken(null);
|
|
7805
|
+
baseClient.clearAccessToken();
|
|
7806
|
+
money.setAccessToken(void 0);
|
|
7807
|
+
}
|
|
7808
|
+
setTokenVersion((v) => v + 1);
|
|
7809
|
+
}
|
|
7810
|
+
if (userResolver) {
|
|
7811
|
+
try {
|
|
7812
|
+
const resolvedUser = await userResolver();
|
|
7813
|
+
if (mounted) {
|
|
7814
|
+
setUser(resolvedUser);
|
|
7815
|
+
setCachedUser(resolvedUser);
|
|
7816
|
+
}
|
|
7817
|
+
} catch (resolveErr) {
|
|
7818
|
+
if (mounted && debug) {
|
|
7819
|
+
console.debug("[ScaleMule] userResolver() failed:", resolveErr);
|
|
7820
|
+
}
|
|
7821
|
+
}
|
|
7822
|
+
}
|
|
7823
|
+
} catch (memberErr) {
|
|
7824
|
+
if (mounted && debug) {
|
|
7825
|
+
console.debug("[ScaleMule] getToken() failed:", memberErr);
|
|
7826
|
+
}
|
|
7827
|
+
} finally {
|
|
7828
|
+
client.resolveSessionPending();
|
|
7829
|
+
}
|
|
7830
|
+
return;
|
|
7831
|
+
}
|
|
7696
7832
|
if (authProxyUrl) {
|
|
7697
7833
|
if (cachedUser && mounted) {
|
|
7698
7834
|
setUser(cachedUser);
|
|
@@ -7764,7 +7900,43 @@ function ScaleMuleProvider({
|
|
|
7764
7900
|
return () => {
|
|
7765
7901
|
mounted = false;
|
|
7766
7902
|
};
|
|
7767
|
-
}, [client, debug, onAuthError, authProxyUrl]);
|
|
7903
|
+
}, [client, baseClient, money, debug, onAuthError, authProxyUrl, memberMode, getToken, userResolver]);
|
|
7904
|
+
useEffect(() => {
|
|
7905
|
+
if (!memberMode) return;
|
|
7906
|
+
if (memberTokenPollMs === null) return;
|
|
7907
|
+
const interval = memberTokenPollMs ?? 6e4;
|
|
7908
|
+
if (interval <= 0) return;
|
|
7909
|
+
let cancelled = false;
|
|
7910
|
+
const id = setInterval(async () => {
|
|
7911
|
+
try {
|
|
7912
|
+
const token = await Promise.resolve(getToken()) ?? null;
|
|
7913
|
+
if (cancelled) return;
|
|
7914
|
+
const current = client.getSessionToken();
|
|
7915
|
+
if (token === current) return;
|
|
7916
|
+
if (token) {
|
|
7917
|
+
client.setSessionToken(token);
|
|
7918
|
+
baseClient.setAccessToken(token);
|
|
7919
|
+
money.setAccessToken(token);
|
|
7920
|
+
} else {
|
|
7921
|
+
client.setSessionToken(null);
|
|
7922
|
+
baseClient.clearAccessToken();
|
|
7923
|
+
money.setAccessToken(void 0);
|
|
7924
|
+
if (debug) {
|
|
7925
|
+
console.debug("[ScaleMule] Member token cleared on refresh");
|
|
7926
|
+
}
|
|
7927
|
+
}
|
|
7928
|
+
setTokenVersion((v) => v + 1);
|
|
7929
|
+
} catch (err) {
|
|
7930
|
+
if (debug) {
|
|
7931
|
+
console.debug("[ScaleMule] Member token refresh failed:", err);
|
|
7932
|
+
}
|
|
7933
|
+
}
|
|
7934
|
+
}, interval);
|
|
7935
|
+
return () => {
|
|
7936
|
+
cancelled = true;
|
|
7937
|
+
clearInterval(id);
|
|
7938
|
+
};
|
|
7939
|
+
}, [memberMode, memberTokenPollMs, getToken, client, baseClient, money, debug]);
|
|
7768
7940
|
const handleSetUser = useCallback(
|
|
7769
7941
|
(newUser) => {
|
|
7770
7942
|
setUser(newUser);
|
|
@@ -8246,8 +8418,8 @@ function useAuth() {
|
|
|
8246
8418
|
const getLinkedAccounts = useCallback(async () => {
|
|
8247
8419
|
setError(null);
|
|
8248
8420
|
try {
|
|
8249
|
-
const data = await client.get("/v1/auth/oauth/
|
|
8250
|
-
return data.
|
|
8421
|
+
const data = await client.get("/v1/auth/oauth/providers");
|
|
8422
|
+
return data.providers;
|
|
8251
8423
|
} catch (err) {
|
|
8252
8424
|
if (err instanceof ScaleMuleApiError) {
|
|
8253
8425
|
setError(err);
|
|
@@ -8256,41 +8428,30 @@ function useAuth() {
|
|
|
8256
8428
|
}
|
|
8257
8429
|
}, [client, setError]);
|
|
8258
8430
|
const linkAccount = useCallback(
|
|
8259
|
-
async (
|
|
8431
|
+
async (_config) => {
|
|
8260
8432
|
setError(null);
|
|
8261
8433
|
if (!user) {
|
|
8262
|
-
const
|
|
8434
|
+
const err2 = {
|
|
8263
8435
|
code: "NOT_AUTHENTICATED",
|
|
8264
8436
|
message: "Must be logged in to link accounts"
|
|
8265
8437
|
};
|
|
8266
|
-
setError(
|
|
8267
|
-
throw
|
|
8268
|
-
}
|
|
8269
|
-
let linkData;
|
|
8270
|
-
try {
|
|
8271
|
-
linkData = await client.post("/v1/auth/oauth/link", {
|
|
8272
|
-
provider: config.provider,
|
|
8273
|
-
redirect_url: config.redirectUrl,
|
|
8274
|
-
scopes: config.scopes
|
|
8275
|
-
});
|
|
8276
|
-
} catch (err) {
|
|
8277
|
-
if (err instanceof ScaleMuleApiError) {
|
|
8278
|
-
setError(err);
|
|
8279
|
-
}
|
|
8280
|
-
throw err;
|
|
8281
|
-
}
|
|
8282
|
-
if (typeof sessionStorage !== "undefined") {
|
|
8283
|
-
sessionStorage.setItem("scalemule_oauth_state", linkData.state);
|
|
8438
|
+
setError(err2);
|
|
8439
|
+
throw err2;
|
|
8284
8440
|
}
|
|
8285
|
-
|
|
8441
|
+
const err = {
|
|
8442
|
+
code: "NOT_IMPLEMENTED",
|
|
8443
|
+
message: "OAuth account linking from a logged-in session is not yet supported. Use the standard OAuth sign-in flow instead."
|
|
8444
|
+
};
|
|
8445
|
+
setError(err);
|
|
8446
|
+
throw err;
|
|
8286
8447
|
},
|
|
8287
|
-
[
|
|
8448
|
+
[user, setError]
|
|
8288
8449
|
);
|
|
8289
8450
|
const unlinkAccount = useCallback(
|
|
8290
8451
|
async (provider) => {
|
|
8291
8452
|
setError(null);
|
|
8292
8453
|
try {
|
|
8293
|
-
await client.delete(`/v1/auth/oauth/
|
|
8454
|
+
await client.delete(`/v1/auth/oauth/providers/${encodeURIComponent(provider)}`);
|
|
8294
8455
|
} catch (err) {
|
|
8295
8456
|
if (err instanceof ScaleMuleApiError) {
|
|
8296
8457
|
setError(err);
|
|
@@ -10900,6 +11061,75 @@ function useFeedback(options = {}) {
|
|
|
10900
11061
|
);
|
|
10901
11062
|
return { items, loading, error, submit, refresh };
|
|
10902
11063
|
}
|
|
11064
|
+
var ZERO = { value: 0, up_count: 0, down_count: 0, score: 0 };
|
|
11065
|
+
function useVote({
|
|
11066
|
+
targetType,
|
|
11067
|
+
targetId,
|
|
11068
|
+
initialState,
|
|
11069
|
+
refetchOnMount = false,
|
|
11070
|
+
enabled = true
|
|
11071
|
+
}) {
|
|
11072
|
+
const { client } = useScaleMule();
|
|
11073
|
+
const [state, setState] = useState(initialState ?? ZERO);
|
|
11074
|
+
const [isLoading, setIsLoading] = useState(!initialState && enabled);
|
|
11075
|
+
const [error, setError] = useState(null);
|
|
11076
|
+
const inFlight = useRef(null);
|
|
11077
|
+
const path = `/v1/social/${encodeURIComponent(targetType)}/${encodeURIComponent(targetId)}/vote`;
|
|
11078
|
+
const refetch = useCallback(async () => {
|
|
11079
|
+
if (!enabled) return;
|
|
11080
|
+
setIsLoading(true);
|
|
11081
|
+
setError(null);
|
|
11082
|
+
try {
|
|
11083
|
+
const data = await client.get(path);
|
|
11084
|
+
setState(data);
|
|
11085
|
+
} catch (e) {
|
|
11086
|
+
setError(e);
|
|
11087
|
+
} finally {
|
|
11088
|
+
setIsLoading(false);
|
|
11089
|
+
}
|
|
11090
|
+
}, [client, path, enabled]);
|
|
11091
|
+
useEffect(() => {
|
|
11092
|
+
if (!enabled) return;
|
|
11093
|
+
if (initialState && !refetchOnMount) return;
|
|
11094
|
+
void refetch();
|
|
11095
|
+
}, [enabled, refetch, initialState, refetchOnMount]);
|
|
11096
|
+
const cast = useCallback(
|
|
11097
|
+
async (value) => {
|
|
11098
|
+
const prev = state;
|
|
11099
|
+
const optimistic = applyVote(prev, value);
|
|
11100
|
+
setState(optimistic);
|
|
11101
|
+
setError(null);
|
|
11102
|
+
const send = async () => {
|
|
11103
|
+
try {
|
|
11104
|
+
const data = await client.put(path, { value });
|
|
11105
|
+
setState(data);
|
|
11106
|
+
} catch (e) {
|
|
11107
|
+
setState(prev);
|
|
11108
|
+
setError(e);
|
|
11109
|
+
}
|
|
11110
|
+
};
|
|
11111
|
+
const p = inFlight.current ? inFlight.current.then(send) : send();
|
|
11112
|
+
inFlight.current = p;
|
|
11113
|
+
await p;
|
|
11114
|
+
if (inFlight.current === p) inFlight.current = null;
|
|
11115
|
+
},
|
|
11116
|
+
[client, path, state]
|
|
11117
|
+
);
|
|
11118
|
+
return { state, isLoading, error, cast, refetch };
|
|
11119
|
+
}
|
|
11120
|
+
function applyVote(prev, next) {
|
|
11121
|
+
let { up_count, down_count } = prev;
|
|
11122
|
+
if (prev.value === 1) up_count = Math.max(0, up_count - 1);
|
|
11123
|
+
if (prev.value === -1) down_count = Math.max(0, down_count - 1);
|
|
11124
|
+
if (next === 1) up_count += 1;
|
|
11125
|
+
if (next === -1) down_count += 1;
|
|
11126
|
+
return {
|
|
11127
|
+
value: next,
|
|
11128
|
+
up_count,
|
|
11129
|
+
down_count,
|
|
11130
|
+
score: up_count - down_count
|
|
11131
|
+
};
|
|
11132
|
+
}
|
|
10903
11133
|
var TYPE_LABELS = {
|
|
10904
11134
|
bug_report: "Bug",
|
|
10905
11135
|
feature_request: "Feature request",
|
|
@@ -11268,449 +11498,128 @@ function FeedbackWidget(props) {
|
|
|
11268
11498
|
) })
|
|
11269
11499
|
] });
|
|
11270
11500
|
}
|
|
11271
|
-
var
|
|
11272
|
-
var
|
|
11273
|
-
var
|
|
11501
|
+
var ARROW_UP = "\u25B2";
|
|
11502
|
+
var ARROW_DOWN = "\u25BC";
|
|
11503
|
+
var STYLES2 = {
|
|
11274
11504
|
root: {
|
|
11275
|
-
|
|
11276
|
-
border: "1px solid rgba(226, 232, 240, 0.8)",
|
|
11277
|
-
background: "linear-gradient(180deg, #f8fbff 0%, #edf4ff 100%)",
|
|
11278
|
-
padding: "1rem",
|
|
11279
|
-
color: "#0f172b",
|
|
11280
|
-
boxShadow: "0 22px 70px rgba(4, 12, 24, 0.28)"
|
|
11281
|
-
},
|
|
11282
|
-
layout: {
|
|
11283
|
-
display: "flex",
|
|
11284
|
-
flexWrap: "wrap",
|
|
11285
|
-
alignItems: "center",
|
|
11286
|
-
gap: "1rem"
|
|
11287
|
-
},
|
|
11288
|
-
playButton: {
|
|
11289
|
-
display: "flex",
|
|
11290
|
-
height: "4.5rem",
|
|
11291
|
-
width: "4.5rem",
|
|
11292
|
-
flexShrink: 0,
|
|
11505
|
+
display: "inline-flex",
|
|
11293
11506
|
alignItems: "center",
|
|
11294
|
-
|
|
11295
|
-
borderRadius: "9999px",
|
|
11296
|
-
border: "none",
|
|
11297
|
-
backgroundColor: "#020618",
|
|
11298
|
-
color: "#ffffff",
|
|
11299
|
-
boxShadow: "0 10px 28px rgba(15, 23, 42, 0.25)",
|
|
11300
|
-
cursor: "pointer"
|
|
11301
|
-
},
|
|
11302
|
-
playIcon: {
|
|
11303
|
-
display: "block",
|
|
11304
|
-
width: "1.75rem",
|
|
11305
|
-
height: "1.75rem",
|
|
11306
|
-
fill: "currentColor"
|
|
11307
|
-
},
|
|
11308
|
-
playIconOffset: {
|
|
11309
|
-
marginLeft: "0.25rem"
|
|
11310
|
-
},
|
|
11311
|
-
content: {
|
|
11312
|
-
minWidth: "16rem",
|
|
11313
|
-
flex: "1 1 18rem"
|
|
11507
|
+
gap: 6
|
|
11314
11508
|
},
|
|
11315
|
-
|
|
11316
|
-
display: "flex",
|
|
11317
|
-
|
|
11318
|
-
justifyContent: "space-between",
|
|
11319
|
-
gap: "0.75rem",
|
|
11320
|
-
fontSize: "0.8rem",
|
|
11321
|
-
fontWeight: 500,
|
|
11322
|
-
color: "#62748e"
|
|
11323
|
-
},
|
|
11324
|
-
metaRight: {
|
|
11325
|
-
display: "flex",
|
|
11509
|
+
rootStacked: {
|
|
11510
|
+
display: "inline-flex",
|
|
11511
|
+
flexDirection: "column",
|
|
11326
11512
|
alignItems: "center",
|
|
11327
|
-
gap:
|
|
11513
|
+
gap: 2
|
|
11328
11514
|
},
|
|
11329
|
-
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
fontSize: "0.65rem",
|
|
11334
|
-
fontWeight: 600,
|
|
11335
|
-
letterSpacing: "0.24em",
|
|
11336
|
-
textTransform: "uppercase",
|
|
11337
|
-
color: "#1447e6"
|
|
11338
|
-
},
|
|
11339
|
-
scrubber: {
|
|
11340
|
-
position: "relative",
|
|
11341
|
-
marginTop: "1rem",
|
|
11342
|
-
height: "3rem",
|
|
11515
|
+
button: {
|
|
11516
|
+
border: "1px solid rgba(255,255,255,0.12)",
|
|
11517
|
+
background: "rgba(255,255,255,0.04)",
|
|
11518
|
+
color: "inherit",
|
|
11343
11519
|
cursor: "pointer",
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
},
|
|
11349
|
-
waveform: {
|
|
11350
|
-
pointerEvents: "none",
|
|
11351
|
-
position: "absolute",
|
|
11352
|
-
inset: 0,
|
|
11353
|
-
height: "100%",
|
|
11354
|
-
width: "100%"
|
|
11355
|
-
},
|
|
11356
|
-
fallbackTrack: {
|
|
11357
|
-
position: "absolute",
|
|
11358
|
-
inset: 0,
|
|
11359
|
-
backgroundColor: "rgba(226, 232, 240, 0.9)"
|
|
11360
|
-
},
|
|
11361
|
-
fallbackProgress: {
|
|
11362
|
-
position: "absolute",
|
|
11363
|
-
insetBlock: 0,
|
|
11364
|
-
left: 0,
|
|
11365
|
-
backgroundColor: "#155dfc"
|
|
11520
|
+
borderRadius: 9999,
|
|
11521
|
+
padding: "6px 10px",
|
|
11522
|
+
lineHeight: 1,
|
|
11523
|
+
fontSize: 14
|
|
11366
11524
|
},
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
flexWrap: "wrap",
|
|
11371
|
-
alignItems: "center",
|
|
11372
|
-
gap: "0.5rem",
|
|
11373
|
-
fontSize: "0.72rem",
|
|
11374
|
-
fontWeight: 500,
|
|
11375
|
-
color: "#62748e"
|
|
11376
|
-
},
|
|
11377
|
-
chipStrong: {
|
|
11378
|
-
borderRadius: "9999px",
|
|
11379
|
-
border: "1px solid #e2e8f0",
|
|
11380
|
-
backgroundColor: "rgba(255, 255, 255, 0.85)",
|
|
11381
|
-
padding: "0.25rem 0.75rem",
|
|
11382
|
-
color: "#334155"
|
|
11383
|
-
},
|
|
11384
|
-
chipMuted: {
|
|
11385
|
-
borderRadius: "9999px",
|
|
11386
|
-
border: "1px solid #e2e8f0",
|
|
11387
|
-
backgroundColor: "rgba(255, 255, 255, 0.65)",
|
|
11388
|
-
padding: "0.25rem 0.75rem"
|
|
11389
|
-
},
|
|
11390
|
-
controls: {
|
|
11391
|
-
display: "flex",
|
|
11392
|
-
flexShrink: 0,
|
|
11393
|
-
alignItems: "center",
|
|
11394
|
-
gap: "0.5rem",
|
|
11395
|
-
alignSelf: "flex-start"
|
|
11525
|
+
buttonCompact: {
|
|
11526
|
+
padding: "3px 7px",
|
|
11527
|
+
fontSize: 12
|
|
11396
11528
|
},
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
padding: "0.5rem 1rem",
|
|
11402
|
-
fontSize: "1rem",
|
|
11403
|
-
fontWeight: 600,
|
|
11404
|
-
color: "#334155",
|
|
11405
|
-
boxShadow: "0 1px 3px rgba(15, 23, 42, 0.08)",
|
|
11406
|
-
cursor: "pointer"
|
|
11529
|
+
buttonActiveUp: {
|
|
11530
|
+
background: "rgba(34,197,94,0.18)",
|
|
11531
|
+
borderColor: "rgba(34,197,94,0.45)",
|
|
11532
|
+
color: "#86efac"
|
|
11407
11533
|
},
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
padding: "0.5rem 1rem",
|
|
11413
|
-
fontSize: "0.875rem",
|
|
11414
|
-
fontWeight: 600,
|
|
11415
|
-
color: "#334155",
|
|
11416
|
-
cursor: "pointer"
|
|
11534
|
+
buttonActiveDown: {
|
|
11535
|
+
background: "rgba(239,68,68,0.18)",
|
|
11536
|
+
borderColor: "rgba(239,68,68,0.45)",
|
|
11537
|
+
color: "#fca5a5"
|
|
11417
11538
|
},
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11539
|
+
score: {
|
|
11540
|
+
minWidth: 24,
|
|
11541
|
+
textAlign: "center",
|
|
11542
|
+
fontVariantNumeric: "tabular-nums",
|
|
11543
|
+
fontWeight: 600
|
|
11421
11544
|
}
|
|
11422
11545
|
};
|
|
11423
|
-
function
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
if (currentIndex === -1) {
|
|
11435
|
-
return SPEEDS[0];
|
|
11436
|
-
}
|
|
11437
|
-
return SPEEDS[(currentIndex + 1) % SPEEDS.length];
|
|
11438
|
-
}
|
|
11439
|
-
function NarrationPlayer({
|
|
11440
|
-
audio,
|
|
11441
|
-
className,
|
|
11442
|
-
providerLabel = "ScaleMule",
|
|
11443
|
-
narrationLabel = "AI-Narrated",
|
|
11444
|
-
refreshing = false,
|
|
11445
|
-
onRefresh,
|
|
11446
|
-
showRefreshButton = false,
|
|
11447
|
-
onPlaybackError
|
|
11546
|
+
function VoteButton({
|
|
11547
|
+
targetType,
|
|
11548
|
+
targetId,
|
|
11549
|
+
initialState,
|
|
11550
|
+
layout = "horizontal",
|
|
11551
|
+
size = "regular",
|
|
11552
|
+
onSignInRequired,
|
|
11553
|
+
onError,
|
|
11554
|
+
classNames,
|
|
11555
|
+
upLabel = "Upvote",
|
|
11556
|
+
downLabel = "Downvote"
|
|
11448
11557
|
}) {
|
|
11449
|
-
const
|
|
11450
|
-
const
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
const
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11460
|
-
return [];
|
|
11461
|
-
}
|
|
11462
|
-
const sampled = audio.waveform_peaks.filter((_, index) => index % 3 === 0).slice(0, 220);
|
|
11463
|
-
return sampled.length > 0 ? sampled : audio.waveform_peaks.slice(0, 220);
|
|
11464
|
-
}, [audio.waveform_peaks]);
|
|
11465
|
-
useEffect(() => {
|
|
11466
|
-
const element = audioRef.current;
|
|
11467
|
-
if (!element) return;
|
|
11468
|
-
recoveredUrlRef.current = null;
|
|
11469
|
-
const resumeTime = pendingResumeTimeRef.current;
|
|
11470
|
-
setCurrentTime(resumeTime ?? 0);
|
|
11471
|
-
setPlaying(false);
|
|
11472
|
-
element.pause();
|
|
11473
|
-
try {
|
|
11474
|
-
element.currentTime = resumeTime ?? 0;
|
|
11475
|
-
} catch {
|
|
11476
|
-
element.currentTime = 0;
|
|
11477
|
-
}
|
|
11478
|
-
if (pendingResumeRef.current) {
|
|
11479
|
-
pendingResumeRef.current = false;
|
|
11480
|
-
pendingResumeTimeRef.current = null;
|
|
11481
|
-
element.play().catch(() => {
|
|
11482
|
-
setPlaying(false);
|
|
11483
|
-
onPlaybackError?.();
|
|
11484
|
-
});
|
|
11485
|
-
return;
|
|
11486
|
-
}
|
|
11487
|
-
pendingResumeTimeRef.current = null;
|
|
11488
|
-
}, [audio.url]);
|
|
11489
|
-
useEffect(() => {
|
|
11490
|
-
const element = audioRef.current;
|
|
11491
|
-
if (!element) return;
|
|
11492
|
-
element.playbackRate = speed;
|
|
11493
|
-
element.preservesPitch = true;
|
|
11494
|
-
}, [speed]);
|
|
11495
|
-
function isUrlExpiringSoon() {
|
|
11496
|
-
if (!audio.expires_at) {
|
|
11497
|
-
return false;
|
|
11498
|
-
}
|
|
11499
|
-
const expiresAtMs = Date.parse(audio.expires_at);
|
|
11500
|
-
if (!Number.isFinite(expiresAtMs)) {
|
|
11501
|
-
return false;
|
|
11502
|
-
}
|
|
11503
|
-
return expiresAtMs - Date.now() <= EXPIRY_REFRESH_WINDOW_MS;
|
|
11504
|
-
}
|
|
11505
|
-
async function refreshAndResume() {
|
|
11506
|
-
if (!onRefresh || refreshing) {
|
|
11507
|
-
return false;
|
|
11508
|
-
}
|
|
11509
|
-
if (recoveredUrlRef.current === (audio.url ?? null)) {
|
|
11510
|
-
return false;
|
|
11511
|
-
}
|
|
11512
|
-
recoveredUrlRef.current = audio.url ?? null;
|
|
11513
|
-
pendingResumeRef.current = true;
|
|
11514
|
-
pendingResumeTimeRef.current = currentTime;
|
|
11515
|
-
try {
|
|
11516
|
-
await Promise.resolve(onRefresh());
|
|
11517
|
-
return true;
|
|
11518
|
-
} catch {
|
|
11519
|
-
pendingResumeRef.current = false;
|
|
11520
|
-
pendingResumeTimeRef.current = null;
|
|
11521
|
-
onPlaybackError?.();
|
|
11522
|
-
return false;
|
|
11523
|
-
}
|
|
11524
|
-
}
|
|
11525
|
-
function togglePlayback() {
|
|
11526
|
-
const element = audioRef.current;
|
|
11527
|
-
if (!element) return;
|
|
11528
|
-
if (element.paused) {
|
|
11529
|
-
if (refreshing) {
|
|
11530
|
-
pendingResumeRef.current = true;
|
|
11531
|
-
pendingResumeTimeRef.current = currentTime;
|
|
11558
|
+
const { isAuthenticated } = useAuth();
|
|
11559
|
+
const { state, cast, error } = useVote({
|
|
11560
|
+
targetType,
|
|
11561
|
+
targetId,
|
|
11562
|
+
initialState: initialState ?? null,
|
|
11563
|
+
enabled: isAuthenticated
|
|
11564
|
+
});
|
|
11565
|
+
const handleVote = useCallback(
|
|
11566
|
+
async (next) => {
|
|
11567
|
+
if (!isAuthenticated) {
|
|
11568
|
+
onSignInRequired?.();
|
|
11532
11569
|
return;
|
|
11533
11570
|
}
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11571
|
+
const desired = state.value === next ? 0 : next;
|
|
11572
|
+
try {
|
|
11573
|
+
await cast(desired);
|
|
11574
|
+
} catch (e) {
|
|
11575
|
+
onError?.(e);
|
|
11537
11576
|
}
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11577
|
+
},
|
|
11578
|
+
[cast, isAuthenticated, onSignInRequired, onError, state.value]
|
|
11579
|
+
);
|
|
11580
|
+
useEffect(() => {
|
|
11581
|
+
if (error) onError?.(error);
|
|
11582
|
+
}, [error, onError]);
|
|
11583
|
+
const compactStyle = size === "compact" ? STYLES2.buttonCompact : {};
|
|
11584
|
+
const upActive = state.value === 1;
|
|
11585
|
+
const downActive = state.value === -1;
|
|
11586
|
+
const upBtn = /* @__PURE__ */ jsx(
|
|
11587
|
+
"button",
|
|
11588
|
+
{
|
|
11589
|
+
type: "button",
|
|
11590
|
+
"aria-label": upLabel,
|
|
11591
|
+
"aria-pressed": upActive,
|
|
11592
|
+
title: isAuthenticated ? upLabel : "Sign in to vote",
|
|
11593
|
+
className: [classNames?.upButton, upActive ? classNames?.upButtonActive : void 0].filter(Boolean).join(" ") || void 0,
|
|
11594
|
+
onClick: () => void handleVote(1),
|
|
11595
|
+
style: classNames?.upButton ? void 0 : { ...STYLES2.button, ...compactStyle, ...upActive ? STYLES2.buttonActiveUp : {} },
|
|
11596
|
+
children: ARROW_UP
|
|
11543
11597
|
}
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
}
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
src: audio.url ?? void 0,
|
|
11570
|
-
preload: "metadata",
|
|
11571
|
-
onLoadedMetadata: (event) => {
|
|
11572
|
-
setDuration(event.currentTarget.duration || 0);
|
|
11573
|
-
},
|
|
11574
|
-
onTimeUpdate: (event) => {
|
|
11575
|
-
setCurrentTime(event.currentTarget.currentTime);
|
|
11576
|
-
},
|
|
11577
|
-
onPlay: () => setPlaying(true),
|
|
11578
|
-
onPause: () => setPlaying(false),
|
|
11579
|
-
onEnded: () => setPlaying(false),
|
|
11580
|
-
onError: () => {
|
|
11581
|
-
if (onRefresh) {
|
|
11582
|
-
void refreshAndResume().then((didRefresh) => {
|
|
11583
|
-
if (!didRefresh) {
|
|
11584
|
-
onPlaybackError?.();
|
|
11585
|
-
}
|
|
11586
|
-
});
|
|
11587
|
-
return;
|
|
11588
|
-
}
|
|
11589
|
-
onPlaybackError?.();
|
|
11590
|
-
}
|
|
11591
|
-
}
|
|
11592
|
-
),
|
|
11593
|
-
/* @__PURE__ */ jsxs("div", { style: styles.layout, children: [
|
|
11594
|
-
/* @__PURE__ */ jsx(
|
|
11595
|
-
"button",
|
|
11596
|
-
{
|
|
11597
|
-
type: "button",
|
|
11598
|
-
onClick: togglePlayback,
|
|
11599
|
-
"aria-label": playing ? "Pause narration" : "Play narration",
|
|
11600
|
-
style: styles.playButton,
|
|
11601
|
-
children: playing ? /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", style: styles.playIcon, "aria-hidden": "true", children: [
|
|
11602
|
-
/* @__PURE__ */ jsx("rect", { x: "6", y: "5", width: "4", height: "14", rx: "1.2" }),
|
|
11603
|
-
/* @__PURE__ */ jsx("rect", { x: "14", y: "5", width: "4", height: "14", rx: "1.2" })
|
|
11604
|
-
] }) : /* @__PURE__ */ jsx(
|
|
11605
|
-
"svg",
|
|
11606
|
-
{
|
|
11607
|
-
viewBox: "0 0 24 24",
|
|
11608
|
-
style: { ...styles.playIcon, ...styles.playIconOffset },
|
|
11609
|
-
"aria-hidden": "true",
|
|
11610
|
-
children: /* @__PURE__ */ jsx("path", { d: "M7 5.2c0-1.02 1.12-1.65 2-.98l10.2 7.78a1.24 1.24 0 0 1 0 1.98L9 21.76c-.88.67-2-.04-2-1.08V5.2Z" })
|
|
11611
|
-
}
|
|
11612
|
-
)
|
|
11613
|
-
}
|
|
11614
|
-
),
|
|
11615
|
-
/* @__PURE__ */ jsxs("div", { style: styles.content, children: [
|
|
11616
|
-
/* @__PURE__ */ jsxs("div", { style: styles.metaRow, children: [
|
|
11617
|
-
/* @__PURE__ */ jsx("span", { children: formatTime(currentTime / speed) }),
|
|
11618
|
-
/* @__PURE__ */ jsxs("div", { style: styles.metaRight, children: [
|
|
11619
|
-
/* @__PURE__ */ jsx("span", { style: styles.badge, children: narrationLabel }),
|
|
11620
|
-
/* @__PURE__ */ jsx("span", { children: formatTime(duration / speed) })
|
|
11621
|
-
] })
|
|
11622
|
-
] }),
|
|
11623
|
-
/* @__PURE__ */ jsx(
|
|
11624
|
-
"div",
|
|
11625
|
-
{
|
|
11626
|
-
ref: scrubRef,
|
|
11627
|
-
role: "slider",
|
|
11628
|
-
"aria-label": "Narration progress",
|
|
11629
|
-
"aria-valuemin": 0,
|
|
11630
|
-
"aria-valuemax": Math.max(1, Math.floor(duration)),
|
|
11631
|
-
"aria-valuenow": Math.floor(currentTime),
|
|
11632
|
-
tabIndex: 0,
|
|
11633
|
-
onClick: (event) => {
|
|
11634
|
-
seekTo(event.clientX);
|
|
11635
|
-
},
|
|
11636
|
-
style: styles.scrubber,
|
|
11637
|
-
children: peaks.length > 0 ? /* @__PURE__ */ jsx(
|
|
11638
|
-
"svg",
|
|
11639
|
-
{
|
|
11640
|
-
viewBox: `0 0 ${peaks.length} 40`,
|
|
11641
|
-
preserveAspectRatio: "none",
|
|
11642
|
-
style: styles.waveform,
|
|
11643
|
-
children: peaks.map((peak, index) => {
|
|
11644
|
-
const height = Math.max(2, Math.round(Math.abs(peak) * 34));
|
|
11645
|
-
const y = (40 - height) / 2;
|
|
11646
|
-
const filled = index / peaks.length < progress;
|
|
11647
|
-
return /* @__PURE__ */ jsx(
|
|
11648
|
-
"rect",
|
|
11649
|
-
{
|
|
11650
|
-
x: index,
|
|
11651
|
-
y,
|
|
11652
|
-
width: 0.82,
|
|
11653
|
-
height,
|
|
11654
|
-
rx: 0.4,
|
|
11655
|
-
fill: filled ? "#155dfc" : "#90c5ff"
|
|
11656
|
-
},
|
|
11657
|
-
`${audio.id}-${index}`
|
|
11658
|
-
);
|
|
11659
|
-
})
|
|
11660
|
-
}
|
|
11661
|
-
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11662
|
-
/* @__PURE__ */ jsx("div", { style: styles.fallbackTrack }),
|
|
11663
|
-
/* @__PURE__ */ jsx(
|
|
11664
|
-
"div",
|
|
11665
|
-
{
|
|
11666
|
-
style: { ...styles.fallbackProgress, width: `${progress * 100}%` }
|
|
11667
|
-
}
|
|
11668
|
-
)
|
|
11669
|
-
] })
|
|
11670
|
-
}
|
|
11671
|
-
),
|
|
11672
|
-
/* @__PURE__ */ jsxs("div", { style: styles.chipsRow, children: [
|
|
11673
|
-
/* @__PURE__ */ jsxs("span", { style: styles.chipStrong, children: [
|
|
11674
|
-
"Provider: ",
|
|
11675
|
-
providerLabel
|
|
11676
|
-
] }),
|
|
11677
|
-
duration > 0 && /* @__PURE__ */ jsxs("span", { style: styles.chipMuted, children: [
|
|
11678
|
-
"Length ",
|
|
11679
|
-
formatTime(duration / speed)
|
|
11680
|
-
] }),
|
|
11681
|
-
expiresLabel && /* @__PURE__ */ jsxs("span", { style: styles.chipMuted, children: [
|
|
11682
|
-
"Expires ",
|
|
11683
|
-
expiresLabel
|
|
11684
|
-
] })
|
|
11685
|
-
] })
|
|
11686
|
-
] }),
|
|
11687
|
-
/* @__PURE__ */ jsxs("div", { style: styles.controls, children: [
|
|
11688
|
-
/* @__PURE__ */ jsxs(
|
|
11689
|
-
"button",
|
|
11690
|
-
{
|
|
11691
|
-
type: "button",
|
|
11692
|
-
onClick: () => {
|
|
11693
|
-
setSpeed((currentSpeed) => getNextSpeed(currentSpeed));
|
|
11694
|
-
},
|
|
11695
|
-
style: styles.secondaryButton,
|
|
11696
|
-
children: [
|
|
11697
|
-
speed,
|
|
11698
|
-
"\xD7"
|
|
11699
|
-
]
|
|
11700
|
-
}
|
|
11701
|
-
),
|
|
11702
|
-
onRefresh && showRefreshButton && /* @__PURE__ */ jsx(
|
|
11703
|
-
"button",
|
|
11704
|
-
{
|
|
11705
|
-
type: "button",
|
|
11706
|
-
onClick: onRefresh,
|
|
11707
|
-
disabled: refreshing,
|
|
11708
|
-
style: refreshing ? { ...styles.refreshButton, ...styles.disabled } : styles.refreshButton,
|
|
11709
|
-
children: refreshing ? "Refreshing\u2026" : "Refresh"
|
|
11710
|
-
}
|
|
11711
|
-
)
|
|
11712
|
-
] })
|
|
11713
|
-
] })
|
|
11598
|
+
);
|
|
11599
|
+
const downBtn = /* @__PURE__ */ jsx(
|
|
11600
|
+
"button",
|
|
11601
|
+
{
|
|
11602
|
+
type: "button",
|
|
11603
|
+
"aria-label": downLabel,
|
|
11604
|
+
"aria-pressed": downActive,
|
|
11605
|
+
title: isAuthenticated ? downLabel : "Sign in to vote",
|
|
11606
|
+
className: [classNames?.downButton, downActive ? classNames?.downButtonActive : void 0].filter(Boolean).join(" ") || void 0,
|
|
11607
|
+
onClick: () => void handleVote(-1),
|
|
11608
|
+
style: classNames?.downButton ? void 0 : { ...STYLES2.button, ...compactStyle, ...downActive ? STYLES2.buttonActiveDown : {} },
|
|
11609
|
+
children: ARROW_DOWN
|
|
11610
|
+
}
|
|
11611
|
+
);
|
|
11612
|
+
const scoreClass = [
|
|
11613
|
+
classNames?.score,
|
|
11614
|
+
state.score > 0 ? classNames?.scorePositive : void 0,
|
|
11615
|
+
state.score < 0 ? classNames?.scoreNegative : void 0
|
|
11616
|
+
].filter(Boolean).join(" ") || void 0;
|
|
11617
|
+
const scoreEl = /* @__PURE__ */ jsx("span", { className: scoreClass, style: classNames?.score ? void 0 : STYLES2.score, children: state.score });
|
|
11618
|
+
const rootStyle = layout === "stacked" ? STYLES2.rootStacked : STYLES2.root;
|
|
11619
|
+
return /* @__PURE__ */ jsxs("div", { className: classNames?.root, style: classNames?.root ? void 0 : rootStyle, children: [
|
|
11620
|
+
upBtn,
|
|
11621
|
+
scoreEl,
|
|
11622
|
+
downBtn
|
|
11714
11623
|
] });
|
|
11715
11624
|
}
|
|
11716
11625
|
|
|
@@ -12005,4 +11914,4 @@ function createSafeLogger(prefix) {
|
|
|
12005
11914
|
};
|
|
12006
11915
|
}
|
|
12007
11916
|
|
|
12008
|
-
export { FeedbackWidget,
|
|
11917
|
+
export { FeedbackWidget, ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleMedia, ScaleMuleProvider, VoteButton, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAudio, useAuth, useBilling, useContent, useFeatureFlags, useFeedback, useFileStatus, useMedia, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useTtsJob, useUser, useVote, validateForm, validators };
|