diff --git a/packages/core/package.json b/packages/core/package.json index d78424d1..c8e53b73 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -141,7 +141,6 @@ "socket.io": "^4.8.0", "svgo": "catalog:", "typescript": "catalog:", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#semver:^20.49.0", "validate-npm-package-name": "^5.0.0", "vite": "catalog:", "vite-node": "catalog:", diff --git a/packages/core/src/cli/lib/init-process.ts b/packages/core/src/cli/lib/init-process.ts index 2e0a0618..4c6f80cb 100644 --- a/packages/core/src/cli/lib/init-process.ts +++ b/packages/core/src/cli/lib/init-process.ts @@ -1,19 +1,6 @@ import kleur from 'kleur'; process.on('uncaughtException', (err) => { - if (err.message.includes('Error loading shared library ld-linux-')) { - console.log([ - '🚨 💡 🚨 💡 🚨', - '', - kleur.bold('uWebsockets compat issue. If you are running in Docker, try adding this line to your Dockerfile:'), - '', - ' RUN ln -s "/lib/libc.musl-$(uname -m).so.1" "/lib/ld-linux-$(uname -m).so.1"', - '', - '🚨 💡 🚨 💡 🚨', - '', - ].join('\n')); - } - console.log(kleur.red(`UNCAUGHT EXCEPTION: ${err.message}`)); console.log(kleur.red(`UNCAUGHT EXCEPTION: ${err.stack}`)); // eslint-disable-next-line no-restricted-syntax diff --git a/packages/core/src/config-loader/dmno-server.ts b/packages/core/src/config-loader/dmno-server.ts index 7c1dc27f..e06266b9 100644 --- a/packages/core/src/config-loader/dmno-server.ts +++ b/packages/core/src/config-loader/dmno-server.ts @@ -1,21 +1,24 @@ import https from 'node:https'; + import path, { dirname } from 'node:path'; import fs from 'node:fs'; import crypto from 'node:crypto'; import { fileURLToPath } from 'node:url'; +import { TLSSocket } from 'node:tls'; +import { ServerResponse } from 'node:http'; import _ from 'lodash-es'; import getPort from 'get-port'; import { Server as SocketIoServer } from 'socket.io'; -import uWS from 'uWebSockets.js'; import launchEditor from 'launch-editor'; import Debug from 'debug'; import { CacheMode } from '@dmno/configraph'; import { createDeferredPromise } from '@dmno/ts-lib'; +import forge from 'node-forge'; import { ConfigLoader } from './config-loader'; import { loadOrCreateTlsCerts } from '../lib/certs'; import { pathExists } from '../lib/fs-utils'; import { findDmnoServices } from './find-services'; -import { MIME_TYPES_BY_EXT, uwsBodyParser, uwsValidateClientCert } from '../lib/uws-utils'; +import { MIME_TYPES_BY_EXT, bodyParser } from '../lib/web-server-utils'; import { UseAtPhases } from '../config-engine/configraph-adapter'; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -34,6 +37,26 @@ function getCurrentPackageNameFromPackageManager() { if (process.env.PNPM_PACKAGE_NAME !== undefined) return process.env.PNPM_PACKAGE_NAME; } + +function writeResponse( + res: ServerResponse, + content: string | any, + statusCode = 200, + contentType = 'application/json', +) { + // res.writeHead(statusCode); + res.statusCode = statusCode; + res.setHeader('content-type', contentType); + // res.setHeader(http2.constants.HTTP2_HEADER_STATUS, statusCode); + // res.setHeader(http2.constants.HTTP2_HEADER_CONTENT_TYPE, contentType); + // res.stream.respond({ + // [http2.constants.HTTP2_HEADER_STATUS]: statusCode, + // [http2.constants.HTTP2_HEADER_CONTENT_TYPE]: contentType, + // }); + res.end(contentType === 'application/json' ? JSON.stringify(content) : content.toString()); +} + + export class DmnoServer { private serverId?: string; private serverPort?: number; @@ -76,8 +99,9 @@ export class DmnoServer { readonly webServerReady?: Promise; - private uwsServer?: uWS.TemplatedApp; + private webServer?: https.Server; private certs?: Awaited>; + private caStore?: forge.pki.CAStore; private _webServerUrl?: string; public get webServerUrl() { return this._webServerUrl; } @@ -94,11 +118,11 @@ export class DmnoServer { // we also probably want to let the user specify a port in workspace config this.serverPort = await getPort({ port: DEFAULT_PORT }); - const uwsServerListeningDeferred = createDeferredPromise(); + const webServerListeningDeferred = createDeferredPromise(); const certDir = `${this.configLoader.workspaceRootPath}/.dmno/certs`; this.certs = await loadOrCreateTlsCerts('localhost', certDir); - + this.caStore = forge.pki.createCaStore([forge.pki.certificateFromPem(this.certs!.caCert)]); const devUiPath = path.resolve(`${__dirname}/../dev-ui-dist/`); @@ -112,135 +136,148 @@ export class DmnoServer { } } - this.uwsServer = uWS.SSLApp({ - cert_file_name: path.join(certDir, 'SERVER.crt'), - key_file_name: path.join(certDir, 'SERVER_key.pem'), - ca_file_name: path.join(certDir, 'CA.crt'), - // passphrase: '1234', - }) - .any('/api/:requestName', async (res, req) => { - /* Can't return or yield from here without responding or attaching an abort handler */ - res.onAborted(() => { - res.aborted = true; - }); + const httpsServer = https.createServer({ + key: this.certs.serverKey, + cert: this.certs.serverCert, + ca: this.certs.caCert, + requestCert: true, + // rejectUnauthorized: true, // if enabled you cannot do authentication based on client cert + // checkClientCertificate: true + }); - if (this.serverId !== req.getHeader('dmno-server-id')) { - res.writeStatus('409'); - res.end(JSON.stringify({ error: 'Incorrect DMNO server ID' })); - return; - } + httpsServer.on('request', async (req, res) => { + if (!(req.socket instanceof TLSSocket)) throw new Error('expected TLSSocket'); - if (!uwsValidateClientCert(res, this.certs!.caCert)) return; + // console.log(`${req.socket.getProtocol()} ${req.method} request from: ${req.connection.remoteAddress}`); - const reqName = req.getParameter(0) || ''; - if (!(reqName in this.commands)) { - res.writeStatus('404'); - res.end(JSON.stringify({ error: 'Not found!' })); - return; - } + if (!req.socket.authorized) { + return writeResponse(res, { error: 'Access denied' }, 401); + } else { + // Examine the cert itself, and even validate based on that if required + // const cert = req.socket.getPeerCertificate(); + // if (cert.subject) { + // console.log(`${cert.subject.CN} issued by: ${cert.issuer.CN} has logged in!`); + // } else { + // console.log('Cert has no subject?'); + // } - // parse the body to get function args - let args; - if (req.getMethod() === 'post') { - try { - args = await uwsBodyParser(res); - } catch (err) { - res.writeStatus('400'); - console.log(err); - res.end(JSON.stringify({ error: 'body parsing failed' })); - return; + // VALIDATE CLIENT CERT + try { + const clientCert = req.socket.getPeerCertificate(true); + const clientCertRaw = clientCert.raw.toString('base64'); + + const derKey = forge.util.decode64(clientCertRaw); + const asnObj = forge.asn1.fromDer(derKey); + const asn1Cert = forge.pki.certificateFromAsn1(asnObj); + const pemCert = forge.pki.certificateToPem(asn1Cert); + const client = forge.pki.certificateFromPem(pemCert); + const certValid = forge.pki.verifyCertificateChain(this.caStore!, [client]); + if (!certValid) { + return writeResponse(res, { error: 'Unauthorized - bad client cert' }, 401); } - } else if (req.getMethod() === 'get') { - args = []; - } else { - res.writeStatus('404'); - res.end(JSON.stringify({ error: 'unsupported method' })); - return; + } catch (err) { + console.log(err); + return writeResponse(res, { error: 'Error validating client cert' }, 401); } + // API request handler + if (req.url?.startsWith('/api/')) { + const [,,requestName] = req.url.split('/'); - // @ts-ignore - const rawResponse = await this.commands[reqName].call(this, ...args); - - /* If we were aborted, you cannot respond */ - if (!res.aborted) { - res.cork(() => { - res.end(JSON.stringify(rawResponse)); - }); - } - }) - .any('/*', async (res, req) => { - res.onAborted(() => { - res.aborted = true; - }); + if (this.serverId !== req.headers['dmno-server-id']) { + return writeResponse(res, { error: 'Incorrect DMNO server ID' }, 409); + } - if (!uwsValidateClientCert(res, this.certs!.caCert)) return; + if (!(requestName in this.commands)) { + return writeResponse(res, { error: 'Not found!' }, 404); + } - if (!this.opts?.enableWebUi) { - res.writeStatus('404'); - res.writeHeader('content-type', 'text/html'); - res.end('

