@stackone/olap 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +80 -1
  2. package/package.json +2 -1
package/dist/index.mjs CHANGED
@@ -1 +1,80 @@
1
- import{CensorType as e,redactObject as t}from"@stackone/redaction";import{notMissing as n}from"@stackone/utils";import{PutObjectCommand as r,S3Client as i}from"@aws-sdk/client-s3";import{Kafka as a,Partitioners as o}from"kafkajs";const s=[`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`];var c=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 send(e,t,n){if(!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending to advanced sink`,category:`AdvancedSink`});return}if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to advanced sink`,category:`AdvancedSink`});return}if(`mode`in e&&this.isDataSyncRequest(e)){this.#t?.debug({message:`Data sync request detected, skipping advanced log storage for actionRunId ${t.actionRunId}`,category:`AdvancedSink`});return}try{let i=await this.createS3Item(e,t,n.ttl);await this.#e.send(new r({Bucket:i.Bucket,Key:i.Key,Body:i.Body,ContentType:i.ContentType,Expires:i.Expires,Tagging:i.Tagging}))}catch(e){throw this.#t?.error({message:`Failed to write advanced logs to S3 account ${t.accountSecureId}`,error:e,code:`AdvancedLogWriteError`,category:`AdvancedSink`,context:{actionRunId:t.actionRunId}}),e}}async createS3Item(e,t,n){let{projectSecureId:r,organizationId:i}=t,a=`ttl=30d`;typeof n==`number`&&(n===1?a=`ttl=1d`:n===7&&(a=`ttl=7d`));let o=Math.floor(Date.now()/1e3)+(n??30)*24*60*60,s=process.env.ADVANCED_LOGS_BUCKET;if(!s)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);return{Bucket:s,Key:this.generateS3Key(t,i,r),Body:this.serialize(e,t,o,10485760),ContentType:`application/json`,Expires:new Date(o*1e3),Tagging:a}}generateS3Key(e,t,n){return`actionId`in e?`${t}/${n}/${e.actionRunId}/${e.actionRunId}.json`:`${t}/${n}/${e.actionRunId}/steps/${e.stepId}.json`}serialize(e,t,n,r){return`actionId`in t?JSON.stringify(this.serializeActionResult(e,t,n,r)):JSON.stringify(this.serializeStepResult(e,t))}serializeActionResult(n,r,i,a){let o=t({req:{...n.headers&&{headers:{...n.headers}}},res:{...r.headers&&{headers:{...r.headers}}}},e.PARTIAL),s=o.req?.headers,c=o.res?.headers,l=t(n.body,e.PARTIAL),u=t(r.body,e.PARTIAL),d=this.isBackgroundLog(n);return{data:{request:{id:r.actionRunId,actionId:r.actionId,method:r.httpMethod,headers:this.filterHeaders(s),url:{url:n.url,path:n.pathParams,queryParams:n.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}}serializeStepResult(e,t){return{}}filterHeaders(e){if(!e)return;let t={},n=s.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)&&[`refresh_authentication`].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 l=(e,t)=>{try{return new i(e)??void 0}catch(e){let n=e;t?.error({message:`Error building s3 client: ${n.message}`,error:n,code:`BuildS3ClientError`,category:`buildS3Client`});return}},u=(e,t)=>{try{return new a(e)??void 0}catch(e){let n=e;t?.error({message:`Error building kafka client: ${n.message}`,error:n,code:`BuildKafkaClientError`,category:`buildKafkaClient`});return}},d=e=>{try{return JSON.stringify(e)}catch{return`[Unserializable payload]`}};var f=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:o.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 send(e,t,n,r){if(!r?.enabled){this.#n?.debug({message:`Logs sink is disabled, skipping sending to log sink`,category:`KafkaSink`});return}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 i=d(this.buildLog(t,n));this.#n?.debug({message:`Sending to topic ${e}: ${i}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:i}]});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}}buildLog(e,t){if(this.isActionResult(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,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0));if(this.isStepResult(t))return Object.fromEntries(Object.entries({actionRunId:t.actionRunId,stepId:t.stepId,skipped:t.skipped,status:t.status,message:t.message,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0));throw this.#n?.error({message:`Unknown result type, cannot build log`,category:`KafkaSink`,code:`UnknownResultType`}),Error(`Unknown result type`)}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}isActionResult(e){return typeof e==`object`&&!!e&&`actionRunId`in e&&`actionId`in e}isStepResult(e){return typeof e==`object`&&!!e&&`actionRunId`in e&&`stepId`in e}};const p={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1}};function m(e){return{...p,...e}}var h=class{#e;#t;#n;#r;#i;constructor({getKafkaClient:e=u,getS3Client:t=l,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 f(this.#e,this.#n),this.#i=new c(this.#t,this.#n)}async initialize(){await this.#r?.initialize(),await this.#i?.initialize()}async recordAction(e,t,n){let{logs:r,advanced:i}=m(n);if(r?.enabled)try{await this.#r?.send(`actions`,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?.send(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}async recordStep(e,t,n){let{logs:r,advanced:i}=m(n);if(r?.enabled)try{await this.#r?.send(`steps`,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?.send(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}};const g=async({getKafkaClient:e=u,getS3Client:t=l,kafkaClientConfig:n,s3ClientConfig:r,logger:i}={})=>{let a=new h({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i});return await a.initialize(),a};var _=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i,getOlapClient:a=g}={}){return this.olapClientPromise||=a({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i}),this.olapClientPromise}static resetInstance(){this.olapClientPromise=null}};export{h as OlapClient,_ as OlapClientManager};
1
+ import{deepCopy as e,isMissing as t,notMissing as n}from"@stackone/utils";import{PutObjectCommand as r,S3Client as i}from"@aws-sdk/client-s3";import{Kafka as a,Partitioners as o}from"kafkajs";var s=Object.create,c=Object.defineProperty,l=Object.getOwnPropertyDescriptor,u=Object.getOwnPropertyNames,d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty,p=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),m=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=u(t),a=0,o=i.length,s;a<o;a++)s=i[a],!f.call(e,s)&&s!==n&&c(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=l(t,s))||r.enumerable});return e},h=(e,t,n)=>(n=e==null?{}:s(d(e)),m(t||!e||!e.__esModule?c(n,`default`,{value:e,enumerable:!0}):n,e)),g=p(((e,t)=>{t.exports=n;function n(e={}){let{ERR_PATHS_MUST_BE_STRINGS:t=()=>`fast-redact - Paths must be (non-empty) strings`,ERR_INVALID_PATH:n=e=>`fast-redact Invalid path (${e})`}=e;return function({paths:e}){e.forEach(e=>{if(typeof e!=`string`)throw Error(t());try{if(/〇/.test(e))throw Error();let t=(e[0]===`[`?``:`.`)+e.replace(/^\*/,`〇`).replace(/\.\*/g,`.〇`).replace(/\[\*\]/g,`[〇]`);if(/\n|\r|;/.test(t)||/\/\*/.test(t))throw Error();Function(`
2
+ 'use strict'
3
+ const o = new Proxy({}, { get: () => o, set: () => { throw Error() } });
4
+ const 〇 = null;
5
+ o${t}
6
+ if ([o${t}].length !== 1) throw Error()`)()}catch{throw Error(n(e))}})}}})),_=p(((e,t)=>{t.exports=/[^.[\]]+|\[((?:.)*?)\]/g})),v=p(((e,t)=>{let n=_();t.exports=r;function r({paths:e}){let t=[];var r=0;let i=e.reduce(function(e,i,a){var o=i.match(n).map(e=>e.replace(/'|"|`/g,``));let s=i[0]===`[`;o=o.map(e=>e[0]===`[`?e.substr(1,e.length-2):e);let c=o.indexOf(`*`);if(c>-1){let e=o.slice(0,c),n=e.join(`.`),i=o.slice(c+1,o.length),a=i.length>0;r++,t.push({before:e,beforeStr:n,after:i,nested:a})}else e[i]={path:o,val:void 0,precensored:!1,circle:``,escPath:JSON.stringify(i),leadingBracket:s};return e},{});return{wildcards:t,wcLen:r,secret:i}}})),y=p(((e,t)=>{let n=_();t.exports=r;function r({secret:e,serialize:t,wcLen:n,strict:r,isCensorFct:c,censorFctTakesPath:l},u){let d=Function(`o`,`
7
+ if (typeof o !== 'object' || o == null) {
8
+ ${s(r,t)}
9
+ }
10
+ const { censor, secret } = this
11
+ const originalSecret = {}
12
+ const secretKeys = Object.keys(secret)
13
+ for (var i = 0; i < secretKeys.length; i++) {
14
+ originalSecret[secretKeys[i]] = secret[secretKeys[i]]
15
+ }
16
+
17
+ ${i(e,c,l)}
18
+ this.compileRestore()
19
+ ${a(n>0,c,l)}
20
+ this.secret = originalSecret
21
+ ${o(t)}
22
+ `).bind(u);return d.state=u,t===!1&&(d.restore=e=>u.restore(e)),d}function i(e,t,r){return Object.keys(e).map(i=>{let{escPath:a,leadingBracket:o,path:s}=e[i],c=o?1:0,l=o?``:`.`,u=[];for(var d;(d=n.exec(i))!==null;){let[,e]=d,{index:t,input:n}=d;t>c&&u.push(n.substring(0,t-(e?0:1)))}var f=u.map(e=>`o${l}${e}`).join(` && `);f.length===0?f+=`o${l}${i} != null`:f+=` && o${l}${i} != null`;let p=`
23
+ switch (true) {
24
+ ${u.reverse().map(e=>`
25
+ case o${l}${e} === censor:
26
+ secret[${a}].circle = ${JSON.stringify(e)}
27
+ break
28
+ `).join(`
29
+ `)}
30
+ }
31
+ `,m=r?`val, ${JSON.stringify(s)}`:`val`;return`
32
+ if (${f}) {
33
+ const val = o${l}${i}
34
+ if (val === censor) {
35
+ secret[${a}].precensored = true
36
+ } else {
37
+ secret[${a}].val = val
38
+ o${l}${i} = ${t?`censor(${m})`:`censor`}
39
+ ${p}
40
+ }
41
+ }
42
+ `}).join(`
43
+ `)}function a(e,t,n){return e===!0?`
44
+ {
45
+ const { wildcards, wcLen, groupRedact, nestedRedact } = this
46
+ for (var i = 0; i < wcLen; i++) {
47
+ const { before, beforeStr, after, nested } = wildcards[i]
48
+ if (nested === true) {
49
+ secret[beforeStr] = secret[beforeStr] || []
50
+ nestedRedact(secret[beforeStr], o, before, after, censor, ${t}, ${n})
51
+ } else secret[beforeStr] = groupRedact(o, before, censor, ${t}, ${n})
52
+ }
53
+ }
54
+ `:``}function o(e){return e===!1?`return o`:`
55
+ var s = this.serialize(o)
56
+ this.restore(o)
57
+ return s
58
+ `}function s(e,t){return e===!0?`throw Error('fast-redact: primitives cannot be redacted')`:t===!1?`return o`:`return this.serialize(o)`}})),b=p(((e,t)=>{t.exports={groupRedact:r,groupRestore:n,nestedRedact:a,nestedRestore:i};function n({keys:e,values:t,target:n}){if(n==null||typeof n==`string`)return;let r=e.length;for(var i=0;i<r;i++){let r=e[i];n[r]=t[i]}}function r(e,t,n,r,i){let a=c(e,t);if(a==null||typeof a==`string`)return{keys:null,values:null,target:a,flat:!0};let o=Object.keys(a),s=o.length,l=t.length,u=i?[...t]:void 0,d=Array(s);for(var f=0;f<s;f++){let e=o[f];d[f]=a[e],i?(u[l]=e,a[e]=n(a[e],u)):r?a[e]=n(a[e]):a[e]=n}return{keys:o,values:d,target:a,flat:!0}}function i(e){for(let t=0;t<e.length;t++){let{target:n,path:r,value:i}=e[t],a=n;for(let e=r.length-1;e>0;e--)a=a[r[e]];a[r[0]]=i}}function a(e,t,n,r,i,a,o){let l=c(t,n);if(l==null)return;let u=Object.keys(l),d=u.length;for(var f=0;f<d;f++){let t=u[f];s(e,l,t,n,r,i,a,o)}return e}function o(e,t){return e==null?!1:`hasOwn`in Object?Object.hasOwn(e,t):Object.prototype.hasOwnProperty.call(e,t)}function s(e,t,n,r,i,a,s,c){let p=i.length,m=p-1,h=n;var g=-1,_,v,y,b=null,x,S,C=!1,w=0,T=0,E=u();if(y=_=t[n],typeof _==`object`){for(;_!=null&&++g<p&&(T+=1,n=i[g],!(n!==`*`&&!b&&!(typeof _==`object`&&n in _)));)if(!(n===`*`&&(b===`*`&&(C=!0),b=n,g!==m))){if(b){let u=Object.keys(_);for(var D=0;D<u.length;D++){let p=u[D];if(S=_[p],x=n===`*`,C)E=d(E,p,T),w=g,y=l(S,w-1,n,r,i,a,s,c,h,_,v,y,x,p,g,m,E,e,t[h],T+1);else if(x||typeof S==`object`&&S&&n in S){if(y=x?S:S[n],v=g===m?s?c?a(y,[...r,h,...i]):a(y):a:y,x){let n=f(d(E,p,T),y,t[h]);e.push(n),_[p]=v}else if(S[n]!==v)if(v===void 0&&a!==void 0||o(S,n)&&v===y)E=d(E,p,T);else{E=d(E,p,T);let r=f(d(E,n,T+1),y,t[h]);e.push(r),S[n]=v}}}b=null}else{if(y=_[n],E=d(E,n,T),v=g===m?s?c?a(y,[...r,h,...i]):a(y):a:y,!(o(_,n)&&v===y||v===void 0&&a!==void 0)){let r=f(E,y,t[h]);e.push(r),_[n]=v}_=_[n]}if(typeof _!=`object`)break}}}function c(e,t){for(var n=-1,r=t.length,i=e;i!=null&&++n<r;)i=i[t[n]];return i}function l(e,t,n,r,i,a,s,c,u,p,m,h,g,_,v,y,b,x,S,C){if(t===0&&(g||typeof e==`object`&&e&&n in e)){if(h=g?e:e[n],m=v===y?s?c?a(h,[...r,u,...i]):a(h):a:h,g){let e=f(b,h,S);x.push(e),p[_]=m}else if(e[n]!==m&&!(m===void 0&&a!==void 0||o(e,n)&&m===h)){let t=f(d(b,n,C+1),h,S);x.push(t),e[n]=m}}for(let o in e)typeof e[o]==`object`&&(b=d(b,o,C),l(e[o],t-1,n,r,i,a,s,c,u,p,m,h,g,_,v,y,b,x,S,C+1))}function u(){return{parent:null,key:null,children:[],depth:0}}function d(e,t,n){if(e.depth===n)return d(e.parent,t,n);var r={parent:e,key:t,depth:n,children:[]};return e.children.push(r),r}function f(e,t,n){let r=e,i=[];do i.push(r.key),r=r.parent;while(r.parent!=null);return{path:i,value:t,target:n}}})),x=p(((e,t)=>{let{groupRestore:n,nestedRestore:r}=b();t.exports=i;function i(){return function(){if(this.restore){this.restore.state.secret=this.secret;return}let{secret:e,wcLen:t}=this,i=Object.keys(e),s=a(e,i),c=t>0,l=c?{secret:e,groupRestore:n,nestedRestore:r}:{secret:e};this.restore=Function(`o`,o(s,i,c)).bind(l),this.restore.state=l}}function a(e,t){return t.map(t=>{let{circle:n,escPath:r,leadingBracket:i}=e[t];return`
59
+ if (secret[${r}].val !== undefined) {
60
+ try { ${n?`o.${n} = secret[${r}].val`:`o${i?``:`.`}${t} = secret[${r}].val`} } catch (e) {}
61
+ ${`secret[${r}].val = undefined`}
62
+ }
63
+ `}).join(``)}function o(e,t,n){return`
64
+ const secret = this.secret
65
+ ${n===!0?`
66
+ const keys = Object.keys(secret)
67
+ const len = keys.length
68
+ for (var i = len - 1; i >= ${t.length}; i--) {
69
+ const k = keys[i]
70
+ const o = secret[k]
71
+ if (o) {
72
+ if (o.flat === true) this.groupRestore(o)
73
+ else this.nestedRestore(o)
74
+ secret[k] = null
75
+ }
76
+ }
77
+ `:``}
78
+ ${e}
79
+ return o
80
+ `}})),S=p(((e,t)=>{t.exports=n;function n(e){let{secret:t,censor:n,compileRestore:r,serialize:i,groupRedact:a,nestedRedact:o,wildcards:s,wcLen:c}=e,l=[{secret:t,censor:n,compileRestore:r}];return i!==!1&&l.push({serialize:i}),c>0&&l.push({groupRedact:a,nestedRedact:o,wildcards:s,wcLen:c}),Object.assign(...l)}})),C=h(p(((e,t)=>{let n=g(),r=v(),i=y(),a=x(),{groupRedact:o,nestedRedact:s}=b(),c=S(),l=_(),u=n(),d=e=>e;d.restore=d,f.rx=l,f.validator=n,t.exports=f;function f(e={}){let t=Array.from(new Set(e.paths||[])),n=`serialize`in e&&(e.serialize===!1||typeof e.serialize==`function`)?e.serialize:JSON.stringify,l=e.remove;if(l===!0&&n!==JSON.stringify)throw Error(`fast-redact – remove option may only be set when serializer is JSON.stringify`);let f=l===!0?void 0:`censor`in e?e.censor:`[REDACTED]`,p=typeof f==`function`,m=p&&f.length>1;if(t.length===0)return n||d;u({paths:t,serialize:n,censor:f});let{wildcards:h,wcLen:g,secret:_}=r({paths:t,censor:f}),v=a();return i({secret:_,wcLen:g,serialize:n,strict:`strict`in e?e.strict:!0,isCensorFct:p,censorFctTakesPath:m},c({secret:_,censor:f,compileRestore:v,serialize:n,groupRedact:o,nestedRedact:s,wildcards:h,wcLen:g}))}}))(),1);const w=[`client_secret`,`access_token`,`refresh_token`,`api_key`,`password`,`job_board_token`,`private_key`,`certificate`,`service_user_token`,`key_id`,`secret_key`,`provhash`,`admin_key`,`session_key`,`id_token`,`authorization`,`bh_rest_token`,`external_trigger_token`,`tempauth`],T=[`req.headers.authorization`,`req.headers.cookie`,`req.headers.cookies`,`req.headers["set-cookie"]`,`req.headers["set-cookies"]`,`req.headers.httpsAgent.options.cert`,`req.headers.httpsAgent.options.key`,`req.headers["x-stackone-external-trigger-token"]`,`error.config.headers.authorization`,`error.config.data`,`error.config.headers.cookie`,`error.config.headers.cookies`,`error.config.headers["set-cookie"]`,`error.config.headers["set-cookies"]`,`error.config.httpsAgent.options.cert`,`error.config.httpsAgent.options.key`,`err.config.headers.authorization`,`err.config.data`,`err.config.headers.cookie`,`err.config.headers.cookies`,`err.config.headers["set-cookie"]`,`err.config.headers["set-cookies"]`,`err.config.httpsAgent.options.cert`,`err.config.httpsAgent.options.key`,`res.headers.authorization`,`res.headers.cookie`,`res.headers.cookies`,`res.headers["set-cookie"]`,`res.headers["set-cookies"]`,`res.headers.httpsAgent.options.cert`,`res.headers.httpsAgent.options.key`,`context.credentials`,...w],E=`**redacted**`;let D=function(e){return e.FULL=`FULL`,e.PARTIAL=`PARTIAL`,e}({});const O=e=>E,k=e=>typeof e==`string`?e.startsWith(E)?e:e.length<=10?E:`${E}${e.slice(-5)}`:E,A=e=>`${e.charAt(0).toUpperCase()}${e.slice(1)}`,j=e=>{let t=e.split(`.`);if(t.length<2)return A(e);let n=A(t.pop()??``);return[...t,n].join(`.`)},M=e=>{let t=e.lastIndexOf(`[`),n=e.indexOf(`]`,t);if(t===-1||n===-1)return;let r=e.slice(t,n+1).replace(/(["'])([^"']*)(["'])/g,(e,t,n)=>n?t+A(n)+t:t+t);return`${e.slice(0,t)}${r}${e.slice(n+1)}`},N=e=>M(e)||j(e),P=(e=[],t=!0)=>{if(!t)return[];let n=e.map(e=>N(e));return[...e,...n]},F=(e=[],t=!0)=>{if(!t)return[];let n=new Set;return e.forEach(e=>{if(n.add(e),e.includes(`_`)){let t=e.replace(/_([a-z])/g,(e,t)=>t.toUpperCase());n.add(t)}else{let t=e.replace(/([A-Z])/g,`_$1`).toLowerCase();n.add(t)}}),Array.from(n)},I={[D.FULL]:O,[D.PARTIAL]:k};F(w);const L=P(T);let R;const z=()=>(t(R)&&(R={[D.FULL]:(0,C.default)({paths:L,serialize:!1,censor:I[D.FULL]}),[D.PARTIAL]:(0,C.default)({paths:L,serialize:!1,censor:I[D.PARTIAL]})}),R),B=(n,r=D.FULL)=>t(n)||typeof n!=`object`||!n?n:z()[r](e(n)),V=[`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`];var H=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 send(e,t,n){if(!n?.enabled){this.#t?.debug({message:`Advanced sink is disabled, skipping sending to advanced sink`,category:`AdvancedSink`});return}if(!this.#e){this.#t?.warning({message:`No s3 client available, cannot send to advanced sink`,category:`AdvancedSink`});return}if(`mode`in e&&this.isDataSyncRequest(e)){this.#t?.debug({message:`Data sync request detected, skipping advanced log storage for actionRunId ${t.actionRunId}`,category:`AdvancedSink`});return}try{let i=await this.createS3Item(e,t,n.ttl);await this.#e.send(new r({Bucket:i.Bucket,Key:i.Key,Body:i.Body,ContentType:i.ContentType,Expires:i.Expires,Tagging:i.Tagging}))}catch(e){throw this.#t?.error({message:`Failed to write advanced logs to S3 account ${t.accountSecureId}`,error:e,code:`AdvancedLogWriteError`,category:`AdvancedSink`,context:{actionRunId:t.actionRunId}}),e}}async createS3Item(e,t,n){let{projectSecureId:r,organizationId:i}=t,a=`ttl=30d`;typeof n==`number`&&(n===1?a=`ttl=1d`:n===7&&(a=`ttl=7d`));let o=Math.floor(Date.now()/1e3)+(n??30)*24*60*60,s=process.env.ADVANCED_LOGS_BUCKET;if(!s)throw Error(`ADVANCED_LOGS_BUCKET environment variable is not set`);return{Bucket:s,Key:this.generateS3Key(t,i,r),Body:this.serialize(e,t,o,10485760),ContentType:`application/json`,Expires:new Date(o*1e3),Tagging:a}}generateS3Key(e,t,n){return`actionId`in e?`${t}/${n}/${e.actionRunId}/${e.actionRunId}.json`:`${t}/${n}/${e.actionRunId}/steps/${e.stepId}.json`}serialize(e,t,n,r){return`actionId`in t?JSON.stringify(this.serializeActionResult(e,t,n,r)):JSON.stringify(this.serializeStepResult(e,t))}serializeActionResult(e,t,n,r){let i=B({req:{...e.headers&&{headers:{...e.headers}}},res:{...t.headers&&{headers:{...t.headers}}}},D.PARTIAL),a=i.req?.headers,o=i.res?.headers,s=B(e.body,D.PARTIAL),c=B(t.body,D.PARTIAL),l=this.isBackgroundLog(e);return{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:s},response:{statusCode:t.statusCode??500,headers:this.filterHeaders(o),body:c},...l?{isBackgroundLog:!0}:{}},metadata:{...l?{isBackgroundLog:!0}:{},expirationTime:n},expirationTime:n}}serializeStepResult(e,t){return{}}filterHeaders(e){if(!e)return;let t={},n=V.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)&&[`refresh_authentication`].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 U=(e,t)=>{try{return new i(e)??void 0}catch(e){let n=e;t?.error({message:`Error building s3 client: ${n.message}`,error:n,code:`BuildS3ClientError`,category:`buildS3Client`});return}},W=(e,t)=>{try{return new a(e)??void 0}catch(e){let n=e;t?.error({message:`Error building kafka client: ${n.message}`,error:n,code:`BuildKafkaClientError`,category:`buildKafkaClient`});return}},G=e=>{try{return JSON.stringify(e)}catch{return`[Unserializable payload]`}};var K=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:o.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 send(e,t,n,r){if(!r?.enabled){this.#n?.debug({message:`Logs sink is disabled, skipping sending to log sink`,category:`KafkaSink`});return}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 i=G(this.buildLog(t,n));this.#n?.debug({message:`Sending to topic ${e}: ${i}`,category:`KafkaSink`});try{let t=await this.#t.send({topic:e,messages:[{value:i}]});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}}buildLog(e,t){if(this.isActionResult(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,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0));if(this.isStepResult(t))return Object.fromEntries(Object.entries({actionRunId:t.actionRunId,stepId:t.stepId,skipped:t.skipped,status:t.status,message:t.message,startTime:t.startTime,endTime:t.endTime,durationMs:this.calculateDuration(t.startTime,t.endTime),eventTime:new Date}).filter(([,e])=>e!==void 0));throw this.#n?.error({message:`Unknown result type, cannot build log`,category:`KafkaSink`,code:`UnknownResultType`}),Error(`Unknown result type`)}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}isActionResult(e){return typeof e==`object`&&!!e&&`actionRunId`in e&&`actionId`in e}isStepResult(e){return typeof e==`object`&&!!e&&`actionRunId`in e&&`stepId`in e}};const q={logs:{enabled:!0},advanced:{enabled:!1,ttl:7,errorsOnly:!1}};function J(e){return{...q,...e}}var Y=class{#e;#t;#n;#r;#i;constructor({getKafkaClient:e=W,getS3Client:t=U,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 K(this.#e,this.#n),this.#i=new H(this.#t,this.#n)}async initialize(){await this.#r?.initialize(),await this.#i?.initialize()}async recordAction(e,t,n){let{logs:r,advanced:i}=J(n);if(r?.enabled)try{await this.#r?.send(`actions`,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?.send(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}async recordStep(e,t,n){let{logs:r,advanced:i}=J(n);if(r?.enabled)try{await this.#r?.send(`steps`,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?.send(e,t,i)}catch(e){this.#n?.warning({message:`[OlapClient] Error sending to s3: ${e.message}`,category:`OlapClient`,error:e})}}};const X=async({getKafkaClient:e=W,getS3Client:t=U,kafkaClientConfig:n,s3ClientConfig:r,logger:i}={})=>{let a=new Y({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i});return await a.initialize(),a};var Z=class{static{this.olapClientPromise=null}static getInstance({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i,getOlapClient:a=X}={}){return this.olapClientPromise||=a({getKafkaClient:e,getS3Client:t,kafkaClientConfig:n,s3ClientConfig:r,logger:i}),this.olapClientPromise}static resetInstance(){this.olapClientPromise=null}};export{Y as OlapClient,Z as OlapClientManager};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/olap",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -42,6 +42,7 @@
42
42
  "license": "ISC",
43
43
  "dependencies": {
44
44
  "@aws-sdk/client-s3": "3.913.0",
45
+ "@stackone/utils": "*",
45
46
  "kafkajs": "2.2.4",
46
47
  "date-fns": "2.30.0"
47
48
  },