@interfere/next 0.0.8 → 0.0.11

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.
Files changed (151) hide show
  1. package/README.md +308 -0
  2. package/dist/__tests__/build/with-interfere-coverage.test.d.ts +2 -0
  3. package/dist/__tests__/build/with-interfere-coverage.test.d.ts.map +1 -0
  4. package/dist/__tests__/build/with-interfere-coverage.test.js +338 -0
  5. package/dist/__tests__/build/with-interfere-coverage.test.js.map +1 -0
  6. package/dist/__tests__/build/with-interfere.test.d.ts +2 -0
  7. package/dist/__tests__/build/with-interfere.test.d.ts.map +1 -0
  8. package/dist/__tests__/build/with-interfere.test.js +466 -0
  9. package/dist/__tests__/build/with-interfere.test.js.map +1 -0
  10. package/dist/__tests__/core/client.test.d.ts.map +1 -0
  11. package/dist/__tests__/core/client.test.js +373 -0
  12. package/dist/__tests__/core/client.test.js.map +1 -0
  13. package/dist/__tests__/core/encoders.test.d.ts.map +1 -0
  14. package/dist/{core → __tests__/core}/encoders.test.js +20 -19
  15. package/dist/__tests__/core/encoders.test.js.map +1 -0
  16. package/dist/__tests__/core/rage-click.test.d.ts +2 -0
  17. package/dist/__tests__/core/rage-click.test.d.ts.map +1 -0
  18. package/dist/__tests__/core/rage-click.test.js +121 -0
  19. package/dist/__tests__/core/rage-click.test.js.map +1 -0
  20. package/dist/__tests__/core/session-manager.test.d.ts +2 -0
  21. package/dist/__tests__/core/session-manager.test.d.ts.map +1 -0
  22. package/dist/__tests__/core/session-manager.test.js +1132 -0
  23. package/dist/__tests__/core/session-manager.test.js.map +1 -0
  24. package/dist/__tests__/integration/release-upload.test.d.ts +2 -0
  25. package/dist/__tests__/integration/release-upload.test.d.ts.map +1 -0
  26. package/dist/__tests__/integration/release-upload.test.js +173 -0
  27. package/dist/__tests__/integration/release-upload.test.js.map +1 -0
  28. package/dist/__tests__/session/persistence.test.d.ts +2 -0
  29. package/dist/__tests__/session/persistence.test.d.ts.map +1 -0
  30. package/dist/__tests__/session/persistence.test.js +129 -0
  31. package/dist/__tests__/session/persistence.test.js.map +1 -0
  32. package/dist/__tests__/session/session-summary.test.d.ts +2 -0
  33. package/dist/__tests__/session/session-summary.test.d.ts.map +1 -0
  34. package/dist/__tests__/session/session-summary.test.js +763 -0
  35. package/dist/__tests__/session/session-summary.test.js.map +1 -0
  36. package/dist/build/index.d.ts +3 -0
  37. package/dist/build/index.d.ts.map +1 -0
  38. package/dist/build/index.js +2 -0
  39. package/dist/build/index.js.map +1 -0
  40. package/dist/build/with-interfere.d.ts +54 -0
  41. package/dist/build/with-interfere.d.ts.map +1 -0
  42. package/dist/build/with-interfere.js +267 -0
  43. package/dist/build/with-interfere.js.map +1 -0
  44. package/dist/core/client-core.d.ts +27 -0
  45. package/dist/core/client-core.d.ts.map +1 -0
  46. package/dist/core/client-core.js +152 -0
  47. package/dist/core/client-core.js.map +1 -0
  48. package/dist/core/client.d.ts +71 -18
  49. package/dist/core/client.d.ts.map +1 -1
  50. package/dist/core/client.js +107 -97
  51. package/dist/core/client.js.map +1 -1
  52. package/dist/core/constants.d.ts +12 -0
  53. package/dist/core/constants.d.ts.map +1 -0
  54. package/dist/core/constants.js +17 -0
  55. package/dist/core/constants.js.map +1 -0
  56. package/dist/core/debug.d.ts +47 -0
  57. package/dist/core/debug.d.ts.map +1 -0
  58. package/dist/core/debug.js +79 -0
  59. package/dist/core/debug.js.map +1 -0
  60. package/dist/core/error-handlers.d.ts +14 -0
  61. package/dist/core/error-handlers.d.ts.map +1 -0
  62. package/dist/core/error-handlers.js +192 -0
  63. package/dist/core/error-handlers.js.map +1 -0
  64. package/dist/core/runtime.d.ts +7 -0
  65. package/dist/core/runtime.d.ts.map +1 -0
  66. package/dist/core/runtime.js +16 -0
  67. package/dist/core/runtime.js.map +1 -0
  68. package/dist/index.d.ts +10 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +9 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/next/middleware.d.ts +8 -0
  73. package/dist/next/middleware.d.ts.map +1 -0
  74. package/dist/next/middleware.js +139 -0
  75. package/dist/next/middleware.js.map +1 -0
  76. package/dist/persistence/storage.d.ts +5 -0
  77. package/dist/persistence/storage.d.ts.map +1 -0
  78. package/dist/persistence/storage.js +67 -0
  79. package/dist/persistence/storage.js.map +1 -0
  80. package/dist/react/provider.d.ts +12 -7
  81. package/dist/react/provider.d.ts.map +1 -1
  82. package/dist/react/provider.jsx +37 -10
  83. package/dist/react/provider.jsx.map +1 -1
  84. package/dist/session/constants.d.ts +19 -0
  85. package/dist/session/constants.d.ts.map +1 -0
  86. package/dist/session/constants.js +34 -0
  87. package/dist/session/constants.js.map +1 -0
  88. package/dist/session/persistence.d.ts +58 -0
  89. package/dist/session/persistence.d.ts.map +1 -0
  90. package/dist/session/persistence.js +180 -0
  91. package/dist/session/persistence.js.map +1 -0
  92. package/dist/session/rage-click.d.ts +17 -0
  93. package/dist/session/rage-click.d.ts.map +1 -0
  94. package/dist/session/rage-click.js +104 -0
  95. package/dist/session/rage-click.js.map +1 -0
  96. package/dist/session/replay.d.ts +3 -0
  97. package/dist/session/replay.d.ts.map +1 -0
  98. package/dist/session/replay.js +109 -0
  99. package/dist/session/replay.js.map +1 -0
  100. package/dist/session/session-manager.d.ts +126 -0
  101. package/dist/session/session-manager.d.ts.map +1 -0
  102. package/dist/session/session-manager.js +635 -0
  103. package/dist/session/session-manager.js.map +1 -0
  104. package/dist/session/session-summary.d.ts +3 -0
  105. package/dist/session/session-summary.d.ts.map +1 -0
  106. package/dist/session/session-summary.js +214 -0
  107. package/dist/session/session-summary.js.map +1 -0
  108. package/dist/types/storage.d.ts +7 -0
  109. package/dist/types/storage.d.ts.map +1 -0
  110. package/dist/types/storage.js +2 -0
  111. package/dist/types/storage.js.map +1 -0
  112. package/package.json +31 -15
  113. package/dist/core/client.test.d.ts.map +0 -1
  114. package/dist/core/client.test.js +0 -227
  115. package/dist/core/client.test.js.map +0 -1
  116. package/dist/core/encoders.test.d.ts.map +0 -1
  117. package/dist/core/encoders.test.js.map +0 -1
  118. package/dist/core/index.d.ts +0 -3
  119. package/dist/core/index.d.ts.map +0 -1
  120. package/dist/core/index.js +0 -3
  121. package/dist/core/index.js.map +0 -1
  122. package/dist/edge/edge.d.ts +0 -11
  123. package/dist/edge/edge.d.ts.map +0 -1
  124. package/dist/edge/edge.js +0 -41
  125. package/dist/edge/edge.js.map +0 -1
  126. package/dist/edge/edge.test.d.ts +0 -2
  127. package/dist/edge/edge.test.d.ts.map +0 -1
  128. package/dist/edge/edge.test.js +0 -109
  129. package/dist/edge/edge.test.js.map +0 -1
  130. package/dist/edge/index.d.ts +0 -2
  131. package/dist/edge/index.d.ts.map +0 -1
  132. package/dist/edge/index.js +0 -2
  133. package/dist/edge/index.js.map +0 -1
  134. package/dist/react/index.d.ts +0 -2
  135. package/dist/react/index.d.ts.map +0 -1
  136. package/dist/react/index.js +0 -2
  137. package/dist/react/index.js.map +0 -1
  138. package/dist/server/index.d.ts +0 -2
  139. package/dist/server/index.d.ts.map +0 -1
  140. package/dist/server/index.js +0 -2
  141. package/dist/server/index.js.map +0 -1
  142. package/dist/server/server.d.ts +0 -6
  143. package/dist/server/server.d.ts.map +0 -1
  144. package/dist/server/server.js +0 -35
  145. package/dist/server/server.js.map +0 -1
  146. package/dist/server/server.test.d.ts +0 -2
  147. package/dist/server/server.test.d.ts.map +0 -1
  148. package/dist/server/server.test.js +0 -88
  149. package/dist/server/server.test.js.map +0 -1
  150. /package/dist/{core → __tests__/core}/client.test.d.ts +0 -0
  151. /package/dist/{core → __tests__/core}/encoders.test.d.ts +0 -0
