sitepong 0.2.13 → 0.2.15

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.
@@ -360,6 +360,14 @@ interface SitePongInitConfig extends SitePongConfig {
360
360
  blockSelector?: string;
361
361
  /** CSS selector whose text is masked in the screen template */
362
362
  maskSelector?: string;
363
+ /**
364
+ * Release channel / environment tagged on events (development | preview |
365
+ * production | …). Defaults to the SDK `environment` (usually 'production').
366
+ * A channel in `ignoreChannels` suppresses capture entirely.
367
+ */
368
+ channel?: string;
369
+ /** Channels for which capture is a no-op (default ['development']). */
370
+ ignoreChannels?: string[];
363
371
  };
364
372
  /** Cron monitoring configuration */
365
373
  crons?: {
@@ -738,6 +746,17 @@ interface WatchtowerConfig {
738
746
  * Default 30_000 (30s). Lower it in tests to exercise session rolling.
739
747
  */
740
748
  sessionGraceMs?: number;
749
+ /**
750
+ * Release channel / environment tagged on every event (development | preview
751
+ * | production | …). When omitted, the native engine auto-resolves it:
752
+ * debug builds → "development", release builds → "production".
753
+ */
754
+ channel?: string;
755
+ /**
756
+ * Channels for which capture is a complete no-op (default ["development"]).
757
+ * Debug builds thus self-suppress; pass [] to capture dev on demand.
758
+ */
759
+ ignoreChannels?: string[];
741
760
  }
742
761
  /**
743
762
  * Start the shared native capture engine for React Native. Idempotent.
@@ -749,7 +768,7 @@ declare function startWatchtower(config: WatchtowerConfig): void;
749
768
  * Set user identity — stamped as distinct_id on every subsequent event. Call
750
769
  * this wherever you call the SDK's identify(), with the same id.
751
770
  */
752
- declare function setWatchtowerUser(distinctId: string | null): void;
771
+ declare function setWatchtowerUser(distinctId: string | null, email?: string | null, name?: string | null): void;
753
772
  /**
754
773
  * The engine's current capture session id (null when not running). Attach it
755
774
  * to error reports/analytics — it is the key that joins an error to its
@@ -792,6 +811,14 @@ interface StructuralCaptureConfig {
792
811
  sampleIntervalMs?: number;
793
812
  flushIntervalMs?: number;
794
813
  debug?: boolean;
814
+ /**
815
+ * Release channel / environment (development | preview | production | …).
816
+ * Defaults to 'development' under __DEV__, else 'production'. A channel in
817
+ * `ignoreChannels` makes start() a no-op so dev replays are never sent.
818
+ */
819
+ channel?: string;
820
+ /** Channels for which capture is a no-op (default ['development']). */
821
+ ignoreChannels?: string[];
795
822
  }
