@scalemule/nextjs 0.0.25 → 0.0.27

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 CHANGED
@@ -1,4 +1,4 @@
1
- import { j as StorageAdapter } from './index-CYS_FzSf.mjs';
1
+ import { j as StorageAdapter } from './index-DewTyMF2.mjs';
2
2
 
3
3
  /**
4
4
  * ScaleMule API Client
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { j as StorageAdapter } from './index-CYS_FzSf.js';
1
+ import { j as StorageAdapter } from './index-DewTyMF2.js';
2
2
 
3
3
  /**
4
4
  * ScaleMule API Client
@@ -533,12 +533,36 @@ interface UTMParams {
533
533
  utm_source?: string;
534
534
  /** Marketing medium (e.g., 'cpc', 'email', 'social') */
535
535
  utm_medium?: string;
536
- /** Campaign name */
536
+ /** Campaign name or ID */
537
537
  utm_campaign?: string;
538
538
  /** Search term for paid search */
539
539
  utm_term?: string;
540
540
  /** Content identifier for A/B testing */
541
541
  utm_content?: string;
542
+ /** Ad group name or ID */
543
+ utm_adgroup?: string;
544
+ /** Google Ads click ID (auto-appended by Google) */
545
+ gclid?: string;
546
+ /** Google Ads click ID for iOS (app attribution) */
547
+ gbraid?: string;
548
+ /** Google Ads click ID for web (cross-domain) */
549
+ wbraid?: string;
550
+ /** Facebook/Meta click ID (auto-appended by Meta) */
551
+ fbclid?: string;
552
+ /** Google Ads campaign ID (via ValueTrack {campaignid}) */
553
+ gad_campaignid?: string;
554
+ /** Google Ads ad group ID (via ValueTrack {adgroupid}) */
555
+ gad_adgroupid?: string;
556
+ /** Google Ads network: g=search, d=display, y=youtube */
557
+ gad_network?: string;
558
+ /** Google Ads match type: b=broad, p=phrase, e=exact */
559
+ gad_matchtype?: string;
560
+ /** Google Ads device: m=mobile, c=desktop, t=tablet */
561
+ gad_device?: string;
562
+ /** Google Ads placement (display/youtube site) */
563
+ gad_placement?: string;
564
+ /** Google Ads source identifier */
565
+ gad_source?: string;
542
566
  }
543
567
  /**
544
568
  * Device information for analytics
@@ -533,12 +533,36 @@ interface UTMParams {
533
533
  utm_source?: string;
534
534
  /** Marketing medium (e.g., 'cpc', 'email', 'social') */
535
535
  utm_medium?: string;
536
- /** Campaign name */
536
+ /** Campaign name or ID */
537
537
  utm_campaign?: string;
538
538
  /** Search term for paid search */
539
539
  utm_term?: string;
540
540
  /** Content identifier for A/B testing */
541
541
  utm_content?: string;
542
+ /** Ad group name or ID */
543
+ utm_adgroup?: string;
544
+ /** Google Ads click ID (auto-appended by Google) */
545
+ gclid?: string;
546
+ /** Google Ads click ID for iOS (app attribution) */
547
+ gbraid?: string;
548
+ /** Google Ads click ID for web (cross-domain) */
549
+ wbraid?: string;
550
+ /** Facebook/Meta click ID (auto-appended by Meta) */
551
+ fbclid?: string;
552
+ /** Google Ads campaign ID (via ValueTrack {campaignid}) */
553
+ gad_campaignid?: string;
554
+ /** Google Ads ad group ID (via ValueTrack {adgroupid}) */
555
+ gad_adgroupid?: string;
556
+ /** Google Ads network: g=search, d=display, y=youtube */
557
+ gad_network?: string;
558
+ /** Google Ads match type: b=broad, p=phrase, e=exact */
559
+ gad_matchtype?: string;
560
+ /** Google Ads device: m=mobile, c=desktop, t=tablet */
561
+ gad_device?: string;
562
+ /** Google Ads placement (display/youtube site) */
563
+ gad_placement?: string;
564
+ /** Google Ads source identifier */
565
+ gad_source?: string;
542
566
  }