dmno web ui is disabled

Run `dmno dev` to boot the web dashboard

'); - return; - } + // parse the body to get function args + let args; + if (req.method?.toLowerCase() === 'post') { + try { + args = await bodyParser(req); + } catch (err) { + console.log(err); + return writeResponse(res, { error: 'body parsing failed' }, 400); + } + } else if (req.method?.toLowerCase() === 'get') { + args = []; + } else { + return writeResponse(res, { error: 'unsupported method!' }, 404); + } - // have to use .any for the route matching to work properly - if (req.getMethod() !== 'get') { - res.writeStatus('404'); - res.end(JSON.stringify({ error: 'method not supported' })); - } + // @ts-ignore + const rawResponse = await this.commands[requestName].call(this, ...args); + return writeResponse(res, rawResponse); + // dev ui + } else { + if (!this.opts?.enableWebUi) { + return writeResponse( + res, + '

dmno web ui is disabled

Run `dmno dev` to boot the web dashboard

', + 404, + 'text/html', + ); + } + if (req.method?.toLowerCase() !== 'get') { + return writeResponse(res, { error: 'unsupported method!' }, 404); + } - let reqPath = req.getUrl(); - if (!reqPath || reqPath === '/') reqPath = '/index.html'; - // debugWeb('http request', reqPath); + let reqPath = req.url; + if (!reqPath || reqPath === '/') reqPath = '/index.html'; + // debugWeb('http request', reqPath); - const fullPath = path.join(devUiPath, reqPath); - const extension = fullPath.split('.').pop(); + const fullPath = path.join(devUiPath, reqPath); + const extension = fullPath.split('.').pop(); - let fileContents = devUiIndexHtml; - let contentType = 'text/html'; + let fileContents = devUiIndexHtml; + let contentType = 'text/html'; - try { - fileContents = await fs.promises.readFile(fullPath, 'utf-8'); - contentType = (MIME_TYPES_BY_EXT as any)[extension || '']; - } catch (err) { - if ((err as any).code === 'ENOENT') { - if (reqPath.startsWith('/assets/')) { - res.writeStatus('404'); - res.writeHeader('content-type', 'text/html'); - res.end('

