@interfere/react 12.4.0 → 12.4.3

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 (116) hide show
  1. package/README.md +1 -1
  2. package/dist/activity-BXnqBJEN.mjs +1 -0
  3. package/dist/{activity-CShcwAW_.d.mts → activity-CBQdSlah.d.mts} +2 -0
  4. package/dist/api-BEM97FWM.mjs +1 -0
  5. package/dist/{api-BXjfYV5Z.d.mts → api-hCzqicRd.d.mts} +2 -3
  6. package/dist/carryover-BAFBokML.d.mts +20 -0
  7. package/dist/carryover-jGdEwhSK.mjs +1 -0
  8. package/dist/cors-guard-CBFsXK5N.mjs +1 -0
  9. package/dist/delivery-MVXiPjqc.mjs +1 -0
  10. package/dist/delivery-ST8Q6V23.d.mts +29 -0
  11. package/dist/environment-CC7GnqAv.mjs +1 -0
  12. package/dist/environment-CTK2srrC.d.mts +4 -0
  13. package/dist/error-boundary.d.mts +1 -1
  14. package/dist/export-carryover-Y9VbQiAB.mjs +1 -0
  15. package/dist/exporter-DqqNP_gQ.mjs +1 -0
  16. package/dist/{exporter-logs-DMr5-1Yi.d.mts → exporter-SwuW_zLa.d.mts} +15 -12
  17. package/dist/{exporter-logs-BbzSiQJi.mjs → exporter-logs-DSG5ys_2.mjs} +1 -1
  18. package/dist/{exporter-metrics-DZYqUo6_.mjs → exporter-metrics-B5xXu8sz.mjs} +1 -1
  19. package/dist/failed-request-evidence-BYcXgFbX.mjs +1 -0
  20. package/dist/failure-policy-BRdTiUfP.d.mts +21 -0
  21. package/dist/failure-policy-Czdz-YWP.mjs +1 -0
  22. package/dist/index-BplJLwnY.d.mts +4 -0
  23. package/dist/instrumentations-BV6-EClr.mjs +1 -0
  24. package/dist/{instrumentations-S-BCpguB.d.mts → instrumentations-CSV9Xo8t.d.mts} +11 -24
  25. package/dist/internal/activity/activity.d.mts +1 -1
  26. package/dist/internal/activity/activity.mjs +1 -1
  27. package/dist/internal/capture/capture-boundary.d.mts +1 -1
  28. package/dist/internal/capture/capture.d.mts +1 -1
  29. package/dist/internal/environment/environment.d.mts +2 -2
  30. package/dist/internal/environment/environment.mjs +1 -1
  31. package/dist/internal/kernel-registry.d.mts +1 -1
  32. package/dist/internal/kernel.d.mts +3 -3
  33. package/dist/internal/kernel.mjs +1 -1
  34. package/dist/internal/otel/export-carryover.d.mts +12 -0
  35. package/dist/internal/otel/export-carryover.mjs +1 -0
  36. package/dist/internal/otel/exporter-logs.d.mts +1 -1
  37. package/dist/internal/otel/exporter-logs.mjs +1 -1
  38. package/dist/internal/otel/exporter-metrics.d.mts +1 -1
  39. package/dist/internal/otel/exporter-metrics.mjs +1 -1
  40. package/dist/internal/otel/exporter.d.mts +1 -1
  41. package/dist/internal/otel/exporter.mjs +1 -1
  42. package/dist/internal/otel/index.d.mts +4 -3
  43. package/dist/internal/otel/index.mjs +1 -1
  44. package/dist/internal/otel/instrumentations/cors-guard.d.mts +26 -0
  45. package/dist/internal/otel/instrumentations/cors-guard.mjs +1 -0
  46. package/dist/internal/otel/instrumentations/failed-request-evidence.d.mts +12 -0
  47. package/dist/internal/otel/instrumentations/failed-request-evidence.mjs +1 -0
  48. package/dist/internal/otel/instrumentations/failure-policy.d.mts +2 -0
  49. package/dist/internal/otel/instrumentations/failure-policy.mjs +1 -0
  50. package/dist/internal/otel/instrumentations/instrumentations.d.mts +3 -2
  51. package/dist/internal/otel/instrumentations/instrumentations.mjs +1 -1
  52. package/dist/internal/otel/instrumentations/propagation-targets.d.mts +7 -0
  53. package/dist/internal/otel/instrumentations/propagation-targets.mjs +1 -0
  54. package/dist/internal/otel/instrumentations/request-callsite.d.mts +6 -0
  55. package/dist/internal/otel/instrumentations/request-callsite.mjs +1 -0
  56. package/dist/internal/otel/keepalive-chunks.d.mts +2 -2
  57. package/dist/internal/otel/keepalive-chunks.mjs +1 -1
  58. package/dist/internal/otel/provider.d.mts +1 -1
  59. package/dist/internal/otel/provider.mjs +1 -1
  60. package/dist/internal/plugins/plugin-runtime.d.mts +1 -1
  61. package/dist/internal/react-context.d.mts +1 -1
  62. package/dist/internal/sw-queue.mjs +1 -1
  63. package/dist/internal/version.mjs +1 -1
  64. package/dist/internal/wrapper-singleton.d.mts +1 -1
  65. package/dist/internal/wrapper-singleton.mjs +1 -1
  66. package/dist/keepalive-chunks-Cb8TUzqR.mjs +1 -0
  67. package/dist/kernel-B2aSrvOQ.mjs +1 -0
  68. package/dist/{msw-C0yLYJU2.mjs → msw-CedHiv_x.mjs} +2 -2
  69. package/dist/plugins/device.d.mts +1 -1
  70. package/dist/plugins/errors.d.mts +1 -1
  71. package/dist/plugins/lib/loader.d.mts +1 -1
  72. package/dist/plugins/lib/types.d.mts +1 -1
  73. package/dist/plugins/logs.d.mts +1 -1
  74. package/dist/plugins/page-events.d.mts +1 -1
  75. package/dist/plugins/rage-clicks.d.mts +1 -1
  76. package/dist/plugins/replay/index.d.mts +1 -1
  77. package/dist/plugins/replay/index.mjs +1 -1
  78. package/dist/plugins/replay/upload/carryover.d.mts +2 -0
  79. package/dist/plugins/replay/upload/carryover.mjs +1 -0
  80. package/dist/plugins/replay/upload/delivery.d.mts +2 -25
  81. package/dist/plugins/replay/upload/delivery.mjs +1 -1
  82. package/dist/plugins/replay/upload/retry-queue.d.mts +15 -0
  83. package/dist/plugins/replay/upload/retry-queue.mjs +1 -0
  84. package/dist/plugins/replay/upload/upload.d.mts +1 -0
  85. package/dist/plugins/replay/upload/upload.mjs +1 -1
  86. package/dist/propagation-targets-CfPOwH4t.mjs +1 -0
  87. package/dist/{provider-BMMGZWyS.d.mts → provider-D3MUu4Pe.d.mts} +11 -8
  88. package/dist/{provider-Dy0mVCx5.d.mts → provider-DVei_D8K.d.mts} +1 -0
  89. package/dist/{provider-DwCQ_vj0.mjs → provider-ToSOe7C4.mjs} +1 -1
  90. package/dist/provider.d.mts +1 -1
  91. package/dist/react-error-handler.d.mts +1 -1
  92. package/dist/request-callsite-DAf7lGBK.mjs +3 -0
  93. package/dist/retry-queue-CUNYO4gZ.mjs +1 -0
  94. package/dist/session-BkvyVdtV.mjs +1 -0
  95. package/dist/tracking/api.d.mts +1 -1
  96. package/dist/tracking/api.mjs +1 -1
  97. package/dist/tracking/lifecycle.fixture.d.mts +1 -1
  98. package/dist/tracking/lifecycle.fixture.mjs +1 -1
  99. package/dist/tracking/registration.fixture.d.mts +1 -1
  100. package/dist/tracking/registration.fixture.mjs +1 -1
  101. package/dist/tracking/session.d.mts +1 -0
  102. package/dist/tracking/session.mjs +1 -1
  103. package/dist/{upload-D55WVf_o.mjs → upload-B9hdPLYo.mjs} +1 -1
  104. package/dist/{version-CtEAnX65.mjs → version-D3OKw6oO.mjs} +1 -1
  105. package/package.json +6 -5
  106. package/dist/activity-oYlZ5aa1.mjs +0 -1
  107. package/dist/api-C8aG7li1.mjs +0 -1
  108. package/dist/delivery-D7hULClu.mjs +0 -1
  109. package/dist/environment-CoEXhF1a.mjs +0 -1
  110. package/dist/environment-CtCFKD2N.d.mts +0 -9
  111. package/dist/exporter-CCgTznZ0.mjs +0 -1
  112. package/dist/index-CPrYhbZR.d.mts +0 -4
  113. package/dist/instrumentations-NN81kslu.mjs +0 -1
  114. package/dist/keepalive-chunks-BZv3PhHT.mjs +0 -1
  115. package/dist/kernel-zu11DwyQ.mjs +0 -1
  116. package/dist/session-C30CtCVv.mjs +0 -1
