diff --git a/bastion/Dockerfile.labd b/bastion/Dockerfile.labd index 50f7305..633b399 100644 --- a/bastion/Dockerfile.labd +++ b/bastion/Dockerfile.labd @@ -11,6 +11,7 @@ WORKDIR /app # Copy workspace config and package manifests first (layer cache) COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json tsconfig.json ./ COPY src/shared/package.json src/shared/tsconfig.json src/shared/ +COPY src/core/package.json src/core/tsconfig.json src/core/ COPY src/labd/package.json src/labd/tsconfig.json src/labd/ # Install all dependencies (dev included -- needed for build) @@ -22,10 +23,13 @@ RUN pnpm --filter @lab/labd exec prisma generate # Copy source code COPY src/shared/src/ src/shared/src/ +COPY src/core/src/ src/core/src/ COPY src/labd/src/ src/labd/src/ -# Build TypeScript (shared first via project references) -RUN pnpm --filter @lab/shared build && pnpm --filter @lab/labd build +# Build TypeScript (shared + core before labd via project references) +RUN pnpm --filter @lab/shared build \ + && pnpm --filter @lab/core build \ + && pnpm --filter @lab/labd build # Hoist the generated Prisma client so stage 2 can COPY it from a stable path RUN mkdir -p /app/_prisma && \ @@ -41,6 +45,7 @@ WORKDIR /app # Copy workspace config and package manifests COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ COPY src/shared/package.json src/shared/ +COPY src/core/package.json src/core/ COPY src/labd/package.json src/labd/ # Install production dependencies only @@ -48,6 +53,7 @@ RUN pnpm install --frozen-lockfile --prod 2>/dev/null || pnpm install --prod # Copy built output from builder COPY --from=builder /app/src/shared/dist/ src/shared/dist/ +COPY --from=builder /app/src/core/dist/ src/core/dist/ COPY --from=builder /app/src/labd/dist/ src/labd/dist/ # Copy Prisma schema + generated client into pnpm store location diff --git a/bastion/pnpm-lock.yaml b/bastion/pnpm-lock.yaml index 4d1cc45..e50b51e 100644 --- a/bastion/pnpm-lock.yaml +++ b/bastion/pnpm-lock.yaml @@ -92,6 +92,12 @@ importers: specifier: ^8.18.1 version: 8.18.1 + src/core: + dependencies: + '@pulumi/pulumi': + specifier: ^3.0.0 + version: 3.228.0(typescript@5.9.3) + src/lab-agent: dependencies: '@lab/shared': @@ -128,12 +134,18 @@ importers: '@fastify/websocket': specifier: ^11.0.2 version: 11.2.0 + '@lab/core': + specifier: workspace:^ + version: link:../core '@lab/shared': specifier: workspace:* version: link:../shared '@prisma/client': specifier: ^6.9.0 version: 6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3) + bcryptjs: + specifier: ^3.0.3 + version: 3.0.3 fastify: specifier: ^5.3.3 version: 5.8.2 @@ -147,6 +159,9 @@ importers: specifier: ^4.3.6 version: 4.3.6 devDependencies: + '@types/bcryptjs': + specifier: ^3.0.0 + version: 3.0.0 '@types/node': specifier: ^22.14.1 version: 22.19.15 @@ -415,6 +430,19 @@ packages: '@fastify/websocket@11.2.0': resolution: {integrity: sha512-3HrDPbAG1CzUCqnslgJxppvzaAZffieOVbLp1DAy1huCSynUWPifSvfdEDUR8HlJLp3sp1A36uOM2tJogADS8w==} + '@gar/promise-retry@1.0.3': + resolution: {integrity: sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@grpc/grpc-js@1.14.3': + resolution: {integrity: sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.8.0': + resolution: {integrity: sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==} + engines: {node: '>=6'} + hasBin: true + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -435,9 +463,19 @@ packages: resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} engines: {node: '>=18'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@isaacs/string-locale-compare@1.1.0': + resolution: {integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@jsep-plugin/assignment@1.3.0': resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} engines: {node: '>= 10.16.0'} @@ -453,10 +491,180 @@ packages: '@kubernetes/client-node@1.4.0': resolution: {integrity: sha512-Zge3YvF7DJi264dU1b3wb/GmzR99JhUpqTvp+VGHfwZT+g7EOOYNScDJNZwXy9cszyIGPIs0VHr+kk8e95qqrA==} + '@logdna/tail-file@2.2.0': + resolution: {integrity: sha512-XGSsWDweP80Fks16lwkAUIr54ICyBs6PsI4mpfTLQaWgEJRtY9xEV+PeyDpJ+sJEGZxqINlpmAwe/6tS1pP8Ng==} + engines: {node: '>=10.3.0'} + '@lukeed/ms@2.0.2': resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} engines: {node: '>=8'} + '@npmcli/agent@4.0.0': + resolution: {integrity: sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/arborist@9.4.2': + resolution: {integrity: sha512-omJgPyzt11cEGrxzgrECoOyxAunmPMgBFTcAB/FbaB+9iOYhGmRdsQqySV8o0LWQ/l2kTeASUIMR4xJufVwmtw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + '@npmcli/fs@5.0.0': + resolution: {integrity: sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/git@7.0.2': + resolution: {integrity: sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/installed-package-contents@4.0.0': + resolution: {integrity: sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + '@npmcli/map-workspaces@5.0.3': + resolution: {integrity: sha512-o2grssXo1e774E5OtEwwrgoszYRh0lqkJH+Pb9r78UcqdGJRDRfhpM8DvZPjzNLLNYeD/rNbjOKM3Ss5UABROw==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/metavuln-calculator@9.0.3': + resolution: {integrity: sha512-94GLSYhLXF2t2LAC7pDwLaM4uCARzxShyAQKsirmlNcpidH89VA4/+K1LbJmRMgz5gy65E/QBBWQdUvGLe2Frg==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/name-from-folder@4.0.0': + resolution: {integrity: sha512-qfrhVlOSqmKM8i6rkNdZzABj8MKEITGFAY+4teqBziksCQAOLutiAxM1wY2BKEd8KjUSpWmWCYxvXr0y4VTlPg==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/node-gyp@5.0.0': + resolution: {integrity: sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/package-json@7.0.5': + resolution: {integrity: sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/promise-spawn@9.0.1': + resolution: {integrity: sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/query@5.0.0': + resolution: {integrity: sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/redact@4.0.0': + resolution: {integrity: sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/run-script@10.0.4': + resolution: {integrity: sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@opentelemetry/api-logs@0.57.2': + resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==} + engines: {node: '>=14'} + + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/context-async-hooks@1.30.1': + resolution: {integrity: sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@1.30.1': + resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-trace-otlp-grpc@0.57.2': + resolution: {integrity: sha512-gHU1vA3JnHbNxEXg5iysqCWxN9j83d7/epTYBZflqQnTyCC4N7yZXn/dMM+bEmyhQPGjhCkNZLx4vZuChH1PYw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-zipkin@1.30.1': + resolution: {integrity: sha512-6S2QIMJahIquvFaaxmcwpvQQRD/YFaMTNoIxrfPIPOeITN+a8lfEcPDxNxn8JDAaxkg+4EnXhz8upVDYenoQjA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + + '@opentelemetry/instrumentation-grpc@0.57.2': + resolution: {integrity: sha512-TR6YQA67cLSZzdxbf2SrbADJy2Y8eBW1+9mF15P0VK2MYcpdoUSmQTF1oMkBwa3B9NwqDFA2fq7wYTTutFQqaQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.57.2': + resolution: {integrity: sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-exporter-base@0.57.2': + resolution: {integrity: sha512-XdxEzL23Urhidyebg5E6jZoaiW5ygP/mRjxLHixogbqwDy2Faduzb5N0o/Oi+XTIJu+iyxXdVORjXax+Qgfxag==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-grpc-exporter-base@0.57.2': + resolution: {integrity: sha512-USn173KTWy0saqqRB5yU9xUZ2xdgb1Rdu5IosJnm9aV4hMTuFFRTUsQxbgc24QxpCHeoKzzCSnS/JzdV0oM2iQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.57.2': + resolution: {integrity: sha512-48IIRj49gbQVK52jYsw70+Jv+JbahT8BqT2Th7C4H7RCM9d0gZ5sgNPoMpWldmfjvIsSgiGJtjfk9MeZvjhoig==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/propagator-b3@1.30.1': + resolution: {integrity: sha512-oATwWWDIJzybAZ4pO76ATN5N6FFbOA1otibAVlS8v90B4S1wClnhRUk7K+2CHAwN1JKYuj4jh/lpCEG5BAqFuQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/propagator-jaeger@1.30.1': + resolution: {integrity: sha512-Pj/BfnYEKIOImirH76M4hDaBSx6HyZ2CXUqk+Kj02m6BB80c/yo4BdWkn/1gDFfU+YPY+bPR2U0DKBfdxCKwmg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/resources@1.30.1': + resolution: {integrity: sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.57.2': + resolution: {integrity: sha512-TXFHJ5c+BKggWbdEQ/inpgIzEmS2BGQowLE9UhsMd7YYlUfBQJ4uax0VF/B5NYigdM/75OoJGhAV3upEhK+3gg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@1.30.1': + resolution: {integrity: sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@1.30.1': + resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-trace-node@1.30.1': + resolution: {integrity: sha512-cBjYOINt1JxXdpw1e5MlHmFRc5fgj4GW/86vsKFxJCJ8AL4PdVtYH41gWwl4qd4uQjqEL1oJVrXkSy5cnduAnQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.28.0': + resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} + engines: {node: '>=14'} + '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} @@ -490,6 +698,48 @@ packages: '@prisma/get-platform@6.19.2': resolution: {integrity: sha512-PGLr06JUSTqIvztJtAzIxOwtWKtJm5WwOG6xpsgD37Rc84FpfUBGLKz65YpJBGtkRQGXTYEFie7pYALocC3MtA==} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@pulumi/pulumi@3.228.0': + resolution: {integrity: sha512-yAwieapB/Huro8/psool1sKhe2rGT80GTnEFLDWbKPHTMo6oSegGb6aYg+bzPuC3vgBOn2dnHkobSuwbBhQ7gQ==} + engines: {node: '>=20'} + peerDependencies: + ts-node: '>= 7.0.1 < 12' + typescript: '>= 3.8.3 < 6' + peerDependenciesMeta: + ts-node: + optional: true + typescript: + optional: true + '@rollup/rollup-android-arm-eabi@4.59.0': resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] @@ -618,6 +868,34 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sigstore/bundle@4.0.0': + resolution: {integrity: sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/core@3.2.0': + resolution: {integrity: sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/protobuf-specs@0.5.0': + resolution: {integrity: sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA==} + engines: {node: ^18.17.0 || >=20.5.0} + + '@sigstore/sign@4.1.1': + resolution: {integrity: sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/tuf@4.0.2': + resolution: {integrity: sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/verify@3.1.0': + resolution: {integrity: sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + '@sindresorhus/merge-streams@4.0.0': resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} @@ -628,6 +906,25 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@tufjs/canonical-json@2.0.0': + resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==} + engines: {node: ^16.14.0 || >=18.0.0} + + '@tufjs/models@4.1.0': + resolution: {integrity: sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@types/bcryptjs@3.0.0': + resolution: {integrity: sha512-WRZOuCuaz8UcZZE4R5HXTco2goQSI2XxjGY3hbM/xDvwmqFWd4ivooImsMx65OKM6CtNKbnZ5YL+YwAwK7c1dg==} + deprecated: This is a stub types definition. bcryptjs provides its own type definitions, so you do not need this installed. + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -640,12 +937,21 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/google-protobuf@3.15.12': + resolution: {integrity: sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==} + + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} + '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} @@ -655,9 +961,21 @@ packages: '@types/node@24.12.0': resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + + '@types/shimmer@1.2.0': + resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} + '@types/stream-buffers@3.0.8': resolution: {integrity: sha512-J+7VaHKNvlNPJPEJXX/fKa9DZtR/xPMwuIbe+yNOwp1YB+ApUOBv2aUpEoBJEi8nJgbgs1x8e73ttg0r1rSUdw==} + '@types/tmp@0.2.6': + resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==} + '@types/triple-beam@1.3.5': resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} @@ -752,9 +1070,18 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + abbrev@4.0.0: + resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} + engines: {node: ^20.17.0 || >=22.9.0} + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -783,6 +1110,17 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -853,10 +1191,21 @@ packages: bare-url@2.4.0: resolution: {integrity: sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==} + bcryptjs@3.0.3: + resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==} + hasBin: true + + bin-links@6.0.0: + resolution: {integrity: sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w==} + engines: {node: ^20.17.0 || >=22.9.0} + brace-expansion@5.0.4: resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} engines: {node: 18 || 20 || >=22} + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + c12@3.1.0: resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} peerDependencies: @@ -869,6 +1218,18 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cacache@20.0.4: + resolution: {integrity: sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==} + engines: {node: ^20.17.0 || >=22.9.0} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -885,16 +1246,41 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} citty@0.2.1: resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + cmd-shim@8.0.0: + resolution: {integrity: sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA==} + engines: {node: ^20.17.0 || >=22.9.0} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + color-convert@3.1.3: resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} engines: {node: '>=14.6'} + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-name@2.1.0: resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} engines: {node: '>=12.20'} @@ -915,6 +1301,10 @@ packages: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} + common-ancestor-path@2.0.0: + resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} + engines: {node: '>= 18'} + confbox@0.2.4: resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} @@ -934,6 +1324,11 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -943,6 +1338,10 @@ packages: supports-color: optional: true + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -954,6 +1353,10 @@ packages: resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} engines: {node: '>=16.0.0'} + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} @@ -986,6 +1389,9 @@ packages: effect@3.18.4: resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -996,6 +1402,10 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -1020,6 +1430,10 @@ packages: engines: {node: '>=18'} hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -1059,6 +1473,11 @@ packages: resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -1081,6 +1500,10 @@ packages: events-universal@1.0.1: resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + execa@9.6.1: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} @@ -1089,6 +1512,9 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -1156,6 +1582,10 @@ packages: resolution: {integrity: sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==} engines: {node: '>=20'} + find-up-simple@1.0.1: + resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} + engines: {node: '>=18'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1178,6 +1608,10 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} + fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1186,6 +1620,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1194,6 +1632,14 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + get-stream@9.0.1: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} @@ -1219,10 +1665,20 @@ packages: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} + google-protobuf@3.21.4: + resolution: {integrity: sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -1235,18 +1691,53 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + + hosted-git-info@9.0.2: + resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} + engines: {node: ^20.17.0 || >=22.9.0} + hpagent@1.2.0: resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==} engines: {node: '>=14'} + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + human-signals@8.0.1: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + ignore-walk@8.0.0: + resolution: {integrity: sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==} + engines: {node: ^20.17.0 || >=22.9.0} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1255,6 +1746,9 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + import-in-the-middle@1.15.0: + resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -1262,6 +1756,14 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} + ip-address@10.1.0: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} @@ -1270,10 +1772,18 @@ packages: resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} engines: {node: '>= 10'} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1297,6 +1807,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@4.0.0: + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} + isomorphic-ws@5.0.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: @@ -1316,6 +1830,10 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -1327,6 +1845,10 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@5.0.0: + resolution: {integrity: sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==} + engines: {node: ^20.17.0 || >=22.9.0} + json-schema-ref-resolver@3.0.0: resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} @@ -1339,11 +1861,24 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-nice@1.1.4: + resolution: {integrity: sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==} + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + jsonpath-plus@10.4.0: resolution: {integrity: sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==} engines: {node: '>=18.0.0'} hasBin: true + just-diff-apply@5.5.0: + resolution: {integrity: sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==} + + just-diff@6.0.2: + resolution: {integrity: sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1361,13 +1896,26 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + logform@2.7.0: resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} engines: {node: '>= 12.0.0'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.7: resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} engines: {node: 20 || >=22} @@ -1375,10 +1923,17 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-fetch-happen@15.0.5: + resolution: {integrity: sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==} + engines: {node: ^20.17.0 || >=22.9.0} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -1392,14 +1947,60 @@ packages: engines: {node: '>=10.0.0'} hasBin: true + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@10.2.4: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass-collect@2.0.1: + resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass-fetch@5.0.2: + resolution: {integrity: sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + minipass-flush@1.0.7: + resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@2.0.0: + resolution: {integrity: sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} @@ -1414,6 +2015,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} @@ -1426,6 +2031,56 @@ packages: encoding: optional: true + node-gyp@12.2.0: + resolution: {integrity: sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + nopt@9.0.0: + resolution: {integrity: sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + normalize-package-data@6.0.2: + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + npm-bundled@5.0.0: + resolution: {integrity: sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-install-checks@8.0.0: + resolution: {integrity: sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-normalize-package-bin@5.0.0: + resolution: {integrity: sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-package-arg@13.0.2: + resolution: {integrity: sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-packlist@10.0.4: + resolution: {integrity: sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-pick-manifest@11.0.3: + resolution: {integrity: sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-registry-fetch@19.1.1: + resolution: {integrity: sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + npm-run-path@6.0.0: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} @@ -1455,6 +2110,10 @@ packages: one-time@1.0.0: resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + openid-client@6.8.2: resolution: {integrity: sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA==} @@ -1462,6 +2121,10 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -1470,9 +2133,26 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + + package-directory@8.2.0: + resolution: {integrity: sha512-qJSu5Mo6tHmRxCy2KCYYKYgcfBdUpy9dwReaZD/xwf608AUk/MoRtIOWzgDtUeGeC7n/55yC3MI1Q+MbSoektw==} + engines: {node: '>=18'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + pacote@21.5.0: + resolution: {integrity: sha512-VtZ0SB8mb5Tzw3dXDfVAIjhyVKUHZkS/ZH9/5mpKenwC9sFOXNI0JI7kEF7IMkwOnsWMFrvAZHzx1T5fmrp9FQ==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + parse-conflict-json@5.0.1: + resolution: {integrity: sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ==} + engines: {node: ^20.17.0 || >=22.9.0} + parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} @@ -1489,6 +2169,9 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -1506,6 +2189,10 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@3.0.2: + resolution: {integrity: sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==} + engines: {node: '>=10'} + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -1523,6 +2210,10 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + postcss@8.5.8: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} @@ -1545,12 +2236,30 @@ packages: typescript: optional: true + proc-log@6.1.0: + resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} + engines: {node: ^20.17.0 || >=22.9.0} + process-warning@4.0.1: resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + proggy@4.0.0: + resolution: {integrity: sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + promise-all-reject-late@1.0.1: + resolution: {integrity: sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==} + + promise-call-limit@3.0.2: + resolution: {integrity: sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==} + + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -1564,9 +2273,17 @@ packages: quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + read-cmd-shim@6.0.0: + resolution: {integrity: sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A==} + engines: {node: ^20.17.0 || >=22.9.0} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -1579,13 +2296,32 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-in-the-middle@7.5.2: + resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} + engines: {node: '>=8.6.0'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + ret@0.5.0: resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} engines: {node: '>=10'} @@ -1621,6 +2357,9 @@ packages: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + secure-json-parse@4.1.0: resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} @@ -1643,13 +2382,23 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shimmer@1.2.1: + resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sigstore@4.1.0: + resolution: {integrity: sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==} + engines: {node: ^20.17.0 || >=22.9.0} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -1669,10 +2418,39 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssri@13.0.1: + resolution: {integrity: sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==} + engines: {node: ^20.17.0 || >=22.9.0} + stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} @@ -1696,9 +2474,21 @@ packages: streamx@2.25.0: resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + strip-final-newline@4.0.0: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} engines: {node: '>=18'} @@ -1706,12 +2496,20 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + tar-fs@3.1.2: resolution: {integrity: sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==} tar-stream@3.1.8: resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} + tar@7.5.13: + resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} + engines: {node: '>=18'} + teex@1.0.1: resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} @@ -1751,6 +2549,10 @@ packages: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + toad-cache@3.7.0: resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} engines: {node: '>=12'} @@ -1762,6 +2564,10 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + treeverse@3.0.0: + resolution: {integrity: sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + triple-beam@1.4.1: resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} engines: {node: '>= 14.0.0'} @@ -1777,6 +2583,10 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tuf-js@4.1.0: + resolution: {integrity: sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==} + engines: {node: ^20.17.0 || >=22.9.0} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1796,12 +2606,23 @@ packages: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} + upath@1.2.0: + resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} + engines: {node: '>=4'} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + validate-npm-package-name@7.0.2: + resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} + engines: {node: ^20.17.0 || >=22.9.0} + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1875,6 +2696,10 @@ packages: jsdom: optional: true + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -1886,6 +2711,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@6.0.1: + resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -1909,9 +2739,17 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + write-file-atomic@7.0.1: + resolution: {integrity: sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==} + engines: {node: ^20.17.0 || >=22.9.0} + ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -1924,6 +2762,25 @@ packages: utf-8-validate: optional: true + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2110,6 +2967,20 @@ snapshots: - bufferutil - utf-8-validate + '@gar/promise-retry@1.0.3': {} + + '@grpc/grpc-js@1.14.3': + dependencies: + '@grpc/proto-loader': 0.8.0 + '@js-sdsl/ordered-map': 4.4.2 + + '@grpc/proto-loader@0.8.0': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.5.4 + yargs: 17.7.2 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -2123,8 +2994,16 @@ snapshots: '@isaacs/cliui@9.0.0': {} + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@isaacs/string-locale-compare@1.1.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@js-sdsl/ordered-map@4.4.2': {} + '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': dependencies: jsep: 1.4.0 @@ -2160,8 +3039,257 @@ snapshots: - supports-color - utf-8-validate + '@logdna/tail-file@2.2.0': {} + '@lukeed/ms@2.0.2': {} + '@npmcli/agent@4.0.0': + dependencies: + agent-base: 7.1.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 11.2.7 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + '@npmcli/arborist@9.4.2': + dependencies: + '@gar/promise-retry': 1.0.3 + '@isaacs/string-locale-compare': 1.1.0 + '@npmcli/fs': 5.0.0 + '@npmcli/installed-package-contents': 4.0.0 + '@npmcli/map-workspaces': 5.0.3 + '@npmcli/metavuln-calculator': 9.0.3 + '@npmcli/name-from-folder': 4.0.0 + '@npmcli/node-gyp': 5.0.0 + '@npmcli/package-json': 7.0.5 + '@npmcli/query': 5.0.0 + '@npmcli/redact': 4.0.0 + '@npmcli/run-script': 10.0.4 + bin-links: 6.0.0 + cacache: 20.0.4 + common-ancestor-path: 2.0.0 + hosted-git-info: 9.0.2 + json-stringify-nice: 1.1.4 + lru-cache: 11.2.7 + minimatch: 10.2.4 + nopt: 9.0.0 + npm-install-checks: 8.0.0 + npm-package-arg: 13.0.2 + npm-pick-manifest: 11.0.3 + npm-registry-fetch: 19.1.1 + pacote: 21.5.0 + parse-conflict-json: 5.0.1 + proc-log: 6.1.0 + proggy: 4.0.0 + promise-all-reject-late: 1.0.1 + promise-call-limit: 3.0.2 + semver: 7.7.4 + ssri: 13.0.1 + treeverse: 3.0.0 + walk-up-path: 4.0.0 + transitivePeerDependencies: + - supports-color + + '@npmcli/fs@5.0.0': + dependencies: + semver: 7.7.4 + + '@npmcli/git@7.0.2': + dependencies: + '@gar/promise-retry': 1.0.3 + '@npmcli/promise-spawn': 9.0.1 + ini: 6.0.0 + lru-cache: 11.2.7 + npm-pick-manifest: 11.0.3 + proc-log: 6.1.0 + semver: 7.7.4 + which: 6.0.1 + + '@npmcli/installed-package-contents@4.0.0': + dependencies: + npm-bundled: 5.0.0 + npm-normalize-package-bin: 5.0.0 + + '@npmcli/map-workspaces@5.0.3': + dependencies: + '@npmcli/name-from-folder': 4.0.0 + '@npmcli/package-json': 7.0.5 + glob: 13.0.6 + minimatch: 10.2.4 + + '@npmcli/metavuln-calculator@9.0.3': + dependencies: + cacache: 20.0.4 + json-parse-even-better-errors: 5.0.0 + pacote: 21.5.0 + proc-log: 6.1.0 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + + '@npmcli/name-from-folder@4.0.0': {} + + '@npmcli/node-gyp@5.0.0': {} + + '@npmcli/package-json@7.0.5': + dependencies: + '@npmcli/git': 7.0.2 + glob: 13.0.6 + hosted-git-info: 9.0.2 + json-parse-even-better-errors: 5.0.0 + proc-log: 6.1.0 + semver: 7.7.4 + spdx-expression-parse: 4.0.0 + + '@npmcli/promise-spawn@9.0.1': + dependencies: + which: 6.0.1 + + '@npmcli/query@5.0.0': + dependencies: + postcss-selector-parser: 7.1.1 + + '@npmcli/redact@4.0.0': {} + + '@npmcli/run-script@10.0.4': + dependencies: + '@npmcli/node-gyp': 5.0.0 + '@npmcli/package-json': 7.0.5 + '@npmcli/promise-spawn': 9.0.1 + node-gyp: 12.2.0 + proc-log: 6.1.0 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/api-logs@0.57.2': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/api@1.9.1': {} + + '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/exporter-trace-otlp-grpc@0.57.2(@opentelemetry/api@1.9.1)': + dependencies: + '@grpc/grpc-js': 1.14.3 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-grpc-exporter-base': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-zipkin@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/instrumentation-grpc@0.57.2(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.57.2 + '@types/shimmer': 1.2.0 + import-in-the-middle: 1.15.0 + require-in-the-middle: 7.5.2 + semver: 7.7.4 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/otlp-exporter-base@0.57.2(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.1) + + '@opentelemetry/otlp-grpc-exporter-base@0.57.2(@opentelemetry/api@1.9.1)': + dependencies: + '@grpc/grpc-js': 1.14.3 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.1) + + '@opentelemetry/otlp-transformer@0.57.2(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.57.2 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) + protobufjs: 7.5.4 + + '@opentelemetry/propagator-b3@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/propagator-jaeger@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/sdk-logs@0.57.2(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.57.2 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/sdk-metrics@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/sdk-trace-node@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/propagator-b3': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/propagator-jaeger': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) + semver: 7.7.4 + + '@opentelemetry/semantic-conventions@1.28.0': {} + '@pinojs/redact@0.4.0': {} '@prisma/client@6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3)': @@ -2199,6 +3327,65 @@ snapshots: dependencies: '@prisma/debug': 6.19.2 + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + + '@pulumi/pulumi@3.228.0(typescript@5.9.3)': + dependencies: + '@grpc/grpc-js': 1.14.3 + '@logdna/tail-file': 2.2.0 + '@npmcli/arborist': 9.4.2 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/exporter-trace-otlp-grpc': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-zipkin': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-grpc': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-node': 1.30.1(@opentelemetry/api@1.9.1) + '@types/google-protobuf': 3.15.12 + '@types/semver': 7.7.1 + '@types/tmp': 0.2.6 + execa: 5.1.1 + fdir: 6.5.0(picomatch@3.0.2) + google-protobuf: 3.21.4 + got: 11.8.6 + ini: 2.0.0 + js-yaml: 3.14.2 + minimist: 1.2.8 + normalize-package-data: 6.0.2 + package-directory: 8.2.0 + picomatch: 3.0.2 + require-from-string: 2.0.2 + semver: 7.7.4 + source-map-support: 0.5.21 + tmp: 0.2.5 + upath: 1.2.0 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true @@ -2276,6 +3463,40 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@sigstore/bundle@4.0.0': + dependencies: + '@sigstore/protobuf-specs': 0.5.0 + + '@sigstore/core@3.2.0': {} + + '@sigstore/protobuf-specs@0.5.0': {} + + '@sigstore/sign@4.1.1': + dependencies: + '@gar/promise-retry': 1.0.3 + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.0 + make-fetch-happen: 15.0.5 + proc-log: 6.1.0 + transitivePeerDependencies: + - supports-color + + '@sigstore/tuf@4.0.2': + dependencies: + '@sigstore/protobuf-specs': 0.5.0 + tuf-js: 4.1.0 + transitivePeerDependencies: + - supports-color + + '@sigstore/verify@3.1.0': + dependencies: + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.0 + + '@sindresorhus/is@4.6.0': {} + '@sindresorhus/merge-streams@4.0.0': {} '@so-ric/colorspace@1.1.6': @@ -2285,6 +3506,28 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@tufjs/canonical-json@2.0.0': {} + + '@tufjs/models@4.1.0': + dependencies: + '@tufjs/canonical-json': 2.0.0 + minimatch: 10.2.4 + + '@types/bcryptjs@3.0.0': + dependencies: + bcryptjs: 3.0.3 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.2.0 + '@types/keyv': 3.1.4 + '@types/node': 22.19.15 + '@types/responselike': 1.0.3 + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -2296,10 +3539,18 @@ snapshots: '@types/estree@1.0.8': {} + '@types/google-protobuf@3.15.12': {} + + '@types/http-cache-semantics@4.2.0': {} + '@types/js-yaml@4.0.9': {} '@types/json-schema@7.0.15': {} + '@types/keyv@3.1.4': + dependencies: + '@types/node': 22.19.15 + '@types/node-fetch@2.6.13': dependencies: '@types/node': 22.19.15 @@ -2313,10 +3564,20 @@ snapshots: dependencies: undici-types: 7.16.0 + '@types/responselike@1.0.3': + dependencies: + '@types/node': 22.19.15 + + '@types/semver@7.7.1': {} + + '@types/shimmer@1.2.0': {} + '@types/stream-buffers@3.0.8': dependencies: '@types/node': 22.19.15 + '@types/tmp@0.2.6': {} + '@types/triple-beam@1.3.5': {} '@types/ws@8.18.1': @@ -2456,8 +3717,14 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 + abbrev@4.0.0: {} + abstract-logging@2.0.1: {} + acorn-import-attributes@1.9.5(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -2484,6 +3751,16 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} assertion-error@2.0.1: {} @@ -2536,10 +3813,22 @@ snapshots: dependencies: bare-path: 3.0.0 + bcryptjs@3.0.3: {} + + bin-links@6.0.0: + dependencies: + cmd-shim: 8.0.0 + npm-normalize-package-bin: 5.0.0 + proc-log: 6.1.0 + read-cmd-shim: 6.0.0 + write-file-atomic: 7.0.1 + brace-expansion@5.0.4: dependencies: balanced-match: 4.0.4 + buffer-from@1.1.2: {} + c12@3.1.0: dependencies: chokidar: 4.0.3 @@ -2557,6 +3846,31 @@ snapshots: cac@6.7.14: {} + cacache@20.0.4: + dependencies: + '@npmcli/fs': 5.0.0 + fs-minipass: 3.0.3 + glob: 13.0.6 + lru-cache: 11.2.7 + minipass: 7.1.3 + minipass-collect: 2.0.1 + minipass-flush: 1.0.7 + minipass-pipeline: 1.2.4 + p-map: 7.0.4 + ssri: 13.0.1 + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -2576,16 +3890,38 @@ snapshots: dependencies: readdirp: 4.1.2 + chownr@3.0.0: {} + citty@0.1.6: dependencies: consola: 3.4.2 citty@0.2.1: {} + cjs-module-lexer@1.4.3: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + cmd-shim@8.0.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + color-convert@3.1.3: dependencies: color-name: 2.1.0 + color-name@1.1.4: {} + color-name@2.1.0: {} color-string@2.1.4: @@ -2603,6 +3939,8 @@ snapshots: commander@13.1.0: {} + common-ancestor-path@2.0.0: {} + confbox@0.2.4: {} consola@3.4.2: {} @@ -2619,16 +3957,24 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cssesc@3.0.0: {} + debug@4.4.3: dependencies: ms: 2.1.3 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + deep-eql@5.0.2: {} deep-is@0.1.4: {} deepmerge-ts@7.1.5: {} + defer-to-connect@2.0.1: {} + defu@6.1.4: {} delayed-stream@1.0.0: {} @@ -2659,6 +4005,8 @@ snapshots: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 + emoji-regex@8.0.0: {} + empathic@2.0.0: {} enabled@2.0.0: {} @@ -2667,6 +4015,8 @@ snapshots: dependencies: once: 1.4.0 + env-paths@2.2.1: {} + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -2713,6 +4063,8 @@ snapshots: '@esbuild/win32-ia32': 0.27.4 '@esbuild/win32-x64': 0.27.4 + escalade@3.2.0: {} + escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} @@ -2775,6 +4127,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 5.0.1 + esprima@4.0.1: {} + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -2797,6 +4151,18 @@ snapshots: transitivePeerDependencies: - bare-abort-controller + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + execa@9.6.1: dependencies: '@sindresorhus/merge-streams': 4.0.0 @@ -2814,6 +4180,8 @@ snapshots: expect-type@1.3.0: {} + exponential-backoff@3.1.3: {} + exsolve@1.0.8: {} fast-check@3.23.2: @@ -2869,6 +4237,10 @@ snapshots: dependencies: reusify: 1.1.0 + fdir@6.5.0(picomatch@3.0.2): + optionalDependencies: + picomatch: 3.0.2 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -2893,6 +4265,8 @@ snapshots: fast-querystring: 1.1.2 safe-regex2: 5.1.0 + find-up-simple@1.0.1: {} + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -2920,11 +4294,17 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + fs-minipass@3.0.3: + dependencies: + minipass: 7.1.3 + fsevents@2.3.3: optional: true function-bind@1.1.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2943,6 +4323,12 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + + get-stream@6.0.1: {} + get-stream@9.0.1: dependencies: '@sec-ant/readable-stream': 0.4.1 @@ -2980,8 +4366,26 @@ snapshots: minipass: 7.1.3 path-scurry: 2.0.2 + google-protobuf@3.21.4: {} + gopd@1.2.0: {} + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graceful-fs@4.2.11: {} + has-symbols@1.1.0: {} has-tostringtag@1.0.2: @@ -2992,8 +4396,18 @@ snapshots: dependencies: function-bind: 1.1.2 + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + + hosted-git-info@9.0.2: + dependencies: + lru-cache: 11.2.7 + hpagent@1.2.0: {} + http-cache-semantics@4.2.0: {} + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -3002,22 +4416,69 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + human-signals@8.0.1: {} + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + optional: true + + ignore-walk@8.0.0: + dependencies: + minimatch: 10.2.4 + ignore@5.3.2: {} ignore@7.0.5: {} + import-in-the-middle@1.15.0: + dependencies: + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + cjs-module-lexer: 1.4.3 + module-details-from-path: 1.0.4 + imurmurhash@0.1.4: {} inherits@2.0.4: {} + ini@2.0.0: {} + + ini@6.0.0: {} + ip-address@10.1.0: {} ipaddr.js@2.3.0: {} + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -3032,6 +4493,8 @@ snapshots: isexe@2.0.0: {} + isexe@4.0.0: {} + isomorphic-ws@5.0.0(ws@8.19.0): dependencies: ws: 8.19.0 @@ -3046,6 +4509,11 @@ snapshots: js-tokens@9.0.1: {} + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -3054,6 +4522,8 @@ snapshots: json-buffer@3.0.1: {} + json-parse-even-better-errors@5.0.0: {} + json-schema-ref-resolver@3.0.0: dependencies: dequal: 2.0.3 @@ -3064,12 +4534,20 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-nice@1.1.4: {} + + jsonparse@1.3.1: {} + jsonpath-plus@10.4.0: dependencies: '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) '@jsep-plugin/regex': 1.0.4(jsep@1.4.0) jsep: 1.4.0 + just-diff-apply@5.5.0: {} + + just-diff@6.0.2: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -3091,6 +4569,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + logform@2.7.0: dependencies: '@colors/colors': 1.6.0 @@ -3100,16 +4580,41 @@ snapshots: safe-stable-stringify: 2.5.0 triple-beam: 1.4.1 + long@5.3.2: {} + loupe@3.2.1: {} + lowercase-keys@2.0.0: {} + + lru-cache@10.4.3: {} + lru-cache@11.2.7: {} magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + make-fetch-happen@15.0.5: + dependencies: + '@gar/promise-retry': 1.0.3 + '@npmcli/agent': 4.0.0 + '@npmcli/redact': 4.0.0 + cacache: 20.0.4 + http-cache-semantics: 4.2.0 + minipass: 7.1.3 + minipass-fetch: 5.0.2 + minipass-flush: 1.0.7 + minipass-pipeline: 1.2.4 + negotiator: 1.0.0 + proc-log: 6.1.0 + ssri: 13.0.1 + transitivePeerDependencies: + - supports-color + math-intrinsics@1.1.0: {} + merge-stream@2.0.0: {} + mime-db@1.52.0: {} mime-types@2.1.35: @@ -3118,12 +4623,54 @@ snapshots: mime@3.0.0: {} + mimic-fn@2.1.0: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + minimatch@10.2.4: dependencies: brace-expansion: 5.0.4 + minimist@1.2.8: {} + + minipass-collect@2.0.1: + dependencies: + minipass: 7.1.3 + + minipass-fetch@5.0.2: + dependencies: + minipass: 7.1.3 + minipass-sized: 2.0.0 + minizlib: 3.1.0 + optionalDependencies: + iconv-lite: 0.7.2 + + minipass-flush@1.0.7: + dependencies: + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass-sized@2.0.0: + dependencies: + minipass: 7.1.3 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + minipass@7.1.3: {} + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + module-details-from-path@1.0.4: {} + moment@2.30.1: {} ms@2.1.3: {} @@ -3132,12 +4679,87 @@ snapshots: natural-compare@1.4.0: {} + negotiator@1.0.0: {} + node-fetch-native@1.6.7: {} node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-gyp@12.2.0: + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + graceful-fs: 4.2.11 + make-fetch-happen: 15.0.5 + nopt: 9.0.0 + proc-log: 6.1.0 + semver: 7.7.4 + tar: 7.5.13 + tinyglobby: 0.2.15 + which: 6.0.1 + transitivePeerDependencies: + - supports-color + + nopt@9.0.0: + dependencies: + abbrev: 4.0.0 + + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.7.4 + validate-npm-package-license: 3.0.4 + + normalize-url@6.1.0: {} + + npm-bundled@5.0.0: + dependencies: + npm-normalize-package-bin: 5.0.0 + + npm-install-checks@8.0.0: + dependencies: + semver: 7.7.4 + + npm-normalize-package-bin@5.0.0: {} + + npm-package-arg@13.0.2: + dependencies: + hosted-git-info: 9.0.2 + proc-log: 6.1.0 + semver: 7.7.4 + validate-npm-package-name: 7.0.2 + + npm-packlist@10.0.4: + dependencies: + ignore-walk: 8.0.0 + proc-log: 6.1.0 + + npm-pick-manifest@11.0.3: + dependencies: + npm-install-checks: 8.0.0 + npm-normalize-package-bin: 5.0.0 + npm-package-arg: 13.0.2 + semver: 7.7.4 + + npm-registry-fetch@19.1.1: + dependencies: + '@npmcli/redact': 4.0.0 + jsonparse: 1.3.1 + make-fetch-happen: 15.0.5 + minipass: 7.1.3 + minipass-fetch: 5.0.2 + minizlib: 3.1.0 + npm-package-arg: 13.0.2 + proc-log: 6.1.0 + transitivePeerDependencies: + - supports-color + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + npm-run-path@6.0.0: dependencies: path-key: 4.0.0 @@ -3165,6 +4787,10 @@ snapshots: dependencies: fn.name: 1.1.0 + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + openid-client@6.8.2: dependencies: jose: 6.2.2 @@ -3179,6 +4805,8 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + p-cancelable@2.1.1: {} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -3187,8 +4815,42 @@ snapshots: dependencies: p-limit: 3.1.0 + p-map@7.0.4: {} + + package-directory@8.2.0: + dependencies: + find-up-simple: 1.0.1 + package-json-from-dist@1.0.1: {} + pacote@21.5.0: + dependencies: + '@gar/promise-retry': 1.0.3 + '@npmcli/git': 7.0.2 + '@npmcli/installed-package-contents': 4.0.0 + '@npmcli/package-json': 7.0.5 + '@npmcli/promise-spawn': 9.0.1 + '@npmcli/run-script': 10.0.4 + cacache: 20.0.4 + fs-minipass: 3.0.3 + minipass: 7.1.3 + npm-package-arg: 13.0.2 + npm-packlist: 10.0.4 + npm-pick-manifest: 11.0.3 + npm-registry-fetch: 19.1.1 + proc-log: 6.1.0 + sigstore: 4.1.0 + ssri: 13.0.1 + tar: 7.5.13 + transitivePeerDependencies: + - supports-color + + parse-conflict-json@5.0.1: + dependencies: + json-parse-even-better-errors: 5.0.0 + just-diff: 6.0.2 + just-diff-apply: 5.5.0 + parse-ms@4.0.0: {} path-exists@4.0.0: {} @@ -3197,6 +4859,8 @@ snapshots: path-key@4.0.0: {} + path-parse@1.0.7: {} + path-scurry@2.0.2: dependencies: lru-cache: 11.2.7 @@ -3210,6 +4874,8 @@ snapshots: picocolors@1.1.1: {} + picomatch@3.0.2: {} + picomatch@4.0.3: {} pino-abstract-transport@3.0.0: @@ -3238,6 +4904,11 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss@8.5.8: dependencies: nanoid: 3.3.11 @@ -3259,10 +4930,33 @@ snapshots: transitivePeerDependencies: - magicast + proc-log@6.1.0: {} + process-warning@4.0.1: {} process-warning@5.0.0: {} + proggy@4.0.0: {} + + promise-all-reject-late@1.0.1: {} + + promise-call-limit@3.0.2: {} + + protobufjs@7.5.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 22.19.15 + long: 5.3.2 + pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -3274,11 +4968,15 @@ snapshots: quick-format-unescaped@4.0.4: {} + quick-lru@5.1.1: {} + rc9@2.1.2: dependencies: defu: 6.1.4 destr: 2.0.5 + read-cmd-shim@6.0.0: {} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -3289,10 +4987,32 @@ snapshots: real-require@0.2.0: {} + require-directory@2.1.1: {} + require-from-string@2.0.2: {} + require-in-the-middle@7.5.2: + dependencies: + debug: 4.4.3 + module-details-from-path: 1.0.4 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + resolve-alpn@1.2.1: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + ret@0.5.0: {} reusify@1.1.0: {} @@ -3345,6 +5065,9 @@ snapshots: safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: + optional: true + secure-json-parse@4.1.0: {} semver@7.7.4: {} @@ -3359,10 +5082,25 @@ snapshots: shebang-regex@3.0.0: {} + shimmer@1.2.1: {} + siginfo@2.0.0: {} + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} + sigstore@4.1.0: + dependencies: + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.0 + '@sigstore/sign': 4.1.1 + '@sigstore/tuf': 4.0.2 + '@sigstore/verify': 3.1.0 + transitivePeerDependencies: + - supports-color + smart-buffer@4.2.0: {} socks-proxy-agent@8.0.5: @@ -3384,8 +5122,40 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.23 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + + spdx-license-ids@3.0.23: {} + split2@4.2.0: {} + sprintf-js@1.0.3: {} + + ssri@13.0.1: + dependencies: + minipass: 7.1.3 + stack-trace@0.0.10: {} stackback@0.0.2: {} @@ -3407,16 +5177,30 @@ snapshots: - bare-abort-controller - react-native-b4a + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-final-newline@2.0.0: {} + strip-final-newline@4.0.0: {} strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 + supports-preserve-symlinks-flag@1.0.0: {} + tar-fs@3.1.2: dependencies: pump: 3.0.4 @@ -3440,6 +5224,14 @@ snapshots: - bare-buffer - react-native-b4a + tar@7.5.13: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + teex@1.0.1: dependencies: streamx: 2.25.0 @@ -3476,12 +5268,16 @@ snapshots: tinyspy@4.0.4: {} + tmp@0.2.5: {} + toad-cache@3.7.0: {} toidentifier@1.0.1: {} tr46@0.0.3: {} + treeverse@3.0.0: {} + triple-beam@1.4.1: {} ts-api-utils@2.4.0(typescript@5.9.3): @@ -3495,6 +5291,14 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tuf-js@4.1.0: + dependencies: + '@tufjs/models': 4.1.0 + debug: 4.4.3 + make-fetch-happen: 15.0.5 + transitivePeerDependencies: + - supports-color + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -3507,12 +5311,21 @@ snapshots: unicorn-magic@0.3.0: {} + upath@1.2.0: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 util-deprecate@1.0.2: {} + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + validate-npm-package-name@7.0.2: {} + vite-node@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(tsx@4.21.0): dependencies: cac: 6.7.14 @@ -3589,6 +5402,8 @@ snapshots: - tsx - yaml + walk-up-path@4.0.0: {} + webidl-conversions@3.0.1: {} whatwg-url@5.0.0: @@ -3600,6 +5415,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@6.0.1: + dependencies: + isexe: 4.0.0 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -3635,10 +5454,38 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrappy@1.0.2: {} + write-file-atomic@7.0.1: + dependencies: + signal-exit: 4.1.0 + ws@8.19.0: {} + y18n@5.0.8: {} + + yallist@4.0.0: {} + + yallist@5.0.0: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} yoctocolors@2.1.2: {} diff --git a/bastion/src/cli/src/commands/serve.ts b/bastion/src/cli/src/commands/serve.ts index a435c92..b3d905d 100644 --- a/bastion/src/cli/src/commands/serve.ts +++ b/bastion/src/cli/src/commands/serve.ts @@ -11,7 +11,7 @@ export function registerStartCommand(parent: Command): void { .command("start") .description("Start the bastion server (HTTP + dnsmasq PXE)") .option("--port ", "HTTP port", "8080") - .option("--dir ", "Bastion data directory", "/tmp/lab-bastion") + .option("--dir ", "Bastion data directory", process.env["BASTION_DIR"] ?? "/tmp/lab-bastion") .option("--domain ", "Internal domain for hostnames", "ad.itaz.eu") .option("--dhcp-mode ", "DHCP mode: proxy or full", "proxy") .option("--fedora ", "Fedora version", "43") diff --git a/bastion/src/cli/src/commands/stop.ts b/bastion/src/cli/src/commands/stop.ts index b1ed687..67ed6d3 100644 --- a/bastion/src/cli/src/commands/stop.ts +++ b/bastion/src/cli/src/commands/stop.ts @@ -8,7 +8,7 @@ export function registerStopCommand(parent: Command): void { parent .command("stop") .description("Stop a running bastion server") - .option("--dir ", "Bastion data directory", "/tmp/lab-bastion") + .option("--dir ", "Bastion data directory", process.env["BASTION_DIR"] ?? "/tmp/lab-bastion") .action((opts: { dir: string }) => { const pidFile = `${opts.dir}/bastion.pid`; diff --git a/bastion/src/core/package.json b/bastion/src/core/package.json new file mode 100644 index 0000000..8a121fc --- /dev/null +++ b/bastion/src/core/package.json @@ -0,0 +1,23 @@ +{ + "name": "@lab/core", + "version": "0.1.0", + "private": true, + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsc --build", + "clean": "rimraf dist", + "test": "vitest", + "test:run": "vitest run" + }, + "dependencies": { + "@pulumi/pulumi": "^3.0.0" + } +} diff --git a/bastion/src/core/src/audit.ts b/bastion/src/core/src/audit.ts new file mode 100644 index 0000000..426bd56 --- /dev/null +++ b/bastion/src/core/src/audit.ts @@ -0,0 +1,75 @@ +// Audit event types for the labctl platform. +// Every mutation is tracked with correlation IDs for causal chains. + +export type AuditEventKind = + | "resource_created" + | "resource_updated" + | "resource_deleted" + | "resource_state_change" + | "plan_generated" + | "apply_started" + | "apply_step" + | "apply_completed" + | "driver_translate" + | "driver_execute" + | "driver_error" + | "fleet_discovery" + | "fleet_classification" + | "fleet_approval" + | "fleet_auto_approve" + | "pipeline_started" + | "pipeline_step_started" + | "pipeline_step_completed" + | "pipeline_completed" + | "deploy_started" + | "deploy_completed" + | "deploy_failed" + | "drift_detected" + | "drift_corrected" + | "sync_triggered" + | "sync_completed" + | "auth_login" + | "auth_logout" + | "auth_bootstrap" + | "rbac_decision" + | "impersonation" + | "server_started" + | "controller_started" + | "agent_connected" + | "agent_disconnected" + | "bastion_registered"; + +export type AuditSource = + | "cli" + | "labd" + | "agent" + | "driver" + | "fleet-controller" + | "sync-controller"; + +export type AuditResult = "success" | "failure" | "denied" | "skipped"; + +export interface AuditEvent { + id: string; + timestamp: Date; + eventKind: AuditEventKind; + source: AuditSource; + verified: boolean; + + userId?: string; + userName?: string; + sessionId?: string; + environmentName?: string; + accountName?: string; + + resourceKind?: string; + resourceName?: string; + + correlationId: string; + parentEventId?: string; + + details: Record; + result: AuditResult; + error?: string; + durationMs?: number; +} diff --git a/bastion/src/core/src/auth.ts b/bastion/src/core/src/auth.ts new file mode 100644 index 0000000..6f4a5bd --- /dev/null +++ b/bastion/src/core/src/auth.ts @@ -0,0 +1,50 @@ +// Auth types for the labctl platform. +// Bearer token auth for CLI/SDK. mTLS stays for agent/bastion. + +export type UserRole = "USER" | "ADMIN"; + +export interface User { + id: string; + email: string; + name?: string; + role: UserRole; + createdAt: Date; +} + +export interface Session { + id: string; + userId: string; + token: string; + expiresAt: Date; + createdAt: Date; +} + +export interface Group { + id: string; + name: string; + description?: string; +} + +export type SubjectKind = "User" | "Group" | "ServiceAccount"; + +export interface RoleBinding { + role: "view" | "edit" | "create" | "delete" | "run" | "admin"; + resource: string; + name?: string; + environment?: string; + action?: string; +} + +export interface RbacSubject { + kind: SubjectKind; + name: string; +} + +export interface RbacDefinition { + id: string; + name: string; + subjects: RbacSubject[]; + roleBindings: RoleBinding[]; + createdAt: Date; + updatedAt: Date; +} diff --git a/bastion/src/core/src/environment.ts b/bastion/src/core/src/environment.ts new file mode 100644 index 0000000..d32daa2 --- /dev/null +++ b/bastion/src/core/src/environment.ts @@ -0,0 +1,24 @@ +// Environment and Account types. +// An Environment is a logical boundary (production, staging, dev). +// An Account is a configured driver instance with credentials. + +export interface Environment { + id: string; + name: string; + status: "active" | "archived"; + createdAt: Date; +} + +export interface Account { + id: string; + name: string; + driver: string; + config: Record; + createdAt: Date; +} + +export interface Binding { + id: string; + environmentId: string; + accountId: string; +} diff --git a/bastion/src/core/src/index.ts b/bastion/src/core/src/index.ts new file mode 100644 index 0000000..4f5bd29 --- /dev/null +++ b/bastion/src/core/src/index.ts @@ -0,0 +1,9 @@ +// @lab/core — foundation types for the labctl platform. +// Phase 1 stub: resource types, auth types, audit types, Output. +// Phase 5 adds: CompositeResource, evaluator integration, full SDK. + +export * from "./resource.js"; +export * from "./environment.js"; +export * from "./audit.js"; +export * from "./auth.js"; +export { Output, output, all, interpolate, secret } from "./output.js"; diff --git a/bastion/src/core/src/output.ts b/bastion/src/core/src/output.ts new file mode 100644 index 0000000..2a711d5 --- /dev/null +++ b/bastion/src/core/src/output.ts @@ -0,0 +1,5 @@ +// Re-export Pulumi's Output type for use across the platform. +// Cloud drivers use this for future values (endpoints, IPs, kubeconfigs). +// Phase 1: type re-export only. Phase 5 adds full evaluator integration. + +export { Output, output, all, interpolate, secret } from "@pulumi/pulumi"; diff --git a/bastion/src/core/src/resource.ts b/bastion/src/core/src/resource.ts new file mode 100644 index 0000000..d735528 --- /dev/null +++ b/bastion/src/core/src/resource.ts @@ -0,0 +1,83 @@ +// Core resource types for the labctl platform. +// Every managed thing (Server, Database, App, Cluster) is a Resource. + +export type ResourceOrigin = "file" | "cli" | "fleet" | "imported"; +export type ResourceManagedBy = "gitops" | "manual" | "auto"; + +export type ResourceStatus = + | "pending" + | "creating" + | "ready" + | "updating" + | "deleting" + | "error" + | "unknown"; + +export interface ResourceMetadata { + kind: string; + name: string; + environmentId: string; + accountId: string; + origin: ResourceOrigin; + managedBy: ResourceManagedBy; + sourceRef?: string; +} + +export interface ResourceState { + status: ResourceStatus; + message?: string; + lastReconciled?: Date; + platformRef?: string; +} + +export interface Resource> { + id: string; + metadata: ResourceMetadata; + desiredSpec: TSpec; + actualSpec?: TSpec; + state: ResourceState; + createdAt: Date; + updatedAt: Date; +} + +// Well-known resource kinds. Drivers register additional kinds. +export const RESOURCE_KINDS = { + SERVER: "server", + DATABASE: "database", + CACHE: "cache", + CLUSTER: "cluster", + APP: "app", + SERVICE: "service", + CRONJOB: "cronjob", + NETWORK: "network", + LOADBALANCER: "loadbalancer", + DNSZONE: "dnszone", + CERTIFICATE: "certificate", + OBJECTSTORE: "objectstore", + QUEUE: "queue", + SECRET: "secret", + FLEET: "fleet", +} as const; + +export type ResourceKind = (typeof RESOURCE_KINDS)[keyof typeof RESOURCE_KINDS]; + +// Resource aliases for CLI (kubectl-style shortnames) +export const RESOURCE_ALIASES: Record = { + srv: "server", + db: "database", + cl: "cluster", + svc: "service", + cj: "cronjob", + lb: "loadbalancer", + dns: "dnszone", + cert: "certificate", + os: "objectstore", + mq: "queue", + sec: "secret", + fl: "fleet", +}; + +export function resolveResourceKind(input: string): string { + const lower = input.toLowerCase(); + return RESOURCE_ALIASES[lower] ?? lower; +} diff --git a/bastion/src/core/tsconfig.json b/bastion/src/core/tsconfig.json new file mode 100644 index 0000000..df59da5 --- /dev/null +++ b/bastion/src/core/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*.ts"] +} diff --git a/bastion/src/labd/package.json b/bastion/src/labd/package.json index 25f2f4c..58d25dc 100644 --- a/bastion/src/labd/package.json +++ b/bastion/src/labd/package.json @@ -26,8 +26,10 @@ "dependencies": { "@fastify/rate-limit": "^10.3.0", "@fastify/websocket": "^11.0.2", + "@lab/core": "workspace:^", "@lab/shared": "workspace:*", "@prisma/client": "^6.9.0", + "bcryptjs": "^3.0.3", "fastify": "^5.3.3", "winston": "^3.17.0", "ws": "^8.19.0", @@ -37,6 +39,7 @@ "seed": "tsx prisma/seed.ts" }, "devDependencies": { + "@types/bcryptjs": "^3.0.0", "@types/node": "^22.14.1", "@types/ws": "^8.18.1", "prisma": "^6.9.0", diff --git a/bastion/src/labd/prisma/schema.prisma b/bastion/src/labd/prisma/schema.prisma index 31a32a2..e2760f8 100644 --- a/bastion/src/labd/prisma/schema.prisma +++ b/bastion/src/labd/prisma/schema.prisma @@ -7,23 +7,241 @@ datasource db { url = env("DATABASE_URL") } +// ── Auth (mcpctl pattern: email/password + bearer token sessions) ── + +model User { + id String @id @default(cuid()) + email String @unique + password String // bcrypt + name String? + role UserRole @default(USER) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + sessions Session[] + auditLogs AuditEvent[] + groups GroupMember[] +} + +enum UserRole { + USER + ADMIN +} + +model Session { + id String @id @default(cuid()) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + token String @unique + expiresAt DateTime + createdAt DateTime @default(now()) + + @@index([userId]) + @@index([token]) +} + +model Group { + id String @id @default(cuid()) + name String @unique + description String? + createdAt DateTime @default(now()) + members GroupMember[] +} + +model GroupMember { + id String @id @default(cuid()) + groupId String + group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([groupId, userId]) +} + +model ServiceAccount { + id String @id @default(cuid()) + name String @unique + token String @unique + createdAt DateTime @default(now()) +} + +// ── RBAC (mcpctl pattern: named definitions with JSON subjects/bindings) ── + +model RbacDefinition { + id String @id @default(cuid()) + name String @unique + subjects Json // [{kind: "User"|"Group"|"ServiceAccount", name: string}] + roleBindings Json // [{role, resource, name?, environment?, action?}] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +// ── Audit (mcpctl pattern: fire-and-forget with correlation IDs) ── + +model AuditEvent { + id String @id @default(cuid()) + timestamp DateTime @default(now()) + eventKind String + source String // cli | labd | agent | driver | fleet-controller | sync-controller + verified Boolean @default(false) + + userId String? + user User? @relation(fields: [userId], references: [id]) + userName String? + sessionId String? + environmentName String? + accountName String? + + resourceKind String? + resourceName String? + + correlationId String + parentEventId String? + + details Json @default("{}") + result String // success | failure | denied | skipped + error String? + durationMs Int? + + @@index([correlationId]) + @@index([eventKind, timestamp]) + @@index([environmentName, timestamp]) + @@index([resourceKind, resourceName]) + @@index([userId, timestamp]) +} + +// ── Core infrastructure ── + +model Environment { + id String @id @default(cuid()) + name String @unique + status String @default("active") // active | archived + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + bindings Binding[] + resources Resource[] +} + +model Account { + id String @id @default(cuid()) + name String @unique + driver String // baremetal-pxe | aws | gcp | kubernetes | ovh + config Json @default("{}") + // Credentials stored in Infisical, referenced by secretPath + secretPath String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + bindings Binding[] + resources Resource[] +} + +model Binding { + id String @id @default(cuid()) + environmentId String + environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade) + accountId String + account Account @relation(fields: [accountId], references: [id], onDelete: Cascade) + + @@unique([environmentId, accountId]) +} + +model Resource { + id String @id @default(cuid()) + kind String + name String + environmentId String + environment Environment @relation(fields: [environmentId], references: [id]) + accountId String + account Account @relation(fields: [accountId], references: [id]) + origin String @default("cli") // file | cli | fleet | imported + managedBy String @default("manual") // gitops | manual | auto + sourceRef String? + desiredSpec Json @default("{}") + actualSpec Json? + platformRef String? + status String @default("pending") // pending | creating | ready | updating | deleting | error + statusMessage String? + lastReconciled DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([kind, name, environmentId]) + @@index([environmentId]) + @@index([accountId]) + @@index([kind, status]) +} + +model Secret { + id String @id @default(cuid()) + name String @unique + // Encrypted data — application-layer encryption as fallback if Infisical unavailable + data Json @default("{}") + version Int @default(1) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +// ── Fleet ── + +model Fleet { + id String @id @default(cuid()) + name String + environmentId String + accountId String + selector Json // fact-matching rules + onboardPipeline Json // step definitions + offboardPipeline Json? + approvalConfig Json? + status String @default("active") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + members FleetMember[] +} + +model FleetMember { + id String @id @default(cuid()) + fleetId String + fleet Fleet @relation(fields: [fleetId], references: [id], onDelete: Cascade) + serverId String + status String // discovered | pending | onboarding | active | offboarding | removed + joinedAt DateTime @default(now()) + + @@index([fleetId]) +} + +// ── Git sources (for sync controller) ── + +model GitSource { + id String @id @default(cuid()) + name String @unique + repo String + branch String @default("main") + path String @default("environments/") + lastSync DateTime? + createdAt DateTime @default(now()) +} + +// ── Existing v1.0 models (kept for bastion/agent compatibility) ── + model Server { - id String @id @default(uuid()) - hostname String @unique - mac String? @unique - cloud String @default("baremetal") - environment String @default("default") - role String @default("worker") - labels Json @default("{}") + id String @id @default(uuid()) + hostname String @unique + mac String? @unique + cloud String @default("baremetal") + environment String @default("default") + role String @default("worker") + labels Json @default("{}") ip String? agentVersion String? - status String @default("unknown") // unknown, online, offline, provisioning + status String @default("unknown") lastHeartbeat DateTime? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt - agent Agent? - auditLogs AuditLog[] + agent Agent? } model Agent { @@ -33,112 +251,29 @@ model Agent { certificatePem String? enrolledAt DateTime @default(now()) lastSeen DateTime? + facts Json? // hardware facts reported by agent @@index([serverId]) } -model User { - id String @id @default(uuid()) - username String @unique - displayName String? - certFingerprint String? @unique - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - roleBindings UserRole[] - auditLogs AuditLog[] -} - -model Role { - id String @id @default(uuid()) - name String @unique - description String? - createdAt DateTime @default(now()) - - permissions Permission[] - userBindings UserRole[] -} - -model Permission { - id String @id @default(uuid()) - roleId String - role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) - type String @default("allow") // allow or deny - action String // read, exec, apply, destroy, manage, admin, kubectl, * - cloud String @default("*") - environment String @default("*") - server String @default("*") - - @@index([roleId]) -} - -model UserRole { - id String @id @default(uuid()) - userId String - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - roleId String - role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) - - @@unique([userId, roleId]) - @@index([userId]) - @@index([roleId]) -} - model JoinToken { id String @id @default(uuid()) token String @unique - type String @default("one-time") // one-time or reusable + type String @default("one-time") label String? - usedBy String? // server hostname that used it + usedBy String? usedAt DateTime? revokedAt DateTime? createdAt DateTime @default(now()) expiresAt DateTime? } -model AuditLog { - id String @id @default(uuid()) - userId String? - user User? @relation(fields: [userId], references: [id]) - serverId String? - server Server? @relation(fields: [serverId], references: [id]) - sessionId String? - action String // exec, kubectl, apply, login, rbac-denied, etc. - resourceType String? // server, cluster, role, app, etc. - resourceName String? - args String? // sanitized command args - result String @default("success") // success, denied, error - durationMs Int? - sourceIp String? - timestamp DateTime @default(now()) - - @@index([userId]) - @@index([serverId]) - @@index([sessionId]) - @@index([timestamp]) - @@index([action]) -} - -model PulumiRun { - id String @id @default(uuid()) - userId String - stackName String - action String // up, preview, destroy - status String @default("pending") // pending, running, succeeded, failed - output String? - startedAt DateTime @default(now()) - completedAt DateTime? - - @@index([userId]) - @@index([stackName]) -} - model Bastion { id String @id @default(uuid()) hostname String @unique network String serverIp String - status String @default("offline") // online, offline + status String @default("offline") lastHeartbeat DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -149,7 +284,7 @@ model Cluster { name String @unique cloud String @default("baremetal") environment String @default("default") - kubeconfigEnc String? // encrypted kubeconfig + kubeconfigEnc String? labels Json @default("{}") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt diff --git a/bastion/src/labd/src/middleware/bearer-auth.ts b/bastion/src/labd/src/middleware/bearer-auth.ts new file mode 100644 index 0000000..0c4f185 --- /dev/null +++ b/bastion/src/labd/src/middleware/bearer-auth.ts @@ -0,0 +1,65 @@ +// Bearer token auth middleware for Fastify. +// Validates Authorization header, resolves user identity, attaches to request. + +import type { FastifyRequest, FastifyReply } from "fastify"; +import type { AuthService } from "../services/auth.js"; + +declare module "fastify" { + interface FastifyRequest { + userId?: string; + userEmail?: string; + userRole?: string; + } +} + +// Paths that don't require authentication +const PUBLIC_PATHS = new Set([ + "/health", + "/api/auth/login", + "/ws/bastion", + "/ws/agent", + "/api/auth/enroll", +]); + +export function createBearerAuthMiddleware(authService: AuthService) { + return async function bearerAuth( + request: FastifyRequest, + reply: FastifyReply, + ): Promise { + // Skip auth for public paths + if (PUBLIC_PATHS.has(request.url.split("?")[0] ?? "")) { + return; + } + + // Skip auth for WebSocket upgrade requests (handled by their own auth) + if (request.headers.upgrade === "websocket") { + return; + } + + const authHeader = request.headers.authorization; + if (!authHeader) { + void reply.code(401).send({ error: "Authorization header required" }); + return; + } + + if (!authHeader.startsWith("Bearer ")) { + void reply.code(401).send({ error: "Invalid authorization format, expected: Bearer " }); + return; + } + + const token = authHeader.slice(7); + if (token.length === 0) { + void reply.code(401).send({ error: "Empty bearer token" }); + return; + } + + try { + const identity = await authService.validateToken(token); + request.userId = identity.userId; + request.userEmail = identity.email; + request.userRole = identity.role; + } catch { + void reply.code(401).send({ error: "Invalid or expired token. Run: labctl login" }); + } + }; +} diff --git a/bastion/src/labd/src/routes/bastions.ts b/bastion/src/labd/src/routes/bastions.ts index 1903534..d77a417 100644 --- a/bastion/src/labd/src/routes/bastions.ts +++ b/bastion/src/labd/src/routes/bastions.ts @@ -84,7 +84,6 @@ export function registerBastionRoutes(app: FastifyInstance, db: DbClient): void app.get("/api/machines", async () => { const live = bastionRegistry.getAggregatedState(); - // Merge DB records for machines not currently in any bastion's live state try { const dbServers = (await db.server.findMany({})) as Array<{ mac: string | null; hostname: string; role: string; ip: string | null; @@ -93,9 +92,49 @@ export function registerBastionRoutes(app: FastifyInstance, db: DbClient): void for (const s of dbServers) { if (!s.mac) continue; const mac = s.mac.toLowerCase(); - // Only add from DB if not already in live state + + // DB knows this machine has been installed at some point if it has a real + // hostname+role (not just product-name-as-hostname and role="unknown"). + // Status alone is unreliable: a rediscovery can re-set it without erasing the + // install identity. If the bastion restarted and lost its installed map, the + // machine will only show up in live.discovered — promote it here so the CLI + // still sees hostname/role/IP. + const dbKnowsInstalled = + s.role !== "unknown" && s.role !== "" && + s.hostname !== "" && s.hostname !== s.mac; + + if (dbKnowsInstalled && !(mac in live.installed) && !(mac in live.install_queue)) { + const hw = live.discovered[mac]; + live.installed[mac] = { + hostname: s.hostname, + role: s.role, + ip: s.ip ?? "", + installed_at: "", + bastionId: hw?.bastionId ?? "db", + ...(hw ? { + product: hw.product, + manufacturer: hw.manufacturer, + cpu_model: hw.cpu_model, + cpu_cores: hw.cpu_cores, + memory_gb: hw.memory_gb, + arch: hw.arch, + } : {}), + }; + delete live.discovered[mac]; + continue; + } + + // Unknown-to-live MAC: fall back to whatever the DB says. if (!(mac in live.discovered) && !(mac in live.install_queue) && !(mac in live.installed)) { - if (s.status === "discovered") { + if (s.status === "online" || s.status === "offline") { + live.installed[mac] = { + hostname: s.hostname, + role: s.role, + ip: s.ip ?? "", + installed_at: "", + bastionId: "db", + }; + } else { live.discovered[mac] = { mac, product: String(s.labels?.product ?? "unknown"), @@ -112,14 +151,6 @@ export function registerBastionRoutes(app: FastifyInstance, db: DbClient): void last_seen: "", bastionId: "db", }; - } else if (s.status === "online" || s.status === "offline") { - live.installed[mac] = { - hostname: s.hostname, - role: s.role, - ip: s.ip ?? "", - installed_at: "", - bastionId: "db", - }; } } } diff --git a/bastion/src/labd/src/routes/environments.ts b/bastion/src/labd/src/routes/environments.ts new file mode 100644 index 0000000..9cb17e5 --- /dev/null +++ b/bastion/src/labd/src/routes/environments.ts @@ -0,0 +1,191 @@ +// Environment and Account management routes. +// GET/POST /api/environments — list/create environments +// GET/POST /api/accounts — list/create accounts +// POST /api/accounts/bind — bind account to environment +// GET /api/bindings — list bindings + +import type { FastifyInstance } from "fastify"; +import type { PrismaClient, Prisma } from "@prisma/client"; +import type { RbacService } from "../services/rbac.js"; +import type { AuditService } from "../services/audit.js"; + +export function registerEnvironmentRoutes( + app: FastifyInstance, + db: PrismaClient, + rbacService: RbacService, + auditService: AuditService, +): void { + // List environments + app.get("/api/environments", async (_request, reply) => { + const envs = await db.environment.findMany({ orderBy: { name: "asc" } }); + return reply.send(envs); + }); + + // Create environment + app.post<{ + Body: { name?: string }; + }>("/api/environments", async (request, reply) => { + const { name } = request.body ?? {}; + if (!name) { + return reply.code(400).send({ error: "name is required" }); + } + + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "admin", + resource: "environments", + }); + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + try { + const env = await db.environment.create({ data: { name } }); + auditService.emit({ + eventKind: "resource_created", + source: "labd", + verified: true, + userId: request.userId ?? null, + resourceKind: "environment", + resourceName: name, + result: "success", + }); + return reply.code(201).send(env); + } catch (err) { + if (err instanceof Error && err.message.includes("Unique constraint")) { + return reply.code(409).send({ error: `Environment '${name}' already exists` }); + } + throw err; + } + }); + + // List accounts + app.get("/api/accounts", async (_request, reply) => { + const accounts = await db.account.findMany({ + orderBy: { name: "asc" }, + select: { id: true, name: true, driver: true, config: true, createdAt: true, updatedAt: true }, + }); + return reply.send(accounts); + }); + + // Create account + app.post<{ + Body: { name?: string; driver?: string; config?: Record }; + }>("/api/accounts", async (request, reply) => { + const { name, driver, config } = request.body ?? {}; + if (!name || !driver) { + return reply.code(400).send({ error: "name and driver are required" }); + } + + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "admin", + resource: "accounts", + }); + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + try { + const account = await db.account.create({ + data: { name, driver, config: (config ?? {}) as Prisma.InputJsonValue }, + }); + auditService.emit({ + eventKind: "resource_created", + source: "labd", + verified: true, + userId: request.userId ?? null, + resourceKind: "account", + resourceName: name, + result: "success", + details: { driver }, + }); + return reply.code(201).send(account); + } catch (err) { + if (err instanceof Error && err.message.includes("Unique constraint")) { + return reply.code(409).send({ error: `Account '${name}' already exists` }); + } + throw err; + } + }); + + // Bind account to environment + app.post<{ + Body: { environmentId?: string; accountId?: string }; + }>("/api/accounts/bind", async (request, reply) => { + const { environmentId, accountId } = request.body ?? {}; + if (!environmentId || !accountId) { + return reply.code(400).send({ error: "environmentId and accountId are required" }); + } + + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "admin", + resource: "accounts", + }); + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + try { + const binding = await db.binding.create({ + data: { environmentId, accountId }, + }); + return reply.code(201).send(binding); + } catch (err) { + if (err instanceof Error && err.message.includes("Unique constraint")) { + return reply.code(409).send({ error: "This account is already bound to this environment" }); + } + throw err; + } + }); + + // List bindings + app.get("/api/bindings", async (_request, reply) => { + const bindings = await db.binding.findMany({ + include: { environment: true, account: true }, + }); + return reply.send(bindings); + }); + + // Audit event query + app.get<{ + Querystring: { + last?: string; + kind?: string; + env?: string; + correlation?: string; + limit?: string; + }; + }>("/api/events", async (request, reply) => { + const { last, kind, env, correlation, limit } = request.query as { last?: string; kind?: string; env?: string; correlation?: string; limit?: string }; + + const where: Record = {}; + + if (last) { + const match = last.match(/^(\d+)(h|d|m)$/); + if (match) { + const [, num, unit] = match; + const ms = { h: 3_600_000, d: 86_400_000, m: 60_000 }[unit!]!; + where.timestamp = { gte: new Date(Date.now() - parseInt(num!) * ms) }; + } + } + if (kind) where.eventKind = kind; + if (env) where.environmentName = env; + if (correlation) where.correlationId = correlation; + + const events = await db.auditEvent.findMany({ + where, + orderBy: { timestamp: "desc" }, + take: Math.min(parseInt(limit ?? "100"), 500), + }); + + return reply.send(events); + }); +} diff --git a/bastion/src/labd/src/routes/resources.ts b/bastion/src/labd/src/routes/resources.ts new file mode 100644 index 0000000..099cf88 --- /dev/null +++ b/bastion/src/labd/src/routes/resources.ts @@ -0,0 +1,196 @@ +// Resource CRUD routes with RBAC enforcement. +// GET /api/resources — list (filtered by RBAC scope) +// GET /api/resources/:id — get +// POST /api/resources — create +// PUT /api/resources/:id — update +// DELETE /api/resources/:id — delete (marks as deleting) + +import type { FastifyInstance } from "fastify"; +import type { ResourceStore, CreateResourceInput } from "../services/resource-store.js"; +import type { RbacService } from "../services/rbac.js"; +import type { AuditService } from "../services/audit.js"; +import { resolveResourceKind } from "@lab/core"; + +export function registerResourceRoutes( + app: FastifyInstance, + resourceStore: ResourceStore, + rbacService: RbacService, + auditService: AuditService, +): void { + // List resources (filtered by kind, environment, status) + app.get<{ + Querystring: { kind?: string; environment?: string; status?: string }; + }>("/api/resources", async (request, reply) => { + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "view", + resource: request.query.kind ? resolveResourceKind(request.query.kind) : undefined, + }); + + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + const resources = await resourceStore.list({ + kind: request.query.kind ? resolveResourceKind(request.query.kind) : undefined, + environmentId: request.query.environment, + status: request.query.status, + }); + + return reply.send(resources); + }); + + // Get single resource + app.get<{ + Params: { id: string }; + }>("/api/resources/:id", async (request, reply) => { + const resource = await resourceStore.get(request.params.id); + if (!resource) { + return reply.code(404).send({ error: "Resource not found" }); + } + + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "view", + resource: resource.kind, + name: resource.name, + }); + + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + return reply.send(resource); + }); + + // Create resource + app.post<{ + Body: CreateResourceInput; + }>("/api/resources", async (request, reply) => { + const input = request.body; + if (!input?.kind || !input?.name || !input?.environmentId || !input?.accountId) { + return reply.code(400).send({ error: "kind, name, environmentId, and accountId are required" }); + } + + const kind = resolveResourceKind(input.kind); + + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "create", + resource: kind, + }); + + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + const correlationId = auditService.createCorrelation(); + + try { + const resource = await resourceStore.create({ ...input, kind }); + + auditService.emit({ + eventKind: "resource_created", + source: "labd", + verified: true, + userId: request.userId ?? null, + userName: request.userEmail ?? null, + resourceKind: kind, + resourceName: input.name, + correlationId, + result: "success", + }); + + return reply.code(201).send(resource); + } catch (err) { + // Prisma unique constraint violation + if (err instanceof Error && err.message.includes("Unique constraint")) { + return reply.code(409).send({ error: `Resource ${kind}/${input.name} already exists in this environment` }); + } + throw err; + } + }); + + // Update resource + app.put<{ + Params: { id: string }; + Body: { desiredSpec?: Record; status?: string }; + }>("/api/resources/:id", async (request, reply) => { + const resource = await resourceStore.get(request.params.id); + if (!resource) { + return reply.code(404).send({ error: "Resource not found" }); + } + + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "edit", + resource: resource.kind, + name: resource.name, + }); + + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + const updated = await resourceStore.update(request.params.id, request.body); + + auditService.emit({ + eventKind: "resource_updated", + source: "labd", + verified: true, + userId: request.userId ?? null, + userName: request.userEmail ?? null, + resourceKind: resource.kind, + resourceName: resource.name, + result: "success", + }); + + return reply.send(updated); + }); + + // Delete resource (marks as deleting) + app.delete<{ + Params: { id: string }; + }>("/api/resources/:id", async (request, reply) => { + const resource = await resourceStore.get(request.params.id); + if (!resource) { + return reply.code(404).send({ error: "Resource not found" }); + } + + const rbac = await rbacService.check({ + userId: request.userId!, + userEmail: request.userEmail!, + userRole: request.userRole!, + action: "delete", + resource: resource.kind, + name: resource.name, + }); + + if (!rbac.allowed) { + return reply.code(403).send({ error: rbac.reason }); + } + + await resourceStore.delete(request.params.id); + + auditService.emit({ + eventKind: "resource_deleted", + source: "labd", + verified: true, + userId: request.userId ?? null, + userName: request.userEmail ?? null, + resourceKind: resource.kind, + resourceName: resource.name, + result: "success", + }); + + return reply.send({ status: "deleting", id: request.params.id }); + }); +} diff --git a/bastion/src/labd/src/routes/v2-auth.ts b/bastion/src/labd/src/routes/v2-auth.ts new file mode 100644 index 0000000..ff8f87a --- /dev/null +++ b/bastion/src/labd/src/routes/v2-auth.ts @@ -0,0 +1,81 @@ +// v2 Auth routes: bearer token login/logout. +// POST /api/auth/login — email + password → session token +// POST /api/auth/logout — revoke session + +import type { FastifyInstance } from "fastify"; +import type { AuthService } from "../services/auth.js"; +import type { AuditService } from "../services/audit.js"; +import { AuthError } from "../services/auth.js"; + +export function registerV2AuthRoutes( + app: FastifyInstance, + authService: AuthService, + auditService: AuditService, +): void { + app.post<{ + Body: { email?: string; password?: string }; + }>("/api/auth/login", async (request, reply) => { + const { email, password } = request.body ?? {}; + + if (!email || !password) { + return reply.code(400).send({ error: "email and password are required" }); + } + + try { + const result = await authService.login(email, password); + + auditService.emit({ + eventKind: result.isBootstrap ? "auth_bootstrap" : "auth_login", + source: "labd", + verified: true, + userId: result.userId, + userName: email, + result: "success", + details: { isBootstrap: result.isBootstrap }, + }); + + return reply.send({ + token: result.token, + expiresAt: result.expiresAt.toISOString(), + isBootstrap: result.isBootstrap, + }); + } catch (err) { + if (err instanceof AuthError) { + auditService.emit({ + eventKind: "auth_login", + source: "labd", + verified: true, + userName: email, + result: "failure", + error: err.message, + }); + return reply.code(401).send({ error: err.message }); + } + return reply.code(500).send({ error: "Login failed" }); + } + }); + + app.post("/api/auth/logout", async (request, reply) => { + const token = request.headers.authorization?.slice(7); + if (!token) { + return reply.code(400).send({ error: "Authorization header required" }); + } + + try { + await authService.logout(token); + auditService.emit({ + eventKind: "auth_logout", + source: "labd", + verified: true, + userId: request.userId ?? null, + result: "success", + }); + return reply.send({ status: "logged_out" }); + } catch (err) { + if (err instanceof AuthError) { + return reply.code(400).send({ error: err.message }); + } + return reply.code(500).send({ error: "Logout failed" }); + } + }); +} diff --git a/bastion/src/labd/src/server.ts b/bastion/src/labd/src/server.ts index b4ac77a..9da02bb 100644 --- a/bastion/src/labd/src/server.ts +++ b/bastion/src/labd/src/server.ts @@ -192,7 +192,9 @@ export async function createApp(_config: LabdConfig, db: DbClient): Promise<{ labels: { cpu: hw.cpu_model, cores: hw.cpu_cores, memory_gb: hw.memory_gb, arch: hw.arch, product: hw.product, manufacturer: hw.manufacturer }, }, update: { - status: "discovered", + // Leave status alone — a previously "online"/"offline" record + // must not be downgraded to "discovered" just because the bastion + // restarted and re-discovered the MAC via DHCP/PXE. lastHeartbeat: new Date(), labels: { cpu: hw.cpu_model, cores: hw.cpu_cores, memory_gb: hw.memory_gb, arch: hw.arch, product: hw.product, manufacturer: hw.manufacturer }, }, diff --git a/bastion/src/labd/src/services/audit.ts b/bastion/src/labd/src/services/audit.ts new file mode 100644 index 0000000..d2ab3ad --- /dev/null +++ b/bastion/src/labd/src/services/audit.ts @@ -0,0 +1,100 @@ +// Audit service: fire-and-forget event collection with batching. +// Batches 50 events or flushes every 5 seconds, whichever comes first. +// Failures never block the operation being audited. + +import { randomBytes } from "node:crypto"; +import type { PrismaClient, Prisma } from "@prisma/client"; +import { logger } from "./logger.js"; + +const BATCH_SIZE = 50; +const FLUSH_INTERVAL_MS = 5_000; + +export interface AuditEventInput { + eventKind: string; + source: string; + verified?: boolean; + userId?: string | null; + userName?: string | null; + sessionId?: string | null; + environmentName?: string | null; + accountName?: string | null; + resourceKind?: string | null; + resourceName?: string | null; + correlationId?: string | null; + parentEventId?: string | null; + details?: Record; + result: string; + error?: string | null; + durationMs?: number | null; +} + +export class AuditService { + private batch: AuditEventInput[] = []; + private timer: ReturnType | null = null; + + constructor(private readonly db: PrismaClient) {} + + start(): void { + this.timer = setInterval(() => { + void this.flush(); + }, FLUSH_INTERVAL_MS); + } + + stop(): void { + if (this.timer) { + clearInterval(this.timer); + this.timer = null; + } + void this.flush(); + } + + emit(event: AuditEventInput): void { + // Generate correlation ID if not provided + if (!event.correlationId) { + event.correlationId = `corr_${randomBytes(8).toString("hex")}`; + } + + this.batch.push(event); + + if (this.batch.length >= BATCH_SIZE) { + void this.flush(); + } + } + + /** Create a correlation context for a chain of related events. */ + createCorrelation(): string { + return `corr_${randomBytes(8).toString("hex")}`; + } + + private async flush(): Promise { + if (this.batch.length === 0) return; + + const events = this.batch.splice(0); + try { + await this.db.auditEvent.createMany({ + data: events.map((e) => ({ + eventKind: e.eventKind, + source: e.source, + verified: e.verified ?? false, + userId: e.userId ?? null, + userName: e.userName ?? null, + sessionId: e.sessionId ?? null, + environmentName: e.environmentName ?? null, + accountName: e.accountName ?? null, + resourceKind: e.resourceKind ?? null, + resourceName: e.resourceName ?? null, + correlationId: e.correlationId ?? `corr_${randomBytes(8).toString("hex")}`, + parentEventId: e.parentEventId ?? null, + details: (e.details ?? {}) as Prisma.InputJsonValue, + result: e.result, + error: e.error ?? null, + durationMs: e.durationMs ?? null, + })), + }); + logger.info(`AUDIT: flushed ${events.length} events`); + } catch (err) { + // Fire-and-forget: audit failures never block operations + logger.warn(`AUDIT: failed to flush ${events.length} events: ${err instanceof Error ? err.message : String(err)}`); + } + } +} diff --git a/bastion/src/labd/src/services/auth.ts b/bastion/src/labd/src/services/auth.ts new file mode 100644 index 0000000..4a61063 --- /dev/null +++ b/bastion/src/labd/src/services/auth.ts @@ -0,0 +1,119 @@ +// Auth service: bearer token authentication with bootstrap flow. +// First login creates the admin user. Subsequent logins return session tokens. + +import { randomBytes } from "node:crypto"; +import bcrypt from "bcryptjs"; +import type { PrismaClient } from "@prisma/client"; +import { logger } from "./logger.js"; + +const SESSION_EXPIRY_DAYS = 30; +const BCRYPT_ROUNDS = 12; + +export interface LoginResult { + token: string; + expiresAt: Date; + userId: string; + isBootstrap: boolean; +} + +export class AuthService { + constructor(private readonly db: PrismaClient) {} + + async login(email: string, password: string): Promise { + const userCount = await this.db.user.count(); + + // Bootstrap: first login creates admin user + if (userCount === 0) { + return this.bootstrap(email, password); + } + + const user = await this.db.user.findUnique({ where: { email } }); + if (!user) { + // Same error for unknown user and wrong password (no enumeration) + throw new AuthError("Invalid email or password"); + } + + const valid = await bcrypt.compare(password, user.password); + if (!valid) { + throw new AuthError("Invalid email or password"); + } + + const session = await this.createSession(user.id); + logger.info(`AUTH LOGIN: ${email} (${user.id.slice(0, 8)}...)`); + + return { + token: session.token, + expiresAt: session.expiresAt, + userId: user.id, + isBootstrap: false, + }; + } + + async logout(token: string): Promise { + const session = await this.db.session.findUnique({ where: { token } }); + if (!session) { + throw new AuthError("Invalid session"); + } + await this.db.session.delete({ where: { id: session.id } }); + logger.info(`AUTH LOGOUT: session ${session.id.slice(0, 8)}...`); + } + + async validateToken(token: string): Promise<{ userId: string; email: string; role: string }> { + const session = await this.db.session.findUnique({ + where: { token }, + include: { user: true }, + }); + + if (!session) { + throw new AuthError("Invalid token"); + } + if (session.expiresAt < new Date()) { + await this.db.session.delete({ where: { id: session.id } }); + throw new AuthError("Token expired"); + } + + return { + userId: session.user.id, + email: session.user.email, + role: session.user.role, + }; + } + + private async bootstrap(email: string, password: string): Promise { + const hashed = await bcrypt.hash(password, BCRYPT_ROUNDS); + const user = await this.db.user.create({ + data: { + email, + password: hashed, + role: "ADMIN", + name: email.split("@")[0] ?? null, + }, + }); + + const session = await this.createSession(user.id); + logger.info(`AUTH BOOTSTRAP: created admin user ${email} (${user.id.slice(0, 8)}...)`); + + return { + token: session.token, + expiresAt: session.expiresAt, + userId: user.id, + isBootstrap: true, + }; + } + + private async createSession(userId: string) { + const token = randomBytes(32).toString("hex"); + const expiresAt = new Date(Date.now() + SESSION_EXPIRY_DAYS * 24 * 60 * 60 * 1000); + + return this.db.session.create({ + data: { userId, token, expiresAt }, + }); + } +} + +export class AuthError extends Error { + constructor(message: string) { + super(message); + this.name = "AuthError"; + } +} diff --git a/bastion/src/labd/src/services/rbac.ts b/bastion/src/labd/src/services/rbac.ts new file mode 100644 index 0000000..da4599b --- /dev/null +++ b/bastion/src/labd/src/services/rbac.ts @@ -0,0 +1,123 @@ +// RBAC service: environment-scoped permission checks. +// Uses named RbacDefinition records with JSON subjects and roleBindings. +// +// Resolution flow: +// 1. Find all RbacDefinitions where subjects match the current user/groups +// 2. Collect all roleBindings from matching definitions +// 3. Check if any binding grants the requested action on the requested resource + +import type { PrismaClient } from "@prisma/client"; +import { logger } from "./logger.js"; + +export interface RbacCheck { + userId: string; + userEmail: string; + userRole: string; + action: string; // "view" | "edit" | "create" | "delete" | "run" | "admin" + resource?: string | undefined; // "servers" | "databases" | "clusters" | "*" + name?: string | undefined; // specific resource name + environment?: string | undefined; // specific environment name +} + +export interface RbacResult { + allowed: boolean; + reason: string; + matchedDefinition?: string; +} + +interface StoredSubject { + kind: string; + name: string; +} + +interface StoredBinding { + role: string; + resource?: string; + name?: string; + environment?: string; + action?: string; +} + +export class RbacService { + constructor(private readonly db: PrismaClient) {} + + async check(req: RbacCheck): Promise { + // Admin users bypass RBAC + if (req.userRole === "ADMIN") { + return { allowed: true, reason: "admin role" }; + } + + // Collect user's group memberships + const memberships = await this.db.groupMember.findMany({ + where: { userId: req.userId }, + include: { group: true }, + }); + const groupNames = memberships.map((m) => m.group.name); + + // Find all RBAC definitions + const definitions = await this.db.rbacDefinition.findMany(); + + for (const def of definitions) { + const subjects = def.subjects as unknown as StoredSubject[]; + const bindings = def.roleBindings as unknown as StoredBinding[]; + + // Check if this definition's subjects match the user + const subjectMatch = subjects.some((s) => { + if (s.kind === "User" && s.name === req.userEmail) return true; + if (s.kind === "Group" && groupNames.includes(s.name)) return true; + return false; + }); + + if (!subjectMatch) continue; + + // Check if any binding grants the requested permission + for (const binding of bindings) { + if (this.bindingMatches(binding, req)) { + logger.info(`RBAC ALLOW: ${req.userEmail} ${req.action} ${req.resource ?? "*"}${req.name ? `/${req.name}` : ""} via ${def.name}`); + return { + allowed: true, + reason: `granted by ${def.name}`, + matchedDefinition: def.name, + }; + } + } + } + + logger.info(`RBAC DENY: ${req.userEmail} ${req.action} ${req.resource ?? "*"}${req.name ? `/${req.name}` : ""}`); + return { + allowed: false, + reason: `no matching role binding for ${req.action} on ${req.resource ?? "*"}`, + }; + } + + private bindingMatches(binding: StoredBinding, req: RbacCheck): boolean { + // Check role grants the action + if (!this.roleGrantsAction(binding.role, req.action)) return false; + + // Check resource scope + if (binding.resource && binding.resource !== "*" && binding.resource !== req.resource) return false; + + // Check name scope + if (binding.name && binding.name !== req.name) return false; + + // Check environment scope + if (binding.environment && binding.environment !== req.environment) return false; + + // Check operation scope (for "run" role with specific actions) + if (binding.action && binding.action !== "*" && binding.action !== req.action) return false; + + return true; + } + + private roleGrantsAction(role: string, action: string): boolean { + const grants: Record = { + admin: ["view", "edit", "create", "delete", "run", "admin"], + edit: ["view", "edit", "create", "delete"], + create: ["create"], + delete: ["delete"], + view: ["view"], + run: ["run"], + }; + return grants[role]?.includes(action) ?? false; + } +} diff --git a/bastion/src/labd/src/services/resource-store.ts b/bastion/src/labd/src/services/resource-store.ts new file mode 100644 index 0000000..4d9a0ec --- /dev/null +++ b/bastion/src/labd/src/services/resource-store.ts @@ -0,0 +1,108 @@ +// Resource store: CRUD for generic resources with origin/managedBy tracking. +// All mutations go through this service so RBAC and audit are applied consistently. + +import type { PrismaClient, Resource as PrismaResource, Prisma } from "@prisma/client"; +import { logger } from "./logger.js"; + +export interface CreateResourceInput { + kind: string; + name: string; + environmentId: string; + accountId: string; + origin?: string; + managedBy?: string; + sourceRef?: string; + desiredSpec: Record; +} + +export interface UpdateResourceInput { + desiredSpec?: Record; + status?: string; + statusMessage?: string; + actualSpec?: Record; + platformRef?: string; +} + +export interface ListResourcesFilter { + kind?: string | undefined; + environmentId?: string | undefined; + accountId?: string | undefined; + status?: string | undefined; +} + +export class ResourceStore { + constructor(private readonly db: PrismaClient) {} + + async create(input: CreateResourceInput): Promise { + const resource = await this.db.resource.create({ + data: { + kind: input.kind, + name: input.name, + environmentId: input.environmentId, + accountId: input.accountId, + origin: input.origin ?? "cli", + managedBy: input.managedBy ?? "manual", + sourceRef: input.sourceRef ?? null, + desiredSpec: input.desiredSpec as Prisma.InputJsonValue, + status: "pending", + }, + }); + + logger.info(`RESOURCE CREATED: ${input.kind}/${input.name} in env ${input.environmentId.slice(0, 8)}...`); + return resource; + } + + async get(id: string): Promise { + return this.db.resource.findUnique({ where: { id } }); + } + + async getByKindNameEnv(kind: string, name: string, environmentId: string): Promise { + return this.db.resource.findUnique({ + where: { kind_name_environmentId: { kind, name, environmentId } }, + }); + } + + async list(filter: ListResourcesFilter = {}): Promise { + return this.db.resource.findMany({ + where: { + ...(filter.kind ? { kind: filter.kind } : {}), + ...(filter.environmentId ? { environmentId: filter.environmentId } : {}), + ...(filter.accountId ? { accountId: filter.accountId } : {}), + ...(filter.status ? { status: filter.status } : {}), + }, + orderBy: { createdAt: "desc" }, + }); + } + + async update(id: string, input: UpdateResourceInput): Promise { + const data: Prisma.ResourceUpdateInput = {}; + if (input.desiredSpec !== undefined) data.desiredSpec = input.desiredSpec as Prisma.InputJsonValue; + if (input.status !== undefined) data.status = input.status; + if (input.statusMessage !== undefined) data.statusMessage = input.statusMessage; + if (input.actualSpec !== undefined) data.actualSpec = input.actualSpec as Prisma.InputJsonValue; + if (input.platformRef !== undefined) data.platformRef = input.platformRef; + if (input.status === "ready") data.lastReconciled = new Date(); + + const resource = await this.db.resource.update({ where: { id }, data }); + + logger.info(`RESOURCE UPDATED: ${resource.kind}/${resource.name} -> ${input.status ?? "spec change"}`); + return resource; + } + + async delete(id: string): Promise { + const resource = await this.db.resource.findUnique({ where: { id } }); + if (!resource) return; + + // Mark as deleting first (driver handles actual deletion) + await this.db.resource.update({ + where: { id }, + data: { status: "deleting" }, + }); + + logger.info(`RESOURCE DELETING: ${resource.kind}/${resource.name}`); + } + + async hardDelete(id: string): Promise { + await this.db.resource.delete({ where: { id } }); + } +} diff --git a/bastion/src/labd/tests/bastions-machines.test.ts b/bastion/src/labd/tests/bastions-machines.test.ts new file mode 100644 index 0000000..2b52cc7 --- /dev/null +++ b/bastion/src/labd/tests/bastions-machines.test.ts @@ -0,0 +1,144 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import Fastify from "fastify"; +import { registerBastionRoutes } from "../src/routes/bastions.js"; +import { bastionRegistry } from "../src/services/bastion-registry.js"; +import type { DbClient } from "../src/server.js"; +import type { BastionState } from "@lab/shared"; + +function createMockDb(servers: unknown[] = []): DbClient { + return { + $queryRaw: vi.fn().mockResolvedValue([{ "?column?": 1 }]), + server: { + findMany: vi.fn().mockResolvedValue(servers), + findUnique: vi.fn().mockResolvedValue(null), + upsert: vi.fn().mockResolvedValue({}), + }, + joinToken: { + findUnique: vi.fn().mockResolvedValue(null), + findMany: vi.fn().mockResolvedValue([]), + create: vi.fn().mockResolvedValue({ id: "t" }), + update: vi.fn().mockResolvedValue({}), + }, + bastion: { + upsert: vi.fn().mockResolvedValue({}), + findMany: vi.fn().mockResolvedValue([]), + findUnique: vi.fn().mockResolvedValue(null), + update: vi.fn().mockResolvedValue({}), + }, + }; +} + +function registerFakeBastion(bastionId: string, state: BastionState): void { + bastionRegistry.register({ + bastionId, + hostname: "fake", + network: "192.168.8.0/24", + serverIp: "192.168.8.11", + // socket is referenced only on commands, not during aggregation + socket: { on: () => undefined, off: () => undefined, send: () => undefined, close: () => undefined } as never, + connectedAt: new Date(), + lastHeartbeat: new Date(), + state, + }); +} + +describe("GET /api/machines aggregation", () => { + beforeEach(() => { + for (const b of bastionRegistry.getAll()) bastionRegistry.unregister(b.bastionId); + }); + + it("promotes a live-discovered MAC to installed when the DB has a real hostname+role for it", async () => { + // Simulates the worker0-k8s0 bug: bastion restarted, lost its installed map, + // rediscovered the machine via DHCP/PXE. DB still has hostname=worker0-k8s0, + // role=infra, ip=192.168.8.23. Without the fix, the CLI sees a "discovered" + // row with no hostname/role/IP. With the fix, the row is promoted to + // "installed" with full identity preserved. + const mac = "78:55:36:08:28:fb"; + registerFakeBastion("b1", { + discovered: { + [mac]: { + mac, product: "SER", board: "SER", serial: "x", manufacturer: "AZW", + cpu_model: "AMD Ryzen 7 255", cpu_cores: 16, memory_gb: 58, arch: "x86_64", + disks: [], nics: [], first_seen: "", last_seen: "", + }, + }, + install_queue: {}, + installed: {}, + debug: {}, + }); + + const app = Fastify({ logger: false }); + const db = createMockDb([ + { mac, hostname: "worker0-k8s0", role: "infra", ip: "192.168.8.23", status: "discovered", labels: {} }, + ]); + registerBastionRoutes(app, db); + + const res = await app.inject({ method: "GET", url: "/api/machines" }); + expect(res.statusCode).toBe(200); + const body = JSON.parse(res.body); + + expect(body.discovered[mac]).toBeUndefined(); + expect(body.installed[mac]).toMatchObject({ + hostname: "worker0-k8s0", + role: "infra", + ip: "192.168.8.23", + cpu_model: "AMD Ryzen 7 255", + cpu_cores: 16, + memory_gb: 58, + }); + + await app.close(); + }); + + it("leaves a fresh-discovery MAC in discovered when DB only has a discovery-shaped record", async () => { + const mac = "aa:bb:cc:dd:ee:ff"; + registerFakeBastion("b1", { + discovered: { + [mac]: { + mac, product: "SER", board: "SER", serial: "x", manufacturer: "AZW", + cpu_model: "AMD Ryzen 7", cpu_cores: 8, memory_gb: 32, arch: "x86_64", + disks: [], nics: [], first_seen: "", last_seen: "", + }, + }, + install_queue: {}, + installed: {}, + debug: {}, + }); + + const app = Fastify({ logger: false }); + // Matches what labd writes on first discovery: hostname=product, role="unknown" + const db = createMockDb([ + { mac, hostname: "SER", role: "unknown", ip: null, status: "discovered", labels: {} }, + ]); + registerBastionRoutes(app, db); + + const res = await app.inject({ method: "GET", url: "/api/machines" }); + const body = JSON.parse(res.body); + + expect(body.discovered[mac]).toBeDefined(); + expect(body.installed[mac]).toBeUndefined(); + + await app.close(); + }); + + it("falls back to DB for MACs not in any live bucket", async () => { + const mac = "11:22:33:44:55:66"; + // No bastions connected + const app = Fastify({ logger: false }); + const db = createMockDb([ + { mac, hostname: "worker1-k8s0", role: "infra", ip: "192.168.8.13", status: "online", labels: {} }, + ]); + registerBastionRoutes(app, db); + + const res = await app.inject({ method: "GET", url: "/api/machines" }); + const body = JSON.parse(res.body); + + expect(body.installed[mac]).toMatchObject({ + hostname: "worker1-k8s0", + role: "infra", + ip: "192.168.8.13", + }); + + await app.close(); + }); +}); diff --git a/bastion/tsconfig.json b/bastion/tsconfig.json index f2fd59f..ae79646 100644 --- a/bastion/tsconfig.json +++ b/bastion/tsconfig.json @@ -1,6 +1,7 @@ { "files": [], "references": [ + { "path": "src/core" }, { "path": "src/shared" }, { "path": "src/bastion" }, { "path": "src/cli" },