@interfere/react 12.0.5 → 12.1.1

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 (182) hide show
  1. package/README.md +103 -0
  2. package/dist/actionable-DOmVf_ib.mjs +1 -0
  3. package/dist/activity-D18VXGTn.mjs +1 -0
  4. package/dist/{activity-BfYxFVcK.d.mts → activity-Duhfgvxt.d.mts} +1 -1
  5. package/dist/{api-DEVCOKkJ.d.mts → api-CMPV9rgU.d.mts} +1 -1
  6. package/dist/api-DXmjUMZE.mjs +1 -0
  7. package/dist/api.mjs +1 -1
  8. package/dist/bot-YLSbnCeg.mjs +1 -0
  9. package/dist/buffer-BRn_kSm-.mjs +1 -0
  10. package/dist/capture-BV2RlsYg.mjs +1 -0
  11. package/dist/capture-boundary-Cz0jO-y5.mjs +1 -0
  12. package/dist/chunking-Dvs3f50A.d.mts +39 -0
  13. package/dist/chunking-qZffPbyY.mjs +2 -0
  14. package/dist/compressor-host-BAz6860r.d.mts +9 -0
  15. package/dist/compressor-host-CrKngamF.mjs +1 -0
  16. package/dist/config-Bm8myQlS.mjs +1 -0
  17. package/dist/config-CBqqY1AV.d.mts +29 -0
  18. package/dist/config-DapTbKhs.mjs +1 -0
  19. package/dist/{config-Rm-ct4K1.d.mts → config-Dyc09HCZ.d.mts} +2 -1
  20. package/dist/consent-COUmLJLD.mjs +1 -0
  21. package/dist/console-patch-WNKoLE7U.mjs +1 -0
  22. package/dist/delivery-DehIJWRh.mjs +1 -0
  23. package/dist/device-6T3DYkLD.mjs +1 -0
  24. package/dist/device-DRK7hhLi.mjs +1 -0
  25. package/dist/device-metadata-Ffi__vup.mjs +1 -0
  26. package/dist/{dist-ByNfzdQp.mjs → dist-Bcb677YG.mjs} +2 -2
  27. package/dist/environment-CoEXhF1a.mjs +1 -0
  28. package/dist/environment-_LKcAXKG.d.mts +9 -0
  29. package/dist/error-boundary.d.mts +1 -1
  30. package/dist/error-boundary.mjs +1 -1
  31. package/dist/errors-BDmCWb5z.mjs +1 -0
  32. package/dist/event-capabilities-Dd0Hoaq2.mjs +1 -0
  33. package/dist/exporter-3w57pctH.mjs +1 -0
  34. package/dist/exporter-logs-DS2AXWnV.mjs +1 -0
  35. package/dist/exporter-metrics-DZYqUo6_.mjs +1 -0
  36. package/dist/geo-D2wa9bGs.mjs +2 -0
  37. package/dist/global-DYq1Z4_H.mjs +1 -0
  38. package/dist/http-span-route-t2gig-KI.mjs +1 -0
  39. package/dist/hydration-BIp2cKhz.mjs +1 -0
  40. package/dist/index-DBsXraeJ.d.mts +4 -0
  41. package/dist/initial-navigation-YeK6UUHX.mjs +1 -0
  42. package/dist/{instrumentations-Bgm2EazU.d.mts → instrumentations-BuccMAMj.d.mts} +8 -1
  43. package/dist/instrumentations-CY8NcP_M.mjs +1 -0
  44. package/dist/internal/{activity.d.mts → activity/activity.d.mts} +1 -1
  45. package/dist/internal/activity/activity.mjs +1 -0
  46. package/dist/internal/browser-context.mjs +1 -1
  47. package/dist/internal/capture-boundary.d.mts +1 -1
  48. package/dist/internal/capture-boundary.mjs +1 -1
  49. package/dist/internal/capture.d.mts +1 -1
  50. package/dist/internal/capture.mjs +1 -1
  51. package/dist/internal/config.d.mts +2 -28
  52. package/dist/internal/config.mjs +1 -1
  53. package/dist/internal/consent.mjs +1 -1
  54. package/dist/internal/console-patch.mjs +1 -1
  55. package/dist/internal/device-metadata.d.mts +41 -0
  56. package/dist/internal/device-metadata.mjs +1 -0
  57. package/dist/internal/dom/actionable.d.mts +4 -13
  58. package/dist/internal/dom/actionable.mjs +1 -1
  59. package/dist/internal/dom/privacy.d.mts +2 -0
  60. package/dist/internal/dom/privacy.mjs +1 -0
  61. package/dist/internal/environment.d.mts +2 -0
  62. package/dist/internal/environment.mjs +1 -0
  63. package/dist/internal/event-capabilities.d.mts +3 -0
  64. package/dist/internal/event-capabilities.mjs +1 -0
  65. package/dist/internal/hydration.mjs +1 -1
  66. package/dist/internal/kernel-registry.d.mts +1 -1
  67. package/dist/internal/kernel-registry.mjs +1 -1
  68. package/dist/internal/kernel.d.mts +5 -3
  69. package/dist/internal/kernel.mjs +1 -1
  70. package/dist/internal/otel/exporter-logs.mjs +1 -1
  71. package/dist/internal/otel/exporter-metrics.mjs +1 -1
  72. package/dist/internal/otel/exporter.mjs +1 -1
  73. package/dist/internal/otel/http-span-route.mjs +1 -1
  74. package/dist/internal/otel/index.d.mts +3 -3
  75. package/dist/internal/otel/index.mjs +1 -1
  76. package/dist/internal/otel/initial-navigation.d.mts +1 -0
  77. package/dist/internal/otel/initial-navigation.mjs +1 -1
  78. package/dist/internal/otel/instrumentations.d.mts +1 -1
  79. package/dist/internal/otel/instrumentations.mjs +1 -1
  80. package/dist/internal/otel/navigation.mjs +1 -1
  81. package/dist/internal/otel/normalize-path.mjs +1 -1
  82. package/dist/internal/otel/page-scope-context-manager.mjs +1 -1
  83. package/dist/internal/otel/propagation.mjs +1 -1
  84. package/dist/internal/otel/provider.d.mts +1 -1
  85. package/dist/internal/otel/provider.mjs +1 -1
  86. package/dist/internal/otel/url-attrs.mjs +1 -1
  87. package/dist/internal/otel/web-vitals.mjs +1 -1
  88. package/dist/internal/{page-lifecycle.d.mts → page-lifecycle/page-lifecycle.d.mts} +1 -1
  89. package/dist/internal/page-lifecycle/page-lifecycle.mjs +1 -0
  90. package/dist/internal/plugins/plugin-runtime.d.mts +2 -0
  91. package/dist/internal/plugins/plugin-runtime.mjs +1 -0
  92. package/dist/internal/react-context.d.mts +1 -1
  93. package/dist/internal/react-context.mjs +1 -1
  94. package/dist/internal/server-digest.mjs +1 -1
  95. package/dist/internal/third-party-hosts.mjs +1 -1
  96. package/dist/internal/version.mjs +1 -1
  97. package/dist/internal/wrapper-singleton.d.mts +1 -1
  98. package/dist/internal/wrapper-singleton.mjs +1 -1
  99. package/dist/kernel-CwyJyyNf.mjs +1 -0
  100. package/dist/kernel-registry-6f-3VCIy.mjs +1 -0
  101. package/dist/loader-BGwWwN2n.mjs +1 -0
  102. package/dist/log-D6Ht--tv.mjs +1 -0
  103. package/dist/navigation-DwkvuhFR.mjs +1 -0
  104. package/dist/normalize-path-BChqP8pA.mjs +1 -0
  105. package/dist/page-events-config-CiJvdAaJ.d.mts +12 -0
  106. package/dist/{internal/page-lifecycle.mjs → page-lifecycle-BhSFqjlK.mjs} +1 -1
  107. package/dist/page-scope-context-manager-DhArvVJ_.mjs +1 -0
  108. package/dist/plugin-runtime-CnFVGbJw.mjs +1 -0
  109. package/dist/plugins/device.d.mts +1 -1
  110. package/dist/plugins/device.mjs +1 -1
  111. package/dist/plugins/errors.d.mts +1 -1
  112. package/dist/plugins/errors.mjs +1 -1
  113. package/dist/plugins/lib/loader.d.mts +1 -1
  114. package/dist/plugins/lib/loader.mjs +1 -1
  115. package/dist/plugins/lib/types.d.mts +1 -1
  116. package/dist/plugins/logs.d.mts +1 -1
  117. package/dist/plugins/logs.mjs +1 -1
  118. package/dist/plugins/page-events-config.d.mts +2 -0
  119. package/dist/plugins/page-events-config.mjs +1 -0
  120. package/dist/plugins/page-events.d.mts +1 -1
  121. package/dist/plugins/rage-clicks.d.mts +1 -1
  122. package/dist/plugins/rage-clicks.mjs +1 -1
  123. package/dist/plugins/replay/buffer.d.mts +1 -1
  124. package/dist/plugins/replay/buffer.mjs +1 -1
  125. package/dist/plugins/replay/chunking.d.mts +2 -38
  126. package/dist/plugins/replay/chunking.mjs +1 -2
  127. package/dist/plugins/replay/compressor-host.d.mts +2 -8
  128. package/dist/plugins/replay/compressor-host.mjs +1 -1
  129. package/dist/plugins/replay/config.d.mts +1 -1
  130. package/dist/plugins/replay/config.mjs +1 -1
  131. package/dist/plugins/replay/delivery.d.mts +4 -4
  132. package/dist/plugins/replay/delivery.mjs +1 -1
  133. package/dist/plugins/replay/index.d.mts +1 -1
  134. package/dist/plugins/replay/index.mjs +1 -1
  135. package/dist/plugins/replay/recorder.d.mts +1 -1
  136. package/dist/plugins/replay/recorder.mjs +1 -1
  137. package/dist/plugins/replay/redact-urls.d.mts +6 -0
  138. package/dist/plugins/replay/redact-urls.mjs +1 -0
  139. package/dist/plugins/replay/sequence.mjs +1 -1
  140. package/dist/plugins/replay/upload.d.mts +1 -1
  141. package/dist/plugins/replay/upload.mjs +1 -1
  142. package/dist/privacy-CPKosXDP.d.mts +31 -0
  143. package/dist/privacy-CRuL0X8r.mjs +1 -0
  144. package/dist/propagation-DVcqCu_E.mjs +1 -0
  145. package/dist/{provider-DWgb6tn9.d.mts → provider-C68KiG80.d.mts} +55 -39
  146. package/dist/provider-DlD5S0wG.mjs +1 -0
  147. package/dist/{provider-2LrbA-ld.d.mts → provider-VZtcX6ZS.d.mts} +4 -1
  148. package/dist/provider.d.mts +4 -3
  149. package/dist/provider.mjs +1 -1
  150. package/dist/react-context-c1uTUJfB.mjs +1 -0
  151. package/dist/react-error-handler.d.mts +1 -1
  152. package/dist/react-error-handler.mjs +1 -1
  153. package/dist/recorder-CM6Ae_0S.mjs +1 -0
  154. package/dist/redact-urls-CwFod9d4.mjs +1 -0
  155. package/dist/sequence-B4dYChb0.mjs +1 -0
  156. package/dist/server-digest-CzGdvjW1.mjs +1 -0
  157. package/dist/session-C30CtCVv.mjs +1 -0
  158. package/dist/session-retry-DJHvfDaO.mjs +1 -0
  159. package/dist/stringify-DvuHsAT4.mjs +1 -0
  160. package/dist/third-party-hosts-BoJNL3xG.mjs +1 -0
  161. package/dist/tracking/api.d.mts +1 -1
  162. package/dist/tracking/api.mjs +1 -1
  163. package/dist/tracking/device.mjs +1 -1
  164. package/dist/tracking/geo.mjs +1 -2
  165. package/dist/tracking/registration.fixture.d.mts +119 -109
  166. package/dist/tracking/registration.fixture.mjs +148 -26
  167. package/dist/tracking/session-retry.mjs +1 -1
  168. package/dist/tracking/session.mjs +1 -1
  169. package/dist/upload-BPaD3YcA.mjs +1 -0
  170. package/dist/url-attrs-BdcyE2n6.mjs +1 -0
  171. package/dist/util/bot.d.mts +1 -0
  172. package/dist/util/bot.mjs +1 -1
  173. package/dist/util/global.mjs +1 -1
  174. package/dist/util/log.mjs +1 -1
  175. package/dist/util/stringify.mjs +1 -1
  176. package/dist/{version-CsfyuVoF.mjs → version-B5O6bg5e.mjs} +1 -1
  177. package/dist/web-vitals-CxXDUgpl.mjs +1 -0
  178. package/package.json +7 -7
  179. package/dist/index-DvFfO2V9.d.mts +0 -4
  180. package/dist/internal/activity.mjs +0 -1
  181. package/dist/internal/plugin-runtime.d.mts +0 -2
  182. package/dist/internal/plugin-runtime.mjs +0 -1