package/README.md CHANGED
@@ -89,7 +89,7 @@ function MyComponent() {
89
89
 
90
90
  ## Session correlation
91
91
 
92
- With the SDK's default browser propagator, instrumented fetch and XHR requests carry `session.id` in W3C baggage to the same origin and hosts in `tracing.apiHosts`. Cross-origin APIs must allow the `baggage` and `traceparent` request headers in their CORS configuration. Existing `tracing.propagateContextUrls` patterns also apply.
92
+ With the SDK's default browser propagator, instrumented fetch and XHR requests carry `session.id` in W3C baggage to the page's own site (same registrable domain, any subdomain or port), to backend hosts Interfere already knows for your organization, and to hosts in `tracing.apiHosts`. Cross-origin APIs must allow the `baggage` and `traceparent` request headers in their CORS configuration. Existing `tracing.propagateContextUrls` patterns also apply.
93
93
 
94
94
  Explicitly denying analytics consent stops session baggage propagation while retaining trace propagation. `tracing: false` disables SDK instrumentation. Existing application-owned propagators are not replaced.
95
95
 
@@ -0,0 +1 @@
1
+ import{t as createLogger}from"./log-D6Ht--tv.mjs";import{n as onPageHidden,r as onPageShown}from"./page-lifecycle-rJEJNdKj.mjs";const log=createLogger(`activity`),IDLE_AFTER_MS=3e5,EXPIRE_AFTER_MS=9e5,MAX_AGE_MS=864e5,CHECK_INTERVAL_MS=3e4,ACTIVITY_EVENTS=[`pointerdown`,`keydown`,`scroll`,`touchstart`,`mousemove`];function monotonicNow(){return typeof performance>`u`?Date.now():performance.now()}function subscribe(set,handler){return set.add(handler),(()=>{set.delete(handler)})}function fire(handlers,arg){for(let handler of handlers)try{handler(arg)}catch(error){log.warn(`activity handler threw: %s`,error instanceof Error?error.constructor.name:`UnknownError`)}}var ActivityMonitor=class{session=null;pausedFor=null;lastPausedExceptionMs=null;lastActivityMs=0;lastActivityWallMs=0;keepaliveUntilMs=0;checkTimer=null;unsubscribeShown=null;unsubscribeHidden=null;pauseHandlers=new Set;resumeHandlers=new Set;pausedExceptionHandlers=new Set;onPause(handler){return subscribe(this.pauseHandlers,handler)}onExceptionWhilePaused(handler){return subscribe(this.pausedExceptionHandlers,handler)}noteException(){if(this.pausedFor===null)return;let now=monotonicNow();this.lastPausedExceptionMs!==null&&now-this.lastPausedExceptionMs<3e5||(this.lastPausedExceptionMs=now,fire(this.pausedExceptionHandlers,this.pausedFor))}onResume(handler){return subscribe(this.resumeHandlers,handler)}start(session){if(this.checkTimer===null&&typeof globalThis.addEventListener==`function`){this.session=session,this.pausedFor=null,this.lastPausedExceptionMs=null,this.lastActivityMs=monotonicNow(),this.lastActivityWallMs=Date.now(),this.keepaliveUntilMs=0;for(let type of ACTIVITY_EVENTS)globalThis.addEventListener(type,this.onInput,{capture:!0,passive:!0});this.unsubscribeShown=onPageShown(this.onInput),this.unsubscribeHidden=onPageHidden(this.onHidden),this.checkTimer=setInterval(this.poll,CHECK_INTERVAL_MS)}}stop(){if(this.checkTimer!==null){clearInterval(this.checkTimer),this.checkTimer=null;for(let type of ACTIVITY_EVENTS)globalThis.removeEventListener(type,this.onInput,!0);this.unsubscribeShown?.(),this.unsubscribeHidden?.(),this.unsubscribeShown=null,this.unsubscribeHidden=null,this.session=null,this.pausedFor=null,this.lastPausedExceptionMs=null,this.lastActivityMs=0,this.keepaliveUntilMs=0}}idleMs(){return monotonicNow()-this.lastActivityMs}isOverMaxAge(){let startedAt=this.session?.startedAt()??0;return startedAt>0&&Date.now()-startedAt>=864e5}pause(reason){this.pausedFor===null&&(this.pausedFor=reason,this.lastPausedExceptionMs=null,log.debug(`session paused: %s`,reason),fire(this.pauseHandlers,reason))}onHidden=()=>{this.pause(`hidden`)};poll=()=>{this.pausedFor===null&&(this.isOverMaxAge()||this.idleMs()>=3e5)&&this.pause(`idle`)};onInput=()=>{let now=monotonicNow(),lastActivity=this.session?.lastActivityAt?.()??this.lastActivityWallMs;if(this.isOverMaxAge()||Date.now()-lastActivity>=9e5){this.resume(now,`rotated`);return}if(this.pausedFor!==null){this.resume(now,`idle`);return}now<this.keepaliveUntilMs||(this.touch(now),this.session?.markActivity())};resume(now,reason){reason===`rotated`&&(log.debug(`resume after expiry → new session`),this.session?.reset()),this.pausedFor=null,this.lastPausedExceptionMs=null,this.touch(now),this.session?.markActivity(),fire(this.resumeHandlers,reason)}touch(now){this.lastActivityMs=now,this.lastActivityWallMs=Date.now(),this.keepaliveUntilMs=now+1e3}};export{MAX_AGE_MS as a,IDLE_AFTER_MS as i,CHECK_INTERVAL_MS as n,EXPIRE_AFTER_MS as r,ActivityMonitor as t};
@@ -7,6 +7,7 @@ declare const MAX_AGE_MS: number;
7
7
  declare const CHECK_INTERVAL_MS: number;
8
8
  interface ActivitySession {
9
9
  markActivity: () => void;
10
+ lastActivityAt?: () => number;
10
11
  reset: () => void;
11
12
  /** Wall-clock epoch ms the session began; `0` when unknown. */
12
13
  startedAt: () => number;
@@ -19,6 +20,7 @@ declare class ActivityMonitor {
19
20
  private pausedFor;
20
21
  private lastPausedExceptionMs;
21
22
  private lastActivityMs;
23
+ private lastActivityWallMs;
22
24
  private keepaliveUntilMs;
23
25
  private checkTimer;
24
26
  private unsubscribeShown;
@@ -0,0 +1 @@
1
+ import{t as createLogger}from"./log-D6Ht--tv.mjs";import{t as ActivityMonitor}from"./activity-BXnqBJEN.mjs";import{n as fetchIngest}from"./ingest-backoff-BdBT-jss.mjs";import{t as DeviceManager}from"./device-DRK7hhLi.mjs";import{t as GeoDetector}from"./geo-D2wa9bGs.mjs";import{t as SessionManager}from"./session-BkvyVdtV.mjs";import{t as SessionRetry}from"./session-retry-Dgkk0yui.mjs";import{omitUndefined}from"@interfere/helpers/omit-undefined";import{InterfereClient,InterfereError}from"@interfere/javascript";const log=createLogger(`tracking`);function syncKey(sessionId,deviceId,fpHash){return`${sessionId}|${deviceId??``}|${fpHash??``}`}var SessionTracker=class{client;device;geo;mgr=null;activity=new ActivityMonitor;currentIdentity=null;identifiedKey=null;lastSyncedKey=null;inflightSyncKey=null;syncAttemptMs=0;generation=0;syncRetry=new SessionRetry;syncRetryKey=null;identityStarted=!1;constructor(opts){this.client=new InterfereClient({...opts.target,maxRetries:0,timeoutInSeconds:10,fetch:Object.assign(async(input,init)=>fetchIngest(input,async()=>(opts.fetcher??globalThis.fetch)(input,{...init,credentials:`omit`,keepalive:!0})),opts.fetcher??globalThis.fetch)}),this.device=opts.device??new DeviceManager,this.geo=opts.geo??new GeoDetector}start(){this.mgr=new SessionManager(id=>{this.onRotate(id)}),this.activity.start({markActivity:()=>{this.markActivity()},reset:()=>{this.rotateSession()},startedAt:()=>this.getSessionStartedAt(),lastActivityAt:()=>this.mgr?.getLastActivityAt()??0})}startDeviceIdentity(){this.identityStarted||(this.invalidateSync(),this.identityStarted=!0,this.device.init(),this.geo.detect(),this.backfillIdentity())}discardDeviceIdentity(){this.invalidateSync(),this.identityStarted=!1,this.device.clear(),this.geo.clear()}async backfillIdentity(){let gen=this.generation;if(await Promise.resolve(),gen!==this.generation||!this.identityStarted)return;let initialSessionId=this.mgr?.getSessionId()??null,initialFpHash=this.device.getFpHash();initialSessionId&&await this.syncSession(initialSessionId,this.device.getDeviceId(),initialFpHash),this.currentIdentity&&this.identify(this.currentIdentity);let fpHash=await this.device.whenFingerprintReady(),sessionId=this.mgr?.getSessionId()??null;gen===this.generation&&this.identityStarted&&sessionId&&fpHash!==initialFpHash&&this.syncSession(sessionId,this.device.getDeviceId(),fpHash)}onSessionPause(handler){return this.activity.onPause(handler)}onSessionExceptionWhilePaused(handler){return this.activity.onExceptionWhilePaused(handler)}noteException(){this.activity.noteException()}onSessionResume(handler){return this.activity.onResume(handler)}sessionId(){let id=this.mgr?.getSessionId()??null;return id&&this.ensureSynced(id),id}windowId(){return this.mgr?.getWindowId()??null}markActivity(){this.mgr?.markActivity()}getSessionStartedAt(){return this.mgr?.getSessionStartedAt()??0}getDeviceId(){return this.device.getDeviceId()}getFpHash(){return this.device.getFpHash()}getIdentity(){return this.currentIdentity}async identify(params){if(!this.mgr)return;let sessionId=this.mgr.getSessionId(),key=JSON.stringify([sessionId,this.device.getDeviceId(),params.identifier,params.source.type,params.source.name]);if(this.identifiedKey===key){log.debug(`skipped, already identified for session %s`,sessionId);return}this.currentIdentity=params,this.identifiedKey=key;let gen=this.generation,[fpHash,country]=await Promise.all([this.device.whenFingerprintReady(),this.geo.detect()]),deviceId=this.device.getDeviceId();if(gen!==this.generation||this.identifiedKey!==key){this.identifiedKey===key&&(this.identifiedKey=null);return}log.info(`POST session %s → identify`,sessionId),this.postIdentify(key,sessionId,omitUndefined({deviceId,fpHash,sessionId,...params,country:country||void 0}))}async postIdentify(key,sessionId,body){try{await this.client.sessions.identifySession(body)}catch{this.identifiedKey===key&&(this.identifiedKey=null),log.warn(`identify failed for session %s`,sessionId)}}clearIdentity(){this.currentIdentity=null,this.identifiedKey=null}reset(){this.invalidateSync(),this.clearIdentity(),this.identityStarted&&this.device.reset(),this.mgr?.reset()}rotateSession(){this.mgr?.reset()}dispose(){this.activity.stop(),this.invalidateSync(),this.clearIdentity(),this.mgr=null}invalidateSync(){this.generation+=1,this.syncRetry.reset(),this.syncRetryKey=null,this.lastSyncedKey=null,this.inflightSyncKey=null,this.syncAttemptMs=0}currentSyncKey(){let sessionId=this.mgr?.sessionId;return sessionId?syncKey(sessionId,this.device.getDeviceId(),this.device.getFpHash()):null}ensureSynced(sessionId){let deviceId=this.device.getDeviceId(),fpHash=this.device.getFpHash(),key=syncKey(sessionId,deviceId,fpHash);this.lastSyncedKey!==key&&this.inflightSyncKey!==key&&(Date.now()-this.syncAttemptMs<5e3||this.syncSession(sessionId,deviceId,fpHash))}async syncSession(sessionId,deviceId,fpHash){let key=syncKey(sessionId,deviceId,fpHash);if(this.lastSyncedKey===key||this.inflightSyncKey===key)return;this.syncRetryKey!==key&&(this.syncRetry.reset(),this.syncRetryKey=key),this.syncRetry.cancel();let{generation}=this;this.inflightSyncKey=key,this.syncAttemptMs=Date.now();try{await this.client.sessions.createSession({sessionId,deviceId,fpHash}),generation===this.generation&&key===this.currentSyncKey()&&(this.lastSyncedKey=key,this.syncRetry.reset())}catch(error){log.warn(`session sync failed`),error instanceof InterfereError&&generation===this.generation&&key===this.currentSyncKey()&&this.syncRetry.schedule(error,()=>{let current=this.mgr?.sessionId;generation===this.generation&&current&&this.ensureSynced(current)})}finally{generation===this.generation&&this.inflightSyncKey===key&&(this.inflightSyncKey=null)}}async onRotate(sessionId){this.syncAttemptMs=Date.now();let gen=this.generation;try{await Promise.resolve();let fpHash=this.device.getFpHash(),deviceId=this.device.getDeviceId();if(gen!==this.generation)return;log.debug(`POST session %s (device=%s fp=%s)`,sessionId,deviceId??`pending`,fpHash??`none`),this.syncSession(sessionId,deviceId,fpHash),this.currentIdentity&&this.identify(this.currentIdentity)}catch{}}};export{SessionTracker as t};
@@ -1,4 +1,4 @@
1
- import { c as SessionResumeReason, s as SessionPauseReason } from "./activity-CShcwAW_.mjs";
1
+ import { c as SessionResumeReason, s as SessionPauseReason } from "./activity-CBQdSlah.mjs";
2
2
  import { t as DeviceManager } from "./device-vFtWy12y.mjs";
3
3
  import { t as GeoDetector } from "./geo-PDfIZY4L.mjs";
4
4
  import { InterfereClient } from "@interfere/javascript";
@@ -17,8 +17,7 @@ declare class SessionTracker {
17
17
  private mgr;
18
18
  private readonly activity;
19
19
  private currentIdentity;
20
- private identifiedSessionId;
21
- private identifiedDeviceId;
20
+ private identifiedKey;
22
21
  private lastSyncedKey;
23
22
  private inflightSyncKey;
24
23
  private syncAttemptMs;
@@ -0,0 +1,20 @@
1
+ import { r as resolveTargets } from "./config-BTWtCcDP.mjs";
2
+ import { z } from "zod";
3
+ //#region src/plugins/replay/upload/carryover.d.ts
4
+ declare const envelopeSchema: z.ZodObject<{
5
+ id: z.ZodString;
6
+ body: z.ZodString;
7
+ sessionId: z.ZodString;
8
+ meta: z.ZodString;
9
+ encoding: z.ZodNullable<z.ZodEnum<{
10
+ gzip: "gzip";
11
+ }>>;
12
+ }, z.core.$strip>;
13
+ type Envelope = z.infer<typeof envelopeSchema>;
14
+ /** Retains prepared replay segments for consented delivery after navigation. */
15
+ declare function createReplayCarryover(target: ReturnType<typeof resolveTargets>["ingest"], allowed: () => boolean): {
16
+ dispose: () => void;
17
+ send(body: Uint8Array, metadata: Omit<Envelope, "body" | "id">): Promise<Response>;
18
+ };
19
+ //#endregion
20
+ export { createReplayCarryover as t };
@@ -0,0 +1 @@
1
+ import{n as withExportCarryover}from"./export-carryover-Y9VbQiAB.mjs";import{t as reserveKeepaliveBody}from"./keepalive-budget-BfoHXD04.mjs";import{t as uploadReplayChunk}from"./upload-B9hdPLYo.mjs";import{toError}from"@interfere/types/sdk/errors";import{omitUndefined}from"@interfere/helpers/omit-undefined";import{ExportResultCode}from"@opentelemetry/core";import{InterfereError}from"@interfere/javascript";import{z}from"zod";const envelopeSchema=z.object({id:z.string(),body:z.string().regex(/^[A-Za-z0-9+/]*={0,2}$/u).refine(value=>value.length%4==0),sessionId:z.string(),meta:z.string(),encoding:z.enum([`gzip`]).nullable()});function createReplayCarryover(target,allowed){let pendingResponses=new Map,carryover=withExportCarryover(`replay:${JSON.stringify([target.baseUrl,target.publicKeyHeader?.apiKey])}`,(payload,callback,signal)=>{async function upload(){if(!allowed())throw Error(`Replay is disabled`);let value;try{value=JSON.parse(new TextDecoder().decode(payload))}catch{throw new InterfereError({statusCode:400,message:`Invalid replay carryover`})}let parsed=envelopeSchema.safeParse(value);if(!parsed.success)throw new InterfereError({statusCode:400,message:`Invalid replay carryover`});let envelope=parsed.data,body=Uint8Array.from(atob(envelope.body),character=>character.codePointAt(0)??0),release=reserveKeepaliveBody(body.byteLength);try{let response=await uploadReplayChunk(target,envelope.sessionId,body,omitUndefined({"x-replay-meta":envelope.meta,"content-encoding":envelope.encoding??void 0}),{keepalive:release!==null,signal}),pending=pendingResponses.get(envelope.id);if(response.ok&&pending?pending.response=response:await response.body?.cancel(),!response.ok)throw new InterfereError({statusCode:response.status})}finally{release?.()}}async function report(){try{await upload(),callback({code:ExportResultCode.SUCCESS});return}catch(error){callback({code:ExportResultCode.FAILED,error:toError(error)});return}}report()},allowed,()=>!0);return{dispose:carryover.dispose,async send(body,metadata){if(body.byteLength>786432)return uploadReplayChunk(target,metadata.sessionId,new Uint8Array(body),omitUndefined({"x-replay-meta":metadata.meta,"content-encoding":metadata.encoding??void 0}));let binary=``;for(let byte of body)binary+=String.fromCodePoint(byte);let id=crypto.randomUUID(),pending={},payload=new TextEncoder().encode(JSON.stringify({...metadata,id,body:btoa(binary)}));pendingResponses.set(id,pending);let keepalive=reserveKeepaliveBody(body.byteLength);keepalive?.();let retainAndSend=keepalive?carryover.deliver:carryover.send;try{return await new Promise((resolve,reject)=>{retainAndSend(payload,result=>{result.code===ExportResultCode.SUCCESS?resolve(pending.response??Response.json({queued:!0},{status:202})):result.error instanceof InterfereError&&result.error.statusCode?resolve(new Response(null,{status:result.error.statusCode})):reject(result.error??Error(`Replay carryover failed`))})})}finally{pendingResponses.delete(id)}}}}export{createReplayCarryover as t};
@@ -0,0 +1 @@
1
+ import{trace}from"@opentelemetry/api";const TRACE_HEADERS=[`traceparent`,`tracestate`,`baggage`],ATTR_TRACE_PROPAGATION=`interfere.trace_propagation`,ESCAPE_RE=/[.*+?^${}()|[\]\\]/gu;function pageOrigin(){return globalThis.location.origin}function originOf(url){try{return new URL(url,globalThis.location.href).origin}catch{return null}}function isRequestInput(input){return input instanceof Request}function stripTraceHeaders(headers){for(let name of TRACE_HEADERS)headers.delete(name);return headers}function corsWarning(origin){return`[interfere] ${origin} rejected the trace headers in its CORS preflight, so Interfere resent the request without them and stops adding them to that origin for this session. To link these requests to your backend traces, add "traceparent, tracestate, baggage" to Access-Control-Allow-Headers on ${origin}.`}var OriginGuardedPattern=class extends RegExp{#isDisabled;constructor(pattern,isDisabled){super(pattern.source,pattern.flags),this.#isDisabled=isDisabled}[Symbol.match](value){return this.#isDisabled(value)?null:super[Symbol.match](value)}};function installCorsGuard(){let nativeFetch=globalThis.fetch,disabled=new Set,verified=new Set;function isDisabled(url){let origin=originOf(url);return origin!==null&&disabled.has(origin)}function planRetry(input,init){let isRequest=isRequestInput(input),method=(init?.method??(isRequest?input.method:`GET`)).toUpperCase();if(method!==`GET`&&method!==`HEAD`||!(isRequest?input.headers:new Headers(init?.headers)).has(`traceparent`))return null;let origin=originOf(isRequest?input.url:String(input));return origin===null||origin===pageOrigin()||verified.has(origin)||disabled.has(origin)?null:isRequest?input.body===null?{origin,retry:async()=>nativeFetch(new Request(input,{headers:stripTraceHeaders(new Headers(input.headers))})),signal:input.signal}:null:init?.body instanceof ReadableStream?null:{origin,retry:async()=>nativeFetch(input,{...init,headers:stripTraceHeaders(new Headers(init?.headers))}),signal:init?.signal}}function disable(origin){disabled.has(origin)||(disabled.add(origin),console.warn(corsWarning(origin)))}async function guardedFetch(input,init){let plan=planRetry(input,init);if(!plan)return nativeFetch(input,init);let span=trace.getActiveSpan();try{let response=await nativeFetch(input,init);return verified.add(plan.origin),response}catch(error){if(!(error instanceof TypeError)||plan.signal?.aborted)throw error;let retried;try{retried=await plan.retry()}catch{throw error}return disable(plan.origin),span?.setAttribute(ATTR_TRACE_PROPAGATION,`disabled_cors`),retried}}return globalThis.fetch=Object.assign(guardedFetch,nativeFetch),{disabledHosts:()=>[...disabled].map(origin=>new URL(origin).host),dispose:()=>{globalThis.fetch===guardedFetch&&(globalThis.fetch=nativeFetch)},guardPatterns:patterns=>patterns.map(pattern=>new OriginGuardedPattern(pattern instanceof RegExp?pattern:RegExp(`^${pattern.replace(ESCAPE_RE,String.raw`\$&`)}$`,`u`),isDisabled))}}export{installCorsGuard as n,ATTR_TRACE_PROPAGATION as t};
@@ -0,0 +1 @@
1
+ import{t as createLogger}from"./log-D6Ht--tv.mjs";import{t as reserveKeepaliveBody}from"./keepalive-budget-BfoHXD04.mjs";import{t as uploadReplayChunk}from"./upload-B9hdPLYo.mjs";import{t as gzipForUnload}from"./unload-gzip-WX9FyWPs.mjs";import{omitUndefined}from"@interfere/helpers/omit-undefined";const log=createLogger(`replay`),REPLAY_TRACER_NAME=`@interfere/react/replay`,textEncoder=new TextEncoder,FATAL_STATUSES=new Set([401,403,413]);function classifyRejection(status,durable=!1){return status===409?`skipped`:FATAL_STATUSES.has(status)?`fatal`:durable&&status>=400&&status<500&&status!==408&&status!==429?`skipped`:`retryable`}async function prepareBody(compressor,rawBytes){if(!compressor.gzip)return{body:rawBytes,encoding:null,release:null};try{return{body:await compressor.gzip(rawBytes),encoding:`gzip`,release:null}}catch(error){return log.warn(`gzip failed for chunk; sending uncompressed: %o`,error),{body:rawBytes,encoding:null,release:null}}}function prepareUnloadBody(rawBytes){let rawRelease=reserveKeepaliveBody(rawBytes.byteLength);if(rawRelease)return{body:rawBytes,encoding:null,release:rawRelease};let compressed=gzipForUnload(rawBytes);return compressed?{body:compressed,encoding:`gzip`,release:reserveKeepaliveBody(compressed.byteLength)}:{body:rawBytes,encoding:null,release: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,sessionId=ctx.getSessionId(),target,carryover,compressor,payload,trigger,unload}){if(!sessionId)return`ok`;let rawBytes=textEncoder.encode(payload.bodyJson),uncompressedBytes=rawBytes.byteLength,prepared=unload?prepareUnloadBody(rawBytes):await prepareBody(compressor,rawBytes),meta=encodeReplayMeta(chunk,payload),headers={"x-replay-meta":meta};prepared.encoding===`gzip`&&(headers[`content-encoding`]=`gzip`);let keepalive=prepared.release!==null,response;try{unload&&carryover&&prepared.release?.();let upload=unload&&carryover?await carryover.send(prepared.body,{sessionId,meta,encoding:prepared.encoding}):await uploadReplayChunk(target,sessionId,prepared.body,headers,{keepalive});if(!upload.ok)return await upload.body?.cancel(),classifyRejection(upload.status,unload&&carryover!==void 0);response=await upload.json()}catch(error){return log.warn(`replay chunk upload failed: %o`,error),`retryable`}finally{unload&&carryover||prepared.release?.()}let queued=typeof response==`object`&&!!response&&`queued`in response&&response.queued===!0,objectKey=typeof response==`object`&&response&&`objectKey`in response&&typeof response.objectKey==`string`?response.objectKey:null;if(trigger===void 0&&!unload)return`ok`;let attributes=omitUndefined({"replay.chunk.size_bytes":uncompressedBytes,"replay.chunk.event_count":payload.eventCount,"replay.chunk.uri":objectKey||void 0,"replay.chunk.queued":queued||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,"replay.chunk.trigger":trigger,"replay.chunk.unload":unload||void 0,"replay.chunk.keepalive":unload?keepalive:void 0});return ctx.getTracer(REPLAY_TRACER_NAME).startSpan(`replay.chunk`,{attributes}).end(),`ok`}export{deliverChunk as n,REPLAY_TRACER_NAME as t};
@@ -0,0 +1,29 @@
1
+ import { E as PluginContext } from "./provider-D3MUu4Pe.mjs";
2
+ import { r as resolveTargets } from "./config-BTWtCcDP.mjs";
3
+ import { n as ReplayChunkPayload } from "./chunking-OfmdRxfq.mjs";
4
+ import { t as Compressor } from "./compressor-host-D3At2PKg.mjs";
5
+ import { t as createReplayCarryover } from "./carryover-BAFBokML.mjs";
6
+ //#region src/plugins/replay/upload/delivery.d.ts
7
+ declare const REPLAY_TRACER_NAME = "@interfere/react/replay";
8
+ type DeliverResult = "ok" | "skipped" | "retryable" | "fatal";
9
+ type ChunkTrigger = "exception";
10
+ interface ReplayChunkRef {
11
+ segmentId: number;
12
+ windowId: string;
13
+ }
14
+ interface DeliverInput {
15
+ target: ReturnType<typeof resolveTargets>["ingest"];
16
+ carryover?: ReturnType<typeof createReplayCarryover>;
17
+ chunk: ReplayChunkRef;
18
+ sessionId?: string;
19
+ compressor: Compressor;
20
+ ctx: PluginContext;
21
+ payload: ReplayChunkPayload;
22
+ /** Why the chunk was cut outside the regular flush cadence, recorded on the `replay.chunk` span. */
23
+ trigger?: ChunkTrigger | undefined;
24
+ /** The page is hiding or unloading: compress synchronously and ask the browser to finish the request after the page unloads while the shared keepalive body budget has room. */
25
+ unload: boolean;
26
+ }
27
+ declare function deliverChunk({ ctx, chunk, sessionId, target, carryover, compressor, payload, trigger, unload }: DeliverInput): Promise<"fatal" | "ok" | "retryable" | "skipped">;
28
+ //#endregion
29
+ export { ReplayChunkRef as a, REPLAY_TRACER_NAME as i, DeliverInput as n, deliverChunk as o, DeliverResult as r, ChunkTrigger as t };
@@ -0,0 +1 @@
1
+ import{n as isForceEnableActive,t as hasPublicKey}from"./config-VOyDjqS7.mjs";function isEnabledByEnvironment(){let environment=typeof process>`u`?void 0:process.env.NODE_ENV;return environment===void 0||environment===`production`||hasPublicKey()||isForceEnableActive()}export{isEnabledByEnvironment as t};
@@ -0,0 +1,4 @@
1
+ //#region src/internal/environment/environment.d.ts
2
+ declare function isEnabledByEnvironment(): boolean;
3
+ //#endregion
4
+ export { isEnabledByEnvironment as t };
@@ -1,4 +1,4 @@
1
- import { a as InterfereContextValue, i as InterfereContext } from "./provider-BMMGZWyS.mjs";
1
+ import { a as InterfereContextValue, i as InterfereContext } from "./provider-D3MUu4Pe.mjs";
2
2
  import { Component, ContextType, ErrorInfo, ReactNode } from "react";
3
3
  //#region src/error-boundary.d.ts
4
4
  export interface ErrorBoundaryProps {
@@ -0,0 +1 @@
1
+ import{r as onPageShown,t as isPageHidden}from"./page-lifecycle-rJEJNdKj.mjs";import{toError}from"@interfere/types/sdk/errors";import{ExportResultCode}from"@opentelemetry/core";import{InterfereError}from"@interfere/javascript";import{z}from"zod";const PREFIX=`interfere:export:v1:`,RESET_KEY=`interfere:export-reset:v1`,MAX_BYTES=1048576,entrySchema=z.object({body:z.string(),created:z.number(),scope:z.string()}),encoder=new TextEncoder;let generation=0,lastCreated=0;const callbacks=new Map,draining=new Set,controllers=new Map,inFlight=new Set;function isTerminal(result){return result.error instanceof InterfereError&&result.error.statusCode!==void 0&&result.error.statusCode>=400&&result.error.statusCode<500&&result.error.statusCode!==408&&result.error.statusCode!==429}function settleEntry(key,result){let terminal=isTerminal(result);return(result.code===ExportResultCode.SUCCESS||terminal)&&localStorage.removeItem(key),callbacks.get(key)?.settle(terminal?result:{code:ExportResultCode.SUCCESS}),callbacks.delete(key),result.code===ExportResultCode.SUCCESS||terminal}function storageKeys(){return Array.from({length:localStorage.length},(_,index)=>localStorage.key(index)).filter(key=>key!==null)}function entries(){let result=[];for(let key of storageKeys()){if(!key.startsWith(PREFIX))continue;let value;try{value=JSON.parse(localStorage.getItem(key)??`null`)}catch{localStorage.removeItem(key);continue}let entry=entrySchema.safeParse(value);if(!entry.success||Date.now()-entry.data.created>864e5){localStorage.removeItem(key);continue}result.push({...entry.data,key})}return result.toSorted((a,b)=>a.created-b.created)}function cancelPending(scopePrefix=``){generation+=1;for(let[controller,scope]of controllers)scope.startsWith(scopePrefix)&&controller.abort();for(let[key,{scope,settle}]of callbacks)scope.startsWith(scopePrefix)&&(callbacks.delete(key),settle({code:ExportResultCode.FAILED,error:Error(`Telemetry carryover cleared`)}))}typeof globalThis.addEventListener==`function`&&globalThis.addEventListener(`storage`,event=>{if(event.key===RESET_KEY&&event.newValue!==null){let scopePrefix=``;try{let reset=z.object({scopePrefix:z.string()}).safeParse(JSON.parse(event.newValue));reset.success&&({scopePrefix}=reset.data)}catch{scopePrefix=``}cancelPending(scopePrefix)}});function clearExportCarryover(scopePrefix=``){cancelPending(scopePrefix);try{for(let entry of entries())entry.scope.startsWith(scopePrefix)&&localStorage.removeItem(entry.key);localStorage.setItem(RESET_KEY,JSON.stringify({scopePrefix,id:crypto.randomUUID()})),localStorage.removeItem(RESET_KEY)}catch{return}}function withExportCarryover(scope,send,allowed,shouldPersist=isPageHidden){let disposed=!1,drain=async()=>{if(disposed||!allowed()||!(`navigator`in globalThis)||!(`locks`in navigator)||draining.has(scope))return;let currentGeneration=generation;draining.add(scope);try{await navigator.locks.request(PREFIX+scope,async()=>{for(let[key,pending]of callbacks)pending.scope===scope&&!localStorage.getItem(key)&&(pending.settle({code:ExportResultCode.SUCCESS}),callbacks.delete(key));for(let entry of entries().filter(item=>item.scope===scope)){if(disposed||!allowed()||currentGeneration!==generation)break;if(inFlight.has(entry.key)||!localStorage.getItem(entry.key))continue;let controller=new AbortController;controllers.set(controller,scope);let result=await new Promise(resolve=>{send(encoder.encode(entry.body),resolve,controller.signal)});if(controllers.delete(controller),!settleEntry(entry.key,result)){for(let pending of entries().filter(item=>item.scope===scope&&!inFlight.has(item.key)))callbacks.get(pending.key)?.settle({code:ExportResultCode.SUCCESS}),callbacks.delete(pending.key);break}}})}catch(error){for(let[key,pending]of callbacks)pending.scope===scope&&(pending.settle({code:ExportResultCode.FAILED,error:toError(error)}),callbacks.delete(key))}finally{draining.delete(scope),(currentGeneration!==generation||[...callbacks].some(([key,pending])=>pending.scope===scope&&!inFlight.has(key)))&&drain()}},unsubscribe=onPageShown(()=>{drain()});queueMicrotask(()=>{drain()});function retain(payload,callback){let body=new TextDecoder().decode(payload),retained=entries(),bytes=retained.reduce((total,entry)=>total+encoder.encode(entry.body).byteLength,payload.byteLength);if(retained.length>=64||bytes>MAX_BYTES)return callback({code:ExportResultCode.FAILED,error:Error(`Telemetry carryover capacity exceeded`)}),null;let key=PREFIX+crypto.randomUUID();lastCreated=Math.max(Date.now(),lastCreated+.001),localStorage.setItem(key,JSON.stringify({body,created:lastCreated,scope}));let afterWrite=entries();return afterWrite.length>64||afterWrite.reduce((total,entry)=>total+encoder.encode(entry.body).byteLength,0)>MAX_BYTES?(localStorage.removeItem(key),callback({code:ExportResultCode.FAILED,error:Error(`Telemetry carryover capacity exceeded`)}),null):(callbacks.set(key,{scope,settle:callback}),key)}function canRetain(payload){return payload!==void 0&&allowed()&&`locks`in navigator}return{dispose:()=>{disposed=!0,unsubscribe()},deliver:((payload,callback)=>{if(!canRetain(payload)){send(payload,callback);return}let key;try{key=retain(payload,callback)}catch{send(payload,callback);return}if(key===null)return;let retainedKey=key,controller=new AbortController;inFlight.add(retainedKey),controllers.set(controller,scope),send(payload,result=>{controllers.delete(controller),inFlight.delete(retainedKey),callbacks.has(retainedKey)&&settleEntry(retainedKey,result)},controller.signal)}),send:((payload,callback)=>{if(!shouldPersist()||!canRetain(payload)){send(payload,callback);return}try{retain(payload,callback)!==null&&drain()}catch{send(payload,callback)}})}}export{withExportCarryover as n,clearExportCarryover as t};
@@ -0,0 +1 @@
1
+ import{t as isPageHidden}from"./page-lifecycle-rJEJNdKj.mjs";import{n as withExportCarryover}from"./export-carryover-Y9VbQiAB.mjs";import{n as fetchIngest}from"./ingest-backoff-BdBT-jss.mjs";import{n as stampSentAt}from"./sent-at-CEM8UV3W.mjs";import{t as reserveKeepaliveBody}from"./keepalive-budget-BfoHXD04.mjs";import{t as sendInKeepaliveChunks}from"./keepalive-chunks-Cb8TUzqR.mjs";import{t as PRODUCER_VERSION}from"./version-D3OKw6oO.mjs";import{t as IngestLogExporter}from"./exporter-logs-DSG5ys_2.mjs";import{t as IngestMetricExporter}from"./exporter-metrics-B5xXu8sz.mjs";import{toError}from"@interfere/types/sdk/errors";import{ExportResultCode}from"@opentelemetry/core";import{InterfereClient,InterfereError}from"@interfere/javascript";import{z}from"zod";import{TELEMETRY_EXPORT_TIMEOUT_MS,retryTelemetry}from"@interfere/helpers/retry-telemetry";import{JsonTraceSerializer}from"@opentelemetry/otlp-transformer";const INGEST_IGNORE_RE=/\/drain\/v1\/(?:traces|logs|metrics)(?:\?|$)/u,AUTH_INVALID_HALT_COOLDOWN_MS=3e5,HALT_MESSAGES={release_not_found:`ingest halted: the ingest endpoint does not recognize this build's release`,public_key_rejected:`ingest paused: the ingest endpoint rejected this page's public key`};let haltReason=null,authHaltExpiresAt=0,consecutiveAuthRejections=0;function resetIngestHalt(){haltReason=null,authHaltExpiresAt=0,consecutiveAuthRejections=0}function currentHaltReason(){return haltReason===`public_key_rejected`&&Date.now()>=authHaltExpiresAt&&(haltReason=null,consecutiveAuthRejections=2),haltReason}function isIngestHalted(){return currentHaltReason()!==null}const textEncoder=new TextEncoder;function detectUnacceptableExport(error){if(currentHaltReason()!==null||error.statusCode!==422&&error.statusCode!==401)return;let body=error.body;if(typeof body==`object`&&body&&`code`in body){if(error.statusCode===422&&body.code===`RELEASE_NOT_FOUND`){haltReason=`release_not_found`,console.warn(`[interfere] the ingest endpoint does not recognize this build's release. Telemetry export is disabled for this page load. Check that source-map upload and finalization succeeded and that build and runtime use the same surface key.`);return}if(error.statusCode===401&&body.code===`AUTH_PK_INVALID`){if(consecutiveAuthRejections+=1,consecutiveAuthRejections<3)return;haltReason=`public_key_rejected`,authHaltExpiresAt=Date.now()+AUTH_INVALID_HALT_COOLDOWN_MS,console.warn(`[interfere] the ingest endpoint rejected this page's public key ${consecutiveAuthRejections} times in a row — telemetry export is paused for ${AUTH_INVALID_HALT_COOLDOWN_MS/6e4} minutes, then retried once. Check that INTERFERE_PUBLIC_KEY matches an active surface; a deleted surface's key stays rejected until the page is rebuilt with the new key.`)}}}function makeSender(input,signal){let client=new InterfereClient({...input.clientOptions,maxRetries:0,timeoutInSeconds:TELEMETRY_EXPORT_TIMEOUT_MS/1e3,fetch:Object.assign(async(url,init)=>fetchIngest(url,async()=>{let body=init?.body,bytes=typeof body==`string`?textEncoder.encode(body).byteLength:0,dispatch=async(abortSignal,keepalive)=>globalThis.fetch(url,{...init,headers:stampSentAt(new Headers(init?.headers)),credentials:`omit`,keepalive,signal:abortSignal});return retryTelemetry(async abortSignal=>{let release=reserveKeepaliveBody(bytes,32e3);if(release===null){if(isPageHidden())throw Error(`Keepalive budget exhausted`);return dispatch(abortSignal,!1)}try{return await dispatch(abortSignal,!0)}catch(error){if(!(error instanceof TypeError)||abortSignal.aborted)throw error}finally{release()}if(isPageHidden())throw Error(`Keepalive request rejected`);return dispatch(abortSignal,!1)},init?.signal)}),globalThis.fetch)}),send=((payload,resultCallback,abortSignal)=>{if(!payload||payload.byteLength===0){resultCallback({code:ExportResultCode.SUCCESS});return}let reason=currentHaltReason();if(reason!==null){resultCallback({code:ExportResultCode.FAILED,error:Error(HALT_MESSAGES[reason])});return}(async()=>{try{let body=z.record(z.string(),z.unknown()).parse(JSON.parse(new TextDecoder().decode(payload)));await client.drain.otlpExport({signal,body},{abortSignal,headers:{"x-interfere-producer-version":PRODUCER_VERSION}}),consecutiveAuthRejections=0,resultCallback({code:ExportResultCode.SUCCESS})}catch(error){error instanceof InterfereError&&detectUnacceptableExport(error),resultCallback({code:ExportResultCode.FAILED,error:toError(error)})}})()}),{baseUrl}=input.clientOptions,publicKey=input.clientOptions.publicKeyHeader?.apiKey;if(typeof baseUrl!=`string`||typeof publicKey!=`string`||input.clientOptions.auth!==void 0)return send;let carryover=withExportCarryover(JSON.stringify([baseUrl,publicKey,signal]),send,input.canPersistExports??(()=>!0));return Object.assign(carryover.send,{dispose:()=>carryover.dispose()})}var IngestTraceExporter=class{send;constructor(send){this.send=send}export(spans,resultCallback){if(spans.length===0){resultCallback({code:ExportResultCode.SUCCESS});return}sendInKeepaliveChunks(spans,chunk=>JsonTraceSerializer.serializeRequest(chunk),this.send,resultCallback)}async shutdown(){return this.send.dispose?.(),Promise.resolve()}async forceFlush(){return Promise.resolve()}};function createTraceExporter(input){return new IngestTraceExporter(makeSender(input,`traces`))}function createMetricExporter(input,gatedResourceAttributes){return new IngestMetricExporter(makeSender(input,`metrics`),gatedResourceAttributes)}function createLogExporter(input){return new IngestLogExporter(makeSender(input,`logs`))}export{isIngestHalted as a,createTraceExporter as i,createLogExporter as n,resetIngestHalt as o,createMetricExporter as r,INGEST_IGNORE_RE as t};
@@ -1,9 +1,18 @@
1
1
  import { Attributes } from "@opentelemetry/api";
2
- import { InterfereClient } from "@interfere/javascript";
3
2
  import { ExportResult } from "@opentelemetry/core";
3
+ import { InterfereClient } from "@interfere/javascript";
4
4
  import { AggregationTemporality, PushMetricExporter, ResourceMetrics } from "@opentelemetry/sdk-metrics";
5
5
  import { LogRecordExporter, ReadableLogRecord } from "@opentelemetry/sdk-logs";
6
6
  import { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
7
+ //#region src/internal/otel/exporter-logs.d.ts
8
+ declare class IngestLogExporter implements LogRecordExporter {
9
+ private readonly send;
10
+ constructor(send: SignalSender);
11
+ export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void;
12
+ shutdown(): Promise<void>;
13
+ forceFlush(): Promise<void>;
14
+ }
15
+ //#endregion
7
16
  //#region src/internal/otel/exporter-metrics.d.ts
8
17
  interface GatedResourceAttributes {
9
18
  attributes: Attributes;
@@ -21,9 +30,12 @@ declare class IngestMetricExporter implements PushMetricExporter {
21
30
  //#endregion
22
31
  //#region src/internal/otel/exporter.d.ts
23
32
  declare const INGEST_IGNORE_RE: RegExp;
24
- type SignalSender = (payload: Uint8Array | undefined, resultCallback: (result: ExportResult) => void) => void;
33
+ type SignalSender = ((payload: Uint8Array | undefined, resultCallback: (result: ExportResult) => void, abortSignal?: AbortSignal) => void) & {
34
+ dispose?: () => void;
35
+ };
25
36
  interface ExporterCommon {
26
37
  clientOptions: InterfereClient.Options;
38
+ canPersistExports?: (() => boolean) | undefined;
27
39
  }
28
40
  /** Test-only reset of the ingest halt state. */
29
41
  declare function resetIngestHalt(): void;
@@ -39,13 +51,4 @@ declare function createTraceExporter(input: ExporterCommon): IngestTraceExporter
39
51
  declare function createMetricExporter(input: ExporterCommon, gatedResourceAttributes?: GatedResourceAttributes): IngestMetricExporter;
40
52
  declare function createLogExporter(input: ExporterCommon): IngestLogExporter;
41
53
  //#endregion
42
- //#region src/internal/otel/exporter-logs.d.ts
43
- declare class IngestLogExporter implements LogRecordExporter {
44
- private readonly send;
45
- constructor(send: SignalSender);
46
- export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void;
47
- shutdown(): Promise<void>;
48
- forceFlush(): Promise<void>;
49
- }
50
- //#endregion
51
- export { createMetricExporter as a, resetIngestHalt as c, createLogExporter as i, GatedResourceAttributes as l, INGEST_IGNORE_RE as n, createTraceExporter as o, SignalSender as r, isIngestHalted as s, IngestLogExporter as t, IngestMetricExporter as u };
54
+ export { createTraceExporter as a, GatedResourceAttributes as c, createMetricExporter as i, IngestMetricExporter as l, SignalSender as n, isIngestHalted as o, createLogExporter as r, resetIngestHalt as s, INGEST_IGNORE_RE as t, IngestLogExporter as u };
@@ -1 +1 @@
1
- import{t as sendInKeepaliveChunks}from"./keepalive-chunks-BZv3PhHT.mjs";import{ExportResultCode}from"@opentelemetry/core";import{JsonLogsSerializer}from"@opentelemetry/otlp-transformer";var IngestLogExporter=class{send;constructor(send){this.send=send}export(logs,resultCallback){if(logs.length===0){resultCallback({code:ExportResultCode.SUCCESS});return}sendInKeepaliveChunks(logs,chunk=>JsonLogsSerializer.serializeRequest(chunk),this.send,resultCallback)}async shutdown(){return Promise.resolve()}async forceFlush(){return Promise.resolve()}};export{IngestLogExporter as t};
1
+ import{t as sendInKeepaliveChunks}from"./keepalive-chunks-Cb8TUzqR.mjs";import{ExportResultCode}from"@opentelemetry/core";import{JsonLogsSerializer}from"@opentelemetry/otlp-transformer";var IngestLogExporter=class{send;constructor(send){this.send=send}export(logs,resultCallback){if(logs.length===0){resultCallback({code:ExportResultCode.SUCCESS});return}sendInKeepaliveChunks(logs,chunk=>JsonLogsSerializer.serializeRequest(chunk),this.send,resultCallback)}async shutdown(){return this.send.dispose?.(),Promise.resolve()}async forceFlush(){return Promise.resolve()}};export{IngestLogExporter as t};
@@ -1 +1 @@
1
- import{JsonMetricsSerializer}from"@opentelemetry/otlp-transformer";import{resourceFromAttributes}from"@opentelemetry/resources";import{AggregationTemporality}from"@opentelemetry/sdk-metrics";var IngestMetricExporter=class{gatedResourceAttributes;send;constructor(send,gatedResourceAttributes){this.send=send,this.gatedResourceAttributes=gatedResourceAttributes??null}export(metrics,resultCallback){let gated=this.gatedResourceAttributes,payload=gated?.isEnabled()===!0?{...metrics,resource:metrics.resource.merge(resourceFromAttributes(gated.attributes))}:metrics;this.send(JsonMetricsSerializer.serializeRequest(payload),resultCallback)}selectAggregationTemporality(){return AggregationTemporality.DELTA}async forceFlush(){return Promise.resolve()}async shutdown(){return Promise.resolve()}};export{IngestMetricExporter as t};
1
+ import{JsonMetricsSerializer}from"@opentelemetry/otlp-transformer";import{resourceFromAttributes}from"@opentelemetry/resources";import{AggregationTemporality}from"@opentelemetry/sdk-metrics";var IngestMetricExporter=class{gatedResourceAttributes;send;constructor(send,gatedResourceAttributes){this.send=send,this.gatedResourceAttributes=gatedResourceAttributes??null}export(metrics,resultCallback){let gated=this.gatedResourceAttributes,payload=gated?.isEnabled()===!0?{...metrics,resource:metrics.resource.merge(resourceFromAttributes(gated.attributes))}:metrics;this.send(JsonMetricsSerializer.serializeRequest(payload),resultCallback)}selectAggregationTemporality(){return AggregationTemporality.DELTA}async forceFlush(){return Promise.resolve()}async shutdown(){return this.send.dispose?.(),Promise.resolve()}};export{IngestMetricExporter as t};
@@ -0,0 +1 @@
1
+ import{z}from"zod";const MAX_BYTES=65536,code=z.string().regex(/^[A-Za-z0-9_.:-]{1,64}$/u),codesSchema=z.object({code:z.unknown().optional(),error_code:z.unknown().optional(),errorCode:z.unknown().optional(),error:z.unknown().optional(),errors:z.unknown().optional()}),nestedCode=z.object({code:z.unknown().optional()}),graphqlCode=z.object({extensions:nestedCode.optional()});function errorCodes(parsed){if(!parsed.success)return[];let{data}=parsed,nested=nestedCode.safeParse(data.error),candidates=[data.code,data.error_code,data.errorCode,...nested.success?[nested.data.code]:[],...(Array.isArray(data.errors)?data.errors.slice(0,5):[]).flatMap(item=>{let result=graphqlCode.safeParse(item);return result.success?[result.data.extensions?.code]:[]})];return[...new Set(candidates.flatMap(value=>{let result=code.safeParse(value);return result.success?[result.data]:[]}))]}function eligible(getHeader){let length=getHeader(`content-length`),type=getHeader(`content-type`)?.split(`;`,1)[0]?.trim();return length!==null&&/^\d+$/u.test(length)&&Number(length)<=MAX_BYTES&&(type===`application/json`||!!type?.endsWith(`+json`))}async function readCodes(response){let clone;try{clone=response.clone()}catch{return[]}let reader=clone.body?.getReader();if(!reader)return[];let timer,expired=new Promise(resolve=>{timer=setTimeout(()=>resolve(void 0),1e3)}),decoder=new TextDecoder,bytes=0,text=``;try{for(;;){let chunk=await Promise.race([reader.read(),expired]);if(!chunk)return[];if(chunk.done)break;if(bytes+=chunk.value.byteLength,bytes>MAX_BYTES)return[];text+=decoder.decode(chunk.value,{stream:!0})}return errorCodes(codesSchema.safeParse(JSON.parse(text+decoder.decode())))}catch{return[]}finally{clearTimeout(timer),reader.cancel().catch(()=>void 0)}}function installFailedResponseEvidence(shouldRead){let original=globalThis.fetch,responses=new WeakMap;async function wrapped(input,init){let response=await original.call(this,input,init);return response.status>=400&&shouldRead(response,input instanceof Request?input:init??{})&&eligible(name=>response.headers.get(name))&&responses.set(response,readCodes(response)),response}return globalThis.fetch=Object.assign(wrapped,original),{read:response=>responses.get(response),dispose:()=>{globalThis.fetch===wrapped&&(globalThis.fetch=original)}}}function xhrErrorCodes(xhr){try{return eligible(name=>xhr.getResponseHeader(name))?xhr.responseType===`json`?errorCodes(codesSchema.safeParse(xhr.response)):xhr.responseType!==``&&xhr.responseType!==`text`||xhr.responseText.length>MAX_BYTES||new TextEncoder().encode(xhr.responseText).byteLength>MAX_BYTES?[]:errorCodes(codesSchema.safeParse(JSON.parse(xhr.responseText))):[]}catch{return[]}}function recordResponseEvidence(span,codes,record){if(!codes){record({});return}let originalEnd=span.end.bind(span);async function settle(pending){let values=await pending,attributes=values.length>0?{"http.response.error_codes":values}:{};span.setAttributes(attributes),record(attributes)}let settled=settle(codes);span.end=time=>{async function finish(){try{await settled}finally{originalEnd(time)}}finish()}}export{recordResponseEvidence as n,xhrErrorCodes as r,installFailedResponseEvidence as t};
@@ -0,0 +1,21 @@
1
+ //#region src/internal/otel/instrumentations/failure-policy.d.ts
2
+ /**
3
+ * Inclusive HTTP status range. `[400, 499]` matches every 4xx;
4
+ * a bare number matches that exact code.
5
+ */
6
+ type HttpStatusCodeRange = number | readonly [number, number];
7
+ interface CaptureFailedRequestsOptions {
8
+ /** Defaults to `[[400, 599]]` (4xx + 5xx) when not specified. */
9
+ statusCodes?: readonly HttpStatusCodeRange[];
10
+ }
11
+ /**
12
+ * Promote tracked failed fetch/XHR responses to captured exception events.
13
+ * On by default (same-origin 4xx + 5xx, deduped + rate-limited); `false`
14
+ * disables, `{ statusCodes }` tunes the matched ranges. Aborted and timed-out
15
+ * requests are not failures: their spans get `interfere.http.cancelled`.
16
+ * Transport failures are dropped within one second of page exit.
17
+ */
18
+ type CaptureFailedRequestsOption = boolean | CaptureFailedRequestsOptions;
19
+ declare function resolveFailureRanges(opt: CaptureFailedRequestsOption | undefined): readonly HttpStatusCodeRange[] | null;
20
+ //#endregion
21
+ export { resolveFailureRanges as i, CaptureFailedRequestsOptions as n, HttpStatusCodeRange as r, CaptureFailedRequestsOption as t };
@@ -0,0 +1 @@
1
+ const DEFAULT_FAILURE_RANGES=[[400,599]];function resolveFailureRanges(opt){if(opt===!1)return null;if(opt===void 0||opt===!0)return DEFAULT_FAILURE_RANGES;let codes=opt.statusCodes;return codes&&codes.length>0?codes:DEFAULT_FAILURE_RANGES}export{resolveFailureRanges as t};
@@ -0,0 +1,4 @@
1
+ import "./instrumentations-CSV9Xo8t.mjs";
2
+ import "./navigation-CkiV6lJY.mjs";
3
+ import "./provider-DVei_D8K.mjs";
4
+ import "./web-vitals-x8y70B5x.mjs";
@@ -0,0 +1 @@
1
+ import{t as DEFAULT_PRIVACY_POLICY}from"./privacy-CRuL0X8r.mjs";import{t as THIRD_PARTY_IGNORE}from"./third-party-hosts-CYOuLL_s.mjs";import{n as describeActionable,r as isActionable}from"./actionable-DOmVf_ib.mjs";import{i as stampUrlAttrs,n as ATTR_URL_FULL,r as ATTR_URL_PATH}from"./url-attrs-BdcyE2n6.mjs";import{t as stampHttpSpanRoute}from"./http-span-route-t2gig-KI.mjs";import{t as createClickSpanGate}from"./click-span-gate-6dNMhjc7.mjs";import{n as recordHttpFailure,t as captureRequestEvidence}from"./request-callsite-DAf7lGBK.mjs";import{n as installCorsGuard}from"./cors-guard-CBFsXK5N.mjs";import{n as recordResponseEvidence,r as xhrErrorCodes,t as installFailedResponseEvidence}from"./failed-request-evidence-BYcXgFbX.mjs";import{a as sameSiteMatcher,n as knownBackendMatchers,r as originMatcher,t as hostMatcher}from"./propagation-targets-CfPOwH4t.mjs";import{n as settleFetchFailure,r as settleXhrFailure,t as createPageExitWatch}from"./network-failure-GVLV_sUF.mjs";import{t as resolveFailureRanges}from"./failure-policy-Czdz-YWP.mjs";import{MECHANISM_TYPE}from"@interfere/types/sdk/errors";import{omitUndefined}from"@interfere/helpers/omit-undefined";import{registerInstrumentations}from"@opentelemetry/instrumentation";import{BrowserNavigationInstrumentation,defaultSanitizeUrl}from"@opentelemetry/instrumentation-browser-navigation";import{DocumentLoadInstrumentation}from"@opentelemetry/instrumentation-document-load";import{FetchInstrumentation}from"@opentelemetry/instrumentation-fetch";import{LongTaskInstrumentation}from"@opentelemetry/instrumentation-long-task";import{UserInteractionInstrumentation}from"@opentelemetry/instrumentation-user-interaction";import{XMLHttpRequestInstrumentation}from"@opentelemetry/instrumentation-xml-http-request";import{getElementXPath}from"@opentelemetry/sdk-trace-web";function createFailureGate(){let seen=new Set,windowStart=0,windowCount=0;return(key=>{if(seen.has(key))return!1;let now=Date.now();return now-windowStart>6e4&&(windowStart=now,windowCount=0),windowCount>=20?!1:(seen.size>=100&&seen.clear(),seen.add(key),windowCount+=1,!0)})}function failureKey(method,discriminator,url){let path;try{path=new URL(url).pathname}catch{path=url}return`${method} ${discriminator} ${path}`}function statusMatches(status,ranges){for(let range of ranges)if(typeof range==`number`){if(status===range)return!0}else if(status>=range[0]&&status<=range[1])return!0;return!1}function maybeCaptureFetchFailure(span,result,failureRanges,method,url,gate,codes){if(!failureRanges)return;let status=result?.status;typeof status!=`number`||status<=0||!statusMatches(status,failureRanges)||(!gate||gate(failureKey(method,status,url)))&&recordResponseEvidence(span,codes,attributes=>recordHttpFailure(span,status,method,url,MECHANISM_TYPE.browser.fetchFailedResponse,attributes))}function applyFetchSpanAttrs(span,request,result,failureRanges,pageExit,isTrackedUrl,resolveRoute,gate,codes){let url=resolveFetchUrl(span,request,result);if(!url)return;let parsed;try{parsed=new URL(url)}catch{return}span.setAttribute(ATTR_URL_PATH,parsed.pathname);let tracked=isTrackedUrl(url),method=resolveFetchMethod(request);if(tracked){if(stampHttpSpanRoute(span,method,parsed.pathname,resolveRoute),isPrefetchRequest(request))return;result instanceof Response?maybeCaptureFetchFailure(span,result,failureRanges,method,url,gate,codes):failureRanges&&settleFetchFailure(span,request,result,pageExit,method,url,()=>!gate||gate(failureKey(method,`network`,url)))}}function applyXhrSpanAttrs(span,xhr,failureRanges,pageExit,isTrackedUrl,gate,resolveRoute){let url=xhr.responseURL||spanUrlFull(span);if(!(url&&isTrackedUrl(url)))return;let parsed;try{parsed=new URL(url)}catch{return}let method=isReadableSpan(span)?String(span.attributes[`http.request.method`]??span.attributes[`http.method`]??`XHR`):`XHR`;if(span.setAttribute(ATTR_URL_PATH,parsed.pathname),stampHttpSpanRoute(span,method,parsed.pathname,resolveRoute),!failureRanges)return;let{status}=xhr;if(typeof status!=`number`)return;if(status===0){settleXhrFailure(span,pageExit,url,()=>!gate||gate(failureKey(`XHR`,`network`,url)));return}if(!statusMatches(status,failureRanges)||gate&&!gate(failureKey(`XHR`,status,url)))return;let codes=xhrErrorCodes(xhr);recordHttpFailure(span,status,`XHR`,url,MECHANISM_TYPE.browser.xhrFailedResponse,codes.length>0?{"http.response.error_codes":codes}:{})}function resolveFetchUrl(span,request,result){return responseUrl(result)??requestUrl(request)??spanUrlFull(span)}function isReadableSpan(span){return`attributes`in span}function spanUrlFull(span){if(!isReadableSpan(span))return null;let url=span.attributes[`url.full`]??span.attributes[`http.url`];return typeof url==`string`?url:null}function responseUrl(result){return result instanceof Response&&result.url?result.url:null}function requestUrl(request){return typeof request==`string`?request:readStringProp(request,`url`)??readStringProp(request,`href`)}function resolveFetchMethod(request){return readStringProp(request,`method`)??`GET`}function readStringProp(value,key){if(!(typeof value==`object`&&value&&key in value))return null;let prop=Reflect.get(value,key);return typeof prop==`string`?prop:null}const testOnlyApplyFetchSpanAttrs=applyFetchSpanAttrs,testOnlyApplyXhrSpanAttrs=applyXhrSpanAttrs,testOnlyCreateFailureGate=createFailureGate,NEVER_MATCH=/^$/u;function sameOriginPattern(){return typeof window>`u`?NEVER_MATCH:originMatcher(globalThis.location.origin)}function pageSameSiteMatcher(){return typeof window>`u`?null:sameSiteMatcher(globalThis.location.hostname)}function stampInteractionAttrs(eventType,element,span,policy){let desc=describeActionable(element,policy);span.setAttribute(`ui.event_type`,eventType),span.setAttribute(`ui.target.tag`,desc.tag),desc.privacy&&(span.setAttribute(`ui.target.privacy`,desc.privacy),span.setAttribute(`target_xpath`,getElementXPath(element,!1))),desc.label&&span.setAttribute(`ui.target.label`,desc.label),desc.id&&span.setAttribute(`ui.target.id`,desc.id),desc.name&&span.setAttribute(`ui.target.name`,desc.name),desc.role&&span.setAttribute(`ui.target.role`,desc.role),desc.ariaLabel&&span.setAttribute(`ui.target.aria_label`,desc.ariaLabel),desc.text&&span.setAttribute(`ui.target.text`,desc.text)}const PREFETCH_HEADER_NAMES=[`next-router-prefetch`,`next-router-segment-prefetch`];function isPrefetchRequest(request){if(typeof request==`string`||request instanceof URL)return!1;let headers;try{headers=typeof Request<`u`&&request instanceof Request?request.headers:new Headers(request.headers)}catch{return!1}return PREFETCH_HEADER_NAMES.some(name=>headers.has(name))||headers.get(`purpose`)===`prefetch`||headers.get(`sec-purpose`)?.includes(`prefetch`)===!0}function registerBundledInstrumentations(input){let{tracerProvider,loggerProvider,ignoreUrls,apiHosts=[],backendHosts=[],propagateContextUrls=[],privacyPolicy=DEFAULT_PRIVACY_POLICY,isInteractionCaptureEnabled=()=>!0,redactUrl=url=>url}=input,{resolveRoute}=input,origin=sameOriginPattern(),sameSite=pageSameSiteMatcher(),explicitMatchers=[...apiHosts.map(host=>hostMatcher(host)),...propagateContextUrls],propagateMatchers=[...sameSite?[sameSite]:[],...knownBackendMatchers(backendHosts),...explicitMatchers],fetchIgnore=[...ignoreUrls,...THIRD_PARTY_IGNORE],failureRanges=resolveFailureRanges(input.captureFailedRequests),failureGate=createFailureGate(),pageExit=createPageExitWatch();function isTrackedUrl(url){return origin.test(url)||propagateMatchers.some(re=>re instanceof RegExp?re.test(url):url.includes(re))}let corsGuard=installCorsGuard(),failedResponses=failureRanges?installFailedResponseEvidence((response,request)=>statusMatches(response.status,failureRanges)&&isTrackedUrl(response.url)&&!isPrefetchRequest(request)):null,propagateTraceHeaderCorsUrls=[origin,...corsGuard.guardPatterns(propagateMatchers)],pageEventsEnabled=!1,admitClick=createClickSpanGate(),coreInstrumentations=[new FetchInstrumentation({applyCustomAttributesOnSpan:(span,request,result)=>{applyFetchSpanAttrs(span,request,result,failureRanges,pageExit,isTrackedUrl,resolveRoute,failureGate,result instanceof Response?failedResponses?.read(result):void 0)},ignoreUrls:fetchIgnore,measureRequestSize:!0,propagateTraceHeaderCorsUrls,requestHook:(span,request)=>{if(isPrefetchRequest(request)){span.setAttribute(`http.request.prefetch`,!0);return}let url=requestUrl(request)??spanUrlFull(span);failureRanges&&url&&isTrackedUrl(url)&&captureRequestEvidence(span,request.headers,redactUrl)}}),new XMLHttpRequestInstrumentation({applyCustomAttributesOnSpan:(span,xhr)=>{applyXhrSpanAttrs(span,xhr,failureRanges,pageExit,isTrackedUrl,failureGate,resolveRoute)},ignoreUrls:fetchIgnore,propagateTraceHeaderCorsUrls:[origin,...corsGuard.guardPatterns(explicitMatchers)]}),new LongTaskInstrumentation({observerCallback:(span,info)=>{stampUrlAttrs(span,resolveRoute);let containerType=info.longtaskEntry.attribution[0]?.containerType;containerType&&span.setAttribute(`longtask.container_type`,containerType)}}),new UserInteractionInstrumentation({eventNames:[`click`,`submit`],shouldPreventSpanCreation:(eventType,element,span)=>!(pageEventsEnabled&&isInteractionCaptureEnabled())||eventType===`click`&&!(isActionable(element)&&admitClick(element))||(stampInteractionAttrs(eventType,element,span,privacyPolicy),stampUrlAttrs(span,resolveRoute),!1)})],pageEventsInstrumentations=[new DocumentLoadInstrumentation({applyCustomAttributesOnSpan:{resourceFetch:(span,entry)=>{let name=entry?.name;if(typeof name!=`string`)return;let url;try{url=new URL(name)}catch{return}let isCrossOrigin=typeof window<`u`&&url.origin!==globalThis.location.origin;span.updateName(isCrossOrigin?`resource: ${url.host}${url.pathname}`:`resource: ${url.pathname}`),span.setAttribute(ATTR_URL_FULL,name),span.setAttribute(ATTR_URL_PATH,url.pathname),span.setAttribute(`server.address`,url.host)}},enabled:!1}),new BrowserNavigationInstrumentation({enabled:!1,sanitizeUrl:url=>redactUrl(defaultSanitizeUrl(url))})],unregisterCore=registerInstrumentations(omitUndefined({tracerProvider,loggerProvider,instrumentations:coreInstrumentations})),unregisterPageEvents=null,setPageEventsEnabled=enabled=>{if(pageEventsEnabled=enabled,enabled){unregisterPageEvents??=registerInstrumentations(omitUndefined({tracerProvider,loggerProvider,instrumentations:pageEventsInstrumentations}));return}unregisterPageEvents?.(),unregisterPageEvents=null};return{dispose:()=>{setPageEventsEnabled(!1),unregisterCore(),failedResponses?.dispose(),corsGuard.dispose(),pageExit.dispose()},propagationDisabledHosts:()=>corsGuard?.disabledHosts()??[],setPageEventsEnabled}}export{testOnlyCreateFailureGate as i,testOnlyApplyFetchSpanAttrs as n,testOnlyApplyXhrSpanAttrs as r,registerBundledInstrumentations as t};
@@ -1,41 +1,25 @@
1
1
  import { i as PrivacyPolicy } from "./privacy-CPKosXDP.mjs";
2
2
  import { n as FetchSpanRequest, r as PageExitWatch, t as FetchError } from "./network-failure-DFMPEnXx.mjs";
3
+ import { r as HttpStatusCodeRange, t as CaptureFailedRequestsOption } from "./failure-policy-BRdTiUfP.mjs";
3
4
  import { Span } from "@opentelemetry/api";
4
5
  import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
5
6
  import { LoggerProvider } from "@opentelemetry/sdk-logs";
6
7
  //#region src/internal/otel/instrumentations/instrumentations.d.ts
7
- /**
8
- * Inclusive HTTP status range. `[400, 499]` matches every 4xx;
9
- * a bare number matches that exact code.
10
- */
11
- type HttpStatusCodeRange = number | readonly [number, number];
12
- interface CaptureFailedRequestsOptions {
13
- /** Defaults to `[[400, 599]]` (4xx + 5xx) when not specified. */
14
- statusCodes?: readonly HttpStatusCodeRange[];
15
- }
16
- /**
17
- * Promote tracked failed fetch/XHR responses to captured exception events.
18
- * On by default (same-origin 4xx + 5xx, deduped + rate-limited); `false`
19
- * disables, `{ statusCodes }` tunes the matched ranges. Aborted and timed-out
20
- * requests are not failures: their spans get `interfere.http.cancelled`.
21
- * Transport failures are dropped when the page is hidden or unloaded
22
- * within one second, since browsers fail in-flight requests on navigation.
23
- */
24
- type CaptureFailedRequestsOption = boolean | CaptureFailedRequestsOptions;
25
- declare function resolveFailureRanges(opt: CaptureFailedRequestsOption | undefined): readonly HttpStatusCodeRange[] | null;
26
8
  declare function createFailureGate(): (key: string) => boolean;
27
- declare function applyFetchSpanAttrs(span: Span, request: FetchSpanRequest, result: Response | FetchError, failureRanges: readonly HttpStatusCodeRange[] | null, pageExit: PageExitWatch, isTrackedUrl: (url: string) => boolean, resolveRoute: ((pathname: string) => string | undefined) | undefined, gate?: (key: string) => boolean): void;
28
- declare function applyXhrSpanAttrs(span: Span, xhr: Pick<XMLHttpRequest, "responseURL" | "status">, failureRanges: readonly HttpStatusCodeRange[] | null, pageExit: PageExitWatch, isTrackedUrl: (url: string) => boolean, gate?: (key: string) => boolean, resolveRoute?: (pathname: string) => string | undefined): void;
9
+ declare function applyFetchSpanAttrs(span: Span, request: FetchSpanRequest, result: Response | FetchError, failureRanges: readonly HttpStatusCodeRange[] | null, pageExit: PageExitWatch, isTrackedUrl: (url: string) => boolean, resolveRoute: ((pathname: string) => string | undefined) | undefined, gate?: (key: string) => boolean, codes?: Promise<string[]>): void;
10
+ declare function applyXhrSpanAttrs(span: Span, xhr: XMLHttpRequest, failureRanges: readonly HttpStatusCodeRange[] | null, pageExit: PageExitWatch, isTrackedUrl: (url: string) => boolean, gate?: (key: string) => boolean, resolveRoute?: (pathname: string) => string | undefined): void;
29
11
  declare const testOnlyApplyFetchSpanAttrs: typeof applyFetchSpanAttrs;
30
12
  declare const testOnlyApplyXhrSpanAttrs: typeof applyXhrSpanAttrs;
31
- declare const testOnlyResolveFailureRanges: typeof resolveFailureRanges;
32
13
  declare const testOnlyCreateFailureGate: typeof createFailureGate;
33
14
  interface InstrumentationsInput {
34
15
  /**
35
16
  * Hostnames the fetch + XHR instrumentations inject `traceparent` onto,
36
- * matched by host (any path/port/scheme). Same-origin always propagates.
17
+ * matched by host (any path/port/scheme), in addition to the page's own
18
+ * site and {@link backendHosts}.
37
19
  */
38
20
  apiHosts?: string[];
21
+ /** The organization's backend hostnames from Interfere remote config. */
22
+ backendHosts?: string[];
39
23
  /** See {@link CaptureFailedRequestsOption}. On by default. */
40
24
  captureFailedRequests?: CaptureFailedRequestsOption;
41
25
  /**
@@ -72,6 +56,8 @@ interface InstrumentationsInput {
72
56
  }
73
57
  interface BundledInstrumentations {
74
58
  dispose: () => void;
59
+ /** Hosts whose CORS preflight rejected the trace headers, in the shape of remote config `backendHosts`. */
60
+ propagationDisabledHosts: () => string[];
75
61
  /** Idempotent toggle for the analytics-consent-gated pageEvents signals. */
76
62
  setPageEventsEnabled: (enabled: boolean) => void;
77
63
  }
@@ -84,7 +70,8 @@ interface BundledInstrumentations {
84
70
  */
85
71
  declare function registerBundledInstrumentations(input: InstrumentationsInput): {
86
72
  dispose: () => void;
73
+ propagationDisabledHosts: () => string[];
87
74
  setPageEventsEnabled: (enabled: boolean) => void;
88
75
  };
89
76
  //#endregion
90
- export { InstrumentationsInput as a, testOnlyApplyXhrSpanAttrs as c, HttpStatusCodeRange as i, testOnlyCreateFailureGate as l, CaptureFailedRequestsOption as n, registerBundledInstrumentations as o, CaptureFailedRequestsOptions as r, testOnlyApplyFetchSpanAttrs as s, BundledInstrumentations as t, testOnlyResolveFailureRanges as u };
77
+ export { testOnlyApplyXhrSpanAttrs as a, testOnlyApplyFetchSpanAttrs as i, InstrumentationsInput as n, testOnlyCreateFailureGate as o, registerBundledInstrumentations as r, BundledInstrumentations as t };
@@ -1,2 +1,2 @@
1
- import { a as IDLE_AFTER_MS, c as SessionResumeReason, i as EXPIRE_AFTER_MS, n as ActivitySession, o as MAX_AGE_MS, r as CHECK_INTERVAL_MS, s as SessionPauseReason, t as ActivityMonitor } from "../../activity-CShcwAW_.mjs";
1
+ import { a as IDLE_AFTER_MS, c as SessionResumeReason, i as EXPIRE_AFTER_MS, n as ActivitySession, o as MAX_AGE_MS, r as CHECK_INTERVAL_MS, s as SessionPauseReason, t as ActivityMonitor } from "../../activity-CBQdSlah.mjs";
2
2
  export { ActivityMonitor, ActivitySession, CHECK_INTERVAL_MS, EXPIRE_AFTER_MS, IDLE_AFTER_MS, MAX_AGE_MS, SessionPauseReason, SessionResumeReason };
@@ -1 +1 @@
1
- import{a as MAX_AGE_MS,i as IDLE_AFTER_MS,n as CHECK_INTERVAL_MS,r as EXPIRE_AFTER_MS,t as ActivityMonitor}from"../../activity-oYlZ5aa1.mjs";export{ActivityMonitor,CHECK_INTERVAL_MS,EXPIRE_AFTER_MS,IDLE_AFTER_MS,MAX_AGE_MS};
1
+ import{a as MAX_AGE_MS,i as IDLE_AFTER_MS,n as CHECK_INTERVAL_MS,r as EXPIRE_AFTER_MS,t as ActivityMonitor}from"../../activity-BXnqBJEN.mjs";export{ActivityMonitor,CHECK_INTERVAL_MS,EXPIRE_AFTER_MS,IDLE_AFTER_MS,MAX_AGE_MS};
@@ -1,4 +1,4 @@
1
- import { a as InterfereContextValue, i as InterfereContext } from "../../provider-BMMGZWyS.mjs";
1
+ import { a as InterfereContextValue, i as InterfereContext } from "../../provider-D3MUu4Pe.mjs";
2
2
  import { Component, ContextType, ReactNode } from "react";
3
3
  //#region src/internal/capture/capture-boundary.d.ts
4
4
  interface CaptureBoundaryProps {
@@ -1,4 +1,4 @@
1
- import { s as Kernel } from "../../provider-BMMGZWyS.mjs";
1
+ import { s as Kernel } from "../../provider-D3MUu4Pe.mjs";
2
2
  import { ErrorMechanism } from "@interfere/types/sdk/plugins/payload/errors";
3
3
  //#region src/internal/capture/capture.d.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { n as isEnvironmentEnabled, t as isEnabledByEnvironment } from "../../environment-CtCFKD2N.mjs";
2
- export { isEnabledByEnvironment, isEnvironmentEnabled };
1
+ import { t as isEnabledByEnvironment } from "../../environment-CTK2srrC.mjs";
2
+ export { isEnabledByEnvironment };
@@ -1 +1 @@
1
- import{n as isEnvironmentEnabled,t as isEnabledByEnvironment}from"../../environment-CoEXhF1a.mjs";export{isEnabledByEnvironment,isEnvironmentEnabled};
1
+ import{t as isEnabledByEnvironment}from"../../environment-CC7GnqAv.mjs";export{isEnabledByEnvironment};
@@ -1,4 +1,4 @@
1
- import { s as Kernel } from "../provider-BMMGZWyS.mjs";
1
+ import { s as Kernel } from "../provider-D3MUu4Pe.mjs";
2
2
  //#region src/internal/kernel-registry.d.ts
3
3
  export declare function registerKernel(kernel: Kernel): void;
4
4
  export declare function unregisterKernel(kernel: Kernel): void;
@@ -1,6 +1,6 @@
1
1
  import { r as PrivacyOptions } from "../privacy-CPKosXDP.mjs";
2
- import { _ as readReleaseSlugFromGlobals, c as KernelConsent, d as KernelInternalOptions, f as KernelOptions, g as createKernel, h as buildSdkStack, l as KernelDevice, m as TracingOptions, p as KernelSession, s as Kernel, u as KernelIdentity } from "../provider-BMMGZWyS.mjs";
3
- import { i as HttpStatusCodeRange, n as CaptureFailedRequestsOption, r as CaptureFailedRequestsOptions } from "../instrumentations-S-BCpguB.mjs";
2
+ import { _ as readReleaseSlugFromGlobals, c as KernelConsent, d as KernelInternalOptions, f as KernelOptions, g as createKernel, h as buildSdkStack, l as KernelDevice, m as TracingOptions, p as KernelSession, s as Kernel, u as KernelIdentity } from "../provider-D3MUu4Pe.mjs";
3
+ import { n as CaptureFailedRequestsOptions, r as HttpStatusCodeRange, t as CaptureFailedRequestsOption } from "../failure-policy-BRdTiUfP.mjs";
4
4
  import { t as RecordExceptionOpts } from "../exception-span-zN1tvBdh.mjs";
5
- import { t as isEnabledByEnvironment } from "../environment-CtCFKD2N.mjs";
5
+ import { t as isEnabledByEnvironment } from "../environment-CTK2srrC.mjs";
6
6
  export { type CaptureFailedRequestsOption, type CaptureFailedRequestsOptions, type HttpStatusCodeRange, Kernel, KernelConsent, KernelDevice, KernelIdentity, KernelInternalOptions, KernelOptions, KernelSession, type PrivacyOptions, type RecordExceptionOpts, TracingOptions, buildSdkStack, createKernel, isEnabledByEnvironment, readReleaseSlugFromGlobals };
@@ -1 +1 @@
1
- import{t as isEnabledByEnvironment}from"../environment-CoEXhF1a.mjs";import{i as readReleaseSlugFromGlobals,n as buildSdkStack,r as createKernel,t as Kernel}from"../kernel-zu11DwyQ.mjs";export{Kernel,buildSdkStack,createKernel,isEnabledByEnvironment,readReleaseSlugFromGlobals};
1
+ import{t as isEnabledByEnvironment}from"../environment-CC7GnqAv.mjs";import{i as readReleaseSlugFromGlobals,n as buildSdkStack,r as createKernel,t as Kernel}from"../kernel-B2aSrvOQ.mjs";export{Kernel,buildSdkStack,createKernel,isEnabledByEnvironment,readReleaseSlugFromGlobals};
@@ -0,0 +1,12 @@
1
+ import { n as SignalSender } from "../../exporter-SwuW_zLa.mjs";
2
+ import { ExportResult } from "@opentelemetry/core";
3
+ //#region src/internal/otel/export-carryover.d.ts
4
+ /** Removes retained exports when consent is revoked or identity is cleared. */
5
+ export declare function clearExportCarryover(scopePrefix?: string): void;
6
+ /** Retains hidden-page exports until acknowledged, bounded by age, count and bytes. */
7
+ export declare function withExportCarryover(scope: string, send: SignalSender, allowed: () => boolean, shouldPersist?: () => boolean): {
8
+ dispose: () => void;
9
+ deliver: (payload: Uint8Array<ArrayBufferLike> | undefined, callback: (result: ExportResult) => void) => void;
10
+ send: (payload: Uint8Array<ArrayBufferLike> | undefined, callback: (result: ExportResult) => void) => void;
11
+ };
12
+ //#endregion
@@ -0,0 +1 @@
1
+ import{n as withExportCarryover,t as clearExportCarryover}from"../../export-carryover-Y9VbQiAB.mjs";export{clearExportCarryover,withExportCarryover};
@@ -1,2 +1,2 @@
1
- import { t as IngestLogExporter } from "../../exporter-logs-DMr5-1Yi.mjs";
1
+ import { u as IngestLogExporter } from "../../exporter-SwuW_zLa.mjs";
2
2
  export { IngestLogExporter };
@@ -1 +1 @@
1
- import{t as IngestLogExporter}from"../../exporter-logs-BbzSiQJi.mjs";export{IngestLogExporter};
1
+ import{t as IngestLogExporter}from"../../exporter-logs-DSG5ys_2.mjs";export{IngestLogExporter};
@@ -1,2 +1,2 @@
1
- import { l as GatedResourceAttributes, u as IngestMetricExporter } from "../../exporter-logs-DMr5-1Yi.mjs";
1
+ import { c as GatedResourceAttributes, l as IngestMetricExporter } from "../../exporter-SwuW_zLa.mjs";
2
2
  export { GatedResourceAttributes, IngestMetricExporter };
@@ -1 +1 @@
1
- import{t as IngestMetricExporter}from"../../exporter-metrics-DZYqUo6_.mjs";export{IngestMetricExporter};
1
+ import{t as IngestMetricExporter}from"../../exporter-metrics-B5xXu8sz.mjs";export{IngestMetricExporter};
@@ -1,2 +1,2 @@
1
- import { a as createMetricExporter, c as resetIngestHalt, i as createLogExporter, n as INGEST_IGNORE_RE, o as createTraceExporter, r as SignalSender, s as isIngestHalted } from "../../exporter-logs-DMr5-1Yi.mjs";
1
+ import { a as createTraceExporter, i as createMetricExporter, n as SignalSender, o as isIngestHalted, r as createLogExporter, s as resetIngestHalt, t as INGEST_IGNORE_RE } from "../../exporter-SwuW_zLa.mjs";
2
2
  export { INGEST_IGNORE_RE, SignalSender, createLogExporter, createMetricExporter, createTraceExporter, isIngestHalted, resetIngestHalt };
@@ -1 +1 @@
1
- import{a as isIngestHalted,i as createTraceExporter,n as createLogExporter,o as resetIngestHalt,r as createMetricExporter,t as INGEST_IGNORE_RE}from"../../exporter-CCgTznZ0.mjs";export{INGEST_IGNORE_RE,createLogExporter,createMetricExporter,createTraceExporter,isIngestHalted,resetIngestHalt};
1
+ import{a as isIngestHalted,i as createTraceExporter,n as createLogExporter,o as resetIngestHalt,r as createMetricExporter,t as INGEST_IGNORE_RE}from"../../exporter-DqqNP_gQ.mjs";export{INGEST_IGNORE_RE,createLogExporter,createMetricExporter,createTraceExporter,isIngestHalted,resetIngestHalt};
@@ -1,7 +1,8 @@
1
- import { a as InstrumentationsInput, i as HttpStatusCodeRange, n as CaptureFailedRequestsOption, o as registerBundledInstrumentations, r as CaptureFailedRequestsOptions, t as BundledInstrumentations } from "../../instrumentations-S-BCpguB.mjs";
1
+ import { n as CaptureFailedRequestsOptions, r as HttpStatusCodeRange, t as CaptureFailedRequestsOption } from "../../failure-policy-BRdTiUfP.mjs";
2
+ import { n as InstrumentationsInput, r as registerBundledInstrumentations, t as BundledInstrumentations } from "../../instrumentations-CSV9Xo8t.mjs";
2
3
  import { a as seedPageScope, i as installNavigationScope, n as PAGE_SCOPE_MAX_AGE_MS, r as createPageScopeRotator, t as NavigationScopeInput } from "../../navigation-CkiV6lJY.mjs";
3
4
  import { t as readPropagationFromDocument } from "../../propagation-CssinKCy.mjs";
4
- import { n as OtelProviderInput, r as buildOtelProvider, t as OtelProviderHandle } from "../../provider-Dy0mVCx5.mjs";
5
+ import { n as OtelProviderInput, r as buildOtelProvider, t as OtelProviderHandle } from "../../provider-DVei_D8K.mjs";
5
6
  import { n as captureWebVitals } from "../../web-vitals-x8y70B5x.mjs";
6
- import "../../index-CPrYhbZR.mjs";
7
+ import "../../index-BplJLwnY.mjs";
7
8
  export { type BundledInstrumentations, type CaptureFailedRequestsOption, type CaptureFailedRequestsOptions, type HttpStatusCodeRange, type InstrumentationsInput, type NavigationScopeInput, type OtelProviderHandle, type OtelProviderInput, PAGE_SCOPE_MAX_AGE_MS, buildOtelProvider, captureWebVitals, createPageScopeRotator, installNavigationScope, readPropagationFromDocument, registerBundledInstrumentations, seedPageScope };
@@ -1 +1 @@
1
- import{t as registerBundledInstrumentations}from"../../instrumentations-NN81kslu.mjs";import{i as seedPageScope,n as createPageScopeRotator,r as installNavigationScope,t as PAGE_SCOPE_MAX_AGE_MS}from"../../navigation-DwkvuhFR.mjs";import{t as readPropagationFromDocument}from"../../propagation-DVcqCu_E.mjs";import{t as buildOtelProvider}from"../../provider-DwCQ_vj0.mjs";import{t as captureWebVitals}from"../../web-vitals-CxXDUgpl.mjs";export{PAGE_SCOPE_MAX_AGE_MS,buildOtelProvider,captureWebVitals,createPageScopeRotator,installNavigationScope,readPropagationFromDocument,registerBundledInstrumentations,seedPageScope};
1
+ import{t as registerBundledInstrumentations}from"../../instrumentations-BV6-EClr.mjs";import{i as seedPageScope,n as createPageScopeRotator,r as installNavigationScope,t as PAGE_SCOPE_MAX_AGE_MS}from"../../navigation-DwkvuhFR.mjs";import{t as readPropagationFromDocument}from"../../propagation-DVcqCu_E.mjs";import{t as buildOtelProvider}from"../../provider-ToSOe7C4.mjs";import{t as captureWebVitals}from"../../web-vitals-CxXDUgpl.mjs";export{PAGE_SCOPE_MAX_AGE_MS,buildOtelProvider,captureWebVitals,createPageScopeRotator,installNavigationScope,readPropagationFromDocument,registerBundledInstrumentations,seedPageScope};
@@ -0,0 +1,26 @@
1
+ //#region src/internal/otel/instrumentations/cors-guard.d.ts
2
+ export declare const ATTR_TRACE_PROPAGATION: "interfere.trace_propagation";
3
+ export interface CorsGuard {
4
+ /** Origins whose CORS preflight rejected the trace headers this session. */
5
+ disabledHosts: () => string[];
6
+ dispose: () => void;
7
+ /** Wraps propagation patterns so they never match a disabled origin. */
8
+ guardPatterns: (patterns: readonly (string | RegExp)[]) => RegExp[];
9
+ }
10
+ declare class OriginGuardedPattern extends RegExp {
11
+ #private;
12
+ constructor(pattern: RegExp, isDisabled: (url: string) => boolean);
13
+ [Symbol.match](value: string): RegExpMatchArray | null;
14
+ }
15
+ /**
16
+ * Wraps `fetch` beneath the OTel fetch instrumentation. A cross-origin request
17
+ * using GET or HEAD and carrying trace headers to an unverified origin is retried
18
+ * once without them when it fails at the network layer; a successful retry
19
+ * disables propagation to that origin for the session and warns once.
20
+ */
21
+ export declare function installCorsGuard(): {
22
+ disabledHosts: () => string[];
23
+ dispose: () => void;
24
+ guardPatterns: (patterns: readonly (string | RegExp)[]) => OriginGuardedPattern[];
25
+ };
26
+ //#endregion
@@ -0,0 +1 @@
1
+ import{n as installCorsGuard,t as ATTR_TRACE_PROPAGATION}from"../../../cors-guard-CBFsXK5N.mjs";export{ATTR_TRACE_PROPAGATION,installCorsGuard};
@@ -0,0 +1,12 @@
1
+ import { Attributes, Span } from "@opentelemetry/api";
2
+ //#region src/internal/otel/instrumentations/failed-request-evidence.d.ts
3
+ /** Collects bounded response identifiers without consuming the application's body. */
4
+ export declare function installFailedResponseEvidence(shouldRead: (response: Response, request: Request | RequestInit) => boolean): {
5
+ read: (response: Response) => Promise<string[]> | undefined;
6
+ dispose: () => void;
7
+ };
8
+ /** Extracts only protocol error identifiers from an eligible XHR response. */
9
+ export declare function xhrErrorCodes(xhr: XMLHttpRequest): string[];
10
+ /** Holds only the failed span while bounded response evidence settles. */
11
+ export declare function recordResponseEvidence(span: Span, codes: Promise<string[]> | undefined, record: (attributes: Attributes) => void): void;
12
+ //#endregion
@@ -0,0 +1 @@
1
+ import{n as recordResponseEvidence,r as xhrErrorCodes,t as installFailedResponseEvidence}from"../../../failed-request-evidence-BYcXgFbX.mjs";export{installFailedResponseEvidence,recordResponseEvidence,xhrErrorCodes};
@@ -0,0 +1,2 @@
1
+ import { i as resolveFailureRanges, n as CaptureFailedRequestsOptions, r as HttpStatusCodeRange, t as CaptureFailedRequestsOption } from "../../../failure-policy-BRdTiUfP.mjs";
2
+ export { CaptureFailedRequestsOption, CaptureFailedRequestsOptions, HttpStatusCodeRange, resolveFailureRanges };
@@ -0,0 +1 @@
1
+ import{t as resolveFailureRanges}from"../../../failure-policy-Czdz-YWP.mjs";export{resolveFailureRanges};