@interfere/vite 11.0.0-canary.2 → 11.0.0-canary.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.
Files changed (50) hide show
  1. package/README.md +2 -1
  2. package/dist/init.d.mts +1 -0
  3. package/dist/internal/build/pipeline.d.mts +2 -1
  4. package/dist/internal/build/pipeline.mjs +1 -1
  5. package/dist/internal/server/request-trace.d.mts +9 -0
  6. package/dist/internal/server/request-trace.mjs +1 -0
  7. package/dist/internal/server/trace-meta.d.mts +1 -1
  8. package/dist/package.mjs +1 -1
  9. package/dist/plugin.d.mts +1 -1
  10. package/dist/plugin.mjs +2 -2
  11. package/dist/tanstack-start.d.mts +6 -0
  12. package/dist/tanstack-start.mjs +1 -0
  13. package/package.json +29 -19
  14. package/dist/init.d.mts.map +0 -1
  15. package/dist/init.mjs.map +0 -1
  16. package/dist/internal/build/pipeline.d.mts.map +0 -1
  17. package/dist/internal/build/pipeline.mjs.map +0 -1
  18. package/dist/internal/build/source-maps.d.mts.map +0 -1
  19. package/dist/internal/build/source-maps.mjs.map +0 -1
  20. package/dist/internal/release-slug.d.mts.map +0 -1
  21. package/dist/internal/release-slug.mjs.map +0 -1
  22. package/dist/internal/route/handle.d.mts.map +0 -1
  23. package/dist/internal/route/handle.mjs.map +0 -1
  24. package/dist/internal/route/proxy.d.mts.map +0 -1
  25. package/dist/internal/route/proxy.mjs.map +0 -1
  26. package/dist/internal/server/capture.d.mts.map +0 -1
  27. package/dist/internal/server/capture.mjs.map +0 -1
  28. package/dist/internal/server/console-bridge.d.mts.map +0 -1
  29. package/dist/internal/server/console-bridge.mjs.map +0 -1
  30. package/dist/internal/server/env.d.mts.map +0 -1
  31. package/dist/internal/server/env.mjs.map +0 -1
  32. package/dist/internal/server/instrumentation-options.d.mts.map +0 -1
  33. package/dist/internal/server/register.d.mts.map +0 -1
  34. package/dist/internal/server/register.mjs.map +0 -1
  35. package/dist/internal/server/remote-config.d.mts.map +0 -1
  36. package/dist/internal/server/remote-config.mjs.map +0 -1
  37. package/dist/internal/server/trace-meta.d.mts.map +0 -1
  38. package/dist/internal/server/trace-meta.mjs.map +0 -1
  39. package/dist/internal/server/traceparent.d.mts.map +0 -1
  40. package/dist/internal/server/traceparent.mjs.map +0 -1
  41. package/dist/internal/server/types.d.mts.map +0 -1
  42. package/dist/internal/server/url.d.mts.map +0 -1
  43. package/dist/internal/server/url.mjs.map +0 -1
  44. package/dist/package.mjs.map +0 -1
  45. package/dist/plugin.d.mts.map +0 -1
  46. package/dist/plugin.mjs.map +0 -1
  47. package/dist/provider.d.mts.map +0 -1
  48. package/dist/provider.mjs.map +0 -1
  49. package/dist/version.d.mts.map +0 -1
  50. package/dist/version.mjs.map +0 -1