796
823
  declare class StructuralCapture {
797
824
  private readonly recorder;
@@ -2625,7 +2625,7 @@ var SitePongClient = class {
2625
2625
  }
2626
2626
  for (const hook of this.identifyHooks) {
2627
2627
  try {
2628
- hook(userId);
2628
+ hook(userId, traits);
2629
2629
  } catch (err) {
2630
2630
  this.log("identify hook failed:", err);
2631
2631
  }
@@ -2731,6 +2731,10 @@ var SitePongClient = class {
2731
2731
  flushInterval: opts.flushInterval,
2732
2732
  blockSelector: opts.blockSelector,
2733
2733
  maskSelector: opts.maskSelector,
2734
+ // Channel defaults to the SDK environment; ignoreChannels defaults to
2735
+ // ['development'] inside the capture when omitted.
2736
+ channel: opts.channel ?? this.config.environment,
2737
+ ignoreChannels: opts.ignoreChannels,
2734
2738
  debug: this.config.debug
2735
2739
  });
2736
2740
  this.watchtowerCapture.start(this.analyticsManager?.getAutocaptureModule() ?? null);
@@ -3149,7 +3153,7 @@ sitepong.flushProfiles.bind(sitepong);
3149
3153
  var getRemoteConfig = sitepong.getRemoteConfig.bind(sitepong);
3150
3154
  var isRemoteConfigFeatureEnabled = sitepong.isRemoteConfigFeatureEnabled.bind(sitepong);
3151
3155
  var onRemoteConfigChange = sitepong.onRemoteConfigChange.bind(sitepong);
3152
- sitepong.registerIdentifyHook.bind(sitepong);
3156
+ var registerIdentifyHook = sitepong.registerIdentifyHook.bind(sitepong);
3153
3157
 
3154
3158
  // src/react-native/storage.ts
3155
3159
  function createAsyncStorageAdapter(asyncStorage) {
@@ -3954,9 +3958,26 @@ function fiberRootFromInstance(instance) {
3954
3958
  return fiberRoot && typeof fiberRoot === "object" && fiberRoot.current ? fiberRoot : null;
3955
3959
  }
3956
3960
 
3961
+ // src/analytics/channel.ts
3962
+ function normalize(v) {
3963
+ const c = v?.trim().toLowerCase();
3964
+ return c && c.length > 0 ? c : void 0;
3965
+ }
3966
+ function resolveChannel(explicit, buildDefault) {
3967
+ return normalize(explicit) ?? buildDefault;
3968
+ }
3969
+ function isChannelSuppressed(channel, ignoreChannels) {
3970
+ const ignore = (ignoreChannels ?? ["development"]).map((c) => normalize(c)).filter((c) => c !== void 0);
3971
+ return ignore.includes(channel);
3972
+ }
3973
+
3957
3974
  // src/react-native/structural/capture.ts
3958
3975
  var WALK_BUDGET_MS = 24;
3959
3976
  var MAX_OVERLOAD_SKIP = 8;
3977
+ function rnDefaultChannel() {
3978
+ const dev = globalThis.__DEV__;
3979
+ return dev ? "development" : "production";
3980
+ }
3960
3981
  function genSessionId() {
3961
3982
  const rand = Math.floor(Math.random() * 16777215).toString(36);
3962
3983
  return `wt-${Date.now().toString(36)}-${rand}`;
@@ -4005,6 +4026,11 @@ var StructuralCapture = class {
4005
4026
  }
4006
4027
  start(cfg) {
4007
4028
  if (this.running) return;
4029
+ const channel = resolveChannel(cfg.channel, rnDefaultChannel());
4030
+ if (isChannelSuppressed(channel, cfg.ignoreChannels)) {
4031
+ if (cfg.debug) console.log("[structural] suppressed channel", channel, "\u2014 not capturing");
4032
+ return;
4033
+ }
4008
4034
  installStructuralHook();
4009
4035
  this.cfg = cfg;
4010
4036
  this.sessionId = cfg.sessionId || genSessionId();
@@ -4725,6 +4751,7 @@ function loadBridge() {
4725
4751
  return getScreenRecorderModule();
4726
4752
  }
4727
4753
  var started = false;
4754
+ var identifyHookUnsub = null;
4728
4755
  function startWatchtower(config) {
4729
4756
  if (started) return;
4730
4757
  const bridge = loadBridge();
@@ -4743,14 +4770,24 @@ function startWatchtower(config) {
4743
4770
  endpoint: config.endpoint,
4744
4771
  sampleRate: config.sampleRate ?? 0.1,
4745
4772
  platform: config.platform ?? "react-native-ios",
4746
- sessionGraceMs: config.sessionGraceMs ?? 3e4
4773
+ sessionGraceMs: config.sessionGraceMs ?? 3e4,
4774
+ // Forwarded to WatchtowerCore; undefined channel → native auto-resolves
4775
+ // (debug→development, release→production). ignoreChannels defaults to
4776
+ // ["development"] natively when omitted.
4777
+ channel: config.channel,
4778
+ ignoreChannels: config.ignoreChannels
4747
4779
  });
4748
4780
  started = true;
4749
4781
  if (config.distinctId) setWatchtowerUser(config.distinctId);
4782
+ if (!identifyHookUnsub) {
4783
+ identifyHookUnsub = registerIdentifyHook(
4784
+ (userId, traits) => setWatchtowerUser(userId, traits?.email ?? null, traits?.name ?? null)
4785
+ );
4786
+ }
4750
4787
  }
4751
- function setWatchtowerUser(distinctId) {
4788
+ function setWatchtowerUser(distinctId, email = null, name = null) {
4752
4789
  try {
4753
- loadBridge()?.watchtowerSetUser(distinctId);
4790
+ loadBridge()?.watchtowerSetUser(distinctId, email, name);
4754
4791
  } catch {
4755
4792
  }
4756
4793
  }
@@ -4765,6 +4802,8 @@ function stopWatchtower() {
4765
4802
  if (!started) return;
4766
4803
  loadBridge()?.watchtowerStop();
4767
4804
  started = false;
4805
+ identifyHookUnsub?.();
4806
+ identifyHookUnsub = null;
4768
4807
  }
4769
4808
  function subscribeNavigationToWatchtower(navigationRef) {
4770
4809
  const unsubscribe = createNavigationTracker(navigationRef, {