@sailfish-ai/sf-veritas 0.2.21 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +53 -0
  2. package/dist/consoleLocationTransformer-BSSB5msZ.cjs +1 -0
  3. package/dist/consoleLocationTransformer-DZu_9MDA.js +51 -0
  4. package/dist/contextManager-BsolAr_q.cjs +1 -0
  5. package/dist/{contextManager-RxrMXs5c.js → contextManager-D2ijKL-E.js} +105 -102
  6. package/dist/plugins/funcspanEsbuildPlugin.cjs +1 -1
  7. package/dist/plugins/funcspanEsbuildPlugin.mjs +20 -16
  8. package/dist/plugins/funcspanRollupPlugin.cjs +1 -1
  9. package/dist/plugins/funcspanRollupPlugin.mjs +17 -13
  10. package/dist/plugins/funcspanTscPlugin.cjs +1 -1
  11. package/dist/plugins/funcspanTscPlugin.mjs +34 -30
  12. package/dist/plugins/funcspanVitePlugin.cjs +1 -1
  13. package/dist/plugins/funcspanVitePlugin.mjs +16 -12
  14. package/dist/plugins/funcspanWebpackLoader.cjs +1 -1
  15. package/dist/plugins/funcspanWebpackLoader.mjs +55 -50
  16. package/dist/plugins/funcspanWebpackPlugin.cjs +1 -1
  17. package/dist/plugins/funcspanWebpackPlugin.mjs +1 -1
  18. package/dist/runtimeConfig-C4mv7SVM.js +484 -0
  19. package/dist/runtimeConfig-XIm4yAFB.cjs +6 -0
  20. package/dist/sf-veritas.cjs +13 -13
  21. package/dist/sf-veritas.mjs +532 -388
  22. package/dist/telemetryWorker.cjs +1 -0
  23. package/dist/types/dataTransmitter.d.ts +6 -5
  24. package/dist/types/exceptionTransmitter.d.ts +2 -1
  25. package/dist/types/networkHopTransmitter.d.ts +2 -1
  26. package/dist/types/networkRequestTransmitter.d.ts +2 -1
  27. package/dist/types/plugins/consoleLocationTransformer.d.ts +37 -0
  28. package/dist/types/requestTransmitter.d.ts +45 -0
  29. package/dist/types/requestUtils.d.ts +17 -6
  30. package/dist/types/setupConfig.d.ts +21 -0
  31. package/dist/types/sourceLocation.d.ts +19 -19
  32. package/dist/types/telemetryWorker.d.ts +1 -0
  33. package/dist/worker-pool-capture.cjs +1 -1
  34. package/dist/worker-pool-capture.mjs +1 -1
  35. package/dist/workerPoolSpanCapture-DzCJnMDA.cjs +83 -0
  36. package/dist/{workerPoolSpanCapture-DVYmzgbN.js → workerPoolSpanCapture-hyxgVqUF.js} +222 -168
  37. package/package.json +17 -1
  38. package/dist/contextManager-0D8uHQ1_.cjs +0 -1
  39. package/dist/runtimeConfig-CB57auSb.js +0 -444
  40. package/dist/runtimeConfig-sm_7bnKx.cjs +0 -9
  41. package/dist/workerPoolSpanCapture-DFnbcpkU.cjs +0 -83