@@ -0,0 +1 @@
1
+ import{ROOT_CONTEXT,trace}from"@opentelemetry/api";import{ZoneContextManager}from"@opentelemetry/context-zone";var PageScopeContextManager=class extends ZoneContextManager{pageScope=ROOT_CONTEXT;pageSpans=new WeakSet;pageScopeSetAtMs=0;rotator=null;maxAgeMs=1/0;rotating=!1;setPageScope(ctx){this.pageScope=ctx,this.pageScopeSetAtMs=Date.now();let span=trace.getSpan(ctx);span&&this.pageSpans.add(span)}setRotation(rotator,maxAgeMs){this.rotator=rotator,this.maxAgeMs=maxAgeMs}active(){let ctx=super.active(),span=trace.getSpan(ctx);if(span&&!this.pageSpans.has(span))return ctx;if(this.pageScope!==ROOT_CONTEXT&&this.rotator&&!this.rotating&&Date.now()-this.pageScopeSetAtMs>this.maxAgeMs){this.rotating=!0;try{this.setPageScope(this.rotator(this.pageScope))}finally{this.rotating=!1}}if(ctx===ROOT_CONTEXT)return this.pageScope;let pageSpan=trace.getSpan(this.pageScope);return pageSpan?trace.setSpan(ctx,pageSpan):ctx}};export{PageScopeContextManager as t};
@@ -0,0 +1 @@
1
+ import{t as createLogger}from"./log-D6Ht--tv.mjs";import{a as resolveGrantedConsent,i as isConsentAllowed,n as getPluginConsentCategory,r as hasConsentChanged}from"./consent-COUmLJLD.mjs";import{t as devicePlugin}from"./device-6T3DYkLD.mjs";import{t as errorsPlugin}from"./errors-BDmCWb5z.mjs";import{n as loadPlugin,r as resolveFeatures}from"./loader-BGwWwN2n.mjs";import{PLUGIN_MANIFEST}from"@interfere/types/sdk/plugins/manifest";const log=createLogger(`plugin-runtime`);var PluginRuntime=class{activeCleanups=new Map;activations=new Map;features=resolveFeatures();pluginConfigListeners=new Map;remoteConfig={};remoteConfigSettled=!1;consentState=null;configSettled=!1;replayConfig={};pageEventsConfig={};syncVersion=0;disposed=!1;context;hasInitialConsent;constructor(context,consent,remoteConfig={}){this.context=context,this.hasInitialConsent=consent!==void 0,this.consentState=consent===void 0?null:resolveGrantedConsent(consent),this.configSettled=this.hasInitialConsent,this.remoteConfig=remoteConfig}getConsent(){return this.consentState}getReplayConfig(){return this.replayConfig}isInteractionCaptureEnabled(){return this.pageEventsConfig.interactions!==!1}applyProviderConfig(overrides,consent){let pageEvents=overrides?.pageEvents,replay=overrides?.replay;this.features=resolveFeatures(overrides),this.pageEventsConfig=typeof pageEvents==`object`?pageEvents:{},this.replayConfig=typeof replay==`object`?replay:{},consent===void 0?this.hasInitialConsent||(this.consentState=null):this.consentState=resolveGrantedConsent(consent),this.configSettled=!0,this.sync()}setConsent(nextConsent){let nextState=resolveGrantedConsent(nextConsent);(!this.configSettled||hasConsentChanged(this.consentState,nextState))&&(this.consentState=nextState,this.configSettled=!0,this.sync())}resetConsent(){(!this.configSettled||hasConsentChanged(this.consentState,null))&&(this.consentState=null,this.configSettled=!0,this.sync())}applyRemoteConfig(config){this.remoteConfig=config,this.remoteConfigSettled=!0,this.emitPluginConfigState(),this.sync()}applyRemoteConfigDefaults(){this.remoteConfigSettled=!0,this.emitPluginConfigState(),this.sync()}start(){for(let[key,plugin]of[[`errors`,errorsPlugin],[`device`,devicePlugin]])if(this.shouldEnablePlugin(key)){let cleanup=plugin.setup(this.context);cleanup&&this.activeCleanups.set(key,cleanup)}this.sync()}async dispose(){this.disposed=!0,this.syncVersion+=1;for(let key of this.activeCleanups.keys())this.deactivate(key,`dispose`);await Promise.allSettled(this.activations.values())}shouldEnablePlugin(key){let category=getPluginConsentCategory(key);return category!==`necessary`&&!this.configSettled?!1:this.features[key]&&this.remoteConfig[key]!==!1&&isConsentAllowed(category,this.consentState)}getPluginConfigState(key){return this.remoteConfigSettled?this.remoteConfig[key]===!1?`disabled`:`enabled`:`pending`}subscribePluginConfigState(key,listener){let listeners=this.pluginConfigListeners.get(key)??new Set;return listeners.add(listener),this.pluginConfigListeners.set(key,listeners),(()=>{listeners.delete(listener),listeners.size===0&&this.pluginConfigListeners.delete(key)})}emitPluginConfigState(){for(let[key,listeners]of this.pluginConfigListeners){let state=this.getPluginConfigState(key);for(let listener of listeners)listener(state)}}teardownReason(key){let category=getPluginConsentCategory(key);return isConsentAllowed(category,this.consentState)?`disabled`:`consent-revoked`}deactivate(key,reason){let cleanup=this.activeCleanups.get(key);if(cleanup){try{cleanup(reason)}catch{log.warn(`cleanup failed for %s`,key)}this.activeCleanups.delete(key)}}async activate(key){if(this.activeCleanups.has(key)||!this.shouldEnablePlugin(key))return;let version=this.syncVersion,cleanup=await loadPlugin(key,this.context);if(cleanup){if(version!==this.syncVersion||!this.shouldEnablePlugin(key)){cleanup(this.teardownReason(key));return}this.activeCleanups.set(key,cleanup)}}sync(){if(!this.disposed){this.syncVersion+=1;for(let plugin of PLUGIN_MANIFEST){if(this.shouldEnablePlugin(plugin.name)){if(plugin.name===`errors`){if(!this.activeCleanups.has(`errors`)){let cleanup=errorsPlugin.setup(this.context);cleanup&&this.activeCleanups.set(`errors`,cleanup)}continue}let previous=this.activations.get(plugin.name);this.activations.set(plugin.name,(async()=>{await previous;try{await this.activate(plugin.name)}catch{log.warn(`non-critical plugin loading failed`)}})());continue}this.deactivate(plugin.name,this.teardownReason(plugin.name))}}}};export{PluginRuntime as t};
@@ -1,4 +1,4 @@
1
- import { T as Plugin } from "../provider-DWgb6tn9.mjs";
1
+ import { w as Plugin } from "../provider-C68KiG80.mjs";
2
2
  //#region src/plugins/device.d.ts
3
3
  declare const devicePlugin: Plugin;
4
4
  //#endregion
@@ -1 +1 @@
1
- const devicePlugin={name:`device`,setup(ctx){return ctx.startDeviceInfoCapture()??void 0}};export{devicePlugin as default};
1
+ import{t as devicePlugin}from"../device-6T3DYkLD.mjs";export{devicePlugin as default};
@@ -1,4 +1,4 @@
1
- import { T as Plugin } from "../provider-DWgb6tn9.mjs";
1
+ import { w as Plugin } from "../provider-C68KiG80.mjs";
2
2
  //#region src/plugins/errors.d.ts
3
3
  declare const errorsPlugin: Plugin;
4
4
  //#endregion
