From c63a3d51175cd1d0cda29ce71b78dd2b563c7254 Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 03:50:46 -0400 Subject: [PATCH 01/17] ci: modernise the workflow and check every SDK builds against the bundle --- .github/actions/download/action.yml | 27 + .github/actions/setup-generator/action.yml | 28 + .github/workflows/ci.yaml | 117 ++- package.json | 2 + pnpm-lock.yaml | 958 ++++++++++++++++++++- 5 files changed, 1067 insertions(+), 65 deletions(-) create mode 100644 .github/actions/download/action.yml create mode 100644 .github/actions/setup-generator/action.yml diff --git a/.github/actions/download/action.yml b/.github/actions/download/action.yml new file mode 100644 index 00000000..a399c64e --- /dev/null +++ b/.github/actions/download/action.yml @@ -0,0 +1,27 @@ +name: Fetch a specification bundle +description: >- + Leaves the requested bundle in the working directory, taken from this run's + artifacts when running inside the specification repository and from the latest + release otherwise. + +inputs: + bundle: + description: >- + Bundle to fetch. + required: false + default: openapi.json + +runs: + using: composite + steps: + - if: github.repository == 'vrchatapi/specification' + uses: actions/download-artifact@v8 + with: + name: ${{ inputs.bundle }} + path: . + + - if: github.repository != 'vrchatapi/specification' + run: >- + curl -Lfo "${{ inputs.bundle }}" + "https://github.com/vrchatapi/specification/releases/latest/download/${{ inputs.bundle }}" + shell: bash diff --git a/.github/actions/setup-generator/action.yml b/.github/actions/setup-generator/action.yml new file mode 100644 index 00000000..0744e84c --- /dev/null +++ b/.github/actions/setup-generator/action.yml @@ -0,0 +1,28 @@ +name: Install the OpenAPI generator +description: >- + Puts `openapi-generator` on the path at the version openapitools.json pins. + The generator is a Java program and the runner image already ships a JDK, so + nothing here needs Node. + +runs: + using: composite + steps: + - uses: actions/cache@v6 + with: + path: ~/.cache/openapi-generator + key: openapi-generator-${{ hashFiles('openapitools.json') }} + + - run: | + set -euo pipefail + + version=$(jq -re '."generator-cli".version' openapitools.json) + jar="$HOME/.cache/openapi-generator/openapi-generator-cli-$version.jar" + + [ -f "$jar" ] || curl -fsSL --create-dirs -o "$jar" \ + "https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/$version/openapi-generator-cli-$version.jar" + + mkdir -p "$HOME/.local/bin" + printf '#!/usr/bin/env bash\nexec java -jar %s "$@"\n' "$jar" > "$HOME/.local/bin/openapi-generator" + chmod +x "$HOME/.local/bin/openapi-generator" + printf '%s\n' "$HOME/.local/bin" >> "$GITHUB_PATH" + shell: bash diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 28416599..2f7085dd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -4,45 +4,22 @@ on: - main pull_request: workflow_dispatch: - inputs: - no_lint: - description: Skip lint job - type: boolean - default: false - no_release: - description: Skip release job - type: boolean - default: false env: GH_TOKEN: ${{ github.token }} jobs: lint: - if: ${{ !contains(github.event.head_commit.message, 'no_lint') && !github.event.inputs.no_lint }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/cache@v4 + - uses: pnpm/setup@v2 with: - key: pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: pnpm- - path: | - ~/.pnpm-store - ~/.cache/pnpm - **/node_modules - - - uses: pnpm/action-setup@v4 - with: - version: 10 - run_install: false - - - uses: oven-sh/setup-bun@v2 - - - run: pnpm install + runtime: bun@latest + cache: true - if: github.event_name == 'push' run: | @@ -98,30 +75,15 @@ jobs: bundle: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: actions/cache@v4 + - uses: pnpm/setup@v2 with: - key: pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: pnpm- - path: | - ~/.pnpm-store - ~/.cache/pnpm - **/node_modules - - - uses: pnpm/action-setup@v4 - with: - version: 10 - run_install: false - - - uses: oven-sh/setup-bun@v2 - - - run: pnpm install + runtime: bun@latest + cache: true - run: bun --bun run bundle - - run: pnpm add @actions/artifact@5.0.2 - - uses: actions/github-script@v8 with: script: | @@ -138,37 +100,64 @@ jobs: return artifact.uploadArtifact(file, [pathname], dirname(pathname)); })); + # Each SDK builds against this run's bundle, so a spec change that breaks a + # generated client fails here rather than after release. + # `uses` takes no expressions, so each SDK needs its own job rather than a + # matrix leg. + build_javascript: + needs: bundle + uses: vrchatapi/vrchatapi-javascript/.github/workflows/build.yaml@ci/modernise-actions + with: + ref: ci/modernise-actions + + build_rust: + needs: bundle + uses: vrchatapi/vrchatapi-rust/.github/workflows/build.yaml@ci/modernise-actions + with: + ref: ci/modernise-actions + + build_java: + needs: bundle + uses: vrchatapi/vrchatapi-java/.github/workflows/build.yaml@ci/modernise-actions + with: + ref: ci/modernise-actions + + build_python: + needs: bundle + uses: vrchatapi/vrchatapi-python/.github/workflows/build.yaml@ci/modernise-actions + with: + ref: ci/modernise-actions + + build_csharp: + needs: bundle + uses: vrchatapi/vrchatapi-csharp/.github/workflows/build.yaml@ci/modernise-actions + with: + ref: ci/modernise-actions + + build_dart: + needs: bundle + uses: vrchatapi/vrchatapi-dart/.github/workflows/build.yaml@ci/modernise-actions + with: + ref: ci/modernise-actions + release: runs-on: ubuntu-latest needs: - lint - bundle - if: ${{ !failure() && !cancelled() && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, 'no_release') && !github.event.inputs.no_release }} + if: ${{ !failure() && !cancelled() && github.ref == 'refs/heads/main' }} outputs: version: ${{ steps.metadata.outputs.version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/cache@v4 - with: - key: pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: pnpm- - path: | - ~/.pnpm-store - ~/.cache/pnpm - **/node_modules - - - uses: pnpm/action-setup@v4 + - uses: pnpm/setup@v2 with: - version: 10 - run_install: false - - - uses: oven-sh/setup-bun@v2 - - - run: pnpm install + runtime: bun@latest + cache: true - uses: actions/download-artifact@v5 with: diff --git a/package.json b/package.json index d4508a45..a8624e68 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "type": "module", "version": "1.0.0", "private": true, + "packageManager": "pnpm@11.20.0", "description": "VRChat API OpenAPI Specification", "author": "", "license": "MIT", @@ -17,6 +18,7 @@ "bundle": "redocly bundle" }, "devDependencies": { + "@actions/artifact": "5.0.2", "@actions/core": "^1.11.1", "@apidevtools/json-schema-ref-parser": "^15.1.2", "@ariesclark/eslint-config": "^3.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd6d036e..ab50b503 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: devDependencies: + '@actions/artifact': + specifier: 5.0.2 + version: 5.0.2 '@actions/core': specifier: ^1.11.1 version: 1.11.1 @@ -80,18 +83,36 @@ importers: packages: + '@actions/artifact@5.0.2': + resolution: {integrity: sha512-NmA+THO1s/Ubqf5y34EZofB1FRORcToa3T8Mb3/Z87TCCozTtvBUaxDn8OPPwgyYQ4ft0nd01Z4kFSu2DTWqGw==} + '@actions/core@1.11.1': resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} + '@actions/core@2.0.3': + resolution: {integrity: sha512-Od9Thc3T1mQJYddvVPM4QGiLUewdh+3txmDYHHxoNdkqysR1MbCT+rFOtNUxYAz+7+6RIsqipVahY2GJqGPyxA==} + '@actions/exec@1.1.1': resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==} + '@actions/exec@2.0.0': + resolution: {integrity: sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==} + + '@actions/github@6.0.1': + resolution: {integrity: sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==} + '@actions/http-client@2.2.3': resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} + '@actions/http-client@3.0.2': + resolution: {integrity: sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==} + '@actions/io@1.1.3': resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==} + '@actions/io@2.0.0': + resolution: {integrity: sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==} + '@antfu/eslint-config@3.16.0': resolution: {integrity: sha512-g6RAXUMeow9vexoOMYwCpByY2xSDpAD78q+rvQLvVpY6MFcxFD/zmdrZGYa/yt7LizK86m17kIYKOGLJ3L8P0w==} hasBin: true @@ -165,6 +186,61 @@ packages: '@asyncapi/specs@6.10.0': resolution: {integrity: sha512-vB5oKLsdrLUORIZ5BXortZTlVyGWWMC1Nud/0LtgxQ3Yn2738HigAD6EVqScvpPsDUI/bcLVsYEXN4dtXQHVng==} + '@azure/abort-controller@2.2.0': + resolution: {integrity: sha512-fNAjWnA/nZ2jz31kxR/AqRaUT8ewHBw/WuBIosK0moMy1C9e5ValbDfFdIxJzVOOYaYkV/b2F1S4H/aHiqfVQg==} + engines: {node: '>=22.0.0'} + + '@azure/core-auth@1.11.0': + resolution: {integrity: sha512-IUZydyTUkDnYdstOW9pFOOUQlBjAepK5teihDE3x6yxsPJs/hsAaaYpeGxdxrgtOiJbBKSjKW7MDk7AEhb4LRg==} + engines: {node: '>=22.0.0'} + + '@azure/core-client@1.11.0': + resolution: {integrity: sha512-JjQWO6akOck45PH/XBrxzsQGAiKrfFl4m5iggJ0ItMIz5omRufOXWpqCPpdjKN3vKDzlSUvFjaMb7Zwf0gvAdA==} + engines: {node: '>=22.0.0'} + + '@azure/core-http-compat@2.5.0': + resolution: {integrity: sha512-BoSmXPx2er1Ai+wKlDvj29jIQespCNBwEmKyZVHO2kEFsWbGjAjwMCGzug3DJM5/QYIV3vej0S1zcU5bq9fa8w==} + engines: {node: '>=22.0.0'} + peerDependencies: + '@azure/core-client': ^1.10.0 + '@azure/core-rest-pipeline': ^1.22.0 + + '@azure/core-lro@2.7.2': + resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} + engines: {node: '>=18.0.0'} + + '@azure/core-paging@1.7.0': + resolution: {integrity: sha512-7GEAoIsaoBr6KELNRb8nypowCqvk8dnCHFCYg4XD4lOQGY2GqjQg5IhkRjyBFRO18CGSMq05PaNqSOE9GQro3g==} + engines: {node: '>=22.0.0'} + + '@azure/core-rest-pipeline@1.25.0': + resolution: {integrity: sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==} + engines: {node: '>=22.0.0'} + + '@azure/core-tracing@1.4.0': + resolution: {integrity: sha512-eGwxD0AtncrxeBM4tG8R55Pc3rdX1hNW2WibJAgYpCVA6E93mvvVH+LcssoVjOBrSKWS55yEIHsk0X8ctHmfOQ==} + engines: {node: '>=22.0.0'} + + '@azure/core-util@1.14.0': + resolution: {integrity: sha512-9n2pWK61veAuN0V20t9lOuoV4CFMdyAZ1ygZzvBGk/pBBJRib/PjL9PLXa/aI2CcPpyHfqVsxxqLCYl6uZlfDw==} + engines: {node: '>=22.0.0'} + + '@azure/core-xml@1.6.0': + resolution: {integrity: sha512-e7lX/dk//F6Qf7BB6PTY4+p2yuOQtyOeHGyapYHNwqSp2OnYpwQt49A/Nin2XmKBQ69pwagR4k/lQBq8lbHQkA==} + engines: {node: '>=22.0.0'} + + '@azure/logger@1.4.0': + resolution: {integrity: sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==} + engines: {node: '>=22.0.0'} + + '@azure/storage-blob@12.33.0': + resolution: {integrity: sha512-2SX8oP8PyblUcAFZSg39c8Ls+tFjavM6sBeV+qpw33mRzRhI/5hrFJmJ/x0H9xx5l6ECPvgSP8uPxqTeVbHNIA==} + engines: {node: '>=22.0.0'} + + '@azure/storage-common@12.5.0': + resolution: {integrity: sha512-bttzuhQiCIwrkzjPDA+AtAR7dg19L/CC6ztcqJ5LfvWpXuys9mHp0UQ0udYnoUvv9SCT9KTR5kqFvFr0e6k0lQ==} + engines: {node: '>=22.0.0'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -190,6 +266,12 @@ packages: resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} + '@bufbuild/protobuf@2.13.0': + resolution: {integrity: sha512-acq7c49vxfm1ggJ95P70TX7ABDM0vxr1SYD3BB0o0jnBLB4OAqeHyKuN+cD3w80gXEDQ2zxHpR6CUeA+O/aU9g==} + + '@bufbuild/protoplugin@2.13.0': + resolution: {integrity: sha512-32eMChKaL/A8Hh5AfMmXSdnuyznN85uoEjoyWiWeRrvtQOtpqX/v1R9PDe0g9vMIgzznK9inMT3CUaal0kjLUQ==} + '@clack/core@0.4.1': resolution: {integrity: sha512-Pxhij4UXg8KSr7rPek6Zowm+5M22rbd2g1nfojHJkxp5YkFqiZ2+YLEM/XGVIzvGOcM0nqjIFxrpDwWRZYWYjA==} @@ -944,6 +1026,9 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} + '@nodable/entities@3.0.0': + resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -956,6 +1041,68 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@octokit/auth-token@4.0.0': + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + + '@octokit/core@5.2.2': + resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==} + engines: {node: '>= 18'} + + '@octokit/endpoint@9.0.6': + resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==} + engines: {node: '>= 18'} + + '@octokit/graphql@7.1.1': + resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==} + engines: {node: '>= 18'} + + '@octokit/openapi-types@12.11.0': + resolution: {integrity: sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==} + + '@octokit/openapi-types@20.0.0': + resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==} + + '@octokit/openapi-types@24.2.0': + resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==} + + '@octokit/plugin-paginate-rest@9.2.2': + resolution: {integrity: sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-request-log@1.0.4': + resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==} + peerDependencies: + '@octokit/core': '>=3' + + '@octokit/plugin-rest-endpoint-methods@10.4.1': + resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-retry@3.0.9': + resolution: {integrity: sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==} + + '@octokit/request-error@5.1.1': + resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} + engines: {node: '>= 18'} + + '@octokit/request@8.4.1': + resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==} + engines: {node: '>= 18'} + + '@octokit/types@12.6.0': + resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==} + + '@octokit/types@13.10.0': + resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} + + '@octokit/types@6.41.0': + resolution: {integrity: sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==} + '@opentelemetry/api-logs@0.202.0': resolution: {integrity: sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==} engines: {node: '>=8.0.0'} @@ -1028,10 +1175,28 @@ packages: resolution: {integrity: sha512-aKcOkyrorBGlajjRdVoJWHTxfxO1vCNHLJVlSDaRHDIdjU+pX8IYQPvPDkYiujKLbRnWU+1TBwEt0QRgSm4SGA==} engines: {node: '>=14'} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@pkgr/core@0.2.9': resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@protobuf-ts/plugin@2.11.1': + resolution: {integrity: sha512-HyuprDcw0bEEJqkOWe1rnXUP0gwYLij8YhPuZyZk6cJbIgc/Q0IFgoHQxOXNIXAcXM4Sbehh6kjVnCzasElw1A==} + hasBin: true + + '@protobuf-ts/protoc@2.11.1': + resolution: {integrity: sha512-mUZJaV0daGO6HUX90o/atzQ6A7bbN2RSuHtdwo8SSF2Qoe3zHwa4IHyCN1evftTeHfLmdz+45qo47sL+5P8nyg==} + hasBin: true + + '@protobuf-ts/runtime-rpc@2.11.1': + resolution: {integrity: sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==} + + '@protobuf-ts/runtime@2.11.1': + resolution: {integrity: sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==} + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -1436,6 +1601,15 @@ packages: resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/vfs@1.6.4': + resolution: {integrity: sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==} + peerDependencies: + typescript: '*' + + '@typespec/ts-http-runtime@0.3.8': + resolution: {integrity: sha512-bLMpVcWZNzq6lYOybwFwOAR1IXKcHnhUNqYeHjl1bET/qE3jFPFH+p8Wrh3rU4xwdnifPxmKNESBYnvnmc75aA==} + engines: {node: '>=22.0.0'} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] @@ -1635,6 +1809,17 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + anynum@1.0.1: + resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + are-docs-informative@0.0.2: resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} engines: {node: '>=14'} @@ -1668,6 +1853,9 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1675,13 +1863,64 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + b4a@1.8.1: + resolution: {integrity: sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.9.1: + resolution: {integrity: sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.8.0: + resolution: {integrity: sha512-fM+MhCvdQhZ7NV6S95a07gPSqjIYKn6mFaXfx266wN3ajZGl/+1AzH+ubkXQ0fFZvOe2nk9VHkzdYkQE5zMV3Q==} + engines: {bare: '>=1.28.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-path@3.1.1: + resolution: {integrity: sha512-JprUlveX3QjApC1cTpsUOiscADftCGVWkzitbHsRqv84hzYwYHw2mbluddsq5TvI8mH/8Ov1f4BiMAdcB0oYnQ==} + + bare-stream@2.13.3: + resolution: {integrity: sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==} + peerDependencies: + bare-abort-controller: '*' + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.5.1: + resolution: {integrity: sha512-cD5ciQuKlx+eumTCfqbfiL+fhQm+dHbVNB/cX4+d+I/nx4JsVop9VoFEPAs5RJ6I84QR6bZIBjpd2kjDOYeWcg==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.8.31: resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==} hasBin: true + before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + better-ajv-errors@1.2.0: resolution: {integrity: sha512-UW+IsFycygIo7bclP9h5ugkNH8EjCSgqyFB/yQ4Hqqa1OEYDtb0uFIkYE0b6+CjkgJYVM5UKI/pJPxjYe9EZlA==} engines: {node: '>= 12.13.0'} @@ -1692,12 +1931,18 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + binary@0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + birecord@0.1.1: resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1713,6 +1958,17 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + buffers@0.1.1: + resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} + engines: {node: '>=0.2.0'} + builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -1761,6 +2017,9 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chainsaw@0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + chalk-template@1.1.2: resolution: {integrity: sha512-2bxTP2yUH7AJj/VAXfcA+4IcWGdQ87HwBANLt5XxGTeomo8yG0y95N1um9i5StvhT/Bl0/2cARA5v1PpPXUxUA==} engines: {node: '>=14.16'} @@ -1852,6 +2111,10 @@ packages: compare-versions@6.1.1: resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1878,6 +2141,15 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1985,6 +2257,9 @@ packages: resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==} engines: {node: '>= 0.6.0'} + deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2353,6 +2628,13 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -2363,6 +2645,9 @@ packages: resolution: {integrity: sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw==} engines: {node: '>=6.0.0'} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} engines: {node: '>=8.6.0'} @@ -2382,10 +2667,17 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-xml-builder@1.3.0: + resolution: {integrity: sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==} + fast-xml-parser@4.5.3: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true + fast-xml-parser@5.10.1: + resolution: {integrity: sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==} + hasBin: true + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -2509,14 +2801,20 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + glob@11.1.0: resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-directory@4.0.1: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} @@ -2590,6 +2888,10 @@ packages: resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==} engines: {node: '>=14'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + http2-client@1.3.5: resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==} @@ -2597,6 +2899,9 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -2738,6 +3043,10 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -2750,6 +3059,9 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-unsafe@2.0.0: + resolution: {integrity: sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -2762,12 +3074,18 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.1.1: resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} engines: {node: 20 || >=22} @@ -2853,9 +3171,16 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} + jwt-decode@3.1.2: + resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -2910,6 +3235,9 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.2: resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} engines: {node: 20 || >=22} @@ -3106,6 +3434,10 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -3305,6 +3637,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-expression-matcher@1.6.2: + resolution: {integrity: sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==} + engines: {node: '>=14.0.0'} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -3316,6 +3652,10 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.1: resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} engines: {node: 20 || >=22} @@ -3410,6 +3750,13 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -3455,10 +3802,20 @@ packages: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} engines: {node: '>=8'} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -3553,6 +3910,9 @@ packages: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -3710,6 +4070,9 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + streamx@2.28.0: + resolution: {integrity: sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==} + string-ts@2.2.1: resolution: {integrity: sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==} @@ -3733,6 +4096,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -3755,6 +4121,9 @@ packages: strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + strnum@2.4.1: + resolution: {integrity: sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==} + styled-components@6.1.19: resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==} engines: {node: '>= 16'} @@ -3790,6 +4159,15 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tar-stream@3.2.0: + resolution: {integrity: sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==} + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -3822,6 +4200,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + traverse@0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -3915,6 +4296,16 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typescript@3.9.10: + resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} + engines: {node: '>=4.2.0'} + hasBin: true + + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -3943,6 +4334,10 @@ packages: resolution: {integrity: sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==} engines: {node: '>=18.17'} + undici@6.28.0: + resolution: {integrity: sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==} + engines: {node: '>=18.17'} + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -3955,6 +4350,9 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -3962,6 +4360,9 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + unzip-stream@0.3.4: + resolution: {integrity: sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw==} + update-browserslist-db@1.1.4: resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} hasBin: true @@ -4075,6 +4476,10 @@ packages: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} + xml-naming@0.3.0: + resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==} + engines: {node: '>=16.0.0'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -4115,6 +4520,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + zod@4.1.13: resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} @@ -4123,22 +4532,69 @@ packages: snapshots: + '@actions/artifact@5.0.2': + dependencies: + '@actions/core': 2.0.3 + '@actions/github': 6.0.1 + '@actions/http-client': 3.0.2 + '@azure/storage-blob': 12.33.0 + '@octokit/core': 5.2.2 + '@octokit/plugin-request-log': 1.0.4(@octokit/core@5.2.2) + '@octokit/plugin-retry': 3.0.9 + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + '@protobuf-ts/plugin': 2.11.1 + archiver: 7.0.1 + jwt-decode: 3.1.2 + unzip-stream: 0.3.4 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + - supports-color + '@actions/core@1.11.1': dependencies: '@actions/exec': 1.1.1 '@actions/http-client': 2.2.3 + '@actions/core@2.0.3': + dependencies: + '@actions/exec': 2.0.0 + '@actions/http-client': 3.0.2 + '@actions/exec@1.1.1': dependencies: '@actions/io': 1.1.3 + '@actions/exec@2.0.0': + dependencies: + '@actions/io': 2.0.0 + + '@actions/github@6.0.1': + dependencies: + '@actions/http-client': 2.2.3 + '@octokit/core': 5.2.2 + '@octokit/plugin-paginate-rest': 9.2.2(@octokit/core@5.2.2) + '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.2.2) + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + undici: 5.29.0 + '@actions/http-client@2.2.3': dependencies: tunnel: 0.0.6 undici: 5.29.0 + '@actions/http-client@3.0.2': + dependencies: + tunnel: 0.0.6 + undici: 6.28.0 + '@actions/io@1.1.3': {} + '@actions/io@2.0.0': {} + '@antfu/eslint-config@3.16.0(@eslint-react/eslint-plugin@2.3.9(eslint@9.39.1)(typescript@5.9.3))(@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.9.3))(@vue/compiler-sfc@3.5.25)(eslint-plugin-react-refresh@0.4.24(eslint@9.39.1))(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@antfu/install-pkg': 1.1.0 @@ -4241,6 +4697,119 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@azure/abort-controller@2.2.0': + dependencies: + tslib: 2.8.1 + + '@azure/core-auth@1.11.0': + dependencies: + '@azure/abort-controller': 2.2.0 + '@azure/core-util': 1.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-client@1.11.0': + dependencies: + '@azure/abort-controller': 2.2.0 + '@azure/core-auth': 1.11.0 + '@azure/core-rest-pipeline': 1.25.0 + '@azure/core-tracing': 1.4.0 + '@azure/core-util': 1.14.0 + '@azure/logger': 1.4.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-http-compat@2.5.0(@azure/core-client@1.11.0)(@azure/core-rest-pipeline@1.25.0)': + dependencies: + '@azure/abort-controller': 2.2.0 + '@azure/core-client': 1.11.0 + '@azure/core-rest-pipeline': 1.25.0 + + '@azure/core-lro@2.7.2': + dependencies: + '@azure/abort-controller': 2.2.0 + '@azure/core-util': 1.14.0 + '@azure/logger': 1.4.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-paging@1.7.0': + dependencies: + tslib: 2.8.1 + + '@azure/core-rest-pipeline@1.25.0': + dependencies: + '@azure/abort-controller': 2.2.0 + '@azure/core-auth': 1.11.0 + '@azure/core-tracing': 1.4.0 + '@azure/core-util': 1.14.0 + '@azure/logger': 1.4.0 + '@typespec/ts-http-runtime': 0.3.8 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.4.0': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.14.0': + dependencies: + '@azure/abort-controller': 2.2.0 + '@typespec/ts-http-runtime': 0.3.8 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-xml@1.6.0': + dependencies: + fast-xml-parser: 5.10.1 + tslib: 2.8.1 + + '@azure/logger@1.4.0': + dependencies: + '@typespec/ts-http-runtime': 0.3.8 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/storage-blob@12.33.0': + dependencies: + '@azure/abort-controller': 2.2.0 + '@azure/core-auth': 1.11.0 + '@azure/core-client': 1.11.0 + '@azure/core-http-compat': 2.5.0(@azure/core-client@1.11.0)(@azure/core-rest-pipeline@1.25.0) + '@azure/core-lro': 2.7.2 + '@azure/core-paging': 1.7.0 + '@azure/core-rest-pipeline': 1.25.0 + '@azure/core-tracing': 1.4.0 + '@azure/core-util': 1.14.0 + '@azure/core-xml': 1.6.0 + '@azure/logger': 1.4.0 + '@azure/storage-common': 12.5.0(@azure/core-client@1.11.0) + events: 3.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/storage-common@12.5.0(@azure/core-client@1.11.0)': + dependencies: + '@azure/abort-controller': 2.2.0 + '@azure/core-auth': 1.11.0 + '@azure/core-http-compat': 2.5.0(@azure/core-client@1.11.0)(@azure/core-rest-pipeline@1.25.0) + '@azure/core-rest-pipeline': 1.25.0 + '@azure/core-tracing': 1.4.0 + '@azure/core-util': 1.14.0 + '@azure/logger': 1.4.0 + events: 3.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@azure/core-client' + - supports-color + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -4262,6 +4831,16 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@bufbuild/protobuf@2.13.0': {} + + '@bufbuild/protoplugin@2.13.0': + dependencies: + '@bufbuild/protobuf': 2.13.0 + '@typescript/vfs': 1.6.4(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + '@clack/core@0.4.1': dependencies: picocolors: 1.1.1 @@ -4905,6 +5484,8 @@ snapshots: '@noble/hashes@1.8.0': {} + '@nodable/entities@3.0.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4917,6 +5498,79 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@octokit/auth-token@4.0.0': {} + + '@octokit/core@5.2.2': + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.1.1 + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + + '@octokit/endpoint@9.0.6': + dependencies: + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/graphql@7.1.1': + dependencies: + '@octokit/request': 8.4.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/openapi-types@12.11.0': {} + + '@octokit/openapi-types@20.0.0': {} + + '@octokit/openapi-types@24.2.0': {} + + '@octokit/plugin-paginate-rest@9.2.2(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + + '@octokit/plugin-request-log@1.0.4(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + + '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + + '@octokit/plugin-retry@3.0.9': + dependencies: + '@octokit/types': 6.41.0 + bottleneck: 2.19.5 + + '@octokit/request-error@5.1.1': + dependencies: + '@octokit/types': 13.10.0 + deprecation: 2.3.1 + once: 1.4.0 + + '@octokit/request@8.4.1': + dependencies: + '@octokit/endpoint': 9.0.6 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/types@12.6.0': + dependencies: + '@octokit/openapi-types': 20.0.0 + + '@octokit/types@13.10.0': + dependencies: + '@octokit/openapi-types': 24.2.0 + + '@octokit/types@6.41.0': + dependencies: + '@octokit/openapi-types': 12.11.0 + '@opentelemetry/api-logs@0.202.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -4993,8 +5647,30 @@ snapshots: '@opentelemetry/semantic-conventions@1.34.0': {} + '@pkgjs/parseargs@0.11.0': + optional: true + '@pkgr/core@0.2.9': {} + '@protobuf-ts/plugin@2.11.1': + dependencies: + '@bufbuild/protobuf': 2.13.0 + '@bufbuild/protoplugin': 2.13.0 + '@protobuf-ts/protoc': 2.11.1 + '@protobuf-ts/runtime': 2.11.1 + '@protobuf-ts/runtime-rpc': 2.11.1 + typescript: 3.9.10 + transitivePeerDependencies: + - supports-color + + '@protobuf-ts/protoc@2.11.1': {} + + '@protobuf-ts/runtime-rpc@2.11.1': + dependencies: + '@protobuf-ts/runtime': 2.11.1 + + '@protobuf-ts/runtime@2.11.1': {} + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -5629,6 +6305,21 @@ snapshots: '@typescript-eslint/types': 8.48.0 eslint-visitor-keys: 4.2.1 + '@typescript/vfs@1.6.4(typescript@5.4.5)': + dependencies: + debug: 4.4.3 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + + '@typespec/ts-http-runtime@0.3.8': + dependencies: + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true @@ -5789,6 +6480,32 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + anynum@1.0.1: {} + + archiver-utils@5.0.2: + dependencies: + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.7.0 + readdir-glob: 1.1.3 + tar-stream: 3.2.0 + zip-stream: 6.0.1 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + are-docs-informative@0.0.2: {} argparse@2.0.1: {} @@ -5822,16 +6539,53 @@ snapshots: async-function@1.0.0: {} + async@3.2.6: {} + asynckit@0.4.0: {} available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 + b4a@1.8.1: {} + balanced-match@1.0.2: {} + bare-events@2.9.1: {} + + bare-fs@4.8.0: + dependencies: + bare-events: 2.9.1 + bare-path: 3.1.1 + bare-stream: 2.13.3(bare-events@2.9.1) + bare-url: 2.5.1 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-path@3.1.1: {} + + bare-stream@2.13.3(bare-events@2.9.1): + dependencies: + b4a: 1.8.1 + streamx: 2.28.0 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.9.1 + transitivePeerDependencies: + - react-native-b4a + + bare-url@2.5.1: + dependencies: + bare-path: 3.1.1 + + base64-js@1.5.1: {} + baseline-browser-mapping@2.8.31: {} + before-after-hook@2.2.3: {} + better-ajv-errors@1.2.0(ajv@8.17.1): dependencies: '@babel/code-frame': 7.27.1 @@ -5843,10 +6597,17 @@ snapshots: binary-extensions@2.3.0: {} + binary@0.3.0: + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + birecord@0.1.1: {} boolbase@1.0.0: {} + bottleneck@2.19.5: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -5868,6 +6629,15 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.28.0) + buffer-crc32@1.0.0: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffers@0.1.1: {} + builtin-modules@3.3.0: {} builtins@1.0.3: {} @@ -5910,6 +6680,10 @@ snapshots: ccount@2.0.1: {} + chainsaw@0.1.0: + dependencies: + traverse: 0.3.9 + chalk-template@1.1.2: dependencies: chalk: 5.6.2 @@ -5998,6 +6772,14 @@ snapshots: compare-versions@6.1.1: {} + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + concat-map@0.0.1: {} confbox@0.1.8: {} @@ -6016,6 +6798,13 @@ snapshots: core-util-is@1.0.3: {} + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.7.0 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -6169,6 +6958,8 @@ snapshots: dependency-graph@0.11.0: {} + deprecation@2.3.1: {} + dequal@2.0.3: {} devlop@1.1.0: @@ -6765,12 +7556,22 @@ snapshots: eventemitter3@5.0.1: {} + events-universal@1.0.1: + dependencies: + bare-events: 2.9.1 + transitivePeerDependencies: + - bare-abort-controller + + events@3.3.0: {} + exsolve@1.0.8: {} fast-deep-equal@3.1.3: {} fast-equals@5.3.3: {} + fast-fifo@1.3.2: {} + fast-glob@3.2.12: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -6789,10 +7590,24 @@ snapshots: fast-uri@3.1.0: {} + fast-xml-builder@1.3.0: + dependencies: + path-expression-matcher: 1.6.2 + xml-naming: 0.3.0 + fast-xml-parser@4.5.3: dependencies: strnum: 1.1.2 + fast-xml-parser@5.10.1: + dependencies: + '@nodable/entities': 3.0.0 + fast-xml-builder: 1.3.0 + is-unsafe: 2.0.0 + path-expression-matcher: 1.6.2 + strnum: 2.4.1 + xml-naming: 0.3.0 + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -6930,6 +7745,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + glob@11.1.0: dependencies: foreground-child: 3.3.1 @@ -7008,6 +7832,13 @@ snapshots: hpagent@1.2.0: {} + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + http2-client@1.3.5: {} https-proxy-agent@7.0.6: @@ -7017,6 +7848,8 @@ snapshots: transitivePeerDependencies: - supports-color + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.5: {} @@ -7157,6 +7990,8 @@ snapshots: dependencies: call-bound: 1.0.4 + is-stream@2.0.1: {} + is-string@1.1.1: dependencies: call-bound: 1.0.4 @@ -7172,6 +8007,8 @@ snapshots: dependencies: which-typed-array: 1.1.19 + is-unsafe@2.0.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -7183,10 +8020,18 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jackspeak@4.1.1: dependencies: '@isaacs/cliui': 8.0.2 @@ -7256,10 +8101,16 @@ snapshots: jsonpointer@5.0.1: {} + jwt-decode@3.1.2: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + leven@3.1.0: {} levn@0.4.1: @@ -7306,6 +8157,8 @@ snapshots: dependencies: js-tokens: 4.0.0 + lru-cache@10.4.3: {} + lru-cache@11.2.2: {} lunr@2.3.9: {} @@ -7674,6 +8527,10 @@ snapshots: minipass@7.1.2: {} + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -7881,12 +8738,19 @@ snapshots: path-exists@4.0.0: {} + path-expression-matcher@1.6.2: {} + path-is-absolute@1.0.1: {} path-key@3.1.1: {} path-parse@1.0.7: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + path-scurry@2.0.1: dependencies: lru-cache: 11.2.2 @@ -7961,6 +8825,10 @@ snapshots: prismjs@1.30.0: {} + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -8020,12 +8888,34 @@ snapshots: parse-json: 5.2.0 type-fest: 0.6.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -8166,6 +9056,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-push-apply@1.0.0: @@ -8344,6 +9236,15 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + streamx@2.28.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + string-ts@2.2.1: {} string-width@4.2.3: @@ -8381,6 +9282,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -8401,6 +9306,10 @@ snapshots: strnum@1.1.2: {} + strnum@2.4.1: + dependencies: + anynum: 1.0.1 + styled-components@6.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@emotion/is-prop-valid': 1.2.2 @@ -8455,6 +9364,30 @@ snapshots: tapable@2.3.0: {} + tar-stream@3.2.0: + dependencies: + b4a: 1.8.1 + bare-fs: 4.8.0 + fast-fifo: 1.3.2 + streamx: 2.28.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + teex@1.0.1: + dependencies: + streamx: 2.28.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + text-decoder@1.2.7: + dependencies: + b4a: 1.8.1 + transitivePeerDependencies: + - react-native-b4a + text-table@0.2.0: {} thenify-all@1.6.0: @@ -8484,6 +9417,8 @@ snapshots: tr46@0.0.3: {} + traverse@0.3.9: {} + tree-kill@1.2.2: {} ts-algebra@1.2.2: {} @@ -8587,6 +9522,10 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typescript@3.9.10: {} + + typescript@5.4.5: {} + typescript@5.9.3: {} ufo@1.6.1: {} @@ -8609,6 +9548,8 @@ snapshots: undici@6.22.0: {} + undici@6.28.0: {} + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -8628,6 +9569,8 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 + universal-user-agent@6.0.1: {} + universalify@2.0.1: {} unrs-resolver@1.11.1: @@ -8654,6 +9597,11 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + unzip-stream@0.3.4: + dependencies: + binary: 0.3.0 + mkdirp: 0.5.6 + update-browserslist-db@1.1.4(browserslist@4.28.0): dependencies: browserslist: 4.28.0 @@ -8780,6 +9728,8 @@ snapshots: xml-name-validator@4.0.0: {} + xml-naming@0.3.0: {} + y18n@5.0.8: {} yaml-ast-parser@0.0.43: {} @@ -8819,6 +9769,12 @@ snapshots: yocto-queue@0.1.0: {} + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.7.0 + zod@4.1.13: {} zwitch@2.0.4: {} From c6813f43f3db59324de1474fe5365258a4f3823b Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 04:01:41 -0400 Subject: [PATCH 02/17] ci: call each SDK's renamed ci workflow --- .github/workflows/ci.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2f7085dd..a5793a16 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -106,37 +106,37 @@ jobs: # matrix leg. build_javascript: needs: bundle - uses: vrchatapi/vrchatapi-javascript/.github/workflows/build.yaml@ci/modernise-actions + uses: vrchatapi/vrchatapi-javascript/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions build_rust: needs: bundle - uses: vrchatapi/vrchatapi-rust/.github/workflows/build.yaml@ci/modernise-actions + uses: vrchatapi/vrchatapi-rust/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions build_java: needs: bundle - uses: vrchatapi/vrchatapi-java/.github/workflows/build.yaml@ci/modernise-actions + uses: vrchatapi/vrchatapi-java/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions build_python: needs: bundle - uses: vrchatapi/vrchatapi-python/.github/workflows/build.yaml@ci/modernise-actions + uses: vrchatapi/vrchatapi-python/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions build_csharp: needs: bundle - uses: vrchatapi/vrchatapi-csharp/.github/workflows/build.yaml@ci/modernise-actions + uses: vrchatapi/vrchatapi-csharp/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions build_dart: needs: bundle - uses: vrchatapi/vrchatapi-dart/.github/workflows/build.yaml@ci/modernise-actions + uses: vrchatapi/vrchatapi-dart/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions From 795bfb59bb9bfdc814b0ec51f3fcf382f9da795f Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 04:10:17 -0400 Subject: [PATCH 03/17] ci: update github-script and download-artifact to current majors --- .github/workflows/ci.yaml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a5793a16..1b0c6361 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -51,7 +51,6 @@ jobs: continue-on-error: true run: pnpm run lint-ci - # Will fail if no paths are defined - name: assert no unused paths if: env.changes != '' run: | @@ -84,7 +83,7 @@ jobs: - run: bun --bun run bundle - - uses: actions/github-script@v8 + - uses: actions/github-script@v9 with: script: | const { readdir } = require("node:fs/promises"); @@ -100,10 +99,6 @@ jobs: return artifact.uploadArtifact(file, [pathname], dirname(pathname)); })); - # Each SDK builds against this run's bundle, so a spec change that breaks a - # generated client fails here rather than after release. - # `uses` takes no expressions, so each SDK needs its own job rather than a - # matrix leg. build_javascript: needs: bundle uses: vrchatapi/vrchatapi-javascript/.github/workflows/ci.yaml@ci/modernise-actions @@ -159,7 +154,7 @@ jobs: runtime: bun@latest cache: true - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v8 with: path: dist merge-multiple: true From c210a4912221f6955af1c5f2904ace5b9853137f Mon Sep 17 00:00:00 2001 From: Aries Date: Sun, 9 Aug 2026 04:58:31 -0400 Subject: [PATCH 04/17] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a8624e68..057dcb84 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "version": "1.0.0", "private": true, "packageManager": "pnpm@11.20.0", + "engines": { "node": ">=22" }, "description": "VRChat API OpenAPI Specification", "author": "", "license": "MIT", From 0c8efb5e3b8f8cf45d467fdf247fe72d6932986e Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 05:25:17 -0400 Subject: [PATCH 05/17] ci: trigger a pull request run to check preview reporting From fb46d00c1c7d19d493385bc7b41acf4f5a5aedef Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 05:31:36 -0400 Subject: [PATCH 06/17] fix: order engines after main in package.json --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 057dcb84..4bf5a7bc 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,13 @@ "version": "1.0.0", "private": true, "packageManager": "pnpm@11.20.0", - "engines": { "node": ">=22" }, "description": "VRChat API OpenAPI Specification", "author": "", "license": "MIT", "main": "index.js", + "engines": { + "node": ">=22" + }, "scripts": { "lint-spectral": "bun spectral openapi/openapi.yaml", "lint-spectral-ci": "bun spectral -i openapi/openapi.yaml", From a5c228f7ee9074260fabb8bf37ab7797df46cbf0 Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 05:35:25 -0400 Subject: [PATCH 07/17] ci: comment how to install the SDKs this run built --- .github/workflows/ci.yaml | 69 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1b0c6361..6a7b8b97 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -135,6 +135,75 @@ jobs: with: ref: ci/modernise-actions + report: + if: always() && github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + pull-requests: write + needs: + - build_javascript + - build_rust + - build_java + - build_python + - build_csharp + - build_dart + steps: + - uses: actions/github-script@v9 + with: + script: | + const marker = ''; + + const sdks = [ + { name: 'JavaScript', install: `${{ needs.build_javascript.outputs.install }}`, artifact: '' }, + { name: 'Rust', install: '', artifact: `${{ needs.build_rust.outputs.artifact }}` }, + { name: 'Java', install: '', artifact: `${{ needs.build_java.outputs.artifact }}` }, + { name: 'Python', install: '', artifact: `${{ needs.build_python.outputs.artifact }}` }, + { name: 'C#', install: '', artifact: `${{ needs.build_csharp.outputs.artifact }}` }, + { name: 'Dart', install: '', artifact: `${{ needs.build_dart.outputs.artifact }}` }, + ]; + + const rows = sdks.map(({ name, install, artifact }) => { + const how = install + ? `\`${install}\`` + : artifact + ? `[download](${artifact})` + : 'unavailable'; + + return `| ${name} | ${how} |`; + }); + + const body = [ + marker, + `### SDKs built from this specification`, + ``, + `| SDK | Install |`, + `| --- | ------- |`, + ...rows, + ``, + `${context.payload.pull_request.head.sha.slice(0, 7)}`, + ].join('\n'); + + const { data: comments } = await github.rest.issues.listComments({ + ...context.repo, + issue_number: context.issue.number, + }); + + const existing = comments.find(({ body }) => body.includes(marker)); + + if (existing) { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, + body, + }); + } + release: runs-on: ubuntu-latest needs: From 8ffbd9cbf55fc233550264610327c465552ff680 Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 05:43:02 -0400 Subject: [PATCH 08/17] ci: report SDK progress in one comment while the run is still going --- .github/actions/report/action.yml | 172 ++++++++++++++++++++++++++++++ .github/workflows/ci.yaml | 69 ++---------- 2 files changed, 178 insertions(+), 63 deletions(-) create mode 100644 .github/actions/report/action.yml diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml new file mode 100644 index 00000000..dec0df9b --- /dev/null +++ b/.github/actions/report/action.yml @@ -0,0 +1,172 @@ +name: Report the SDKs a run builds +description: >- + Keeps one pull request comment up to date with what each SDK job is doing and, + once a job finishes, how to install what it produced. Polls until every + `build_` job in the run has finished, so the comment is live rather + than written once at the end. + +inputs: + token: + description: >- + Token used to read the run's jobs and write the comment. + required: false + default: ${{ github.token }} + interval: + description: >- + Seconds between refreshes. + required: false + default: '15' + timeout: + description: >- + Seconds to keep refreshing before giving up. + required: false + default: '2700' + +runs: + using: composite + steps: + - uses: actions/github-script@v9 + with: + github-token: ${{ inputs.token }} + script: | + const marker = ''; + const interval = Number(${{ inputs.interval }}) * 1000; + const deadline = Date.now() + Number(${{ inputs.timeout }}) * 1000; + + const labels = { + javascript: 'JavaScript', + rust: 'Rust', + java: 'Java', + python: 'Python', + csharp: 'C#', + dart: 'Dart', + }; + + const stages = { + generate: 'generating', + build: 'building', + test: 'testing', + install: 'installing', + analyze: 'analysing', + pana: 'analysing', + format: 'checking formatting', + }; + + const artifacts = { + javascript: 'generated-javascript', + rust: 'generated-rust', + java: 'generated-java', + python: 'dist-python', + csharp: 'generated-csharp', + dart: 'generated-dart', + }; + + const pull = context.payload.pull_request?.number; + + async function jobsBySdk() { + const jobs = await github.paginate( + github.rest.actions.listJobsForWorkflowRun, + { ...context.repo, run_id: context.runId, per_page: 100 }, + ); + + const bySdk = {}; + + for (const job of jobs) { + const match = /^build_(\w+) \/ (.+)$/.exec(job.name); + if (!match) continue; + + const [, sdk, step] = match; + (bySdk[sdk] ??= []).push({ ...job, step: step.split(' (')[0] }); + } + + return bySdk; + } + + async function downloads() { + const uploaded = await github.paginate( + github.rest.actions.listWorkflowRunArtifacts, + { ...context.repo, run_id: context.runId, per_page: 100 }, + ); + + return Object.fromEntries(uploaded.map(({ name, id }) => [ + name, + `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/artifacts/${id}`, + ])); + } + + function state(jobs) { + if (!jobs?.length) return { status: 'queued', done: false }; + + const failed = jobs.find(({ conclusion }) => + conclusion === 'failure' || conclusion === 'cancelled'); + if (failed) return { status: `failed while ${stages[failed.step] ?? failed.step}`, done: true }; + + const running = jobs.find(({ status }) => status !== 'completed'); + if (running) return { status: stages[running.step] ?? running.step, done: false }; + + return { status: 'built', done: true }; + } + + function install(sdk, urls) { + if (sdk === 'javascript' && pull) { + return `\`pnpm add https://pkg.pr.new/vrchat@${pull}\``; + } + + const url = urls[artifacts[sdk]]; + return url ? `[download](${url})` : ''; + } + + async function report() { + const bySdk = await jobsBySdk(); + const urls = await downloads(); + + const rows = Object.entries(labels).map(([sdk, label]) => { + const { status, done } = state(bySdk[sdk]); + const how = status === 'built' ? install(sdk, urls) : ''; + + return `| ${label} | ${status} | ${how} |`; + }); + + const body = [ + marker, + '### SDKs built from this specification', + '', + '| SDK | Status | Install |', + '| --- | ------ | ------- |', + ...rows, + ].join('\n'); + + const comments = await github.paginate(github.rest.issues.listComments, { + ...context.repo, + issue_number: pull, + per_page: 100, + }); + + const existing = comments.find((comment) => comment.body.includes(marker)); + + if (existing) { + if (existing.body !== body) { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existing.id, + body, + }); + } + } else { + await github.rest.issues.createComment({ + ...context.repo, + issue_number: pull, + body, + }); + } + + const sdks = Object.keys(labels).map((sdk) => state(bySdk[sdk])); + return sdks.length > 0 && sdks.every(({ done }) => done); + } + + if (!pull) return; + + while (Date.now() < deadline) { + if (await report()) return; + await new Promise((resolve) => setTimeout(resolve, interval)); + } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6a7b8b97..2f4c5b64 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -136,73 +136,16 @@ jobs: ref: ci/modernise-actions report: - if: always() && github.event_name == 'pull_request' + if: github.event_name == 'pull_request' + needs: bundle runs-on: ubuntu-latest permissions: + actions: read pull-requests: write - needs: - - build_javascript - - build_rust - - build_java - - build_python - - build_csharp - - build_dart steps: - - uses: actions/github-script@v9 - with: - script: | - const marker = ''; - - const sdks = [ - { name: 'JavaScript', install: `${{ needs.build_javascript.outputs.install }}`, artifact: '' }, - { name: 'Rust', install: '', artifact: `${{ needs.build_rust.outputs.artifact }}` }, - { name: 'Java', install: '', artifact: `${{ needs.build_java.outputs.artifact }}` }, - { name: 'Python', install: '', artifact: `${{ needs.build_python.outputs.artifact }}` }, - { name: 'C#', install: '', artifact: `${{ needs.build_csharp.outputs.artifact }}` }, - { name: 'Dart', install: '', artifact: `${{ needs.build_dart.outputs.artifact }}` }, - ]; - - const rows = sdks.map(({ name, install, artifact }) => { - const how = install - ? `\`${install}\`` - : artifact - ? `[download](${artifact})` - : 'unavailable'; - - return `| ${name} | ${how} |`; - }); - - const body = [ - marker, - `### SDKs built from this specification`, - ``, - `| SDK | Install |`, - `| --- | ------- |`, - ...rows, - ``, - `${context.payload.pull_request.head.sha.slice(0, 7)}`, - ].join('\n'); - - const { data: comments } = await github.rest.issues.listComments({ - ...context.repo, - issue_number: context.issue.number, - }); - - const existing = comments.find(({ body }) => body.includes(marker)); - - if (existing) { - await github.rest.issues.updateComment({ - ...context.repo, - comment_id: existing.id, - body, - }); - } else { - await github.rest.issues.createComment({ - ...context.repo, - issue_number: context.issue.number, - body, - }); - } + - uses: actions/checkout@v7 + + - uses: ./.github/actions/report release: runs-on: ubuntu-latest From da541113e08cdde12d2d45bb3d3854345d6c58fd Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 05:49:04 -0400 Subject: [PATCH 09/17] ci: let each SDK report its own install command --- .github/actions/report/action.yml | 150 ++++++++++++------------------ .github/workflows/ci.yaml | 29 +++++- 2 files changed, 86 insertions(+), 93 deletions(-) diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml index dec0df9b..2454a4bb 100644 --- a/.github/actions/report/action.yml +++ b/.github/actions/report/action.yml @@ -1,9 +1,8 @@ name: Report the SDKs a run builds description: >- - Keeps one pull request comment up to date with what each SDK job is doing and, - once a job finishes, how to install what it produced. Polls until every - `build_` job in the run has finished, so the comment is live rather - than written once at the end. + Keeps one pull request comment up to date with what each SDK job is doing. + Without `installs` it polls the run and reports progress; with `installs` it + writes the commands the SDKs reported for themselves and returns. inputs: token: @@ -11,57 +10,40 @@ inputs: Token used to read the run's jobs and write the comment. required: false default: ${{ github.token }} + installs: + description: >- + JSON object mapping an SDK to how it says to install what it built. + required: false + default: "" interval: description: >- Seconds between refreshes. required: false - default: '15' + default: "15" timeout: description: >- Seconds to keep refreshing before giving up. required: false - default: '2700' + default: "2700" runs: using: composite steps: - uses: actions/github-script@v9 + env: + INSTALLS: ${{ inputs.installs }} + INTERVAL: ${{ inputs.interval }} + TIMEOUT: ${{ inputs.timeout }} with: github-token: ${{ inputs.token }} script: | const marker = ''; - const interval = Number(${{ inputs.interval }}) * 1000; - const deadline = Date.now() + Number(${{ inputs.timeout }}) * 1000; - - const labels = { - javascript: 'JavaScript', - rust: 'Rust', - java: 'Java', - python: 'Python', - csharp: 'C#', - dart: 'Dart', - }; - - const stages = { - generate: 'generating', - build: 'building', - test: 'testing', - install: 'installing', - analyze: 'analysing', - pana: 'analysing', - format: 'checking formatting', - }; - - const artifacts = { - javascript: 'generated-javascript', - rust: 'generated-rust', - java: 'generated-java', - python: 'dist-python', - csharp: 'generated-csharp', - dart: 'generated-dart', - }; + const installs = process.env.INSTALLS ? JSON.parse(process.env.INSTALLS) : null; + const interval = Number(process.env.INTERVAL) * 1000; + const deadline = Date.now() + Number(process.env.TIMEOUT) * 1000; const pull = context.payload.pull_request?.number; + if (!pull) return; async function jobsBySdk() { const jobs = await github.paginate( @@ -82,60 +64,20 @@ runs: return bySdk; } - async function downloads() { - const uploaded = await github.paginate( - github.rest.actions.listWorkflowRunArtifacts, - { ...context.repo, run_id: context.runId, per_page: 100 }, - ); - - return Object.fromEntries(uploaded.map(({ name, id }) => [ - name, - `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/artifacts/${id}`, - ])); - } - function state(jobs) { if (!jobs?.length) return { status: 'queued', done: false }; const failed = jobs.find(({ conclusion }) => conclusion === 'failure' || conclusion === 'cancelled'); - if (failed) return { status: `failed while ${stages[failed.step] ?? failed.step}`, done: true }; + if (failed) return { status: `failed to ${failed.step}`, done: true }; const running = jobs.find(({ status }) => status !== 'completed'); - if (running) return { status: stages[running.step] ?? running.step, done: false }; + if (running) return { status: running.step, done: false }; return { status: 'built', done: true }; } - function install(sdk, urls) { - if (sdk === 'javascript' && pull) { - return `\`pnpm add https://pkg.pr.new/vrchat@${pull}\``; - } - - const url = urls[artifacts[sdk]]; - return url ? `[download](${url})` : ''; - } - - async function report() { - const bySdk = await jobsBySdk(); - const urls = await downloads(); - - const rows = Object.entries(labels).map(([sdk, label]) => { - const { status, done } = state(bySdk[sdk]); - const how = status === 'built' ? install(sdk, urls) : ''; - - return `| ${label} | ${status} | ${how} |`; - }); - - const body = [ - marker, - '### SDKs built from this specification', - '', - '| SDK | Status | Install |', - '| --- | ------ | ------- |', - ...rows, - ].join('\n'); - + async function upsert(body) { const comments = await github.paginate(github.rest.issues.listComments, { ...context.repo, issue_number: pull, @@ -144,29 +86,53 @@ runs: const existing = comments.find((comment) => comment.body.includes(marker)); - if (existing) { - if (existing.body !== body) { - await github.rest.issues.updateComment({ - ...context.repo, - comment_id: existing.id, - body, - }); - } - } else { + if (!existing) { await github.rest.issues.createComment({ ...context.repo, issue_number: pull, body, }); + return; } - const sdks = Object.keys(labels).map((sdk) => state(bySdk[sdk])); - return sdks.length > 0 && sdks.every(({ done }) => done); + if (existing.body !== body) { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existing.id, + body, + }); + } } - if (!pull) return; + function render(bySdk) { + const rows = Object.keys(bySdk).sort().map((sdk) => { + const { status } = state(bySdk[sdk]); + const how = status === 'built' ? (installs?.[sdk] ?? '') : ''; + + return `| ${sdk} | ${status} | ${how} |`; + }); + + return [ + marker, + '### SDKs built from this specification', + '', + '| SDK | Status | Install |', + '| --- | ------ | ------- |', + ...rows, + ].join('\n'); + } + + if (installs) { + await upsert(render(await jobsBySdk())); + return; + } while (Date.now() < deadline) { - if (await report()) return; + const bySdk = await jobsBySdk(); + await upsert(render(bySdk)); + + const sdks = Object.values(bySdk).map(state); + if (sdks.length > 0 && sdks.every(({ done }) => done)) return; + await new Promise((resolve) => setTimeout(resolve, interval)); } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2f4c5b64..50210209 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -137,7 +137,6 @@ jobs: report: if: github.event_name == 'pull_request' - needs: bundle runs-on: ubuntu-latest permissions: actions: read @@ -147,6 +146,34 @@ jobs: - uses: ./.github/actions/report + report_install: + if: always() && github.event_name == 'pull_request' + needs: + - build_javascript + - build_rust + - build_java + - build_python + - build_csharp + - build_dart + runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write + steps: + - uses: actions/checkout@v7 + + - uses: ./.github/actions/report + with: + installs: | + { + "javascript": ${{ toJSON(needs.build_javascript.outputs.install) }}, + "rust": ${{ toJSON(needs.build_rust.outputs.install) }}, + "java": ${{ toJSON(needs.build_java.outputs.install) }}, + "python": ${{ toJSON(needs.build_python.outputs.install) }}, + "csharp": ${{ toJSON(needs.build_csharp.outputs.install) }}, + "dart": ${{ toJSON(needs.build_dart.outputs.install) }} + } + release: runs-on: ubuntu-latest needs: From a37ae966186081f3b7f8a81ee1b4bf1dc854d7b6 Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 05:55:05 -0400 Subject: [PATCH 10/17] ci: group the report by what each SDK is doing --- .github/actions/report/action.yml | 106 ++++++++++++++++++++++-------- .github/workflows/ci.yaml | 37 ++++++++++- 2 files changed, 113 insertions(+), 30 deletions(-) diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml index 2454a4bb..815bba64 100644 --- a/.github/actions/report/action.yml +++ b/.github/actions/report/action.yml @@ -1,8 +1,9 @@ name: Report the SDKs a run builds description: >- - Keeps one pull request comment up to date with what each SDK job is doing. - Without `installs` it polls the run and reports progress; with `installs` it - writes the commands the SDKs reported for themselves and returns. + Keeps one pull request comment up to date with the bundles a run produced and + what each SDK job is doing. Without `installs` it polls the run and reports + progress; with `installs` it writes the commands the SDKs reported for + themselves and returns. inputs: token: @@ -10,6 +11,16 @@ inputs: Token used to read the run's jobs and write the comment. required: false default: ${{ github.token }} + sdks: + description: >- + JSON object naming each SDK a `build_` job builds, and the repository + it comes from. + required: true + bundles: + description: >- + JSON array of the bundles this run produced, as `name` and `url`. + required: false + default: "[]" installs: description: >- JSON object mapping an SDK to how it says to install what it built. @@ -31,6 +42,8 @@ runs: steps: - uses: actions/github-script@v9 env: + SDKS: ${{ inputs.sdks }} + BUNDLES: ${{ inputs.bundles }} INSTALLS: ${{ inputs.installs }} INTERVAL: ${{ inputs.interval }} TIMEOUT: ${{ inputs.timeout }} @@ -38,13 +51,30 @@ runs: github-token: ${{ inputs.token }} script: | const marker = ''; + + const sdks = JSON.parse(process.env.SDKS); + const bundles = JSON.parse(process.env.BUNDLES); const installs = process.env.INSTALLS ? JSON.parse(process.env.INSTALLS) : null; + const interval = Number(process.env.INTERVAL) * 1000; const deadline = Date.now() + Number(process.env.TIMEOUT) * 1000; const pull = context.payload.pull_request?.number; if (!pull) return; + const headings = { + queued: 'Queued', + generate: 'Generating', + build: 'Building', + test: 'Testing', + install: 'Installing', + analyze: 'Analysing', + pana: 'Analysing', + format: 'Checking formatting', + built: 'Built', + failed: 'Failed', + }; + async function jobsBySdk() { const jobs = await github.paginate( github.rest.actions.listJobsForWorkflowRun, @@ -65,16 +95,54 @@ runs: } function state(jobs) { - if (!jobs?.length) return { status: 'queued', done: false }; + if (!jobs?.length) return { stage: 'queued', done: false }; - const failed = jobs.find(({ conclusion }) => + const failed = jobs.some(({ conclusion }) => conclusion === 'failure' || conclusion === 'cancelled'); - if (failed) return { status: `failed to ${failed.step}`, done: true }; + if (failed) return { stage: 'failed', done: true }; const running = jobs.find(({ status }) => status !== 'completed'); - if (running) return { status: running.step, done: false }; + if (running) return { stage: running.step, done: false }; + + return { stage: 'built', done: true }; + } + + function render(bySdk) { + const lines = [marker]; + + if (bundles.length > 0) { + lines.push('### Bundles', ''); + lines.push(...bundles.map(({ name, url }) => `* [${name}](${url})`)); + lines.push(''); + } + + lines.push('### SDKs', ''); + + const grouped = {}; - return { status: 'built', done: true }; + for (const [key, { name, repository }] of Object.entries(sdks)) { + const { stage } = state(bySdk[key]); + const heading = headings[stage] ?? stage; + + (grouped[heading] ??= []).push({ key, name, repository }); + } + + for (const [heading, members] of Object.entries(grouped)) { + lines.push(`#### ${heading}`, ''); + + for (const { key, name, repository } of members) { + lines.push(`* [**${name}**](https://github.com/${repository})`); + + const how = installs?.[key]; + if (how) { + lines.push(how.startsWith('[') ? ` → ${how}` : ` → \`${how}\``); + } + } + + lines.push(''); + } + + return lines.join('\n').trimEnd(); } async function upsert(body) { @@ -104,24 +172,6 @@ runs: } } - function render(bySdk) { - const rows = Object.keys(bySdk).sort().map((sdk) => { - const { status } = state(bySdk[sdk]); - const how = status === 'built' ? (installs?.[sdk] ?? '') : ''; - - return `| ${sdk} | ${status} | ${how} |`; - }); - - return [ - marker, - '### SDKs built from this specification', - '', - '| SDK | Status | Install |', - '| --- | ------ | ------- |', - ...rows, - ].join('\n'); - } - if (installs) { await upsert(render(await jobsBySdk())); return; @@ -131,8 +181,8 @@ runs: const bySdk = await jobsBySdk(); await upsert(render(bySdk)); - const sdks = Object.values(bySdk).map(state); - if (sdks.length > 0 && sdks.every(({ done }) => done)) return; + const states = Object.keys(sdks).map((key) => state(bySdk[key])); + if (states.every(({ done }) => done)) return; await new Promise((resolve) => setTimeout(resolve, interval)); } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 50210209..b01f310a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -73,6 +73,8 @@ jobs: bundle: runs-on: ubuntu-latest + outputs: + artifacts: ${{ steps.upload.outputs.artifacts }} steps: - uses: actions/checkout@v7 @@ -83,7 +85,8 @@ jobs: - run: bun --bun run bundle - - uses: actions/github-script@v9 + - id: upload + uses: actions/github-script@v9 with: script: | const { readdir } = require("node:fs/promises"); @@ -96,9 +99,16 @@ jobs: const artifacts = await Promise.all(files.map(async (file) => { const pathname = resolve(`./dist/${file}`); - return artifact.uploadArtifact(file, [pathname], dirname(pathname)); + const { id } = await artifact.uploadArtifact(file, [pathname], dirname(pathname)); + + return { + name: file, + url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/artifacts/${id}`, + }; })); + core.setOutput("artifacts", JSON.stringify(artifacts)); + build_javascript: needs: bundle uses: vrchatapi/vrchatapi-javascript/.github/workflows/ci.yaml@ci/modernise-actions @@ -137,6 +147,7 @@ jobs: report: if: github.event_name == 'pull_request' + needs: bundle runs-on: ubuntu-latest permissions: actions: read @@ -145,10 +156,22 @@ jobs: - uses: actions/checkout@v7 - uses: ./.github/actions/report + with: + bundles: ${{ needs.bundle.outputs.artifacts }} + sdks: | + { + "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, + "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, + "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, + "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, + "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, + "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } + } report_install: if: always() && github.event_name == 'pull_request' needs: + - bundle - build_javascript - build_rust - build_java @@ -164,6 +187,16 @@ jobs: - uses: ./.github/actions/report with: + bundles: ${{ needs.bundle.outputs.artifacts }} + sdks: | + { + "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, + "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, + "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, + "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, + "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, + "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } + } installs: | { "javascript": ${{ toJSON(needs.build_javascript.outputs.install) }}, From 8e7e9214d68d6709d9b70fdee6e133f1b2f18180 Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 05:58:15 -0400 Subject: [PATCH 11/17] ci: report from the start of the run and name the commit --- .github/actions/report/action.yml | 7 ++++++- .github/workflows/ci.yaml | 2 -- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml index 815bba64..45a9cb14 100644 --- a/.github/actions/report/action.yml +++ b/.github/actions/report/action.yml @@ -30,7 +30,7 @@ inputs: description: >- Seconds between refreshes. required: false - default: "15" + default: "5" timeout: description: >- Seconds to keep refreshing before giving up. @@ -142,6 +142,11 @@ runs: lines.push(''); } + const sha = context.payload.pull_request.head.sha; + const commit = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`; + + lines.push(`built from [\`${sha.slice(0, 7)}\`](${commit})`); + return lines.join('\n').trimEnd(); } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b01f310a..f48bf945 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -147,7 +147,6 @@ jobs: report: if: github.event_name == 'pull_request' - needs: bundle runs-on: ubuntu-latest permissions: actions: read @@ -157,7 +156,6 @@ jobs: - uses: ./.github/actions/report with: - bundles: ${{ needs.bundle.outputs.artifacts }} sdks: | { "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, From ae8f91f675f6b5738a409cc0d3cde50b8441556b Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 06:01:55 -0400 Subject: [PATCH 12/17] fix(ci): leave the finished report to the job that knows the commands --- .github/actions/report/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml index 45a9cb14..e0fd5de1 100644 --- a/.github/actions/report/action.yml +++ b/.github/actions/report/action.yml @@ -184,10 +184,10 @@ runs: while (Date.now() < deadline) { const bySdk = await jobsBySdk(); - await upsert(render(bySdk)); - const states = Object.keys(sdks).map((key) => state(bySdk[key])); + if (states.every(({ done }) => done)) return; + await upsert(render(bySdk)); await new Promise((resolve) => setTimeout(resolve, interval)); } From 7fdbf568c020f18e909c4bae35518fa8d8407f8d Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 06:09:34 -0400 Subject: [PATCH 13/17] ci: report each SDK as it finishes and group bundles by format --- .github/actions/report/action.yml | 103 +++++++++++++-------- .github/workflows/ci.yaml | 149 ++++++++++++++++++++++++++++-- 2 files changed, 205 insertions(+), 47 deletions(-) diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml index e0fd5de1..5b022421 100644 --- a/.github/actions/report/action.yml +++ b/.github/actions/report/action.yml @@ -2,8 +2,9 @@ name: Report the SDKs a run builds description: >- Keeps one pull request comment up to date with the bundles a run produced and what each SDK job is doing. Without `installs` it polls the run and reports - progress; with `installs` it writes the commands the SDKs reported for - themselves and returns. + progress; with `installs` it records how to install what an SDK built and + returns. Commands already in the comment are kept, so each SDK can report as + soon as it finishes. inputs: token: @@ -51,10 +52,12 @@ runs: github-token: ${{ inputs.token }} script: | const marker = ''; + const opening = ''; const sdks = JSON.parse(process.env.SDKS); const bundles = JSON.parse(process.env.BUNDLES); - const installs = process.env.INSTALLS ? JSON.parse(process.env.INSTALLS) : null; + const reported = process.env.INSTALLS ? JSON.parse(process.env.INSTALLS) : null; const interval = Number(process.env.INTERVAL) * 1000; const deadline = Date.now() + Number(process.env.TIMEOUT) * 1000; @@ -62,17 +65,17 @@ runs: const pull = context.payload.pull_request?.number; if (!pull) return; - const headings = { - queued: 'Queued', - generate: 'Generating', - build: 'Building', - test: 'Testing', - install: 'Installing', - analyze: 'Analysing', - pana: 'Analysing', - format: 'Checking formatting', - built: 'Built', - failed: 'Failed', + const stages = { + queued: 'queued', + generate: 'generating', + build: 'building', + test: 'testing', + install: 'installing', + analyze: 'analysing', + pana: 'analysing', + format: 'checking formatting', + built: 'built', + failed: 'failed', }; async function jobsBySdk() { @@ -107,50 +110,66 @@ runs: return { stage: 'built', done: true }; } - function render(bySdk) { - const lines = [marker]; + function recall(body) { + const start = body?.indexOf(opening) ?? -1; + if (start === -1) return {}; - if (bundles.length > 0) { - lines.push('### Bundles', ''); - lines.push(...bundles.map(({ name, url }) => `* [${name}](${url})`)); - lines.push(''); + const end = body.indexOf(closing, start); + if (end === -1) return {}; + + try { + return JSON.parse(body.slice(start + opening.length, end)); + } catch { + return {}; } + } - lines.push('### SDKs', ''); + function render(bySdk, installs) { + const lines = [marker, `${opening}${JSON.stringify(installs)}${closing}`]; - const grouped = {}; + if (bundles.length > 0) { + const byStem = {}; - for (const [key, { name, repository }] of Object.entries(sdks)) { - const { stage } = state(bySdk[key]); - const heading = headings[stage] ?? stage; + for (const { name, url } of bundles) { + const cut = name.lastIndexOf('.'); + const stem = cut === -1 ? name : name.slice(0, cut); + const format = cut === -1 ? name : name.slice(cut + 1); - (grouped[heading] ??= []).push({ key, name, repository }); - } + (byStem[stem] ??= []).push({ format, url }); + } - for (const [heading, members] of Object.entries(grouped)) { - lines.push(`#### ${heading}`, ''); + lines.push('### Bundles', ''); - for (const { key, name, repository } of members) { - lines.push(`* [**${name}**](https://github.com/${repository})`); + for (const stem of Object.keys(byStem).sort((a, b) => b.localeCompare(a))) { + const formats = byStem[stem] + .sort((a, b) => a.format.localeCompare(b.format)) + .map(({ format, url }) => `[${format}](${url})`); - const how = installs?.[key]; - if (how) { - lines.push(how.startsWith('[') ? ` → ${how}` : ` → \`${how}\``); - } + lines.push(`* ${stem} (${formats.join(', ')})`); } lines.push(''); } + lines.push('### SDKs', ''); + + for (const [key, { name, repository }] of Object.entries(sdks)) { + const { stage } = state(bySdk[key]); + const how = installs[key]; + const suffix = how ? ` ${how.startsWith('[') ? how : `\`${how}\``}` : ''; + + lines.push(`* [**${name}**](https://github.com/${repository}) → ${stages[stage] ?? stage}${suffix}`); + } + const sha = context.payload.pull_request.head.sha; const commit = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`; - lines.push(`built from [\`${sha.slice(0, 7)}\`](${commit})`); + lines.push('', `built from [\`${sha.slice(0, 7)}\`](${commit})`); - return lines.join('\n').trimEnd(); + return lines.join('\n'); } - async function upsert(body) { + async function upsert(bySdk) { const comments = await github.paginate(github.rest.issues.listComments, { ...context.repo, issue_number: pull, @@ -158,6 +177,8 @@ runs: }); const existing = comments.find((comment) => comment.body.includes(marker)); + const installs = { ...recall(existing?.body), ...reported }; + const body = render(bySdk, installs); if (!existing) { await github.rest.issues.createComment({ @@ -177,8 +198,8 @@ runs: } } - if (installs) { - await upsert(render(await jobsBySdk())); + if (reported) { + await upsert(await jobsBySdk()); return; } @@ -186,8 +207,8 @@ runs: const bySdk = await jobsBySdk(); const states = Object.keys(sdks).map((key) => state(bySdk[key])); + await upsert(bySdk); if (states.every(({ done }) => done)) return; - await upsert(render(bySdk)); await new Promise((resolve) => setTimeout(resolve, interval)); } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f48bf945..d38ddf99 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -147,6 +147,7 @@ jobs: report: if: github.event_name == 'pull_request' + needs: bundle runs-on: ubuntu-latest permissions: actions: read @@ -156,6 +157,7 @@ jobs: - uses: ./.github/actions/report with: + bundles: ${{ needs.bundle.outputs.artifacts }} sdks: | { "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, @@ -166,15 +168,155 @@ jobs: "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } } - report_install: + report_javascript: if: always() && github.event_name == 'pull_request' needs: - bundle - build_javascript + runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write + steps: + - uses: actions/checkout@v7 + + - uses: ./.github/actions/report + with: + bundles: ${{ needs.bundle.outputs.artifacts }} + sdks: | + { + "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, + "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, + "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, + "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, + "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, + "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } + } + installs: | + { + "javascript": ${{ toJSON(needs.build_javascript.outputs.install) }} + } + + report_rust: + if: always() && github.event_name == 'pull_request' + needs: + - bundle - build_rust + runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write + steps: + - uses: actions/checkout@v7 + + - uses: ./.github/actions/report + with: + bundles: ${{ needs.bundle.outputs.artifacts }} + sdks: | + { + "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, + "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, + "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, + "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, + "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, + "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } + } + installs: | + { + "rust": ${{ toJSON(needs.build_rust.outputs.install) }} + } + + report_java: + if: always() && github.event_name == 'pull_request' + needs: + - bundle - build_java + runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write + steps: + - uses: actions/checkout@v7 + + - uses: ./.github/actions/report + with: + bundles: ${{ needs.bundle.outputs.artifacts }} + sdks: | + { + "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, + "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, + "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, + "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, + "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, + "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } + } + installs: | + { + "java": ${{ toJSON(needs.build_java.outputs.install) }} + } + + report_python: + if: always() && github.event_name == 'pull_request' + needs: + - bundle - build_python + runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write + steps: + - uses: actions/checkout@v7 + + - uses: ./.github/actions/report + with: + bundles: ${{ needs.bundle.outputs.artifacts }} + sdks: | + { + "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, + "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, + "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, + "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, + "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, + "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } + } + installs: | + { + "python": ${{ toJSON(needs.build_python.outputs.install) }} + } + + report_csharp: + if: always() && github.event_name == 'pull_request' + needs: + - bundle - build_csharp + runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write + steps: + - uses: actions/checkout@v7 + + - uses: ./.github/actions/report + with: + bundles: ${{ needs.bundle.outputs.artifacts }} + sdks: | + { + "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, + "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, + "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, + "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, + "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, + "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } + } + installs: | + { + "csharp": ${{ toJSON(needs.build_csharp.outputs.install) }} + } + + report_dart: + if: always() && github.event_name == 'pull_request' + needs: + - bundle - build_dart runs-on: ubuntu-latest permissions: @@ -197,11 +339,6 @@ jobs: } installs: | { - "javascript": ${{ toJSON(needs.build_javascript.outputs.install) }}, - "rust": ${{ toJSON(needs.build_rust.outputs.install) }}, - "java": ${{ toJSON(needs.build_java.outputs.install) }}, - "python": ${{ toJSON(needs.build_python.outputs.install) }}, - "csharp": ${{ toJSON(needs.build_csharp.outputs.install) }}, "dart": ${{ toJSON(needs.build_dart.outputs.install) }} } From c108bcf60fa8656bb297b656c1f02e4ef6134418 Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 06:16:45 -0400 Subject: [PATCH 14/17] ci: keep the SDK catalogue in the report action --- .github/actions/report/action.yml | 119 ++++++++++--------- .github/workflows/ci.yaml | 186 +----------------------------- 2 files changed, 61 insertions(+), 244 deletions(-) diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml index 5b022421..ced05b97 100644 --- a/.github/actions/report/action.yml +++ b/.github/actions/report/action.yml @@ -1,10 +1,10 @@ name: Report the SDKs a run builds description: >- Keeps one pull request comment up to date with the bundles a run produced and - what each SDK job is doing. Without `installs` it polls the run and reports - progress; with `installs` it records how to install what an SDK built and - returns. Commands already in the comment are kept, so each SDK can report as - soon as it finishes. + the SDKs it builds. Called without `install` it follows the run and reports + which SDKs are still building; called with `install` an SDK records how to + install what it just built. Anything already recorded is kept, so an SDK can + report as soon as it is ready. inputs: token: @@ -12,21 +12,21 @@ inputs: Token used to read the run's jobs and write the comment. required: false default: ${{ github.token }} - sdks: + sdk: description: >- - JSON object naming each SDK a `build_` job builds, and the repository - it comes from. - required: true + Key of the SDK reporting itself, matching its `build_` job. + required: false + default: "" + install: + description: >- + How to install what the reporting SDK built. + required: false + default: "" bundles: description: >- JSON array of the bundles this run produced, as `name` and `url`. required: false default: "[]" - installs: - description: >- - JSON object mapping an SDK to how it says to install what it built. - required: false - default: "" interval: description: >- Seconds between refreshes. @@ -43,9 +43,9 @@ runs: steps: - uses: actions/github-script@v9 env: - SDKS: ${{ inputs.sdks }} + SDK: ${{ inputs.sdk }} + INSTALL: ${{ inputs.install }} BUNDLES: ${{ inputs.bundles }} - INSTALLS: ${{ inputs.installs }} INTERVAL: ${{ inputs.interval }} TIMEOUT: ${{ inputs.timeout }} with: @@ -55,9 +55,19 @@ runs: const opening = ''; - const sdks = JSON.parse(process.env.SDKS); + const sdks = { + javascript: { name: 'JavaScript', repository: 'vrchatapi/vrchatapi-javascript' }, + rust: { name: 'Rust', repository: 'vrchatapi/vrchatapi-rust' }, + java: { name: 'Java', repository: 'vrchatapi/vrchatapi-java' }, + python: { name: 'Python', repository: 'vrchatapi/vrchatapi-python' }, + csharp: { name: 'C#', repository: 'vrchatapi/vrchatapi-csharp' }, + dart: { name: 'Dart', repository: 'vrchatapi/vrchatapi-dart' }, + }; + const bundles = JSON.parse(process.env.BUNDLES); - const reported = process.env.INSTALLS ? JSON.parse(process.env.INSTALLS) : null; + const reported = process.env.SDK && process.env.INSTALL + ? { [process.env.SDK]: process.env.INSTALL } + : null; const interval = Number(process.env.INTERVAL) * 1000; const deadline = Date.now() + Number(process.env.TIMEOUT) * 1000; @@ -65,49 +75,25 @@ runs: const pull = context.payload.pull_request?.number; if (!pull) return; - const stages = { - queued: 'queued', - generate: 'generating', - build: 'building', - test: 'testing', - install: 'installing', - analyze: 'analysing', - pana: 'analysing', - format: 'checking formatting', - built: 'built', - failed: 'failed', - }; - - async function jobsBySdk() { + async function building() { const jobs = await github.paginate( github.rest.actions.listJobsForWorkflowRun, { ...context.repo, run_id: context.runId, per_page: 100 }, ); - const bySdk = {}; + const running = new Set(); + const seen = new Set(); for (const job of jobs) { - const match = /^build_(\w+) \/ (.+)$/.exec(job.name); + const match = /^build_(\w+) \//.exec(job.name); if (!match) continue; - const [, sdk, step] = match; - (bySdk[sdk] ??= []).push({ ...job, step: step.split(' (')[0] }); + const [, sdk] = match; + seen.add(sdk); + if (job.status !== 'completed') running.add(sdk); } - return bySdk; - } - - function state(jobs) { - if (!jobs?.length) return { stage: 'queued', done: false }; - - const failed = jobs.some(({ conclusion }) => - conclusion === 'failure' || conclusion === 'cancelled'); - if (failed) return { stage: 'failed', done: true }; - - const running = jobs.find(({ status }) => status !== 'completed'); - if (running) return { stage: running.step, done: false }; - - return { stage: 'built', done: true }; + return { running, done: seen.size > 0 && running.size === 0 }; } function recall(body) { @@ -124,7 +110,7 @@ runs: } } - function render(bySdk, installs) { + function render(running, installs) { const lines = [marker, `${opening}${JSON.stringify(installs)}${closing}`]; if (bundles.length > 0) { @@ -154,11 +140,10 @@ runs: lines.push('### SDKs', ''); for (const [key, { name, repository }] of Object.entries(sdks)) { - const { stage } = state(bySdk[key]); const how = installs[key]; - const suffix = how ? ` ${how.startsWith('[') ? how : `\`${how}\``}` : ''; + const suffix = running.has(key) ? ' → building' : how ? ` \`${how}\`` : ''; - lines.push(`* [**${name}**](https://github.com/${repository}) → ${stages[stage] ?? stage}${suffix}`); + lines.push(`* [**${name}**](https://github.com/${repository})${suffix}`); } const sha = context.payload.pull_request.head.sha; @@ -169,16 +154,20 @@ runs: return lines.join('\n'); } - async function upsert(bySdk) { + async function current() { const comments = await github.paginate(github.rest.issues.listComments, { ...context.repo, issue_number: pull, per_page: 100, }); - const existing = comments.find((comment) => comment.body.includes(marker)); + return comments.find((comment) => comment.body.includes(marker)); + } + + async function upsert(running) { + const existing = await current(); const installs = { ...recall(existing?.body), ...reported }; - const body = render(bySdk, installs); + const body = render(running, installs); if (!existing) { await github.rest.issues.createComment({ @@ -199,16 +188,24 @@ runs: } if (reported) { - await upsert(await jobsBySdk()); + for (let attempt = 0; attempt < 5; attempt += 1) { + const { running } = await building(); + await upsert(running); + + const installs = recall((await current())?.body); + if (installs[process.env.SDK] === process.env.INSTALL) return; + + await new Promise((resolve) => setTimeout(resolve, 2000)); + } + return; } while (Date.now() < deadline) { - const bySdk = await jobsBySdk(); - const states = Object.keys(sdks).map((key) => state(bySdk[key])); + const { running, done } = await building(); + await upsert(running); - await upsert(bySdk); - if (states.every(({ done }) => done)) return; + if (done) return; await new Promise((resolve) => setTimeout(resolve, interval)); } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d38ddf99..381a26e3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -111,6 +111,9 @@ jobs: build_javascript: needs: bundle + permissions: + actions: read + pull-requests: write uses: vrchatapi/vrchatapi-javascript/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions @@ -158,189 +161,6 @@ jobs: - uses: ./.github/actions/report with: bundles: ${{ needs.bundle.outputs.artifacts }} - sdks: | - { - "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, - "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, - "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, - "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, - "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, - "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } - } - - report_javascript: - if: always() && github.event_name == 'pull_request' - needs: - - bundle - - build_javascript - runs-on: ubuntu-latest - permissions: - actions: read - pull-requests: write - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/report - with: - bundles: ${{ needs.bundle.outputs.artifacts }} - sdks: | - { - "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, - "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, - "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, - "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, - "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, - "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } - } - installs: | - { - "javascript": ${{ toJSON(needs.build_javascript.outputs.install) }} - } - - report_rust: - if: always() && github.event_name == 'pull_request' - needs: - - bundle - - build_rust - runs-on: ubuntu-latest - permissions: - actions: read - pull-requests: write - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/report - with: - bundles: ${{ needs.bundle.outputs.artifacts }} - sdks: | - { - "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, - "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, - "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, - "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, - "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, - "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } - } - installs: | - { - "rust": ${{ toJSON(needs.build_rust.outputs.install) }} - } - - report_java: - if: always() && github.event_name == 'pull_request' - needs: - - bundle - - build_java - runs-on: ubuntu-latest - permissions: - actions: read - pull-requests: write - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/report - with: - bundles: ${{ needs.bundle.outputs.artifacts }} - sdks: | - { - "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, - "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, - "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, - "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, - "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, - "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } - } - installs: | - { - "java": ${{ toJSON(needs.build_java.outputs.install) }} - } - - report_python: - if: always() && github.event_name == 'pull_request' - needs: - - bundle - - build_python - runs-on: ubuntu-latest - permissions: - actions: read - pull-requests: write - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/report - with: - bundles: ${{ needs.bundle.outputs.artifacts }} - sdks: | - { - "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, - "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, - "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, - "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, - "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, - "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } - } - installs: | - { - "python": ${{ toJSON(needs.build_python.outputs.install) }} - } - - report_csharp: - if: always() && github.event_name == 'pull_request' - needs: - - bundle - - build_csharp - runs-on: ubuntu-latest - permissions: - actions: read - pull-requests: write - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/report - with: - bundles: ${{ needs.bundle.outputs.artifacts }} - sdks: | - { - "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, - "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, - "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, - "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, - "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, - "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } - } - installs: | - { - "csharp": ${{ toJSON(needs.build_csharp.outputs.install) }} - } - - report_dart: - if: always() && github.event_name == 'pull_request' - needs: - - bundle - - build_dart - runs-on: ubuntu-latest - permissions: - actions: read - pull-requests: write - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/report - with: - bundles: ${{ needs.bundle.outputs.artifacts }} - sdks: | - { - "javascript": { "name": "JavaScript", "repository": "vrchatapi/vrchatapi-javascript" }, - "rust": { "name": "Rust", "repository": "vrchatapi/vrchatapi-rust" }, - "java": { "name": "Java", "repository": "vrchatapi/vrchatapi-java" }, - "python": { "name": "Python", "repository": "vrchatapi/vrchatapi-python" }, - "csharp": { "name": "C#", "repository": "vrchatapi/vrchatapi-csharp" }, - "dart": { "name": "Dart", "repository": "vrchatapi/vrchatapi-dart" } - } - installs: | - { - "dart": ${{ toJSON(needs.build_dart.outputs.install) }} - } release: runs-on: ubuntu-latest From 99af83a97bbcf4f6514d95ceef91805d900faefe Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 06:27:08 -0400 Subject: [PATCH 15/17] fix(ci): forget what an earlier commit reported --- .github/actions/report/action.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml index ced05b97..992690e3 100644 --- a/.github/actions/report/action.yml +++ b/.github/actions/report/action.yml @@ -96,6 +96,8 @@ runs: return { running, done: seen.size > 0 && running.size === 0 }; } + const sha = context.payload.pull_request.head.sha; + function recall(body) { const start = body?.indexOf(opening) ?? -1; if (start === -1) return {}; @@ -104,14 +106,15 @@ runs: if (end === -1) return {}; try { - return JSON.parse(body.slice(start + opening.length, end)); + const recorded = JSON.parse(body.slice(start + opening.length, end)); + return recorded.sha === sha ? recorded.installs ?? {} : {}; } catch { return {}; } } function render(running, installs) { - const lines = [marker, `${opening}${JSON.stringify(installs)}${closing}`]; + const lines = [marker, `${opening}${JSON.stringify({ sha, installs })}${closing}`]; if (bundles.length > 0) { const byStem = {}; @@ -146,7 +149,6 @@ runs: lines.push(`* [**${name}**](https://github.com/${repository})${suffix}`); } - const sha = context.payload.pull_request.head.sha; const commit = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`; lines.push('', `built from [\`${sha.slice(0, 7)}\`](${commit})`); From 6d8e1143eaeb726e790bd6ca1250e1f5865cf9ce Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 06:31:35 -0400 Subject: [PATCH 16/17] ci: drop the pull request report --- .github/actions/report/action.yml | 213 ------------------------------ .github/workflows/ci.yaml | 31 +---- 2 files changed, 2 insertions(+), 242 deletions(-) delete mode 100644 .github/actions/report/action.yml diff --git a/.github/actions/report/action.yml b/.github/actions/report/action.yml deleted file mode 100644 index 992690e3..00000000 --- a/.github/actions/report/action.yml +++ /dev/null @@ -1,213 +0,0 @@ -name: Report the SDKs a run builds -description: >- - Keeps one pull request comment up to date with the bundles a run produced and - the SDKs it builds. Called without `install` it follows the run and reports - which SDKs are still building; called with `install` an SDK records how to - install what it just built. Anything already recorded is kept, so an SDK can - report as soon as it is ready. - -inputs: - token: - description: >- - Token used to read the run's jobs and write the comment. - required: false - default: ${{ github.token }} - sdk: - description: >- - Key of the SDK reporting itself, matching its `build_` job. - required: false - default: "" - install: - description: >- - How to install what the reporting SDK built. - required: false - default: "" - bundles: - description: >- - JSON array of the bundles this run produced, as `name` and `url`. - required: false - default: "[]" - interval: - description: >- - Seconds between refreshes. - required: false - default: "5" - timeout: - description: >- - Seconds to keep refreshing before giving up. - required: false - default: "2700" - -runs: - using: composite - steps: - - uses: actions/github-script@v9 - env: - SDK: ${{ inputs.sdk }} - INSTALL: ${{ inputs.install }} - BUNDLES: ${{ inputs.bundles }} - INTERVAL: ${{ inputs.interval }} - TIMEOUT: ${{ inputs.timeout }} - with: - github-token: ${{ inputs.token }} - script: | - const marker = ''; - const opening = ''; - - const sdks = { - javascript: { name: 'JavaScript', repository: 'vrchatapi/vrchatapi-javascript' }, - rust: { name: 'Rust', repository: 'vrchatapi/vrchatapi-rust' }, - java: { name: 'Java', repository: 'vrchatapi/vrchatapi-java' }, - python: { name: 'Python', repository: 'vrchatapi/vrchatapi-python' }, - csharp: { name: 'C#', repository: 'vrchatapi/vrchatapi-csharp' }, - dart: { name: 'Dart', repository: 'vrchatapi/vrchatapi-dart' }, - }; - - const bundles = JSON.parse(process.env.BUNDLES); - const reported = process.env.SDK && process.env.INSTALL - ? { [process.env.SDK]: process.env.INSTALL } - : null; - - const interval = Number(process.env.INTERVAL) * 1000; - const deadline = Date.now() + Number(process.env.TIMEOUT) * 1000; - - const pull = context.payload.pull_request?.number; - if (!pull) return; - - async function building() { - const jobs = await github.paginate( - github.rest.actions.listJobsForWorkflowRun, - { ...context.repo, run_id: context.runId, per_page: 100 }, - ); - - const running = new Set(); - const seen = new Set(); - - for (const job of jobs) { - const match = /^build_(\w+) \//.exec(job.name); - if (!match) continue; - - const [, sdk] = match; - seen.add(sdk); - if (job.status !== 'completed') running.add(sdk); - } - - return { running, done: seen.size > 0 && running.size === 0 }; - } - - const sha = context.payload.pull_request.head.sha; - - function recall(body) { - const start = body?.indexOf(opening) ?? -1; - if (start === -1) return {}; - - const end = body.indexOf(closing, start); - if (end === -1) return {}; - - try { - const recorded = JSON.parse(body.slice(start + opening.length, end)); - return recorded.sha === sha ? recorded.installs ?? {} : {}; - } catch { - return {}; - } - } - - function render(running, installs) { - const lines = [marker, `${opening}${JSON.stringify({ sha, installs })}${closing}`]; - - if (bundles.length > 0) { - const byStem = {}; - - for (const { name, url } of bundles) { - const cut = name.lastIndexOf('.'); - const stem = cut === -1 ? name : name.slice(0, cut); - const format = cut === -1 ? name : name.slice(cut + 1); - - (byStem[stem] ??= []).push({ format, url }); - } - - lines.push('### Bundles', ''); - - for (const stem of Object.keys(byStem).sort((a, b) => b.localeCompare(a))) { - const formats = byStem[stem] - .sort((a, b) => a.format.localeCompare(b.format)) - .map(({ format, url }) => `[${format}](${url})`); - - lines.push(`* ${stem} (${formats.join(', ')})`); - } - - lines.push(''); - } - - lines.push('### SDKs', ''); - - for (const [key, { name, repository }] of Object.entries(sdks)) { - const how = installs[key]; - const suffix = running.has(key) ? ' → building' : how ? ` \`${how}\`` : ''; - - lines.push(`* [**${name}**](https://github.com/${repository})${suffix}`); - } - - const commit = `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha}`; - - lines.push('', `built from [\`${sha.slice(0, 7)}\`](${commit})`); - - return lines.join('\n'); - } - - async function current() { - const comments = await github.paginate(github.rest.issues.listComments, { - ...context.repo, - issue_number: pull, - per_page: 100, - }); - - return comments.find((comment) => comment.body.includes(marker)); - } - - async function upsert(running) { - const existing = await current(); - const installs = { ...recall(existing?.body), ...reported }; - const body = render(running, installs); - - if (!existing) { - await github.rest.issues.createComment({ - ...context.repo, - issue_number: pull, - body, - }); - return; - } - - if (existing.body !== body) { - await github.rest.issues.updateComment({ - ...context.repo, - comment_id: existing.id, - body, - }); - } - } - - if (reported) { - for (let attempt = 0; attempt < 5; attempt += 1) { - const { running } = await building(); - await upsert(running); - - const installs = recall((await current())?.body); - if (installs[process.env.SDK] === process.env.INSTALL) return; - - await new Promise((resolve) => setTimeout(resolve, 2000)); - } - - return; - } - - while (Date.now() < deadline) { - const { running, done } = await building(); - await upsert(running); - - if (done) return; - - await new Promise((resolve) => setTimeout(resolve, interval)); - } diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 381a26e3..1b0c6361 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -73,8 +73,6 @@ jobs: bundle: runs-on: ubuntu-latest - outputs: - artifacts: ${{ steps.upload.outputs.artifacts }} steps: - uses: actions/checkout@v7 @@ -85,8 +83,7 @@ jobs: - run: bun --bun run bundle - - id: upload - uses: actions/github-script@v9 + - uses: actions/github-script@v9 with: script: | const { readdir } = require("node:fs/promises"); @@ -99,21 +96,11 @@ jobs: const artifacts = await Promise.all(files.map(async (file) => { const pathname = resolve(`./dist/${file}`); - const { id } = await artifact.uploadArtifact(file, [pathname], dirname(pathname)); - - return { - name: file, - url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/artifacts/${id}`, - }; + return artifact.uploadArtifact(file, [pathname], dirname(pathname)); })); - core.setOutput("artifacts", JSON.stringify(artifacts)); - build_javascript: needs: bundle - permissions: - actions: read - pull-requests: write uses: vrchatapi/vrchatapi-javascript/.github/workflows/ci.yaml@ci/modernise-actions with: ref: ci/modernise-actions @@ -148,20 +135,6 @@ jobs: with: ref: ci/modernise-actions - report: - if: github.event_name == 'pull_request' - needs: bundle - runs-on: ubuntu-latest - permissions: - actions: read - pull-requests: write - steps: - - uses: actions/checkout@v7 - - - uses: ./.github/actions/report - with: - bundles: ${{ needs.bundle.outputs.artifacts }} - release: runs-on: ubuntu-latest needs: From ae182d3593c8d2213129a189f26aa0ccf37a243b Mon Sep 17 00:00:00 2001 From: Aries Clark Date: Sun, 9 Aug 2026 06:40:49 -0400 Subject: [PATCH 17/17] ci: let download resolve the bundle a release dispatched --- .github/actions/download/action.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/actions/download/action.yml b/.github/actions/download/action.yml index a399c64e..33ddd200 100644 --- a/.github/actions/download/action.yml +++ b/.github/actions/download/action.yml @@ -1,8 +1,9 @@ name: Fetch a specification bundle description: >- Leaves the requested bundle in the working directory, taken from this run's - artifacts when running inside the specification repository and from the latest - release otherwise. + artifacts when running inside the specification repository, from the release + that triggered the run when there is one, and from the latest release + otherwise. inputs: bundle: @@ -10,6 +11,12 @@ inputs: Bundle to fetch. required: false default: openapi.json + url: + description: >- + Where to fetch the bundle from, overriding both the triggering release and + the latest one. + required: false + default: "" runs: using: composite @@ -22,6 +29,7 @@ runs: - if: github.repository != 'vrchatapi/specification' run: >- - curl -Lfo "${{ inputs.bundle }}" - "https://github.com/vrchatapi/specification/releases/latest/download/${{ inputs.bundle }}" + curl -Lfo "${{ inputs.bundle }}" "${{ inputs.url + || github.event.client_payload.artifacts[inputs.bundle] + || format('https://github.com/vrchatapi/specification/releases/latest/download/{0}', inputs.bundle) }}" shell: bash