@@ -0,0 +1 @@
1
+ "use strict";const a=require("worker_threads");if(!a.parentPort)throw new Error("telemetryWorker must run as a Worker thread");const p=process.env.SF_FLUSH_TELEMETRY_IN_BATCH==="1",u=parseInt(process.env.SF_BATCH_FLUSH_INTERVAL_MS||"50",10),_=parseInt(process.env.SF_NBPOST_BATCH_MAX||"50",10),h=parseInt(process.env.SF_WORKER_MAX_CONCURRENT||"10",10);let o=[],f=0,r=[];function l(n,s){if(f>=h)return r.length>=1e4&&r.shift(),void r.push({url:n,item:s});f++,fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}).catch(()=>{}).finally(()=>{for(f--;r.length>0&&f<h;){const t=r.shift();l(t.url,t.item)}})}function i(){if(o.length===0)return;const n=o;o=[];const s=new Map;for(const t of n){let e=s.get(t.url);e||(e=[],s.set(t.url,e)),e.push(t.item)}if(p)for(const[t,e]of s){const c=e.length===1?JSON.stringify(e[0]):JSON.stringify(e);fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:c}).catch(()=>{})}else for(const[t,e]of s)for(const c of e)l(t,c)}setInterval(i,u).unref(),a.parentPort.on("message",n=>{if(n!=="flush"){if("batch"in n)for(const s of n.batch)o.push(s);else o.push(n);o.length>=_&&i()}else i()});
@@ -9,14 +9,15 @@ export declare class DataTransmitter extends BaseTransmitter {
9
9
  * Constructor for DataTransmitter.
10
10
  */
11
11
  constructor();
12
+ private identifyStarted;
12
13
  /**
13
- * Sends the application identifier by invoking the serviceIdentifier.
14
- * This function ensures the app identifier is sent before any other data.
14
+ * Start a background task that sends IdentifyServiceDetails and retries
15
+ * every 5 seconds until the backend confirms receipt.
16
+ * This runs OFF the hot path — doSend() never blocks on it.
15
17
  */
16
- sendAppIdentifier(): Promise<void>;
18
+ startBackgroundIdentify(): void;
17
19
  /**
18
- * Main method to send data.
19
- * This first sends the application identifier and then sends the actual content.
20
+ * Main method to send data. Hot path — no IdentifyServiceDetails here.
20
21
  * @param args - The arguments to be sent, including contents and level.
21
22
  */
22
23
  doSend(args: any): Promise<void>;
@@ -34,7 +34,8 @@ export declare class ExceptionTransmitter extends BaseTransmitter {
34
34
  * Sends the application identifier to the server to associate the exception
35
35
  * data with the application.
36
36
  */
37
- sendAppIdentifier(): Promise<void>;
37
+ private identifyStarted;
38
+ startBackgroundIdentify(): void;
38
39
  /**
39
40
  * Primary method to send exception data. It triggers the process of sending
40
41
  * the application identifier and exception details (message and stack trace).
@@ -32,7 +32,8 @@ export declare class NetworkHopTransmitter extends BaseTransmitter {
32
32
  * it delegates to the ServiceIdentifier's doSend method, which may include
33
33
  * any app-specific logic or fields needed by the server.
34
34
  */
35
- sendAppIdentifier(): Promise<void>;
35
+ private identifyStarted;
36
+ startBackgroundIdentify(): void;
36
37
  /**
37
38
  * A convenience method that first sends the app identifier,
38
39
  * then sends the detailed network hops data.
@@ -22,7 +22,8 @@ export interface NetworkRequestData {
22
22
  export declare class NetworkRequestTransmitter extends BaseTransmitter {
23
23
  private serviceIdentifier;
24
24
  constructor();
25
- sendAppIdentifier(): Promise<void>;
25
+ private identifyStarted;
26
+ startBackgroundIdentify(): void;
26
27
  doSend(data: NetworkRequestData): Promise<void>;
27
28
  private getQuery;
28
29
  private send;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Console Location AST Transformer
3
+ *
4
+ * Transforms console.log/error/warn/info/debug calls to append a
5
+ * "__sf:relative/path.ts:42" sentinel as the last argument.
6
+ *
7
+ * At runtime, the SDK's logHandler detects this sentinel and uses it
8
+ * as the source location (Tier 1: 0µs), skipping V8 stack capture.
9
+ * The sentinel is stripped before the message reaches the original console.
10
+ *
11
+ * Example:
12
+ * // Before:
13
+ * console.log("Processing request", data);
14
+ *
15
+ * // After:
16
+ * console.log("Processing request", data, "__sf:src/handlers/api.ts:42");
17
+ */
18
+ export interface ConsoleLocationTransformOptions {
19
+ projectRoot?: string;
20
+ includeNodeModules?: string[];
21
+ debug?: boolean;
22
+ }
23
+ export interface ConsoleLocationTransformResult {
24
+ code: string;
25
+ map?: any;
26
+ modified: boolean;
27
+ callsTransformed: number;
28
+ }
29
+ /**
30
+ * Transform console method calls to include source location sentinels.
31
+ * Async version with source map support.
32
+ */
33
+ export declare function transformConsoleLocations(source: string, filePath: string, options?: ConsoleLocationTransformOptions): Promise<ConsoleLocationTransformResult>;
34
+ /**
35
+ * Sync version — no source map loading (for runtime hooks).
36
+ */
37
+ export declare function transformConsoleLocationsSync(source: string, filePath: string, options?: ConsoleLocationTransformOptions): ConsoleLocationTransformResult;
@@ -1 +1,46 @@
1
+ import { NetworkHopTransmitter } from "./networkHopTransmitter";
2
+ import { NetworkRequestTransmitter } from "./networkRequestTransmitter";
3
+ export declare class RequestInterceptor {
4
+ private readonly HEADER_TRACING;
5
+ private readonly HEADER_LOG_GUARD;
6
+ private readonly HEADER_PRINT_GUARD;
7
+ private readonly HEADER_EXCEPTION_GUARD;
8
+ private contextManager;
9
+ constructor(excludedDomains?: string[]);
10
+ private extractIdsFromTraceHeader;
11
+ private parseStackFrame;
12
+ /**
13
+ * Attempts to map a transpiled file location (line/column) back to the original source
14
+ * using the .map file. If the .map file is missing or cannot be parsed,
15
+ * returns a fallback original position constructed from the input parameters.
16
+ *
17
+ * @param bundlePath - The path to the transpiled bundle (e.g. ".next/server/chunks/106.js")
18
+ * @param line - The transpiled line number from a stack trace or instrumentation
19
+ * @param column - The transpiled column number
20
+ * @param count - How many context lines to retrieve in the source snippet
21
+ * @returns An object containing:
22
+ * - originalPos: the mapped original position (or fallback if unavailable)
23
+ * - snippet: an array of source code lines around the mapped position, or null
24
+ */
25
+ private getOriginalPosition;
26
+ private captureFirstUserLines;
27
+ private addReentrancyGuardHeaders;
28
+ private shouldPropagateHeaders;
29
+ addTracingHeaders(headers: Headers, url: string): boolean;
30
+ private addTracingHeader;
31
+ patchFetch(networkHopTransmitter: NetworkHopTransmitter, networkRequestTransmitter: NetworkRequestTransmitter): void;
32
+ /**
33
+ * Set a header on either a plain object (OutgoingHttpHeaders) or a Headers instance.
34
+ */
35
+ private setHeader;
36
+ /**
37
+ * Add tracing headers to plain-object headers (used by http/https patches).
38
+ * Unlike addTracingHeaders() which expects a Headers instance, this works
39
+ * with the Record<string, string> style headers used by http.request().
40
+ */
41
+ private addTracingHeadersToPlainObject;
42
+ patchHttp(networkHopTransmitter: NetworkHopTransmitter, networkRequestTransmitter: NetworkRequestTransmitter): void;
43
+ tryPatch(patchFunction: () => void, packageName: string): void;
44
+ getExcludedDomains(): string[];
45
+ }
1
46
  export declare function patchRequests(domainsToNotPropagateHeadersTo?: string[]): void;
@@ -1,12 +1,23 @@
1
1
  export declare function isSendingInternalTelemetry(): boolean;
2
2
  /**
3
3
  * Sends a non-blocking POST request to a GraphQL endpoint.
4
- * The request is sent asynchronously, and any response errors or issues are logged.
5
4
  *
6
- * @param {string} url - The URL of the GraphQL endpoint.
7
- * @param {string} operationName - The name of the GraphQL operation being invoked.
8
- * @param {string} query - The GraphQL query string.
9
- * @param {Record<string, any>} variables - The variables to be sent with the GraphQL query.
10
- * @returns {Promise<void>} Resolves when the request has been handled.
5
+ * Default: batches items on the main thread and sends them to the Worker
6
+ * in a single postMessage at the microtask boundary. The worker then sends
7
+ * each item to the backend individually (backend doesn't support batch).
8
+ *
9
+ * Main thread cost per log: ~0.08µs (push to array)
10
+ * Main thread cost per tick: ~0.35µs (one postMessage with batch)
11
+ *
12
+ * Config:
13
+ * SF_MAIN_BATCH_SIZE=0 — microtask batching (default, all items per tick)
14
+ * SF_MAIN_BATCH_SIZE=1 — per-item postMessage (no main-thread batching)
15
+ * SF_NBPOST_DISABLE_BATCHING=1 — no worker, direct fetch on main thread
11
16
  */
12
17
  export declare function nonBlockingPost(url: string, operationName: string, query: string, variables: Record<string, any>): Promise<void>;
18
+ /**
19
+ * Flush any pending batched items immediately.
20
+ * Call this during graceful shutdown to ensure no telemetry is lost.
21
+ */
22
+ export declare function flushPendingTelemetry(): void;
23
+ export declare function registerShutdownHooks(): void;
@@ -76,6 +76,26 @@ export interface SetupOptions {
76
76
  * Optional list of site and distribution packages for which local variables should be collected.
77
77
  */
78
78
  nodeModulesToCollectLocalVariablesOn?: string[];
79
+ /**
80
+ * How to handle 400/403 responses on requests carrying our tracing
81
+ * header (X-Sf3-Rid). When a server rejects a request that carried
82
+ * the header, Sailfish can retry the request ONCE without the
83
+ * header so the customer's call succeeds transparently.
84
+ *
85
+ * - 'all' (default) — retry once without the tracing header for
86
+ * every method. Most transparent; matches pre-0.3.1 behavior.
87
+ * Recommended for backends that reject unknown headers at the
88
+ * edge (API gateways / WAFs) before any business logic runs.
89
+ * - 'idempotent' — retry only GET/HEAD/OPTIONS. Safer for
90
+ * backends that may commit side effects before returning 4xx
91
+ * (payment processors, booking systems, inventory APIs).
92
+ * - 'none' — never retry; callers see the original 4xx directly.
93
+ *
94
+ * If a specific domain consistently rejects the tracing header,
95
+ * prefer adding it to `domainsToNotPropagateHeadersTo` — that
96
+ * avoids the first 4xx round-trip entirely.
97
+ */
98
+ retryOnClientError?: "all" | "idempotent" | "none";
79
99
  }
80
100
  export interface GetOrCreateConfig {
81
101
  config: AppConfig;
@@ -118,6 +138,7 @@ declare class AppConfig {
118
138
  captureResponseBody: boolean;
119
139
  requestBodyLimitBytes: number;
120
140
  responseBodyLimitBytes: number;
141
+ retryOnClientError: "all" | "idempotent" | "none";
121
142
  private _serviceIdentificationReceived;
122
143
  constructor(options: SetupOptions);
123
144
  private getPackageVersion;
@@ -1,30 +1,30 @@
1
1
  /**
2
- * Get caller location from the call stack.
3
- * Captures file path and line number of the code that triggered the log,
4
- * filtering out internal library frames.
2
+ * Check if the last argument is a build-time sentinel.
3
+ * Returns [file, line, true] if found, [null, null, false] if not.
5
4
  *
6
- * Performance: ~7-15 µs per call (first call), ~50 ns (cached)
7
- *
8
- * @param skipFrames - Additional frames to skip beyond this function
9
- * Default: 0 (skip only getCallerLocation itself)
5
+ * The sentinel format is: "__sf:relative/path/to/file.ts:42"
6
+ */
7
+ export declare function extractBuildTimeSentinel(args: any[]): [string | null, number | null, boolean];
8
+ /**
9
+ * Get caller location using the configured tier system.
10
10
  *
11
- * @returns Tuple of [absolutePath, lineNumber] or [null, null] if not found
11
+ * @param callerFn - The wrapper function to skip in stack traces (Tier 2)
12
+ * @param args - The console.log arguments (checked for Tier 1 sentinel)
13
+ * @returns [file, line] or [null, null]
14
+ */
15
+ export declare function getCallerLocation(skipFrames?: number, callerFn?: Function, args?: any[]): [string | null, number | null];
16
+ /**
17
+ * Strip the build-time sentinel from console.log args before outputting.
18
+ * Call this AFTER extracting the location, before passing args to the original console.log.
12
19
  *
13
- * @example
14
- * // From user code:
15
- * const [sourceFile, sourceLine] = getCallerLocation(2);
16
- * // Returns: ['/Users/name/project/src/app.ts', 42]
20
+ * @returns The args array without the sentinel (or unchanged if no sentinel)
17
21
  */
18
- export declare function getCallerLocation(skipFrames?: number): [string | null, number | null];
22
+ export declare function stripSentinel(args: any[]): any[];
19
23
  /**
20
- * Clear the location cache.
21
- * Useful for testing or if cache invalidation is needed.
24
+ * Clear the location cache. Useful for testing.
22
25
  */
23
26
  export declare function clearLocationCache(): void;
24
27
  /**
25
- * Get current cache size.
26
- * Useful for monitoring and testing cache effectiveness.
27
- *
28
- * @returns Number of entries in cache
28
+ * Get current cache size. Useful for monitoring.
29
29
  */
30
30
  export declare function getCacheSize(): number;
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./workerPoolSpanCapture-DFnbcpkU.cjs");exports.captureWorkerPoolOperation=e.captureWorkerPoolOperation;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./workerPoolSpanCapture-DzCJnMDA.cjs");exports.captureWorkerPoolOperation=e.captureWorkerPoolOperation;
@@ -1,4 +1,4 @@
1
- import { c as e } from "./workerPoolSpanCapture-DVYmzgbN.js";
1
+ import { c as e } from "./workerPoolSpanCapture-hyxgVqUF.js";
2
2
  export {
3
3
  e as captureWorkerPoolOperation
4
4
  };
@@ -0,0 +1,83 @@
1
+ "use strict";const j=require("async_hooks"),Q=require("fs"),$=require("worker_threads"),l=require("./contextManager-BsolAr_q.cjs"),z=require("path"),X=require("url");class G{apiKey;endpoint;queryType="mutation";operationName="";serviceUUID=l.getConfig().serviceUUID;contextManager;constructor(){this.apiKey=l.getConfig().apiKey,this.endpoint=l.getConfig().apiGraphqlEndpoint,this.contextManager=l.ContextManager.getInstance()}get queryName(){return this.operationName?this.operationName.charAt(0).toLowerCase()+this.operationName.slice(1):""}getDefaultVariables(){const t=Date.now().toString(),o=this.contextManager.getOrSetSfTraceId(),a=this.contextManager.getCurrentFunctionSpanId();return{apiKey:this.apiKey,serviceUuid:this.serviceUUID,sessionId:o,timestampMs:t,parentSpanId:a}}getVariables(t={}){return{...this.getDefaultVariables(),...t}}setOperationName(t){this.operationName=t}setEndpoint(t){this.endpoint=t}setServiceUUID(t){this.serviceUUID=t}}const Z=typeof __dirname<"u"?__dirname:z.dirname(X.fileURLToPath(require("node:url").pathToFileURL(__filename).href)),Y=fetch;let I=!1;const ee=process.env.SF_NBPOST_DISABLE_BATCHING==="1",k=parseInt(process.env.SF_MAIN_BATCH_SIZE||"0",10);let m=null,C=!1;function B(){if(C)return null;if(m)return m;try{const n=z.join(Z,"telemetryWorker.cjs");return m=new $.Worker(n,{env:{...process.env,SF_NBPOST_BATCH_MAX:process.env.SF_NBPOST_BATCH_MAX||"50",SF_FLUSH_TELEMETRY_IN_BATCH:process.env.SF_FLUSH_TELEMETRY_IN_BATCH||"0",SF_BATCH_FLUSH_INTERVAL_MS:process.env.SF_BATCH_FLUSH_INTERVAL_MS||"50",SF_WORKER_MAX_CONCURRENT:process.env.SF_WORKER_MAX_CONCURRENT||"10"}}),m.unref(),m.on("error",()=>{C=!0,m=null}),m.on("exit",()=>{m=null}),m}catch{return C=!0,null}}let S=[],b=!1;function U(){if(S.length===0)return;const n=B();if(!n){for(const t of S)L(t.url,t.item.operationName,t.item.query,t.item.variables);return S=[],void(b=!1)}S.length===1?n.postMessage(S[0]):n.postMessage({batch:S}),S=[],b=!1}async function E(n,t,o,a){if(ee)return L(n,t,o,a);const s={url:n,item:{query:o,variables:a,operationName:t}};if(k===1){const i=B();return i?void i.postMessage(s):L(n,t,o,a)}S.push(s),k>1&&S.length>=k?U():b||(b=!0,queueMicrotask(U))}async function L(n,t,o,a){try{const s=l.getConfig();let i;try{i=JSON.stringify({query:o,variables:a,operationName:t})}catch{i=JSON.stringify({query:o,operationName:t})}I=!0,Y(n,{method:"POST",headers:{"Content-Type":"application/json"},body:i}).then(async e=>{if(I=!1,!e.ok)return void(s.sfDebug&&console.error(`GraphQL request failed with status ${e.status} for ${t}`));const r=await e.json();r.errors?.length?(function(u,g,c){const d=u&&typeof u=="object"&&!Array.isArray(u)?Object.keys(u)[0]:void 0;console.error(d==="identifyServiceDetails"?`IdentifyServiceDetails NOT sent successfully for service: UUID=${c.serviceUUID}`:`GraphQL request failed with errors: ${JSON.stringify(g)} for operation key ${d}`)})(r.data,r.errors,s):s.sfDebug&&(function(u,g,c){const d=u&&typeof u=="object"&&!Array.isArray(u)?Object.keys(u)[0]:void 0,p=u[d]||!1;d==="identifyServiceDetails"&&(c.setServiceIdentificationReceived(p),l.getConfig().sfDebug&&console.log(`IdentifyServiceDetails sent successfully for service: UUID=${c.serviceUUID}; serviceIdentificationReceived=${d==="identifyServiceDetails"?p:"N/A"}`))})(r.data,0,s)}).catch(e=>{I=!1,s.sfDebug&&(console.error(`[RequestUtils] Fetch error for ${t} to ${n}:`,e),e.cause&&console.error("[RequestUtils] Error cause:",e.cause))})}catch(s){I=!1,l.getConfig().sfDebug&&console.error("Error sending data to GraphQL server:",s)}}let V=!1;function h(n,t){if(!n)return t;const o=n.toLowerCase();return o==="true"||o==="1"||o==="yes"}const M="__sf_funcspanOverrideStorage";globalThis[M]||(globalThis[M]=new j.AsyncLocalStorage);const P=globalThis[M];function D(n,t){try{const o=JSON.stringify(n).length/1048576;return o<=t?n:{_truncated:!0,_originalSizeMB:o.toFixed(2),_limitMB:t,_preview:JSON.stringify(n).substring(0,500)+"..."}}catch{return{_error:"Failed to serialize data",_type:typeof n}}}function y(n,t){const o=process.env[n];return o===void 0?t:o==="true"||o==="1"}function q(n,t){const o=process.env[n];if(o===void 0)return t;const a=parseFloat(o);return isNaN(a)?t:a}function A(){return{enabled:y("SF_WORKER_POOL_ENABLED",!0),trackFs:y("SF_WORKER_POOL_TRACK_FS",!1),trackDns:y("SF_WORKER_POOL_TRACK_DNS",!1),trackCrypto:y("SF_WORKER_POOL_TRACK_CRYPTO",!1),trackZlib:y("SF_WORKER_POOL_TRACK_ZLIB",!1),captureArguments:y("SF_WORKER_POOL_CAPTURE_ARGUMENTS",!0),captureReturnValue:y("SF_WORKER_POOL_CAPTURE_RETURN_VALUE",!0),argLimitMb:q("SF_WORKER_POOL_ARG_LIMIT_MB",1),returnLimitMb:q("SF_WORKER_POOL_RETURN_LIMIT_MB",1)}}function x(n,t,o,a){let s;try{switch(n){case"fs":s=(function(i,e){const r={};switch(i){case"readFile":case"writeFile":case"appendFile":r.path=String(e[0]||""),e[1]&&typeof e[1]=="object"?(r.encoding=e[1].encoding||null,r.flag=e[1].flag||null):typeof e[1]=="string"&&(r.encoding=e[1]),i!=="writeFile"&&i!=="appendFile"||(Buffer.isBuffer(e[1])?(r.dataType="Buffer",r.dataSize=e[1].length):typeof e[1]=="string"&&(r.dataType="string",r.dataSize=e[1].length));break;case"readdir":case"stat":case"lstat":case"access":case"chmod":case"mkdir":case"rmdir":case"unlink":r.path=String(e[0]||""),e[1]&&typeof e[1]=="object"&&(r.options={...e[1]},delete r.options.callback);break;case"rename":r.oldPath=String(e[0]||""),r.newPath=String(e[1]||"");break;case"open":r.path=String(e[0]||""),r.flags=e[1],r.mode=e[2];break;case"close":case"fstat":r.fd=e[0];break;case"read":case"write":r.fd=e[0],Buffer.isBuffer(e[1])&&(r.bufferSize=e[1].length),r.offset=e[2],r.length=e[3],r.position=e[4];break;default:r.argsCount=e.length-1}return r})(t,o);break;case"dns":s=(function(i,e){const r={};switch(i){case"lookup":r.hostname=String(e[0]||""),typeof e[1]=="object"?(r.family=e[1].family,r.all=e[1].all):typeof e[1]=="number"&&(r.family=e[1]);break;case"resolve":case"resolve4":case"resolve6":case"resolveAny":case"resolveMx":case"resolveNs":case"resolveTxt":r.hostname=String(e[0]||"");break;case"reverse":r.ip=String(e[0]||"");break;default:r.argsCount=e.length-1}return r})(t,o);break;case"crypto":s=(function(i,e){const r={};switch(i){case"pbkdf2":r.passwordType=typeof e[0],r.saltType=typeof e[1],r.iterations=e[2],r.keylen=e[3],r.digest=e[4];break;case"scrypt":r.passwordType=typeof e[0],r.saltType=typeof e[1],r.keylen=e[2],typeof e[3]=="object"&&(r.N=e[3].N,r.r=e[3].r,r.p=e[3].p);break;case"randomBytes":r.size=e[0];break;case"generateKeyPair":r.type=e[0],typeof e[1]=="object"&&(r.modulusLength=e[1].modulusLength,r.namedCurve=e[1].namedCurve);break;default:r.argsCount=e.length-1}return r})(t,o);break;case"zlib":s=(function(i,e){const r={};return Buffer.isBuffer(e[0])?(r.inputType="Buffer",r.inputSize=e[0].length):typeof e[0]=="string"?(r.inputType="string",r.inputSize=e[0].length):r.inputType=typeof e[0],e[1]&&typeof e[1]=="object"&&typeof e[1]!="function"&&(r.options={...e[1]}),r})(0,o);break;default:return null}return a>0?D(s,a):s}catch{return{error:"Failed to capture arguments",argsCount:o.length-1}}}function J(n,t,o,a){let s;try{switch(n){case"fs":s=(function(i,e){if(!e)return null;switch(i){case"readFile":return Buffer.isBuffer(e)?{type:"Buffer",size:e.length}:typeof e=="string"?{type:"string",size:e.length}:{type:typeof e};case"readdir":return{count:Array.isArray(e)?e.length:0,items:e};case"stat":case"lstat":case"fstat":return{size:e.size,mode:e.mode,isFile:e.isFile(),isDirectory:e.isDirectory()};case"open":return{fd:e};case"read":return{bytesRead:e};case"write":return{bytesWritten:e};default:return e}})(t,o);break;case"dns":s=(function(i,e){if(!e)return null;switch(i){case"lookup":return Array.isArray(e)?{count:e.length,addresses:e}:e;case"resolve":case"resolve4":case"resolve6":case"resolveAny":case"resolveMx":case"resolveNs":case"resolveTxt":return{count:Array.isArray(e)?e.length:0,records:e};case"reverse":return{hostnames:e};default:return e}})(t,o);break;case"crypto":s=(function(i,e){if(!e)return null;switch(i){case"pbkdf2":case"scrypt":case"randomBytes":return Buffer.isBuffer(e)?{type:"Buffer",size:e.length}:{type:typeof e};case"generateKeyPair":return{hasPublicKey:!!e?.publicKey,hasPrivateKey:!!e?.privateKey};default:return e}})(t,o);break;case"zlib":s=(function(i,e){return e?Buffer.isBuffer(e)?{type:"Buffer",size:e.length}:typeof e=="string"?{type:"string",size:e.length}:{type:typeof e}:null})(0,o);break;default:return null}return a>0?D(s,a):s}catch{return{error:"Failed to capture result",type:typeof o}}}function te(n){return n.operationType==="worker_pool"}class H extends G{constructor(){super(),this.operationName="CollectFunctionSpans"}send(t){const o=l.getConfig().sfDebug;o&&console.log(`[FunctionSpanTransmitter] Preparing to send ${t.length} function span(s)`);for(const a of t)try{if(te(a)){this.sendWorkerPoolSpan(a,o);continue}const s=a;let i;if(s.result!==void 0&&s.result!==null){const r=typeof s.result;i=JSON.stringify({type:r,has_value:!0,value:s.result})}else i=s.result===null?JSON.stringify({type:"null",has_value:!0,value:null}):JSON.stringify({type:"undefined",has_value:!1,value:null});const e=this.getVariables({library:"JS/TS BACKEND",version:l.getConfig().version,spanId:s.spanId,parentSpanId:s.parentSpanId,filePath:s.filePath,lineNumber:s.metadata.line,columnNumber:s.metadata.column,functionName:s.functionName,arguments:JSON.stringify(s.args||{}),returnValue:i,startTimeNs:(1e6*Date.now()-1e6*s.duration).toString(),durationNs:(1e6*s.duration).toString()});o&&(console.log(`[FunctionSpanTransmitter] Sending GraphQL mutation to ${this.endpoint}`),console.log("[FunctionSpanTransmitter] Variables:",JSON.stringify(e,null,2))),E(this.endpoint,this.operationName,this.getQuery(),e),o&&console.log(`[FunctionSpanTransmitter] Queued function span for ${s.functionName}`)}catch(s){console.error(`[FunctionSpanTransmitter] Error preparing function span for ${a.functionName}:`,s)}}sendWorkerPoolSpan(t,o){try{let a;if(t.result!==void 0&&t.result!==null){const i=typeof t.result;a=JSON.stringify({type:i,has_value:!0,value:t.result})}else a=t.result===null?JSON.stringify({type:"null",has_value:!0,value:null}):JSON.stringify({type:"undefined",has_value:!1,value:null});const s=this.getVariables({library:"JS/TS BACKEND",version:l.getConfig().version,spanId:t.spanId,operationName:t.operationName,moduleName:t.moduleName,methodName:t.methodName,startTimeNs:t.startTimeNs,durationNs:t.durationNs,arguments:JSON.stringify(t.args||{}),returnValue:a,error:t.error,pid:t.pid,threadId:t.threadId});o&&(console.log(`[FunctionSpanTransmitter] Sending worker pool span: ${t.operationName}`),console.log("[FunctionSpanTransmitter] Variables:",JSON.stringify(s,null,2))),E(this.endpoint,"CollectWorkerPoolSpans",this.getWorkerPoolQuery(),s),o&&console.log(`[FunctionSpanTransmitter] Queued worker pool span for ${t.operationName}`)}catch(a){console.error(`[FunctionSpanTransmitter] Error preparing worker pool span for ${t.operationName}:`,a)}}getWorkerPoolQuery(){return`
2
+ mutation CollectWorkerPoolSpans(
3
+ $apiKey: String!,
4
+ $serviceUuid: String!,
5
+ $sessionId: String!,
6
+ $timestampMs: String!,
7
+ $library: String!,
8
+ $version: String!,
9
+ $spanId: String!,
10
+ $operationName: String!,
11
+ $moduleName: String!,
12
+ $methodName: String!,
13
+ $startTimeNs: String!,
14
+ $durationNs: String!,
15
+ $parentSpanId: String,
16
+ $arguments: String,
17
+ $returnValue: String,
18
+ $error: String,
19
+ $pid: Int,
20
+ $threadId: Int
21
+ ) {
22
+ collectWorkerPoolSpans(
23
+ apiKey: $apiKey,
24
+ serviceUuid: $serviceUuid,
25
+ sessionId: $sessionId,
26
+ timestampMs: $timestampMs,
27
+ library: $library,
28
+ version: $version,
29
+ spanId: $spanId,
30
+ operationName: $operationName,
31
+ moduleName: $moduleName,
32
+ methodName: $methodName,
33
+ startTimeNs: $startTimeNs,
34
+ durationNs: $durationNs,
35
+ parentSpanId: $parentSpanId,
36
+ arguments: $arguments,
37
+ returnValue: $returnValue,
38
+ error: $error,
39
+ pid: $pid,
40
+ threadId: $threadId
41
+ )
42
+ }
43
+ `}getQuery(){return`
44
+ ${this.queryType} ${this.operationName}(
45
+ $apiKey: String!,
46
+ $serviceUuid: String!,
47
+ $sessionId: String!,
48
+ $timestampMs: String!,
49
+ $parentSpanId: String,
50
+ $library: String!,
51
+ $version: String!,
52
+ $spanId: String!,
53
+ $filePath: String!,
54
+ $lineNumber: Int!,
55
+ $columnNumber: Int!,
56
+ $functionName: String!,
57
+ $arguments: String!,
58
+ $returnValue: String,
59
+ $startTimeNs: String!,
60
+ $durationNs: String!
61
+ ) {
62
+ ${this.queryName}(
63
+ apiKey: $apiKey,
64
+ serviceUuid: $serviceUuid,
65
+ sessionId: $sessionId,
66
+ timestampMs: $timestampMs,
67
+ parentSpanId: $parentSpanId,
68
+ library: $library,
69
+ version: $version,
70
+ spanId: $spanId,
71
+ filePath: $filePath,
72
+ lineNumber: $lineNumber,
73
+ columnNumber: $columnNumber,
74
+ functionName: $functionName,
75
+ arguments: $arguments,
76
+ returnValue: $returnValue,
77
+ startTimeNs: $startTimeNs,
78
+ durationNs: $durationNs
79
+ )
80
+ }
81
+ `}}let O=null;function R(n){const t=l.getGlobalConfigUnsafe(),o=t?.sfDebug||!1;o&&console.log("[WorkerPool] Capturing span:",{operation:n.operationName,duration:`${n.duration}ms`,error:n.error,spanId:n.spanId,parentSpanId:n.parentSpanId}),process.env.SF_FUNCSPAN_CONSOLE_OUTPUT==="true"&&console.log(`
82
+ ⚙️ Worker Pool Operation:`,{operation:n.operationName,duration:`${n.duration.toFixed(2)}ms`,arguments:n.args,result:n.error?`Error: ${n.error}`:n.result,spanId:n.spanId,parentSpanId:n.parentSpanId||"none"});const a=process.env.SF_FUNCSPAN_JSONL_FILE;if(a)try{const s=a==="true"||a==="1"?"funcspans.jsonl":a,i=Date.now(),e=process.hrtime.bigint(),r=BigInt(n.startTimeNs),u=Number(e-r)/1e6,g=new Date(i-u).toISOString(),c=JSON.stringify({timestamp:g,operationType:n.operationType,operationName:n.operationName,moduleName:n.moduleName,methodName:n.methodName,duration:n.duration,durationNs:n.durationNs,startTimeNs:n.startTimeNs,arguments:n.args,returnValue:n.error?{error:String(n.error)}:n.result,spanId:n.spanId,parentSpanId:n.parentSpanId,pid:n.pid,threadId:n.threadId})+`
83
+ `;Q.appendFileSync(s,c,"utf-8")}catch(s){console.error("[WorkerPool] Error writing to JSONL file:",s)}if(o&&console.log("[WorkerPool] Sending span to transmitter"),process.env.SF_FUNCSPAN_SKIP_BACKEND!=="true")try{(O||(O=new H),O).send([n]),o&&console.log("[WorkerPool] Span sent successfully")}catch(s){o&&console.error("[WorkerPool] Error sending span:",s)}}exports.BaseTransmitter=G,exports.FunctionSpanTransmitter=H,exports.captureWorkerPoolOperation=function(n,t,o,a,s){const i=l.getGlobalConfigUnsafe(),e=i?.sfDebug||!1;e&&console.log(`[WorkerPool] Capturing ${n}.${t}`);const r=A(),u=l.ContextManager.getInstance().getCurrentFunctionSpanId(),g=l.v4();e&&console.log(`[WorkerPool] Span ID: ${g}, Parent: ${u||"none"}`);const c=new j.AsyncResource("WorkerPoolOperation"),d=process.hrtime.bigint();let p=null;r.captureArguments&&(p=x(n,t,a,r.argLimitMb));const f=a.findIndex(N=>typeof N=="function");if(f===-1)return e&&console.log(`[WorkerPool] No callback found for ${n}.${t}`),o.apply(s,a);const _=a[f],v=[...a];return v[f]=function(N,...T){const F=process.hrtime.bigint()-d,w=Number(F)/1e6;_(N,...T),c.runInAsyncScope(()=>{e&&console.log(`[WorkerPool] ${n}.${t} completed in ${w.toFixed(3)}ms (${F}ns)`);let W=null,K=null;N?K=N?.message||String(N):r.captureReturnValue&&T.length>0&&(W=J(n,t,T[0],r.returnLimitMb)),R({operationType:"worker_pool",operationName:`${n}.${t}`,moduleName:n,methodName:t,duration:w,durationNs:F.toString(),startTimeNs:d.toString(),args:p,result:W,error:K,spanId:g,parentSpanId:u,pid:process.pid,threadId:$.threadId})}),c.emitDestroy()},o.apply(s,v)},exports.captureWorkerPoolPromiseOperation=function(n,t,o,a,s){const i=l.getGlobalConfigUnsafe(),e=i?.sfDebug||!1;e&&console.log(`[WorkerPool] Capturing ${n}.${t} (Promise)`);const r=A(),u=l.ContextManager.getInstance().getCurrentFunctionSpanId(),g=l.v4();e&&console.log(`[WorkerPool] Span ID: ${g}, Parent: ${u||"none"}`);const c=process.hrtime.bigint();let d=null;return r.captureArguments&&(d=x(n,t,a,r.argLimitMb)),o.apply(s,a).then(p=>{const f=process.hrtime.bigint()-c,_=Number(f)/1e6;e&&console.log(`[WorkerPool] ${n}.${t} completed in ${_.toFixed(3)}ms (${f}ns)`);let v=null;return r.captureReturnValue&&(v=J(n,t,p,r.returnLimitMb)),R({operationType:"worker_pool",operationName:`${n}.${t}`,moduleName:n,methodName:t,duration:_,durationNs:f.toString(),startTimeNs:c.toString(),args:d,result:v,error:null,spanId:g,parentSpanId:u,pid:process.pid,threadId:$.threadId}),p},p=>{const f=process.hrtime.bigint()-c,_=Number(f)/1e6;throw e&&console.log(`[WorkerPool] ${n}.${t} failed in ${_.toFixed(3)}ms: ${p?.message||p}`),R({operationType:"worker_pool",operationName:`${n}.${t}`,moduleName:n,methodName:t,duration:_,durationNs:f.toString(),startTimeNs:c.toString(),args:d,result:null,error:p?.message||String(p),spanId:g,parentSpanId:u,pid:process.pid,threadId:$.threadId}),p})},exports.clearFuncspanOverride=function(){},exports.funcspanOverrideStorage=P,exports.getDefaultConfig=function(){return{capture_arguments:!1,capture_return_value:!1,arg_limit_mb:1,return_limit_mb:1,autocapture_all_child_functions:!1,sample_rate:0,enable_sampling:!1,capture_sf_veritas:!1,parse_json_strings:!1}},exports.getEnvConfig=function(){return{capture_arguments:h(process.env.SF_FUNCSPAN_CAPTURE_ARGUMENTS,!0),capture_return_value:h(process.env.SF_FUNCSPAN_CAPTURE_RETURN_VALUE,!0),arg_limit_mb:parseInt(process.env.SF_FUNCSPAN_ARG_LIMIT_MB||"1",10),return_limit_mb:parseInt(process.env.SF_FUNCSPAN_RETURN_LIMIT_MB||"1",10),autocapture_all_child_functions:h(process.env.SF_FUNCSPAN_AUTOCAPTURE_ALL_CHILD_FUNCTIONS,!1),sample_rate:parseFloat(process.env.SF_FUNCSPAN_SAMPLE_RATE||"1.0"),enable_sampling:h(process.env.SF_FUNCSPAN_ENABLE_SAMPLING,!1),capture_sf_veritas:h(process.env.SF_FUNCSPAN_CAPTURE_SF_VERITAS,!1),parse_json_strings:h(process.env.SF_FUNCSPAN_PARSE_JSON_STRINGS,!1)}},exports.getFuncspanOverride=function(){return P.getStore()},exports.isModuleTrackingEnabled=function(n){const t=A();if(!t.enabled)return!1;switch(n){case"fs":return t.trackFs;case"dns":return t.trackDns;case"crypto":return t.trackCrypto;case"zlib":return t.trackZlib;default:return!1}},exports.isSendingInternalTelemetry=function(){return I},exports.mergeConfigs=function(...n){const t={};for(const o of n)for(const a in o)o[a]!==void 0&&(t[a]=o[a]);return t},exports.nonBlockingPost=E,exports.parseHeaderOverride=function(n){try{const t=n.split("-");return t.length!==9?(console.error(`[FuncSpan] Invalid header format: expected 9 parts, got ${t.length}`),null):{capture_arguments:t[0]==="1",capture_return_value:t[1]==="1",arg_limit_mb:parseInt(t[2],10),return_limit_mb:parseInt(t[3],10),autocapture_all_child_functions:t[4]==="1",sample_rate:parseFloat(t[5]),enable_sampling:t[6]==="1",capture_sf_veritas:t[7]==="1",parse_json_strings:t[8]==="1"}}catch(t){return console.error(`[FuncSpan] Failed to parse header override "${n}":`,t),null}},exports.registerShutdownHooks=function(){if(V)return;V=!0;const n=()=>{try{(function(){U();const t=B();t&&t.postMessage("flush")})()}catch{}};process.on("beforeExit",n),process.on("SIGTERM",n),process.on("SIGINT",n)},exports.setFuncspanOverride=function(n){P.enterWith(n)},exports.truncateToLimit=D;