diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 5a49e3f2d..26e58be4f 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -2,6 +2,7 @@ "name": "@homarr/nextjs", "version": "0.1.0", "private": true, + "type": "module", "scripts": { "build": "pnpm with-env next build", "clean": "git clean -xdf .next .turbo node_modules", @@ -38,7 +39,7 @@ "@tiptap/extension-link": "^2.2.4", "@tiptap/react": "^2.2.4", "@tiptap/starter-kit": "^2.2.4", - "@trpc/client": "next", + "@trpc/client": "11.0.0-next-beta.316", "@trpc/next": "next", "@trpc/react-query": "next", "@trpc/server": "next", @@ -63,8 +64,10 @@ "@types/react-dom": "^18.2.22", "@types/chroma-js": "2.4.4", "dotenv-cli": "^7.4.1", + "concurrently": "^8.2.2", "eslint": "^8.57.0", "prettier": "^3.2.5", + "tsx": "^4.7.1", "typescript": "^5.4.2" }, "eslintConfig": { diff --git a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx index dcf7d63a1..00a923407 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx @@ -5,11 +5,21 @@ import { useState } from "react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experimental"; -import { loggerLink, unstable_httpBatchStreamLink } from "@trpc/client"; +import { + createWSClient, + loggerLink, + unstable_httpBatchStreamLink, + wsLink, +} from "@trpc/client"; import superjson from "superjson"; +import type { AppRouter } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; +const wsClient = createWSClient({ + url: "ws://localhost:3001", +}); + export function TRPCReactProvider(props: PropsWithChildren) { const [queryClient] = useState( () => @@ -22,26 +32,39 @@ export function TRPCReactProvider(props: PropsWithChildren) { }), ); - const [trpcClient] = useState(() => - clientApi.createClient({ + const [trpcClient] = useState(() => { + return clientApi.createClient({ links: [ loggerLink({ enabled: (opts) => process.env.NODE_ENV === "development" || (opts.direction === "down" && opts.result instanceof Error), }), - unstable_httpBatchStreamLink({ - transformer: superjson, - url: getBaseUrl() + "/api/trpc", - headers() { - const headers = new Headers(); - headers.set("x-trpc-source", "nextjs-react"); - return headers; - }, - }), + (args) => { + return ({ op, next }) => { + console.log("op", op.type, op.input, op.path, op.id); + if (op.type === "subscription") { + const link = wsLink({ + client: wsClient, + transformer: superjson, + }); + return link(args)({ op, next }); + } + + return unstable_httpBatchStreamLink({ + transformer: superjson, + url: `${getBaseUrl()}/api/trpc`, + headers() { + const headers = new Headers(); + headers.set("x-trpc-source", "nextjs-react"); + return headers; + }, + })(args)({ op, next }); + }; + }, ], - }), - ); + }); + }); return ( diff --git a/apps/nextjs/src/app/[locale]/manage/page.tsx b/apps/nextjs/src/app/[locale]/manage/page.tsx index d45aeb0e1..a625622ce 100644 --- a/apps/nextjs/src/app/[locale]/manage/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/page.tsx @@ -1,6 +1,8 @@ import { getScopedI18n } from "@homarr/translation/server"; import { Title } from "@homarr/ui"; +import { Test } from "./test"; + export async function generateMetadata() { const t = await getScopedI18n("management"); const metaTitle = `${t("metaTitle")} • Homarr`; @@ -24,6 +26,7 @@ export default async function ManagementPage() { return ( <> {t(timeOfDay, { username: "admin" })} + ); } diff --git a/apps/nextjs/src/app/[locale]/manage/test.tsx b/apps/nextjs/src/app/[locale]/manage/test.tsx new file mode 100644 index 000000000..abdf3a520 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/manage/test.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { useState } from "react"; + +import { clientApi } from "@homarr/api/client"; +import { Stack, Text } from "@homarr/ui"; + +export const Test = () => { + const [value, setValue] = useState(0); + clientApi.user.test.useSubscription(undefined, { + onData(data) { + setValue(data); + }, + onError(err) { + alert(err); + }, + }); + return ( + + This will change after one second: {value} + + ); +}; diff --git a/apps/nextjs/src/app/api/trpc/[trpc]/route.ts b/apps/nextjs/src/app/api/trpc/[trpc]/route.ts index ef65a1ee6..74ff0f7d9 100644 --- a/apps/nextjs/src/app/api/trpc/[trpc]/route.ts +++ b/apps/nextjs/src/app/api/trpc/[trpc]/route.ts @@ -2,6 +2,7 @@ import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; import { appRouter, createTRPCContext } from "@homarr/api"; import { auth } from "@homarr/auth"; +import { logger } from "@homarr/log"; /** * Configure basic CORS headers @@ -29,8 +30,10 @@ const handler = auth(async (req) => { req, createContext: () => createTRPCContext({ session: req.auth, headers: req.headers }), - onError({ error, path }) { - console.error(`>>> tRPC Error on '${path}'`, error); + onError({ error, path, type }) { + logger.error( + `tRPC Error with ${type} on '${path}': (${error.code}) - ${error.message}`, + ); }, }); diff --git a/packages/api/package.json b/packages/api/package.json index c14136508..4b6164cb9 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -10,7 +10,9 @@ "main": "./index.ts", "types": "./index.ts", "license": "MIT", + "type": "module", "scripts": { + "dev": "pnpm tsx ./src/wssDevServer.ts", "clean": "rm -rf .turbo node_modules", "lint": "eslint .", "format": "prettier --check . --ignore-path ../../.gitignore", @@ -18,17 +20,20 @@ }, "dependencies": { "@homarr/auth": "workspace:^0.1.0", - "@homarr/definitions": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", + "@homarr/definitions": "workspace:^0.1.0", + "@homarr/log": "workspace:^", "@homarr/validation": "workspace:^0.1.0", "@trpc/client": "next", "@trpc/server": "next", - "superjson": "2.2.1" + "superjson": "2.2.1", + "ws": "^8.16.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", + "@types/ws": "^8.5.10", "eslint": "^8.57.0", "prettier": "^3.2.5", "typescript": "^5.4.2" diff --git a/packages/api/src/router/user.ts b/packages/api/src/router/user.ts index bcc921e14..0aa02f5f7 100644 --- a/packages/api/src/router/user.ts +++ b/packages/api/src/router/user.ts @@ -1,6 +1,5 @@ -import "server-only"; - import { TRPCError } from "@trpc/server"; +import { observable } from "@trpc/server/observable"; import { createSalt, hashPassword } from "@homarr/auth"; import type { Database } from "@homarr/db"; @@ -99,6 +98,15 @@ export const userRouter = createTRPCRouter({ }) .where(eq(users.id, input.userId)); }), + test: publicProcedure.subscription(() => { + return observable((emit) => { + let counter = 0; + setInterval(() => { + counter = counter + 1; + emit.next(counter); + }, 1000); + }); + }), }); const createUser = async ( diff --git a/packages/api/src/trpc.ts b/packages/api/src/trpc.ts index 3ef11e351..08a2ede92 100644 --- a/packages/api/src/trpc.ts +++ b/packages/api/src/trpc.ts @@ -12,6 +12,7 @@ import superjson from "superjson"; import type { Session } from "@homarr/auth"; import { auth } from "@homarr/auth"; import { db } from "@homarr/db"; +import { logger } from "@homarr/log"; import { ZodError } from "@homarr/validation"; /** @@ -33,7 +34,10 @@ export const createTRPCContext = async (opts: { const session = opts.session ?? (await auth()); const source = opts.headers.get("x-trpc-source") ?? "unknown"; - console.log(">>> tRPC Request from", source, "by", session?.user); + logger.info( + `tRPC request from ${source} by user '${session?.user.id}'`, + session?.user, + ); return { session, diff --git a/packages/api/src/wssDevServer.ts b/packages/api/src/wssDevServer.ts new file mode 100644 index 000000000..1f09640a0 --- /dev/null +++ b/packages/api/src/wssDevServer.ts @@ -0,0 +1,53 @@ +import { applyWSSHandler } from "@trpc/server/adapters/ws"; +import { WebSocketServer } from "ws"; + +import { logger } from "@homarr/log"; + +import { appRouter } from "./root"; +import { createTRPCContext } from "./trpc"; + +const wss = new WebSocketServer({ + port: 3001, +}); +const handler = applyWSSHandler({ + wss, + router: appRouter, + createContext: ({ req }) => { + return createTRPCContext({ + headers: { + ...req.headers, + get(key: string) { + const item = req.headers[key]; + return typeof item === "string" ? item ?? null : item?.at(0) ?? null; + }, + } as Headers, + session: { + // TODO: replace with actual session + user: { + id: "1", + name: "Test User", + email: "", + }, + expires: new Date().toISOString(), + }, + }); + }, +}); + +wss.on("connection", (ws, incomingMessage) => { + logger.info( + `➕ Connection (${wss.clients.size}) ${incomingMessage.method} ${incomingMessage.url}`, + ); + ws.once("close", (code, reason) => { + logger.info( + `➖ Connection (${wss.clients.size}) ${code} ${reason.toString()}`, + ); + }); +}); +logger.info("✅ WebSocket Server listening on ws://localhost:3001"); + +process.on("SIGTERM", () => { + logger.info("SIGTERM"); + handler.broadcastReconnectNotification(); + wss.close(); +}); diff --git a/packages/auth/package.json b/packages/auth/package.json index 218cb898d..ca36521fa 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,7 @@ { "name": "@homarr/auth", "version": "0.1.0", + "type": "module", "exports": { ".": "./index.ts", "./security": "./security.ts", diff --git a/packages/common/package.json b/packages/common/package.json index ef550162c..98512fe57 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -2,6 +2,7 @@ "name": "@homarr/common", "private": true, "version": "0.1.0", + "type": "module", "exports": { ".": "./index.ts" }, diff --git a/packages/definitions/package.json b/packages/definitions/package.json index de12d483d..f1e9b9f79 100644 --- a/packages/definitions/package.json +++ b/packages/definitions/package.json @@ -2,6 +2,7 @@ "name": "@homarr/definitions", "private": true, "version": "0.1.0", + "type": "module", "exports": { ".": "./index.ts" }, diff --git a/packages/validation/package.json b/packages/validation/package.json index f28575de3..caf2fb740 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -2,6 +2,7 @@ "name": "@homarr/validation", "private": true, "version": "0.1.0", + "type": "module", "exports": { ".": "./index.ts" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c202dce60..36550d6b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -211,14 +211,14 @@ importers: specifier: ^2.2.4 version: 2.2.4(@tiptap/pm@2.2.4) '@trpc/client': - specifier: next - version: 11.0.0-next-beta.289(@trpc/server@11.0.0-next-beta.289) + specifier: 11.0.0-next-beta.316 + version: 11.0.0-next-beta.316(@trpc/server@11.0.0-next-beta.289) '@trpc/next': specifier: next - version: 11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.289)(@trpc/react-query@11.0.0-next-beta.289)(@trpc/server@11.0.0-next-beta.289)(next@14.1.3)(react-dom@18.2.0)(react@18.2.0) + version: 11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.316)(@trpc/react-query@11.0.0-next-beta.289)(@trpc/server@11.0.0-next-beta.289)(next@14.1.3)(react-dom@18.2.0)(react@18.2.0) '@trpc/react-query': specifier: next - version: 11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.289)(@trpc/server@11.0.0-next-beta.289)(react-dom@18.2.0)(react@18.2.0) + version: 11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.316)(@trpc/server@11.0.0-next-beta.289)(react-dom@18.2.0)(react@18.2.0) '@trpc/server': specifier: next version: 11.0.0-next-beta.289 @@ -277,6 +277,9 @@ importers: '@types/react-dom': specifier: ^18.2.22 version: 18.2.22 + concurrently: + specifier: ^8.2.2 + version: 8.2.2 dotenv-cli: specifier: ^7.4.1 version: 7.4.1 @@ -286,6 +289,9 @@ importers: prettier: specifier: ^3.2.5 version: 3.2.5 + tsx: + specifier: ^4.7.1 + version: 4.7.1 typescript: specifier: ^5.4.2 version: 5.4.2 @@ -301,6 +307,9 @@ importers: '@homarr/definitions': specifier: workspace:^0.1.0 version: link:../definitions + '@homarr/log': + specifier: workspace:^ + version: link:../log '@homarr/validation': specifier: workspace:^0.1.0 version: link:../validation @@ -313,6 +322,9 @@ importers: superjson: specifier: 2.2.1 version: 2.2.1 + ws: + specifier: ^8.16.0 + version: 8.16.0 devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -323,6 +335,9 @@ importers: '@homarr/tsconfig': specifier: workspace:^0.1.0 version: link:../../tooling/typescript + '@types/ws': + specifier: ^8.5.10 + version: 8.5.10 eslint: specifier: ^8.57.0 version: 8.57.0 @@ -2964,7 +2979,15 @@ packages: '@trpc/server': 11.0.0-next-beta.289 dev: false - /@trpc/next@11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.289)(@trpc/react-query@11.0.0-next-beta.289)(@trpc/server@11.0.0-next-beta.289)(next@14.1.3)(react-dom@18.2.0)(react@18.2.0): + /@trpc/client@11.0.0-next-beta.316(@trpc/server@11.0.0-next-beta.289): + resolution: {integrity: sha512-SR5Z+LtvQ/IzY2ymSnbGYl4kB7GnqBktTH9o3YhGN2MrwgEJ9qNotVQ7wcAmhumpY26hJnXqG3hD5SZPZdeJlg==} + peerDependencies: + '@trpc/server': 11.0.0-next-beta.316+dcae8bd89 + dependencies: + '@trpc/server': 11.0.0-next-beta.289 + dev: false + + /@trpc/next@11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.316)(@trpc/react-query@11.0.0-next-beta.289)(@trpc/server@11.0.0-next-beta.289)(next@14.1.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-AKCrcbtHh/zFrld6lMG0RC37d/aac4ZisLDjJcViMnEmJXCo0J5nhoZa6f+G9N683NdMWZVmY2rmJidw9IX3QQ==} peerDependencies: '@tanstack/react-query': ^5.0.0 @@ -2981,15 +3004,15 @@ packages: optional: true dependencies: '@tanstack/react-query': 5.28.0(react@18.2.0) - '@trpc/client': 11.0.0-next-beta.289(@trpc/server@11.0.0-next-beta.289) - '@trpc/react-query': 11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.289)(@trpc/server@11.0.0-next-beta.289)(react-dom@18.2.0)(react@18.2.0) + '@trpc/client': 11.0.0-next-beta.316(@trpc/server@11.0.0-next-beta.289) + '@trpc/react-query': 11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.316)(@trpc/server@11.0.0-next-beta.289)(react-dom@18.2.0)(react@18.2.0) '@trpc/server': 11.0.0-next-beta.289 next: 14.1.3(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)(sass@1.71.1) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@trpc/react-query@11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.289)(@trpc/server@11.0.0-next-beta.289)(react-dom@18.2.0)(react@18.2.0): + /@trpc/react-query@11.0.0-next-beta.289(@tanstack/react-query@5.28.0)(@trpc/client@11.0.0-next-beta.316)(@trpc/server@11.0.0-next-beta.289)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-SAn09DmZ4eFYLS0cCHOVNvRHJhHZ2ssUj4LUTj56wym0MieaCSrcxTqiolnaMfF+mWc1SJlLOzebrxaTHPwJSw==} peerDependencies: '@tanstack/react-query': ^5.0.0 @@ -2999,7 +3022,7 @@ packages: react-dom: '>=18.2.0' dependencies: '@tanstack/react-query': 5.28.0(react@18.2.0) - '@trpc/client': 11.0.0-next-beta.289(@trpc/server@11.0.0-next-beta.289) + '@trpc/client': 11.0.0-next-beta.316(@trpc/server@11.0.0-next-beta.289) '@trpc/server': 11.0.0-next-beta.289 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -3321,6 +3344,12 @@ packages: resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} dev: false + /@types/ws@8.5.10: + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + dependencies: + '@types/node': 20.11.27 + dev: true + /@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==} engines: {node: ^16.0.0 || >=18.0.0} @@ -4341,6 +4370,15 @@ packages: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} @@ -4447,6 +4485,22 @@ packages: readable-stream: 2.3.8 typedarray: 0.0.6 + /concurrently@8.2.2: + resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} + engines: {node: ^14.13.0 || >=16.0.0} + hasBin: true + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.1 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + dev: true + /consola@2.15.3: resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} @@ -4603,6 +4657,13 @@ packages: whatwg-url: 14.0.0 dev: true + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.23.9 + dev: true + /dayjs@1.11.10: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} dev: false @@ -5868,6 +5929,11 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true @@ -8439,6 +8505,11 @@ packages: engines: {node: '>=0.10'} dev: true + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -8730,6 +8801,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + /shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + dev: true + /shelljs@0.8.5: resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} engines: {node: '>=4'} @@ -8847,6 +8922,10 @@ packages: engines: {node: '>= 8'} dev: true + /spawn-command@0.0.2: + resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + dev: true + /sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} dev: true @@ -9377,6 +9456,17 @@ packages: engines: {node: '>=0.6.x'} dev: false + /tsx@4.7.1: + resolution: {integrity: sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + esbuild: 0.19.12 + get-tsconfig: 4.7.2 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: @@ -10133,7 +10223,6 @@ packages: optional: true utf-8-validate: optional: true - dev: true /xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} @@ -10148,6 +10237,11 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -10159,6 +10253,19 @@ packages: engines: {node: '>=12'} dev: true + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + 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 + dev: true + /yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'}