oops! file does not exist

'); - return; + try { + fileContents = await fs.promises.readFile(fullPath, 'utf-8'); + contentType = (MIME_TYPES_BY_EXT as any)[extension || '']; + } catch (err) { + if ((err as any).code === 'ENOENT') { + if (reqPath.startsWith('/assets/')) { + return writeResponse( + res, + '

oops! file does not exist

', + 404, + 'text/html', + ); + } + } else { + throw err; } - } else { - throw err; } - } - if (!res.aborted) { - res.cork(() => { - res.writeStatus('200'); - res.writeHeader('content-type', contentType); - res.end(fileContents); - }); + + return writeResponse(res, fileContents, 200, contentType); } - }) - .listen(this.serverPort, (token) => { - this._webServerUrl = `https://localhost:${this.serverPort}`; - if (!token) throw new Error('uWS failed to bind to port?'); - uwsServerListeningDeferred.resolve(); - }); + } + }); + + this.webServer = httpsServer; + + httpsServer.listen(this.serverPort, () => { + let host = (httpsServer.address() as any).address; + if (host === '::') host = 'localhost'; + this._webServerUrl = `https://${host}:${this.serverPort}`; + webServerListeningDeferred.resolve(); + }); process.on('exit', (code) => { // TODO: can be smarter about tracking what needs to be shut down try { - this.uwsServer?.close(); + this.webServer?.close(); } catch (err) { - } }); - await uwsServerListeningDeferred.promise; + await webServerListeningDeferred.promise; if (this.opts?.enableWebUi) { await this.initSocketIoServer(); @@ -252,7 +289,7 @@ export class DmnoServer { const debugWeb = Debug('dmno:webserver'); - this.socketIoServer = new SocketIoServer({ + this.socketIoServer = new SocketIoServer(this.webServer, { path: '/ws', serveClient: false, // allowRequest: (req, callback) => { @@ -261,7 +298,6 @@ export class DmnoServer { // }, cors: { origin: '*' }, }); - this.socketIoServer.attachApp(this.uwsServer); this.socketIoServer.on('connection', (socket) => { debugWeb('socket connection'); // let handshake = socket.handshake; @@ -298,7 +334,7 @@ export class DmnoServer { shutdown() { - this.uwsServer?.close(); + this.webServer?.close(); this.configLoader?.shutdown().catch(() => { console.log('error shutting down dmno vite dev server'); }); @@ -354,6 +390,10 @@ export class DmnoServer { cert: this.certs.clientCert, ca: [this.certs.caCert], rejectUnauthorized: false, + // enableHttp2: false, + // onlyHttp2: false, + // allowHTTP1: true, + // minVersion: 'TLSv1.2', }; const req = https.request(clientOptions, (res) => { diff --git a/packages/core/src/lib/uws-utils.ts b/packages/core/src/lib/uws-utils.ts deleted file mode 100644 index f0be3b6a..00000000 --- a/packages/core/src/lib/uws-utils.ts +++ /dev/null @@ -1,69 +0,0 @@ -import crypto from 'node:crypto'; -import uWS from 'uWebSockets.js'; - -const MAX_BODY_SIZE = 1024; - -export const MIME_TYPES_BY_EXT = { - js: 'text/javascript', - html: 'text/html', - css: 'text/css', - ico: 'image/x-icon', - // TODO: will need more for images -}; - -export function uwsBodyParser(res: uWS.HttpResponse): Promise<{ [key: string]: any } | null> { - return new Promise((resolve, reject) => { - let buffer: Buffer = Buffer.alloc(0); - let totalSize = 0; - - res.onData((ab, isLast) => { - try { - if (res.aborted) { - reject(new Error('Request aborted')); - return; - } - - if (ab.byteLength > 0) { // I found some non-last onData with 0 byte length - // Immediately copy the ArrayBuffer into a Buffer, every return of onData neuters the ArrayBuffer - // const copy = copyArrayBuffer(ab); - const copy = ab; - totalSize += copy.byteLength; - buffer = Buffer.concat([buffer, Buffer.from(copy)]); - } - - if (totalSize > MAX_BODY_SIZE) { // define your allowed max size if it applies to you - reject(new Error('Request body too large: max 4MB allowed')); - return; - } - - if (isLast) { - // If this is the last chunk, process the final buffer - // Convert the buffer to a string and parse it as JSON - // this will fail if the buffer doesn't contain a valid JSON (e.g. length = 0) - const resolveValue = JSON.parse(buffer.toString()); - resolve(resolveValue); - } - } catch (err: any) { - reject(new Error(`Failed to parse JSON: ${err.message}`)); - } - }); - }); -} - -export function uwsValidateClientCert(res: uWS.HttpResponse, caCert: string) { - // validate client certs (mTLS) - try { - const clientCert = res.getX509Certificate(); - const x509 = new crypto.X509Certificate(clientCert); - if (!x509.verify(crypto.createPublicKey(caCert))) { - res.writeStatus('401'); - res.end(JSON.stringify({ error: 'Unauthorized!' })); - return false; - } - return true; - } catch (err) { - res.writeStatus('401'); - res.end('Unauthorized!'); - return false; - } -} diff --git a/packages/core/src/lib/web-server-utils.ts b/packages/core/src/lib/web-server-utils.ts new file mode 100644 index 00000000..dfa6c098 --- /dev/null +++ b/packages/core/src/lib/web-server-utils.ts @@ -0,0 +1,34 @@ +import crypto from 'node:crypto'; +import { IncomingMessage } from 'node:http'; + +const MAX_BODY_SIZE = 1024; + +export const MIME_TYPES_BY_EXT = { + js: 'text/javascript', + html: 'text/html', + css: 'text/css', + ico: 'image/x-icon', + // TODO: will need more for images +}; + + +export function bodyParser(req: IncomingMessage): Promise<{ [key: string]: any } | null> { + return new Promise((resolve, reject) => { + let body: any = []; + req + .on('data', (chunk) => { + body.push(chunk); + // TODO: re-implement max size check + }) + .on('end', () => { + body = Buffer.concat(body).toString(); + // at this point, `body` has the entire request body stored in it as a string + try { + const resolveValue = JSON.parse(body); + resolve(resolveValue); + } catch (err: any) { + reject(new Error(`Failed to parse JSON: ${err.message}`)); + } + }); + }); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16cb6377..cd29bcca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,7 +131,7 @@ importers: version: 2.1.2(@types/node@20.14.12)(less@4.2.0) vite-tsconfig-paths: specifier: ^5.0.1 - version: 5.0.1(typescript@5.5.4)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)) + version: 5.0.1(typescript@5.5.4)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)) vitest: specifier: 'catalog:' version: 2.1.2(@types/node@20.14.12)(less@4.2.0) @@ -170,7 +170,7 @@ importers: version: 12.0.0 debug: specifier: 'catalog:' - version: 4.3.7(supports-color@9.4.0) + version: 4.3.7 diff: specifier: ^5.2.0 version: 5.2.0 @@ -231,9 +231,6 @@ importers: typescript: specifier: 'catalog:' version: 5.5.4 - uWebSockets.js: - specifier: github:uNetworking/uWebSockets.js#semver:^20.49.0 - version: https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/442087c0a01bf146acb7386910739ec81df06700 validate-npm-package-name: specifier: ^5.0.0 version: 5.0.0 @@ -409,7 +406,7 @@ importers: version: 0.25.5(astro@4.15.9(@types/node@20.14.12)(less@4.2.0)(rollup@4.21.3)(typescript@5.5.4)) '@astrojs/vue': specifier: ^4.5.0 - version: 4.5.0(astro@4.15.9(@types/node@20.14.12)(less@4.2.0)(rollup@4.21.3)(typescript@5.5.4))(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) + version: 4.5.0(astro@4.15.9(@types/node@20.14.12)(less@4.2.0)(rollup@4.21.3)(typescript@5.5.4))(rollup@4.21.3)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) '@dmno/astro-integration': specifier: workspace:* version: link:../integrations/astro @@ -1582,16 +1579,6 @@ packages: '@emotion/hash@0.9.1': resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} - '@esbuild-plugins/node-globals-polyfill@0.2.3': - resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} - peerDependencies: - esbuild: '*' - - '@esbuild-plugins/node-modules-polyfill@0.2.2': - resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} - peerDependencies: - esbuild: '*' - '@esbuild/aix-ppc64@0.19.11': resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} engines: {node: '>=12'} @@ -6231,9 +6218,6 @@ packages: estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} - estree-walker@0.6.1: - resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -8806,10 +8790,6 @@ packages: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - npm-run-path@6.0.0: - resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} - engines: {node: '>=18'} - npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} deprecated: This package is no longer supported. @@ -9118,10 +9098,6 @@ packages: resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} engines: {node: '>=12'} - parse-ms@4.0.0: - resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} - engines: {node: '>=18'} - parse-node-version@1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} @@ -10982,10 +10958,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - uWebSockets.js@https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/442087c0a01bf146acb7386910739ec81df06700: - resolution: {tarball: https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/442087c0a01bf146acb7386910739ec81df06700} - version: 20.49.0 - ufo@1.5.3: resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} @@ -11833,21 +11805,6 @@ packages: resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} engines: {node: '>= 10.0.0'} - workerd@1.20241106.1: - resolution: {integrity: sha512-1GdKl0kDw8rrirr/ThcK66Kbl4/jd4h8uHx5g7YHBrnenY5SX1UPuop2cnCzYUxlg55kPjzIqqYslz1muRFgFw==} - engines: {node: '>=16'} - hasBin: true - - wrangler@3.91.0: - resolution: {integrity: sha512-Hdzn6wbY9cz5kL85ZUvWLwLIH7nPaEVRblfms40jhRf4qQO/Zf74aFlku8rQFbe8/2aVZFaxJVfBd6JQMeMSBQ==} - engines: {node: '>=16.17.0'} - hasBin: true - peerDependencies: - '@cloudflare/workers-types': ^4.20241106.0 - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -12226,13 +12183,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/vue@4.5.0(astro@4.15.9(@types/node@20.14.12)(less@4.2.0)(rollup@4.21.3)(typescript@5.5.4))(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': + '@astrojs/vue@4.5.0(astro@4.15.9(@types/node@20.14.12)(less@4.2.0)(rollup@4.21.3)(typescript@5.5.4))(rollup@4.21.3)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': dependencies: - '@vitejs/plugin-vue': 5.1.4(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) - '@vitejs/plugin-vue-jsx': 4.0.0(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) + '@vitejs/plugin-vue': 5.1.4(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) + '@vitejs/plugin-vue-jsx': 4.0.0(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) '@vue/compiler-sfc': 3.4.30 astro: 4.15.9(@types/node@20.14.12)(less@4.2.0)(rollup@4.21.3)(typescript@5.5.4) - vite-plugin-vue-devtools: 7.5.2(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) + vite-plugin-vue-devtools: 7.5.2(rollup@4.21.3)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) vue: 3.5.8(typescript@5.5.4) transitivePeerDependencies: - '@nuxt/kit' @@ -13322,9 +13279,6 @@ snapshots: '@esbuild/linux-x64@0.23.0': optional: true - '@esbuild/netbsd-x64@0.17.19': - optional: true - '@esbuild/netbsd-x64@0.17.6': optional: true @@ -13349,9 +13303,6 @@ snapshots: '@esbuild/openbsd-arm64@0.23.0': optional: true - '@esbuild/openbsd-x64@0.17.19': - optional: true - '@esbuild/openbsd-x64@0.17.6': optional: true @@ -13436,9 +13387,6 @@ snapshots: '@esbuild/win32-ia32@0.23.0': optional: true - '@esbuild/win32-x64@0.17.19': - optional: true - '@esbuild/win32-x64@0.17.6': optional: true @@ -15654,25 +15602,25 @@ snapshots: dependencies: vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) - '@vitejs/plugin-vue-jsx@4.0.0(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': + '@vitejs/plugin-vue-jsx@4.0.0(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': dependencies: '@babel/core': 7.24.7 '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.7) '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.7) - vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) + vite: 5.4.11(@types/node@20.14.12)(less@4.2.0) vue: 3.5.8(typescript@5.5.4) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.1.4(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4))': + '@vitejs/plugin-vue@5.1.4(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': dependencies: - vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) - vue: 3.5.12(typescript@5.5.4) + vite: 5.4.11(@types/node@20.14.12)(less@4.2.0) + vue: 3.5.8(typescript@5.5.4) - '@vitejs/plugin-vue@5.1.4(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': + '@vitejs/plugin-vue@5.1.4(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4))': dependencies: vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) - vue: 3.5.8(typescript@5.5.4) + vue: 3.5.12(typescript@5.5.4) '@vitest/expect@2.1.2': dependencies: @@ -15977,19 +15925,19 @@ snapshots: '@vue/devtools-api@6.6.4': {} - '@vue/devtools-core@7.5.2(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4))': + '@vue/devtools-core@7.5.2(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': dependencies: '@vue/devtools-kit': 7.5.2 '@vue/devtools-shared': 7.5.2 mitt: 3.0.1 nanoid: 3.3.7 pathe: 1.1.2 - vite-hot-client: 0.2.3(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)) - vue: 3.5.12(typescript@5.5.4) + vite-hot-client: 0.2.3(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)) + vue: 3.5.8(typescript@5.5.4) transitivePeerDependencies: - vite - '@vue/devtools-core@7.5.2(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4))': + '@vue/devtools-core@7.5.2(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4))': dependencies: '@vue/devtools-kit': 7.5.2 '@vue/devtools-shared': 7.5.2 @@ -15997,7 +15945,7 @@ snapshots: nanoid: 3.3.7 pathe: 1.1.2 vite-hot-client: 0.2.3(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)) - vue: 3.5.8(typescript@5.5.4) + vue: 3.5.12(typescript@5.5.4) transitivePeerDependencies: - vite @@ -16980,13 +16928,6 @@ snapshots: caniuse-lite@1.0.30001663: {} - capnp-ts@0.7.0: - dependencies: - debug: 4.3.7(supports-color@9.4.0) - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - ccount@2.0.1: {} chai@5.1.1: @@ -17531,6 +17472,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.3.7: + dependencies: + ms: 2.1.3 + debug@4.3.7(supports-color@9.4.0): dependencies: ms: 2.1.3 @@ -17813,7 +17758,7 @@ snapshots: base64id: 2.0.0 cookie: 0.4.2 cors: 2.8.5 - debug: 4.3.7(supports-color@9.4.0) + debug: 4.3.7 engine.io-parser: 5.2.3 ws: 8.17.1 transitivePeerDependencies: @@ -21463,25 +21408,6 @@ snapshots: min-indent@1.0.1: {} - miniflare@3.20241106.1: - dependencies: - '@cspotcode/source-map-support': 0.8.1 - acorn: 8.12.1 - acorn-walk: 8.3.3 - capnp-ts: 0.7.0 - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - stoppable: 1.1.0 - undici: 5.28.4 - workerd: 1.20241106.1 - ws: 8.18.0 - youch: 3.3.4 - zod: 3.23.8 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -23479,20 +23405,6 @@ snapshots: dependencies: glob: 7.2.3 - rollup-plugin-inject@3.0.2: - dependencies: - estree-walker: 0.6.1 - magic-string: 0.25.9 - rollup-pluginutils: 2.8.2 - - rollup-plugin-node-polyfills@0.2.1: - dependencies: - rollup-plugin-inject: 3.0.2 - - rollup-pluginutils@2.8.2: - dependencies: - estree-walker: 0.6.1 - rollup@4.19.0: dependencies: '@types/estree': 1.0.5 @@ -23851,7 +23763,7 @@ snapshots: socket.io-adapter@2.5.5: dependencies: - debug: 4.3.7(supports-color@9.4.0) + debug: 4.3.7 ws: 8.17.1 transitivePeerDependencies: - bufferutil @@ -23872,7 +23784,7 @@ snapshots: socket.io-parser@4.2.4: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7(supports-color@9.4.0) + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -23881,7 +23793,7 @@ snapshots: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.5 - debug: 4.3.7(supports-color@9.4.0) + debug: 4.3.7 engine.io: 6.6.1 socket.io-adapter: 2.5.5 socket.io-parser: 4.2.4 @@ -24515,7 +24427,7 @@ snapshots: cac: 6.7.14 chokidar: 3.6.0 consola: 3.2.3 - debug: 4.3.7(supports-color@9.4.0) + debug: 4.3.7 esbuild: 0.23.0 execa: 5.1.1 globby: 11.1.0 @@ -24684,8 +24596,6 @@ snapshots: typescript@5.5.4: {} - uWebSockets.js@https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/442087c0a01bf146acb7386910739ec81df06700: {} - ufo@1.5.3: {} uid-safe@2.1.5: @@ -25110,6 +25020,10 @@ snapshots: '@types/unist': 3.0.2 vfile-message: 4.0.2 + vite-hot-client@0.2.3(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)): + dependencies: + vite: 5.4.11(@types/node@20.14.12)(less@4.2.0) + vite-hot-client@0.2.3(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)): dependencies: vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) @@ -25135,7 +25049,7 @@ snapshots: vite-node@2.1.2(@types/node@20.14.12)(less@4.2.0): dependencies: cac: 6.7.14 - debug: 4.3.7(supports-color@9.4.0) + debug: 4.3.7 pathe: 1.1.2 vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) transitivePeerDependencies: @@ -25149,6 +25063,22 @@ snapshots: - supports-color - terser + vite-plugin-inspect@0.8.7(rollup@4.21.3)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)): + dependencies: + '@antfu/utils': 0.7.10 + '@rollup/pluginutils': 5.1.0(rollup@4.21.3) + debug: 4.3.7(supports-color@9.4.0) + error-stack-parser-es: 0.1.5 + fs-extra: 11.2.0 + open: 10.1.0 + perfect-debounce: 1.0.0 + picocolors: 1.1.0 + sirv: 2.0.4 + vite: 5.4.11(@types/node@20.14.12)(less@4.2.0) + transitivePeerDependencies: + - rollup + - supports-color + vite-plugin-inspect@0.8.7(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)): dependencies: '@antfu/utils': 0.7.10 @@ -25165,25 +25095,25 @@ snapshots: - rollup - supports-color - vite-plugin-vue-devtools@7.5.2(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4)): + vite-plugin-vue-devtools@7.5.2(rollup@4.21.3)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)): dependencies: - '@vue/devtools-core': 7.5.2(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4)) + '@vue/devtools-core': 7.5.2(vite@5.4.11(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) '@vue/devtools-kit': 7.5.2 '@vue/devtools-shared': 7.5.2 execa: 8.0.1 sirv: 2.0.4 - vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) - vite-plugin-inspect: 0.8.7(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)) - vite-plugin-vue-inspector: 5.2.0(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)) + vite: 5.4.11(@types/node@20.14.12)(less@4.2.0) + vite-plugin-inspect: 0.8.7(rollup@4.21.3)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)) + vite-plugin-vue-inspector: 5.2.0(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)) transitivePeerDependencies: - '@nuxt/kit' - rollup - supports-color - vue - vite-plugin-vue-devtools@7.5.2(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)): + vite-plugin-vue-devtools@7.5.2(rollup@4.21.3)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4)): dependencies: - '@vue/devtools-core': 7.5.2(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.8(typescript@5.5.4)) + '@vue/devtools-core': 7.5.2(vite@5.4.6(@types/node@20.14.12)(less@4.2.0))(vue@3.5.12(typescript@5.5.4)) '@vue/devtools-kit': 7.5.2 '@vue/devtools-shared': 7.5.2 execa: 8.0.1 @@ -25197,6 +25127,21 @@ snapshots: - supports-color - vue + vite-plugin-vue-inspector@5.2.0(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)): + dependencies: + '@babel/core': 7.25.2 + '@babel/plugin-proposal-decorators': 7.24.1(@babel/core@7.25.2) + '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.25.2) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.25.2) + '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2) + '@vue/compiler-dom': 3.5.12 + kolorist: 1.8.0 + magic-string: 0.30.11 + vite: 5.4.11(@types/node@20.14.12)(less@4.2.0) + transitivePeerDependencies: + - supports-color + vite-plugin-vue-inspector@5.2.0(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)): dependencies: '@babel/core': 7.25.2 @@ -25217,13 +25162,13 @@ snapshots: svgo: 3.3.2 vue: 3.5.12(typescript@5.5.4) - vite-tsconfig-paths@5.0.1(typescript@5.5.4)(vite@5.4.6(@types/node@20.14.12)(less@4.2.0)): + vite-tsconfig-paths@5.0.1(typescript@5.5.4)(vite@5.4.11(@types/node@20.14.12)(less@4.2.0)): dependencies: debug: 4.3.7(supports-color@9.4.0) globrex: 0.1.2 tsconfck: 3.1.0(typescript@5.5.4) optionalDependencies: - vite: 5.4.6(@types/node@20.14.12)(less@4.2.0) + vite: 5.4.11(@types/node@20.14.12)(less@4.2.0) transitivePeerDependencies: - supports-color - typescript @@ -25272,7 +25217,7 @@ snapshots: '@vitest/spy': 2.1.2 '@vitest/utils': 2.1.2 chai: 5.1.1 - debug: 4.3.7(supports-color@9.4.0) + debug: 4.3.7 magic-string: 0.30.12 pathe: 1.1.2 std-env: 3.7.0