@@ -1 +1 @@
1
- import{hasServerDigest}from"../internal/server-digest.mjs";import{onConsoleCall}from"../internal/console-patch.mjs";import{THIRD_PARTY_IGNORE}from"../internal/third-party-hosts.mjs";import{MECHANISM_TYPE,isNonErrorException,toException}from"@interfere/types/sdk/errors";import{omitUndefined}from"@interfere/helpers/omit-undefined";function capture(ctx,opts){ctx.recordException(opts.error,omitUndefined({mechanism:opts.mechanism,fallbackFrames:opts.fallbackFrame&&!isNonErrorException(opts.error)?[opts.fallbackFrame]:void 0}))}function findErrorArg(args){return args.find(arg=>arg instanceof Error)??null}function resourceError(target){return target instanceof HTMLImageElement||target instanceof HTMLScriptElement?target.src?{tag:target.localName,url:target.src}:null:target instanceof HTMLLinkElement&&target.href?{tag:target.localName,url:target.href}:null}function isIgnoredResourceUrl(url){return THIRD_PARTY_IGNORE.some(pattern=>pattern.test(url))}function createResourceGate(){let seen=new Set,windowStart=0,windowCount=0;return(url=>{if(seen.has(url))return!1;let now=Date.now();return now-windowStart>6e4&&(windowStart=now,windowCount=0),windowCount>=20?!1:(seen.size>=100&&seen.clear(),seen.add(url),windowCount+=1,!0)})}function createRepeatGate(){let counts=new Map,windowStart=0;return(key=>{let now=Date.now();now-windowStart>6e4&&(windowStart=now,counts.clear());let count=counts.get(key)??0;return count>=5?!1:(counts.size>=100&&counts.clear(),counts.set(key,count+1),!0)})}const errorsPlugin={name:`errors`,setup(ctx){let originalOnError=globalThis.onerror,originalStackTraceLimit=Error.stackTraceLimit;Error.stackTraceLimit<50&&(Error.stackTraceLimit=50);let repeatGate=createRepeatGate();globalThis.onerror=(msg,source,line,col,error)=>{if(error instanceof Error&&!hasServerDigest(error)&&repeatGate(`${typeof msg==`string`?msg:msg.type}|${String(source)}|${String(line)}|${String(col)}`)){let fallbackFrame=typeof source==`string`?omitUndefined({file:source,id:`fallback-0`,line:typeof line==`number`?line:void 0,column:typeof col==`number`?col:void 0}):null;capture(ctx,omitUndefined({error,mechanism:{handled:!1,type:MECHANISM_TYPE.browser.onerror},fallbackFrame:fallbackFrame??void 0}))}return typeof originalOnError==`function`&&originalOnError.call(globalThis,msg,source,line,col,error)};let onUnhandledRejection=event=>{hasServerDigest(event.reason)||capture(ctx,{error:toException(event.reason),mechanism:omitUndefined({handled:!1,type:MECHANISM_TYPE.browser.onunhandledrejection,synthetic:event.reason instanceof Error?void 0:!0})})},cspReportsByDisposition={enforce:new Set,report:new Set},onSecurityPolicyViolation=event=>{let seenCspReports=cspReportsByDisposition[event.disposition],key=`${event.violatedDirective}|${event.blockedURI}`;seenCspReports.has(key)||seenCspReports.size>=5||(seenCspReports.add(key),capture(ctx,{error:{kind:`non-error`,serialized:{blockedURI:event.blockedURI,columnNumber:event.columnNumber,disposition:event.disposition,lineNumber:event.lineNumber,sourceFile:event.sourceFile,violatedDirective:event.violatedDirective},type:`SecurityPolicyViolation`,value:event.disposition===`report`?`CSP ${event.violatedDirective} reported ${event.blockedURI||`inline`} (report-only)`:`CSP ${event.violatedDirective} blocked ${event.blockedURI||`inline`}`},mechanism:{handled:event.disposition===`report`,type:MECHANISM_TYPE.browser.securityPolicyViolation}}))},resourceGate=createResourceGate(),onResourceError=event=>{let resource=resourceError(event.target);resource&&!isIgnoredResourceUrl(resource.url)&&resourceGate(resource.url)&&capture(ctx,{error:{kind:`non-error`,serialized:{url:resource.url},type:`ResourceLoadError`,value:`Failed to load ${resource.tag}: ${resource.url}`},mechanism:{handled:!1,type:MECHANISM_TYPE.browser.resourceError}})},supportsEventTarget=typeof globalThis.addEventListener==`function`&&typeof globalThis.removeEventListener==`function`;supportsEventTarget&&(globalThis.addEventListener(`unhandledrejection`,onUnhandledRejection),globalThis.addEventListener(`securitypolicyviolation`,onSecurityPolicyViolation),globalThis.addEventListener(`error`,onResourceError,!0));let unsubscribeConsole=onConsoleCall((level,args)=>{if(level!==`error`)return;let error=findErrorArg(args);error&&!hasServerDigest(error)&&capture(ctx,{error,mechanism:{handled:!0,type:MECHANISM_TYPE.browser.consoleError}})});return()=>{Error.stackTraceLimit=originalStackTraceLimit,globalThis.onerror=originalOnError,supportsEventTarget&&(globalThis.removeEventListener(`unhandledrejection`,onUnhandledRejection),globalThis.removeEventListener(`securitypolicyviolation`,onSecurityPolicyViolation),globalThis.removeEventListener(`error`,onResourceError,!0)),unsubscribeConsole()}}};export{errorsPlugin as default};
1
+ import{t as errorsPlugin}from"../errors-BDmCWb5z.mjs";export{errorsPlugin as default};
@@ -1,2 +1,2 @@
1
- import { C as loadPlugin, S as PluginOverrides, w as resolveFeatures, x as LOADERS } from "../../provider-DWgb6tn9.mjs";
1
+ import { C as resolveFeatures, S as loadPlugin, b as LOADERS, x as PluginOverrides } from "../../provider-C68KiG80.mjs";
2
2
  export { LOADERS, PluginOverrides, loadPlugin, resolveFeatures };
@@ -1 +1 @@
1
- import{createLogger}from"../../util/log.mjs";import errorsPlugin from"../errors.mjs";import{PLUGIN_MANIFEST}from"@interfere/types/sdk/plugins/manifest";const log=createLogger(`plugins`),LOADERS={device:async()=>import(`../device.mjs`),errors:()=>errorsPlugin,logs:async()=>import(`../logs.mjs`),pageEvents:async()=>import(`../page-events.mjs`),rageClick:async()=>import(`../rage-clicks.mjs`),replay:async()=>import(`../replay/index.mjs`)},DEFAULTS=Object.fromEntries(PLUGIN_MANIFEST.map(p=>[p.name,p.defaultEnabled]));function resolveFeatures(overrides){if(!overrides)return{...DEFAULTS};let{replay,...rest}=overrides;return{...DEFAULTS,...rest,replay:replay===void 0?DEFAULTS.replay:replay!==!1}}function resolvePlugin(mod){return`default`in mod?mod.default:mod}async function loadPlugin(key,context){let loader=LOADERS[key];if(loader===void 0)return null;try{let cleanup=resolvePlugin(await loader()).setup(context);return log.debug(`loaded %s`,key),cleanup??null}catch{return log.error(`failed to load plugin %s`,key),null}}export{LOADERS,loadPlugin,resolveFeatures};
1
+ import{n as loadPlugin,r as resolveFeatures,t as LOADERS}from"../../loader-BGwWwN2n.mjs";export{LOADERS,loadPlugin,resolveFeatures};
@@ -1,2 +1,2 @@
1
- import { D as PluginConfigState, E as PluginCleanup, O as PluginContext, T as Plugin, k as PluginTeardownReason } from "../../provider-DWgb6tn9.mjs";
1
+ import { D as PluginContext, E as PluginConfigState, O as PluginTeardownReason, T as PluginCleanup, w as Plugin } from "../../provider-C68KiG80.mjs";
2
2
  export { Plugin, PluginCleanup, PluginConfigState, PluginContext, PluginTeardownReason };
@@ -1,4 +1,4 @@
1
- import { T as Plugin } from "../provider-DWgb6tn9.mjs";
1
+ import { w as Plugin } from "../provider-C68KiG80.mjs";
2
2
  //#region src/plugins/logs.d.ts
