@stackone/olap 1.16.0 → 1.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +522 -5
- package/dist/index.d.mts +523 -5
- package/dist/index.mjs +1 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});let t=require(`@stackone/redaction`),n=require(`@stackone/utils`),r=require(`@aws-sdk/client-s3`),i=require(`kafkajs`);const a=[`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`],o=[`refresh_authentication`],s=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 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 i=`ttl=30d`;typeof t==`number`&&(t===1?i=`ttl=1d`:t===7&&(i=`ttl=7d`));let a=Math.floor(Date.now()/1e3)+(t??30)*24*60*60;this.#t?.debug({message:`Storing advanced log in S3 bucket ${n} with ttl of ${i}`,category:`AdvancedSink`,context:{bucket:n,key:e.Key,ttlTag:i,expiresAt:new Date(a*1e3).toISOString()}});try{await this.#e.send(new r.PutObjectCommand({Bucket:n,Key:e.Key,Body:e.Body,ContentType:e.ContentType,Expires:new Date(a*1e3),Tagging:i}))}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,s),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,s),ContentType:`application/json`,Expires:new Date(i*1e3)}}serializeActionResult(e,n,r,i){let a=(0,t.redactObject)({req:{...e.headers&&{headers:{...e.headers}}},res:{...n.headers&&{headers:{...n.headers}}}},t.CensorType.PARTIAL),o=a.req?.headers,s=a.res?.headers,c=(0,t.redactObject)(e.body,t.CensorType.PARTIAL),l=(0,t.redactObject)(n.body,t.CensorType.PARTIAL),u=this.isBackgroundLog(e),d={data:{request:{id:n.actionRunId,actionId:n.actionId,method:n.httpMethod,headers:this.filterHeaders(o),url:{url:e.url,path:e.pathParams,queryParams:e.queryParams},body:c},response:{statusCode:n.statusCode??500,headers:this.filterHeaders(s),body:l},...u?{isBackgroundLog:!0}:{}},metadata:{...u?{isBackgroundLog:!0}:{},expirationTime:r},expirationTime:r};return this.serializeAndLimit(d,i)}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=a.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,n.notMissing)(e.mode)&&o.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 r.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 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 r.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}}createActionS3(e){return{Key:`${e.organizationId}/${e.projectSecureId}/${e.actionRunId}/defender.json`,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 buildKafkaClient=(e,t)=>{try{return new i.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 LogsSink=class{#e;#t;#n;constructor(e,t){this.#e=e,this.#n=t}async initialize(){if(!this.#e){this.#n?.warning({message:`No kafka client provided, logs sink cannot be initialized`,category:`LogsSink`});return}if(!this.#t){try{this.#t=this.#e.producer({createPartitioner:i.Partitioners.DefaultPartitioner})}catch(e){this.#n?.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.#n?.error?.({message:`Failed to connect kafka producer for logs sink`,code:`KafkaProducerConnectionError`,category:`LogsSink`,error:e}),this.#t=void 0;return}this.#n?.info({message:`Logs sink kafka producer initialized`,category:`LogsSink`})}}async sendAction(e,t,n){if(!n?.enabled){this.#n?.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.#n?.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 send(e,t){if(!this.#t)throw this.#n?.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.#n?.debug({message:`Sending to topic ${e}: ${n}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:n}]});this.#n?.debug({message:`Kafka producer response: ${JSON.stringify(t)}`,category:`KafkaSink`})}catch(t){throw this.#n?.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 c={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1,includeBackground:!1},defender:{enabled:!0}};function resolveOlapOptions(e){return{logs:{...c.logs,...e?.logs},advanced:{...c.advanced,...e?.advanced},defender:{...c.defender,...e?.defender}}}var OlapClient=class{#e;#t;#n;#r;#i;#a;constructor({getKafkaClient:e=buildKafkaClient,getS3Client:t=buildS3Client,kafkaClientConfig:n,s3ClientConfig:r,logger:i}={}){this.name=`OlapClient`,this.#e=e(n,i),this.#t=t(r,i),this.#n=i,this.#r=new LogsSink(this.#e,this.#n),this.#i=new AdvancedSink(this.#t,this.#n),this.#a=new DefenderSink(this.#t,this.#n)}async initialize(){await this.#r?.initialize(),await this.#i?.initialize(),await this.#a?.initialize()}async recordAction(e,t,n){let{logs:r,advanced:i,defender:a}=resolveOlapOptions(n);if(this.#n?.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.#r?.sendAction(e,t,r)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#i?.sendAction(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to advanced logs s3: ${e.message}`,category:`OlapClient`,error:e})}if(a?.enabled)try{await this.#a?.sendAction(e,t,a)}catch(e){this.#n?.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.#r?.sendStep(e,t,r)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#i?.sendStep(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}};const buildOlapClientInstance=async({getKafkaClient:e=buildKafkaClient,getS3Client:t=buildS3Client,kafkaClientConfig:n,s3ClientConfig:r,logger:i}={})=>{let a=new OlapClient({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i});return await a.initialize(),a};var OlapClientManager=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i,getOlapClient:a=buildOlapClientInstance}={}){return this.olapClientPromise||=a({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i}),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`}),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;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
2
|
+
import * as redis from "redis";
|
|
3
|
+
import { AxiosInstance } from "axios";
|
|
4
|
+
import http from "node:http";
|
|
5
|
+
import https from "node:https";
|
|
6
|
+
import { Readable } from "node:stream";
|
|
2
7
|
import { Kafka } from "kafkajs";
|
|
3
8
|
|
|
4
9
|
//#region rolldown:runtime
|
|
@@ -85,10 +90,487 @@ type DefenderOptions = {
|
|
|
85
90
|
enabled?: boolean;
|
|
86
91
|
};
|
|
87
92
|
//#endregion
|
|
93
|
+
//#region ../transport/src/cacheClient/types.d.ts
|
|
94
|
+
interface ICacheClient<ClientType = unknown> {
|
|
95
|
+
getData<T>(key: string): Promise<T | null>;
|
|
96
|
+
listData<T>({
|
|
97
|
+
partialKey,
|
|
98
|
+
limit,
|
|
99
|
+
cursor
|
|
100
|
+
}: {
|
|
101
|
+
partialKey: string;
|
|
102
|
+
limit?: number;
|
|
103
|
+
cursor?: string;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
items: T[] | null;
|
|
106
|
+
cursor?: string;
|
|
107
|
+
}>;
|
|
108
|
+
setData<T>({
|
|
109
|
+
key,
|
|
110
|
+
value,
|
|
111
|
+
cacheTTL,
|
|
112
|
+
groupKey
|
|
113
|
+
}: {
|
|
114
|
+
key: string;
|
|
115
|
+
value: T;
|
|
116
|
+
cacheTTL: number;
|
|
117
|
+
groupKey?: string;
|
|
118
|
+
}): Promise<boolean>;
|
|
119
|
+
executeScript?<T>({
|
|
120
|
+
sha1,
|
|
121
|
+
keys,
|
|
122
|
+
args
|
|
123
|
+
}: {
|
|
124
|
+
sha1: string;
|
|
125
|
+
keys: string[];
|
|
126
|
+
args: string[];
|
|
127
|
+
}): Promise<T | null>;
|
|
128
|
+
loadScript?(script: string): Promise<string | null>;
|
|
129
|
+
scriptExists?(shas: string[]): Promise<boolean[]>;
|
|
130
|
+
increment?(key: string, cacheTTL: number): Promise<number | null>;
|
|
131
|
+
decrement?(key: string, cacheTTL: number): Promise<number | null>;
|
|
132
|
+
subscribe?<T extends boolean = false>(pattern: string, listener: PubSubListener<T>): Promise<boolean>;
|
|
133
|
+
unsubscribe?(pattern: string): Promise<boolean>;
|
|
134
|
+
publish?(channel: string, message: string): Promise<number | null>;
|
|
135
|
+
getClient?(): ClientType | null;
|
|
136
|
+
deleteData?(key: string): Promise<boolean>;
|
|
137
|
+
close?(): Promise<void> | void;
|
|
138
|
+
}
|
|
139
|
+
type PubSubListener<ReturnsBuffer extends boolean = false> = <T extends (ReturnsBuffer extends true ? Buffer : string)>(message: T, channel: T) => unknown;
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region ../transport/src/redisClient/types.d.ts
|
|
142
|
+
type RedisClientType = redis.RedisClientType;
|
|
143
|
+
interface RedisClientConfig {
|
|
144
|
+
getRedisClient?: typeof redis.createClient;
|
|
145
|
+
host?: string;
|
|
146
|
+
port?: number;
|
|
147
|
+
tls?: boolean;
|
|
148
|
+
reconnect?: boolean;
|
|
149
|
+
database?: number;
|
|
150
|
+
}
|
|
151
|
+
type RedisClientBuilder = (config: RedisClientConfig, logger?: ILogger, invoker?: string) => Promise<ICacheClient<RedisClientType> | undefined>;
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region ../transport/src/concurrencyManager/types.d.ts
|
|
154
|
+
type ConcurrencySubPoolConfig = {
|
|
155
|
+
subPoolKey: string;
|
|
156
|
+
urlPattern: RegExp | string;
|
|
157
|
+
maxConcurrency: number;
|
|
158
|
+
};
|
|
159
|
+
type ConcurrencyConfig = {
|
|
160
|
+
mainMaxConcurrency: number;
|
|
161
|
+
subPools?: ConcurrencySubPoolConfig[];
|
|
162
|
+
};
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region ../transport/src/rateLimitManager/types.d.ts
|
|
165
|
+
type RateLimitSubPoolConfig = {
|
|
166
|
+
subPoolKey: string;
|
|
167
|
+
urlPattern: RegExp | string;
|
|
168
|
+
rateLimit: number;
|
|
169
|
+
};
|
|
170
|
+
type RetryUnit = 'seconds' | 'milliseconds' | 'date';
|
|
171
|
+
type MappedRateLimitErrorConfig = {
|
|
172
|
+
errorStatus: number;
|
|
173
|
+
errorMessage: string | RegExp;
|
|
174
|
+
errorMessagePath?: string;
|
|
175
|
+
retryAfterPath?: string;
|
|
176
|
+
retryAfterUnit?: RetryUnit;
|
|
177
|
+
retryAfterValue?: number;
|
|
178
|
+
};
|
|
179
|
+
type RateLimitConfig = {
|
|
180
|
+
mainRatelimit: number;
|
|
181
|
+
subPools?: RateLimitSubPoolConfig[];
|
|
182
|
+
mappedRateLimitErrors?: MappedRateLimitErrorConfig[];
|
|
183
|
+
};
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region ../transport/src/interceptors/types.d.ts
|
|
186
|
+
type RequestConfig = {
|
|
187
|
+
rateLimits?: RateLimitConfig;
|
|
188
|
+
concurrency?: ConcurrencyConfig;
|
|
189
|
+
};
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region ../transport/src/parsers/types.d.ts
|
|
192
|
+
declare const QueryArrayFormats: readonly ["repeat", "brackets", "comma"];
|
|
193
|
+
type QueryArrayFormat = (typeof QueryArrayFormats)[number];
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region ../transport/src/httpClient/types.d.ts
|
|
196
|
+
type HttpHeader = string | string[];
|
|
197
|
+
type HttpHeaders = {
|
|
198
|
+
[key: string]: HttpHeader;
|
|
199
|
+
};
|
|
200
|
+
type HttpQueryParamValue = {
|
|
201
|
+
value: string | string[];
|
|
202
|
+
arrayFormat?: QueryArrayFormat;
|
|
203
|
+
};
|
|
204
|
+
type HttpQueryParams = {
|
|
205
|
+
[key: string]: string | string[] | HttpQueryParamValue;
|
|
206
|
+
};
|
|
207
|
+
declare const HttpMethods: readonly ["get", "post", "put", "delete", "patch"];
|
|
208
|
+
type HttpMethod = (typeof HttpMethods)[number];
|
|
209
|
+
type HttpResponse<T = any, P = any> = {
|
|
210
|
+
data: T;
|
|
211
|
+
status: number;
|
|
212
|
+
headers: HttpHeaders;
|
|
213
|
+
requestUrl: string;
|
|
214
|
+
responseType?: string;
|
|
215
|
+
responseTime?: Date;
|
|
216
|
+
message?: string;
|
|
217
|
+
body?: P;
|
|
218
|
+
};
|
|
219
|
+
type StreamHttpResponse = {
|
|
220
|
+
status: number;
|
|
221
|
+
headers: HttpHeaders;
|
|
222
|
+
stream: Readable;
|
|
223
|
+
requestUrl: string;
|
|
224
|
+
};
|
|
225
|
+
interface IHttpClient {
|
|
226
|
+
request<P, T>({
|
|
227
|
+
headers,
|
|
228
|
+
url,
|
|
229
|
+
method,
|
|
230
|
+
queryParams,
|
|
231
|
+
maxRedirects,
|
|
232
|
+
responseType,
|
|
233
|
+
cacheTTL,
|
|
234
|
+
context,
|
|
235
|
+
payload,
|
|
236
|
+
httpsAgent,
|
|
237
|
+
httpAgent,
|
|
238
|
+
requestConfig,
|
|
239
|
+
httpsAgentConfig
|
|
240
|
+
}: {
|
|
241
|
+
headers?: HttpHeaders;
|
|
242
|
+
url: string;
|
|
243
|
+
method?: HttpMethod;
|
|
244
|
+
queryParams?: HttpQueryParams;
|
|
245
|
+
maxRedirects?: number;
|
|
246
|
+
responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text';
|
|
247
|
+
cacheTTL?: number;
|
|
248
|
+
context?: RequestContext;
|
|
249
|
+
payload?: P;
|
|
250
|
+
httpsAgent?: https.Agent;
|
|
251
|
+
httpAgent?: http.Agent;
|
|
252
|
+
requestConfig?: RequestConfig;
|
|
253
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
254
|
+
}): Promise<HttpResponse<T>>;
|
|
255
|
+
get<T>({
|
|
256
|
+
headers,
|
|
257
|
+
url,
|
|
258
|
+
queryParams,
|
|
259
|
+
maxRedirects,
|
|
260
|
+
cacheTTL,
|
|
261
|
+
context,
|
|
262
|
+
requestConfig
|
|
263
|
+
}: {
|
|
264
|
+
headers?: HttpHeaders;
|
|
265
|
+
url: string;
|
|
266
|
+
queryParams?: HttpQueryParams;
|
|
267
|
+
maxRedirects?: number;
|
|
268
|
+
cacheTTL?: number;
|
|
269
|
+
context?: RequestContext;
|
|
270
|
+
requestConfig?: RequestConfig;
|
|
271
|
+
}): Promise<HttpResponse<T>>;
|
|
272
|
+
post<P, T>({
|
|
273
|
+
headers,
|
|
274
|
+
url,
|
|
275
|
+
maxRedirects,
|
|
276
|
+
cacheTTL,
|
|
277
|
+
context,
|
|
278
|
+
payload,
|
|
279
|
+
requestConfig
|
|
280
|
+
}: {
|
|
281
|
+
headers?: HttpHeaders;
|
|
282
|
+
url: string;
|
|
283
|
+
maxRedirects?: number;
|
|
284
|
+
cacheTTL?: number;
|
|
285
|
+
context?: RequestContext;
|
|
286
|
+
payload?: P;
|
|
287
|
+
requestConfig?: RequestConfig;
|
|
288
|
+
}): Promise<HttpResponse<T>>;
|
|
289
|
+
requestStream({
|
|
290
|
+
headers,
|
|
291
|
+
url,
|
|
292
|
+
method,
|
|
293
|
+
queryParams,
|
|
294
|
+
maxRedirects,
|
|
295
|
+
context,
|
|
296
|
+
traceId,
|
|
297
|
+
payload,
|
|
298
|
+
httpsAgent,
|
|
299
|
+
httpAgent,
|
|
300
|
+
requestConfig,
|
|
301
|
+
httpsAgentConfig
|
|
302
|
+
}: {
|
|
303
|
+
headers?: HttpHeaders;
|
|
304
|
+
url: string;
|
|
305
|
+
method?: HttpMethod;
|
|
306
|
+
queryParams?: HttpQueryParams;
|
|
307
|
+
maxRedirects?: number;
|
|
308
|
+
context?: RequestContext;
|
|
309
|
+
traceId?: string;
|
|
310
|
+
payload?: unknown;
|
|
311
|
+
httpsAgent?: https.Agent;
|
|
312
|
+
httpAgent?: http.Agent;
|
|
313
|
+
requestConfig?: RequestConfig;
|
|
314
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
315
|
+
}): Promise<StreamHttpResponse>;
|
|
316
|
+
}
|
|
317
|
+
interface OperationSetting {
|
|
318
|
+
url?: string;
|
|
319
|
+
query?: Record<string, string>;
|
|
320
|
+
config?: Partial<APIConfig>;
|
|
321
|
+
custom_settings?: Record<string, unknown>;
|
|
322
|
+
}
|
|
323
|
+
type OperationSettings = Record<string, OperationSetting>;
|
|
324
|
+
type AccountSettings = Record<string, string | number | boolean | object>;
|
|
325
|
+
type HttpClientBehaviour = 'CONCURRENCY' | 'RETRY';
|
|
326
|
+
type APIConfig = Record<string, unknown>;
|
|
327
|
+
type RequestContext = {
|
|
328
|
+
accountSecureId?: string;
|
|
329
|
+
projectSecureId?: string;
|
|
330
|
+
organizationId?: number | string;
|
|
331
|
+
environment?: string;
|
|
332
|
+
authConfigKey?: string;
|
|
333
|
+
provider?: string;
|
|
334
|
+
service?: string;
|
|
335
|
+
resource?: string;
|
|
336
|
+
subResource?: string;
|
|
337
|
+
childResource?: string;
|
|
338
|
+
operation?: string;
|
|
339
|
+
action?: string;
|
|
340
|
+
mode?: string;
|
|
341
|
+
testerUniqueToken?: string;
|
|
342
|
+
externalKey?: string;
|
|
343
|
+
dataKey?: string;
|
|
344
|
+
isDataSync?: boolean;
|
|
345
|
+
operationSettings?: OperationSettings;
|
|
346
|
+
accountSettings?: AccountSettings;
|
|
347
|
+
behaviours?: HttpClientBehaviour[];
|
|
348
|
+
};
|
|
349
|
+
type ErrorMappingFn<TError extends Error = Error> = (error: Error) => TError | undefined;
|
|
350
|
+
type TransportFactory = ({
|
|
351
|
+
logger,
|
|
352
|
+
redisClientConfig,
|
|
353
|
+
context,
|
|
354
|
+
requestConfig,
|
|
355
|
+
httpsAgentConfig
|
|
356
|
+
}: {
|
|
357
|
+
logger?: ILogger;
|
|
358
|
+
redisClientConfig?: RedisClientConfig;
|
|
359
|
+
context?: RequestContext;
|
|
360
|
+
requestConfig?: RequestConfig;
|
|
361
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
362
|
+
}) => Promise<AxiosInstance>;
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region ../transport/src/httpClient/httpClient.d.ts
|
|
365
|
+
declare class HttpClient<TError extends Error = Error> implements IHttpClient {
|
|
366
|
+
#private;
|
|
367
|
+
name: string;
|
|
368
|
+
constructor({
|
|
369
|
+
transportFactory,
|
|
370
|
+
getRedisClient,
|
|
371
|
+
logger,
|
|
372
|
+
redisClientConfig,
|
|
373
|
+
errorMappingFn
|
|
374
|
+
}?: {
|
|
375
|
+
transportFactory?: TransportFactory;
|
|
376
|
+
getRedisClient?: RedisClientBuilder;
|
|
377
|
+
logger?: ILogger;
|
|
378
|
+
redisClientConfig?: RedisClientConfig;
|
|
379
|
+
errorMappingFn?: ErrorMappingFn<TError>;
|
|
380
|
+
});
|
|
381
|
+
request<P, T>({
|
|
382
|
+
headers,
|
|
383
|
+
url,
|
|
384
|
+
method,
|
|
385
|
+
queryParams,
|
|
386
|
+
maxRedirects,
|
|
387
|
+
responseType,
|
|
388
|
+
cacheTTL,
|
|
389
|
+
context,
|
|
390
|
+
traceId,
|
|
391
|
+
payload,
|
|
392
|
+
httpsAgent,
|
|
393
|
+
httpAgent,
|
|
394
|
+
requestConfig,
|
|
395
|
+
httpsAgentConfig
|
|
396
|
+
}: {
|
|
397
|
+
headers?: HttpHeaders;
|
|
398
|
+
url: string;
|
|
399
|
+
method?: HttpMethod;
|
|
400
|
+
queryParams?: HttpQueryParams;
|
|
401
|
+
maxRedirects?: number;
|
|
402
|
+
responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text';
|
|
403
|
+
cacheTTL?: number;
|
|
404
|
+
context?: RequestContext;
|
|
405
|
+
traceId?: string;
|
|
406
|
+
payload?: P;
|
|
407
|
+
httpsAgent?: https.Agent;
|
|
408
|
+
httpAgent?: http.Agent;
|
|
409
|
+
requestConfig?: RequestConfig;
|
|
410
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
411
|
+
}): Promise<HttpResponse<T>>;
|
|
412
|
+
get<T>({
|
|
413
|
+
headers,
|
|
414
|
+
url,
|
|
415
|
+
queryParams,
|
|
416
|
+
maxRedirects,
|
|
417
|
+
cacheTTL,
|
|
418
|
+
context,
|
|
419
|
+
traceId,
|
|
420
|
+
requestConfig
|
|
421
|
+
}: {
|
|
422
|
+
headers?: HttpHeaders;
|
|
423
|
+
url: string;
|
|
424
|
+
queryParams?: HttpQueryParams;
|
|
425
|
+
maxRedirects?: number;
|
|
426
|
+
cacheTTL?: number;
|
|
427
|
+
context?: RequestContext;
|
|
428
|
+
traceId?: string;
|
|
429
|
+
requestConfig?: RequestConfig;
|
|
430
|
+
}): Promise<HttpResponse<T>>;
|
|
431
|
+
post<P, T>({
|
|
432
|
+
headers,
|
|
433
|
+
url,
|
|
434
|
+
maxRedirects,
|
|
435
|
+
cacheTTL,
|
|
436
|
+
context,
|
|
437
|
+
traceId,
|
|
438
|
+
payload,
|
|
439
|
+
requestConfig
|
|
440
|
+
}: {
|
|
441
|
+
headers?: HttpHeaders;
|
|
442
|
+
url: string;
|
|
443
|
+
maxRedirects?: number;
|
|
444
|
+
cacheTTL?: number;
|
|
445
|
+
context?: RequestContext;
|
|
446
|
+
traceId?: string;
|
|
447
|
+
payload?: P;
|
|
448
|
+
requestConfig?: RequestConfig;
|
|
449
|
+
}): Promise<HttpResponse<T>>;
|
|
450
|
+
requestStream({
|
|
451
|
+
headers,
|
|
452
|
+
url,
|
|
453
|
+
method,
|
|
454
|
+
queryParams,
|
|
455
|
+
maxRedirects,
|
|
456
|
+
context,
|
|
457
|
+
traceId,
|
|
458
|
+
payload,
|
|
459
|
+
httpsAgent,
|
|
460
|
+
httpAgent,
|
|
461
|
+
requestConfig,
|
|
462
|
+
httpsAgentConfig
|
|
463
|
+
}: {
|
|
464
|
+
headers?: HttpHeaders;
|
|
465
|
+
url: string;
|
|
466
|
+
method?: HttpMethod;
|
|
467
|
+
queryParams?: HttpQueryParams;
|
|
468
|
+
maxRedirects?: number;
|
|
469
|
+
context?: RequestContext;
|
|
470
|
+
traceId?: string;
|
|
471
|
+
payload?: unknown;
|
|
472
|
+
httpsAgent?: https.Agent;
|
|
473
|
+
httpAgent?: http.Agent;
|
|
474
|
+
requestConfig?: RequestConfig;
|
|
475
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
476
|
+
}): Promise<StreamHttpResponse>;
|
|
477
|
+
}
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/logs/types.d.ts
|
|
480
|
+
type ActionsQuery = {
|
|
481
|
+
organizationId?: string | string[];
|
|
482
|
+
projectSecureId?: string | string[];
|
|
483
|
+
actionRunId?: string | string[];
|
|
484
|
+
accountSecureId?: string | string[];
|
|
485
|
+
actionId?: string | string[];
|
|
486
|
+
connectorKey?: string | string[];
|
|
487
|
+
mode?: string | string[];
|
|
488
|
+
category?: string | string[];
|
|
489
|
+
success?: boolean;
|
|
490
|
+
startTime?: Date;
|
|
491
|
+
endTime?: Date;
|
|
492
|
+
pageNumber?: number;
|
|
493
|
+
pageSize?: number;
|
|
494
|
+
};
|
|
495
|
+
type ActionsQueryResult = {
|
|
496
|
+
actionLogs: ActionLog[];
|
|
497
|
+
total: number;
|
|
498
|
+
pageNumber: number;
|
|
499
|
+
pageSize: number;
|
|
500
|
+
};
|
|
501
|
+
type StepsQuery = {
|
|
502
|
+
organizationId?: string | string[];
|
|
503
|
+
projectSecureId?: string | string[];
|
|
504
|
+
accountSecureId?: string | string[];
|
|
505
|
+
actionRunId?: string | string[];
|
|
506
|
+
stepId?: string | string[];
|
|
507
|
+
success?: boolean;
|
|
508
|
+
startTime?: Date;
|
|
509
|
+
endTime?: Date;
|
|
510
|
+
pageNumber?: number;
|
|
511
|
+
pageSize?: number;
|
|
512
|
+
};
|
|
513
|
+
type StepsQueryResult = {
|
|
514
|
+
stepLogs: StepLog[];
|
|
515
|
+
total: number;
|
|
516
|
+
pageNumber: number;
|
|
517
|
+
pageSize: number;
|
|
518
|
+
};
|
|
519
|
+
type HttpClientBuilder = (logger?: ILogger) => HttpClient | undefined;
|
|
520
|
+
interface KafkaClientConfig {
|
|
521
|
+
brokers: string[];
|
|
522
|
+
}
|
|
523
|
+
type KafkaClientBuilder = (config?: KafkaClientConfig, logger?: ILogger) => Kafka | undefined;
|
|
524
|
+
type ActionLog = {
|
|
525
|
+
actionRunId: string;
|
|
526
|
+
actionId: string;
|
|
527
|
+
connectorKey: string;
|
|
528
|
+
connectorVersion: string;
|
|
529
|
+
organizationId: string;
|
|
530
|
+
projectSecureId: string;
|
|
531
|
+
accountSecureId: string;
|
|
532
|
+
mode?: string;
|
|
533
|
+
category?: string;
|
|
534
|
+
originOwnerId?: string;
|
|
535
|
+
originOwnerName?: string;
|
|
536
|
+
httpMethod?: string;
|
|
537
|
+
url?: string;
|
|
538
|
+
sourceType?: string;
|
|
539
|
+
sourceId?: string;
|
|
540
|
+
sourceValue?: string;
|
|
541
|
+
success?: boolean;
|
|
542
|
+
statusCode?: number;
|
|
543
|
+
startTime?: Date;
|
|
544
|
+
endTime?: Date;
|
|
545
|
+
durationMs?: number;
|
|
546
|
+
eventTime?: Date;
|
|
547
|
+
riskLevel?: string;
|
|
548
|
+
tier2Score?: number;
|
|
549
|
+
};
|
|
550
|
+
type StepLog = {
|
|
551
|
+
actionRunId: string;
|
|
552
|
+
stepIndex: number;
|
|
553
|
+
stepId: string;
|
|
554
|
+
organizationId: string;
|
|
555
|
+
projectSecureId: string;
|
|
556
|
+
accountSecureId: string;
|
|
557
|
+
skipped?: boolean;
|
|
558
|
+
success?: boolean;
|
|
559
|
+
message?: string;
|
|
560
|
+
startTime?: Date;
|
|
561
|
+
endTime?: Date;
|
|
562
|
+
durationMs?: number;
|
|
563
|
+
eventTime?: Date;
|
|
564
|
+
};
|
|
565
|
+
//#endregion
|
|
88
566
|
//#region src/types.d.ts
|
|
89
567
|
interface IOlapClient {
|
|
90
568
|
recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): void;
|
|
91
569
|
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>;
|
|
92
574
|
}
|
|
93
575
|
type DefenderContext = {
|
|
94
576
|
riskLevel: string;
|
|
@@ -161,11 +643,30 @@ interface S3ClientConfig {
|
|
|
161
643
|
}
|
|
162
644
|
type S3ClientBuilder = (config?: S3ClientConfig, logger?: ILogger) => S3Client | undefined;
|
|
163
645
|
//#endregion
|
|
164
|
-
//#region src/logs/
|
|
165
|
-
interface
|
|
166
|
-
|
|
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;
|
|
167
669
|
}
|
|
168
|
-
type KafkaClientBuilder = (config?: KafkaClientConfig, logger?: ILogger) => Kafka | undefined;
|
|
169
670
|
//#endregion
|
|
170
671
|
//#region src/olap/olapClient.d.ts
|
|
171
672
|
declare class OlapClient implements IOlapClient {
|
|
@@ -173,54 +674,70 @@ declare class OlapClient implements IOlapClient {
|
|
|
173
674
|
name: string;
|
|
174
675
|
constructor({
|
|
175
676
|
getKafkaClient,
|
|
677
|
+
getHttpClient,
|
|
176
678
|
getS3Client,
|
|
177
679
|
kafkaClientConfig,
|
|
178
680
|
s3ClientConfig,
|
|
681
|
+
tinybirdConfig,
|
|
179
682
|
logger
|
|
180
683
|
}?: {
|
|
181
684
|
getKafkaClient?: KafkaClientBuilder;
|
|
685
|
+
getHttpClient?: HttpClientBuilder;
|
|
182
686
|
getS3Client?: S3ClientBuilder;
|
|
183
687
|
kafkaClientConfig?: KafkaClientConfig;
|
|
184
688
|
s3ClientConfig?: S3ClientConfig;
|
|
689
|
+
tinybirdConfig?: TinybirdConfig;
|
|
185
690
|
logger?: ILogger;
|
|
186
691
|
});
|
|
187
692
|
initialize(): Promise<void>;
|
|
188
693
|
recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): Promise<void>;
|
|
189
694
|
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>;
|
|
190
699
|
}
|
|
191
700
|
//#endregion
|
|
192
701
|
//#region src/olap/olapClientManager.d.ts
|
|
193
702
|
declare const buildOlapClientInstance: ({
|
|
194
703
|
getKafkaClient,
|
|
704
|
+
getHttpClient,
|
|
195
705
|
getS3Client,
|
|
196
706
|
kafkaClientConfig,
|
|
197
707
|
s3ClientConfig,
|
|
708
|
+
tinybirdConfig,
|
|
198
709
|
logger
|
|
199
710
|
}?: {
|
|
200
711
|
getKafkaClient?: KafkaClientBuilder;
|
|
712
|
+
getHttpClient?: HttpClientBuilder;
|
|
201
713
|
getS3Client?: S3ClientBuilder;
|
|
202
714
|
kafkaClientConfig?: KafkaClientConfig;
|
|
203
715
|
s3ClientConfig?: S3ClientConfig;
|
|
716
|
+
tinybirdConfig?: TinybirdConfig;
|
|
204
717
|
logger?: ILogger;
|
|
205
718
|
}) => Promise<IOlapClient>;
|
|
206
719
|
declare class OlapClientManager {
|
|
207
720
|
private static olapClientPromise;
|
|
208
721
|
static getInstance({
|
|
209
722
|
getKafkaClient,
|
|
723
|
+
getHttpClient,
|
|
210
724
|
getS3Client,
|
|
211
725
|
kafkaClientConfig,
|
|
212
726
|
s3ClientConfig,
|
|
727
|
+
tinybirdConfig,
|
|
213
728
|
logger,
|
|
214
729
|
getOlapClient
|
|
215
730
|
}?: {
|
|
216
731
|
getKafkaClient?: KafkaClientBuilder;
|
|
732
|
+
getHttpClient?: HttpClientBuilder;
|
|
217
733
|
getS3Client?: S3ClientBuilder;
|
|
218
734
|
kafkaClientConfig?: KafkaClientConfig;
|
|
219
735
|
s3ClientConfig?: S3ClientConfig;
|
|
736
|
+
tinybirdConfig?: TinybirdConfig;
|
|
220
737
|
logger?: ILogger;
|
|
221
738
|
getOlapClient?: typeof buildOlapClientInstance;
|
|
222
739
|
}): Promise<IOlapClient>;
|
|
223
740
|
static resetInstance(): void;
|
|
224
741
|
}
|
|
225
742
|
//#endregion
|
|
226
|
-
export { type ActionInput, type ActionResult, type AdvancedOptions, type DefenderContext, type DefenderOptions, type IOlapClient, type LogsOptions, OlapClient, OlapClientManager, type OlapOptions, type StepInput, type StepResult };
|
|
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 };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { t as __name } from "./chunk-Cfxk5zVN.mjs";
|
|
2
|
+
import "@stackone/utils";
|
|
2
3
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
3
4
|
import { Kafka } from "kafkajs";
|
|
5
|
+
import http from "node:http";
|
|
6
|
+
import * as redis from "redis";
|
|
7
|
+
import { AxiosInstance } from "axios";
|
|
8
|
+
import https from "node:https";
|
|
9
|
+
import { Readable } from "node:stream";
|
|
4
10
|
|
|
5
11
|
//#region ../logger/src/types.d.ts
|
|
6
12
|
interface ILogger {
|
|
@@ -84,10 +90,487 @@ type DefenderOptions = {
|
|
|
84
90
|
enabled?: boolean;
|
|
85
91
|
};
|
|
86
92
|
//#endregion
|
|
93
|
+
//#region ../transport/src/cacheClient/types.d.ts
|
|
94
|
+
interface ICacheClient<ClientType = unknown> {
|
|
95
|
+
getData<T>(key: string): Promise<T | null>;
|
|
96
|
+
listData<T>({
|
|
97
|
+
partialKey,
|
|
98
|
+
limit,
|
|
99
|
+
cursor
|
|
100
|
+
}: {
|
|
101
|
+
partialKey: string;
|
|
102
|
+
limit?: number;
|
|
103
|
+
cursor?: string;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
items: T[] | null;
|
|
106
|
+
cursor?: string;
|
|
107
|
+
}>;
|
|
108
|
+
setData<T>({
|
|
109
|
+
key,
|
|
110
|
+
value,
|
|
111
|
+
cacheTTL,
|
|
112
|
+
groupKey
|
|
113
|
+
}: {
|
|
114
|
+
key: string;
|
|
115
|
+
value: T;
|
|
116
|
+
cacheTTL: number;
|
|
117
|
+
groupKey?: string;
|
|
118
|
+
}): Promise<boolean>;
|
|
119
|
+
executeScript?<T>({
|
|
120
|
+
sha1,
|
|
121
|
+
keys,
|
|
122
|
+
args
|
|
123
|
+
}: {
|
|
124
|
+
sha1: string;
|
|
125
|
+
keys: string[];
|
|
126
|
+
args: string[];
|
|
127
|
+
}): Promise<T | null>;
|
|
128
|
+
loadScript?(script: string): Promise<string | null>;
|
|
129
|
+
scriptExists?(shas: string[]): Promise<boolean[]>;
|
|
130
|
+
increment?(key: string, cacheTTL: number): Promise<number | null>;
|
|
131
|
+
decrement?(key: string, cacheTTL: number): Promise<number | null>;
|
|
132
|
+
subscribe?<T extends boolean = false>(pattern: string, listener: PubSubListener<T>): Promise<boolean>;
|
|
133
|
+
unsubscribe?(pattern: string): Promise<boolean>;
|
|
134
|
+
publish?(channel: string, message: string): Promise<number | null>;
|
|
135
|
+
getClient?(): ClientType | null;
|
|
136
|
+
deleteData?(key: string): Promise<boolean>;
|
|
137
|
+
close?(): Promise<void> | void;
|
|
138
|
+
}
|
|
139
|
+
type PubSubListener<ReturnsBuffer extends boolean = false> = <T extends (ReturnsBuffer extends true ? Buffer : string)>(message: T, channel: T) => unknown;
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region ../transport/src/redisClient/types.d.ts
|
|
142
|
+
type RedisClientType = redis.RedisClientType;
|
|
143
|
+
interface RedisClientConfig {
|
|
144
|
+
getRedisClient?: typeof redis.createClient;
|
|
145
|
+
host?: string;
|
|
146
|
+
port?: number;
|
|
147
|
+
tls?: boolean;
|
|
148
|
+
reconnect?: boolean;
|
|
149
|
+
database?: number;
|
|
150
|
+
}
|
|
151
|
+
type RedisClientBuilder = (config: RedisClientConfig, logger?: ILogger, invoker?: string) => Promise<ICacheClient<RedisClientType> | undefined>;
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region ../transport/src/concurrencyManager/types.d.ts
|
|
154
|
+
type ConcurrencySubPoolConfig = {
|
|
155
|
+
subPoolKey: string;
|
|
156
|
+
urlPattern: RegExp | string;
|
|
157
|
+
maxConcurrency: number;
|
|
158
|
+
};
|
|
159
|
+
type ConcurrencyConfig = {
|
|
160
|
+
mainMaxConcurrency: number;
|
|
161
|
+
subPools?: ConcurrencySubPoolConfig[];
|
|
162
|
+
};
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region ../transport/src/rateLimitManager/types.d.ts
|
|
165
|
+
type RateLimitSubPoolConfig = {
|
|
166
|
+
subPoolKey: string;
|
|
167
|
+
urlPattern: RegExp | string;
|
|
168
|
+
rateLimit: number;
|
|
169
|
+
};
|
|
170
|
+
type RetryUnit = 'seconds' | 'milliseconds' | 'date';
|
|
171
|
+
type MappedRateLimitErrorConfig = {
|
|
172
|
+
errorStatus: number;
|
|
173
|
+
errorMessage: string | RegExp;
|
|
174
|
+
errorMessagePath?: string;
|
|
175
|
+
retryAfterPath?: string;
|
|
176
|
+
retryAfterUnit?: RetryUnit;
|
|
177
|
+
retryAfterValue?: number;
|
|
178
|
+
};
|
|
179
|
+
type RateLimitConfig = {
|
|
180
|
+
mainRatelimit: number;
|
|
181
|
+
subPools?: RateLimitSubPoolConfig[];
|
|
182
|
+
mappedRateLimitErrors?: MappedRateLimitErrorConfig[];
|
|
183
|
+
};
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region ../transport/src/interceptors/types.d.ts
|
|
186
|
+
type RequestConfig = {
|
|
187
|
+
rateLimits?: RateLimitConfig;
|
|
188
|
+
concurrency?: ConcurrencyConfig;
|
|
189
|
+
};
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region ../transport/src/parsers/types.d.ts
|
|
192
|
+
declare const QueryArrayFormats: readonly ["repeat", "brackets", "comma"];
|
|
193
|
+
type QueryArrayFormat = (typeof QueryArrayFormats)[number];
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region ../transport/src/httpClient/types.d.ts
|
|
196
|
+
type HttpHeader = string | string[];
|
|
197
|
+
type HttpHeaders = {
|
|
198
|
+
[key: string]: HttpHeader;
|
|
199
|
+
};
|
|
200
|
+
type HttpQueryParamValue = {
|
|
201
|
+
value: string | string[];
|
|
202
|
+
arrayFormat?: QueryArrayFormat;
|
|
203
|
+
};
|
|
204
|
+
type HttpQueryParams = {
|
|
205
|
+
[key: string]: string | string[] | HttpQueryParamValue;
|
|
206
|
+
};
|
|
207
|
+
declare const HttpMethods: readonly ["get", "post", "put", "delete", "patch"];
|
|
208
|
+
type HttpMethod = (typeof HttpMethods)[number];
|
|
209
|
+
type HttpResponse<T = any, P = any> = {
|
|
210
|
+
data: T;
|
|
211
|
+
status: number;
|
|
212
|
+
headers: HttpHeaders;
|
|
213
|
+
requestUrl: string;
|
|
214
|
+
responseType?: string;
|
|
215
|
+
responseTime?: Date;
|
|
216
|
+
message?: string;
|
|
217
|
+
body?: P;
|
|
218
|
+
};
|
|
219
|
+
type StreamHttpResponse = {
|
|
220
|
+
status: number;
|
|
221
|
+
headers: HttpHeaders;
|
|
222
|
+
stream: Readable;
|
|
223
|
+
requestUrl: string;
|
|
224
|
+
};
|
|
225
|
+
interface IHttpClient {
|
|
226
|
+
request<P, T>({
|
|
227
|
+
headers,
|
|
228
|
+
url,
|
|
229
|
+
method,
|
|
230
|
+
queryParams,
|
|
231
|
+
maxRedirects,
|
|
232
|
+
responseType,
|
|
233
|
+
cacheTTL,
|
|
234
|
+
context,
|
|
235
|
+
payload,
|
|
236
|
+
httpsAgent,
|
|
237
|
+
httpAgent,
|
|
238
|
+
requestConfig,
|
|
239
|
+
httpsAgentConfig
|
|
240
|
+
}: {
|
|
241
|
+
headers?: HttpHeaders;
|
|
242
|
+
url: string;
|
|
243
|
+
method?: HttpMethod;
|
|
244
|
+
queryParams?: HttpQueryParams;
|
|
245
|
+
maxRedirects?: number;
|
|
246
|
+
responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text';
|
|
247
|
+
cacheTTL?: number;
|
|
248
|
+
context?: RequestContext;
|
|
249
|
+
payload?: P;
|
|
250
|
+
httpsAgent?: https.Agent;
|
|
251
|
+
httpAgent?: http.Agent;
|
|
252
|
+
requestConfig?: RequestConfig;
|
|
253
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
254
|
+
}): Promise<HttpResponse<T>>;
|
|
255
|
+
get<T>({
|
|
256
|
+
headers,
|
|
257
|
+
url,
|
|
258
|
+
queryParams,
|
|
259
|
+
maxRedirects,
|
|
260
|
+
cacheTTL,
|
|
261
|
+
context,
|
|
262
|
+
requestConfig
|
|
263
|
+
}: {
|
|
264
|
+
headers?: HttpHeaders;
|
|
265
|
+
url: string;
|
|
266
|
+
queryParams?: HttpQueryParams;
|
|
267
|
+
maxRedirects?: number;
|
|
268
|
+
cacheTTL?: number;
|
|
269
|
+
context?: RequestContext;
|
|
270
|
+
requestConfig?: RequestConfig;
|
|
271
|
+
}): Promise<HttpResponse<T>>;
|
|
272
|
+
post<P, T>({
|
|
273
|
+
headers,
|
|
274
|
+
url,
|
|
275
|
+
maxRedirects,
|
|
276
|
+
cacheTTL,
|
|
277
|
+
context,
|
|
278
|
+
payload,
|
|
279
|
+
requestConfig
|
|
280
|
+
}: {
|
|
281
|
+
headers?: HttpHeaders;
|
|
282
|
+
url: string;
|
|
283
|
+
maxRedirects?: number;
|
|
284
|
+
cacheTTL?: number;
|
|
285
|
+
context?: RequestContext;
|
|
286
|
+
payload?: P;
|
|
287
|
+
requestConfig?: RequestConfig;
|
|
288
|
+
}): Promise<HttpResponse<T>>;
|
|
289
|
+
requestStream({
|
|
290
|
+
headers,
|
|
291
|
+
url,
|
|
292
|
+
method,
|
|
293
|
+
queryParams,
|
|
294
|
+
maxRedirects,
|
|
295
|
+
context,
|
|
296
|
+
traceId,
|
|
297
|
+
payload,
|
|
298
|
+
httpsAgent,
|
|
299
|
+
httpAgent,
|
|
300
|
+
requestConfig,
|
|
301
|
+
httpsAgentConfig
|
|
302
|
+
}: {
|
|
303
|
+
headers?: HttpHeaders;
|
|
304
|
+
url: string;
|
|
305
|
+
method?: HttpMethod;
|
|
306
|
+
queryParams?: HttpQueryParams;
|
|
307
|
+
maxRedirects?: number;
|
|
308
|
+
context?: RequestContext;
|
|
309
|
+
traceId?: string;
|
|
310
|
+
payload?: unknown;
|
|
311
|
+
httpsAgent?: https.Agent;
|
|
312
|
+
httpAgent?: http.Agent;
|
|
313
|
+
requestConfig?: RequestConfig;
|
|
314
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
315
|
+
}): Promise<StreamHttpResponse>;
|
|
316
|
+
}
|
|
317
|
+
interface OperationSetting {
|
|
318
|
+
url?: string;
|
|
319
|
+
query?: Record<string, string>;
|
|
320
|
+
config?: Partial<APIConfig>;
|
|
321
|
+
custom_settings?: Record<string, unknown>;
|
|
322
|
+
}
|
|
323
|
+
type OperationSettings = Record<string, OperationSetting>;
|
|
324
|
+
type AccountSettings = Record<string, string | number | boolean | object>;
|
|
325
|
+
type HttpClientBehaviour = 'CONCURRENCY' | 'RETRY';
|
|
326
|
+
type APIConfig = Record<string, unknown>;
|
|
327
|
+
type RequestContext = {
|
|
328
|
+
accountSecureId?: string;
|
|
329
|
+
projectSecureId?: string;
|
|
330
|
+
organizationId?: number | string;
|
|
331
|
+
environment?: string;
|
|
332
|
+
authConfigKey?: string;
|
|
333
|
+
provider?: string;
|
|
334
|
+
service?: string;
|
|
335
|
+
resource?: string;
|
|
336
|
+
subResource?: string;
|
|
337
|
+
childResource?: string;
|
|
338
|
+
operation?: string;
|
|
339
|
+
action?: string;
|
|
340
|
+
mode?: string;
|
|
341
|
+
testerUniqueToken?: string;
|
|
342
|
+
externalKey?: string;
|
|
343
|
+
dataKey?: string;
|
|
344
|
+
isDataSync?: boolean;
|
|
345
|
+
operationSettings?: OperationSettings;
|
|
346
|
+
accountSettings?: AccountSettings;
|
|
347
|
+
behaviours?: HttpClientBehaviour[];
|
|
348
|
+
};
|
|
349
|
+
type ErrorMappingFn<TError extends Error = Error> = (error: Error) => TError | undefined;
|
|
350
|
+
type TransportFactory = ({
|
|
351
|
+
logger,
|
|
352
|
+
redisClientConfig,
|
|
353
|
+
context,
|
|
354
|
+
requestConfig,
|
|
355
|
+
httpsAgentConfig
|
|
356
|
+
}: {
|
|
357
|
+
logger?: ILogger;
|
|
358
|
+
redisClientConfig?: RedisClientConfig;
|
|
359
|
+
context?: RequestContext;
|
|
360
|
+
requestConfig?: RequestConfig;
|
|
361
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
362
|
+
}) => Promise<AxiosInstance>;
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region ../transport/src/httpClient/httpClient.d.ts
|
|
365
|
+
declare class HttpClient<TError extends Error = Error> implements IHttpClient {
|
|
366
|
+
#private;
|
|
367
|
+
name: string;
|
|
368
|
+
constructor({
|
|
369
|
+
transportFactory,
|
|
370
|
+
getRedisClient,
|
|
371
|
+
logger,
|
|
372
|
+
redisClientConfig,
|
|
373
|
+
errorMappingFn
|
|
374
|
+
}?: {
|
|
375
|
+
transportFactory?: TransportFactory;
|
|
376
|
+
getRedisClient?: RedisClientBuilder;
|
|
377
|
+
logger?: ILogger;
|
|
378
|
+
redisClientConfig?: RedisClientConfig;
|
|
379
|
+
errorMappingFn?: ErrorMappingFn<TError>;
|
|
380
|
+
});
|
|
381
|
+
request<P, T>({
|
|
382
|
+
headers,
|
|
383
|
+
url,
|
|
384
|
+
method,
|
|
385
|
+
queryParams,
|
|
386
|
+
maxRedirects,
|
|
387
|
+
responseType,
|
|
388
|
+
cacheTTL,
|
|
389
|
+
context,
|
|
390
|
+
traceId,
|
|
391
|
+
payload,
|
|
392
|
+
httpsAgent,
|
|
393
|
+
httpAgent,
|
|
394
|
+
requestConfig,
|
|
395
|
+
httpsAgentConfig
|
|
396
|
+
}: {
|
|
397
|
+
headers?: HttpHeaders;
|
|
398
|
+
url: string;
|
|
399
|
+
method?: HttpMethod;
|
|
400
|
+
queryParams?: HttpQueryParams;
|
|
401
|
+
maxRedirects?: number;
|
|
402
|
+
responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text';
|
|
403
|
+
cacheTTL?: number;
|
|
404
|
+
context?: RequestContext;
|
|
405
|
+
traceId?: string;
|
|
406
|
+
payload?: P;
|
|
407
|
+
httpsAgent?: https.Agent;
|
|
408
|
+
httpAgent?: http.Agent;
|
|
409
|
+
requestConfig?: RequestConfig;
|
|
410
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
411
|
+
}): Promise<HttpResponse<T>>;
|
|
412
|
+
get<T>({
|
|
413
|
+
headers,
|
|
414
|
+
url,
|
|
415
|
+
queryParams,
|
|
416
|
+
maxRedirects,
|
|
417
|
+
cacheTTL,
|
|
418
|
+
context,
|
|
419
|
+
traceId,
|
|
420
|
+
requestConfig
|
|
421
|
+
}: {
|
|
422
|
+
headers?: HttpHeaders;
|
|
423
|
+
url: string;
|
|
424
|
+
queryParams?: HttpQueryParams;
|
|
425
|
+
maxRedirects?: number;
|
|
426
|
+
cacheTTL?: number;
|
|
427
|
+
context?: RequestContext;
|
|
428
|
+
traceId?: string;
|
|
429
|
+
requestConfig?: RequestConfig;
|
|
430
|
+
}): Promise<HttpResponse<T>>;
|
|
431
|
+
post<P, T>({
|
|
432
|
+
headers,
|
|
433
|
+
url,
|
|
434
|
+
maxRedirects,
|
|
435
|
+
cacheTTL,
|
|
436
|
+
context,
|
|
437
|
+
traceId,
|
|
438
|
+
payload,
|
|
439
|
+
requestConfig
|
|
440
|
+
}: {
|
|
441
|
+
headers?: HttpHeaders;
|
|
442
|
+
url: string;
|
|
443
|
+
maxRedirects?: number;
|
|
444
|
+
cacheTTL?: number;
|
|
445
|
+
context?: RequestContext;
|
|
446
|
+
traceId?: string;
|
|
447
|
+
payload?: P;
|
|
448
|
+
requestConfig?: RequestConfig;
|
|
449
|
+
}): Promise<HttpResponse<T>>;
|
|
450
|
+
requestStream({
|
|
451
|
+
headers,
|
|
452
|
+
url,
|
|
453
|
+
method,
|
|
454
|
+
queryParams,
|
|
455
|
+
maxRedirects,
|
|
456
|
+
context,
|
|
457
|
+
traceId,
|
|
458
|
+
payload,
|
|
459
|
+
httpsAgent,
|
|
460
|
+
httpAgent,
|
|
461
|
+
requestConfig,
|
|
462
|
+
httpsAgentConfig
|
|
463
|
+
}: {
|
|
464
|
+
headers?: HttpHeaders;
|
|
465
|
+
url: string;
|
|
466
|
+
method?: HttpMethod;
|
|
467
|
+
queryParams?: HttpQueryParams;
|
|
468
|
+
maxRedirects?: number;
|
|
469
|
+
context?: RequestContext;
|
|
470
|
+
traceId?: string;
|
|
471
|
+
payload?: unknown;
|
|
472
|
+
httpsAgent?: https.Agent;
|
|
473
|
+
httpAgent?: http.Agent;
|
|
474
|
+
requestConfig?: RequestConfig;
|
|
475
|
+
httpsAgentConfig?: https.AgentOptions;
|
|
476
|
+
}): Promise<StreamHttpResponse>;
|
|
477
|
+
}
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/logs/types.d.ts
|
|
480
|
+
type ActionsQuery = {
|
|
481
|
+
organizationId?: string | string[];
|
|
482
|
+
projectSecureId?: string | string[];
|
|
483
|
+
actionRunId?: string | string[];
|
|
484
|
+
accountSecureId?: string | string[];
|
|
485
|
+
actionId?: string | string[];
|
|
486
|
+
connectorKey?: string | string[];
|
|
487
|
+
mode?: string | string[];
|
|
488
|
+
category?: string | string[];
|
|
489
|
+
success?: boolean;
|
|
490
|
+
startTime?: Date;
|
|
491
|
+
endTime?: Date;
|
|
492
|
+
pageNumber?: number;
|
|
493
|
+
pageSize?: number;
|
|
494
|
+
};
|
|
495
|
+
type ActionsQueryResult = {
|
|
496
|
+
actionLogs: ActionLog[];
|
|
497
|
+
total: number;
|
|
498
|
+
pageNumber: number;
|
|
499
|
+
pageSize: number;
|
|
500
|
+
};
|
|
501
|
+
type StepsQuery = {
|
|
502
|
+
organizationId?: string | string[];
|
|
503
|
+
projectSecureId?: string | string[];
|
|
504
|
+
accountSecureId?: string | string[];
|
|
505
|
+
actionRunId?: string | string[];
|
|
506
|
+
stepId?: string | string[];
|
|
507
|
+
success?: boolean;
|
|
508
|
+
startTime?: Date;
|
|
509
|
+
endTime?: Date;
|
|
510
|
+
pageNumber?: number;
|
|
511
|
+
pageSize?: number;
|
|
512
|
+
};
|
|
513
|
+
type StepsQueryResult = {
|
|
514
|
+
stepLogs: StepLog[];
|
|
515
|
+
total: number;
|
|
516
|
+
pageNumber: number;
|
|
517
|
+
pageSize: number;
|
|
518
|
+
};
|
|
519
|
+
type HttpClientBuilder = (logger?: ILogger) => HttpClient | undefined;
|
|
520
|
+
interface KafkaClientConfig {
|
|
521
|
+
brokers: string[];
|
|
522
|
+
}
|
|
523
|
+
type KafkaClientBuilder = (config?: KafkaClientConfig, logger?: ILogger) => Kafka | undefined;
|
|
524
|
+
type ActionLog = {
|
|
525
|
+
actionRunId: string;
|
|
526
|
+
actionId: string;
|
|
527
|
+
connectorKey: string;
|
|
528
|
+
connectorVersion: string;
|
|
529
|
+
organizationId: string;
|
|
530
|
+
projectSecureId: string;
|
|
531
|
+
accountSecureId: string;
|
|
532
|
+
mode?: string;
|
|
533
|
+
category?: string;
|
|
534
|
+
originOwnerId?: string;
|
|
535
|
+
originOwnerName?: string;
|
|
536
|
+
httpMethod?: string;
|
|
537
|
+
url?: string;
|
|
538
|
+
sourceType?: string;
|
|
539
|
+
sourceId?: string;
|
|
540
|
+
sourceValue?: string;
|
|
541
|
+
success?: boolean;
|
|
542
|
+
statusCode?: number;
|
|
543
|
+
startTime?: Date;
|
|
544
|
+
endTime?: Date;
|
|
545
|
+
durationMs?: number;
|
|
546
|
+
eventTime?: Date;
|
|
547
|
+
riskLevel?: string;
|
|
548
|
+
tier2Score?: number;
|
|
549
|
+
};
|
|
550
|
+
type StepLog = {
|
|
551
|
+
actionRunId: string;
|
|
552
|
+
stepIndex: number;
|
|
553
|
+
stepId: string;
|
|
554
|
+
organizationId: string;
|
|
555
|
+
projectSecureId: string;
|
|
556
|
+
accountSecureId: string;
|
|
557
|
+
skipped?: boolean;
|
|
558
|
+
success?: boolean;
|
|
559
|
+
message?: string;
|
|
560
|
+
startTime?: Date;
|
|
561
|
+
endTime?: Date;
|
|
562
|
+
durationMs?: number;
|
|
563
|
+
eventTime?: Date;
|
|
564
|
+
};
|
|
565
|
+
//#endregion
|
|
87
566
|
//#region src/types.d.ts
|
|
88
567
|
interface IOlapClient {
|
|
89
568
|
recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): void;
|
|
90
569
|
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>;
|
|
91
574
|
}
|
|
92
575
|
type DefenderContext = {
|
|
93
576
|
riskLevel: string;
|
|
@@ -160,11 +643,30 @@ interface S3ClientConfig {
|
|
|
160
643
|
}
|
|
161
644
|
type S3ClientBuilder = (config?: S3ClientConfig, logger?: ILogger) => S3Client | undefined;
|
|
162
645
|
//#endregion
|
|
163
|
-
//#region src/logs/
|
|
164
|
-
interface
|
|
165
|
-
|
|
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;
|
|
166
669
|
}
|
|
167
|
-
type KafkaClientBuilder = (config?: KafkaClientConfig, logger?: ILogger) => Kafka | undefined;
|
|
168
670
|
//#endregion
|
|
169
671
|
//#region src/olap/olapClient.d.ts
|
|
170
672
|
declare class OlapClient implements IOlapClient {
|
|
@@ -172,54 +674,70 @@ declare class OlapClient implements IOlapClient {
|
|
|
172
674
|
name: string;
|
|
173
675
|
constructor({
|
|
174
676
|
getKafkaClient,
|
|
677
|
+
getHttpClient,
|
|
175
678
|
getS3Client,
|
|
176
679
|
kafkaClientConfig,
|
|
177
680
|
s3ClientConfig,
|
|
681
|
+
tinybirdConfig,
|
|
178
682
|
logger
|
|
179
683
|
}?: {
|
|
180
684
|
getKafkaClient?: KafkaClientBuilder;
|
|
685
|
+
getHttpClient?: HttpClientBuilder;
|
|
181
686
|
getS3Client?: S3ClientBuilder;
|
|
182
687
|
kafkaClientConfig?: KafkaClientConfig;
|
|
183
688
|
s3ClientConfig?: S3ClientConfig;
|
|
689
|
+
tinybirdConfig?: TinybirdConfig;
|
|
184
690
|
logger?: ILogger;
|
|
185
691
|
});
|
|
186
692
|
initialize(): Promise<void>;
|
|
187
693
|
recordAction(actionInput: ActionInput, actionResult: ActionResult, options?: OlapOptions): Promise<void>;
|
|
188
694
|
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>;
|
|
189
699
|
}
|
|
190
700
|
//#endregion
|
|
191
701
|
//#region src/olap/olapClientManager.d.ts
|
|
192
702
|
declare const buildOlapClientInstance: ({
|
|
193
703
|
getKafkaClient,
|
|
704
|
+
getHttpClient,
|
|
194
705
|
getS3Client,
|
|
195
706
|
kafkaClientConfig,
|
|
196
707
|
s3ClientConfig,
|
|
708
|
+
tinybirdConfig,
|
|
197
709
|
logger
|
|
198
710
|
}?: {
|
|
199
711
|
getKafkaClient?: KafkaClientBuilder;
|
|
712
|
+
getHttpClient?: HttpClientBuilder;
|
|
200
713
|
getS3Client?: S3ClientBuilder;
|
|
201
714
|
kafkaClientConfig?: KafkaClientConfig;
|
|
202
715
|
s3ClientConfig?: S3ClientConfig;
|
|
716
|
+
tinybirdConfig?: TinybirdConfig;
|
|
203
717
|
logger?: ILogger;
|
|
204
718
|
}) => Promise<IOlapClient>;
|
|
205
719
|
declare class OlapClientManager {
|
|
206
720
|
private static olapClientPromise;
|
|
207
721
|
static getInstance({
|
|
208
722
|
getKafkaClient,
|
|
723
|
+
getHttpClient,
|
|
209
724
|
getS3Client,
|
|
210
725
|
kafkaClientConfig,
|
|
211
726
|
s3ClientConfig,
|
|
727
|
+
tinybirdConfig,
|
|
212
728
|
logger,
|
|
213
729
|
getOlapClient
|
|
214
730
|
}?: {
|
|
215
731
|
getKafkaClient?: KafkaClientBuilder;
|
|
732
|
+
getHttpClient?: HttpClientBuilder;
|
|
216
733
|
getS3Client?: S3ClientBuilder;
|
|
217
734
|
kafkaClientConfig?: KafkaClientConfig;
|
|
218
735
|
s3ClientConfig?: S3ClientConfig;
|
|
736
|
+
tinybirdConfig?: TinybirdConfig;
|
|
219
737
|
logger?: ILogger;
|
|
220
738
|
getOlapClient?: typeof buildOlapClientInstance;
|
|
221
739
|
}): Promise<IOlapClient>;
|
|
222
740
|
static resetInstance(): void;
|
|
223
741
|
}
|
|
224
742
|
//#endregion
|
|
225
|
-
export { type ActionInput, type ActionResult, type AdvancedOptions, type DefenderContext, type DefenderOptions, type IOlapClient, type LogsOptions, OlapClient, OlapClientManager, type OlapOptions, type StepInput, type StepResult };
|
|
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./chunk-Cfxk5zVN.mjs";import{CensorType as t,redactObject as n}from"@stackone/redaction";import{notMissing as r}from"@stackone/utils";import{PutObjectCommand as i,S3Client as a}from"@aws-sdk/client-s3";import{Kafka as o,Partitioners as s}from"kafkajs";const c=[`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`],l=[`refresh_authentication`],u=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 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 a=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(a*1e3).toISOString()}});try{await this.#e.send(new i({Bucket:n,Key:e.Key,Body:e.Body,ContentType:e.ContentType,Expires:new Date(a*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,u),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,u),ContentType:`application/json`,Expires:new Date(i*1e3)}}serializeActionResult(e,r,i,a){let o=n({req:{...e.headers&&{headers:{...e.headers}}},res:{...r.headers&&{headers:{...r.headers}}}},t.PARTIAL),s=o.req?.headers,c=o.res?.headers,l=n(e.body,t.PARTIAL),u=n(r.body,t.PARTIAL),d=this.isBackgroundLog(e),f={data:{request:{id:r.actionRunId,actionId:r.actionId,method:r.httpMethod,headers:this.filterHeaders(s),url:{url:e.url,path:e.pathParams,queryParams:e.queryParams},body:l},response:{statusCode:r.statusCode??500,headers:this.filterHeaders(c),body:u},...d?{isBackgroundLog:!0}:{}},metadata:{...d?{isBackgroundLog:!0}:{},expirationTime:i},expirationTime:i};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=c.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 r(e.mode)&&l.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 a(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 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 i({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}}createActionS3(e){return{Key:`${e.organizationId}/${e.projectSecureId}/${e.actionRunId}/defender.json`,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 buildKafkaClient=(e,t)=>{try{return new o(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 LogsSink=class{#e;#t;#n;constructor(e,t){this.#e=e,this.#n=t}async initialize(){if(!this.#e){this.#n?.warning({message:`No kafka client provided, logs sink cannot be initialized`,category:`LogsSink`});return}if(!this.#t){try{this.#t=this.#e.producer({createPartitioner:s.DefaultPartitioner})}catch(e){this.#n?.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.#n?.error?.({message:`Failed to connect kafka producer for logs sink`,code:`KafkaProducerConnectionError`,category:`LogsSink`,error:e}),this.#t=void 0;return}this.#n?.info({message:`Logs sink kafka producer initialized`,category:`LogsSink`})}}async sendAction(e,t,n){if(!n?.enabled){this.#n?.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.#n?.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 send(e,t){if(!this.#t)throw this.#n?.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.#n?.debug({message:`Sending to topic ${e}: ${n}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:n}]});this.#n?.debug({message:`Kafka producer response: ${JSON.stringify(t)}`,category:`KafkaSink`})}catch(t){throw this.#n?.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 d={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1,includeBackground:!1},defender:{enabled:!0}};function resolveOlapOptions(e){return{logs:{...d.logs,...e?.logs},advanced:{...d.advanced,...e?.advanced},defender:{...d.defender,...e?.defender}}}var OlapClient=class{#e;#t;#n;#r;#i;#a;constructor({getKafkaClient:e=buildKafkaClient,getS3Client:t=buildS3Client,kafkaClientConfig:n,s3ClientConfig:r,logger:i}={}){this.name=`OlapClient`,this.#e=e(n,i),this.#t=t(r,i),this.#n=i,this.#r=new LogsSink(this.#e,this.#n),this.#i=new AdvancedSink(this.#t,this.#n),this.#a=new DefenderSink(this.#t,this.#n)}async initialize(){await this.#r?.initialize(),await this.#i?.initialize(),await this.#a?.initialize()}async recordAction(e,t,n){let{logs:r,advanced:i,defender:a}=resolveOlapOptions(n);if(this.#n?.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.#r?.sendAction(e,t,r)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#i?.sendAction(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to advanced logs s3: ${e.message}`,category:`OlapClient`,error:e})}if(a?.enabled)try{await this.#a?.sendAction(e,t,a)}catch(e){this.#n?.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.#r?.sendStep(e,t,r)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to kafka: ${e.message}`,category:`OlapClient`,error:e})}if(i?.enabled)try{await this.#i?.sendStep(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}};const buildOlapClientInstance=async({getKafkaClient:e=buildKafkaClient,getS3Client:t=buildS3Client,kafkaClientConfig:n,s3ClientConfig:r,logger:i}={})=>{let a=new OlapClient({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i});return await a.initialize(),a};var OlapClientManager=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i,getOlapClient:a=buildOlapClientInstance}={}){return this.olapClientPromise||=a({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i}),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`}),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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackone/olap",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
"license": "ISC",
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@aws-sdk/client-s3": "3.913.0",
|
|
45
|
+
"@stackone/logger": "*",
|
|
45
46
|
"@stackone/redaction": "*",
|
|
47
|
+
"@stackone/transport": "*",
|
|
46
48
|
"@stackone/utils": "*",
|
|
47
49
|
"kafkajs": "2.2.4",
|
|
48
50
|
"date-fns": "2.30.0"
|