543
567
  /**
544
568
  * Device information for analytics
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-CYS_FzSf.mjs';
6
- export { a2 as AccountBalance, a9 as AnalyticsEvent, k as ApiResponse, af as BatchTrackRequest, a3 as BillingPayment, a5 as BillingPayout, a4 as BillingRefund, a7 as BillingTransaction, r as ChangeEmailRequest, C as ChangePasswordRequest, $ as ClientContext, a1 as ConnectedAccount, D as DeviceFingerprint, ac as DeviceInfo, ad as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, x as LinkedAccount, T as ListFilesResponse, n as LoginDeviceInfo, l as LoginRequest, m as LoginResponseWithMFA, o as LoginRiskInfo, G as MFAChallengeResponse, M as MFAMethod, B as MFASMSSetupResponse, y as MFASetupRequest, H as MFAStatus, z as MFATOTPSetupResponse, E as MFAVerifyRequest, v as OAuthCallbackRequest, w as OAuthCallbackResponse, t as OAuthConfig, O as OAuthProvider, u as OAuthStartResponse, aa as PageViewData, a6 as PayoutSchedule, K as PhoneLoginRequest, I as PhoneSendCodeRequest, J as PhoneVerifyRequest, P as Profile, p as RefreshResponse, R as RegisterRequest, q as ResetPasswordRequest, h as ScaleMuleApiError, i as ScaleMuleEnvironment, s as Session, _ as SignedUploadCompleteRequest, Y as SignedUploadRequest, Z as SignedUploadResponse, X as SignedUploadUrl, j as StorageAdapter, N as StorageFile, ae as TrackEventResponse, a8 as TransactionSummary, ab as UTMParams, a0 as UpdateProfileRequest, Q as UploadOptions, W as UploadResponse, V as VerifyEmailRequest } from './index-CYS_FzSf.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-DewTyMF2.mjs';
6
+ export { a2 as AccountBalance, a9 as AnalyticsEvent, k as ApiResponse, af as BatchTrackRequest, a3 as BillingPayment, a5 as BillingPayout, a4 as BillingRefund, a7 as BillingTransaction, r as ChangeEmailRequest, C as ChangePasswordRequest, $ as ClientContext, a1 as ConnectedAccount, D as DeviceFingerprint, ac as DeviceInfo, ad as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, x as LinkedAccount, T as ListFilesResponse, n as LoginDeviceInfo, l as LoginRequest, m as LoginResponseWithMFA, o as LoginRiskInfo, G as MFAChallengeResponse, M as MFAMethod, B as MFASMSSetupResponse, y as MFASetupRequest, H as MFAStatus, z as MFATOTPSetupResponse, E as MFAVerifyRequest, v as OAuthCallbackRequest, w as OAuthCallbackResponse, t as OAuthConfig, O as OAuthProvider, u as OAuthStartResponse, aa as PageViewData, a6 as PayoutSchedule, K as PhoneLoginRequest, I as PhoneSendCodeRequest, J as PhoneVerifyRequest, P as Profile, p as RefreshResponse, R as RegisterRequest, q as ResetPasswordRequest, h as ScaleMuleApiError, i as ScaleMuleEnvironment, s as Session, _ as SignedUploadCompleteRequest, Y as SignedUploadRequest, Z as SignedUploadResponse, X as SignedUploadUrl, j as StorageAdapter, N as StorageFile, ae as TrackEventResponse, a8 as TransactionSummary, ab as UTMParams, a0 as UpdateProfileRequest, Q as UploadOptions, W as UploadResponse, V as VerifyEmailRequest } from './index-DewTyMF2.mjs';
7
7
 
8
8
  interface ScaleMuleContextValue {
9
9
  /** The API client instance */
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-CYS_FzSf.js';
6
- export { a2 as AccountBalance, a9 as AnalyticsEvent, k as ApiResponse, af as BatchTrackRequest, a3 as BillingPayment, a5 as BillingPayout, a4 as BillingRefund, a7 as BillingTransaction, r as ChangeEmailRequest, C as ChangePasswordRequest, $ as ClientContext, a1 as ConnectedAccount, D as DeviceFingerprint, ac as DeviceInfo, ad as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, x as LinkedAccount, T as ListFilesResponse, n as LoginDeviceInfo, l as LoginRequest, m as LoginResponseWithMFA, o as LoginRiskInfo, G as MFAChallengeResponse, M as MFAMethod, B as MFASMSSetupResponse, y as MFASetupRequest, H as MFAStatus, z as MFATOTPSetupResponse, E as MFAVerifyRequest, v as OAuthCallbackRequest, w as OAuthCallbackResponse, t as OAuthConfig, O as OAuthProvider, u as OAuthStartResponse, aa as PageViewData, a6 as PayoutSchedule, K as PhoneLoginRequest, I as PhoneSendCodeRequest, J as PhoneVerifyRequest, P as Profile, p as RefreshResponse, R as RegisterRequest, q as ResetPasswordRequest, h as ScaleMuleApiError, i as ScaleMuleEnvironment, s as Session, _ as SignedUploadCompleteRequest, Y as SignedUploadRequest, Z as SignedUploadResponse, X as SignedUploadUrl, j as StorageAdapter, N as StorageFile, ae as TrackEventResponse, a8 as TransactionSummary, ab as UTMParams, a0 as UpdateProfileRequest, Q as UploadOptions, W as UploadResponse, V as VerifyEmailRequest } from './index-CYS_FzSf.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-DewTyMF2.js';
6
+ export { a2 as AccountBalance, a9 as AnalyticsEvent, k as ApiResponse, af as BatchTrackRequest, a3 as BillingPayment, a5 as BillingPayout, a4 as BillingRefund, a7 as BillingTransaction, r as ChangeEmailRequest, C as ChangePasswordRequest, $ as ClientContext, a1 as ConnectedAccount, D as DeviceFingerprint, ac as DeviceInfo, ad as EnhancedAnalyticsEvent, F as ForgotPasswordRequest, x as LinkedAccount, T as ListFilesResponse, n as LoginDeviceInfo, l as LoginRequest, m as LoginResponseWithMFA, o as LoginRiskInfo, G as MFAChallengeResponse, M as MFAMethod, B as MFASMSSetupResponse, y as MFASetupRequest, H as MFAStatus, z as MFATOTPSetupResponse, E as MFAVerifyRequest, v as OAuthCallbackRequest, w as OAuthCallbackResponse, t as OAuthConfig, O as OAuthProvider, u as OAuthStartResponse, aa as PageViewData, a6 as PayoutSchedule, K as PhoneLoginRequest, I as PhoneSendCodeRequest, J as PhoneVerifyRequest, P as Profile, p as RefreshResponse, R as RegisterRequest, q as ResetPasswordRequest, h as ScaleMuleApiError, i as ScaleMuleEnvironment, s as Session, _ as SignedUploadCompleteRequest, Y as SignedUploadRequest, Z as SignedUploadResponse, X as SignedUploadUrl, j as StorageAdapter, N as StorageFile, ae as TrackEventResponse, a8 as TransactionSummary, ab as UTMParams, a0 as UpdateProfileRequest, Q as UploadOptions, W as UploadResponse, V as VerifyEmailRequest } from './index-DewTyMF2.js';
7
7
 
