@interfere/react 11.0.3 → 11.0.4

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.
@@ -1 +1 @@
1
- import{getGlobal,setGlobal}from"../util/global.mjs";import{API_PATHS,API_URL}from"@interfere/constants/api";const INGEST_HOST_GLOBAL=`__INTERFERE_INGEST_URL__`,TRAILING_SLASH_RE=/\/$/,RELATIVE_URL_BASE=`https://interfere.local`;function resolvePublicKey(){let injected=getGlobal(`__INTERFERE_PUBLIC_KEY__`);if(injected)return injected;if(typeof process<`u`)return process.env.INTERFERE_PUBLIC_KEY??void 0}function isForceEnableActive(){return!!getGlobal(`__INTERFERE_FORCE_ENABLE__`)}function resolveApiHost(explicit){return explicit??getGlobal(`__INTERFERE_API_URL__`)}function resolveIngestHost(explicit){return explicit??getGlobal(INGEST_HOST_GLOBAL)}function setIngestHost(host){setGlobal(INGEST_HOST_GLOBAL,host)}function normalizeOrigin(host){try{return new URL(host).origin}catch{return API_URL}}function serializeUrl(input,url){return input.startsWith(`/`)?`${url.pathname}${url.search}`:url.toString()}function withQueryParam(url,key,value){let next=new URL(url,RELATIVE_URL_BASE);return next.searchParams.set(key,value),serializeUrl(url,next)}function appendPublicKey(url,publicKey){return publicKey?withQueryParam(url,`pk`,publicKey):url}function appendPathBeforeQuery(url,path){let next=new URL(url,RELATIVE_URL_BASE),suffix=path.startsWith(`/`)?path:`/${path}`;return next.pathname=`${next.pathname.replace(TRAILING_SLASH_RE,``)}${suffix}`,serializeUrl(url,next)}function resolveTargets(apiHost,ingestHost){let publicKey=resolvePublicKey(),headers=new Headers({"content-type":`application/json`});isForceEnableActive()&&headers.set(`x-interfere-force-enable`,`1`);let configHost=resolveApiHost(apiHost),configBaseUrl=configHost?normalizeOrigin(configHost):API_URL,resolvedIngestHost=resolveIngestHost(ingestHost),ingestBaseUrl=resolvedIngestHost?normalizeOrigin(resolvedIngestHost):configBaseUrl;return{collectorBaseUrl:appendPublicKey(ingestBaseUrl,publicKey),config:{url:appendPublicKey(`${configBaseUrl}${API_PATHS.CONFIG}`,publicKey),headers},ingest:{headers},session:{url:appendPublicKey(`${ingestBaseUrl}${API_PATHS.SESSION}`,publicKey),headers}}}export{appendPathBeforeQuery,resolveTargets,setIngestHost,withQueryParam};
1
+ import{getGlobal,setGlobal}from"../util/global.mjs";import{API_PATHS,API_URL}from"@interfere/constants/api";import{API_URL_GLOBAL,FORCE_ENABLE_GLOBAL,INGEST_URL_GLOBAL,PUBLIC_KEY_GLOBAL}from"@interfere/types/sdk/injected-globals";const TRAILING_SLASH_RE=/\/$/,RELATIVE_URL_BASE=`https://interfere.local`;function resolvePublicKey(){let injected=getGlobal(PUBLIC_KEY_GLOBAL);if(injected)return injected;if(typeof process<`u`)return process.env.INTERFERE_PUBLIC_KEY??void 0}function isForceEnableActive(){return!!getGlobal(FORCE_ENABLE_GLOBAL)}function resolveApiHost(explicit){return explicit??getGlobal(API_URL_GLOBAL)}function resolveIngestHost(explicit){return explicit??getGlobal(INGEST_URL_GLOBAL)}function setIngestHost(host){setGlobal(INGEST_URL_GLOBAL,host)}function normalizeOrigin(host){try{return new URL(host).origin}catch{return API_URL}}function serializeUrl(input,url){return input.startsWith(`/`)?`${url.pathname}${url.search}`:url.toString()}function withQueryParam(url,key,value){let next=new URL(url,RELATIVE_URL_BASE);return next.searchParams.set(key,value),serializeUrl(url,next)}function appendPublicKey(url,publicKey){return publicKey?withQueryParam(url,`pk`,publicKey):url}function appendPathBeforeQuery(url,path){let next=new URL(url,RELATIVE_URL_BASE),suffix=path.startsWith(`/`)?path:`/${path}`;return next.pathname=`${next.pathname.replace(TRAILING_SLASH_RE,``)}${suffix}`,serializeUrl(url,next)}function resolveTargets(apiHost,ingestHost){let publicKey=resolvePublicKey(),headers=new Headers({"content-type":`application/json`});isForceEnableActive()&&headers.set(`x-interfere-force-enable`,`1`);let configHost=resolveApiHost(apiHost),configBaseUrl=configHost?normalizeOrigin(configHost):API_URL,resolvedIngestHost=resolveIngestHost(ingestHost),ingestBaseUrl=resolvedIngestHost?normalizeOrigin(resolvedIngestHost):configBaseUrl;return{collectorBaseUrl:appendPublicKey(ingestBaseUrl,publicKey),config:{url:appendPublicKey(`${configBaseUrl}${API_PATHS.CONFIG}`,publicKey),headers},ingest:{headers},session:{url:appendPublicKey(`${ingestBaseUrl}${API_PATHS.SESSION}`,publicKey),headers}}}export{appendPathBeforeQuery,resolveTargets,setIngestHost,withQueryParam};
@@ -116,26 +116,11 @@ interface TracingOptions {
116
116
  * clean.
117
117
  */
118
118
  interface KernelInternalOptions extends KernelOptions {
119
- /**
120
- * Extra log-record processors fanned into the LoggerProvider's
121
- * processor list. Used by `@interfere/observability` for internal-only
122
- * dual-write to BetterStack from `interfere/homepage` +
123
- * `interfere/dashboard`. **Not part of the customer surface** — the
124
- * SDK doesn't expose a way to fan-out to other observability vendors.
125
- */
119
+ /** @internal */
126
120
  _internalAdditionalLogRecordProcessors?: LogRecordProcessor[];
127
- /**
128
- * Extra metric readers fanned into the MeterProvider's reader list.
129
- * See `_internalAdditionalLogRecordProcessors`. Used to keep web
130
- * vitals histograms landing on the BetterStack-fronting OTel
131
- * collector after the rum.ts → SDK migration moved the primary path
132
- * to `/v2/sink` (Tinybird-only).
133
- */
121
+ /** @internal */
134
122
  _internalAdditionalMetricReaders?: MetricReader[];
135
- /**
136
- * Extra span processors fanned into the WebTracerProvider's processor
137
- * list. See `_internalAdditionalLogRecordProcessors`.
138
- */
123
+ /** @internal */
139
124
  _internalAdditionalSpanProcessors?: SpanProcessor[];
140
125
  /** Wrapper SDK versions (e.g. `@interfere/next@10.0.0`). */
141
126
  _wrapperVersions?: string[];
@@ -1 +1 @@
1
- import{createLogger}from"../util/log.mjs";import{onPageHidden}from"./page-lifecycle.mjs";import{getGlobal}from"../util/global.mjs";import{resolveTargets,setIngestHost}from"./config.mjs";import{SessionTracker}from"../tracking/api.mjs";import{safeStringify}from"../util/stringify.mjs";import{recordInitialNavigation}from"./otel/initial-navigation.mjs";import{PluginRuntime}from"./plugin-runtime.mjs";import{PRODUCER_VERSION}from"./version.mjs";import{isNonErrorException,shouldDropBrowserExtensionNoise,shouldDropUnresolvableStack,toExceptions}from"@interfere/types/sdk/errors";import{trace}from"@opentelemetry/api";import{releaseSlugSchema}from"@interfere/types/releases/slug";import{readBakedPlugins}from"@interfere/types/sdk/remote-config";const log=createLogger(`kernel`),TRAILING_SLASH_RE=/\/$/,REPLAY_UPLOAD_RE=/\/v2\/replay\/upload\//;function buildSdkStack(wrapperVersions){return[...wrapperVersions??[],PRODUCER_VERSION]}function buildExceptionEventAttrs(value,opts){let attrs={"interfere.exception.mechanism":opts.mechanism.type,"interfere.exception.handled":opts.mechanism.handled};if(opts.errorDigest&&(attrs[`interfere.error.digest`]=opts.errorDigest),opts.subtype&&(attrs[`interfere.exception.subtype`]=opts.subtype),isNonErrorException(value))return attrs[`exception.type`]=value.type,attrs[`exception.message`]=value.value,attrs[`interfere.exception.kind`]=`non-error`,attrs[`interfere.exception.serialized`]=safeStringify(value.serialized),attrs;attrs[`exception.type`]=value.name,attrs[`exception.message`]=value.message,attrs[`interfere.exception.kind`]=`error`,value.stack&&(attrs[`exception.stacktrace`]=value.stack),attrs[`interfere.exception.chain`]=safeStringify(toExceptions(value,opts.mechanism));let debugIds=globalThis._debugIds;return debugIds&&typeof debugIds==`object`&&Object.keys(debugIds).length>0&&(attrs[`interfere.exception.debug_ids`]=safeStringify(debugIds)),opts.appendFrames&&opts.appendFrames.length>0&&(attrs[`interfere.exception.appended_frames`]=safeStringify(opts.appendFrames)),opts.fallbackFrames&&opts.fallbackFrames.length>0&&(attrs[`interfere.exception.fallback_frames`]=safeStringify(opts.fallbackFrames)),attrs}var Kernel=class{consent;identity;device;session;tracker;seen=new WeakSet;initialNavigationSeen=new Set;runtime=null;otel=null;otelDispose=null;unsubscribePageHidden=null;constructor(tracker){this.tracker=tracker,this.consent={get:()=>this.requireRuntime().getConsent(),set:value=>{let runtime=this.requireRuntime();value?runtime.setConsent(value):runtime.resetConsent()}},this.identity={clear:()=>this.tracker.reset(),get:()=>this.tracker.getIdentity(),set:params=>this.tracker.identify(params)},this.device={getDeviceId:()=>this.tracker.getDeviceId(),getFpHash:()=>this.tracker.getFpHash()},this.session={getId:()=>this.tracker.sessionId(),getWindowId:()=>this.tracker.windowId()},this.unsubscribePageHidden=onPageHidden(()=>{this.flush().catch(()=>void 0)})}attachRuntime(runtime){this.runtime=runtime}requireRuntime(){if(!this.runtime)throw Error(`Kernel runtime not attached. createKernel must call attachRuntime before any consent/dispose path runs.`);return this.runtime}getSessionId(){return this.tracker.sessionId()??``}getWindowId(){return this.tracker.windowId()??``}onSessionPause(handler){return this.tracker.onSessionPause(handler)}onSessionResume(handler){return this.tracker.onSessionResume(handler)}getPluginConfigState(key){return this.requireRuntime().getPluginConfigState(key)}getReplayConfig(){return this.requireRuntime().getReplayConfig()}subscribePluginConfigState(key,listener){return this.requireRuntime().subscribePluginConfigState(key,listener)}recordException(value,opts){if(!isNonErrorException(value)){if(this.seen.has(value))return;this.seen.add(value)}if(!isNonErrorException(value)){let stacks=[],current=value;for(let depth=0;current&&depth<5;depth+=1)current.stack&&stacks.push(current.stack),current=current.cause instanceof Error?current.cause:void 0;if(shouldDropBrowserExtensionNoise(stacks)||shouldDropUnresolvableStack(stacks))return}let attrs=buildExceptionEventAttrs(value,opts),active=trace.getActiveSpan();if(active?.isRecording()){active.addEvent(`exception`,attrs);return}let span=this.otel?.tracerProvider.getTracer(`@interfere/react/exception`).startSpan(`interfere.exception.capture`);span&&(span.addEvent(`exception`,attrs),span.end())}recordLog(input){this.otel&&this.otel.loggerProvider.getLogger(`@interfere/react`).emit({severityText:input.severityText,severityNumber:input.severityNumber,body:input.body,...input.attributes?{attributes:input.attributes}:{}})}recordInitialNavigation(loggerProvider){recordInitialNavigation({getSessionId:()=>this.session.getId(),getWindowId:()=>this.session.getWindowId(),loggerProvider,seen:this.initialNavigationSeen})}async flush(){this.otel&&await this.otel.flush()}attachOtel(handle,dispose){this.otel=handle,this.otelDispose=dispose}syncProviderConfig(config){this.requireRuntime().applyProviderConfig(config.plugins,config.consent)}async dispose(){this.unsubscribePageHidden?.(),this.unsubscribePageHidden=null,this.runtime&&await this.runtime.dispose(),this.tracker.dispose(),this.otelDispose?.(),this.otelDispose=null,this.otel&&=(await this.otel.shutdown(),null)}};async function createKernel(input={}){let{opts={}}=input,fetcher=opts.fetch??globalThis.fetch.bind(globalThis),remotePlugins=await resolveRemotePlugins(opts,fetcher),targets=resolveTargets(opts.apiHost);log.info(`collector: %s`,targets.collectorBaseUrl),getGlobal(`__INTERFERE_FORCE_ENABLE__`)&&log.warn(`FORCE_ENABLE is active. Events will be dropped by production collectors. This should only be set during local development.`);let tracker=new SessionTracker({target:targets.session,fetcher});opts._wrapperVersions?.length&&(globalThis.__INTERFERE_SDK_STACK__=opts._wrapperVersions);let kernel=new Kernel(tracker),runtime=new PluginRuntime(kernel);if(kernel.attachRuntime(runtime),tracker.start(),runtime.start(),opts.tracing!==!1){let tracingOpts=typeof opts.tracing==`object`?opts.tracing:void 0;await wireOtel(kernel,targets,opts._wrapperVersions,{...tracingOpts??{},...opts.serviceName?{serviceName:opts.serviceName}:{},...opts._internalAdditionalSpanProcessors?{additionalSpanProcessors:opts._internalAdditionalSpanProcessors}:{},...opts._internalAdditionalLogRecordProcessors?{additionalLogRecordProcessors:opts._internalAdditionalLogRecordProcessors}:{},...opts._internalAdditionalMetricReaders?{additionalMetricReaders:opts._internalAdditionalMetricReaders}:{}})}return remotePlugins?runtime.applyRemoteConfig(remotePlugins):runtime.applyRemoteConfigDefaults(),kernel}async function resolveRemotePlugins(opts,fetcher){let baked=readBakedPlugins();if(baked)return baked;let remoteConfig=await fetchRemoteConfig(resolveTargets(opts.apiHost).config,fetcher);return remoteConfig?.ingestUrl&&setIngestHost(remoteConfig.ingestUrl),remoteConfig?.plugins??null}async function wireOtel(kernel,targets,wrapperVersions,tracing){let{buildOtelProvider,captureWebVitals,readPropagationFromDocument,registerBundledInstrumentations}=await import(`./otel/index.mjs`),collectorUrl=targets.collectorBaseUrl.replace(TRAILING_SLASH_RE,``),releaseSlug=readReleaseSlugFromGlobals(),handle=buildOtelProvider({collectorUrl,authHeaders:targets.ingest.headers,sdkStack:buildSdkStack(wrapperVersions),getSessionId:()=>kernel.session.getId(),getDeviceId:()=>kernel.device.getDeviceId(),releaseSlug,...tracing.serviceName?{serviceName:tracing.serviceName}:{},...tracing.additionalSpanProcessors?{additionalSpanProcessors:tracing.additionalSpanProcessors}:{},...tracing.additionalLogRecordProcessors?{additionalLogRecordProcessors:tracing.additionalLogRecordProcessors}:{},...tracing.additionalMetricReaders?{additionalMetricReaders:tracing.additionalMetricReaders}:{}}),extracted=readPropagationFromDocument();extracted&&handle.contextManager.setPageScope(extracted);let dispose=registerBundledInstrumentations({tracerProvider:handle.tracerProvider,loggerProvider:handle.loggerProvider,ignoreUrls:[`${collectorUrl}/v2/sink`,targets.config.url,targets.session.url,REPLAY_UPLOAD_RE],...tracing.apiHosts?{apiHosts:tracing.apiHosts}:{},...tracing.propagateContextUrls?{propagateContextUrls:tracing.propagateContextUrls}:{},...tracing.resolveRoute?{resolveRoute:tracing.resolveRoute}:{},...tracing.captureFailedRequests===void 0?{}:{captureFailedRequests:tracing.captureFailedRequests}});tracing.webVitals!==!1&&captureWebVitals({meter:handle.meterProvider.getMeter(`@interfere/react/web-vitals`),flush:()=>handle.flush(),...tracing.resolveRoute?{resolveRoute:tracing.resolveRoute}:{}}),kernel.attachOtel(handle,dispose),kernel.recordInitialNavigation(handle.loggerProvider)}async function fetchRemoteConfig(configTarget,fetcher){try{let headers=Object.fromEntries(configTarget.headers.entries()),res=await fetcher(configTarget.url,{method:`GET`,headers,credentials:`omit`,signal:AbortSignal.timeout(1e4)});return res.ok?await res.json():null}catch{return log.warn(`remote config fetch failed, using local defaults`),null}}function isEnabledByEnvironment(){if(typeof process>`u`||!process.env)return!0;let nodeEnv=process.env.NODE_ENV;return nodeEnv===`production`||nodeEnv===void 0||!!(getGlobal(`__INTERFERE_FORCE_ENABLE__`)||process.env.INTERFERE_FORCE_ENABLE)}function readReleaseSlugFromGlobals(){let value=getGlobal(`__INTERFERE_RELEASE_SLUG__`);return typeof value==`string`?releaseSlugSchema.parse(value):null}export{Kernel,buildSdkStack,createKernel,isEnabledByEnvironment,readReleaseSlugFromGlobals};
1
+ import{createLogger}from"../util/log.mjs";import{onPageHidden}from"./page-lifecycle.mjs";import{getGlobal}from"../util/global.mjs";import{resolveTargets,setIngestHost}from"./config.mjs";import{SessionTracker}from"../tracking/api.mjs";import{safeStringify}from"../util/stringify.mjs";import{recordInitialNavigation}from"./otel/initial-navigation.mjs";import{PluginRuntime}from"./plugin-runtime.mjs";import{PRODUCER_VERSION}from"./version.mjs";import{isNonErrorException,shouldDropBrowserExtensionNoise,shouldDropUnresolvableStack,toExceptions}from"@interfere/types/sdk/errors";import{trace}from"@opentelemetry/api";import{FORCE_ENABLE_GLOBAL,RELEASE_SLUG_GLOBAL,SDK_STACK_GLOBAL}from"@interfere/types/sdk/injected-globals";import{releaseSlugSchema}from"@interfere/types/releases/slug";import{readBakedPlugins}from"@interfere/types/sdk/remote-config";const log=createLogger(`kernel`),TRAILING_SLASH_RE=/\/$/,REPLAY_UPLOAD_RE=/\/v2\/replay\/upload\//;function buildSdkStack(wrapperVersions){return[...wrapperVersions??[],PRODUCER_VERSION]}function buildExceptionEventAttrs(value,opts){let attrs={"interfere.exception.mechanism":opts.mechanism.type,"interfere.exception.handled":opts.mechanism.handled};if(opts.errorDigest&&(attrs[`interfere.error.digest`]=opts.errorDigest),opts.subtype&&(attrs[`interfere.exception.subtype`]=opts.subtype),isNonErrorException(value))return attrs[`exception.type`]=value.type,attrs[`exception.message`]=value.value,attrs[`interfere.exception.kind`]=`non-error`,attrs[`interfere.exception.serialized`]=safeStringify(value.serialized),attrs;attrs[`exception.type`]=value.name,attrs[`exception.message`]=value.message,attrs[`interfere.exception.kind`]=`error`,value.stack&&(attrs[`exception.stacktrace`]=value.stack),attrs[`interfere.exception.chain`]=safeStringify(toExceptions(value,opts.mechanism));let debugIds=globalThis._debugIds;return debugIds&&typeof debugIds==`object`&&Object.keys(debugIds).length>0&&(attrs[`interfere.exception.debug_ids`]=safeStringify(debugIds)),opts.appendFrames&&opts.appendFrames.length>0&&(attrs[`interfere.exception.appended_frames`]=safeStringify(opts.appendFrames)),opts.fallbackFrames&&opts.fallbackFrames.length>0&&(attrs[`interfere.exception.fallback_frames`]=safeStringify(opts.fallbackFrames)),attrs}var Kernel=class{consent;identity;device;session;tracker;seen=new WeakSet;initialNavigationSeen=new Set;runtime=null;otel=null;otelDispose=null;unsubscribePageHidden=null;constructor(tracker){this.tracker=tracker,this.consent={get:()=>this.requireRuntime().getConsent(),set:value=>{let runtime=this.requireRuntime();value?runtime.setConsent(value):runtime.resetConsent()}},this.identity={clear:()=>this.tracker.reset(),get:()=>this.tracker.getIdentity(),set:params=>this.tracker.identify(params)},this.device={getDeviceId:()=>this.tracker.getDeviceId(),getFpHash:()=>this.tracker.getFpHash()},this.session={getId:()=>this.tracker.sessionId(),getWindowId:()=>this.tracker.windowId()},this.unsubscribePageHidden=onPageHidden(()=>{this.flush().catch(()=>void 0)})}attachRuntime(runtime){this.runtime=runtime}requireRuntime(){if(!this.runtime)throw Error(`Kernel runtime not attached. createKernel must call attachRuntime before any consent/dispose path runs.`);return this.runtime}getSessionId(){return this.tracker.sessionId()??``}getWindowId(){return this.tracker.windowId()??``}onSessionPause(handler){return this.tracker.onSessionPause(handler)}onSessionResume(handler){return this.tracker.onSessionResume(handler)}getPluginConfigState(key){return this.requireRuntime().getPluginConfigState(key)}getReplayConfig(){return this.requireRuntime().getReplayConfig()}subscribePluginConfigState(key,listener){return this.requireRuntime().subscribePluginConfigState(key,listener)}recordException(value,opts){if(!isNonErrorException(value)){if(this.seen.has(value))return;this.seen.add(value)}if(!isNonErrorException(value)){let stacks=[],current=value;for(let depth=0;current&&depth<5;depth+=1)current.stack&&stacks.push(current.stack),current=current.cause instanceof Error?current.cause:void 0;if(shouldDropBrowserExtensionNoise(stacks)||shouldDropUnresolvableStack(stacks))return}let attrs=buildExceptionEventAttrs(value,opts),active=trace.getActiveSpan();if(active?.isRecording()){active.addEvent(`exception`,attrs);return}let span=this.otel?.tracerProvider.getTracer(`@interfere/react/exception`).startSpan(`interfere.exception.capture`);span&&(span.addEvent(`exception`,attrs),span.end())}recordLog(input){this.otel&&this.otel.loggerProvider.getLogger(`@interfere/react`).emit({severityText:input.severityText,severityNumber:input.severityNumber,body:input.body,...input.attributes?{attributes:input.attributes}:{}})}recordInitialNavigation(loggerProvider){recordInitialNavigation({getSessionId:()=>this.session.getId(),getWindowId:()=>this.session.getWindowId(),loggerProvider,seen:this.initialNavigationSeen})}async flush(){this.otel&&await this.otel.flush()}attachOtel(handle,dispose){this.otel=handle,this.otelDispose=dispose}syncProviderConfig(config){this.requireRuntime().applyProviderConfig(config.plugins,config.consent)}async dispose(){this.unsubscribePageHidden?.(),this.unsubscribePageHidden=null,this.runtime&&await this.runtime.dispose(),this.tracker.dispose(),this.otelDispose?.(),this.otelDispose=null,this.otel&&=(await this.otel.shutdown(),null)}};async function createKernel(input={}){let{opts={}}=input,fetcher=opts.fetch??globalThis.fetch.bind(globalThis),remotePlugins=await resolveRemotePlugins(opts,fetcher),targets=resolveTargets(opts.apiHost);log.info(`collector: %s`,targets.collectorBaseUrl),getGlobal(FORCE_ENABLE_GLOBAL)&&log.warn(`FORCE_ENABLE is active. Events will be dropped by production collectors. This should only be set during local development.`);let tracker=new SessionTracker({target:targets.session,fetcher});opts._wrapperVersions?.length&&(globalThis[SDK_STACK_GLOBAL]=opts._wrapperVersions);let kernel=new Kernel(tracker),runtime=new PluginRuntime(kernel);if(kernel.attachRuntime(runtime),tracker.start(),runtime.start(),opts.tracing!==!1){let tracingOpts=typeof opts.tracing==`object`?opts.tracing:void 0;await wireOtel(kernel,targets,opts._wrapperVersions,{...tracingOpts??{},...opts.serviceName?{serviceName:opts.serviceName}:{},...opts._internalAdditionalSpanProcessors?{additionalSpanProcessors:opts._internalAdditionalSpanProcessors}:{},...opts._internalAdditionalLogRecordProcessors?{additionalLogRecordProcessors:opts._internalAdditionalLogRecordProcessors}:{},...opts._internalAdditionalMetricReaders?{additionalMetricReaders:opts._internalAdditionalMetricReaders}:{}})}return remotePlugins?runtime.applyRemoteConfig(remotePlugins):runtime.applyRemoteConfigDefaults(),kernel}async function resolveRemotePlugins(opts,fetcher){let baked=readBakedPlugins();if(baked)return baked;let remoteConfig=await fetchRemoteConfig(resolveTargets(opts.apiHost).config,fetcher);return remoteConfig?.ingestUrl&&setIngestHost(remoteConfig.ingestUrl),remoteConfig?.plugins??null}async function wireOtel(kernel,targets,wrapperVersions,tracing){let{buildOtelProvider,captureWebVitals,readPropagationFromDocument,registerBundledInstrumentations}=await import(`./otel/index.mjs`),collectorUrl=targets.collectorBaseUrl.replace(TRAILING_SLASH_RE,``),releaseSlug=readReleaseSlugFromGlobals(),handle=buildOtelProvider({collectorUrl,authHeaders:targets.ingest.headers,sdkStack:buildSdkStack(wrapperVersions),getSessionId:()=>kernel.session.getId(),getDeviceId:()=>kernel.device.getDeviceId(),releaseSlug,...tracing.serviceName?{serviceName:tracing.serviceName}:{},...tracing.additionalSpanProcessors?{additionalSpanProcessors:tracing.additionalSpanProcessors}:{},...tracing.additionalLogRecordProcessors?{additionalLogRecordProcessors:tracing.additionalLogRecordProcessors}:{},...tracing.additionalMetricReaders?{additionalMetricReaders:tracing.additionalMetricReaders}:{}}),extracted=readPropagationFromDocument();extracted&&handle.contextManager.setPageScope(extracted);let dispose=registerBundledInstrumentations({tracerProvider:handle.tracerProvider,loggerProvider:handle.loggerProvider,ignoreUrls:[`${collectorUrl}/v2/sink`,targets.config.url,targets.session.url,REPLAY_UPLOAD_RE],...tracing.apiHosts?{apiHosts:tracing.apiHosts}:{},...tracing.propagateContextUrls?{propagateContextUrls:tracing.propagateContextUrls}:{},...tracing.resolveRoute?{resolveRoute:tracing.resolveRoute}:{},...tracing.captureFailedRequests===void 0?{}:{captureFailedRequests:tracing.captureFailedRequests}});tracing.webVitals!==!1&&captureWebVitals({meter:handle.meterProvider.getMeter(`@interfere/react/web-vitals`),flush:()=>handle.flush(),...tracing.resolveRoute?{resolveRoute:tracing.resolveRoute}:{}}),kernel.attachOtel(handle,dispose),kernel.recordInitialNavigation(handle.loggerProvider)}async function fetchRemoteConfig(configTarget,fetcher){try{let headers=Object.fromEntries(configTarget.headers.entries()),res=await fetcher(configTarget.url,{method:`GET`,headers,credentials:`omit`,signal:AbortSignal.timeout(1e4)});return res.ok?await res.json():null}catch{return log.warn(`remote config fetch failed, using local defaults`),null}}function isEnabledByEnvironment(){if(typeof process>`u`||!process.env)return!0;let nodeEnv=process.env.NODE_ENV;return nodeEnv===`production`||nodeEnv===void 0||!!(getGlobal(FORCE_ENABLE_GLOBAL)||process.env.INTERFERE_FORCE_ENABLE)}function readReleaseSlugFromGlobals(){let value=getGlobal(RELEASE_SLUG_GLOBAL);return typeof value==`string`?releaseSlugSchema.parse(value):null}export{Kernel,buildSdkStack,createKernel,isEnabledByEnvironment,readReleaseSlugFromGlobals};
@@ -7,34 +7,11 @@ import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
7
7
  import { SessionId } from "@interfere/types/data/session";
8
8
  //#region src/internal/otel/provider.d.ts
9
9
  interface OtelProviderInput {
10
- /**
11
- * @internal
12
- *
13
- * Extra log-record processors fanned into the LoggerProvider's
14
- * processor list at construction. Used by `@interfere/observability`
15
- * for internal-only dual-write to BetterStack — keeps a parallel
16
- * destination's queue/exporter independent of the SDK's own.
17
- * Customers don't get a fan-out hook on the SDK surface; this is a
18
- * private bridge for our own dogfood apps.
19
- */
10
+ /** @internal */
20
11
  additionalLogRecordProcessors?: LogRecordProcessor[];
21
- /**
22
- * @internal
23
- *
24
- * Extra metric readers fanned into the MeterProvider's reader list
25
- * at construction. Used by `@interfere/observability` for internal-
26
- * only dual-write of web vitals histograms (`web_vitals.{ttfb,fcp,
27
- * lcp,inp,cls}`) to the BetterStack-fronting OTel collector. Each
28
- * reader owns its own queue + exporter so a 5xx / network outage on
29
- * the parallel destination backs off only its own batch.
30
- */
12
+ /** @internal */
31
13
  additionalMetricReaders?: MetricReader[];
32
- /**
33
- * @internal
34
- *
35
- * Extra span processors fanned into the WebTracerProvider's processor
36
- * list at construction. See `additionalLogRecordProcessors`.
37
- */
14
+ /** @internal */
38
15
  additionalSpanProcessors?: SpanProcessor[];
39
16
  /**
40
17
  * Auth + content headers for OTLP exports. Sourced from the kernel's
@@ -1 +1 @@
1
- import{getGlobal}from"../../util/global.mjs";import{SDK_NAME,SDK_VERSION}from"../version.mjs";import{createLogExporter,createMetricExporter,createTraceExporter}from"./exporter.mjs";import{PageScopeContextManager}from"./page-scope-context-manager.mjs";import{context,propagation}from"@opentelemetry/api";import{CompositePropagator,W3CBaggagePropagator,W3CTraceContextPropagator}from"@opentelemetry/core";import{MeterProvider,PeriodicExportingMetricReader}from"@opentelemetry/sdk-metrics";import{resolveEnvironment}from"@interfere/types/sdk/runtime";import{browserDetector}from"@opentelemetry/opentelemetry-browser-detector";import{detectResources,resourceFromAttributes}from"@opentelemetry/resources";import{BatchLogRecordProcessor,LoggerProvider}from"@opentelemetry/sdk-logs";import{BatchSpanProcessor}from"@opentelemetry/sdk-trace-base";import{WebTracerProvider}from"@opentelemetry/sdk-trace-web";import{createSessionLogRecordProcessor,createSessionSpanProcessor}from"@opentelemetry/web-common";const ATTR_DEVICE_ID=`device.id`,BROWSER_BATCH_OPTIONS={maxQueueSize:50,maxExportBatchSize:10,scheduledDelayMillis:2e3,exportTimeoutMillis:1e4};function createDeviceSpanProcessor(opts){return{onStart(span){let id=opts.getDeviceId();id&&span.setAttribute(ATTR_DEVICE_ID,id)},onEnd(){},forceFlush:()=>Promise.resolve(),shutdown:()=>Promise.resolve()}}function createDeviceLogRecordProcessor(opts){return{onEmit(logRecord){let id=opts.getDeviceId();id&&logRecord.setAttribute(ATTR_DEVICE_ID,id)},forceFlush:()=>Promise.resolve(),shutdown:()=>Promise.resolve()}}function buildOtelProvider(input){let environment=resolveEnvironment({explicit:getGlobal(`__INTERFERE_ENVIRONMENT__`),env:typeof process>`u`?{}:{INTERFERE_ENVIRONMENT:process.env.INTERFERE_ENVIRONMENT,VERCEL_ENV:process.env.VERCEL_ENV,NODE_ENV:process.env.NODE_ENV}}),baseResource=resourceFromAttributes({"service.name":input.serviceName??`interfere-sdk`,"service.namespace":`interfere`,"deployment.environment.name":environment,"telemetry.sdk.language":`webjs`,"interfere.sdk.name":SDK_NAME,"interfere.sdk.version":SDK_VERSION,"interfere.sdk.stack":input.sdkStack.join(`, `),...input.releaseSlug?{"release.slug":input.releaseSlug}:{}}),detected=detectResources({detectors:[browserDetector]}),resource=baseResource.merge(detected),traceExporter=createTraceExporter({collectorUrl:input.collectorUrl,authHeaders:input.authHeaders}),getSessionId=input.getSessionId,getDeviceId=input.getDeviceId,tracerProvider=new WebTracerProvider({resource,spanProcessors:[createSessionSpanProcessor({getSessionId}),createDeviceSpanProcessor({getDeviceId}),new BatchSpanProcessor(traceExporter,BROWSER_BATCH_OPTIONS),...input.additionalSpanProcessors??[]]}),contextManager=new PageScopeContextManager;contextManager.enable(),context.setGlobalContextManager(contextManager)||contextManager.disable(),propagation.fields().length===0&&propagation.setGlobalPropagator(new CompositePropagator({propagators:[new W3CTraceContextPropagator,new W3CBaggagePropagator]}));let metricReader=new PeriodicExportingMetricReader({exporter:createMetricExporter({collectorUrl:input.collectorUrl,authHeaders:input.authHeaders}),exportIntervalMillis:3e4}),meterProvider=new MeterProvider({resource,readers:[metricReader,...input.additionalMetricReaders??[]]}),logExporter=createLogExporter({collectorUrl:input.collectorUrl,authHeaders:input.authHeaders}),loggerProvider=new LoggerProvider({resource,processors:[createSessionLogRecordProcessor({getSessionId}),createDeviceLogRecordProcessor({getDeviceId}),new BatchLogRecordProcessor(logExporter,BROWSER_BATCH_OPTIONS),...input.additionalLogRecordProcessors??[]]});return{contextManager,tracerProvider,meterProvider,metricReader,loggerProvider,flush:async()=>{await Promise.all([tracerProvider.forceFlush(),metricReader.forceFlush(),loggerProvider.forceFlush()])},shutdown:async()=>{await Promise.all([tracerProvider.shutdown(),meterProvider.shutdown(),loggerProvider.shutdown()])}}}export{buildOtelProvider};
1
+ import{getGlobal}from"../../util/global.mjs";import{SDK_NAME,SDK_VERSION}from"../version.mjs";import{createLogExporter,createMetricExporter,createTraceExporter}from"./exporter.mjs";import{PageScopeContextManager}from"./page-scope-context-manager.mjs";import{context,propagation}from"@opentelemetry/api";import{ENVIRONMENT_GLOBAL}from"@interfere/types/sdk/injected-globals";import{CompositePropagator,W3CBaggagePropagator,W3CTraceContextPropagator}from"@opentelemetry/core";import{MeterProvider,PeriodicExportingMetricReader}from"@opentelemetry/sdk-metrics";import{resolveEnvironment}from"@interfere/types/sdk/runtime";import{browserDetector}from"@opentelemetry/opentelemetry-browser-detector";import{detectResources,resourceFromAttributes}from"@opentelemetry/resources";import{BatchLogRecordProcessor,LoggerProvider}from"@opentelemetry/sdk-logs";import{BatchSpanProcessor}from"@opentelemetry/sdk-trace-base";import{WebTracerProvider}from"@opentelemetry/sdk-trace-web";import{createSessionLogRecordProcessor,createSessionSpanProcessor}from"@opentelemetry/web-common";const ATTR_DEVICE_ID=`device.id`,BROWSER_BATCH_OPTIONS={maxQueueSize:50,maxExportBatchSize:10,scheduledDelayMillis:2e3,exportTimeoutMillis:1e4};function createDeviceSpanProcessor(opts){return{onStart(span){let id=opts.getDeviceId();id&&span.setAttribute(ATTR_DEVICE_ID,id)},onEnd(){},forceFlush:()=>Promise.resolve(),shutdown:()=>Promise.resolve()}}function createDeviceLogRecordProcessor(opts){return{onEmit(logRecord){let id=opts.getDeviceId();id&&logRecord.setAttribute(ATTR_DEVICE_ID,id)},forceFlush:()=>Promise.resolve(),shutdown:()=>Promise.resolve()}}function buildOtelProvider(input){let environment=resolveEnvironment({explicit:getGlobal(ENVIRONMENT_GLOBAL),env:typeof process>`u`?{}:{INTERFERE_ENVIRONMENT:process.env.INTERFERE_ENVIRONMENT,VERCEL_ENV:process.env.VERCEL_ENV,NODE_ENV:process.env.NODE_ENV}}),baseResource=resourceFromAttributes({"service.name":input.serviceName??`interfere-sdk`,"service.namespace":`interfere`,"deployment.environment.name":environment,"telemetry.sdk.language":`webjs`,"interfere.sdk.name":SDK_NAME,"interfere.sdk.version":SDK_VERSION,"interfere.sdk.stack":input.sdkStack.join(`, `),...input.releaseSlug?{"release.slug":input.releaseSlug}:{}}),detected=detectResources({detectors:[browserDetector]}),resource=baseResource.merge(detected),traceExporter=createTraceExporter({collectorUrl:input.collectorUrl,authHeaders:input.authHeaders}),getSessionId=input.getSessionId,getDeviceId=input.getDeviceId,tracerProvider=new WebTracerProvider({resource,spanProcessors:[createSessionSpanProcessor({getSessionId}),createDeviceSpanProcessor({getDeviceId}),new BatchSpanProcessor(traceExporter,BROWSER_BATCH_OPTIONS),...input.additionalSpanProcessors??[]]}),contextManager=new PageScopeContextManager;contextManager.enable(),context.setGlobalContextManager(contextManager)||contextManager.disable(),propagation.fields().length===0&&propagation.setGlobalPropagator(new CompositePropagator({propagators:[new W3CTraceContextPropagator,new W3CBaggagePropagator]}));let metricReader=new PeriodicExportingMetricReader({exporter:createMetricExporter({collectorUrl:input.collectorUrl,authHeaders:input.authHeaders}),exportIntervalMillis:3e4}),meterProvider=new MeterProvider({resource,readers:[metricReader,...input.additionalMetricReaders??[]]}),logExporter=createLogExporter({collectorUrl:input.collectorUrl,authHeaders:input.authHeaders}),loggerProvider=new LoggerProvider({resource,processors:[createSessionLogRecordProcessor({getSessionId}),createDeviceLogRecordProcessor({getDeviceId}),new BatchLogRecordProcessor(logExporter,BROWSER_BATCH_OPTIONS),...input.additionalLogRecordProcessors??[]]});return{contextManager,tracerProvider,meterProvider,metricReader,loggerProvider,flush:async()=>{await Promise.all([tracerProvider.forceFlush(),metricReader.forceFlush(),loggerProvider.forceFlush()])},shutdown:async()=>{await Promise.all([tracerProvider.shutdown(),meterProvider.shutdown(),loggerProvider.shutdown()])}}}export{buildOtelProvider};
package/dist/package.mjs CHANGED
@@ -1 +1 @@
1
- var name=`@interfere/react`,version=`11.0.3`;export{name,version};
1
+ var name=`@interfere/react`,version=`11.0.4`;export{name,version};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/react",
3
- "version": "11.0.3",
3
+ "version": "11.0.4",
4
4
  "license": "MIT",
5
5
  "description": "Client-side React SDK for Interfere. Error tracking, session replay, and analytics.",
6
6
  "keywords": [