package/README.md CHANGED
@@ -236,9 +236,10 @@ function useInterfereIdentity() {
236
236
  | Method | Description |
237
237
  | --- | --- |
238
238
  | `identity.set(params)` | Link the current session to a user. Deduplicated per session — only the first call sends a request. |
239
+ | `identity.clear()` | Clears the linked identity and rotates the session. Call on logout. |
239
240
  | `identity.get()` | Returns the current `IdentifyParams`, or `null` if no identity has been set. |
240
241
 
241
- Identity is automatically cleared when the SDK is closed or the session rotates.
242
+ Identity is automatically cleared when the SDK is closed. Call `identity.clear()` on logout to start a fresh anonymous session.
242
243
 
243
244
  ## Consent Management
244
245
 
package/dist/init.d.mts CHANGED
@@ -7,6 +7,7 @@ declare const close: () => Promise<void>, consent: {
7
7
  get(): import("@interfere/types/sdk/plugins/manifest").ConsentState | null;
8
8
  set(value?: import("@interfere/types/sdk/plugins/manifest").ConsentState): void;
9
9
  }, getKernel: () => import("@interfere/react/internal/kernel").Kernel, getKernelOrNull: () => import("@interfere/react/internal/kernel").Kernel | null, identity: {
10
+ clear(): void;
10
11
  get(): import("@interfere/types/sdk/identify").IdentifyParams | null;
11
12
  set(params: import("@interfere/types/sdk/identify").IdentifyParams): Promise<void>;
12
13
  }, init: (opts?: import("@interfere/react/internal/kernel").KernelOptions) => Promise<import("@interfere/react/internal/kernel").Kernel | null>, subscribeToKernel: (listener: () => void) => () => void;
@@ -48,6 +48,7 @@ interface ReleasePipelineInput {
48
48
  buildId: string;
49
49
  bundler: ManifestBundler;
50
50
  discovery: DiscoveryResult;
51
+ environment: string | null;
51
52
  producerVersion: string;
52
53
  releaseSlug: ReleaseSlug;
53
54
  releasesConfig: ReleasesConfigResponse;
@@ -64,4 +65,4 @@ declare function createSdkClient(opts: {
64
65
  };
65
66
  declare function runReleasePipeline(input: ReleasePipelineInput): Promise<ReleasePipelineResult>;
66
67
  //#endregion
67
- export { BuildTiming, ReleasePipelineFailure, ReleasePipelineInput, ReleasePipelineResult, ReleasePipelineSuccess, createSdkClient, runReleasePipeline };
68
+ export { ReleasePipelineInput, ReleasePipelineResult, createSdkClient, runReleasePipeline };
@@ -1 +1 @@
1
- import{cleanupSourceMaps,uploadSourceMaps}from"./source-maps.mjs";import{parseEnvValue}from"@interfere/types/sdk/env";import{releaseSlugSchema}from"@interfere/types/releases/slug";import{execSync}from"node:child_process";import{HTTPClient,Interfere}from"@interfere/sdk";import{destinationProviderSchema}from"@interfere/types/integrations";const sources={github:resolveGithubSource},destinations={vercel:resolveVercelDestination};async function timed(fn){let start=performance.now();return[await fn(),Math.round(performance.now()-start)]}function createSdkClient(opts){let httpClient=new HTTPClient;return httpClient.addHook(`beforeRequest`,request=>{let next=new Request(request);return next.headers.set(`Authorization`,`Bearer ${opts.apiKey}`),next}),{httpClient,sdk:new Interfere({serverURL:opts.apiUrl,httpClient}),security:{apiKey:opts.apiKey}}}function resolveReleaseRequest(buildId,releaseSlug,producerVersion,config){if(!config.surface.sourceProvider)return{ok:!1,reason:`missing_source_provider`};let destinationProvider=destinationProviderSchema.safeParse(config.surface.destinationProvider);return destinationProvider.success?{ok:!0,request:{source:sources[config.surface.sourceProvider](),destination:destinations[destinationProvider.data](),buildId,slug:releaseSlug,producerVersion}}:{ok:!1,reason:`missing_destination_provider`}}async function runReleasePipeline(input){let{apiKey,apiUrl,bundler,discovery,releasesConfig}=input,releaseRequest=resolveReleaseRequest(input.buildId,input.releaseSlug,input.producerVersion,releasesConfig);if(!releaseRequest.ok)return{ok:!1,failure:{kind:releaseRequest.reason,config:releasesConfig}};let start=performance.now(),{httpClient,sdk,security}=createSdkClient({apiKey,apiUrl}),[release,createReleaseMs]=await timed(()=>sdk.releases.create(security,releaseRequest.request)),releaseSlug=releaseSlugSchema.parse(release.destination.slug),buildId=release.build.hash??input.buildId,[{totalBytes},uploadMs]=await timed(()=>uploadSourceMaps({apiUrl,bundler,discovered:discovery,httpClient,releaseSlug})),[,preflightMs]=await timed(()=>sdk.releases.preflight(security,{releaseSlug})),[{failures},cleanupMs]=await timed(()=>cleanupSourceMaps(discovery.files));return{ok:!0,data:{buildId,cleanupFailures:failures,config:releasesConfig,fileCount:discovery.files.length,release:{...release,destination:{...release.destination,slug:releaseSlug}},releaseSlug,timing:{createRelease:createReleaseMs,upload:uploadMs,preflight:preflightMs,cleanup:cleanupMs,total:Math.round(performance.now()-start),fileCount:discovery.files.length,totalBytes}}}}function runGitCommand(command){try{let output=execSync(command,{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim();return output.length>0?output:null}catch{return null}}function resolveGithubSource(){return{provider:`github`,branch:parseEnvValue(process.env.VERCEL_GIT_COMMIT_REF)??parseEnvValue(process.env.GITHUB_REF_NAME)??parseEnvValue(process.env.GITHUB_HEAD_REF)??runGitCommand(`git rev-parse --abbrev-ref HEAD`)??`unknown`,commitMessage:parseEnvValue(process.env.VERCEL_GIT_COMMIT_MESSAGE)??runGitCommand(`git log -1 --pretty=%B`)??``,commitSha:parseEnvValue(process.env.VERCEL_GIT_COMMIT_SHA)??parseEnvValue(process.env.GITHUB_SHA)??runGitCommand(`git rev-parse HEAD`)}}function resolveVercelDestination(){let environment=parseEnvValue(process.env.VERCEL_ENV??process.env.VERCEL_TARGET_ENV),deploymentId=parseEnvValue(process.env.VERCEL_DEPLOYMENT_ID);return{provider:`vercel`,destinationReleaseId:deploymentId,environment,deploymentId,deploymentUrl:resolveDeploymentUrl(),environmentName:environment,environmentTarget:environment}}function resolveDeploymentUrl(){let deploymentUrl=parseEnvValue(process.env.VERCEL_URL);return deploymentUrl===null?null:deploymentUrl.startsWith(`https://`)||deploymentUrl.startsWith(`http://`)?deploymentUrl:`https://${deploymentUrl}`}export{createSdkClient,runReleasePipeline};
1
+ import{cleanupSourceMaps,uploadSourceMaps}from"./source-maps.mjs";import{parseEnvValue}from"@interfere/types/sdk/env";import{releaseSlugSchema}from"@interfere/types/releases/slug";import{applyDeployEnvironment}from"@interfere/types/sdk/deploy-environment";import{execSync}from"node:child_process";import{HTTPClient,Interfere}from"@interfere/sdk";import{releaseDestinationProviderSchema}from"@interfere/types/integrations";import{resolveCliReleaseDestination}from"@interfere/types/sdk/cli-destination";const sources={github:resolveGithubSource},destinations={vercel:resolveVercelDestination,cloudflare:resolveCloudflareDestination,cli:resolveCliDestination};async function timed(fn){let start=performance.now();return[await fn(),Math.round(performance.now()-start)]}function createSdkClient(opts){let httpClient=new HTTPClient;return httpClient.addHook(`beforeRequest`,request=>{let next=new Request(request);return next.headers.set(`Authorization`,`Bearer ${opts.apiKey}`),next}),{httpClient,sdk:new Interfere({serverURL:opts.apiUrl,httpClient}),security:{apiKey:opts.apiKey}}}function resolveReleaseRequest(buildId,environment,releaseSlug,producerVersion,config){if(!config.surface.sourceProvider)return{ok:!1,reason:`missing_source_provider`};let destinationProvider=releaseDestinationProviderSchema.safeParse(config.surface.destinationProvider);return destinationProvider.success?{ok:!0,request:{source:sources[config.surface.sourceProvider](),destination:applyDeployEnvironment(destinations[destinationProvider.data](releaseSlug),environment),buildId,slug:releaseSlug,producerVersion}}:{ok:!1,reason:`missing_destination_provider`}}async function runReleasePipeline(input){let{apiKey,apiUrl,bundler,discovery,releasesConfig}=input,releaseRequest=resolveReleaseRequest(input.buildId,input.environment,input.releaseSlug,input.producerVersion,releasesConfig);if(!releaseRequest.ok)return{ok:!1,failure:{kind:releaseRequest.reason,config:releasesConfig}};let start=performance.now(),{httpClient,sdk,security}=createSdkClient({apiKey,apiUrl}),[release,createReleaseMs]=await timed(()=>sdk.releases.create(security,releaseRequest.request)),releaseSlug=releaseSlugSchema.parse(release.destination.slug),buildId=release.build.hash??input.buildId,[{totalBytes},uploadMs]=await timed(()=>uploadSourceMaps({apiUrl,bundler,discovered:discovery,httpClient,releaseSlug})),[,preflightMs]=await timed(()=>sdk.releases.preflight(security,{releaseSlug})),[{failures},cleanupMs]=await timed(()=>cleanupSourceMaps(discovery.files));return{ok:!0,data:{buildId,cleanupFailures:failures,config:releasesConfig,fileCount:discovery.files.length,release:{...release,destination:{...release.destination,slug:releaseSlug}},releaseSlug,timing:{createRelease:createReleaseMs,upload:uploadMs,preflight:preflightMs,cleanup:cleanupMs,total:Math.round(performance.now()-start),fileCount:discovery.files.length,totalBytes}}}}function runGitCommand(command){try{let output=execSync(command,{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim();return output.length>0?output:null}catch{return null}}function resolveGithubSource(){return{provider:`github`,branch:parseEnvValue(process.env.VERCEL_GIT_COMMIT_REF)??parseEnvValue(process.env.GITHUB_REF_NAME)??parseEnvValue(process.env.GITHUB_HEAD_REF)??runGitCommand(`git rev-parse --abbrev-ref HEAD`)??`unknown`,commitMessage:parseEnvValue(process.env.VERCEL_GIT_COMMIT_MESSAGE)??runGitCommand(`git log -1 --pretty=%B`)??``,commitSha:parseEnvValue(process.env.VERCEL_GIT_COMMIT_SHA)??parseEnvValue(process.env.GITHUB_SHA)??runGitCommand(`git rev-parse HEAD`)}}function resolveVercelDestination(){let environment=parseEnvValue(process.env.VERCEL_ENV??process.env.VERCEL_TARGET_ENV),deploymentId=parseEnvValue(process.env.VERCEL_DEPLOYMENT_ID);return{provider:`vercel`,destinationReleaseId:deploymentId,environment,deploymentId,deploymentUrl:resolveDeploymentUrl(),environmentName:environment,environmentTarget:environment}}function resolveDeploymentUrl(){let deploymentUrl=parseEnvValue(process.env.VERCEL_URL);return deploymentUrl===null?null:deploymentUrl.startsWith(`https://`)||deploymentUrl.startsWith(`http://`)?deploymentUrl:`https://${deploymentUrl}`}function resolveCloudflareDestination(){let raw=parseEnvValue(process.env.CF_VERSION_METADATA),versionMetadata=null;if(raw)try{versionMetadata=JSON.parse(raw)}catch{versionMetadata=null}let versionId=parseEnvValue(process.env.CF_VERSION_ID)??versionMetadata?.id??parseEnvValue(process.env.WORKERS_CI_BUILD_UUID)??null,scriptName=parseEnvValue(process.env.CF_WORKER_NAME)??parseEnvValue(process.env.WORKERS_CI_SCRIPT_NAME)??null,accountId=parseEnvValue(process.env.CF_ACCOUNT_ID)??parseEnvValue(process.env.CLOUDFLARE_ACCOUNT_ID)??null,environment=parseEnvValue(process.env.WORKERS_CI_BRANCH)??versionMetadata?.tag??null;return{provider:`cloudflare`,destinationReleaseId:versionId,environment,versionId,scriptName,accountId,deploymentUrl:resolveCloudflareDeploymentUrl(),environmentName:environment,environmentTarget:environment}}function resolveCloudflareDeploymentUrl(){let candidate=parseEnvValue(process.env.CF_PAGES_URL)??parseEnvValue(process.env.WORKERS_CI_DEPLOY_URL);return candidate===null?null:candidate.startsWith(`https://`)||candidate.startsWith(`http://`)?candidate:`https://${candidate}`}function resolveCliDestination(releaseSlug){return resolveCliReleaseDestination(process.env,releaseSlug)}export{createSdkClient,runReleasePipeline};
@@ -0,0 +1,9 @@
1
+ //#region src/internal/server/request-trace.d.ts
2
+ interface TraceMetaDescriptor {
3
+ content: string;
4
+ name: string;
5
+ }
6
+ declare function traceMeta(): TraceMetaDescriptor[];
7
+ declare function withRequestSpan<T>(request: Request, next: () => Promise<T>): Promise<T>;
8
+ //#endregion
9
+ export { TraceMetaDescriptor, traceMeta, withRequestSpan };
@@ -0,0 +1 @@
1
+ import{isEnabledOnServer}from"./env.mjs";import{SpanKind,SpanStatusCode,TraceFlags,context,propagation,trace}from"@opentelemetry/api";const SAMPLED_BIT=TraceFlags.SAMPLED,PROPAGATED_FIELDS=[`traceparent`,`tracestate`,`baggage`];function traceMeta(){let span=trace.getActiveSpan();if(!span||(span.spanContext().traceFlags&SAMPLED_BIT)!==SAMPLED_BIT)return[];let carrier={};propagation.inject(context.active(),carrier);let meta=[];for(let name of PROPAGATED_FIELDS){let content=carrier[name];content&&meta.push({content,name})}return meta}function withRequestSpan(request,next){if(!isEnabledOnServer())return next();let parent=propagation.extract(context.active(),headersToCarrier(request.headers));return context.with(parent,()=>trace.getTracer(`@interfere/vite/tanstack-start`).startActiveSpan(spanName(request),{attributes:requestAttributes(request),kind:SpanKind.SERVER},async span=>{try{return await next()}catch(error){throw span.recordException(error),span.setStatus({code:SpanStatusCode.ERROR}),error}finally{span.end()}}))}function headersToCarrier(headers){let carrier={};for(let[key,value]of headers)carrier[key]=value;return carrier}function spanName(request){return`${request.method} ${new URL(request.url).pathname}`}function requestAttributes(request){let url=new URL(request.url);return{"http.request.method":request.method,"server.address":url.host,"url.full":url.href,"url.path":url.pathname}}export{traceMeta,withRequestSpan};
@@ -29,6 +29,6 @@
29
29
  * browser span starts a fresh root, which is at least internally
30
30
  * consistent.
31
31
  */
32
- declare function TraceMeta(): import("react/jsx-runtime").JSX.Element | null;
32
+ declare function TraceMeta(): import("react").JSX.Element | null;
33
33
  //#endregion
34
34
  export { TraceMeta };
package/dist/package.mjs CHANGED
@@ -1 +1 @@
1
- var name=`@interfere/vite`,version=`11.0.0-canary.2`;export{name,version};
1
+ var name=`@interfere/vite`,version=`11.0.0-canary.4`;export{name,version};
package/dist/plugin.d.mts CHANGED
@@ -39,4 +39,4 @@ interface InterfereViteOptions {
39
39
  }
40
40
  declare function interfere(options?: InterfereViteOptions): Plugin;
41
41
  //#endregion
42
- export { InterfereViteMode, InterfereViteOptions, interfere as default, interfere };
42
+ export { InterfereViteMode, InterfereViteOptions, interfere };
package/dist/plugin.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import{PRODUCER_VERSION}from"./version.mjs";import{discoverByPairing}from"./internal/build/source-maps.mjs";import{createSdkClient,runReleasePipeline}from"./internal/build/pipeline.mjs";import{resolveCommitSha}from"./internal/release-slug.mjs";import{API_URL}from"@interfere/constants/api";import{deriveReleaseSlug}from"@interfere/types/releases/slug";import{existsSync,readdirSync,statSync}from"node:fs";import{join,resolve}from"node:path";import{loadEnv}from"vite";const SERVER_RUNTIME_PLUGIN_HINTS=[`tanstack-start`,`nitro`,`@tanstack/react-start`];function isTruthyEnvFlag(value){if(!value)return!1;let normalized=value.trim().toLowerCase();return normalized===`1`||normalized===`true`}function isTestEnv(){return!!(process.env.VITEST||process.env.VITEST_WORKER_ID)}function failMissingPublicKey(){let lines=[`interfere() requires VITE_INTERFERE_PUBLIC_KEY to identify your project at runtime.`,`Set the VITE_INTERFERE_PUBLIC_KEY environment variable, or remove interfere() from your Vite config.`,`See: https://support.interfere.com/docs/guides/vite`];if(isTestEnv())throw Error(`Interfere: Public key not set\n${lines.join(`
1
+ import{PRODUCER_VERSION}from"./version.mjs";import{discoverByPairing}from"./internal/build/source-maps.mjs";import{createSdkClient,runReleasePipeline}from"./internal/build/pipeline.mjs";import{resolveCommitSha}from"./internal/release-slug.mjs";import{API_URL}from"@interfere/constants/api";import{deriveReleaseSlug}from"@interfere/types/releases/slug";import{API_KEY_PREFIX,classifyReleasePipelineError,diagnoseRelease}from"@interfere/types/sdk/build-diagnostics";import{resolveDeployEnvironment}from"@interfere/types/sdk/deploy-environment";import{existsSync,readdirSync,statSync}from"node:fs";import{join,resolve}from"node:path";import{loadEnv}from"vite";const SERVER_RUNTIME_PLUGIN_HINTS=[`tanstack-start`,`nitro`,`@tanstack/react-start`],DIAGNOSTIC_CONTEXT={publicKeyEnvVar:`VITE_INTERFERE_PUBLIC_KEY`};function reportReleaseDiagnostic(logger,code,input){let diagnostic=diagnoseRelease(code,DIAGNOSTIC_CONTEXT,input);logger.warn(`[interfere] ${diagnostic.title}`);for(let line of diagnostic.details)logger.warn(`[interfere] ${line}`)}function isTruthyEnvFlag(value){if(!value)return!1;let normalized=value.trim().toLowerCase();return normalized===`1`||normalized===`true`}function isTestEnv(){return!!(process.env.VITEST||process.env.VITEST_WORKER_ID)}function pickEnvValue(env,key){let value=env[key];return value&&value.length>0?value:void 0}function failMissingPublicKey(){let lines=[`interfere() requires VITE_INTERFERE_PUBLIC_KEY to identify your project at runtime.`,`Set the VITE_INTERFERE_PUBLIC_KEY environment variable, or remove interfere() from your Vite config.`,`See: https://support.interfere.com/docs/guides/vite`];if(isTestEnv())throw Error(`Interfere: Public key not set\n${lines.join(`
2
2
  `)}`);console.error(`
3
- ⨯ Interfere → Public key not set`);for(let i=0;i<lines.length;i+=1){let line=lines[i];if(!line)continue;let connector=i===lines.length-1?`└`:`├`;console.error(` ${connector} ${line}`)}process.exit(1)}function detectServerRuntime(config){return config.plugins.some(p=>SERVER_RUNTIME_PLUGIN_HINTS.some(hint=>p.name?.includes(hint)))}function resolveMode(optsMode,config,logger){let requested=optsMode??`auto`;if(requested!==`auto`)return logger.info(`[interfere] mode=${requested} (explicit)`),requested;let detected=detectServerRuntime(config)?`proxy`:`direct`;return logger.info(`[interfere] mode=${detected} (auto-detected). Override with \`interfere({ mode: "..." })\`.`),detected}function hasFreshServerSourceMaps(root,sinceMs){if(!existsSync(root))return!1;let entries=readdirSync(root,{withFileTypes:!0});for(let entry of entries){let absolute=join(root,entry.name);if(entry.isDirectory()){if(hasFreshServerSourceMaps(absolute,sinceMs))return!0;continue}if(entry.name.endsWith(`.map`)&&statSync(absolute).mtimeMs>=sinceMs)return!0}return!1}function isUploadReady(state){return!!(state.enableUpload&&state.apiKey&&state.releaseSlug&&state.commitSha&&!state.uploadStarted)}function shouldWaitForServerOutput(state){return state.mode===`proxy`&&!hasFreshServerSourceMaps(join(state.uploadOutDir,`server`),state.buildStartedAt)}function logSkippedRelease(logger,failure){if(failure.kind===`missing_source_provider`){logger.warn(`[interfere] release skipped: this surface has no version control provider configured. Configure one at https://interfere.com/~/${failure.config.org.slug}/surfaces/${failure.config.surface.slug}.`);return}logger.warn(`[interfere] release skipped: this surface has no deployment target configured. Configure one at https://interfere.com/~/${failure.config.org.slug}/surfaces/${failure.config.surface.slug}.`)}function logCleanupFailures(logger,failures){for(let failure of failures)logger.warn(`[interfere] cleanup left ${failure.absolute} on disk: ${failure.code??failure.message}`)}async function uploadSourceMaps(state){let{apiKey,apiUrl,releaseSlug,commitSha,logger,projectDir,uploadOutDir}=state;logger.info(`[interfere] uploading source maps for release ${releaseSlug}…`);try{let{sdk,security}=createSdkClient({apiKey,apiUrl}),[discovered,releasesConfig]=await Promise.all([discoverByPairing({projectDir,distDir:uploadOutDir,subtrees:[`.`],publicPathRewrites:[{from:`public`,to:``}]}),sdk.releases.getConfig(security)]);if(discovered.files.length===0){logger.info(`[interfere] no source maps found, skipping upload.`);return}let result=await runReleasePipeline({apiKey,apiUrl,bundler:`rollup`,buildId:commitSha,discovery:discovered,producerVersion:PRODUCER_VERSION,releasesConfig,releaseSlug});if(!result.ok){logSkippedRelease(logger,result.failure);return}logCleanupFailures(logger,result.data.cleanupFailures),logger.info(`[interfere] release ${result.data.releaseSlug} confirmed — ${result.data.fileCount} maps, ${result.data.timing.total}ms.`)}catch(err){let message=err instanceof Error?err.message:String(err);logger.warn(`[interfere] release pipeline failed: ${message}. Build continues; events from this release will ingest but be ignored as evidence.`)}}async function uploadSourceMapsWhenReady(state){if(isUploadReady(state)){if(shouldWaitForServerOutput(state)){state.logger.info(`[interfere] waiting for Nitro server output before uploading source maps.`);return}state.uploadStarted=!0,await uploadSourceMaps(state)}}function emitSetupWarnings(state){let{logger,mode,publicKeyPresent,apiKey,releaseSlug,sourceMapsExplicit,isProductionBuild}=state;mode===`proxy`&&publicKeyPresent&&logger.info(`[interfere] mode=proxy: using VITE_INTERFERE_PUBLIC_KEY with the first-party proxy route.`),sourceMapsExplicit!==!1&&apiKey&&!releaseSlug&&logger.warn(`[interfere] No commit SHA available. Release metadata publishing is disabled. Set INTERFERE_SOURCE_ID, expose VERCEL_GIT_COMMIT_SHA / GITHUB_SHA, or run inside a git checkout.`),isProductionBuild&&sourceMapsExplicit!==!1&&!apiKey&&logger.warn("[interfere] INTERFERE_API_KEY is not set. Release metadata will not be published. Create an Interfere API key in the dashboard and set it in your build environment, or pass `interfere({ sourceMaps: false })` to suppress this warning if release metadata is intentionally handled out-of-band.")}function buildPluginState(options,config){let logger=config.logger,mode=resolveMode(options.mode,config,logger),publicKey=config.env.VITE_INTERFERE_PUBLIC_KEY;config.command===`build`&&!publicKey&&failMissingPublicKey();let commitSha=options.commitSha??config.env.VITE_INTERFERE_COMMIT_SHA??resolveCommitSha(),releaseSlug=commitSha?deriveReleaseSlug(commitSha):null,fileEnv=loadEnv(config.mode,config.envDir,``),pickEnv=key=>{let shell=process.env[key];if(shell&&shell.length>0)return shell;let file=fileEnv[key];return file&&file.length>0?file:void 0},apiKey=pickEnv(`INTERFERE_API_KEY`),apiUrl=pickEnv(`INTERFERE_API_URL`)??API_URL,enableUpload=options.sourceMaps??(apiKey!==void 0&&apiKey.length>0&&releaseSlug!==null),rawBrowserApiUrl=config.env.VITE_INTERFERE_API_URL,browserApiUrl=rawBrowserApiUrl&&rawBrowserApiUrl.length>0?rawBrowserApiUrl:void 0;return emitSetupWarnings({apiKey,isProductionBuild:config.command===`build`,logger,mode,publicKeyPresent:!!publicKey,releaseSlug,sourceMapsExplicit:options.sourceMaps}),{apiKey,apiUrl,browserApiUrl:mode===`direct`?browserApiUrl:void 0,commitSha,enableUpload,forceEnable:isTruthyEnvFlag(config.env.VITE_INTERFERE_FORCE_ENABLE),logger,mode,projectDir:config.root,publicKey,releaseSlug,uploadOutDir:resolve(config.root,config.build.outDir),uploadStarted:!1,buildStartedAt:Date.now()}}function interfere(options={}){let state=null;return{name:`interfere`,enforce:`pre`,configResolved(config){let next=buildPluginState(options,config);state?.mode===`proxy`&&next.mode===`proxy`&&(next.uploadOutDir=state.uploadOutDir,next.uploadStarted=state.uploadStarted,next.buildStartedAt=state.buildStartedAt),state=next},transformIndexHtml(){let assignments=[];return state?.releaseSlug&&assignments.push(`globalThis["__INTERFERE_RELEASE_SLUG__"]=${JSON.stringify(state.releaseSlug)};`),state?.publicKey&&assignments.push(`globalThis["__INTERFERE_PUBLIC_KEY__"]=${JSON.stringify(state.publicKey)};`),state?.forceEnable&&assignments.push(`globalThis["__INTERFERE_FORCE_ENABLE__"]=true;`),state?.mode===`proxy`&&state.publicKey&&assignments.push(`globalThis["__INTERFERE_PROXY_MODE__"]=true;`),state?.mode===`direct`&&state.browserApiUrl&&assignments.push(`globalThis["__INTERFERE_API_URL__"]=${JSON.stringify(state.browserApiUrl)};`),assignments.length===0?[]:[{tag:`script`,children:assignments.join(``),injectTo:`head-prepend`}]},async closeBundle(){state&&await uploadSourceMapsWhenReady(state)}}}export{interfere as default,interfere};
3
+ ⨯ Interfere → Public key not set`);for(let i=0;i<lines.length;i+=1){let line=lines[i];if(!line)continue;let connector=i===lines.length-1?`└`:`├`;console.error(` ${connector} ${line}`)}process.exit(1)}function detectServerRuntime(config){return config.plugins.some(p=>SERVER_RUNTIME_PLUGIN_HINTS.some(hint=>p.name?.includes(hint)))}function resolveMode(optsMode,config,logger,announce){let requested=optsMode??`auto`;if(requested!==`auto`)return announce&&logger.info(`[interfere] mode=${requested} (explicit)`),requested;let detected=detectServerRuntime(config)?`proxy`:`direct`;return announce&&logger.info(`[interfere] mode=${detected} (auto-detected). Override with \`interfere({ mode: "..." })\`.`),detected}function hasFreshServerSourceMaps(root,sinceMs){if(!existsSync(root))return!1;let entries=readdirSync(root,{withFileTypes:!0});for(let entry of entries){let absolute=join(root,entry.name);if(entry.isDirectory()){if(hasFreshServerSourceMaps(absolute,sinceMs))return!0;continue}if(entry.name.endsWith(`.map`)&&statSync(absolute).mtimeMs>=sinceMs)return!0}return!1}function isUploadReady(state){return!!(state.isProductionBuild&&state.enableUpload&&state.apiKey&&state.releaseSlug&&state.commitSha&&!state.uploadStarted)}function shouldWaitForServerOutput(state){return state.mode===`proxy`&&!hasFreshServerSourceMaps(join(state.uploadOutDir,`server`),state.buildStartedAt)}function logSkippedRelease(logger,failure){if(failure.kind===`missing_source_provider`){logger.warn(`[interfere] release skipped: this surface has no version control provider configured. Configure one at https://interfere.com/~/${failure.config.org.slug}/surfaces/${failure.config.surface.slug}.`);return}logger.warn(`[interfere] release skipped: this surface has no deployment target configured. Configure one at https://interfere.com/~/${failure.config.org.slug}/surfaces/${failure.config.surface.slug}.`)}function logCleanupFailures(logger,failures){for(let failure of failures)logger.warn(`[interfere] cleanup left ${failure.absolute} on disk: ${failure.code??failure.message}`)}async function uploadSourceMaps(state){let{apiKey,apiUrl,releaseSlug,commitSha,logger,projectDir,uploadOutDir}=state;if(!apiKey.startsWith(API_KEY_PREFIX)){reportReleaseDiagnostic(logger,`API_KEY_WRONG_PREFIX`,{apiKey});return}logger.info(`[interfere] uploading source maps for release ${releaseSlug}…`);try{let{sdk,security}=createSdkClient({apiKey,apiUrl}),[discovered,releasesConfig]=await Promise.all([discoverByPairing({projectDir,distDir:uploadOutDir,subtrees:[`.`],publicPathRewrites:[{from:`public`,to:``}]}),sdk.releases.getConfig(security)]);if(discovered.files.length===0){logger.info(`[interfere] no source maps found, skipping upload.`);return}let result=await runReleasePipeline({apiKey,apiUrl,bundler:`rollup`,buildId:commitSha,discovery:discovered,environment:state.environment,producerVersion:PRODUCER_VERSION,releasesConfig,releaseSlug});if(!result.ok){logSkippedRelease(logger,result.failure);return}logCleanupFailures(logger,result.data.cleanupFailures),logger.info(`[interfere] release ${result.data.releaseSlug} confirmed — ${result.data.fileCount} maps, ${result.data.timing.total}ms.`)}catch(err){let message=err instanceof Error?err.message:String(err);reportReleaseDiagnostic(logger,classifyReleasePipelineError(err),{errorMessage:message})}}async function uploadSourceMapsWhenReady(state){if(isUploadReady(state)){if(shouldWaitForServerOutput(state)){state.logger.info(`[interfere] waiting for Nitro server output before uploading source maps.`);return}state.uploadStarted=!0,await uploadSourceMaps(state)}}function emitSetupWarnings(state){let{logger,mode,publicKeyPresent,apiKey,releaseSlug,sourceMapsExplicit,isProductionBuild}=state;mode===`proxy`&&publicKeyPresent&&logger.info(`[interfere] mode=proxy: using VITE_INTERFERE_PUBLIC_KEY with the first-party proxy route.`),sourceMapsExplicit!==!1&&apiKey&&!releaseSlug&&logger.warn(`[interfere] No commit SHA available. Release metadata publishing is disabled. Set INTERFERE_SOURCE_ID, expose VERCEL_GIT_COMMIT_SHA / GITHUB_SHA, or run inside a git checkout.`),isProductionBuild&&sourceMapsExplicit!==!1&&!apiKey&&logger.warn("[interfere] INTERFERE_API_KEY is not set. Release metadata will not be published. Create an Interfere API key in the dashboard and set it in your build environment, or pass `interfere({ sourceMaps: false })` to suppress this warning if release metadata is intentionally handled out-of-band.")}function resolveReleaseEnv(config){return{...loadEnv(config.mode,config.envDir,``),...process.env}}function resolveReleaseIdentity(options,config){let commitSha=options.commitSha??config.env.VITE_INTERFERE_COMMIT_SHA??resolveCommitSha();return{commitSha,releaseSlug:commitSha?deriveReleaseSlug(commitSha):null}}function shouldEnableUpload({apiKey,isProductionBuild,releaseSlug,sourceMaps}){return isProductionBuild?sourceMaps??!!(apiKey&&releaseSlug):!1}function buildPluginState(options,config,announce){let logger=config.logger,mode=resolveMode(options.mode,config,logger,announce),publicKey=config.env.VITE_INTERFERE_PUBLIC_KEY,isProductionBuild=config.command===`build`;isProductionBuild&&!publicKey&&failMissingPublicKey();let releaseEnv=resolveReleaseEnv(config),pickEnv=key=>pickEnvValue(releaseEnv,key),apiKey=pickEnv(`INTERFERE_API_KEY`),apiUrl=pickEnv(`INTERFERE_API_URL`)??API_URL,{commitSha,releaseSlug}=resolveReleaseIdentity(options,config),environment=isProductionBuild?resolveDeployEnvironment(releaseEnv):null,rawBrowserApiUrl=config.env.VITE_INTERFERE_API_URL,browserApiUrl=rawBrowserApiUrl&&rawBrowserApiUrl.length>0?rawBrowserApiUrl:void 0;return announce&&emitSetupWarnings({apiKey,isProductionBuild,logger,mode,publicKeyPresent:!!publicKey,releaseSlug,sourceMapsExplicit:options.sourceMaps}),{apiKey,apiUrl,browserApiUrl:mode===`direct`?browserApiUrl:void 0,commitSha,enableUpload:shouldEnableUpload({apiKey,isProductionBuild,releaseSlug,sourceMaps:options.sourceMaps}),environment,forceEnable:isTruthyEnvFlag(config.env.VITE_INTERFERE_FORCE_ENABLE),isProductionBuild,logger,mode,projectDir:config.root,publicKey,releaseSlug,uploadOutDir:resolve(config.root,config.build.outDir),uploadStarted:!1,buildStartedAt:Date.now()}}function interfere(options={}){let state=null,forcedSourcemapOriginal,announced=!1;return{name:`interfere`,enforce:`pre`,config(userConfig,{command,mode}){if(command!==`build`||options.sourceMaps===!1)return;let root=userConfig.root?resolve(process.cwd(),userConfig.root):process.cwd();if(!pickEnvValue(loadEnv(mode,userConfig.envDir?resolve(root,userConfig.envDir):root,``),`INTERFERE_API_KEY`))return;let current=userConfig.build?.sourcemap;current!==void 0&&current!==!0&&(forcedSourcemapOriginal=current),userConfig.build={...userConfig.build,sourcemap:!0}},configResolved(config){let next=buildPluginState(options,config,!announced);announced=!0,state?.mode===`proxy`&&next.mode===`proxy`&&(next.uploadOutDir=state.uploadOutDir,next.uploadStarted=state.uploadStarted,next.buildStartedAt=state.buildStartedAt),state=next,forcedSourcemapOriginal!==void 0&&(next.logger.warn(`[interfere] Forced build.sourcemap to true (was ${JSON.stringify(forcedSourcemapOriginal)}). Source maps are required to symbolicate errors; they are uploaded then deleted from the build output, so they are never served. Pass interfere({ sourceMaps: false }) to opt out.`),forcedSourcemapOriginal=void 0)},transformIndexHtml(){let assignments=[];return state?.releaseSlug&&assignments.push(`globalThis["__INTERFERE_RELEASE_SLUG__"]=${JSON.stringify(state.releaseSlug)};`),state?.publicKey&&assignments.push(`globalThis["__INTERFERE_PUBLIC_KEY__"]=${JSON.stringify(state.publicKey)};`),state?.environment&&assignments.push(`globalThis["__INTERFERE_ENVIRONMENT__"]=${JSON.stringify(state.environment)};`),state?.forceEnable&&assignments.push(`globalThis["__INTERFERE_FORCE_ENABLE__"]=true;`),state?.mode===`proxy`&&state.publicKey&&assignments.push(`globalThis["__INTERFERE_PROXY_MODE__"]=true;`),state?.mode===`direct`&&state.browserApiUrl&&assignments.push(`globalThis["__INTERFERE_API_URL__"]=${JSON.stringify(state.browserApiUrl)};`),assignments.length===0?[]:[{tag:`script`,children:assignments.join(``),injectTo:`head-prepend`}]},async closeBundle(){state&&await uploadSourceMapsWhenReady(state)}}}export{interfere};
@@ -0,0 +1,6 @@
1
+ import { TraceMetaDescriptor, traceMeta } from "./internal/server/request-trace.mjs";
2
+
3
+ //#region src/tanstack-start.d.ts
4
+ declare const interfereRequestMiddleware: import("@tanstack/react-start").RequestMiddlewareAfterServer<{}, undefined, undefined>;
5
+ //#endregion
6
+ export { type TraceMetaDescriptor, interfereRequestMiddleware, traceMeta };
@@ -0,0 +1 @@
1
+ import{traceMeta,withRequestSpan}from"./internal/server/request-trace.mjs";import{createMiddleware}from"@tanstack/react-start";const interfereRequestMiddleware=createMiddleware().server(({next,request})=>withRequestSpan(request,()=>Promise.resolve(next())));export{interfereRequestMiddleware,traceMeta};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/vite",
3
- "version": "11.0.0-canary.2",
3
+ "version": "11.0.0-canary.4",
4
4
  "license": "MIT",
5
5
  "description": "Vite build plugin and client + server initialization for Interfere.",
6
6
  "keywords": [
@@ -47,6 +47,11 @@
47
47
  "types": "./dist/server.d.mts",
48
48
  "default": "./dist/server.mjs"
49
49
  },
50
+ "./tanstack-start": {
51
+ "monorepo": "./src/tanstack-start.ts",
52
+ "types": "./dist/tanstack-start.d.mts",
53
+ "default": "./dist/tanstack-start.mjs"
54
+ },
50
55
  "./handler": {
51
56
  "monorepo": "./src/handler.ts",
52
57
  "types": "./dist/handler.d.mts",
@@ -64,31 +69,35 @@
64
69
  "dependencies": {
65
70
  "@interfere/constants": "^9.0.2-canary.0",
66
71
  "@interfere/helpers": "^9.0.0",
67
- "@interfere/react": "^11.0.0-canary.2",
68
- "@interfere/sdk": "^11.0.0-canary.2",
69
- "@interfere/types": "^9.0.3-canary.1",
72
+ "@interfere/react": "^11.0.0-canary.4",
73
+ "@interfere/sdk": "^11.0.0-canary.4",
74
+ "@interfere/types": "^9.0.3-canary.2",
70
75
  "@opentelemetry/api": "^1.9.1",
71
- "@opentelemetry/api-logs": "^0.218.0",
76
+ "@opentelemetry/api-logs": "^0.219.0",
72
77
  "@opentelemetry/baggage-span-processor": "^0.5.0",
73
78
  "@opentelemetry/context-async-hooks": "^2.7.1",
74
79
  "@opentelemetry/core": "^2.7.0",
75
- "@opentelemetry/exporter-logs-otlp-http": "^0.218.0",
76
- "@opentelemetry/exporter-metrics-otlp-http": "^0.218.0",
77
- "@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
78
- "@opentelemetry/instrumentation": "^0.218.0",
79
- "@opentelemetry/instrumentation-undici": "^0.28.0",
80
+ "@opentelemetry/exporter-logs-otlp-http": "^0.219.0",
81
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.219.0",
82
+ "@opentelemetry/exporter-trace-otlp-http": "^0.219.0",
83
+ "@opentelemetry/instrumentation": "^0.219.0",
84
+ "@opentelemetry/instrumentation-undici": "^0.29.0",
80
85
  "@opentelemetry/resources": "^2.7.0",
81
- "@opentelemetry/sdk-logs": "^0.218.0",
86
+ "@opentelemetry/sdk-logs": "^0.219.0",
82
87
  "@opentelemetry/sdk-metrics": "^2.7.0",
83
88
  "@opentelemetry/sdk-trace-base": "^2.7.0",
84
89
  "@opentelemetry/sdk-trace-node": "^2.7.1"
85
90
  },
86
91
  "peerDependencies": {
92
+ "@tanstack/react-start": "1.168.26",
87
93
  "react": "^19.2.6",
88
94
  "react-dom": "^19.2.6",
89
- "vite": "^8.0.13"
95
+ "vite": "^8.1.0"
90
96
  },
91
97
  "peerDependenciesMeta": {
98
+ "@tanstack/react-start": {
99
+ "optional": true
100
+ },
92
101
  "react": {
93
102
  "optional": true
94
103
  },
@@ -102,15 +111,16 @@
102
111
  "devDependencies": {
103
112
  "@interfere/test-utils": "^9.0.0",
104
113
  "@interfere/typescript-config": "^9.0.0",
105
- "@types/node": "^24.12.0",
106
- "@types/react": "19.2.15",
114
+ "@tanstack/react-start": "1.168.26",
115
+ "@types/node": "^26.0.0",
116
+ "@types/react": "19.2.17",
107
117
  "@types/react-dom": "19.2.3",
108
- "@typescript/native-preview": "7.0.0-dev.20260601.1",
109
- "@vitest/coverage-v8": "4.1.8",
118
+ "@typescript/native-preview": "7.0.0-dev.20260623.1",
119
+ "@vitest/coverage-v8": "4.1.9",
110
120
  "react": "^19.2.6",
111
121
  "react-dom": "^19.2.6",
112
- "tsdown": "0.22.1",
113
- "vite": "^8.0.13",
114
- "vitest": "4.1.8"
122
+ "tsdown": "^0.22.2",
123
+ "vite": "^8.1.0",
124
+ "vitest": "4.1.9"
115
125
  }
116
126
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"init.d.mts","names":[],"sources":["../src/init.ts"],"mappings":";;;;;cAmBE,KAAA,QAAK,OAAA;;;iEAEI,MAAA,oEACM,MAAA;;;YAEX,IAAA,8CAAA,aAAA,KAAA,OAAA,4CAAA,MAAA,8BACa,QAAA"}
package/dist/init.mjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"init.mjs","names":[],"sources":["../src/init.ts"],"sourcesContent":["import { createWrapperSingleton } from \"@interfere/react/internal/wrapper-singleton\";\n\nimport { PRODUCER_VERSION } from \"./version.js\";\n\n// biome-ignore lint/performance/noBarrelFile: customer-facing one-import surface — `@interfere/vite/init` re-exports the runtime helpers so callers don't have to also import `@interfere/react/api`.\nexport { capture, span } from \"@interfere/react/api\";\nexport type { Kernel, KernelOptions } from \"@interfere/react/internal/kernel\";\nexport type {\n ConsentCategory,\n ConsentState,\n GateableCategory,\n} from \"@interfere/types/sdk/plugins/manifest\";\n\nconst wrapper = createWrapperSingleton({\n producerVersion: PRODUCER_VERSION,\n initEntryName: \"Vite\",\n});\n\nexport const {\n close,\n consent,\n getKernel,\n getKernelOrNull,\n identity,\n init,\n subscribeToKernel,\n} = wrapper;\n"],"mappings":"2KAkBA,KAAa,CACX,MACA,QACA,UACA,gBACA,SACA,KACA,mBAZc,uBAAuB,CACrC,gBAAiB,iBACjB,cAAe,MACjB,CAUI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipeline.d.mts","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"mappings":";;;;;;;;UA4BiB,WAAA;EACf,OAAA;EACA,aAAA;EACA,SAAA;EACA,SAAA;EACA,KAAA;EACA,UAAA;EACA,MAAA;AAAA;AAAA,KAGU,sBAAA;EACN,IAAA;EAAiC,MAAA,EAAQ,sBAAA;AAAA;EACzC,IAAA;EAAsC,MAAA,EAAQ,sBAAsB;AAAA;AAAA,KAE9D,qBAAA;EACN,EAAA;EAAU,IAAA,EAAM,sBAAA;AAAA;EAChB,EAAA;EAAW,OAAA,EAAS,sBAAsB;AAAA;AAAA,UAE/B,sBAAA;EACf,OAAA;EACA,eAAA;IACE,QAAA;IACA,IAAA;IACA,OAAA;EAAA;EAEF,MAAA,EAAQ,sBAAA;EACR,SAAA;EACA,OAAA,EAAS,qBAAA;EACT,WAAA,EAAa,WAAA;EACb,MAAA,EAAQ,WAAA;AAAA;AAAA,UAGO,oBAAA;EACf,MAAA;EACA,MAAA;EACA,OAAA;EACA,OAAA,EAAS,eAAA;EACT,SAAA,EAAW,eAAA;EACX,eAAA;EACA,WAAA,EAAa,WAAA;EACb,cAAA,EAAgB,sBAAA;AAAA;AAAA,iBA6BF,eAAA,CAAgB,IAAA;EAAQ,MAAA;EAAgB,MAAA;AAAA;EACtD,UAAA,EAAY,UAAA;EACZ,GAAA,EAAK,SAAS;EACd,QAAA;IAAY,MAAA;EAAA;AAAA;AAAA,iBA4CQ,kBAAA,CACpB,KAAA,EAAO,oBAAA,GACN,OAAA,CAAQ,qBAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipeline.mjs","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\n\nimport { HTTPClient, Interfere } from \"@interfere/sdk\";\nimport type { ReleasesConfigResponse } from \"@interfere/sdk/models/releases-config-response.js\";\nimport type { ManifestBundler } from \"@interfere/types/data/source-maps\";\nimport {\n destinationProviderSchema,\n type DestinationProvider,\n type ReleaseDestinationMetadata,\n type ReleaseSourceMetadata,\n type SourceProvider,\n} from \"@interfere/types/integrations\";\nimport type {\n CreateReleaseRequest,\n CreateReleaseResponse,\n} from \"@interfere/types/releases/definition\";\nimport {\n type ReleaseSlug,\n releaseSlugSchema,\n} from \"@interfere/types/releases/slug\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\n\nimport {\n cleanupSourceMaps,\n type DiscoveryResult,\n uploadSourceMaps,\n} from \"./source-maps.js\";\n\nexport interface BuildTiming {\n cleanup: number;\n createRelease: number;\n fileCount: number;\n preflight: number;\n total: number;\n totalBytes: number;\n upload: number;\n}\n\nexport type ReleasePipelineFailure =\n | { kind: \"missing_source_provider\"; config: ReleasesConfigResponse }\n | { kind: \"missing_destination_provider\"; config: ReleasesConfigResponse };\n\nexport type ReleasePipelineResult =\n | { ok: true; data: ReleasePipelineSuccess }\n | { ok: false; failure: ReleasePipelineFailure };\n\nexport interface ReleasePipelineSuccess {\n buildId: string;\n cleanupFailures: {\n absolute: string;\n code: string | undefined;\n message: string;\n }[];\n config: ReleasesConfigResponse;\n fileCount: number;\n release: CreateReleaseResponse;\n releaseSlug: ReleaseSlug;\n timing: BuildTiming;\n}\n\nexport interface ReleasePipelineInput {\n apiKey: string;\n apiUrl: string;\n buildId: string;\n bundler: ManifestBundler;\n discovery: DiscoveryResult;\n producerVersion: string;\n releaseSlug: ReleaseSlug;\n releasesConfig: ReleasesConfigResponse;\n}\n\ntype ResolveReleaseRequestResult =\n | { ok: true; request: CreateReleaseRequest }\n | {\n ok: false;\n reason: \"missing_source_provider\" | \"missing_destination_provider\";\n };\n\nconst sources: Record<SourceProvider, () => ReleaseSourceMetadata> = {\n github: resolveGithubSource,\n};\n\nconst destinations: Record<\n DestinationProvider,\n () => ReleaseDestinationMetadata\n> = {\n vercel: resolveVercelDestination,\n};\n\nasync function timed<T>(\n fn: () => Promise<T>\n): Promise<[result: T, durationMs: number]> {\n const start = performance.now();\n const result = await fn();\n return [result, Math.round(performance.now() - start)];\n}\n\nexport function createSdkClient(opts: { apiKey: string; apiUrl: string }): {\n httpClient: HTTPClient;\n sdk: Interfere;\n security: { apiKey: string };\n} {\n const httpClient = new HTTPClient();\n httpClient.addHook(\"beforeRequest\", (request) => {\n const next = new Request(request);\n next.headers.set(\"Authorization\", `Bearer ${opts.apiKey}`);\n return next;\n });\n return {\n httpClient,\n sdk: new Interfere({ serverURL: opts.apiUrl, httpClient }),\n security: { apiKey: opts.apiKey },\n };\n}\n\nfunction resolveReleaseRequest(\n buildId: string,\n releaseSlug: ReleaseSlug,\n producerVersion: string,\n config: ReleasesConfigResponse\n): ResolveReleaseRequestResult {\n if (!config.surface.sourceProvider) {\n return { ok: false, reason: \"missing_source_provider\" };\n }\n\n const destinationProvider = destinationProviderSchema.safeParse(\n config.surface.destinationProvider\n );\n if (!destinationProvider.success) {\n return { ok: false, reason: \"missing_destination_provider\" };\n }\n\n return {\n ok: true,\n request: {\n source: sources[config.surface.sourceProvider](),\n destination: destinations[destinationProvider.data](),\n buildId,\n slug: releaseSlug,\n producerVersion,\n },\n };\n}\n\nexport async function runReleasePipeline(\n input: ReleasePipelineInput\n): Promise<ReleasePipelineResult> {\n const { apiKey, apiUrl, bundler, discovery, releasesConfig } = input;\n const releaseRequest = resolveReleaseRequest(\n input.buildId,\n input.releaseSlug,\n input.producerVersion,\n releasesConfig\n );\n\n if (!releaseRequest.ok) {\n return {\n ok: false,\n failure: { kind: releaseRequest.reason, config: releasesConfig },\n };\n }\n\n const start = performance.now();\n const { httpClient, sdk, security } = createSdkClient({ apiKey, apiUrl });\n const [release, createReleaseMs] = await timed(() =>\n sdk.releases.create(security, releaseRequest.request)\n );\n const releaseSlug = releaseSlugSchema.parse(release.destination.slug);\n const buildId = release.build.hash ?? input.buildId;\n const [{ totalBytes }, uploadMs] = await timed(() =>\n uploadSourceMaps({\n apiUrl,\n bundler,\n discovered: discovery,\n httpClient,\n releaseSlug,\n })\n );\n const [, preflightMs] = await timed(() =>\n sdk.releases.preflight(security, { releaseSlug })\n );\n const [{ failures }, cleanupMs] = await timed(() =>\n cleanupSourceMaps(discovery.files)\n );\n\n return {\n ok: true,\n data: {\n buildId,\n cleanupFailures: failures,\n config: releasesConfig,\n fileCount: discovery.files.length,\n release: {\n ...release,\n destination: { ...release.destination, slug: releaseSlug },\n },\n releaseSlug,\n timing: {\n createRelease: createReleaseMs,\n upload: uploadMs,\n preflight: preflightMs,\n cleanup: cleanupMs,\n total: Math.round(performance.now() - start),\n fileCount: discovery.files.length,\n totalBytes,\n },\n },\n };\n}\n\nfunction runGitCommand(command: string): string | null {\n try {\n const output = execSync(command, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return output.length > 0 ? output : null;\n } catch {\n return null;\n }\n}\n\nfunction resolveGithubSource(): ReleaseSourceMetadata {\n return {\n provider: \"github\",\n branch:\n parseEnvValue(process.env[\"VERCEL_GIT_COMMIT_REF\"]) ??\n parseEnvValue(process.env[\"GITHUB_REF_NAME\"]) ??\n parseEnvValue(process.env[\"GITHUB_HEAD_REF\"]) ??\n runGitCommand(\"git rev-parse --abbrev-ref HEAD\") ??\n \"unknown\",\n commitMessage:\n parseEnvValue(process.env[\"VERCEL_GIT_COMMIT_MESSAGE\"]) ??\n runGitCommand(\"git log -1 --pretty=%B\") ??\n \"\",\n commitSha:\n parseEnvValue(process.env[\"VERCEL_GIT_COMMIT_SHA\"]) ??\n parseEnvValue(process.env[\"GITHUB_SHA\"]) ??\n runGitCommand(\"git rev-parse HEAD\"),\n };\n}\n\nfunction resolveVercelDestination(): ReleaseDestinationMetadata {\n const environment = parseEnvValue(\n process.env[\"VERCEL_ENV\"] ?? process.env[\"VERCEL_TARGET_ENV\"]\n );\n const deploymentId = parseEnvValue(process.env[\"VERCEL_DEPLOYMENT_ID\"]);\n\n return {\n provider: \"vercel\",\n destinationReleaseId: deploymentId,\n environment,\n deploymentId,\n deploymentUrl: resolveDeploymentUrl(),\n environmentName: environment,\n environmentTarget: environment,\n };\n}\n\nfunction resolveDeploymentUrl(): string | null {\n const deploymentUrl = parseEnvValue(process.env[\"VERCEL_URL\"]);\n if (deploymentUrl === null) {\n return null;\n }\n if (\n deploymentUrl.startsWith(\"https://\") ||\n deploymentUrl.startsWith(\"http://\")\n ) {\n return deploymentUrl;\n }\n return `https://${deploymentUrl}`;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"source-maps.d.mts","names":[],"sources":["../../../src/internal/build/source-maps.ts"],"mappings":";;;;;UAqBiB,aAAA;EAAA,SACN,QAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGM,eAAA;EAAA,SACN,KAAA,EAAO,aAAa;EAAA,SACpB,eAAA;AAAA;AAAA,UAGD,iBAAA;EACR,IAAA;EACA,EAAE;AAAA;AAAA,UAGa,wBAAA;EACf,OAAA;EACA,UAAA;EACA,kBAAA,WAA6B,iBAAiB;EAC9C,QAAA;AAAA;AAAA,UAGe,cAAA;EAAA,SACN,QAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA;AAAA;AAAA,UAGD,YAAA;EACR,MAAA;EACA,OAAA,EAAS,eAAA;EACT,UAAA,EAAY,eAAA;EACZ,UAAA,EAAY,UAAA;EACZ,WAAA,EAAa,WAAA;AAAA;AAAA,UAGE,YAAA;EACf,SAAA;EACA,UAAU;AAAA;AAAA,iBA+EU,iBAAA,CACpB,IAAA,EAAM,wBAAA,GACL,OAAA,CAAQ,eAAA;AAAA,iBA6FW,iBAAA,CACpB,KAAA,WAAgB,aAAA,KACf,OAAA;EAAU,QAAA,EAAU,cAAA;AAAA;AAAA,iBAyBD,gBAAA;EACpB,MAAA;EACA,OAAA;EACA,UAAA;EACA,UAAA;EACA;AAAA,GACC,YAAA,GAAe,OAAA,CAAQ,YAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"source-maps.mjs","names":[],"sources":["../../../src/internal/build/source-maps.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { readdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\n\nimport type { HTTPClient } from \"@interfere/sdk\";\nimport type {\n CompleteSourceMapsRequest,\n CompleteSourceMapsResponse,\n ManifestBundler,\n SignSourceMapsRequest,\n SignSourceMapsResponse,\n} from \"@interfere/types/data/source-maps\";\nimport type { ReleaseSlug } from \"@interfere/types/releases/slug\";\n\nconst LEADING_DOT_SLASH_RE = /^(\\.\\/)+/;\nconst PUT_CONCURRENCY = 12;\nconst SOURCEMAPPING_RE = /\\/\\/[#@]\\s*sourceMappingURL=(\\S+)\\s*$/;\nconst SPEC_LAST_DEBUG_ID_RE =\n /\\/\\/# debugId=([a-fA-F0-9-]+)(?![\\s\\S]*\\/\\/# debugId=)/m;\nconst SCRIPT_SUFFIXES = [\".js\", \".mjs\", \".cjs\"] as const;\n\nexport interface SourceMapFile {\n readonly absolute: string;\n readonly chunkUrl: string;\n readonly content: string;\n readonly debugId: string;\n readonly hash: string;\n readonly path: string;\n}\n\nexport interface DiscoveryResult {\n readonly files: SourceMapFile[];\n readonly sourceFileCount: number;\n}\n\ninterface PublicPathRewrite {\n from: string;\n to: string;\n}\n\nexport interface DiscoverByPairingOptions {\n distDir: string;\n projectDir: string;\n publicPathRewrites: readonly PublicPathRewrite[];\n subtrees: readonly string[];\n}\n\nexport interface CleanupFailure {\n readonly absolute: string;\n readonly code: string | undefined;\n readonly message: string;\n}\n\ninterface UploadParams {\n apiUrl: string;\n bundler: ManifestBundler;\n discovered: DiscoveryResult;\n httpClient: HTTPClient;\n releaseSlug: ReleaseSlug;\n}\n\nexport interface UploadResult {\n fileCount: number;\n totalBytes: number;\n}\n\nfunction normalizeDistDir(distDir: string): string {\n return distDir.replaceAll(\"\\\\\", \"/\").replace(LEADING_DOT_SLASH_RE, \"\");\n}\n\nfunction resolveDistDir(projectDir: string, distDir: string): string {\n return isAbsolute(distDir) ? distDir : resolve(projectDir, distDir);\n}\n\nasync function walkDistTrees(\n absDistDir: string,\n suffixes: readonly string[],\n subtrees: readonly string[]\n): Promise<string[]> {\n const results = await Promise.all(\n subtrees.map(async (subtree) => {\n const root = subtree === \".\" ? absDistDir : join(absDistDir, subtree);\n const entries = await readdir(root, { recursive: true }).catch(\n () => [] as string[]\n );\n const out: string[] = [];\n for (const entry of entries) {\n if (\n typeof entry === \"string\" &&\n suffixes.some((suffix) => entry.endsWith(suffix))\n ) {\n out.push(join(root, entry));\n }\n }\n return out;\n })\n );\n\n return results.flat();\n}\n\nfunction toPublicPath(\n rel: string,\n rewrites: readonly PublicPathRewrite[]\n): string {\n const normalized = rel.replaceAll(\"\\\\\", \"/\");\n for (const { from, to } of rewrites) {\n const prefix = from.endsWith(\"/\") ? from : `${from}/`;\n if (normalized.startsWith(prefix)) {\n return `${to}${normalized.slice(prefix.length)}`;\n }\n }\n return normalized;\n}\n\nfunction readDebugIdFromJs(content: string): string | null {\n const match = SPEC_LAST_DEBUG_ID_RE.exec(content);\n return match?.[1] ?? null;\n}\n\nfunction injectDebugIdIntoJs(content: string, debugId: string): string {\n const debugIdComment = `//# debugId=${debugId}`;\n\n if (SPEC_LAST_DEBUG_ID_RE.test(content)) {\n return content.replace(SPEC_LAST_DEBUG_ID_RE, debugIdComment);\n }\n\n const match = SOURCEMAPPING_RE.exec(content);\n if (match) {\n const before = content.slice(0, match.index).trimEnd();\n return `${before}\\n${debugIdComment}\\n${match[0]}`;\n }\n\n return `${content}\\n${debugIdComment}`;\n}\n\nfunction injectDebugIdIntoMap(content: string, debugId: string): string {\n const json = JSON.parse(content) as Record<string, unknown>;\n json[\"debugId\"] = debugId;\n return JSON.stringify(json);\n}\n\nexport async function discoverByPairing(\n opts: DiscoverByPairingOptions\n): Promise<DiscoveryResult> {\n const absDistDir = resolveDistDir(\n opts.projectDir,\n normalizeDistDir(opts.distDir)\n );\n const jsPaths = await walkDistTrees(\n absDistDir,\n SCRIPT_SUFFIXES,\n opts.subtrees\n );\n const pairs = new Map<\n string,\n {\n existingDebugId: string | null;\n jsAbs: string;\n jsContent: string;\n jsPublic: string;\n mapAbs: string;\n }\n >();\n\n for (const jsAbs of jsPaths) {\n const content = await readFile(jsAbs, \"utf8\");\n const match = SOURCEMAPPING_RE.exec(content);\n if (!match?.[1]) {\n continue;\n }\n\n const jsDir = jsAbs.slice(0, jsAbs.lastIndexOf(\"/\") + 1);\n const mapAbs = `${jsDir}${decodeURIComponent(match[1])}`;\n const jsPublic = toPublicPath(\n relative(absDistDir, jsAbs),\n opts.publicPathRewrites\n );\n const mapPublic = toPublicPath(\n relative(absDistDir, mapAbs),\n opts.publicPathRewrites\n );\n\n pairs.set(mapPublic, {\n existingDebugId: readDebugIdFromJs(content),\n jsAbs,\n jsContent: content,\n jsPublic,\n mapAbs,\n });\n }\n\n const files = await Promise.all(\n Array.from(\n pairs.entries(),\n async ([mapPublic, pair]): Promise<SourceMapFile | null> => {\n const mapContent = await readFile(pair.mapAbs, \"utf8\").catch(\n () => null\n );\n if (mapContent === null) {\n return null;\n }\n\n const debugId = pair.existingDebugId ?? randomUUID();\n if (!pair.existingDebugId) {\n await writeFile(\n pair.jsAbs,\n injectDebugIdIntoJs(pair.jsContent, debugId),\n \"utf8\"\n );\n }\n\n const mapJson = JSON.parse(mapContent) as Record<string, unknown>;\n const finalMap =\n mapJson[\"debugId\"] === debugId\n ? mapContent\n : injectDebugIdIntoMap(mapContent, debugId);\n if (finalMap !== mapContent) {\n await writeFile(pair.mapAbs, finalMap, \"utf8\");\n }\n\n return {\n absolute: pair.mapAbs,\n path: mapPublic,\n content: finalMap,\n hash: createHash(\"sha256\").update(finalMap).digest(\"hex\"),\n debugId,\n chunkUrl: pair.jsPublic,\n };\n }\n )\n );\n\n const loaded = files.filter((file): file is SourceMapFile => file !== null);\n return { files: loaded, sourceFileCount: pairs.size };\n}\n\nexport async function cleanupSourceMaps(\n files: readonly SourceMapFile[]\n): Promise<{ failures: CleanupFailure[] }> {\n const results = await Promise.allSettled(\n files.map((file) => unlink(file.absolute))\n );\n const failures: CleanupFailure[] = [];\n\n for (const [index, result] of results.entries()) {\n if (result.status !== \"rejected\") {\n continue;\n }\n const error = result.reason as NodeJS.ErrnoException;\n if (error.code === \"ENOENT\") {\n continue;\n }\n const file = files[index];\n failures.push({\n absolute: file?.absolute ?? \"<unknown>\",\n code: error.code,\n message: error.message ?? String(error),\n });\n }\n\n return { failures };\n}\n\nexport async function uploadSourceMaps({\n apiUrl,\n bundler,\n discovered,\n httpClient,\n releaseSlug,\n}: UploadParams): Promise<UploadResult> {\n const filesByPath = new Map(discovered.files.map((file) => [file.path, file]));\n const signRequest = {\n files: discovered.files.map((file) => ({\n path: file.path,\n sizeBytes: byteLengthOf(file.content),\n ...extractRichness(file.content),\n })),\n } satisfies SignSourceMapsRequest;\n\n const signResponse = await postJson<SignSourceMapsResponse>(\n httpClient,\n new URL(\n `/v1/releases/${encodeURIComponent(releaseSlug)}/source-maps/sign`,\n apiUrl\n ),\n signRequest\n );\n\n let totalBytes = 0;\n await mapWithConcurrency(\n signResponse.uploads,\n PUT_CONCURRENCY,\n async (upload) => {\n const file = filesByPath.get(upload.path);\n if (!file) {\n throw new Error(\n `Sign response referenced unknown path \"${upload.path}\"`\n );\n }\n\n totalBytes += byteLengthOf(file.content);\n await putToR2(upload.presignedUrl, file.content);\n }\n );\n\n const completeRequest = {\n files: discovered.files.map((file) => ({\n path: file.path,\n hash: file.hash,\n debugId: file.debugId,\n chunkUrl: file.chunkUrl,\n })),\n sourceFileCount: discovered.sourceFileCount,\n bundler,\n } satisfies CompleteSourceMapsRequest;\n\n const completeResponse = await postJson<CompleteSourceMapsResponse>(\n httpClient,\n new URL(\n `/v1/releases/${encodeURIComponent(releaseSlug)}/source-maps/complete`,\n apiUrl\n ),\n completeRequest\n );\n\n return {\n fileCount: completeResponse.fileCount,\n totalBytes,\n };\n}\n\nfunction byteLengthOf(content: string) {\n return new TextEncoder().encode(content).byteLength;\n}\n\ninterface SourceMapRichness {\n hasFile: boolean;\n hasNames: boolean;\n hasSourcesContent: boolean;\n mappingsPresent: boolean;\n}\n\nconst EMPTY_RICHNESS: SourceMapRichness = {\n hasSourcesContent: false,\n hasNames: false,\n hasFile: false,\n mappingsPresent: false,\n};\n\nfunction leafRichness(map: Record<string, unknown>): SourceMapRichness {\n const sourcesContent = map[\"sourcesContent\"];\n const names = map[\"names\"];\n const file = map[\"file\"];\n const mappings = map[\"mappings\"];\n\n return {\n hasSourcesContent:\n Array.isArray(sourcesContent) && sourcesContent.length > 0,\n hasNames: Array.isArray(names) && names.length > 0,\n hasFile: typeof file === \"string\" && file.length > 0,\n mappingsPresent: typeof mappings === \"string\" && mappings.length > 0,\n };\n}\n\nfunction extractRichness(content: string): SourceMapRichness {\n let parsed: unknown;\n try {\n parsed = JSON.parse(content);\n } catch {\n return EMPTY_RICHNESS;\n }\n\n if (!(parsed && typeof parsed === \"object\")) {\n return EMPTY_RICHNESS;\n }\n\n const top = parsed as Record<string, unknown>;\n const sections = top[\"sections\"];\n if (!Array.isArray(sections)) {\n return leafRichness(top);\n }\n\n const merged: SourceMapRichness = {\n hasSourcesContent: false,\n hasNames: false,\n hasFile:\n typeof top[\"file\"] === \"string\" && (top[\"file\"] as string).length > 0,\n mappingsPresent: false,\n };\n\n for (const section of sections) {\n const inner = (section as { map?: unknown } | null)?.map;\n if (!(inner && typeof inner === \"object\")) {\n continue;\n }\n const richness = leafRichness(inner as Record<string, unknown>);\n merged.hasSourcesContent ||= richness.hasSourcesContent;\n merged.hasNames ||= richness.hasNames;\n merged.mappingsPresent ||= richness.mappingsPresent;\n }\n\n return merged;\n}\n\nasync function postJson<T>(\n httpClient: HTTPClient,\n url: URL,\n body: unknown\n): Promise<T> {\n const response = await httpClient.request(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n },\n body: JSON.stringify(body),\n })\n );\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(\n `Source-map API request failed: POST ${url.pathname} -> ${response.status} ${detail}`\n );\n }\n\n return (await response.json()) as T;\n}\n\nasync function putToR2(presignedUrl: string, content: string) {\n const response = await fetch(presignedUrl, {\n method: \"PUT\",\n headers: { \"content-type\": \"application/json\" },\n body: content,\n });\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(\n `Release metadata file upload failed: ${response.status} ${detail}`\n );\n }\n}\n\nasync function mapWithConcurrency<T>(\n items: T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<void>\n): Promise<void> {\n let cursor = 0;\n\n async function worker() {\n while (true) {\n const index = cursor++;\n if (index >= items.length) {\n return;\n }\n const item = items[index];\n if (item === undefined) {\n return;\n }\n await fn(item, index);\n }\n }\n\n await Promise.all(\n Array.from({ length: Math.min(concurrency, items.length) }, () => worker())\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"release-slug.d.mts","names":[],"sources":["../../src/internal/release-slug.ts"],"mappings":";;;iBAqBgB,gBAAA;AAAA,iBAOA,kBAAA;EACd,SAAA;EACA,IAAA,EAAM,WAAW;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"release-slug.mjs","names":[],"sources":["../../src/internal/release-slug.ts"],"sourcesContent":["import { releaseSourceIdEnvKeys } from \"@interfere/types/integrations\";\nimport {\n deriveReleaseSlug,\n type ReleaseSlug,\n} from \"@interfere/types/releases/slug\";\nimport { readFirstEnvValue } from \"@interfere/types/sdk/env\";\n\nimport { execSync } from \"node:child_process\";\n\nfunction runGitCommand(command: string): string | null {\n try {\n const output = execSync(command, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return output.length > 0 ? output : null;\n } catch {\n return null;\n }\n}\n\nexport function resolveCommitSha(): string | null {\n return (\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\")\n );\n}\n\nexport function resolveReleaseSlug(): {\n commitSha: string | null;\n slug: ReleaseSlug | null;\n} {\n const commitSha = resolveCommitSha();\n return {\n commitSha,\n slug: commitSha ? deriveReleaseSlug(commitSha) : null,\n };\n}\n"],"mappings":"iOASA,SAAS,cAAc,QAAgC,CACrD,GAAI,CACF,IAAM,OAAS,SAAS,QAAS,CAC/B,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,EAAE,KAAK,EACR,OAAO,OAAO,OAAS,EAAI,OAAS,IACtC,MAAQ,CACN,OAAO,IACT,CACF,CAEA,SAAgB,kBAAkC,CAChD,OACE,kBAAkB,QAAQ,IAAK,sBAAsB,GACrD,cAAc,oBAAoB,CAEtC,CAEA,SAAgB,oBAGd,CACA,IAAM,UAAY,iBAAiB,EACnC,MAAO,CACL,UACA,KAAM,UAAY,kBAAkB,SAAS,EAAI,IACnD,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"handle.d.mts","names":[],"sources":["../../../src/internal/route/handle.ts"],"mappings":";;AAyCA;;;;;;;;;;;;;AAAgE;;iBAA1C,MAAA,CAAO,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"handle.mjs","names":[],"sources":["../../../src/internal/route/handle.ts"],"sourcesContent":["import { SW_SCRIPT } from \"@interfere/react/sw\";\n\nimport { isEnabledOnServer } from \"../server/env.js\";\nimport {\n extractSubPath,\n formatProxyError,\n forwardToCollector,\n resolveAuthenticatedEnv,\n} from \"./proxy.js\";\n\nconst SW_HEADERS: Record<string, string> = {\n \"content-type\": \"application/javascript; charset=utf-8\",\n \"service-worker-allowed\": \"/\",\n \"cache-control\": \"public, max-age=3600\",\n};\n\nconst CORS_HEADERS = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n \"Access-Control-Max-Age\": \"86400\",\n};\n\nconst DISABLED_RESPONSE = () => new Response(null, { status: 204 });\n\n/**\n * Web-Standards `Request → Response` handler that customers wire\n * into their server framework's catch-all API route. Same proxy\n * behavior as `@interfere/next/route-handler` but built for\n * TanStack Start / Nitro's Web-Standards request handlers.\n *\n * Routes by HTTP method:\n * - `GET /sw` — serves the SDK service worker so customers get\n * offline-durable telemetry without shipping a SW from their\n * own domain.\n * - `GET /*` — proxies to the collector (config fetch).\n * - `POST /*` — proxies to the collector (OTLP ingest, replay,\n * session sync).\n * - `OPTIONS /*` — CORS preflight.\n * - everything else — 405.\n */\nexport async function handle(request: Request): Promise<Response> {\n const method = request.method;\n\n if (method === \"OPTIONS\") {\n return new Response(null, { status: 200, headers: CORS_HEADERS });\n }\n\n if (method === \"GET\") {\n return await handleGet(request);\n }\n\n if (method === \"POST\") {\n return await handlePost(request);\n }\n\n return new Response(null, { status: 405 });\n}\n\nasync function handleGet(request: Request): Promise<Response> {\n const subPath = extractSubPath(request);\n\n if (subPath === \"/sw\") {\n return new Response(SW_SCRIPT, { status: 200, headers: SW_HEADERS });\n }\n\n if (!isEnabledOnServer()) {\n return DISABLED_RESPONSE();\n }\n\n const env = resolveAuthenticatedEnv();\n try {\n return await forwardToCollector(request, env, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n console.error(\n `[interfere] Proxy ${request.method} ${subPath} failed: ${detail.lines.join(\" | \")}`\n );\n return Response.json(\n { code: \"INTERFERE_PROXY_ERROR\", message: detail.message },\n { status: 502 }\n );\n }\n}\n\nasync function handlePost(request: Request): Promise<Response> {\n if (!isEnabledOnServer()) {\n return DISABLED_RESPONSE();\n }\n\n const env = resolveAuthenticatedEnv();\n const subPath = extractSubPath(request);\n try {\n return await forwardToCollector(request, env, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n console.error(\n `[interfere] Proxy ${request.method} ${subPath} failed: ${detail.lines.join(\" | \")}`\n );\n return Response.json(\n { code: \"INTERFERE_PROXY_ERROR\", message: detail.message },\n { status: 502 }\n );\n }\n}\n"],"mappings":"gMAUA,MAAM,WAAqC,CACzC,eAAgB,wCAChB,yBAA0B,IAC1B,gBAAiB,sBACnB,EAEM,aAAe,CACnB,8BAA+B,IAC/B,+BAAgC,qBAChC,+BAAgC,eAChC,yBAA0B,OAC5B,EAEM,sBAA0B,IAAI,SAAS,KAAM,CAAE,OAAQ,GAAI,CAAC,EAkBlE,eAAsB,OAAO,QAAqC,CAChE,IAAM,OAAS,QAAQ,OAcvB,OAZI,SAAW,UACN,IAAI,SAAS,KAAM,CAAE,OAAQ,IAAK,QAAS,YAAa,CAAC,EAG9D,SAAW,MACN,MAAM,UAAU,OAAO,EAG5B,SAAW,OACN,MAAM,WAAW,OAAO,EAG1B,IAAI,SAAS,KAAM,CAAE,OAAQ,GAAI,CAAC,CAC3C,CAEA,eAAe,UAAU,QAAqC,CAC5D,IAAM,QAAU,eAAe,OAAO,EAEtC,GAAI,UAAY,MACd,OAAO,IAAI,SAAS,UAAW,CAAE,OAAQ,IAAK,QAAS,UAAW,CAAC,EAGrE,GAAI,CAAC,kBAAkB,EACrB,OAAO,kBAAkB,EAG3B,IAAM,IAAM,wBAAwB,EACpC,GAAI,CACF,OAAO,MAAM,mBAAmB,QAAS,IAAK,OAAO,CACvD,OAAS,MAAO,CACd,IAAM,OAAS,iBAAiB,KAAK,EAIrC,OAHA,QAAQ,MACN,qBAAqB,QAAQ,OAAO,GAAG,QAAQ,WAAW,OAAO,MAAM,KAAK,KAAK,GACnF,EACO,SAAS,KACd,CAAE,KAAM,wBAAyB,QAAS,OAAO,OAAQ,EACzD,CAAE,OAAQ,GAAI,CAChB,CACF,CACF,CAEA,eAAe,WAAW,QAAqC,CAC7D,GAAI,CAAC,kBAAkB,EACrB,OAAO,kBAAkB,EAG3B,IAAM,IAAM,wBAAwB,EAC9B,QAAU,eAAe,OAAO,EACtC,GAAI,CACF,OAAO,MAAM,mBAAmB,QAAS,IAAK,OAAO,CACvD,OAAS,MAAO,CACd,IAAM,OAAS,iBAAiB,KAAK,EAIrC,OAHA,QAAQ,MACN,qBAAqB,QAAQ,OAAO,GAAG,QAAQ,WAAW,OAAO,MAAM,KAAK,KAAK,GACnF,EACO,SAAS,KACd,CAAE,KAAM,wBAAyB,QAAS,OAAO,OAAQ,EACzD,CAAE,OAAQ,GAAI,CAChB,CACF,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"proxy.d.mts","names":[],"sources":["../../../src/internal/route/proxy.ts"],"mappings":";;;;;AAkCA;;;;iBAAgB,gBAAA,CAAiB,OAAA,EAAS,OAAA,GAAU,OAAO;AAAA,UAW1C,gBAAA;EACf,MAAA;EACA,WAAA,EAAa,kBAAkB;AAAA;AAAA,iBAGjB,uBAAA,IAA2B,gBAAgB;AAAA,iBAQ3C,cAAA,CAAe,OAAgB,EAAP,OAAO;;;;;;;AAXd;AAGjC;;iBA+BgB,aAAA,CAAc,OAAgB,EAAP,OAAO;AAAA,iBAI9B,gBAAA,CAAiB,KAAA;EAC/B,OAAA;EACA,KAAA;AAAA;AAAA,iBAwBoB,kBAAA,CACpB,OAAA,EAAS,OAAA,EACT,GAAA,EAAK,gBAAA,EACL,OAAA,WACC,OAAA,CAAQ,QAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"proxy.mjs","names":[],"sources":["../../../src/internal/route/proxy.ts"],"sourcesContent":["import { resolveRoutePrefix } from \"@interfere/constants/route-prefix\";\nimport { omitUndefined } from \"@interfere/helpers/omit-undefined\";\nimport { extractCountryHeader } from \"@interfere/types/sdk/geo\";\n\nimport {\n type InterfereServerEnv,\n readInterfereServerEnv,\n} from \"../server/env.js\";\n\nconst STRIPPED_AUTH_HEADERS = [\n \"authorization\",\n \"x-api-key\",\n \"x-interfere-api-key\",\n] as const;\n\nconst STRIPPED_TRANSPORT_HEADERS = [\n \"host\",\n \"content-length\",\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"te\",\n \"trailer\",\n \"upgrade\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n] as const;\n\n/**\n * Clone the inbound request's headers, removing entries that should\n * never cross the proxy boundary. Returns a mutable `Headers` so\n * callers can `.set()`/`.delete()` upstream-specific values without\n * having to merge record literals (which lose case-insensitivity).\n */\nexport function forwardedHeaders(request: Request): Headers {\n const headers = new Headers(request.headers);\n for (const name of STRIPPED_AUTH_HEADERS) {\n headers.delete(name);\n }\n for (const name of STRIPPED_TRANSPORT_HEADERS) {\n headers.delete(name);\n }\n return headers;\n}\n\nexport interface AuthenticatedEnv {\n apiUrl: string;\n forceEnable: InterfereServerEnv[\"forceEnable\"];\n}\n\nexport function resolveAuthenticatedEnv(): AuthenticatedEnv {\n const env = readInterfereServerEnv();\n return {\n apiUrl: env.apiUrl,\n forceEnable: env.forceEnable,\n };\n}\n\nexport function extractSubPath(request: Request): string {\n const prefix = resolveRoutePrefix();\n const url = new URL(request.url);\n const idx = url.pathname.indexOf(prefix);\n if (idx === -1) {\n return \"/\";\n }\n const remainder = url.pathname.slice(idx + prefix.length);\n if (remainder === \"\") {\n return \"/\";\n }\n return remainder.startsWith(\"/\") ? remainder : `/${remainder}`;\n}\n\n/**\n * Preserve any query string verbatim when forwarding upstream.\n *\n * The browser SDK uses `?_pv=…` and `?pk=…` (and `?_pt=…` in direct\n * mode) as a `navigator.sendBeacon` fallback when `visibilitychange→\n * hidden` aborts the keepalive fetch path, so authentication works without\n * custom headers. The collector's `otlpProducerGuard` and `surfacePkAuth`\n * accept those values verbatim — but only if the proxy actually forwards them.\n */\nexport function extractSearch(request: Request): string {\n return new URL(request.url).search;\n}\n\nexport function formatProxyError(error: unknown): {\n message: string;\n lines: string[];\n} {\n if (!(error instanceof Error)) {\n return { message: String(error), lines: [String(error)] };\n }\n\n const lines = [`${error.name}: ${error.message}`];\n\n if (\"cause\" in error && error.cause) {\n const cause =\n error.cause instanceof Error ? error.cause.message : String(error.cause);\n lines.push(`cause: ${cause}`);\n }\n\n if (\n \"code\" in error &&\n typeof (error as NodeJS.ErrnoException).code === \"string\"\n ) {\n lines.push(`code: ${(error as NodeJS.ErrnoException).code}`);\n }\n\n return { message: `${error.name}: ${error.message}`, lines };\n}\n\nexport async function forwardToCollector(\n request: Request,\n env: AuthenticatedEnv,\n subPath: string\n): Promise<Response> {\n const url = `${env.apiUrl}${subPath}${extractSearch(request)}`;\n const hasBody = request.method !== \"GET\" && request.method !== \"HEAD\";\n const body = hasBody\n ? new Uint8Array(await request.arrayBuffer())\n : undefined;\n\n const headers = forwardedHeaders(request);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n if (env.forceEnable) {\n headers.set(\"x-interfere-force-enable\", \"1\");\n }\n const country = extractCountryHeader(request);\n if (country !== null) {\n headers.set(\"x-country-code\", country);\n }\n\n const upstream = await fetch(url, {\n ...omitUndefined({ body }),\n method: request.method,\n headers,\n signal: AbortSignal.timeout(10_000),\n });\n\n if (!upstream.ok) {\n const text = await upstream.text().catch(() => \"\");\n\n if (upstream.status >= 500) {\n console.error(\n `[interfere] Upstream ${upstream.status} for ${request.method} ${subPath}: ${text}`\n );\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: text },\n { status: upstream.status }\n );\n }\n if (upstream.status >= 400) {\n console.warn(\n `[interfere] Upstream ${upstream.status} for ${request.method} ${subPath}: ${text}`\n );\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_WARNING\", message: text },\n { status: upstream.status }\n );\n }\n\n console.error(\n `[interfere] Upstream ${upstream.status} for ${request.method} ${subPath}: ${text}`\n );\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: text },\n { status: upstream.status }\n );\n }\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"capture.d.mts","names":[],"sources":["../../../src/internal/server/capture.ts"],"mappings":";;;iBAwFgB,YAAA,CAAa,KAAA,WAAgB,GAAA,GAAM,mBAAmB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"capture.mjs","names":[],"sources":["../../../src/internal/server/capture.ts"],"sourcesContent":["import {\n isNonErrorException,\n MECHANISM_TYPE,\n type NonErrorException,\n toException,\n} from \"@interfere/types/sdk/errors\";\nimport type { ErrorMechanism } from \"@interfere/types/sdk/plugins/payload/errors\";\n\nimport { context, SpanKind, SpanStatusCode, trace } from \"@opentelemetry/api\";\n\nimport { isEnabledOnServer } from \"./env.js\";\nimport { isPluginEnabled } from \"./remote-config.js\";\nimport type { CaptureErrorContext } from \"./types.js\";\n\nconst TRACER_NAME = \"@interfere/vite/server\";\n\nconst DEFAULT_CAPTURE_ERROR_MECHANISM: ErrorMechanism = {\n type: MECHANISM_TYPE.node.captureError,\n handled: true,\n};\n\nconst seen = new WeakSet<Error>();\n\nfunction buildAttrs(\n value: Error | NonErrorException,\n mechanism: ErrorMechanism,\n ctx: CaptureErrorContext | undefined\n): Record<string, string> {\n const attrs: Record<string, string> = {\n \"interfere.exception.mechanism\": mechanism.type,\n \"interfere.exception.handled\": String(mechanism.handled),\n };\n if (ctx?.request?.method) {\n attrs[\"http.request.method\"] = ctx.request.method;\n }\n if (ctx?.request?.path) {\n attrs[\"url.path\"] = ctx.request.path;\n }\n if (isNonErrorException(value)) {\n attrs[\"exception.type\"] = value.type;\n attrs[\"exception.message\"] = value.value;\n attrs[\"interfere.exception.kind\"] = \"non-error\";\n return attrs;\n }\n attrs[\"exception.type\"] = value.name;\n attrs[\"exception.message\"] = value.message;\n if (value.stack) {\n attrs[\"exception.stacktrace\"] = value.stack;\n }\n return attrs;\n}\n\nfunction recordException(\n error: unknown,\n mechanism: ErrorMechanism,\n ctx: CaptureErrorContext | undefined\n): void {\n const value = toException(error);\n const attrs = buildAttrs(value, mechanism, ctx);\n\n const tracer = trace.getTracer(TRACER_NAME);\n const active = trace.getActiveSpan();\n if (active) {\n active.addEvent(\"exception\", attrs);\n if (!mechanism.handled) {\n active.setStatus({\n code: SpanStatusCode.ERROR,\n message: isNonErrorException(value) ? value.value : value.message,\n });\n }\n return;\n }\n\n const span = tracer.startSpan(\n \"interfere.captureError\",\n { kind: SpanKind.INTERNAL },\n context.active()\n );\n span.addEvent(\"exception\", attrs);\n if (!mechanism.handled) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: isNonErrorException(value) ? value.value : value.message,\n });\n }\n span.end();\n}\n\nexport function captureError(error: unknown, ctx?: CaptureErrorContext): void {\n if (!isEnabledOnServer()) {\n return;\n }\n if (!isPluginEnabled(\"errors\")) {\n return;\n }\n\n if (error instanceof Error) {\n if (seen.has(error)) {\n return;\n }\n seen.add(error);\n }\n\n recordException(\n error,\n ctx?.mechanism ?? DEFAULT_CAPTURE_ERROR_MECHANISM,\n ctx\n );\n}\n"],"mappings":"wPAcA,MAEM,gCAAkD,CACtD,KAAM,eAAe,KAAK,aAC1B,QAAS,EACX,EAEM,KAAO,IAAI,QAEjB,SAAS,WACP,MACA,UACA,IACwB,CACxB,IAAM,MAAgC,CACpC,gCAAiC,UAAU,KAC3C,8BAA+B,OAAO,UAAU,OAAO,CACzD,EAkBA,OAjBI,KAAK,SAAS,SAChB,MAAM,uBAAyB,IAAI,QAAQ,QAEzC,KAAK,SAAS,OAChB,MAAM,YAAc,IAAI,QAAQ,MAE9B,oBAAoB,KAAK,GAC3B,MAAM,kBAAoB,MAAM,KAChC,MAAM,qBAAuB,MAAM,MACnC,MAAM,4BAA8B,YAC7B,QAET,MAAM,kBAAoB,MAAM,KAChC,MAAM,qBAAuB,MAAM,QAC/B,MAAM,QACR,MAAM,wBAA0B,MAAM,OAEjC,MACT,CAEA,SAAS,gBACP,MACA,UACA,IACM,CACN,IAAM,MAAQ,YAAY,KAAK,EACzB,MAAQ,WAAW,MAAO,UAAW,GAAG,EAExC,OAAS,MAAM,UAAU,wBAAW,EACpC,OAAS,MAAM,cAAc,EACnC,GAAI,OAAQ,CACV,OAAO,SAAS,YAAa,KAAK,EAC7B,UAAU,SACb,OAAO,UAAU,CACf,KAAM,eAAe,MACrB,QAAS,oBAAoB,KAAK,EAAI,MAAM,MAAQ,MAAM,OAC5D,CAAC,EAEH,MACF,CAEA,IAAM,KAAO,OAAO,UAClB,yBACA,CAAE,KAAM,SAAS,QAAS,EAC1B,QAAQ,OAAO,CACjB,EACA,KAAK,SAAS,YAAa,KAAK,EAC3B,UAAU,SACb,KAAK,UAAU,CACb,KAAM,eAAe,MACrB,QAAS,oBAAoB,KAAK,EAAI,MAAM,MAAQ,MAAM,OAC5D,CAAC,EAEH,KAAK,IAAI,CACX,CAEA,SAAgB,aAAa,MAAgB,IAAiC,CACvE,qBAAkB,GAGlB,gBAAgB,QAAQ,EAI7B,IAAI,iBAAiB,MAAO,CAC1B,GAAI,KAAK,IAAI,KAAK,EAChB,OAEF,KAAK,IAAI,KAAK,CAChB,CAEA,gBACE,MACA,KAAK,WAAa,gCAClB,GACF,CANA,CAOF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"console-bridge.d.mts","names":[],"sources":["../../../src/internal/server/console-bridge.ts"],"mappings":";;AAoFA;;;;AAAmC;;;;;;;;;;;;;;iBAAnB,mBAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"console-bridge.mjs","names":[],"sources":["../../../src/internal/server/console-bridge.ts"],"sourcesContent":["import { context, trace } from \"@opentelemetry/api\";\nimport { logs, type SeverityNumber } from \"@opentelemetry/api-logs\";\n\nconst ATTR_EXCEPTION_TYPE = \"exception.type\" as const;\nconst ATTR_EXCEPTION_MESSAGE = \"exception.message\" as const;\nconst ATTR_EXCEPTION_STACKTRACE = \"exception.stacktrace\" as const;\n\nconst CONSOLE_METHODS = [\"debug\", \"log\", \"info\", \"warn\", \"error\"] as const;\ntype ConsoleMethod = (typeof CONSOLE_METHODS)[number];\n\nconst SEVERITY: Record<ConsoleMethod, SeverityNumber> = {\n debug: 5,\n log: 9,\n info: 9,\n warn: 13,\n error: 17,\n};\n\n/**\n * Bound at first failure log; subsequent failures only re-log every\n * Nth occurrence so a misconfigured logger backend doesn't itself\n * spam the console with bridge errors at line rate.\n */\nconst BRIDGE_FAILURE_LOG_INTERVAL = 100;\n\nfunction stringify(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value instanceof Error) {\n return value.stack ?? `${value.name}: ${value.message}`;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction extractException(args: unknown[]): Error | undefined {\n for (const arg of args) {\n if (arg instanceof Error) {\n return arg;\n }\n }\n return;\n}\n\nfunction buildExceptionAttributes(\n args: unknown[]\n): Record<string, string> | undefined {\n const exception = extractException(args);\n if (!exception) {\n return;\n }\n const attrs: Record<string, string> = {\n [ATTR_EXCEPTION_TYPE]: exception.name,\n [ATTR_EXCEPTION_MESSAGE]: exception.message,\n };\n if (exception.stack) {\n attrs[ATTR_EXCEPTION_STACKTRACE] = exception.stack;\n }\n return attrs;\n}\n\n/**\n * Patches `console.{debug,log,info,warn,error}` to additionally emit\n * OTel `LogRecord`s alongside the original output. Every log record\n * carries the active span's context (so trace ↔ log correlation\n * works in dashboards) and any `Error` arg gets unpacked into\n * semconv exception attrs.\n *\n * Returns a disposer that restores the original `console.*` methods.\n *\n * Cycle protection: `emitting` guards against the bridge re-entering\n * itself if a logger backend itself logs to console (which would\n * recursively emit forever). Failures are bounded-rate logged via\n * the original `console.error` so a broken backend doesn't drown\n * the customer's logs in bridge-failure messages.\n *\n * Sibling of `@interfere/next/internal/server/console-bridge` — same\n * bridge, same trade-offs, intentionally kept in the Vite adapter's\n * source tree so SDKs do not share build/runtime internals.\n */\nexport function bridgeConsoleToOtel(): () => void {\n const logger = logs.getLogger(\"@interfere/vite/console\");\n let emitting = false;\n let bridgeFailures = 0;\n\n const original: Record<ConsoleMethod, (...args: unknown[]) => void> = {\n debug: console.debug,\n log: console.log,\n info: console.info,\n warn: console.warn,\n error: console.error,\n };\n\n function emitLog(\n orig: (...args: unknown[]) => void,\n severity: SeverityNumber,\n method: ConsoleMethod,\n body: string,\n activeContext: ReturnType<typeof context.active>,\n activeSpan: ReturnType<typeof trace.getSpan>,\n attributes: Record<string, string> | undefined\n ): void {\n if (emitting) {\n return;\n }\n emitting = true;\n try {\n logger.emit({\n severityNumber: severity,\n severityText: method.toUpperCase(),\n body,\n ...(activeSpan ? { context: activeContext } : {}),\n ...(attributes ? { attributes } : {}),\n });\n } catch (error) {\n bridgeFailures++;\n if (bridgeFailures % BRIDGE_FAILURE_LOG_INTERVAL === 1) {\n orig.call(\n console,\n `[interfere] console→OTel bridge emission failed (${bridgeFailures} total):`,\n error\n );\n }\n } finally {\n emitting = false;\n }\n }\n\n for (const method of CONSOLE_METHODS) {\n const orig = original[method];\n const severity = SEVERITY[method];\n console[method] = (...args: unknown[]) => {\n orig.apply(console, args);\n\n const body = args.map(stringify).join(\" \");\n const activeContext = context.active();\n const activeSpan = trace.getSpan(activeContext);\n const attributes = buildExceptionAttributes(args);\n\n queueMicrotask(() => {\n emitLog(\n orig,\n severity,\n method,\n body,\n activeContext,\n activeSpan,\n attributes\n );\n });\n };\n }\n\n return () => {\n for (const method of CONSOLE_METHODS) {\n console[method] = original[method];\n }\n };\n}\n"],"mappings":"wFAGA,MAIM,gBAAkB,CAAC,QAAS,MAAO,OAAQ,OAAQ,OAAO,EAG1D,SAAkD,CACtD,MAAO,EACP,IAAK,EACL,KAAM,EACN,KAAM,GACN,MAAO,EACT,EASA,SAAS,UAAU,MAAwB,CACzC,GAAI,OAAO,OAAU,SACnB,OAAO,MAET,GAAI,iBAAiB,MACnB,OAAO,MAAM,OAAS,GAAG,MAAM,KAAK,IAAI,MAAM,UAEhD,GAAI,CACF,OAAO,KAAK,UAAU,KAAK,CAC7B,MAAQ,CACN,OAAO,OAAO,KAAK,CACrB,CACF,CAEA,SAAS,iBAAiB,KAAoC,CAC5D,IAAK,IAAM,OAAO,KAChB,GAAI,eAAe,MACjB,OAAO,GAIb,CAEA,SAAS,yBACP,KACoC,CACpC,IAAM,UAAY,iBAAiB,IAAI,EACvC,GAAI,CAAC,UACH,OAEF,IAAM,MAAgC,CACnC,iBAAsB,UAAU,KAChC,oBAAyB,UAAU,OACtC,EAIA,OAHI,UAAU,QACZ,MAAM,wBAA6B,UAAU,OAExC,KACT,CAqBA,SAAgB,qBAAkC,CAChD,IAAM,OAAS,KAAK,UAAU,yBAAyB,EACnD,SAAW,GACX,eAAiB,EAEf,SAAgE,CACpE,MAAO,QAAQ,MACf,IAAK,QAAQ,IACb,KAAM,QAAQ,KACd,KAAM,QAAQ,KACd,MAAO,QAAQ,KACjB,EAEA,SAAS,QACP,KACA,SACA,OACA,KACA,cACA,WACA,WACM,CACF,aAGJ,UAAW,GACX,GAAI,CACF,OAAO,KAAK,CACV,eAAgB,SAChB,aAAc,OAAO,YAAY,EACjC,KACA,GAAI,WAAa,CAAE,QAAS,aAAc,EAAI,CAAC,EAC/C,GAAI,WAAa,CAAE,UAAW,EAAI,CAAC,CACrC,CAAC,CACH,OAAS,MAAO,CACd,iBACI,eAAiB,KAAgC,GACnD,KAAK,KACH,QACA,oDAAoD,eAAe,UACnE,KACF,CAEJ,QAAU,CACR,SAAW,EACb,CApBW,CAqBb,CAEA,IAAK,IAAM,UAAU,gBAAiB,CACpC,IAAM,KAAO,SAAS,QAChB,SAAW,SAAS,QAC1B,QAAQ,SAAW,GAAG,OAAoB,CACxC,KAAK,MAAM,QAAS,IAAI,EAExB,IAAM,KAAO,KAAK,IAAI,SAAS,EAAE,KAAK,GAAG,EACnC,cAAgB,QAAQ,OAAO,EAC/B,WAAa,MAAM,QAAQ,aAAa,EACxC,WAAa,yBAAyB,IAAI,EAEhD,mBAAqB,CACnB,QACE,KACA,SACA,OACA,KACA,cACA,WACA,UACF,CACF,CAAC,CACH,CACF,CAEA,UAAa,CACX,IAAK,IAAM,UAAU,gBACnB,QAAQ,QAAU,SAAS,OAE/B,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"env.d.mts","names":[],"sources":["../../../src/internal/server/env.ts"],"mappings":";UAIiB,kBAAA;EAAA,SACN,MAAA;EAAA,SACA,WAAA;EAAA,SACA,eAAA;EAAA,SACA,SAAA;AAAA;;;;;AAAS;AAYpB;;;;iBAAgB,iBAAA;AAAA,iBAOA,sBAAA,IAA0B,kBAAkB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"env.mjs","names":[],"sources":["../../../src/internal/server/env.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\nimport { resolveEnvironment } from \"@interfere/types/sdk/runtime\";\n\nexport interface InterfereServerEnv {\n readonly apiUrl: string;\n readonly forceEnable: boolean;\n readonly nodeEnvironment: string;\n readonly publicKey: string | null;\n}\n\n/**\n * Server-side gate for the proxy handler, the `captureError` /\n * `onRequestError` helpers, and the OTel register path. Distinct\n * from the browser-side `isEnabledByEnvironment` (in\n * `@interfere/react/internal/kernel`) because the server has\n * different env conventions: a configured public key is the\n * opt-in for proxy/server runtimes in dev. Collector ingress remains the\n * authority on whether local / unknown / production events are allowed.\n */\nexport function isEnabledOnServer(): boolean {\n if (process.env[\"NODE_ENV\"] === \"production\") {\n return true;\n }\n return Boolean(process.env[\"INTERFERE_PUBLIC_KEY\"]);\n}\n\nexport function readInterfereServerEnv(): InterfereServerEnv {\n const nodeEnvironment = resolveEnvironment({ env: process.env });\n\n return {\n apiUrl: parseEnvValue(process.env[\"INTERFERE_API_URL\"]) ?? API_URL,\n forceEnable: Boolean(process.env[\"INTERFERE_FORCE_ENABLE\"]),\n nodeEnvironment,\n publicKey: parseEnvValue(process.env[\"INTERFERE_PUBLIC_KEY\"]),\n };\n}\n"],"mappings":"+JAoBA,SAAgB,mBAA6B,CAI3C,OAHI,QAAQ,IAAI,WAAgB,aACvB,GAEF,EAAQ,QAAQ,IAAI,oBAC7B,CAEA,SAAgB,wBAA6C,CAC3D,IAAM,gBAAkB,mBAAmB,CAAE,IAAK,QAAQ,GAAI,CAAC,EAE/D,MAAO,CACL,OAAQ,cAAc,QAAQ,IAAI,iBAAoB,GAAK,QAC3D,YAAa,EAAQ,QAAQ,IAAI,uBACjC,gBACA,UAAW,cAAc,QAAQ,IAAI,oBAAuB,CAC9D,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"instrumentation-options.d.mts","names":[],"sources":["../../../src/internal/server/instrumentation-options.ts"],"mappings":";;AAYA;;;;;;;;;;;UAAiB,4BAAA;;;;;;;EAOf,aAAA;;;;;;;EAOA,UAAA,aAAuB,MAAA;;;;;;;;EAQvB,oBAAA,aAAiC,MAAM;;;;;EAKvC,WAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"register.d.mts","names":[],"sources":["../../../src/internal/server/register.ts"],"mappings":";;;;;AA2EA;;;;;;;;AAEU;;;;;;;;;;;;;;iBAFY,QAAA,CACpB,IAAA,GAAM,4BAAA,GACL,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"register.mjs","names":[],"sources":["../../../src/internal/server/register.ts"],"sourcesContent":["import type { AttributeValue, Span } from \"@opentelemetry/api\";\nimport { metrics, propagation } from \"@opentelemetry/api\";\nimport { BaggageSpanProcessor } from \"@opentelemetry/baggage-span-processor\";\nimport { AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\";\nimport {\n CompositePropagator,\n W3CBaggagePropagator,\n W3CTraceContextPropagator,\n} from \"@opentelemetry/core\";\nimport { OTLPLogExporter } from \"@opentelemetry/exporter-logs-otlp-http\";\nimport {\n AggregationTemporalityPreference,\n OTLPMetricExporter,\n} from \"@opentelemetry/exporter-metrics-otlp-http\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport { registerInstrumentations } from \"@opentelemetry/instrumentation\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport {\n BatchLogRecordProcessor,\n LoggerProvider,\n} from \"@opentelemetry/sdk-logs\";\nimport {\n MeterProvider,\n PeriodicExportingMetricReader,\n} from \"@opentelemetry/sdk-metrics\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\n\nimport { PRODUCER_VERSION } from \"../../version.js\";\nimport { resolveReleaseSlug } from \"../release-slug.js\";\nimport { bridgeConsoleToOtel } from \"./console-bridge.js\";\nimport { readInterfereServerEnv } from \"./env.js\";\nimport type { ServerInstrumentationOptions } from \"./instrumentation-options.js\";\nimport { fetchAndCacheRemoteConfig } from \"./remote-config.js\";\nimport { withPublicKey } from \"./url.js\";\n\nconst DEFAULT_SERVICE_NAME = \"interfere-sdk-vite-server\";\nconst SERVICE_NAMESPACE = \"interfere\";\n\nlet registered = false;\n\nfunction matchesAny(url: string, patterns: (string | RegExp)[]): boolean {\n for (const pattern of patterns) {\n if (pattern instanceof RegExp ? pattern.test(url) : url.includes(pattern)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * One-line server-side bootstrap for Nitro / TanStack Start. Customer\n * Nitro server entry (or any server-only init module) becomes:\n *\n * ```ts\n * import { register } from \"@interfere/vite/server\";\n * await register();\n * ```\n *\n * Wires private `NodeTracerProvider` / `LoggerProvider` /\n * `MeterProvider` against the global slots, installs the\n * `console.*` → OTel bridge, and fetches the remote-config gate.\n *\n * Idempotent — repeat calls (e.g. HMR) short-circuit on the\n * module-scoped `registered` flag.\n *\n * Bails silently when `INTERFERE_PUBLIC_KEY` is unset so dev runs\n * without the SDK configured don't crash.\n *\n * Wired against the Node OTel SDK (`NodeTracerProvider`,\n * `AsyncLocalStorageContextManager`) — only ships into the Node\n * runtime. Cloudflare Workers / Deno presets need a separate edge\n * stub (Phase 5).\n */\nexport async function register(\n opts: ServerInstrumentationOptions = {}\n): Promise<void> {\n if (registered) {\n return;\n }\n\n const env = readInterfereServerEnv();\n if (!env.publicKey) {\n return;\n }\n\n const { slug: releaseSlug } = resolveReleaseSlug();\n if (!releaseSlug) {\n console.warn(\n \"[interfere] No commit SHA available; server spans will ship without `release.slug`. Set `INTERFERE_SOURCE_ID` (or any of `VERCEL_GIT_COMMIT_SHA`, `GITHUB_SHA`) on the runtime env.\"\n );\n }\n\n const sinkUrl = withPublicKey(`${env.apiUrl}/v2/sink`, env.publicKey);\n\n const ignoreUrls = [sinkUrl, ...(opts.ignoreUrls ?? [])];\n const propagateContextUrls = opts.propagateContextUrls ?? [];\n\n const exporterHeaders: Record<string, string> = {\n \"x-interfere-producer-version\": PRODUCER_VERSION,\n };\n\n const resourceAttributes: Record<string, AttributeValue> = {\n \"service.name\": opts.serviceName ?? DEFAULT_SERVICE_NAME,\n \"service.namespace\": SERVICE_NAMESPACE,\n \"deployment.environment.name\": env.nodeEnvironment,\n \"telemetry.sdk.language\": \"nodejs\",\n \"interfere.sdk.name\": \"@interfere/vite\",\n \"interfere.sdk.version\": PRODUCER_VERSION,\n ...(releaseSlug ? { \"release.slug\": releaseSlug } : {}),\n };\n\n const resource = resourceFromAttributes(resourceAttributes);\n\n const tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: [\n new BaggageSpanProcessor(() => true),\n new BatchSpanProcessor(\n new OTLPTraceExporter({ url: sinkUrl, headers: exporterHeaders })\n ),\n ],\n });\n\n if (propagation.fields().length === 0) {\n propagation.setGlobalPropagator(\n new CompositePropagator({\n propagators: [\n new W3CTraceContextPropagator(),\n new W3CBaggagePropagator(),\n ],\n })\n );\n }\n\n tracerProvider.register({\n contextManager: new AsyncLocalStorageContextManager().enable(),\n });\n\n const loggerProvider = new LoggerProvider({\n resource,\n processors: [\n new BatchLogRecordProcessor(\n new OTLPLogExporter({ url: sinkUrl, headers: exporterHeaders })\n ),\n ],\n });\n\n const { logs: logsApi } = await import(\"@opentelemetry/api-logs\");\n logsApi.setGlobalLoggerProvider(loggerProvider);\n\n const meterProvider = new MeterProvider({\n resource,\n readers: [\n new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({\n url: sinkUrl,\n headers: exporterHeaders,\n temporalityPreference: AggregationTemporalityPreference.DELTA,\n }),\n exportIntervalMillis: 30_000,\n }),\n ],\n });\n metrics.setGlobalMeterProvider(meterProvider);\n\n registerInstrumentations({\n tracerProvider,\n meterProvider,\n instrumentations: [\n new UndiciInstrumentation({\n ignoreRequestHook: (req: { origin: string; path: string }) => {\n const url = `${req.origin}${req.path}`;\n return matchesAny(url, ignoreUrls);\n },\n requestHook: (span: Span, req: { origin: string; path: string }) => {\n const url = `${req.origin}${req.path}`;\n if (matchesAny(url, propagateContextUrls)) {\n span.setAttribute(\"interfere.propagated\", true);\n }\n },\n }),\n ],\n });\n\n if (opts.consoleBridge !== false) {\n bridgeConsoleToOtel();\n }\n\n registered = true;\n\n await fetchAndCacheRemoteConfig();\n}\n"],"mappings":"qzCAwCA,IAAI,WAAa,GAEjB,SAAS,WAAW,IAAa,SAAwC,CACvE,IAAK,IAAM,WAAW,SACpB,GAAI,mBAAmB,OAAS,QAAQ,KAAK,GAAG,EAAI,IAAI,SAAS,OAAO,EACtE,MAAO,GAGX,MAAO,EACT,CA0BA,eAAsB,SACpB,KAAqC,CAAC,EACvB,CACf,GAAI,WACF,OAGF,IAAM,IAAM,uBAAuB,EACnC,GAAI,CAAC,IAAI,UACP,OAGF,GAAM,CAAE,KAAM,aAAgB,mBAAmB,EAC5C,aACH,QAAQ,KACN,qLACF,EAGF,IAAM,QAAU,cAAc,GAAG,IAAI,OAAO,UAAW,IAAI,SAAS,EAE9D,WAAa,CAAC,QAAS,GAAI,KAAK,YAAc,CAAC,CAAE,EACjD,qBAAuB,KAAK,sBAAwB,CAAC,EAErD,gBAA0C,CAC9C,+BAAgC,gBAClC,EAYM,SAAW,uBAAuB,CATtC,eAAgB,KAAK,aAAe,4BACpC,oBAAqB,YACrB,8BAA+B,IAAI,gBACnC,yBAA0B,SAC1B,qBAAsB,kBACtB,wBAAyB,iBACzB,GAAI,YAAc,CAAE,eAAgB,WAAY,EAAI,CAAC,CAGE,CAAC,EAEpD,eAAiB,IAAI,mBAAmB,CAC5C,SACA,eAAgB,CACd,IAAI,yBAA2B,EAAI,EACnC,IAAI,mBACF,IAAI,kBAAkB,CAAE,IAAK,QAAS,QAAS,eAAgB,CAAC,CAClE,CACF,CACF,CAAC,EAEG,YAAY,OAAO,EAAE,SAAW,GAClC,YAAY,oBACV,IAAI,oBAAoB,CACtB,YAAa,CACX,IAAI,0BACJ,IAAI,oBACN,CACF,CAAC,CACH,EAGF,eAAe,SAAS,CACtB,eAAgB,IAAI,gCAAgC,EAAE,OAAO,CAC/D,CAAC,EAED,IAAM,eAAiB,IAAI,eAAe,CACxC,SACA,WAAY,CACV,IAAI,wBACF,IAAI,gBAAgB,CAAE,IAAK,QAAS,QAAS,eAAgB,CAAC,CAChE,CACF,CACF,CAAC,EAEK,CAAE,KAAM,SAAY,MAAM,OAAO,2BACvC,QAAQ,wBAAwB,cAAc,EAE9C,IAAM,cAAgB,IAAI,cAAc,CACtC,SACA,QAAS,CACP,IAAI,8BAA8B,CAChC,SAAU,IAAI,mBAAmB,CAC/B,IAAK,QACL,QAAS,gBACT,sBAAuB,iCAAiC,KAC1D,CAAC,EACD,qBAAsB,GACxB,CAAC,CACH,CACF,CAAC,EACD,QAAQ,uBAAuB,aAAa,EAE5C,yBAAyB,CACvB,eACA,cACA,iBAAkB,CAChB,IAAI,sBAAsB,CACxB,kBAAoB,KAEX,WAAW,GADH,IAAI,SAAS,IAAI,OACT,UAAU,EAEnC,aAAc,KAAY,MAA0C,CAE9D,WAAW,GADA,IAAI,SAAS,IAAI,OACZ,oBAAoB,GACtC,KAAK,aAAa,uBAAwB,EAAI,CAElD,CACF,CAAC,CACH,CACF,CAAC,EAEG,KAAK,gBAAkB,IACzB,oBAAoB,EAGtB,WAAa,GAEb,MAAM,0BAA0B,CAClC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"remote-config.d.mts","names":[],"sources":["../../../src/internal/server/remote-config.ts"],"mappings":";iBAWsB,yBAAA,IAA6B,OAAO;AAAA,iBAoC1C,eAAA,CAAgB,MAAc"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"remote-config.mjs","names":[],"sources":["../../../src/internal/server/remote-config.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport type {\n RemoteConfig,\n RemotePluginConfig,\n} from \"@interfere/types/sdk/remote-config\";\n\nimport { isEnabledOnServer, readInterfereServerEnv } from \"./env.js\";\nimport { withPublicKey } from \"./url.js\";\n\nlet cachedConfig: RemotePluginConfig | null = null;\n\nexport async function fetchAndCacheRemoteConfig(): Promise<void> {\n if (!isEnabledOnServer()) {\n return;\n }\n\n const env = readInterfereServerEnv();\n if (env.publicKey === null) {\n return;\n }\n\n try {\n const url = withPublicKey(\n `${env.apiUrl}${API_PATHS.CONFIG}`,\n env.publicKey\n );\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"content-type\": \"application/json\",\n },\n signal: AbortSignal.timeout(10_000),\n });\n\n if (!response.ok) {\n return;\n }\n\n const config = (await response.json()) as RemoteConfig;\n if (config?.plugins) {\n cachedConfig = config.plugins;\n }\n } catch {\n return;\n }\n}\n\nexport function isPluginEnabled(plugin: string): boolean {\n if (!cachedConfig) {\n return true;\n }\n return cachedConfig[plugin as keyof RemotePluginConfig] !== false;\n}\n"],"mappings":"qJASA,IAAI,aAA0C,KAE9C,eAAsB,2BAA2C,CAC/D,GAAI,CAAC,kBAAkB,EACrB,OAGF,IAAM,IAAM,uBAAuB,EAC/B,OAAI,YAAc,KAItB,GAAI,CACF,IAAM,IAAM,cACV,GAAG,IAAI,SAAS,UAAU,SAC1B,IAAI,SACN,EACM,SAAW,MAAM,MAAM,IAAK,CAChC,OAAQ,MACR,QAAS,CACP,eAAgB,kBAClB,EACA,OAAQ,YAAY,QAAQ,GAAM,CACpC,CAAC,EAED,GAAI,CAAC,SAAS,GACZ,OAGF,IAAM,OAAU,MAAM,SAAS,KAAK,EAChC,QAAQ,UACV,aAAe,OAAO,QAE1B,MAAQ,CACN,MACF,CACF,CAEA,SAAgB,gBAAgB,OAAyB,CAIvD,OAHK,aAGE,aAAa,UAAwC,GAFnD,EAGX"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"trace-meta.d.mts","names":[],"sources":["../../../src/internal/server/trace-meta.tsx"],"mappings":";;AAgCA;;;;AAAyB;;;;;;;;;;;;;;;;;;;;;;;;;iBAAT,SAAA,gCAAS,GAAA,CAAA,OAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"trace-meta.mjs","names":[],"sources":["../../../src/internal/server/trace-meta.tsx"],"sourcesContent":["import { activeTraceparent } from \"./traceparent.js\";\n\n/**\n * Server Component that emits a `<meta name=\"traceparent\">` tag so\n * the client SDK can stitch every browser span onto the server-side\n * trace.\n *\n * Customer usage — drop into the root layout's `<head>` (TanStack\n * Start uses the `head()` route option, but the meta tag also works\n * if rendered into the React tree):\n *\n * ```tsx\n * import { TraceMeta } from \"@interfere/vite/server\";\n *\n * function RootComponent() {\n * return (\n * <html>\n * <head>\n * <TraceMeta />\n * </head>\n * <body>...</body>\n * </html>\n * );\n * }\n * ```\n *\n * Renders nothing when no OTel span is active (dev without OTel\n * registered, or unsampled traces). The client SDK's propagation\n * reader handles a missing meta tag the same as no parent — every\n * browser span starts a fresh root, which is at least internally\n * consistent.\n */\nexport function TraceMeta() {\n const traceparent = activeTraceparent();\n if (!traceparent) {\n return null;\n }\n return <meta content={traceparent} name=\"traceparent\" />;\n}\n"],"mappings":"oFAgCA,SAAgB,WAAY,CAC1B,IAAM,YAAc,kBAAkB,EAItC,OAHK,YAGE,IAAC,OAAD,CAAM,QAAS,YAAa,KAAK,aAAe,CAAA,EAF9C,IAGX"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"traceparent.d.mts","names":[],"sources":["../../../src/internal/server/traceparent.ts"],"mappings":";;AAkBA;;;;AAAiC;;;;;;;;iBAAjB,iBAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"traceparent.mjs","names":[],"sources":["../../../src/internal/server/traceparent.ts"],"sourcesContent":["import { TraceFlags, trace } from \"@opentelemetry/api\";\n\nconst SAMPLED_BIT = TraceFlags.SAMPLED;\nconst W3C_TRACECONTEXT_VERSION = \"00\";\n\n/**\n * Build a W3C `traceparent` string from the currently-active OTel\n * span, or `null` if no span is active or the trace is not sampled.\n *\n * Server-side counterpart to the client SDK's\n * `internal/otel/propagation.ts`: both ends of the wire filter\n * unsampled traces. The browser doesn't honor the `sampled` bit\n * when creating child spans, so propagating an unsampled trace_id\n * from the server would orphan every browser span under a trace\n * with no recorded server segments. Returning null lets the\n * browser fall back to its own root, which is at least internally\n * consistent.\n */\nexport function activeTraceparent(): string | null {\n const span = trace.getActiveSpan();\n if (!span) {\n return null;\n }\n const ctx = span.spanContext();\n // biome-ignore lint/suspicious/noBitwiseOperators: W3C trace_flags is a bitmask; SAMPLED (0x01) must be tested independently of any future reserved flags.\n if ((ctx.traceFlags & SAMPLED_BIT) !== SAMPLED_BIT) {\n return null;\n }\n const flags = ctx.traceFlags.toString(16).padStart(2, \"0\");\n return `${W3C_TRACECONTEXT_VERSION}-${ctx.traceId}-${ctx.spanId}-${flags}`;\n}\n"],"mappings":"iDAEA,MAAM,YAAc,WAAW,QAgB/B,SAAgB,mBAAmC,CACjD,IAAM,KAAO,MAAM,cAAc,EACjC,GAAI,CAAC,KACH,OAAO,KAET,IAAM,IAAM,KAAK,YAAY,EAE7B,IAAK,IAAI,WAAa,eAAiB,YACrC,OAAO,KAET,IAAM,MAAQ,IAAI,WAAW,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,EACzD,MAAO,MAA+B,IAAI,QAAQ,GAAG,IAAI,OAAO,GAAG,OACrE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/internal/server/types.ts"],"mappings":";;;UAEiB,mBAAA;EAAA,SACN,SAAA,GAAY,cAAc;EADpB;;;;;EAAA,SAON,OAAA;IACP,MAAA;IACA,IAAA;EAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"url.d.mts","names":[],"sources":["../../../src/internal/server/url.ts"],"mappings":";iBAEgB,aAAA,CAAc,GAAA,UAAa,SAAiB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"url.mjs","names":[],"sources":["../../../src/internal/server/url.ts"],"sourcesContent":["const PUBLIC_KEY_QUERY = \"pk\";\n\nexport function withPublicKey(url: string, publicKey: string): string {\n const next = new URL(url);\n next.searchParams.set(PUBLIC_KEY_QUERY, publicKey);\n return next.toString();\n}\n"],"mappings":"AAEA,SAAgB,cAAc,IAAa,UAA2B,CACpE,IAAM,KAAO,IAAI,IAAI,GAAG,EAExB,OADA,KAAK,aAAa,IAAI,KAAkB,SAAS,EAC1C,KAAK,SAAS,CACvB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"package.mjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin.d.mts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;KAwBY,iBAAA;AAAA,UAEK,oBAAA;EAFL;;;;AAAiB;AAE7B;EAOE,SAAA;;;;;;;;AA0BU;AAsWZ;;;;;;;;AAAqE;EA9WnE,IAAA,GAAO,iBAAiB;;;;;;;;EAQxB,UAAA;AAAA;AAAA,iBAsWc,SAAA,CAAU,OAAA,GAAS,oBAAA,GAA4B,MAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin.mjs","names":["resolvePath"],"sources":["../src/plugin.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport {\n deriveReleaseSlug,\n type ReleaseSlug,\n} from \"@interfere/types/releases/slug\";\n\nimport { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join, resolve as resolvePath } from \"node:path\";\nimport {\n type HtmlTagDescriptor,\n type Logger,\n loadEnv,\n type Plugin,\n type ResolvedConfig,\n} from \"vite\";\n\nimport {\n createSdkClient,\n runReleasePipeline,\n} from \"./internal/build/pipeline.js\";\nimport { discoverByPairing } from \"./internal/build/source-maps.js\";\nimport { resolveCommitSha } from \"./internal/release-slug.js\";\nimport { PRODUCER_VERSION } from \"./version.js\";\n\nexport type InterfereViteMode = \"auto\" | \"direct\" | \"proxy\";\n\nexport interface InterfereViteOptions {\n /**\n * Override the commit SHA used to derive the release slug. Defaults\n * to `VITE_INTERFERE_COMMIT_SHA` env then `git rev-parse HEAD`.\n * Set this when the build runs outside a git checkout (e.g. a\n * Docker layer-cached image build).\n */\n commitSha?: string;\n /**\n * How the runtime SDK should reach the collector.\n *\n * - `\"auto\"` (default) — detect from the surrounding plugin set:\n * if `tanstack-start` / `nitro` is present, choose\n * `\"proxy\"`; otherwise `\"direct\"`.\n * - `\"direct\"` — stamp `__INTERFERE_PUBLIC_KEY__` into the bundle\n * so the kernel posts ingest at the configured collector URL\n * directly (`in.interfere.com/v2/sink`). The only option for\n * vanilla Vite SPAs.\n * - `\"proxy\"` — stamp the public key and force the kernel to post\n * ingest at `/api/interfere/*`. The server-side handler forwards\n * requests through as a first-party collector proxy. Strongly\n * preferred for any deployment with a server origin because adblock filter\n * lists target the collector hostname more aggressively than\n * first-party paths.\n */\n mode?: InterfereViteMode;\n /**\n * `false` skips the post-build release metadata pipeline. Defaults\n * to enabled when an `INTERFERE_API_KEY` is set; defaults to\n * disabled when one isn't (so dev runs without creds don't fail).\n * Useful when source maps are uploaded out-of-band via the\n * `@interfere/cli`.\n */\n sourceMaps?: boolean;\n}\n\nconst SERVER_RUNTIME_PLUGIN_HINTS = [\n \"tanstack-start\",\n \"nitro\",\n \"@tanstack/react-start\",\n] as const;\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n if (!value) {\n return false;\n }\n const normalized = value.trim().toLowerCase();\n return normalized === \"1\" || normalized === \"true\";\n}\n\nfunction isTestEnv(): boolean {\n return Boolean(process.env[\"VITEST\"] || process.env[\"VITEST_WORKER_ID\"]);\n}\n\n/**\n * Fail the build with a Next-style error block when the public key\n * env var is absent during a production build. Skipped\n * in dev (`vite serve`) and in\n * test runs (so plugin-level tests can exercise the configuration\n * surface without crashing the test process).\n */\nfunction failMissingPublicKey(): never {\n const lines = [\n \"interfere() requires VITE_INTERFERE_PUBLIC_KEY to identify your project at runtime.\",\n \"Set the VITE_INTERFERE_PUBLIC_KEY environment variable, or remove interfere() from your Vite config.\",\n \"See: https://support.interfere.com/docs/guides/vite\",\n ];\n if (isTestEnv()) {\n throw new Error(`Interfere: Public key not set\\n${lines.join(\"\\n\")}`);\n }\n console.error(\"\\n⨯ Interfere → Public key not set\");\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i];\n if (!line) {\n continue;\n }\n const connector = i === lines.length - 1 ? \"└\" : \"├\";\n console.error(` ${connector} ${line}`);\n }\n process.exit(1);\n}\n\nfunction detectServerRuntime(config: ResolvedConfig): boolean {\n return config.plugins.some((p) =>\n SERVER_RUNTIME_PLUGIN_HINTS.some((hint) => p.name?.includes(hint))\n );\n}\n\nfunction resolveMode(\n optsMode: InterfereViteMode | undefined,\n config: ResolvedConfig,\n logger: Logger\n): \"direct\" | \"proxy\" {\n const requested = optsMode ?? \"auto\";\n if (requested !== \"auto\") {\n logger.info(`[interfere] mode=${requested} (explicit)`);\n return requested;\n }\n const detected = detectServerRuntime(config) ? \"proxy\" : \"direct\";\n logger.info(\n `[interfere] mode=${detected} (auto-detected). Override with \\`interfere({ mode: \"...\" })\\`.`\n );\n return detected;\n}\n\ninterface PluginState {\n apiKey: string | undefined;\n apiUrl: string;\n /**\n * The runtime collector URL stamped onto `__INTERFERE_API_URL__`\n * for the browser kernel. Distinct from `apiUrl` (server-side\n * env, used by the build pipeline) — direct-mode customers\n * pointing at a regional collector / self-hosted gateway /\n * localhost need to set `VITE_INTERFERE_API_URL` separately so\n * the browser bundle's destination matches the server-side one.\n * `undefined` in proxy mode and when the env is unset (kernel\n * falls through to the compiled-in `API_URL`).\n */\n browserApiUrl: string | undefined;\n buildStartedAt: number;\n commitSha: string | null;\n enableUpload: boolean;\n forceEnable: boolean;\n logger: Logger;\n mode: \"direct\" | \"proxy\";\n projectDir: string;\n publicKey: string | undefined;\n releaseSlug: ReleaseSlug | null;\n uploadOutDir: string;\n uploadStarted: boolean;\n}\n\ntype UploadReadyPluginState = PluginState & {\n apiKey: string;\n commitSha: string;\n releaseSlug: ReleaseSlug;\n};\n\nfunction hasFreshServerSourceMaps(root: string, sinceMs: number): boolean {\n if (!existsSync(root)) {\n return false;\n }\n const entries = readdirSync(root, { withFileTypes: true });\n for (const entry of entries) {\n const absolute = join(root, entry.name);\n if (entry.isDirectory()) {\n if (hasFreshServerSourceMaps(absolute, sinceMs)) {\n return true;\n }\n continue;\n }\n if (!entry.name.endsWith(\".map\")) {\n continue;\n }\n if (statSync(absolute).mtimeMs >= sinceMs) {\n return true;\n }\n }\n return false;\n}\n\nfunction isUploadReady(state: PluginState): state is UploadReadyPluginState {\n return Boolean(\n state.enableUpload &&\n state.apiKey &&\n state.releaseSlug &&\n state.commitSha &&\n !state.uploadStarted\n );\n}\n\nfunction shouldWaitForServerOutput(state: UploadReadyPluginState): boolean {\n return (\n state.mode === \"proxy\" &&\n !hasFreshServerSourceMaps(\n join(state.uploadOutDir, \"server\"),\n state.buildStartedAt\n )\n );\n}\n\ntype ReleasePipelineFailure = Extract<\n Awaited<ReturnType<typeof runReleasePipeline>>,\n { ok: false }\n>[\"failure\"];\ntype ReleasePipelineSuccess = Extract<\n Awaited<ReturnType<typeof runReleasePipeline>>,\n { ok: true }\n>;\n\nfunction logSkippedRelease(\n logger: Logger,\n failure: ReleasePipelineFailure\n): void {\n if (failure.kind === \"missing_source_provider\") {\n logger.warn(\n `[interfere] release skipped: this surface has no version control provider configured. Configure one at https://interfere.com/~/${failure.config.org.slug}/surfaces/${failure.config.surface.slug}.`\n );\n return;\n }\n logger.warn(\n `[interfere] release skipped: this surface has no deployment target configured. Configure one at https://interfere.com/~/${failure.config.org.slug}/surfaces/${failure.config.surface.slug}.`\n );\n}\n\nfunction logCleanupFailures(\n logger: Logger,\n failures: ReleasePipelineSuccess[\"data\"][\"cleanupFailures\"]\n): void {\n for (const failure of failures) {\n logger.warn(\n `[interfere] cleanup left ${failure.absolute} on disk: ${failure.code ?? failure.message}`\n );\n }\n}\n\nasync function uploadSourceMaps(state: UploadReadyPluginState): Promise<void> {\n const {\n apiKey,\n apiUrl,\n releaseSlug,\n commitSha,\n logger,\n projectDir,\n uploadOutDir,\n } = state;\n\n logger.info(`[interfere] uploading source maps for release ${releaseSlug}…`);\n\n try {\n const { sdk, security } = createSdkClient({ apiKey, apiUrl });\n\n const [discovered, releasesConfig] = await Promise.all([\n discoverByPairing({\n projectDir,\n distDir: uploadOutDir,\n\n subtrees: [\".\"],\n\n publicPathRewrites: [{ from: \"public\", to: \"\" }],\n }),\n sdk.releases.getConfig(security),\n ]);\n\n if (discovered.files.length === 0) {\n logger.info(\"[interfere] no source maps found, skipping upload.\");\n return;\n }\n\n const result = await runReleasePipeline({\n apiKey,\n apiUrl,\n bundler: \"rollup\",\n buildId: commitSha,\n discovery: discovered,\n producerVersion: PRODUCER_VERSION,\n releasesConfig,\n releaseSlug,\n });\n\n if (!result.ok) {\n logSkippedRelease(logger, result.failure);\n return;\n }\n\n logCleanupFailures(logger, result.data.cleanupFailures);\n logger.info(\n `[interfere] release ${result.data.releaseSlug} confirmed — ${result.data.fileCount} maps, ${result.data.timing.total}ms.`\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logger.warn(\n `[interfere] release pipeline failed: ${message}. Build continues; events from this release will ingest but be ignored as evidence.`\n );\n }\n}\n\nasync function uploadSourceMapsWhenReady(state: PluginState): Promise<void> {\n if (!isUploadReady(state)) {\n return;\n }\n if (shouldWaitForServerOutput(state)) {\n state.logger.info(\n \"[interfere] waiting for Nitro server output before uploading source maps.\"\n );\n return;\n }\n state.uploadStarted = true;\n await uploadSourceMaps(state);\n}\n\nfunction emitSetupWarnings(\n state: Pick<PluginState, \"apiKey\" | \"logger\" | \"mode\" | \"releaseSlug\"> & {\n isProductionBuild: boolean;\n publicKeyPresent: boolean;\n sourceMapsExplicit: boolean | undefined;\n }\n): void {\n const {\n logger,\n mode,\n publicKeyPresent,\n apiKey,\n releaseSlug,\n sourceMapsExplicit,\n isProductionBuild,\n } = state;\n\n if (mode === \"proxy\" && publicKeyPresent) {\n logger.info(\n \"[interfere] mode=proxy: using VITE_INTERFERE_PUBLIC_KEY with the first-party proxy route.\"\n );\n }\n if (sourceMapsExplicit !== false && apiKey && !releaseSlug) {\n logger.warn(\n \"[interfere] No commit SHA available. Release metadata publishing is disabled. Set INTERFERE_SOURCE_ID, expose VERCEL_GIT_COMMIT_SHA / GITHUB_SHA, or run inside a git checkout.\"\n );\n }\n if (isProductionBuild && sourceMapsExplicit !== false && !apiKey) {\n logger.warn(\n \"[interfere] INTERFERE_API_KEY is not set. Release metadata will not be published. Create an Interfere API key in the dashboard and set it in your build environment, or pass `interfere({ sourceMaps: false })` to suppress this warning if release metadata is intentionally handled out-of-band.\"\n );\n }\n}\n\nfunction buildPluginState(\n options: InterfereViteOptions,\n config: ResolvedConfig\n): PluginState {\n const logger = config.logger;\n const mode = resolveMode(options.mode, config, logger);\n const publicKey = config.env[\"VITE_INTERFERE_PUBLIC_KEY\"];\n\n if (config.command === \"build\" && !publicKey) {\n failMissingPublicKey();\n }\n\n const explicitSha =\n options.commitSha ?? config.env[\"VITE_INTERFERE_COMMIT_SHA\"];\n const commitSha = explicitSha ?? resolveCommitSha();\n const releaseSlug = commitSha ? deriveReleaseSlug(commitSha) : null;\n\n const fileEnv = loadEnv(config.mode, config.envDir, \"\");\n const pickEnv = (key: string): string | undefined => {\n const shell = process.env[key];\n if (shell && shell.length > 0) {\n return shell;\n }\n const file = fileEnv[key];\n return file && file.length > 0 ? file : undefined;\n };\n const apiKey = pickEnv(\"INTERFERE_API_KEY\");\n const apiUrl = pickEnv(\"INTERFERE_API_URL\") ?? API_URL;\n const enableUpload =\n options.sourceMaps ??\n (apiKey !== undefined && apiKey.length > 0 && releaseSlug !== null);\n\n const rawBrowserApiUrl = config.env[\"VITE_INTERFERE_API_URL\"];\n const browserApiUrl =\n rawBrowserApiUrl && rawBrowserApiUrl.length > 0\n ? rawBrowserApiUrl\n : undefined;\n\n emitSetupWarnings({\n apiKey,\n isProductionBuild: config.command === \"build\",\n logger,\n mode,\n publicKeyPresent: Boolean(publicKey),\n releaseSlug,\n sourceMapsExplicit: options.sourceMaps,\n });\n\n return {\n apiKey,\n apiUrl,\n browserApiUrl: mode === \"direct\" ? browserApiUrl : undefined,\n commitSha,\n enableUpload,\n forceEnable: isTruthyEnvFlag(config.env[\"VITE_INTERFERE_FORCE_ENABLE\"]),\n logger,\n mode,\n projectDir: config.root,\n publicKey,\n releaseSlug,\n uploadOutDir: resolvePath(config.root, config.build.outDir),\n uploadStarted: false,\n buildStartedAt: Date.now(),\n };\n}\n\nexport function interfere(options: InterfereViteOptions = {}): Plugin {\n let state: PluginState | null = null;\n\n return {\n name: \"interfere\",\n enforce: \"pre\",\n\n configResolved(config) {\n const next = buildPluginState(options, config);\n if (state?.mode === \"proxy\" && next.mode === \"proxy\") {\n next.uploadOutDir = state.uploadOutDir;\n next.uploadStarted = state.uploadStarted;\n next.buildStartedAt = state.buildStartedAt;\n }\n state = next;\n },\n\n transformIndexHtml() {\n const assignments: string[] = [];\n if (state?.releaseSlug) {\n assignments.push(\n `globalThis[\"__INTERFERE_RELEASE_SLUG__\"]=${JSON.stringify(state.releaseSlug)};`\n );\n }\n if (state?.publicKey) {\n assignments.push(\n `globalThis[\"__INTERFERE_PUBLIC_KEY__\"]=${JSON.stringify(state.publicKey)};`\n );\n }\n if (state?.forceEnable) {\n assignments.push('globalThis[\"__INTERFERE_FORCE_ENABLE__\"]=true;');\n }\n if (state?.mode === \"proxy\" && state.publicKey) {\n assignments.push('globalThis[\"__INTERFERE_PROXY_MODE__\"]=true;');\n }\n if (state?.mode === \"direct\" && state.browserApiUrl) {\n assignments.push(\n `globalThis[\"__INTERFERE_API_URL__\"]=${JSON.stringify(state.browserApiUrl)};`\n );\n }\n\n if (assignments.length === 0) {\n return [];\n }\n\n return [\n {\n tag: \"script\",\n children: assignments.join(\"\"),\n injectTo: \"head-prepend\",\n },\n ] satisfies HtmlTagDescriptor[];\n },\n\n async closeBundle() {\n if (!state) {\n return;\n }\n await uploadSourceMapsWhenReady(state);\n },\n };\n}\n\nexport default interfere;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider.d.mts","names":[],"sources":["../src/provider.tsx"],"mappings":";;;;;UAaU,sBAAA,SAA+B,iBAAiB;EACxD,OAAA,GAAU,cAAA;EACV,aAAA;AAAA;;;;;iBAOc,iBAAA;EACd,QAAA;EACA,OAAA;EACA;AAAA,GACC,sBAAA,GAAyB,SAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider.mjs","names":["CoreInterfereProvider"],"sources":["../src/provider.tsx"],"sourcesContent":["import { InterfereProvider as CoreInterfereProvider } from \"@interfere/react/provider\";\nimport type { ConsentState } from \"@interfere/types/sdk/plugins/manifest\";\n\nimport {\n type PropsWithChildren,\n type ReactNode,\n useSyncExternalStore,\n} from \"react\";\n\nimport { getKernelOrNull, subscribeToKernel } from \"./init.js\";\n\nconst nullSnapshot = () => null;\n\ninterface InterfereProviderProps extends PropsWithChildren {\n consent?: ConsentState | undefined;\n errorBoundary?: boolean;\n}\n\n/**\n * Vite wrapper around `@interfere/react`'s provider that reads the\n * kernel created by `@interfere/vite/init`.\n */\nexport function InterfereProvider({\n children,\n consent,\n errorBoundary,\n}: InterfereProviderProps): ReactNode {\n const kernel = useSyncExternalStore(\n subscribeToKernel,\n getKernelOrNull,\n nullSnapshot\n );\n return (\n <CoreInterfereProvider\n kernel={kernel}\n {...(consent === undefined ? {} : { consent })}\n {...(errorBoundary === undefined ? {} : { errorBoundary })}\n >\n {children}\n </CoreInterfereProvider>\n );\n}\n\n// biome-ignore lint/performance/noBarrelFile: Vite provider entrypoint re-exports the React SDK hooks for one-line customer setup.\nexport { useInterfere, useSession } from \"@interfere/react/provider\";\nexport type {\n ConsentCategory,\n ConsentState,\n GateableCategory,\n} from \"@interfere/types/sdk/plugins/manifest\";\n"],"mappings":"6OAWA,MAAM,iBAAqB,KAW3B,SAAgB,kBAAkB,CAChC,SACA,QACA,eACoC,CAMpC,OACE,IAACA,oBAAD,CACE,OAPW,qBACb,kBACA,gBACA,YAIe,EACb,GAAK,UAAY,IAAA,GAAY,CAAC,EAAI,CAAE,OAAQ,EAC5C,GAAK,gBAAkB,IAAA,GAAY,CAAC,EAAI,CAAE,aAAc,EAEvD,QACoB,CAAA,CAE3B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"version.d.mts","names":[],"sources":["../src/version.ts"],"mappings":";cAEa,gBAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"version.mjs","names":["pkg.name","pkg.version"],"sources":["../src/version.ts"],"sourcesContent":["import pkg from \"../package.json\" with { type: \"json\" };\n\nexport const PRODUCER_VERSION = `${pkg.name}@${pkg.version}`;\n"],"mappings":"wCAEA,MAAa,iBAAmB,GAAGA,KAAS,GAAGC"}