@zuplo/cli 7.12.6 → 7.12.7
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/node_modules/@posthog/core/dist/featureFlagLocalEvaluation.d.ts +13 -1
- package/node_modules/@posthog/core/dist/featureFlagLocalEvaluation.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/featureFlagLocalEvaluation.js +101 -31
- package/node_modules/@posthog/core/dist/featureFlagLocalEvaluation.mjs +99 -32
- package/node_modules/@posthog/core/dist/index.d.ts +2 -2
- package/node_modules/@posthog/core/dist/index.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/index.js +17 -7
- package/node_modules/@posthog/core/dist/index.mjs +1 -1
- package/node_modules/@posthog/core/dist/posthog-core.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/posthog-core.js +1 -1
- package/node_modules/@posthog/core/dist/posthog-core.mjs +1 -1
- package/node_modules/@posthog/core/dist/types.d.ts +2 -0
- package/node_modules/@posthog/core/dist/types.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/types.js +1 -0
- package/node_modules/@posthog/core/dist/types.mjs +1 -0
- package/node_modules/@posthog/core/package.json +1 -1
- package/node_modules/@posthog/core/src/featureFlagLocalEvaluation.ts +143 -63
- package/node_modules/@posthog/core/src/index.ts +2 -0
- package/node_modules/@posthog/core/src/posthog-core.ts +3 -1
- package/node_modules/@posthog/core/src/types.ts +2 -0
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/core/zeno.js +4 -4
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +1 -1
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/node_modules/body-parser/README.md +17 -13
- package/node_modules/body-parser/lib/read.js +74 -57
- package/node_modules/body-parser/lib/types/json.js +11 -11
- package/node_modules/body-parser/lib/types/urlencoded.js +5 -5
- package/node_modules/body-parser/lib/utils.js +0 -15
- package/node_modules/body-parser/package.json +7 -12
- package/node_modules/on-finished/index.js +14 -2
- package/node_modules/on-finished/package.json +11 -7
- package/package.json +11 -11
- package/node_modules/on-finished/HISTORY.md +0 -98
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
* DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*--------------------------------------------------------------------------------------------*/
|
|
24
24
|
|
|
25
|
-
var ft=Object.defineProperty;var o=(r,e)=>ft(r,"name",{value:e,configurable:!0});import{scheduler as
|
|
26
|
-
`),Nt=z.encode("*"),vt=z.encode("$");function ue(r){let e=[Nt,z.encode(r.length.toString()),X];for(let t of r){let n=t instanceof Uint8Array?t:z.encode(t.toString());e.push(vt,z.encode(n.byteLength.toString()),X,n,X)}return ee(e)}o(ue,"createRequest");async function*Pt(r){let e=new Uint8Array;for await(let t of r){e=ee([e,t]);let n;for(;(n=e.indexOf(X[0]))!==-1&&e[n+1]===X[1];)yield e.subarray(0,n),e=e.subarray(n+2)}}o(Pt,"readLines");function J(r,e,t=!1){return Array.fromAsync({length:e},()=>q(r,t))}o(J,"readNReplies");function k(r){return pe.decode(r.slice(1))}o(k,"parseLine");function Ot(r){let e=[];for(let t=0;t<r.length;t+=2)e.push(r.slice(t,t+2));return e}o(Ot,"chunk");async function q(r,e=!1){let{value:t}=await r.next();switch(t[0]){case pt:case _t:{let n=Number(k(t));return n===-1?null:await J(r,n)}case mt:{let n=Number(k(t))*2;return await J(r,n),q(r,e)}case gt:return BigInt(k(t));case ht:{let{value:n}=await r.next();return Promise.reject(pe.decode(n))}case yt:return k(t)==="t";case bt:case St:return k(t)==="-1"?null:q(r,e);case At:case Ct:switch(k(t)){case"inf":return 1/0;case"-inf":return-1/0;default:return Number(k(t))}case Tt:return Promise.reject(k(t));case xt:{let n=Number(k(t))*2,s=await J(r,n);return Object.fromEntries(Ot(s))}case Rt:return null;case Et:return new Set(await J(r,Number(k(t)),e));case wt:return k(t);default:return e?t:pe.decode(t)}}o(q,"readReply");var te=class{static{o(this,"RedisClient")}#e;#r;#t=Promise.resolve();constructor(e){this.#e=e.writable.getWriter(),this.#r=Pt(e.readable)}#n(e){return this.#t=this.#t.then(e),this.#t}sendCommand(e,t=!1){return this.#n(()=>(this.#e.write(ue(e)),q(this.#r,t)))}writeCommand(e){return this.#n(()=>this.#e.write(ue(e)))}async*readReplies(e=!1){for(;;)yield q(this.#r,e)}pipelineCommands(e,t=!1){return this.#n(()=>{let n=ee(e.map(ue));return this.#e.write(n),J(this.#r,e.length,t)})}};var R=globalThis.Deno?.build.os==="windows"||globalThis.navigator?.platform?.startsWith("Win")||globalThis.process?.platform?.startsWith("win")||!1;function _(r){if(typeof r!="string")throw new TypeError(`Path must be a string, received "${JSON.stringify(r)}"`)}o(_,"assertPath");function M(r){return r===47}o(M,"isPosixPathSeparator");function T(r){return r===47||r===92}o(T,"isPathSeparator");function H(r){return r>=97&&r<=122||r>=65&&r<=90}o(H,"isWindowsDeviceRoot");function ne(r){if(_(r),r.length===0)return"."}o(ne,"assertArg");function V(r,e,t,n){let s="",i=0,l=-1,a=0,d;for(let c=0;c<=r.length;++c){if(c<r.length)d=r.charCodeAt(c);else{if(n(d))break;d=47}if(n(d)){if(!(l===c-1||a===1))if(l!==c-1&&a===2){if(s.length<2||i!==2||s.charCodeAt(s.length-1)!==46||s.charCodeAt(s.length-2)!==46){if(s.length>2){let p=s.lastIndexOf(t);p===-1?(s="",i=0):(s=s.slice(0,p),i=s.length-1-s.lastIndexOf(t)),l=c,a=0;continue}else if(s.length===2||s.length===1){s="",i=0,l=c,a=0;continue}}e&&(s.length>0?s+=`${t}..`:s="..",i=2)}else s.length>0?s+=t+r.slice(l+1,c):s=r.slice(l+1,c),i=c-l-1;l=c,a=0}else d===46&&a!==-1?++a:a=-1}return s}o(V,"normalizeString");function oe(r){ne(r);let e=M(r.charCodeAt(0)),t=M(r.charCodeAt(r.length-1));return r=V(r,!e,"/",M),r.length===0&&!e&&(r="."),r.length>0&&t&&(r+="/"),e?`/${r}`:r}o(oe,"normalize");function ge(...r){if(r.length===0)return".";r.forEach(t=>_(t));let e=r.filter(t=>t.length>0).join("/");return e===""?".":oe(e)}o(ge,"join");function se(r){ne(r);let e=r.length,t=0,n,s=!1,i=r.charCodeAt(0);if(e>1)if(T(i))if(s=!0,T(r.charCodeAt(1))){let a=2,d=a;for(;a<e&&!T(r.charCodeAt(a));++a);if(a<e&&a!==d){let c=r.slice(d,a);for(d=a;a<e&&T(r.charCodeAt(a));++a);if(a<e&&a!==d){for(d=a;a<e&&!T(r.charCodeAt(a));++a);if(a===e)return`\\\\${c}\\${r.slice(d)}\\`;a!==d&&(n=`\\\\${c}\\${r.slice(d,a)}`,t=a)}}}else t=1;else H(i)&&r.charCodeAt(1)===58&&(n=r.slice(0,2),t=2,e>2&&T(r.charCodeAt(2))&&(s=!0,t=3));else if(T(i))return"\\";let l;return t<e?l=V(r.slice(t),!s,"\\",T):l="",l.length===0&&!s&&(l="."),l.length>0&&T(r.charCodeAt(e-1))&&(l+="\\"),n===void 0?s?l.length>0?`\\${l}`:"\\":l:s?l.length>0?`${n}\\${l}`:`${n}\\`:n+l}o(se,"normalize");function he(...r){if(r.forEach(i=>_(i)),r=r.filter(i=>i.length>0),r.length===0)return".";let e=!0,t=0,n=r[0];if(T(n.charCodeAt(0))){++t;let i=n.length;i>1&&T(n.charCodeAt(1))&&(++t,i>2&&(T(n.charCodeAt(2))?++t:e=!1))}let s=r.join("\\");if(e){for(;t<s.length&&T(s.charCodeAt(t));++t);t>=2&&(s=`\\${s.slice(t)}`)}return se(s)}o(he,"join");function N(...r){return R?he(...r):ge(...r)}o(N,"join");function qt(r){if(r.length>=255)throw new TypeError("Alphabet too long");let e=new Uint8Array(256);for(let c=0;c<e.length;c++)e[c]=255;for(let c=0;c<r.length;c++){let p=r.charAt(c),g=p.charCodeAt(0);if(e[g]!==255)throw new TypeError(p+" is ambiguous");e[g]=c}let t=r.length,n=r.charAt(0),s=Math.log(t)/Math.log(256),i=Math.log(256)/Math.log(t);function l(c){if(c instanceof Uint8Array||(ArrayBuffer.isView(c)?c=new Uint8Array(c.buffer,c.byteOffset,c.byteLength):Array.isArray(c)&&(c=Uint8Array.from(c))),!(c instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(c.length===0)return"";let p=0,g=0,h=0,C=c.length;for(;h!==C&&c[h]===0;)h++,p++;let E=(C-h)*i+1>>>0,w=new Uint8Array(E);for(;h!==C;){let A=c[h],S=0;for(let O=E-1;(A!==0||S<g)&&O!==-1;O--,S++)A+=256*w[O]>>>0,w[O]=A%t>>>0,A=A/t>>>0;if(A!==0)throw new Error("Non-zero carry");g=S,h++}let v=E-g;for(;v!==E&&w[v]===0;)v++;let x=n.repeat(p);for(;v<E;++v)x+=r.charAt(w[v]);return x}o(l,"encode");function a(c){if(typeof c!="string")throw new TypeError("Expected String");if(c.length===0)return new Uint8Array;let p=0,g=0,h=0;for(;c[p]===n;)g++,p++;let C=(c.length-p)*s+1>>>0,E=new Uint8Array(C);for(;p<c.length;){let A=c.charCodeAt(p);if(A>255)return;let S=e[A];if(S===255)return;let O=0;for(let u=C-1;(S!==0||O<h)&&u!==-1;u--,O++)S+=t*E[u]>>>0,E[u]=S%256>>>0,S=S/256>>>0;if(S!==0)throw new Error("Non-zero carry");h=O,p++}let w=C-h;for(;w!==C&&E[w]===0;)w++;let v=new Uint8Array(g+(C-w)),x=g;for(;w!==C;)v[x++]=E[w++];return v}o(a,"decodeUnsafe");function d(c){let p=a(c);if(p)return p;throw new Error("Non-base"+t+" character")}return o(d,"decode"),{encode:l,decodeUnsafe:a,decode:d}}o(qt,"base");var Me=qt;var Yt="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",Le=Me(Yt);import{pathToFileURL as He}from"node:url";import Ie from"dotenv";var ye=class{static{o(this,"ZenoLogger")}prefix="[ZENO]:";logLevel;originalConsole={debug:console.debug,info:console.info,warn:console.warn,error:console.error};constructor(e="info"){this.logLevel=e}debug(...e){(this.shouldLog("debug")||Deno.env.get("ZENO_DEBUG"))&&this.originalConsole.debug(this.prefix,"[DEBUG]",...e)}info(...e){this.shouldLog("info")&&this.originalConsole.info(this.prefix,"[INFO]",...e)}warn(...e){this.shouldLog("warn")&&this.originalConsole.warn(this.prefix,"[WARN]",...e)}error(...e){this.shouldLog("error")&&this.originalConsole.error(this.prefix,"[ERROR]",...e)}shouldLog(e){let t=["debug","info","warn","error"],n=t.indexOf(this.logLevel);return t.indexOf(e)>=n}setLogLevel(e){this.logLevel=e}},m=new ye;async function Be(r){let e={};for(let[t,n]of Object.entries(Deno.env.toObject()))n!==void 0&&(e[t]=n);try{let t=N(r,".env.zuplo"),n=new TextDecoder("utf-8"),s=await Deno.readFile(He(t)),i=n.decode(s),l=Ie.parse(i);for(let[a,d]of Object.entries(l))if(e[a]=d,a==="ZUPLO_SYSTEM_CONFIGURATIONS")try{let c=new TextDecoder().decode(Le.decode(d)),p=JSON.parse(c);for(let[g,h]of Object.entries(p))e[g]=String(h)}catch(c){Deno.build.standalone||m.error("Failed to parse ZUPLO_SYSTEM_CONFIGURATIONS from .env.zuplo:",c)}}catch(t){t instanceof Deno.errors.NotFound||m.error("Failed to load .env.zuplo file:",t)}try{let t=N(r,".env"),n=new TextDecoder("utf-8"),s=await Deno.readFile(He(t)),i=n.decode(s),l=Ie.parse(i);for(let[a,d]of Object.entries(l))e[a]=d}catch(t){t instanceof Deno.errors.NotFound||m.error("Failed to load .env.zuplo file:",t)}for(let[t,n]of Object.entries(e))n===void 0&&delete e[t];return e.__ZUPLO_IS_MANAGED_DEDICATED="true",e}o(Be,"loadEnvironment");function $e(r){return r?["true","1","yes","y"].includes(r.toLowerCase()):!1}o($e,"parseEnvBool");var be=class{static{o(this,"CacheStorage")}#e;constructor(){this.#e=new Map}async open(e){let t=this.#e.get(e);return t||(t=new Ae,this.#e.set(e,t)),t}async has(e){return this.#e.has(e)}async delete(e){throw new Error("caches.delete is not supported")}};async function Qt(){let r=Deno.env.get("ZUPLO_CACHE_REDIS_HOSTNAME");if(r===void 0)throw new Error("ZUPLO_CACHE_REDIS_HOSTNAME is not set");let e=parseInt(Deno.env.get("ZUPLO_CACHE_REDIS_PORT")||"6379"),t=await Deno.connect({hostname:r,port:e});return new te(t)}o(Qt,"getRedisClient");function er(r){let e={};return r&&r.split(",").forEach(n=>{let[s,i]=n.trim().split("=");e[s.toLowerCase()]=i?i.trim():!0}),e}o(er,"parseHeaderValue");function tr(r){let e={};for(let[t,n]of r.entries())e[t]=n;return e}o(tr,"objectifyHeaders");async function rr(r){let e=await r.arrayBuffer(),t=new Uint8Array(e),n="";for(let s=0;s<t.length;s++)n+=String.fromCharCode(t[s]);return btoa(n)}o(rr,"serializeResponseBody");function nr(r){let e=atob(r),t=e.length,n=new Uint8Array(t);for(let s=0;s<t;s++)n[s]=e.charCodeAt(s);return n}o(nr,"deserializeResponseBody");var Ae=class{static{o(this,"Cache")}#e;#r;#t;constructor(e="default",t={}){this.#e=e;let n=Deno.env.get("ZUPLO_CACHE_REDIS_HOSTNAME")&&Deno.env.get("ZUPLO_CACHE_REDIS_PORT");this.#r=!n||!$e(Deno.env.get("USE_ZENO_ZONE_CACHE")),this.#t=t.getRedisClient||Qt}#n(e){return`${this.#e}:${e.url}`}async match(e,t){if(this.#r)return;let n=this.#n(e),s=await this.#t();await s.sendCommand(["HELLO",3]);let i=await s.sendCommand(["TTL",n]);if(i!==-2){if(i<2)return;{let l=await s.sendCommand(["HGETALL",n]),a=l.status,d=l.status,c=new Headers(JSON.parse(l.headers));return new Response(nr(l.body),{status:a,statusText:d,headers:c})}}}async put(e,t){if(this.#r)return;let n=1*60*60,s=er(t.headers.get("cache-control")),i=parseInt(s["s-maxage"]),l=parseInt(s["max-age"]),a=s["no-store"],d=s["no-cache"],c=i||l||0;if(c===0&&!a&&!d&&(c=n,t.headers.append("cache-control",`s-maxage=${n}`)),c>0){let p=this.#n(e),g=await this.#t();await g.sendCommand(["HELLO",3]),await g.sendCommand(["HSET",p,"maxage",c,"status",t.status,"statusText",t.statusText,"headers",JSON.stringify(tr(t.headers)),"body",await rr(t)]),await g.sendCommand(["EXPIRE",p,c])}}async delete(e){if(this.#r)return;let t=this.#n(e);if(await(await this.#t()).sendCommand(["DEL",t])!==1)throw new Error("Failed to delete cache entry")}},or=new be;Object.defineProperty(globalThis,"caches",{value:or,writable:!1,enumerable:!0,configurable:!1});var Ge="text/plain; version=0.0.4; charset=utf-8",P=Object.freeze({nameLength:200,helpLength:1024,labelNames:16,labelNameLength:100,labelValueLength:256,buckets:50,defaultMaxSeries:500,expositionBytes:1024*1024}),sr=/^[a-zA-Z_:][a-zA-Z0-9_:]*$/,ir=/^[a-zA-Z_][a-zA-Z0-9_]*$/,Te=24,ar=Object.freeze({inc(){}}),lr=Object.freeze({set(){},inc(){},dec(){}}),cr=Object.freeze({observe(){}}),Ce=class{static{o(this,"ExpositionBudget")}#e=0;#r;constructor(e){this.#r=e}tryCharge(e){return this.#e+e>this.#r?!1:(this.#e+=e,!0)}refund(e){this.#e=Math.max(0,this.#e-e)}},ie=class{static{o(this,"Metric")}name;help;labelNames;series=new Map;#e;#r;#t;#n=!1;exposeZeroWhenEmpty=!0;constructor(e,t){this.name=e.name,this.help=e.help,this.labelNames=Object.freeze([...e.labelNames??[]]),this.#e=e.maxSeries??P.defaultMaxSeries,this.#r=t}child(e){if(e!==void 0&&(typeof e!="object"||e===null))return this.#o("labels must be an object");if(this.labelNames.length===0)return e!==void 0&&pr(e)?this.#o("this metric has no labels"):(this.#t===void 0&&(this.#t=this.#s("",[])),this.#t??this.noopChild());if(e===void 0)return this.#o("labels are required");let t=new Array(this.labelNames.length);for(let i=0;i<this.labelNames.length;i++){let l=e[this.labelNames[i]];if(typeof l!="string")return this.#o(`label "${this.labelNames[i]}" is missing`);if(l.length>P.labelValueLength)return this.#o(`label "${this.labelNames[i]}" is longer than ${P.labelValueLength} characters`);t[i]=l}if(mr(e)!==this.labelNames.length)return this.#o("unexpected label names");let n=ur(t),s=this.series.get(n);return s!==void 0?s.child:this.#s(n,t)??this.noopChild()}reset(){let e=0;for(let{cost:t}of this.series.values())e+=t;this.#r.budget?.refund(e),this.series.clear(),this.#t=void 0}matches(e,t){let n=t.labelNames??[];return e===this.type&&n.length===this.labelNames.length&&n.every((s,i)=>s===this.labelNames[i])}render(e){e.push(`# HELP ${this.name} ${gr(this.help)}`),e.push(`# TYPE ${this.name} ${this.type}`),this.exposeZeroWhenEmpty&&this.labelNames.length===0&&this.series.size===0&&this.child();for(let{labelText:t,child:n}of this.series.values())this.renderSeries(e,t,n)}#s(e,t){if(this.series.size>=this.#e){this.#r.onDrop(this.name,"series_limit");return}let n="";for(let l=0;l<t.length;l++)l>0&&(n+=","),n+=`${this.labelNames[l]}="${hr(t[l])}"`;let s=this.seriesCost(n);if(this.#r.budget!==void 0&&!this.#r.budget.tryCharge(s)){this.#r.onDrop(this.name,"budget");return}let i=this.createChild();return this.series.set(e,{labelText:n,child:i,cost:s}),i}#o(e){return this.#n||(this.#n=!0,m.warn(`Metric ${this.name} expects labels [${this.labelNames.join(", ")}] (${e}); dropping these observations`)),this.noopChild()}},ae=class{static{o(this,"ValueSeries")}value=0;#e;constructor(e){this.#e=e}set(e){typeof e=="number"&&(this.value=e)}inc(e=1){typeof e!="number"||this.#e&&!(e>=0)||(this.value+=e)}dec(e=1){typeof e=="number"&&(this.value-=e)}},le=class extends ie{static{o(this,"ValueMetric")}#e;#r=!1;constructor(e,t){super(e,t),this.#e=e.collect,this.exposeZeroWhenEmpty=e.collect===void 0}render(e){if(this.#e!==void 0){this.reset();try{this.#e((t,n)=>{this.child(n).set(t)})}catch(t){this.#r||(this.#r=!0,m.warn(`Failed to collect metric ${this.name}:`,t))}}super.render(e)}seriesCost(e){return this.name.length+e.length+Te+4}renderSeries(e,t,n){let{value:s}=n;e.push(`${this.name}${ze(t)} ${Q(s)}`)}},ce=class extends le{static{o(this,"Counter")}type="counter";inc(e){this.child().inc(e)}createChild(){return new ae(!0)}noopChild(){return ar}},xe=class extends le{static{o(this,"Gauge")}type="gauge";set(e){this.child().set(e)}inc(e){this.child().inc(e)}dec(e){this.child().dec(e)}createChild(){return new ae(!1)}noopChild(){return lr}},Re=class{static{o(this,"HistogramSeries")}#e;counts;sum=0;count=0;constructor(e){this.#e=e,this.counts=new Float64Array(e.length+1)}observe(e){if(typeof e!="number"||Number.isNaN(e))return;let t=this.#e,n=0;for(;n<t.length&&e>t[n];)n++;this.counts[n]++,this.sum+=e,this.count++}},_e=class extends ie{static{o(this,"Histogram")}type="histogram";#e;#r;#t;constructor(e,t){super(e,t),this.#e=Float64Array.from(e.buckets),this.#r=[...e.buckets.map(Q),"+Inf"],this.#t=this.#r.reduce((n,s)=>n+s.length,0)}observe(e){this.child().observe(e)}matches(e,t){let n=t.buckets??[];return super.matches(e,t)&&n.length===this.#e.length&&n.every((s,i)=>s===this.#e[i])}createChild(){return new Re(this.#e)}noopChild(){return cr}seriesCost(e){let n=this.#r.length*(this.name.length+e.length+16+Te)+this.#t,s=2*(this.name.length+e.length+10+Te);return n+s}renderSeries(e,t,n){let s=n,i=t===""?"{":`{${t},`,l=0;for(let d=0;d<s.counts.length;d++)l+=s.counts[d],e.push(`${this.name}_bucket${i}le="${this.#r[d]}"} ${Q(l)}`);let a=ze(t);e.push(`${this.name}_sum${a} ${Q(s.sum)}`),e.push(`${this.name}_count${a} ${Q(s.count)}`)}},Fe={name:"zeno_metrics_series_dropped_total",help:"Observations dropped because a metric reached its series limit or the /metrics size budget.",labelNames:["metric","reason"],maxSeries:1/0},de=class{static{o(this,"Registry")}#e=new Map;#r=new Map;#t;#n=new Set;#s;constructor(e={}){this.#t=new Ce(e.expositionBytes??P.expositionBytes)}counter(e){return this.#o("counter",e,t=>new ce(e,t),this.#t)}gauge(e){return this.#o("gauge",e,t=>new xe(e,t),this.#t)}histogram(e){return this.#o("histogram",e,t=>new _e(e,t),this.#t)}render(){let e=[],t=[];for(let n of this.#e.values()){t.length=0;try{n.render(t)}catch(s){this.#n.has(n)||(this.#n.add(n),m.warn(`Failed to render metric ${n.name}:`,s));continue}for(let s of t)e.push(s)}return e.push(""),e.join(`
|
|
27
|
-
`)}#o(e,t,n,s){fr(e,t);let i=this.#e.get(t.name);if(i!==void 0){if(!i.matches(e,t))throw new Error(`Metric ${t.name} is already registered with a different type, labels or buckets`);return i}let l=dr(e,t.name);for(let c of l){let p=this.#r.get(c);if(p!==void 0)throw new Error(`Metric ${t.name} would expose ${c}, which ${p.type} ${p.name} already uses`)}let a=2*t.name.length+2*t.help.length+32;if(s!==void 0&&!s.tryCharge(a))throw new Error(`Metric ${t.name} not registered: the /metrics size budget is exhausted`);let d=n({budget:s,onDrop:this.#i});this.#e.set(d.name,d);for(let c of l)this.#r.set(c,d);return d}#i=o((e,t)=>{this.#s??=this.#o("counter",Fe,n=>new ce(Fe,n),void 0),this.#s.child({metric:e,reason:t}).inc()},"#onDrop")};function dr(r,e){return r==="histogram"?[e,`${e}_bucket`,`${e}_sum`,`${e}_count`]:[e]}o(dr,"exposedNames");function fr(r,e){if(typeof e!="object"||e===null)throw new Error("Metric definition must be an object");let{name:t,help:n,labelNames:s,maxSeries:i}=e;if(typeof t!="string"||t.length>P.nameLength||!sr.test(t))throw new Error(`Invalid metric name ${Ue(t)}: use [a-zA-Z_:][a-zA-Z0-9_:]*, at most ${P.nameLength} characters`);if(typeof n!="string"||n.length>P.helpLength)throw new Error(`Metric ${t} needs a help string of at most ${P.helpLength} characters`);if(s!==void 0){if(!Array.isArray(s)||s.length>P.labelNames)throw new Error(`Metric ${t} labelNames must be an array of at most ${P.labelNames} names`);for(let a of s){if(typeof a!="string"||a.length>P.labelNameLength||!ir.test(a)||a.startsWith("__"))throw new Error(`Invalid label name ${Ue(a)} on metric ${t}`);if(r==="histogram"&&a==="le")throw new Error(`Histogram ${t} cannot use the label "le"`)}if(new Set(s).size!==s.length)throw new Error(`Duplicate label names on metric ${t}`)}if(i!==void 0&&(typeof i!="number"||!(i>=0)))throw new Error(`Metric ${t} maxSeries must be a non-negative number`);if(r!=="histogram"){let{collect:a}=e;if(a!==void 0&&typeof a!="function")throw new Error(`Metric ${t} collect must be a function`);return}let{buckets:l}=e;if(!Array.isArray(l)||l.length===0||l.length>P.buckets)throw new Error(`Histogram ${t} needs between 1 and ${P.buckets} buckets`);for(let a=0;a<l.length;a++){if(typeof l[a]!="number"||!Number.isFinite(l[a]))throw new Error(`Histogram ${t} has a non-finite bucket`);if(a>0&&l[a]<=l[a-1])throw new Error(`Histogram ${t} buckets must be strictly ascending`)}}o(fr,"validateOptions");function ur(r){if(r.length===1)return r[0];let e="";for(let t of r)e+=`${t.length}:${t}`;return e}o(ur,"seriesKey");function pr(r){for(let e in r)if(Object.hasOwn(r,e))return!0;return!1}o(pr,"hasOwnKeys");function mr(r){let e=0;for(let t in r)Object.hasOwn(r,t)&&e++;return e}o(mr,"countOwnKeys");function ze(r){return r===""?"":`{${r}}`}o(ze,"braces");function Ue(r){let e=typeof r=="string"?r:typeof r;return e.length>64?`"${e.slice(0,64)}\u2026"`:`"${e}"`}o(Ue,"preview");function Q(r){return Number.isNaN(r)?"NaN":r===1/0?"+Inf":r===-1/0?"-Inf":String(r)}o(Q,"formatNumber");function gr(r){return r.replace(/\\/g,"\\\\").replace(/\n/g,"\\n")}o(gr,"escapeHelp");function hr(r){return r.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n")}o(hr,"escapeLabelValue");var W="ZUPLO_METRICS_PORT",Ee=0;function Ve(r){let{port:e,flag:t,env:n}=r,[s,i]=t!==void 0?["--metrics-port",t]:n!==void 0?[W,n]:[void 0,void 0];if(s===void 0){let d=e+1;return d>65535?(m.warn(`Stats server disabled: the default metrics port is the gateway port + 1, and port ${e} leaves no room for it. Set --metrics-port or ${W} to a free port.`),Ee):d}let l=i.trim(),a=Number(l);if(l===""||!Number.isInteger(a)||a<0||a>65535)throw new Error(`Invalid ${s} "${i}". Use a port between 1 and 65535, or 0 to disable the stats server.`);if(a===e)throw new Error(`Invalid ${s} "${i}": it is the same as the gateway port. Pick a different free port, or 0 to disable the stats server.`);return a}o(Ve,"resolveMetricsPort");import We from"node:v8";import je from"node:process";var yr=[.001,.005,.01,.025,.05,.1,.25,.5,1,2.5],br=100;function Ke(r){r.counter({name:"process_cpu_user_seconds_total",help:"User CPU time spent by the process, in seconds.",collect:o(t=>t(je.cpuUsage().user/1e6),"collect")}),r.counter({name:"process_cpu_system_seconds_total",help:"System CPU time spent by the process, in seconds.",collect:o(t=>t(je.cpuUsage().system/1e6),"collect")}),r.gauge({name:"process_resident_memory_bytes",help:"Resident set size of the process, in bytes.",collect:o(t=>t(Deno.memoryUsage().rss),"collect")});let e=performance.timeOrigin/1e3;r.gauge({name:"process_start_time_seconds",help:"Start time of the process since the Unix epoch, in seconds.",collect:o(t=>t(e),"collect")}),Ar(r),r.gauge({name:"zeno_build_info",help:"Always 1. Labels carry the Deno and V8 versions.",labelNames:["deno_version","v8_version"],collect:o(t=>t(1,{deno_version:Deno.version.deno,v8_version:Deno.version.v8}),"collect")})}o(Ke,"registerProcessMetrics");function Ar(r){let e=o((n,s,i)=>r.gauge({name:n,help:s,collect:o(l=>l(i(We.getHeapStatistics())),"collect")}),"heapStat");e("v8_heap_size_limit_bytes","Maximum size the V8 heap can grow to, in bytes.",n=>n.heap_size_limit),e("v8_heap_total_bytes","Total size of the V8 heap, in bytes.",n=>n.total_heap_size),e("v8_heap_used_bytes","Used size of the V8 heap, in bytes.",n=>n.used_heap_size),e("v8_heap_available_bytes","Bytes the V8 heap can still allocate before reaching its limit.",n=>n.total_available_size),e("v8_heap_physical_bytes","Committed physical memory of the V8 heap, in bytes.",n=>n.total_physical_size),e("v8_malloced_memory_bytes","Memory V8 allocated outside the heap with malloc, in bytes.",n=>n.malloced_memory),e("v8_peak_malloced_memory_bytes","Peak memory V8 allocated outside the heap with malloc, in bytes.",n=>n.peak_malloced_memory),e("v8_native_contexts","Number of live V8 native contexts.",n=>n.number_of_native_contexts),e("v8_detached_contexts","Number of detached V8 contexts. Growth indicates a leak.",n=>n.number_of_detached_contexts),r.gauge({name:"v8_external_memory_bytes",help:"Memory held by JS objects bound to native memory, such as ArrayBuffers, in bytes.",collect:o(n=>n(Deno.memoryUsage().external),"collect")});let t=o((n,s,i)=>r.gauge({name:n,help:s,labelNames:["space"],collect:o(l=>{for(let a of We.getHeapSpaceStatistics())l(i(a),{space:a.space_name})},"collect")}),"heapSpaceStat");t("v8_heap_space_size_bytes","Size of each V8 heap space, in bytes.",n=>n.space_size),t("v8_heap_space_used_bytes","Used size of each V8 heap space, in bytes.",n=>n.space_used_size),t("v8_heap_space_available_bytes","Available size of each V8 heap space, in bytes.",n=>n.space_available_size)}o(Ar,"registerHeapMetrics");function Ze(r){return r.histogram({name:"deno_event_loop_lag_seconds",help:"How late a timer scheduled every 100ms fired, in seconds. Measures event loop blocking.",buckets:yr})}o(Ze,"registerEventLoopLag");function Je(r,e=br){let t,n=!1,s=o(()=>{let i=performance.now()+e,l=setTimeout(()=>{r.observe(Math.max(0,performance.now()-i)/1e3),n||s()},e);Deno.unrefTimer(l),t=l},"schedule");return s(),()=>{n=!0,clearTimeout(t)}}o(Je,"startEventLoopLagSampler");var Tr=[.005,.01,.025,.05,.1,.25,.5,1,2.5,5,10,30,60],we=["1xx","2xx","3xx","4xx","5xx"];function Cr(r){let e=r.gauge({name:"zeno_http_requests_in_flight",help:"Requests the worker module is currently handling."}),t=r.histogram({name:"zeno_http_request_duration_seconds",help:"Time until the worker module returned response headers, in seconds. Excludes body streaming.",labelNames:["code"],buckets:Tr}),n=r.counter({name:"zeno_errors_total",help:"Errors Zeno caught outside the runtime's own error handling.",labelNames:["kind"]});return{inFlight:e,durationByStatusClass:we.map(s=>t.child({code:s})),handlerErrors:n.child({kind:"handler"}),waitUntilErrors:n.child({kind:"wait_until"})}}o(Cr,"createServerMetrics");var xr={inFlight:{inc(){},dec(){}},durationByStatusClass:we.map(()=>({observe(){}})),handlerErrors:{inc(){}},waitUntilErrors:{inc(){}}};function Rr(r){try{Ke(r)}catch(e){m.error("Failed to register process metrics:",e)}try{return Cr(r)}catch(e){return m.error("Failed to register request metrics:",e),xr}}o(Rr,"registerBuiltinMetrics");var fe=class{static{o(this,"WorkerServer")}#e;#r;#t;#n;#s;#o;#i=o(()=>({waitUntil:o(e=>{e.catch(t=>{this.#o.waitUntilErrors.inc(),console.error("Error in waitUntil:",t)})},"waitUntil")}),"#createContext");constructor(e){this.#n=e,this.#s=e.registry??new de,this.#o=Rr(this.#s)}async start(){let{port:e,workerModule:t,env:n}=this.#n,s=this.#o;try{this.#t=Je(Ze(this.#s))}catch(i){m.error("Failed to start the event loop lag sampler:",i)}this.#r=this.#a(this.#n.metricsPort??e+1),this.#e=Deno.serve({port:e,onListen:o(()=>{m.debug(`Server running at http://localhost:${e}`)},"onListen")},async i=>{let l=performance.now();s.inFlight.inc();let a=500;try{let d=await t.default.fetch(i,n,this.#i());return a=d.status,d}catch(d){return s.handlerErrors.inc(),m.error("Error handling request:",d),new Response("Internal Server Error",{status:500})}finally{s.inFlight.dec(),s.durationByStatusClass[_r(a)].observe((performance.now()-l)/1e3)}}),await this.#e.finished,await this.#r?.finished}async stop(){this.#t?.(),await Promise.all([this.#e?.shutdown(),this.#r?.shutdown()])}#a(e){if(e===Ee){m.info("Stats server disabled (metrics port is 0)");return}try{return Deno.serve({port:e,onListen:o(()=>{m.debug(`Stats server running at http://localhost:${e}`)},"onListen")},t=>this.#l(t))}catch(t){m.error(`Could not start the stats server on port ${e}; serving traffic without /metrics. Set --metrics-port or ${W} to a free port, or to 0 to disable it.`,t);return}}#l(e){let{pathname:t}=new URL(e.url);return t==="/metrics"?new Response(this.#s.render(),{headers:{"content-type":Ge}}):t==="/__zuplo/internal_memory_metrics"?new Response(JSON.stringify(Deno.memoryUsage()),{headers:{"content-type":"application/json"}}):new Response("Not Found",{status:404})}};function _r(r){let e=Math.floor(r/100)-1;return e>=0&&e<we.length?e:4}o(_r,"statusClassIndex");import{pathToFileURL as Er}from"node:url";var Xe=N("dist","worker.js");function qe(){if(Deno.build.standalone)return N("..",Xe);let r=Deno.cwd();return N(r,Xe)}o(qe,"getDefaultWorkerPath");function wr(r){return typeof r=="object"&&r!==null&&"default"in r&&typeof r.default=="object"&&"fetch"in r.default&&typeof r.default.fetch=="function"}o(wr,"isWorkerModule");async function Se(r){let e;if(Deno.build.standalone?(m.debug("Loading worker module from: ",r),e=await import(r)):(m.debug("Loading dev worker module from: ",r),e=await import(Er(r).href)),!wr(e))throw new Error("Invalid worker module");return e}o(Se,"importWorkerModule");function Ye(){m.info("Enabling fetch host header override");let r=globalThis.fetch,e=Deno.createHttpClient({allowHost:!0,http2:!1});return globalThis.fetch=(t,n)=>{let s={...n??{},client:e};return r(t,s)},e}o(Ye,"setFetchHostOverride");function Qe(r){if(new.target)throw new TypeError("Cannot create an instance: parse is not a constructor");return new Ne(r).parse()}o(Qe,"parse");var Ne=class{static{o(this,"JsoncParser")}#e=new Set(` \r
|
|
25
|
+
var ft=Object.defineProperty;var o=(r,e)=>ft(r,"name",{value:e,configurable:!0});import{scheduler as dt}from"node:timers/promises";Object.defineProperty(globalThis,"scheduler",{value:dt,writable:!1,enumerable:!0,configurable:!1});function ee(r){let e=0;for(let s of r)e+=s.length;let t=new Uint8Array(e),n=0;for(let s of r)t.set(s,n),n+=s.length;return t}o(ee,"concat");var z=new TextEncoder,ge=new TextDecoder,ut=42,pt=124,mt=40,gt=33,ht=35,bt=36,yt=44,At=45,Tt=58,Ct=37,xt=95,Rt=62,Et=126,_t=43,wt=61,X=z.encode(`\r
|
|
26
|
+
`),St=z.encode("*"),Nt=z.encode("$");function me(r){let e=[St,z.encode(r.length.toString()),X];for(let t of r){let n=t instanceof Uint8Array?t:z.encode(t.toString());e.push(Nt,z.encode(n.byteLength.toString()),X,n,X)}return ee(e)}o(me,"createRequest");async function*vt(r){let e=new Uint8Array;for await(let t of r){e=ee([e,t]);let n;for(;(n=e.indexOf(X[0]))!==-1&&e[n+1]===X[1];)yield e.subarray(0,n),e=e.subarray(n+2)}}o(vt,"readLines");function J(r,e,t=!1){return Array.fromAsync({length:e},()=>q(r,t))}o(J,"readNReplies");function k(r){return ge.decode(r.slice(1))}o(k,"parseLine");function Pt(r){let e=[];for(let t=0;t<r.length;t+=2)e.push(r.slice(t,t+2));return e}o(Pt,"chunk");async function q(r,e=!1){let{value:t}=await r.next();switch(t[0]){case ut:case Rt:{let n=Number(k(t));return n===-1?null:await J(r,n)}case pt:{let n=Number(k(t))*2;return await J(r,n),q(r,e)}case mt:return BigInt(k(t));case gt:{let{value:n}=await r.next();return Promise.reject(ge.decode(n))}case ht:return k(t)==="t";case bt:case wt:return k(t)==="-1"?null:q(r,e);case yt:case Tt:switch(k(t)){case"inf":return 1/0;case"-inf":return-1/0;default:return Number(k(t))}case At:return Promise.reject(k(t));case Ct:{let n=Number(k(t))*2,s=await J(r,n);return Object.fromEntries(Pt(s))}case xt:return null;case Et:return new Set(await J(r,Number(k(t)),e));case _t:return k(t);default:return e?t:ge.decode(t)}}o(q,"readReply");var te=class{static{o(this,"RedisClient")}#e;#r;#t=Promise.resolve();constructor(e){this.#e=e.writable.getWriter(),this.#r=vt(e.readable)}#n(e){return this.#t=this.#t.then(e),this.#t}sendCommand(e,t=!1){return this.#n(()=>(this.#e.write(me(e)),q(this.#r,t)))}writeCommand(e){return this.#n(()=>this.#e.write(me(e)))}async*readReplies(e=!1){for(;;)yield q(this.#r,e)}pipelineCommands(e,t=!1){return this.#n(()=>{let n=ee(e.map(me));return this.#e.write(n),J(this.#r,e.length,t)})}};var R=globalThis.Deno?.build.os==="windows"||globalThis.navigator?.platform?.startsWith("Win")||globalThis.process?.platform?.startsWith("win")||!1;function E(r){if(typeof r!="string")throw new TypeError(`Path must be a string, received "${JSON.stringify(r)}"`)}o(E,"assertPath");function L(r){return r===47}o(L,"isPosixPathSeparator");function T(r){return r===47||r===92}o(T,"isPathSeparator");function M(r){return r>=97&&r<=122||r>=65&&r<=90}o(M,"isWindowsDeviceRoot");function ne(r){if(E(r),r.length===0)return"."}o(ne,"assertArg");function V(r,e,t,n){let s="",i=0,l=-1,a=0,d;for(let c=0;c<=r.length;++c){if(c<r.length)d=r.charCodeAt(c);else{if(n(d))break;d=47}if(n(d)){if(!(l===c-1||a===1))if(l!==c-1&&a===2){if(s.length<2||i!==2||s.charCodeAt(s.length-1)!==46||s.charCodeAt(s.length-2)!==46){if(s.length>2){let m=s.lastIndexOf(t);m===-1?(s="",i=0):(s=s.slice(0,m),i=s.length-1-s.lastIndexOf(t)),l=c,a=0;continue}else if(s.length===2||s.length===1){s="",i=0,l=c,a=0;continue}}e&&(s.length>0?s+=`${t}..`:s="..",i=2)}else s.length>0?s+=t+r.slice(l+1,c):s=r.slice(l+1,c),i=c-l-1;l=c,a=0}else d===46&&a!==-1?++a:a=-1}return s}o(V,"normalizeString");function oe(r){ne(r);let e=L(r.charCodeAt(0)),t=L(r.charCodeAt(r.length-1));return r=V(r,!e,"/",L),r.length===0&&!e&&(r="."),r.length>0&&t&&(r+="/"),e?`/${r}`:r}o(oe,"normalize");function be(...r){if(r.length===0)return".";r.forEach(t=>E(t));let e=r.filter(t=>t.length>0).join("/");return e===""?".":oe(e)}o(be,"join");function se(r){ne(r);let e=r.length,t=0,n,s=!1,i=r.charCodeAt(0);if(e>1)if(T(i))if(s=!0,T(r.charCodeAt(1))){let a=2,d=a;for(;a<e&&!T(r.charCodeAt(a));++a);if(a<e&&a!==d){let c=r.slice(d,a);for(d=a;a<e&&T(r.charCodeAt(a));++a);if(a<e&&a!==d){for(d=a;a<e&&!T(r.charCodeAt(a));++a);if(a===e)return`\\\\${c}\\${r.slice(d)}\\`;a!==d&&(n=`\\\\${c}\\${r.slice(d,a)}`,t=a)}}}else t=1;else M(i)&&r.charCodeAt(1)===58&&(n=r.slice(0,2),t=2,e>2&&T(r.charCodeAt(2))&&(s=!0,t=3));else if(T(i))return"\\";let l;return t<e?l=V(r.slice(t),!s,"\\",T):l="",l.length===0&&!s&&(l="."),l.length>0&&T(r.charCodeAt(e-1))&&(l+="\\"),n===void 0?s?l.length>0?`\\${l}`:"\\":l:s?l.length>0?`${n}\\${l}`:`${n}\\`:n+l}o(se,"normalize");function ye(...r){if(r.forEach(i=>E(i)),r=r.filter(i=>i.length>0),r.length===0)return".";let e=!0,t=0,n=r[0];if(T(n.charCodeAt(0))){++t;let i=n.length;i>1&&T(n.charCodeAt(1))&&(++t,i>2&&(T(n.charCodeAt(2))?++t:e=!1))}let s=r.join("\\");if(e){for(;t<s.length&&T(s.charCodeAt(t));++t);t>=2&&(s=`\\${s.slice(t)}`)}return se(s)}o(ye,"join");function N(...r){return R?ye(...r):be(...r)}o(N,"join");function Xt(r){if(r.length>=255)throw new TypeError("Alphabet too long");let e=new Uint8Array(256);for(let c=0;c<e.length;c++)e[c]=255;for(let c=0;c<r.length;c++){let m=r.charAt(c),g=m.charCodeAt(0);if(e[g]!==255)throw new TypeError(m+" is ambiguous");e[g]=c}let t=r.length,n=r.charAt(0),s=Math.log(t)/Math.log(256),i=Math.log(256)/Math.log(t);function l(c){if(c instanceof Uint8Array||(ArrayBuffer.isView(c)?c=new Uint8Array(c.buffer,c.byteOffset,c.byteLength):Array.isArray(c)&&(c=Uint8Array.from(c))),!(c instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(c.length===0)return"";let m=0,g=0,y=0,C=c.length;for(;y!==C&&c[y]===0;)y++,m++;let _=(C-y)*i+1>>>0,w=new Uint8Array(_);for(;y!==C;){let A=c[y],S=0;for(let O=_-1;(A!==0||S<g)&&O!==-1;O--,S++)A+=256*w[O]>>>0,w[O]=A%t>>>0,A=A/t>>>0;if(A!==0)throw new Error("Non-zero carry");g=S,y++}let v=_-g;for(;v!==_&&w[v]===0;)v++;let x=n.repeat(m);for(;v<_;++v)x+=r.charAt(w[v]);return x}o(l,"encode");function a(c){if(typeof c!="string")throw new TypeError("Expected String");if(c.length===0)return new Uint8Array;let m=0,g=0,y=0;for(;c[m]===n;)g++,m++;let C=(c.length-m)*s+1>>>0,_=new Uint8Array(C);for(;m<c.length;){let A=c.charCodeAt(m);if(A>255)return;let S=e[A];if(S===255)return;let O=0;for(let u=C-1;(S!==0||O<y)&&u!==-1;u--,O++)S+=t*_[u]>>>0,_[u]=S%256>>>0,S=S/256>>>0;if(S!==0)throw new Error("Non-zero carry");y=O,m++}let w=C-y;for(;w!==C&&_[w]===0;)w++;let v=new Uint8Array(g+(C-w)),x=g;for(;w!==C;)v[x++]=_[w++];return v}o(a,"decodeUnsafe");function d(c){let m=a(c);if(m)return m;throw new Error("Non-base"+t+" character")}return o(d,"decode"),{encode:l,decodeUnsafe:a,decode:d}}o(Xt,"base");var Ie=Xt;var qt="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",$e=Ie(qt);import{pathToFileURL as Ue}from"node:url";import Fe from"dotenv";var Ae=class{static{o(this,"ZenoLogger")}prefix="[ZENO]:";logLevel;originalConsole={debug:console.debug,info:console.info,warn:console.warn,error:console.error};constructor(e="info"){this.logLevel=e}debug(...e){(this.shouldLog("debug")||Deno.env.get("ZENO_DEBUG"))&&this.originalConsole.debug(this.prefix,"[DEBUG]",...e)}info(...e){this.shouldLog("info")&&this.originalConsole.info(this.prefix,"[INFO]",...e)}warn(...e){this.shouldLog("warn")&&this.originalConsole.warn(this.prefix,"[WARN]",...e)}error(...e){this.shouldLog("error")&&this.originalConsole.error(this.prefix,"[ERROR]",...e)}shouldLog(e){let t=["debug","info","warn","error"],n=t.indexOf(this.logLevel);return t.indexOf(e)>=n}setLogLevel(e){this.logLevel=e}},p=new Ae;async function Be(r){let e={};for(let[t,n]of Object.entries(Deno.env.toObject()))n!==void 0&&(e[t]=n);try{let t=N(r,".env.zuplo"),n=new TextDecoder("utf-8"),s=await Deno.readFile(Ue(t)),i=n.decode(s),l=Fe.parse(i);for(let[a,d]of Object.entries(l))if(e[a]=d,a==="ZUPLO_SYSTEM_CONFIGURATIONS")try{let c=new TextDecoder().decode($e.decode(d)),m=JSON.parse(c);for(let[g,y]of Object.entries(m))e[g]=String(y)}catch(c){Deno.build.standalone||p.error("Failed to parse ZUPLO_SYSTEM_CONFIGURATIONS from .env.zuplo:",c)}}catch(t){t instanceof Deno.errors.NotFound||p.error("Failed to load .env.zuplo file:",t)}try{let t=N(r,".env"),n=new TextDecoder("utf-8"),s=await Deno.readFile(Ue(t)),i=n.decode(s),l=Fe.parse(i);for(let[a,d]of Object.entries(l))e[a]=d}catch(t){t instanceof Deno.errors.NotFound||p.error("Failed to load .env.zuplo file:",t)}for(let[t,n]of Object.entries(e))n===void 0&&delete e[t];return e.__ZUPLO_IS_MANAGED_DEDICATED="true",e}o(Be,"loadEnvironment");function ie(r){return r?["true","1","yes","y"].includes(r.toLowerCase()):!1}o(ie,"parseEnvBool");var Te=class{static{o(this,"CacheStorage")}#e;constructor(){this.#e=new Map}async open(e){let t=this.#e.get(e);return t||(t=new Ce,this.#e.set(e,t)),t}async has(e){return this.#e.has(e)}async delete(e){throw new Error("caches.delete is not supported")}};async function Yt(){let r=Deno.env.get("ZUPLO_CACHE_REDIS_HOSTNAME");if(r===void 0)throw new Error("ZUPLO_CACHE_REDIS_HOSTNAME is not set");let e=parseInt(Deno.env.get("ZUPLO_CACHE_REDIS_PORT")||"6379"),t=await Deno.connect({hostname:r,port:e});return new te(t)}o(Yt,"getRedisClient");function Qt(r){let e={};return r&&r.split(",").forEach(n=>{let[s,i]=n.trim().split("=");e[s.toLowerCase()]=i?i.trim():!0}),e}o(Qt,"parseHeaderValue");function er(r){let e={};for(let[t,n]of r.entries())e[t]=n;return e}o(er,"objectifyHeaders");async function tr(r){let e=await r.arrayBuffer(),t=new Uint8Array(e),n="";for(let s=0;s<t.length;s++)n+=String.fromCharCode(t[s]);return btoa(n)}o(tr,"serializeResponseBody");function rr(r){let e=atob(r),t=e.length,n=new Uint8Array(t);for(let s=0;s<t;s++)n[s]=e.charCodeAt(s);return n}o(rr,"deserializeResponseBody");var Ce=class{static{o(this,"Cache")}#e;#r;#t;constructor(e="default",t={}){this.#e=e;let n=Deno.env.get("ZUPLO_CACHE_REDIS_HOSTNAME")&&Deno.env.get("ZUPLO_CACHE_REDIS_PORT");this.#r=!n||!ie(Deno.env.get("USE_ZENO_ZONE_CACHE")),this.#t=t.getRedisClient||Yt}#n(e){return`${this.#e}:${e.url}`}async match(e,t){if(this.#r)return;let n=this.#n(e),s=await this.#t();await s.sendCommand(["HELLO",3]);let i=await s.sendCommand(["TTL",n]);if(i!==-2){if(i<2)return;{let l=await s.sendCommand(["HGETALL",n]),a=l.status,d=l.status,c=new Headers(JSON.parse(l.headers));return new Response(rr(l.body),{status:a,statusText:d,headers:c})}}}async put(e,t){if(this.#r)return;let n=1*60*60,s=Qt(t.headers.get("cache-control")),i=parseInt(s["s-maxage"]),l=parseInt(s["max-age"]),a=s["no-store"],d=s["no-cache"],c=i||l||0;if(c===0&&!a&&!d&&(c=n,t.headers.append("cache-control",`s-maxage=${n}`)),c>0){let m=this.#n(e),g=await this.#t();await g.sendCommand(["HELLO",3]),await g.sendCommand(["HSET",m,"maxage",c,"status",t.status,"statusText",t.statusText,"headers",JSON.stringify(er(t.headers)),"body",await tr(t)]),await g.sendCommand(["EXPIRE",m,c])}}async delete(e){if(this.#r)return;let t=this.#n(e);if(await(await this.#t()).sendCommand(["DEL",t])!==1)throw new Error("Failed to delete cache entry")}},nr=new Te;Object.defineProperty(globalThis,"caches",{value:nr,writable:!1,enumerable:!0,configurable:!1});var Ve="text/plain; version=0.0.4; charset=utf-8",P=Object.freeze({nameLength:200,helpLength:1024,labelNames:16,labelNameLength:100,labelValueLength:256,buckets:50,defaultMaxSeries:500,expositionBytes:1024*1024}),or=/^[a-zA-Z_:][a-zA-Z0-9_:]*$/,sr=/^[a-zA-Z_][a-zA-Z0-9_]*$/,xe=24,ir=Object.freeze({inc(){}}),ar=Object.freeze({set(){},inc(){},dec(){}}),lr=Object.freeze({observe(){}}),Re=class{static{o(this,"ExpositionBudget")}#e=0;#r;constructor(e){this.#r=e}tryCharge(e){return this.#e+e>this.#r?!1:(this.#e+=e,!0)}refund(e){this.#e=Math.max(0,this.#e-e)}},ae=class{static{o(this,"Metric")}name;help;labelNames;series=new Map;#e;#r;#t;#n=!1;exposeZeroWhenEmpty=!0;constructor(e,t){this.name=e.name,this.help=e.help,this.labelNames=Object.freeze([...e.labelNames??[]]),this.#e=e.maxSeries??P.defaultMaxSeries,this.#r=t}child(e){if(e!==void 0&&(typeof e!="object"||e===null))return this.#o("labels must be an object");if(this.labelNames.length===0)return e!==void 0&&ur(e)?this.#o("this metric has no labels"):(this.#t===void 0&&(this.#t=this.#s("",[])),this.#t??this.noopChild());if(e===void 0)return this.#o("labels are required");let t=new Array(this.labelNames.length);for(let i=0;i<this.labelNames.length;i++){let l=e[this.labelNames[i]];if(typeof l!="string")return this.#o(`label "${this.labelNames[i]}" is missing`);if(l.length>P.labelValueLength)return this.#o(`label "${this.labelNames[i]}" is longer than ${P.labelValueLength} characters`);t[i]=l}if(pr(e)!==this.labelNames.length)return this.#o("unexpected label names");let n=dr(t),s=this.series.get(n);return s!==void 0?s.child:this.#s(n,t)??this.noopChild()}reset(){let e=0;for(let{cost:t}of this.series.values())e+=t;this.#r.budget?.refund(e),this.series.clear(),this.#t=void 0}matches(e,t){let n=t.labelNames??[];return e===this.type&&n.length===this.labelNames.length&&n.every((s,i)=>s===this.labelNames[i])}render(e){e.push(`# HELP ${this.name} ${mr(this.help)}`),e.push(`# TYPE ${this.name} ${this.type}`),this.exposeZeroWhenEmpty&&this.labelNames.length===0&&this.series.size===0&&this.child();for(let{labelText:t,child:n}of this.series.values())this.renderSeries(e,t,n)}#s(e,t){if(this.series.size>=this.#e){this.#r.onDrop(this.name,"series_limit");return}let n="";for(let l=0;l<t.length;l++)l>0&&(n+=","),n+=`${this.labelNames[l]}="${gr(t[l])}"`;let s=this.seriesCost(n);if(this.#r.budget!==void 0&&!this.#r.budget.tryCharge(s)){this.#r.onDrop(this.name,"budget");return}let i=this.createChild();return this.series.set(e,{labelText:n,child:i,cost:s}),i}#o(e){return this.#n||(this.#n=!0,p.warn(`Metric ${this.name} expects labels [${this.labelNames.join(", ")}] (${e}); dropping these observations`)),this.noopChild()}},le=class{static{o(this,"ValueSeries")}value=0;#e;constructor(e){this.#e=e}set(e){typeof e=="number"&&(this.value=e)}inc(e=1){typeof e!="number"||this.#e&&!(e>=0)||(this.value+=e)}dec(e=1){typeof e=="number"&&(this.value-=e)}},ce=class extends ae{static{o(this,"ValueMetric")}#e;#r=!1;constructor(e,t){super(e,t),this.#e=e.collect,this.exposeZeroWhenEmpty=e.collect===void 0}render(e){if(this.#e!==void 0){this.reset();try{this.#e((t,n)=>{this.child(n).set(t)})}catch(t){this.#r||(this.#r=!0,p.warn(`Failed to collect metric ${this.name}:`,t))}}super.render(e)}seriesCost(e){return this.name.length+e.length+xe+4}renderSeries(e,t,n){let{value:s}=n;e.push(`${this.name}${We(t)} ${Q(s)}`)}},fe=class extends ce{static{o(this,"Counter")}type="counter";inc(e){this.child().inc(e)}createChild(){return new le(!0)}noopChild(){return ir}},Ee=class extends ce{static{o(this,"Gauge")}type="gauge";set(e){this.child().set(e)}inc(e){this.child().inc(e)}dec(e){this.child().dec(e)}createChild(){return new le(!1)}noopChild(){return ar}},_e=class{static{o(this,"HistogramSeries")}#e;counts;sum=0;count=0;constructor(e){this.#e=e,this.counts=new Float64Array(e.length+1)}observe(e){if(typeof e!="number"||Number.isNaN(e))return;let t=this.#e,n=0;for(;n<t.length&&e>t[n];)n++;this.counts[n]++,this.sum+=e,this.count++}},we=class extends ae{static{o(this,"Histogram")}type="histogram";#e;#r;#t;constructor(e,t){super(e,t),this.#e=Float64Array.from(e.buckets),this.#r=[...e.buckets.map(Q),"+Inf"],this.#t=this.#r.reduce((n,s)=>n+s.length,0)}observe(e){this.child().observe(e)}matches(e,t){let n=t.buckets??[];return super.matches(e,t)&&n.length===this.#e.length&&n.every((s,i)=>s===this.#e[i])}createChild(){return new _e(this.#e)}noopChild(){return lr}seriesCost(e){let n=this.#r.length*(this.name.length+e.length+16+xe)+this.#t,s=2*(this.name.length+e.length+10+xe);return n+s}renderSeries(e,t,n){let s=n,i=t===""?"{":`{${t},`,l=0;for(let d=0;d<s.counts.length;d++)l+=s.counts[d],e.push(`${this.name}_bucket${i}le="${this.#r[d]}"} ${Q(l)}`);let a=We(t);e.push(`${this.name}_sum${a} ${Q(s.sum)}`),e.push(`${this.name}_count${a} ${Q(s.count)}`)}},Ge={name:"zeno_metrics_series_dropped_total",help:"Observations dropped because a metric reached its series limit or the /metrics size budget.",labelNames:["metric","reason"],maxSeries:1/0},de=class{static{o(this,"Registry")}#e=new Map;#r=new Map;#t;#n=new Set;#s;constructor(e={}){this.#t=new Re(e.expositionBytes??P.expositionBytes)}counter(e){return this.#o("counter",e,t=>new fe(e,t),this.#t)}gauge(e){return this.#o("gauge",e,t=>new Ee(e,t),this.#t)}histogram(e){return this.#o("histogram",e,t=>new we(e,t),this.#t)}render(){let e=[],t=[];for(let n of this.#e.values()){t.length=0;try{n.render(t)}catch(s){this.#n.has(n)||(this.#n.add(n),p.warn(`Failed to render metric ${n.name}:`,s));continue}for(let s of t)e.push(s)}return e.push(""),e.join(`
|
|
27
|
+
`)}#o(e,t,n,s){fr(e,t);let i=this.#e.get(t.name);if(i!==void 0){if(!i.matches(e,t))throw new Error(`Metric ${t.name} is already registered with a different type, labels or buckets`);return i}let l=cr(e,t.name);for(let c of l){let m=this.#r.get(c);if(m!==void 0)throw new Error(`Metric ${t.name} would expose ${c}, which ${m.type} ${m.name} already uses`)}let a=2*t.name.length+2*t.help.length+32;if(s!==void 0&&!s.tryCharge(a))throw new Error(`Metric ${t.name} not registered: the /metrics size budget is exhausted`);let d=n({budget:s,onDrop:this.#i});this.#e.set(d.name,d);for(let c of l)this.#r.set(c,d);return d}#i=o((e,t)=>{this.#s??=this.#o("counter",Ge,n=>new fe(Ge,n),void 0),this.#s.child({metric:e,reason:t}).inc()},"#onDrop")};function cr(r,e){return r==="histogram"?[e,`${e}_bucket`,`${e}_sum`,`${e}_count`]:[e]}o(cr,"exposedNames");function fr(r,e){if(typeof e!="object"||e===null)throw new Error("Metric definition must be an object");let{name:t,help:n,labelNames:s,maxSeries:i}=e;if(typeof t!="string"||t.length>P.nameLength||!or.test(t))throw new Error(`Invalid metric name ${ze(t)}: use [a-zA-Z_:][a-zA-Z0-9_:]*, at most ${P.nameLength} characters`);if(typeof n!="string"||n.length>P.helpLength)throw new Error(`Metric ${t} needs a help string of at most ${P.helpLength} characters`);if(s!==void 0){if(!Array.isArray(s)||s.length>P.labelNames)throw new Error(`Metric ${t} labelNames must be an array of at most ${P.labelNames} names`);for(let a of s){if(typeof a!="string"||a.length>P.labelNameLength||!sr.test(a)||a.startsWith("__"))throw new Error(`Invalid label name ${ze(a)} on metric ${t}`);if(r==="histogram"&&a==="le")throw new Error(`Histogram ${t} cannot use the label "le"`)}if(new Set(s).size!==s.length)throw new Error(`Duplicate label names on metric ${t}`)}if(i!==void 0&&(typeof i!="number"||!(i>=0)))throw new Error(`Metric ${t} maxSeries must be a non-negative number`);if(r!=="histogram"){let{collect:a}=e;if(a!==void 0&&typeof a!="function")throw new Error(`Metric ${t} collect must be a function`);return}let{buckets:l}=e;if(!Array.isArray(l)||l.length===0||l.length>P.buckets)throw new Error(`Histogram ${t} needs between 1 and ${P.buckets} buckets`);for(let a=0;a<l.length;a++){if(typeof l[a]!="number"||!Number.isFinite(l[a]))throw new Error(`Histogram ${t} has a non-finite bucket`);if(a>0&&l[a]<=l[a-1])throw new Error(`Histogram ${t} buckets must be strictly ascending`)}}o(fr,"validateOptions");function dr(r){if(r.length===1)return r[0];let e="";for(let t of r)e+=`${t.length}:${t}`;return e}o(dr,"seriesKey");function ur(r){for(let e in r)if(Object.hasOwn(r,e))return!0;return!1}o(ur,"hasOwnKeys");function pr(r){let e=0;for(let t in r)Object.hasOwn(r,t)&&e++;return e}o(pr,"countOwnKeys");function We(r){return r===""?"":`{${r}}`}o(We,"braces");function ze(r){let e=typeof r=="string"?r:typeof r;return e.length>64?`"${e.slice(0,64)}\u2026"`:`"${e}"`}o(ze,"preview");function Q(r){return Number.isNaN(r)?"NaN":r===1/0?"+Inf":r===-1/0?"-Inf":String(r)}o(Q,"formatNumber");function mr(r){return r.replace(/\\/g,"\\\\").replace(/\n/g,"\\n")}o(mr,"escapeHelp");function gr(r){return r.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n")}o(gr,"escapeLabelValue");var W="ZUPLO_METRICS_PORT",Se=0;function je(r){let{port:e,flag:t,env:n}=r,[s,i]=t!==void 0?["--metrics-port",t]:n!==void 0?[W,n]:[void 0,void 0];if(s===void 0){let d=e+1;return d>65535?(p.warn(`Stats server disabled: the default metrics port is the gateway port + 1, and port ${e} leaves no room for it. Set --metrics-port or ${W} to a free port.`),Se):d}let l=i.trim(),a=Number(l);if(l===""||!Number.isInteger(a)||a<0||a>65535)throw new Error(`Invalid ${s} "${i}". Use a port between 1 and 65535, or 0 to disable the stats server.`);if(a===e)throw new Error(`Invalid ${s} "${i}": it is the same as the gateway port. Pick a different free port, or 0 to disable the stats server.`);return a}o(je,"resolveMetricsPort");import Ze from"node:v8";import Ke from"node:process";var hr=[.001,.005,.01,.025,.05,.1,.25,.5,1,2.5],br=100;function Je(r){r.counter({name:"process_cpu_user_seconds_total",help:"User CPU time spent by the process, in seconds.",collect:o(t=>t(Ke.cpuUsage().user/1e6),"collect")}),r.counter({name:"process_cpu_system_seconds_total",help:"System CPU time spent by the process, in seconds.",collect:o(t=>t(Ke.cpuUsage().system/1e6),"collect")}),r.gauge({name:"process_resident_memory_bytes",help:"Resident set size of the process, in bytes.",collect:o(t=>t(Deno.memoryUsage().rss),"collect")});let e=performance.timeOrigin/1e3;r.gauge({name:"process_start_time_seconds",help:"Start time of the process since the Unix epoch, in seconds.",collect:o(t=>t(e),"collect")}),yr(r),r.gauge({name:"zeno_build_info",help:"Always 1. Labels carry the Deno and V8 versions.",labelNames:["deno_version","v8_version"],collect:o(t=>t(1,{deno_version:Deno.version.deno,v8_version:Deno.version.v8}),"collect")})}o(Je,"registerProcessMetrics");function yr(r){let e=o((n,s,i)=>r.gauge({name:n,help:s,collect:o(l=>l(i(Ze.getHeapStatistics())),"collect")}),"heapStat");e("v8_heap_size_limit_bytes","Maximum size the V8 heap can grow to, in bytes.",n=>n.heap_size_limit),e("v8_heap_total_bytes","Total size of the V8 heap, in bytes.",n=>n.total_heap_size),e("v8_heap_used_bytes","Used size of the V8 heap, in bytes.",n=>n.used_heap_size),e("v8_heap_available_bytes","Bytes the V8 heap can still allocate before reaching its limit.",n=>n.total_available_size),e("v8_heap_physical_bytes","Committed physical memory of the V8 heap, in bytes.",n=>n.total_physical_size),e("v8_malloced_memory_bytes","Memory V8 allocated outside the heap with malloc, in bytes.",n=>n.malloced_memory),e("v8_peak_malloced_memory_bytes","Peak memory V8 allocated outside the heap with malloc, in bytes.",n=>n.peak_malloced_memory),e("v8_native_contexts","Number of live V8 native contexts.",n=>n.number_of_native_contexts),e("v8_detached_contexts","Number of detached V8 contexts. Growth indicates a leak.",n=>n.number_of_detached_contexts),r.gauge({name:"v8_external_memory_bytes",help:"Memory held by JS objects bound to native memory, such as ArrayBuffers, in bytes.",collect:o(n=>n(Deno.memoryUsage().external),"collect")});let t=o((n,s,i)=>r.gauge({name:n,help:s,labelNames:["space"],collect:o(l=>{for(let a of Ze.getHeapSpaceStatistics())l(i(a),{space:a.space_name})},"collect")}),"heapSpaceStat");t("v8_heap_space_size_bytes","Size of each V8 heap space, in bytes.",n=>n.space_size),t("v8_heap_space_used_bytes","Used size of each V8 heap space, in bytes.",n=>n.space_used_size),t("v8_heap_space_available_bytes","Available size of each V8 heap space, in bytes.",n=>n.space_available_size)}o(yr,"registerHeapMetrics");function Xe(r){return r.histogram({name:"deno_event_loop_lag_seconds",help:"How late a timer scheduled every 100ms fired, in seconds. Measures event loop blocking.",buckets:hr})}o(Xe,"registerEventLoopLag");function qe(r,e=br){let t,n=!1,s=o(()=>{let i=performance.now()+e,l=setTimeout(()=>{r.observe(Math.max(0,performance.now()-i)/1e3),n||s()},e);Deno.unrefTimer(l),t=l},"schedule");return s(),()=>{n=!0,clearTimeout(t)}}o(qe,"startEventLoopLagSampler");var Ar=[.005,.01,.025,.05,.1,.25,.5,1,2.5,5,10,30,60],Ne=["1xx","2xx","3xx","4xx","5xx"];function Tr(r){let e=r.gauge({name:"zeno_http_requests_in_flight",help:"Requests the worker module is currently handling."}),t=r.histogram({name:"zeno_http_request_duration_seconds",help:"Time until the worker module returned response headers, in seconds. Excludes body streaming.",labelNames:["code"],buckets:Ar}),n=r.counter({name:"zeno_errors_total",help:"Errors Zeno caught outside the runtime's own error handling.",labelNames:["kind"]});return{inFlight:e,durationByStatusClass:Ne.map(s=>t.child({code:s})),handlerErrors:n.child({kind:"handler"}),waitUntilErrors:n.child({kind:"wait_until"})}}o(Tr,"createServerMetrics");var Cr={inFlight:{inc(){},dec(){}},durationByStatusClass:Ne.map(()=>({observe(){}})),handlerErrors:{inc(){}},waitUntilErrors:{inc(){}}};function xr(r){try{Je(r)}catch(e){p.error("Failed to register process metrics:",e)}try{return Tr(r)}catch(e){return p.error("Failed to register request metrics:",e),Cr}}o(xr,"registerBuiltinMetrics");var ue=class{static{o(this,"WorkerServer")}#e;#r;#t;#n;#s;#o;#i=o(e=>(e.catch(()=>{}),{__zuploResponseCompleted:e,waitUntil:o(t=>{t.catch(n=>{this.#o.waitUntilErrors.inc(),console.error("Error in waitUntil:",n)})},"waitUntil")}),"#createContext");constructor(e){this.#n=e,this.#s=e.registry??new de,this.#o=xr(this.#s)}async start(){let{port:e,workerModule:t,env:n}=this.#n,s=this.#o;try{this.#t=qe(Xe(this.#s))}catch(i){p.error("Failed to start the event loop lag sampler:",i)}this.#r=this.#a(this.#n.metricsPort??e+1),this.#e=Deno.serve({port:e,onListen:o(()=>{p.debug(`Server running at http://localhost:${e}`)},"onListen")},async(i,l)=>{let a=performance.now();s.inFlight.inc();let d=500;try{let c=await t.default.fetch(i,n,this.#i(l.completed));return d=c.status,c}catch(c){return s.handlerErrors.inc(),p.error("Error handling request:",c),new Response("Internal Server Error",{status:500})}finally{s.inFlight.dec(),s.durationByStatusClass[Rr(d)].observe((performance.now()-a)/1e3)}}),await this.#e.finished,await this.#r?.finished}async stop(){this.#t?.(),await Promise.all([this.#e?.shutdown(),this.#r?.shutdown()])}#a(e){if(e===Se){p.info("Stats server disabled (metrics port is 0)");return}try{return Deno.serve({port:e,onListen:o(()=>{p.debug(`Stats server running at http://localhost:${e}`)},"onListen")},t=>this.#l(t))}catch(t){p.error(`Could not start the stats server on port ${e}; serving traffic without /metrics. Set --metrics-port or ${W} to a free port, or to 0 to disable it.`,t);return}}#l(e){let{pathname:t}=new URL(e.url);return t==="/metrics"?new Response(this.#s.render(),{headers:{"content-type":Ve}}):t==="/__zuplo/internal_memory_metrics"?new Response(JSON.stringify(Deno.memoryUsage()),{headers:{"content-type":"application/json"}}):new Response("Not Found",{status:404})}};function Rr(r){let e=Math.floor(r/100)-1;return e>=0&&e<Ne.length?e:4}o(Rr,"statusClassIndex");import{pathToFileURL as Er}from"node:url";var Ye=N("dist","worker.js");function Qe(){if(Deno.build.standalone)return N("..",Ye);let r=Deno.cwd();return N(r,Ye)}o(Qe,"getDefaultWorkerPath");function _r(r){return typeof r=="object"&&r!==null&&"default"in r&&typeof r.default=="object"&&"fetch"in r.default&&typeof r.default.fetch=="function"}o(_r,"isWorkerModule");async function ve(r){let e;if(Deno.build.standalone?(p.debug("Loading worker module from: ",r),e=await import(r)):(p.debug("Loading dev worker module from: ",r),e=await import(Er(r).href)),!_r(e))throw new Error("Invalid worker module");return e}o(ve,"importWorkerModule");function et(r){if(new.target)throw new TypeError("Cannot create an instance: parse is not a constructor");return new Pe(r).parse()}o(et,"parse");var Pe=class{static{o(this,"JsoncParser")}#e=new Set(` \r
|
|
28
28
|
`);#r=new Set([..."[]{}:,/",...this.#e]);#t;#n;#s;constructor(e){this.#t=`${e}`,this.#n=this.#t.length,this.#s=this.#i()}parse(){let e=this.#o(),t=this.#a(e),{done:n,value:s}=this.#s.next();if(!n)throw new SyntaxError(F(s));return t}#o(){let{done:e,value:t}=this.#s.next();if(e)throw new SyntaxError("Cannot parse JSONC: unexpected end of JSONC input");return t}*#i(){for(let e=0;e<this.#n;e++)if(!this.#e.has(this.#t[e])){if(this.#t[e]==="/"&&this.#t[e+1]==="*"){e+=2;let t=!1;for(;e<this.#n;e++)if(this.#t[e]==="*"&&this.#t[e+1]==="/"){t=!0;break}if(!t)throw new SyntaxError("Cannot parse JSONC: unexpected end of JSONC input");e++;continue}if(this.#t[e]==="/"&&this.#t[e+1]==="/"){for(e+=2;e<this.#n&&!(this.#t[e]===`
|
|
29
|
-
`||this.#t[e]==="\r");e++);continue}switch(this.#t[e]){case"{":yield{type:"BeginObject",position:e};break;case"}":yield{type:"EndObject",position:e};break;case"[":yield{type:"BeginArray",position:e};break;case"]":yield{type:"EndArray",position:e};break;case":":yield{type:"NameSeparator",position:e};break;case",":yield{type:"ValueSeparator",position:e};break;case'"':{let t=e,n=!1;for(e++;e<this.#n&&!(this.#t[e]==='"'&&!n);e++)n=this.#t[e]==="\\"&&!n;yield{type:"String",sourceText:this.#t.substring(t,e+1),position:t};break}default:{let t=e;for(;e<this.#n&&!this.#r.has(this.#t[e]);e++);e--,yield{type:"NullOrTrueOrFalseOrNumber",sourceText:this.#t.substring(t,e+1),position:t}}}}}#a(e){switch(e.type){case"BeginObject":return this.#l();case"BeginArray":return this.#
|
|
29
|
+
`||this.#t[e]==="\r");e++);continue}switch(this.#t[e]){case"{":yield{type:"BeginObject",position:e};break;case"}":yield{type:"EndObject",position:e};break;case"[":yield{type:"BeginArray",position:e};break;case"]":yield{type:"EndArray",position:e};break;case":":yield{type:"NameSeparator",position:e};break;case",":yield{type:"ValueSeparator",position:e};break;case'"':{let t=e,n=!1;for(e++;e<this.#n&&!(this.#t[e]==='"'&&!n);e++)n=this.#t[e]==="\\"&&!n;yield{type:"String",sourceText:this.#t.substring(t,e+1),position:t};break}default:{let t=e;for(;e<this.#n&&!this.#r.has(this.#t[e]);e++);e--,yield{type:"NullOrTrueOrFalseOrNumber",sourceText:this.#t.substring(t,e+1),position:t}}}}}#a(e){switch(e.type){case"BeginObject":return this.#l();case"BeginArray":return this.#f();case"NullOrTrueOrFalseOrNumber":return this.#d(e);case"String":return this.#c(e);default:throw new SyntaxError(F(e))}}#l(){let e={};for(;;){let t=this.#o();if(t.type==="EndObject")return e;if(t.type!=="String")throw new SyntaxError(F(t));let n=this.#c(t),s=this.#o();if(s.type!=="NameSeparator")throw new SyntaxError(F(s));let i=this.#o();Object.defineProperty(e,n,{value:this.#a(i),writable:!0,enumerable:!0,configurable:!0});let l=this.#o();if(l.type==="EndObject")return e;if(l.type!=="ValueSeparator")throw new SyntaxError(F(l))}}#f(){let e=[];for(;;){let t=this.#o();if(t.type==="EndArray")return e;e.push(this.#a(t));let n=this.#o();if(n.type==="EndArray")return e;if(n.type!=="ValueSeparator")throw new SyntaxError(F(n))}}#c(e){let t;try{t=JSON.parse(e.sourceText)}catch{throw new SyntaxError(F(e))}if(typeof t!="string")throw new TypeError(`Parsed value is not a string: ${t}`);return t}#d(e){if(e.sourceText==="null")return null;if(e.sourceText==="true")return!0;if(e.sourceText==="false")return!1;let t;try{t=JSON.parse(e.sourceText)}catch{throw new SyntaxError(F(e))}if(typeof t!="number")throw new TypeError(`Parsed value is not a number: ${t}`);return t}};function F({type:r,sourceText:e,position:t}){let n="";switch(r){case"BeginObject":n="{";break;case"EndObject":n="}";break;case"BeginArray":n="[";break;case"EndArray":n="]";break;case"NameSeparator":n=":";break;case"ValueSeparator":n=",";break;case"NullOrTrueOrFalseOrNumber":case"String":n=30<e.length?`${e.slice(0,30)}...`:e;break}return`Cannot parse JSONC: unexpected token "${n}" in JSONC at position ${t}`}o(F,"buildErrorMessage");var tt="zuplo.jsonc";function rt(r){let e=N(r,tt),t;try{t=Deno.readTextFileSync(e)}catch(i){p.warn(i,`Failed to read ${tt}`);return}let n=et(t);if(n===null)return;let s;return typeof n=="object"&&"managedDedicatedFlags"in n?s=n.managedDedicatedFlags:typeof n=="object"&&"flags"in n&&typeof n.flags=="object"&&n.flags!==null&&"managedDedicatedFlags"in n.flags?s=n.flags.managedDedicatedFlags:typeof n=="object"&&("projectType"in n||"allowHostHeaderOverride"in n)&&(s={useZeno:"projectType"in n&&n.projectType!=="managed-edge",allowFetchHostHeaderOverride:"allowHostHeaderOverride"in n&&n.allowHostHeaderOverride===!0}),s}o(rt,"getManagedDedicatedSettings");var nt="__ZUPLO_MTLS_CLIENT_CERT_NAMES",ot="__ZUPLO_MTLS_CLIENT_CERT_BASE_DIR",st="__ZUPLO_FETCH_HTTP1_ONLY";var wr=globalThis.fetch.bind(globalThis);function Sr(r){return r?[...new Set(r.split(",").map(e=>e.trim()).filter(e=>e.length>0))]:[]}o(Sr,"getMtlsCertNames");var pe=class r{static{o(this,"HttpClientBuilder")}#e={allowHostHeaderOverride:!1,http1Only:!1};#r=!1;#t;static fromZenoConfig(e,t,{loadMtls:n}){let s=new r().allowHostHeaderOverride(!!t?.allowFetchHostHeaderOverride).http1Only(ie(e[st]));if(n){let i=Sr(e[nt]),l=e[ot];s.mtlsCertificates(l&&i.length>0?{basePath:l,certNames:i}:void 0)}return s}allowHostHeaderOverride(e=!0){return this.#e.allowHostHeaderOverride=e,this}http1Only(e=!0){return this.#e.http1Only=e,this}mtlsCertificates(e){return this.#r=!0,this.#t=e,this}clientOptions(){if(this.#e.allowHostHeaderOverride)return{allowHost:!0,http2:!1};if(this.#e.http1Only)return{http2:!1}}async build(){let e=this.clientOptions(),t;e&&(p.info(this.#e.allowHostHeaderOverride?"Enabling fetch host header override":"Forcing HTTP/1.1 for outbound fetch"),t=Deno.createHttpClient(e));let n;return this.#t&&(p.info(`Initializing ${this.#t.certNames.length} mTLS client(s)`),n=await vr(this.#t,e)),new Oe({defaultClient:t,mtlsClients:n,mtlsEnabled:this.#r})}},Oe=class{static{o(this,"ZenoHttpClients")}defaultClient;mtlsClients;#e;#r;constructor({defaultClient:e,mtlsClients:t,mtlsEnabled:n}){this.defaultClient=e,this.mtlsClients=t??{},this.#e=t!==void 0,this.#r=n}install(){if(this.defaultClient&&Nr(this.defaultClient),this.#e){let e={},t={};for(let[n,s]of Object.entries(this.mtlsClients))e[n]=s,t[n]={fetch:o((i,l)=>{let a={...l??{},client:s};return wr(i,a)},"fetch")};globalThis.managedDedicatedMtlsClients=e,globalThis.managedDedicatedMtlsBindings=t}}close(){if(this.#r){for(let e of Object.values(this.mtlsClients))e.close();globalThis.managedDedicatedMtlsClients={},globalThis.managedDedicatedMtlsBindings={}}this.defaultClient&&this.defaultClient.close()}};function Nr(r){let e=globalThis.fetch;globalThis.fetch=(t,n)=>{let s={...n??{},client:r};return e(t,s)}}o(Nr,"wrapGlobalFetch");async function vr({basePath:r,certNames:e},t){let n=await Promise.all(e.map(async i=>{let l=N(r,i,"tls.crt"),a=N(r,i,"tls.key");p.info(`Loading mTLS certificate ${i}`);try{let d=await Deno.readTextFile(l),c=await Deno.readTextFile(a),m=Deno.createHttpClient({...t,cert:d,key:c});return p.info(`Successfully loaded mTLS certificate ${i}`),{certName:i,client:m}}catch(d){return p.warn(`Failed to load mTLS certificate ${i}: ${d}`),null}})),s={};for(let i of n)i!==null&&(s[i.certName]=i.client);return s}o(vr,"loadMtlsClients");var Pr=/^(?:-(?:(?<doubleDash>-)(?<negated>no-)?)?)(?<key>.+?)(?:=(?<value>.+?))?$/s,Or=/[A-Za-z]/,Dr=/-?\d+(\.\d*)?(e-?\d+)?$/,kr=/^(-|--)[^-]/,Lr=/=(?<value>.+)/,Hr=/^--[^=]+$/,Mr=/\W/,Ir=/\S/;function it(r){return Ir.test(r)&&Number.isFinite(Number(r))}o(it,"isNumber");function j(r,e,t,n=!1){e=[...e];let s=e.pop();if(e.forEach(i=>r=r[i]??={}),n){let i=r[s];if(Array.isArray(i)){i.push(t);return}t=i?[i,t]:[t]}r[s]=t}o(j,"setNested");function De(r,e){for(let t of e){let n=r[t];if(!Object.hasOwn(r,t))return!1;r=n}return!0}o(De,"hasNested");function at(r,e,t){let n=r.get(t);if(n===void 0)return!1;for(let s of n)if(e.has(s))return!0;return!1}o(at,"aliasIsBoolean");function lt(r){return r==="true"||r==="false"}o(lt,"isBooleanString");function ke(r){return r!=="false"}o(ke,"parseBooleanString");function ct(r,e){let{"--":t=!1,alias:n={},boolean:s=!1,default:i={},stopEarly:l=!1,string:a=[],collect:d=[],negatable:c=[],unknown:m=o(u=>u,"unknownFn")}=e??{},g=new Map,y=new Set,C=new Set,_=new Set,w=new Set,v=!1;if(n)for(let[u,f]of Object.entries(n)){if(f===void 0)throw new TypeError("Alias value must be defined");let h=Array.isArray(f)?f:[f];g.set(u,new Set(h)),h.forEach(I=>g.set(I,new Set([u,...h.filter(G=>G!==I)])))}if(s)if(typeof s=="boolean")v=s;else{let u=Array.isArray(s)?s:[s];for(let f of u.filter(Boolean))y.add(f),g.get(f)?.forEach(h=>{y.add(h)})}if(a){let u=Array.isArray(a)?a:[a];for(let f of u.filter(Boolean))C.add(f),g.get(f)?.forEach(h=>C.add(h))}if(d){let u=Array.isArray(d)?d:[d];for(let f of u.filter(Boolean))_.add(f),g.get(f)?.forEach(h=>_.add(h))}if(c){let u=Array.isArray(c)?c:[c];for(let f of u.filter(Boolean))w.add(f),g.get(f)?.forEach(h=>w.add(h))}let x={_:[]};function A(u,f,h,I){if(!y.has(u)&&!C.has(u)&&!g.has(u)&&!(v&&Hr.test(h))&&m?.(h,u,f)===!1)return;typeof f=="string"&&!C.has(u)&&(f=it(f)?Number(f):f);let G=I&&_.has(u);j(x,u.split("."),f,G),g.get(u)?.forEach(b=>{j(x,b.split("."),f,G)})}o(A,"setArgument");let S=[],O=r.indexOf("--");O!==-1&&(S=r.slice(O+1),r=r.slice(0,O));e:for(let u=0;u<r.length;u++){let f=r[u],h=f.match(Pr)?.groups;if(h){let{doubleDash:I,negated:G}=h,b=h.key,H=h.value;if(I){if(H){y.has(b)&&(H=ke(H)),A(b,H,f,!0);continue}if(G){if(w.has(b)){A(b,!1,f,!1);continue}b=`no-${b}`}let D=r[u+1];if(D){if(!y.has(b)&&!v&&!D.startsWith("-")&&(!g.has(b)||!at(g,y,b))){H=D,u++,A(b,H,f,!0);continue}if(lt(D)){H=ke(D),u++,A(b,H,f,!0);continue}}H=C.has(b)?"":!0,A(b,H,f,!0);continue}let Le=f.slice(1,-1).split("");for(let[D,B]of Le.entries()){let K=f.slice(D+2);if(K==="-"){A(B,K,f,!0);continue}if(Or.test(B)){let He=Lr.exec(K)?.groups;if(He){A(B,He.value,f,!0);continue e}if(Dr.test(K)){A(B,K,f,!0);continue e}}if(Le[D+1]?.match(Mr)){A(B,f.slice(D+2),f,!0);continue e}A(B,C.has(B)?"":!0,f,!0)}if(b=f.slice(-1),b==="-")continue;let Z=r[u+1];if(Z){if(!kr.test(Z)&&!y.has(b)&&(!g.has(b)||!at(g,y,b))){A(b,Z,f,!0),u++;continue}if(lt(Z)){let D=ke(Z);A(b,D,f,!0),u++;continue}}A(b,C.has(b)?"":!0,f,!0);continue}if(m?.(f)!==!1&&x._.push(C.has("_")||!it(f)?f:Number(f)),l){x._.push(...r.slice(u+1));break}}for(let[u,f]of Object.entries(i)){let h=u.split(".");De(x,h)||(j(x,h,f),g.get(u)?.forEach(I=>j(x,I.split("."),f)))}for(let u of y.keys()){let f=u.split(".");if(!De(x,f)){let h=_.has(u)?[]:!1;j(x,f,h)}}for(let u of C.keys()){let f=u.split(".");!De(x,f)&&_.has(u)&&j(x,f,[])}return t?x["--"]=S:x._.push(...S),x}o(ct,"parseArgs");async function $r(){let r;p.debug("Starting Zeno server...");let e=ct(Deno.args,{boolean:["help"],string:["port","dir","metrics-port"],default:{port:9e3}}),t=Number(e.port);(isNaN(t)||t<1||t>65535)&&(p.error(`Invalid port: ${e.port}. Port must be a number between 1 and 65535.`),Deno.exit(1));let n=t,s;try{s=je({port:n,flag:e["metrics-port"],env:Deno.env.get(W)})}catch(i){p.error(i.message),Deno.exit(1)}try{let i=e.dir?e.dir:Deno.cwd(),l=N(i,"dist","worker.js"),a;Deno.build.standalone?a=await ve(Qe()):a=await ve(l);let d=await Be(i),c=rt(i);r=await pe.fromZenoConfig(d,c,{loadMtls:!0}).build(),r.install(),await new ue({port:n,metricsPort:s,workerModule:a,env:d}).start()}catch(i){p.error("Failed to start server:",i)}finally{r?.close()}}o($r,"main");import.meta.main&&await $r();export{$r as main};
|
|
@@ -37,6 +37,10 @@ This module provides the following parsers:
|
|
|
37
37
|
* [Text body parser](#bodyparsertextoptions)
|
|
38
38
|
* [URL-encoded form body parser](#bodyparserurlencodedoptions)
|
|
39
39
|
|
|
40
|
+
All parsers support automatic inflation of `gzip`, `br` (brotli), `deflate`
|
|
41
|
+
and `zstd` encodings. `zstd` is available in Node.js `^22.15.0` and
|
|
42
|
+
`>=23.8.0`.
|
|
43
|
+
|
|
40
44
|
Other body parsers you might be interested in:
|
|
41
45
|
|
|
42
46
|
- [body](https://www.npmjs.com/package/body#readme)
|
|
@@ -65,6 +69,12 @@ The `bodyParser` object exposes various factories to create middlewares. All
|
|
|
65
69
|
middlewares will populate the `req.body` property with the parsed body when
|
|
66
70
|
the `Content-Type` request header matches the `type` option.
|
|
67
71
|
|
|
72
|
+
**Note** As of v2, `req.body` is left `undefined` when no body is parsed (for
|
|
73
|
+
example when the request has neither `Content-Length` nor `Transfer-Encoding`,
|
|
74
|
+
or when `Content-Type` does not match). In v1, `req.body` was always initialized
|
|
75
|
+
to `{}`. Code that assumes `req.body` is always an object should use optional
|
|
76
|
+
chaining (for example `req.body?.username`) or set a default.
|
|
77
|
+
|
|
68
78
|
The various errors returned by this module are described in the
|
|
69
79
|
[errors section](#errors).
|
|
70
80
|
|
|
@@ -72,8 +82,7 @@ The various errors returned by this module are described in the
|
|
|
72
82
|
|
|
73
83
|
Returns middleware that only parses `json` and only looks at requests where
|
|
74
84
|
the `Content-Type` header matches the `type` option. This parser accepts any
|
|
75
|
-
Unicode encoding of the body
|
|
76
|
-
`br` (brotli) and `deflate` encodings.
|
|
85
|
+
Unicode encoding of the body.
|
|
77
86
|
|
|
78
87
|
A new `body` object containing the parsed data is populated on the `request`
|
|
79
88
|
object after the middleware (i.e. `req.body`).
|
|
@@ -110,7 +119,7 @@ argument. You can find more information on this argument
|
|
|
110
119
|
|
|
111
120
|
##### strict
|
|
112
121
|
|
|
113
|
-
When set to `true`, will only accept arrays and objects; when `false
|
|
122
|
+
When set to `true`, it will only accept arrays and objects; when `false`, it will
|
|
114
123
|
accept anything `JSON.parse` accepts. Defaults to `true`.
|
|
115
124
|
|
|
116
125
|
##### type
|
|
@@ -133,9 +142,7 @@ encoding of the request. The parsing can be aborted by throwing an error.
|
|
|
133
142
|
### bodyParser.raw([options])
|
|
134
143
|
|
|
135
144
|
Returns middleware that parses all bodies as a `Buffer` and only looks at
|
|
136
|
-
requests where the `Content-Type` header matches the `type` option.
|
|
137
|
-
parser supports automatic inflation of `gzip`, `br` (brotli) and `deflate`
|
|
138
|
-
encodings.
|
|
145
|
+
requests where the `Content-Type` header matches the `type` option.
|
|
139
146
|
|
|
140
147
|
A new `body` object containing the parsed data is populated on the `request`
|
|
141
148
|
object after the middleware (i.e. `req.body`). This will be a `Buffer` object
|
|
@@ -181,9 +188,7 @@ encoding of the request. The parsing can be aborted by throwing an error.
|
|
|
181
188
|
### bodyParser.text([options])
|
|
182
189
|
|
|
183
190
|
Returns middleware that parses all bodies as a string and only looks at
|
|
184
|
-
requests where the `Content-Type` header matches the `type` option.
|
|
185
|
-
parser supports automatic inflation of `gzip`, `br` (brotli) and `deflate`
|
|
186
|
-
encodings.
|
|
191
|
+
requests where the `Content-Type` header matches the `type` option.
|
|
187
192
|
|
|
188
193
|
A new `body` string containing the parsed data is populated on the `request`
|
|
189
194
|
object after the middleware (i.e. `req.body`). This will be a string of the
|
|
@@ -234,8 +239,7 @@ encoding of the request. The parsing can be aborted by throwing an error.
|
|
|
234
239
|
|
|
235
240
|
Returns middleware that only parses `urlencoded` bodies and only looks at
|
|
236
241
|
requests where the `Content-Type` header matches the `type` option. This
|
|
237
|
-
parser accepts only UTF-8 and ISO-8859-1 encodings of the body
|
|
238
|
-
automatic inflation of `gzip`, `br` (brotli) and `deflate` encodings.
|
|
242
|
+
parser accepts only UTF-8 and ISO-8859-1 encodings of the body.
|
|
239
243
|
|
|
240
244
|
A new `body` object containing the parsed data is populated on the `request`
|
|
241
245
|
object after the middleware (i.e. `req.body`). This object will contain
|
|
@@ -346,7 +350,7 @@ the entity value that failed parsing.
|
|
|
346
350
|
### entity verify failed
|
|
347
351
|
|
|
348
352
|
This error will occur when the request contained an entity that could not be
|
|
349
|
-
|
|
353
|
+
verified by the defined `verify` option. The `status` property is
|
|
350
354
|
set to `403`, the `type` property is set to `'entity.verify.failed'`, and the
|
|
351
355
|
`body` property is set to the entity value that failed verification.
|
|
352
356
|
|
|
@@ -413,7 +417,7 @@ property is set to the encoding that is unsupported.
|
|
|
413
417
|
|
|
414
418
|
### The input exceeded the depth
|
|
415
419
|
|
|
416
|
-
This error occurs when using `bodyParser.urlencoded` with the `extended` property set to `true` and the input exceeds the configured `depth` option. The `status` property is set to `400`. It is recommended to review the `depth` option and evaluate if it requires a higher value.
|
|
420
|
+
This error occurs when using `bodyParser.urlencoded` with the `extended` property set to `true` and the input exceeds the configured `depth` option. The `status` property is set to `400`. It is recommended to review the `depth` option and evaluate if it requires a higher value. With the default `depth` of `32`, an input with 33 or more levels of nesting gets this error.
|
|
417
421
|
|
|
418
422
|
## Examples
|
|
419
423
|
|
|
@@ -17,7 +17,7 @@ const iconv = require('iconv-lite')
|
|
|
17
17
|
const onFinished = require('on-finished')
|
|
18
18
|
const zlib = require('node:zlib')
|
|
19
19
|
const hasBody = require('type-is').hasBody
|
|
20
|
-
const
|
|
20
|
+
const contentType = require('content-type')
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Module exports.
|
|
@@ -25,6 +25,12 @@ const { getCharset } = require('./utils')
|
|
|
25
25
|
|
|
26
26
|
module.exports = read
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @const
|
|
30
|
+
* whether current node version has zstandard support
|
|
31
|
+
*/
|
|
32
|
+
const hasZstandardSupport = 'createZstdDecompress' in zlib
|
|
33
|
+
|
|
28
34
|
/**
|
|
29
35
|
* Read a request into a buffer and parse.
|
|
30
36
|
*
|
|
@@ -79,38 +85,53 @@ function read (req, res, next, parse, debug, options) {
|
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
let length
|
|
82
|
-
const opts = options
|
|
83
88
|
let stream
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
const verify = options.verify
|
|
91
|
+
|
|
92
|
+
// assert charset is supported before creating the decompression stream, so an
|
|
93
|
+
// unsupported charset cannot leave a decoder piped with no error listener
|
|
94
|
+
if (verify && encoding !== null && !iconv.encodingExists(encoding)) {
|
|
95
|
+
return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
|
|
96
|
+
charset: encoding.toLowerCase(),
|
|
97
|
+
type: 'charset.unsupported'
|
|
98
|
+
}))
|
|
99
|
+
}
|
|
87
100
|
|
|
88
101
|
try {
|
|
102
|
+
const contentEncoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
|
|
103
|
+
|
|
104
|
+
debug('content-encoding "%s"', contentEncoding)
|
|
105
|
+
|
|
106
|
+
if (options.inflate === false && contentEncoding !== 'identity') {
|
|
107
|
+
throw createError(415, 'content encoding unsupported', {
|
|
108
|
+
encoding: contentEncoding,
|
|
109
|
+
type: 'encoding.unsupported'
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
89
113
|
// get the content stream
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
114
|
+
if (contentEncoding === 'identity') {
|
|
115
|
+
length = req.headers['content-length']
|
|
116
|
+
stream = req
|
|
117
|
+
} else {
|
|
118
|
+
stream = createDecompressionStream(contentEncoding, debug)
|
|
119
|
+
req.pipe(stream)
|
|
120
|
+
}
|
|
93
121
|
} catch (err) {
|
|
94
122
|
return next(err)
|
|
95
123
|
}
|
|
96
124
|
|
|
97
125
|
// set raw-body options
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
? null
|
|
101
|
-
:
|
|
102
|
-
|
|
103
|
-
// assert charset is supported
|
|
104
|
-
if (opts.encoding === null && encoding !== null && !iconv.encodingExists(encoding)) {
|
|
105
|
-
return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
|
|
106
|
-
charset: encoding.toLowerCase(),
|
|
107
|
-
type: 'charset.unsupported'
|
|
108
|
-
}))
|
|
126
|
+
const rawBodyOptions = {
|
|
127
|
+
length,
|
|
128
|
+
encoding: verify ? null : encoding,
|
|
129
|
+
limit: options.limit
|
|
109
130
|
}
|
|
110
131
|
|
|
111
132
|
// read body
|
|
112
133
|
debug('read body')
|
|
113
|
-
getBody(stream,
|
|
134
|
+
getBody(stream, rawBodyOptions, function (error, body) {
|
|
114
135
|
if (error) {
|
|
115
136
|
let _error
|
|
116
137
|
|
|
@@ -138,6 +159,17 @@ function read (req, res, next, parse, debug, options) {
|
|
|
138
159
|
return
|
|
139
160
|
}
|
|
140
161
|
|
|
162
|
+
// detach and destroy the decompression stream to
|
|
163
|
+
// avoid decompression errors on the finished stream
|
|
164
|
+
if (stream !== req) {
|
|
165
|
+
req.unpipe(stream)
|
|
166
|
+
stream.on('error', () => {})
|
|
167
|
+
stream.destroy()
|
|
168
|
+
|
|
169
|
+
// consume any remaining bytes so the HTTP request can finish
|
|
170
|
+
req.resume()
|
|
171
|
+
}
|
|
172
|
+
|
|
141
173
|
// verify
|
|
142
174
|
if (verify) {
|
|
143
175
|
try {
|
|
@@ -145,7 +177,7 @@ function read (req, res, next, parse, debug, options) {
|
|
|
145
177
|
verify(req, res, body, encoding)
|
|
146
178
|
} catch (err) {
|
|
147
179
|
next(createError(403, err, {
|
|
148
|
-
body
|
|
180
|
+
body,
|
|
149
181
|
type: err.type || 'entity.verify.failed'
|
|
150
182
|
}))
|
|
151
183
|
return
|
|
@@ -172,38 +204,6 @@ function read (req, res, next, parse, debug, options) {
|
|
|
172
204
|
})
|
|
173
205
|
}
|
|
174
206
|
|
|
175
|
-
/**
|
|
176
|
-
* Get the content stream of the request.
|
|
177
|
-
*
|
|
178
|
-
* @param {Object} req
|
|
179
|
-
* @param {Function} debug
|
|
180
|
-
* @param {boolean} inflate
|
|
181
|
-
* @returns {Object}
|
|
182
|
-
* @private
|
|
183
|
-
*/
|
|
184
|
-
function contentstream (req, debug, inflate) {
|
|
185
|
-
const encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
|
|
186
|
-
const length = req.headers['content-length']
|
|
187
|
-
|
|
188
|
-
debug('content-encoding "%s"', encoding)
|
|
189
|
-
|
|
190
|
-
if (inflate === false && encoding !== 'identity') {
|
|
191
|
-
throw createError(415, 'content encoding unsupported', {
|
|
192
|
-
encoding: encoding,
|
|
193
|
-
type: 'encoding.unsupported'
|
|
194
|
-
})
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (encoding === 'identity') {
|
|
198
|
-
req.length = length
|
|
199
|
-
return req
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const stream = createDecompressionStream(encoding, debug)
|
|
203
|
-
req.pipe(stream)
|
|
204
|
-
return stream
|
|
205
|
-
}
|
|
206
|
-
|
|
207
207
|
/**
|
|
208
208
|
* Create a decompression stream for the given encoding.
|
|
209
209
|
* @param {string} encoding
|
|
@@ -222,12 +222,16 @@ function createDecompressionStream (encoding, debug) {
|
|
|
222
222
|
case 'br':
|
|
223
223
|
debug('brotli decompress body')
|
|
224
224
|
return zlib.createBrotliDecompress()
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
225
|
+
case 'zstd':
|
|
226
|
+
if (hasZstandardSupport) {
|
|
227
|
+
debug('zstd decompress body')
|
|
228
|
+
return zlib.createZstdDecompress()
|
|
229
|
+
}
|
|
230
230
|
}
|
|
231
|
+
throw createError(415, 'unsupported content encoding "' + encoding + '"', {
|
|
232
|
+
encoding,
|
|
233
|
+
type: 'encoding.unsupported'
|
|
234
|
+
})
|
|
231
235
|
}
|
|
232
236
|
|
|
233
237
|
/**
|
|
@@ -245,3 +249,16 @@ function dump (req, callback) {
|
|
|
245
249
|
req.resume()
|
|
246
250
|
}
|
|
247
251
|
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get the charset of a request.
|
|
255
|
+
*
|
|
256
|
+
* @param {Object} req
|
|
257
|
+
* @returns {string | undefined}
|
|
258
|
+
* @private
|
|
259
|
+
*/
|
|
260
|
+
function getCharset (req) {
|
|
261
|
+
const header = req.headers['content-type']
|
|
262
|
+
if (!header) return undefined
|
|
263
|
+
return contentType.parse(header).parameters.charset?.toLowerCase()
|
|
264
|
+
}
|
|
@@ -23,7 +23,7 @@ const { normalizeOptions } = require('../utils')
|
|
|
23
23
|
module.exports = json
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* RegExp to match the first non-
|
|
26
|
+
* RegExp to match the first non-whitespace character in a string.
|
|
27
27
|
*
|
|
28
28
|
* Allowed whitespace is defined in RFC 7159:
|
|
29
29
|
*
|
|
@@ -33,7 +33,7 @@ module.exports = json
|
|
|
33
33
|
* %x0A / ; Line feed or New line
|
|
34
34
|
* %x0D ) ; Carriage return
|
|
35
35
|
*/
|
|
36
|
-
const
|
|
36
|
+
const FIRST_NON_WHITESPACE_REGEXP = /^[\x20\x09\x0a\x0d]*([^\x20\x09\x0a\x0d]|$)/ // eslint-disable-line no-control-regex
|
|
37
37
|
|
|
38
38
|
const JSON_SYNTAX_CHAR = '#'
|
|
39
39
|
const JSON_SYNTAX_REGEXP = /#+/g
|
|
@@ -80,10 +80,12 @@ function createJsonParser (options) {
|
|
|
80
80
|
return {}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
if (body[0] !== '{' && body[0] !== '[') {
|
|
84
|
+
const first = firstNonWhitespaceChar(body)
|
|
85
|
+
if (first !== '{' && first !== '[') {
|
|
86
|
+
debug('strict violation')
|
|
87
|
+
throw createStrictSyntaxError(body, first)
|
|
88
|
+
}
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
try {
|
|
@@ -152,12 +154,10 @@ function createStrictSyntaxError (str, char) {
|
|
|
152
154
|
* @returns {string|undefined}
|
|
153
155
|
* @private
|
|
154
156
|
*/
|
|
155
|
-
function
|
|
156
|
-
const match =
|
|
157
|
+
function firstNonWhitespaceChar (str) {
|
|
158
|
+
const match = FIRST_NON_WHITESPACE_REGEXP.exec(str)
|
|
157
159
|
|
|
158
|
-
return match
|
|
159
|
-
? match[1]
|
|
160
|
-
: undefined
|
|
160
|
+
return match && match[1] ? match[1] : undefined
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/**
|
|
@@ -98,12 +98,12 @@ function createQueryParser (options) {
|
|
|
98
98
|
try {
|
|
99
99
|
return qs.parse(body, {
|
|
100
100
|
allowPrototypes: true,
|
|
101
|
-
arrayLimit
|
|
102
|
-
depth
|
|
103
|
-
charsetSentinel
|
|
104
|
-
interpretNumericEntities
|
|
101
|
+
arrayLimit,
|
|
102
|
+
depth,
|
|
103
|
+
charsetSentinel,
|
|
104
|
+
interpretNumericEntities,
|
|
105
105
|
charset: encoding,
|
|
106
|
-
parameterLimit
|
|
106
|
+
parameterLimit,
|
|
107
107
|
strictDepth: true
|
|
108
108
|
})
|
|
109
109
|
} catch (err) {
|