@scalemule/nextjs 0.0.38 → 0.0.40

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.mjs CHANGED
@@ -1,4 +1,6 @@
1
1
  import { createContext, useState, useMemo, useEffect, useCallback, useContext, useRef } from 'react';
2
+ import { createMoneyClient } from '@scalemule/money';
3
+ export { MoneyClient, createMoneyClient } from '@scalemule/money';
2
4
  import { jsx } from 'react/jsx-runtime';
3
5
 
4
6
  var __defProp = Object.defineProperty;
@@ -3215,29 +3217,10 @@ var RealtimeService = class extends ServiceModule {
3215
3217
  // --------------------------------------------------------------------------
3216
3218
  connect() {
3217
3219
  if (this._status === "connecting" || this._status === "connected") return;
3218
- this.setStatus(this.reconnectAttempt > 0 ? "reconnecting" : "connecting");
3219
- this.fetchTicketAndConnect();
3220
- }
3221
- async fetchTicketAndConnect() {
3222
3220
  const baseUrl = this.client.getBaseUrl();
3221
+ const wsUrl = baseUrl.replace(/^http/, "ws") + "/v1/realtime/ws";
3222
+ this.setStatus(this.reconnectAttempt > 0 ? "reconnecting" : "connecting");
3223
3223
  try {
3224
- const headers = { "Content-Type": "application/json" };
3225
- const apiKey = this.client.getApiKey();
3226
- if (apiKey) headers["x-api-key"] = apiKey;
3227
- const token = this.client.getSessionToken();
3228
- if (token) headers["Authorization"] = `Bearer ${token}`;
3229
- const ticketRes = await fetch(`${baseUrl}/v1/realtime/ws/ticket`, {
3230
- method: "POST",
3231
- headers
3232
- });
3233
- let wsUrl;
3234
- if (ticketRes.ok) {
3235
- const ticketData = await ticketRes.json();
3236
- const ticket = ticketData.ticket;
3237
- wsUrl = baseUrl.replace(/^http/, "ws") + `/v1/realtime/ws?ticket=${encodeURIComponent(ticket)}`;
3238
- } else {
3239
- wsUrl = baseUrl.replace(/^http/, "ws") + "/v1/realtime/ws";
3240
- }
3241
3224
  this.ws = new WebSocket(wsUrl);
3242
3225
  } catch {
3243
3226
  this.scheduleReconnect();
@@ -6933,6 +6916,8 @@ function ScaleMuleProvider({
6933
6916
  analyticsProxyUrl,
6934
6917
  authProxyUrl,
6935
6918
  publishableKey,
6919
+ enableAccountSwitcher,
6920
+ accountSwitcherPrivacy,
6936
6921
  children,
6937
6922
  onLogin,
6938
6923
  onLogout,
@@ -6942,20 +6927,30 @@ function ScaleMuleProvider({
6942
6927
  const [user, setUser] = useState(null);
6943
6928
  const [initializing, setInitializing] = useState(true);
6944
6929
  const [error, setError] = useState(null);
6930
+ const resolvedGatewayUrl = gatewayUrl || (environment === "dev" ? "https://api-dev.scalemule.com" : "https://api.scalemule.com");
6945
6931
  const client = useMemo(
6946
6932
  () => createClient({
6947
6933
  apiKey,
6948
6934
  applicationId,
6949
6935
  environment,
6950
- gatewayUrl,
6936
+ gatewayUrl: resolvedGatewayUrl,
6951
6937
  debug,
6952
6938
  storage,
6953
6939
  pendingSessionInit: !!authProxyUrl
6954
6940
  }),
6955
- [apiKey, applicationId, environment, gatewayUrl, debug, storage, authProxyUrl]
6941
+ [apiKey, applicationId, environment, resolvedGatewayUrl, debug, storage, authProxyUrl]
6942
+ );
6943
+ const money = useMemo(
6944
+ () => createMoneyClient({
6945
+ apiKey,
6946
+ gatewayUrl: resolvedGatewayUrl,
6947
+ environment,
6948
+ accessToken: client.getSessionToken() || void 0,
6949
+ fetch: globalThis.fetch.bind(globalThis)
6950
+ }),
6951
+ [apiKey, resolvedGatewayUrl, environment, client]
6956
6952
  );
6957
6953
  const baseClient = useMemo(() => {
6958
- const resolvedGatewayUrl = gatewayUrl || (environment === "dev" ? "https://api-dev.scalemule.com" : "https://api.scalemule.com");
6959
6954
  return new ScaleMule({
6960
6955
  apiKey,
6961
6956
  applicationId,
@@ -6963,15 +6958,17 @@ function ScaleMuleProvider({
6963
6958
  environment,
6964
6959
  debug
6965
6960
  });
6966
- }, [apiKey, applicationId, environment, gatewayUrl, debug]);
6961
+ }, [apiKey, applicationId, environment, resolvedGatewayUrl, debug]);
6967
6962
  useEffect(() => {
6968
6963
  const token = client.getSessionToken();
6969
6964
  if (token) {
6970
6965
  baseClient.setAccessToken(token);
6966
+ money.setAccessToken(token);
6971
6967
  } else {
6972
6968
  baseClient.clearAccessToken();
6969
+ money.setAccessToken(void 0);
6973
6970
  }
6974
- }, [client, baseClient, user]);
6971
+ }, [client, baseClient, money, user]);
6975
6972
  useEffect(() => {
6976
6973
  let mounted = true;
6977
6974
  async function initialize() {
@@ -7059,6 +7056,7 @@ function ScaleMuleProvider({
7059
7056
  const value = useMemo(
7060
7057
  () => ({
7061
7058
  client,
7059
+ money,
7062
7060
  realtime: baseClient.realtime,
7063
7061
  user,
7064
7062
  setUser: handleSetUser,
@@ -7068,11 +7066,13 @@ function ScaleMuleProvider({
7068
7066
  analyticsProxyUrl,
7069
7067
  authProxyUrl,
7070
7068
  publishableKey,
7071
- gatewayUrl: gatewayUrl || (environment === "dev" ? "https://api-dev.scalemule.com" : "https://api.scalemule.com"),
7069
+ gatewayUrl: resolvedGatewayUrl,
7072
7070
  environment: environment || void 0,
7071
+ enableAccountSwitcher,
7072
+ accountSwitcherPrivacy,
7073
7073
  bootstrapFlags
7074
7074
  }),
7075
- [client, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, gatewayUrl, environment, bootstrapFlags]
7075
+ [client, money, baseClient, user, handleSetUser, initializing, error, analyticsProxyUrl, authProxyUrl, publishableKey, resolvedGatewayUrl, environment, enableAccountSwitcher, accountSwitcherPrivacy, bootstrapFlags]
7076
7076
  );
7077
7077
  return /* @__PURE__ */ jsx(ScaleMuleContext.Provider, { value, children });
7078
7078
  }
@@ -7089,6 +7089,45 @@ function useScaleMuleClient() {
7089
7089
  const { client } = useScaleMule();
7090
7090
  return client;
7091
7091
  }
7092
+ function useMoneyClient() {
7093
+ const { money } = useScaleMule();
7094
+ return money;
7095
+ }
7096
+ function maskEmail2(email) {
7097
+ const [local, domain] = email.split("@");
7098
+ if (!domain) return "***@***.***";
7099
+ const tldDot = domain.lastIndexOf(".");
7100
+ const tld = tldDot > 0 ? domain.slice(tldDot) : "";
7101
+ const domainBase = tldDot > 0 ? domain.slice(0, tldDot) : domain;
7102
+ return `${local[0] || "*"}***@${domainBase[0] || "*"}***${tld}`;
7103
+ }
7104
+ function stableColorIndex2(userId) {
7105
+ let hash = 0;
7106
+ for (let i = 0; i < userId.length; i++) {
7107
+ hash = (hash << 5) - hash + userId.charCodeAt(i) | 0;
7108
+ }
7109
+ return Math.abs(hash) % 8;
7110
+ }
7111
+ function applyClientPrivacy(entry, privacy) {
7112
+ if (!privacy || privacy === "full") return entry;
7113
+ if (privacy === "masked") {
7114
+ return {
7115
+ userId: entry.userId,
7116
+ email: entry.email ? maskEmail2(entry.email) : void 0,
7117
+ fullName: entry.fullName ? `${entry.fullName[0].toUpperCase()}.` : void 0,
7118
+ provider: entry.provider,
7119
+ lastActiveAt: entry.lastActiveAt,
7120
+ colorIndex: stableColorIndex2(entry.userId)
7121
+ };
7122
+ }
7123
+ return {
7124
+ userId: entry.userId,
7125
+ provider: entry.provider,
7126
+ lastActiveAt: entry.lastActiveAt,
7127
+ displayLabel: "Account",
7128
+ colorIndex: stableColorIndex2(entry.userId)
7129
+ };
7130
+ }
7092
7131
  function getCookie(name) {
7093
7132
  if (typeof document === "undefined") return void 0;
7094
7133
  const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
@@ -7117,7 +7156,7 @@ async function proxyFetch(proxyUrl, path, options = {}) {
7117
7156
  return data;
7118
7157
  }
7119
7158
  function useAuth() {
7120
- const { client, user, setUser, initializing, error, setError, authProxyUrl } = useScaleMule();
7159
+ const { client, user, setUser, initializing, error, setError, authProxyUrl, enableAccountSwitcher, accountSwitcherPrivacy } = useScaleMule();
7121
7160
  const register = useCallback(
7122
7161
  async (data) => {
7123
7162
  setError(null);
@@ -7725,6 +7764,63 @@ function useAuth() {
7725
7764
  },
7726
7765
  [client, setUser, setError, authProxyUrl]
7727
7766
  );
7767
+ const readKnownAccountsCookie = useCallback(() => {
7768
+ if (!enableAccountSwitcher) return [];
7769
+ if (typeof document === "undefined") return [];
7770
+ const match = document.cookie.match(/(?:^|; )sm_known_accounts=([^;]*)/);
7771
+ if (!match) return [];
7772
+ try {
7773
+ const decoded = decodeURIComponent(match[1]);
7774
+ const accounts = JSON.parse(decoded);
7775
+ let entries = Object.values(accounts);
7776
+ if (accountSwitcherPrivacy && accountSwitcherPrivacy !== "full") {
7777
+ entries = entries.map((e) => applyClientPrivacy(e, accountSwitcherPrivacy));
7778
+ }
7779
+ return entries;
7780
+ } catch {
7781
+ return [];
7782
+ }
7783
+ }, [enableAccountSwitcher, accountSwitcherPrivacy]);
7784
+ const [knownAccounts, setKnownAccounts] = useState([]);
7785
+ useEffect(() => {
7786
+ setKnownAccounts(readKnownAccountsCookie());
7787
+ }, [readKnownAccountsCookie, user]);
7788
+ const switchAccount = useCallback(
7789
+ async (userId) => {
7790
+ const target = knownAccounts.find((a) => a.userId === userId) || null;
7791
+ if (!target) return null;
7792
+ if (authProxyUrl) {
7793
+ await proxyFetch(authProxyUrl, "switch-account");
7794
+ } else {
7795
+ const sessionToken = client.getSessionToken();
7796
+ if (sessionToken) {
7797
+ try {
7798
+ await client.post("/v1/auth/logout", { session_token: sessionToken });
7799
+ } catch {
7800
+ }
7801
+ }
7802
+ await client.clearSession();
7803
+ }
7804
+ setUser(null);
7805
+ return target;
7806
+ },
7807
+ [client, setUser, knownAccounts, authProxyUrl]
7808
+ );
7809
+ const removeKnownAccount = useCallback(
7810
+ async (userId) => {
7811
+ if (authProxyUrl) {
7812
+ await proxyFetch(authProxyUrl, "forget-account", { body: { user_id: userId } });
7813
+ }
7814
+ setKnownAccounts((prev) => prev.filter((a) => a.userId !== userId));
7815
+ },
7816
+ [authProxyUrl]
7817
+ );
7818
+ const clearKnownAccounts = useCallback(async () => {
7819
+ if (authProxyUrl) {
7820
+ await proxyFetch(authProxyUrl, "forget-all-accounts");
7821
+ }
7822
+ setKnownAccounts([]);
7823
+ }, [authProxyUrl]);
7728
7824
  return useMemo(
7729
7825
  () => ({
7730
7826
  user,
@@ -7756,7 +7852,12 @@ function useAuth() {
7756
7852
  // Phone auth
7757
7853
  sendPhoneCode,
7758
7854
  verifyPhone,
7759
- loginWithPhone
7855
+ loginWithPhone,
7856
+ // Account switcher
7857
+ knownAccounts,
7858
+ switchAccount,
7859
+ removeKnownAccount,
7860
+ clearKnownAccounts
7760
7861
  }),
7761
7862
  [
7762
7863
  user,
@@ -7783,10 +7884,20 @@ function useAuth() {
7783
7884
  regenerateBackupCodes,
7784
7885
  sendPhoneCode,
7785
7886
  verifyPhone,
7786
- loginWithPhone
7887
+ loginWithPhone,
7888
+ knownAccounts,
7889
+ switchAccount,
7890
+ removeKnownAccount,
7891
+ clearKnownAccounts
7787
7892
  ]
7788
7893
  );
7789
7894
  }
7895
+ function retiredBillingRouteError(route) {
7896
+ return {
7897
+ code: "MONEY_BILLING_ROUTE_RETIRED",
7898
+ message: `${route} was retired after the money-services cutover. Use @scalemule/money for subscriptions, pricing, and asset operations.`
7899
+ };
7900
+ }
7790
7901
  function useBilling() {
7791
7902
  const { client } = useScaleMule();
7792
7903
  const [loading, setLoading] = useState(false);
@@ -7796,7 +7907,7 @@ function useBilling() {
7796
7907
  setError(null);
7797
7908
  setLoading(true);
7798
7909
  try {
7799
- return await client.post("/v1/billing/connected-accounts", data);
7910
+ return await client.post("/v1/money/billing/connected-accounts", data);
7800
7911
  } catch (err) {
7801
7912
  const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
7802
7913
  setError(apiError);
@@ -7811,7 +7922,7 @@ function useBilling() {
7811
7922
  setError(null);
7812
7923
  setLoading(true);
7813
7924
  try {
7814
- return await client.get("/v1/billing/connected-accounts/me");
7925
+ return await client.get("/v1/money/billing/connected-accounts/me");
7815
7926
  } catch (err) {
7816
7927
  const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
7817
7928
  setError(apiError);
@@ -7825,7 +7936,7 @@ function useBilling() {
7825
7936
  setError(null);
7826
7937
  setLoading(true);
7827
7938
  try {
7828
- return await client.get(`/v1/billing/connected-accounts/${id}`);
7939
+ return await client.get(`/v1/money/billing/connected-accounts/${id}`);
7829
7940
  } catch (err) {
7830
7941
  const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
7831
7942
  setError(apiError);
@@ -7842,7 +7953,7 @@ function useBilling() {
7842
7953
  setLoading(true);
7843
7954
  try {
7844
7955
  const result = await client.post(
7845
- `/v1/billing/connected-accounts/${id}/onboarding-link`,
7956
+ `/v1/money/billing/connected-accounts/${id}/onboarding-link`,
7846
7957
  data
7847
7958
  );
7848
7959
  return result.url;
@@ -7861,11 +7972,7 @@ function useBilling() {
7861
7972
  setError(null);
7862
7973
  setLoading(true);
7863
7974
  try {
7864
- return await client.get(
7865
- `/v1/billing/connected-accounts/${id}/balance`
7866
- );
7867
- } catch (err) {
7868
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
7975
+ const apiError = retiredBillingRouteError(`/v1/money/billing/connected-accounts/${id}/balance`);
7869
7976
  setError(apiError);
7870
7977
  return null;
7871
7978
  } finally {
@@ -7879,9 +7986,8 @@ function useBilling() {
7879
7986
  setError(null);
7880
7987
  setLoading(true);
7881
7988
  try {
7882
- return await client.post("/v1/billing/payments", data);
7883
- } catch (err) {
7884
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
7989
+ void data;
7990
+ const apiError = retiredBillingRouteError("/v1/money/billing/payments");
7885
7991
  setError(apiError);
7886
7992
  return null;
7887
7993
  } finally {
@@ -7895,9 +8001,7 @@ function useBilling() {
7895
8001
  setError(null);
7896
8002
  setLoading(true);
7897
8003
  try {
7898
- return await client.get(`/v1/billing/payments/${id}`);
7899
- } catch (err) {
7900
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
8004
+ const apiError = retiredBillingRouteError(`/v1/money/billing/payments/${id}`);
7901
8005
  setError(apiError);
7902
8006
  return null;
7903
8007
  } finally {
@@ -7911,10 +8015,8 @@ function useBilling() {
7911
8015
  setError(null);
7912
8016
  setLoading(true);
7913
8017
  try {
7914
- const query = params ? "?" + Object.entries(params).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&") : "";
7915
- return await client.get(`/v1/billing/payments${query}`);
7916
- } catch (err) {
7917
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
8018
+ void params;
8019
+ const apiError = retiredBillingRouteError("/v1/money/billing/payments");
7918
8020
  setError(apiError);
7919
8021
  return [];
7920
8022
  } finally {
@@ -7928,9 +8030,8 @@ function useBilling() {
7928
8030
  setError(null);
7929
8031
  setLoading(true);
7930
8032
  try {
7931
- return await client.post(`/v1/billing/payments/${id}/refund`, data);
7932
- } catch (err) {
7933
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
8033
+ void data;
8034
+ const apiError = retiredBillingRouteError(`/v1/money/billing/payments/${id}/refund`);
7934
8035
  setError(apiError);
7935
8036
  return null;
7936
8037
  } finally {
@@ -7944,12 +8045,8 @@ function useBilling() {
7944
8045
  setError(null);
7945
8046
  setLoading(true);
7946
8047
  try {
7947
- const query = params ? "?" + Object.entries(params).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&") : "";
7948
- return await client.get(
7949
- `/v1/billing/connected-accounts/${accountId}/payouts${query}`
7950
- );
7951
- } catch (err) {
7952
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
8048
+ void params;
8049
+ const apiError = retiredBillingRouteError(`/v1/money/billing/connected-accounts/${accountId}/payouts`);
7953
8050
  setError(apiError);
7954
8051
  return [];
7955
8052
  } finally {
@@ -7964,7 +8061,7 @@ function useBilling() {
7964
8061
  setLoading(true);
7965
8062
  try {
7966
8063
  return await client.get(
7967
- `/v1/billing/connected-accounts/${accountId}/payout-schedule`
8064
+ `/v1/money/billing/connected-accounts/${accountId}/payout-schedule`
7968
8065
  );
7969
8066
  } catch (err) {
7970
8067
  const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
@@ -7982,7 +8079,7 @@ function useBilling() {
7982
8079
  setLoading(true);
7983
8080
  try {
7984
8081
  return await client.put(
7985
- `/v1/billing/connected-accounts/${accountId}/payout-schedule`,
8082
+ `/v1/money/billing/connected-accounts/${accountId}/payout-schedule`,
7986
8083
  data
7987
8084
  );
7988
8085
  } catch (err) {
@@ -8000,10 +8097,8 @@ function useBilling() {
8000
8097
  setError(null);
8001
8098
  setLoading(true);
8002
8099
  try {
8003
- const query = params ? "?" + Object.entries(params).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&") : "";
8004
- return await client.get(`/v1/billing/transactions${query}`);
8005
- } catch (err) {
8006
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
8100
+ void params;
8101
+ const apiError = retiredBillingRouteError("/v1/money/billing/transactions");
8007
8102
  setError(apiError);
8008
8103
  return [];
8009
8104
  } finally {
@@ -8017,12 +8112,8 @@ function useBilling() {
8017
8112
  setError(null);
8018
8113
  setLoading(true);
8019
8114
  try {
8020
- const query = params ? "?" + Object.entries(params).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&") : "";
8021
- return await client.get(
8022
- `/v1/billing/transactions/summary${query}`
8023
- );
8024
- } catch (err) {
8025
- const apiError = err instanceof ScaleMuleApiError ? err : { code: "UNKNOWN", message: err instanceof Error ? err.message : "Unknown error" };
8115
+ void params;
8116
+ const apiError = retiredBillingRouteError("/v1/money/billing/transactions/summary");
8026
8117
  setError(apiError);
8027
8118
  return null;
8028
8119
  } finally {
@@ -8037,7 +8128,7 @@ function useBilling() {
8037
8128
  setLoading(true);
8038
8129
  try {
8039
8130
  const result = await client.post(
8040
- "/v1/billing/setup-sessions",
8131
+ "/v1/money/billing/setup-sessions",
8041
8132
  data
8042
8133
  );
8043
8134
  return result.client_secret;
@@ -8279,6 +8370,9 @@ function useContent(options = {}) {
8279
8370
  ]
8280
8371
  );
8281
8372
  }
8373
+
8374
+ // src/hooks/useMoney.ts
8375
+ var useMoney = useMoneyClient;
8282
8376
  function useUser() {
8283
8377
  const { client, user, setUser, setError } = useScaleMule();
8284
8378
  const [loading, setLoading] = useState(false);
@@ -9634,4 +9728,4 @@ function createSafeLogger(prefix) {
9634
9728
  };
9635
9729
  }
9636
9730
 
9637
- export { ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };
9731
+ export { ScaleMuleApiError, ScaleMuleClient2 as ScaleMuleClient, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, useMoney, useMoneyClient, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useShare, useUser, validateForm, validators };