3
3
  /**
4
4
  * Subscribes to the central console patch so string-only console calls
@@ -1 +1 @@
1
- import{activeKernel}from"../internal/kernel-registry.mjs";import{onConsoleCall}from"../internal/console-patch.mjs";import{safeStringify}from"../util/stringify.mjs";import{SeverityNumber}from"@opentelemetry/api-logs";const LEVEL_TO_SEVERITY={debug:{number:SeverityNumber.DEBUG,text:`DEBUG`},error:{number:SeverityNumber.ERROR,text:`ERROR`},info:{number:SeverityNumber.INFO,text:`INFO`},log:{number:SeverityNumber.INFO,text:`INFO`},warn:{number:SeverityNumber.WARN,text:`WARN`}},logsPlugin={name:`logs`,setup(){return onConsoleCall((level,args)=>{if(args.some(a=>a instanceof Error))return;let kernel=activeKernel();if(!kernel)return;let sev=LEVEL_TO_SEVERITY[level];kernel.recordLog({attributes:{"console.level":level},body:args.length===1?safeStringify(args[0]):args.map(element=>safeStringify(element)).join(` `),severityNumber:sev.number,severityText:sev.text})})}};export{logsPlugin as default};
1
+ import{t as activeKernel}from"../kernel-registry-6f-3VCIy.mjs";import{n as onConsoleCall}from"../console-patch-WNKoLE7U.mjs";import{t as safeStringify}from"../stringify-DvuHsAT4.mjs";import{SeverityNumber}from"@opentelemetry/api-logs";const LEVEL_TO_SEVERITY={debug:{number:SeverityNumber.DEBUG,text:`DEBUG`},error:{number:SeverityNumber.ERROR,text:`ERROR`},info:{number:SeverityNumber.INFO,text:`INFO`},log:{number:SeverityNumber.INFO,text:`INFO`},warn:{number:SeverityNumber.WARN,text:`WARN`}},logsPlugin={name:`logs`,setup(){return onConsoleCall((level,args)=>{if(args.some(a=>a instanceof Error))return;let kernel=activeKernel();if(!kernel)return;let sev=LEVEL_TO_SEVERITY[level];kernel.recordLog({attributes:{"console.level":level},body:args.length===1?safeStringify(args[0]):args.map(element=>safeStringify(element)).join(` `),severityNumber:sev.number,severityText:sev.text})})}};export{logsPlugin as default};
@@ -0,0 +1,2 @@
1
+ import { n as PageEventsOption, t as PageEventsConfig } from "../page-events-config-CiJvdAaJ.mjs";
2
+ export { PageEventsConfig, PageEventsOption };
@@ -0,0 +1 @@
1
+ export{};
@@ -1,4 +1,4 @@
1
- import { T as Plugin } from "../provider-DWgb6tn9.mjs";
1
+ import { w as Plugin } from "../provider-C68KiG80.mjs";
2
2
  //#region src/plugins/page-events.d.ts
3
3
  declare const pageEventsPlugin: Plugin;
4
4
  //#endregion
@@ -1,4 +1,4 @@
1
- import { T as Plugin } from "../provider-DWgb6tn9.mjs";
1
+ import { w as Plugin } from "../provider-C68KiG80.mjs";
2
2
  //#region src/plugins/rage-clicks.d.ts
3
3
  declare const rageClicksPlugin: Plugin;
4
4
  //#endregion
@@ -1 +1 @@
1
- function distance(a,b){return Math.hypot(a.x-b.x,a.y-b.y)}function selectorFor(el){if(!el)return`unknown`;if(el.id)return`#${el.id}`;let classes=[...el.classList].slice(0,3).join(`.`),tag=el.tagName.toLowerCase();return classes?`${tag}.${classes}`:tag}const rageClicksPlugin={name:`rage-clicks`,setup(ctx){let clicks=[],onClick=event=>{let now=Date.now();for(clicks.push({target:event.target instanceof Element?event.target:null,ts:now,x:event.clientX,y:event.clientY});clicks.length>0&&now-(clicks[0]?.ts??0)>800;)clicks.shift();if(clicks.length<3)return;let[anchor]=clicks;if(!anchor)return;let clustered=clicks.filter(c=>distance(anchor,c)<=30);if(clustered.length<3)return;let last=clustered.at(-1);last&&(ctx.getTracer(`@interfere/react/rage-clicks`).startSpan(`rage_click`,{attributes:{"ui.event_type":`rage_click`,"ui.rage_click.count":clustered.length,"ui.rage_click.selector":selectorFor(last.target),"ui.rage_click.text":last.target?.textContent.trim().slice(0,120)??``,"ui.rage_click.time_window_ms":last.ts-anchor.ts,"ui.rage_click.x":last.x,"ui.rage_click.y":last.y}}).end(),clicks.length=0)};return document.addEventListener(`click`,onClick,{capture:!0}),()=>{document.removeEventListener(`click`,onClick,{capture:!0})}}};export{rageClicksPlugin as default};
1
+ import{n as describeActionable}from"../actionable-DOmVf_ib.mjs";import{omitUndefined}from"@interfere/helpers/omit-undefined";function distance(a,b){return Math.hypot(a.x-b.x,a.y-b.y)}function describeTarget(el,policy){if(!el)return{selector:`unknown`,text:``};let{id,label,privacy,tag,text=``}=describeActionable(el,policy),classes=privacy?[]:[...el.classList].slice(0,3);return{label,privacy,selector:id?`#${id}`:[tag,...classes].join(`.`),text}}const rageClicksPlugin={name:`rage-clicks`,setup(ctx){let clicks=[],onClick=event=>{let now=Date.now();for(clicks.push({target:event.target instanceof Element?event.target:null,ts:now,x:event.clientX,y:event.clientY});clicks.length>0&&now-(clicks[0]?.ts??0)>800;)clicks.shift();if(clicks.length<3)return;let[anchor]=clicks;if(!anchor)return;let clustered=clicks.filter(c=>distance(anchor,c)<=30);if(clustered.length<3)return;let last=clustered.at(-1);if(!last)return;let target=describeTarget(last.target,ctx.privacyPolicy);ctx.getTracer(`@interfere/react/rage-clicks`).startSpan(`rage_click`,{attributes:omitUndefined({"ui.event_type":`rage_click`,"ui.rage_click.count":clustered.length,"ui.rage_click.selector":target.selector,"ui.rage_click.text":target.text,"ui.rage_click.time_window_ms":last.ts-anchor.ts,"ui.rage_click.x":last.x,"ui.rage_click.y":last.y,"ui.target.label":target.label,"ui.target.privacy":target.privacy})}).end(),clicks.length=0};return document.addEventListener(`click`,onClick,{capture:!0}),()=>{document.removeEventListener(`click`,onClick,{capture:!0})}}};export{rageClicksPlugin as default};
@@ -1,4 +1,4 @@
1
- import { BufferedReplayEvent } from "./chunking.mjs";
1
+ import { t as BufferedReplayEvent } from "../../chunking-Dvs3f50A.mjs";
2
2
  import { eventWithTime } from "@rrweb/types";
3
3
  //#region src/plugins/replay/buffer.d.ts
4
4
  export interface ReplayBuffer {
@@ -1 +1 @@
1
- import{classifyReplayEvent,utf8ByteLength}from"./chunking.mjs";function createReplayBuffer(opts){let entries=[],totalBytes=0;return{drain(){let drained=entries;return entries=[],totalBytes=0,drained},push(event){let json=JSON.stringify(event),bytes=utf8ByteLength(json),{isActivity,isFullSnapshot}=classifyReplayEvent(event);entries.push({json,ts:Date.now(),bytes,isActivity,isFullSnapshot}),totalBytes+=bytes,totalBytes>=opts.softLimitBytes&&opts.onSoftLimit()}}}export{createReplayBuffer};
1
+ import{t as createReplayBuffer}from"../../buffer-BRn_kSm-.mjs";export{createReplayBuffer};
@@ -1,38 +1,2 @@
1
- //#region src/plugins/replay/chunking.d.ts
2
- export interface BufferedReplayEvent {
3
- bytes: number;
4
- isActivity: boolean;
5
- isFullSnapshot: boolean;
6
- json: string;
7
- ts: number;
8
- }
9
- export interface ReplayChunkPayload {
10
- activityCount: number;
11
- bodyJson: string;
12
- eventCount: number;
13
- firstTs: number | null;
14
- hasFullSnapshot: boolean;
15
- lastTs: number | null;
16
- }
17
- export interface SplitReplayEventsResult {
18
- chunks: BufferedReplayEvent[][];
19
- droppedEventBytes: number[];
20
- }
21
- export declare function classifyReplayEvent(event: unknown): {
22
- isActivity: boolean;
23
- isFullSnapshot: boolean;
24
- };
25
- export declare function toReplayChunkPayload(group: BufferedReplayEvent[]): {
26
- activityCount: number;
27
- bodyJson: string;
28
- eventCount: number;
29
- firstTs: number | null;
30
- hasFullSnapshot: boolean;
31
- lastTs: number | null;
32
- };
33
- export declare function splitReplayEvents(buffered: BufferedReplayEvent[]): {
34
- chunks: BufferedReplayEvent[][];
35
- droppedEventBytes: number[];
36
- };
37
- export declare function utf8ByteLength(value: string): number;
38
- //#endregion
1
+ import { a as splitReplayEvents, i as classifyReplayEvent, n as ReplayChunkPayload, o as toReplayChunkPayload, r as SplitReplayEventsResult, s as utf8ByteLength, t as BufferedReplayEvent } from "../../chunking-Dvs3f50A.mjs";
2
+ export { BufferedReplayEvent, ReplayChunkPayload, SplitReplayEventsResult, classifyReplayEvent, splitReplayEvents, toReplayChunkPayload, utf8ByteLength };
@@ -1,2 +1 @@
1
- import{EventType,IncrementalSource}from"@rrweb/types";const textEncoder=new TextEncoder,ACTIVITY_SOURCES=new Set([IncrementalSource.MouseMove,IncrementalSource.MouseInteraction,IncrementalSource.Scroll,IncrementalSource.Input,IncrementalSource.TouchMove,IncrementalSource.Drag,IncrementalSource.Selection]);function classifyReplayEvent(event){if(typeof event!=`object`||!event||!(`type`in event)||typeof event.type!=`number`)return{isActivity:!1,isFullSnapshot:!1};if(event.type===EventType.FullSnapshot)return{isActivity:!1,isFullSnapshot:!0};if(event.type===EventType.IncrementalSnapshot&&`data`in event&&event.data!==null&&typeof event.data==`object`&&`source`in event.data){let{source}=event.data;if(typeof source==`number`&&ACTIVITY_SOURCES.has(source))return{isActivity:!0,isFullSnapshot:!1}}return{isActivity:!1,isFullSnapshot:!1}}function countActivityEvents(group){let count=0;for(let entry of group)entry.isActivity&&(count+=1);return count}function toReplayChunkPayload(group){let parts=[],hasFullSnapshot=!1;for(let entry of group)parts.push(entry.json),entry.isFullSnapshot&&(hasFullSnapshot=!0);let firstTs=group[0]?.ts??null;return{activityCount:countActivityEvents(group),bodyJson:parts.length>0?`${parts.join(`
2
- `)}\n`:``,eventCount:group.length,firstTs,hasFullSnapshot,lastTs:group.at(-1)?.ts??null}}function splitReplayEvents(buffered){let chunks=[],droppedEventBytes=[],current=[],currentBytes=0;for(let entry of buffered){let singleEventBodyBytes=entry.bytes+1;if(singleEventBodyBytes>8388608){droppedEventBytes.push(singleEventBodyBytes);continue}current.length>0&&currentBytes+singleEventBodyBytes>6291456&&(chunks.push(current),current=[],currentBytes=0),currentBytes+=singleEventBodyBytes,current.push(entry)}return current.length>0&&chunks.push(current),{chunks,droppedEventBytes}}function utf8ByteLength(value){return textEncoder.encode(value).length}export{classifyReplayEvent,splitReplayEvents,toReplayChunkPayload,utf8ByteLength};
1
+ import{i as utf8ByteLength,n as splitReplayEvents,r as toReplayChunkPayload,t as classifyReplayEvent}from"../../chunking-qZffPbyY.mjs";export{classifyReplayEvent,splitReplayEvents,toReplayChunkPayload,utf8ByteLength};
@@ -1,8 +1,2 @@
1
- //#region src/plugins/replay/compressor-host.d.ts
2
- /** `gzip` is `null` when compression is unavailable — callers must POST the chunk uncompressed. */
3
- export interface Compressor {
4
- readonly dispose: () => void;
5
- readonly gzip: ((bytes: Uint8Array) => Promise<Uint8Array<ArrayBuffer>>) | null;
6
- }
7
- export declare function createCompressor(): Compressor;
8
- //#endregion
1
+ import { n as createCompressor, t as Compressor } from "../../compressor-host-BAz6860r.mjs";
2
+ export { Compressor, createCompressor };
@@ -1 +1 @@
1
- import{createLogger}from"../../util/log.mjs";const log=createLogger(`replay/compressor`),FAIL_OPEN={dispose:()=>void 0,gzip:null},gzip=async bytes=>{let cs=new CompressionStream(`gzip`),compressed=new Response(cs.readable).arrayBuffer(),writer=cs.writable.getWriter();return await writer.write(new Uint8Array(bytes)),await writer.close(),new Uint8Array(await compressed)};function createCompressor(){return typeof CompressionStream>`u`?(log.warn(`CompressionStream unavailable; replay chunks will POST uncompressed`),FAIL_OPEN):{dispose:()=>void 0,gzip}}export{createCompressor};
1
+ import{t as createCompressor}from"../../compressor-host-CrKngamF.mjs";export{createCompressor};
@@ -1,2 +1,2 @@
1
- import { a as ReplayOption, i as ReplayConfig, n as INTERFERE_IGNORE_CLASS, o as ReplayRecordOptions, r as INTERFERE_MASK_TEXT_CLASS, s as toRecordOptions, t as INTERFERE_BLOCK_CLASS } from "../../config-Rm-ct4K1.mjs";
1
+ import { a as ReplayOption, i as ReplayConfig, n as INTERFERE_IGNORE_CLASS, o as ReplayRecordOptions, r as INTERFERE_MASK_TEXT_CLASS, s as toRecordOptions, t as INTERFERE_BLOCK_CLASS } from "../../config-Dyc09HCZ.mjs";
2
2
  export { INTERFERE_BLOCK_CLASS, INTERFERE_IGNORE_CLASS, INTERFERE_MASK_TEXT_CLASS, ReplayConfig, ReplayOption, ReplayRecordOptions, toRecordOptions };
@@ -1 +1 @@
1
- const INTERFERE_MASK_TEXT_CLASS=`interfere-mask`,INTERFERE_BLOCK_CLASS=`interfere-block`,INTERFERE_IGNORE_CLASS=`interfere-ignore`;function toRecordOptions(config){return{...config,blockClass:INTERFERE_BLOCK_CLASS,ignoreClass:INTERFERE_IGNORE_CLASS,maskTextClass:INTERFERE_MASK_TEXT_CLASS}}export{INTERFERE_BLOCK_CLASS,INTERFERE_IGNORE_CLASS,INTERFERE_MASK_TEXT_CLASS,toRecordOptions};
1
+ import{i as toRecordOptions,n as INTERFERE_IGNORE_CLASS,r as INTERFERE_MASK_TEXT_CLASS,t as INTERFERE_BLOCK_CLASS}from"../../config-DapTbKhs.mjs";export{INTERFERE_BLOCK_CLASS,INTERFERE_IGNORE_CLASS,INTERFERE_MASK_TEXT_CLASS,toRecordOptions};
@@ -1,7 +1,7 @@
1
- import { O as PluginContext } from "../../provider-DWgb6tn9.mjs";
2
- import { resolveTargets } from "../../internal/config.mjs";
3
- import { ReplayChunkPayload } from "./chunking.mjs";
4
- import { Compressor } from "./compressor-host.mjs";
1
+ import { D as PluginContext } from "../../provider-C68KiG80.mjs";
2
+ import { n as resolveTargets } from "../../config-CBqqY1AV.mjs";
3
+ import { n as ReplayChunkPayload } from "../../chunking-Dvs3f50A.mjs";
4
+ import { t as Compressor } from "../../compressor-host-BAz6860r.mjs";
5
5
  //#region src/plugins/replay/delivery.d.ts
6
6
  export type DeliverResult = "ok" | "retryable" | "fatal";
