@sailfish-ai/sf-veritas 0.2.20 → 0.3.0
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.
- package/dist/consoleLocationTransformer-BSSB5msZ.cjs +1 -0
- package/dist/consoleLocationTransformer-DZu_9MDA.js +51 -0
- package/dist/contextManager-0D8uHQ1_.cjs +1 -0
- package/dist/{contextManager-Dw7Yot7r.js → contextManager-RxrMXs5c.js} +106 -83
- package/dist/plugins/funcspanEsbuildPlugin.cjs +1 -1
- package/dist/plugins/funcspanEsbuildPlugin.mjs +20 -16
- package/dist/plugins/funcspanRollupPlugin.cjs +1 -1
- package/dist/plugins/funcspanRollupPlugin.mjs +17 -13
- package/dist/plugins/funcspanTscPlugin.cjs +1 -1
- package/dist/plugins/funcspanTscPlugin.mjs +34 -30
- package/dist/plugins/funcspanVitePlugin.cjs +1 -1
- package/dist/plugins/funcspanVitePlugin.mjs +16 -12
- package/dist/plugins/funcspanWebpackLoader.cjs +1 -1
- package/dist/plugins/funcspanWebpackLoader.mjs +55 -50
- package/dist/plugins/funcspanWebpackPlugin.cjs +1 -1
- package/dist/plugins/funcspanWebpackPlugin.mjs +1 -1
- package/dist/runtimeConfig-BZ61efqE.js +485 -0
- package/dist/runtimeConfig-CWpFWsmz.cjs +6 -0
- package/dist/sf-veritas.cjs +25 -13
- package/dist/sf-veritas.mjs +453 -393
- package/dist/telemetryWorker.cjs +1 -0
- package/dist/types/dataTransmitter.d.ts +6 -5
- package/dist/types/exceptionTransmitter.d.ts +2 -1
- package/dist/types/frameworkDetection.d.ts +18 -0
- package/dist/types/networkHopTransmitter.d.ts +2 -1
- package/dist/types/networkRequestTransmitter.d.ts +2 -1
- package/dist/types/plugins/consoleLocationTransformer.d.ts +37 -0
- package/dist/types/requestUtils.d.ts +17 -6
- package/dist/types/setupConfig.d.ts +3 -0
- package/dist/types/sourceLocation.d.ts +19 -19
- package/dist/types/telemetryWorker.d.ts +1 -0
- package/dist/worker-pool-capture.cjs +1 -1
- package/dist/worker-pool-capture.mjs +1 -1
- package/dist/workerPoolSpanCapture-Bg5av6gn.cjs +83 -0
- package/dist/{workerPoolSpanCapture-Dm4Reseo.js → workerPoolSpanCapture-BjdZn3LE.js} +222 -168
- package/package.json +1 -1
- package/dist/contextManager-DQMeQfS_.cjs +0 -1
- package/dist/runtimeConfig-Bfqf33tO.js +0 -444
- package/dist/runtimeConfig-DmD4lUhG.cjs +0 -9
- package/dist/workerPoolSpanCapture-CAM2z9Jx.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
|
-
*
|
|
14
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework auto-detection for the JS/TS Backend SDK.
|
|
3
|
+
* Uses require.resolve() in try/catch to detect installed frameworks
|
|
4
|
+
* without actually importing them.
|
|
5
|
+
*/
|
|
6
|
+
export interface FrameworkDetectionResult {
|
|
7
|
+
framework: string | null;
|
|
8
|
+
additionalFrameworks: string[];
|
|
9
|
+
serviceRole: "backend" | "fullstack";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Detects which web framework(s) are installed in the current project.
|
|
13
|
+
* Uses require.resolve() wrapped in try/catch — does not import the modules.
|
|
14
|
+
* Runs once at setup time.
|
|
15
|
+
*
|
|
16
|
+
* @returns Detection result with primary framework, additional frameworks, and serviceRole.
|
|
17
|
+
*/
|
|
18
|
+
export declare function detectFramework(): FrameworkDetectionResult;
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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,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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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;
|
|
@@ -106,6 +106,9 @@ declare class AppConfig {
|
|
|
106
106
|
serviceDisplayName?: string;
|
|
107
107
|
infrastructureType?: string;
|
|
108
108
|
infrastructureDetails?: Record<string, string>;
|
|
109
|
+
framework?: string;
|
|
110
|
+
additionalFrameworks: string[];
|
|
111
|
+
serviceRole: "backend" | "fullstack";
|
|
109
112
|
setupInterceptorsFile?: string;
|
|
110
113
|
setupInterceptorsLine?: number;
|
|
111
114
|
logIgnoreRegex?: RegExp;
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
* @
|
|
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
|
-
* @
|
|
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
|
|
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-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./workerPoolSpanCapture-Bg5av6gn.cjs");exports.captureWorkerPoolOperation=e.captureWorkerPoolOperation;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";const j=require("async_hooks"),Q=require("fs"),$=require("worker_threads"),l=require("./contextManager-0D8uHQ1_.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;
|