@scalemule/nextjs 0.0.27 → 0.0.29
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 +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/{index-DewTyMF2.d.mts → index-BoENfro3.d.mts} +1 -1
- package/dist/{index-DewTyMF2.d.ts → index-BoENfro3.d.ts} +1 -1
- package/dist/index.d.mts +33 -3
- package/dist/index.d.ts +33 -3
- package/dist/index.js +204 -16
- package/dist/index.mjs +204 -17
- package/dist/server/index.d.mts +46 -9
- package/dist/server/index.d.ts +46 -9
- package/dist/server/index.js +132 -0
- package/dist/server/index.mjs +132 -1
- 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-CQ2lZgy0.d.ts → webhook-handler-CjSSCdvI.d.ts} +2 -2
- package/dist/{webhook-handler-DS0r_w4M.d.mts → webhook-handler-Cz9jtet2.d.mts} +2 -2
- package/package.json +2 -2
package/dist/client.d.mts
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -842,4 +842,4 @@ interface UseBillingReturn {
|
|
|
842
842
|
}) => Promise<string | null>;
|
|
843
843
|
}
|
|
844
844
|
|
|
845
|
-
export { type
|
|
845
|
+
export { type ResetPasswordRequest as $, type ApiError as A, type BatchTrackRequest as B, type ChangeEmailRequest as C, type DeviceFingerprint as D, type EnhancedAnalyticsEvent as E, type ForgotPasswordRequest as F, type MFASetupRequest as G, type MFAStatus as H, type MFATOTPSetupResponse as I, type MFAVerifyRequest as J, type OAuthCallbackResponse as K, type LoginResponse as L, type MFAChallengeResponse as M, type OAuthConfig as N, type OAuthCallbackRequest as O, type OAuthProvider as P, type OAuthStartResponse as Q, type PageViewData as R, type ScaleMuleConfig as S, type PayoutSchedule as T, type User as U, type PhoneLoginRequest as V, type PhoneSendCodeRequest as W, type PhoneVerifyRequest as X, type Profile as Y, type RefreshResponse as Z, type RegisterRequest as _, type UseAuthReturn as a, ScaleMuleApiError as a0, type ScaleMuleEnvironment as a1, type Session as a2, type SignedUploadCompleteRequest as a3, type SignedUploadRequest as a4, type SignedUploadResponse as a5, type SignedUploadUrl as a6, type StorageAdapter as a7, type StorageFile as a8, type TrackEventResponse as a9, type TransactionSummary as aa, type UTMParams as ab, type UpdateProfileRequest as ac, type UploadOptions as ad, type UploadResponse as ae, type VerifyEmailRequest as af, type UseBillingReturn as b, type ListFilesParams as c, type UseContentReturn as d, type UseUserReturn as e, type UseAnalyticsOptions as f, type UseAnalyticsReturn as g, type AccountBalance as h, type AnalyticsEvent as i, type ApiResponse as j, type BillingPayment as k, type BillingPayout as l, type BillingRefund as m, type BillingTransaction as n, type ChangePasswordRequest as o, type ClientContext as p, type ConnectedAccount as q, type DeviceInfo as r, type LinkedAccount as s, type ListFilesResponse as t, type LoginDeviceInfo as u, type LoginRequest as v, type LoginResponseWithMFA as w, type LoginRiskInfo as x, type MFAMethod as y, type MFASMSSetupResponse as z };
|
|
@@ -842,4 +842,4 @@ interface UseBillingReturn {
|
|
|
842
842
|
}) => Promise<string | null>;
|
|
843
843
|
}
|
|
844
844
|
|
|
845
|
-
export { type
|
|
845
|
+
export { type ResetPasswordRequest as $, type ApiError as A, type BatchTrackRequest as B, type ChangeEmailRequest as C, type DeviceFingerprint as D, type EnhancedAnalyticsEvent as E, type ForgotPasswordRequest as F, type MFASetupRequest as G, type MFAStatus as H, type MFATOTPSetupResponse as I, type MFAVerifyRequest as J, type OAuthCallbackResponse as K, type LoginResponse as L, type MFAChallengeResponse as M, type OAuthConfig as N, type OAuthCallbackRequest as O, type OAuthProvider as P, type OAuthStartResponse as Q, type PageViewData as R, type ScaleMuleConfig as S, type PayoutSchedule as T, type User as U, type PhoneLoginRequest as V, type PhoneSendCodeRequest as W, type PhoneVerifyRequest as X, type Profile as Y, type RefreshResponse as Z, type RegisterRequest as _, type UseAuthReturn as a, ScaleMuleApiError as a0, type ScaleMuleEnvironment as a1, type Session as a2, type SignedUploadCompleteRequest as a3, type SignedUploadRequest as a4, type SignedUploadResponse as a5, type SignedUploadUrl as a6, type StorageAdapter as a7, type StorageFile as a8, type TrackEventResponse as a9, type TransactionSummary as aa, type UTMParams as ab, type UpdateProfileRequest as ac, type UploadOptions as ad, type UploadResponse as ae, type VerifyEmailRequest as af, type UseBillingReturn as b, type ListFilesParams as c, type UseContentReturn as d, type UseUserReturn as e, type UseAnalyticsOptions as f, type UseAnalyticsReturn as g, type AccountBalance as h, type AnalyticsEvent as i, type ApiResponse as j, type BillingPayment as k, type BillingPayout as l, type BillingRefund as m, type BillingTransaction as n, type ChangePasswordRequest as o, type ClientContext as p, type ConnectedAccount as q, type DeviceInfo as r, type LinkedAccount as s, type ListFilesResponse as t, type LoginDeviceInfo as u, type LoginRequest as v, type LoginResponseWithMFA as w, type LoginRiskInfo as x, type MFAMethod as y, type MFASMSSetupResponse as z };
|
package/dist/index.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { ScaleMuleClient } from './client.mjs';
|
|
4
4
|
export { ClientConfig, RequestOptions, createClient } from './client.mjs';
|
|
5
|
-
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-
|
|
6
|
-
export {
|
|
5
|
+
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-BoENfro3.mjs';
|
|
6
|
+
export { h as AccountBalance, i as AnalyticsEvent, j as ApiResponse, B as BatchTrackRequest, k as BillingPayment, l as BillingPayout, m as BillingRefund, n as BillingTransaction, C as ChangeEmailRequest, o as ChangePasswordRequest, p as ClientContext, q as ConnectedAccount, D as DeviceFingerprint, r as DeviceInfo, E as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, s as LinkedAccount, t as ListFilesResponse, u as LoginDeviceInfo, v as LoginRequest, w as LoginResponseWithMFA, x as LoginRiskInfo, M as MFAChallengeResponse, y as MFAMethod, z as MFASMSSetupResponse, G as MFASetupRequest, H as MFAStatus, I as MFATOTPSetupResponse, J as MFAVerifyRequest, O as OAuthCallbackRequest, K as OAuthCallbackResponse, N as OAuthConfig, P as OAuthProvider, Q as OAuthStartResponse, R as PageViewData, T as PayoutSchedule, V as PhoneLoginRequest, W as PhoneSendCodeRequest, X as PhoneVerifyRequest, Y as Profile, Z as RefreshResponse, _ as RegisterRequest, $ as ResetPasswordRequest, a0 as ScaleMuleApiError, a1 as ScaleMuleEnvironment, a2 as Session, a3 as SignedUploadCompleteRequest, a4 as SignedUploadRequest, a5 as SignedUploadResponse, a6 as SignedUploadUrl, a7 as StorageAdapter, a8 as StorageFile, a9 as TrackEventResponse, aa as TransactionSummary, ab as UTMParams, ac as UpdateProfileRequest, ad as UploadOptions, ae as UploadResponse, af as VerifyEmailRequest } from './index-BoENfro3.mjs';
|
|
7
7
|
|
|
8
8
|
interface ScaleMuleContextValue {
|
|
9
9
|
/** The API client instance */
|
|
@@ -289,6 +289,36 @@ interface UseFeatureFlagsReturn {
|
|
|
289
289
|
}
|
|
290
290
|
declare function useFeatureFlags(options?: UseFeatureFlagsOptions): UseFeatureFlagsReturn;
|
|
291
291
|
|
|
292
|
+
interface UsePushNotificationsOptions {
|
|
293
|
+
/** Service worker URL (default: '/sw.js') */
|
|
294
|
+
serviceWorkerUrl?: string;
|
|
295
|
+
/** Push proxy URL (default: '/api/push') */
|
|
296
|
+
pushProxyUrl?: string;
|
|
297
|
+
/** Called when a push notification is received while app is in foreground */
|
|
298
|
+
onNotification?: (data: unknown) => void;
|
|
299
|
+
}
|
|
300
|
+
interface UsePushNotificationsReturn {
|
|
301
|
+
/** Whether the browser supports Web Push */
|
|
302
|
+
isSupported: boolean;
|
|
303
|
+
/** Current notification permission state */
|
|
304
|
+
permission: NotificationPermission | 'unsupported';
|
|
305
|
+
/** Whether push is currently subscribed */
|
|
306
|
+
isSubscribed: boolean;
|
|
307
|
+
/** Whether an operation is in progress */
|
|
308
|
+
isLoading: boolean;
|
|
309
|
+
/** Last error */
|
|
310
|
+
error: ApiError | null;
|
|
311
|
+
/** Request permission and subscribe to push notifications */
|
|
312
|
+
subscribe: () => Promise<void>;
|
|
313
|
+
/** Unsubscribe from push notifications */
|
|
314
|
+
unsubscribe: () => Promise<void>;
|
|
315
|
+
/** Clear user association (call before logout) */
|
|
316
|
+
disassociateUser: () => Promise<void>;
|
|
317
|
+
/** The push token ID from backend registration */
|
|
318
|
+
tokenId: string | null;
|
|
319
|
+
}
|
|
320
|
+
declare function usePushNotifications(options?: UsePushNotificationsOptions): UsePushNotificationsReturn;
|
|
321
|
+
|
|
292
322
|
/**
|
|
293
323
|
* Client-side validation helpers
|
|
294
324
|
*
|
|
@@ -447,4 +477,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
447
477
|
error: (message: string, data?: unknown) => void;
|
|
448
478
|
};
|
|
449
479
|
|
|
450
|
-
export { ApiError, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, ListFilesParams, LoginResponse, 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 UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UseRealtimeOptions, type UseRealtimeReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, useRealtime, useScaleMule, useScaleMuleClient, useUser, validateForm, validators };
|
|
480
|
+
export { ApiError, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, ListFilesParams, LoginResponse, 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 UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UsePushNotificationsOptions, type UsePushNotificationsReturn, type UseRealtimeOptions, type UseRealtimeReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useUser, validateForm, validators };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { ScaleMuleClient } from './client.js';
|
|
4
4
|
export { ClientConfig, RequestOptions, createClient } from './client.js';
|
|
5
|
-
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-
|
|
6
|
-
export {
|
|
5
|
+
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-BoENfro3.js';
|
|
6
|
+
export { h as AccountBalance, i as AnalyticsEvent, j as ApiResponse, B as BatchTrackRequest, k as BillingPayment, l as BillingPayout, m as BillingRefund, n as BillingTransaction, C as ChangeEmailRequest, o as ChangePasswordRequest, p as ClientContext, q as ConnectedAccount, D as DeviceFingerprint, r as DeviceInfo, E as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, s as LinkedAccount, t as ListFilesResponse, u as LoginDeviceInfo, v as LoginRequest, w as LoginResponseWithMFA, x as LoginRiskInfo, M as MFAChallengeResponse, y as MFAMethod, z as MFASMSSetupResponse, G as MFASetupRequest, H as MFAStatus, I as MFATOTPSetupResponse, J as MFAVerifyRequest, O as OAuthCallbackRequest, K as OAuthCallbackResponse, N as OAuthConfig, P as OAuthProvider, Q as OAuthStartResponse, R as PageViewData, T as PayoutSchedule, V as PhoneLoginRequest, W as PhoneSendCodeRequest, X as PhoneVerifyRequest, Y as Profile, Z as RefreshResponse, _ as RegisterRequest, $ as ResetPasswordRequest, a0 as ScaleMuleApiError, a1 as ScaleMuleEnvironment, a2 as Session, a3 as SignedUploadCompleteRequest, a4 as SignedUploadRequest, a5 as SignedUploadResponse, a6 as SignedUploadUrl, a7 as StorageAdapter, a8 as StorageFile, a9 as TrackEventResponse, aa as TransactionSummary, ab as UTMParams, ac as UpdateProfileRequest, ad as UploadOptions, ae as UploadResponse, af as VerifyEmailRequest } from './index-BoENfro3.js';
|
|
7
7
|
|
|
8
8
|
interface ScaleMuleContextValue {
|
|
9
9
|
/** The API client instance */
|
|
@@ -289,6 +289,36 @@ interface UseFeatureFlagsReturn {
|
|
|
289
289
|
}
|
|
290
290
|
declare function useFeatureFlags(options?: UseFeatureFlagsOptions): UseFeatureFlagsReturn;
|
|
291
291
|
|
|
292
|
+
interface UsePushNotificationsOptions {
|
|
293
|
+
/** Service worker URL (default: '/sw.js') */
|
|
294
|
+
serviceWorkerUrl?: string;
|
|
295
|
+
/** Push proxy URL (default: '/api/push') */
|
|
296
|
+
pushProxyUrl?: string;
|
|
297
|
+
/** Called when a push notification is received while app is in foreground */
|
|
298
|
+
onNotification?: (data: unknown) => void;
|
|
299
|
+
}
|
|
300
|
+
interface UsePushNotificationsReturn {
|
|
301
|
+
/** Whether the browser supports Web Push */
|
|
302
|
+
isSupported: boolean;
|
|
303
|
+
/** Current notification permission state */
|
|
304
|
+
permission: NotificationPermission | 'unsupported';
|
|
305
|
+
/** Whether push is currently subscribed */
|
|
306
|
+
isSubscribed: boolean;
|
|
307
|
+
/** Whether an operation is in progress */
|
|
308
|
+
isLoading: boolean;
|
|
309
|
+
/** Last error */
|
|
310
|
+
error: ApiError | null;
|
|
311
|
+
/** Request permission and subscribe to push notifications */
|
|
312
|
+
subscribe: () => Promise<void>;
|
|
313
|
+
/** Unsubscribe from push notifications */
|
|
314
|
+
unsubscribe: () => Promise<void>;
|
|
315
|
+
/** Clear user association (call before logout) */
|
|
316
|
+
disassociateUser: () => Promise<void>;
|
|
317
|
+
/** The push token ID from backend registration */
|
|
318
|
+
tokenId: string | null;
|
|
319
|
+
}
|
|
320
|
+
declare function usePushNotifications(options?: UsePushNotificationsOptions): UsePushNotificationsReturn;
|
|
321
|
+
|
|
292
322
|
/**
|
|
293
323
|
* Client-side validation helpers
|
|
294
324
|
*
|
|
@@ -447,4 +477,4 @@ declare function createSafeLogger(prefix: string): {
|
|
|
447
477
|
error: (message: string, data?: unknown) => void;
|
|
448
478
|
};
|
|
449
479
|
|
|
450
|
-
export { ApiError, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, ListFilesParams, LoginResponse, 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 UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UseRealtimeOptions, type UseRealtimeReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, useRealtime, useScaleMule, useScaleMuleClient, useUser, validateForm, validators };
|
|
480
|
+
export { ApiError, type FeatureFlagEvaluation, type FeatureFlagEvaluation as FeatureFlagResult, ListFilesParams, LoginResponse, 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 UseFeatureFlagsOptions as UseFlagsOptions, type UseFeatureFlagsReturn as UseFlagsReturn, type UsePushNotificationsOptions, type UsePushNotificationsReturn, type UseRealtimeOptions, type UseRealtimeReturn, UseUserReturn, User, type UsernameValidationResult, composePhone, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useUser, validateForm, validators };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var sdk = require('@scalemule/sdk');
|
|
5
6
|
|
|
6
7
|
// src/provider.tsx
|
|
7
8
|
|
|
@@ -2726,14 +2727,22 @@ function useAnalytics(options = {}) {
|
|
|
2726
2727
|
const sendEvent = react.useCallback(
|
|
2727
2728
|
async (event) => {
|
|
2728
2729
|
const fullEvent = buildFullEvent(event);
|
|
2730
|
+
const payload = JSON.stringify(fullEvent);
|
|
2729
2731
|
if (analyticsProxyUrl) {
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2732
|
+
const sent = typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function" && navigator.sendBeacon(
|
|
2733
|
+
analyticsProxyUrl,
|
|
2734
|
+
new Blob([payload], { type: "application/json" })
|
|
2735
|
+
);
|
|
2736
|
+
if (!sent) {
|
|
2737
|
+
fetch(analyticsProxyUrl, {
|
|
2738
|
+
method: "POST",
|
|
2739
|
+
headers: { "Content-Type": "application/json" },
|
|
2740
|
+
body: payload,
|
|
2741
|
+
keepalive: true
|
|
2742
|
+
}).catch((err) => {
|
|
2743
|
+
console.debug("[ScaleMule Analytics] Proxy tracking failed:", err);
|
|
2744
|
+
});
|
|
2745
|
+
}
|
|
2737
2746
|
return { tracked: 1, session_id: sessionIdRef.current || void 0 };
|
|
2738
2747
|
}
|
|
2739
2748
|
if (publishableKey && gatewayUrl) {
|
|
@@ -2744,7 +2753,8 @@ function useAnalytics(options = {}) {
|
|
|
2744
2753
|
"Content-Type": "application/json",
|
|
2745
2754
|
"x-api-key": publishableKey
|
|
2746
2755
|
},
|
|
2747
|
-
body:
|
|
2756
|
+
body: payload,
|
|
2757
|
+
keepalive: true
|
|
2748
2758
|
}).catch((err) => {
|
|
2749
2759
|
console.debug("[ScaleMule Analytics] Direct tracking failed:", err);
|
|
2750
2760
|
});
|
|
@@ -2807,13 +2817,21 @@ function useAnalytics(options = {}) {
|
|
|
2807
2817
|
const fullEvents = events.map((event) => buildFullEvent(event));
|
|
2808
2818
|
if (analyticsProxyUrl) {
|
|
2809
2819
|
for (const event of fullEvents) {
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2820
|
+
const payload = JSON.stringify(event);
|
|
2821
|
+
const sent = typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function" && navigator.sendBeacon(
|
|
2822
|
+
analyticsProxyUrl,
|
|
2823
|
+
new Blob([payload], { type: "application/json" })
|
|
2824
|
+
);
|
|
2825
|
+
if (!sent) {
|
|
2826
|
+
fetch(analyticsProxyUrl, {
|
|
2827
|
+
method: "POST",
|
|
2828
|
+
headers: { "Content-Type": "application/json" },
|
|
2829
|
+
body: payload,
|
|
2830
|
+
keepalive: true
|
|
2831
|
+
}).catch((err) => {
|
|
2832
|
+
console.debug("[ScaleMule Analytics] Proxy batch tracking failed:", err);
|
|
2833
|
+
});
|
|
2834
|
+
}
|
|
2817
2835
|
}
|
|
2818
2836
|
setLoading(false);
|
|
2819
2837
|
return { tracked: events.length, session_id: sessionIdRef.current || void 0 };
|
|
@@ -2826,7 +2844,8 @@ function useAnalytics(options = {}) {
|
|
|
2826
2844
|
"Content-Type": "application/json",
|
|
2827
2845
|
"x-api-key": publishableKey
|
|
2828
2846
|
},
|
|
2829
|
-
body: JSON.stringify({ events: fullEvents })
|
|
2847
|
+
body: JSON.stringify({ events: fullEvents }),
|
|
2848
|
+
keepalive: true
|
|
2830
2849
|
}).catch((err) => {
|
|
2831
2850
|
console.debug("[ScaleMule Analytics] Direct batch tracking failed:", err);
|
|
2832
2851
|
});
|
|
@@ -3035,6 +3054,174 @@ function useFeatureFlags(options = {}) {
|
|
|
3035
3054
|
getFlag
|
|
3036
3055
|
};
|
|
3037
3056
|
}
|
|
3057
|
+
function getCsrfToken() {
|
|
3058
|
+
if (typeof document === "undefined") return "";
|
|
3059
|
+
const match = document.cookie.match(/(?:^|;\s*)sm_csrf=([^;]*)/);
|
|
3060
|
+
return match ? decodeURIComponent(match[1]) : "";
|
|
3061
|
+
}
|
|
3062
|
+
function usePushNotifications(options = {}) {
|
|
3063
|
+
const { serviceWorkerUrl = "/sw.js", pushProxyUrl = "/api/push", onNotification } = options;
|
|
3064
|
+
const { user } = useScaleMule();
|
|
3065
|
+
const [isSupported, setIsSupported] = react.useState(false);
|
|
3066
|
+
const [permission, setPermission] = react.useState("unsupported");
|
|
3067
|
+
const [isSubscribed, setIsSubscribed] = react.useState(false);
|
|
3068
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
3069
|
+
const [error, setError] = react.useState(null);
|
|
3070
|
+
const [tokenId, setTokenId] = react.useState(null);
|
|
3071
|
+
const onNotificationRef = react.useRef(onNotification);
|
|
3072
|
+
react.useEffect(() => {
|
|
3073
|
+
onNotificationRef.current = onNotification;
|
|
3074
|
+
}, [onNotification]);
|
|
3075
|
+
const prevUserRef = react.useRef(null);
|
|
3076
|
+
const fetcher = react.useMemo(() => {
|
|
3077
|
+
async function proxyGet(path) {
|
|
3078
|
+
const res = await fetch(`${pushProxyUrl}/${path}`);
|
|
3079
|
+
const json = await res.json();
|
|
3080
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3081
|
+
return json.data;
|
|
3082
|
+
}
|
|
3083
|
+
async function proxyPost(path, body) {
|
|
3084
|
+
const res = await fetch(`${pushProxyUrl}/${path}`, {
|
|
3085
|
+
method: "POST",
|
|
3086
|
+
headers: {
|
|
3087
|
+
"Content-Type": "application/json",
|
|
3088
|
+
"x-csrf-token": getCsrfToken()
|
|
3089
|
+
},
|
|
3090
|
+
body: body ? JSON.stringify(body) : void 0
|
|
3091
|
+
});
|
|
3092
|
+
const json = await res.json();
|
|
3093
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3094
|
+
return json.data;
|
|
3095
|
+
}
|
|
3096
|
+
async function proxyPut(path, body) {
|
|
3097
|
+
const res = await fetch(`${pushProxyUrl}/${path}`, {
|
|
3098
|
+
method: "PUT",
|
|
3099
|
+
headers: {
|
|
3100
|
+
"Content-Type": "application/json",
|
|
3101
|
+
"x-csrf-token": getCsrfToken()
|
|
3102
|
+
},
|
|
3103
|
+
body: body ? JSON.stringify(body) : void 0
|
|
3104
|
+
});
|
|
3105
|
+
const json = await res.json();
|
|
3106
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3107
|
+
return json.data;
|
|
3108
|
+
}
|
|
3109
|
+
async function proxyDelete(path) {
|
|
3110
|
+
const res = await fetch(`${pushProxyUrl}/${path}`, {
|
|
3111
|
+
method: "DELETE",
|
|
3112
|
+
headers: {
|
|
3113
|
+
"x-csrf-token": getCsrfToken()
|
|
3114
|
+
}
|
|
3115
|
+
});
|
|
3116
|
+
const json = await res.json();
|
|
3117
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3118
|
+
}
|
|
3119
|
+
return {
|
|
3120
|
+
getSettings: () => proxyGet("settings/me"),
|
|
3121
|
+
registerToken: (data) => proxyPost("register", data),
|
|
3122
|
+
unregisterToken: (id) => proxyDelete(`tokens/by-id/${id}`),
|
|
3123
|
+
associateUser: (id) => proxyPut(`tokens/by-id/${id}/user`, {}),
|
|
3124
|
+
disassociateUser: (id) => proxyDelete(`tokens/by-id/${id}/user`)
|
|
3125
|
+
};
|
|
3126
|
+
}, [pushProxyUrl]);
|
|
3127
|
+
const manager = react.useMemo(() => {
|
|
3128
|
+
if (typeof window === "undefined") return null;
|
|
3129
|
+
try {
|
|
3130
|
+
return new sdk.WebPushManager({ fetcher, serviceWorkerUrl });
|
|
3131
|
+
} catch {
|
|
3132
|
+
return null;
|
|
3133
|
+
}
|
|
3134
|
+
}, [fetcher, serviceWorkerUrl]);
|
|
3135
|
+
react.useEffect(() => {
|
|
3136
|
+
if (!manager) return;
|
|
3137
|
+
const supported = manager.isSupported();
|
|
3138
|
+
setIsSupported(supported);
|
|
3139
|
+
setPermission(manager.getPermissionState());
|
|
3140
|
+
if (supported) {
|
|
3141
|
+
manager.isSubscribed().then((sub) => {
|
|
3142
|
+
setIsSubscribed(sub);
|
|
3143
|
+
setTokenId(manager.getTokenId());
|
|
3144
|
+
});
|
|
3145
|
+
}
|
|
3146
|
+
}, [manager]);
|
|
3147
|
+
react.useEffect(() => {
|
|
3148
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return;
|
|
3149
|
+
function handleMessage(event) {
|
|
3150
|
+
if (event.data?.type === "push-received") {
|
|
3151
|
+
onNotificationRef.current?.(event.data.payload);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
navigator.serviceWorker.addEventListener("message", handleMessage);
|
|
3155
|
+
return () => navigator.serviceWorker.removeEventListener("message", handleMessage);
|
|
3156
|
+
}, []);
|
|
3157
|
+
react.useEffect(() => {
|
|
3158
|
+
if (!manager) return;
|
|
3159
|
+
const currentUserId = user?.id || null;
|
|
3160
|
+
const prevUserId = prevUserRef.current;
|
|
3161
|
+
if (currentUserId && !prevUserId && isSubscribed) {
|
|
3162
|
+
manager.associateUser().catch(() => {
|
|
3163
|
+
});
|
|
3164
|
+
}
|
|
3165
|
+
prevUserRef.current = currentUserId;
|
|
3166
|
+
}, [user?.id, manager, isSubscribed]);
|
|
3167
|
+
const subscribe = react.useCallback(async () => {
|
|
3168
|
+
if (!manager) return;
|
|
3169
|
+
setIsLoading(true);
|
|
3170
|
+
setError(null);
|
|
3171
|
+
try {
|
|
3172
|
+
const result = await manager.subscribe();
|
|
3173
|
+
if (result) {
|
|
3174
|
+
setIsSubscribed(true);
|
|
3175
|
+
setTokenId(result.tokenId);
|
|
3176
|
+
setPermission("granted");
|
|
3177
|
+
} else {
|
|
3178
|
+
setPermission(manager.getPermissionState());
|
|
3179
|
+
}
|
|
3180
|
+
} catch (e) {
|
|
3181
|
+
setError({
|
|
3182
|
+
code: "PUSH_SUBSCRIBE_ERROR",
|
|
3183
|
+
message: e instanceof Error ? e.message : "Failed to subscribe"
|
|
3184
|
+
});
|
|
3185
|
+
} finally {
|
|
3186
|
+
setIsLoading(false);
|
|
3187
|
+
}
|
|
3188
|
+
}, [manager]);
|
|
3189
|
+
const unsubscribe = react.useCallback(async () => {
|
|
3190
|
+
if (!manager) return;
|
|
3191
|
+
setIsLoading(true);
|
|
3192
|
+
setError(null);
|
|
3193
|
+
try {
|
|
3194
|
+
await manager.unsubscribe();
|
|
3195
|
+
setIsSubscribed(false);
|
|
3196
|
+
setTokenId(null);
|
|
3197
|
+
} catch (e) {
|
|
3198
|
+
setError({
|
|
3199
|
+
code: "PUSH_UNSUBSCRIBE_ERROR",
|
|
3200
|
+
message: e instanceof Error ? e.message : "Failed to unsubscribe"
|
|
3201
|
+
});
|
|
3202
|
+
} finally {
|
|
3203
|
+
setIsLoading(false);
|
|
3204
|
+
}
|
|
3205
|
+
}, [manager]);
|
|
3206
|
+
const disassociateUser = react.useCallback(async () => {
|
|
3207
|
+
if (!manager) return;
|
|
3208
|
+
try {
|
|
3209
|
+
await manager.disassociateUser();
|
|
3210
|
+
} catch {
|
|
3211
|
+
}
|
|
3212
|
+
}, [manager]);
|
|
3213
|
+
return {
|
|
3214
|
+
isSupported,
|
|
3215
|
+
permission,
|
|
3216
|
+
isSubscribed,
|
|
3217
|
+
isLoading,
|
|
3218
|
+
error,
|
|
3219
|
+
subscribe,
|
|
3220
|
+
unsubscribe,
|
|
3221
|
+
disassociateUser,
|
|
3222
|
+
tokenId
|
|
3223
|
+
};
|
|
3224
|
+
}
|
|
3038
3225
|
|
|
3039
3226
|
// src/validation.ts
|
|
3040
3227
|
var phoneCountries = [
|
|
@@ -3341,6 +3528,7 @@ exports.useAuth = useAuth;
|
|
|
3341
3528
|
exports.useBilling = useBilling;
|
|
3342
3529
|
exports.useContent = useContent;
|
|
3343
3530
|
exports.useFeatureFlags = useFeatureFlags;
|
|
3531
|
+
exports.usePushNotifications = usePushNotifications;
|
|
3344
3532
|
exports.useRealtime = useRealtime;
|
|
3345
3533
|
exports.useScaleMule = useScaleMule;
|
|
3346
3534
|
exports.useScaleMuleClient = useScaleMuleClient;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createContext, useState, useMemo, useEffect, useCallback, useContext, useRef } from 'react';
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { WebPushManager } from '@scalemule/sdk';
|
|
3
4
|
|
|
4
5
|
// src/provider.tsx
|
|
5
6
|
|
|
@@ -2724,14 +2725,22 @@ function useAnalytics(options = {}) {
|
|
|
2724
2725
|
const sendEvent = useCallback(
|
|
2725
2726
|
async (event) => {
|
|
2726
2727
|
const fullEvent = buildFullEvent(event);
|
|
2728
|
+
const payload = JSON.stringify(fullEvent);
|
|
2727
2729
|
if (analyticsProxyUrl) {
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2730
|
+
const sent = typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function" && navigator.sendBeacon(
|
|
2731
|
+
analyticsProxyUrl,
|
|
2732
|
+
new Blob([payload], { type: "application/json" })
|
|
2733
|
+
);
|
|
2734
|
+
if (!sent) {
|
|
2735
|
+
fetch(analyticsProxyUrl, {
|
|
2736
|
+
method: "POST",
|
|
2737
|
+
headers: { "Content-Type": "application/json" },
|
|
2738
|
+
body: payload,
|
|
2739
|
+
keepalive: true
|
|
2740
|
+
}).catch((err) => {
|
|
2741
|
+
console.debug("[ScaleMule Analytics] Proxy tracking failed:", err);
|
|
2742
|
+
});
|
|
2743
|
+
}
|
|
2735
2744
|
return { tracked: 1, session_id: sessionIdRef.current || void 0 };
|
|
2736
2745
|
}
|
|
2737
2746
|
if (publishableKey && gatewayUrl) {
|
|
@@ -2742,7 +2751,8 @@ function useAnalytics(options = {}) {
|
|
|
2742
2751
|
"Content-Type": "application/json",
|
|
2743
2752
|
"x-api-key": publishableKey
|
|
2744
2753
|
},
|
|
2745
|
-
body:
|
|
2754
|
+
body: payload,
|
|
2755
|
+
keepalive: true
|
|
2746
2756
|
}).catch((err) => {
|
|
2747
2757
|
console.debug("[ScaleMule Analytics] Direct tracking failed:", err);
|
|
2748
2758
|
});
|
|
@@ -2805,13 +2815,21 @@ function useAnalytics(options = {}) {
|
|
|
2805
2815
|
const fullEvents = events.map((event) => buildFullEvent(event));
|
|
2806
2816
|
if (analyticsProxyUrl) {
|
|
2807
2817
|
for (const event of fullEvents) {
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2818
|
+
const payload = JSON.stringify(event);
|
|
2819
|
+
const sent = typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function" && navigator.sendBeacon(
|
|
2820
|
+
analyticsProxyUrl,
|
|
2821
|
+
new Blob([payload], { type: "application/json" })
|
|
2822
|
+
);
|
|
2823
|
+
if (!sent) {
|
|
2824
|
+
fetch(analyticsProxyUrl, {
|
|
2825
|
+
method: "POST",
|
|
2826
|
+
headers: { "Content-Type": "application/json" },
|
|
2827
|
+
body: payload,
|
|
2828
|
+
keepalive: true
|
|
2829
|
+
}).catch((err) => {
|
|
2830
|
+
console.debug("[ScaleMule Analytics] Proxy batch tracking failed:", err);
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2815
2833
|
}
|
|
2816
2834
|
setLoading(false);
|
|
2817
2835
|
return { tracked: events.length, session_id: sessionIdRef.current || void 0 };
|
|
@@ -2824,7 +2842,8 @@ function useAnalytics(options = {}) {
|
|
|
2824
2842
|
"Content-Type": "application/json",
|
|
2825
2843
|
"x-api-key": publishableKey
|
|
2826
2844
|
},
|
|
2827
|
-
body: JSON.stringify({ events: fullEvents })
|
|
2845
|
+
body: JSON.stringify({ events: fullEvents }),
|
|
2846
|
+
keepalive: true
|
|
2828
2847
|
}).catch((err) => {
|
|
2829
2848
|
console.debug("[ScaleMule Analytics] Direct batch tracking failed:", err);
|
|
2830
2849
|
});
|
|
@@ -3033,6 +3052,174 @@ function useFeatureFlags(options = {}) {
|
|
|
3033
3052
|
getFlag
|
|
3034
3053
|
};
|
|
3035
3054
|
}
|
|
3055
|
+
function getCsrfToken() {
|
|
3056
|
+
if (typeof document === "undefined") return "";
|
|
3057
|
+
const match = document.cookie.match(/(?:^|;\s*)sm_csrf=([^;]*)/);
|
|
3058
|
+
return match ? decodeURIComponent(match[1]) : "";
|
|
3059
|
+
}
|
|
3060
|
+
function usePushNotifications(options = {}) {
|
|
3061
|
+
const { serviceWorkerUrl = "/sw.js", pushProxyUrl = "/api/push", onNotification } = options;
|
|
3062
|
+
const { user } = useScaleMule();
|
|
3063
|
+
const [isSupported, setIsSupported] = useState(false);
|
|
3064
|
+
const [permission, setPermission] = useState("unsupported");
|
|
3065
|
+
const [isSubscribed, setIsSubscribed] = useState(false);
|
|
3066
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
3067
|
+
const [error, setError] = useState(null);
|
|
3068
|
+
const [tokenId, setTokenId] = useState(null);
|
|
3069
|
+
const onNotificationRef = useRef(onNotification);
|
|
3070
|
+
useEffect(() => {
|
|
3071
|
+
onNotificationRef.current = onNotification;
|
|
3072
|
+
}, [onNotification]);
|
|
3073
|
+
const prevUserRef = useRef(null);
|
|
3074
|
+
const fetcher = useMemo(() => {
|
|
3075
|
+
async function proxyGet(path) {
|
|
3076
|
+
const res = await fetch(`${pushProxyUrl}/${path}`);
|
|
3077
|
+
const json = await res.json();
|
|
3078
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3079
|
+
return json.data;
|
|
3080
|
+
}
|
|
3081
|
+
async function proxyPost(path, body) {
|
|
3082
|
+
const res = await fetch(`${pushProxyUrl}/${path}`, {
|
|
3083
|
+
method: "POST",
|
|
3084
|
+
headers: {
|
|
3085
|
+
"Content-Type": "application/json",
|
|
3086
|
+
"x-csrf-token": getCsrfToken()
|
|
3087
|
+
},
|
|
3088
|
+
body: body ? JSON.stringify(body) : void 0
|
|
3089
|
+
});
|
|
3090
|
+
const json = await res.json();
|
|
3091
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3092
|
+
return json.data;
|
|
3093
|
+
}
|
|
3094
|
+
async function proxyPut(path, body) {
|
|
3095
|
+
const res = await fetch(`${pushProxyUrl}/${path}`, {
|
|
3096
|
+
method: "PUT",
|
|
3097
|
+
headers: {
|
|
3098
|
+
"Content-Type": "application/json",
|
|
3099
|
+
"x-csrf-token": getCsrfToken()
|
|
3100
|
+
},
|
|
3101
|
+
body: body ? JSON.stringify(body) : void 0
|
|
3102
|
+
});
|
|
3103
|
+
const json = await res.json();
|
|
3104
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3105
|
+
return json.data;
|
|
3106
|
+
}
|
|
3107
|
+
async function proxyDelete(path) {
|
|
3108
|
+
const res = await fetch(`${pushProxyUrl}/${path}`, {
|
|
3109
|
+
method: "DELETE",
|
|
3110
|
+
headers: {
|
|
3111
|
+
"x-csrf-token": getCsrfToken()
|
|
3112
|
+
}
|
|
3113
|
+
});
|
|
3114
|
+
const json = await res.json();
|
|
3115
|
+
if (!json.success) throw new Error(json.error?.message || "Request failed");
|
|
3116
|
+
}
|
|
3117
|
+
return {
|
|
3118
|
+
getSettings: () => proxyGet("settings/me"),
|
|
3119
|
+
registerToken: (data) => proxyPost("register", data),
|
|
3120
|
+
unregisterToken: (id) => proxyDelete(`tokens/by-id/${id}`),
|
|
3121
|
+
associateUser: (id) => proxyPut(`tokens/by-id/${id}/user`, {}),
|
|
3122
|
+
disassociateUser: (id) => proxyDelete(`tokens/by-id/${id}/user`)
|
|
3123
|
+
};
|
|
3124
|
+
}, [pushProxyUrl]);
|
|
3125
|
+
const manager = useMemo(() => {
|
|
3126
|
+
if (typeof window === "undefined") return null;
|
|
3127
|
+
try {
|
|
3128
|
+
return new WebPushManager({ fetcher, serviceWorkerUrl });
|
|
3129
|
+
} catch {
|
|
3130
|
+
return null;
|
|
3131
|
+
}
|
|
3132
|
+
}, [fetcher, serviceWorkerUrl]);
|
|
3133
|
+
useEffect(() => {
|
|
3134
|
+
if (!manager) return;
|
|
3135
|
+
const supported = manager.isSupported();
|
|
3136
|
+
setIsSupported(supported);
|
|
3137
|
+
setPermission(manager.getPermissionState());
|
|
3138
|
+
if (supported) {
|
|
3139
|
+
manager.isSubscribed().then((sub) => {
|
|
3140
|
+
setIsSubscribed(sub);
|
|
3141
|
+
setTokenId(manager.getTokenId());
|
|
3142
|
+
});
|
|
3143
|
+
}
|
|
3144
|
+
}, [manager]);
|
|
3145
|
+
useEffect(() => {
|
|
3146
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return;
|
|
3147
|
+
function handleMessage(event) {
|
|
3148
|
+
if (event.data?.type === "push-received") {
|
|
3149
|
+
onNotificationRef.current?.(event.data.payload);
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
navigator.serviceWorker.addEventListener("message", handleMessage);
|
|
3153
|
+
return () => navigator.serviceWorker.removeEventListener("message", handleMessage);
|
|
3154
|
+
}, []);
|
|
3155
|
+
useEffect(() => {
|
|
3156
|
+
if (!manager) return;
|
|
3157
|
+
const currentUserId = user?.id || null;
|
|
3158
|
+
const prevUserId = prevUserRef.current;
|
|
3159
|
+
if (currentUserId && !prevUserId && isSubscribed) {
|
|
3160
|
+
manager.associateUser().catch(() => {
|
|
3161
|
+
});
|
|
3162
|
+
}
|
|
3163
|
+
prevUserRef.current = currentUserId;
|
|
3164
|
+
}, [user?.id, manager, isSubscribed]);
|
|
3165
|
+
const subscribe = useCallback(async () => {
|
|
3166
|
+
if (!manager) return;
|
|
3167
|
+
setIsLoading(true);
|
|
3168
|
+
setError(null);
|
|
3169
|
+
try {
|
|
3170
|
+
const result = await manager.subscribe();
|
|
3171
|
+
if (result) {
|
|
3172
|
+
setIsSubscribed(true);
|
|
3173
|
+
setTokenId(result.tokenId);
|
|
3174
|
+
setPermission("granted");
|
|
3175
|
+
} else {
|
|
3176
|
+
setPermission(manager.getPermissionState());
|
|
3177
|
+
}
|
|
3178
|
+
} catch (e) {
|
|
3179
|
+
setError({
|
|
3180
|
+
code: "PUSH_SUBSCRIBE_ERROR",
|
|
3181
|
+
message: e instanceof Error ? e.message : "Failed to subscribe"
|
|
3182
|
+
});
|
|
3183
|
+
} finally {
|
|
3184
|
+
setIsLoading(false);
|
|
3185
|
+
}
|
|
3186
|
+
}, [manager]);
|
|
3187
|
+
const unsubscribe = useCallback(async () => {
|
|
3188
|
+
if (!manager) return;
|
|
3189
|
+
setIsLoading(true);
|
|
3190
|
+
setError(null);
|
|
3191
|
+
try {
|
|
3192
|
+
await manager.unsubscribe();
|
|
3193
|
+
setIsSubscribed(false);
|
|
3194
|
+
setTokenId(null);
|
|
3195
|
+
} catch (e) {
|
|
3196
|
+
setError({
|
|
3197
|
+
code: "PUSH_UNSUBSCRIBE_ERROR",
|
|
3198
|
+
message: e instanceof Error ? e.message : "Failed to unsubscribe"
|
|
3199
|
+
});
|
|
3200
|
+
} finally {
|
|
3201
|
+
setIsLoading(false);
|
|
3202
|
+
}
|
|
3203
|
+
}, [manager]);
|
|
3204
|
+
const disassociateUser = useCallback(async () => {
|
|
3205
|
+
if (!manager) return;
|
|
3206
|
+
try {
|
|
3207
|
+
await manager.disassociateUser();
|
|
3208
|
+
} catch {
|
|
3209
|
+
}
|
|
3210
|
+
}, [manager]);
|
|
3211
|
+
return {
|
|
3212
|
+
isSupported,
|
|
3213
|
+
permission,
|
|
3214
|
+
isSubscribed,
|
|
3215
|
+
isLoading,
|
|
3216
|
+
error,
|
|
3217
|
+
subscribe,
|
|
3218
|
+
unsubscribe,
|
|
3219
|
+
disassociateUser,
|
|
3220
|
+
tokenId
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3036
3223
|
|
|
3037
3224
|
// src/validation.ts
|
|
3038
3225
|
var phoneCountries = [
|
|
@@ -3325,4 +3512,4 @@ function createSafeLogger(prefix) {
|
|
|
3325
3512
|
};
|
|
3326
3513
|
}
|
|
3327
3514
|
|
|
3328
|
-
export { ScaleMuleApiError, ScaleMuleClient, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, useRealtime, useScaleMule, useScaleMuleClient, useUser, validateForm, validators };
|
|
3515
|
+
export { ScaleMuleApiError, ScaleMuleClient, ScaleMuleProvider, composePhone, createClient, createSafeLogger, normalizePhone, phoneCountries, sanitizeForLog, useAnalytics, useAuth, useBilling, useContent, useFeatureFlags, usePushNotifications, useRealtime, useScaleMule, useScaleMuleClient, useUser, validateForm, validators };
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { S as ServerConfig } from '../webhook-handler-
|
|
2
|
-
export { a as ScaleMuleServer,
|
|
3
|
-
import {
|
|
1
|
+
import { S as ServerConfig } from '../webhook-handler-Cz9jtet2.mjs';
|
|
2
|
+
export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-Cz9jtet2.mjs';
|
|
3
|
+
import { p as ClientContext, A as ApiError } from '../index-BoENfro3.mjs';
|
|
4
4
|
import { NextRequest, NextResponse } from 'next/server';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -231,7 +231,7 @@ interface AuthRoutesConfig {
|
|
|
231
231
|
email: string;
|
|
232
232
|
}) => void | Promise<void>;
|
|
233
233
|
}
|
|
234
|
-
type RouteHandler = (request: Request, context: {
|
|
234
|
+
type RouteHandler$1 = (request: Request, context: {
|
|
235
235
|
params: Promise<{
|
|
236
236
|
scalemule?: string[];
|
|
237
237
|
}>;
|
|
@@ -264,10 +264,10 @@ type RouteHandler = (request: Request, context: {
|
|
|
264
264
|
* - POST /api/auth/verify-email - Verify email
|
|
265
265
|
*/
|
|
266
266
|
declare function createAuthRoutes(config?: AuthRoutesConfig): {
|
|
267
|
-
GET: RouteHandler;
|
|
268
|
-
POST: RouteHandler;
|
|
269
|
-
DELETE: RouteHandler;
|
|
270
|
-
PATCH: RouteHandler;
|
|
267
|
+
GET: RouteHandler$1;
|
|
268
|
+
POST: RouteHandler$1;
|
|
269
|
+
DELETE: RouteHandler$1;
|
|
270
|
+
PATCH: RouteHandler$1;
|
|
271
271
|
};
|
|
272
272
|
interface AnalyticsTrackingGateConfig {
|
|
273
273
|
/** Feature flag key used to decide whether to forward analytics */
|
|
@@ -346,7 +346,44 @@ interface AnalyticsRoutesConfig {
|
|
|
346
346
|
* ```
|
|
347
347
|
*/
|
|
348
348
|
declare function createAnalyticsRoutes(config?: AnalyticsRoutesConfig): {
|
|
349
|
+
POST: RouteHandler$1;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Push Notification Proxy Routes
|
|
354
|
+
*
|
|
355
|
+
* Drop-in route handlers for Next.js App Router that proxy push notification
|
|
356
|
+
* requests to the ScaleMule gateway. Follows the same pattern as createAuthRoutes().
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* ```ts
|
|
360
|
+
* // app/api/push/[...action]/route.ts
|
|
361
|
+
* import { createPushRoutes } from '@scalemule/nextjs/server'
|
|
362
|
+
*
|
|
363
|
+
* export const { GET, POST, PUT, DELETE } = createPushRoutes({
|
|
364
|
+
* apiKey: process.env.SCALEMULE_API_KEY!,
|
|
365
|
+
* gatewayUrl: process.env.SCALEMULE_API_URL!,
|
|
366
|
+
* })
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
interface PushRoutesConfig {
|
|
370
|
+
/** Server-side secret API key */
|
|
371
|
+
apiKey: string;
|
|
372
|
+
/** Gateway URL (e.g., https://api.scalemule.com) */
|
|
373
|
+
gatewayUrl: string;
|
|
374
|
+
/** Enable CSRF validation on POST/PUT/DELETE (default: true) */
|
|
375
|
+
csrf?: boolean;
|
|
376
|
+
}
|
|
377
|
+
type RouteHandler = (request: Request, context: {
|
|
378
|
+
params: Promise<{
|
|
379
|
+
action?: string[];
|
|
380
|
+
}>;
|
|
381
|
+
}) => Promise<Response>;
|
|
382
|
+
declare function createPushRoutes(config: PushRoutesConfig): {
|
|
383
|
+
GET: RouteHandler;
|
|
349
384
|
POST: RouteHandler;
|
|
385
|
+
PUT: RouteHandler;
|
|
386
|
+
DELETE: RouteHandler;
|
|
350
387
|
};
|
|
351
388
|
|
|
352
389
|
/**
|
|
@@ -940,4 +977,4 @@ declare function invalidateBundleCache(key?: string): void;
|
|
|
940
977
|
*/
|
|
941
978
|
declare function prefetchBundles(keys: string[]): Promise<void>;
|
|
942
979
|
|
|
943
|
-
export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, type HandlerContext, type HandlerOptions, type MySqlBundle, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PostgresBundle, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, ScaleMuleError, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, prefetchBundles, prefetchSecrets, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, withAuth, withCSRFProtection, withCSRFToken, withSession };
|
|
980
|
+
export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, type HandlerContext, type HandlerOptions, type MySqlBundle, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PostgresBundle, type PushRoutesConfig, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, ScaleMuleError, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createPushRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, prefetchBundles, prefetchSecrets, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, withAuth, withCSRFProtection, withCSRFToken, withSession };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { S as ServerConfig } from '../webhook-handler-
|
|
2
|
-
export { a as ScaleMuleServer,
|
|
3
|
-
import {
|
|
1
|
+
import { S as ServerConfig } from '../webhook-handler-CjSSCdvI.js';
|
|
2
|
+
export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-CjSSCdvI.js';
|
|
3
|
+
import { p as ClientContext, A as ApiError } from '../index-BoENfro3.js';
|
|
4
4
|
import { NextRequest, NextResponse } from 'next/server';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -231,7 +231,7 @@ interface AuthRoutesConfig {
|
|
|
231
231
|
email: string;
|
|
232
232
|
}) => void | Promise<void>;
|
|
233
233
|
}
|
|
234
|
-
type RouteHandler = (request: Request, context: {
|
|
234
|
+
type RouteHandler$1 = (request: Request, context: {
|
|
235
235
|
params: Promise<{
|
|
236
236
|
scalemule?: string[];
|
|
237
237
|
}>;
|
|
@@ -264,10 +264,10 @@ type RouteHandler = (request: Request, context: {
|
|
|
264
264
|
* - POST /api/auth/verify-email - Verify email
|
|
265
265
|
*/
|
|
266
266
|
declare function createAuthRoutes(config?: AuthRoutesConfig): {
|
|
267
|
-
GET: RouteHandler;
|
|
268
|
-
POST: RouteHandler;
|
|
269
|
-
DELETE: RouteHandler;
|
|
270
|
-
PATCH: RouteHandler;
|
|
267
|
+
GET: RouteHandler$1;
|
|
268
|
+
POST: RouteHandler$1;
|
|
269
|
+
DELETE: RouteHandler$1;
|
|
270
|
+
PATCH: RouteHandler$1;
|
|
271
271
|
};
|
|
272
272
|
interface AnalyticsTrackingGateConfig {
|
|
273
273
|
/** Feature flag key used to decide whether to forward analytics */
|
|
@@ -346,7 +346,44 @@ interface AnalyticsRoutesConfig {
|
|
|
346
346
|
* ```
|
|
347
347
|
*/
|
|
348
348
|
declare function createAnalyticsRoutes(config?: AnalyticsRoutesConfig): {
|
|
349
|
+
POST: RouteHandler$1;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Push Notification Proxy Routes
|
|
354
|
+
*
|
|
355
|
+
* Drop-in route handlers for Next.js App Router that proxy push notification
|
|
356
|
+
* requests to the ScaleMule gateway. Follows the same pattern as createAuthRoutes().
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* ```ts
|
|
360
|
+
* // app/api/push/[...action]/route.ts
|
|
361
|
+
* import { createPushRoutes } from '@scalemule/nextjs/server'
|
|
362
|
+
*
|
|
363
|
+
* export const { GET, POST, PUT, DELETE } = createPushRoutes({
|
|
364
|
+
* apiKey: process.env.SCALEMULE_API_KEY!,
|
|
365
|
+
* gatewayUrl: process.env.SCALEMULE_API_URL!,
|
|
366
|
+
* })
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
interface PushRoutesConfig {
|
|
370
|
+
/** Server-side secret API key */
|
|
371
|
+
apiKey: string;
|
|
372
|
+
/** Gateway URL (e.g., https://api.scalemule.com) */
|
|
373
|
+
gatewayUrl: string;
|
|
374
|
+
/** Enable CSRF validation on POST/PUT/DELETE (default: true) */
|
|
375
|
+
csrf?: boolean;
|
|
376
|
+
}
|
|
377
|
+
type RouteHandler = (request: Request, context: {
|
|
378
|
+
params: Promise<{
|
|
379
|
+
action?: string[];
|
|
380
|
+
}>;
|
|
381
|
+
}) => Promise<Response>;
|
|
382
|
+
declare function createPushRoutes(config: PushRoutesConfig): {
|
|
383
|
+
GET: RouteHandler;
|
|
349
384
|
POST: RouteHandler;
|
|
385
|
+
PUT: RouteHandler;
|
|
386
|
+
DELETE: RouteHandler;
|
|
350
387
|
};
|
|
351
388
|
|
|
352
389
|
/**
|
|
@@ -940,4 +977,4 @@ declare function invalidateBundleCache(key?: string): void;
|
|
|
940
977
|
*/
|
|
941
978
|
declare function prefetchBundles(keys: string[]): Promise<void>;
|
|
942
979
|
|
|
943
|
-
export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, type HandlerContext, type HandlerOptions, type MySqlBundle, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PostgresBundle, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, ScaleMuleError, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, prefetchBundles, prefetchSecrets, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, withAuth, withCSRFProtection, withCSRFToken, withSession };
|
|
980
|
+
export { type AnalyticsRoutesConfig, type AnalyticsTrackingGateConfig, type AuthMiddlewareConfig, type AuthRoutesConfig, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, type HandlerContext, type HandlerOptions, type MySqlBundle, OAUTH_STATE_COOKIE_NAME, type OAuthBundle, type PostgresBundle, type PushRoutesConfig, type RedisBundle, type S3Bundle, SESSION_COOKIE_NAME, ScaleMuleError, ServerConfig, type SessionCookieOptions, type SessionData, type SmtpBundle, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createPushRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, prefetchBundles, prefetchSecrets, requireAppSecret, requireBundle, requireSession, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, withAuth, withCSRFProtection, withCSRFToken, withSession };
|
package/dist/server/index.js
CHANGED
|
@@ -1601,6 +1601,137 @@ function createAnalyticsRoutes(config = {}) {
|
|
|
1601
1601
|
return { POST };
|
|
1602
1602
|
}
|
|
1603
1603
|
|
|
1604
|
+
// src/server/push.ts
|
|
1605
|
+
function errorResponse2(code, message, status) {
|
|
1606
|
+
return new Response(
|
|
1607
|
+
JSON.stringify({ success: false, error: { code, message } }),
|
|
1608
|
+
{ status, headers: { "Content-Type": "application/json" } }
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
function successResponse2(data, status = 200) {
|
|
1612
|
+
return new Response(
|
|
1613
|
+
JSON.stringify({ success: true, data }),
|
|
1614
|
+
{ status, headers: { "Content-Type": "application/json" } }
|
|
1615
|
+
);
|
|
1616
|
+
}
|
|
1617
|
+
function createPushRoutes(config) {
|
|
1618
|
+
const { apiKey, gatewayUrl, csrf = true } = config;
|
|
1619
|
+
async function proxyToGateway(request, method, subPath) {
|
|
1620
|
+
const targetUrl = `${gatewayUrl}/v1/communication/push/${subPath}`;
|
|
1621
|
+
const headers2 = {
|
|
1622
|
+
"x-api-key": apiKey
|
|
1623
|
+
};
|
|
1624
|
+
const session = getSessionFromRequest(request);
|
|
1625
|
+
if (session?.sessionToken) {
|
|
1626
|
+
headers2["Authorization"] = `Bearer ${session.sessionToken}`;
|
|
1627
|
+
}
|
|
1628
|
+
const clientContext = extractClientContext(
|
|
1629
|
+
request
|
|
1630
|
+
);
|
|
1631
|
+
const contextHeaders = buildClientContextHeaders(clientContext);
|
|
1632
|
+
Object.assign(headers2, contextHeaders);
|
|
1633
|
+
const workspaceId = request.headers.get("x-sm-workspace-id");
|
|
1634
|
+
if (workspaceId) {
|
|
1635
|
+
headers2["x-sm-workspace-id"] = workspaceId;
|
|
1636
|
+
}
|
|
1637
|
+
const fetchOptions = {
|
|
1638
|
+
method,
|
|
1639
|
+
headers: headers2
|
|
1640
|
+
};
|
|
1641
|
+
if (method !== "GET" && method !== "DELETE") {
|
|
1642
|
+
try {
|
|
1643
|
+
const body = await request.text();
|
|
1644
|
+
if (body) {
|
|
1645
|
+
headers2["Content-Type"] = "application/json";
|
|
1646
|
+
fetchOptions.body = body;
|
|
1647
|
+
}
|
|
1648
|
+
} catch {
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
const response = await fetch(targetUrl, fetchOptions);
|
|
1652
|
+
if (response.status === 204) {
|
|
1653
|
+
return successResponse2(null);
|
|
1654
|
+
}
|
|
1655
|
+
const contentType = response.headers.get("content-type") || "";
|
|
1656
|
+
if (contentType.includes("application/json")) {
|
|
1657
|
+
const json = await response.json();
|
|
1658
|
+
if (response.ok) {
|
|
1659
|
+
return new Response(JSON.stringify(json), {
|
|
1660
|
+
status: response.status,
|
|
1661
|
+
headers: { "Content-Type": "application/json" }
|
|
1662
|
+
});
|
|
1663
|
+
} else {
|
|
1664
|
+
const errMsg = json?.error?.message || json?.message || "Request failed";
|
|
1665
|
+
const errCode = json?.error?.code || json?.code || "PUSH_ERROR";
|
|
1666
|
+
return errorResponse2(errCode, errMsg, response.status);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
const text = await response.text();
|
|
1670
|
+
if (response.ok) {
|
|
1671
|
+
return successResponse2(text);
|
|
1672
|
+
}
|
|
1673
|
+
return errorResponse2("PUSH_ERROR", text || "Request failed", response.status);
|
|
1674
|
+
}
|
|
1675
|
+
function extractSubPath(params) {
|
|
1676
|
+
return (params.action || []).join("/");
|
|
1677
|
+
}
|
|
1678
|
+
const GET = async (request, context) => {
|
|
1679
|
+
try {
|
|
1680
|
+
const params = await context?.params;
|
|
1681
|
+
const subPath = extractSubPath(params || {});
|
|
1682
|
+
return proxyToGateway(request, "GET", subPath);
|
|
1683
|
+
} catch (e) {
|
|
1684
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
const POST = async (request, context) => {
|
|
1688
|
+
if (csrf) {
|
|
1689
|
+
const csrfError = validateCSRFToken(request);
|
|
1690
|
+
if (csrfError) {
|
|
1691
|
+
return errorResponse2("CSRF_ERROR", "CSRF validation failed", 403);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
try {
|
|
1695
|
+
const params = await context?.params;
|
|
1696
|
+
const subPath = extractSubPath(params || {});
|
|
1697
|
+
return proxyToGateway(request, "POST", subPath);
|
|
1698
|
+
} catch (e) {
|
|
1699
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
const PUT = async (request, context) => {
|
|
1703
|
+
if (csrf) {
|
|
1704
|
+
const csrfError = validateCSRFToken(request);
|
|
1705
|
+
if (csrfError) {
|
|
1706
|
+
return errorResponse2("CSRF_ERROR", "CSRF validation failed", 403);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
try {
|
|
1710
|
+
const params = await context?.params;
|
|
1711
|
+
const subPath = extractSubPath(params || {});
|
|
1712
|
+
return proxyToGateway(request, "PUT", subPath);
|
|
1713
|
+
} catch (e) {
|
|
1714
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
const DELETE = async (request, context) => {
|
|
1718
|
+
if (csrf) {
|
|
1719
|
+
const csrfError = validateCSRFToken(request);
|
|
1720
|
+
if (csrfError) {
|
|
1721
|
+
return errorResponse2("CSRF_ERROR", "CSRF validation failed", 403);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
try {
|
|
1725
|
+
const params = await context?.params;
|
|
1726
|
+
const subPath = extractSubPath(params || {});
|
|
1727
|
+
return proxyToGateway(request, "DELETE", subPath);
|
|
1728
|
+
} catch (e) {
|
|
1729
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
return { GET, POST, PUT, DELETE };
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1604
1735
|
// src/server/errors.ts
|
|
1605
1736
|
var ScaleMuleError = class extends Error {
|
|
1606
1737
|
constructor(code, message, status = 400, details) {
|
|
@@ -2220,6 +2351,7 @@ exports.configureSecrets = configureSecrets;
|
|
|
2220
2351
|
exports.createAnalyticsRoutes = createAnalyticsRoutes;
|
|
2221
2352
|
exports.createAuthMiddleware = createAuthMiddleware;
|
|
2222
2353
|
exports.createAuthRoutes = createAuthRoutes;
|
|
2354
|
+
exports.createPushRoutes = createPushRoutes;
|
|
2223
2355
|
exports.createServerClient = createServerClient;
|
|
2224
2356
|
exports.createWebhookHandler = createWebhookHandler;
|
|
2225
2357
|
exports.createWebhookRoutes = createWebhookRoutes;
|
package/dist/server/index.mjs
CHANGED
|
@@ -1599,6 +1599,137 @@ function createAnalyticsRoutes(config = {}) {
|
|
|
1599
1599
|
return { POST };
|
|
1600
1600
|
}
|
|
1601
1601
|
|
|
1602
|
+
// src/server/push.ts
|
|
1603
|
+
function errorResponse2(code, message, status) {
|
|
1604
|
+
return new Response(
|
|
1605
|
+
JSON.stringify({ success: false, error: { code, message } }),
|
|
1606
|
+
{ status, headers: { "Content-Type": "application/json" } }
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1609
|
+
function successResponse2(data, status = 200) {
|
|
1610
|
+
return new Response(
|
|
1611
|
+
JSON.stringify({ success: true, data }),
|
|
1612
|
+
{ status, headers: { "Content-Type": "application/json" } }
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1615
|
+
function createPushRoutes(config) {
|
|
1616
|
+
const { apiKey, gatewayUrl, csrf = true } = config;
|
|
1617
|
+
async function proxyToGateway(request, method, subPath) {
|
|
1618
|
+
const targetUrl = `${gatewayUrl}/v1/communication/push/${subPath}`;
|
|
1619
|
+
const headers2 = {
|
|
1620
|
+
"x-api-key": apiKey
|
|
1621
|
+
};
|
|
1622
|
+
const session = getSessionFromRequest(request);
|
|
1623
|
+
if (session?.sessionToken) {
|
|
1624
|
+
headers2["Authorization"] = `Bearer ${session.sessionToken}`;
|
|
1625
|
+
}
|
|
1626
|
+
const clientContext = extractClientContext(
|
|
1627
|
+
request
|
|
1628
|
+
);
|
|
1629
|
+
const contextHeaders = buildClientContextHeaders(clientContext);
|
|
1630
|
+
Object.assign(headers2, contextHeaders);
|
|
1631
|
+
const workspaceId = request.headers.get("x-sm-workspace-id");
|
|
1632
|
+
if (workspaceId) {
|
|
1633
|
+
headers2["x-sm-workspace-id"] = workspaceId;
|
|
1634
|
+
}
|
|
1635
|
+
const fetchOptions = {
|
|
1636
|
+
method,
|
|
1637
|
+
headers: headers2
|
|
1638
|
+
};
|
|
1639
|
+
if (method !== "GET" && method !== "DELETE") {
|
|
1640
|
+
try {
|
|
1641
|
+
const body = await request.text();
|
|
1642
|
+
if (body) {
|
|
1643
|
+
headers2["Content-Type"] = "application/json";
|
|
1644
|
+
fetchOptions.body = body;
|
|
1645
|
+
}
|
|
1646
|
+
} catch {
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
const response = await fetch(targetUrl, fetchOptions);
|
|
1650
|
+
if (response.status === 204) {
|
|
1651
|
+
return successResponse2(null);
|
|
1652
|
+
}
|
|
1653
|
+
const contentType = response.headers.get("content-type") || "";
|
|
1654
|
+
if (contentType.includes("application/json")) {
|
|
1655
|
+
const json = await response.json();
|
|
1656
|
+
if (response.ok) {
|
|
1657
|
+
return new Response(JSON.stringify(json), {
|
|
1658
|
+
status: response.status,
|
|
1659
|
+
headers: { "Content-Type": "application/json" }
|
|
1660
|
+
});
|
|
1661
|
+
} else {
|
|
1662
|
+
const errMsg = json?.error?.message || json?.message || "Request failed";
|
|
1663
|
+
const errCode = json?.error?.code || json?.code || "PUSH_ERROR";
|
|
1664
|
+
return errorResponse2(errCode, errMsg, response.status);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
const text = await response.text();
|
|
1668
|
+
if (response.ok) {
|
|
1669
|
+
return successResponse2(text);
|
|
1670
|
+
}
|
|
1671
|
+
return errorResponse2("PUSH_ERROR", text || "Request failed", response.status);
|
|
1672
|
+
}
|
|
1673
|
+
function extractSubPath(params) {
|
|
1674
|
+
return (params.action || []).join("/");
|
|
1675
|
+
}
|
|
1676
|
+
const GET = async (request, context) => {
|
|
1677
|
+
try {
|
|
1678
|
+
const params = await context?.params;
|
|
1679
|
+
const subPath = extractSubPath(params || {});
|
|
1680
|
+
return proxyToGateway(request, "GET", subPath);
|
|
1681
|
+
} catch (e) {
|
|
1682
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1683
|
+
}
|
|
1684
|
+
};
|
|
1685
|
+
const POST = async (request, context) => {
|
|
1686
|
+
if (csrf) {
|
|
1687
|
+
const csrfError = validateCSRFToken(request);
|
|
1688
|
+
if (csrfError) {
|
|
1689
|
+
return errorResponse2("CSRF_ERROR", "CSRF validation failed", 403);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
try {
|
|
1693
|
+
const params = await context?.params;
|
|
1694
|
+
const subPath = extractSubPath(params || {});
|
|
1695
|
+
return proxyToGateway(request, "POST", subPath);
|
|
1696
|
+
} catch (e) {
|
|
1697
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
const PUT = async (request, context) => {
|
|
1701
|
+
if (csrf) {
|
|
1702
|
+
const csrfError = validateCSRFToken(request);
|
|
1703
|
+
if (csrfError) {
|
|
1704
|
+
return errorResponse2("CSRF_ERROR", "CSRF validation failed", 403);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
try {
|
|
1708
|
+
const params = await context?.params;
|
|
1709
|
+
const subPath = extractSubPath(params || {});
|
|
1710
|
+
return proxyToGateway(request, "PUT", subPath);
|
|
1711
|
+
} catch (e) {
|
|
1712
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1713
|
+
}
|
|
1714
|
+
};
|
|
1715
|
+
const DELETE = async (request, context) => {
|
|
1716
|
+
if (csrf) {
|
|
1717
|
+
const csrfError = validateCSRFToken(request);
|
|
1718
|
+
if (csrfError) {
|
|
1719
|
+
return errorResponse2("CSRF_ERROR", "CSRF validation failed", 403);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
try {
|
|
1723
|
+
const params = await context?.params;
|
|
1724
|
+
const subPath = extractSubPath(params || {});
|
|
1725
|
+
return proxyToGateway(request, "DELETE", subPath);
|
|
1726
|
+
} catch (e) {
|
|
1727
|
+
return errorResponse2("INTERNAL_ERROR", String(e), 500);
|
|
1728
|
+
}
|
|
1729
|
+
};
|
|
1730
|
+
return { GET, POST, PUT, DELETE };
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1602
1733
|
// src/server/errors.ts
|
|
1603
1734
|
var ScaleMuleError = class extends Error {
|
|
1604
1735
|
constructor(code, message, status = 400, details) {
|
|
@@ -2201,4 +2332,4 @@ async function prefetchBundles(keys) {
|
|
|
2201
2332
|
await Promise.all(keys.map((key) => getBundle(key)));
|
|
2202
2333
|
}
|
|
2203
2334
|
|
|
2204
|
-
export { CSRF_COOKIE_NAME, CSRF_HEADER_NAME, OAUTH_STATE_COOKIE_NAME, SESSION_COOKIE_NAME, ScaleMuleError, ScaleMuleServer, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createServerClient, createWebhookHandler, createWebhookRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, parseWebhookEvent, prefetchBundles, prefetchSecrets, registerVideoWebhook, requireAppSecret, requireBundle, requireSession, resolveGatewayUrl, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, verifyWebhookSignature, withAuth, withCSRFProtection, withCSRFToken, withSession };
|
|
2335
|
+
export { CSRF_COOKIE_NAME, CSRF_HEADER_NAME, OAUTH_STATE_COOKIE_NAME, SESSION_COOKIE_NAME, ScaleMuleError, ScaleMuleServer, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, buildFlagContext, clearOAuthState, clearSession, configureBundles, configureSecrets, createAnalyticsRoutes, createAuthMiddleware, createAuthRoutes, createPushRoutes, createServerClient, createWebhookHandler, createWebhookRoutes, errorCodeToStatus, extractClientContext, extractClientContextFromReq, generateCSRFToken, getAppSecret, getAppSecretOrDefault, getBootstrapFlags, getBundle, getCSRFToken, getMySqlBundle, getOAuthBundle, getPostgresBundle, getRedisBundle, getS3Bundle, getSession, getSessionFromRequest, getSmtpBundle, invalidateBundleCache, invalidateSecretCache, parseWebhookEvent, prefetchBundles, prefetchSecrets, registerVideoWebhook, requireAppSecret, requireBundle, requireSession, resolveGatewayUrl, setOAuthState, unwrap, validateCSRFToken, validateCSRFTokenAsync, validateOAuthState, validateOAuthStateAsync, verifyWebhookSignature, withAuth, withCSRFProtection, withCSRFToken, withSession };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import '../index-
|
|
1
|
+
export { g as createWebhookHandler } from '../webhook-handler-Cz9jtet2.mjs';
|
|
2
|
+
import '../index-BoENfro3.mjs';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import '../index-
|
|
1
|
+
export { g as createWebhookHandler } from '../webhook-handler-CjSSCdvI.js';
|
|
2
|
+
import '../index-BoENfro3.js';
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { U as User,
|
|
3
|
+
import { U as User, A as ApiError, a8 as StorageFile } from './index-BoENfro3.mjs';
|
|
4
4
|
|
|
5
5
|
interface MockUserOptions {
|
|
6
6
|
id?: string;
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { U as User,
|
|
3
|
+
import { U as User, A as ApiError, a8 as StorageFile } from './index-BoENfro3.js';
|
|
4
4
|
|
|
5
5
|
interface MockUserOptions {
|
|
6
6
|
id?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as RegisterRequest, p as ClientContext, U as User, v as LoginRequest, L as LoginResponse, c as ListFilesParams, t as ListFilesResponse, a8 as StorageFile, ae as UploadResponse } from './index-BoENfro3.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Server-Side ScaleMule Client
|
|
@@ -776,4 +776,4 @@ type RouteHandler = (request: Request) => Promise<Response>;
|
|
|
776
776
|
*/
|
|
777
777
|
declare function createWebhookHandler(config?: WebhookHandlerConfig): RouteHandler;
|
|
778
778
|
|
|
779
|
-
export { type ServerConfig as S, type
|
|
779
|
+
export { type ServerConfig as S, type VideoFailedEvent as V, type WebhookEvent as W, ScaleMuleServer as a, type VideoReadyEvent as b, type VideoTranscodedEvent as c, type VideoUploadedEvent as d, type WebhookRoutesConfig as e, createServerClient as f, createWebhookHandler as g, createWebhookRoutes as h, resolveGatewayUrl as i, parseWebhookEvent as p, registerVideoWebhook as r, verifyWebhookSignature as v };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as RegisterRequest, p as ClientContext, U as User, v as LoginRequest, L as LoginResponse, c as ListFilesParams, t as ListFilesResponse, a8 as StorageFile, ae as UploadResponse } from './index-BoENfro3.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Server-Side ScaleMule Client
|
|
@@ -776,4 +776,4 @@ type RouteHandler = (request: Request) => Promise<Response>;
|
|
|
776
776
|
*/
|
|
777
777
|
declare function createWebhookHandler(config?: WebhookHandlerConfig): RouteHandler;
|
|
778
778
|
|
|
779
|
-
export { type ServerConfig as S, type
|
|
779
|
+
export { type ServerConfig as S, type VideoFailedEvent as V, type WebhookEvent as W, ScaleMuleServer as a, type VideoReadyEvent as b, type VideoTranscodedEvent as c, type VideoUploadedEvent as d, type WebhookRoutesConfig as e, createServerClient as f, createWebhookHandler as g, createWebhookRoutes as h, resolveGatewayUrl as i, parseWebhookEvent as p, registerVideoWebhook as r, verifyWebhookSignature as v };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalemule/nextjs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.29",
|
|
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",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"clean": "rm -rf dist"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@scalemule/sdk": "^0.0.
|
|
55
|
+
"@scalemule/sdk": "^0.0.23"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"next": ">=14.0.0",
|