7
7
  export interface ReplayChunkRef {
@@ -1 +1 @@
1
- import{createLogger}from"../../util/log.mjs";import{uploadReplayChunk}from"./upload.mjs";import{trace}from"@opentelemetry/api";import{omitUndefined}from"@interfere/helpers/omit-undefined";const log=createLogger(`replay`),textEncoder=new TextEncoder;async function prepareBody(compressor,rawBytes){if(!compressor.gzip)return{body:rawBytes,encoding:null};try{return{body:await compressor.gzip(rawBytes),encoding:`gzip`}}catch(error){return log.warn(`gzip failed for chunk; sending uncompressed: %o`,error),{body:rawBytes,encoding:null}}}function encodeReplayMeta(chunk,payload){return btoa(JSON.stringify({activityCount:payload.activityCount,eventCount:payload.eventCount,firstTs:payload.firstTs,hasFullSnapshot:payload.hasFullSnapshot,lastTs:payload.lastTs,segmentId:chunk.segmentId,windowId:chunk.windowId}))}async function deliverChunk({ctx,chunk,target,compressor,payload,skipCompression}){let sessionId=ctx.getSessionId();if(!sessionId)return`ok`;let rawBytes=textEncoder.encode(payload.bodyJson),uncompressedBytes=rawBytes.byteLength,prepared=skipCompression?{body:rawBytes,encoding:null}:await prepareBody(compressor,rawBytes),headers={"x-replay-meta":encodeReplayMeta(chunk,payload)};prepared.encoding===`gzip`&&(headers[`content-encoding`]=`gzip`);let response;try{let upload=await uploadReplayChunk(target,sessionId,prepared.body,headers);if(!upload.ok)return await upload.body?.cancel(),upload.status>=400&&upload.status<500?`fatal`:`retryable`;response=await upload.json()}catch(error){return log.warn(`replay chunk upload failed: %o`,error),`retryable`}let objectKey=typeof response==`object`&&response&&`objectKey`in response&&typeof response.objectKey==`string`?response.objectKey:null,attributes=omitUndefined({"replay.chunk.size_bytes":uncompressedBytes,"replay.chunk.event_count":payload.eventCount,"replay.chunk.uri":objectKey||void 0,"replay.chunk.compressed_bytes":prepared.encoding===`gzip`?prepared.body.byteLength:void 0,"replay.chunk.first_event_ts":payload.firstTs??void 0,"replay.chunk.last_event_ts":payload.lastTs??void 0});return trace.getTracer(`@interfere/react/replay`).startSpan(`replay.chunk`,{attributes}).end(),`ok`}export{deliverChunk};
1
+ import{t as deliverChunk}from"../../delivery-DehIJWRh.mjs";export{deliverChunk};
@@ -1,4 +1,4 @@
1
- import { T as Plugin } from "../../provider-DWgb6tn9.mjs";
1
+ import { w as Plugin } from "../../provider-C68KiG80.mjs";
2
2
  //#region src/plugins/replay/index.d.ts
3
3
  declare const replayPlugin: Plugin;
4
4
  //#endregion
@@ -1 +1 @@
1
- import{createLogger}from"../../util/log.mjs";import{onPageHidden,onPageShown}from"../../internal/page-lifecycle.mjs";import{resolveTargets}from"../../internal/config.mjs";import{splitReplayEvents,toReplayChunkPayload}from"./chunking.mjs";import{createReplayBuffer}from"./buffer.mjs";import{createCompressor}from"./compressor-host.mjs";import{toRecordOptions}from"./config.mjs";import{deliverChunk}from"./delivery.mjs";import{startReplayRecorder}from"./recorder.mjs";import{createSegmentSequence}from"./sequence.mjs";import{EventType}from"@rrweb/types";const log=createLogger(`replay`),replayPlugin={name:`replay`,setup(ctx){let targets=resolveTargets(),recorder=null,flushTimer=null,unsubscribeConfig=null,unsubscribeHidden=null,unsubscribeShown=null,unsubscribePause=null,unsubscribeResume=null,isPaused=!1,startup=new AbortController,compressor=createCompressor(),windowId=ctx.getWindowId(),sequence=createSegmentSequence(windowId),consecutiveFailures=0,recorderFaults=0,halted=!1;function halt(){halted||(halted=!0,startup.abort(),flushTimer&&=(clearInterval(flushTimer),null),recorder?.stop(),recorder=null)}function handleResult(result){if(result===`ok`){consecutiveFailures=0;return}if(result===`fatal`){log.warn(`replay halted: upload rejected`),halt();return}consecutiveFailures+=1,consecutiveFailures>=3&&(log.warn(`replay halted after %d consecutive upload failures`,consecutiveFailures),halt())}function handleRecorderFault(error){recorderFaults+=1,!(recorderFaults>10)&&(log.warn(`recorder fault: %s`,error instanceof Error?error.constructor.name:`UnknownError`),recorderFaults===10&&(log.warn(`replay halted after %d recorder faults`,10),flush(),halt()))}let buffer=createReplayBuffer({onSoftLimit:flush,softLimitBytes:4194304});function flush(opts){if(halted||ctx.getPluginConfigState(`replay`)!==`enabled`)return;let drained=buffer.drain();if(drained.length===0)return;let{chunks,droppedEventBytes}=splitReplayEvents(drained);for(let bytes of droppedEventBytes)log.warn(`dropping replay event of ~%d bytes: too large to upload`,bytes);for(let group of chunks)sendChunk(toReplayChunkPayload(group),opts?.skipCompression??!1)}async function sendChunk(payload,skipCompression){try{handleResult(await deliverChunk({target:targets.ingest,chunk:{segmentId:sequence.take(),windowId},compressor,ctx,payload,skipCompression}))}catch(error){log.warn(`replay chunk dropped: %s`,error instanceof Error?error.constructor.name:`UnknownError`),handleResult(`retryable`)}}let pauseRecording=unload=>{isPaused||(isPaused=!0,recorder?.stop(),flush(unload?{skipCompression:!0}:void 0))},resumeRecording=()=>{isPaused&&(isPaused=!1,recorder?.start())},recordOptions=toRecordOptions(ctx.getReplayConfig());return(async()=>{if(recorder=await startReplayRecorder({onEvent:(event,isCheckout)=>{startup.signal.aborted||(isCheckout&&event.type===EventType.Meta&&flush(),buffer.push(event))},onFault:handleRecorderFault,recordOptions,signal:startup.signal}),startup.signal.aborted){recorder?.stop(),recorder=null;return}recorder&&(unsubscribeConfig=ctx.subscribePluginConfigState(`replay`,state=>{state===`enabled`&&flush()}),flushTimer=setInterval(flush,1e4),unsubscribeHidden=onPageHidden(()=>{pauseRecording(!0)}),unsubscribeShown=onPageShown(resumeRecording),unsubscribePause=ctx.onSessionPause(()=>{pauseRecording(!1)}),unsubscribeResume=ctx.onSessionResume(resumeRecording),log.debug(`recording started`))})().catch(error=>{log.warn(`replay initialization failed: %s`,error instanceof Error?error.constructor.name:`UnknownError`),halt()}),reason=>{reason===`consent-revoked`?(buffer.drain(),log.debug(`replay buffer discarded: consent revoked`)):flush(),startup.abort(),recorder?.stop(),flushTimer&&clearInterval(flushTimer),unsubscribeConfig?.(),unsubscribeHidden?.(),unsubscribeShown?.(),unsubscribePause?.(),unsubscribeResume?.(),compressor.dispose()}}};export{replayPlugin as default};
1
+ import{t as createLogger}from"../../log-D6Ht--tv.mjs";import{n as resolveTargets}from"../../config-Bm8myQlS.mjs";import{n as onPageShown,t as onPageHidden}from"../../page-lifecycle-BhSFqjlK.mjs";import{i as toRecordOptions}from"../../config-DapTbKhs.mjs";import{n as splitReplayEvents,r as toReplayChunkPayload}from"../../chunking-qZffPbyY.mjs";import{t as createReplayBuffer}from"../../buffer-BRn_kSm-.mjs";import{t as createCompressor}from"../../compressor-host-CrKngamF.mjs";import{t as deliverChunk}from"../../delivery-DehIJWRh.mjs";import{t as startReplayRecorder}from"../../recorder-CM6Ae_0S.mjs";import{t as redactReplayEvent}from"../../redact-urls-CwFod9d4.mjs";import{t as createSegmentSequence}from"../../sequence-B4dYChb0.mjs";import{EventType}from"@rrweb/types";const log=createLogger(`replay`),replayPlugin={name:`replay`,setup(ctx){let targets=resolveTargets(),recorder=null,flushTimer=null,unsubscribeConfig=null,unsubscribeHidden=null,unsubscribeShown=null,unsubscribePause=null,unsubscribeResume=null,isPaused=!1,startup=new AbortController,compressor=createCompressor(),windowId=ctx.getWindowId(),sequence=createSegmentSequence(windowId),consecutiveFailures=0,recorderFaults=0,halted=!1;function halt(){halted||(halted=!0,startup.abort(),flushTimer&&=(clearInterval(flushTimer),null),recorder?.stop(),recorder=null)}function handleResult(result){if(result===`ok`){consecutiveFailures=0;return}if(result===`fatal`){log.warn(`replay halted: upload rejected`),halt();return}consecutiveFailures+=1,consecutiveFailures>=3&&(log.warn(`replay halted after %d consecutive upload failures`,consecutiveFailures),halt())}function handleRecorderFault(error){recorderFaults+=1,!(recorderFaults>10)&&(log.warn(`recorder fault: %s`,error instanceof Error?error.constructor.name:`UnknownError`),recorderFaults===10&&(log.warn(`replay halted after %d recorder faults`,10),flush(),halt()))}let buffer=createReplayBuffer({onSoftLimit:flush,softLimitBytes:4194304});function flush(opts){if(halted||ctx.getPluginConfigState(`replay`)!==`enabled`)return;let drained=buffer.drain();if(drained.length===0)return;let{chunks,droppedEventBytes}=splitReplayEvents(drained);for(let bytes of droppedEventBytes)log.warn(`dropping replay event of ~%d bytes: too large to upload`,bytes);for(let group of chunks)sendChunk(toReplayChunkPayload(group),opts?.skipCompression??!1)}async function sendChunk(payload,skipCompression){try{handleResult(await deliverChunk({target:targets.ingest,chunk:{segmentId:sequence.take(),windowId},compressor,ctx,payload,skipCompression}))}catch(error){log.warn(`replay chunk dropped: %s`,error instanceof Error?error.constructor.name:`UnknownError`),handleResult(`retryable`)}}let pauseRecording=unload=>{isPaused||(isPaused=!0,recorder?.stop(),flush(unload?{skipCompression:!0}:void 0))},resumeRecording=()=>{isPaused&&(isPaused=!1,recorder?.start())},recordOptions=toRecordOptions(ctx.getReplayConfig(),ctx.privacyPolicy);return(async()=>{if(recorder=await startReplayRecorder({onEvent:(event,isCheckout)=>{startup.signal.aborted||(isCheckout&&event.type===EventType.Meta&&flush(),redactReplayEvent(event,ctx.redactUrl),buffer.push(event))},onFault:handleRecorderFault,recordOptions,signal:startup.signal}),startup.signal.aborted){recorder?.stop(),recorder=null;return}recorder&&(unsubscribeConfig=ctx.subscribePluginConfigState(`replay`,state=>{state===`enabled`&&flush()}),flushTimer=setInterval(flush,1e4),unsubscribeHidden=onPageHidden(()=>{pauseRecording(!0)}),unsubscribeShown=onPageShown(resumeRecording),unsubscribePause=ctx.onSessionPause(()=>{pauseRecording(!1)}),unsubscribeResume=ctx.onSessionResume(resumeRecording),log.debug(`recording started`))})().catch(error=>{log.warn(`replay initialization failed: %s`,error instanceof Error?error.constructor.name:`UnknownError`),halt()}),reason=>{reason===`consent-revoked`?(buffer.drain(),log.debug(`replay buffer discarded: consent revoked`)):flush(),startup.abort(),recorder?.stop(),flushTimer&&clearInterval(flushTimer),unsubscribeConfig?.(),unsubscribeHidden?.(),unsubscribeShown?.(),unsubscribePause?.(),unsubscribeResume?.(),compressor.dispose()}}};export{replayPlugin as default};
@@ -1,4 +1,4 @@
1
- import { o as ReplayRecordOptions } from "../../config-Rm-ct4K1.mjs";
1
+ import { o as ReplayRecordOptions } from "../../config-Dyc09HCZ.mjs";
2
2
  import { eventWithTime } from "@rrweb/types";
3
3
  //#region src/plugins/replay/recorder.d.ts
4
4
  export interface ReplayRecorder {
@@ -1 +1 @@
1
- import{createLogger}from"../../util/log.mjs";const log=createLogger(`replay`);async function startReplayRecorder({onEvent,onFault,recordOptions,signal}){let record;try{({record}=await import(`../../rrweb-CE6GKCEq.mjs`))}catch{return log.error(`rrweb failed to load, replay disabled`),null}if(signal?.aborted)return null;let stopRecording,recorder={start:()=>(stopRecording??=record({emit:onEvent,recordAfter:`load`,inlineStylesheet:!0,slimDOMOptions:`all`,checkoutEveryNms:6e4,sampling:{media:800,mousemove:50,scroll:150},...recordOptions,errorHandler:error=>(onFault(error),!0)}),stopRecording!==void 0),stop:()=>{stopRecording?.(),stopRecording=void 0}};return recorder.start()?recorder:(log.error(`rrweb failed to start, replay disabled`),null)}export{startReplayRecorder};
1
+ import{t as startReplayRecorder}from"../../recorder-CM6Ae_0S.mjs";export{startReplayRecorder};
@@ -0,0 +1,6 @@
1
+ import { eventWithTime } from "@rrweb/types";
2
+ //#region src/plugins/replay/redact-urls.d.ts
3
+ type RedactUrl = (url: string) => string;
4
+ /** Rewrites URLs that rrweb records in page metadata and DOM attributes before the event leaves the browser. */
5
+ export declare function redactReplayEvent(event: eventWithTime, redactUrl: RedactUrl): void;
6
+ //#endregion
@@ -0,0 +1 @@
1
+ import{t as redactReplayEvent}from"../../redact-urls-CwFod9d4.mjs";export{redactReplayEvent};
@@ -1 +1 @@
1
- function sessionStore(){try{let store=globalThis.sessionStorage,probe=`__interfere_replay_seq_probe__`;return store.setItem(probe,`1`),store.removeItem(probe),store}catch{return null}}function createSegmentSequence(windowId){let key=`interfere:replay_seq:${windowId}`,store=sessionStore(),stored=store?.getItem(key),next=stored?Number(stored):0;return(!Number.isInteger(next)||next<0)&&(next=0),{take(){let persisted=Number(store?.getItem(key));Number.isSafeInteger(persisted)&&persisted>next&&(next=persisted);let seq=next;return next+=1,store?.setItem(key,String(next)),seq}}}export{createSegmentSequence};
1
+ import{t as createSegmentSequence}from"../../sequence-B4dYChb0.mjs";export{createSegmentSequence};
@@ -1,4 +1,4 @@
1
- import { resolveTargets } from "../../internal/config.mjs";
1
+ import { n as resolveTargets } from "../../config-CBqqY1AV.mjs";
2
2
  //#region src/plugins/replay/upload.d.ts
3
3
  export declare function uploadReplayChunk(target: ReturnType<typeof resolveTargets>["ingest"], sessionId: string, body: Uint8Array<ArrayBuffer>, headers: Record<string, string>): Promise<Response>;
4
4
  //#endregion
@@ -1 +1 @@
1
- async function uploadReplayChunk(target,sessionId,body,headers){let requestHeaders=new Headers(target.headers);target.publicKeyHeader&&requestHeaders.set(`x-interfere-public-key`,target.publicKeyHeader.apiKey);for(let[name,value]of Object.entries(headers))requestHeaders.set(name,value);return requestHeaders.set(`content-type`,`application/octet-stream`),fetch(new URL(`/v3/replay/upload/${encodeURIComponent(sessionId)}`,target.baseUrl),{method:`POST`,credentials:`omit`,headers:requestHeaders,body:new Blob([body]),signal:AbortSignal.timeout(target.timeoutInSeconds*1e3)})}export{uploadReplayChunk};
1
+ import{t as uploadReplayChunk}from"../../upload-BPaD3YcA.mjs";export{uploadReplayChunk};
@@ -0,0 +1,31 @@
1
+ import { UrlRedactionOption } from "@interfere/types/sdk/url-redaction";
2
+ //#region src/internal/dom/privacy.d.ts
3
+ type PrivacyLevel = "blocked" | "masked" | "public";
4
+ /** What the SDK never records. Selectors apply to session replay and to click, submit and rage-click records from the first capture. */
5
+ interface PrivacyOptions {
6
+ /**
7
+ * CSS selector for elements recorded only as placeholders. Replay shows a
8
+ * same-size box; interaction records keep the event, tag and field label.
9
+ * Matches the element and everything inside it.
10
+ */
11
+ blockSelector?: string;
12
+ /**
13
+ * CSS selector for elements whose text is masked in replay and omitted from
14
+ * interaction records. Matches the element and everything inside it.
15
+ */
16
+ maskTextSelector?: string;
17
+ /** Query values and fragments to redact in recorded URLs. Defaults to built-in sensitive parameter names. */
18
+ urls?: UrlRedactionOption;
19
+ }
20
+ interface PrivacyPolicy {
21
+ readonly blockAll: boolean;
22
+ readonly blockSelector: string;
23
+ readonly maskSelector: string;
24
+ }
25
+ declare const DEFAULT_PRIVACY_POLICY: PrivacyPolicy;
26
+ declare function resolvePrivacyPolicy({ blockSelector, maskTextSelector }?: PrivacyOptions): PrivacyPolicy;
27
+ declare function privacyLevel(element: Element, policy: PrivacyPolicy): "blocked" | "masked" | "public";
28
+ declare function publicText(element: Element, policy: PrivacyPolicy): string;
29
+ declare function fieldLabel(element: Element, policy: PrivacyPolicy): string;
30
+ //#endregion
31
+ export { fieldLabel as a, resolvePrivacyPolicy as c, PrivacyPolicy as i, PrivacyLevel as n, privacyLevel as o, PrivacyOptions as r, publicText as s, DEFAULT_PRIVACY_POLICY as t };
@@ -0,0 +1 @@
1
+ import{t as createLogger}from"./log-D6Ht--tv.mjs";import{r as INTERFERE_MASK_TEXT_CLASS,t as INTERFERE_BLOCK_CLASS}from"./config-DapTbKhs.mjs";const log=createLogger(`privacy`),LABEL_ATTRIBUTE=`data-interfere-label`,FORM_FIELD_SELECTOR=`input, select, textarea`,DEFAULT_PRIVACY_POLICY={blockAll:!1,blockSelector:`.${INTERFERE_BLOCK_CLASS}`,maskSelector:`.${INTERFERE_MASK_TEXT_CLASS}`};function resolvePrivacyPolicy({blockSelector,maskTextSelector}={}){let policy={blockAll:!1,blockSelector:[DEFAULT_PRIVACY_POLICY.blockSelector,blockSelector].filter(Boolean).join(`, `),maskSelector:[DEFAULT_PRIVACY_POLICY.maskSelector,maskTextSelector].filter(Boolean).join(`, `)};try{return document.querySelector(`${policy.blockSelector}, ${policy.maskSelector}`),policy}catch{return log.warn(`invalid privacy selector; interaction details are blocked`),{...policy,blockAll:!0}}}function privacyLevel(element,policy){return policy.blockAll||element.closest(policy.blockSelector)?`blocked`:element.closest(policy.maskSelector)?`masked`:`public`}function publicText(element,policy){if(element.matches(FORM_FIELD_SELECTOR))return``;let hidden=`${policy.blockSelector}, ${policy.maskSelector}, ${FORM_FIELD_SELECTOR}`,walker=document.createTreeWalker(element,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,{acceptNode(node){return node instanceof Element?node.matches(hidden)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_SKIP:NodeFilter.FILTER_ACCEPT}}),text=``;for(let node=walker.nextNode();node&&text.trimStart().length<120;node=walker.nextNode())text+=node.nodeValue??``;return text.trim().slice(0,120)}function labelElements(element){let labels=element instanceof HTMLButtonElement||element instanceof HTMLInputElement||element instanceof HTMLSelectElement||element instanceof HTMLTextAreaElement?[...element.labels??[]]:[];for(let id of element.getAttribute(`aria-labelledby`)?.split(/\s+/u)??[]){let labelledBy=id?element.ownerDocument.querySelector(`#${CSS.escape(id)}`):null;labelledBy&&labels.push(labelledBy)}return labels}function fieldLabel(element,policy){let explicit=element.closest(`[${LABEL_ATTRIBUTE}]`)?.getAttribute(LABEL_ATTRIBUTE)?.trim();return explicit?explicit.slice(0,120):labelElements(element).filter(label=>privacyLevel(label,policy)===`public`).map(label=>publicText(label,policy)).filter(Boolean).join(` `).slice(0,120)}export{resolvePrivacyPolicy as a,publicText as i,fieldLabel as n,privacyLevel as r,DEFAULT_PRIVACY_POLICY as t};
@@ -0,0 +1 @@
1
+ import{ROOT_CONTEXT,defaultTextMapGetter,trace}from"@opentelemetry/api";import{omitUndefined}from"@interfere/helpers/omit-undefined";import{W3CBaggagePropagator,W3CTraceContextPropagator}from"@opentelemetry/core";import{TRACESTATE_FRESHNESS_KEY,isFreshnessStampExpired}from"@interfere/types/sdk/trace-freshness";const TRACESTATE_META=`tracestate`,BAGGAGE_META=`baggage`,W3C_PROPAGATOR=new W3CTraceContextPropagator,W3C_BAGGAGE_PROPAGATOR=new W3CBaggagePropagator;function readMeta(name){return typeof document>`u`?null:document.querySelector(`meta[name="${name}"]`)?.getAttribute(`content`)??null}function readTracestateMeta(){if(typeof document>`u`)return null;let contents=[...document.querySelectorAll(`meta[name="${TRACESTATE_META}"]`)].flatMap(el=>{let content=el.getAttribute(`content`);return content===null?[]:[content]});return contents.find(content=>RegExp(`(?:^|,)\\s*${TRACESTATE_FRESHNESS_KEY}=`,`u`).test(content))??contents.at(0)??null}function readPropagationFromDocument(){let traceparent=readMeta(`traceparent`);if(!traceparent)return null;let carrier=omitUndefined({traceparent,[TRACESTATE_META]:readTracestateMeta()||void 0,[BAGGAGE_META]:readMeta(BAGGAGE_META)||void 0}),withTrace=W3C_PROPAGATOR.extract(ROOT_CONTEXT,carrier,defaultTextMapGetter),extracted=W3C_BAGGAGE_PROPAGATOR.extract(withTrace,carrier,defaultTextMapGetter),spanCtx=trace.getSpanContext(extracted);return!spanCtx||spanCtx.traceId===`00000000000000000000000000000000`||!(spanCtx.traceFlags&1)||isStaleTraceparent(spanCtx.traceState?.get(TRACESTATE_FRESHNESS_KEY))?null:extracted}function isStaleTraceparent(freshnessStamp){return freshnessStamp?isFreshnessStampExpired(freshnessStamp,Date.now()):!1}export{readPropagationFromDocument as t};
@@ -1,14 +1,17 @@
1
- import { c as SessionResumeReason } from "./activity-BfYxFVcK.mjs";
2
- import { a as ReplayOption, i as ReplayConfig } from "./config-Rm-ct4K1.mjs";
3
- import { t as SessionTracker } from "./api-DEVCOKkJ.mjs";
4
- import { n as CaptureFailedRequestsOption, t as BundledInstrumentations } from "./instrumentations-Bgm2EazU.mjs";
5
- import { t as OtelProviderHandle } from "./provider-2LrbA-ld.mjs";
6
- import "./index-DvFfO2V9.mjs";
1
+ import { c as SessionResumeReason } from "./activity-Duhfgvxt.mjs";
2
+ import { i as PrivacyPolicy, r as PrivacyOptions } from "./privacy-CPKosXDP.mjs";
3
+ import { a as ReplayOption, i as ReplayConfig } from "./config-Dyc09HCZ.mjs";
4
+ import { n as PageEventsOption } from "./page-events-config-CiJvdAaJ.mjs";
5
+ import { t as SessionTracker } from "./api-CMPV9rgU.mjs";
6
+ import { n as CaptureFailedRequestsOption, t as BundledInstrumentations } from "./instrumentations-BuccMAMj.mjs";
7
+ import { t as OtelProviderHandle } from "./provider-VZtcX6ZS.mjs";
8
+ import "./index-DBsXraeJ.mjs";
7
9
  import { NonErrorException } from "@interfere/types/sdk/errors";
8
10
  import { Tracer } from "@opentelemetry/api";
9
11
  import { PropsWithChildren } from "react";
10
12
  import { ConsentInput, ConsentState, PluginKey } from "@interfere/types/sdk/plugins/manifest";
11
13
  import { RemotePluginConfig } from "@interfere/types/sdk/remote-config";
14
+ import { UrlRedactionPolicy } from "@interfere/types/sdk/url-redaction";
12
15
  import { SessionId } from "@interfere/types/data/session";
13
16
  import { MetricReader } from "@opentelemetry/sdk-metrics";
14
17
  import { LogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
@@ -23,12 +26,14 @@ type PluginConfigState = "disabled" | "enabled" | "pending";
23
26
  interface PluginContext {
24
27
  getPluginConfigState: (key: PluginKey) => PluginConfigState;
25
28
  getReplayConfig: () => ReplayConfig;
29
+ readonly privacyPolicy: PrivacyPolicy;
26
30
  getSessionId: () => string;
27
31
  getTracer: (name: string) => Tracer;
28
32
  getWindowId: () => string;
29
33
  onSessionPause: (handler: () => void) => () => void;
30
34
  onSessionResume: (handler: (reason: SessionResumeReason) => void) => () => void;
31
35
  recordException: (value: Error | NonErrorException, opts: RecordExceptionOpts) => void;
36
+ redactUrl: (url: string) => string;
32
37
  startDeviceInfoCapture: () => PluginCleanup | null;
33
38
  startPageEventsCapture: () => PluginCleanup | null;
34
39
  subscribePluginConfigState: (key: PluginKey, listener: (state: PluginConfigState) => void) => () => void;
@@ -43,7 +48,8 @@ type PluginLoader = () => Promise<{
43
48
  default: Plugin;
44
49
  } | Plugin> | Plugin;
45
50
  declare const LOADERS: Record<PluginKey, PluginLoader>;
46
- type PluginOverrides = Partial<Record<Exclude<PluginKey, "replay">, boolean>> & {
51
+ type PluginOverrides = Partial<Record<Exclude<PluginKey, "pageEvents" | "replay">, boolean>> & {
52
+ pageEvents?: PageEventsOption;
47
53
  replay?: ReplayOption;
48
54
  };
49
55
  declare function resolveFeatures(overrides?: PluginOverrides): {
@@ -56,10 +62,10 @@ declare function resolveFeatures(overrides?: PluginOverrides): {
56
62
  };
57
63
  declare function loadPlugin(key: PluginKey, context: PluginContext): Promise<PluginCleanup | null>;
58
64
  //#endregion
59
- //#region src/internal/plugin-runtime.d.ts
65
+ //#region src/internal/plugins/plugin-runtime.d.ts
60
66
  declare class PluginRuntime {
61
67
  private readonly activeCleanups;
62
- private readonly pending;
68
+ private readonly activations;
63
69
  private features;
64
70
  private readonly pluginConfigListeners;
65
71
  private remoteConfig;
@@ -67,6 +73,7 @@ declare class PluginRuntime {
67
73
  private consentState;
68
74
  private configSettled;
69
75
  private replayConfig;
76
+ private pageEventsConfig;
70
77
  private syncVersion;
71
78
  private disposed;
72
79
  private readonly context;
@@ -74,6 +81,7 @@ declare class PluginRuntime {
74
81
  constructor(context: PluginContext, consent?: ConsentInput, remoteConfig?: RemotePluginConfig);
75
82
  getConsent(): ConsentState | null;
76
83
  getReplayConfig(): ReplayConfig;
84
+ isInteractionCaptureEnabled(): boolean;
77
85
  applyProviderConfig(overrides: PluginOverrides | undefined, consent: ConsentInput | undefined): void;
78
86
  setConsent(nextConsent?: ConsentInput): void;
79
87
  resetConsent(): void;
@@ -127,6 +135,14 @@ interface KernelOptions {
127
135
  serviceName?: string;
128
136
  /** Optional application namespace for grouping related services. */
129
137
  serviceNamespace?: string;
138
+ /**
139
+ * What the SDK never records. `blockSelector` and `maskTextSelector` apply
140
+ * to session replay and to click, submit and rage-click records from the
141
+ * first capture; the `interfere-block` and `interfere-mask` classes always
142
+ * apply. `urls` controls query and fragment redaction; URL credentials are
143
+ * always redacted.
144
+ */
145
+ privacy?: PrivacyOptions;
130
146
  /**
131
147
  * `false` skips the OTel module entirely — the bundler code-splits
132
148
  * `internal/otel/*` out of this path so the error-only bundle never
@@ -143,6 +159,12 @@ interface KernelOptions {
143
159
  * need to touch any of these — sensible defaults ship out of the box.
144
160
  */
145
161
  interface TracingOptions {
162
+ /**
163
+ * Additional OpenTelemetry processors, in array order after built-in enrichment
164
+ * and before wrapper processors and export. Complete redaction synchronously
165
+ * in onEnd. The SDK owns forceFlush and shutdown for these instances.
166
+ */
167
+ spanProcessors?: SpanProcessor[];
146
168
  /**
147
169
  * Backend hostnames that receive trace context and session baggage, e.g.
148
170
  * `["api.example.com"]`. Same-origin requests always propagate. Entries
@@ -271,6 +293,9 @@ declare class Kernel implements PluginContext {
271
293
  readonly identity: KernelIdentity;
272
294
  readonly device: KernelDevice;
273
295
  readonly session: KernelSession;
296
+ readonly privacyPolicy: PrivacyPolicy;
297
+ readonly urlRedaction: UrlRedactionPolicy;
298
+ readonly redactUrl: (url: string) => string;
274
299
  private readonly seen;
275
300
  private readonly initialNavigationSeen;
276
301
  private runtime;
@@ -280,7 +305,7 @@ declare class Kernel implements PluginContext {
280
305
  private deviceInfoCaptureEnabled;
281
306
  private unsubscribePageHidden;
282
307
  private readonly tracker;
283
- constructor(tracker: SessionTracker);
308
+ constructor(tracker: SessionTracker, privacy?: PrivacyOptions);
284
309
  /**
285
310
  * Bound by `createKernel` immediately after construction.
286
311
  *
@@ -295,6 +320,7 @@ declare class Kernel implements PluginContext {
295
320
  onSessionResume(handler: (reason: SessionResumeReason) => void): () => void;
296
321
  getPluginConfigState(key: PluginKey): "disabled" | "enabled" | "pending";
297
322
  getReplayConfig(): ReplayConfig;
323
+ isInteractionCaptureEnabled(): boolean;
298
324
  subscribePluginConfigState(key: PluginKey, listener: (state: PluginConfigState) => void): () => void;
299
325
  getTracer(name: string): import("@opentelemetry/api").Tracer;
300
326
  startPageEventsCapture(): (() => void) | null;
@@ -363,7 +389,6 @@ interface CreateKernelInput {
363
389
  opts?: KernelInternalOptions;
364
390
  }
365
391
  declare function createKernel(input?: CreateKernelInput): Promise<Kernel>;
366
- declare function isEnabledByEnvironment(): boolean;
367
392
  /**
368
393
  * Build-time-derived release slug. The build step
369
394
  * (`@interfere/next/withInterfere`, `@interfere/vite/plugin`) takes the
@@ -426,22 +451,9 @@ interface InterfereProviderProps extends PropsWithChildren {
426
451
  * consent, omitting this prop leaves every category allowed.
427
452
  */
428
453
  consent?: ConsentInput | undefined;
429
- /**
430
- * Auto-install an internal capture boundary around `children` so
431
- * render-phase React errors are reported even when the host app has no
432
- * `ErrorBoundary` / `error.tsx` of its own.
433
- *
434
- * The internal boundary is transparent: it captures the error and then
435
- * re-throws so upstream boundaries (the customer's own, Next.js's
436
- * `error.tsx` / `global-error.tsx`, or React's default unmount) keep full
437
- * control of what the user sees. Safe to leave enabled.
438
- *
439
- * Pass `false` only if you explicitly don't want automatic capture of
440
- * render-phase errors — for example, if you've already wired
441
- * {@link reactErrorHandler} into `createRoot()`.
442
- *
443
- * @default true
444
- */
454
+ /** Reports render errors and rethrows to the host boundary. Defaults to true. */
455
+ captureRenderErrors?: boolean;
456
+ /** @deprecated Use captureRenderErrors, which takes precedence when both are set. */
445
457
  errorBoundary?: boolean;
446
458
  /**
447
459
  * The active kernel from `init()`. Pass `null` (or omit on the server)
@@ -452,21 +464,25 @@ interface InterfereProviderProps extends PropsWithChildren {
452
464
  kernel: Kernel | null;
453
465
  /**
454
466
  * Per-plugin overrides, merged over the manifest defaults. Generic plugins
455
- * are booleans (e.g. `{ pageEvents: false }`). `replay` additionally accepts
456
- * a config object — `{ replay: { maskAllInputs: true } }` enables replay
457
- * with that masking config; `{ replay: false }` disables it. Privacy classes
458
- * are always applied, regardless of config: `interfere-block` elements are
459
- * dropped and replay as a same-size placeholder, `interfere-mask` masks the
460
- * text of an element and all its children, and `interfere-ignore` stops an
461
- * element's input events from being recorded. `input[type="password"]` is
462
- * masked by default; use `maskInputOptions`/`maskAllInputs` to mask other
463
- * input values. `init()` no longer accepts plugin config; this is the only
464
- * place it lives.
467
+ * are booleans (e.g. `{ rageClick: false }`). `pageEvents` also accepts
468
+ * `{ interactions: false }`, which keeps navigation, document-load and
469
+ * resource timing while dropping click and submit spans. `replay`
470
+ * additionally accepts a config object — `{ replay: { maskAllInputs: true } }`
471
+ * enables replay with that masking config; `{ replay: false }` disables it.
472
+ * Privacy classes are always applied, regardless of config:
473
+ * `interfere-block` elements are dropped and replay as a same-size
474
+ * placeholder, `interfere-mask` masks the text of an element and all its
475
+ * children, and `interfere-ignore` stops an element's input events from
476
+ * being recorded. `input[type="password"]` is masked by default; use
477
+ * `maskInputOptions`/`maskAllInputs` to mask other input values. Use
478
+ * `init()`'s `privacy` option for selectors that also govern click, submit
479
+ * and rage-click capture. `init()` no longer accepts plugin config; this is
480
+ * the only place it lives.
465
481
  */
466
482
  plugins?: PluginOverrides | undefined;
467
483
  }
468
- declare function InterfereProvider({ kernel, children, consent, plugins, errorBoundary }: InterfereProviderProps): import("react").JSX.Element;
484
+ declare function InterfereProvider({ kernel, children, consent, plugins, captureRenderErrors, errorBoundary }: InterfereProviderProps): import("react").JSX.Element;
469
485
  declare function useInterfere(): InterfereContextValue;
470
486
  declare function useSession(): string | null;
471
487
  //#endregion
472
- export { loadPlugin as C, PluginConfigState as D, PluginCleanup as E, PluginContext as O, PluginOverrides as S, Plugin as T, createKernel as _, InterfereContextValue as a, PluginRuntime as b, KernelConsent as c, KernelInternalOptions as d, KernelOptions as f, buildSdkStack as g, TracingOptions as h, InterfereContext as i, PluginTeardownReason as k, KernelDevice as l, RecordExceptionOpts as m, useInterfere as n, NULL_CONTEXT_VALUE as o, KernelSession as p, useSession as r, Kernel as s, InterfereProvider as t, KernelIdentity as u, isEnabledByEnvironment as v, resolveFeatures as w, LOADERS as x, readReleaseSlugFromGlobals as y };
488
+ export { resolveFeatures as C, PluginContext as D, PluginConfigState as E, PluginTeardownReason as O, loadPlugin as S, PluginCleanup as T, createKernel as _, InterfereContextValue as a, LOADERS as b, KernelConsent as c, KernelInternalOptions as d, KernelOptions as f, buildSdkStack as g, TracingOptions as h, InterfereContext as i, KernelDevice as l, RecordExceptionOpts as m, useInterfere as n, NULL_CONTEXT_VALUE as o, KernelSession as p, useSession as r, Kernel as s, InterfereProvider as t, KernelIdentity as u, readReleaseSlugFromGlobals as v, Plugin as w, PluginOverrides as x, PluginRuntime as y };
@@ -0,0 +1 @@
1
+ import{n as getStringGlobal}from"./global-DYq1Z4_H.mjs";import{n as SDK_NAME,r as SDK_VERSION}from"./version-B5O6bg5e.mjs";import{i as createTraceExporter,n as createLogExporter,r as createMetricExporter}from"./exporter-3w57pctH.mjs";import{t as PageScopeContextManager}from"./page-scope-context-manager-DhArvVJ_.mjs";import{context,propagation}from"@opentelemetry/api";import{omitUndefined}from"@interfere/helpers/omit-undefined";import{ENVIRONMENT_GLOBAL}from"@interfere/types/sdk/injected-globals";import{createUrlRedactionSpanProcessor,resolveUrlRedaction}from"@interfere/types/sdk/url-redaction";import{CompositePropagator,W3CBaggagePropagator,W3CTraceContextPropagator}from"@opentelemetry/core";import{defaultServiceName,detectResources,resourceFromAttributes}from"@opentelemetry/resources";import{MeterProvider,PeriodicExportingMetricReader}from"@opentelemetry/sdk-metrics";import{WebTracerProvider}from"@opentelemetry/sdk-trace-web";import{resolveEnvironment}from"@interfere/types/sdk/runtime";import{browserDetector}from"@opentelemetry/opentelemetry-browser-detector";import{BatchLogRecordProcessor,LoggerProvider}from"@opentelemetry/sdk-logs";import{BatchSpanProcessor}from"@opentelemetry/sdk-trace-base";import{createSessionLogRecordProcessor,createSessionSpanProcessor}from"@opentelemetry/web-common";const ATTR_DEVICE_ID=`device.id`,BROWSER_BATCH_OPTIONS={exportTimeoutMillis:7e4,maxExportBatchSize:10,maxQueueSize:2048,scheduledDelayMillis:2e3};function createSessionBaggagePropagator(getSessionId){let propagator=new W3CBaggagePropagator;return{fields:()=>propagator.fields(),extract:(ctx,carrier,getter)=>propagator.extract(ctx,carrier,getter),inject:(ctx,carrier,setter)=>{let sessionId=getSessionId(),baggage=propagation.getBaggage(ctx)??propagation.createBaggage(),updated=sessionId?baggage.setEntry(`session.id`,{value:sessionId}):baggage.removeEntry(`session.id`);propagator.inject(propagation.setBaggage(ctx,updated),carrier,setter)}}}function createDeviceSpanProcessor(opts){return{forceFlush:async()=>Promise.resolve(),onEnd(){},onStart(span){let id=opts.getDeviceId();id&&span.setAttribute(ATTR_DEVICE_ID,id)},shutdown:async()=>Promise.resolve()}}function createDeviceLogRecordProcessor(opts){return{forceFlush:async()=>Promise.resolve(),onEmit(logRecord){let id=opts.getDeviceId();id&&logRecord.setAttribute(ATTR_DEVICE_ID,id)},shutdown:async()=>Promise.resolve()}}function stampGatedAttributes(target,opts){if(opts.isEnabled())for(let[key,value]of Object.entries(opts.attributes))value!==void 0&&target.setAttribute(key,value)}function createDeviceInfoSpanProcessor(opts){return{forceFlush:async()=>Promise.resolve(),onEnd(){},onStart:span=>{stampGatedAttributes(span,opts)},shutdown:async()=>Promise.resolve()}}function createDeviceInfoLogRecordProcessor(opts){return{forceFlush:async()=>Promise.resolve(),onEmit:logRecord=>{stampGatedAttributes(logRecord,opts)},shutdown:async()=>Promise.resolve()}}function buildOtelProvider(input){let environment=resolveEnvironment({explicit:getStringGlobal(ENVIRONMENT_GLOBAL),env:typeof process>`u`?{}:{INTERFERE_ENVIRONMENT:process.env.INTERFERE_ENVIRONMENT,NODE_ENV:process.env.NODE_ENV,VERCEL_ENV:process.env.VERCEL_ENV}}),resource=resourceFromAttributes(omitUndefined({"service.name":input.serviceName||defaultServiceName(),"service.namespace":input.serviceNamespace,"deployment.environment.name":environment,"telemetry.sdk.language":`webjs`,"interfere.sdk.name":SDK_NAME,"interfere.sdk.version":SDK_VERSION,"interfere.sdk.stack":input.sdkStack.join(`, `),"release.slug":input.releaseSlug||void 0})),deviceInfoAttributes=detectResources({detectors:[browserDetector]}).attributes,isDeviceInfoEnabled=input.isDeviceInfoEnabled??(()=>!1),traceExporter=createTraceExporter({clientOptions:input.clientOptions}),{getSessionId}=input,{getDeviceId}=input,spanProcessors=[createUrlRedactionSpanProcessor(input.urlRedaction??resolveUrlRedaction()),createSessionSpanProcessor({getSessionId}),createDeviceSpanProcessor({getDeviceId}),createDeviceInfoSpanProcessor({attributes:deviceInfoAttributes,isEnabled:isDeviceInfoEnabled}),...input.additionalSpanProcessors??[],new BatchSpanProcessor(traceExporter,BROWSER_BATCH_OPTIONS)],tracerProvider=new WebTracerProvider({resource,spanProcessors}),contextManager=new PageScopeContextManager;contextManager.enable(),context.setGlobalContextManager(contextManager)||contextManager.disable();let isShutdown=!1,getPropagationSessionId=input.getPropagationSessionId??getSessionId;propagation.fields().length===0&&propagation.setGlobalPropagator(new CompositePropagator({propagators:[new W3CTraceContextPropagator,createSessionBaggagePropagator(()=>isShutdown?null:getPropagationSessionId())]}));let metricExporter=createMetricExporter({clientOptions:input.clientOptions},{attributes:deviceInfoAttributes,isEnabled:isDeviceInfoEnabled}),metricReader=new PeriodicExportingMetricReader({exportIntervalMillis:75e3,exportTimeoutMillis:7e4,exporter:metricExporter}),meterProvider=new MeterProvider({readers:[metricReader,...input.additionalMetricReaders??[]],resource}),logExporter=createLogExporter({clientOptions:input.clientOptions}),loggerProvider=new LoggerProvider({processors:[createSessionLogRecordProcessor({getSessionId}),createDeviceLogRecordProcessor({getDeviceId}),createDeviceInfoLogRecordProcessor({attributes:deviceInfoAttributes,isEnabled:isDeviceInfoEnabled}),new BatchLogRecordProcessor({exporter:logExporter,...BROWSER_BATCH_OPTIONS}),...input.additionalLogRecordProcessors??[]],resource});return{contextManager,flush:async()=>{await Promise.allSettled([tracerProvider.forceFlush({timeoutMillis:75e3}),metricReader.forceFlush({timeoutMillis:75e3}),loggerProvider.forceFlush({timeoutMillis:75e3})])},loggerProvider,meterProvider,metricReader,shutdown:async()=>{isShutdown=!0,await Promise.allSettled([tracerProvider.shutdown(),meterProvider.shutdown(),loggerProvider.shutdown()])},tracerProvider}}export{buildOtelProvider as t};
@@ -1,11 +1,12 @@
1
1
  import { t as PageScopeContextManager } from "./page-scope-context-manager-r92ZMJok.mjs";
2
2
  import { InterfereClient } from "@interfere/javascript";
3
3
  import { ReleaseSlug } from "@interfere/types/releases/slug";
4
+ import { UrlRedactionPolicy } from "@interfere/types/sdk/url-redaction";
4
5
  import { SessionId } from "@interfere/types/data/session";
5
6
  import { MeterProvider, MetricReader, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
7
+ import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
6
8
  import { LogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
7
9
  import { SpanProcessor } from "@opentelemetry/sdk-trace-base";
8
- import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
9
10
  //#region src/internal/otel/provider.d.ts
10
11
  interface OtelProviderInput {
11
12
  /** @internal */
@@ -64,6 +65,8 @@ interface OtelProviderInput {
64
65
  serviceName?: string;
65
66
  /** Optional application namespace for grouping related services. */
66
67
  serviceNamespace?: string;
68
+ /** URL redaction applied in `onEnding`, before customer processors and export. Defaults to built-in sensitive names. */
69
+ urlRedaction?: UrlRedactionPolicy;
67
70
  }
68
71
  interface OtelProviderHandle {
69
72
  /**