@autofleet/sheilta 2.3.0 → 2.4.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.
@@ -0,0 +1 @@
1
+ var e=Object.defineProperty,t=t=>{let n={};for(var r in t)e(n,r,{get:t[r],enumerable:!0});return n};export{t as __export};
package/lib/index.cjs CHANGED
@@ -1,2 +1,116 @@
1
- 'use strict';var Jt=require('@autofleet/logger'),errors=require('@autofleet/errors'),m=require('joi'),commonTypes=require('@autofleet/common-types'),sequelize=require('sequelize');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var Jt__default=/*#__PURE__*/_interopDefault(Jt);var m__default=/*#__PURE__*/_interopDefault(m);var j=["eq","ne","gte","gt","lte","lt","not","in","notIn","is","like","iLike","notLike","between","and","or","overlap","contains"],R="$",et={$eq:"=",$ne:"!=",$gte:">=",$gt:">",$lte:"<=",$lt:"<",$not:"NOT",$in:"IN",$notIn:"NOT IN",$is:"IS",$like:"LIKE",$iLike:"ILIKE",$notLike:"NOT LIKE",$and:"AND",$or:"OR"},bt=t=>{let{Op:e}=t;return j.reduce((o,r)=>(o[`${R+r}`]=e[r],o),{})};var Ot=t=>Math.floor(Math.random()*Math.floor(t)),y="-",f=".",C="$",q=20,I=1,V=100,v=1,rt=1,ot=t=>`${R}${t}${R}`,S=(t,e)=>t.includes(f)&&e.includes(t.split(f)[0]),k=(t,e)=>{let o=t;return t.includes(y)&&(o=o.split(y)[1]),S(o,e)&&([o]=o.split(f)),o},M=t=>t.includes(y),g=t=>{throw new errors.BadRequest([new Error(t)])},nt=t=>t.split(f)[1],O=(t=5)=>{let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";return Array.from({length:t},()=>e.charAt(Ot(e.length))).join("")},D=(t,e)=>Object.fromEntries(e.map(o=>[o,t[o]]));var J={length:"length"};function it(t){return t.replace(/(?!^)[A-Z]/g,e=>`_${e.toLowerCase()}`)}function ht(t){switch(t.action){case J.length:{let e=`jsonb_array_length(${it(t.columnName)})`;return [sequelize.literal(e),t.alias]}default:return t.action,[]}}function Pt(t){return t.map(e=>ht(e))}function Et(t){return t.map(e=>{let o=it(e.columnName),r=`json_build_object(${e.keys.map(n=>`'${n}', ${o} -> '${n}'`).join(", ")})`,s=e.alias||e.columnName;return [sequelize.literal(r),s]})}function G({select:t=[],computed:e=[]}={}){let o=Et(t),r=Pt(e);return [...o,...r]}var St="id",at="DESC",xt="ASC",b="customFields.",{CUSTOM_FIELDS_FILTER_SCOPE:W,CUSTOM_FIELDS_SORT_SCOPE:K}=commonTypes.customFields,_t=t=>["string","number"].includes(typeof t)||Array.isArray(t)?t:Object.entries(t).map(([e,o])=>({operator:et[e],value:o})),Ft=(t,e={})=>{let{literalAttributes:o=[],DBFormatter:r=void 0}=e,[s,n]=t.reduce((i,d)=>{let[a,c="ASC"]=Array.isArray(d)?d:[d],l=o?.find(u=>u.attribute===a);return l?(i[1].push(l.literal),i[0].push([r?r(`"${l.attribute}" ${c}`):`${l.attribute} ${c}`])):i[0].push(d),i},[[],[]]);return [s,n]},ct=t=>{let e={};return Object.entries(t).forEach(([o,r])=>{let s=O();if(e[s]=o.split(b)[1],Array.isArray(r))r.forEach(n=>{let i=O();e[i]=typeof n=="string"?n:n.value;});else if(typeof r=="string"||typeof r=="number"){let n=O();e[n]=r;}else if(r?.operator){let n=O();e[n]=r.value;}}),e},Tt=t=>{let e={};return t.forEach(o=>{if(o.startsWith(b)){let r=O();e[r]=o.split(b)[1];}else if(o.substring(1).startsWith(b)){let r=O();e[r]=o.substring(1).split(b)[1];}}),e},wt=(t,e)=>({...Tt(t),...ct(e)}),qt=({order:t,associationModels:e=[],replacementsMap:o={}})=>{let r=[],s=new Map;return t.forEach(n=>{if([n,n.substring(1)].some(c=>c.startsWith(b))){s.has(K)||s.set(K,{});let c=n.split(b)[1];s.get(K)[c]=M(n)?at:xt;return}let i=[k(n,e)],d=M(n);S(d?n.split(y)[1]:n,e)&&i.push(nt(n)),d&&i.push(at),r.push(i);}),{formattedOrders:r,replacementsMap:o,orderScopes:Array.from(s.entries()).map(([n,i])=>i?{method:[n,{replacementsMap:o,scopeValue:i}]}:n)}},It=t=>t||I,Mt=t=>t||q,lt=(t,e={})=>{let o=t.map(r=>{let s=e[typeof r=="string"?r:r.association||r.model];return {...typeof r!="string"&&r,association:s,required:typeof r=="string"||r.required!==false,...typeof r!="string"&&r.include&&{include:lt(r.include,s?.target?.associations)}}});return o=o.map(({model:r,...s})=>s),o},$t=(t,e,o,r=[])=>{console.log("formatQuery - input query:",JSON.stringify(t,null,2)),console.log("formatQuery - associationModels:",e);let s={},n={},i=new Map;Object.entries(t).forEach(([a,c])=>{if(console.log("formatQuery - processing field:",{queryItemKey:a,queryItemValue:c}),a.startsWith(b)){i.has(W)||i.set(W,{});let u=a.split(b)[1];i.get(W)[u]=_t(c);return}if(r.includes(a)){n[a]=c;return}let l=S(a,e)?ot(a):a;console.log("formatQuery - final key assignment:",{original:a,final:l}),s[l]=c;});let d=Array.from(i.entries()).map(([a,c])=>c?{method:[a,{replacementsMap:o,scopeValue:c}]}:a);return console.log("formatQuery - final result:",{formattedQuery:s,externalQueryValues:n,formattedScopes:d}),{formattedQuery:s,externalQueryValues:n,formattedScopes:d}},Lt=(t,e,o)=>{console.log("formatSearchTerm - inputs:",{searchTerm:t,attributesToSend:e,rawAttributesKeys:Object.keys(o)});let r=e.filter(n=>o[n].type.key==="STRING");console.log("formatSearchTerm - stringAttributes:",r);let s={$and:t.split(" ").map(n=>({$or:r.map(i=>({[i]:{$iLike:`%${n}%`}}))}))};return console.log("formatSearchTerm - generated query:",JSON.stringify(s,null,2)),s},kt=({order:t=[],page:e=I,perPage:o=q,include:r=[],query:s={},attributes:n=null,searchTerm:i=null,jsonAttributes:d={}},a,c)=>{let l=wt(t,s),u=Object.keys(a?.associations||{}),{formattedOrders:p,orderScopes:_}=qt({order:[...t,St],associationModels:u,replacementsMap:l}),[P,F]=Ft(p,c),$=G(d),T=[...F,...n||[],...$],E=n?.length?T:{include:T},L=lt(r,a?.associations),w=It(e),N=Mt(o),Y=$t(s,u,l,c?.additionalAllowedAttributes),{formattedScopes:yt,externalQueryValues:Z}=Y,{formattedQuery:A}=Y;if(i&&!c?.skipSearchTermFormat){console.log("Processing searchTerm in formatPayload:",{searchTerm:i,skipSearchTermFormat:c?.skipSearchTermFormat});let ft=n?.length?n:Object.keys(a.rawAttributes);console.log("formatPayload - formattedQuery before searchTerm processing:",JSON.stringify(A,null,2));let tt=Lt(i,ft,a.rawAttributes);A=!A||Object.keys(A).length===0?tt:{$and:[A,tt]},console.log("formatPayload - formattedQuery after searchTerm processing:",JSON.stringify(A,null,2));}return {query:A,order:P,page:w,perPage:N,include:L,scopes:[...yt,..._],...E&&{attributes:E},...Object.keys(Z).length>0&&{externalQueryValues:Z}}},dt=kt;var Qt=t=>j.includes(t.split(R)[1]),ut=(t,e=[],o=[],r=[])=>{let s=t.startsWith(C)&&t.endsWith(C)?t.slice(1,-1):t;return [...e,...o].includes(s.includes(f)?s.split(f)[0]:s)||r.includes(s)},Nt=(t,e,o,r={})=>{let s=M(t);s&&t[0]!==y&&g(`${y} must be only at the beginning of the word`);let n=s?t.split(y)[1]:t,i=S(n,o),d=k(t,o),a=r?.literalAttributes?.map(c=>c.attribute)?.includes(n);!i&&d.includes(f)&&([d]=d.split(f)),e.includes(d)||i||a||g(`${t} is invalid. isLiteralAttribute: ${a}`);},jt=(t,e)=>{e.includes(t)||g(`${t} is invalid`);},mt=(t,e,o=[],r={})=>{t.forEach(s=>Nt(s,e,o,r));},H=(t,e)=>{t.forEach(o=>jt(o,e));},Ct=(t,e)=>{let o=[...t.select?.map(r=>r.columnName)||[],...t.computed?.map(r=>r.columnName)||[]];H(o,e);},Vt=(t,e)=>{let o=Array.isArray(t)?t:Object.keys(t);if(!o?.length)return;let r=o.find(s=>!e?.enrichmentAttributes?.includes(s));r&&g(`enrichment attribute ${r} is invalid`);},Q=(t,e,o=[],r=[])=>{Object.entries(t).forEach(([s,n])=>{Array.isArray(n)?n[0]&&typeof n[0]=="object"&&n.map(i=>Q(i,e,o,r)):Qt(s)||ut(s,e,o,r)?n&&typeof n=="object"&&Q(n,e,[],r):g(`invalid key: ${s}`);});},vt=({page:t,perPage:e})=>{t<rt&&g("Page must be greater than 0"),(e>V||e<v)&&g(`PerPage must be between ${v} to ${V}`);},Dt=(t,e)=>{let o=Object.keys(e);t.forEach(r=>{ut(r.model,o);let s=e[r.model]?.target;s||g("model not found in associations");let{rawAttributes:n}=s,i=Object.keys(n);r.where&&Q(r.where,i),r.order&&mt(r.order,i),r.attributes&&H(r.attributes,i),[null,void 0,true,false].includes(r.required)||g("include.required must be a boolean");});},U=({query:t={},order:e=[],attributes:o=[],include:r=[],page:s=I,perPage:n=q,enrichments:i=[],group:d=[],jsonAttributes:a={}},c,l={})=>{let u=Object.keys(c.rawAttributes),p=Object.keys(c?.associations||{});return !o||o.length===0?o=u:H(o,u),mt(e,u,p,l),Q(t,u,p,l.additionalAllowedAttributes),Vt(i,l),Ct(a,u),Array.isArray(d)||g("group must be an array"),r.length&&typeof r=="object"?Dt(r,c?.associations):r&&typeof r!="object"&&g("include must be an array"),vt({page:s,perPage:n}),true};var {object:B,string:h,number:pt,any:Kt,array:x,alternatives:Ht}=m__default.default.types(),Ut=Jt__default.default(),Bt=B.keys({query:B,attributes:x.items(h),order:x.items(h),page:pt,perPage:pt,include:x.items(Kt),searchTerm:h,group:x.items(h),enrichments:Ht.try(x.items(h),B.pattern(h,{exclude:x.items(h)})),jsonAttributes:m__default.default.object({select:m__default.default.array().items(m__default.default.object({columnName:m__default.default.string().required(),keys:m__default.default.array().items(m__default.default.string().required()).required(),alias:m__default.default.string().optional()})).default([]),computed:m__default.default.array().items(m__default.default.object({columnName:m__default.default.string().required(),action:m__default.default.string().valid(...Object.values(J)).required(),alias:m__default.default.string().required()})).default([])}).default({})}),X=(t,e,o={})=>{let{query:r,attributes:s,order:n,page:i,perPage:d,include:a,group:c,enrichments:l,jsonAttributes:u}=e,p=Bt.validate(e);if(p.error)throw new errors.BadRequest([p.error],null);U({query:r,attributes:s,order:n,page:i,perPage:d,include:a,enrichments:l,group:c,jsonAttributes:u},t,o);},Xt=(t,e={},o="body")=>async(r,s,n)=>{try{X(t,r[o],e),n();}catch(i){let{query:d,attributes:a,order:c}=r[o];errors.handleError(i,s,{logger:e.logger||Ut,message:"error in query middleware",payload:{error:i,query:d,attributes:a,order:c}});}},z=(t,e,o={})=>{let{order:r,page:s,perPage:n,include:i,query:d,attributes:a,searchTerm:c,jsonAttributes:l}=e,{query:u,externalQueryValues:p,order:_,page:P,perPage:F,include:$,scopes:T,attributes:E}=dt({query:d,order:r,page:s,perPage:n,include:i,attributes:a,searchTerm:c,jsonAttributes:l},t,o);e.query=u,e.externalQueryValues=p,e.order=_,e.attributes=E,e.page=P,e.perPage=F,e.include=$,e.scopes=T,o.includeRawPayload&&(e.rawPayload={order:r,page:s,perPage:n,include:i,query:d,attributes:a,searchTerm:c});},zt=(t,e={},o="body")=>async(r,s,n)=>{z(t,r[o],e),n();};var Zt=({model:t,logger:e,validationOptions:o,formatOptions:r,modelName:s=t.constructor?.name,additionalScopes:n=[],modifyQueryValues:i,onRowsRetrieved:d})=>async(a,c)=>{try{X(t,a.body,{...o,logger:e});}catch(l){let u=D(a.body,["query","order","attributes"]);errors.handleError(l,c,{logger:e,message:"error in query endpoint",payload:u});return}try{e.info("BEFORE queryFormat - req.body:",{body:a.body}),z(t,a.body,r),e.info("AFTER queryFormat - req.body:",{body:a.body});let l=Object.assign(D(a.body,["query","externalQueryValues","order","attributes","page","perPage","include","scopes","enrichments"]),{distinct:!0});e.info("queryValues after pick:",{queryValues:l});let u=i?.(l)??l;e.info("modifiedQuery:",{modifiedQuery:u});let{scopes:p=[],query:_,perPage:P,page:F,enrichments:$,externalQueryValues:T,...E}=u,L={where:_,limit:P,offset:(F-1)*P,...E};e.info("Sequelize query object:",{sequelizeQuery:L,scopes:[...n,...p]});let w=await t.scope([...n,...p]).findAndCountAll(L);if(!w.rows.length||!d){c.json(w);return}let N=await d(w,u);c.json(N);}catch(l){e.error("Raw error caught in queryHandler:",{error:l,errorMessage:l.message,errorStack:l.stack,errorName:l.name,originalRequestBody:a.body}),errors.handleError(new errors.UnexpectedError(l),c,{logger:e,message:`Error while querying ${s}`,payload:{query:a.body}});}};exports.formatOperators=bt;exports.generateFilterReplacements=ct;exports.queryFormatMiddleware=zt;exports.queryHandler=Zt;exports.queryValidationMiddleware=Xt;exports.validatePayload=U;//# sourceMappingURL=index.cjs.map
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=e=>{let n={};for(var r in e)t(n,r,{get:e[r],enumerable:!0});return n},s=(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},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let l=require(`sequelize`);l=c(l);let u=require(`@autofleet/logger`);u=c(u);let d=require(`@autofleet/errors`);d=c(d);let f=require(`joi`);f=c(f);let p=require(`@autofleet/common-types`);p=c(p);let m=require(`node:crypto`);m=c(m);let h=require(`redis`);h=c(h);let g=require(`express`);g=c(g);let _=require(`zod/v3`);_=c(_);let v=require(`node:events`);v=c(v);const y=[`eq`,`ne`,`gte`,`gt`,`lte`,`lt`,`not`,`in`,`notIn`,`is`,`like`,`iLike`,`notLike`,`between`,`and`,`or`,`overlap`,`contains`],ee=`$`,b={$eq:`=`,$ne:`!=`,$gte:`>=`,$gt:`>`,$lte:`<=`,$lt:`<`,$not:`NOT`,$in:`IN`,$notIn:`NOT IN`,$is:`IS`,$like:`LIKE`,$iLike:`ILIKE`,$notLike:`NOT LIKE`,$and:`AND`,$or:`OR`},x=(e={Op:l.Op})=>{let{Op:t}=e;return Object.fromEntries(y.map(e=>[`${`$`+e}`,t[e]]))},te=`-`,S=`.`,C=`$`,ne=20,re=1,ie=100,ae=1,oe=1,se=e=>`\$${e}\$`,w=(e,t)=>e.includes(`.`)&&t.includes(e.split(`.`,1)[0]),T=(e,t)=>{let n=e;return e.includes(`-`)&&([,n]=n.split(`-`,2)),w(n,t)&&([n]=n.split(`.`,1)),n},E=e=>e.includes(`-`),D=e=>{throw new d.BadRequest([Error(e)])},ce=e=>e.split(`.`,2)[1],O=(e=5)=>Array.from({length:e},()=>`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.charAt((0,m.randomInt)(52))).join(``),k=(e,t)=>Object.fromEntries(t.map(t=>[t,e[t]])),A={length:`length`};function j(e){return e.replace(/(?!^)[A-Z]/g,e=>`_${e.toLowerCase()}`)}function le(e){switch(e.action){case A.length:return[(0,l.literal)(`jsonb_array_length(${j(e.columnName)})`),e.alias];default:return e.action,[]}}function ue(e){return e.map(e=>le(e))}function de(e){return e.map(e=>{let t=j(e.columnName),n=`json_build_object(${e.keys.map(e=>`'${e}', ${t} -> '${e}'`).join(`, `)})`,r=e.alias||e.columnName;return[(0,l.literal)(n),r]})}function fe({select:e=[],computed:t=[]}={}){let n=de(e),r=ue(t);return[...n,...r]}const pe=`id`,M=`DESC`,me=`ASC`,N=`customFields.`,{CUSTOM_FIELDS_FILTER_SCOPE:P,CUSTOM_FIELDS_SORT_SCOPE:F}=p.customFields,he=e=>[`string`,`number`].includes(typeof e)||Array.isArray(e)?e:Object.entries(e).map(([e,t])=>({operator:b[e],value:t})),ge=(e,t={})=>{let{literalAttributes:n=[],DBFormatter:r=void 0}=t,[i,a]=e.reduce((e,t)=>{let[i,a=`ASC`]=Array.isArray(t)?t:[t],o=n?.find(e=>e.attribute===i);if(o){let t=r?r(`"${o.attribute}" ${a}`):`${o.attribute} ${a}`;e[1].push(o.literal),e[0].push([t])}else e[0].push(t);return e},[[],[]]);return[i,a]},I=e=>{let t={};return Object.entries(e).forEach(([e,n])=>{let r=O();if(t[r]=e.split(N,2)[1],Array.isArray(n))n.forEach(e=>{let n=O();t[n]=typeof e==`string`?e:e.value});else if(typeof n==`string`||typeof n==`number`){let e=O();t[e]=n}else if(n?.operator){let e=O();t[e]=n.value}}),t},_e=e=>{let t={};return e.forEach(e=>{if(e.startsWith(N)){let n=O();t[n]=e.split(N,2)[1]}else if(e.substring(1).startsWith(N)){let n=O();t[n]=e.substring(1).split(N,2)[1]}}),t},ve=(e,t)=>({..._e(e),...I(t)}),ye=({order:e,associationModels:t=[],replacementsMap:n={}})=>{let r=[],i=new Map;return e.forEach(e=>{if([e,e.substring(1)].some(e=>e.startsWith(N))){i.has(F)||i.set(F,{});let t=e.split(N,2)[1];i.get(F)[t]=E(e)?M:`ASC`;return}let n=[T(e,t)],a=E(e);w(a?e.split(`-`,2)[1]:e,t)&&n.push(ce(e)),a&&n.push(M),r.push(n)}),{formattedOrders:r,replacementsMap:n,orderScopes:Array.from(i.entries()).map(([e,t])=>t?{method:[e,{replacementsMap:n,scopeValue:t}]}:e)}},be=e=>e||1,xe=e=>e||20,L=(e,t={})=>{let n=e.map(e=>{let n=t[typeof e==`string`?e:e.association||e.model];return{...typeof e!=`string`&&e,association:n,required:typeof e==`string`||e.required!==!1,...typeof e!=`string`&&e.include&&{include:L(e.include,n?.target?.associations)}}});return n=n.map(({model:e,...t})=>t),n},Se=(e,t,n,r=[])=>{let i={},a={},o=new Map;return Object.entries(e).forEach(([e,n])=>{if(e.startsWith(N)){o.has(P)||o.set(P,{});let t=e.split(N,2)[1];o.get(P)[t]=he(n);return}if(r.includes(e)){a[e]=n;return}let s=w(e,t)?se(e):e;i[s]=n}),{formattedQuery:i,externalQueryValues:a,formattedScopes:Array.from(o.entries()).map(([e,t])=>t?{method:[e,{replacementsMap:n,scopeValue:t}]}:e)}},Ce=(e,t,n)=>({$and:e.split(` `).map(e=>({$or:t.filter(e=>n[e].type.key===`STRING`).map(t=>({[t]:{$iLike:`%${e}%`}}))}))}),we=({order:e=[],page:t=1,perPage:n=20,include:r=[],query:i={},attributes:a=null,searchTerm:o=null,jsonAttributes:s={}},c,l)=>{let u=ve(e,i),d=Object.keys(c?.associations||{}),{formattedOrders:f,orderScopes:p}=ye({order:[...e,`id`],associationModels:d,replacementsMap:u}),[m,h]=ge(f,l),g=fe(s),_=[...h,...a??[],...g],v=a?.length?_:{include:_},y=L(r,c?.associations),ee=be(t),b=xe(n),x=Se(i,d,u,l?.additionalAllowedAttributes),{formattedScopes:te,externalQueryValues:S}=x,{formattedQuery:C}=x;if(o&&!l?.skipSearchTermFormat){let e=Ce(o,a?.length?a:Object.keys(c.rawAttributes||{}),c.rawAttributes);C=!C||Object.keys(C).length===0?e:{$and:[C,e]}}return{query:C,order:m,page:ee,perPage:b,include:y,scopes:[...te,...p],...v&&{attributes:v},...Object.keys(S).length>0&&{externalQueryValues:S}}};var Te=we;const Ee=e=>y.includes(e.split(`$`,2)[1]),R=(e,t=[],n=[],r=[])=>{let i=e.startsWith(`$`)&&e.endsWith(`$`)?e.slice(1,-1):e;return[...t,...n].includes(i.includes(`.`)?i.split(`.`,1)[0]:i)||r.includes(i)},De=(e,t,n,r={})=>{let i=E(e);i&&!e.startsWith(`-`)&&D(`- must be only at the beginning of the word`);let a=i?e.split(`-`,2)[1]:e,o=w(a,n),s=T(e,n),c=r?.literalAttributes?.map(e=>e.attribute)?.includes(a);!o&&s.includes(`.`)&&([s]=s.split(`.`,1)),t.includes(s)||o||c||D(`${e} is invalid. isLiteralAttribute: ${c}`)},Oe=(e,t)=>{t.includes(e)||D(`${e} is invalid`)},z=(e,t,n=[],r={})=>{e.forEach(e=>De(e,t,n,r))},B=(e,t)=>{e.forEach(e=>Oe(e,t))},ke=(e,t)=>{B([...e.select?.map(e=>e.columnName)??[],...e.computed?.map(e=>e.columnName)??[]],t)},Ae=(e,t)=>{let n=Array.isArray(e)?e:Object.keys(e);if(!n?.length)return;let r=n.find(e=>!t?.enrichmentAttributes?.includes(e));r&&D(`enrichment attribute ${r} is invalid`)},V=(e,t,n=[],r=[])=>{Object.entries(e).forEach(([e,i])=>{Array.isArray(i)?i[0]&&typeof i[0]==`object`&&i.map(e=>V(e,t,n,r)):Ee(e)||R(e,t,n,r)?i&&typeof i==`object`&&V(i,t,[],r):D(`invalid key: ${e}`)})},je=({page:e,perPage:t})=>{e<1&&D(`Page must be greater than 0`),(t>100||t<1)&&D(`PerPage must be between 1 to 100`)},Me=(e,t)=>{let n=Object.keys(t);e.forEach(e=>{R(e.model,n);let r=t[e.model]?.target;r||D(`model not found in associations`);let{rawAttributes:i}=r,a=Object.keys(i);e.where&&V(e.where,a),e.order&&z(e.order,a),e.attributes&&B(e.attributes,a),[null,void 0,!0,!1].includes(e.required)||D(`include.required must be a boolean`)})},H=({query:e={},order:t=[],attributes:n=[],include:r=[],page:i=1,perPage:a=20,enrichments:o=[],group:s=[],jsonAttributes:c={}},l,u={})=>{let d=Object.keys(l.rawAttributes),f=Object.keys(l?.associations||{});return!n||n.length===0?n=d:B(n,d),z(t,d,f,u),V(e,d,f,u.additionalAllowedAttributes),Ae(o,u),ke(c,d),Array.isArray(s)||D(`group must be an array`),r.length&&typeof r==`object`?Me(r,l?.associations):r&&typeof r!=`object`&&D(`include must be an array`),je({page:i,perPage:a}),!0},{object:U,string:W,number:G,any:Ne,array:K,alternatives:Pe}=f.default.types(),Fe=(0,u.default)(),Ie=U.keys({query:U,attributes:K.items(W),order:K.items(W),page:G,perPage:G,include:K.items(Ne),searchTerm:W,group:K.items(W),enrichments:Pe.try(K.items(W),U.pattern(W,{exclude:K.items(W)})),jsonAttributes:f.default.object({select:f.default.array().items(f.default.object({columnName:f.default.string().required(),keys:f.default.array().items(f.default.string().required()).required(),alias:f.default.string().optional()})).default([]),computed:f.default.array().items(f.default.object({columnName:f.default.string().required(),action:f.default.string().valid(...Object.values(A)).required(),alias:f.default.string().required()})).default([])}).default({})}),q=(e,t,n={})=>{let{query:r,attributes:i,order:a,page:o,perPage:s,include:c,group:l,enrichments:u,jsonAttributes:f}=t,p=Ie.validate(t);if(p.error)throw new d.BadRequest([p.error]);H({query:r,attributes:i,order:a,page:o,perPage:s,include:c,enrichments:u,group:l,jsonAttributes:f},e,n)},Le=(e,t={},n=`body`)=>(r,i,a)=>{try{q(e,r[n],t),a()}catch(e){let{query:a,attributes:o,order:s}=r[n];(0,d.handleError)(e,i,{logger:t.logger??Fe,message:`error in query middleware`,payload:{error:e,query:a,attributes:o,order:s}})}},J=(e,t,n={})=>{let{order:r,page:i,perPage:a,include:o,query:s,attributes:c,searchTerm:l,jsonAttributes:u}=t,{query:d,externalQueryValues:f,order:p,page:m,perPage:h,include:g,scopes:_,attributes:v}=Te({query:s,order:r,page:i,perPage:a,include:o,attributes:c,searchTerm:l,jsonAttributes:u},e,n);t.query=d,t.externalQueryValues=f,t.order=p,t.attributes=v,t.page=m,t.perPage=h,t.include=g,t.scopes=_,n.includeRawPayload&&(t.rawPayload={order:r,page:i,perPage:a,include:o,query:s,attributes:c,searchTerm:l})},Re=(e,t={},n=`body`)=>(r,i,a)=>{J(e,r[n],t),a()},ze=({model:e,logger:t,validationOptions:n,formatOptions:r,modelName:i=e.constructor?.name,additionalScopes:a=[],modifyQueryValues:o,onRowsRetrieved:s})=>async(c,l)=>{try{q(e,c.body,{...n,logger:t})}catch(e){(0,d.handleError)(e,l,{logger:t,message:`error in query endpoint`,payload:k(c.body,[`query`,`order`,`attributes`])});return}try{J(e,c.body,r);let n=Object.assign(k(c.body,[`query`,`externalQueryValues`,`order`,`attributes`,`page`,`perPage`,`include`,`scopes`,`enrichments`]),{distinct:!0});t.info(`querying ${i}`,{queryValues:n});let u=o?.(n)??n,{scopes:d=[],query:f,perPage:p,page:m,enrichments:h,externalQueryValues:g,..._}=u,v=await e.scope([...a,...d]).findAndCountAll({where:f,limit:p,offset:(m-1)*p,..._});if(!v.rows.length||!s){l.json(v);return}let y=await s(v,u);l.json(y)}catch(e){(0,d.handleError)(new d.UnexpectedError(e),l,{logger:t,message:`Error while querying ${i}`,payload:{query:c.body}})}};var Y=class e extends Error{constructor(e,t=!1){super(e),this.name=`BulkerError`,this.retryable=t,Object.setPrototypeOf(this,new.target.prototype)}static isBulkerError(t){return t instanceof e}static wrap(t,n,r=!1){return t instanceof e?new e(n??t.message,r||t.retryable):new e(n?`${n}: ${t instanceof Error?t.message:String(t)}`:String(t),r)}static retryable(t){return new e(t,!0)}static nonRetryable(t){return new e(t,!1)}};const Be=e=>e.length===0?`No keys provided`:e.length===1?`Key "${e[0]}" is required`:`Exactly one of [${e.join(`, `)}] must be provided`;function X(e,t){return _.z.object(e).refine(e=>t.filter(t=>e[t]!==void 0&&e[t]!==null).length===1,{message:Be(t)})}const Z=_.z.string().uuid();function Ve(e){return X(Object.fromEntries(e.map(e=>[e,_.z.union([Z,_.z.array(Z)]).optional()])),e)}const He=[`businessModelId`,`fleetId`,`demandSourceId`,`contextId`,`userId`,`businessAccountId`,`activeBusinessModelId`];var Q=class{constructor(e,t){if(this.bulker=e,this.opts=t,this.rabbitQueueName=null,this.rabbit=null,this.bulkHandler=async(e,t,n)=>{try{let{query:n,payload:r,preview:i}=e.body??{},a=r;if(r&&this.payloadSchema)try{a=this.payloadSchema.parse(r)}catch(e){if(e instanceof _.z.ZodError)return t.status(400).json({error:`invalid_payload`,details:e.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`, `)});throw e}try{q(this.model,n,{logger:this.bulker.logger})}catch(e){return t.status(400).json({error:`invalid_query`,details:e.message||e})}let o=this.identityScopeSchema.safeParse(n?.query||{});if(!o.success)return t.status(400).json({error:`invalid_identity_scope`,details:o.error.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`, `)});J(this.model,n,{includeRawPayload:!0});let{query:s,...c}=Object.assign(k(n,[`query`,`externalQueryValues`,`order`,`include`,`scopes`,`enrichments`]),{distinct:!0}),l=[];if(this.opts.additionalIdsHook){let{rawPayload:e}=n;try{l=await this.opts.additionalIdsHook({rawPayload:e,payload:a}),this.bulker.logger.info(`additionalIdsHook returned ${l.length} IDs for action ${this.action}`)}catch(e){return this.bulker.logger.error(`Error in additionalIdsHook for action ${this.action}: ${e.message||e}`,{err:e}),t.status(500).json({error:`additional_ids_hook_error`,details:e.message||e})}}let u=[];s&&typeof s==`object`&&Object.keys(s).length>0&&u.push(s),Array.isArray(l)&&l.length>0&&u.push({id:{$in:l}});let d;if(u.length===0)return t.status(400).json({error:`no_query`,details:`No valid query provided to select records`});if(u.length===1){let[e]=u;d=e}else d={$or:u};this.bulker.logger.info(`Constructed final where clause for action ${this.action}`,{where:d});let f={where:d,...c},p=await this.model.scope(this.modelScopes).count({...f,col:this.idField});if(i)return t.json({estimatedCount:p});let h=(0,m.randomUUID)();return await this.bulker.jobManager.initJob(h,{status:`queued`,total:p,action:this.action}),this.bulker.emitEvent(`job:created`,{jobId:h,action:this.action,total:p}),setImmediate(()=>{this.rabbitScanAndEnqueue(h,f,a).catch(e=>this.bulker.logger.error(e))}),t.status(202).json({jobId:h,estimatedCount:p})}catch(e){return this.bulker.logger.error(`Error in bulkHandler for action ${this.action}: ${e.message||e}`,{err:e}),n(e)}},this.action=t.action,this.model=t.model,this.modelScopes=t.modelScopes??[],this.consumer=t.consumer,this.rabbit=e.rabbit,this.rabbitQueueName=t.rabbitQueueName??`bulk-${this.action}-queue`,this.consumerOptions={enableRabbitTrace:!0,...this.opts.consumerOptions},this.queryFunction=t.queryFunction,this.payloadSchema=t.payloadSchema,!/^[a-zA-Z0-9-_]+$/.test(this.action))throw Error(`BulkRoute action must be alphanumeric`);if(!this.model||typeof this.model.findAll!=`function`||typeof this.model.count!=`function`)throw Error(`BulkRoute model must be a valid Sequelize model`);if(typeof this.consumer!=`function`)throw Error(`BulkRoute consumer must be a function`);if(this.queryFunction&&typeof this.queryFunction!=`function`)throw Error(`BulkRoute queryFunction must be a function`);if(this.payloadSchema&&!(this.payloadSchema instanceof _.z.ZodType))throw Error(`BulkRoute payloadSchema must be a Zod schema`);if(this.modelScopes&&!Array.isArray(this.modelScopes))throw Error(`BulkRoute scopes must be an array of strings`);if(this.opts.additionalIdsHook&&typeof this.opts.additionalIdsHook!=`function`)throw Error(`BulkRoute additionalIdsHook must be a function`);this.idField=t.idField??e.defaults.idField,this.pageSize=t.pageSize??e.defaults.pageSize;let n=this.model.rawAttributes||{},r=(t.identityScopes&&t.identityScopes.length>0?t.identityScopes:He).filter(e=>!!n[e]);r.length===0&&this.bulker.logger.warn(`BulkRoute for action ${this.action} has no valid identityScopes configured - all records will be accessible`),this.bulker.logger.info(`BulkRoute for action ${this.action} using idField ${this.idField}, pageSize ${this.pageSize}, identityScopes: ${r.join(`, `)}`),this.identityScopeSchema=Ve(r),this.startRabbitWorker().catch(e=>{this.bulker.logger.error(`Failed to start RabbitMQ worker for queue ${this.rabbitQueueName}: ${e.message||e}`)})}async getUserJobs(e,t=20){return this.bulker.jobManager.getUserJobs(e,t)}async rabbitScanAndEnqueue(e,t,n){if(!this.rabbit)throw Error(`RabbitMQ not configured in Bulker`);let r=Date.now().toString();if(this.bulker.getUserId){let t=this.bulker.getUserId();t&&await this.bulker.jobManager.addUserJob(t,e)}await this.bulker.jobManager.setJobFields(e,{status:`running`,startTime:r}),this.bulker.emitEvent(`job:started`,{jobId:e,action:this.action});let i=null,a=0,o=0;for(;;){let r=await this.bulker.jobManager.getJobField(e,`status`);if(!r||r===`canceled`){this.bulker.logger.info(`Job ${e} was canceled, stopping scan and enqueue`);break}let s=i?{[l.Op.and]:[t.where,{[this.idField]:{[l.Op.gt]:i}}]}:t.where,c=await this.model.scope(this.modelScopes).findAll({where:s,...k(t,[`include`,`order`,`scopes`]),attributes:[this.idField],order:[[this.idField,`ASC`]],limit:this.pageSize,raw:!0,subQuery:!1});if(c.length===0)break;let u=c.map(t=>({jobId:e,id:t[this.idField],payload:n}));this.bulker.logger.info(`Enqueuing ${u.length} messages to RabbitMQ queue ${this.rabbitQueueName}`);let d=(await Promise.allSettled(u.map(e=>this.rabbit.sendToQueue(this.rabbitQueueName,e)))).filter(e=>e.status===`rejected`);if(d.length>0)throw this.bulker.logger.error(`Failed to enqueue ${d.length} messages to RabbitMQ`,{rejected:d}),Error(`Failed to enqueue ${d.length} messages to RabbitMQ`);a+=c.length,await this.bulker.jobManager.incrJobField(e,`queued`,c.length),i=c[c.length-1][this.idField],o+=1,this.bulker.emitEvent(`scan:page`,{jobId:e,action:this.action,pageNumber:o,itemsInPage:c.length});let f=await this.bulker.jobManager.getJob(e);f&&this.bulker.emitEvent(`job:queued`,{jobId:e,action:this.action,queued:a,total:f.total})}a===0&&await this.bulker.jobManager.completeEmptyJob(e)}async startRabbitWorker(){return this.bulker.logger.info(`Starting RabbitMQ consumer for queue ${this.rabbitQueueName}`),this.bulker.emitEvent(`worker:started`,{action:this.action,queueName:this.rabbitQueueName}),this.rabbit?.consume(this.rabbitQueueName,async(e,t,n)=>{if(!e)return;let{jobId:r,id:i,payload:a}=e.content,o=!1,s=async()=>{o||(o=!0,await Promise.all([this.bulker.jobManager.ack(r),t()]),this.bulker.emitEvent(`item:processed`,{jobId:r,action:this.action,id:i}))},c=async(e,t)=>{if(o)return;o=!0;let s=t;s===void 0&&(s=Y.isBulkerError(e)?e.retryable:!1),await Promise.all([this.bulker.jobManager.nack(r,e?e.message||String(e):`nacked`,{id:i,payload:a}),n(void 0,{skipRetry:!s})]),s?this.bulker.emitEvent(`item:retrying`,{jobId:r,action:this.action,id:i}):this.bulker.emitEvent(`item:failed`,{jobId:r,action:this.action,id:i,error:e?e.message||String(e):`nacked`})},l=await this.bulker.jobManager.getJobField(r,`status`);if(!l||l===`canceled`){await this.bulker.jobManager.incrJobField(r,`processed`,1);return}try{this.bulker.logger.info(`Processing job ${r} action ${this.action} id ${i}`),this.bulker.emitEvent(`item:processing`,{jobId:r,action:this.action,id:i}),await this.consumer({jobId:r,id:i,payload:a},s,c),await s()}catch(e){this.bulker.logger.error(`Error processing job ${r} action ${this.action} id ${i}: ${e.message||e}`,{err:e}),this.bulker.emitEvent(`worker:error`,{action:this.action,error:e.message||String(e)}),await c(e,!1)}},this.consumerOptions)}},Ue=class{constructor(e,t,n=`/bulk-actions`){this.routes=[],this.actionsToRouteMap=new Map,this.bulkHandler=async(e,t,n)=>{try{let{action:r}=e.body??{};if(!r)return t.status(400).json({error:`missing_action`,message:`Request body must include an "action" field`});let i=this.actionsToRouteMap.get(r);return i?i.bulkHandler(e,t,n):t.status(404).json({error:`unknown_action`,message:`Action "${r}" is not registered`,availableActions:Array.from(this.actionsToRouteMap.keys())})}catch(e){return this.bulker.logger.error(`Error in BulkRouter bulkHandler: ${e.message||e}`,{err:e}),n(e),null}},this.getJobHandler=async(e,t,n)=>{try{if(!e.params.id)return t.status(400).json({error:`missing_id`});let n=await this.bulker.jobManager.getJob(e.params.id);return n?t.json(n):t.status(404).json({error:`not_found`})}catch(e){return n(e)}},this.cancelJobHandler=async(e,t,n)=>{try{return e.params.id?await this.bulker.jobManager.cancelJob(e.params.id)?(this.bulker.logger.info(`Job ${e.params.id} cancel requested`),t.json({ok:!0})):t.status(404).json({error:`not_found`}):t.status(400).json({error:`missing_id`})}catch(e){return n(e)}},this.getMyJobsHandler=async(e,t,n)=>{try{if(!this.bulker.getUserId)return t.status(400).json({error:`user_id_function_not_configured`,message:`Bulker instance does not have a getUserId function configured`});let e=this.bulker.getUserId();if(!e)return t.json([]);let n=(await this.bulker.jobManager.getUserJobs(e)).filter(e=>e!==null);return n.sort((e,t)=>{let n=e.createdAt?new Date(e.createdAt).getTime():0;return(t.createdAt?new Date(t.createdAt).getTime():0)-n}),t.json(n)}catch(e){return n(e)}},this.bulker=e,this.router=t??(0,g.Router)(),this.staticRoute=n,this.registerStaticRoutes()}registerStaticRoutes(){this.router.post(this.staticRoute,this.bulkHandler),this.router.get(`/jobs/:id`,this.getJobHandler),this.router.get(`/jobs`,this.getMyJobsHandler),this.router.post(`/jobs/:id/cancel`,this.cancelJobHandler)}addAction(e,t){let n=new Q(this.bulker,{action:e,...t});if(this.bulker.logger.info(`Registering action handler: ${e}`),this.actionsToRouteMap.has(e))throw Error(`Action "${e}" is already registered`);return this.actionsToRouteMap.set(e,n),this.routes.push(n),n}getRouter(){return this.router}};const We=`
2
+ local jobKey = KEYS[1]
3
+ local updatedAt = ARGV[1]
4
+ local total = tonumber(redis.call('HGET', jobKey, 'total'))
5
+ if not total then
6
+ return 0
7
+ end
8
+
9
+ local processed = redis.call('HINCRBY', jobKey, 'processed', 1)
10
+ redis.call('HINCRBY', jobKey, 'succeeded', 1)
11
+ redis.call('HSET', jobKey, 'updatedAt', updatedAt)
12
+
13
+ if processed >= total then
14
+ redis.call('HSET', jobKey, 'status', 'completed')
15
+ redis.call('HSET', jobKey, 'endTime', updatedAt)
16
+ end
17
+
18
+ return processed
19
+ `,Ge=`
20
+ local jobKey = KEYS[1]
21
+ local errorMsg = ARGV[1]
22
+ local errorData = ARGV[2]
23
+ local errorLogLimit = tonumber(ARGV[3])
24
+ local updatedAt = ARGV[4]
25
+
26
+ local total = tonumber(redis.call('HGET', jobKey, 'total'))
27
+ if not total then
28
+ return 0
29
+ end
30
+
31
+ -- Add error
32
+ local errorsJson = redis.call('HGET', jobKey, 'errors') or '[]'
33
+ local errors = cjson.decode(errorsJson)
34
+
35
+ if #errors >= errorLogLimit then
36
+ -- Keep only the last (errorLogLimit - 1) entries
37
+ local newErrors = {}
38
+ for i = #errors - errorLogLimit + 2, #errors do
39
+ table.insert(newErrors, errors[i])
40
+ end
41
+ errors = newErrors
42
+ end
43
+
44
+ table.insert(errors, { message = errorMsg, data = cjson.decode(errorData) })
45
+ redis.call('HSET', jobKey, 'errors', cjson.encode(errors))
46
+
47
+ -- Update counters
48
+ redis.call('HINCRBY', jobKey, 'failed', 1)
49
+ local processed = redis.call('HINCRBY', jobKey, 'processed', 1)
50
+ redis.call('HSET', jobKey, 'updatedAt', updatedAt)
51
+
52
+ if processed >= total then
53
+ redis.call('HSET', jobKey, 'status', 'completed')
54
+ redis.call('HSET', jobKey, 'endTime', updatedAt)
55
+ end
56
+
57
+ return processed
58
+ `;var $=class e{constructor(e,t){this.redis=e,this.defaults={maxJobsPerUser:t?.maxJobsPerUser??-1,jobTtlSeconds:t?.jobTtlSeconds??168*3600,errorLogLimit:t?.errorLogLimit??10}}setEventEmitter(e){this.eventEmitter=e}static jobKey(e){return`bulker:job:${e}`}static userJobsKey(e){return`bulker:user:${e}:jobs`}async initJob(t,n){let r=Date.now().toString(),i=e.jobKey(t),a=this.redis.multi();a.hSet(i,{status:n.status,total:String(n.total),queued:`0`,processed:`0`,succeeded:`0`,failed:`0`,action:n.action,errors:JSON.stringify([]),createdAt:r,updatedAt:r,startTime:r,endTime:``}),a.expire(i,this.defaults.jobTtlSeconds),await a.exec()}async getJob(t){let n=e.jobKey(t),r=await this.redis.hGetAll(n);if(!r||Object.keys(r).length===0)return null;let i=r.startTime?Number(r.startTime):null,a=r.endTime&&r.endTime!==``?Number(r.endTime):null,o=Date.now(),s={startTime:i?new Date(i).toISOString():null,endTime:a?new Date(a).toISOString():null,durationMs:i?(a||o)-i:null};return{jobId:t,status:r.status,action:r.action,total:Number(r.total??0),queued:Number(r.queued??0),processed:Number(r.processed??0),succeeded:Number(r.succeeded??0),failed:Number(r.failed??0),errors:r.errors?JSON.parse(r.errors):[],createdAt:r.createdAt?new Date(Number(r.createdAt)).toISOString():void 0,updatedAt:r.updatedAt?new Date(Number(r.updatedAt)).toISOString():void 0,duration:s}}async setJobField(t,n,r){let i=e.jobKey(t);if(!await this.redis.exists(i))return!1;let a=this.redis.multi();return a.hSet(i,n,r),a.hSet(i,`updatedAt`,Date.now().toString()),await a.exec(),!0}async setJobFields(t,n){let r=e.jobKey(t);if(!await this.redis.exists(r))return!1;let i=this.redis.multi();return i.hSet(r,n),i.hSet(r,`updatedAt`,Date.now().toString()),await i.exec(),!0}async incrJobField(t,n,r=1){let i=e.jobKey(t),a=this.redis.multi();a.hIncrBy(i,n,r),a.hSet(i,`updatedAt`,Date.now().toString());let o=await a.exec();return o?.[0]&&o[0][0]===null?o[0][1]:0}async getJobField(t,n){let r=e.jobKey(t);return this.redis.hGet(r,n)}async cancelJob(e){return this.setJobField(e,`status`,`canceled`)}async completeEmptyJob(e){let t=Date.now().toString();await this.setJobFields(e,{status:`completed`,endTime:t})}async ack(t){let n=e.jobKey(t);await this.redis.eval(`
59
+ local jobKey = KEYS[1]
60
+ local updatedAt = ARGV[1]
61
+ local total = tonumber(redis.call('HGET', jobKey, 'total'))
62
+ if not total then
63
+ return 0
64
+ end
65
+
66
+ local processed = redis.call('HINCRBY', jobKey, 'processed', 1)
67
+ redis.call('HINCRBY', jobKey, 'succeeded', 1)
68
+ redis.call('HSET', jobKey, 'updatedAt', updatedAt)
69
+
70
+ if processed >= total then
71
+ redis.call('HSET', jobKey, 'status', 'completed')
72
+ redis.call('HSET', jobKey, 'endTime', updatedAt)
73
+ end
74
+
75
+ return processed
76
+ `,{keys:[n],arguments:[Date.now().toString()]});let r=await this.getJob(t);if(r&&r.status===`completed`){let e=r.duration.durationMs||0;this.eventEmitter?.emitEvent(`job:completed`,{jobId:t,action:r.action,processed:r.processed,failed:r.failed,duration:e})}}async nack(t,n,r){let i=e.jobKey(t);await this.redis.eval(`
77
+ local jobKey = KEYS[1]
78
+ local errorMsg = ARGV[1]
79
+ local errorData = ARGV[2]
80
+ local errorLogLimit = tonumber(ARGV[3])
81
+ local updatedAt = ARGV[4]
82
+
83
+ local total = tonumber(redis.call('HGET', jobKey, 'total'))
84
+ if not total then
85
+ return 0
86
+ end
87
+
88
+ -- Add error
89
+ local errorsJson = redis.call('HGET', jobKey, 'errors') or '[]'
90
+ local errors = cjson.decode(errorsJson)
91
+
92
+ if #errors >= errorLogLimit then
93
+ -- Keep only the last (errorLogLimit - 1) entries
94
+ local newErrors = {}
95
+ for i = #errors - errorLogLimit + 2, #errors do
96
+ table.insert(newErrors, errors[i])
97
+ end
98
+ errors = newErrors
99
+ end
100
+
101
+ table.insert(errors, { message = errorMsg, data = cjson.decode(errorData) })
102
+ redis.call('HSET', jobKey, 'errors', cjson.encode(errors))
103
+
104
+ -- Update counters
105
+ redis.call('HINCRBY', jobKey, 'failed', 1)
106
+ local processed = redis.call('HINCRBY', jobKey, 'processed', 1)
107
+ redis.call('HSET', jobKey, 'updatedAt', updatedAt)
108
+
109
+ if processed >= total then
110
+ redis.call('HSET', jobKey, 'status', 'completed')
111
+ redis.call('HSET', jobKey, 'endTime', updatedAt)
112
+ end
113
+
114
+ return processed
115
+ `,{keys:[i],arguments:[n,JSON.stringify(r),String(this.defaults.errorLogLimit),Date.now().toString()]});let a=await this.getJob(t);if(a&&a.status===`completed`){let e=a.duration.durationMs||0;this.eventEmitter?.emitEvent(`job:completed`,{jobId:t,action:a.action,processed:a.processed,failed:a.failed,duration:e})}}async addUserJob(t,n){let r=e.userJobsKey(t),i=this.redis.multi();i.lPush(r,n),this.defaults.maxJobsPerUser>0&&i.lTrim(r,0,this.defaults.maxJobsPerUser-1),i.expire(r,3600),await i.exec()}async removeUserJob(t,n){let r=e.userJobsKey(t);await this.redis.lRem(r,0,n)}async getUserJobs(t,n=20){let r=e.userJobsKey(t),i=await this.redis.lRange(r,0,n-1);return await Promise.all(i.map(e=>this.getJob(e)))}},Ke=o({BulkRoute:()=>Q,Bulker:()=>Je,BulkerError:()=>Y,JobManager:()=>$,z:()=>_.z});const qe={emitEvent:()=>{}};var Je=class extends v.EventEmitter{constructor(e){if(super(),this.bulkRouters=[],this.sequelize=e.sequelize,this.logger=e.logger,this.rabbit=e.rabbit,this.eventsEnabled=e.emitEvents??!1,e.redis&&typeof e.redis.connect==`function`)this.redis=e.redis,this.redis.isOpen||this.redis.connect().catch(e=>{this.logger.error(`Error connecting to Redis:`,e)});else{let t=e.redis;this.redis=(0,h.createClient)({socket:{host:t.host,port:t.port},password:t.password,database:t.db}),this.redis.connect().catch(e=>{this.logger.error(`Error connecting to Redis:`,e)})}this.getUserId=e.getUserId??(()=>null),this.defaults={maxJobsPerUser:e.defaults?.maxJobsPerUser??-1,pageSize:e.defaults?.pageSize??1e3,idField:e.defaults?.idField??`id`,workerConcurrency:e.defaults?.workerConcurrency??16,jobTtlSeconds:e.defaults?.jobTtlSeconds??168*3600,errorLogLimit:e.defaults?.errorLogLimit??10},this.jobManager=new $(this.redis,{maxJobsPerUser:this.defaults.maxJobsPerUser,jobTtlSeconds:this.defaults.jobTtlSeconds,errorLogLimit:this.defaults.errorLogLimit}),this.jobManager.setEventEmitter(this.eventsEnabled?{emitEvent:this.emitEvent.bind(this)}:qe)}createBulkRouter(e,t){let n=new Ue(this,e,t);return this.bulkRouters.push(n),n}emitEvent(e,...t){this.eventsEnabled&&this.emit(e,...t)}};Object.defineProperty(exports,`Bulker`,{enumerable:!0,get:function(){return Ke}}),exports.formatOperators=x,exports.generateFilterReplacements=I,exports.queryFormatMiddleware=Re,exports.queryHandler=ze,exports.queryValidationMiddleware=Le,exports.validatePayload=H;
2
116
  //# sourceMappingURL=index.cjs.map