8
8
  interface ScaleMuleContextValue {
9
9
  /** The API client instance */
package/dist/index.js CHANGED
@@ -2511,20 +2511,34 @@ function parseUtmParams() {
2511
2511
  const campaign = params.get("utm_campaign");
2512
2512
  const term = params.get("utm_term");
2513
2513
  const content = params.get("utm_content");
2514
+ const adgroup = params.get("utm_adgroup");
2514
2515
  if (source) utm.utm_source = source;
2515
2516
  if (medium) utm.utm_medium = medium;
2516
2517
  if (campaign) utm.utm_campaign = campaign;
2517
2518
  if (term) utm.utm_term = term;
2518
2519
  if (content) utm.utm_content = content;
2519
- if (!utm.utm_source && (params.get("gclid") || params.get("gad_source") || params.get("wbraid") || params.get("gbraid"))) {
2520
+ if (adgroup) utm.utm_adgroup = adgroup;
2521
+ const gclid = params.get("gclid");
2522
+ const gbraid = params.get("gbraid");
2523
+ const wbraid = params.get("wbraid");
2524
+ const fbclid = params.get("fbclid");
2525
+ if (gclid) utm.gclid = gclid;
2526
+ if (gbraid) utm.gbraid = gbraid;
2527
+ if (wbraid) utm.wbraid = wbraid;
2528
+ if (fbclid) utm.fbclid = fbclid;
2529
+ const gadFields = ["gad_source", "gad_campaignid", "gad_adgroupid", "gad_network", "gad_matchtype", "gad_device", "gad_placement"];
2530
+ for (const field of gadFields) {
2531
+ const val = params.get(field);
2532
+ if (val) utm[field] = val;
2533
+ }
2534
+ if (!utm.utm_source && (gclid || utm.gad_source || wbraid || gbraid)) {
2520
2535
  utm.utm_source = "google";
2521
2536
  utm.utm_medium = utm.utm_medium || "cpc";
2522
- const gadCampaign = params.get("gad_campaignid");
2523
- if (gadCampaign && !utm.utm_campaign) {
2524
- utm.utm_campaign = gadCampaign;
2537
+ if (utm.gad_campaignid && !utm.utm_campaign) {
2538
+ utm.utm_campaign = utm.gad_campaignid;
2525
2539
  }
2526
2540
  }
2527
- if (!utm.utm_source && params.get("fbclid")) {
2541
+ if (!utm.utm_source && fbclid) {
2528
2542
  utm.utm_source = "facebook";
2529
2543
  utm.utm_medium = utm.utm_medium || "cpc";
2530
2544
  }
package/dist/index.mjs CHANGED
@@ -2509,20 +2509,34 @@ function parseUtmParams() {
2509
2509
  const campaign = params.get("utm_campaign");
2510
2510
  const term = params.get("utm_term");
2511
2511
  const content = params.get("utm_content");
2512
+ const adgroup = params.get("utm_adgroup");
2512
2513
  if (source) utm.utm_source = source;
2513
2514
  if (medium) utm.utm_medium = medium;
2514
2515
  if (campaign) utm.utm_campaign = campaign;
2515
2516
  if (term) utm.utm_term = term;
2516
2517
  if (content) utm.utm_content = content;
2517
- if (!utm.utm_source && (params.get("gclid") || params.get("gad_source") || params.get("wbraid") || params.get("gbraid"))) {
2518
+ if (adgroup) utm.utm_adgroup = adgroup;
2519
+ const gclid = params.get("gclid");
2520
+ const gbraid = params.get("gbraid");
2521
+ const wbraid = params.get("wbraid");
2522
+ const fbclid = params.get("fbclid");
2523
+ if (gclid) utm.gclid = gclid;
2524
+ if (gbraid) utm.gbraid = gbraid;
2525
+ if (wbraid) utm.wbraid = wbraid;
2526
+ if (fbclid) utm.fbclid = fbclid;
2527
+ const gadFields = ["gad_source", "gad_campaignid", "gad_adgroupid", "gad_network", "gad_matchtype", "gad_device", "gad_placement"];
2528
+ for (const field of gadFields) {
2529
+ const val = params.get(field);
2530
+ if (val) utm[field] = val;
2531
+ }
2532
+ if (!utm.utm_source && (gclid || utm.gad_source || wbraid || gbraid)) {
2518
2533
  utm.utm_source = "google";
2519
2534
  utm.utm_medium = utm.utm_medium || "cpc";
2520
- const gadCampaign = params.get("gad_campaignid");
2521
- if (gadCampaign && !utm.utm_campaign) {
2522
- utm.utm_campaign = gadCampaign;
2535
+ if (utm.gad_campaignid && !utm.utm_campaign) {
2536
+ utm.utm_campaign = utm.gad_campaignid;
2523
2537
  }
2524
2538
  }
2525
- if (!utm.utm_source && params.get("fbclid")) {
2539
+ if (!utm.utm_source && fbclid) {
2526
2540
  utm.utm_source = "facebook";
2527
2541
  utm.utm_medium = utm.utm_medium || "cpc";
2528
2542
  }
@@ -1,6 +1,6 @@
1
- import { S as ServerConfig } from '../webhook-handler-BlklRG--.mjs';
2
- export { a as ScaleMuleServer, e as VideoFailedEvent, V as VideoReadyEvent, g as VideoTranscodedEvent, f as VideoUploadedEvent, W as WebhookEvent, h as WebhookRoutesConfig, c as createServerClient, i as createWebhookHandler, d as createWebhookRoutes, p as parseWebhookEvent, b as registerVideoWebhook, r as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-BlklRG--.mjs';
3
- import { $ as ClientContext, A as ApiError } from '../index-CYS_FzSf.mjs';
1
+ import { S as ServerConfig } from '../webhook-handler-DS0r_w4M.mjs';
2
+ export { a as ScaleMuleServer, e as VideoFailedEvent, V as VideoReadyEvent, g as VideoTranscodedEvent, f as VideoUploadedEvent, W as WebhookEvent, h as WebhookRoutesConfig, c as createServerClient, i as createWebhookHandler, d as createWebhookRoutes, p as parseWebhookEvent, b as registerVideoWebhook, r as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-DS0r_w4M.mjs';
3
+ import { $ as ClientContext, A as ApiError } from '../index-DewTyMF2.mjs';
4
4
  import { NextRequest, NextResponse } from 'next/server';
5
5
 
6
6
  /**
@@ -94,6 +94,13 @@ declare function extractClientContextFromReq(req: IncomingMessageLike): ClientCo
94
94
  * @internal
95
95
  */
96
96
  declare function buildClientContextHeaders(context: ClientContext | undefined): Record<string, string>;
97
+ /**
98
+ * Build feature-flag evaluation context from forwarded client context.
99
+ *
100
+ * This keeps server-side flag evaluation aligned with targeting rules that use
101
+ * `ip_address`, while letting callers merge any additional attributes they need.
102
+ */
103
+ declare function buildFlagContext(clientContext: Pick<ClientContext, 'ip'> | undefined, extraContext?: Record<string, unknown>): Record<string, unknown>;
97
104
 
98
105
  /**
99
106
  * Cookie Utilities for Secure Session Management
@@ -262,6 +269,27 @@ declare function createAuthRoutes(config?: AuthRoutesConfig): {
262
269
  DELETE: RouteHandler;
263
270
  PATCH: RouteHandler;
264
271
  };
272
+ interface AnalyticsTrackingGateConfig {
273
+ /** Feature flag key used to decide whether to forward analytics */
274
+ flagKey: string;
275
+ /** Feature flag environment (default: 'prod') */
276
+ environment?: string;
277
+ /**
278
+ * When true, analytics continues if flag evaluation fails.
279
+ * Default: true
280
+ */
281
+ failOpen?: boolean;
282
+ /**
283
+ * Build feature-flag evaluation context from the inbound analytics request.
284
+ * Defaults to { ip_address, user_id, anonymous_id, session_id, event_name, page_url }
285
+ * when those values are present.
286
+ */
287
+ buildContext?: (args: {
288
+ body: Record<string, unknown>;
289
+ clientContext: ClientContext;
290
+ request: Request;
291
+ }) => Record<string, unknown>;
292
+ }
265
293
  interface AnalyticsRoutesConfig {
266
294
  /** Server client config (optional if using env vars) */
267
295
  client?: Partial<ServerConfig>;
@@ -276,6 +304,12 @@ interface AnalyticsRoutesConfig {
276
304
  * Default: false (uses catch-all route pattern)
277
305
  */
278
306
  simpleProxy?: boolean;
307
+ /**
308
+ * Optional feature flag gate that suppresses analytics forwarding when the
309
+ * evaluated flag returns false. Useful for test users, internal IPs, or
310
+ * staged rollouts without adding app-specific proxy logic.
311
+ */
312
+ trackingGate?: AnalyticsTrackingGateConfig;
279
313
  }
280
314
  /**
281
315
  * Create analytics API route handlers
@@ -906,4 +940,4 @@ declare function invalidateBundleCache(key?: string): void;
906
940
  */
907
941
  declare function prefetchBundles(keys: string[]): Promise<void>;
908
942
 
909
- export { type AnalyticsRoutesConfig, 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, 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 };
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 };
@@ -1,6 +1,6 @@
1
- import { S as ServerConfig } from '../webhook-handler-DHCE2Utl.js';
2
- export { a as ScaleMuleServer, e as VideoFailedEvent, V as VideoReadyEvent, g as VideoTranscodedEvent, f as VideoUploadedEvent, W as WebhookEvent, h as WebhookRoutesConfig, c as createServerClient, i as createWebhookHandler, d as createWebhookRoutes, p as parseWebhookEvent, b as registerVideoWebhook, r as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-DHCE2Utl.js';
3
- import { $ as ClientContext, A as ApiError } from '../index-CYS_FzSf.js';
1
+ import { S as ServerConfig } from '../webhook-handler-CQ2lZgy0.js';
2
+ export { a as ScaleMuleServer, e as VideoFailedEvent, V as VideoReadyEvent, g as VideoTranscodedEvent, f as VideoUploadedEvent, W as WebhookEvent, h as WebhookRoutesConfig, c as createServerClient, i as createWebhookHandler, d as createWebhookRoutes, p as parseWebhookEvent, b as registerVideoWebhook, r as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-CQ2lZgy0.js';
3
+ import { $ as ClientContext, A as ApiError } from '../index-DewTyMF2.js';
4
4
  import { NextRequest, NextResponse } from 'next/server';
5
5
 
6
6
  /**
@@ -94,6 +94,13 @@ declare function extractClientContextFromReq(req: IncomingMessageLike): ClientCo
94
94
  * @internal
95
95
  */
96
96
  declare function buildClientContextHeaders(context: ClientContext | undefined): Record<string, string>;
97
+ /**
98
+ * Build feature-flag evaluation context from forwarded client context.
99
+ *
100
+ * This keeps server-side flag evaluation aligned with targeting rules that use
101
+ * `ip_address`, while letting callers merge any additional attributes they need.
102
+ */
103
+ declare function buildFlagContext(clientContext: Pick<ClientContext, 'ip'> | undefined, extraContext?: Record<string, unknown>): Record<string, unknown>;
97
104
 
98
105
  /**
99
106
  * Cookie Utilities for Secure Session Management
@@ -262,6 +269,27 @@ declare function createAuthRoutes(config?: AuthRoutesConfig): {
262
269
  DELETE: RouteHandler;
263
270
  PATCH: RouteHandler;
264
271
  };
272
+ interface AnalyticsTrackingGateConfig {
273
+ /** Feature flag key used to decide whether to forward analytics */
274
+ flagKey: string;
275
+ /** Feature flag environment (default: 'prod') */
276
+ environment?: string;
277
+ /**
278
+ * When true, analytics continues if flag evaluation fails.
279
+ * Default: true
280
+ */
281
+ failOpen?: boolean;
282
+ /**
283
+ * Build feature-flag evaluation context from the inbound analytics request.
284
+ * Defaults to { ip_address, user_id, anonymous_id, session_id, event_name, page_url }
285
+ * when those values are present.
286
+ */
287
+ buildContext?: (args: {
288
+ body: Record<string, unknown>;
289
+ clientContext: ClientContext;
290
+ request: Request;
291
+ }) => Record<string, unknown>;
292
+ }
265
293
  interface AnalyticsRoutesConfig {
266
294
  /** Server client config (optional if using env vars) */
267
295
  client?: Partial<ServerConfig>;
@@ -276,6 +304,12 @@ interface AnalyticsRoutesConfig {
276
304
  * Default: false (uses catch-all route pattern)
277
305
  */
278
306
  simpleProxy?: boolean;
307
+ /**
308
+ * Optional feature flag gate that suppresses analytics forwarding when the
309
+ * evaluated flag returns false. Useful for test users, internal IPs, or
310
+ * staged rollouts without adding app-specific proxy logic.
311
+ */
312
+ trackingGate?: AnalyticsTrackingGateConfig;
279
313
  }
280
314
  /**
281
315
  * Create analytics API route handlers
@@ -906,4 +940,4 @@ declare function invalidateBundleCache(key?: string): void;
906
940
  */
907
941
  declare function prefetchBundles(keys: string[]): Promise<void>;
908
942
 
909
- export { type AnalyticsRoutesConfig, 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, 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 };
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 };
@@ -159,6 +159,13 @@ function buildClientContextHeaders(context) {
159
159
  }
160
160
  return headers2;
161
161
  }
162
+ function buildFlagContext(clientContext, extraContext = {}) {
163
+ const context = { ...extraContext };
164
+ if (clientContext?.ip && context.ip_address === void 0) {
165
+ context.ip_address = clientContext.ip;
166
+ }
167
+ return context;
168
+ }
162
169
 
163
170
  // src/server/client.ts
164
171
  var GATEWAY_URLS = {
@@ -1385,8 +1392,50 @@ function createAuthRoutes(config = {}) {
1385
1392
  };
1386
1393
  return { GET, POST, DELETE, PATCH };
1387
1394
  }
1395
+ function getPrimaryTrackingContextSource(body) {
1396
+ if (Array.isArray(body.events)) {
1397
+ const firstEvent = body.events.find((event) => event && typeof event === "object" && !Array.isArray(event));
1398
+ if (firstEvent && typeof firstEvent === "object" && !Array.isArray(firstEvent)) {
1399
+ return firstEvent;
1400
+ }
1401
+ }
1402
+ return body;
1403
+ }
1404
+ function buildDefaultTrackingGateContext(args) {
1405
+ const source = getPrimaryTrackingContextSource(args.body);
1406
+ const extraContext = {};
1407
+ for (const key of ["user_id", "anonymous_id", "session_id", "event_name", "page_url"]) {
1408
+ const value = source[key];
1409
+ if (typeof value === "string" && value.trim()) {
1410
+ extraContext[key] = value;
1411
+ }
1412
+ }
1413
+ return buildFlagContext(args.clientContext, extraContext);
1414
+ }
1388
1415
  function createAnalyticsRoutes(config = {}) {
1389
1416
  const sm = createServerClient(config.client);
1417
+ const shouldSuppressTracking = async (body, clientContext, request) => {
1418
+ const gate = config.trackingGate;
1419
+ if (!gate) {
1420
+ return false;
1421
+ }
1422
+ try {
1423
+ const contextBuilder = gate.buildContext || ((args) => buildDefaultTrackingGateContext(args));
1424
+ const evaluation = await sm.flags.evaluate(
1425
+ gate.flagKey,
1426
+ contextBuilder({ body, clientContext, request }) || {},
1427
+ gate.environment || "prod",
1428
+ { clientContext }
1429
+ );
1430
+ return evaluation?.value === false;
1431
+ } catch (err) {
1432
+ if (gate.failOpen === false) {
1433
+ console.warn(`[ScaleMule Analytics] Tracking gate blocked "${gate.flagKey}" after evaluation failure`, err);
1434
+ return true;
1435
+ }
1436
+ return false;
1437
+ }
1438
+ };
1390
1439
  const handleTrackEvent = async (body, clientContext) => {
1391
1440
  const {
1392
1441
  event_name,
@@ -1469,8 +1518,12 @@ function createAnalyticsRoutes(config = {}) {
1469
1518
  };
1470
1519
  const POST = async (request, context) => {
1471
1520
  try {
1472
- const body = await request.json().catch(() => ({}));
1521
+ const rawBody = await request.json().catch(() => ({}));
1522
+ const body = rawBody && typeof rawBody === "object" && !Array.isArray(rawBody) ? rawBody : {};
1473
1523
  const clientContext = extractClientContext(request);
1524
+ if (await shouldSuppressTracking(body, clientContext, request)) {
1525
+ return successResponse({ tracked: 0, suppressed: true }, 202);
1526
+ }
1474
1527
  if (config.simpleProxy) {
1475
1528
  return handleTrackEvent(body, clientContext);
1476
1529
  }
@@ -1515,7 +1568,13 @@ function createAnalyticsRoutes(config = {}) {
1515
1568
  let pageViewResult;
1516
1569
  try {
1517
1570
  pageViewResult = await sm.analytics.trackPageView(
1518
- { page_url, page_title, referrer, session_id, user_id },
1571
+ {
1572
+ page_url,
1573
+ page_title,
1574
+ referrer,
1575
+ session_id,
1576
+ user_id
1577
+ },
1519
1578
  { clientContext }
1520
1579
  );
1521
1580
  } catch (err) {
@@ -2153,6 +2212,7 @@ exports.ScaleMuleServer = ScaleMuleServer;
2153
2212
  exports.USER_ID_COOKIE_NAME = USER_ID_COOKIE_NAME;
2154
2213
  exports.apiHandler = apiHandler;
2155
2214
  exports.buildClientContextHeaders = buildClientContextHeaders;
2215
+ exports.buildFlagContext = buildFlagContext;
2156
2216
  exports.clearOAuthState = clearOAuthState;
2157
2217
  exports.clearSession = clearSession;
2158
2218
  exports.configureBundles = configureBundles;
@@ -157,6 +157,13 @@ function buildClientContextHeaders(context) {
157
157
  }
158
158
  return headers2;
159
159
  }
160
+ function buildFlagContext(clientContext, extraContext = {}) {
161
+ const context = { ...extraContext };
162
+ if (clientContext?.ip && context.ip_address === void 0) {
163
+ context.ip_address = clientContext.ip;
164
+ }
165
+ return context;
166
+ }
160
167
 
161
168
  // src/server/client.ts
162
169
  var GATEWAY_URLS = {
@@ -1383,8 +1390,50 @@ function createAuthRoutes(config = {}) {
1383
1390
  };
1384
1391
  return { GET, POST, DELETE, PATCH };
1385
1392
  }
1393
+ function getPrimaryTrackingContextSource(body) {
1394
+ if (Array.isArray(body.events)) {
1395
+ const firstEvent = body.events.find((event) => event && typeof event === "object" && !Array.isArray(event));
1396
+ if (firstEvent && typeof firstEvent === "object" && !Array.isArray(firstEvent)) {
1397
+ return firstEvent;
1398
+ }
1399
+ }
1400
+ return body;
1401
+ }
1402
+ function buildDefaultTrackingGateContext(args) {
1403
+ const source = getPrimaryTrackingContextSource(args.body);
1404
+ const extraContext = {};
1405
+ for (const key of ["user_id", "anonymous_id", "session_id", "event_name", "page_url"]) {
1406
+ const value = source[key];
1407
+ if (typeof value === "string" && value.trim()) {
1408
+ extraContext[key] = value;
1409
+ }
1410
+ }
1411
+ return buildFlagContext(args.clientContext, extraContext);
1412
+ }
1386
1413
  function createAnalyticsRoutes(config = {}) {
1387
1414
  const sm = createServerClient(config.client);
1415
+ const shouldSuppressTracking = async (body, clientContext, request) => {
1416
+ const gate = config.trackingGate;
1417
+ if (!gate) {
1418
+ return false;
1419
+ }
1420
+ try {
1421
+ const contextBuilder = gate.buildContext || ((args) => buildDefaultTrackingGateContext(args));
1422
+ const evaluation = await sm.flags.evaluate(
1423
+ gate.flagKey,
1424
+ contextBuilder({ body, clientContext, request }) || {},
1425
+ gate.environment || "prod",
1426
+ { clientContext }
1427
+ );
1428
+ return evaluation?.value === false;
1429
+ } catch (err) {
1430
+ if (gate.failOpen === false) {
1431
+ console.warn(`[ScaleMule Analytics] Tracking gate blocked "${gate.flagKey}" after evaluation failure`, err);
1432
+ return true;
1433
+ }
1434
+ return false;
1435
+ }
1436
+ };
1388
1437
  const handleTrackEvent = async (body, clientContext) => {
1389
1438
  const {
1390
1439
  event_name,
@@ -1467,8 +1516,12 @@ function createAnalyticsRoutes(config = {}) {
1467
1516
  };
1468
1517
  const POST = async (request, context) => {
1469
1518
  try {
1470
- const body = await request.json().catch(() => ({}));
1519
+ const rawBody = await request.json().catch(() => ({}));
1520
+ const body = rawBody && typeof rawBody === "object" && !Array.isArray(rawBody) ? rawBody : {};
1471
1521
  const clientContext = extractClientContext(request);
1522
+ if (await shouldSuppressTracking(body, clientContext, request)) {
1523
+ return successResponse({ tracked: 0, suppressed: true }, 202);
1524
+ }
1472
1525
  if (config.simpleProxy) {
1473
1526
  return handleTrackEvent(body, clientContext);
1474
1527
  }
@@ -1513,7 +1566,13 @@ function createAnalyticsRoutes(config = {}) {
1513
1566
  let pageViewResult;
1514
1567
  try {
1515
1568
  pageViewResult = await sm.analytics.trackPageView(
1516
- { page_url, page_title, referrer, session_id, user_id },
1569
+ {
1570
+ page_url,
1571
+ page_title,
1572
+ referrer,
1573
+ session_id,
1574
+ user_id
1575
+ },
1517
1576
  { clientContext }
1518
1577
  );
1519
1578
  } catch (err) {
@@ -2142,4 +2201,4 @@ async function prefetchBundles(keys) {
2142
2201
  await Promise.all(keys.map((key) => getBundle(key)));
2143
2202
  }
2144
2203
 
2145
- export { CSRF_COOKIE_NAME, CSRF_HEADER_NAME, OAUTH_STATE_COOKIE_NAME, SESSION_COOKIE_NAME, ScaleMuleError, ScaleMuleServer, USER_ID_COOKIE_NAME, apiHandler, buildClientContextHeaders, 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 };
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 };
@@ -1,2 +1,2 @@
1
- export { i as createWebhookHandler } from '../webhook-handler-BlklRG--.mjs';
2
- import '../index-CYS_FzSf.mjs';
1
+ export { i as createWebhookHandler } from '../webhook-handler-DS0r_w4M.mjs';
2
+ import '../index-DewTyMF2.mjs';
@@ -1,2 +1,2 @@
1
- export { i as createWebhookHandler } from '../webhook-handler-DHCE2Utl.js';
2
- import '../index-CYS_FzSf.js';
1
+ export { i as createWebhookHandler } from '../webhook-handler-CQ2lZgy0.js';
2
+ import '../index-DewTyMF2.js';
@@ -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, N as StorageFile, A as ApiError } from './index-CYS_FzSf.mjs';
3
+ import { U as User, N as StorageFile, A as ApiError } from './index-DewTyMF2.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, N as StorageFile, A as ApiError } from './index-CYS_FzSf.js';
3
+ import { U as User, N as StorageFile, A as ApiError } from './index-DewTyMF2.js';
4
4
 
5
5
  interface MockUserOptions {
6
6
  id?: string;
@@ -1,4 +1,4 @@
1
- import { R as RegisterRequest, $ as ClientContext, U as User, l as LoginRequest, L as LoginResponse, c as ListFilesParams, T as ListFilesResponse, N as StorageFile, W as UploadResponse } from './index-CYS_FzSf.js';
1
+ import { R as RegisterRequest, $ as ClientContext, U as User, l as LoginRequest, L as LoginResponse, c as ListFilesParams, T as ListFilesResponse, N as StorageFile, W as UploadResponse } from './index-DewTyMF2.js';
2
2
 
3
3
  /**
4
4
  * Server-Side ScaleMule Client
@@ -1,4 +1,4 @@
1
- import { R as RegisterRequest, $ as ClientContext, U as User, l as LoginRequest, L as LoginResponse, c as ListFilesParams, T as ListFilesResponse, N as StorageFile, W as UploadResponse } from './index-CYS_FzSf.mjs';
1
+ import { R as RegisterRequest, $ as ClientContext, U as User, l as LoginRequest, L as LoginResponse, c as ListFilesParams, T as ListFilesResponse, N as StorageFile, W as UploadResponse } from './index-DewTyMF2.mjs';
2
2
 
3
3
  /**
4
4
  * Server-Side ScaleMule Client
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalemule/nextjs",
3
- "version": "0.0.25",
3
+ "version": "0.0.27",
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",