@stackone/olap 1.17.1 → 1.20.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/index.cjs CHANGED
@@ -1 +1 @@
1
- var e=Object.create,t=Object.defineProperty,__name=(e,n)=>t(e,`name`,{value:n,configurable:!0}),n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,__copyProps=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},__toESM=(n,r,a)=>(a=n==null?{}:e(i(n)),__copyProps(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let o=require(`@stackone/utils`),s=require(`@stackone/redaction`),c=require(`@aws-sdk/client-s3`),l=require(`@stackone/transport`),u=require(`kafkajs`),d=require(`node:http`);d=__toESM(d);const f=[`x-datadog-parent-id`,`x-datadog-sampling-priority`,`x-datadog-tags`,`x-datadog-trace-id`,`x-forwarded-proto`,`x-forwarded-port`,`x-forwarded-for`,`x-amzn-trace-id`,`traceparent`,`tracestate`,`x-request-nonce`,`x-signing-method`,`x-signature`,`host`,`via`],p=[`refresh_authentication`],m=10*1024*1024;var AdvancedSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, advanced sink will not function`,category:`AdvancedSink`});return}}async sendAction(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send action`,category:`AdvancedSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,statusCode:t.statusCode,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending action to advanced sink`,category:`AdvancedSink`});return}if(n.errorsOnly&&t.success){this.#t?.debug({message:`Advanced sink errorsOnly is enabled, skipping successful action for ${e.mode||`action`}`,category:`AdvancedSink`});return}if(this.isBackgroundLog(e)&&!n.includeBackground){this.#t?.debug({message:`Advanced sink is configured to exclude background logs, skipping action with mode ${e.mode}`,category:`AdvancedSink`});return}let r=this.createActionS3(e,t,n?.ttl);await this.send(r)}async sendStep(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send step`,category:`AdvancedSink`,context:{actionRunId:e.actionRunId,success:t.success,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending step to advanced sink`,category:`AdvancedSink`});return}let r=this.createStepS3(e,t,n?.ttl);await this.send(r)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from advanced sink`,category:`AdvancedSink`});return}let r=process.env.ADVANCED_LOGS_BUCKET;if(!r)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);try{let i=new c.GetObjectCommand({Bucket:r,Key:`${e}/${t}/${n}/${n}.json`}),a=await this.#e.send(i);if(!a.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`AdvancedSink`});return}let o=await a.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved advanced log from S3 for actionRunId ${n}`,category:`AdvancedSink`}),o}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Advanced log not found in S3 for actionRunId ${n}`,category:`AdvancedSink`});return}throw this.#t?.error({message:`Error when getting advanced log from S3 for actionRunId ${n}`,error:e,code:`AdvancedLogReadError`,category:`AdvancedSink`}),e}}async send(e,t){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to advanced sink`,category:`AdvancedSink`});return}let n=process.env.ADVANCED_LOGS_BUCKET;if(!n)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);let r=`ttl=30d`;typeof t==`number`&&(t===1?r=`ttl=1d`:t===7&&(r=`ttl=7d`));let i=Math.floor(Date.now()/1e3)+(t??30)*24*60*60;this.#t?.debug({message:`Storing advanced log in S3 bucket ${n} with ttl of ${r}`,category:`AdvancedSink`,context:{bucket:n,key:e.Key,ttlTag:r,expiresAt:new Date(i*1e3).toISOString()}});try{await this.#e.send(new c.PutObjectCommand({Bucket:n,Key:e.Key,Body:e.Body,ContentType:e.ContentType,Expires:new Date(i*1e3),Tagging:r}))}catch(t){throw this.#t?.error({message:`Failed to write advanced logs to S3 at ${e.Key}`,error:t,code:`AdvancedLogWriteError`,category:`AdvancedSink`}),t}}createActionS3(e,t,n){let r=`${t.organizationId}/${t.projectSecureId}/${t.actionRunId}/${t.actionRunId}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeActionResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}createStepS3(e,t,n){let r=`${e.organizationId}/${e.projectSecureId}/${e.actionRunId}/steps/${e.stepIndex}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeStepResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}serializeActionResult(e,t,n,r){let i=(0,s.redactObject)({req:{...e.headers&&{headers:{...e.headers}}},res:{...t.headers&&{headers:{...t.headers}}}},s.CensorType.PARTIAL),a=i.req?.headers,o=i.res?.headers,c=(0,s.redactObject)(e.body,s.CensorType.PARTIAL),l=(0,s.redactObject)(t.body,s.CensorType.PARTIAL),u=this.isBackgroundLog(e),d={data:{request:{id:t.actionRunId,actionId:t.actionId,method:t.httpMethod,headers:this.filterHeaders(a),url:{url:e.url,path:e.pathParams,queryParams:e.queryParams},body:c},response:{statusCode:t.statusCode??500,headers:this.filterHeaders(o),body:l},...u?{isBackgroundLog:!0}:{}},metadata:{...u?{isBackgroundLog:!0}:{},expirationTime:n},expirationTime:n};return this.serializeAndLimit(d,r)}serializeStepResult(e,t,n,r){let i={data:{id:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,input:e.inputs,outputs:t.outputs,errors:t.errors},metadata:{expirationTime:n}};return this.serializeAndLimit(i,r)}serializeAndLimit(e,t){let n=JSON.stringify(e);if(Buffer.byteLength(n,`utf8`)>t){let t={...e,data:{outputs:{error:`Error.TOO_LARGE`}}};n=JSON.stringify(t)}return n}filterHeaders(e){if(!e)return;let t={},n=f.map(e=>e.toLowerCase());for(let[r,i]of Object.entries(e))n.includes(r.toLowerCase())||(t[r]=i);return t}isDataSyncRequest(e){return e.mode===`data_sync`}isBackgroundLog(e){return(0,o.notMissing)(e.mode)&&p.includes(e.mode)}getContentType(e){if(!e)return;let t=[`content-type`,`contenttype`];return Object.entries(e).find(([e])=>t.includes(e.toLowerCase()))?.[1]?.toString()}};const buildS3Client=(e,t)=>{try{return new c.S3Client(e)??void 0}catch(e){let n=e;t?.error({message:`Error building s3 client: ${n.message}`,error:n,code:`BuildS3ClientError`,category:`buildS3Client`});return}};var DefenderSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, defender sink will not function`,category:`DefenderSink`});return}}async sendAction(e,t,n){if(this.#t?.debug({message:`Defender sink called to send action`,category:`DefenderSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,statusCode:t.statusCode,options:{enabled:n?.enabled}}}),!n?.enabled){this.#t?.debug({message:`Defender sink is disabled, skipping sending action to defender sink`,category:`DefenderSink`});return}let r=this.createActionS3(t);await this.send(r)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from defender sink`,category:`DefenderSink`});return}let r=process.env.DEFENDER_LOGS_BUCKET;if(!r)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);try{let i=new c.GetObjectCommand({Bucket:r,Key:this.generateS3Key(e,t,n)}),a=await this.#e.send(i);if(!a.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`DefenderSink`});return}let o=await a.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved defender log from S3 for actionRunId ${n}`,category:`DefenderSink`}),o}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Defender log not found in S3 for actionRunId ${n}`,category:`DefenderSink`});return}throw this.#t?.error({message:`Error when getting defender log from S3 for actionRunId ${n}`,error:e,code:`DefenderLogReadError`,category:`DefenderSink`}),e}}async send(e){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to defender sink`,category:`DefenderSink`});return}let t=process.env.DEFENDER_LOGS_BUCKET;if(!t)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);this.#t?.debug({message:`Storing defender log in S3 bucket ${t}`,category:`DefenderSink`,context:{bucket:t,key:e.Key}});try{await this.#e.send(new c.PutObjectCommand({Bucket:t,Key:e.Key,Body:e.Body,ContentType:e.ContentType}))}catch(t){throw this.#t?.error({message:`Failed to write defender logs to S3 at ${e.Key}`,error:t,code:`DefenderLogWriteError`,category:`DefenderSink`}),t}}generateS3Key(e,t,n){return`${e}/${t}/${n}/defender.json`}createActionS3(e){let t=e.organizationId,n=e.projectSecureId;return{Key:this.generateS3Key(t,n,e.actionRunId),Body:this.serializeDefenderContext(e),ContentType:`application/json`}}serializeDefenderContext(e){let t=e.defenderContext;return t?JSON.stringify(t):JSON.stringify({data:null,metadata:null})}};const buildHttpClient=e=>{try{return new l.HttpClient({logger:e})}catch(t){let n=t;e?.error({message:`Error building http client: ${n.message}`,error:n,code:`BuildHttpClientError`,category:`buildHttpClient`});return}},buildKafkaClient=(e,t)=>{try{return new u.Kafka(e)??void 0}catch(e){let n=e;t?.error({message:`Error building kafka client: ${n.message}`,error:n,code:`BuildKafkaClientError`,category:`buildKafkaClient`});return}},safeSerialize=e=>{try{return JSON.stringify(e)}catch{return`[Unserializable payload]`}};var TinybirdClient=class{#e;#t;#n;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async query(e){if(!this.#e)throw this.#n?.error({message:`HTTP client not initialized, cannot perform Tinybird query`,category:`TinybirdClient`,code:`HttpClientNotReady`}),Error(`HTTP client is not initialized`);if(!this.#t?.token)throw this.#n?.warning({message:`Missing OLAP token, cannot perform Tinybird query`,category:`TinybirdClient`}),Error(`TinybirdClient - Missing token`);let t=new URL(`/v0/pipes/${e.endpoint}`,this.#t.baseUrl);try{this.#n?.debug({message:`Querying Tinybird endpoint: ${e.endpoint}`,category:`TinybirdClient`,context:{endpoint:e.endpoint,params:e.params}});let n=await this.#e.request({method:`post`,url:t.toString(),payload:e.params,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.#t.token}`},...this.#t.allowHttp&&{httpAgent:this.#r()}}),r=n.data.data;return this.#n?.debug({message:`Tinybird query returned ${r.length} rows`,category:`TinybirdClient`,context:{endpoint:e.endpoint,rows:n.data.rows,statistics:n.data.statistics}}),r}catch(t){let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}async queryWithPagination(e){if(!this.#e)throw this.#n?.error({message:`HTTP client not initialized, cannot perform Tinybird query`,category:`TinybirdClient`,code:`HttpClientNotReady`}),Error(`HTTP client is not initialized`);if(!this.#t?.token)throw this.#n?.warning({message:`Missing OLAP token, cannot perform Tinybird query`,category:`TinybirdClient`}),Error(`TinybirdClient - Missing token`);let t=new URL(`/v0/pipes/${e.endpoint}`,this.#t.baseUrl);try{let n=await this.#e.request({method:`post`,url:t.toString(),payload:e.params,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.#t.token}`},...this.#t.allowHttp&&{httpAgent:this.#r()}}),r=n.data.data;return{data:r,total:n.data.rows_before_limit_at_least??n.data.rows??r.length,pageNumber:e.pageNumber??1,pageSize:e.pageSize??r.length}}catch(t){let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}isReady(){return!!(this.#e&&this.#t?.token)}#r(){return new d.default.Agent({})}};const h=`project_actions_logs.json`,g=`project_steps_logs.json`;var LogsSink=class{#e;#t;#n;#r;constructor(e,t,n,r){this.#e=e,this.#r=r,this.#n=new TinybirdClient(t,n,r)}async initialize(){if(!this.#e){this.#r?.warning({message:`No kafka client provided, logs sink cannot be initialized`,category:`LogsSink`});return}if(this.#n?.isReady()||this.#r?.warning({message:`Tinybird client is not ready (missing HTTP client or Tinybird config/token), logs sink will not be able to query`,category:`LogsSink`}),!this.#t){try{this.#t=this.#e.producer({createPartitioner:u.Partitioners.DefaultPartitioner})}catch(e){this.#r?.error({message:`Failed to create kafka producer for logs sink`,code:`KafkaProducerCreationError`,category:`LogsSink`,error:e}),this.#t=void 0;return}try{await this.#t.connect()}catch(e){this.#r?.error?.({message:`Failed to connect kafka producer for logs sink`,code:`KafkaProducerConnectionError`,category:`LogsSink`,error:e}),this.#t=void 0;return}this.#r?.info({message:`Logs sink kafka producer initialized`,category:`LogsSink`})}}async sendAction(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending action to log sink`,category:`KafkaSink`});return}let r=this.buildActionLog(e,t);await this.send(`actions`,r)}async sendStep(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending step to log sink`,category:`KafkaSink`});return}let r=this.buildStepLog(e,t);await this.send(`steps`,r)}async getAction(e){return(await this.getActions({actionRunId:e})).actionLogs[0]}async getActions(e){try{this.#r?.info({message:`Querying action logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_actions_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} action logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{actionLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#n?.isReady()?this.#r?.warning({message:`Failed to query Tinybird for action logs, returning empty results`,category:`LogsSink`,error:t}):this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async getSteps(e){return(await this.querySteps({actionRunId:e})).stepLogs}async querySteps(e){try{this.#r?.info({message:`Querying step logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_steps_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} step logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{stepLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async send(e,t){if(!this.#t)throw this.#r?.error({message:`Kafka not initialized, dropping message for topic ${e}`,category:`KafkaSink`,code:`KafkaNotReady`}),Error(`Kafka client is not initialized`);let n=safeSerialize(t);this.#r?.debug({message:`Sending to topic ${e}: ${n}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:n}]});this.#r?.debug({message:`Kafka producer response: ${JSON.stringify(t)}`,category:`KafkaSink`})}catch(t){throw this.#r?.error({message:`Error sending to topic ${e}: ${t.message}`,category:`KafkaSink`,error:t,code:`KafkaSendError`}),t}}buildActionLog(e,t){return Object.fromEntries(Object.entries({actionRunId:t.actionRunId,actionId:t.actionId,organizationId:String(t.organizationId),projectSecureId:t.projectSecureId,accountSecureId:t.accountSecureId,mode:e.mode,connectorKey:t.connectorKey,connectorVersion:t.connectorVersion,actionType:t.actionType,category:t.category,originOwnerId:t.originOwnerId,originOwnerName:t.originOwnerName,httpMethod:t.httpMethod,url:t.url,sourceId:e.sourceId,sourceType:e.sourceType,sourceValue:e.sourceValue,success:t.success,statusCode:t.statusCode,riskLevel:t.defenderContext?.riskLevel,tier2Score:t.defenderContext?.tier2Score,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}buildStepLog(e,t){return Object.fromEntries(Object.entries({actionRunId:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,organizationId:String(e.organizationId),projectSecureId:String(e.projectSecureId),accountSecureId:String(e.accountSecureId),skipped:t.skipped,success:t.success,message:t.message,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}calculateDuration(e,t){if(!(e instanceof Date)||!(t instanceof Date))return;let n=e.getTime(),r=t.getTime();if(!(Number.isNaN(n)||Number.isNaN(r)||r<n))return r-n}};const _={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1,includeBackground:!1},defender:{enabled:!0}};function resolveOlapOptions(e){return{logs:{..._.logs,...e?.logs},advanced:{..._.advanced,...e?.advanced},defender:{..._.defender,...e?.defender}}}var OlapClient=class{#e;#t;#n;#r;#i;#a;#o;constructor({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={}){this.name=`OlapClient`,this.#e=e(r,o),this.#t=t(o),this.#n=n(i,o),this.#r=o,this.#i=new LogsSink(this.#e,this.#t,a,this.#r),this.#a=new AdvancedSink(this.#n,this.#r),this.#o=new DefenderSink(this.#n,this.#r)}async initialize(){await this.#i?.initialize(),await this.#a?.initialize(),await this.#o?.initialize()}async recordAction(e,t,n){let{logs:r,advanced:i,defender:a}=resolveOlapOptions(n);if(this.#r?.debug({message:`Olap client called to record action`,category:`OlapClient`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,options:n,resolvedOptions:{logs:r,advanced:i,defender:a}}}),r?.enabled)try{await this.#i?.sendAction(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendAction(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to advanced logs s3: ${e.message}`,category:`OlapClient`,error:e})}if(a?.enabled)try{await this.#o?.sendAction(e,t,a)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to defender logs s3: ${e.message}`,category:`OlapClient`,error:e})}}async recordStep(e,t,n){let{logs:r,advanced:i}=resolveOlapOptions(n);if(r?.enabled)try{await this.#i?.sendStep(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendStep(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}async getActions(e,t,n){return this.#r?.debug({message:`Querying action logs`,category:`OlapClient`,context:{query:n}}),await this.#i?.getActions({...n,organizationId:e,projectSecureId:t})||(this.#r?.warning({message:`Failed to query action logs, returning empty result`,category:`OlapClient`}),{actionLogs:[],total:0,pageNumber:n.pageNumber??1,pageSize:n.pageSize??0})}async getAction(e,t,n){let r=await this.#i?.getActions({organizationId:e,projectSecureId:t,actionRunId:n});if((0,o.isMissing)(r)||r.actionLogs.length===0){this.#r?.debug({message:`Failed to retrieve action log for actionRunId ${n}`,category:`OlapClient`});return}return r.actionLogs[0]}async getAdvanced(e,t,n){let r=await this.#a?.getAction(e,t,n);if((0,o.isMissing)(r)){this.#r?.debug({message:`Failed to retrieve advanced log for actionRunId ${n}`,category:`OlapClient`});return}return r}async getDefender(e,t,n){let r=await this.#o?.getAction(e,t,n);if((0,o.isMissing)(r)){this.#r?.debug({message:`Failed to retrieve defender log for actionRunId ${n}`,category:`OlapClient`});return}return r}};const buildOlapClientInstance=async({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={})=>{let s=new OlapClient({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o});return await s.initialize(),s};var OlapClientManager=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o,getOlapClient:s=buildOlapClientInstance}={}){return this.olapClientPromise||=s({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}),this.olapClientPromise}static resetInstance(){this.olapClientPromise=null}};exports.OlapClient=OlapClient,exports.OlapClientManager=OlapClientManager;
1
+ var e=Object.create,t=Object.defineProperty,__name=(e,n)=>t(e,`name`,{value:n,configurable:!0}),n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,__copyProps=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},__toESM=(n,r,a)=>(a=n==null?{}:e(i(n)),__copyProps(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let o=require(`@stackone/utils`),s=require(`@stackone/redaction`),c=require(`@aws-sdk/client-s3`),l=require(`@stackone/transport`),u=require(`kafkajs`),d=require(`node:http`);d=__toESM(d);const f=[`x-datadog-parent-id`,`x-datadog-sampling-priority`,`x-datadog-tags`,`x-datadog-trace-id`,`x-forwarded-proto`,`x-forwarded-port`,`x-forwarded-for`,`x-amzn-trace-id`,`traceparent`,`tracestate`,`x-request-nonce`,`x-signing-method`,`x-signature`,`host`,`via`],p=[`refresh_authentication`],m=10*1024*1024;var AdvancedSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, advanced sink will not function`,category:`AdvancedSink`});return}}async sendAction(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send action`,category:`AdvancedSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,statusCode:t.statusCode,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending action to advanced sink`,category:`AdvancedSink`});return}if(n.errorsOnly&&t.success){this.#t?.debug({message:`Advanced sink errorsOnly is enabled, skipping successful action for ${e.mode||`action`}`,category:`AdvancedSink`});return}if(this.isBackgroundLog(e)&&!n.includeBackground){this.#t?.debug({message:`Advanced sink is configured to exclude background logs, skipping action with mode ${e.mode}`,category:`AdvancedSink`});return}let r=this.createActionS3(e,t,n?.ttl);await this.send(r)}async sendStep(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send step`,category:`AdvancedSink`,context:{actionRunId:e.actionRunId,success:t.success,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending step to advanced sink`,category:`AdvancedSink`});return}let r=this.createStepS3(e,t,n?.ttl);await this.send(r)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from advanced sink`,category:`AdvancedSink`});return}let r=process.env.ADVANCED_LOGS_BUCKET;if(!r)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);try{let i=new c.GetObjectCommand({Bucket:r,Key:`${e}/${t}/${n}/${n}.json`}),a=await this.#e.send(i);if(!a.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`AdvancedSink`});return}let o=await a.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved advanced log from S3 for actionRunId ${n}`,category:`AdvancedSink`}),JSON.parse(o)}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Advanced log not found in S3 for actionRunId ${n}`,category:`AdvancedSink`});return}throw this.#t?.error({message:`Error when getting advanced log from S3 for actionRunId ${n}`,error:e,code:`AdvancedLogReadError`,category:`AdvancedSink`}),e}}async getStep(e,t,n,r){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get step log from advanced sink`,category:`AdvancedSink`});return}let i=process.env.ADVANCED_LOGS_BUCKET;if(!i)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);try{let a=new c.GetObjectCommand({Bucket:i,Key:`${e}/${t}/${n}/steps/${r}.json`}),o=await this.#e.send(a);if(!o.Body){this.#t?.warning({message:`Received empty body when trying to get step log from S3 for actionRunId ${n} stepIndex ${r}`,category:`AdvancedSink`});return}let s=await o.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved step log from S3 for actionRunId ${n} stepIndex ${r}`,category:`AdvancedSink`}),JSON.parse(s)}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Step log not found in S3 for actionRunId ${n} stepIndex ${r}`,category:`AdvancedSink`});return}throw this.#t?.error({message:`Error when getting step log from S3 for actionRunId ${n} stepIndex ${r}`,error:e,code:`AdvancedLogReadError`,category:`AdvancedSink`}),e}}async send(e,t){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to advanced sink`,category:`AdvancedSink`});return}let n=process.env.ADVANCED_LOGS_BUCKET;if(!n)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);let r=`ttl=30d`;typeof t==`number`&&(t===1?r=`ttl=1d`:t===7&&(r=`ttl=7d`));let i=Math.floor(Date.now()/1e3)+(t??30)*24*60*60;this.#t?.debug({message:`Storing advanced log in S3 bucket ${n} with ttl of ${r}`,category:`AdvancedSink`,context:{bucket:n,key:e.Key,ttlTag:r,expiresAt:new Date(i*1e3).toISOString()}});try{await this.#e.send(new c.PutObjectCommand({Bucket:n,Key:e.Key,Body:e.Body,ContentType:e.ContentType,Expires:new Date(i*1e3),Tagging:r}))}catch(t){throw this.#t?.error({message:`Failed to write advanced logs to S3 at ${e.Key}`,error:t,code:`AdvancedLogWriteError`,category:`AdvancedSink`}),t}}createActionS3(e,t,n){let r=`${t.organizationId}/${t.projectSecureId}/${t.actionRunId}/${t.actionRunId}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeActionResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}createStepS3(e,t,n){let r=`${e.organizationId}/${e.projectSecureId}/${e.actionRunId}/steps/${e.stepIndex}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeStepResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}serializeActionResult(e,t,n,r){let i=(0,s.redactObject)({req:{...e.headers&&{headers:{...e.headers}}},res:{...t.headers&&{headers:{...t.headers}}}},s.CensorType.PARTIAL),a=i.req?.headers,o=i.res?.headers,c=(0,s.redactObject)(e.body,s.CensorType.PARTIAL),l=(0,s.redactObject)(t.body,s.CensorType.PARTIAL),u=this.isBackgroundLog(e),d={data:{request:{id:t.actionRunId,actionId:t.actionId,method:t.httpMethod,headers:this.filterHeaders(a),url:{url:e.url,path:e.pathParams,queryParams:e.queryParams},body:c},response:{statusCode:t.statusCode??500,headers:this.filterHeaders(o),body:l},...u?{isBackgroundLog:!0}:{}},metadata:{...u?{isBackgroundLog:!0}:{},expirationTime:n}};return this.serializeAndLimit(d,r)}serializeStepResult(e,t,n,r){let i={data:{id:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,input:e.inputs,outputs:t.outputs,errors:t.errors},metadata:{expirationTime:n}};return this.serializeAndLimit(i,r)}serializeAndLimit(e,t){let n=JSON.stringify(e);if(Buffer.byteLength(n,`utf8`)>t){let t={...e,data:{outputs:{error:`Error.TOO_LARGE`}}};n=JSON.stringify(t)}return n}filterHeaders(e){if(!e)return;let t={},n=f.map(e=>e.toLowerCase());for(let[r,i]of Object.entries(e))n.includes(r.toLowerCase())||(t[r]=i);return t}isDataSyncRequest(e){return e.mode===`data_sync`}isBackgroundLog(e){return(0,o.notMissing)(e.mode)&&p.includes(e.mode)}getContentType(e){if(!e)return;let t=[`content-type`,`contenttype`];return Object.entries(e).find(([e])=>t.includes(e.toLowerCase()))?.[1]?.toString()}};const buildS3Client=(e,t)=>{try{return new c.S3Client(e)??void 0}catch(e){let n=e;t?.error({message:`Error building s3 client: ${n.message}`,error:n,code:`BuildS3ClientError`,category:`buildS3Client`});return}};var DefenderSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, defender sink will not function`,category:`DefenderSink`});return}}async sendAction(e,t,n){if(this.#t?.debug({message:`Defender sink called to send action`,category:`DefenderSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,statusCode:t.statusCode,options:{enabled:n?.enabled}}}),(0,o.isMissing)(t.defenderContext)){this.#t?.debug({message:`No defender context in action result, skipping sending action to defender sink`,category:`DefenderSink`,context:{actionRunId:t.actionRunId}});return}if(!n?.enabled){this.#t?.debug({message:`Defender sink is disabled, skipping sending action to defender sink`,category:`DefenderSink`});return}let r=this.createActionS3(t);await this.send(r)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from defender sink`,category:`DefenderSink`});return}let r=process.env.DEFENDER_LOGS_BUCKET;if(!r)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);try{let i=new c.GetObjectCommand({Bucket:r,Key:this.generateS3Key(e,t,n)}),a=await this.#e.send(i);if(!a.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`DefenderSink`});return}let o=await a.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved defender log from S3 for actionRunId ${n}`,category:`DefenderSink`}),JSON.parse(o)}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Defender log not found in S3 for actionRunId ${n}`,category:`DefenderSink`});return}throw this.#t?.error({message:`Error when getting defender log from S3 for actionRunId ${n}`,error:e,code:`DefenderLogReadError`,category:`DefenderSink`}),e}}async send(e){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to defender sink`,category:`DefenderSink`});return}let t=process.env.DEFENDER_LOGS_BUCKET;if(!t)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);this.#t?.debug({message:`Storing defender log in S3 bucket ${t}`,category:`DefenderSink`,context:{bucket:t,key:e.Key}});try{await this.#e.send(new c.PutObjectCommand({Bucket:t,Key:e.Key,Body:e.Body,ContentType:e.ContentType}))}catch(t){throw this.#t?.error({message:`Failed to write defender logs to S3 at ${e.Key}`,error:t,code:`DefenderLogWriteError`,category:`DefenderSink`}),t}}generateS3Key(e,t,n){return`${e}/${t}/${n}/defender.json`}createActionS3(e){let t=e.organizationId,n=e.projectSecureId;return{Key:this.generateS3Key(t,n,e.actionRunId),Body:JSON.stringify(e.defenderContext),ContentType:`application/json`}}};const buildHttpClient=e=>{try{return new l.HttpClient({logger:e})}catch(t){let n=t;e?.error({message:`Error building http client: ${n.message}`,error:n,code:`BuildHttpClientError`,category:`buildHttpClient`});return}},buildKafkaClient=(e,t)=>{try{return new u.Kafka(e)??void 0}catch(e){let n=e;t?.error({message:`Error building kafka client: ${n.message}`,error:n,code:`BuildKafkaClientError`,category:`buildKafkaClient`});return}},safeSerialize=e=>{try{return JSON.stringify(e)}catch{return`[Unserializable payload]`}};var SchemaValidationError=class extends Error{constructor(e,t){super(e),this.name=`SchemaValidationError`,this.cause=t}},TinybirdClient=class{#e;#t;#n;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async query(e){try{let t=await this.#o(e.endpoint,e.params);return this.#a(t.data,e.schema)}catch(t){if(t instanceof SchemaValidationError)throw t;let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}async queryWithPagination(e){try{let t=await this.#o(e.endpoint,e.params),n=this.#a(t.data,e.schema);return{data:n,total:t.rows_before_limit_at_least??t.rows??n.length,pageNumber:e.pageNumber??1,pageSize:e.pageSize??n.length}}catch(t){if(t instanceof SchemaValidationError)throw t;let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}async queryRaw(e){try{let t=await this.#o(e.endpoint,e.params);return t.data=this.#a(t.data,e.schema),t}catch(t){if(t instanceof SchemaValidationError)throw t;let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}isReady(){return!!(this.#e&&this.#t?.token)}#r(){return new d.default.Agent({})}#i(){if(!this.#e)throw this.#n?.error({message:`HTTP client not initialized, cannot perform Tinybird query`,category:`TinybirdClient`,code:`HttpClientNotReady`}),Error(`HTTP client is not initialized`);if(!this.#t?.token)throw this.#n?.warning({message:`Missing OLAP token, cannot perform Tinybird query`,category:`TinybirdClient`}),Error(`TinybirdClient - Missing token`)}#a(e,t){if(!t)return e;try{let n=e.map(e=>t.parse(e));return this.#n?.debug({message:`Schema validation passed for ${n.length} rows`,category:`TinybirdClient`}),n}catch(e){let t=e instanceof Error?e.message:String(e);throw this.#n?.error({message:`Schema validation failed: ${t}`,category:`TinybirdClient`,code:`SchemaValidationError`,error:e}),new SchemaValidationError(t,e)}}async#o(e,t){this.#i();let n=this.#e,r=this.#t;if(!n||!r)throw Error(`Client validation failed`);let i=new URL(`/v0/pipes/${e}`,r.baseUrl);this.#n?.debug({message:`Querying Tinybird endpoint: ${e}`,category:`TinybirdClient`,context:{endpoint:e,params:t}});let a=await n.request({method:`post`,url:i.toString(),payload:t,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${r.token}`},...r.allowHttp&&{httpAgent:this.#r()}});return this.#n?.debug({message:`Tinybird query returned ${a.data.data.length} rows`,category:`TinybirdClient`,context:{endpoint:e,rows:a.data.rows,statistics:a.data.statistics}}),a.data}};const h=`project_actions_logs.json`,g=`project_steps_logs.json`;var LogsSink=class{#e;#t;#n;#r;constructor(e,t,n,r){this.#e=e,this.#r=r,this.#n=new TinybirdClient(t,n,r)}get tinybirdClient(){return this.#n}async initialize(){if(!this.#e){this.#r?.warning({message:`No kafka client provided, logs sink cannot be initialized`,category:`LogsSink`});return}if(this.#n?.isReady()||this.#r?.warning({message:`Tinybird client is not ready (missing HTTP client or Tinybird config/token), logs sink will not be able to query`,category:`LogsSink`}),!this.#t){try{this.#t=this.#e.producer({createPartitioner:u.Partitioners.DefaultPartitioner})}catch(e){this.#r?.error({message:`Failed to create kafka producer for logs sink`,code:`KafkaProducerCreationError`,category:`LogsSink`,error:e}),this.#t=void 0;return}try{await this.#t.connect()}catch(e){this.#r?.error?.({message:`Failed to connect kafka producer for logs sink`,code:`KafkaProducerConnectionError`,category:`LogsSink`,error:e}),this.#t=void 0;return}this.#r?.info({message:`Logs sink kafka producer initialized`,category:`LogsSink`})}}async sendAction(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending action to log sink`,category:`KafkaSink`});return}let r=this.buildActionLog(e,t);await this.send(`actions`,r)}async sendStep(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending step to log sink`,category:`KafkaSink`});return}let r=this.buildStepLog(e,t);await this.send(`steps`,r)}async getActions(e){try{this.#r?.info({message:`Querying action logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_actions_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} action logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{actionLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#n?.isReady()?this.#r?.warning({message:`Failed to query Tinybird for action logs, returning empty results`,category:`LogsSink`,error:t}):this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async getAction(e,t,n){return(await this.getActions({organizationId:e,projectSecureId:t,actionRunId:n})).actionLogs[0]}async getSteps(e){try{this.#r?.info({message:`Querying step logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_steps_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} step logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{stepLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async getStep(e,t,n,r){return(await this.getSteps({organizationId:e,projectSecureId:t,actionRunId:n,stepIndex:r})).stepLogs[0]}async send(e,t){if(!this.#t)throw this.#r?.error({message:`Kafka not initialized, dropping message for topic ${e}`,category:`KafkaSink`,code:`KafkaNotReady`}),Error(`Kafka client is not initialized`);let n=safeSerialize(t);this.#r?.debug({message:`Sending to topic ${e}: ${n}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:n}]});this.#r?.debug({message:`Kafka producer response: ${JSON.stringify(t)}`,category:`KafkaSink`})}catch(t){throw this.#r?.error({message:`Error sending to topic ${e}: ${t.message}`,category:`KafkaSink`,error:t,code:`KafkaSendError`}),t}}buildActionLog(e,t){return Object.fromEntries(Object.entries({actionRunId:t.actionRunId,actionId:t.actionId,organizationId:String(t.organizationId),projectSecureId:t.projectSecureId,accountSecureId:t.accountSecureId,mode:e.mode,connectorKey:t.connectorKey,connectorVersion:t.connectorVersion,actionType:t.actionType,category:t.category,originOwnerId:t.originOwnerId,originOwnerName:t.originOwnerName,httpMethod:t.httpMethod,url:t.url,sourceId:e.sourceId,sourceType:e.sourceType,sourceValue:e.sourceValue,success:t.success,statusCode:t.statusCode,riskLevel:t.defenderContext?.riskLevel,tier2Score:t.defenderContext?.tier2Score,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}buildStepLog(e,t){return Object.fromEntries(Object.entries({actionRunId:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,organizationId:String(e.organizationId),projectSecureId:String(e.projectSecureId),accountSecureId:String(e.accountSecureId),skipped:t.skipped,success:t.success,message:t.message,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}calculateDuration(e,t){if(!(e instanceof Date)||!(t instanceof Date))return;let n=e.getTime(),r=t.getTime();if(!(Number.isNaN(n)||Number.isNaN(r)||r<n))return r-n}};const _={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1,includeBackground:!1},defender:{enabled:!0}};function resolveOlapOptions(e){return{logs:{..._.logs,...e?.logs},advanced:{..._.advanced,...e?.advanced},defender:{..._.defender,...e?.defender}}}var OlapClient=class{#e;#t;#n;#r;#i;#a;#o;constructor({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={}){this.name=`OlapClient`,this.#e=e(r,o),this.#t=t(o),this.#n=n(i,o),this.#r=o,this.#i=new LogsSink(this.#e,this.#t,a,this.#r),this.#a=new AdvancedSink(this.#n,this.#r),this.#o=new DefenderSink(this.#n,this.#r)}async initialize(){await this.#i?.initialize(),await this.#a?.initialize(),await this.#o?.initialize()}get tinybirdClient(){return this.#i?.tinybirdClient}async recordAction(e,t,n){let{logs:r,advanced:i,defender:a}=resolveOlapOptions(n);if(this.#r?.debug({message:`Olap client called to record action`,category:`OlapClient`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,options:n,resolvedOptions:{logs:r,advanced:i,defender:a}}}),r?.enabled)try{await this.#i?.sendAction(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendAction(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to advanced logs s3: ${e.message}`,category:`OlapClient`,error:e})}if(a?.enabled)try{await this.#o?.sendAction(e,t,a)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to defender logs s3: ${e.message}`,category:`OlapClient`,error:e})}}async recordStep(e,t,n){let{logs:r,advanced:i}=resolveOlapOptions(n);if(r?.enabled)try{await this.#i?.sendStep(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendStep(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}async getActionLogs(e,t,n){return this.#r?.debug({message:`Querying action logs`,category:`OlapClient`,context:{query:n}}),await this.#i?.getActions({...n,organizationId:e,projectSecureId:t})||(this.#r?.warning({message:`Failed to query action logs, returning empty result`,category:`OlapClient`}),{actionLogs:[],total:0,pageNumber:n.pageNumber??1,pageSize:n.pageSize??0})}async getActionLog(e,t,n){let r=await this.#i?.getAction(e,t,n);if((0,o.isMissing)(r)){this.#r?.debug({message:`Failed to retrieve action log for actionRunId ${n}`,category:`OlapClient`});return}return r}async getStepLogs(e,t,n){return this.#r?.debug({message:`Querying step logs`,category:`OlapClient`,context:{query:n}}),await this.#i?.getSteps({...n,organizationId:e,projectSecureId:t})||(this.#r?.warning({message:`Failed to query step logs, returning empty result`,category:`OlapClient`}),{stepLogs:[],total:0,pageNumber:n.pageNumber??1,pageSize:n.pageSize??0})}async getStepLog(e,t,n,r){let i=await this.#i?.getStep(e,t,n,r);if((0,o.isMissing)(i)){this.#r?.debug({message:`Failed to retrieve step log for actionRunId ${n} stepIndex ${r}`,category:`OlapClient`});return}return i}async getActionAdvancedLog(e,t,n){let r=await this.#a?.getAction(e,t,n);if((0,o.isMissing)(r)){this.#r?.debug({message:`Failed to retrieve action advanced log for actionRunId ${n}`,category:`OlapClient`});return}return r}async getStepAdvancedLog(e,t,n,r){let i=await this.#a?.getStep(e,t,n,r);if((0,o.isMissing)(i)){this.#r?.debug({message:`Failed to retrieve step advanced log for actionRunId ${n} stepIndex ${r}`,category:`OlapClient`});return}return i}async getDefenderLog(e,t,n){let r=await this.#o?.getAction(e,t,n);if((0,o.isMissing)(r)){this.#r?.debug({message:`Failed to retrieve defender log for actionRunId ${n}`,category:`OlapClient`});return}return r}};const buildOlapClientInstance=async({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={})=>{let s=new OlapClient({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o});return await s.initialize(),s};var OlapClientManager=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o,getOlapClient:s=buildOlapClientInstance}={}){return this.olapClientPromise||=s({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}),this.olapClientPromise}static resetInstance(){this.olapClientPromise=null}};exports.OlapClient=OlapClient,exports.OlapClientManager=OlapClientManager;
package/dist/index.d.cts CHANGED
@@ -90,6 +90,13 @@ type DefenderOptions = {
90
90
  enabled?: boolean;
91
91
  };
92
92
  //#endregion
93
+ //#region src/defender/types.d.ts
94
+ type DefenderLog = {
95
+ riskLevel: string;
96
+ tier2Score: number;
97
+ [key: string]: unknown;
98
+ };
99
+ //#endregion
93
100
  //#region ../transport/src/cacheClient/types.d.ts
94
101
  interface ICacheClient<ClientType = unknown> {
95
102
  getData<T>(key: string): Promise<T | null>;
@@ -145,6 +152,7 @@ interface RedisClientConfig {
145
152
  host?: string;
146
153
  port?: number;
147
154
  tls?: boolean;
155
+ keepAlive?: number;
148
156
  reconnect?: boolean;
149
157
  database?: number;
150
158
  }
@@ -504,6 +512,7 @@ type StepsQuery = {
504
512
  accountSecureId?: string | string[];
505
513
  actionRunId?: string | string[];
506
514
  stepId?: string | string[];
515
+ stepIndex?: number | number[];
507
516
  success?: boolean;
508
517
  startTime?: Date;
509
518
  endTime?: Date;
@@ -521,6 +530,46 @@ interface KafkaClientConfig {
521
530
  brokers: string[];
522
531
  }
523
532
  type KafkaClientBuilder = (config?: KafkaClientConfig, logger?: ILogger) => Kafka | undefined;
533
+ interface TinybirdConfig {
534
+ baseUrl: string;
535
+ token: string;
536
+ allowHttp?: boolean;
537
+ }
538
+ interface TinybirdResponse<T> {
539
+ meta: Array<{
540
+ name: string;
541
+ type: string;
542
+ }>;
543
+ data: T;
544
+ rows: number;
545
+ rows_before_limit_at_least?: number;
546
+ statistics?: {
547
+ elapsed: number;
548
+ rows_read: number;
549
+ bytes_read: number;
550
+ };
551
+ }
552
+ interface TinybirdQueryOptions<TParams = Record<string, unknown>, TResult = unknown> {
553
+ endpoint: string;
554
+ params?: TParams;
555
+ schema?: {
556
+ parse: (data: unknown) => TResult;
557
+ };
558
+ }
559
+ interface ITinybirdClient {
560
+ query<TParams = Record<string, unknown>, TResult = unknown>(options: TinybirdQueryOptions<TParams, TResult>): Promise<TResult[]>;
561
+ queryWithPagination<TParams = Record<string, unknown>, TResult = unknown>(options: TinybirdQueryOptions<TParams, TResult> & {
562
+ pageNumber?: number;
563
+ pageSize?: number;
564
+ }): Promise<{
565
+ data: TResult[];
566
+ total: number;
567
+ pageNumber: number;
568
+ pageSize: number;
569
+ }>;
570
+ queryRaw<TParams = Record<string, unknown>, TResult = unknown>(options: TinybirdQueryOptions<TParams, TResult>): Promise<TinybirdResponse<TResult[]>>;
571
+ isReady(): boolean;
572
+ }
524
573
  type ActionLog = {
525
574
  actionRunId: string;
526
575
  actionId: string;
@@ -567,10 +616,13 @@ type StepLog = {
567
616
  interface IOlapClient {
568
617
  recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): void;
569
618
  recordStep(stepInput: StepInput, stepResult: StepResult, options?: OlapOptions): void;
570
- getActions(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
571
- getAction(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
572
- getAdvanced(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
573
- getDefender(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
619
+ getActionLogs(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
620
+ getActionLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
621
+ getStepLogs(organizationId: string, projectSecureId: string, query: StepsQuery): Promise<StepsQueryResult>;
622
+ getStepLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepLog | undefined>;
623
+ getActionAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionAdvancedLog | undefined>;
624
+ getStepAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepAdvancedLog | undefined>;
625
+ getDefenderLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<DefenderLog | undefined>;
574
626
  }
575
627
  type DefenderContext = {
576
628
  riskLevel: string;
@@ -638,36 +690,28 @@ type StepResult = {
638
690
  };
639
691
  //#endregion
640
692
  //#region src/advanced/types.d.ts
693
+ type ActionAdvancedLog = {
694
+ data: {
695
+ [key: string]: unknown;
696
+ };
697
+ metadata?: {
698
+ isBackgroundLog?: boolean;
699
+ expirationTime?: number;
700
+ };
701
+ };
702
+ type StepAdvancedLog = {
703
+ data: {
704
+ [key: string]: unknown;
705
+ };
706
+ metadata?: {
707
+ expirationTime?: number;
708
+ };
709
+ };
641
710
  interface S3ClientConfig {
642
711
  region?: string;
643
712
  }
644
713
  type S3ClientBuilder = (config?: S3ClientConfig, logger?: ILogger) => S3Client | undefined;
645
714
  //#endregion
646
- //#region src/logs/tinybirdClient.d.ts
647
- interface TinybirdConfig {
648
- baseUrl: string;
649
- token: string;
650
- allowHttp?: boolean;
651
- }
652
- interface TinybirdResponse<T> {
653
- meta: Array<{
654
- name: string;
655
- type: string;
656
- }>;
657
- data: T;
658
- rows: number;
659
- rows_before_limit_at_least?: number;
660
- statistics?: {
661
- elapsed: number;
662
- rows_read: number;
663
- bytes_read: number;
664
- };
665
- }
666
- interface TinybirdQueryOptions<TParams = Record<string, unknown>> {
667
- endpoint: string;
668
- params?: TParams;
669
- }
670
- //#endregion
671
715
  //#region src/olap/olapClient.d.ts
672
716
  declare class OlapClient implements IOlapClient {
673
717
  #private;
@@ -690,12 +734,16 @@ declare class OlapClient implements IOlapClient {
690
734
  logger?: ILogger;
691
735
  });
692
736
  initialize(): Promise<void>;
737
+ get tinybirdClient(): ITinybirdClient | undefined;
693
738
  recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): Promise<void>;
694
739
  recordStep(stepInput: StepInput, stepResult: StepResult, options?: OlapOptions): Promise<void>;
695
- getActions(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
696
- getAction(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
697
- getAdvanced(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
698
- getDefender(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
740
+ getActionLogs(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
741
+ getActionLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
742
+ getStepLogs(organizationId: string, projectSecureId: string, query: StepsQuery): Promise<StepsQueryResult>;
743
+ getStepLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepLog | undefined>;
744
+ getActionAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionAdvancedLog | undefined>;
745
+ getStepAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepAdvancedLog | undefined>;
746
+ getDefenderLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<DefenderLog | undefined>;
699
747
  }
700
748
  //#endregion
701
749
  //#region src/olap/olapClientManager.d.ts
@@ -740,4 +788,4 @@ declare class OlapClientManager {
740
788
  static resetInstance(): void;
741
789
  }
742
790
  //#endregion
743
- export { type ActionInput, type ActionLog, type ActionResult, type ActionsQuery, type ActionsQueryResult, type AdvancedOptions, type DefenderContext, type DefenderOptions, type IOlapClient, type LogsOptions, OlapClient, OlapClientManager, type OlapOptions, type StepInput, type StepLog, type StepResult, type StepsQuery, type StepsQueryResult, type TinybirdConfig, type TinybirdQueryOptions, type TinybirdResponse };
791
+ export { type ActionAdvancedLog, type ActionInput, type ActionLog, type ActionResult, type ActionsQuery, type ActionsQueryResult, type AdvancedOptions, type DefenderContext, type DefenderLog, type DefenderOptions, type IOlapClient, type ITinybirdClient, type LogsOptions, OlapClient, OlapClientManager, type OlapOptions, type StepAdvancedLog, type StepInput, type StepLog, type StepResult, type StepsQuery, type StepsQueryResult, type TinybirdConfig, type TinybirdQueryOptions, type TinybirdResponse };
package/dist/index.d.mts CHANGED
@@ -90,6 +90,13 @@ type DefenderOptions = {
90
90
  enabled?: boolean;
91
91
  };
92
92
  //#endregion
93
+ //#region src/defender/types.d.ts
94
+ type DefenderLog = {
95
+ riskLevel: string;
96
+ tier2Score: number;
97
+ [key: string]: unknown;
98
+ };
99
+ //#endregion
93
100
  //#region ../transport/src/cacheClient/types.d.ts
94
101
  interface ICacheClient<ClientType = unknown> {
95
102
  getData<T>(key: string): Promise<T | null>;
@@ -145,6 +152,7 @@ interface RedisClientConfig {
145
152
  host?: string;
146
153
  port?: number;
147
154
  tls?: boolean;
155
+ keepAlive?: number;
148
156
  reconnect?: boolean;
149
157
  database?: number;
150
158
  }
@@ -504,6 +512,7 @@ type StepsQuery = {
504
512
  accountSecureId?: string | string[];
505
513
  actionRunId?: string | string[];
506
514
  stepId?: string | string[];
515
+ stepIndex?: number | number[];
507
516
  success?: boolean;
508
517
  startTime?: Date;
509
518
  endTime?: Date;
@@ -521,6 +530,46 @@ interface KafkaClientConfig {
521
530
  brokers: string[];
522
531
  }
523
532
  type KafkaClientBuilder = (config?: KafkaClientConfig, logger?: ILogger) => Kafka | undefined;
533
+ interface TinybirdConfig {
534
+ baseUrl: string;
535
+ token: string;
536
+ allowHttp?: boolean;
537
+ }
538
+ interface TinybirdResponse<T> {
539
+ meta: Array<{
540
+ name: string;
541
+ type: string;
542
+ }>;
543
+ data: T;
544
+ rows: number;
545
+ rows_before_limit_at_least?: number;
546
+ statistics?: {
547
+ elapsed: number;
548
+ rows_read: number;
549
+ bytes_read: number;
550
+ };
551
+ }
552
+ interface TinybirdQueryOptions<TParams = Record<string, unknown>, TResult = unknown> {
553
+ endpoint: string;
554
+ params?: TParams;
555
+ schema?: {
556
+ parse: (data: unknown) => TResult;
557
+ };
558
+ }
559
+ interface ITinybirdClient {
560
+ query<TParams = Record<string, unknown>, TResult = unknown>(options: TinybirdQueryOptions<TParams, TResult>): Promise<TResult[]>;
561
+ queryWithPagination<TParams = Record<string, unknown>, TResult = unknown>(options: TinybirdQueryOptions<TParams, TResult> & {
562
+ pageNumber?: number;
563
+ pageSize?: number;
564
+ }): Promise<{
565
+ data: TResult[];
566
+ total: number;
567
+ pageNumber: number;
568
+ pageSize: number;
569
+ }>;
570
+ queryRaw<TParams = Record<string, unknown>, TResult = unknown>(options: TinybirdQueryOptions<TParams, TResult>): Promise<TinybirdResponse<TResult[]>>;
571
+ isReady(): boolean;
572
+ }
524
573
  type ActionLog = {
525
574
  actionRunId: string;
526
575
  actionId: string;
@@ -567,10 +616,13 @@ type StepLog = {
567
616
  interface IOlapClient {
568
617
  recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): void;
569
618
  recordStep(stepInput: StepInput, stepResult: StepResult, options?: OlapOptions): void;
570
- getActions(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
571
- getAction(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
572
- getAdvanced(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
573
- getDefender(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
619
+ getActionLogs(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
620
+ getActionLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
621
+ getStepLogs(organizationId: string, projectSecureId: string, query: StepsQuery): Promise<StepsQueryResult>;
622
+ getStepLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepLog | undefined>;
623
+ getActionAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionAdvancedLog | undefined>;
624
+ getStepAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepAdvancedLog | undefined>;
625
+ getDefenderLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<DefenderLog | undefined>;
574
626
  }
575
627
  type DefenderContext = {
576
628
  riskLevel: string;
@@ -638,36 +690,28 @@ type StepResult = {
638
690
  };
639
691
  //#endregion
640
692
  //#region src/advanced/types.d.ts
693
+ type ActionAdvancedLog = {
694
+ data: {
695
+ [key: string]: unknown;
696
+ };
697
+ metadata?: {
698
+ isBackgroundLog?: boolean;
699
+ expirationTime?: number;
700
+ };
701
+ };
702
+ type StepAdvancedLog = {
703
+ data: {
704
+ [key: string]: unknown;
705
+ };
706
+ metadata?: {
707
+ expirationTime?: number;
708
+ };
709
+ };
641
710
  interface S3ClientConfig {
642
711
  region?: string;
643
712
  }
644
713
  type S3ClientBuilder = (config?: S3ClientConfig, logger?: ILogger) => S3Client | undefined;
645
714
  //#endregion
646
- //#region src/logs/tinybirdClient.d.ts
647
- interface TinybirdConfig {
648
- baseUrl: string;
649
- token: string;
650
- allowHttp?: boolean;
651
- }
652
- interface TinybirdResponse<T> {
653
- meta: Array<{
654
- name: string;
655
- type: string;
656
- }>;
657
- data: T;
658
- rows: number;
659
- rows_before_limit_at_least?: number;
660
- statistics?: {
661
- elapsed: number;
662
- rows_read: number;
663
- bytes_read: number;
664
- };
665
- }
666
- interface TinybirdQueryOptions<TParams = Record<string, unknown>> {
667
- endpoint: string;
668
- params?: TParams;
669
- }
670
- //#endregion
671
715
  //#region src/olap/olapClient.d.ts
672
716
  declare class OlapClient implements IOlapClient {
673
717
  #private;
@@ -690,12 +734,16 @@ declare class OlapClient implements IOlapClient {
690
734
  logger?: ILogger;
691
735
  });
692
736
  initialize(): Promise<void>;
737
+ get tinybirdClient(): ITinybirdClient | undefined;
693
738
  recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): Promise<void>;
694
739
  recordStep(stepInput: StepInput, stepResult: StepResult, options?: OlapOptions): Promise<void>;
695
- getActions(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
696
- getAction(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
697
- getAdvanced(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
698
- getDefender(organizationId: string, projectSecureId: string, actionRunId: string): Promise<string | undefined>;
740
+ getActionLogs(organizationId: string, projectSecureId: string, query: ActionsQuery): Promise<ActionsQueryResult>;
741
+ getActionLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionLog | undefined>;
742
+ getStepLogs(organizationId: string, projectSecureId: string, query: StepsQuery): Promise<StepsQueryResult>;
743
+ getStepLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepLog | undefined>;
744
+ getActionAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<ActionAdvancedLog | undefined>;
745
+ getStepAdvancedLog(organizationId: string, projectSecureId: string, actionRunId: string, stepIndex: number): Promise<StepAdvancedLog | undefined>;
746
+ getDefenderLog(organizationId: string, projectSecureId: string, actionRunId: string): Promise<DefenderLog | undefined>;
699
747
  }
700
748
  //#endregion
701
749
  //#region src/olap/olapClientManager.d.ts
@@ -740,4 +788,4 @@ declare class OlapClientManager {
740
788
  static resetInstance(): void;
741
789
  }
742
790
  //#endregion
743
- export { type ActionInput, type ActionLog, type ActionResult, type ActionsQuery, type ActionsQueryResult, type AdvancedOptions, type DefenderContext, type DefenderOptions, type IOlapClient, type LogsOptions, OlapClient, OlapClientManager, type OlapOptions, type StepInput, type StepLog, type StepResult, type StepsQuery, type StepsQueryResult, type TinybirdConfig, type TinybirdQueryOptions, type TinybirdResponse };
791
+ export { type ActionAdvancedLog, type ActionInput, type ActionLog, type ActionResult, type ActionsQuery, type ActionsQueryResult, type AdvancedOptions, type DefenderContext, type DefenderLog, type DefenderOptions, type IOlapClient, type ITinybirdClient, type LogsOptions, OlapClient, OlapClientManager, type OlapOptions, type StepAdvancedLog, type StepInput, type StepLog, type StepResult, type StepsQuery, type StepsQueryResult, type TinybirdConfig, type TinybirdQueryOptions, type TinybirdResponse };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./chunk-Cfxk5zVN.mjs";import{isMissing as t,notMissing as n}from"@stackone/utils";import{CensorType as r,redactObject as i}from"@stackone/redaction";import{GetObjectCommand as a,PutObjectCommand as o,S3Client as s}from"@aws-sdk/client-s3";import{HttpClient as c}from"@stackone/transport";import{Kafka as l,Partitioners as u}from"kafkajs";import d from"node:http";const f=[`x-datadog-parent-id`,`x-datadog-sampling-priority`,`x-datadog-tags`,`x-datadog-trace-id`,`x-forwarded-proto`,`x-forwarded-port`,`x-forwarded-for`,`x-amzn-trace-id`,`traceparent`,`tracestate`,`x-request-nonce`,`x-signing-method`,`x-signature`,`host`,`via`],p=[`refresh_authentication`],m=10*1024*1024;var AdvancedSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, advanced sink will not function`,category:`AdvancedSink`});return}}async sendAction(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send action`,category:`AdvancedSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,statusCode:t.statusCode,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending action to advanced sink`,category:`AdvancedSink`});return}if(n.errorsOnly&&t.success){this.#t?.debug({message:`Advanced sink errorsOnly is enabled, skipping successful action for ${e.mode||`action`}`,category:`AdvancedSink`});return}if(this.isBackgroundLog(e)&&!n.includeBackground){this.#t?.debug({message:`Advanced sink is configured to exclude background logs, skipping action with mode ${e.mode}`,category:`AdvancedSink`});return}let r=this.createActionS3(e,t,n?.ttl);await this.send(r)}async sendStep(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send step`,category:`AdvancedSink`,context:{actionRunId:e.actionRunId,success:t.success,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending step to advanced sink`,category:`AdvancedSink`});return}let r=this.createStepS3(e,t,n?.ttl);await this.send(r)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from advanced sink`,category:`AdvancedSink`});return}let r=process.env.ADVANCED_LOGS_BUCKET;if(!r)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);try{let i=new a({Bucket:r,Key:`${e}/${t}/${n}/${n}.json`}),o=await this.#e.send(i);if(!o.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`AdvancedSink`});return}let s=await o.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved advanced log from S3 for actionRunId ${n}`,category:`AdvancedSink`}),s}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Advanced log not found in S3 for actionRunId ${n}`,category:`AdvancedSink`});return}throw this.#t?.error({message:`Error when getting advanced log from S3 for actionRunId ${n}`,error:e,code:`AdvancedLogReadError`,category:`AdvancedSink`}),e}}async send(e,t){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to advanced sink`,category:`AdvancedSink`});return}let n=process.env.ADVANCED_LOGS_BUCKET;if(!n)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);let r=`ttl=30d`;typeof t==`number`&&(t===1?r=`ttl=1d`:t===7&&(r=`ttl=7d`));let i=Math.floor(Date.now()/1e3)+(t??30)*24*60*60;this.#t?.debug({message:`Storing advanced log in S3 bucket ${n} with ttl of ${r}`,category:`AdvancedSink`,context:{bucket:n,key:e.Key,ttlTag:r,expiresAt:new Date(i*1e3).toISOString()}});try{await this.#e.send(new o({Bucket:n,Key:e.Key,Body:e.Body,ContentType:e.ContentType,Expires:new Date(i*1e3),Tagging:r}))}catch(t){throw this.#t?.error({message:`Failed to write advanced logs to S3 at ${e.Key}`,error:t,code:`AdvancedLogWriteError`,category:`AdvancedSink`}),t}}createActionS3(e,t,n){let r=`${t.organizationId}/${t.projectSecureId}/${t.actionRunId}/${t.actionRunId}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeActionResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}createStepS3(e,t,n){let r=`${e.organizationId}/${e.projectSecureId}/${e.actionRunId}/steps/${e.stepIndex}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeStepResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}serializeActionResult(e,t,n,a){let o=i({req:{...e.headers&&{headers:{...e.headers}}},res:{...t.headers&&{headers:{...t.headers}}}},r.PARTIAL),s=o.req?.headers,c=o.res?.headers,l=i(e.body,r.PARTIAL),u=i(t.body,r.PARTIAL),d=this.isBackgroundLog(e),f={data:{request:{id:t.actionRunId,actionId:t.actionId,method:t.httpMethod,headers:this.filterHeaders(s),url:{url:e.url,path:e.pathParams,queryParams:e.queryParams},body:l},response:{statusCode:t.statusCode??500,headers:this.filterHeaders(c),body:u},...d?{isBackgroundLog:!0}:{}},metadata:{...d?{isBackgroundLog:!0}:{},expirationTime:n},expirationTime:n};return this.serializeAndLimit(f,a)}serializeStepResult(e,t,n,r){let i={data:{id:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,input:e.inputs,outputs:t.outputs,errors:t.errors},metadata:{expirationTime:n}};return this.serializeAndLimit(i,r)}serializeAndLimit(e,t){let n=JSON.stringify(e);if(Buffer.byteLength(n,`utf8`)>t){let t={...e,data:{outputs:{error:`Error.TOO_LARGE`}}};n=JSON.stringify(t)}return n}filterHeaders(e){if(!e)return;let t={},n=f.map(e=>e.toLowerCase());for(let[r,i]of Object.entries(e))n.includes(r.toLowerCase())||(t[r]=i);return t}isDataSyncRequest(e){return e.mode===`data_sync`}isBackgroundLog(e){return n(e.mode)&&p.includes(e.mode)}getContentType(e){if(!e)return;let t=[`content-type`,`contenttype`];return Object.entries(e).find(([e])=>t.includes(e.toLowerCase()))?.[1]?.toString()}};const buildS3Client=(e,t)=>{try{return new s(e)??void 0}catch(e){let n=e;t?.error({message:`Error building s3 client: ${n.message}`,error:n,code:`BuildS3ClientError`,category:`buildS3Client`});return}};var DefenderSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, defender sink will not function`,category:`DefenderSink`});return}}async sendAction(e,t,n){if(this.#t?.debug({message:`Defender sink called to send action`,category:`DefenderSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,statusCode:t.statusCode,options:{enabled:n?.enabled}}}),!n?.enabled){this.#t?.debug({message:`Defender sink is disabled, skipping sending action to defender sink`,category:`DefenderSink`});return}let r=this.createActionS3(t);await this.send(r)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from defender sink`,category:`DefenderSink`});return}let r=process.env.DEFENDER_LOGS_BUCKET;if(!r)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);try{let i=new a({Bucket:r,Key:this.generateS3Key(e,t,n)}),o=await this.#e.send(i);if(!o.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`DefenderSink`});return}let s=await o.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved defender log from S3 for actionRunId ${n}`,category:`DefenderSink`}),s}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Defender log not found in S3 for actionRunId ${n}`,category:`DefenderSink`});return}throw this.#t?.error({message:`Error when getting defender log from S3 for actionRunId ${n}`,error:e,code:`DefenderLogReadError`,category:`DefenderSink`}),e}}async send(e){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to defender sink`,category:`DefenderSink`});return}let t=process.env.DEFENDER_LOGS_BUCKET;if(!t)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);this.#t?.debug({message:`Storing defender log in S3 bucket ${t}`,category:`DefenderSink`,context:{bucket:t,key:e.Key}});try{await this.#e.send(new o({Bucket:t,Key:e.Key,Body:e.Body,ContentType:e.ContentType}))}catch(t){throw this.#t?.error({message:`Failed to write defender logs to S3 at ${e.Key}`,error:t,code:`DefenderLogWriteError`,category:`DefenderSink`}),t}}generateS3Key(e,t,n){return`${e}/${t}/${n}/defender.json`}createActionS3(e){let t=e.organizationId,n=e.projectSecureId;return{Key:this.generateS3Key(t,n,e.actionRunId),Body:this.serializeDefenderContext(e),ContentType:`application/json`}}serializeDefenderContext(e){let t=e.defenderContext;return t?JSON.stringify(t):JSON.stringify({data:null,metadata:null})}};const buildHttpClient=e=>{try{return new c({logger:e})}catch(t){let n=t;e?.error({message:`Error building http client: ${n.message}`,error:n,code:`BuildHttpClientError`,category:`buildHttpClient`});return}},buildKafkaClient=(e,t)=>{try{return new l(e)??void 0}catch(e){let n=e;t?.error({message:`Error building kafka client: ${n.message}`,error:n,code:`BuildKafkaClientError`,category:`buildKafkaClient`});return}},safeSerialize=e=>{try{return JSON.stringify(e)}catch{return`[Unserializable payload]`}};var TinybirdClient=class{#e;#t;#n;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async query(e){if(!this.#e)throw this.#n?.error({message:`HTTP client not initialized, cannot perform Tinybird query`,category:`TinybirdClient`,code:`HttpClientNotReady`}),Error(`HTTP client is not initialized`);if(!this.#t?.token)throw this.#n?.warning({message:`Missing OLAP token, cannot perform Tinybird query`,category:`TinybirdClient`}),Error(`TinybirdClient - Missing token`);let t=new URL(`/v0/pipes/${e.endpoint}`,this.#t.baseUrl);try{this.#n?.debug({message:`Querying Tinybird endpoint: ${e.endpoint}`,category:`TinybirdClient`,context:{endpoint:e.endpoint,params:e.params}});let n=await this.#e.request({method:`post`,url:t.toString(),payload:e.params,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.#t.token}`},...this.#t.allowHttp&&{httpAgent:this.#r()}}),r=n.data.data;return this.#n?.debug({message:`Tinybird query returned ${r.length} rows`,category:`TinybirdClient`,context:{endpoint:e.endpoint,rows:n.data.rows,statistics:n.data.statistics}}),r}catch(t){let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}async queryWithPagination(e){if(!this.#e)throw this.#n?.error({message:`HTTP client not initialized, cannot perform Tinybird query`,category:`TinybirdClient`,code:`HttpClientNotReady`}),Error(`HTTP client is not initialized`);if(!this.#t?.token)throw this.#n?.warning({message:`Missing OLAP token, cannot perform Tinybird query`,category:`TinybirdClient`}),Error(`TinybirdClient - Missing token`);let t=new URL(`/v0/pipes/${e.endpoint}`,this.#t.baseUrl);try{let n=await this.#e.request({method:`post`,url:t.toString(),payload:e.params,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.#t.token}`},...this.#t.allowHttp&&{httpAgent:this.#r()}}),r=n.data.data;return{data:r,total:n.data.rows_before_limit_at_least??n.data.rows??r.length,pageNumber:e.pageNumber??1,pageSize:e.pageSize??r.length}}catch(t){let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}isReady(){return!!(this.#e&&this.#t?.token)}#r(){return new d.Agent({})}},LogsSink=class{#e;#t;#n;#r;constructor(e,t,n,r){this.#e=e,this.#r=r,this.#n=new TinybirdClient(t,n,r)}async initialize(){if(!this.#e){this.#r?.warning({message:`No kafka client provided, logs sink cannot be initialized`,category:`LogsSink`});return}if(this.#n?.isReady()||this.#r?.warning({message:`Tinybird client is not ready (missing HTTP client or Tinybird config/token), logs sink will not be able to query`,category:`LogsSink`}),!this.#t){try{this.#t=this.#e.producer({createPartitioner:u.DefaultPartitioner})}catch(e){this.#r?.error({message:`Failed to create kafka producer for logs sink`,code:`KafkaProducerCreationError`,category:`LogsSink`,error:e}),this.#t=void 0;return}try{await this.#t.connect()}catch(e){this.#r?.error?.({message:`Failed to connect kafka producer for logs sink`,code:`KafkaProducerConnectionError`,category:`LogsSink`,error:e}),this.#t=void 0;return}this.#r?.info({message:`Logs sink kafka producer initialized`,category:`LogsSink`})}}async sendAction(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending action to log sink`,category:`KafkaSink`});return}let r=this.buildActionLog(e,t);await this.send(`actions`,r)}async sendStep(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending step to log sink`,category:`KafkaSink`});return}let r=this.buildStepLog(e,t);await this.send(`steps`,r)}async getAction(e){return(await this.getActions({actionRunId:e})).actionLogs[0]}async getActions(e){try{this.#r?.info({message:`Querying action logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_actions_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} action logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{actionLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#n?.isReady()?this.#r?.warning({message:`Failed to query Tinybird for action logs, returning empty results`,category:`LogsSink`,error:t}):this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async getSteps(e){return(await this.querySteps({actionRunId:e})).stepLogs}async querySteps(e){try{this.#r?.info({message:`Querying step logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_steps_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} step logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{stepLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async send(e,t){if(!this.#t)throw this.#r?.error({message:`Kafka not initialized, dropping message for topic ${e}`,category:`KafkaSink`,code:`KafkaNotReady`}),Error(`Kafka client is not initialized`);let n=safeSerialize(t);this.#r?.debug({message:`Sending to topic ${e}: ${n}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:n}]});this.#r?.debug({message:`Kafka producer response: ${JSON.stringify(t)}`,category:`KafkaSink`})}catch(t){throw this.#r?.error({message:`Error sending to topic ${e}: ${t.message}`,category:`KafkaSink`,error:t,code:`KafkaSendError`}),t}}buildActionLog(e,t){return Object.fromEntries(Object.entries({actionRunId:t.actionRunId,actionId:t.actionId,organizationId:String(t.organizationId),projectSecureId:t.projectSecureId,accountSecureId:t.accountSecureId,mode:e.mode,connectorKey:t.connectorKey,connectorVersion:t.connectorVersion,actionType:t.actionType,category:t.category,originOwnerId:t.originOwnerId,originOwnerName:t.originOwnerName,httpMethod:t.httpMethod,url:t.url,sourceId:e.sourceId,sourceType:e.sourceType,sourceValue:e.sourceValue,success:t.success,statusCode:t.statusCode,riskLevel:t.defenderContext?.riskLevel,tier2Score:t.defenderContext?.tier2Score,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}buildStepLog(e,t){return Object.fromEntries(Object.entries({actionRunId:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,organizationId:String(e.organizationId),projectSecureId:String(e.projectSecureId),accountSecureId:String(e.accountSecureId),skipped:t.skipped,success:t.success,message:t.message,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}calculateDuration(e,t){if(!(e instanceof Date)||!(t instanceof Date))return;let n=e.getTime(),r=t.getTime();if(!(Number.isNaN(n)||Number.isNaN(r)||r<n))return r-n}};const h={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1,includeBackground:!1},defender:{enabled:!0}};function resolveOlapOptions(e){return{logs:{...h.logs,...e?.logs},advanced:{...h.advanced,...e?.advanced},defender:{...h.defender,...e?.defender}}}var OlapClient=class{#e;#t;#n;#r;#i;#a;#o;constructor({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={}){this.name=`OlapClient`,this.#e=e(r,o),this.#t=t(o),this.#n=n(i,o),this.#r=o,this.#i=new LogsSink(this.#e,this.#t,a,this.#r),this.#a=new AdvancedSink(this.#n,this.#r),this.#o=new DefenderSink(this.#n,this.#r)}async initialize(){await this.#i?.initialize(),await this.#a?.initialize(),await this.#o?.initialize()}async recordAction(e,t,n){let{logs:r,advanced:i,defender:a}=resolveOlapOptions(n);if(this.#r?.debug({message:`Olap client called to record action`,category:`OlapClient`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,options:n,resolvedOptions:{logs:r,advanced:i,defender:a}}}),r?.enabled)try{await this.#i?.sendAction(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendAction(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to advanced logs s3: ${e.message}`,category:`OlapClient`,error:e})}if(a?.enabled)try{await this.#o?.sendAction(e,t,a)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to defender logs s3: ${e.message}`,category:`OlapClient`,error:e})}}async recordStep(e,t,n){let{logs:r,advanced:i}=resolveOlapOptions(n);if(r?.enabled)try{await this.#i?.sendStep(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendStep(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}async getActions(e,t,n){return this.#r?.debug({message:`Querying action logs`,category:`OlapClient`,context:{query:n}}),await this.#i?.getActions({...n,organizationId:e,projectSecureId:t})||(this.#r?.warning({message:`Failed to query action logs, returning empty result`,category:`OlapClient`}),{actionLogs:[],total:0,pageNumber:n.pageNumber??1,pageSize:n.pageSize??0})}async getAction(e,n,r){let i=await this.#i?.getActions({organizationId:e,projectSecureId:n,actionRunId:r});if(t(i)||i.actionLogs.length===0){this.#r?.debug({message:`Failed to retrieve action log for actionRunId ${r}`,category:`OlapClient`});return}return i.actionLogs[0]}async getAdvanced(e,n,r){let i=await this.#a?.getAction(e,n,r);if(t(i)){this.#r?.debug({message:`Failed to retrieve advanced log for actionRunId ${r}`,category:`OlapClient`});return}return i}async getDefender(e,n,r){let i=await this.#o?.getAction(e,n,r);if(t(i)){this.#r?.debug({message:`Failed to retrieve defender log for actionRunId ${r}`,category:`OlapClient`});return}return i}};const buildOlapClientInstance=async({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={})=>{let s=new OlapClient({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o});return await s.initialize(),s};var OlapClientManager=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o,getOlapClient:s=buildOlapClientInstance}={}){return this.olapClientPromise||=s({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}),this.olapClientPromise}static resetInstance(){this.olapClientPromise=null}};export{OlapClient,OlapClientManager};
1
+ import{t as e}from"./chunk-Cfxk5zVN.mjs";import{isMissing as t,notMissing as n}from"@stackone/utils";import{CensorType as r,redactObject as i}from"@stackone/redaction";import{GetObjectCommand as a,PutObjectCommand as o,S3Client as s}from"@aws-sdk/client-s3";import{HttpClient as c}from"@stackone/transport";import{Kafka as l,Partitioners as u}from"kafkajs";import d from"node:http";const f=[`x-datadog-parent-id`,`x-datadog-sampling-priority`,`x-datadog-tags`,`x-datadog-trace-id`,`x-forwarded-proto`,`x-forwarded-port`,`x-forwarded-for`,`x-amzn-trace-id`,`traceparent`,`tracestate`,`x-request-nonce`,`x-signing-method`,`x-signature`,`host`,`via`],p=[`refresh_authentication`],m=10*1024*1024;var AdvancedSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, advanced sink will not function`,category:`AdvancedSink`});return}}async sendAction(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send action`,category:`AdvancedSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,statusCode:t.statusCode,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending action to advanced sink`,category:`AdvancedSink`});return}if(n.errorsOnly&&t.success){this.#t?.debug({message:`Advanced sink errorsOnly is enabled, skipping successful action for ${e.mode||`action`}`,category:`AdvancedSink`});return}if(this.isBackgroundLog(e)&&!n.includeBackground){this.#t?.debug({message:`Advanced sink is configured to exclude background logs, skipping action with mode ${e.mode}`,category:`AdvancedSink`});return}let r=this.createActionS3(e,t,n?.ttl);await this.send(r)}async sendStep(e,t,n){if(this.#t?.debug({message:`Advanced sink called to send step`,category:`AdvancedSink`,context:{actionRunId:e.actionRunId,success:t.success,options:{enabled:n?.enabled,errorsOnly:n?.errorsOnly,includeBackground:n?.includeBackground,ttl:n?.ttl}}}),!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending step to advanced sink`,category:`AdvancedSink`});return}let r=this.createStepS3(e,t,n?.ttl);await this.send(r)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from advanced sink`,category:`AdvancedSink`});return}let r=process.env.ADVANCED_LOGS_BUCKET;if(!r)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);try{let i=new a({Bucket:r,Key:`${e}/${t}/${n}/${n}.json`}),o=await this.#e.send(i);if(!o.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`AdvancedSink`});return}let s=await o.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved advanced log from S3 for actionRunId ${n}`,category:`AdvancedSink`}),JSON.parse(s)}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Advanced log not found in S3 for actionRunId ${n}`,category:`AdvancedSink`});return}throw this.#t?.error({message:`Error when getting advanced log from S3 for actionRunId ${n}`,error:e,code:`AdvancedLogReadError`,category:`AdvancedSink`}),e}}async getStep(e,t,n,r){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get step log from advanced sink`,category:`AdvancedSink`});return}let i=process.env.ADVANCED_LOGS_BUCKET;if(!i)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);try{let o=new a({Bucket:i,Key:`${e}/${t}/${n}/steps/${r}.json`}),s=await this.#e.send(o);if(!s.Body){this.#t?.warning({message:`Received empty body when trying to get step log from S3 for actionRunId ${n} stepIndex ${r}`,category:`AdvancedSink`});return}let c=await s.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved step log from S3 for actionRunId ${n} stepIndex ${r}`,category:`AdvancedSink`}),JSON.parse(c)}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Step log not found in S3 for actionRunId ${n} stepIndex ${r}`,category:`AdvancedSink`});return}throw this.#t?.error({message:`Error when getting step log from S3 for actionRunId ${n} stepIndex ${r}`,error:e,code:`AdvancedLogReadError`,category:`AdvancedSink`}),e}}async send(e,t){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to advanced sink`,category:`AdvancedSink`});return}let n=process.env.ADVANCED_LOGS_BUCKET;if(!n)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);let r=`ttl=30d`;typeof t==`number`&&(t===1?r=`ttl=1d`:t===7&&(r=`ttl=7d`));let i=Math.floor(Date.now()/1e3)+(t??30)*24*60*60;this.#t?.debug({message:`Storing advanced log in S3 bucket ${n} with ttl of ${r}`,category:`AdvancedSink`,context:{bucket:n,key:e.Key,ttlTag:r,expiresAt:new Date(i*1e3).toISOString()}});try{await this.#e.send(new o({Bucket:n,Key:e.Key,Body:e.Body,ContentType:e.ContentType,Expires:new Date(i*1e3),Tagging:r}))}catch(t){throw this.#t?.error({message:`Failed to write advanced logs to S3 at ${e.Key}`,error:t,code:`AdvancedLogWriteError`,category:`AdvancedSink`}),t}}createActionS3(e,t,n){let r=`${t.organizationId}/${t.projectSecureId}/${t.actionRunId}/${t.actionRunId}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeActionResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}createStepS3(e,t,n){let r=`${e.organizationId}/${e.projectSecureId}/${e.actionRunId}/steps/${e.stepIndex}.json`,i=Math.floor(Date.now()/1e3)+(n??30)*24*60*60;return{Key:r,Body:this.serializeStepResult(e,t,i,m),ContentType:`application/json`,Expires:new Date(i*1e3)}}serializeActionResult(e,t,n,a){let o=i({req:{...e.headers&&{headers:{...e.headers}}},res:{...t.headers&&{headers:{...t.headers}}}},r.PARTIAL),s=o.req?.headers,c=o.res?.headers,l=i(e.body,r.PARTIAL),u=i(t.body,r.PARTIAL),d=this.isBackgroundLog(e),f={data:{request:{id:t.actionRunId,actionId:t.actionId,method:t.httpMethod,headers:this.filterHeaders(s),url:{url:e.url,path:e.pathParams,queryParams:e.queryParams},body:l},response:{statusCode:t.statusCode??500,headers:this.filterHeaders(c),body:u},...d?{isBackgroundLog:!0}:{}},metadata:{...d?{isBackgroundLog:!0}:{},expirationTime:n}};return this.serializeAndLimit(f,a)}serializeStepResult(e,t,n,r){let i={data:{id:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,input:e.inputs,outputs:t.outputs,errors:t.errors},metadata:{expirationTime:n}};return this.serializeAndLimit(i,r)}serializeAndLimit(e,t){let n=JSON.stringify(e);if(Buffer.byteLength(n,`utf8`)>t){let t={...e,data:{outputs:{error:`Error.TOO_LARGE`}}};n=JSON.stringify(t)}return n}filterHeaders(e){if(!e)return;let t={},n=f.map(e=>e.toLowerCase());for(let[r,i]of Object.entries(e))n.includes(r.toLowerCase())||(t[r]=i);return t}isDataSyncRequest(e){return e.mode===`data_sync`}isBackgroundLog(e){return n(e.mode)&&p.includes(e.mode)}getContentType(e){if(!e)return;let t=[`content-type`,`contenttype`];return Object.entries(e).find(([e])=>t.includes(e.toLowerCase()))?.[1]?.toString()}};const buildS3Client=(e,t)=>{try{return new s(e)??void 0}catch(e){let n=e;t?.error({message:`Error building s3 client: ${n.message}`,error:n,code:`BuildS3ClientError`,category:`buildS3Client`});return}};var DefenderSink=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}async initialize(){if(!this.#e){this.#t?.warning({message:`No s3 client provided, defender sink will not function`,category:`DefenderSink`});return}}async sendAction(e,n,r){if(this.#t?.debug({message:`Defender sink called to send action`,category:`DefenderSink`,context:{mode:e.mode,actionId:e.actionId,actionRunId:n.actionRunId,success:n.success,statusCode:n.statusCode,options:{enabled:r?.enabled}}}),t(n.defenderContext)){this.#t?.debug({message:`No defender context in action result, skipping sending action to defender sink`,category:`DefenderSink`,context:{actionRunId:n.actionRunId}});return}if(!r?.enabled){this.#t?.debug({message:`Defender sink is disabled, skipping sending action to defender sink`,category:`DefenderSink`});return}let i=this.createActionS3(n);await this.send(i)}async getAction(e,t,n){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot get action log from defender sink`,category:`DefenderSink`});return}let r=process.env.DEFENDER_LOGS_BUCKET;if(!r)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);try{let i=new a({Bucket:r,Key:this.generateS3Key(e,t,n)}),o=await this.#e.send(i);if(!o.Body){this.#t?.warning({message:`Received empty body when trying to get action log from S3 for actionRunId ${n}`,category:`DefenderSink`});return}let s=await o.Body.transformToString();return this.#t?.debug({message:`Successfully retrieved defender log from S3 for actionRunId ${n}`,category:`DefenderSink`}),JSON.parse(s)}catch(e){let t=e;if(t.name===`NoSuchKey`||t.$metadata?.httpStatusCode===404){this.#t?.debug({message:`Defender log not found in S3 for actionRunId ${n}`,category:`DefenderSink`});return}throw this.#t?.error({message:`Error when getting defender log from S3 for actionRunId ${n}`,error:e,code:`DefenderLogReadError`,category:`DefenderSink`}),e}}async send(e){if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to defender sink`,category:`DefenderSink`});return}let t=process.env.DEFENDER_LOGS_BUCKET;if(!t)throw Error(`DEFENDER_LOGS_BUCKET environment variable is not set`);this.#t?.debug({message:`Storing defender log in S3 bucket ${t}`,category:`DefenderSink`,context:{bucket:t,key:e.Key}});try{await this.#e.send(new o({Bucket:t,Key:e.Key,Body:e.Body,ContentType:e.ContentType}))}catch(t){throw this.#t?.error({message:`Failed to write defender logs to S3 at ${e.Key}`,error:t,code:`DefenderLogWriteError`,category:`DefenderSink`}),t}}generateS3Key(e,t,n){return`${e}/${t}/${n}/defender.json`}createActionS3(e){let t=e.organizationId,n=e.projectSecureId;return{Key:this.generateS3Key(t,n,e.actionRunId),Body:JSON.stringify(e.defenderContext),ContentType:`application/json`}}};const buildHttpClient=e=>{try{return new c({logger:e})}catch(t){let n=t;e?.error({message:`Error building http client: ${n.message}`,error:n,code:`BuildHttpClientError`,category:`buildHttpClient`});return}},buildKafkaClient=(e,t)=>{try{return new l(e)??void 0}catch(e){let n=e;t?.error({message:`Error building kafka client: ${n.message}`,error:n,code:`BuildKafkaClientError`,category:`buildKafkaClient`});return}},safeSerialize=e=>{try{return JSON.stringify(e)}catch{return`[Unserializable payload]`}};var SchemaValidationError=class extends Error{constructor(e,t){super(e),this.name=`SchemaValidationError`,this.cause=t}},TinybirdClient=class{#e;#t;#n;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async query(e){try{let t=await this.#o(e.endpoint,e.params);return this.#a(t.data,e.schema)}catch(t){if(t instanceof SchemaValidationError)throw t;let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}async queryWithPagination(e){try{let t=await this.#o(e.endpoint,e.params),n=this.#a(t.data,e.schema);return{data:n,total:t.rows_before_limit_at_least??t.rows??n.length,pageNumber:e.pageNumber??1,pageSize:e.pageSize??n.length}}catch(t){if(t instanceof SchemaValidationError)throw t;let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}async queryRaw(e){try{let t=await this.#o(e.endpoint,e.params);return t.data=this.#a(t.data,e.schema),t}catch(t){if(t instanceof SchemaValidationError)throw t;let n=t instanceof Error?t.message:String(t);throw this.#n?.error({message:`Error querying Tinybird endpoint ${e.endpoint}: ${n}`,category:`TinybirdClient`,code:`TinybirdQueryError`}),t}}isReady(){return!!(this.#e&&this.#t?.token)}#r(){return new d.Agent({})}#i(){if(!this.#e)throw this.#n?.error({message:`HTTP client not initialized, cannot perform Tinybird query`,category:`TinybirdClient`,code:`HttpClientNotReady`}),Error(`HTTP client is not initialized`);if(!this.#t?.token)throw this.#n?.warning({message:`Missing OLAP token, cannot perform Tinybird query`,category:`TinybirdClient`}),Error(`TinybirdClient - Missing token`)}#a(e,t){if(!t)return e;try{let n=e.map(e=>t.parse(e));return this.#n?.debug({message:`Schema validation passed for ${n.length} rows`,category:`TinybirdClient`}),n}catch(e){let t=e instanceof Error?e.message:String(e);throw this.#n?.error({message:`Schema validation failed: ${t}`,category:`TinybirdClient`,code:`SchemaValidationError`,error:e}),new SchemaValidationError(t,e)}}async#o(e,t){this.#i();let n=this.#e,r=this.#t;if(!n||!r)throw Error(`Client validation failed`);let i=new URL(`/v0/pipes/${e}`,r.baseUrl);this.#n?.debug({message:`Querying Tinybird endpoint: ${e}`,category:`TinybirdClient`,context:{endpoint:e,params:t}});let a=await n.request({method:`post`,url:i.toString(),payload:t,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${r.token}`},...r.allowHttp&&{httpAgent:this.#r()}});return this.#n?.debug({message:`Tinybird query returned ${a.data.data.length} rows`,category:`TinybirdClient`,context:{endpoint:e,rows:a.data.rows,statistics:a.data.statistics}}),a.data}},LogsSink=class{#e;#t;#n;#r;constructor(e,t,n,r){this.#e=e,this.#r=r,this.#n=new TinybirdClient(t,n,r)}get tinybirdClient(){return this.#n}async initialize(){if(!this.#e){this.#r?.warning({message:`No kafka client provided, logs sink cannot be initialized`,category:`LogsSink`});return}if(this.#n?.isReady()||this.#r?.warning({message:`Tinybird client is not ready (missing HTTP client or Tinybird config/token), logs sink will not be able to query`,category:`LogsSink`}),!this.#t){try{this.#t=this.#e.producer({createPartitioner:u.DefaultPartitioner})}catch(e){this.#r?.error({message:`Failed to create kafka producer for logs sink`,code:`KafkaProducerCreationError`,category:`LogsSink`,error:e}),this.#t=void 0;return}try{await this.#t.connect()}catch(e){this.#r?.error?.({message:`Failed to connect kafka producer for logs sink`,code:`KafkaProducerConnectionError`,category:`LogsSink`,error:e}),this.#t=void 0;return}this.#r?.info({message:`Logs sink kafka producer initialized`,category:`LogsSink`})}}async sendAction(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending action to log sink`,category:`KafkaSink`});return}let r=this.buildActionLog(e,t);await this.send(`actions`,r)}async sendStep(e,t,n){if(!n?.enabled){this.#r?.debug({message:`Logs sink is disabled, skipping sending step to log sink`,category:`KafkaSink`});return}let r=this.buildStepLog(e,t);await this.send(`steps`,r)}async getActions(e){try{this.#r?.info({message:`Querying action logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_actions_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} action logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{actionLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#n?.isReady()?this.#r?.warning({message:`Failed to query Tinybird for action logs, returning empty results`,category:`LogsSink`,error:t}):this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{actionLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async getAction(e,t,n){return(await this.getActions({organizationId:e,projectSecureId:t,actionRunId:n})).actionLogs[0]}async getSteps(e){try{this.#r?.info({message:`Querying step logs from Tinybird`,category:`LogsSink`,context:{query:e}});let t=await this.#n?.queryWithPagination({endpoint:`project_steps_logs.json`,params:e,pageNumber:e.pageNumber,pageSize:e.pageSize});return t?(this.#r?.info({message:`Successfully retrieved ${t.data.length} step logs from Tinybird (${t.total} total)`,category:`LogsSink`}),{stepLogs:t.data,total:t.total,pageNumber:t.pageNumber,pageSize:t.pageSize}):(this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0})}catch(t){return this.#r?.warning({message:`Tinybird client not available, returning empty results`,category:`LogsSink`,error:t}),{stepLogs:[],total:0,pageNumber:e.pageNumber??1,pageSize:e.pageSize??0}}}async getStep(e,t,n,r){return(await this.getSteps({organizationId:e,projectSecureId:t,actionRunId:n,stepIndex:r})).stepLogs[0]}async send(e,t){if(!this.#t)throw this.#r?.error({message:`Kafka not initialized, dropping message for topic ${e}`,category:`KafkaSink`,code:`KafkaNotReady`}),Error(`Kafka client is not initialized`);let n=safeSerialize(t);this.#r?.debug({message:`Sending to topic ${e}: ${n}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:n}]});this.#r?.debug({message:`Kafka producer response: ${JSON.stringify(t)}`,category:`KafkaSink`})}catch(t){throw this.#r?.error({message:`Error sending to topic ${e}: ${t.message}`,category:`KafkaSink`,error:t,code:`KafkaSendError`}),t}}buildActionLog(e,t){return Object.fromEntries(Object.entries({actionRunId:t.actionRunId,actionId:t.actionId,organizationId:String(t.organizationId),projectSecureId:t.projectSecureId,accountSecureId:t.accountSecureId,mode:e.mode,connectorKey:t.connectorKey,connectorVersion:t.connectorVersion,actionType:t.actionType,category:t.category,originOwnerId:t.originOwnerId,originOwnerName:t.originOwnerName,httpMethod:t.httpMethod,url:t.url,sourceId:e.sourceId,sourceType:e.sourceType,sourceValue:e.sourceValue,success:t.success,statusCode:t.statusCode,riskLevel:t.defenderContext?.riskLevel,tier2Score:t.defenderContext?.tier2Score,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}buildStepLog(e,t){return Object.fromEntries(Object.entries({actionRunId:e.actionRunId,stepIndex:e.stepIndex,stepId:e.stepId,organizationId:String(e.organizationId),projectSecureId:String(e.projectSecureId),accountSecureId:String(e.accountSecureId),skipped:t.skipped,success:t.success,message:t.message,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0))}calculateDuration(e,t){if(!(e instanceof Date)||!(t instanceof Date))return;let n=e.getTime(),r=t.getTime();if(!(Number.isNaN(n)||Number.isNaN(r)||r<n))return r-n}};const h={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1,includeBackground:!1},defender:{enabled:!0}};function resolveOlapOptions(e){return{logs:{...h.logs,...e?.logs},advanced:{...h.advanced,...e?.advanced},defender:{...h.defender,...e?.defender}}}var OlapClient=class{#e;#t;#n;#r;#i;#a;#o;constructor({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={}){this.name=`OlapClient`,this.#e=e(r,o),this.#t=t(o),this.#n=n(i,o),this.#r=o,this.#i=new LogsSink(this.#e,this.#t,a,this.#r),this.#a=new AdvancedSink(this.#n,this.#r),this.#o=new DefenderSink(this.#n,this.#r)}async initialize(){await this.#i?.initialize(),await this.#a?.initialize(),await this.#o?.initialize()}get tinybirdClient(){return this.#i?.tinybirdClient}async recordAction(e,t,n){let{logs:r,advanced:i,defender:a}=resolveOlapOptions(n);if(this.#r?.debug({message:`Olap client called to record action`,category:`OlapClient`,context:{mode:e.mode,actionId:e.actionId,actionRunId:t.actionRunId,success:t.success,options:n,resolvedOptions:{logs:r,advanced:i,defender:a}}}),r?.enabled)try{await this.#i?.sendAction(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendAction(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to advanced logs s3: ${e.message}`,category:`OlapClient`,error:e})}if(a?.enabled)try{await this.#o?.sendAction(e,t,a)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to defender logs s3: ${e.message}`,category:`OlapClient`,error:e})}}async recordStep(e,t,n){let{logs:r,advanced:i}=resolveOlapOptions(n);if(r?.enabled)try{await this.#i?.sendStep(e,t,r)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#a?.sendStep(e,t,i)}catch(e){this.#r?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}async getActionLogs(e,t,n){return this.#r?.debug({message:`Querying action logs`,category:`OlapClient`,context:{query:n}}),await this.#i?.getActions({...n,organizationId:e,projectSecureId:t})||(this.#r?.warning({message:`Failed to query action logs, returning empty result`,category:`OlapClient`}),{actionLogs:[],total:0,pageNumber:n.pageNumber??1,pageSize:n.pageSize??0})}async getActionLog(e,n,r){let i=await this.#i?.getAction(e,n,r);if(t(i)){this.#r?.debug({message:`Failed to retrieve action log for actionRunId ${r}`,category:`OlapClient`});return}return i}async getStepLogs(e,t,n){return this.#r?.debug({message:`Querying step logs`,category:`OlapClient`,context:{query:n}}),await this.#i?.getSteps({...n,organizationId:e,projectSecureId:t})||(this.#r?.warning({message:`Failed to query step logs, returning empty result`,category:`OlapClient`}),{stepLogs:[],total:0,pageNumber:n.pageNumber??1,pageSize:n.pageSize??0})}async getStepLog(e,n,r,i){let a=await this.#i?.getStep(e,n,r,i);if(t(a)){this.#r?.debug({message:`Failed to retrieve step log for actionRunId ${r} stepIndex ${i}`,category:`OlapClient`});return}return a}async getActionAdvancedLog(e,n,r){let i=await this.#a?.getAction(e,n,r);if(t(i)){this.#r?.debug({message:`Failed to retrieve action advanced log for actionRunId ${r}`,category:`OlapClient`});return}return i}async getStepAdvancedLog(e,n,r,i){let a=await this.#a?.getStep(e,n,r,i);if(t(a)){this.#r?.debug({message:`Failed to retrieve step advanced log for actionRunId ${r} stepIndex ${i}`,category:`OlapClient`});return}return a}async getDefenderLog(e,n,r){let i=await this.#o?.getAction(e,n,r);if(t(i)){this.#r?.debug({message:`Failed to retrieve defender log for actionRunId ${r}`,category:`OlapClient`});return}return i}};const buildOlapClientInstance=async({getKafkaClient:e=buildKafkaClient,getHttpClient:t=buildHttpClient,getS3Client:n=buildS3Client,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}={})=>{let s=new OlapClient({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o});return await s.initialize(),s};var OlapClientManager=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o,getOlapClient:s=buildOlapClientInstance}={}){return this.olapClientPromise||=s({getKafkaClient:e,getHttpClient:t,getS3Client:n,kafkaClientConfig:r,s3ClientConfig:i,tinybirdConfig:a,logger:o}),this.olapClientPromise}static resetInstance(){this.olapClientPromise=null}};export{OlapClient,OlapClientManager};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/olap",
3
- "version": "1.17.1",
3
+ "version": "1.20.0",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",