From 175dd7d1bfad0bac9c21c144bc40a70fc1d110e5 Mon Sep 17 00:00:00 2001 From: Jason Saayman Date: Mon, 18 May 2026 19:46:35 +0200 Subject: [PATCH 1/6] feat: support release stream baselines --- README.md | 29 ++++++- action.yml | 7 +- dist/index.js | 6 +- .../.openspec.yaml | 2 + .../design.md | 55 ++++++++++++ .../proposal.md | 34 ++++++++ .../historical-bundle-size-reporting/spec.md | 49 +++++++++++ .../specs/npm-release-baselines/spec.md | 45 ++++++++++ .../support-release-stream-baselines/tasks.md | 34 ++++++++ src/action.ts | 9 +- src/comment.ts | 20 ++++- src/comparison.ts | 6 +- src/config.ts | 18 ++++ src/npm.ts | 37 +++++++- src/types.ts | 2 + tests/action.test.ts | 86 +++++++++++++++++++ tests/comment.test.ts | 11 +++ tests/comparison.test.ts | 2 +- tests/config.test.ts | 66 +++++++++++++- tests/npm.test.ts | 84 +++++++++++++++++- tests/report.test.ts | 16 ++++ 21 files changed, 600 insertions(+), 18 deletions(-) create mode 100644 openspec/changes/support-release-stream-baselines/.openspec.yaml create mode 100644 openspec/changes/support-release-stream-baselines/design.md create mode 100644 openspec/changes/support-release-stream-baselines/proposal.md create mode 100644 openspec/changes/support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md create mode 100644 openspec/changes/support-release-stream-baselines/specs/npm-release-baselines/spec.md create mode 100644 openspec/changes/support-release-stream-baselines/tasks.md diff --git a/README.md b/README.md index f282526..b531719 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ There is no normal `lib/` workflow. Vite bundles the action directly from TypeSc |------|----------|---------|-------------| | `path` | No | `.` | Path to the local project root containing built artifacts. | | `package-name` | Yes | | npm package name whose latest and previous releases provide baseline archives. | +| `release-stream` | No | | Optional leading major version number, such as `0` or `1`, used to select npm release baselines from that release stream. | | `files` | Yes | | Newline-delimited file paths to compare in the local project and npm release baselines. | | `output-file` | No | `bundle-size-comparison.json` | Path, relative to `path`, where the JSON comparison report will be written. | | `comment-pr` | No | `false` | Post or update a bundle size summary comment on pull requests. | @@ -64,8 +65,8 @@ There is no normal `lib/` workflow. Vite bundles the action directly from TypeSc | `size` | Total current gzip size in bytes for all compared files. | | `comparison-file` | Absolute path to the generated JSON comparison file. | | `total-current-gzip-size` | Total current gzip size in bytes for all compared files. | -| `total-baseline-gzip-size` | Total latest-release baseline gzip size in bytes for all compared files. | -| `total-delta-gzip-size` | Difference in gzip bytes between current and latest-release baseline totals. | +| `total-baseline-gzip-size` | Total selected primary-release baseline gzip size in bytes for all compared files. | +| `total-delta-gzip-size` | Difference in gzip bytes between current and selected primary-release baseline totals. | --- @@ -121,6 +122,26 @@ steps: github-token: ${{ github.token }} ``` +To compare against a maintained major-version stream instead of the npm `latest` stream, set `release-stream` to the leading major version. For example, this compares the local build against the newest stable axios `1.x` release and up to 10 previous stable `1.x` releases, even if npm `latest` points to another major version: + +```yaml +steps: + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build artifacts + run: pnpm run build + + - name: Compare Bundle Size Against Axios 1.x + uses: axios/bundle-size@main + with: + package-name: 'axios' + release-stream: '1' + files: | + dist/axios.js + dist/axios.min.js +``` + When `comment-pr` is enabled outside a pull request event, the action writes the JSON report and skips commenting. Fork pull requests receive a read-only `GITHUB_TOKEN` regardless of the workflow's requested permissions; in that case the action logs a warning, skips commenting, and still produces the JSON report and outputs. The comparison file is JSON: @@ -185,7 +206,7 @@ The comparison file is JSON: } ``` -The latest npm release is the primary baseline for top-level `baseline`, `files`, `totals`, and action outputs. The `history` array includes the latest release plus up to 10 previous stable releases ordered by npm publish time. Previous releases that do not contain every configured file are marked as incomplete instead of failing the action. +When `release-stream` is omitted, the npm `latest` release is the primary baseline for top-level `baseline`, `files`, `totals`, and action outputs. The `history` array includes the latest release plus up to 10 previous stable releases ordered by npm publish time. When `release-stream` is configured, the newest stable release in that major-version stream is the primary baseline and `history` is limited to that stream; the report includes a top-level `releaseStream` number and pull request comments describe the configured stream. Previous releases that do not contain every configured file are marked as incomplete instead of failing the action. Because this repository *is* the action, a workflow inside the same repo can reference it with `./` after preparing local files to compare: @@ -274,7 +295,7 @@ env \ ## Current Behavior -The action fetches npm registry metadata for `package-name`, resolves the `latest` dist-tag plus up to 10 previous stable releases, downloads each selected release tarball, reads regular file entries, strips a single shared top-level directory such as `package/`, and compares the configured paths against local files under `path`. It measures gzip-compressed bytes for each file and writes a JSON report. It does not enforce budgets or target sizes. +The action fetches npm registry metadata for `package-name`, resolves either the `latest` dist-tag plus up to 10 previous stable releases or the configured `release-stream` plus up to 10 previous stable releases in that major version, downloads each selected release tarball, reads regular file entries, strips a single shared top-level directory such as `package/`, and compares the configured paths against local files under `path`. It measures gzip-compressed bytes for each file and writes a JSON report. It does not enforce budgets or target sizes. Suggested next steps: diff --git a/action.yml b/action.yml index 66b783d..7a77e55 100644 --- a/action.yml +++ b/action.yml @@ -14,6 +14,9 @@ inputs: package-name: description: 'npm package name whose latest and previous releases provide baseline archives.' required: true + release-stream: + description: 'Optional leading major version number, such as 0 or 1, used to select npm release baselines from that release stream.' + required: false files: description: 'Newline-delimited file paths to compare in the local project and npm release baselines.' required: true @@ -37,9 +40,9 @@ outputs: total-current-gzip-size: description: 'Total current gzip size in bytes for all compared files.' total-baseline-gzip-size: - description: 'Total latest-release baseline gzip size in bytes for all compared files.' + description: 'Total selected primary-release baseline gzip size in bytes for all compared files.' total-delta-gzip-size: - description: 'Difference in gzip bytes between current and latest-release baseline totals.' + description: 'Difference in gzip bytes between current and selected primary-release baseline totals.' runs: using: 'node24' diff --git a/dist/index.js b/dist/index.js index 4b64e4b..facc7e8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -14,6 +14,6 @@ ${n.count} ${n.noun} ${n.is} pending: ${e.format(t)} `.trim())}}})),Fe=o(((e,t)=>{var n=Symbol.for(`undici.globalDispatcher.1`),{InvalidArgumentError:r}=M(),i=Q();o()===void 0&&a(new i);function a(e){if(!e||typeof e.dispatch!=`function`)throw new r(`Argument agent must implement Agent`);Object.defineProperty(globalThis,n,{value:e,writable:!0,enumerable:!1,configurable:!1})}function o(){return globalThis[n]}t.exports={setGlobalDispatcher:a,getGlobalDispatcher:o}})),Ie=o(((e,t)=>{t.exports=class{#e;constructor(e){if(typeof e!=`object`||!e)throw TypeError(`handler must be an object`);this.#e=e}onConnect(...e){return this.#e.onConnect?.(...e)}onError(...e){return this.#e.onError?.(...e)}onUpgrade(...e){return this.#e.onUpgrade?.(...e)}onResponseStarted(...e){return this.#e.onResponseStarted?.(...e)}onHeaders(...e){return this.#e.onHeaders?.(...e)}onData(...e){return this.#e.onData?.(...e)}onComplete(...e){return this.#e.onComplete?.(...e)}onBodySent(...e){return this.#e.onBodySent?.(...e)}}})),Le=o(((e,t)=>{var n=ce();t.exports=e=>{let t=e?.maxRedirections;return e=>function(r,i){let{maxRedirections:a=t,...o}=r;return a?e(o,new n(e,a,r,i)):e(r,i)}}})),Re=o(((e,t)=>{var n=he();t.exports=e=>t=>function(r,i){return t(r,new n({...r,retryOptions:{...e,...r.retryOptions}},{handler:i,dispatch:t}))}})),ze=o(((e,t)=>{var n=F(),{InvalidArgumentError:r,RequestAbortedError:i}=M(),a=Ie(),o=class extends a{#e=1024*1024;#t=null;#n=!1;#r=!1;#i=0;#a=null;#o=null;constructor({maxSize:e},t){if(super(t),e!=null&&(!Number.isFinite(e)||e<1))throw new r(`maxSize must be a number greater than 0`);this.#e=e??this.#e,this.#o=t}onConnect(e){this.#t=e,this.#o.onConnect(this.#s.bind(this))}#s(e){this.#r=!0,this.#a=e}onHeaders(e,t,r,a){let o=n.parseHeaders(t)[`content-length`];if(o!=null&&o>this.#e)throw new i(`Response size (${o}) larger than maxSize (${this.#e})`);return this.#r?!0:this.#o.onHeaders(e,t,r,a)}onError(e){this.#n||(e=this.#a??e,this.#o.onError(e))}onData(e){return this.#i+=e.length,this.#i>=this.#e&&(this.#n=!0,this.#r?this.#o.onError(this.#a):this.#o.onComplete([])),!0}onComplete(e){if(!this.#n){if(this.#r){this.#o.onError(this.reason);return}this.#o.onComplete(e)}}};function s({maxSize:e}={maxSize:1024*1024}){return t=>function(n,r){let{dumpMaxSize:i=e}=n;return t(n,new o({maxSize:i},r))}}t.exports=s})),Be=o(((e,t)=>{var{isIP:n}=require(`node:net`),{lookup:r}=require(`node:dns`),i=Ie(),{InvalidArgumentError:a,InformationalError:o}=M(),s=2**31-1,c=class{#e=0;#t=0;#n=new Map;dualStack=!0;affinity=null;lookup=null;pick=null;constructor(e){this.#e=e.maxTTL,this.#t=e.maxItems,this.dualStack=e.dualStack,this.affinity=e.affinity,this.lookup=e.lookup??this.#r,this.pick=e.pick??this.#i}get full(){return this.#n.size===this.#t}runLookup(e,t,n){let r=this.#n.get(e.hostname);if(r==null&&this.full){n(null,e.origin);return}let i={affinity:this.affinity,dualStack:this.dualStack,lookup:this.lookup,pick:this.pick,...t.dns,maxTTL:this.#e,maxItems:this.#t};if(r==null)this.lookup(e,i,(t,r)=>{if(t||r==null||r.length===0){n(t??new o(`No DNS entries found`));return}this.setRecords(e,r);let a=this.#n.get(e.hostname),s=this.pick(e,a,i.affinity),c;c=typeof s.port==`number`?`:${s.port}`:e.port===``?``:`:${e.port}`,n(null,`${e.protocol}//${s.family===6?`[${s.address}]`:s.address}${c}`)});else{let a=this.pick(e,r,i.affinity);if(a==null){this.#n.delete(e.hostname),this.runLookup(e,t,n);return}let o;o=typeof a.port==`number`?`:${a.port}`:e.port===``?``:`:${e.port}`,n(null,`${e.protocol}//${a.family===6?`[${a.address}]`:a.address}${o}`)}}#r(e,t,n){r(e.hostname,{all:!0,family:this.dualStack===!1?this.affinity:0,order:`ipv4first`},(e,t)=>{if(e)return n(e);let r=new Map;for(let e of t)r.set(`${e.address}:${e.family}`,e);n(null,r.values())})}#i(e,t,n){let r=null,{records:i,offset:a}=t,o;if(this.dualStack?(n??(a==null||a===s?(t.offset=0,n=4):(t.offset++,n=(t.offset&1)==1?6:4)),o=i[n]!=null&&i[n].ips.length>0?i[n]:i[n===4?6:4]):o=i[n],o==null||o.ips.length===0)return r;o.offset==null||o.offset===s?o.offset=0:o.offset++;let c=o.offset%o.ips.length;return r=o.ips[c]??null,r==null?r:Date.now()-r.timestamp>r.ttl?(o.ips.splice(c,1),this.pick(e,t,n)):r}setRecords(e,t){let n=Date.now(),r={records:{4:null,6:null}};for(let e of t){e.timestamp=n,typeof e.ttl==`number`?e.ttl=Math.min(e.ttl,this.#e):e.ttl=this.#e;let t=r.records[e.family]??{ips:[]};t.ips.push(e),r.records[e.family]=t}this.#n.set(e.hostname,r)}getHandler(e,t){return new l(this,e,t)}},l=class extends i{#e=null;#t=null;#n=null;#r=null;#i=null;constructor(e,{origin:t,handler:n,dispatch:r},i){super(n),this.#i=t,this.#r=n,this.#t={...i},this.#e=e,this.#n=r}onError(e){switch(e.code){case`ETIMEDOUT`:case`ECONNREFUSED`:if(this.#e.dualStack){this.#e.runLookup(this.#i,this.#t,(e,t)=>{if(e)return this.#r.onError(e);let n={...this.#t,origin:t};this.#n(n,this)});return}this.#r.onError(e);return;case`ENOTFOUND`:this.#e.deleteRecord(this.#i);default:this.#r.onError(e);break}}};t.exports=e=>{if(e?.maxTTL!=null&&(typeof e?.maxTTL!=`number`||e?.maxTTL<0))throw new a(`Invalid maxTTL. Must be a positive number`);if(e?.maxItems!=null&&(typeof e?.maxItems!=`number`||e?.maxItems<1))throw new a(`Invalid maxItems. Must be a positive number and greater than zero`);if(e?.affinity!=null&&e?.affinity!==4&&e?.affinity!==6)throw new a(`Invalid affinity. Must be either 4 or 6`);if(e?.dualStack!=null&&typeof e?.dualStack!=`boolean`)throw new a(`Invalid dualStack. Must be a boolean`);if(e?.lookup!=null&&typeof e?.lookup!=`function`)throw new a(`Invalid lookup. Must be a function`);if(e?.pick!=null&&typeof e?.pick!=`function`)throw new a(`Invalid pick. Must be a function`);let t=e?.dualStack??!0,r;r=t?e?.affinity??null:e?.affinity??4;let i=new c({maxTTL:e?.maxTTL??1e4,lookup:e?.lookup??null,pick:e?.pick??null,dualStack:t,affinity:r,maxItems:e?.maxItems??1/0});return e=>function(t,r){let a=t.origin.constructor===URL?t.origin:new URL(t.origin);return n(a.hostname)===0?(i.runLookup(a,t,(n,o)=>{if(n)return r.onError(n);let s=null;s={...t,servername:a.hostname,origin:o,headers:{host:a.hostname,...t.headers}},e(s,i.getHandler({origin:a,dispatch:e,handler:r},t))}),!0):e(t,r)}}})),Ve=o(((e,t)=>{var{kConstruct:n}=j(),{kEnumerableProperty:r}=F(),{iteratorMixin:i,isValidHeaderName:a,isValidHeaderValue:o}=W(),{webidl:s}=U(),c=require(`node:assert`),l=require(`node:util`),u=Symbol(`headers map`),d=Symbol(`headers map sorted`);function f(e){return e===10||e===13||e===9||e===32}function p(e){let t=0,n=e.length;for(;n>t&&f(e.charCodeAt(n-1));)--n;for(;n>t&&f(e.charCodeAt(t));)++t;return t===0&&n===e.length?e:e.substring(t,n)}function m(e,t){if(Array.isArray(t))for(let n=0;n>`,`record`]})}function h(e,t,n){if(n=p(n),!a(t))throw s.errors.invalidArgument({prefix:`Headers.append`,value:t,type:`header name`});if(!o(n))throw s.errors.invalidArgument({prefix:`Headers.append`,value:n,type:`header value`});if(y(e)===`immutable`)throw TypeError(`immutable`);return x(e).append(t,n,!1)}function g(e,t){return e[0]>1),t[s][0]<=l[0]?o=s+1:a=s;if(r!==s){for(i=r;i>o;)t[i]=t[--i];t[o]=l}}if(!n.next().done)throw TypeError(`Unreachable`);return t}else{let e=0;for(let{0:n,1:{value:r}}of this[u])t[e++]=[n,r],c(r!==null);return t.sort(g)}}},v=class e{#e;#t;constructor(e=void 0){s.util.markAsUncloneable(this),e!==n&&(this.#t=new _,this.#e=`none`,e!==void 0&&(e=s.converters.HeadersInit(e,`Headers contructor`,`init`),m(this,e)))}append(t,n){s.brandCheck(this,e),s.argumentLengthCheck(arguments,2,`Headers.append`);let r=`Headers.append`;return t=s.converters.ByteString(t,r,`name`),n=s.converters.ByteString(n,r,`value`),h(this,t,n)}delete(t){if(s.brandCheck(this,e),s.argumentLengthCheck(arguments,1,`Headers.delete`),t=s.converters.ByteString(t,`Headers.delete`,`name`),!a(t))throw s.errors.invalidArgument({prefix:`Headers.delete`,value:t,type:`header name`});if(this.#e===`immutable`)throw TypeError(`immutable`);this.#t.contains(t,!1)&&this.#t.delete(t,!1)}get(t){s.brandCheck(this,e),s.argumentLengthCheck(arguments,1,`Headers.get`);let n=`Headers.get`;if(t=s.converters.ByteString(t,n,`name`),!a(t))throw s.errors.invalidArgument({prefix:n,value:t,type:`header name`});return this.#t.get(t,!1)}has(t){s.brandCheck(this,e),s.argumentLengthCheck(arguments,1,`Headers.has`);let n=`Headers.has`;if(t=s.converters.ByteString(t,n,`name`),!a(t))throw s.errors.invalidArgument({prefix:n,value:t,type:`header name`});return this.#t.contains(t,!1)}set(t,n){s.brandCheck(this,e),s.argumentLengthCheck(arguments,2,`Headers.set`);let r=`Headers.set`;if(t=s.converters.ByteString(t,r,`name`),n=s.converters.ByteString(n,r,`value`),n=p(n),!a(t))throw s.errors.invalidArgument({prefix:r,value:t,type:`header name`});if(!o(n))throw s.errors.invalidArgument({prefix:r,value:n,type:`header value`});if(this.#e===`immutable`)throw TypeError(`immutable`);this.#t.set(t,n,!1)}getSetCookie(){s.brandCheck(this,e);let t=this.#t.cookies;return t?[...t]:[]}get[d](){if(this.#t[d])return this.#t[d];let e=[],t=this.#t.toSortedArray(),n=this.#t.cookies;if(n===null||n.length===1)return this.#t[d]=t;for(let r=0;r>`](e,t,n,r.bind(e)):s.converters[`record`](e,t,n)}throw s.errors.conversionFailed({prefix:`Headers constructor`,argument:`Argument 1`,types:[`sequence>`,`record`]})},t.exports={fill:m,compareHeaderName:g,Headers:v,HeadersList:_,getHeadersGuard:y,setHeadersGuard:b,setHeadersList:S,getHeadersList:x}})),He=o(((e,t)=>{var{Headers:n,HeadersList:r,fill:i,getHeadersGuard:a,setHeadersGuard:o,setHeadersList:s}=Ve(),{extractBody:c,cloneBody:l,mixinBody:u,hasFinalizationRegistry:d,streamRegistry:f,bodyUnusable:p}=oe(),m=F(),h=require(`node:util`),{kEnumerableProperty:g}=m,{isValidReasonPhrase:_,isCancelled:v,isAborted:y,isBlobLike:b,serializeJavascriptValueToJSONString:x,isErrorLike:S,isomorphicEncode:C,environmentSettingsObject:w}=W(),{redirectStatusSet:T,nullBodyStatus:E}=ie(),{kState:D,kHeaders:O}=G(),{webidl:k}=U(),{FormData:A}=q(),{URLSerializer:M}=H(),{kConstruct:N}=j(),P=require(`node:assert`),{types:I}=require(`node:util`),L=new TextEncoder(`utf-8`),R=class e{static error(){return K(V(),`immutable`)}static json(e,t={}){k.argumentLengthCheck(arguments,1,`Response.json`),t!==null&&(t=k.converters.ResponseInit(t));let n=c(L.encode(x(e))),r=K(B({}),`response`);return ae(r,t,{body:n[0],type:`application/json`}),r}static redirect(e,t=302){k.argumentLengthCheck(arguments,1,`Response.redirect`),e=k.converters.USVString(e),t=k.converters[`unsigned short`](t);let n;try{n=new URL(e,w.settingsObject.baseUrl)}catch(t){throw TypeError(`Failed to parse URL from ${e}`,{cause:t})}if(!T.has(t))throw RangeError(`Invalid status code ${t}`);let r=K(B({}),`immutable`);r[D].status=t;let i=C(M(n));return r[D].headersList.append(`location`,i,!0),r}constructor(e=null,t={}){if(k.util.markAsUncloneable(this),e===N)return;e!==null&&(e=k.converters.BodyInit(e)),t=k.converters.ResponseInit(t),this[D]=B({}),this[O]=new n(N),o(this[O],`response`),s(this[O],this[D].headersList);let r=null;if(e!=null){let[t,n]=c(e);r={body:t,type:n}}ae(this,t,r)}get type(){return k.brandCheck(this,e),this[D].type}get url(){k.brandCheck(this,e);let t=this[D].urlList,n=t[t.length-1]??null;return n===null?``:M(n,!0)}get redirected(){return k.brandCheck(this,e),this[D].urlList.length>1}get status(){return k.brandCheck(this,e),this[D].status}get ok(){return k.brandCheck(this,e),this[D].status>=200&&this[D].status<=299}get statusText(){return k.brandCheck(this,e),this[D].statusText}get headers(){return k.brandCheck(this,e),this[O]}get body(){return k.brandCheck(this,e),this[D].body?this[D].body.stream:null}get bodyUsed(){return k.brandCheck(this,e),!!this[D].body&&m.isDisturbed(this[D].body.stream)}clone(){if(k.brandCheck(this,e),p(this))throw k.errors.exception({header:`Response.clone`,message:`Body has already been consumed.`});let t=z(this[D]);return d&&this[D].body?.stream&&f.register(this,new WeakRef(this[D].body.stream)),K(t,a(this[O]))}[h.inspect.custom](e,t){t.depth===null&&(t.depth=2),t.colors??=!0;let n={status:this.status,statusText:this.statusText,headers:this.headers,body:this.body,bodyUsed:this.bodyUsed,ok:this.ok,redirected:this.redirected,type:this.type,url:this.url};return`Response ${h.formatWithOptions(t,n)}`}};u(R),Object.defineProperties(R.prototype,{type:g,url:g,status:g,ok:g,redirected:g,statusText:g,headers:g,clone:g,body:g,bodyUsed:g,[Symbol.toStringTag]:{value:`Response`,configurable:!0}}),Object.defineProperties(R,{json:g,redirect:g,error:g});function z(e){if(e.internalResponse)return ne(z(e.internalResponse),e.type);let t=B({...e,body:null});return e.body!=null&&(t.body=l(t,e.body)),t}function B(e){return{aborted:!1,rangeRequested:!1,timingAllowPassed:!1,requestIncludesCredentials:!1,type:`default`,status:200,timingInfo:null,cacheState:``,statusText:``,...e,headersList:e?.headersList?new r(e?.headersList):new r,urlList:e?.urlList?[...e.urlList]:[]}}function V(e){return B({type:`error`,status:0,error:S(e)?e:Error(e&&String(e)),aborted:e&&e.name===`AbortError`})}function ee(e){return e.type===`error`&&e.status===0}function te(e,t){return t={internalResponse:e,...t},new Proxy(e,{get(e,n){return n in t?t[n]:e[n]},set(e,n,r){return P(!(n in t)),e[n]=r,!0}})}function ne(e,t){if(t===`basic`)return te(e,{type:`basic`,headersList:e.headersList});if(t===`cors`)return te(e,{type:`cors`,headersList:e.headersList});if(t===`opaque`)return te(e,{type:`opaque`,urlList:Object.freeze([]),status:0,statusText:``,body:null});if(t===`opaqueredirect`)return te(e,{type:`opaqueredirect`,status:0,statusText:``,headersList:[],body:null});P(!1)}function re(e,t=null){return P(v(e)),y(e)?V(Object.assign(new DOMException(`The operation was aborted.`,`AbortError`),{cause:t})):V(Object.assign(new DOMException(`Request was cancelled.`),{cause:t}))}function ae(e,t,n){if(t.status!==null&&(t.status<200||t.status>599))throw RangeError(`init["status"] must be in the range of 200 to 599, inclusive.`);if(`statusText`in t&&t.statusText!=null&&!_(String(t.statusText)))throw TypeError(`Invalid statusText`);if(`status`in t&&t.status!=null&&(e[D].status=t.status),`statusText`in t&&t.statusText!=null&&(e[D].statusText=t.statusText),`headers`in t&&t.headers!=null&&i(e[O],t.headers),n){if(E.includes(e.status))throw k.errors.exception({header:`Response constructor`,message:`Invalid response status code ${e.status}`});e[D].body=n.body,n.type!=null&&!e[D].headersList.contains(`content-type`,!0)&&e[D].headersList.append(`content-type`,n.type,!0)}}function K(e,t){let r=new R(N);return r[D]=e,r[O]=new n(N),s(r[O],e.headersList),o(r[O],t),d&&e.body?.stream&&f.register(r,new WeakRef(e.body.stream)),r}k.converters.ReadableStream=k.interfaceConverter(ReadableStream),k.converters.FormData=k.interfaceConverter(A),k.converters.URLSearchParams=k.interfaceConverter(URLSearchParams),k.converters.XMLHttpRequestBodyInit=function(e,t,n){return typeof e==`string`?k.converters.USVString(e,t,n):b(e)?k.converters.Blob(e,t,n,{strict:!1}):ArrayBuffer.isView(e)||I.isArrayBuffer(e)?k.converters.BufferSource(e,t,n):m.isFormDataLike(e)?k.converters.FormData(e,t,n,{strict:!1}):e instanceof URLSearchParams?k.converters.URLSearchParams(e,t,n):k.converters.DOMString(e,t,n)},k.converters.BodyInit=function(e,t,n){return e instanceof ReadableStream?k.converters.ReadableStream(e,t,n):e?.[Symbol.asyncIterator]?e:k.converters.XMLHttpRequestBodyInit(e,t,n)},k.converters.ResponseInit=k.dictionaryConverter([{key:`status`,converter:k.converters[`unsigned short`],defaultValue:()=>200},{key:`statusText`,converter:k.converters.ByteString,defaultValue:()=>``},{key:`headers`,converter:k.converters.HeadersInit}]),t.exports={isNetworkError:ee,makeNetworkError:V,makeResponse:B,makeAppropriateNetworkError:re,filterResponse:ne,Response:R,cloneResponse:z,fromInnerResponse:K}})),Ue=o(((e,t)=>{var{kConnected:n,kSize:r}=j(),i=class{constructor(e){this.value=e}deref(){return this.value[n]===0&&this.value[r]===0?void 0:this.value}},a=class{constructor(e){this.finalizer=e}register(e,t){e.on&&e.on(`disconnect`,()=>{e[n]===0&&e[r]===0&&this.finalizer(t)})}unregister(e){}};t.exports=function(){return process.env.NODE_V8_COVERAGE&&process.version.startsWith(`v18`)?(process._rawDebug(`Using compatibility WeakRef and FinalizationRegistry`),{WeakRef:i,FinalizationRegistry:a}):{WeakRef,FinalizationRegistry}}})),We=o(((e,t)=>{var{extractBody:n,mixinBody:r,cloneBody:i,bodyUnusable:a}=oe(),{Headers:o,fill:s,HeadersList:c,setHeadersGuard:l,getHeadersGuard:u,setHeadersList:d,getHeadersList:f}=Ve(),{FinalizationRegistry:p}=Ue()(),m=F(),h=require(`node:util`),{isValidHTTPToken:g,sameOrigin:_,environmentSettingsObject:v}=W(),{forbiddenMethodsSet:y,corsSafeListedMethodsSet:b,referrerPolicy:x,requestRedirect:S,requestMode:C,requestCredentials:w,requestCache:T,requestDuplex:E}=ie(),{kEnumerableProperty:D,normalizedMethodRecordsBase:O,normalizedMethodRecords:k}=m,{kHeaders:A,kSignal:M,kState:N,kDispatcher:P}=G(),{webidl:I}=U(),{URLSerializer:L}=H(),{kConstruct:R}=j(),z=require(`node:assert`),{getMaxListeners:B,setMaxListeners:V,getEventListeners:ee,defaultMaxListeners:te}=require(`node:events`),ne=Symbol(`abortController`),re=new p(({signal:e,abort:t})=>{e.removeEventListener(`abort`,t)}),ae=new WeakMap;function K(e){return t;function t(){let n=e.deref();if(n!==void 0){re.unregister(t),this.removeEventListener(`abort`,t),n.abort(this.reason);let e=ae.get(n.signal);if(e!==void 0){if(e.size!==0){for(let t of e){let e=t.deref();e!==void 0&&e.abort(this.reason)}e.clear()}ae.delete(n.signal)}}}}var q=!1,J=class e{constructor(t,r={}){if(I.util.markAsUncloneable(this),t===R)return;let i=`Request constructor`;I.argumentLengthCheck(arguments,1,i),t=I.converters.RequestInfo(t,i,`input`),r=I.converters.RequestInit(r,i,`init`);let u=null,p=null,h=v.settingsObject.baseUrl,x=null;if(typeof t==`string`){this[P]=r.dispatcher;let e;try{e=new URL(t,h)}catch(e){throw TypeError(`Failed to parse URL from `+t,{cause:e})}if(e.username||e.password)throw TypeError(`Request cannot be constructed from a URL that includes credentials: `+t);u=Y({urlList:[e]}),p=`cors`}else this[P]=r.dispatcher||t[P],z(t instanceof e),u=t[N],x=t[M];let S=v.settingsObject.origin,C=`client`;if(u.window?.constructor?.name===`EnvironmentSettingsObject`&&_(u.window,S)&&(C=u.window),r.window!=null)throw TypeError(`'window' option '${C}' must be null`);`window`in r&&(C=`no-window`),u=Y({method:u.method,headersList:u.headersList,unsafeRequest:u.unsafeRequest,client:v.settingsObject,window:C,priority:u.priority,origin:u.origin,referrer:u.referrer,referrerPolicy:u.referrerPolicy,mode:u.mode,credentials:u.credentials,cache:u.cache,redirect:u.redirect,integrity:u.integrity,keepalive:u.keepalive,reloadNavigation:u.reloadNavigation,historyNavigation:u.historyNavigation,urlList:[...u.urlList]});let w=Object.keys(r).length!==0;if(w&&(u.mode===`navigate`&&(u.mode=`same-origin`),u.reloadNavigation=!1,u.historyNavigation=!1,u.origin=`client`,u.referrer=`client`,u.referrerPolicy=``,u.url=u.urlList[u.urlList.length-1],u.urlList=[u.url]),r.referrer!==void 0){let e=r.referrer;if(e===``)u.referrer=`no-referrer`;else{let t;try{t=new URL(e,h)}catch(t){throw TypeError(`Referrer "${e}" is not a valid URL.`,{cause:t})}t.protocol===`about:`&&t.hostname===`client`||S&&!_(t,v.settingsObject.baseUrl)?u.referrer=`client`:u.referrer=t}}r.referrerPolicy!==void 0&&(u.referrerPolicy=r.referrerPolicy);let T;if(T=r.mode===void 0?p:r.mode,T===`navigate`)throw I.errors.exception({header:`Request constructor`,message:`invalid request mode navigate.`});if(T!=null&&(u.mode=T),r.credentials!==void 0&&(u.credentials=r.credentials),r.cache!==void 0&&(u.cache=r.cache),u.cache===`only-if-cached`&&u.mode!==`same-origin`)throw TypeError(`'only-if-cached' can be set only with 'same-origin' mode`);if(r.redirect!==void 0&&(u.redirect=r.redirect),r.integrity!=null&&(u.integrity=String(r.integrity)),r.keepalive!==void 0&&(u.keepalive=!!r.keepalive),r.method!==void 0){let e=r.method,t=k[e];if(t!==void 0)u.method=t;else{if(!g(e))throw TypeError(`'${e}' is not a valid HTTP method.`);let t=e.toUpperCase();if(y.has(t))throw TypeError(`'${e}' HTTP method is unsupported.`);e=O[t]??e,u.method=e}!q&&u.method===`patch`&&(process.emitWarning("Using `patch` is highly likely to result in a `405 Method Not Allowed`. `PATCH` is much more likely to succeed.",{code:`UNDICI-FETCH-patch`}),q=!0)}r.signal!==void 0&&(x=r.signal),this[N]=u;let E=new AbortController;if(this[M]=E.signal,x!=null){if(!x||typeof x.aborted!=`boolean`||typeof x.addEventListener!=`function`)throw TypeError(`Failed to construct 'Request': member signal is not of type AbortSignal.`);if(x.aborted)E.abort(x.reason);else{this[ne]=E;let e=K(new WeakRef(E));try{(typeof B==`function`&&B(x)===te||ee(x,`abort`).length>=te)&&V(1500,x)}catch{}m.addAbortListener(x,e),re.register(E,{signal:x,abort:e},e)}}if(this[A]=new o(R),d(this[A],u.headersList),l(this[A],`request`),T===`no-cors`){if(!b.has(u.method))throw TypeError(`'${u.method} is unsupported in no-cors mode.`);l(this[A],`request-no-cors`)}if(w){let e=f(this[A]),t=r.headers===void 0?new c(e):r.headers;if(e.clear(),t instanceof c){for(let{name:n,value:r}of t.rawValues())e.append(n,r,!1);e.cookies=t.cookies}else s(this[A],t)}let D=t instanceof e?t[N].body:null;if((r.body!=null||D!=null)&&(u.method===`GET`||u.method===`HEAD`))throw TypeError(`Request with GET/HEAD method cannot have body.`);let j=null;if(r.body!=null){let[e,t]=n(r.body,u.keepalive);j=e,t&&!f(this[A]).contains(`content-type`,!0)&&this[A].append(`content-type`,t)}let F=j??D;if(F!=null&&F.source==null){if(j!=null&&r.duplex==null)throw TypeError(`RequestInit: duplex option is required when sending a body.`);if(u.mode!==`same-origin`&&u.mode!==`cors`)throw TypeError(`If request is made from ReadableStream, mode should be "same-origin" or "cors"`);u.useCORSPreflightFlag=!0}let L=F;if(j==null&&D!=null){if(a(t))throw TypeError(`Cannot construct a Request with a Request object that has already been used.`);let e=new TransformStream;D.stream.pipeThrough(e),L={source:D.source,length:D.length,stream:e.readable}}this[N].body=L}get method(){return I.brandCheck(this,e),this[N].method}get url(){return I.brandCheck(this,e),L(this[N].url)}get headers(){return I.brandCheck(this,e),this[A]}get destination(){return I.brandCheck(this,e),this[N].destination}get referrer(){return I.brandCheck(this,e),this[N].referrer===`no-referrer`?``:this[N].referrer===`client`?`about:client`:this[N].referrer.toString()}get referrerPolicy(){return I.brandCheck(this,e),this[N].referrerPolicy}get mode(){return I.brandCheck(this,e),this[N].mode}get credentials(){return this[N].credentials}get cache(){return I.brandCheck(this,e),this[N].cache}get redirect(){return I.brandCheck(this,e),this[N].redirect}get integrity(){return I.brandCheck(this,e),this[N].integrity}get keepalive(){return I.brandCheck(this,e),this[N].keepalive}get isReloadNavigation(){return I.brandCheck(this,e),this[N].reloadNavigation}get isHistoryNavigation(){return I.brandCheck(this,e),this[N].historyNavigation}get signal(){return I.brandCheck(this,e),this[M]}get body(){return I.brandCheck(this,e),this[N].body?this[N].body.stream:null}get bodyUsed(){return I.brandCheck(this,e),!!this[N].body&&m.isDisturbed(this[N].body.stream)}get duplex(){return I.brandCheck(this,e),`half`}clone(){if(I.brandCheck(this,e),a(this))throw TypeError(`unusable`);let t=se(this[N]),n=new AbortController;if(this.signal.aborted)n.abort(this.signal.reason);else{let e=ae.get(this.signal);e===void 0&&(e=new Set,ae.set(this.signal,e));let t=new WeakRef(n);e.add(t),m.addAbortListener(n.signal,K(t))}return ce(t,n.signal,u(this[A]))}[h.inspect.custom](e,t){t.depth===null&&(t.depth=2),t.colors??=!0;let n={method:this.method,url:this.url,headers:this.headers,destination:this.destination,referrer:this.referrer,referrerPolicy:this.referrerPolicy,mode:this.mode,credentials:this.credentials,cache:this.cache,redirect:this.redirect,integrity:this.integrity,keepalive:this.keepalive,isReloadNavigation:this.isReloadNavigation,isHistoryNavigation:this.isHistoryNavigation,signal:this.signal};return`Request ${h.formatWithOptions(t,n)}`}};r(J);function Y(e){return{method:e.method??`GET`,localURLsOnly:e.localURLsOnly??!1,unsafeRequest:e.unsafeRequest??!1,body:e.body??null,client:e.client??null,reservedClient:e.reservedClient??null,replacesClientId:e.replacesClientId??``,window:e.window??`client`,keepalive:e.keepalive??!1,serviceWorkers:e.serviceWorkers??`all`,initiator:e.initiator??``,destination:e.destination??``,priority:e.priority??null,origin:e.origin??`client`,policyContainer:e.policyContainer??`client`,referrer:e.referrer??`client`,referrerPolicy:e.referrerPolicy??``,mode:e.mode??`no-cors`,useCORSPreflightFlag:e.useCORSPreflightFlag??!1,credentials:e.credentials??`same-origin`,useCredentials:e.useCredentials??!1,cache:e.cache??`default`,redirect:e.redirect??`follow`,integrity:e.integrity??``,cryptoGraphicsNonceMetadata:e.cryptoGraphicsNonceMetadata??``,parserMetadata:e.parserMetadata??``,reloadNavigation:e.reloadNavigation??!1,historyNavigation:e.historyNavigation??!1,userActivation:e.userActivation??!1,taintedOrigin:e.taintedOrigin??!1,redirectCount:e.redirectCount??0,responseTainting:e.responseTainting??`basic`,preventNoCacheCacheControlHeaderModification:e.preventNoCacheCacheControlHeaderModification??!1,done:e.done??!1,timingAllowFailed:e.timingAllowFailed??!1,urlList:e.urlList,url:e.urlList[0],headersList:e.headersList?new c(e.headersList):new c}}function se(e){let t=Y({...e,body:null});return e.body!=null&&(t.body=i(t,e.body)),t}function ce(e,t,n){let r=new J(R);return r[N]=e,r[M]=t,r[A]=new o(R),d(r[A],e.headersList),l(r[A],n),r}Object.defineProperties(J.prototype,{method:D,url:D,headers:D,redirect:D,clone:D,signal:D,duplex:D,destination:D,body:D,bodyUsed:D,isHistoryNavigation:D,isReloadNavigation:D,keepalive:D,integrity:D,cache:D,credentials:D,attribute:D,referrerPolicy:D,referrer:D,mode:D,[Symbol.toStringTag]:{value:`Request`,configurable:!0}}),I.converters.Request=I.interfaceConverter(J),I.converters.RequestInfo=function(e,t,n){return typeof e==`string`?I.converters.USVString(e,t,n):e instanceof J?I.converters.Request(e,t,n):I.converters.USVString(e,t,n)},I.converters.AbortSignal=I.interfaceConverter(AbortSignal),I.converters.RequestInit=I.dictionaryConverter([{key:`method`,converter:I.converters.ByteString},{key:`headers`,converter:I.converters.HeadersInit},{key:`body`,converter:I.nullableConverter(I.converters.BodyInit)},{key:`referrer`,converter:I.converters.USVString},{key:`referrerPolicy`,converter:I.converters.DOMString,allowedValues:x},{key:`mode`,converter:I.converters.DOMString,allowedValues:C},{key:`credentials`,converter:I.converters.DOMString,allowedValues:w},{key:`cache`,converter:I.converters.DOMString,allowedValues:T},{key:`redirect`,converter:I.converters.DOMString,allowedValues:S},{key:`integrity`,converter:I.converters.DOMString},{key:`keepalive`,converter:I.converters.boolean},{key:`signal`,converter:I.nullableConverter(e=>I.converters.AbortSignal(e,`RequestInit`,`signal`,{strict:!1}))},{key:`window`,converter:I.converters.any},{key:`duplex`,converter:I.converters.DOMString,allowedValues:E},{key:`dispatcher`,converter:I.converters.any}]),t.exports={Request:J,makeRequest:Y,fromInnerRequest:ce,cloneRequest:se}})),Ge=o(((e,t)=>{var{makeNetworkError:n,makeAppropriateNetworkError:r,filterResponse:i,makeResponse:a,fromInnerResponse:o}=He(),{HeadersList:s}=Ve(),{Request:c,cloneRequest:l}=We(),u=require(`node:zlib`),{bytesMatch:d,makePolicyContainer:f,clonePolicyContainer:p,requestBadPort:m,TAOCheck:h,appendRequestOriginHeader:g,responseLocationURL:_,requestCurrentURL:v,setRequestReferrerPolicyOnRedirect:y,tryUpgradeRequestToAPotentiallyTrustworthyURL:b,createOpaqueTimingInfo:x,appendFetchMetadata:S,corsCheck:C,crossOriginResourcePolicyCheck:w,determineRequestsReferrer:T,coarsenedSharedCurrentTime:E,createDeferredPromise:D,isBlobLike:O,sameOrigin:k,isCancelled:A,isAborted:j,isErrorLike:M,fullyReadBody:N,readableStreamClose:P,isomorphicEncode:I,urlIsLocal:L,urlIsHttpHttpsScheme:R,urlHasHttpsScheme:z,clampAndCoarsenConnectionTimingInfo:B,simpleRangeHeaderValue:V,buildContentRange:ee,createInflate:te,extractMimeType:ne}=W(),{kState:re,kDispatcher:ae}=G(),K=require(`node:assert`),{safelyExtractBody:q,extractBody:J}=oe(),{redirectStatusSet:Y,nullBodyStatus:se,safeMethodsSet:ce,requestBodyHeader:le,subresourceSet:X}=ie(),ue=require(`node:events`),{Readable:de,pipeline:fe,finished:pe}=require(`node:stream`),{addAbortListener:Z,isErrored:Q,isReadable:me,bufferToLowerCasedHeaderName:$}=F(),{dataURLProcessor:he,serializeAMimeType:ge,minimizeSupportedMimeType:_e}=H(),{getGlobalDispatcher:ve}=Fe(),{webidl:ye}=U(),{STATUS_CODES:be}=require(`node:http`),xe=[`GET`,`HEAD`],Se=typeof __UNDICI_IS_NODE__<`u`||typeof esbuildDetection<`u`?`node`:`undici`,Ce,we=class extends ue{constructor(e){super(),this.dispatcher=e,this.connection=null,this.dump=!1,this.state=`ongoing`}terminate(e){this.state===`ongoing`&&(this.state=`terminated`,this.connection?.destroy(e),this.emit(`terminated`,e))}abort(e){this.state===`ongoing`&&(this.state=`aborted`,e||=new DOMException(`The operation was aborted.`,`AbortError`),this.serializedAbortReason=e,this.connection?.destroy(e),this.emit(`terminated`,e))}};function Te(e){De(e,`fetch`)}function Ee(e,t=void 0){ye.argumentLengthCheck(arguments,1,`globalThis.fetch`);let n=D(),r;try{r=new c(e,t)}catch(e){return n.reject(e),n.promise}let i=r[re];if(r.signal.aborted)return ke(n,i,null,r.signal.reason),n.promise;i.client.globalObject?.constructor?.name===`ServiceWorkerGlobalScope`&&(i.serviceWorkers=`none`);let a=null,s=!1,l=null;return Z(r.signal,()=>{s=!0,K(l!=null),l.abort(r.signal.reason);let e=a?.deref();ke(n,i,e,r.signal.reason)}),l=Ae({request:i,processResponseEndOfBody:Te,processResponse:e=>{if(!s){if(e.aborted){ke(n,i,a,l.serializedAbortReason);return}if(e.type===`error`){n.reject(TypeError(`fetch failed`,{cause:e.error}));return}a=new WeakRef(o(e,`immutable`)),n.resolve(a.deref()),n=null}},dispatcher:r[ae]}),n.promise}function De(e,t=`other`){if(e.type===`error`&&e.aborted||!e.urlList?.length)return;let n=e.urlList[0],r=e.timingInfo,i=e.cacheState;R(n)&&r!==null&&(e.timingAllowPassed||(r=x({startTime:r.startTime}),i=``),r.endTime=E(),e.timingInfo=r,Oe(r,n.href,t,globalThis,i))}var Oe=performance.markResourceTiming;function ke(e,t,n,r){if(e&&e.reject(r),t.body!=null&&me(t.body?.stream)&&t.body.stream.cancel(r).catch(e=>{if(e.code!==`ERR_INVALID_STATE`)throw e}),n==null)return;let i=n[re];i.body!=null&&me(i.body?.stream)&&i.body.stream.cancel(r).catch(e=>{if(e.code!==`ERR_INVALID_STATE`)throw e})}function Ae({request:e,processRequestBodyChunkLength:t,processRequestEndOfBody:n,processResponse:r,processResponseEndOfBody:i,processResponseConsumeBody:a,useParallelQueue:o=!1,dispatcher:s=ve()}){K(s);let c=null,l=!1;e.client!=null&&(c=e.client.globalObject,l=e.client.crossOriginIsolatedCapability);let u=x({startTime:E(l)}),d={controller:new we(s),request:e,timingInfo:u,processRequestBodyChunkLength:t,processRequestEndOfBody:n,processResponse:r,processResponseConsumeBody:a,processResponseEndOfBody:i,taskDestination:c,crossOriginIsolatedCapability:l};return K(!e.body||e.body.stream),e.window===`client`&&(e.window=e.client?.globalObject?.constructor?.name===`Window`?e.client:`no-window`),e.origin===`client`&&(e.origin=e.client.origin),e.policyContainer===`client`&&(e.client==null?e.policyContainer=f():e.policyContainer=p(e.client.policyContainer)),e.headersList.contains(`accept`,!0)||e.headersList.append(`accept`,`*/*`,!0),e.headersList.contains(`accept-language`,!0)||e.headersList.append(`accept-language`,`*`,!0),e.priority,X.has(e.destination),je(d).catch(e=>{d.controller.terminate(e)}),d.controller}async function je(e,t=!1){let r=e.request,a=null;if(r.localURLsOnly&&!L(v(r))&&(a=n(`local URLs only`)),b(r),m(r)===`blocked`&&(a=n(`bad port`)),r.referrerPolicy===``&&(r.referrerPolicy=r.policyContainer.referrerPolicy),r.referrer!==`no-referrer`&&(r.referrer=T(r)),a===null&&(a=await(async()=>{let t=v(r);return k(t,r.url)&&r.responseTainting===`basic`||t.protocol===`data:`||r.mode===`navigate`||r.mode===`websocket`?(r.responseTainting=`basic`,await Me(e)):r.mode===`same-origin`?n(`request mode cannot be "same-origin"`):r.mode===`no-cors`?r.redirect===`follow`?(r.responseTainting=`opaque`,await Me(e)):n(`redirect mode cannot be "follow" for "no-cors" request`):R(v(r))?(r.responseTainting=`cors`,await Ie(e)):n(`URL scheme must be a HTTP(S) scheme`)})()),t)return a;a.status!==0&&!a.internalResponse&&(r.responseTainting,r.responseTainting===`basic`?a=i(a,`basic`):r.responseTainting===`cors`?a=i(a,`cors`):r.responseTainting===`opaque`?a=i(a,`opaque`):K(!1));let o=a.status===0?a:a.internalResponse;if(o.urlList.length===0&&o.urlList.push(...r.urlList),r.timingAllowFailed||(a.timingAllowPassed=!0),a.type===`opaque`&&o.status===206&&o.rangeRequested&&!r.headers.contains(`range`,!0)&&(a=o=n()),a.status!==0&&(r.method===`HEAD`||r.method===`CONNECT`||se.includes(o.status))&&(o.body=null,e.controller.dump=!0),r.integrity){let t=t=>Pe(e,n(t));if(r.responseTainting===`opaque`||a.body==null){t(a.error);return}await N(a.body,n=>{if(!d(n,r.integrity)){t(`integrity mismatch`);return}a.body=q(n)[0],Pe(e,a)},t)}else Pe(e,a)}function Me(e){if(A(e)&&e.request.redirectCount===0)return Promise.resolve(r(e));let{request:t}=e,{protocol:i}=v(t);switch(i){case`about:`:return Promise.resolve(n(`about scheme is not supported`));case`blob:`:{Ce||=require(`node:buffer`).resolveObjectURL;let e=v(t);if(e.search.length!==0)return Promise.resolve(n(`NetworkError when attempting to fetch resource.`));let r=Ce(e.toString());if(t.method!==`GET`||!O(r))return Promise.resolve(n(`invalid method`));let i=a(),o=r.size,s=I(`${o}`),c=r.type;if(t.headersList.contains(`range`,!0)){i.rangeRequested=!0;let e=V(t.headersList.get(`range`,!0),!0);if(e===`failure`)return Promise.resolve(n(`failed to fetch the data URL`));let{rangeStartValue:a,rangeEndValue:s}=e;if(a===null)a=o-s,s=a+s-1;else{if(a>=o)return Promise.resolve(n(`Range start is greater than the blob's size.`));(s===null||s>=o)&&(s=o-1)}let l=r.slice(a,s,c);i.body=J(l)[0];let u=I(`${l.size}`),d=ee(a,s,o);i.status=206,i.statusText=`Partial Content`,i.headersList.set(`content-length`,u,!0),i.headersList.set(`content-type`,c,!0),i.headersList.set(`content-range`,d,!0)}else{let e=J(r);i.statusText=`OK`,i.body=e[0],i.headersList.set(`content-length`,s,!0),i.headersList.set(`content-type`,c,!0)}return Promise.resolve(i)}case`data:`:{let e=he(v(t));if(e===`failure`)return Promise.resolve(n(`failed to fetch the data URL`));let r=ge(e.mimeType);return Promise.resolve(a({statusText:`OK`,headersList:[[`content-type`,{name:`Content-Type`,value:r}]],body:q(e.body)[0]}))}case`file:`:return Promise.resolve(n(`not implemented... yet...`));case`http:`:case`https:`:return Ie(e).catch(e=>n(e));default:return Promise.resolve(n(`unknown scheme`))}}function Ne(e,t){e.request.done=!0,e.processResponseDone!=null&&queueMicrotask(()=>e.processResponseDone(t))}function Pe(e,t){let n=e.timingInfo,r=()=>{let r=Date.now();e.request.destination===`document`&&(e.controller.fullTimingInfo=n),e.controller.reportTimingSteps=()=>{if(e.request.url.protocol!==`https:`)return;n.endTime=r;let i=t.cacheState,a=t.bodyInfo;t.timingAllowPassed||(n=x(n),i=``);let o=0;if(e.request.mode!==`navigator`||!t.hasCrossOriginRedirects){o=t.status;let e=ne(t.headersList);e!==`failure`&&(a.contentType=_e(e))}e.request.initiatorType!=null&&Oe(n,e.request.url.href,e.request.initiatorType,globalThis,i,a,o)};let i=()=>{e.request.done=!0,e.processResponseEndOfBody!=null&&queueMicrotask(()=>e.processResponseEndOfBody(t)),e.request.initiatorType!=null&&e.controller.reportTimingSteps()};queueMicrotask(()=>i())};e.processResponse!=null&&queueMicrotask(()=>{e.processResponse(t),e.processResponse=null});let i=t.type===`error`?t:t.internalResponse??t;i.body==null?r():pe(i.body.stream,()=>{r()})}async function Ie(e){let t=e.request,r=null,i=null,a=e.timingInfo;if(t.serviceWorkers,r===null){if(t.redirect===`follow`&&(t.serviceWorkers=`none`),i=r=await Re(e),t.responseTainting===`cors`&&C(t,r)===`failure`)return n(`cors failure`);h(t,r)===`failure`&&(t.timingAllowFailed=!0)}return(t.responseTainting===`opaque`||r.type===`opaque`)&&w(t.origin,t.client,t.destination,i)===`blocked`?n(`blocked`):(Y.has(i.status)&&(t.redirect!==`manual`&&e.controller.connection.destroy(void 0,!1),t.redirect===`error`?r=n(`unexpected redirect`):t.redirect===`manual`?r=i:t.redirect===`follow`?r=await Le(e,r):K(!1)),r.timingInfo=a,r)}function Le(e,t){let r=e.request,i=t.internalResponse?t.internalResponse:t,a;try{if(a=_(i,v(r).hash),a==null)return t}catch(e){return Promise.resolve(n(e))}if(!R(a))return Promise.resolve(n(`URL scheme must be a HTTP(S) scheme`));if(r.redirectCount===20)return Promise.resolve(n(`redirect count exceeded`));if(r.redirectCount+=1,r.mode===`cors`&&(a.username||a.password)&&!k(r,a))return Promise.resolve(n(`cross origin not allowed for request mode "cors"`));if(r.responseTainting===`cors`&&(a.username||a.password))return Promise.resolve(n(`URL cannot contain credentials for request mode "cors"`));if(i.status!==303&&r.body!=null&&r.body.source==null)return Promise.resolve(n());if([301,302].includes(i.status)&&r.method===`POST`||i.status===303&&!xe.includes(r.method)){r.method=`GET`,r.body=null;for(let e of le)r.headersList.delete(e)}k(v(r),a)||(r.headersList.delete(`authorization`,!0),r.headersList.delete(`proxy-authorization`,!0),r.headersList.delete(`cookie`,!0),r.headersList.delete(`host`,!0)),r.body!=null&&(K(r.body.source!=null),r.body=q(r.body.source)[0]);let o=e.timingInfo;return o.redirectEndTime=o.postRedirectStartTime=E(e.crossOriginIsolatedCapability),o.redirectStartTime===0&&(o.redirectStartTime=o.startTime),r.urlList.push(a),y(r,i),je(e,!0)}async function Re(e,t=!1,i=!1){let a=e.request,o=null,s=null,c=null;a.window===`no-window`&&a.redirect===`error`?(o=e,s=a):(s=l(a),o={...e},o.request=s);let u=a.credentials===`include`||a.credentials===`same-origin`&&a.responseTainting===`basic`,d=s.body?s.body.length:null,f=null;if(s.body==null&&[`POST`,`PUT`].includes(s.method)&&(f=`0`),d!=null&&(f=I(`${d}`)),f!=null&&s.headersList.append(`content-length`,f,!0),d!=null&&s.keepalive,s.referrer instanceof URL&&s.headersList.append(`referer`,I(s.referrer.href),!0),g(s),S(s),s.headersList.contains(`user-agent`,!0)||s.headersList.append(`user-agent`,Se),s.cache===`default`&&(s.headersList.contains(`if-modified-since`,!0)||s.headersList.contains(`if-none-match`,!0)||s.headersList.contains(`if-unmodified-since`,!0)||s.headersList.contains(`if-match`,!0)||s.headersList.contains(`if-range`,!0))&&(s.cache=`no-store`),s.cache===`no-cache`&&!s.preventNoCacheCacheControlHeaderModification&&!s.headersList.contains(`cache-control`,!0)&&s.headersList.append(`cache-control`,`max-age=0`,!0),(s.cache===`no-store`||s.cache===`reload`)&&(s.headersList.contains(`pragma`,!0)||s.headersList.append(`pragma`,`no-cache`,!0),s.headersList.contains(`cache-control`,!0)||s.headersList.append(`cache-control`,`no-cache`,!0)),s.headersList.contains(`range`,!0)&&s.headersList.append(`accept-encoding`,`identity`,!0),s.headersList.contains(`accept-encoding`,!0)||(z(v(s))?s.headersList.append(`accept-encoding`,`br, gzip, deflate`,!0):s.headersList.append(`accept-encoding`,`gzip, deflate`,!0)),s.headersList.delete(`host`,!0),s.cache=`no-store`,s.cache!==`no-store`&&s.cache,c==null){if(s.cache===`only-if-cached`)return n(`only if cached`);let e=await ze(o,u,i);!ce.has(s.method)&&e.status>=200&&e.status,c??=e}if(c.urlList=[...s.urlList],s.headersList.contains(`range`,!0)&&(c.rangeRequested=!0),c.requestIncludesCredentials=u,c.status===407)return a.window===`no-window`?n():A(e)?r(e):n(`proxy authentication required`);if(c.status===421&&!i&&(a.body==null||a.body.source!=null)){if(A(e))return r(e);e.controller.connection.destroy(),c=await Re(e,t,!0)}return c}async function ze(e,t=!1,i=!1){K(!e.controller.connection||e.controller.connection.destroyed),e.controller.connection={abort:null,destroyed:!1,destroy(e,t=!0){this.destroyed||(this.destroyed=!0,t&&this.abort?.(e??new DOMException(`The operation was aborted.`,`AbortError`)))}};let o=e.request,c=null,l=e.timingInfo;o.cache=`no-store`,o.mode;let d=null;if(o.body==null&&e.processRequestEndOfBody)queueMicrotask(()=>e.processRequestEndOfBody());else if(o.body!=null){let t=async function*(t){A(e)||(yield t,e.processRequestBodyChunkLength?.(t.byteLength))},n=()=>{A(e)||e.processRequestEndOfBody&&e.processRequestEndOfBody()},r=t=>{A(e)||(t.name===`AbortError`?e.controller.abort():e.controller.terminate(t))};d=(async function*(){try{for await(let e of o.body.stream)yield*t(e);n()}catch(e){r(e)}})()}try{let{body:t,status:n,statusText:r,headersList:i,socket:o}=await g({body:d});if(o)c=a({status:n,statusText:r,headersList:i,socket:o});else{let o=t[Symbol.asyncIterator]();e.controller.next=()=>o.next(),c=a({status:n,statusText:r,headersList:i})}}catch(t){return t.name===`AbortError`?(e.controller.connection.destroy(),r(e,t)):n(t)}let f=async()=>{await e.controller.resume()},p=t=>{A(e)||e.controller.abort(t)},m=new ReadableStream({async start(t){e.controller.controller=t},async pull(e){await f(e)},async cancel(e){await p(e)},type:`bytes`});c.body={stream:m,source:null,length:null},e.controller.onAborted=h,e.controller.on(`terminated`,h),e.controller.resume=async()=>{for(;;){let t,n;try{let{done:n,value:r}=await e.controller.next();if(j(e))break;t=n?void 0:r}catch(r){e.controller.ended&&!l.encodedBodySize?t=void 0:(t=r,n=!0)}if(t===void 0){P(e.controller.controller),Ne(e,c);return}if(l.decodedBodySize+=t?.byteLength??0,n){e.controller.terminate(t);return}let r=new Uint8Array(t);if(r.byteLength&&e.controller.controller.enqueue(r),Q(m)){e.controller.terminate();return}if(e.controller.controller.desiredSize<=0)return}};function h(t){j(e)?(c.aborted=!0,me(m)&&e.controller.controller.error(e.controller.serializedAbortReason)):me(m)&&e.controller.controller.error(TypeError(`terminated`,{cause:M(t)?t:void 0})),e.controller.connection.destroy()}return c;function g({body:t}){let n=v(o),r=e.controller.dispatcher;return new Promise((i,a)=>r.dispatch({path:n.pathname+n.search,origin:n.origin,method:o.method,body:r.isMockActive?o.body&&(o.body.source||o.body.stream):t,headers:o.headersList.entries,maxRedirections:0,upgrade:o.mode===`websocket`?`websocket`:void 0},{body:null,abort:null,onConnect(t){let{connection:n}=e.controller;l.finalConnectionTimingInfo=B(void 0,l.postRedirectStartTime,e.crossOriginIsolatedCapability),n.destroyed?t(new DOMException(`The operation was aborted.`,`AbortError`)):(e.controller.on(`terminated`,t),this.abort=n.abort=t),l.finalNetworkRequestStartTime=E(e.crossOriginIsolatedCapability)},onResponseStarted(){l.finalNetworkResponseStartTime=E(e.crossOriginIsolatedCapability)},onHeaders(e,t,n,r){if(e<200)return;let c=``,l=new s;for(let e=0;e5)return a(Error(`too many content-encodings in response: ${t.length}, maximum allowed is 5`)),!0;for(let e=t.length-1;e>=0;--e){let n=t[e].trim();if(n===`x-gzip`||n===`gzip`)d.push(u.createGunzip({flush:u.constants.Z_SYNC_FLUSH,finishFlush:u.constants.Z_SYNC_FLUSH}));else if(n===`deflate`)d.push(te({flush:u.constants.Z_SYNC_FLUSH,finishFlush:u.constants.Z_SYNC_FLUSH}));else if(n===`br`)d.push(u.createBrotliDecompress({flush:u.constants.BROTLI_OPERATION_FLUSH,finishFlush:u.constants.BROTLI_OPERATION_FLUSH}));else{d.length=0;break}}}let p=this.onError.bind(this);return i({status:e,statusText:r,headersList:l,body:d.length?fe(this.body,...d,e=>{e&&this.onError(e)}).on(`error`,p):this.body.on(`error`,p)}),!0},onData(t){if(e.controller.dump)return;let n=t;return l.encodedBodySize+=n.byteLength,this.body.push(n)},onComplete(){this.abort&&e.controller.off(`terminated`,this.abort),e.controller.onAborted&&e.controller.off(`terminated`,e.controller.onAborted),e.controller.ended=!0,this.body.push(null)},onError(t){this.abort&&e.controller.off(`terminated`,this.abort),this.body?.destroy(t),e.controller.terminate(t),a(t)},onUpgrade(e,t,n){if(e!==101)return;let r=new s;for(let e=0;e{t.exports={kState:Symbol(`FileReader state`),kResult:Symbol(`FileReader result`),kError:Symbol(`FileReader error`),kLastProgressEventFired:Symbol(`FileReader last progress event fired timestamp`),kEvents:Symbol(`FileReader events`),kAborted:Symbol(`FileReader aborted`)}})),qe=o(((e,t)=>{var{webidl:n}=U(),r=Symbol(`ProgressEvent state`),i=class e extends Event{constructor(e,t={}){e=n.converters.DOMString(e,`ProgressEvent constructor`,`type`),t=n.converters.ProgressEventInit(t??{}),super(e,t),this[r]={lengthComputable:t.lengthComputable,loaded:t.loaded,total:t.total}}get lengthComputable(){return n.brandCheck(this,e),this[r].lengthComputable}get loaded(){return n.brandCheck(this,e),this[r].loaded}get total(){return n.brandCheck(this,e),this[r].total}};n.converters.ProgressEventInit=n.dictionaryConverter([{key:`lengthComputable`,converter:n.converters.boolean,defaultValue:()=>!1},{key:`loaded`,converter:n.converters[`unsigned long long`],defaultValue:()=>0},{key:`total`,converter:n.converters[`unsigned long long`],defaultValue:()=>0},{key:`bubbles`,converter:n.converters.boolean,defaultValue:()=>!1},{key:`cancelable`,converter:n.converters.boolean,defaultValue:()=>!1},{key:`composed`,converter:n.converters.boolean,defaultValue:()=>!1}]),t.exports={ProgressEvent:i}})),Je=o(((e,t)=>{function n(e){if(!e)return`failure`;switch(e.trim().toLowerCase()){case`unicode-1-1-utf-8`:case`unicode11utf8`:case`unicode20utf8`:case`utf-8`:case`utf8`:case`x-unicode20utf8`:return`UTF-8`;case`866`:case`cp866`:case`csibm866`:case`ibm866`:return`IBM866`;case`csisolatin2`:case`iso-8859-2`:case`iso-ir-101`:case`iso8859-2`:case`iso88592`:case`iso_8859-2`:case`iso_8859-2:1987`:case`l2`:case`latin2`:return`ISO-8859-2`;case`csisolatin3`:case`iso-8859-3`:case`iso-ir-109`:case`iso8859-3`:case`iso88593`:case`iso_8859-3`:case`iso_8859-3:1988`:case`l3`:case`latin3`:return`ISO-8859-3`;case`csisolatin4`:case`iso-8859-4`:case`iso-ir-110`:case`iso8859-4`:case`iso88594`:case`iso_8859-4`:case`iso_8859-4:1988`:case`l4`:case`latin4`:return`ISO-8859-4`;case`csisolatincyrillic`:case`cyrillic`:case`iso-8859-5`:case`iso-ir-144`:case`iso8859-5`:case`iso88595`:case`iso_8859-5`:case`iso_8859-5:1988`:return`ISO-8859-5`;case`arabic`:case`asmo-708`:case`csiso88596e`:case`csiso88596i`:case`csisolatinarabic`:case`ecma-114`:case`iso-8859-6`:case`iso-8859-6-e`:case`iso-8859-6-i`:case`iso-ir-127`:case`iso8859-6`:case`iso88596`:case`iso_8859-6`:case`iso_8859-6:1987`:return`ISO-8859-6`;case`csisolatingreek`:case`ecma-118`:case`elot_928`:case`greek`:case`greek8`:case`iso-8859-7`:case`iso-ir-126`:case`iso8859-7`:case`iso88597`:case`iso_8859-7`:case`iso_8859-7:1987`:case`sun_eu_greek`:return`ISO-8859-7`;case`csiso88598e`:case`csisolatinhebrew`:case`hebrew`:case`iso-8859-8`:case`iso-8859-8-e`:case`iso-ir-138`:case`iso8859-8`:case`iso88598`:case`iso_8859-8`:case`iso_8859-8:1988`:case`visual`:return`ISO-8859-8`;case`csiso88598i`:case`iso-8859-8-i`:case`logical`:return`ISO-8859-8-I`;case`csisolatin6`:case`iso-8859-10`:case`iso-ir-157`:case`iso8859-10`:case`iso885910`:case`l6`:case`latin6`:return`ISO-8859-10`;case`iso-8859-13`:case`iso8859-13`:case`iso885913`:return`ISO-8859-13`;case`iso-8859-14`:case`iso8859-14`:case`iso885914`:return`ISO-8859-14`;case`csisolatin9`:case`iso-8859-15`:case`iso8859-15`:case`iso885915`:case`iso_8859-15`:case`l9`:return`ISO-8859-15`;case`iso-8859-16`:return`ISO-8859-16`;case`cskoi8r`:case`koi`:case`koi8`:case`koi8-r`:case`koi8_r`:return`KOI8-R`;case`koi8-ru`:case`koi8-u`:return`KOI8-U`;case`csmacintosh`:case`mac`:case`macintosh`:case`x-mac-roman`:return`macintosh`;case`iso-8859-11`:case`iso8859-11`:case`iso885911`:case`tis-620`:case`windows-874`:return`windows-874`;case`cp1250`:case`windows-1250`:case`x-cp1250`:return`windows-1250`;case`cp1251`:case`windows-1251`:case`x-cp1251`:return`windows-1251`;case`ansi_x3.4-1968`:case`ascii`:case`cp1252`:case`cp819`:case`csisolatin1`:case`ibm819`:case`iso-8859-1`:case`iso-ir-100`:case`iso8859-1`:case`iso88591`:case`iso_8859-1`:case`iso_8859-1:1987`:case`l1`:case`latin1`:case`us-ascii`:case`windows-1252`:case`x-cp1252`:return`windows-1252`;case`cp1253`:case`windows-1253`:case`x-cp1253`:return`windows-1253`;case`cp1254`:case`csisolatin5`:case`iso-8859-9`:case`iso-ir-148`:case`iso8859-9`:case`iso88599`:case`iso_8859-9`:case`iso_8859-9:1989`:case`l5`:case`latin5`:case`windows-1254`:case`x-cp1254`:return`windows-1254`;case`cp1255`:case`windows-1255`:case`x-cp1255`:return`windows-1255`;case`cp1256`:case`windows-1256`:case`x-cp1256`:return`windows-1256`;case`cp1257`:case`windows-1257`:case`x-cp1257`:return`windows-1257`;case`cp1258`:case`windows-1258`:case`x-cp1258`:return`windows-1258`;case`x-mac-cyrillic`:case`x-mac-ukrainian`:return`x-mac-cyrillic`;case`chinese`:case`csgb2312`:case`csiso58gb231280`:case`gb2312`:case`gb_2312`:case`gb_2312-80`:case`gbk`:case`iso-ir-58`:case`x-gbk`:return`GBK`;case`gb18030`:return`gb18030`;case`big5`:case`big5-hkscs`:case`cn-big5`:case`csbig5`:case`x-x-big5`:return`Big5`;case`cseucpkdfmtjapanese`:case`euc-jp`:case`x-euc-jp`:return`EUC-JP`;case`csiso2022jp`:case`iso-2022-jp`:return`ISO-2022-JP`;case`csshiftjis`:case`ms932`:case`ms_kanji`:case`shift-jis`:case`shift_jis`:case`sjis`:case`windows-31j`:case`x-sjis`:return`Shift_JIS`;case`cseuckr`:case`csksc56011987`:case`euc-kr`:case`iso-ir-149`:case`korean`:case`ks_c_5601-1987`:case`ks_c_5601-1989`:case`ksc5601`:case`ksc_5601`:case`windows-949`:return`EUC-KR`;case`csiso2022kr`:case`hz-gb-2312`:case`iso-2022-cn`:case`iso-2022-cn-ext`:case`iso-2022-kr`:case`replacement`:return`replacement`;case`unicodefffe`:case`utf-16be`:return`UTF-16BE`;case`csunicode`:case`iso-10646-ucs-2`:case`ucs-2`:case`unicode`:case`unicodefeff`:case`utf-16`:case`utf-16le`:return`UTF-16LE`;case`x-user-defined`:return`x-user-defined`;default:return`failure`}}t.exports={getEncoding:n}})),Ye=o(((e,t)=>{var{kState:n,kError:r,kResult:i,kAborted:a,kLastProgressEventFired:o}=Ke(),{ProgressEvent:s}=qe(),{getEncoding:c}=Je(),{serializeAMimeType:l,parseMIMEType:u}=H(),{types:d}=require(`node:util`),{StringDecoder:f}=require(`string_decoder`),{btoa:p}=require(`node:buffer`),m={enumerable:!0,writable:!1,configurable:!1};function h(e,t,s,c){if(e[n]===`loading`)throw new DOMException(`Invalid state`,`InvalidStateError`);e[n]=`loading`,e[i]=null,e[r]=null;let l=t.stream().getReader(),u=[],f=l.read(),p=!0;(async()=>{for(;!e[a];)try{let{done:m,value:h}=await f;if(p&&!e[a]&&queueMicrotask(()=>{g(`loadstart`,e)}),p=!1,!m&&d.isUint8Array(h))u.push(h),(e[o]===void 0||Date.now()-e[o]>=50)&&!e[a]&&(e[o]=Date.now(),queueMicrotask(()=>{g(`progress`,e)})),f=l.read();else if(m){queueMicrotask(()=>{e[n]=`done`;try{let n=_(u,s,t.type,c);if(e[a])return;e[i]=n,g(`load`,e)}catch(t){e[r]=t,g(`error`,e)}e[n]!==`loading`&&g(`loadend`,e)});break}}catch(t){if(e[a])return;queueMicrotask(()=>{e[n]=`done`,e[r]=t,g(`error`,e),e[n]!==`loading`&&g(`loadend`,e)});break}})()}function g(e,t){let n=new s(e,{bubbles:!1,cancelable:!1});t.dispatchEvent(n)}function _(e,t,n,r){switch(t){case`DataURL`:{let t=`data:`,r=u(n||`application/octet-stream`);r!==`failure`&&(t+=l(r)),t+=`;base64,`;let i=new f(`latin1`);for(let n of e)t+=p(i.write(n));return t+=p(i.end()),t}case`Text`:{let t=`failure`;if(r&&(t=c(r)),t===`failure`&&n){let e=u(n);e!==`failure`&&(t=c(e.parameters.get(`charset`)))}return t===`failure`&&(t=`UTF-8`),v(e,t)}case`ArrayBuffer`:return b(e).buffer;case`BinaryString`:{let t=``,n=new f(`latin1`);for(let r of e)t+=n.write(r);return t+=n.end(),t}}}function v(e,t){let n=b(e),r=y(n),i=0;r!==null&&(t=r,i=r===`UTF-8`?3:2);let a=n.slice(i);return new TextDecoder(t).decode(a)}function y(e){let[t,n,r]=e;return t===239&&n===187&&r===191?`UTF-8`:t===254&&n===255?`UTF-16BE`:t===255&&n===254?`UTF-16LE`:null}function b(e){let t=e.reduce((e,t)=>e+t.byteLength,0),n=0;return e.reduce((e,t)=>(e.set(t,n),n+=t.byteLength,e),new Uint8Array(t))}t.exports={staticPropertyDescriptors:m,readOperation:h,fireAProgressEvent:g}})),Xe=o(((e,t)=>{var{staticPropertyDescriptors:n,readOperation:r,fireAProgressEvent:i}=Ye(),{kState:a,kError:o,kResult:s,kEvents:c,kAborted:l}=Ke(),{webidl:u}=U(),{kEnumerableProperty:d}=F(),f=class e extends EventTarget{constructor(){super(),this[a]=`empty`,this[s]=null,this[o]=null,this[c]={loadend:null,error:null,abort:null,load:null,progress:null,loadstart:null}}readAsArrayBuffer(t){u.brandCheck(this,e),u.argumentLengthCheck(arguments,1,`FileReader.readAsArrayBuffer`),t=u.converters.Blob(t,{strict:!1}),r(this,t,`ArrayBuffer`)}readAsBinaryString(t){u.brandCheck(this,e),u.argumentLengthCheck(arguments,1,`FileReader.readAsBinaryString`),t=u.converters.Blob(t,{strict:!1}),r(this,t,`BinaryString`)}readAsText(t,n=void 0){u.brandCheck(this,e),u.argumentLengthCheck(arguments,1,`FileReader.readAsText`),t=u.converters.Blob(t,{strict:!1}),n!==void 0&&(n=u.converters.DOMString(n,`FileReader.readAsText`,`encoding`)),r(this,t,`Text`,n)}readAsDataURL(t){u.brandCheck(this,e),u.argumentLengthCheck(arguments,1,`FileReader.readAsDataURL`),t=u.converters.Blob(t,{strict:!1}),r(this,t,`DataURL`)}abort(){if(this[a]===`empty`||this[a]===`done`){this[s]=null;return}this[a]===`loading`&&(this[a]=`done`,this[s]=null),this[l]=!0,i(`abort`,this),this[a]!==`loading`&&i(`loadend`,this)}get readyState(){switch(u.brandCheck(this,e),this[a]){case`empty`:return this.EMPTY;case`loading`:return this.LOADING;case`done`:return this.DONE}}get result(){return u.brandCheck(this,e),this[s]}get error(){return u.brandCheck(this,e),this[o]}get onloadend(){return u.brandCheck(this,e),this[c].loadend}set onloadend(t){u.brandCheck(this,e),this[c].loadend&&this.removeEventListener(`loadend`,this[c].loadend),typeof t==`function`?(this[c].loadend=t,this.addEventListener(`loadend`,t)):this[c].loadend=null}get onerror(){return u.brandCheck(this,e),this[c].error}set onerror(t){u.brandCheck(this,e),this[c].error&&this.removeEventListener(`error`,this[c].error),typeof t==`function`?(this[c].error=t,this.addEventListener(`error`,t)):this[c].error=null}get onloadstart(){return u.brandCheck(this,e),this[c].loadstart}set onloadstart(t){u.brandCheck(this,e),this[c].loadstart&&this.removeEventListener(`loadstart`,this[c].loadstart),typeof t==`function`?(this[c].loadstart=t,this.addEventListener(`loadstart`,t)):this[c].loadstart=null}get onprogress(){return u.brandCheck(this,e),this[c].progress}set onprogress(t){u.brandCheck(this,e),this[c].progress&&this.removeEventListener(`progress`,this[c].progress),typeof t==`function`?(this[c].progress=t,this.addEventListener(`progress`,t)):this[c].progress=null}get onload(){return u.brandCheck(this,e),this[c].load}set onload(t){u.brandCheck(this,e),this[c].load&&this.removeEventListener(`load`,this[c].load),typeof t==`function`?(this[c].load=t,this.addEventListener(`load`,t)):this[c].load=null}get onabort(){return u.brandCheck(this,e),this[c].abort}set onabort(t){u.brandCheck(this,e),this[c].abort&&this.removeEventListener(`abort`,this[c].abort),typeof t==`function`?(this[c].abort=t,this.addEventListener(`abort`,t)):this[c].abort=null}};f.EMPTY=f.prototype.EMPTY=0,f.LOADING=f.prototype.LOADING=1,f.DONE=f.prototype.DONE=2,Object.defineProperties(f.prototype,{EMPTY:n,LOADING:n,DONE:n,readAsArrayBuffer:d,readAsBinaryString:d,readAsText:d,readAsDataURL:d,abort:d,readyState:d,result:d,error:d,onloadstart:d,onprogress:d,onload:d,onabort:d,onerror:d,onloadend:d,[Symbol.toStringTag]:{value:`FileReader`,writable:!1,enumerable:!1,configurable:!0}}),Object.defineProperties(f,{EMPTY:n,LOADING:n,DONE:n}),t.exports={FileReader:f}})),Ze=o(((e,t)=>{t.exports={kConstruct:j().kConstruct}})),Qe=o(((e,t)=>{var n=require(`node:assert`),{URLSerializer:r}=H(),{isValidHeaderName:i}=W();function a(e,t,n=!1){return r(e,n)===r(t,n)}function o(e){n(e!==null);let t=[];for(let n of e.split(`,`))n=n.trim(),i(n)&&t.push(n);return t}t.exports={urlEquals:a,getFieldValues:o}})),$e=o(((e,t)=>{var{kConstruct:n}=Ze(),{urlEquals:r,getFieldValues:i}=Qe(),{kEnumerableProperty:a,isDisturbed:o}=F(),{webidl:s}=U(),{Response:c,cloneResponse:l,fromInnerResponse:u}=He(),{Request:d,fromInnerRequest:f}=We(),{kState:p}=G(),{fetching:m}=Ge(),{urlIsHttpHttpsScheme:h,createDeferredPromise:g,readAllBytes:_}=W(),v=require(`node:assert`),y=class e{#e;constructor(){arguments[0]!==n&&s.illegalConstructor(),s.util.markAsUncloneable(this),this.#e=arguments[1]}async match(t,n={}){s.brandCheck(this,e);let r=`Cache.match`;s.argumentLengthCheck(arguments,1,r),t=s.converters.RequestInfo(t,r,`request`),n=s.converters.CacheQueryOptions(n,r,`options`);let i=this.#i(t,n,1);if(i.length!==0)return i[0]}async matchAll(t=void 0,n={}){s.brandCheck(this,e);let r=`Cache.matchAll`;return t!==void 0&&(t=s.converters.RequestInfo(t,r,`request`)),n=s.converters.CacheQueryOptions(n,r,`options`),this.#i(t,n)}async add(t){s.brandCheck(this,e);let n=`Cache.add`;s.argumentLengthCheck(arguments,1,n),t=s.converters.RequestInfo(t,n,`request`);let r=[t];return await this.addAll(r)}async addAll(t){s.brandCheck(this,e);let n=`Cache.addAll`;s.argumentLengthCheck(arguments,1,n);let r=[],a=[];for(let e of t){if(e===void 0)throw s.errors.conversionFailed({prefix:n,argument:`Argument 1`,types:[`undefined is not allowed`]});if(e=s.converters.RequestInfo(e),typeof e==`string`)continue;let t=e[p];if(!h(t.url)||t.method!==`GET`)throw s.errors.exception({header:n,message:`Expected http/s scheme when method is not GET.`})}let o=[];for(let e of t){let t=new d(e)[p];if(!h(t.url))throw s.errors.exception({header:n,message:`Expected http/s scheme.`});t.initiator=`fetch`,t.destination=`subresource`,a.push(t);let c=g();o.push(m({request:t,processResponse(e){if(e.type===`error`||e.status===206||e.status<200||e.status>299)c.reject(s.errors.exception({header:`Cache.addAll`,message:`Received an invalid status code or the request failed.`}));else if(e.headersList.contains(`vary`)){let t=i(e.headersList.get(`vary`));for(let e of t)if(e===`*`){c.reject(s.errors.exception({header:`Cache.addAll`,message:`invalid vary field value`}));for(let e of o)e.abort();return}}},processResponseEndOfBody(e){if(e.aborted){c.reject(new DOMException(`aborted`,`AbortError`));return}c.resolve(e)}})),r.push(c.promise)}let c=await Promise.all(r),l=[],u=0;for(let e of c){let t={type:`put`,request:a[u],response:e};l.push(t),u++}let f=g(),_=null;try{this.#t(l)}catch(e){_=e}return queueMicrotask(()=>{_===null?f.resolve(void 0):f.reject(_)}),f.promise}async put(t,n){s.brandCheck(this,e);let r=`Cache.put`;s.argumentLengthCheck(arguments,2,r),t=s.converters.RequestInfo(t,r,`request`),n=s.converters.Response(n,r,`response`);let a=null;if(a=t instanceof d?t[p]:new d(t)[p],!h(a.url)||a.method!==`GET`)throw s.errors.exception({header:r,message:`Expected an http/s scheme when method is not GET`});let c=n[p];if(c.status===206)throw s.errors.exception({header:r,message:`Got 206 status`});if(c.headersList.contains(`vary`)){let e=i(c.headersList.get(`vary`));for(let t of e)if(t===`*`)throw s.errors.exception({header:r,message:`Got * vary field value`})}if(c.body&&(o(c.body.stream)||c.body.stream.locked))throw s.errors.exception({header:r,message:`Response body is locked or disturbed`});let u=l(c),f=g();c.body==null?f.resolve(void 0):_(c.body.stream.getReader()).then(f.resolve,f.reject);let m=[],v={type:`put`,request:a,response:u};m.push(v);let y=await f.promise;u.body!=null&&(u.body.source=y);let b=g(),x=null;try{this.#t(m)}catch(e){x=e}return queueMicrotask(()=>{x===null?b.resolve():b.reject(x)}),b.promise}async delete(t,n={}){s.brandCheck(this,e);let r=`Cache.delete`;s.argumentLengthCheck(arguments,1,r),t=s.converters.RequestInfo(t,r,`request`),n=s.converters.CacheQueryOptions(n,r,`options`);let i=null;if(t instanceof d){if(i=t[p],i.method!==`GET`&&!n.ignoreMethod)return!1}else v(typeof t==`string`),i=new d(t)[p];let a=[],o={type:`delete`,request:i,options:n};a.push(o);let c=g(),l=null,u;try{u=this.#t(a)}catch(e){l=e}return queueMicrotask(()=>{l===null?c.resolve(!!u?.length):c.reject(l)}),c.promise}async keys(t=void 0,n={}){s.brandCheck(this,e);let r=`Cache.keys`;t!==void 0&&(t=s.converters.RequestInfo(t,r,`request`)),n=s.converters.CacheQueryOptions(n,r,`options`);let i=null;if(t!==void 0)if(t instanceof d){if(i=t[p],i.method!==`GET`&&!n.ignoreMethod)return[]}else typeof t==`string`&&(i=new d(t)[p]);let a=g(),o=[];if(t===void 0)for(let e of this.#e)o.push(e[0]);else{let e=this.#n(i,n);for(let t of e)o.push(t[0])}return queueMicrotask(()=>{let e=[];for(let t of o){let n=f(t,new AbortController().signal,`immutable`);e.push(n)}a.resolve(Object.freeze(e))}),a.promise}#t(e){let t=this.#e,n=[...t],r=[],i=[];try{for(let n of e){if(n.type!==`delete`&&n.type!==`put`)throw s.errors.exception({header:`Cache.#batchCacheOperations`,message:`operation type does not match "delete" or "put"`});if(n.type===`delete`&&n.response!=null)throw s.errors.exception({header:`Cache.#batchCacheOperations`,message:`delete operation should not have an associated response`});if(this.#n(n.request,n.options,r).length)throw new DOMException(`???`,`InvalidStateError`);let e;if(n.type===`delete`){if(e=this.#n(n.request,n.options),e.length===0)return[];for(let n of e){let e=t.indexOf(n);v(e!==-1),t.splice(e,1)}}else if(n.type===`put`){if(n.response==null)throw s.errors.exception({header:`Cache.#batchCacheOperations`,message:`put operation should have an associated response`});let i=n.request;if(!h(i.url))throw s.errors.exception({header:`Cache.#batchCacheOperations`,message:`expected http or https scheme`});if(i.method!==`GET`)throw s.errors.exception({header:`Cache.#batchCacheOperations`,message:`not get method`});if(n.options!=null)throw s.errors.exception({header:`Cache.#batchCacheOperations`,message:`options must not be defined`});e=this.#n(n.request);for(let n of e){let e=t.indexOf(n);v(e!==-1),t.splice(e,1)}t.push([n.request,n.response]),r.push([n.request,n.response])}i.push([n.request,n.response])}return i}catch(e){throw this.#e.length=0,this.#e=n,e}}#n(e,t,n){let r=[],i=n??this.#e;for(let n of i){let[i,a]=n;this.#r(e,i,a,t)&&r.push(n)}return r}#r(e,t,n=null,a){let o=new URL(e.url),s=new URL(t.url);if(a?.ignoreSearch&&(s.search=``,o.search=``),!r(o,s,!0))return!1;if(n==null||a?.ignoreVary||!n.headersList.contains(`vary`))return!0;let c=i(n.headersList.get(`vary`));for(let n of c)if(n===`*`||t.headersList.get(n)!==e.headersList.get(n))return!1;return!0}#i(e,t,n=1/0){let r=null;if(e!==void 0)if(e instanceof d){if(r=e[p],r.method!==`GET`&&!t.ignoreMethod)return[]}else typeof e==`string`&&(r=new d(e)[p]);let i=[];if(e===void 0)for(let e of this.#e)i.push(e[1]);else{let e=this.#n(r,t);for(let t of e)i.push(t[1])}let a=[];for(let e of i){let t=u(e,`immutable`);if(a.push(t.clone()),a.length>=n)break}return Object.freeze(a)}};Object.defineProperties(y.prototype,{[Symbol.toStringTag]:{value:`Cache`,configurable:!0},match:a,matchAll:a,add:a,addAll:a,put:a,delete:a,keys:a});var b=[{key:`ignoreSearch`,converter:s.converters.boolean,defaultValue:()=>!1},{key:`ignoreMethod`,converter:s.converters.boolean,defaultValue:()=>!1},{key:`ignoreVary`,converter:s.converters.boolean,defaultValue:()=>!1}];s.converters.CacheQueryOptions=s.dictionaryConverter(b),s.converters.MultiCacheQueryOptions=s.dictionaryConverter([...b,{key:`cacheName`,converter:s.converters.DOMString}]),s.converters.Response=s.interfaceConverter(c),s.converters[`sequence`]=s.sequenceConverter(s.converters.RequestInfo),t.exports={Cache:y}})),et=o(((e,t)=>{var{kConstruct:n}=Ze(),{Cache:r}=$e(),{webidl:i}=U(),{kEnumerableProperty:a}=F(),o=class e{#e=new Map;constructor(){arguments[0]!==n&&i.illegalConstructor(),i.util.markAsUncloneable(this)}async match(t,a={}){if(i.brandCheck(this,e),i.argumentLengthCheck(arguments,1,`CacheStorage.match`),t=i.converters.RequestInfo(t),a=i.converters.MultiCacheQueryOptions(a),a.cacheName!=null){if(this.#e.has(a.cacheName))return await new r(n,this.#e.get(a.cacheName)).match(t,a)}else for(let e of this.#e.values()){let i=await new r(n,e).match(t,a);if(i!==void 0)return i}}async has(t){i.brandCheck(this,e);let n=`CacheStorage.has`;return i.argumentLengthCheck(arguments,1,n),t=i.converters.DOMString(t,n,`cacheName`),this.#e.has(t)}async open(t){i.brandCheck(this,e);let a=`CacheStorage.open`;if(i.argumentLengthCheck(arguments,1,a),t=i.converters.DOMString(t,a,`cacheName`),this.#e.has(t))return new r(n,this.#e.get(t));let o=[];return this.#e.set(t,o),new r(n,o)}async delete(t){i.brandCheck(this,e);let n=`CacheStorage.delete`;return i.argumentLengthCheck(arguments,1,n),t=i.converters.DOMString(t,n,`cacheName`),this.#e.delete(t)}async keys(){return i.brandCheck(this,e),[...this.#e.keys()]}};Object.defineProperties(o.prototype,{[Symbol.toStringTag]:{value:`CacheStorage`,configurable:!0},match:a,has:a,open:a,delete:a,keys:a}),t.exports={CacheStorage:o}})),tt=o(((e,t)=>{t.exports={maxAttributeValueSize:1024,maxNameValuePairSize:4096}})),nt=o(((e,t)=>{function n(e){for(let t=0;t=0&&n<=8||n>=10&&n<=31||n===127)return!0}return!1}function r(e){for(let t=0;t126||n===34||n===40||n===41||n===60||n===62||n===64||n===44||n===59||n===58||n===92||n===47||n===91||n===93||n===63||n===61||n===123||n===125)throw Error(`Invalid cookie name`)}}function i(e){let t=e.length,n=0;if(e[0]===`"`){if(t===1||e[t-1]!==`"`)throw Error(`Invalid cookie value`);--t,++n}for(;n126||t===34||t===44||t===59||t===92)throw Error(`Invalid cookie value`)}}function a(e){for(let t=0;tt.toString().padStart(2,`0`));function u(e){return typeof e==`number`&&(e=new Date(e)),`${s[e.getUTCDay()]}, ${l[e.getUTCDate()]} ${c[e.getUTCMonth()]} ${e.getUTCFullYear()} ${l[e.getUTCHours()]}:${l[e.getUTCMinutes()]}:${l[e.getUTCSeconds()]} GMT`}function d(e){if(e<0)throw Error(`Invalid cookie max-age`)}function f(e){if(e.name.length===0)return null;r(e.name),i(e.value);let t=[`${e.name}=${e.value}`];e.name.startsWith(`__Secure-`)&&(e.secure=!0),e.name.startsWith(`__Host-`)&&(e.secure=!0,e.domain=null,e.path=`/`),e.secure&&t.push(`Secure`),e.httpOnly&&t.push(`HttpOnly`),typeof e.maxAge==`number`&&(d(e.maxAge),t.push(`Max-Age=${e.maxAge}`)),e.domain&&(o(e.domain),t.push(`Domain=${e.domain}`)),e.path&&(a(e.path),t.push(`Path=${e.path}`)),e.expires&&e.expires.toString()!==`Invalid Date`&&t.push(`Expires=${u(e.expires)}`),e.sameSite&&t.push(`SameSite=${e.sameSite}`);for(let n of e.unparsed){if(!n.includes(`=`))throw Error(`Invalid unparsed`);let[e,...r]=n.split(`=`);t.push(`${e.trim()}=${r.join(`=`)}`)}return t.join(`; `)}t.exports={isCTLExcludingHtab:n,validateCookieName:r,validateCookiePath:a,validateCookieValue:i,toIMFDate:u,stringify:f}})),rt=o(((e,t)=>{var{maxNameValuePairSize:n,maxAttributeValueSize:r}=tt(),{isCTLExcludingHtab:i}=nt(),{collectASequenceOfCodePointsFast:a}=H(),o=require(`node:assert`);function s(e){if(i(e))return null;let t=``,r=``,o=``,s=``;if(e.includes(`;`)){let n={position:0};t=a(`;`,e,n),r=e.slice(n.position)}else t=e;if(!t.includes(`=`))s=t;else{let e={position:0};o=a(`=`,t,e),s=t.slice(e.position+1)}return o=o.trim(),s=s.trim(),o.length+s.length>n?null:{name:o,value:s,...c(r)}}function c(e,t={}){if(e.length===0)return t;o(e[0]===`;`),e=e.slice(1);let n=``;e.includes(`;`)?(n=a(`;`,e,{position:0}),e=e.slice(n.length)):(n=e,e=``);let i=``,s=``;if(n.includes(`=`)){let e={position:0};i=a(`=`,n,e),s=n.slice(e.position+1)}else i=n;if(i=i.trim(),s=s.trim(),s.length>r)return c(e,t);let l=i.toLowerCase();if(l===`expires`)t.expires=new Date(s);else if(l===`max-age`){let n=s.charCodeAt(0);if((n<48||n>57)&&s[0]!==`-`||!/^\d+$/.test(s))return c(e,t);t.maxAge=Number(s)}else if(l===`domain`){let e=s;e[0]===`.`&&(e=e.slice(1)),e=e.toLowerCase(),t.domain=e}else if(l===`path`){let e=``;e=s.length===0||s[0]!==`/`?`/`:s,t.path=e}else if(l===`secure`)t.secure=!0;else if(l===`httponly`)t.httpOnly=!0;else if(l===`samesite`){let e=`Default`,n=s.toLowerCase();n.includes(`none`)&&(e=`None`),n.includes(`strict`)&&(e=`Strict`),n.includes(`lax`)&&(e=`Lax`),t.sameSite=e}else t.unparsed??=[],t.unparsed.push(`${i}=${s}`);return c(e,t)}t.exports={parseSetCookie:s,parseUnparsedAttributes:c}})),it=o(((e,t)=>{var{parseSetCookie:n}=rt(),{stringify:r}=nt(),{webidl:i}=U(),{Headers:a}=Ve();function o(e){i.argumentLengthCheck(arguments,1,`getCookies`),i.brandCheck(e,a,{strict:!1});let t=e.get(`cookie`),n={};if(!t)return n;for(let e of t.split(`;`)){let[t,...r]=e.split(`=`);n[t.trim()]=r.join(`=`)}return n}function s(e,t,n){i.brandCheck(e,a,{strict:!1});let r=`deleteCookie`;i.argumentLengthCheck(arguments,2,r),t=i.converters.DOMString(t,r,`name`),n=i.converters.DeleteCookieAttributes(n),l(e,{name:t,value:``,expires:new Date(0),...n})}function c(e){i.argumentLengthCheck(arguments,1,`getSetCookies`),i.brandCheck(e,a,{strict:!1});let t=e.getSetCookie();return t?t.map(e=>n(e)):[]}function l(e,t){i.argumentLengthCheck(arguments,2,`setCookie`),i.brandCheck(e,a,{strict:!1}),t=i.converters.Cookie(t);let n=r(t);n&&e.append(`Set-Cookie`,n)}i.converters.DeleteCookieAttributes=i.dictionaryConverter([{converter:i.nullableConverter(i.converters.DOMString),key:`path`,defaultValue:()=>null},{converter:i.nullableConverter(i.converters.DOMString),key:`domain`,defaultValue:()=>null}]),i.converters.Cookie=i.dictionaryConverter([{converter:i.converters.DOMString,key:`name`},{converter:i.converters.DOMString,key:`value`},{converter:i.nullableConverter(e=>typeof e==`number`?i.converters[`unsigned long long`](e):new Date(e)),key:`expires`,defaultValue:()=>null},{converter:i.nullableConverter(i.converters[`long long`]),key:`maxAge`,defaultValue:()=>null},{converter:i.nullableConverter(i.converters.DOMString),key:`domain`,defaultValue:()=>null},{converter:i.nullableConverter(i.converters.DOMString),key:`path`,defaultValue:()=>null},{converter:i.nullableConverter(i.converters.boolean),key:`secure`,defaultValue:()=>null},{converter:i.nullableConverter(i.converters.boolean),key:`httpOnly`,defaultValue:()=>null},{converter:i.converters.USVString,key:`sameSite`,allowedValues:[`Strict`,`Lax`,`None`]},{converter:i.sequenceConverter(i.converters.DOMString),key:`unparsed`,defaultValue:()=>[]}]),t.exports={getCookies:o,deleteCookie:s,getSetCookies:c,setCookie:l}})),at=o(((e,t)=>{var{webidl:n}=U(),{kEnumerableProperty:r}=F(),{kConstruct:i}=j(),{MessagePort:a}=require(`node:worker_threads`),o=class e extends Event{#e;constructor(e,t={}){if(e===i){super(arguments[1],arguments[2]),n.util.markAsUncloneable(this);return}let r=`MessageEvent constructor`;n.argumentLengthCheck(arguments,1,r),e=n.converters.DOMString(e,r,`type`),t=n.converters.MessageEventInit(t,r,`eventInitDict`),super(e,t),this.#e=t,n.util.markAsUncloneable(this)}get data(){return n.brandCheck(this,e),this.#e.data}get origin(){return n.brandCheck(this,e),this.#e.origin}get lastEventId(){return n.brandCheck(this,e),this.#e.lastEventId}get source(){return n.brandCheck(this,e),this.#e.source}get ports(){return n.brandCheck(this,e),Object.isFrozen(this.#e.ports)||Object.freeze(this.#e.ports),this.#e.ports}initMessageEvent(t,r=!1,i=!1,a=null,o=``,s=``,c=null,l=[]){return n.brandCheck(this,e),n.argumentLengthCheck(arguments,1,`MessageEvent.initMessageEvent`),new e(t,{bubbles:r,cancelable:i,data:a,origin:o,lastEventId:s,source:c,ports:l})}static createFastMessageEvent(t,n){let r=new e(i,t,n);return r.#e=n,r.#e.data??=null,r.#e.origin??=``,r.#e.lastEventId??=``,r.#e.source??=null,r.#e.ports??=[],r}},{createFastMessageEvent:s}=o;delete o.createFastMessageEvent;var c=class e extends Event{#e;constructor(e,t={}){let r=`CloseEvent constructor`;n.argumentLengthCheck(arguments,1,r),e=n.converters.DOMString(e,r,`type`),t=n.converters.CloseEventInit(t),super(e,t),this.#e=t,n.util.markAsUncloneable(this)}get wasClean(){return n.brandCheck(this,e),this.#e.wasClean}get code(){return n.brandCheck(this,e),this.#e.code}get reason(){return n.brandCheck(this,e),this.#e.reason}},l=class e extends Event{#e;constructor(e,t){let r=`ErrorEvent constructor`;n.argumentLengthCheck(arguments,1,r),super(e,t),n.util.markAsUncloneable(this),e=n.converters.DOMString(e,r,`type`),t=n.converters.ErrorEventInit(t??{}),this.#e=t}get message(){return n.brandCheck(this,e),this.#e.message}get filename(){return n.brandCheck(this,e),this.#e.filename}get lineno(){return n.brandCheck(this,e),this.#e.lineno}get colno(){return n.brandCheck(this,e),this.#e.colno}get error(){return n.brandCheck(this,e),this.#e.error}};Object.defineProperties(o.prototype,{[Symbol.toStringTag]:{value:`MessageEvent`,configurable:!0},data:r,origin:r,lastEventId:r,source:r,ports:r,initMessageEvent:r}),Object.defineProperties(c.prototype,{[Symbol.toStringTag]:{value:`CloseEvent`,configurable:!0},reason:r,code:r,wasClean:r}),Object.defineProperties(l.prototype,{[Symbol.toStringTag]:{value:`ErrorEvent`,configurable:!0},message:r,filename:r,lineno:r,colno:r,error:r}),n.converters.MessagePort=n.interfaceConverter(a),n.converters[`sequence`]=n.sequenceConverter(n.converters.MessagePort);var u=[{key:`bubbles`,converter:n.converters.boolean,defaultValue:()=>!1},{key:`cancelable`,converter:n.converters.boolean,defaultValue:()=>!1},{key:`composed`,converter:n.converters.boolean,defaultValue:()=>!1}];n.converters.MessageEventInit=n.dictionaryConverter([...u,{key:`data`,converter:n.converters.any,defaultValue:()=>null},{key:`origin`,converter:n.converters.USVString,defaultValue:()=>``},{key:`lastEventId`,converter:n.converters.DOMString,defaultValue:()=>``},{key:`source`,converter:n.nullableConverter(n.converters.MessagePort),defaultValue:()=>null},{key:`ports`,converter:n.converters[`sequence`],defaultValue:()=>[]}]),n.converters.CloseEventInit=n.dictionaryConverter([...u,{key:`wasClean`,converter:n.converters.boolean,defaultValue:()=>!1},{key:`code`,converter:n.converters[`unsigned short`],defaultValue:()=>0},{key:`reason`,converter:n.converters.USVString,defaultValue:()=>``}]),n.converters.ErrorEventInit=n.dictionaryConverter([...u,{key:`message`,converter:n.converters.DOMString,defaultValue:()=>``},{key:`filename`,converter:n.converters.USVString,defaultValue:()=>``},{key:`lineno`,converter:n.converters[`unsigned long`],defaultValue:()=>0},{key:`colno`,converter:n.converters[`unsigned long`],defaultValue:()=>0},{key:`error`,converter:n.converters.any}]),t.exports={MessageEvent:o,CloseEvent:c,ErrorEvent:l,createFastMessageEvent:s}})),ot=o(((e,t)=>{t.exports={uid:`258EAFA5-E914-47DA-95CA-C5AB0DC85B11`,sentCloseFrameState:{NOT_SENT:0,PROCESSING:1,SENT:2},staticPropertyDescriptors:{enumerable:!0,writable:!1,configurable:!1},states:{CONNECTING:0,OPEN:1,CLOSING:2,CLOSED:3},opcodes:{CONTINUATION:0,TEXT:1,BINARY:2,CLOSE:8,PING:9,PONG:10},maxUnsigned16Bit:2**16-1,parserStates:{INFO:0,PAYLOADLENGTH_16:2,PAYLOADLENGTH_64:3,READ_DATA:4},emptyBuffer:Buffer.allocUnsafe(0),sendHints:{string:1,typedArray:2,arrayBuffer:3,blob:4}}})),st=o(((e,t)=>{t.exports={kWebSocketURL:Symbol(`url`),kReadyState:Symbol(`ready state`),kController:Symbol(`controller`),kResponse:Symbol(`response`),kBinaryType:Symbol(`binary type`),kSentClose:Symbol(`sent close`),kReceivedClose:Symbol(`received close`),kByteParser:Symbol(`byte parser`)}})),ct=o(((e,t)=>{var{kReadyState:n,kController:r,kResponse:i,kBinaryType:a,kWebSocketURL:o}=st(),{states:s,opcodes:c}=ot(),{ErrorEvent:l,createFastMessageEvent:u}=at(),{isUtf8:d}=require(`node:buffer`),{collectASequenceOfCodePointsFast:f,removeHTTPWhitespace:p}=H();function m(e){return e[n]===s.CONNECTING}function h(e){return e[n]===s.OPEN}function g(e){return e[n]===s.CLOSING}function _(e){return e[n]===s.CLOSED}function v(e,t,n=(e,t)=>new Event(e,t),r={}){let i=n(e,r);t.dispatchEvent(i)}function y(e,t,r){if(e[n]!==s.OPEN)return;let i;if(t===c.TEXT)try{i=M(r)}catch{C(e,`Received invalid UTF-8 in text frame.`);return}else t===c.BINARY&&(i=e[a]===`blob`?new Blob([r]):b(r));v(`message`,e,u,{origin:e[o].origin,data:i})}function b(e){return e.byteLength===e.buffer.byteLength?e.buffer:e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}function x(e){if(e.length===0)return!1;for(let t=0;t126||n===34||n===40||n===41||n===44||n===47||n===58||n===59||n===60||n===61||n===62||n===63||n===64||n===91||n===92||n===93||n===123||n===125)return!1}return!0}function S(e){return e>=1e3&&e<1015?e!==1004&&e!==1005&&e!==1006:e>=3e3&&e<=4999}function C(e,t){let{[r]:n,[i]:a}=e;n.abort(),a?.socket&&!a.socket.destroyed&&a.socket.destroy(),t&&v(`error`,e,(e,t)=>new l(e,t),{error:Error(t),message:t})}function w(e){return e===c.CLOSE||e===c.PING||e===c.PONG}function T(e){return e===c.CONTINUATION}function E(e){return e===c.TEXT||e===c.BINARY}function D(e){return E(e)||T(e)||w(e)}function O(e){let t={position:0},n=new Map;for(;t.position57)return!1}let t=Number.parseInt(e,10);return t>=8&&t<=15}var A=typeof process.versions.icu==`string`,j=A?new TextDecoder(`utf-8`,{fatal:!0}):void 0,M=A?j.decode.bind(j):function(e){if(d(e))return e.toString(`utf-8`);throw TypeError(`Invalid utf-8 received.`)};t.exports={isConnecting:m,isEstablished:h,isClosing:g,isClosed:_,fireEvent:v,isValidSubprotocol:x,isValidStatusCode:S,failWebsocketConnection:C,websocketMessageReceived:y,utf8Decode:M,isControlFrame:w,isContinuationFrame:T,isTextBinaryFrame:E,isValidOpcode:D,parseExtensions:O,isValidClientWindowBits:k}})),lt=o(((e,t)=>{var{maxUnsigned16Bit:n}=ot(),r=16386,i,a=null,o=r;try{i=require(`node:crypto`)}catch{i={randomFillSync:function(e,t,n){for(let t=0;tn?(o+=8,a=127):i>125&&(o+=2,a=126);let c=Buffer.allocUnsafe(i+o);c[0]=c[1]=0,c[0]|=128,c[0]=(c[0]&240)+e,c[o-4]=r[0],c[o-3]=r[1],c[o-2]=r[2],c[o-1]=r[3],c[1]=a,a===126?c.writeUInt16BE(i,2):a===127&&(c[2]=c[3]=0,c.writeUIntBE(i,4,6)),c[1]|=128;for(let e=0;e{var{uid:n,states:r,sentCloseFrameState:i,emptyBuffer:a,opcodes:o}=ot(),{kReadyState:s,kSentClose:c,kByteParser:l,kReceivedClose:u,kResponse:d}=st(),{fireEvent:f,failWebsocketConnection:p,isClosing:m,isClosed:h,isEstablished:g,parseExtensions:_}=ct(),{channels:v}=I(),{CloseEvent:y}=at(),{makeRequest:b}=We(),{fetching:x}=Ge(),{Headers:S,getHeadersList:C}=Ve(),{getDecodeSplit:w}=W(),{WebsocketFrameSend:T}=lt(),E;try{E=require(`node:crypto`)}catch{}function D(e,t,r,i,a,o){let s=e;s.protocol=e.protocol===`ws:`?`http:`:`https:`;let c=b({urlList:[s],client:r,serviceWorkers:`none`,referrer:`no-referrer`,mode:`websocket`,credentials:`include`,cache:`no-store`,redirect:`error`});o.headers&&(c.headersList=C(new S(o.headers)));let l=E.randomBytes(16).toString(`base64`);c.headersList.append(`sec-websocket-key`,l),c.headersList.append(`sec-websocket-version`,`13`);for(let e of t)c.headersList.append(`sec-websocket-protocol`,e);return c.headersList.append(`sec-websocket-extensions`,`permessage-deflate; client_max_window_bits`),x({request:c,useParallelQueue:!0,dispatcher:o.dispatcher,processResponse(e){if(e.type===`error`||e.status!==101){p(i,`Received network error or non-101 status code.`);return}if(t.length!==0&&!e.headersList.get(`Sec-WebSocket-Protocol`)){p(i,`Server did not respond with sent protocols.`);return}if(e.headersList.get(`Upgrade`)?.toLowerCase()!==`websocket`){p(i,`Server did not set Upgrade header to "websocket".`);return}if(e.headersList.get(`Connection`)?.toLowerCase()!==`upgrade`){p(i,`Server did not set Connection header to "upgrade".`);return}if(e.headersList.get(`Sec-WebSocket-Accept`)!==E.createHash(`sha1`).update(l+n).digest(`base64`)){p(i,`Incorrect hash received in Sec-WebSocket-Accept header.`);return}let r=e.headersList.get(`Sec-WebSocket-Extensions`),o;if(r!==null&&(o=_(r),!o.has(`permessage-deflate`))){p(i,`Sec-WebSocket-Extensions header does not match.`);return}let s=e.headersList.get(`Sec-WebSocket-Protocol`);if(s!==null&&!w(`sec-websocket-protocol`,c.headersList).includes(s)){p(i,`Protocol was not set in the opening handshake.`);return}e.socket.on(`data`,k),e.socket.on(`close`,A),e.socket.on(`error`,j),v.open.hasSubscribers&&v.open.publish({address:e.socket.address(),protocol:s,extensions:r}),a(e,o)}})}function O(e,t,n,l){if(!(m(e)||h(e)))if(!g(e))p(e,`Connection was closed before it was established.`),e[s]=r.CLOSING;else if(e[c]===i.NOT_SENT){e[c]=i.PROCESSING;let u=new T;t!==void 0&&n===void 0?(u.frameData=Buffer.allocUnsafe(2),u.frameData.writeUInt16BE(t,0)):t!==void 0&&n!==void 0?(u.frameData=Buffer.allocUnsafe(2+l),u.frameData.writeUInt16BE(t,0),u.frameData.write(n,2,`utf-8`)):u.frameData=a,e[d].socket.write(u.createFrame(o.CLOSE)),e[c]=i.SENT,e[s]=r.CLOSING}else e[s]=r.CLOSING}function k(e){this.ws[l].write(e)||this.pause()}function A(){let{ws:e}=this,{[d]:t}=e;t.socket.off(`data`,k),t.socket.off(`close`,A),t.socket.off(`error`,j);let n=e[c]===i.SENT&&e[u],a=1005,o=``,p=e[l].closingInfo;p&&!p.error?(a=p.code??1005,o=p.reason):e[u]||(a=1006),e[s]=r.CLOSED,f(`close`,e,(e,t)=>new y(e,t),{wasClean:n,code:a,reason:o}),v.close.hasSubscribers&&v.close.publish({websocket:e,code:a,reason:o})}function j(e){let{ws:t}=this;t[s]=r.CLOSING,v.socketError.hasSubscribers&&v.socketError.publish(e),this.destroy()}t.exports={establishWebSocketConnection:D,closeWebSocketConnection:O}})),dt=o(((e,t)=>{var{createInflateRaw:n,Z_DEFAULT_WINDOWBITS:r}=require(`node:zlib`),{isValidClientWindowBits:i}=ct(),{MessageSizeExceededError:a}=M(),o=Buffer.from([0,0,255,255]),s=Symbol(`kBuffer`),c=Symbol(`kLength`);t.exports={PerMessageDeflate:class{#e;#t={};#n=0;constructor(e,t){this.#t.serverNoContextTakeover=e.has(`server_no_context_takeover`),this.#t.serverMaxWindowBits=e.get(`server_max_window_bits`),this.#n=t.maxPayloadSize}decompress(e,t,l){if(!this.#e){let e=r;if(this.#t.serverMaxWindowBits){if(!i(this.#t.serverMaxWindowBits)){l(Error(`Invalid server_max_window_bits`));return}e=Number.parseInt(this.#t.serverMaxWindowBits)}try{this.#e=n({windowBits:e})}catch(e){l(e);return}this.#e[s]=[],this.#e[c]=0,this.#e.on(`data`,e=>{if(this.#e[c]+=e.length,this.#n>0&&this.#e[c]>this.#n){l(new a),this.#e.removeAllListeners(),this.#e=null;return}this.#e[s].push(e)}),this.#e.on(`error`,e=>{this.#e=null,l(e)})}this.#e.write(e),t&&this.#e.write(o),this.#e.flush(()=>{if(!this.#e)return;let e=Buffer.concat(this.#e[s],this.#e[c]);this.#e[s].length=0,this.#e[c]=0,l(null,e)})}}}})),ft=o(((e,t)=>{var{Writable:n}=require(`node:stream`),r=require(`node:assert`),{parserStates:i,opcodes:a,states:o,emptyBuffer:s,sentCloseFrameState:c}=ot(),{kReadyState:l,kSentClose:u,kResponse:d,kReceivedClose:f}=st(),{channels:p}=I(),{isValidStatusCode:m,isValidOpcode:h,failWebsocketConnection:g,websocketMessageReceived:_,utf8Decode:v,isControlFrame:y,isTextBinaryFrame:b,isContinuationFrame:x}=ct(),{WebsocketFrameSend:S}=lt(),{closeWebSocketConnection:C}=ut(),{PerMessageDeflate:w}=dt(),{MessageSizeExceededError:T}=M();t.exports={ByteParser:class extends n{#e=[];#t=0;#n=0;#r=!1;#i=i.INFO;#a={};#o=[];#s;#c;constructor(e,t,n={}){super(),this.ws=e,this.#s=t??new Map,this.#c=n.maxPayloadSize??0,this.#s.has(`permessage-deflate`)&&this.#s.set(`permessage-deflate`,new w(t,n))}_write(e,t,n){this.#e.push(e),this.#n+=e.length,this.#r=!0,this.run(n)}#l(){return this.#c>0&&!y(this.#a.opcode)&&this.#a.payloadLength>this.#c?(g(this.ws,`Payload size exceeds maximum allowed size`),!1):!0}run(e){for(;this.#r;)if(this.#i===i.INFO){if(this.#n<2)return e();let t=this.consume(2),n=(t[0]&128)!=0,r=t[0]&15,o=(t[1]&128)==128,s=!n&&r!==a.CONTINUATION,c=t[1]&127,l=t[0]&64,u=t[0]&32,d=t[0]&16;if(!h(r))return g(this.ws,`Invalid opcode received`),e();if(o)return g(this.ws,`Frame cannot be masked`),e();if(l!==0&&!this.#s.has(`permessage-deflate`)){g(this.ws,`Expected RSV1 to be clear.`);return}if(u!==0||d!==0){g(this.ws,`RSV1, RSV2, RSV3 must be clear`);return}if(s&&!b(r)){g(this.ws,`Invalid frame type was fragmented.`);return}if(b(r)&&this.#o.length>0){g(this.ws,`Expected continuation frame`);return}if(this.#a.fragmented&&s){g(this.ws,`Fragmented frame exceeded 125 bytes.`);return}if((c>125||s)&&y(r)){g(this.ws,`Control frame either too large or fragmented`);return}if(x(r)&&this.#o.length===0&&!this.#a.compressed){g(this.ws,`Unexpected continuation frame`);return}if(c<=125){if(this.#a.payloadLength=c,this.#i=i.READ_DATA,!this.#l())return}else c===126?this.#i=i.PAYLOADLENGTH_16:c===127&&(this.#i=i.PAYLOADLENGTH_64);b(r)&&(this.#a.binaryType=r,this.#a.compressed=l!==0),this.#a.opcode=r,this.#a.masked=o,this.#a.fin=n,this.#a.fragmented=s}else if(this.#i===i.PAYLOADLENGTH_16){if(this.#n<2)return e();let t=this.consume(2);if(this.#a.payloadLength=t.readUInt16BE(0),this.#i=i.READ_DATA,!this.#l())return}else if(this.#i===i.PAYLOADLENGTH_64){if(this.#n<8)return e();let t=this.consume(8),n=t.readUInt32BE(0),r=t.readUInt32BE(4);if(n!==0||r>2**31-1){g(this.ws,`Received payload length > 2^31 bytes.`);return}if(this.#a.payloadLength=r,this.#i=i.READ_DATA,!this.#l())return}else if(this.#i===i.READ_DATA){if(this.#n{if(t){g(this.ws,t.message);return}if(this.writeFragments(n),this.#c>0&&this.#t>this.#c){g(this.ws,new T().message);return}if(!this.#a.fin){this.#i=i.INFO,this.#r=!0,this.run(e);return}_(this.ws,this.#a.binaryType,this.consumeFragments()),this.#r=!0,this.#i=i.INFO,this.run(e)}),this.#r=!1;break}else{if(this.writeFragments(t),this.#c>0&&this.#t>this.#c){g(this.ws,new T().message);return}!this.#a.fragmented&&this.#a.fin&&_(this.ws,this.#a.binaryType,this.consumeFragments()),this.#i=i.INFO}}}consume(e){if(e>this.#n)throw Error(`Called consume() before buffers satiated.`);if(e===0)return s;if(this.#e[0].length===e)return this.#n-=this.#e[0].length,this.#e.shift();let t=Buffer.allocUnsafe(e),n=0;for(;n!==e;){let r=this.#e[0],{length:i}=r;if(i+n===e){t.set(this.#e.shift(),n);break}else if(i+n>e){t.set(r.subarray(0,e-n),n),this.#e[0]=r.subarray(e-n);break}else t.set(this.#e.shift(),n),n+=r.length}return this.#n-=e,t}writeFragments(e){this.#t+=e.length,this.#o.push(e)}consumeFragments(){let e=this.#o;if(e.length===1)return this.#t=0,e.shift();let t=Buffer.concat(e,this.#t);return this.#o=[],this.#t=0,t}parseCloseBody(e){r(e.length!==1);let t;if(e.length>=2&&(t=e.readUInt16BE(0)),t!==void 0&&!m(t))return{code:1002,reason:`Invalid status code`,error:!0};let n=e.subarray(2);n[0]===239&&n[1]===187&&n[2]===191&&(n=n.subarray(3));try{n=v(n)}catch{return{code:1007,reason:`Invalid UTF-8`,error:!0}}return{code:t,reason:n,error:!1}}parseControlFrame(e){let{opcode:t,payloadLength:n}=this.#a;if(t===a.CLOSE){if(n===1)return g(this.ws,`Received close frame with a 1-byte body.`),!1;if(this.#a.closeInfo=this.parseCloseBody(e),this.#a.closeInfo.error){let{code:e,reason:t}=this.#a.closeInfo;return C(this.ws,e,t,t.length),g(this.ws,t),!1}if(this.ws[u]!==c.SENT){let e=s;this.#a.closeInfo.code&&(e=Buffer.allocUnsafe(2),e.writeUInt16BE(this.#a.closeInfo.code,0));let t=new S(e);this.ws[d].socket.write(t.createFrame(a.CLOSE),e=>{e||(this.ws[u]=c.SENT)})}return this.ws[l]=o.CLOSING,this.ws[f]=!0,!1}else if(t===a.PING){if(!this.ws[f]){let t=new S(e);this.ws[d].socket.write(t.createFrame(a.PONG)),p.ping.hasSubscribers&&p.ping.publish({payload:e})}}else t===a.PONG&&p.pong.hasSubscribers&&p.pong.publish({payload:e});return!0}get closingInfo(){return this.#a.closeInfo}}}})),pt=o(((e,t)=>{var{WebsocketFrameSend:n}=lt(),{opcodes:r,sendHints:i}=ot(),a=ue(),o=Buffer[Symbol.species],s=class{#e=new a;#t=!1;#n;constructor(e){this.#n=e}add(e,t,n){if(n!==i.blob){let r=c(e,n);if(!this.#t)this.#n.write(r,t);else{let e={promise:null,callback:t,frame:r};this.#e.push(e)}return}let r={promise:e.arrayBuffer().then(e=>{r.promise=null,r.frame=c(e,n)}),callback:t,frame:null};this.#e.push(r),this.#t||this.#r()}async#r(){this.#t=!0;let e=this.#e;for(;!e.isEmpty();){let t=e.shift();t.promise!==null&&await t.promise,this.#n.write(t.frame,t.callback),t.callback=t.frame=null}this.#t=!1}};function c(e,t){return new n(l(e,t)).createFrame(t===i.string?r.TEXT:r.BINARY)}function l(e,t){switch(t){case i.string:return Buffer.from(e);case i.arrayBuffer:case i.blob:return new o(e);case i.typedArray:return new o(e.buffer,e.byteOffset,e.byteLength)}}t.exports={SendQueue:s}})),mt=o(((e,t)=>{var{webidl:n}=U(),{URLSerializer:r}=H(),{environmentSettingsObject:i}=W(),{staticPropertyDescriptors:a,states:o,sentCloseFrameState:s,sendHints:c}=ot(),{kWebSocketURL:l,kReadyState:u,kController:d,kBinaryType:f,kResponse:p,kSentClose:m,kByteParser:h}=st(),{isConnecting:g,isEstablished:_,isClosing:v,isValidSubprotocol:y,fireEvent:b}=ct(),{establishWebSocketConnection:x,closeWebSocketConnection:S}=ut(),{ByteParser:C}=ft(),{kEnumerableProperty:w,isBlobLike:T}=F(),{getGlobalDispatcher:E}=Fe(),{types:D}=require(`node:util`),{ErrorEvent:O,CloseEvent:k}=at(),{SendQueue:A}=pt(),j=class e extends EventTarget{#e={open:null,error:null,close:null,message:null};#t=0;#n=``;#r=``;#i;constructor(t,r=[]){super(),n.util.markAsUncloneable(this);let a=`WebSocket constructor`;n.argumentLengthCheck(arguments,1,a);let o=n.converters[`DOMString or sequence or WebSocketInit`](r,a,`options`);t=n.converters.USVString(t,a,`url`),r=o.protocols;let c=i.settingsObject.baseUrl,p;try{p=new URL(t,c)}catch(e){throw new DOMException(e,`SyntaxError`)}if(p.protocol===`http:`?p.protocol=`ws:`:p.protocol===`https:`&&(p.protocol=`wss:`),p.protocol!==`ws:`&&p.protocol!==`wss:`)throw new DOMException(`Expected a ws: or wss: protocol, got ${p.protocol}`,`SyntaxError`);if(p.hash||p.href.endsWith(`#`))throw new DOMException(`Got fragment`,`SyntaxError`);if(typeof r==`string`&&(r=[r]),r.length!==new Set(r.map(e=>e.toLowerCase())).size||r.length>0&&!r.every(e=>y(e)))throw new DOMException(`Invalid Sec-WebSocket-Protocol value`,`SyntaxError`);this[l]=new URL(p.href);let h=i.settingsObject;this[d]=x(p,r,h,this,(e,t)=>this.#a(e,t),o),this[u]=e.CONNECTING,this[m]=s.NOT_SENT,this[f]=`blob`}close(t=void 0,r=void 0){n.brandCheck(this,e);let i=`WebSocket.close`;if(t!==void 0&&(t=n.converters[`unsigned short`](t,i,`code`,{clamp:!0})),r!==void 0&&(r=n.converters.USVString(r,i,`reason`)),t!==void 0&&t!==1e3&&(t<3e3||t>4999))throw new DOMException(`invalid code`,`InvalidAccessError`);let a=0;if(r!==void 0&&(a=Buffer.byteLength(r),a>123))throw new DOMException(`Reason must be less than 123 bytes; received ${a}`,`SyntaxError`);S(this,t,r,a)}send(t){n.brandCheck(this,e);let r=`WebSocket.send`;if(n.argumentLengthCheck(arguments,1,r),t=n.converters.WebSocketSendData(t,r,`data`),g(this))throw new DOMException(`Sent before connected.`,`InvalidStateError`);if(!(!_(this)||v(this)))if(typeof t==`string`){let e=Buffer.byteLength(t);this.#t+=e,this.#i.add(t,()=>{this.#t-=e},c.string)}else D.isArrayBuffer(t)?(this.#t+=t.byteLength,this.#i.add(t,()=>{this.#t-=t.byteLength},c.arrayBuffer)):ArrayBuffer.isView(t)?(this.#t+=t.byteLength,this.#i.add(t,()=>{this.#t-=t.byteLength},c.typedArray)):T(t)&&(this.#t+=t.size,this.#i.add(t,()=>{this.#t-=t.size},c.blob))}get readyState(){return n.brandCheck(this,e),this[u]}get bufferedAmount(){return n.brandCheck(this,e),this.#t}get url(){return n.brandCheck(this,e),r(this[l])}get extensions(){return n.brandCheck(this,e),this.#r}get protocol(){return n.brandCheck(this,e),this.#n}get onopen(){return n.brandCheck(this,e),this.#e.open}set onopen(t){n.brandCheck(this,e),this.#e.open&&this.removeEventListener(`open`,this.#e.open),typeof t==`function`?(this.#e.open=t,this.addEventListener(`open`,t)):this.#e.open=null}get onerror(){return n.brandCheck(this,e),this.#e.error}set onerror(t){n.brandCheck(this,e),this.#e.error&&this.removeEventListener(`error`,this.#e.error),typeof t==`function`?(this.#e.error=t,this.addEventListener(`error`,t)):this.#e.error=null}get onclose(){return n.brandCheck(this,e),this.#e.close}set onclose(t){n.brandCheck(this,e),this.#e.close&&this.removeEventListener(`close`,this.#e.close),typeof t==`function`?(this.#e.close=t,this.addEventListener(`close`,t)):this.#e.close=null}get onmessage(){return n.brandCheck(this,e),this.#e.message}set onmessage(t){n.brandCheck(this,e),this.#e.message&&this.removeEventListener(`message`,this.#e.message),typeof t==`function`?(this.#e.message=t,this.addEventListener(`message`,t)):this.#e.message=null}get binaryType(){return n.brandCheck(this,e),this[f]}set binaryType(t){n.brandCheck(this,e),t!==`blob`&&t!==`arraybuffer`?this[f]=`blob`:this[f]=t}#a(e,t){this[p]=e;let n=this[d]?.dispatcher?.webSocketOptions?.maxPayloadSize,r=new C(this,t,{maxPayloadSize:n});r.on(`drain`,M),r.on(`error`,N.bind(this)),e.socket.ws=this,this[h]=r,this.#i=new A(e.socket),this[u]=o.OPEN;let i=e.headersList.get(`sec-websocket-extensions`);i!==null&&(this.#r=i);let a=e.headersList.get(`sec-websocket-protocol`);a!==null&&(this.#n=a),b(`open`,this)}};j.CONNECTING=j.prototype.CONNECTING=o.CONNECTING,j.OPEN=j.prototype.OPEN=o.OPEN,j.CLOSING=j.prototype.CLOSING=o.CLOSING,j.CLOSED=j.prototype.CLOSED=o.CLOSED,Object.defineProperties(j.prototype,{CONNECTING:a,OPEN:a,CLOSING:a,CLOSED:a,url:w,readyState:w,bufferedAmount:w,onopen:w,onerror:w,onclose:w,close:w,onmessage:w,binaryType:w,send:w,extensions:w,protocol:w,[Symbol.toStringTag]:{value:`WebSocket`,writable:!1,enumerable:!1,configurable:!0}}),Object.defineProperties(j,{CONNECTING:a,OPEN:a,CLOSING:a,CLOSED:a}),n.converters[`sequence`]=n.sequenceConverter(n.converters.DOMString),n.converters[`DOMString or sequence`]=function(e,t,r){return n.util.Type(e)===`Object`&&Symbol.iterator in e?n.converters[`sequence`](e):n.converters.DOMString(e,t,r)},n.converters.WebSocketInit=n.dictionaryConverter([{key:`protocols`,converter:n.converters[`DOMString or sequence`],defaultValue:()=>[]},{key:`dispatcher`,converter:n.converters.any,defaultValue:()=>E()},{key:`headers`,converter:n.nullableConverter(n.converters.HeadersInit)}]),n.converters[`DOMString or sequence or WebSocketInit`]=function(e){return n.util.Type(e)===`Object`&&!(Symbol.iterator in e)?n.converters.WebSocketInit(e):{protocols:n.converters[`DOMString or sequence`](e)}},n.converters.WebSocketSendData=function(e){if(n.util.Type(e)===`Object`){if(T(e))return n.converters.Blob(e,{strict:!1});if(ArrayBuffer.isView(e)||D.isArrayBuffer(e))return n.converters.BufferSource(e)}return n.converters.USVString(e)};function M(){this.ws[p].socket.resume()}function N(e){let t,n;e instanceof k?(t=e.reason,n=e.code):t=e.message,b(`error`,this,()=>new O(`error`,{error:e,message:t})),S(this,n)}t.exports={WebSocket:j}})),ht=o(((e,t)=>{function n(e){return e.indexOf(`\0`)===-1}function r(e){if(e.length===0)return!1;for(let t=0;t57)return!1;return!0}function i(e){return new Promise(t=>{setTimeout(t,e).unref()})}t.exports={isValidLastEventId:n,isASCIINumber:r,delay:i}})),gt=o(((e,t)=>{var{Transform:n}=require(`node:stream`),{isASCIINumber:r,isValidLastEventId:i}=ht(),a=[239,187,191],o=10,s=13,c=58,l=32;t.exports={EventSourceStream:class extends n{state=null;checkBOM=!0;crlfCheck=!1;eventEndCheck=!1;buffer=null;pos=0;event={data:void 0,event:void 0,id:void 0,retry:void 0};constructor(e={}){e.readableObjectMode=!0,super(e),this.state=e.eventSourceSettings||{},e.push&&(this.push=e.push)}_transform(e,t,n){if(e.length===0){n();return}if(this.buffer?this.buffer=Buffer.concat([this.buffer,e]):this.buffer=e,this.checkBOM)switch(this.buffer.length){case 1:if(this.buffer[0]===a[0]){n();return}this.checkBOM=!1,n();return;case 2:if(this.buffer[0]===a[0]&&this.buffer[1]===a[1]){n();return}this.checkBOM=!1;break;case 3:if(this.buffer[0]===a[0]&&this.buffer[1]===a[1]&&this.buffer[2]===a[2]){this.buffer=Buffer.alloc(0),this.checkBOM=!1,n();return}this.checkBOM=!1;break;default:this.buffer[0]===a[0]&&this.buffer[1]===a[1]&&this.buffer[2]===a[2]&&(this.buffer=this.buffer.subarray(3)),this.checkBOM=!1;break}for(;this.pos0&&(t[a]=o);break}}processEvent(e){e.retry&&r(e.retry)&&(this.state.reconnectionTime=parseInt(e.retry,10)),e.id&&i(e.id)&&(this.state.lastEventId=e.id),e.data!==void 0&&this.push({type:e.event||`message`,options:{data:e.data,lastEventId:this.state.lastEventId,origin:this.state.origin}})}clearEvent(){this.event={data:void 0,event:void 0,id:void 0,retry:void 0}}}}})),_t=o(((e,t)=>{var{pipeline:n}=require(`node:stream`),{fetching:r}=Ge(),{makeRequest:i}=We(),{webidl:a}=U(),{EventSourceStream:o}=gt(),{parseMIMEType:s}=H(),{createFastMessageEvent:c}=at(),{isNetworkError:l}=He(),{delay:u}=ht(),{kEnumerableProperty:d}=F(),{environmentSettingsObject:f}=W(),p=!1,m=3e3,h=0,g=1,_=2,v=`anonymous`,y=`use-credentials`,b=class e extends EventTarget{#e={open:null,error:null,message:null};#t=null;#n=!1;#r=h;#i=null;#a=null;#o;#s;constructor(e,t={}){super(),a.util.markAsUncloneable(this);let n=`EventSource constructor`;a.argumentLengthCheck(arguments,1,n),p||(p=!0,process.emitWarning(`EventSource is experimental, expect them to change at any time.`,{code:`UNDICI-ES`})),e=a.converters.USVString(e,n,`url`),t=a.converters.EventSourceInitDict(t,n,`eventSourceInitDict`),this.#o=t.dispatcher,this.#s={lastEventId:``,reconnectionTime:m};let r=f,o;try{o=new URL(e,r.settingsObject.baseUrl),this.#s.origin=o.origin}catch(e){throw new DOMException(e,`SyntaxError`)}this.#t=o.href;let s=v;t.withCredentials&&(s=y,this.#n=!0);let c={redirect:`follow`,keepalive:!0,mode:`cors`,credentials:s===`anonymous`?`same-origin`:`omit`,referrer:`no-referrer`};c.client=f.settingsObject,c.headersList=[[`accept`,{name:`accept`,value:`text/event-stream`}]],c.cache=`no-store`,c.initiator=`other`,c.urlList=[new URL(this.#t)],this.#i=i(c),this.#c()}get readyState(){return this.#r}get url(){return this.#t}get withCredentials(){return this.#n}#c(){if(this.#r===_)return;this.#r=h;let e={request:this.#i,dispatcher:this.#o};e.processResponseEndOfBody=e=>{l(e)&&(this.dispatchEvent(new Event(`error`)),this.close()),this.#l()},e.processResponse=e=>{if(l(e))if(e.aborted){this.close(),this.dispatchEvent(new Event(`error`));return}else{this.#l();return}let t=e.headersList.get(`content-type`,!0),r=t===null?`failure`:s(t),i=r!==`failure`&&r.essence===`text/event-stream`;if(e.status!==200||i===!1){this.close(),this.dispatchEvent(new Event(`error`));return}this.#r=g,this.dispatchEvent(new Event(`open`)),this.#s.origin=e.urlList[e.urlList.length-1].origin;let a=new o({eventSourceSettings:this.#s,push:e=>{this.dispatchEvent(c(e.type,e.options))}});n(e.body.stream,a,e=>{e?.aborted===!1&&(this.close(),this.dispatchEvent(new Event(`error`)))})},this.#a=r(e)}async#l(){this.#r!==_&&(this.#r=h,this.dispatchEvent(new Event(`error`)),await u(this.#s.reconnectionTime),this.#r===h&&(this.#s.lastEventId.length&&this.#i.headersList.set(`last-event-id`,this.#s.lastEventId,!0),this.#c()))}close(){a.brandCheck(this,e),this.#r!==_&&(this.#r=_,this.#a.abort(),this.#i=null)}get onopen(){return this.#e.open}set onopen(e){this.#e.open&&this.removeEventListener(`open`,this.#e.open),typeof e==`function`?(this.#e.open=e,this.addEventListener(`open`,e)):this.#e.open=null}get onmessage(){return this.#e.message}set onmessage(e){this.#e.message&&this.removeEventListener(`message`,this.#e.message),typeof e==`function`?(this.#e.message=e,this.addEventListener(`message`,e)):this.#e.message=null}get onerror(){return this.#e.error}set onerror(e){this.#e.error&&this.removeEventListener(`error`,this.#e.error),typeof e==`function`?(this.#e.error=e,this.addEventListener(`error`,e)):this.#e.error=null}},x={CONNECTING:{__proto__:null,configurable:!1,enumerable:!0,value:h,writable:!1},OPEN:{__proto__:null,configurable:!1,enumerable:!0,value:g,writable:!1},CLOSED:{__proto__:null,configurable:!1,enumerable:!0,value:_,writable:!1}};Object.defineProperties(b,x),Object.defineProperties(b.prototype,x),Object.defineProperties(b.prototype,{close:d,onerror:d,onmessage:d,onopen:d,readyState:d,url:d,withCredentials:d}),a.converters.EventSourceInitDict=a.dictionaryConverter([{key:`withCredentials`,converter:a.converters.boolean,defaultValue:()=>!1},{key:`dispatcher`,converter:a.converters.any}]),t.exports={EventSource:b,defaultReconnectionTime:m}})),vt=o(((e,t)=>{var n=X(),r=R(),i=pe(),a=Z(),o=Q(),s=me(),c=$(),l=ge(),u=M(),d=F(),{InvalidArgumentError:f}=u,p=Te(),m=V(),h=Ae(),g=Pe(),_=je(),v=Ee(),y=he(),{getGlobalDispatcher:b,setGlobalDispatcher:x}=Fe(),S=Ie(),C=ce(),w=le();Object.assign(r.prototype,p),t.exports.Dispatcher=r,t.exports.Client=n,t.exports.Pool=i,t.exports.BalancedPool=a,t.exports.Agent=o,t.exports.ProxyAgent=s,t.exports.EnvHttpProxyAgent=c,t.exports.RetryAgent=l,t.exports.RetryHandler=y,t.exports.DecoratorHandler=S,t.exports.RedirectHandler=C,t.exports.createRedirectInterceptor=w,t.exports.interceptors={redirect:Le(),retry:Re(),dump:ze(),dns:Be()},t.exports.buildConnector=m,t.exports.errors=u,t.exports.util={parseHeaders:d.parseHeaders,headerNameToString:d.headerNameToString};function T(e){return(t,n,r)=>{if(typeof n==`function`&&(r=n,n=null),!t||typeof t!=`string`&&typeof t!=`object`&&!(t instanceof URL))throw new f(`invalid url`);if(n!=null&&typeof n!=`object`)throw new f(`invalid opts`);if(n&&n.path!=null){if(typeof n.path!=`string`)throw new f(`invalid opts.path`);let e=n.path;n.path.startsWith(`/`)||(e=`/${e}`),t=new URL(d.parseOrigin(t).origin+e)}else n||=typeof t==`object`?t:{},t=d.parseURL(t);let{agent:i,dispatcher:a=b()}=n;if(i)throw new f(`unsupported opts.agent. Did you mean opts.client?`);return e.call(a,{...n,origin:t.origin,path:t.search?`${t.pathname}${t.search}`:t.pathname,method:n.method||(n.body?`PUT`:`GET`)},r)}}t.exports.setGlobalDispatcher=x,t.exports.getGlobalDispatcher=b;var E=Ge().fetch;t.exports.fetch=async function(e,t=void 0){try{return await E(e,t)}catch(e){throw e&&typeof e==`object`&&Error.captureStackTrace(e),e}},t.exports.Headers=Ve().Headers,t.exports.Response=He().Response,t.exports.Request=We().Request,t.exports.FormData=q().FormData,t.exports.File=globalThis.File??require(`node:buffer`).File,t.exports.FileReader=Xe().FileReader;var{setGlobalOrigin:D,getGlobalOrigin:O}=ae();t.exports.setGlobalOrigin=D,t.exports.getGlobalOrigin=O;var{CacheStorage:k}=et(),{kConstruct:A}=Ze();t.exports.caches=new k(A);var{deleteCookie:j,getCookies:N,getSetCookies:P,setCookie:I}=it();t.exports.deleteCookie=j,t.exports.getCookies=N,t.exports.getSetCookies=P,t.exports.setCookie=I;var{parseMIMEType:L,serializeAMimeType:z}=H();t.exports.parseMIMEType=L,t.exports.serializeAMimeType=z;var{CloseEvent:B,ErrorEvent:ee,MessageEvent:te}=at();t.exports.WebSocket=mt().WebSocket,t.exports.CloseEvent=B,t.exports.ErrorEvent=ee,t.exports.MessageEvent=te,t.exports.request=T(p.request),t.exports.stream=T(p.stream),t.exports.pipeline=T(p.pipeline),t.exports.connect=T(p.connect),t.exports.upgrade=T(p.upgrade),t.exports.MockClient=h,t.exports.MockPool=_,t.exports.MockAgent=g,t.exports.mockErrors=v;var{EventSource:ne}=_t();t.exports.EventSource=ne}));A(),vt();var yt;(function(e){e[e.OK=200]=`OK`,e[e.MultipleChoices=300]=`MultipleChoices`,e[e.MovedPermanently=301]=`MovedPermanently`,e[e.ResourceMoved=302]=`ResourceMoved`,e[e.SeeOther=303]=`SeeOther`,e[e.NotModified=304]=`NotModified`,e[e.UseProxy=305]=`UseProxy`,e[e.SwitchProxy=306]=`SwitchProxy`,e[e.TemporaryRedirect=307]=`TemporaryRedirect`,e[e.PermanentRedirect=308]=`PermanentRedirect`,e[e.BadRequest=400]=`BadRequest`,e[e.Unauthorized=401]=`Unauthorized`,e[e.PaymentRequired=402]=`PaymentRequired`,e[e.Forbidden=403]=`Forbidden`,e[e.NotFound=404]=`NotFound`,e[e.MethodNotAllowed=405]=`MethodNotAllowed`,e[e.NotAcceptable=406]=`NotAcceptable`,e[e.ProxyAuthenticationRequired=407]=`ProxyAuthenticationRequired`,e[e.RequestTimeout=408]=`RequestTimeout`,e[e.Conflict=409]=`Conflict`,e[e.Gone=410]=`Gone`,e[e.TooManyRequests=429]=`TooManyRequests`,e[e.InternalServerError=500]=`InternalServerError`,e[e.NotImplemented=501]=`NotImplemented`,e[e.BadGateway=502]=`BadGateway`,e[e.ServiceUnavailable=503]=`ServiceUnavailable`,e[e.GatewayTimeout=504]=`GatewayTimeout`})(yt||={});var bt;(function(e){e.Accept=`accept`,e.ContentType=`content-type`})(bt||={});var xt;(function(e){e.ApplicationJson=`application/json`})(xt||={}),yt.MovedPermanently,yt.ResourceMoved,yt.SeeOther,yt.TemporaryRedirect,yt.PermanentRedirect,yt.BadGateway,yt.ServiceUnavailable,yt.GatewayTimeout;var St=function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},{access:Ct,appendFile:wt,writeFile:Tt}=p.promises,Et=`GITHUB_STEP_SUMMARY`;new class{constructor(){this._buffer=``}filePath(){return St(this,void 0,void 0,function*(){if(this._filePath)return this._filePath;let e=process.env[Et];if(!e)throw Error(`Unable to find environment variable for $${Et}. Check if your runtime environment supports job summaries.`);try{yield Ct(e,p.constants.R_OK|p.constants.W_OK)}catch{throw Error(`Unable to access summary file: '${e}'. Check if the file has correct read/write permissions.`)}return this._filePath=e,this._filePath})}wrap(e,t,n={}){let r=Object.entries(n).map(([e,t])=>` ${e}="${t}"`).join(``);return t?`<${e}${r}>${t}`:`<${e}${r}>`}write(e){return St(this,void 0,void 0,function*(){let t=!!e?.overwrite,n=yield this.filePath();return yield(t?Tt:wt)(n,this._buffer,{encoding:`utf8`}),this.emptyBuffer()})}clear(){return St(this,void 0,void 0,function*(){return this.emptyBuffer().write({overwrite:!0})})}stringify(){return this._buffer}isEmptyBuffer(){return this._buffer.length===0}emptyBuffer(){return this._buffer=``,this}addRaw(e,t=!1){return this._buffer+=e,t?this.addEOL():this}addEOL(){return this.addRaw(d.EOL)}addCodeBlock(e,t){let n=Object.assign({},t&&{lang:t}),r=this.wrap(`pre`,this.wrap(`code`,e),n);return this.addRaw(r).addEOL()}addList(e,t=!1){let n=t?`ol`:`ul`,r=e.map(e=>this.wrap(`li`,e)).join(``),i=this.wrap(n,r);return this.addRaw(i).addEOL()}addTable(e){let t=e.map(e=>{let t=e.map(e=>{if(typeof e==`string`)return this.wrap(`td`,e);let{header:t,data:n,colspan:r,rowspan:i}=e,a=t?`th`:`td`,o=Object.assign(Object.assign({},r&&{colspan:r}),i&&{rowspan:i});return this.wrap(a,n,o)}).join(``);return this.wrap(`tr`,t)}).join(``),n=this.wrap(`table`,t);return this.addRaw(n).addEOL()}addDetails(e,t){let n=this.wrap(`details`,this.wrap(`summary`,e)+t);return this.addRaw(n).addEOL()}addImage(e,t,n){let{width:r,height:i}=n||{},a=Object.assign(Object.assign({},r&&{width:r}),i&&{height:i}),o=this.wrap(`img`,null,Object.assign({src:e,alt:t},a));return this.addRaw(o).addEOL()}addHeading(e,t){let n=`h${t}`,r=[`h1`,`h2`,`h3`,`h4`,`h5`,`h6`].includes(n)?n:`h1`,i=this.wrap(r,e);return this.addRaw(i).addEOL()}addSeparator(){let e=this.wrap(`hr`,null);return this.addRaw(e).addEOL()}addBreak(){let e=this.wrap(`br`,null);return this.addRaw(e).addEOL()}addQuote(e,t){let n=Object.assign({},t&&{cite:t}),r=this.wrap(`blockquote`,e,n);return this.addRaw(r).addEOL()}addLink(e,t){let n=this.wrap(`a`,e,{href:t});return this.addRaw(n).addEOL()}};var Dt=function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},{chmod:Ot,copyFile:kt,lstat:At,mkdir:jt,open:Mt,readdir:Nt,rename:Pt,rm:Ft,rmdir:It,stat:Lt,symlink:Rt,unlink:zt}=p.promises,Bt=process.platform===`win32`;p.constants.O_RDONLY;function Vt(e){if(e=Ut(e),!e)throw Error(`isRooted() parameter "p" cannot be empty`);return Bt?e.startsWith(`\\`)||/^[A-Z]:/i.test(e):e.startsWith(`/`)}function Ht(e,t){return Dt(this,void 0,void 0,function*(){let n;try{n=yield Lt(e)}catch(t){t.code!==`ENOENT`&&console.log(`Unexpected error attempting to determine if executable file exists '${e}': ${t}`)}if(n&&n.isFile()){if(Bt){let n=m.extname(e).toUpperCase();if(t.some(e=>e.toUpperCase()===n))return e}else if(Wt(n))return e}let r=e;for(let i of t){e=r+i,n=void 0;try{n=yield Lt(e)}catch(t){t.code!==`ENOENT`&&console.log(`Unexpected error attempting to determine if executable file exists '${e}': ${t}`)}if(n&&n.isFile()){if(Bt){try{let t=m.dirname(e),n=m.basename(e).toUpperCase();for(let r of yield Nt(t))if(n===r.toUpperCase()){e=m.join(t,r);break}}catch(t){console.log(`Unexpected error attempting to determine the actual case of the file '${e}': ${t}`)}return e}else if(Wt(n))return e}}return``})}function Ut(e){return e||=``,Bt?(e=e.replace(/\//g,`\\`),e.replace(/\\\\+/g,`\\`)):e.replace(/\/\/+/g,`/`)}function Wt(e){return(e.mode&1)>0||(e.mode&8)>0&&process.getgid!==void 0&&e.gid===process.getgid()||(e.mode&64)>0&&process.getuid!==void 0&&e.uid===process.getuid()}var Gt=function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})};function Kt(e,t){return Gt(this,void 0,void 0,function*(){if(!e)throw Error(`parameter 'tool' is required`);if(t){let t=yield Kt(e,!1);if(!t)throw Error(Bt?`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`:`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`);return t}let n=yield qt(e);return n&&n.length>0?n[0]:``})}function qt(e){return Gt(this,void 0,void 0,function*(){if(!e)throw Error(`parameter 'tool' is required`);let t=[];if(Bt&&process.env.PATHEXT)for(let e of process.env.PATHEXT.split(m.delimiter))e&&t.push(e);if(Vt(e)){let n=yield Ht(e,t);return n?[n]:[]}if(e.includes(m.sep))return[];let n=[];if(process.env.PATH)for(let e of process.env.PATH.split(m.delimiter))e&&n.push(e);let r=[];for(let i of n){let n=yield Ht(m.join(i,e),t);n&&r.push(n)}return r})}process.platform,h.EventEmitter,h.EventEmitter,d.default.platform(),d.default.arch();var Jt;(function(e){e[e.Success=0]=`Success`,e[e.Failure=1]=`Failure`})(Jt||={});function Yt(e,t){let n=process.env[`INPUT_${e.replace(/ /g,`_`).toUpperCase()}`]||``;if(t&&t.required&&!n)throw Error(`Input required and not supplied: ${e}`);return t&&t.trimWhitespace===!1?n:n.trim()}function Xt(e,t){let n=Yt(e,t).split(` -`).filter(e=>e!==``);return t&&t.trimWhitespace===!1?n:n.map(e=>e.trim())}function Zt(e,t){let n=[`true`,`True`,`TRUE`],r=[`false`,`False`,`FALSE`],i=Yt(e,t);if(n.includes(i))return!0;if(r.includes(i))return!1;throw TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${e}\nSupport boolean input list: \`true | True | TRUE | false | False | FALSE\``)}function Qt(e,t){if(process.env.GITHUB_OUTPUT)return D(`OUTPUT`,O(e,t));process.stdout.write(d.EOL),S(`set-output`,{name:e},b(t))}function $t(e){process.exitCode=Jt.Failure,en(e)}function en(e,t={}){S(`error`,x(t),e instanceof Error?e.toString():e)}function tn(e,t={}){S(`warning`,x(t),e instanceof Error?e.toString():e)}function nn(e){process.stdout.write(e+d.EOL)}var rn=``;function an(e){let t=e<0?`-`:``,n=Math.abs(e);return n<1024?`${t}${n} B`:`${t}${(n/1024).toFixed(1)} KiB`}function on(e,t){let n=an(e);return t===null?n:`${n} (${t>0?`+`:``}${t.toFixed(2)}%)`}function sn(e){return e.replace(/\\/g,`\\\\`).replace(/\|/g,`\\|`)}function cn(e){let t=sn(e),n=t.match(/`+/g)??[],r=Math.max(0,...n.map(e=>e.length))+1,i="`".repeat(r),a=t.startsWith("`")||t.endsWith("`")?` `:``;return`${i}${a}${t}${a}${i}`}function ln(e){return e===null?`⚪`:e<=1?`🟢`:e<=3?`🔵`:e<=6?`🟡`:e<=9?`🟠`:`🔴`}function un(e){return`| ${cn(e.path)} | ${an(e.baselineBytes)} | ${an(e.currentBytes)} | ${on(e.deltaBytes,e.deltaPercent)} | ${ln(e.deltaPercent)} |`}function dn(e){let t=e.latest?` latest`:``;return`${cn(e.version)}${t}`}function fn(e){if(!e.totals){let t=e.missingFiles.map(cn).join(`, `);return`| ${dn(e)} | n/a | n/a | Incomplete: missing ${t} | ⚪ |`}return`| ${dn(e)} | ${an(e.totals.baselineBytes)} | ${an(e.totals.currentBytes)} | ${on(e.totals.deltaBytes,e.totals.deltaPercent)} | ${ln(e.totals.deltaPercent)} |`}function pn(e){let t=e.files.map(un);return t.push(`| **Total** | **${an(e.totals.baselineBytes)}** | **${an(e.totals.currentBytes)}** | **${on(e.totals.deltaBytes,e.totals.deltaPercent)}** | **${ln(e.totals.deltaPercent)}** |`),[rn,``,`## Bundle Size Report`,``,`Compared current build against latest npm release ${cn(e.baseline.version)} for ${cn(e.packageName)}.`,``,`| File | Baseline gzip | Current gzip | Difference | Status |`,`|---|---:|---:|---:|:---:|`,...t,``,`
`,`Historical comparison: latest + 10 previous npm releases`,``,`| Release | Baseline gzip | Current gzip | Difference | Status |`,`|---|---:|---:|---:|:---:|`,...e.history.map(fn),``,`
`].join(` -`)}function mn(e){let t=e.trim().replace(/\\/g,`/`);if(/^[A-Za-z]:\//.test(t)||t.startsWith(`//`))throw Error(`Configured file path must be relative and stay inside the project: ${e}`);let n=l.default.posix.normalize(t);if(!n||n===`.`)throw Error(`Configured file paths must not be empty.`);if(n.startsWith(`/`)||n===`..`||n.startsWith(`../`))throw Error(`Configured file path must be relative and stay inside the project: ${e}`);return n}function hn(e){let t=e.split(/\r?\n/).map(e=>e.trim()).filter(Boolean).map(mn);if(t.length===0)throw Error(`At least one file path must be provided via the files input.`);return[...new Set(t)]}function gn(e,t){let n=l.default.resolve(e),r=l.default.resolve(n,t),i=l.default.relative(n,r);if(i===``||i===`..`||i.startsWith(`..${l.default.sep}`)||l.default.isAbsolute(i))throw Error(`Path must stay inside the project root: ${t}`);return r}var _n=(0,g.promisify)(_.gzip);async function vn(e){return(await _n(e,{level:_.constants.Z_BEST_COMPRESSION})).length}function yn(e,t){return t===0?null:Number(((e-t)/t*100).toFixed(2))}async function bn(e,t,n,r){let[i]=r;if(!i)throw Error(`At least one npm release baseline is required.`);let a=[];for(let t of r)a.push(await xn(e,n,t,t.latest));let[o]=a;if(!o.totals)throw Error(`Latest release comparison is incomplete: ${i.version}`);return{metric:`gzip`,packageName:t,baseline:{version:i.version,uri:i.uri},localRoot:e,files:o.files,totals:o.totals,history:a}}async function xn(e,t,n,r){let i=[],a=[];for(let o of t){let t=n.files.get(o);if(!t){if(r)throw Error(`Baseline file not found in latest release ${n.version}: ${o}`);a.push(o);continue}let s=gn(e,o),c;try{c=await(0,y.readFile)(s)}catch(e){throw Error(`Local file not found: ${o} (${e instanceof Error?e.message:String(e)})`)}let l=await vn(t),u=await vn(c),d=u-l;i.push({path:o,baselineBytes:l,currentBytes:u,deltaBytes:d,deltaPercent:yn(u,l)})}let o=i.reduce((e,t)=>e+t.baselineBytes,0),s=i.reduce((e,t)=>e+t.currentBytes,0),c=a.length>0?null:{baselineBytes:o,currentBytes:s,deltaBytes:s-o,deltaPercent:yn(s,o)};return{version:n.version,uri:n.uri,latest:n.latest,complete:a.length===0,missingFiles:a,files:i,totals:c}}function Sn(e){let t=e.trim();if(!t)throw Error(`The package-name input is required.`);if(/\s/.test(t)||t.includes(`:`))throw Error(`Invalid npm package name: ${e}`);if(t.startsWith(`@`)){let n=t.split(`/`);if(n.length!==2||!n[0].slice(1)||!n[1])throw Error(`Invalid npm package name: ${e}`);return t}if(t.includes(`/`))throw Error(`Invalid npm package name: ${e}`);return t}function Cn(){let e=l.default.resolve(Yt(`path`,{required:!1})||`.`),t=Sn(Yt(`package-name`,{required:!0})),n=Xt(`files`,{required:!0}).join(` -`),r=mn(Yt(`output-file`,{required:!1})||`bundle-size-comparison.json`),i=Zt(`comment-pr`,{required:!1}),a=Yt(`github-token`,{required:!1});if(i&&!a)throw Error(`The github-token input is required when comment-pr is enabled.`);return{localRoot:e,packageName:t,filePaths:hn(n),outputFile:r,commentPr:i,githubToken:a}}var wn=`https://registry.npmjs.org`,Tn=10;function En(e){return`${wn}/${encodeURIComponent(e)}`}function Dn(e){return!e.includes(`-`)}function On(e,t,n){let r=n.versions?.[t]?.dist?.tarball;if(typeof r!=`string`||!r.trim())throw Error(`Npm package ${e} version ${t} is missing a tarball URL.`);let i;try{i=new URL(r)}catch{throw Error(`Npm package ${e} version ${t} has an invalid tarball URL.`)}if(i.protocol!==`http:`&&i.protocol!==`https:`)throw Error(`Npm package ${e} version ${t} has an unsupported tarball URL protocol: ${i.protocol}`);return r}function kn(e,t,n){let r=n.time?.[t],i=r?Date.parse(r):NaN;if(Number.isNaN(i))throw Error(`Npm package ${e} version ${t} is missing publish time metadata.`);return i}function An(e,t){let n=t[`dist-tags`]?.latest;if(typeof n!=`string`||!n||!t.versions?.[n])throw Error(`Npm package ${e} does not define a usable latest release.`);let r=kn(e,n,t);return[n,...Object.keys(t.versions).filter(e=>e!==n&&Dn(e)).map(n=>({version:n,publishedAt:kn(e,n,t)})).filter(e=>e.publishedAtt.publishedAt-e.publishedAt).slice(0,Tn).map(e=>e.version)].map((n,r)=>({version:n,uri:On(e,n,t),latest:r===0}))}async function jn(e){let t=En(e),n;try{n=await fetch(t)}catch(t){throw Error(`Failed to fetch npm metadata for ${e}: ${t instanceof Error?t.message:String(t)}`)}if(!n.ok)throw Error(`Failed to fetch npm metadata for ${e}: HTTP ${n.status} ${n.statusText}`);let r;try{r=await n.json()}catch(t){throw Error(`Failed to parse npm metadata for ${e}: ${t instanceof Error?t.message:String(t)}`)}return An(e,r)}var Mn=class extends Error{status;constructor(e,t){super(e),this.name=`GitHubApiError`,this.status=t}};async function Nn(){let e=process.env.GITHUB_EVENT_PATH;if(!e)return null;let t=JSON.parse(await(0,y.readFile)(e,`utf8`)),n=t.pull_request?.number??t.number;return typeof n==`number`?n:null}function Pn(){let e=process.env.GITHUB_REPOSITORY;if(!e)throw Error(`GITHUB_REPOSITORY is required to post a pull request comment.`);let[t,n]=e.split(`/`);if(!t||!n)throw Error(`Invalid GITHUB_REPOSITORY value: ${e}`);return{owner:t,repo:n}}async function Fn(e){try{let t=await e.json();return t.message?`: ${t.message}`:``}catch{return``}}function In(e){if(!e)return null;for(let t of e.split(`,`))if(t.includes(`rel="next"`))return/<([^>]+)>/.exec(t)?.[1]??null;return null}async function Ln(e,t,n,r){let i=await fetch(n,{method:t,headers:{accept:`application/vnd.github+json`,authorization:`Bearer ${e}`,"content-type":`application/json`,"user-agent":`axios-bundle-size-action`,"x-github-api-version":`2022-11-28`},body:r===void 0?void 0:JSON.stringify(r)});if(!i.ok){let e=await Fn(i),t=i.status===401||i.status===403?` Check that github-token has permission to write pull request or issue comments.`:``;throw new Mn(`GitHub comments API request failed (${i.status} ${i.statusText})${e}.${t}`,i.status)}return{body:await i.json(),nextUrl:In(i.headers.get(`link`))}}async function Rn(e,t,n,r){return(await Ln(e,t,n,r)).body}function zn(e){return e.body?.includes(rn)===!0}async function Bn(e,t){let n=t;for(;n;){let t=await Ln(e,`GET`,n),r=t.body.find(zn);if(r)return r;n=t.nextUrl}}async function Vn(e,t){let n=await Nn();if(n===null){nn(`Skipping bundle size PR comment because this run is not for a pull request.`);return}let{owner:r,repo:i}=Pn(),a=`https://api.github.com/repos/${r}/${i}`;try{let r=await Bn(e,`${a}/issues/${n}/comments?per_page=100`);if(r){await Rn(e,`PATCH`,`${a}/issues/comments/${r.id}`,{body:t}),nn(`Updated existing bundle size PR comment.`);return}await Rn(e,`POST`,`${a}/issues/${n}/comments`,{body:t}),nn(`Created bundle size PR comment.`)}catch(e){if(e instanceof Mn&&(e.status===401||e.status===403)){tn(`Skipping bundle size PR comment: ${e.message}`);return}throw e}}async function Hn(e,t,n){let r=gn(e,t);return await(0,y.mkdir)(l.default.dirname(r),{recursive:!0}),await(0,y.writeFile)(r,`${JSON.stringify(n,null,2)}\n`,`utf8`),r}var Un=(0,g.promisify)(_.gunzip),Wn=512;async function Gn(e){let t;try{t=await fetch(e)}catch(t){throw Error(`Failed to download tarball URI ${e}: ${t instanceof Error?t.message:String(t)}`)}if(!t.ok)throw Error(`Failed to download tarball URI ${e}: HTTP ${t.status} ${t.statusText}`);return Buffer.from(await t.arrayBuffer())}function Kn(e,t,n){let r=e.subarray(t,t+n),i=r.indexOf(0);return(i===-1?r:r.subarray(0,i)).toString(`utf8`).trim()}function qn(e,t){let n=Kn(e,124,12).replaceAll(`\0`,``).trim();if(!n)return 0;if(!/^[0-7]+$/.test(n))throw Error(`Tarball entry has invalid size field: ${t}`);let r=Number.parseInt(n,8);if(!Number.isSafeInteger(r))throw Error(`Tarball entry size is too large: ${t}`);return r}function Jn(e){return e.every(e=>e===0)}function Yn(e){return l.default.posix.normalize(e.replace(/\\/g,`/`)).replace(/^\.\//,``).replace(/^\/+/,``)}async function Xn(e){let t;try{t=await Un(e)}catch(e){throw Error(`Tarball is not a valid .tar.gz archive: ${e instanceof Error?e.message:String(e)}`)}let n=[],r=0;for(;r+Wn<=t.length;){let e=t.subarray(r,r+Wn);if(Jn(e))break;let i=Kn(e,0,100),a=Kn(e,345,155),o=Yn(a?`${a}/${i}`:i),s=qn(e,o),c=Kn(e,156,1),l=r+Wn,u=l+s;if(u>t.length)throw Error(`Tarball entry is truncated: ${o}`);o&&(c===``||c===`0`)&&n.push({path:o,content:Buffer.from(t.subarray(l,u))}),r=l+Math.ceil(s/Wn)*Wn}if(n.length===0)throw Error(`Tarball did not contain any regular files.`);return n}function Zn(e){let t=e.map(e=>e.split(`/`)[0]).filter(Boolean),[n]=t;return!n||t.some(e=>e!==n)?null:e.every(e=>e.includes(`/`))?n:null}function Qn(e){let t=new Map,n=Zn(e.map(e=>e.path));for(let r of e)t.set(r.path,r.content),n&&r.path.startsWith(`${n}/`)&&t.set(r.path.slice(n.length+1),r.content);return t}async function $n(){try{let e=Cn();nn(`Local project root: ${e.localRoot}`),nn(`Npm package baseline: ${e.packageName}`),nn(`Comparing ${e.filePaths.length} file(s) using gzip size.`);let t=await jn(e.packageName);nn(`Resolved ${t.length} npm release baseline(s).`);let n=[];for(let r of t){nn(`Downloading ${e.packageName}@${r.version}: ${r.uri}`);let t=await Gn(r.uri);n.push({...r,files:Qn(await Xn(t))})}let r=await bn(e.localRoot,e.packageName,e.filePaths,n),i=await Hn(e.localRoot,e.outputFile,r);nn(`Wrote bundle size comparison file: ${i}`),Qt(`comparison-file`,i),Qt(`size`,String(r.totals.currentBytes)),Qt(`total-current-gzip-size`,String(r.totals.currentBytes)),Qt(`total-baseline-gzip-size`,String(r.totals.baselineBytes)),Qt(`total-delta-gzip-size`,String(r.totals.deltaBytes)),e.commentPr&&await Vn(e.githubToken,pn(r))}catch(e){$t(e instanceof Error?e.message:String(e))}}var er=process.argv[1];function tr(e=er,t=process.env){return!!(t.GITHUB_ACTIONS===`true`&&t.INPUT_FILES!==void 0||e&&({}.url===(0,u.pathToFileURL)(e).href||(0,l.normalize)(e).endsWith((0,l.join)(`dist`,`index.js`))))}tr()&&$n(),exports.buildComparisonReport=bn,exports.createTarballFileMap=Qn,exports.extractTarGzEntries=Xn,exports.getPullRequestNumberFromEvent=Nn,exports.parseFilePaths=hn,exports.renderBundleSizeComment=pn,exports.resolveNpmReleaseBaselines=jn,exports.run=$n,exports.shouldRunEntrypoint=tr,exports.statusEmoji=ln,exports.upsertPullRequestComment=Vn; \ No newline at end of file +`).filter(e=>e!==``);return t&&t.trimWhitespace===!1?n:n.map(e=>e.trim())}function Zt(e,t){let n=[`true`,`True`,`TRUE`],r=[`false`,`False`,`FALSE`],i=Yt(e,t);if(n.includes(i))return!0;if(r.includes(i))return!1;throw TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${e}\nSupport boolean input list: \`true | True | TRUE | false | False | FALSE\``)}function Qt(e,t){if(process.env.GITHUB_OUTPUT)return D(`OUTPUT`,O(e,t));process.stdout.write(d.EOL),S(`set-output`,{name:e},b(t))}function $t(e){process.exitCode=Jt.Failure,en(e)}function en(e,t={}){S(`error`,x(t),e instanceof Error?e.toString():e)}function tn(e,t={}){S(`warning`,x(t),e instanceof Error?e.toString():e)}function nn(e){process.stdout.write(e+d.EOL)}var rn=``;function an(e){let t=e<0?`-`:``,n=Math.abs(e);return n<1024?`${t}${n} B`:`${t}${(n/1024).toFixed(1)} KiB`}function on(e,t){let n=an(e);return t===null?n:`${n} (${t>0?`+`:``}${t.toFixed(2)}%)`}function sn(e){return e.replace(/\\/g,`\\\\`).replace(/\|/g,`\\|`)}function cn(e){let t=sn(e),n=t.match(/`+/g)??[],r=Math.max(0,...n.map(e=>e.length))+1,i="`".repeat(r),a=t.startsWith("`")||t.endsWith("`")?` `:``;return`${i}${a}${t}${a}${i}`}function ln(e){return e===null?`⚪`:e<=1?`🟢`:e<=3?`🔵`:e<=6?`🟡`:e<=9?`🟠`:`🔴`}function un(e){return`| ${cn(e.path)} | ${an(e.baselineBytes)} | ${an(e.currentBytes)} | ${on(e.deltaBytes,e.deltaPercent)} | ${ln(e.deltaPercent)} |`}function dn(e){let t=e.latest?` latest`:``;return`${cn(e.version)}${t}`}function fn(e){if(!e.totals){let t=e.missingFiles.map(cn).join(`, `);return`| ${dn(e)} | n/a | n/a | Incomplete: missing ${t} | ⚪ |`}return`| ${dn(e)} | ${an(e.totals.baselineBytes)} | ${an(e.totals.currentBytes)} | ${on(e.totals.deltaBytes,e.totals.deltaPercent)} | ${ln(e.totals.deltaPercent)} |`}function pn(e){return e.releaseStream===void 0?`Compared current build against latest npm release ${cn(e.baseline.version)} for ${cn(e.packageName)}.`:`Compared current build against ${cn(`${e.releaseStream}.x`)} release stream baseline ${cn(e.baseline.version)} for ${cn(e.packageName)}.`}function mn(e){return e.releaseStream===void 0?`Historical comparison: latest + 10 previous npm releases`:`Historical comparison: ${e.releaseStream}.x release stream baselines`}function hn(e){let t=e.files.map(un);return t.push(`| **Total** | **${an(e.totals.baselineBytes)}** | **${an(e.totals.currentBytes)}** | **${on(e.totals.deltaBytes,e.totals.deltaPercent)}** | **${ln(e.totals.deltaPercent)}** |`),[rn,``,`## Bundle Size Report`,``,pn(e),``,`| File | Baseline gzip | Current gzip | Difference | Status |`,`|---|---:|---:|---:|:---:|`,...t,``,`
`,`${mn(e)}`,``,`| Release | Baseline gzip | Current gzip | Difference | Status |`,`|---|---:|---:|---:|:---:|`,...e.history.map(fn),``,`
`].join(` +`)}function gn(e){let t=e.trim().replace(/\\/g,`/`);if(/^[A-Za-z]:\//.test(t)||t.startsWith(`//`))throw Error(`Configured file path must be relative and stay inside the project: ${e}`);let n=l.default.posix.normalize(t);if(!n||n===`.`)throw Error(`Configured file paths must not be empty.`);if(n.startsWith(`/`)||n===`..`||n.startsWith(`../`))throw Error(`Configured file path must be relative and stay inside the project: ${e}`);return n}function _n(e){let t=e.split(/\r?\n/).map(e=>e.trim()).filter(Boolean).map(gn);if(t.length===0)throw Error(`At least one file path must be provided via the files input.`);return[...new Set(t)]}function vn(e,t){let n=l.default.resolve(e),r=l.default.resolve(n,t),i=l.default.relative(n,r);if(i===``||i===`..`||i.startsWith(`..${l.default.sep}`)||l.default.isAbsolute(i))throw Error(`Path must stay inside the project root: ${t}`);return r}var yn=(0,g.promisify)(_.gzip);async function bn(e){return(await yn(e,{level:_.constants.Z_BEST_COMPRESSION})).length}function xn(e,t){return t===0?null:Number(((e-t)/t*100).toFixed(2))}async function Sn(e,t,n,r,i){let[a]=r;if(!a)throw Error(`At least one npm release baseline is required.`);let o=[];for(let t of r)o.push(await Cn(e,n,t,t.latest));let[s]=o;if(!s.totals)throw Error(`Primary release comparison is incomplete: ${a.version}`);return{metric:`gzip`,packageName:t,releaseStream:i,baseline:{version:a.version,uri:a.uri},localRoot:e,files:s.files,totals:s.totals,history:o}}async function Cn(e,t,n,r){let i=[],a=[];for(let o of t){let t=n.files.get(o);if(!t){if(r)throw Error(`Baseline file not found in primary release ${n.version}: ${o}`);a.push(o);continue}let s=vn(e,o),c;try{c=await(0,y.readFile)(s)}catch(e){throw Error(`Local file not found: ${o} (${e instanceof Error?e.message:String(e)})`)}let l=await bn(t),u=await bn(c),d=u-l;i.push({path:o,baselineBytes:l,currentBytes:u,deltaBytes:d,deltaPercent:xn(u,l)})}let o=i.reduce((e,t)=>e+t.baselineBytes,0),s=i.reduce((e,t)=>e+t.currentBytes,0),c=a.length>0?null:{baselineBytes:o,currentBytes:s,deltaBytes:s-o,deltaPercent:xn(s,o)};return{version:n.version,uri:n.uri,latest:n.latest,complete:a.length===0,missingFiles:a,files:i,totals:c}}function wn(e){let t=e.trim();if(!t)throw Error(`The package-name input is required.`);if(/\s/.test(t)||t.includes(`:`))throw Error(`Invalid npm package name: ${e}`);if(t.startsWith(`@`)){let n=t.split(`/`);if(n.length!==2||!n[0].slice(1)||!n[1])throw Error(`Invalid npm package name: ${e}`);return t}if(t.includes(`/`))throw Error(`Invalid npm package name: ${e}`);return t}function Tn(e){let t=e.trim();if(t){if(!/^\d+$/.test(t))throw Error(`Invalid release-stream input: ${e}`);return Number(t)}}function En(){let e=l.default.resolve(Yt(`path`,{required:!1})||`.`),t=wn(Yt(`package-name`,{required:!0})),n=Tn(Yt(`release-stream`,{required:!1})),r=Xt(`files`,{required:!0}).join(` +`),i=gn(Yt(`output-file`,{required:!1})||`bundle-size-comparison.json`),a=Zt(`comment-pr`,{required:!1}),o=Yt(`github-token`,{required:!1});if(a&&!o)throw Error(`The github-token input is required when comment-pr is enabled.`);return{localRoot:e,packageName:t,releaseStream:n,filePaths:_n(r),outputFile:i,commentPr:a,githubToken:o}}var Dn=`https://registry.npmjs.org`,On=10;function kn(e){return`${Dn}/${encodeURIComponent(e)}`}function An(e){return!e.includes(`-`)}function jn(e){let t=/^(\d+)\./.exec(e);return t?Number(t[1]):null}function Mn(e,t,n){let r=n.versions?.[t]?.dist?.tarball;if(typeof r!=`string`||!r.trim())throw Error(`Npm package ${e} version ${t} is missing a tarball URL.`);let i;try{i=new URL(r)}catch{throw Error(`Npm package ${e} version ${t} has an invalid tarball URL.`)}if(i.protocol!==`http:`&&i.protocol!==`https:`)throw Error(`Npm package ${e} version ${t} has an unsupported tarball URL protocol: ${i.protocol}`);return r}function Nn(e,t,n){let r=n.time?.[t],i=r?Date.parse(r):NaN;if(Number.isNaN(i))throw Error(`Npm package ${e} version ${t} is missing publish time metadata.`);return i}function Pn(e,t,n){if(n!==void 0){let r=Object.keys(t.versions??{}).filter(e=>An(e)&&jn(e)===n).map(n=>({version:n,publishedAt:Nn(e,n,t)})).sort((e,t)=>t.publishedAt-e.publishedAt).slice(0,On+1).map(e=>e.version);if(r.length===0)throw Error(`Npm package ${e} has no stable releases in release stream ${n}.`);return r.map((n,r)=>({version:n,uri:Mn(e,n,t),latest:r===0}))}let r=t[`dist-tags`]?.latest;if(typeof r!=`string`||!r||!t.versions?.[r])throw Error(`Npm package ${e} does not define a usable latest release.`);let i=Nn(e,r,t);return[r,...Object.keys(t.versions).filter(e=>e!==r&&An(e)).map(n=>({version:n,publishedAt:Nn(e,n,t)})).filter(e=>e.publishedAtt.publishedAt-e.publishedAt).slice(0,On).map(e=>e.version)].map((n,r)=>({version:n,uri:Mn(e,n,t),latest:r===0}))}async function Fn(e,t){let n=kn(e),r;try{r=await fetch(n)}catch(t){throw Error(`Failed to fetch npm metadata for ${e}: ${t instanceof Error?t.message:String(t)}`)}if(!r.ok)throw Error(`Failed to fetch npm metadata for ${e}: HTTP ${r.status} ${r.statusText}`);let i;try{i=await r.json()}catch(t){throw Error(`Failed to parse npm metadata for ${e}: ${t instanceof Error?t.message:String(t)}`)}return Pn(e,i,t)}var In=class extends Error{status;constructor(e,t){super(e),this.name=`GitHubApiError`,this.status=t}};async function Ln(){let e=process.env.GITHUB_EVENT_PATH;if(!e)return null;let t=JSON.parse(await(0,y.readFile)(e,`utf8`)),n=t.pull_request?.number??t.number;return typeof n==`number`?n:null}function Rn(){let e=process.env.GITHUB_REPOSITORY;if(!e)throw Error(`GITHUB_REPOSITORY is required to post a pull request comment.`);let[t,n]=e.split(`/`);if(!t||!n)throw Error(`Invalid GITHUB_REPOSITORY value: ${e}`);return{owner:t,repo:n}}async function zn(e){try{let t=await e.json();return t.message?`: ${t.message}`:``}catch{return``}}function Bn(e){if(!e)return null;for(let t of e.split(`,`))if(t.includes(`rel="next"`))return/<([^>]+)>/.exec(t)?.[1]??null;return null}async function Vn(e,t,n,r){let i=await fetch(n,{method:t,headers:{accept:`application/vnd.github+json`,authorization:`Bearer ${e}`,"content-type":`application/json`,"user-agent":`axios-bundle-size-action`,"x-github-api-version":`2022-11-28`},body:r===void 0?void 0:JSON.stringify(r)});if(!i.ok){let e=await zn(i),t=i.status===401||i.status===403?` Check that github-token has permission to write pull request or issue comments.`:``;throw new In(`GitHub comments API request failed (${i.status} ${i.statusText})${e}.${t}`,i.status)}return{body:await i.json(),nextUrl:Bn(i.headers.get(`link`))}}async function Hn(e,t,n,r){return(await Vn(e,t,n,r)).body}function Un(e){return e.body?.includes(rn)===!0}async function Wn(e,t){let n=t;for(;n;){let t=await Vn(e,`GET`,n),r=t.body.find(Un);if(r)return r;n=t.nextUrl}}async function Gn(e,t){let n=await Ln();if(n===null){nn(`Skipping bundle size PR comment because this run is not for a pull request.`);return}let{owner:r,repo:i}=Rn(),a=`https://api.github.com/repos/${r}/${i}`;try{let r=await Wn(e,`${a}/issues/${n}/comments?per_page=100`);if(r){await Hn(e,`PATCH`,`${a}/issues/comments/${r.id}`,{body:t}),nn(`Updated existing bundle size PR comment.`);return}await Hn(e,`POST`,`${a}/issues/${n}/comments`,{body:t}),nn(`Created bundle size PR comment.`)}catch(e){if(e instanceof In&&(e.status===401||e.status===403)){tn(`Skipping bundle size PR comment: ${e.message}`);return}throw e}}async function Kn(e,t,n){let r=vn(e,t);return await(0,y.mkdir)(l.default.dirname(r),{recursive:!0}),await(0,y.writeFile)(r,`${JSON.stringify(n,null,2)}\n`,`utf8`),r}var qn=(0,g.promisify)(_.gunzip),Jn=512;async function Yn(e){let t;try{t=await fetch(e)}catch(t){throw Error(`Failed to download tarball URI ${e}: ${t instanceof Error?t.message:String(t)}`)}if(!t.ok)throw Error(`Failed to download tarball URI ${e}: HTTP ${t.status} ${t.statusText}`);return Buffer.from(await t.arrayBuffer())}function Xn(e,t,n){let r=e.subarray(t,t+n),i=r.indexOf(0);return(i===-1?r:r.subarray(0,i)).toString(`utf8`).trim()}function Zn(e,t){let n=Xn(e,124,12).replaceAll(`\0`,``).trim();if(!n)return 0;if(!/^[0-7]+$/.test(n))throw Error(`Tarball entry has invalid size field: ${t}`);let r=Number.parseInt(n,8);if(!Number.isSafeInteger(r))throw Error(`Tarball entry size is too large: ${t}`);return r}function Qn(e){return e.every(e=>e===0)}function $n(e){return l.default.posix.normalize(e.replace(/\\/g,`/`)).replace(/^\.\//,``).replace(/^\/+/,``)}async function er(e){let t;try{t=await qn(e)}catch(e){throw Error(`Tarball is not a valid .tar.gz archive: ${e instanceof Error?e.message:String(e)}`)}let n=[],r=0;for(;r+Jn<=t.length;){let e=t.subarray(r,r+Jn);if(Qn(e))break;let i=Xn(e,0,100),a=Xn(e,345,155),o=$n(a?`${a}/${i}`:i),s=Zn(e,o),c=Xn(e,156,1),l=r+Jn,u=l+s;if(u>t.length)throw Error(`Tarball entry is truncated: ${o}`);o&&(c===``||c===`0`)&&n.push({path:o,content:Buffer.from(t.subarray(l,u))}),r=l+Math.ceil(s/Jn)*Jn}if(n.length===0)throw Error(`Tarball did not contain any regular files.`);return n}function tr(e){let t=e.map(e=>e.split(`/`)[0]).filter(Boolean),[n]=t;return!n||t.some(e=>e!==n)?null:e.every(e=>e.includes(`/`))?n:null}function nr(e){let t=new Map,n=tr(e.map(e=>e.path));for(let r of e)t.set(r.path,r.content),n&&r.path.startsWith(`${n}/`)&&t.set(r.path.slice(n.length+1),r.content);return t}async function rr(){try{let e=En();nn(`Local project root: ${e.localRoot}`),nn(`Npm package baseline: ${e.packageName}`),e.releaseStream!==void 0&&nn(`Npm release stream baseline: ${e.releaseStream}.x`),nn(`Comparing ${e.filePaths.length} file(s) using gzip size.`);let t=await Fn(e.packageName,e.releaseStream);nn(`Resolved ${t.length} npm release baseline(s).`);let n=[];for(let r of t){nn(`Downloading ${e.packageName}@${r.version}: ${r.uri}`);let t=await Yn(r.uri);n.push({...r,files:nr(await er(t))})}let r=await Sn(e.localRoot,e.packageName,e.filePaths,n,e.releaseStream),i=await Kn(e.localRoot,e.outputFile,r);nn(`Wrote bundle size comparison file: ${i}`),Qt(`comparison-file`,i),Qt(`size`,String(r.totals.currentBytes)),Qt(`total-current-gzip-size`,String(r.totals.currentBytes)),Qt(`total-baseline-gzip-size`,String(r.totals.baselineBytes)),Qt(`total-delta-gzip-size`,String(r.totals.deltaBytes)),e.commentPr&&await Gn(e.githubToken,hn(r))}catch(e){$t(e instanceof Error?e.message:String(e))}}var ir=process.argv[1];function ar(e=ir,t=process.env){return!!(t.GITHUB_ACTIONS===`true`&&t.INPUT_FILES!==void 0||e&&({}.url===(0,u.pathToFileURL)(e).href||(0,l.normalize)(e).endsWith((0,l.join)(`dist`,`index.js`))))}ar()&&rr(),exports.buildComparisonReport=Sn,exports.createTarballFileMap=nr,exports.extractTarGzEntries=er,exports.getPullRequestNumberFromEvent=Ln,exports.parseFilePaths=_n,exports.renderBundleSizeComment=hn,exports.resolveNpmReleaseBaselines=Fn,exports.run=rr,exports.shouldRunEntrypoint=ar,exports.statusEmoji=ln,exports.upsertPullRequestComment=Gn; \ No newline at end of file diff --git a/openspec/changes/support-release-stream-baselines/.openspec.yaml b/openspec/changes/support-release-stream-baselines/.openspec.yaml new file mode 100644 index 0000000..66da1ae --- /dev/null +++ b/openspec/changes/support-release-stream-baselines/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-05-17 diff --git a/openspec/changes/support-release-stream-baselines/design.md b/openspec/changes/support-release-stream-baselines/design.md new file mode 100644 index 0000000..07947d2 --- /dev/null +++ b/openspec/changes/support-release-stream-baselines/design.md @@ -0,0 +1,55 @@ +## Context + +The action currently resolves npm baselines from package metadata by taking the `latest` dist-tag as the primary baseline, then selecting up to 10 previous stable releases ordered by publish time. This works for packages with a single active release line, but it mixes major-version streams for packages that maintain multiple lines, such as axios `0.x` and `1.x`. + +Release stream selection needs to happen before tarball download and comparison. The comparison layer already treats the first selected release as the primary baseline and handles later releases as historical context, so the cleanest change is to adjust npm baseline selection while preserving downstream comparison semantics. + +## Goals / Non-Goals + +**Goals:** + +- Add an optional `release-stream` action input for selecting a major-version stream such as `0` or `1`. +- Preserve current default behavior when `release-stream` is omitted. +- When configured, make the newest stable release in the stream the primary baseline, even if npm `latest` points to another major. +- Restrict historical comparisons to stable releases from the configured major-version stream. +- Keep reports and pull request comments clear about whether results represent npm `latest` behavior or a configured stream. + +**Non-Goals:** + +- Supporting full semver ranges such as `^1.2.0`, `>=1 <2`, `1.2`, or npm dist-tags other than `latest`. +- Changing gzip size semantics, threshold enforcement, target sizes, or failure behavior for missing local/latest baseline files. +- Adding runtime dependencies for semver parsing. +- Building target package artifacts inside the action. + +## Decisions + +### Use `release-stream` as an optional major-version input + +The input will represent the leading semantic version number. Values such as `0` and `1` are valid. Empty input means no stream filter and preserves the existing npm `latest` behavior. + +Alternative considered: name the input `major-version` or `baseline-major`. `release-stream` better matches the user-facing concept of parallel maintained release lines and leaves room for documentation that says `release-stream: '1'` means the `1.x` stream. + +### Select the primary baseline from the stream when configured + +When `release-stream` is set, npm `latest` no longer determines the primary baseline. The resolver should select the newest stable published version whose parsed major equals the configured stream, then select up to 10 earlier stable versions in that same stream. + +Alternative considered: keep npm `latest` as the primary baseline and filter only historical rows. That would produce split reports such as a `1.x` primary baseline with `0.x` history when running maintenance-branch checks, which is misleading for multi-stream packages. + +### Keep semver parsing intentionally narrow + +The resolver only needs enough parsing to identify stable versions and compare the leading numeric major. Existing stable filtering already excludes versions containing `-`. The implementation can parse the major with a small regular expression for `^(\d+)\.` and avoid adding a semver dependency. + +Alternative considered: add a semver package. That would be more general, but the proposed capability is intentionally limited to leading major-version streams and the action keeps runtime dependencies small. + +### Preserve report structure and add minimal stream metadata if needed + +The existing JSON report already includes package identity, primary baseline metadata, and a `history` array. The baseline version itself communicates the selected primary release. If comment/report wording needs to distinguish stream mode, the action config or report can include optional release-stream metadata without changing gzip comparison fields. + +Alternative considered: restructure `history` around stream objects. That would be heavier than needed because the action still compares one selected primary release plus historical release rows. + +## Risks / Trade-offs + +- Ambiguous version strings in npm metadata → Ignore prereleases as today and match only versions with a numeric major segment; add tests for malformed/non-matching versions if supported by metadata fixtures. +- Users may expect semver ranges from `release-stream` → Document that only a leading major number is accepted and fail validation for anything else. +- Comment wording may become inaccurate if left hardcoded → Update the collapsed history summary and tests alongside resolver behavior. +- Stream with no matching stable releases → Fail during npm baseline resolution with an error naming the package and requested release stream. diff --git a/openspec/changes/support-release-stream-baselines/proposal.md b/openspec/changes/support-release-stream-baselines/proposal.md new file mode 100644 index 0000000..83c0f7e --- /dev/null +++ b/openspec/changes/support-release-stream-baselines/proposal.md @@ -0,0 +1,34 @@ +## Why + +Packages such as axios maintain multiple release streams, where the npm `latest` dist-tag may point at `1.x` while `0.x` still receives maintenance releases. The action currently selects historical baselines across all stable versions before `latest`, which can mix unrelated major-version streams and make maintenance-branch bundle-size comparisons noisy or misleading. + +## What Changes + +- Add an optional `release-stream` input that accepts a leading major version number such as `0` or `1`. +- When `release-stream` is omitted, preserve the current behavior: use the npm `latest` dist-tag as the primary baseline and select up to 10 previous stable releases by publish time. +- When `release-stream` is provided, select the newest stable release in that major-version stream as the primary baseline, then select up to 10 previous stable releases from the same stream. +- Fail with a clear error when the configured release stream has no matching stable releases. +- Reflect release-stream selection in reports, pull request comments, README examples, and action metadata. +- Non-goals: no threshold enforcement, no target-size behavior, no package build orchestration, and no semver range expression support beyond a leading major version stream. + +## Capabilities + +### New Capabilities + +- None. + +### Modified Capabilities + +- `npm-release-baselines`: Add optional release-stream selection and define how npm release baselines are selected when a major-version stream is configured. +- `historical-bundle-size-reporting`: Clarify that the primary baseline and history may represent either the npm latest baseline or a configured release stream. + +## Impact + +- `action.yml`: add and document the optional `release-stream` input. +- `src/config.ts` and `src/types.ts`: read, validate, and pass through the optional release stream. +- `src/npm.ts`: filter/select release baselines by configured major-version stream while preserving default behavior. +- `src/action.ts`: pass the configured release stream into npm release baseline resolution. +- `src/comment.ts` and report-related types/tests: describe release-stream history accurately instead of always saying latest plus 10 previous npm releases. +- `README.md`: document input behavior, examples, and report/comment semantics. +- `tests/`: add module-aligned coverage for configuration validation, npm baseline selection, action orchestration, and comment/report wording. +- `dist/index.js`: rebuild so the committed GitHub Action runtime matches the TypeScript source. diff --git a/openspec/changes/support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md b/openspec/changes/support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md new file mode 100644 index 0000000..cb8546c --- /dev/null +++ b/openspec/changes/support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md @@ -0,0 +1,49 @@ +## MODIFIED Requirements + +### Requirement: Compare Against Historical Releases +The action SHALL compare configured local artifacts against the selected primary npm release baseline and each selected previous npm release baseline. + +#### Scenario: Historical releases are selected +- **WHEN** npm release resolution returns a primary release and previous releases +- **THEN** the action computes gzip byte sizes, byte deltas, and percent deltas for each configured file against each release baseline + +#### Scenario: No previous releases exist +- **WHEN** npm release resolution returns only the selected primary release +- **THEN** the action still produces a successful primary-release comparison without requiring historical releases + +### Requirement: Latest Release Remains Primary Baseline +The action SHALL treat the selected npm release as the primary baseline for top-level report totals and action outputs. + +#### Scenario: Latest comparison succeeds +- **WHEN** the action compares local files against the selected primary npm release +- **THEN** existing total size outputs describe the current build compared with the selected primary release baseline + +#### Scenario: Latest baseline file is missing +- **WHEN** a configured file cannot be found in the selected primary release tarball +- **THEN** the action fails with an error naming the missing baseline file and release version + +### Requirement: Generate Historical Comparison Report +The action SHALL write a JSON comparison report containing the primary release comparison and historical release comparisons. + +#### Scenario: Comparison report is written +- **WHEN** release comparisons complete successfully +- **THEN** the JSON report includes package identity, primary baseline metadata, top-level primary comparison results, and a history list for the selected primary release plus selected previous releases + +#### Scenario: Historical release is incomplete +- **WHEN** a historical release is missing one or more configured files +- **THEN** the JSON report identifies the release as incomplete and lists missing paths without fabricating gzip totals for missing files + +### Requirement: Render Collapsible Historical Comment +The action SHALL render historical release comparisons inside a collapsed details section when pull request commenting is enabled. + +#### Scenario: Pull request comment is rendered +- **WHEN** the action renders a bundle-size pull request comment with historical results +- **THEN** the selected primary release comparison is visible by default and the historical release summary appears inside an HTML `
` block + +#### Scenario: Historical summary includes selected releases +- **WHEN** the historical comment details section is expanded +- **THEN** it shows a release-level summary for the selected primary release and each selected previous release + +#### Scenario: Release stream comment is rendered +- **WHEN** the action renders a bundle-size pull request comment for a configured release stream +- **THEN** the comment identifies the configured release stream instead of describing the history as npm latest plus previous releases diff --git a/openspec/changes/support-release-stream-baselines/specs/npm-release-baselines/spec.md b/openspec/changes/support-release-stream-baselines/specs/npm-release-baselines/spec.md new file mode 100644 index 0000000..b32137b --- /dev/null +++ b/openspec/changes/support-release-stream-baselines/specs/npm-release-baselines/spec.md @@ -0,0 +1,45 @@ +## MODIFIED Requirements + +### Requirement: Select Latest And Previous Releases +The action SHALL select npm release baselines from either the package `latest` dist-tag or a configured major-version release stream. + +#### Scenario: More than 10 previous releases exist +- **WHEN** the package has a latest release and more than 10 earlier stable releases +- **THEN** the action selects the latest release plus the 10 most recently published previous stable releases + +#### Scenario: Fewer than 10 previous releases exist +- **WHEN** the package has a latest release and fewer than 10 earlier stable releases +- **THEN** the action selects the latest release plus all available previous stable releases + +#### Scenario: Latest dist-tag is missing +- **WHEN** the package metadata does not define a `latest` dist-tag that points to a version record and no release stream is configured +- **THEN** the action fails with an error naming the missing latest release metadata + +#### Scenario: Release stream is configured +- **WHEN** the workflow configures `release-stream` with a major version number +- **THEN** the action selects the newest stable release in that major-version stream as the primary baseline plus up to 10 earlier stable releases from the same stream + +#### Scenario: Release stream excludes npm latest +- **WHEN** the npm `latest` dist-tag points to a different major version than the configured `release-stream` +- **THEN** the action selects the newest stable release from the configured stream instead of the npm latest release + +#### Scenario: Release stream has no stable releases +- **WHEN** the workflow configures `release-stream` and package metadata contains no stable versions in that major-version stream +- **THEN** the action fails with an error naming the package and requested release stream + +## ADDED Requirements + +### Requirement: Configure Release Stream Baseline +The action SHALL accept an optional release-stream input that identifies the npm major-version stream used for release baseline selection. + +#### Scenario: Release stream is omitted +- **WHEN** the workflow invokes the action without a release-stream input +- **THEN** the action preserves default npm latest baseline selection behavior + +#### Scenario: Release stream is provided +- **WHEN** the workflow invokes the action with a release-stream input such as `1` +- **THEN** the action uses that leading major version number to resolve npm release baselines from the matching release stream + +#### Scenario: Release stream is invalid +- **WHEN** the workflow invokes the action with a release-stream input that is not a non-negative integer major version +- **THEN** the action fails with a configuration error naming the invalid release-stream input diff --git a/openspec/changes/support-release-stream-baselines/tasks.md b/openspec/changes/support-release-stream-baselines/tasks.md new file mode 100644 index 0000000..a36cb92 --- /dev/null +++ b/openspec/changes/support-release-stream-baselines/tasks.md @@ -0,0 +1,34 @@ +## 1. Inputs And Configuration + +- [x] 1.1 Add the optional `release-stream` input to `action.yml` with documentation that it accepts a leading major version number. +- [x] 1.2 Extend shared config types to carry an optional release stream value. +- [x] 1.3 Update `src/config.ts` to read and validate `release-stream`, preserving current behavior when omitted. +- [x] 1.4 Add configuration tests for omitted release stream, valid `0` and `1` streams, and invalid non-integer or negative values. + +## 2. Npm Release Selection + +- [x] 2.1 Update npm release baseline selection to accept an optional release stream parameter. +- [x] 2.2 Preserve existing latest-dist-tag selection when no release stream is configured. +- [x] 2.3 When a release stream is configured, select the newest stable release in that major version as the primary baseline and up to 10 previous stable releases from the same stream. +- [x] 2.4 Add npm resolver tests for stream filtering, stream latest overriding npm `latest`, stream limiting to 10 previous releases, missing stream matches, and default behavior compatibility. + +## 3. Action Orchestration And Reporting + +- [x] 3.1 Pass the configured release stream from action configuration into npm release baseline resolution. +- [x] 3.2 Update report types or metadata only as needed to describe configured release-stream selection without changing gzip comparison fields. +- [x] 3.3 Update pull request comment rendering so stream-filtered history does not say `latest + 10 previous npm releases`. +- [x] 3.4 Add or update action, report, and comment tests covering configured release streams and default wording. + +## 4. Documentation And Examples + +- [x] 4.1 Update README input documentation for `release-stream`. +- [x] 4.2 Add a workflow example for comparing against a specific release stream such as axios `1.x`. +- [x] 4.3 Update report/comment documentation to explain primary baseline behavior with and without `release-stream`. + +## 5. Verification And Build Artifacts + +- [x] 5.1 Run `pnpm run lint` and fix reported lint issues. +- [x] 5.2 Run `pnpm run typecheck` and fix TypeScript errors. +- [x] 5.3 Run `pnpm test` and confirm the test suite passes. +- [x] 5.4 Run `pnpm run build` and include the updated `dist/index.js` output. +- [x] 5.5 Inspect `dist/index.js`, `action.yml`, README, and tests to confirm the committed action matches the release-stream baseline contract. diff --git a/src/action.ts b/src/action.ts index fcff4b6..c8614d7 100644 --- a/src/action.ts +++ b/src/action.ts @@ -17,9 +17,15 @@ export async function run(): Promise { core.info(`Local project root: ${config.localRoot}`); core.info(`Npm package baseline: ${config.packageName}`); + if (config.releaseStream !== undefined) { + core.info(`Npm release stream baseline: ${config.releaseStream}.x`); + } core.info(`Comparing ${config.filePaths.length} file(s) using gzip size.`); - const releases = await resolveNpmReleaseBaselines(config.packageName); + const releases = await resolveNpmReleaseBaselines( + config.packageName, + config.releaseStream, + ); core.info(`Resolved ${releases.length} npm release baseline(s).`); const releaseArchives = []; @@ -39,6 +45,7 @@ export async function run(): Promise { config.packageName, config.filePaths, releaseArchives, + config.releaseStream, ); const outputPath = await writeComparisonReport( config.localRoot, diff --git a/src/comment.ts b/src/comment.ts index e9cabaa..458d78f 100644 --- a/src/comment.ts +++ b/src/comment.ts @@ -86,6 +86,22 @@ function renderHistoryRow(release: ReleaseComparisonResult): string { return `| ${renderReleaseLabel(release)} | ${formatBytes(release.totals.baselineBytes)} | ${formatBytes(release.totals.currentBytes)} | ${formatDelta(release.totals.deltaBytes, release.totals.deltaPercent)} | ${statusEmoji(release.totals.deltaPercent)} |`; } +function renderBaselineDescription(report: ComparisonReport): string { + if (report.releaseStream !== undefined) { + return `Compared current build against ${renderMarkdownCodeSpan(`${report.releaseStream}.x`)} release stream baseline ${renderMarkdownCodeSpan(report.baseline.version)} for ${renderMarkdownCodeSpan(report.packageName)}.`; + } + + return `Compared current build against latest npm release ${renderMarkdownCodeSpan(report.baseline.version)} for ${renderMarkdownCodeSpan(report.packageName)}.`; +} + +function renderHistorySummary(report: ComparisonReport): string { + if (report.releaseStream !== undefined) { + return `Historical comparison: ${report.releaseStream}.x release stream baselines`; + } + + return "Historical comparison: latest + 10 previous npm releases"; +} + export function renderBundleSizeComment(report: ComparisonReport): string { const rows = report.files.map(renderFileRow); @@ -98,14 +114,14 @@ export function renderBundleSizeComment(report: ComparisonReport): string { "", "## Bundle Size Report", "", - `Compared current build against latest npm release ${renderMarkdownCodeSpan(report.baseline.version)} for ${renderMarkdownCodeSpan(report.packageName)}.`, + renderBaselineDescription(report), "", "| File | Baseline gzip | Current gzip | Difference | Status |", "|---|---:|---:|---:|:---:|", ...rows, "", "
", - "Historical comparison: latest + 10 previous npm releases", + `${renderHistorySummary(report)}`, "", "| Release | Baseline gzip | Current gzip | Difference | Status |", "|---|---:|---:|---:|:---:|", diff --git a/src/comparison.ts b/src/comparison.ts index 524f811..8749fb5 100644 --- a/src/comparison.ts +++ b/src/comparison.ts @@ -38,6 +38,7 @@ export async function buildComparisonReport( packageName: string, filePaths: string[], releases: BaselineReleaseArchive[], + releaseStream?: number, ): Promise { const [latestRelease] = releases; @@ -56,12 +57,13 @@ export async function buildComparisonReport( const [latestComparison] = history; if (!latestComparison.totals) { - throw new Error(`Latest release comparison is incomplete: ${latestRelease.version}`); + throw new Error(`Primary release comparison is incomplete: ${latestRelease.version}`); } return { metric: "gzip", packageName, + releaseStream, baseline: { version: latestRelease.version, uri: latestRelease.uri, @@ -88,7 +90,7 @@ async function buildReleaseComparison( if (!baselineContent) { if (strictMissingBaseline) { throw new Error( - `Baseline file not found in latest release ${release.version}: ${filePath}`, + `Baseline file not found in primary release ${release.version}: ${filePath}`, ); } diff --git a/src/config.ts b/src/config.ts index e031c21..e8fbb7e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -31,6 +31,20 @@ export function validateNpmPackageName(packageName: string): string { return trimmedPackageName; } +export function parseReleaseStream(releaseStream: string): number | undefined { + const trimmedReleaseStream = releaseStream.trim(); + + if (!trimmedReleaseStream) { + return undefined; + } + + if (!/^\d+$/.test(trimmedReleaseStream)) { + throw new Error(`Invalid release-stream input: ${releaseStream}`); + } + + return Number(trimmedReleaseStream); +} + export function getConfig(): ActionConfig { const localRoot = path.resolve( core.getInput("path", { required: false }) || ".", @@ -38,6 +52,9 @@ export function getConfig(): ActionConfig { const packageName = validateNpmPackageName( core.getInput("package-name", { required: true }), ); + const releaseStream = parseReleaseStream( + core.getInput("release-stream", { required: false }), + ); const filesInput = core .getMultilineInput("files", { required: true }) .join("\n"); @@ -55,6 +72,7 @@ export function getConfig(): ActionConfig { return { localRoot, packageName, + releaseStream, filePaths: parseFilePaths(filesInput), outputFile, commentPr, diff --git a/src/npm.ts b/src/npm.ts index 5d8e1ab..0cc6fdd 100644 --- a/src/npm.ts +++ b/src/npm.ts @@ -25,6 +25,12 @@ function isStableVersion(version: string): boolean { return !version.includes("-"); } +function getMajorVersion(version: string): number | null { + const match = /^(\d+)\./.exec(version); + + return match ? Number(match[1]) : null; +} + function getTarballUri( packageName: string, version: string, @@ -70,7 +76,35 @@ function getPublishedTime( export function selectNpmReleaseBaselines( packageName: string, metadata: NpmPackageMetadata, + releaseStream?: number, ): NpmReleaseBaseline[] { + if (releaseStream !== undefined) { + const streamReleases = Object.keys(metadata.versions ?? {}) + .filter( + (version) => + isStableVersion(version) && getMajorVersion(version) === releaseStream, + ) + .map((version) => ({ + version, + publishedAt: getPublishedTime(packageName, version, metadata), + })) + .sort((left, right) => right.publishedAt - left.publishedAt) + .slice(0, PREVIOUS_RELEASE_LIMIT + 1) + .map((release) => release.version); + + if (streamReleases.length === 0) { + throw new Error( + `Npm package ${packageName} has no stable releases in release stream ${releaseStream}.`, + ); + } + + return streamReleases.map((version, index) => ({ + version, + uri: getTarballUri(packageName, version, metadata), + latest: index === 0, + })); + } + const latestVersion = metadata["dist-tags"]?.latest; if ( @@ -102,6 +136,7 @@ export function selectNpmReleaseBaselines( export async function resolveNpmReleaseBaselines( packageName: string, + releaseStream?: number, ): Promise { const metadataUrl = getNpmPackageMetadataUrl(packageName); let response: Response; @@ -129,5 +164,5 @@ export async function resolveNpmReleaseBaselines( ); } - return selectNpmReleaseBaselines(packageName, metadata); + return selectNpmReleaseBaselines(packageName, metadata, releaseStream); } diff --git a/src/types.ts b/src/types.ts index 2249c71..864f29f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -26,6 +26,7 @@ export interface ReleaseComparisonResult { export interface ComparisonReport { metric: "gzip"; packageName: string; + releaseStream?: number; baseline: { version: string; uri: string; @@ -39,6 +40,7 @@ export interface ComparisonReport { export interface ActionConfig { localRoot: string; packageName: string; + releaseStream?: number; filePaths: string[]; outputFile: string; commentPr: boolean; diff --git a/tests/action.test.ts b/tests/action.test.ts index 189caf3..4698e81 100644 --- a/tests/action.test.ts +++ b/tests/action.test.ts @@ -11,6 +11,7 @@ import type { ComparisonReport } from '@/types'; const AXIOS_METADATA_URL = 'https://registry.npmjs.org/axios'; const AXIOS_LATEST_TARBALL_URL = 'https://registry.npmjs.org/axios/-/axios-1.12.2.tgz'; const AXIOS_PREVIOUS_TARBALL_URL = 'https://registry.npmjs.org/axios/-/axios-1.12.1.tgz'; +const AXIOS_NEXT_TARBALL_URL = 'https://registry.npmjs.org/axios/-/axios-2.0.0.tgz'; function writeOctal(buffer: Buffer, value: number, offset: number, length: number): void { const octal = value.toString(8).padStart(length - 1, '0'); @@ -92,6 +93,7 @@ async function withActionEnvironment( 'GITHUB_OUTPUT', 'INPUT_PATH', 'INPUT_PACKAGE-NAME', + 'INPUT_RELEASE-STREAM', 'INPUT_FILES', 'INPUT_OUTPUT-FILE', 'INPUT_COMMENT-PR', @@ -224,3 +226,87 @@ test('run writes outputs and a comparison report for mocked axios npm releases', await rm(tempRoot, { force: true, recursive: true }); } }); + +test('run resolves npm baselines from a configured release stream', async () => { + const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'bundle-size-action-')); + const outputFile = path.join(tempRoot, 'github-output.txt'); + const originalFetch = global.fetch; + + try { + await mkdir(path.join(tempRoot, 'dist'), { recursive: true }); + await writeFile(path.join(tempRoot, 'dist/axios.min.js'), 'current axios artifact'); + await writeFile(outputFile, ''); + + const streamLatestArchive = gzipSync(createTar([ + ['package/dist/axios.min.js', 'stream baseline axios artifact'], + ])); + const previousArchive = gzipSync(createTar([ + ['package/dist/axios.min.js', 'previous axios artifact'], + ])); + + global.fetch = async (uri) => { + if (uri === AXIOS_METADATA_URL) { + return Response.json({ + 'dist-tags': { latest: '2.0.0' }, + versions: { + '1.12.1': { dist: { tarball: AXIOS_PREVIOUS_TARBALL_URL } }, + '1.12.2': { dist: { tarball: AXIOS_LATEST_TARBALL_URL } }, + '2.0.0': { dist: { tarball: AXIOS_NEXT_TARBALL_URL } }, + }, + time: { + '1.12.1': '2025-09-01T00:00:00.000Z', + '1.12.2': '2025-09-02T00:00:00.000Z', + '2.0.0': '2025-10-01T00:00:00.000Z', + }, + }); + } + + if (uri === AXIOS_LATEST_TARBALL_URL) { + return new Response( + streamLatestArchive.buffer.slice( + streamLatestArchive.byteOffset, + streamLatestArchive.byteOffset + streamLatestArchive.byteLength, + ), + { status: 200 }, + ); + } + + assert.equal(uri, AXIOS_PREVIOUS_TARBALL_URL); + + return new Response( + previousArchive.buffer.slice( + previousArchive.byteOffset, + previousArchive.byteOffset + previousArchive.byteLength, + ), + { status: 200 }, + ); + }; + + await withActionEnvironment( + { + GITHUB_OUTPUT: outputFile, + INPUT_PATH: tempRoot, + 'INPUT_PACKAGE-NAME': 'axios', + 'INPUT_RELEASE-STREAM': '1', + INPUT_FILES: 'dist/axios.min.js', + 'INPUT_OUTPUT-FILE': 'reports/comparison.json', + }, + async () => { + await run(); + }, + ); + + assert.equal(process.exitCode, undefined); + + const report = JSON.parse( + await readFile(path.join(tempRoot, 'reports/comparison.json'), 'utf8'), + ) as ComparisonReport; + + assert.equal(report.releaseStream, 1); + assert.equal(report.baseline.version, '1.12.2'); + assert.deepEqual(report.history.map((release) => release.version), ['1.12.2', '1.12.1']); + } finally { + global.fetch = originalFetch; + await rm(tempRoot, { force: true, recursive: true }); + } +}); diff --git a/tests/comment.test.ts b/tests/comment.test.ts index 802f5b6..843fbc0 100644 --- a/tests/comment.test.ts +++ b/tests/comment.test.ts @@ -109,6 +109,17 @@ test('renderBundleSizeComment renders historical release summary in details bloc assert.match(markdown, /<\/details>/); }); +test('renderBundleSizeComment describes release stream histories', () => { + const report = createReport(); + report.releaseStream = 1; + + const markdown = renderBundleSizeComment(report); + + assert.match(markdown, /against `1\.x` release stream baseline `1\.2\.0` for `axios`/); + assert.match(markdown, /Historical comparison: 1\.x release stream baselines<\/summary>/); + assert.doesNotMatch(markdown, /latest \+ 10 previous npm releases/); +}); + test('renderBundleSizeComment renders incomplete historical releases', () => { const report = createReport(); report.history = [ diff --git a/tests/comparison.test.ts b/tests/comparison.test.ts index a05ff42..d34d58b 100644 --- a/tests/comparison.test.ts +++ b/tests/comparison.test.ts @@ -114,7 +114,7 @@ test('buildComparisonReport fails when baseline file is missing', async () => { files: new Map(), }, ]), - /Baseline file not found in latest release 1\.0\.0/, + /Baseline file not found in primary release 1\.0\.0/, ); } finally { await rm(localRoot, { force: true, recursive: true }); diff --git a/tests/config.test.ts b/tests/config.test.ts index 83dfdf9..e44b449 100644 --- a/tests/config.test.ts +++ b/tests/config.test.ts @@ -2,11 +2,12 @@ import assert from 'node:assert/strict'; import path from 'node:path'; import { test } from 'vitest'; -import { getConfig, validateNpmPackageName } from '@/config'; +import { getConfig, parseReleaseStream, validateNpmPackageName } from '@/config'; const INPUT_KEYS = [ 'INPUT_PATH', 'INPUT_PACKAGE-NAME', + 'INPUT_RELEASE-STREAM', 'INPUT_TARBALL-URI', 'INPUT_FILES', 'INPUT_OUTPUT-FILE', @@ -53,6 +54,18 @@ test('validateNpmPackageName rejects missing and invalid package names', () => { assert.throws(() => validateNpmPackageName('npm:axios@latest'), /Invalid npm package name/); }); +test('parseReleaseStream accepts empty and non-negative integer streams', () => { + assert.equal(parseReleaseStream(''), undefined); + assert.equal(parseReleaseStream(' 0 '), 0); + assert.equal(parseReleaseStream('1'), 1); +}); + +test('parseReleaseStream rejects non-integer and negative streams', () => { + assert.throws(() => parseReleaseStream('1.x'), /Invalid release-stream input/); + assert.throws(() => parseReleaseStream('1.0'), /Invalid release-stream input/); + assert.throws(() => parseReleaseStream('-1'), /Invalid release-stream input/); +}); + test('getConfig reads defaults and parses multiline files input', async () => { await withInputs( { @@ -63,6 +76,7 @@ test('getConfig reads defaults and parses multiline files input', async () => { assert.deepEqual(getConfig(), { localRoot: path.resolve('.'), packageName: 'axios', + releaseStream: undefined, filePaths: ['dist/a.js', 'dist/b.js'], outputFile: 'bundle-size-comparison.json', commentPr: false, @@ -84,6 +98,7 @@ test('getConfig reads explicit path and output file inputs', async () => { assert.deepEqual(getConfig(), { localRoot: path.resolve('fixtures/project'), packageName: '@scope/package', + releaseStream: undefined, filePaths: ['dist/a.js'], outputFile: 'reports/result.json', commentPr: false, @@ -105,6 +120,7 @@ test('getConfig reads PR comment inputs', async () => { assert.deepEqual(getConfig(), { localRoot: path.resolve('.'), packageName: 'axios', + releaseStream: undefined, filePaths: ['dist/a.js'], outputFile: 'bundle-size-comparison.json', commentPr: true, @@ -127,6 +143,54 @@ test('getConfig requires github-token when PR comments are enabled', async () => ); }); +test('getConfig reads valid release stream inputs', async () => { + await withInputs( + { + 'INPUT_PACKAGE-NAME': 'axios', + 'INPUT_RELEASE-STREAM': '0', + INPUT_FILES: 'dist/a.js', + }, + () => { + assert.equal(getConfig().releaseStream, 0); + }, + ); + + await withInputs( + { + 'INPUT_PACKAGE-NAME': 'axios', + 'INPUT_RELEASE-STREAM': '1', + INPUT_FILES: 'dist/a.js', + }, + () => { + assert.equal(getConfig().releaseStream, 1); + }, + ); +}); + +test('getConfig rejects invalid release stream inputs', async () => { + await withInputs( + { + 'INPUT_PACKAGE-NAME': 'axios', + 'INPUT_RELEASE-STREAM': 'latest', + INPUT_FILES: 'dist/a.js', + }, + () => { + assert.throws(() => getConfig(), /Invalid release-stream input/); + }, + ); + + await withInputs( + { + 'INPUT_PACKAGE-NAME': 'axios', + 'INPUT_RELEASE-STREAM': '-1', + INPUT_FILES: 'dist/a.js', + }, + () => { + assert.throws(() => getConfig(), /Invalid release-stream input/); + }, + ); +}); + test('getConfig rejects invalid output file paths', async () => { await withInputs( { diff --git a/tests/npm.test.ts b/tests/npm.test.ts index 361337e..7a17ed8 100644 --- a/tests/npm.test.ts +++ b/tests/npm.test.ts @@ -44,6 +44,20 @@ test('selectNpmReleaseBaselines selects latest plus fewer than 10 previous relea assert.equal(releases[1].latest, false); }); +test('selectNpmReleaseBaselines preserves latest behavior without release stream', () => { + const releases = selectNpmReleaseBaselines( + 'axios', + createMetadata(['0.27.2', '1.0.0', '1.1.0', '2.0.0'], '2.0.0'), + ); + + assert.deepEqual(releases.map((release) => release.version), [ + '2.0.0', + '1.1.0', + '1.0.0', + '0.27.2', + ]); +}); + test('selectNpmReleaseBaselines selects at most 10 previous stable releases', () => { const versions = Array.from({ length: 13 }, (_, index) => `1.${index}.0`); const releases = selectNpmReleaseBaselines('axios', createMetadata(versions)); @@ -73,6 +87,74 @@ test('selectNpmReleaseBaselines skips prerelease versions in previous releases', assert.deepEqual(releases.map((release) => release.version), ['1.1.0', '1.0.0']); }); +test('selectNpmReleaseBaselines filters baselines to a release stream', () => { + const releases = selectNpmReleaseBaselines( + 'axios', + createMetadata(['0.27.2', '1.0.0', '1.1.0', '2.0.0'], '2.0.0'), + 1, + ); + + assert.deepEqual(releases.map((release) => release.version), ['1.1.0', '1.0.0']); + assert.equal(releases[0].latest, true); + assert.equal(releases[1].latest, false); +}); + +test('selectNpmReleaseBaselines uses newest stream release instead of npm latest', () => { + const releases = selectNpmReleaseBaselines( + 'axios', + createMetadata(['0.27.2', '1.0.0', '1.1.0', '2.0.0'], '2.0.0'), + 0, + ); + + assert.deepEqual(releases.map((release) => release.version), ['0.27.2']); + assert.equal(releases[0].latest, true); +}); + +test('selectNpmReleaseBaselines limits previous releases within the stream', () => { + const releases = selectNpmReleaseBaselines( + 'axios', + createMetadata([ + '1.0.0', + '2.0.0', + '1.1.0', + '1.2.0', + '1.3.0', + '1.4.0', + '1.5.0', + '1.6.0', + '1.7.0', + '1.8.0', + '1.9.0', + '1.10.0', + '1.11.0', + '1.12.0', + ]), + 1, + ); + + assert.equal(releases.length, 11); + assert.deepEqual(releases.map((release) => release.version), [ + '1.12.0', + '1.11.0', + '1.10.0', + '1.9.0', + '1.8.0', + '1.7.0', + '1.6.0', + '1.5.0', + '1.4.0', + '1.3.0', + '1.2.0', + ]); +}); + +test('selectNpmReleaseBaselines rejects streams with no stable matches', () => { + assert.throws( + () => selectNpmReleaseBaselines('axios', createMetadata(['1.0.0', '2.0.0']), 0), + /axios has no stable releases in release stream 0/, + ); +}); + test('selectNpmReleaseBaselines rejects missing latest metadata', () => { assert.throws( () => selectNpmReleaseBaselines('axios', createMetadata(['1.0.0'], '2.0.0')), @@ -102,7 +184,7 @@ test('resolveNpmReleaseBaselines fetches and parses npm metadata', async () => { return Response.json(createMetadata(['1.0.0', '1.1.0'])); }; - const releases = await resolveNpmReleaseBaselines('@scope/package'); + const releases = await resolveNpmReleaseBaselines('@scope/package', 1); assert.equal(requestedUrl, 'https://registry.npmjs.org/%40scope%2Fpackage'); assert.deepEqual(releases.map((release) => release.version), ['1.1.0', '1.0.0']); diff --git a/tests/report.test.ts b/tests/report.test.ts index f6cb272..73557f7 100644 --- a/tests/report.test.ts +++ b/tests/report.test.ts @@ -87,6 +87,22 @@ test('writeComparisonReport writes pretty JSON with trailing newline', async () } }); +test('writeComparisonReport preserves release stream metadata', async () => { + const localRoot = await mkdtemp(path.join(os.tmpdir(), 'bundle-size-')); + + try { + const report = createReport(); + report.releaseStream = 1; + const outputPath = await writeComparisonReport(localRoot, 'comparison.json', report); + + const writtenReport = JSON.parse(await readFile(outputPath, 'utf8')) as ComparisonReport; + assert.equal(writtenReport.releaseStream, 1); + assert.equal(writtenReport.baseline.version, '1.2.0'); + } finally { + await rm(localRoot, { force: true, recursive: true }); + } +}); + test('writeComparisonReport rejects unsafe output paths', async () => { const localRoot = await mkdtemp(path.join(os.tmpdir(), 'bundle-size-')); From b5cbdaafc0ad48069412a7957f9e2dfb40b9dbb2 Mon Sep 17 00:00:00 2001 From: Jason Saayman Date: Mon, 18 May 2026 19:52:45 +0200 Subject: [PATCH 2/6] docs: archive release stream baselines change --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../historical-bundle-size-reporting/spec.md | 0 .../specs/npm-release-baselines/spec.md | 0 .../tasks.md | 0 .../historical-bundle-size-reporting/spec.md | 60 ++++++++++++++ openspec/specs/npm-release-baselines/spec.md | 80 +++++++++++++++++++ 8 files changed, 140 insertions(+) rename openspec/changes/{support-release-stream-baselines => archive/2026-05-18-support-release-stream-baselines}/.openspec.yaml (100%) rename openspec/changes/{support-release-stream-baselines => archive/2026-05-18-support-release-stream-baselines}/design.md (100%) rename openspec/changes/{support-release-stream-baselines => archive/2026-05-18-support-release-stream-baselines}/proposal.md (100%) rename openspec/changes/{support-release-stream-baselines => archive/2026-05-18-support-release-stream-baselines}/specs/historical-bundle-size-reporting/spec.md (100%) rename openspec/changes/{support-release-stream-baselines => archive/2026-05-18-support-release-stream-baselines}/specs/npm-release-baselines/spec.md (100%) rename openspec/changes/{support-release-stream-baselines => archive/2026-05-18-support-release-stream-baselines}/tasks.md (100%) create mode 100644 openspec/specs/historical-bundle-size-reporting/spec.md create mode 100644 openspec/specs/npm-release-baselines/spec.md diff --git a/openspec/changes/support-release-stream-baselines/.openspec.yaml b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/.openspec.yaml similarity index 100% rename from openspec/changes/support-release-stream-baselines/.openspec.yaml rename to openspec/changes/archive/2026-05-18-support-release-stream-baselines/.openspec.yaml diff --git a/openspec/changes/support-release-stream-baselines/design.md b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/design.md similarity index 100% rename from openspec/changes/support-release-stream-baselines/design.md rename to openspec/changes/archive/2026-05-18-support-release-stream-baselines/design.md diff --git a/openspec/changes/support-release-stream-baselines/proposal.md b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/proposal.md similarity index 100% rename from openspec/changes/support-release-stream-baselines/proposal.md rename to openspec/changes/archive/2026-05-18-support-release-stream-baselines/proposal.md diff --git a/openspec/changes/support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md similarity index 100% rename from openspec/changes/support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md rename to openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md diff --git a/openspec/changes/support-release-stream-baselines/specs/npm-release-baselines/spec.md b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/npm-release-baselines/spec.md similarity index 100% rename from openspec/changes/support-release-stream-baselines/specs/npm-release-baselines/spec.md rename to openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/npm-release-baselines/spec.md diff --git a/openspec/changes/support-release-stream-baselines/tasks.md b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/tasks.md similarity index 100% rename from openspec/changes/support-release-stream-baselines/tasks.md rename to openspec/changes/archive/2026-05-18-support-release-stream-baselines/tasks.md diff --git a/openspec/specs/historical-bundle-size-reporting/spec.md b/openspec/specs/historical-bundle-size-reporting/spec.md new file mode 100644 index 0000000..9b91380 --- /dev/null +++ b/openspec/specs/historical-bundle-size-reporting/spec.md @@ -0,0 +1,60 @@ +## Requirements + +### Requirement: Compare Against Historical Releases +The action SHALL compare configured local artifacts against the selected primary npm release baseline and each selected previous npm release baseline. + +#### Scenario: Historical releases are selected +- **WHEN** npm release resolution returns a primary release and previous releases +- **THEN** the action computes gzip byte sizes, byte deltas, and percent deltas for each configured file against each release baseline + +#### Scenario: No previous releases exist +- **WHEN** npm release resolution returns only the selected primary release +- **THEN** the action still produces a successful primary-release comparison without requiring historical releases + +### Requirement: Latest Release Remains Primary Baseline +The action SHALL treat the selected npm release as the primary baseline for top-level report totals and action outputs. + +#### Scenario: Latest comparison succeeds +- **WHEN** the action compares local files against the selected primary npm release +- **THEN** existing total size outputs describe the current build compared with the selected primary release baseline + +#### Scenario: Latest baseline file is missing +- **WHEN** a configured file cannot be found in the selected primary release tarball +- **THEN** the action fails with an error naming the missing baseline file and release version + +### Requirement: Historical Missing Files Are Reported +The action SHALL report missing configured files in previous-release baselines without failing the entire action. + +#### Scenario: Previous release is missing a configured file +- **WHEN** a configured file cannot be found in a previous release tarball +- **THEN** the historical comparison marks that release or file as incomplete and includes the missing file path in the report + +#### Scenario: Previous release has all configured files +- **WHEN** a previous release tarball contains all configured files +- **THEN** the historical comparison records complete per-file and total gzip comparison results for that release + +### Requirement: Generate Historical Comparison Report +The action SHALL write a JSON comparison report containing the primary release comparison and historical release comparisons. + +#### Scenario: Comparison report is written +- **WHEN** release comparisons complete successfully +- **THEN** the JSON report includes package identity, primary baseline metadata, top-level primary comparison results, and a history list for the selected primary release plus selected previous releases + +#### Scenario: Historical release is incomplete +- **WHEN** a historical release is missing one or more configured files +- **THEN** the JSON report identifies the release as incomplete and lists missing paths without fabricating gzip totals for missing files + +### Requirement: Render Collapsible Historical Comment +The action SHALL render historical release comparisons inside a collapsed details section when pull request commenting is enabled. + +#### Scenario: Pull request comment is rendered +- **WHEN** the action renders a bundle-size pull request comment with historical results +- **THEN** the selected primary release comparison is visible by default and the historical release summary appears inside an HTML `
` block + +#### Scenario: Historical summary includes selected releases +- **WHEN** the historical comment details section is expanded +- **THEN** it shows a release-level summary for the selected primary release and each selected previous release + +#### Scenario: Release stream comment is rendered +- **WHEN** the action renders a bundle-size pull request comment for a configured release stream +- **THEN** the comment identifies the configured release stream instead of describing the history as npm latest plus previous releases diff --git a/openspec/specs/npm-release-baselines/spec.md b/openspec/specs/npm-release-baselines/spec.md new file mode 100644 index 0000000..eb7695f --- /dev/null +++ b/openspec/specs/npm-release-baselines/spec.md @@ -0,0 +1,80 @@ +## Requirements + +### Requirement: Configure Npm Package Baseline +The action SHALL accept an npm package name input that identifies the package used for release baseline comparisons. + +#### Scenario: Package name is provided +- **WHEN** the workflow invokes the action with a valid npm package name +- **THEN** the action uses that package's npm registry metadata to resolve release baselines + +#### Scenario: Package name is missing +- **WHEN** the workflow invokes the action without an npm package name +- **THEN** the action fails with a configuration error naming the missing package input + +#### Scenario: Scoped package name is provided +- **WHEN** the workflow invokes the action with a scoped package name such as `@scope/name` +- **THEN** the action requests the correctly encoded npm registry metadata URL for that package + +### Requirement: Fetch Npm Registry Metadata +The action SHALL fetch package metadata from the public npm registry to discover available package releases. + +#### Scenario: Registry metadata is available +- **WHEN** the npm registry returns metadata for the configured package +- **THEN** the action reads dist-tags, version records, publish times, and tarball URLs from the metadata + +#### Scenario: Registry metadata request fails +- **WHEN** the npm registry metadata request fails or returns a non-successful response +- **THEN** the action fails with an error naming the package and registry request failure + +### Requirement: Select Latest And Previous Releases +The action SHALL select npm release baselines from either the package `latest` dist-tag or a configured major-version release stream. + +#### Scenario: More than 10 previous releases exist +- **WHEN** the package has a latest release and more than 10 earlier stable releases +- **THEN** the action selects the latest release plus the 10 most recently published previous stable releases + +#### Scenario: Fewer than 10 previous releases exist +- **WHEN** the package has a latest release and fewer than 10 earlier stable releases +- **THEN** the action selects the latest release plus all available previous stable releases + +#### Scenario: Latest dist-tag is missing +- **WHEN** the package metadata does not define a `latest` dist-tag that points to a version record and no release stream is configured +- **THEN** the action fails with an error naming the missing latest release metadata + +#### Scenario: Release stream is configured +- **WHEN** the workflow configures `release-stream` with a major version number +- **THEN** the action selects the newest stable release in that major-version stream as the primary baseline plus up to 10 earlier stable releases from the same stream + +#### Scenario: Release stream excludes npm latest +- **WHEN** the npm `latest` dist-tag points to a different major version than the configured `release-stream` +- **THEN** the action selects the newest stable release from the configured stream instead of the npm latest release + +#### Scenario: Release stream has no stable releases +- **WHEN** the workflow configures `release-stream` and package metadata contains no stable versions in that major-version stream +- **THEN** the action fails with an error naming the package and requested release stream + +### Requirement: Configure Release Stream Baseline +The action SHALL accept an optional release-stream input that identifies the npm major-version stream used for release baseline selection. + +#### Scenario: Release stream is omitted +- **WHEN** the workflow invokes the action without a release-stream input +- **THEN** the action preserves default npm latest baseline selection behavior + +#### Scenario: Release stream is provided +- **WHEN** the workflow invokes the action with a release-stream input such as `1` +- **THEN** the action uses that leading major version number to resolve npm release baselines from the matching release stream + +#### Scenario: Release stream is invalid +- **WHEN** the workflow invokes the action with a release-stream input that is not a non-negative integer major version +- **THEN** the action fails with a configuration error naming the invalid release-stream input + +### Requirement: Resolve Release Tarball URIs +The action SHALL use each selected npm version's `dist.tarball` URL as the archive source for that release baseline. + +#### Scenario: Selected version has tarball URL +- **WHEN** a selected version record contains a tarball URL +- **THEN** the action downloads that tarball and uses it for baseline file resolution + +#### Scenario: Selected version lacks tarball URL +- **WHEN** a selected version record does not contain a usable tarball URL +- **THEN** the action fails with an error naming the affected package version From 8cc0f5fefbaf095d2dc89c40a2ff209ef559b9b7 Mon Sep 17 00:00:00 2001 From: Jason Saayman Date: Mon, 18 May 2026 19:54:27 +0200 Subject: [PATCH 3/6] chore: updated git attributes --- .gitattributes | 2 ++ .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../historical-bundle-size-reporting/spec.md | 0 .../specs/npm-release-baselines/spec.md | 0 .../specs/tarball-gzip-comparison/spec.md | 0 .../tasks.md | 0 .../specs/tarball-gzip-comparison/spec.md | 33 ++++++++----------- 9 files changed, 15 insertions(+), 20 deletions(-) create mode 100644 .gitattributes rename openspec/changes/{support-npm-release-history => archive/2026-05-17-support-npm-release-history}/.openspec.yaml (100%) rename openspec/changes/{support-npm-release-history => archive/2026-05-17-support-npm-release-history}/design.md (100%) rename openspec/changes/{support-npm-release-history => archive/2026-05-17-support-npm-release-history}/proposal.md (100%) rename openspec/changes/{support-npm-release-history => archive/2026-05-17-support-npm-release-history}/specs/historical-bundle-size-reporting/spec.md (100%) rename openspec/changes/{support-npm-release-history => archive/2026-05-17-support-npm-release-history}/specs/npm-release-baselines/spec.md (100%) rename openspec/changes/{support-npm-release-history => archive/2026-05-17-support-npm-release-history}/specs/tarball-gzip-comparison/spec.md (100%) rename openspec/changes/{support-npm-release-history => archive/2026-05-17-support-npm-release-history}/tasks.md (100%) diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c305e38 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +dist/** linguist-generated=true +openspec/** linguist-generated=true diff --git a/openspec/changes/support-npm-release-history/.openspec.yaml b/openspec/changes/archive/2026-05-17-support-npm-release-history/.openspec.yaml similarity index 100% rename from openspec/changes/support-npm-release-history/.openspec.yaml rename to openspec/changes/archive/2026-05-17-support-npm-release-history/.openspec.yaml diff --git a/openspec/changes/support-npm-release-history/design.md b/openspec/changes/archive/2026-05-17-support-npm-release-history/design.md similarity index 100% rename from openspec/changes/support-npm-release-history/design.md rename to openspec/changes/archive/2026-05-17-support-npm-release-history/design.md diff --git a/openspec/changes/support-npm-release-history/proposal.md b/openspec/changes/archive/2026-05-17-support-npm-release-history/proposal.md similarity index 100% rename from openspec/changes/support-npm-release-history/proposal.md rename to openspec/changes/archive/2026-05-17-support-npm-release-history/proposal.md diff --git a/openspec/changes/support-npm-release-history/specs/historical-bundle-size-reporting/spec.md b/openspec/changes/archive/2026-05-17-support-npm-release-history/specs/historical-bundle-size-reporting/spec.md similarity index 100% rename from openspec/changes/support-npm-release-history/specs/historical-bundle-size-reporting/spec.md rename to openspec/changes/archive/2026-05-17-support-npm-release-history/specs/historical-bundle-size-reporting/spec.md diff --git a/openspec/changes/support-npm-release-history/specs/npm-release-baselines/spec.md b/openspec/changes/archive/2026-05-17-support-npm-release-history/specs/npm-release-baselines/spec.md similarity index 100% rename from openspec/changes/support-npm-release-history/specs/npm-release-baselines/spec.md rename to openspec/changes/archive/2026-05-17-support-npm-release-history/specs/npm-release-baselines/spec.md diff --git a/openspec/changes/support-npm-release-history/specs/tarball-gzip-comparison/spec.md b/openspec/changes/archive/2026-05-17-support-npm-release-history/specs/tarball-gzip-comparison/spec.md similarity index 100% rename from openspec/changes/support-npm-release-history/specs/tarball-gzip-comparison/spec.md rename to openspec/changes/archive/2026-05-17-support-npm-release-history/specs/tarball-gzip-comparison/spec.md diff --git a/openspec/changes/support-npm-release-history/tasks.md b/openspec/changes/archive/2026-05-17-support-npm-release-history/tasks.md similarity index 100% rename from openspec/changes/support-npm-release-history/tasks.md rename to openspec/changes/archive/2026-05-17-support-npm-release-history/tasks.md diff --git a/openspec/specs/tarball-gzip-comparison/spec.md b/openspec/specs/tarball-gzip-comparison/spec.md index 117b9af..444a773 100644 --- a/openspec/specs/tarball-gzip-comparison/spec.md +++ b/openspec/specs/tarball-gzip-comparison/spec.md @@ -1,18 +1,7 @@ ## Requirements -### Requirement: Configure Tarball Baseline -The action SHALL accept a tarball URI input that identifies the baseline archive used for comparison. - -#### Scenario: Valid tarball URI is provided -- **WHEN** the workflow invokes the action with a tarball URI -- **THEN** the action uses that URI as the baseline source for all configured file comparisons - -#### Scenario: Tarball URI is missing -- **WHEN** the workflow invokes the action without a tarball URI -- **THEN** the action fails with a configuration error - ### Requirement: Configure Compared File Paths -The action SHALL accept one or more file paths that identify artifacts to compare between the local build output and the baseline tarball. +The action SHALL accept one or more file paths that identify artifacts to compare between the local build output and npm release baseline tarballs. #### Scenario: Multiple files are configured - **WHEN** the workflow provides multiple file paths @@ -34,15 +23,15 @@ The action SHALL resolve configured file paths relative to the local project roo - **THEN** the action fails with an error naming the missing local file ### Requirement: Resolve Tarball Artifacts -The action SHALL resolve configured file paths inside the downloaded tarball baseline. +The action SHALL resolve configured file paths inside downloaded npm release tarball baselines. #### Scenario: Tarball contains package root directory -- **WHEN** the tarball stores files under a single top-level directory +- **WHEN** a release tarball stores files under a single top-level directory - **THEN** the action resolves configured paths relative to that top-level directory -#### Scenario: Baseline file is missing -- **WHEN** a configured file cannot be found in the tarball baseline -- **THEN** the action fails with an error naming the missing baseline file +#### Scenario: Latest baseline file is missing +- **WHEN** a configured file cannot be found in the latest release tarball baseline +- **THEN** the action fails with an error naming the missing baseline file and release version ### Requirement: Measure Gzip Size The action SHALL measure gzip-compressed size in bytes for each configured local and baseline file. @@ -52,11 +41,15 @@ The action SHALL measure gzip-compressed size in bytes for each configured local - **THEN** the action records gzip byte sizes for both versions of the file ### Requirement: Generate Comparison File -The action SHALL write a comparison file containing gzip-size results for every configured file. +The action SHALL write a comparison file containing gzip-size results for every configured file against the latest release and historical release baselines. #### Scenario: Comparison succeeds -- **WHEN** all configured files are read and measured successfully -- **THEN** the action writes a comparison file with baseline bytes, current bytes, byte delta, and percent delta for each file +- **WHEN** all configured local files and latest baseline files are read and measured successfully +- **THEN** the action writes a comparison file with latest baseline bytes, current bytes, byte delta, and percent delta for each file + +#### Scenario: Historical comparisons exist +- **WHEN** previous release baselines are selected +- **THEN** the action includes historical comparison results in the comparison file #### Scenario: No target size is configured - **WHEN** the action generates the comparison file From fb82e492b2aa0920a7b27f16ee0af6546277e0d6 Mon Sep 17 00:00:00 2001 From: Jason Saayman Date: Mon, 18 May 2026 19:54:58 +0200 Subject: [PATCH 4/6] chore: bump version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45efefa..ae4cd76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bundle-size-action", - "version": "0.1.0", + "version": "0.1.1", "description": "A GitHub Action to check and report bundle sizes", "type": "module", "main": "dist/index.js", From 161c03f20ebb6b1096e2666619a58d91fb9292fd Mon Sep 17 00:00:00 2001 From: Jason Saayman Date: Mon, 18 May 2026 19:57:57 +0200 Subject: [PATCH 5/6] chore: apply review changes --- .../specs/historical-bundle-size-reporting/spec.md | 2 +- openspec/specs/historical-bundle-size-reporting/spec.md | 2 +- tests/action.test.ts | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md index cb8546c..e530287 100644 --- a/openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md +++ b/openspec/changes/archive/2026-05-18-support-release-stream-baselines/specs/historical-bundle-size-reporting/spec.md @@ -11,7 +11,7 @@ The action SHALL compare configured local artifacts against the selected primary - **WHEN** npm release resolution returns only the selected primary release - **THEN** the action still produces a successful primary-release comparison without requiring historical releases -### Requirement: Latest Release Remains Primary Baseline +### Requirement: Selected Release Remains Primary Baseline The action SHALL treat the selected npm release as the primary baseline for top-level report totals and action outputs. #### Scenario: Latest comparison succeeds diff --git a/openspec/specs/historical-bundle-size-reporting/spec.md b/openspec/specs/historical-bundle-size-reporting/spec.md index 9b91380..13d1abf 100644 --- a/openspec/specs/historical-bundle-size-reporting/spec.md +++ b/openspec/specs/historical-bundle-size-reporting/spec.md @@ -11,7 +11,7 @@ The action SHALL compare configured local artifacts against the selected primary - **WHEN** npm release resolution returns only the selected primary release - **THEN** the action still produces a successful primary-release comparison without requiring historical releases -### Requirement: Latest Release Remains Primary Baseline +### Requirement: Selected Release Remains Primary Baseline The action SHALL treat the selected npm release as the primary baseline for top-level report totals and action outputs. #### Scenario: Latest comparison succeeds diff --git a/tests/action.test.ts b/tests/action.test.ts index 4698e81..5b108cf 100644 --- a/tests/action.test.ts +++ b/tests/action.test.ts @@ -231,6 +231,7 @@ test('run resolves npm baselines from a configured release stream', async () => const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'bundle-size-action-')); const outputFile = path.join(tempRoot, 'github-output.txt'); const originalFetch = global.fetch; + let exitCode: number | string | null | undefined; try { await mkdir(path.join(tempRoot, 'dist'), { recursive: true }); @@ -293,10 +294,11 @@ test('run resolves npm baselines from a configured release stream', async () => }, async () => { await run(); + exitCode = process.exitCode; }, ); - assert.equal(process.exitCode, undefined); + assert.equal(exitCode, undefined); const report = JSON.parse( await readFile(path.join(tempRoot, 'reports/comparison.json'), 'utf8'), From b9469f491cc5d1ca491a9ddfec0f2460ed7e0f1b Mon Sep 17 00:00:00 2001 From: Jason Saayman Date: Mon, 18 May 2026 20:00:44 +0200 Subject: [PATCH 6/6] chore: update generated qualifier --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index c305e38..16878a1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ dist/** linguist-generated=true -openspec/** linguist-generated=true +openspec/changes/archive/** linguist-generated=true