@@ -0,0 +1,34 @@
1
+ export const SESSION_ID = "$session_id";
2
+ export const WINDOW_ID = "$window_id";
3
+ // Time constants - all in milliseconds internally
4
+ const SECONDS_IN_MINUTE = 60;
5
+ const MINUTES_IN_HOUR = 60;
6
+ const MILLISECONDS_IN_SECOND = 1000;
7
+ const SECONDS_IN_HOUR = MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
8
+ const MILLISECONDS_IN_HOUR = SECONDS_IN_HOUR * MILLISECONDS_IN_SECOND;
9
+ // Time utility functions
10
+ export const toMs = (seconds) => seconds * MILLISECONDS_IN_SECOND;
11
+ export const toSeconds = (milliseconds) => Math.floor(milliseconds / MILLISECONDS_IN_SECOND);
12
+ // Session timeout constants (exported in seconds for config compatibility)
13
+ const DEFAULT_IDLE_TIMEOUT_MINUTES = 30;
14
+ export const DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS = DEFAULT_IDLE_TIMEOUT_MINUTES * SECONDS_IN_MINUTE; // 30 minutes
15
+ export const MAX_SESSION_IDLE_TIMEOUT_SECONDS = 10 * SECONDS_IN_HOUR; // 10 hours
16
+ export const MIN_SESSION_IDLE_TIMEOUT_SECONDS = SECONDS_IN_MINUTE; // 1 minute
17
+ // Session length limit (in milliseconds)
18
+ export const SESSION_LENGTH_LIMIT_MILLISECONDS = 24 * MILLISECONDS_IN_HOUR; // 24 hours
19
+ // Static SDK configuration values
20
+ // These may become server-configurable in the future
21
+ // Session summary
22
+ export const SESSION_SUMMARY_ENABLED = true; // Always enabled
23
+ export const SESSION_SUMMARY_WINDOW_MS = 10_000; // 10 seconds
24
+ export const SESSION_SUMMARY_MAX_EVENTS = 200;
25
+ export const ALLOW_BROWSER_AI = true;
26
+ // Session replay
27
+ export const REPLAY_ENABLED = true; // Always enabled
28
+ export const REPLAY_CHUNK_MS = 10_000; // 10 seconds
29
+ // Rage click detection
30
+ export const RAGE_CLICK_ENABLED = true; // Always enabled
31
+ export const RAGE_CLICK_RADIUS_PX = 30;
32
+ export const RAGE_CLICK_TIMEOUT_MS = 1000; // 1 second
33
+ export const RAGE_CLICK_COUNT = 3; // 3 rapid clicks trigger rage click
34
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/session/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC;AACxC,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC;AAEtC,kDAAkD;AAClD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,sBAAsB,GAAG,IAAI,CAAC;AACpC,MAAM,eAAe,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAC5D,MAAM,oBAAoB,GAAG,eAAe,GAAG,sBAAsB,CAAC;AAEtE,yBAAyB;AACzB,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAU,EAAE,CAC9C,OAAO,GAAG,sBAAsB,CAAC;AACnC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,YAAoB,EAAU,EAAE,CACxD,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,sBAAsB,CAAC,CAAC;AAEpD,2EAA2E;AAC3E,MAAM,4BAA4B,GAAG,EAAE,CAAC;AACxC,MAAM,CAAC,MAAM,oCAAoC,GAC/C,4BAA4B,GAAG,iBAAiB,CAAC,CAAC,aAAa;AACjE,MAAM,CAAC,MAAM,gCAAgC,GAAG,EAAE,GAAG,eAAe,CAAC,CAAC,WAAW;AACjF,MAAM,CAAC,MAAM,gCAAgC,GAAG,iBAAiB,CAAC,CAAC,WAAW;AAE9E,yCAAyC;AACzC,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,GAAG,oBAAoB,CAAC,CAAC,WAAW;AAEvF,kCAAkC;AAClC,qDAAqD;AAErD,kBAAkB;AAClB,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC,CAAC,iBAAiB;AAC9D,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,CAAC,aAAa;AAC9D,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAC9C,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAErC,iBAAiB;AACjB,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,CAAC,iBAAiB;AACrD,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,aAAa;AAEpD,uBAAuB;AACvB,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,CAAC,iBAAiB;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC,CAAC,WAAW;AACtD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,CAAC,oCAAoC"}
@@ -0,0 +1,58 @@
1
+ import type { Config } from "@interfere/schemas/config";
2
+ import type { PersistentStore } from "../types/storage.js";
3
+ export type Properties = {
4
+ [key: string]: unknown;
5
+ };
6
+ export type PersistenceOptions = {
7
+ /** Use deep equality check for register method (slower but more accurate for objects) */
8
+ useDeepEquality?: boolean;
9
+ /** Custom storage implementation for testing */
10
+ customStorage?: PersistentStore;
11
+ };
12
+ export declare class InterferePersistence {
13
+ private readonly _config;
14
+ private _props;
15
+ private readonly _storage;
16
+ private readonly _name;
17
+ private _disabled;
18
+ private readonly _useDeepEquality;
19
+ constructor(config: Partial<Config>, surface: string, isDisabled?: boolean, options?: PersistenceOptions);
20
+ private _parseName;
21
+ private _buildStorage;
22
+ isDisabled(): boolean;
23
+ load(): void;
24
+ save(): void;
25
+ /**
26
+ * Deep equality helper for objects and arrays
27
+ */
28
+ private _deepEqual;
29
+ register(props: Properties): boolean;
30
+ /**
31
+ * Remove a single property from persistence
32
+ */
33
+ removeProp(prop: string): void;
34
+ /**
35
+ * Get a property value with optional generic typing
36
+ */
37
+ getProperty<T = unknown>(prop: string): T | undefined;
38
+ /**
39
+ * Set a property value
40
+ */
41
+ setProperty<T = unknown>(prop: string, value: T): void;
42
+ /**
43
+ * Get all properties (immutable copy)
44
+ */
45
+ getAllProperties(): Readonly<Properties>;
46
+ /**
47
+ * Remove all data from storage and memory
48
+ */
49
+ removeAll(): void;
50
+ /**
51
+ * Clear both storage and in-memory props (alias for removeAll)
52
+ */
53
+ clear(): void;
54
+ setDisabled(disabled: boolean): void;
55
+ /** @deprecated Use removeProp instead */
56
+ unregister(prop: string): void;
57
+ }
58
+ //# sourceMappingURL=persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/session/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,2BAA2B,CAAC;AAQzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,yFAAyF;IACzF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gDAAgD;IAChD,aAAa,CAAC,EAAE,eAAe,CAAC;CACjC,CAAC;AAEF,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;gBAGzC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,EACvB,OAAO,EAAE,MAAM,EACf,UAAU,UAAQ,EAClB,OAAO,GAAE,kBAAuB;IAelC,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,aAAa;IAiBrB,UAAU,IAAI,OAAO;IAIrB,IAAI,IAAI,IAAI;IAgBZ,IAAI,IAAI,IAAI;IAaZ;;OAEG;IACH,OAAO,CAAC,UAAU;IAsBlB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IA0BpC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO9B;;OAEG;IACH,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAIrD;;OAEG;IACH,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAKtD;;OAEG;IACH,gBAAgB,IAAI,QAAQ,CAAC,UAAU,CAAC;IAIxC;;OAEG;IACH,SAAS,IAAI,IAAI;IAcjB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAWpC,yCAAyC;IACzC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAG/B"}
@@ -0,0 +1,180 @@
1
+ import { localStore, memoryStore, sessionStore, } from "../persistence/storage.js";
2
+ export class InterferePersistence {
3
+ _config;
4
+ _props = {};
5
+ _storage;
6
+ _name;
7
+ _disabled;
8
+ _useDeepEquality;
9
+ constructor(config, surface, isDisabled = false, options = {}) {
10
+ this._config = config;
11
+ this._name = this._parseName(surface);
12
+ this._disabled = isDisabled;
13
+ this._useDeepEquality = options.useDeepEquality ?? false;
14
+ // Short-circuit storage building if disabled
15
+ this._storage = this._disabled
16
+ ? null
17
+ : (options.customStorage ?? this._buildStorage());
18
+ this.load();
19
+ }
20
+ _parseName(surface) {
21
+ // Normalize consecutive non-alphanumerics to single underscore
22
+ const cleanSurface = surface.replace(/[^a-zA-Z0-9]+/g, "_");
23
+ return `interfere_${cleanSurface}`;
24
+ }
25
+ _buildStorage() {
26
+ const persistenceType = this._config.persistence || "localStorage";
27
+ switch (persistenceType) {
28
+ case "localStorage":
29
+ return localStore._is_supported() ? localStore : memoryStore;
30
+ case "sessionStorage":
31
+ return sessionStore._is_supported() ? sessionStore : memoryStore;
32
+ case "memory":
33
+ return memoryStore;
34
+ default:
35
+ // TypeScript ensures exhaustiveness, but keep default for safety
36
+ return localStore._is_supported() ? localStore : memoryStore;
37
+ }
38
+ }
39
+ isDisabled() {
40
+ return this._disabled;
41
+ }
42
+ load() {
43
+ if (this._disabled || !this._storage) {
44
+ return;
45
+ }
46
+ try {
47
+ const entry = this._storage._parse(this._name);
48
+ if (entry && typeof entry === "object" && entry !== null) {
49
+ this._props = { ...entry };
50
+ }
51
+ }
52
+ catch {
53
+ // Gracefully handle parse errors, keep existing props
54
+ // In production, we silently fail to avoid console noise
55
+ }
56
+ }
57
+ save() {
58
+ if (this._disabled || !this._storage) {
59
+ return;
60
+ }
61
+ try {
62
+ this._storage._set(this._name, this._props);
63
+ }
64
+ catch {
65
+ // Gracefully handle storage errors (e.g., quota exceeded)
66
+ // In production, we silently fail to avoid console noise
67
+ }
68
+ }
69
+ /**
70
+ * Deep equality helper for objects and arrays
71
+ */
72
+ _deepEqual(a, b) {
73
+ if (a === b) {
74
+ return true;
75
+ }
76
+ if (a == null || b == null) {
77
+ return a === b;
78
+ }
79
+ if (typeof a !== typeof b) {
80
+ return false;
81
+ }
82
+ if (typeof a !== "object" || typeof b !== "object") {
83
+ return a === b;
84
+ }
85
+ try {
86
+ return JSON.stringify(a) === JSON.stringify(b);
87
+ }
88
+ catch {
89
+ // Fallback to shallow comparison for non-serializable objects
90
+ return a === b;
91
+ }
92
+ }
93
+ register(props) {
94
+ if (!props || typeof props !== "object") {
95
+ return false;
96
+ }
97
+ let hasChanges = false;
98
+ for (const [prop, val] of Object.entries(props)) {
99
+ const currentVal = this._props[prop];
100
+ const isEqual = this._useDeepEquality
101
+ ? this._deepEqual(currentVal, val)
102
+ : currentVal === val;
103
+ if (!isEqual) {
104
+ this._props[prop] = val;
105
+ hasChanges = true;
106
+ }
107
+ }
108
+ // biome-ignore lint/nursery/noUnnecessaryConditions: false positive, hasChanges can be true
109
+ if (hasChanges) {
110
+ this.save();
111
+ }
112
+ return hasChanges;
113
+ }
114
+ /**
115
+ * Remove a single property from persistence
116
+ */
117
+ removeProp(prop) {
118
+ if (prop in this._props) {
119
+ delete this._props[prop];
120
+ this.save();
121
+ }
122
+ }
123
+ /**
124
+ * Get a property value with optional generic typing
125
+ */
126
+ getProperty(prop) {
127
+ return this._props[prop];
128
+ }
129
+ /**
130
+ * Set a property value
131
+ */
132
+ setProperty(prop, value) {
133
+ this._props[prop] = value;
134
+ this.save();
135
+ }
136
+ /**
137
+ * Get all properties (immutable copy)
138
+ */
139
+ getAllProperties() {
140
+ return { ...this._props };
141
+ }
142
+ /**
143
+ * Remove all data from storage and memory
144
+ */
145
+ removeAll() {
146
+ this._props = {};
147
+ if (!this._storage) {
148
+ return;
149
+ }
150
+ try {
151
+ this._storage._remove(this._name);
152
+ }
153
+ catch {
154
+ // Gracefully handle removal errors
155
+ // In production, we silently fail to avoid console noise
156
+ }
157
+ }
158
+ /**
159
+ * Clear both storage and in-memory props (alias for removeAll)
160
+ */
161
+ clear() {
162
+ this.removeAll();
163
+ }
164
+ setDisabled(disabled) {
165
+ this._disabled = disabled;
166
+ if (this._disabled) {
167
+ this.removeAll();
168
+ }
169
+ else if (Object.keys(this._props).length > 0) {
170
+ // Only save if we have properties to persist
171
+ this.save();
172
+ }
173
+ }
174
+ // Deprecated methods for backward compatibility
175
+ /** @deprecated Use removeProp instead */
176
+ unregister(prop) {
177
+ this.removeProp(prop);
178
+ }
179
+ }
180
+ //# sourceMappingURL=persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/session/persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export default class RageClick {
2
+ private clicks;
3
+ private readonly radiusPx;
4
+ private readonly timeoutMs;
5
+ private readonly clickCount;
6
+ constructor();
7
+ isRageClick(x: number, y: number, timestamp: number): boolean;
8
+ getElementInfo(target: HTMLElement | null): {
9
+ tagName?: string;
10
+ className?: string;
11
+ id?: string;
12
+ text?: string;
13
+ ariaLabel?: string;
14
+ };
15
+ }
16
+ export declare function setupRageClick(): void;
17
+ //# sourceMappingURL=rage-click.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rage-click.d.ts","sourceRoot":"","sources":["../../src/session/rage-click.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,OAAO,OAAO,SAAS;IAC5B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;;IASpC,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAkC7D,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG;QAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;CAaF;AASD,wBAAgB,cAAc,IAAI,IAAI,CA0DrC"}
@@ -0,0 +1,104 @@
1
+ /* Rage click detection for identifying user frustration patterns */
2
+ "use client";
3
+ import { RAGE_CLICK_COUNT, RAGE_CLICK_ENABLED, RAGE_CLICK_RADIUS_PX, RAGE_CLICK_TIMEOUT_MS, } from "./constants.js";
4
+ const MAX_TEXT_LENGTH = 100;
5
+ export default class RageClick {
6
+ clicks = [];
7
+ radiusPx;
8
+ timeoutMs;
9
+ clickCount;
10
+ constructor() {
11
+ // Use static values - config options no longer used
12
+ this.radiusPx = RAGE_CLICK_RADIUS_PX;
13
+ this.timeoutMs = RAGE_CLICK_TIMEOUT_MS;
14
+ this.clickCount = RAGE_CLICK_COUNT;
15
+ }
16
+ isRageClick(x, y, timestamp) {
17
+ const current = { x, y, timestamp };
18
+ // Keep only recent clicks within timeout window
19
+ this.clicks = this.clicks.filter((c) => timestamp - c.timestamp <= this.timeoutMs);
20
+ this.clicks.push(current);
21
+ // Check if enough clicks happened in close proximity
22
+ if (this.clicks.length >= this.clickCount) {
23
+ const first = this.clicks[0];
24
+ const last = this.clicks.at(-1);
25
+ // Check time window - both first and last should exist due to length check
26
+ if (first && last && last.timestamp - first.timestamp <= this.timeoutMs) {
27
+ // Ensure all clicks are within radius of the first
28
+ const allWithinRadius = this.clicks.every((c) => {
29
+ const dx = c.x - first.x;
30
+ const dy = c.y - first.y;
31
+ return Math.sqrt(dx * dx + dy * dy) <= this.radiusPx;
32
+ });
33
+ if (allWithinRadius) {
34
+ this.clicks = []; // reset after detection
35
+ return true;
36
+ }
37
+ }
38
+ }
39
+ return false;
40
+ }
41
+ // Get the element information for the rage click event
42
+ getElementInfo(target) {
43
+ if (!target) {
44
+ return {};
45
+ }
46
+ return {
47
+ tagName: target.tagName?.toLowerCase(),
48
+ className: target.className || undefined,
49
+ id: target.id || undefined,
50
+ text: target.innerText?.slice(0, MAX_TEXT_LENGTH) || undefined,
51
+ ariaLabel: target.getAttribute("aria-label") || undefined,
52
+ };
53
+ }
54
+ }
55
+ let rageClickDetector = null;
56
+ let initialized = false;
57
+ function isBrowser() {
58
+ return typeof window !== "undefined";
59
+ }
60
+ export function setupRageClick() {
61
+ if (initialized) {
62
+ return;
63
+ }
64
+ if (!isBrowser()) {
65
+ return;
66
+ }
67
+ if (!RAGE_CLICK_ENABLED) {
68
+ return;
69
+ }
70
+ initialized = true;
71
+ rageClickDetector = new RageClick();
72
+ // Import capture function dynamically to avoid circular dependencies
73
+ import("../core/client.js")
74
+ .then(({ capture }) => {
75
+ document.addEventListener("click", (e) => {
76
+ if (!rageClickDetector) {
77
+ return;
78
+ }
79
+ const mouseEvent = e;
80
+ const timestamp = Date.now();
81
+ if (rageClickDetector.isRageClick(mouseEvent.clientX, mouseEvent.clientY, timestamp)) {
82
+ const target = mouseEvent.target;
83
+ const elementInfo = rageClickDetector.getElementInfo(target);
84
+ try {
85
+ capture("rage_click", {
86
+ timestamp,
87
+ x: mouseEvent.clientX,
88
+ y: mouseEvent.clientY,
89
+ element: elementInfo,
90
+ url: window.location.href,
91
+ userAgent: navigator.userAgent,
92
+ });
93
+ }
94
+ catch {
95
+ // Swallow errors to avoid impacting the host app
96
+ }
97
+ }
98
+ }, { capture: true });
99
+ })
100
+ .catch(() => {
101
+ // Swallow import errors
102
+ });
103
+ }
104
+ //# sourceMappingURL=rage-click.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rage-click.js","sourceRoot":"","sources":["../../src/session/rage-click.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function setupReplay(): void;
2
+ export declare function stopReplay(): void;
3
+ //# sourceMappingURL=replay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"AAUA,wBAAgB,WAAW,SAuG1B;AAED,wBAAgB,UAAU,SAEzB"}
@@ -0,0 +1,109 @@
1
+ /* Session replay capture using rrweb, chunked streaming to ingest */
2
+ "use client";
3
+ import { capture, flush } from "../core/client.js";
4
+ import { REPLAY_CHUNK_MS, REPLAY_ENABLED } from "./constants.js";
5
+ let started = false;
6
+ let stopFn = null;
7
+ export function setupReplay() {
8
+ if (started) {
9
+ return;
10
+ }
11
+ if (typeof window === "undefined") {
12
+ return;
13
+ }
14
+ if (!REPLAY_ENABLED) {
15
+ return;
16
+ }
17
+ started = true;
18
+ Promise.all([import("rrweb"), import("@rrweb/packer")])
19
+ .then(([rrwebModule, packerModule]) => {
20
+ // Handle different module export patterns
21
+ const rrweb = rrwebModule.default || rrwebModule;
22
+ const record = rrweb.record || rrweb;
23
+ const { pack } = packerModule;
24
+ const events = [];
25
+ // Check if record is a function
26
+ if (typeof record !== "function") {
27
+ // biome-ignore lint/suspicious/noConsole: error logging needed
28
+ console.error("rrweb.record is not available");
29
+ return;
30
+ }
31
+ const stopRecord = record({
32
+ emit(event) {
33
+ // Compress the event before storing it
34
+ const packedEvent = pack(event);
35
+ events.push(packedEvent);
36
+ },
37
+ maskAllInputs: true, // Privacy: mask all text inputs by default
38
+ });
39
+ const sendChunk = () => {
40
+ if (events.length === 0) {
41
+ return;
42
+ }
43
+ const chunk = events.splice(0, events.length);
44
+ try {
45
+ capture("replay_chunk", {
46
+ version: 1,
47
+ chunkTs: Date.now(),
48
+ count: chunk.length,
49
+ // rrweb events are pre-compressed with @rrweb/packer
50
+ events: chunk,
51
+ });
52
+ flush();
53
+ }
54
+ catch {
55
+ // swallow
56
+ }
57
+ };
58
+ const intervalId = window.setInterval(sendChunk, REPLAY_CHUNK_MS);
59
+ const flushNow = () => {
60
+ try {
61
+ sendChunk();
62
+ }
63
+ catch {
64
+ // swallow
65
+ }
66
+ };
67
+ const beforeUnload = () => flushNow();
68
+ const visibility = () => {
69
+ if (document.visibilityState === "hidden") {
70
+ flushNow();
71
+ }
72
+ };
73
+ window.addEventListener("beforeunload", beforeUnload);
74
+ document.addEventListener("visibilitychange", visibility);
75
+ stopFn = () => {
76
+ try {
77
+ if (typeof stopRecord === "function") {
78
+ stopRecord();
79
+ }
80
+ }
81
+ catch {
82
+ /* no-op */
83
+ }
84
+ try {
85
+ window.clearInterval(intervalId);
86
+ }
87
+ catch {
88
+ /* no-op */
89
+ }
90
+ try {
91
+ window.removeEventListener("beforeunload", beforeUnload);
92
+ document.removeEventListener("visibilitychange", visibility);
93
+ }
94
+ catch {
95
+ /* no-op */
96
+ }
97
+ started = false;
98
+ stopFn = null;
99
+ };
100
+ })
101
+ .catch((error) => {
102
+ // biome-ignore lint/suspicious/noConsole: Just for testing
103
+ console.error("Failed to load rrweb:", error);
104
+ });
105
+ }
106
+ export function stopReplay() {
107
+ stopFn?.();
108
+ }
109
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/session/replay.ts"],"names":[],"mappings":"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"}