diff --git a/.dockerignore b/.dockerignore index d926ae054..0aed2410c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,10 +1,13 @@ node_modules npm-debug.log -Dockerfile +*Dockerfile .dockerignore .git .gitignore bin -dist +*/*/dist* +*/*/build* + .pseudotv -.dizquetv \ No newline at end of file +.dizquetv +.tunarr \ No newline at end of file diff --git a/build.Dockerfile b/build.Dockerfile new file mode 100644 index 000000000..f99f00eee --- /dev/null +++ b/build.Dockerfile @@ -0,0 +1,69 @@ +FROM node:20-alpine3.19 AS base + +# Update +RUN apk add --no-cache libc6-compat +RUN apk update + +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" + +RUN corepack enable + +FROM base as sources +WORKDIR /tunarr +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ +COPY server/ ./server +COPY shared/ ./shared +COPY types ./types +COPY web2 ./web2 + +FROM sources AS prod-deps +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile + +### Begin server build ### +FROM sources AS build-server +# Install deps +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile +# Build common modules +RUN pnpm run --filter=types --filter=shared build +# Runs tsc --noEmit on the server to ensure the code builds +RUN pnpm run --filter=server typecheck +# Build ORM metadata cache using source files +RUN cd server && pnpm mikro-orm-esm cache:generate --combined --ts +# Replace the non-cached metadata config with the cache +RUN mv server/mikro-orm.prod.config.ts server/mikro-orm.config.ts +# Build and bundle the server +RUN pnpm run --filter=server bundle +### End server build ### + +### Begin server web ### +FROM sources AS build-web +# Install deps +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile +# Build common modules +RUN pnpm run --filter=types --filter=shared build +RUN pnpm run --filter=web build + +### Experimental: Build a SEA +FROM build-server AS build-exec +COPY --from=build-server /tunarr/server/node_modules /tunarr/server/node_modules +COPY --from=build-server /tunarr/server/build /tunarr/server/build +RUN pnpm run --filter=server make-exec +### + +### Begin server run ### +FROM base AS server +COPY --from=prod-deps /tunarr/node_modules /tunarr/node_modules +COPY --from=prod-deps /tunarr/server/node_modules /tunarr/server/node_modules +COPY --from=build-server /tunarr/types /tunarr/types +COPY --from=build-server /tunarr/shared /tunarr/shared +COPY --from=build-server /tunarr/server/package.json /tunarr/server/package.json +COPY --from=build-server /tunarr/server/build /tunarr/server/build +ENV TUNARR_BIND_ADDR=0.0.0.0 +EXPOSE 8000 +CMD [ "/tunarr/server/build/bundle.js" ] +### Begin server run + +### Full stack ### +FROM server AS full-stack +COPY --from=build-web /tunarr/web2/dist /tunarr/server/build/web diff --git a/nvidia.Dockerfile b/nvidia.Dockerfile new file mode 100644 index 000000000..94551432b --- /dev/null +++ b/nvidia.Dockerfile @@ -0,0 +1,77 @@ +# Setup a node + ffmpeg + nvidia base +FROM jrottenberg/ffmpeg:4.4.4-nvidia2204 AS ffmpeg-base +ENV NODE_MAJOR=20 + +# Install musl for native node bindings (sqlite) +RUN apt-get install -y musl-dev +RUN ln -s /usr/lib/x86_64-linux-musl/libc.so /lib/libc.musl-x86_64.so.1 + +# Install node +RUN <=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + '@jridgewell/gen-mapping': 0.3.3 + jsesc: 2.5.2 + dev: true + /@babel/generator@7.23.6: resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} engines: {node: '>=6.9.0'} @@ -659,6 +698,14 @@ packages: js-tokens: 4.0.0 dev: true + /@babel/parser@7.18.4: + resolution: {integrity: sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.6 + dev: true + /@babel/parser@7.23.3: resolution: {integrity: sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==} engines: {node: '>=6.0.0'} @@ -716,6 +763,15 @@ packages: - supports-color dev: true + /@babel/types@7.19.0: + resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + /@babel/types@7.23.3: resolution: {integrity: sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==} engines: {node: '>=6.9.0'} @@ -1452,6 +1508,18 @@ packages: resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: true + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + /@jercle/yargonaut@1.1.5: resolution: {integrity: sha512-zBp2myVvBHp1UaJsNTyS6q4UDKT7eRiqTS4oNTS6VQMd6mpxYOdbeK4pY279cDCdakGy6hG0J3ejoXZVsPwHqw==} dependencies: @@ -1646,7 +1714,7 @@ packages: '@mikro-orm/core': 6.0.4 globby: 11.1.0 ts-morph: 21.0.1 - dev: false + dev: true /@mui/base@5.0.0-beta.23(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-9L8SQUGAWtd/Qi7Qem26+oSSgpY7f2iQTuvcz/rsGpyZjSomMMO6lwYeQSA0CpWM7+aN7eGoSY/WV6wxJiIxXw==} @@ -1997,6 +2065,13 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + /@popperjs/core@2.11.8: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false @@ -2310,7 +2385,7 @@ packages: minimatch: 9.0.3 mkdirp: 3.0.1 path-browserify: 1.0.1 - dev: false + dev: true /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} @@ -2441,11 +2516,11 @@ packages: /@types/lodash-es@4.17.10: resolution: {integrity: sha512-YJP+w/2khSBwbUSFdGsSqmDvmnN3cCKoPOL7Zjle6s30ZtemkkqhjVfFqGwPN7ASil5VyjE2GtyU/yqYY6mC0A==} dependencies: - '@types/lodash': 4.14.200 + '@types/lodash': 4.14.202 dev: true - /@types/lodash@4.14.200: - resolution: {integrity: sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q==} + /@types/lodash@4.14.202: + resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} dev: true /@types/mime@1.3.5: @@ -2854,6 +2929,15 @@ packages: engines: {node: '>= 18.18.0'} dev: false + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + dev: true + /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -2910,6 +2994,11 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -2927,6 +3016,11 @@ packages: engines: {node: '>=10'} dev: true + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: true @@ -3025,6 +3119,11 @@ packages: /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + /at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + /atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} @@ -3157,7 +3256,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: false /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -3360,6 +3458,16 @@ packages: resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} dev: true + /bundle-require@4.0.2(esbuild@0.19.5): + resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.17' + dependencies: + esbuild: 0.19.5 + load-tsconfig: 0.2.5 + dev: true + /busboy@0.3.1: resolution: {integrity: sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==} engines: {node: '>=4.5.0'} @@ -3540,8 +3648,8 @@ packages: restore-cursor: 2.0.0 dev: true - /cli-spinners@2.9.1: - resolution: {integrity: sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==} + /cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} dev: true @@ -3553,6 +3661,14 @@ packages: wrap-ansi: 5.1.0 dev: true + /cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -3595,7 +3711,7 @@ packages: /code-block-writer@12.0.0: resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==} - dev: false + dev: true /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -3666,6 +3782,16 @@ packages: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true @@ -4066,11 +4192,6 @@ packages: minimalistic-assert: 1.0.1 dev: true - /destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - dev: false - /detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} @@ -4174,6 +4295,10 @@ packages: resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} dev: true + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: false @@ -4206,22 +4331,21 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /enabled@2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} dev: false - /encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - dev: false - /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: once: 1.4.0 - /enhanced-resolve@5.15.0: - resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + /enhanced-resolve@5.15.1: + resolution: {integrity: sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 @@ -4458,11 +4582,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - dev: false - /eval-estree-expression@1.1.0: resolution: {integrity: sha512-6ZAHSb0wsqxutjk2lXZcW7btSc51I8BhlIetit0wIf5sOb5xDNBrIqe0g8RFyQ/EW6Xwn1szrtButztU7Vdj1Q==} dev: true @@ -4487,6 +4606,21 @@ packages: safe-buffer: 5.2.1 dev: true + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + 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 + dev: true + /execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} @@ -4543,17 +4677,6 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - /fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -4808,6 +4931,14 @@ packages: is-callable: 1.2.7 dev: true + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + /form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -4821,11 +4952,6 @@ packages: engines: {node: '>= 0.6'} dev: false - /fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - dev: false - /from2@2.3.0: resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} dependencies: @@ -4853,6 +4979,16 @@ packages: jsonfile: 6.1.0 universalify: 2.0.1 + /fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -4933,6 +5069,11 @@ packages: pump: 3.0.0 dev: true + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + /get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} @@ -4957,6 +5098,18 @@ packages: is-glob: 4.0.3 dev: true + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.1 + dev: true + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: @@ -4998,7 +5151,7 @@ packages: '@types/glob': 7.2.0 array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 + fast-glob: 3.3.2 glob: 7.2.3 ignore: 5.2.4 merge2: 1.4.1 @@ -5233,6 +5386,21 @@ packages: resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} dev: true + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + dev: true + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -5336,6 +5504,14 @@ packages: p-is-promise: 1.1.0 dev: true + /into-stream@6.0.0: + resolution: {integrity: sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==} + engines: {node: '>=10'} + dependencies: + from2: 2.3.0 + p-is-promise: 3.0.0 + dev: true + /ip@1.1.8: resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} dev: false @@ -5381,6 +5557,12 @@ packages: dependencies: hasown: 2.0.0 + /is-core-module@2.9.0: + resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==} + dependencies: + has: 1.0.4 + dev: true + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -5447,7 +5629,6 @@ packages: /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - dev: false /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} @@ -5484,6 +5665,20 @@ packages: is-object: 1.0.2 dev: true + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5711,9 +5906,13 @@ packages: set-cookie-parser: 2.6.0 dev: false + /lilconfig@3.1.1: + resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} + engines: {node: '>=14'} + dev: true + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: false /load-json-file@4.0.0: resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} @@ -5725,6 +5924,11 @@ packages: strip-bom: 3.0.0 dev: true + /load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /local-pkg@0.5.0: resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} engines: {node: '>=14'} @@ -5778,6 +5982,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + dev: true + /lodash.truncate@4.4.2: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} dev: false @@ -5850,6 +6058,11 @@ packages: engines: {node: '>=8'} dev: true + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + dev: true + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -5950,8 +6163,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - /meriyah@4.3.8: - resolution: {integrity: sha512-b1bddpQZK3FVr/x6KISsfNQdS9jVNgVuFDRi7I9AJbYVggdcA6ij9idboD0aW5ZYELsDMOubi58SDfsW81VakA==} + /meriyah@4.3.9: + resolution: {integrity: sha512-IepKx25Ph/5T67o+Q6Ezrt+repNAcJsydfsNWgelrdOhdcQcs4NI9qPHxB9Qz3WSYpj77hScNJrq5IjdwE1woQ==} engines: {node: '>=10.4.0'} dev: true @@ -5984,12 +6197,6 @@ packages: dependencies: mime-db: 1.52.0 - /mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - dev: false - /mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -6001,6 +6208,11 @@ packages: engines: {node: '>=4'} dev: true + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -6041,7 +6253,7 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: false + dev: true /minimist-options@3.0.2: resolution: {integrity: sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==} @@ -6054,6 +6266,11 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} @@ -6074,7 +6291,7 @@ packages: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} hasBin: true - dev: false + dev: true /mlly@1.4.2: resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} @@ -6148,6 +6365,14 @@ packages: readable-stream: 3.6.2 dev: true + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -6169,8 +6394,8 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true - /nexe@4.0.0-rc.2: - resolution: {integrity: sha512-icz+gIlYZ4zCrLo8zVChnbwAMB6ffqQKiF4vy/eehWbVkMlHTSNqlIwNmRlAq6dNmJCaKNEoff7nhunsXRSWeA==} + /nexe@4.0.0-rc.4: + resolution: {integrity: sha512-A135LPN7fdOyEYkm5BB8oEeISMYJM/cD0TysIEhlGc/WsuLBS6moMhk/2Lf65kdrAI+0S4Z1GHtSTGv3uwXfPA==} engines: {node: '>=10'} hasBin: true dependencies: @@ -6181,7 +6406,7 @@ packages: download: 8.0.0 globby: 11.1.0 got: 11.8.6 - meriyah: 4.3.8 + meriyah: 4.3.9 minimist: 1.2.8 mkdirp: 1.0.4 multistream: 4.1.0 @@ -6203,6 +6428,18 @@ packages: clone: 2.1.2 dev: false + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + /node-graceful-shutdown@1.1.0: resolution: {integrity: sha512-g1tq/R8ie/At5xRHGfF+chTge1jVPxf1NEClLpZIPxOPi6PJ9II81T35ms1u+s4N/mqOCp60CFd+ps+DIWRigQ==} engines: {node: '>=6'} @@ -6268,6 +6505,23 @@ packages: undefsafe: 2.0.5 dev: true + /nodemon@3.1.0: + resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + chokidar: 3.5.3 + debug: 4.3.4(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 7.5.4 + simple-update-notifier: 2.0.0 + supports-color: 5.5.0 + touch: 3.1.0 + undefsafe: 2.0.5 + dev: true + /noms@0.0.0: resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} dependencies: @@ -6318,6 +6572,13 @@ packages: pify: 3.0.0 dev: true + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + /npm-run-path@5.2.0: resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6374,13 +6635,6 @@ packages: ee-first: 1.1.1 dev: false - /on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - dependencies: - ee-first: 1.1.1 - dev: false - /on-headers@1.0.2: resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} engines: {node: '>= 0.8'} @@ -6404,6 +6658,13 @@ packages: mimic-fn: 1.2.0 dev: true + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + /onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -6463,7 +6724,7 @@ packages: dependencies: chalk: 2.4.2 cli-cursor: 2.1.0 - cli-spinners: 2.9.1 + cli-spinners: 2.9.2 log-symbols: 2.2.0 strip-ansi: 5.2.0 wcwidth: 1.0.1 @@ -6500,6 +6761,11 @@ packages: engines: {node: '>=4'} dev: true + /p-is-promise@3.0.0: + resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==} + engines: {node: '>=8'} + dev: true + /p-limit@1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} @@ -6641,11 +6907,6 @@ packages: lines-and-columns: 1.2.4 dev: false - /parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - dev: false - /pastable@2.2.1(react@18.2.0): resolution: {integrity: sha512-K4ClMxRKpgN4sXj6VIPPrvor/TMp2yPNCGtfhvV106C73SwefQ3FuegURsH7AQHpqu0WwbvKXRl1HQxF6qax9w==} engines: {node: '>=14.x'} @@ -6668,6 +6929,7 @@ packages: /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} @@ -6702,6 +6964,14 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.2.0 + minipass: 7.0.4 + dev: true + /path-to-regexp@6.2.1: resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} dev: false @@ -6806,6 +7076,28 @@ packages: thread-stream: 2.4.1 dev: false + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + + /pkg-fetch@3.4.2: + resolution: {integrity: sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==} + hasBin: true + dependencies: + chalk: 4.1.2 + fs-extra: 9.1.0 + https-proxy-agent: 5.0.1 + node-fetch: 2.7.0 + progress: 2.0.3 + semver: 7.5.4 + tar-fs: 2.1.1 + yargs: 16.2.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + /pkg-types@1.0.3: resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} dependencies: @@ -6814,11 +7106,56 @@ packages: pathe: 1.1.1 dev: true + /pkg@5.8.1: + resolution: {integrity: sha512-CjBWtFStCfIiT4Bde9QpJy0KeH19jCfwZRJqHFDFXfhUklCx8JoFmMj3wgnEYIwGmZVNkhsStPHEOnrtrQhEXA==} + hasBin: true + peerDependencies: + node-notifier: '>=9.0.1' + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@babel/generator': 7.18.2 + '@babel/parser': 7.18.4 + '@babel/types': 7.19.0 + chalk: 4.1.2 + fs-extra: 9.1.0 + globby: 11.1.0 + into-stream: 6.0.0 + is-core-module: 2.9.0 + minimist: 1.2.8 + multistream: 4.1.0 + pkg-fetch: 3.4.2 + prebuild-install: 7.1.1 + resolve: 1.22.8 + stream-meter: 1.0.4 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + /pony-cause@2.1.10: resolution: {integrity: sha512-3IKLNXclQgkU++2fSi93sQ6BznFuxSLB11HdvZQ6JW/spahf/P1pAHBQEahr20rs0htZW0UDkM1HmA+nZkXKsw==} engines: {node: '>=12.0.0'} dev: false + /postcss-load-config@4.0.2(ts-node@10.9.1): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.1 + ts-node: 10.9.1(@types/node@20.8.9)(typescript@5.3.3) + yaml: 2.3.4 + dev: true + /postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} @@ -6837,6 +7174,14 @@ packages: source-map-js: 1.0.2 dev: true + /postject@1.0.0-alpha.6: + resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + commander: 9.5.0 + dev: true + /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} engines: {node: '>=10'} @@ -6898,6 +7243,11 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: true + /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -7010,11 +7360,6 @@ packages: safe-buffer: 5.2.1 dev: true - /range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - dev: false - /raw-body@2.4.0: resolution: {integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==} engines: {node: '>= 0.8'} @@ -7279,9 +7624,9 @@ packages: /resolve-dependencies@6.0.9: resolution: {integrity: sha512-1BfxvQZyAjSC3Kkcov3ZhHQiLaXVWX1dhFjWyyrPA5yb9yeW9aSC8GQP6TtkJImM7XvitN7kHrLcQxG+1VU7Gg==} dependencies: - enhanced-resolve: 5.15.0 - fast-glob: 3.3.1 - meriyah: 4.3.8 + enhanced-resolve: 5.15.1 + fast-glob: 3.3.2 + meriyah: 4.3.9 dev: true /resolve-from@4.0.0: @@ -7345,6 +7690,14 @@ packages: glob: 7.2.3 dev: true + /rimraf@5.0.5: + resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} + engines: {node: '>=14'} + hasBin: true + dependencies: + glob: 10.3.10 + dev: true + /ripemd160@2.0.2: resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} dependencies: @@ -7450,39 +7803,6 @@ packages: dependencies: lru-cache: 6.0.0 - /send@0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} - engines: {node: '>= 0.8.0'} - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /serve-static@1.15.0: - resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} - engines: {node: '>= 0.8.0'} - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.18.0 - transitivePeerDependencies: - - supports-color - dev: false - /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true @@ -7651,6 +7971,13 @@ packages: engines: {node: '>=0.10.0'} dev: true + /source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + dependencies: + whatwg-url: 7.1.0 + dev: true + /spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: @@ -7740,6 +8067,12 @@ packages: xtend: 4.0.2 dev: true + /stream-meter@1.0.4: + resolution: {integrity: sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==} + dependencies: + readable-stream: 2.3.8 + dev: true + /stream-splicer@2.0.1: resolution: {integrity: sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==} dependencies: @@ -7779,6 +8112,15 @@ packages: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + /string_decoder@0.10.31: resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} dev: true @@ -7807,6 +8149,13 @@ packages: dependencies: ansi-regex: 5.0.1 + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + /strip-bom@2.0.0: resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} engines: {node: '>=0.10.0'} @@ -7825,6 +8174,11 @@ packages: is-natural-number: 4.0.1 dev: true + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -7867,6 +8221,20 @@ packages: minimist: 1.2.8 dev: true + /sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 10.3.10 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -7956,6 +8324,19 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + /thread-stream@2.4.1: resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==} dependencies: @@ -8051,6 +8432,21 @@ packages: nopt: 1.0.10 dev: true + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true + + /tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + dependencies: + punycode: 2.3.1 + dev: true + + /tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: true + /trim-newlines@2.0.0: resolution: {integrity: sha512-MTBWv3jhVjTU7XR3IQHllbiJs8sc75a80OEhB6or/q7pLTWgQ0bMGQXXYQSrSuXe6WiKWDZ5txXY5P59a/coVA==} engines: {node: '>=4'} @@ -8088,14 +8484,29 @@ packages: typescript: 5.2.2 dev: true + /ts-essentials@9.4.1(typescript@5.3.3): + resolution: {integrity: sha512-oke0rI2EN9pzHsesdmrOrnqv1eQODmJpd/noJjwj2ZPC3Z4N2wbjrOEqnsEgmvlO2+4fBb0a794DCna2elEVIQ==} + peerDependencies: + typescript: '>=4.1.0' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.3.3 + dev: true + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + /ts-morph@21.0.1: resolution: {integrity: sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==} dependencies: '@ts-morph/common': 0.22.0 code-block-writer: 12.0.0 - dev: false + dev: true - /ts-node@10.9.1(@types/node@20.8.9)(typescript@5.2.2): + /ts-node@10.9.1(@types/node@20.8.9)(typescript@5.3.3): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -8121,7 +8532,7 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.2.2 + typescript: 5.3.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -8152,7 +8563,7 @@ packages: strip-json-comments: 2.0.1 dev: true - /tsify@5.0.4(browserify@17.0.0)(typescript@5.2.2): + /tsify@5.0.4(browserify@17.0.0)(typescript@5.3.3): resolution: {integrity: sha512-XAZtQ5OMPsJFclkZ9xMZWkSNyMhMxEPsz3D2zu79yoKorH9j/DT4xCloJeXk5+cDhosEibu4bseMVjyPOAyLJA==} engines: {node: '>=0.12'} peerDependencies: @@ -8166,12 +8577,51 @@ packages: semver: 6.3.1 through2: 2.0.5 tsconfig: 5.0.3 - typescript: 5.2.2 + typescript: 5.3.3 dev: true /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tsup@8.0.2(ts-node@10.9.1)(typescript@5.3.3): + resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.0.2(esbuild@0.19.5) + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4(supports-color@5.5.0) + esbuild: 0.19.5 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 4.0.2(ts-node@10.9.1) + resolve-from: 5.0.0 + rollup: 4.9.5 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tree-kill: 1.2.2 + typescript: 5.3.3 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + /tty-browserify@0.0.1: resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} dev: true @@ -8232,6 +8682,12 @@ packages: hasBin: true dev: true + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + /ufo@1.3.1: resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==} dev: true @@ -8547,6 +9003,29 @@ packages: defaults: 1.0.4 dev: true + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + + /webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + dev: true + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + + /whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: true + /whence@2.0.0: resolution: {integrity: sha512-exmM13v2lg8juBbfS2tao/alV68jyryPXS+jf29NBNGLzE2hRgmzvQFQGX5CxNfH4Ag9qRqd6gGpXTH2JxqKHg==} engines: {node: '>=14'} @@ -8655,6 +9134,15 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -8705,6 +9193,11 @@ packages: decamelize: 1.2.0 dev: true + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -8724,6 +9217,19 @@ packages: yargs-parser: 13.1.2 dev: true + /yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 91ab49e6d..fa1e2b5de 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,5 @@ packages: - - "server/" - - "web2/" - - "types/" - - "shared/" \ No newline at end of file + - server + - web2 + - types + - shared \ No newline at end of file diff --git a/server/1.json b/server/1.json deleted file mode 100644 index fa830ddb7..000000000 --- a/server/1.json +++ /dev/null @@ -1 +0,0 @@ -{"items":[{"type":"content","id":"50b50157-3f03-4ca4-870c-5589c8e35993","durationMs":5526279},{"type":"content","id":"d7e04cc1-94fc-4b53-9cae-247937353851","durationMs":6308448},{"type":"content","id":"32084337-f1db-4459-a558-1b2845eb78df","durationMs":7436480},{"type":"content","id":"c1f9bed1-d3b1-4abc-bec4-d51a0587c0a8","durationMs":5053010},{"type":"content","id":"5020e186-f461-43cc-bbc1-345a085c1d05","durationMs":5776799}]} \ No newline at end of file diff --git a/server/cjs-shim.ts b/server/cjs-shim.ts new file mode 100644 index 000000000..b8f2373e2 --- /dev/null +++ b/server/cjs-shim.ts @@ -0,0 +1,7 @@ +import { createRequire } from 'node:module'; +import path from 'node:path'; +import url from 'node:url'; + +globalThis.require = createRequire(import.meta.url); +globalThis.__filename = url.fileURLToPath(import.meta.url); +globalThis.__dirname = path.dirname(__filename); diff --git a/server/esbuild/native-node-module.ts b/server/esbuild/native-node-module.ts new file mode 100644 index 000000000..bda9740e1 --- /dev/null +++ b/server/esbuild/native-node-module.ts @@ -0,0 +1,57 @@ +import path from 'path'; +import { Plugin } from 'esbuild'; + +// Copied from https://github.com/evanw/esbuild/issues/1051#issuecomment-806325487 +export const nativeNodeModulesPlugin = (): Plugin => { + return { + name: 'native-node-modules', + setup(build) { + // If a ".node" file is imported within a module in the "file" namespace, resolve + // it to an absolute path and put it into the "node-file" virtual namespace. + build.onResolve({ filter: /\.node$/, namespace: 'file' }, (args) => { + const resolvedId = require.resolve(args.path, { + paths: [args.resolveDir], + }); + if (resolvedId.endsWith('.node')) { + return { + path: resolvedId, + namespace: 'node-file', + }; + } + return { + path: resolvedId, + }; + }); + + // Files in the "node-file" virtual namespace call "require()" on the + // path from esbuild of the ".node" file in the output directory. + build.onLoad({ filter: /.*/, namespace: 'node-file' }, (args) => { + return { + contents: ` + import path from ${JSON.stringify(args.path)} + try { module.exports = require(path) } + catch {} + `, + resolveDir: path.dirname(args.path), + }; + }); + + // If a ".node" file is imported within a module in the "node-file" namespace, put + // it in the "file" namespace where esbuild's default loading behavior will handle + // it. It is already an absolute path since we resolved it to one above. + build.onResolve( + { filter: /\.node$/, namespace: 'node-file' }, + (args) => ({ + path: args.path, + namespace: 'file', + }), + ); + + // Tell esbuild's default loading behavior to use the "file" loader for + // these ".node" files. + const opts = build.initialOptions; + opts.loader = opts.loader || {}; + opts.loader['.node'] = 'file'; + }, + }; +}; diff --git a/server/esbuild/node-protocol.ts b/server/esbuild/node-protocol.ts new file mode 100644 index 000000000..ea31ba9fc --- /dev/null +++ b/server/esbuild/node-protocol.ts @@ -0,0 +1,24 @@ +import { Plugin } from 'esbuild'; + +/** + * The node: protocol was added to require in Node v14.18.0 + * https://nodejs.org/api/esm.html#node-imports + */ +export const nodeProtocolPlugin = (): Plugin => { + const nodeProtocol = 'node:'; + + return { + name: 'node-protocol-plugin', + setup({ onResolve }) { + onResolve( + { + filter: /^node:/, + }, + ({ path }) => ({ + path: path.slice(nodeProtocol.length), + external: true, + }), + ); + }, + }; +}; diff --git a/server/mikro-orm.base.config.ts b/server/mikro-orm.base.config.ts new file mode 100644 index 000000000..723581c8a --- /dev/null +++ b/server/mikro-orm.base.config.ts @@ -0,0 +1,46 @@ +import { + UnderscoreNamingStrategy, + defineConfig, +} from '@mikro-orm/better-sqlite'; +import { Migrator } from '@mikro-orm/migrations'; +import { fileURLToPath } from 'node:url'; +import path, { dirname } from 'path'; +import { CachedImage } from './src/dao/entities/CachedImage.js'; +import { Channel } from './src/dao/entities/Channel.js'; +import { ChannelFillerShow } from './src/dao/entities/ChannelFillerShow.js'; +import { CustomShow } from './src/dao/entities/CustomShow.js'; +import { CustomShowContent } from './src/dao/entities/CustomShowContent.js'; +import { FillerListContent } from './src/dao/entities/FillerListContent.js'; +import { FillerShow } from './src/dao/entities/FillerShow.js'; +import { PlexServerSettings } from './src/dao/entities/PlexServerSettings.js'; +import { Program } from './src/dao/entities/Program.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const dbPath = path.join(process.env.DB_PATH ?? '.dizquetv', 'db.db'); + +export default defineConfig({ + dbName: dbPath, + baseDir: __dirname, + entities: [ + CachedImage, + Channel, + ChannelFillerShow, + CustomShow, + CustomShowContent, + FillerListContent, + FillerShow, + PlexServerSettings, + Program, + ], + debug: !!process.env['DATABASE_DEBUG_LOGGING'], + namingStrategy: UnderscoreNamingStrategy, + forceUndefined: true, + dynamicImportProvider: (id) => import(id), + migrations: { + path: './migrations', + pathTs: './src/migrations', + }, + extensions: [Migrator], +}); diff --git a/server/mikro-orm.config.ts b/server/mikro-orm.config.ts index cf9765c5d..7739caace 100644 --- a/server/mikro-orm.config.ts +++ b/server/mikro-orm.config.ts @@ -1,30 +1,10 @@ -import { - UnderscoreNamingStrategy, - defineConfig, -} from '@mikro-orm/better-sqlite'; -import { Migrator } from '@mikro-orm/migrations'; +import { defineConfig } from '@mikro-orm/better-sqlite'; import { TsMorphMetadataProvider } from '@mikro-orm/reflection'; -import { fileURLToPath } from 'node:url'; -import path, { dirname } from 'path'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -const dbPath = path.join(process.env.DB_PATH ?? '.dizquetv', 'db.db'); +import baseConfig from './mikro-orm.base.config.js'; export default defineConfig({ - dbName: dbPath, - baseDir: __dirname, - entities: ['./build/dao/entities'], // path to our JS entities (dist), relative to `baseDir` - entitiesTs: ['./dao/entities'], // path to our TS entities (src), relative to `baseDir` - debug: !!process.env['DATABASE_DEBUG_LOGGING'], - namingStrategy: UnderscoreNamingStrategy, - forceUndefined: true, - dynamicImportProvider: (id) => import(id), + ...baseConfig, + entities: ['./dao/entities'], // path to our JS entities (dist), relative to `baseDir` + entitiesTs: ['./src/dao/entities'], // path to our TS entities (src), relative to `baseDir` metadataProvider: TsMorphMetadataProvider, - migrations: { - path: './build/migrations', - pathTs: './migrations', - }, - extensions: [Migrator], }); diff --git a/server/mikro-orm.prod.config.ts b/server/mikro-orm.prod.config.ts new file mode 100644 index 000000000..26d367246 --- /dev/null +++ b/server/mikro-orm.prod.config.ts @@ -0,0 +1,14 @@ +import { GeneratedCacheAdapter, defineConfig } from '@mikro-orm/better-sqlite'; +import baseConfig from './mikro-orm.base.config.js'; +import metadataJson from './temp/metadata.json' assert { type: 'json' }; + +export default defineConfig({ + ...baseConfig, + metadataCache: { + enabled: true, + adapter: GeneratedCacheAdapter, + options: { + data: metadataJson, + }, + }, +}); diff --git a/server/package.json b/server/package.json index 44bb9f2cf..f5b5cd095 100644 --- a/server/package.json +++ b/server/package.json @@ -5,17 +5,18 @@ "license": "Zlib", "author": "chrisbenincasa", "type": "module", - "main": "index.ts", + "main": "src/index.ts", "bin": "dist/index.js", "scripts": { "build": "tsc -p tsconfig.build.json", - "buildw": "nodemon -e ts --watch . --watch index.ts --ignore build/ -e .json,.ts,.yml,.yaml,.js -x tsc --project tsconfig.build.json", + "typecheck": "tsc -p tsconfig.build.json --noEmit", + "bundle": "node --loader ts-node/esm scripts/bundle.ts", + "clean": "rimraf build", "debug": "nodemon --ignore build/ -e .json,.ts,.yml,.yaml,.js --exec \"node --inspect-brk=0.0.0.0:4321 --loader ts-node/esm ./index.ts\"", - "dev": "nodemon -e ts --watch . --watch index.ts --ignore build/ --ignore streams/ -e .json,.ts,.yml,.yaml,.js -x ts-node-esm -r tsconfig-paths/register --files --project tsconfig.build.json index.ts --inspect=4321", - "dizquetv": "ts-node-esm index.ts", - "preinstall": "npx only-allow pnpm", + "dev": "nodemon -e ts --watch src/ --ignore build/ --ignore streams/ -e .json,.ts,.yml,.yaml,.js -x ts-node-esm -r tsconfig-paths/register --files --project tsconfig.build.json src/index.ts --inspect=4321", + "make-exec": "node --loader ts-node/esm scripts/makeExecutable.ts", "mikro-orm": "NODE_OPTIONS='--loader ts-node/esm --no-warnings' mikro-orm", - "package": "sh ./make_dist.sh", + "preinstall": "npx only-allow pnpm", "test": "vitest" }, "dependencies": { @@ -27,7 +28,6 @@ "@mikro-orm/better-sqlite": "^6.0.4", "@mikro-orm/core": "^6.0.4", "@mikro-orm/migrations": "6.0.4", - "@mikro-orm/reflection": "^6.0.4", "@tunarr/shared": "workspace:*", "@tunarr/types": "workspace:*", "JSONStream": "1.0.5", @@ -46,6 +46,7 @@ "fastify-print-routes": "^2.2.0", "fastify-type-provider-zod": "^1.1.9", "fluent-ffmpeg": "^2.1.2", + "lodash": "^4.17.21", "lodash-es": "^4.17.21", "lowdb": "^7.0.0", "morgan": "^1.10.0", @@ -57,7 +58,6 @@ "random-js": "2.1.0", "reflect-metadata": "^0.1.13", "retry": "^0.13.1", - "serve-static": "^1.15.0", "tslib": "^2.6.2", "uuid": "^9.0.1", "winston": "^3.11.0", @@ -68,11 +68,13 @@ }, "devDependencies": { "@mikro-orm/cli": "^6.0.4", + "@mikro-orm/reflection": "^6.0.4", "@types/async-retry": "^1.4.8", "@types/better-sqlite3": "^7.6.8", "@types/express": "^4.17.20", "@types/express-fileupload": "^1.4.3", "@types/fluent-ffmpeg": "^2.1.23", + "@types/lodash": "^4.14.202", "@types/lodash-es": "^4.17.10", "@types/morgan": "^1.9.7", "@types/node": "^20.8.9", @@ -84,17 +86,23 @@ "@types/yargs": "^17.0.29", "copyfiles": "^2.2.0", "del-cli": "^3.0.0", - "nexe": "^4.0.0-rc.2", + "esbuild": "^0.19.5", + "fast-glob": "^3.3.2", + "nexe": "4.0.0-rc.4", "nodemon": "^3.0.3", + "pkg": "^5.8.1", + "postject": "1.0.0-alpha.6", "prettier": "^3.0.3", + "rimraf": "^5.0.5", "tmp": "^0.2.1", "tmp-promise": "^3.0.3", "ts-essentials": "^9.4.1", "ts-node": "^10.9.1", "tsconfig-paths": "^4.2.0", "tsify": "^5.0.4", + "tsup": "^8.0.2", "typed-emitter": "^2.1.0", - "typescript": "^5.2.2", + "typescript": "^5.3.3", "vitest": "^1.2.0" }, "mikro-orm": { diff --git a/server/scripts/bundle.ts b/server/scripts/bundle.ts new file mode 100644 index 000000000..40930154c --- /dev/null +++ b/server/scripts/bundle.ts @@ -0,0 +1,62 @@ +import esbuild from 'esbuild'; +import fg from 'fast-glob'; +import fs from 'node:fs'; +import { rimraf } from 'rimraf'; +import { nativeNodeModulesPlugin } from '../esbuild/native-node-module.js'; +import { nodeProtocolPlugin } from '../esbuild/node-protocol.js'; + +if (fs.existsSync('build')) { + console.log('Deleting old build...'); + await rimraf('build'); +} + +fs.mkdirSync('build'); + +console.log('Copying images...'); +fs.cpSync('src/resources/images', 'build/resources/images', { + recursive: true, +}); + +console.log('Bundling app...'); +await esbuild.build({ + entryPoints: ['src/index.ts'], + bundle: true, + // minify: true, + // We can't make this mjs yet because mikro-orm breaks + // when using cached metadata w/ not js/ts suffixes: + // https://github.com/mikro-orm/mikro-orm/blob/e005cc22ef4e247f9741bdcaf1af012337977b7e/packages/core/src/cache/GeneratedCacheAdapter.ts#L16 + outfile: 'build/bundle.js', + format: 'esm', + platform: 'node', + target: 'node18', + inject: ['cjs-shim.ts'], + packages: 'external', + tsconfig: './tsconfig.build.json', + logLevel: 'verbose', + // external: [ + // 'mysql', + // 'mysql2', + // 'sqlite3', + // 'pg', + // 'tedious', + // 'pg-query-stream', + // 'oracledb', + // 'assert', + // ], + mainFields: ['module', 'main'], + plugins: [nativeNodeModulesPlugin(), nodeProtocolPlugin()], +}); + +console.log('Bundling DB migrations...'); +await esbuild.build({ + entryPoints: await fg('src/migrations/*'), + outdir: 'build/migrations', + bundle: false, + packages: 'external', + tsconfig: './tsconfig.build.json', +}); + +fs.cpSync( + 'src/migrations/.snapshot-db.db.json', + 'build/migrations/.snapshot-db.db.json', +); diff --git a/server/scripts/makeExecutable.ts b/server/scripts/makeExecutable.ts new file mode 100644 index 000000000..a9aa1bc0e --- /dev/null +++ b/server/scripts/makeExecutable.ts @@ -0,0 +1,10 @@ +import { compile } from 'nexe'; + +await compile({ + input: './build/bundle.js', + output: './build/server-macos', + targets: ['x64-20.11.1'], + build: true, + resources: ['./build/**/*', 'node_modules/**/*'], + python: 'python3', +}); diff --git a/server/scripts/pkg-config.json b/server/scripts/pkg-config.json new file mode 100644 index 000000000..a149e9928 --- /dev/null +++ b/server/scripts/pkg-config.json @@ -0,0 +1,5 @@ +{ + "scripts": "build/bundle.js", + "targets": ["node18-linux-arm64"], + "outputPath": "dist" +} diff --git a/server/scripts/sea.json b/server/scripts/sea.json new file mode 100644 index 000000000..4e45f758a --- /dev/null +++ b/server/scripts/sea.json @@ -0,0 +1,5 @@ +{ + "main": "build/bundle.js", + "output": "build/blob.blob", + "disableExperimentalSEAWarning": true +} diff --git a/server/api.ts b/server/src/api.ts similarity index 100% rename from server/api.ts rename to server/src/api.ts diff --git a/server/api/channelToolsApi.ts.ignore b/server/src/api/channelToolsApi.ts.ignore similarity index 100% rename from server/api/channelToolsApi.ts.ignore rename to server/src/api/channelToolsApi.ts.ignore diff --git a/server/api/ffmpegSettingsApi.ts b/server/src/api/ffmpegSettingsApi.ts similarity index 100% rename from server/api/ffmpegSettingsApi.ts rename to server/src/api/ffmpegSettingsApi.ts diff --git a/server/api/guideApi.ts b/server/src/api/guideApi.ts similarity index 100% rename from server/api/guideApi.ts rename to server/src/api/guideApi.ts diff --git a/server/api/hdhrSettingsApi.ts b/server/src/api/hdhrSettingsApi.ts similarity index 100% rename from server/api/hdhrSettingsApi.ts rename to server/src/api/hdhrSettingsApi.ts diff --git a/server/api/plexServersApi.ts b/server/src/api/plexServersApi.ts similarity index 100% rename from server/api/plexServersApi.ts rename to server/src/api/plexServersApi.ts diff --git a/server/api/plexSettingsApi.ts b/server/src/api/plexSettingsApi.ts similarity index 100% rename from server/api/plexSettingsApi.ts rename to server/src/api/plexSettingsApi.ts diff --git a/server/api/schedulerApi.ts b/server/src/api/schedulerApi.ts similarity index 100% rename from server/api/schedulerApi.ts rename to server/src/api/schedulerApi.ts diff --git a/server/api/schemas/errorSchema.ts b/server/src/api/schemas/errorSchema.ts similarity index 100% rename from server/api/schemas/errorSchema.ts rename to server/src/api/schemas/errorSchema.ts diff --git a/server/api/schemas/guideSchemas.ts b/server/src/api/schemas/guideSchemas.ts similarity index 100% rename from server/api/schemas/guideSchemas.ts rename to server/src/api/schemas/guideSchemas.ts diff --git a/server/api/v2/channelsApiV2.ts b/server/src/api/v2/channelsApiV2.ts similarity index 100% rename from server/api/v2/channelsApiV2.ts rename to server/src/api/v2/channelsApiV2.ts diff --git a/server/api/v2/customShowsApiV2.ts b/server/src/api/v2/customShowsApiV2.ts similarity index 100% rename from server/api/v2/customShowsApiV2.ts rename to server/src/api/v2/customShowsApiV2.ts diff --git a/server/api/v2/debugApi.ts b/server/src/api/v2/debugApi.ts similarity index 100% rename from server/api/v2/debugApi.ts rename to server/src/api/v2/debugApi.ts diff --git a/server/api/v2/fillerListsApiV2.ts b/server/src/api/v2/fillerListsApiV2.ts similarity index 100% rename from server/api/v2/fillerListsApiV2.ts rename to server/src/api/v2/fillerListsApiV2.ts diff --git a/server/api/v2/index.ts b/server/src/api/v2/index.ts similarity index 100% rename from server/api/v2/index.ts rename to server/src/api/v2/index.ts diff --git a/server/api/v2/plexServersApiV2.ts b/server/src/api/v2/plexServersApiV2.ts similarity index 100% rename from server/api/v2/plexServersApiV2.ts rename to server/src/api/v2/plexServersApiV2.ts diff --git a/server/api/v2/programmingApi.ts b/server/src/api/v2/programmingApi.ts similarity index 100% rename from server/api/v2/programmingApi.ts rename to server/src/api/v2/programmingApi.ts diff --git a/server/api/v2/settingsApiV2.ts b/server/src/api/v2/settingsApiV2.ts similarity index 100% rename from server/api/v2/settingsApiV2.ts rename to server/src/api/v2/settingsApiV2.ts diff --git a/server/api/v2/tasksApi.ts b/server/src/api/v2/tasksApi.ts similarity index 100% rename from server/api/v2/tasksApi.ts rename to server/src/api/v2/tasksApi.ts diff --git a/server/api/videoApi.ts b/server/src/api/videoApi.ts similarity index 100% rename from server/api/videoApi.ts rename to server/src/api/videoApi.ts diff --git a/server/api/xmltvSettingsApi.ts b/server/src/api/xmltvSettingsApi.ts similarity index 96% rename from server/api/xmltvSettingsApi.ts rename to server/src/api/xmltvSettingsApi.ts index cd9289916..2a7ef936b 100644 --- a/server/api/xmltvSettingsApi.ts +++ b/server/src/api/xmltvSettingsApi.ts @@ -4,6 +4,7 @@ import { XmlTvSettings, defaultXmlTvSettings } from '../dao/settings.js'; import createLogger from '../logger.js'; import { scheduledJobsById } from '../services/scheduler.js'; import { firstDefined } from '../util.js'; +import { serverOptions } from '../globals.js'; const logger = createLogger(import.meta); @@ -70,7 +71,7 @@ export const xmlTvSettingsRouter: FastifyPluginCallback = ( try { await req.serverCtx.settings.updateSettings( 'xmltv', - defaultXmlTvSettings, + defaultXmlTvSettings(serverOptions().database), ); const xmltv = req.serverCtx.settings.xmlTvSettings(); await res.send(xmltv); diff --git a/server/channelCache.ts b/server/src/channelCache.ts similarity index 100% rename from server/channelCache.ts rename to server/src/channelCache.ts diff --git a/server/constants.ts b/server/src/constants.ts similarity index 100% rename from server/constants.ts rename to server/src/constants.ts diff --git a/server/dao/channelDb.ts b/server/src/dao/channelDb.ts similarity index 100% rename from server/dao/channelDb.ts rename to server/src/dao/channelDb.ts diff --git a/server/dao/converters/programConverters.ts b/server/src/dao/converters/programConverters.ts similarity index 100% rename from server/dao/converters/programConverters.ts rename to server/src/dao/converters/programConverters.ts diff --git a/server/dao/customShowDb.ts b/server/src/dao/customShowDb.ts similarity index 100% rename from server/dao/customShowDb.ts rename to server/src/dao/customShowDb.ts diff --git a/server/dao/custom_types/DurationType.ts b/server/src/dao/custom_types/DurationType.ts similarity index 100% rename from server/dao/custom_types/DurationType.ts rename to server/src/dao/custom_types/DurationType.ts diff --git a/server/dao/custom_types/ResolutionType.ts b/server/src/dao/custom_types/ResolutionType.ts similarity index 100% rename from server/dao/custom_types/ResolutionType.ts rename to server/src/dao/custom_types/ResolutionType.ts diff --git a/server/dao/dataSource.ts b/server/src/dao/dataSource.ts similarity index 97% rename from server/dao/dataSource.ts rename to server/src/dao/dataSource.ts index 5f9895191..1cc0708c3 100644 --- a/server/dao/dataSource.ts +++ b/server/src/dao/dataSource.ts @@ -10,7 +10,7 @@ import path from 'node:path'; import 'reflect-metadata'; import { globalOptions } from '../globals.js'; import createLogger from '../logger.js'; -import dbConfig from '../mikro-orm.config.js'; +import dbConfig from '../../mikro-orm.config.js'; const logger = createLogger(import.meta); diff --git a/server/dao/derived_types/Lineup.ts b/server/src/dao/derived_types/Lineup.ts similarity index 100% rename from server/dao/derived_types/Lineup.ts rename to server/src/dao/derived_types/Lineup.ts diff --git a/server/dao/derived_types/StreamLineup.ts b/server/src/dao/derived_types/StreamLineup.ts similarity index 100% rename from server/dao/derived_types/StreamLineup.ts rename to server/src/dao/derived_types/StreamLineup.ts diff --git a/server/dao/entities/BaseEntity.ts b/server/src/dao/entities/BaseEntity.ts similarity index 100% rename from server/dao/entities/BaseEntity.ts rename to server/src/dao/entities/BaseEntity.ts diff --git a/server/dao/entities/CachedImage.ts b/server/src/dao/entities/CachedImage.ts similarity index 100% rename from server/dao/entities/CachedImage.ts rename to server/src/dao/entities/CachedImage.ts diff --git a/server/dao/entities/Channel.ts b/server/src/dao/entities/Channel.ts similarity index 100% rename from server/dao/entities/Channel.ts rename to server/src/dao/entities/Channel.ts diff --git a/server/dao/entities/ChannelFillerShow.ts b/server/src/dao/entities/ChannelFillerShow.ts similarity index 100% rename from server/dao/entities/ChannelFillerShow.ts rename to server/src/dao/entities/ChannelFillerShow.ts diff --git a/server/dao/entities/CustomShow.ts b/server/src/dao/entities/CustomShow.ts similarity index 100% rename from server/dao/entities/CustomShow.ts rename to server/src/dao/entities/CustomShow.ts diff --git a/server/dao/entities/CustomShowContent.ts b/server/src/dao/entities/CustomShowContent.ts similarity index 100% rename from server/dao/entities/CustomShowContent.ts rename to server/src/dao/entities/CustomShowContent.ts diff --git a/server/dao/entities/FillerListContent.ts b/server/src/dao/entities/FillerListContent.ts similarity index 100% rename from server/dao/entities/FillerListContent.ts rename to server/src/dao/entities/FillerListContent.ts diff --git a/server/dao/entities/FillerShow.ts b/server/src/dao/entities/FillerShow.ts similarity index 100% rename from server/dao/entities/FillerShow.ts rename to server/src/dao/entities/FillerShow.ts diff --git a/server/dao/entities/PlexServerSettings.ts b/server/src/dao/entities/PlexServerSettings.ts similarity index 100% rename from server/dao/entities/PlexServerSettings.ts rename to server/src/dao/entities/PlexServerSettings.ts diff --git a/server/dao/entities/Program.ts b/server/src/dao/entities/Program.ts similarity index 100% rename from server/dao/entities/Program.ts rename to server/src/dao/entities/Program.ts diff --git a/server/dao/fillerDb.test.ts b/server/src/dao/fillerDb.test.ts similarity index 100% rename from server/dao/fillerDb.test.ts rename to server/src/dao/fillerDb.test.ts diff --git a/server/dao/fillerDb.ts b/server/src/dao/fillerDb.ts similarity index 100% rename from server/dao/fillerDb.ts rename to server/src/dao/fillerDb.ts diff --git a/server/dao/legacyDbMigration.test.ts b/server/src/dao/legacyDbMigration.test.ts similarity index 97% rename from server/dao/legacyDbMigration.test.ts rename to server/src/dao/legacyDbMigration.test.ts index 565f8df67..f27a63ff7 100644 --- a/server/dao/legacyDbMigration.test.ts +++ b/server/src/dao/legacyDbMigration.test.ts @@ -1,6 +1,6 @@ import { test, describe, beforeAll, afterAll } from 'vitest'; import { MikroORM, RequestContext } from '@mikro-orm/better-sqlite'; -import dbConfig from '../mikro-orm.config.js'; +import dbConfig from '../../mikro-orm.prod.config.js'; import { migrateChannel, migratePrograms, diff --git a/server/dao/legacyDbMigration.ts b/server/src/dao/legacyDbMigration.ts similarity index 99% rename from server/dao/legacyDbMigration.ts rename to server/src/dao/legacyDbMigration.ts index b4cd6dde5..7a8051638 100644 --- a/server/dao/legacyDbMigration.ts +++ b/server/src/dao/legacyDbMigration.ts @@ -141,7 +141,7 @@ async function migrateFromLegacyDbInner( ) { const entitiesToMigrate = entities ?? MigratableEntities; // First initialize the default schema: - db.data = { ...defaultSchema }; + db.data = { ...defaultSchema(globalOptions().database) }; await db.write(); let settings: Partial = {}; @@ -180,7 +180,7 @@ async function migrateFromLegacyDbInner( settings = { ...settings, xmltv: { - ...defaultXmlTvSettings, + ...defaultXmlTvSettings(globalOptions().database), }, }; } else { diff --git a/server/dao/legacy_migration/channelMigrator.ts b/server/src/dao/legacy_migration/channelMigrator.ts similarity index 100% rename from server/dao/legacy_migration/channelMigrator.ts rename to server/src/dao/legacy_migration/channelMigrator.ts diff --git a/server/dao/legacy_migration/customShowMigrator.ts b/server/src/dao/legacy_migration/customShowMigrator.ts similarity index 100% rename from server/dao/legacy_migration/customShowMigrator.ts rename to server/src/dao/legacy_migration/customShowMigrator.ts diff --git a/server/dao/legacy_migration/migrationUtil.ts b/server/src/dao/legacy_migration/migrationUtil.ts similarity index 100% rename from server/dao/legacy_migration/migrationUtil.ts rename to server/src/dao/legacy_migration/migrationUtil.ts diff --git a/server/dao/plexServerDb.ts b/server/src/dao/plexServerDb.ts similarity index 100% rename from server/dao/plexServerDb.ts rename to server/src/dao/plexServerDb.ts diff --git a/server/dao/programHelpers.ts b/server/src/dao/programHelpers.ts similarity index 100% rename from server/dao/programHelpers.ts rename to server/src/dao/programHelpers.ts diff --git a/server/dao/settings.ts b/server/src/dao/settings.ts similarity index 90% rename from server/dao/settings.ts rename to server/src/dao/settings.ts index e050c989d..f278b8eea 100644 --- a/server/dao/settings.ts +++ b/server/src/dao/settings.ts @@ -11,7 +11,6 @@ import { JSONFilePreset } from 'lowdb/node'; import path from 'path'; import { DeepReadonly } from 'ts-essentials'; import { v4 as uuidv4 } from 'uuid'; -import constants from '../constants.js'; import { globalOptions } from '../globals.js'; const CURRENT_VERSION = 1; @@ -55,12 +54,12 @@ export type XmlTvSettings = { enableImageCache: boolean; }; -export const defaultXmlTvSettings: XmlTvSettings = { +export const defaultXmlTvSettings = (dbBasePath: string): XmlTvSettings => ({ programmingHours: 12, refreshHours: 4, - outputPath: path.resolve(constants.DEFAULT_DATA_DIR, 'xmltv.xml'), + outputPath: path.resolve(dbBasePath, 'xmltv.xml'), enableImageCache: false, -}; +}); export type SettingsSchema = { clientId: string; @@ -86,7 +85,7 @@ export type Schema = { settings: SettingsSchema; }; -export const defaultSchema: Schema = { +export const defaultSchema = (dbBasePath: string): Schema => ({ version: 1, migration: { legacyMigration: false, @@ -94,11 +93,11 @@ export const defaultSchema: Schema = { settings: { clientId: uuidv4(), hdhr: defaultHdhrSettings, - xmltv: defaultXmlTvSettings, + xmltv: defaultXmlTvSettings(dbBasePath), plexStream: defaultPlexStreamSettings, ffmpeg: defaultFfmpegSettings, }, -}; +}); export class Settings { private db: Low; @@ -150,7 +149,10 @@ export const getSettingsRawDb = once(async (dbPath?: string) => { const needsFlush = !existsSync(actualPath); - const db = await JSONFilePreset(actualPath, defaultSchema); + const db = await JSONFilePreset( + actualPath, + defaultSchema(globalOptions().database), + ); await db.read(); if (needsFlush) { diff --git a/server/ffmpeg.ts b/server/src/ffmpeg.ts similarity index 100% rename from server/ffmpeg.ts rename to server/src/ffmpeg.ts diff --git a/server/ffmpegInfo.ts b/server/src/ffmpegInfo.ts similarity index 100% rename from server/ffmpegInfo.ts rename to server/src/ffmpegInfo.ts diff --git a/server/ffmpegText.ts b/server/src/ffmpegText.ts similarity index 100% rename from server/ffmpegText.ts rename to server/src/ffmpegText.ts diff --git a/server/globals.ts b/server/src/globals.ts similarity index 100% rename from server/globals.ts rename to server/src/globals.ts diff --git a/server/hdhr.ts b/server/src/hdhr.ts similarity index 100% rename from server/hdhr.ts rename to server/src/hdhr.ts diff --git a/server/helperFuncs.ts b/server/src/helperFuncs.ts similarity index 100% rename from server/helperFuncs.ts rename to server/src/helperFuncs.ts diff --git a/server/index.ts b/server/src/index.ts similarity index 72% rename from server/index.ts rename to server/src/index.ts index be859528c..5c3e4a978 100644 --- a/server/index.ts +++ b/server/src/index.ts @@ -16,11 +16,22 @@ import createLogger from './logger.js'; import { ServerOptions } from './types.js'; import { existsSync } from 'node:fs'; import { mkdir, writeFile } from 'node:fs/promises'; +import { initServer } from './server.js'; const logger = createLogger(import.meta); +const maybeEnvPort = () => { + const port = process.env['TUNARR_SERVER_PORT']; + if (!port) { + return; + } + + const parsed = parseInt(port); + return isNaN(parsed) ? undefined : parsed; +}; + yargs(hideBin(process.argv)) - .scriptName('dizquetv') + .scriptName('tunarr') .option('database', { alias: 'd', type: 'string', @@ -31,7 +42,7 @@ yargs(hideBin(process.argv)) }) .option('force_migration', { type: 'boolean', - desc: 'Forces a migration from a legacy dizque database. Useful for development and debugging. NOTE: This WILL override any settings you have!', + desc: 'Forces a migration from a legacy dizquetv database. Useful for development and debugging. NOTE: This WILL override any settings you have!', default: false, }) .middleware(setGlobalOptions) @@ -40,19 +51,33 @@ yargs(hideBin(process.argv)) }) .command( ['server', '$0'], - 'Run the dizqueTV server', + 'Run the Tunarr server', (yargs) => { return yargs .option('port', { alias: 'p', type: 'number', - desc: 'The port to run the dizque server on', - default: 8000, + desc: 'The port to run the Tunarr server on', + default: maybeEnvPort() ?? 8000, + }) + .option('printRoutes', { + type: 'boolean', + default: false, }) .middleware(setServerOptions); }, async (args: ArgumentsCamelCase) => { - (await import('./server.js')).initServer(args); + console.log( + ` \\ + Tunarr ${constants.VERSION_NAME} + .------------. + |:::///### o | + |:::///### | + ':::///### o | + '------------' + `, + ); + await initServer(args); }, ) .command( @@ -63,13 +88,17 @@ yargs(hideBin(process.argv)) .option('port', { alias: 'p', type: 'number', - desc: 'The port to run the dizque server on', - default: 8000, + desc: 'The port to run the Tunarr server on', + default: maybeEnvPort() ?? 8000, + }) + .option('printRoutes', { + type: 'boolean', + default: false, }) .middleware(setServerOptions); }, async (args: ArgumentsCamelCase) => { - const f = await (await import('./server.js')).initServer(args); + const f = await initServer(args); const x = await f .inject({ method: 'get', url: '/docs/json' }) .then((r) => r.body); diff --git a/server/logger.ts b/server/src/logger.ts similarity index 71% rename from server/logger.ts rename to server/src/logger.ts index b84005f0d..4740384e4 100644 --- a/server/logger.ts +++ b/server/src/logger.ts @@ -6,6 +6,7 @@ import { isUndefined, join } from 'lodash-es'; import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import chalk from 'chalk'; +import { isProduction } from './util.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -15,27 +16,32 @@ const getLabel = (callingModule: ImportMeta) => { return path.join(parts[parts.length - 2], parts.pop() ?? ''); }; -const hformat = (module: ImportMeta) => - winston.format.printf(({ level, label, message, timestamp, ...metadata }) => { - let msg = `${timestamp} [${level}] ${getLabel(module)}${ - label ? `[${label}]` : '' - }: ${message} `; - for (const key of Object.keys(metadata)) { - if (key === 'stack') { - msg += metadata.message; - if (metadata.stack) { - msg += '\n'; - msg += join( - metadata.stack.split('\n').map((line) => '\t' + line), - '\n', - ); +const hformat = (module: ImportMeta) => { + // Exclude module label in prod build because it will always be the same (bundle.js) + const moduleLabel = isProduction ? '' : ` ${getLabel(module)}`; + return winston.format.printf( + ({ level, label, message, timestamp, ...metadata }) => { + let msg = `${timestamp} [${level}]${moduleLabel}${ + label ? `[${label}]` : '' + }: ${message} `; + for (const key of Object.keys(metadata)) { + if (key === 'stack') { + msg += metadata.message; + if (metadata.stack) { + msg += '\n'; + msg += join( + metadata.stack.split('\n').map((line) => '\t' + line), + '\n', + ); + } + } else if (isUndefined(metadata)) { + msg += chalk.gray('undefined'); } - } else if (isUndefined(metadata)) { - msg += chalk.gray('undefined'); } - } - return msg; - }); + return msg; + }, + ); +}; const createLogger = (module: ImportMeta) => { const logger = winston.createLogger({ diff --git a/server/migrations/.snapshot-db.db.json b/server/src/migrations/.snapshot-db.db.json similarity index 100% rename from server/migrations/.snapshot-db.db.json rename to server/src/migrations/.snapshot-db.db.json diff --git a/server/migrations/Migration20240124115044.ts b/server/src/migrations/Migration20240124115044.ts similarity index 100% rename from server/migrations/Migration20240124115044.ts rename to server/src/migrations/Migration20240124115044.ts diff --git a/server/migrations/Migration20240126165808.ts b/server/src/migrations/Migration20240126165808.ts similarity index 100% rename from server/migrations/Migration20240126165808.ts rename to server/src/migrations/Migration20240126165808.ts diff --git a/server/migrations/Migration20240221201014.ts b/server/src/migrations/Migration20240221201014.ts similarity index 100% rename from server/migrations/Migration20240221201014.ts rename to server/src/migrations/Migration20240221201014.ts diff --git a/server/offlinePlayer.ts b/server/src/offlinePlayer.ts similarity index 100% rename from server/offlinePlayer.ts rename to server/src/offlinePlayer.ts diff --git a/server/player.ts b/server/src/player.ts similarity index 100% rename from server/player.ts rename to server/src/player.ts diff --git a/server/plex.ts b/server/src/plex.ts similarity index 100% rename from server/plex.ts rename to server/src/plex.ts diff --git a/server/plexPlayer.ts b/server/src/plexPlayer.ts similarity index 100% rename from server/plexPlayer.ts rename to server/src/plexPlayer.ts diff --git a/server/plexTranscoder.ts b/server/src/plexTranscoder.ts similarity index 100% rename from server/plexTranscoder.ts rename to server/src/plexTranscoder.ts diff --git a/server/programPlayer.ts b/server/src/programPlayer.ts similarity index 100% rename from server/programPlayer.ts rename to server/src/programPlayer.ts diff --git a/server/src/resources/images/dizquetv.png b/server/src/resources/images/dizquetv.png new file mode 100644 index 000000000..f3c0eec12 Binary files /dev/null and b/server/src/resources/images/dizquetv.png differ diff --git a/server/src/resources/images/favicon.ico b/server/src/resources/images/favicon.ico new file mode 100644 index 000000000..88d727b03 Binary files /dev/null and b/server/src/resources/images/favicon.ico differ diff --git a/server/src/resources/images/favicon.svg b/server/src/resources/images/favicon.svg new file mode 100644 index 000000000..8de15422e --- /dev/null +++ b/server/src/resources/images/favicon.svg @@ -0,0 +1,136 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + dizqueTV + + diff --git a/server/src/resources/images/generic-error-screen.png b/server/src/resources/images/generic-error-screen.png new file mode 100644 index 000000000..d0ffd0c16 Binary files /dev/null and b/server/src/resources/images/generic-error-screen.png differ diff --git a/server/src/resources/images/generic-music-screen.png b/server/src/resources/images/generic-music-screen.png new file mode 100644 index 000000000..4efa71f91 Binary files /dev/null and b/server/src/resources/images/generic-music-screen.png differ diff --git a/server/src/resources/images/generic-offline-screen.png b/server/src/resources/images/generic-offline-screen.png new file mode 100644 index 000000000..73b778dfb Binary files /dev/null and b/server/src/resources/images/generic-offline-screen.png differ diff --git a/server/src/resources/images/loading-screen.png b/server/src/resources/images/loading-screen.png new file mode 100644 index 000000000..8bfda9a6f Binary files /dev/null and b/server/src/resources/images/loading-screen.png differ diff --git a/server/resources/test/legacy-migration/channels/1.json b/server/src/resources/test/legacy-migration/channels/1.json similarity index 100% rename from server/resources/test/legacy-migration/channels/1.json rename to server/src/resources/test/legacy-migration/channels/1.json diff --git a/server/resources/test/legacy-migration/custom-shows/e2920853-6024-4360-934d-4fd8d582f3e3.json b/server/src/resources/test/legacy-migration/custom-shows/e2920853-6024-4360-934d-4fd8d582f3e3.json similarity index 100% rename from server/resources/test/legacy-migration/custom-shows/e2920853-6024-4360-934d-4fd8d582f3e3.json rename to server/src/resources/test/legacy-migration/custom-shows/e2920853-6024-4360-934d-4fd8d582f3e3.json diff --git a/server/server.ts b/server/src/server.ts similarity index 78% rename from server/server.ts rename to server/src/server.ts index aa18cfeab..ea0a65697 100644 --- a/server/server.ts +++ b/server/src/server.ts @@ -17,11 +17,7 @@ import { import fs from 'fs'; import morgan from 'morgan'; import { onShutdown } from 'node-graceful-shutdown'; -import { dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import path from 'path'; -import serveStatic from 'serve-static'; -import { URL } from 'url'; +import path, { dirname } from 'path'; import { miscRouter } from './api.js'; import { ffmpegSettingsRouter } from './api/ffmpegSettingsApi.js'; import { guideRouter } from './api/guideApi.js'; @@ -32,7 +28,6 @@ import { schedulerRouter } from './api/schedulerApi.js'; import { debugApi } from './api/v2/debugApi.js'; import registerV2Routes from './api/v2/index.js'; import { xmlTvSettingsRouter } from './api/xmltvSettingsApi.js'; -import constants from './constants.js'; import { EntityManager, initOrm } from './dao/dataSource.js'; import { migrateFromLegacyDb } from './dao/legacyDbMigration.js'; import { getSettingsRawDb } from './dao/settings.js'; @@ -40,36 +35,14 @@ import { serverOptions } from './globals.js'; import createLogger from './logger.js'; import { serverContext } from './serverContext.js'; import { scheduleJobs, scheduledJobsById } from './services/scheduler.js'; +import { runFixers } from './tasks/fixers/index.js'; import { UpdateXmlTvTask } from './tasks/updateXmlTvTask.js'; import { ServerOptions } from './types.js'; -import { wait } from './util.js'; +import { filename, wait } from './util.js'; import { videoRouter } from './video.js'; -import { runFixers } from './tasks/fixers/index.js'; const logger = createLogger(import.meta); - -// Temporary -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -console.log( - ` \\ - Tunarr ${constants.VERSION_NAME} -.------------. -|:::///### o | -|:::///### | -':::///### o | -'------------' -`, -); - -const NODE = parseInt(process.version.match(/^[^0-9]*(\d+)\..*$/)![1]); - -if (NODE < 12) { - logger.error( - `WARNING: Your nodejs version ${process.version} is lower than supported. dizqueTV has been tested best on nodejs 12.16.`, - ); -} +const currentDirectory = dirname(filename(import.meta.url)); function initDbDirectories() { const opts = serverOptions(); @@ -106,6 +79,27 @@ function initDbDirectories() { } export async function initServer(opts: ServerOptions) { + onShutdown('log', [], async () => { + const ctx = await serverContext(); + const t = new Date().getTime(); + ctx.eventService.push({ + type: 'lifecycle', + message: `Initiated Server Shutdown`, + detail: { + time: t, + }, + level: 'warning', + }); + + logger.info('Received exit signal, attempting graceful shutdonw...'); + await wait(2000); + }); + + onShutdown('xmltv-writer', [], async () => { + const ctx = await serverContext(); + await ctx.xmltv.shutdown(); + }); + const hadLegacyDb = initDbDirectories(); const orm = await initOrm(); @@ -122,11 +116,12 @@ export async function initServer(opts: ServerOptions) { const updateXMLPromise = scheduledJobsById[UpdateXmlTvTask.ID]!.runNow(); - const app = fastify({ logger: false, bodyLimit: 50 * 1024 * 1024 }); - await app + const app = fastify({ logger: false, bodyLimit: 50 * 1024 * 1024 }) .setValidatorCompiler(validatorCompiler) .setSerializerCompiler(serializerCompiler) - .withTypeProvider() + .withTypeProvider(); + + await app .register(fastifySwagger, { openapi: { info: { @@ -149,7 +144,6 @@ export async function initServer(opts: ServerOptions) { RequestContext.create(orm.em, done), ) .addHook('onClose', async () => await orm.close()) - .register(fastifyPrintRoutes) .register( fp((f, _, done) => { f.decorateRequest('serverCtx', null); @@ -162,7 +156,11 @@ export async function initServer(opts: ServerOptions) { }), ); - await app.use( + if (serverOptions().printRoutes) { + await app.register(fastifyPrintRoutes); + } + + app.use( morgan(':method :url :status :res[content-length] - :response-time ms', { stream: { write: (message) => logger.http(message.trim()), @@ -175,20 +173,28 @@ export async function initServer(opts: ServerOptions) { ctx.eventService.setup(app); - await app - .use(serveStatic(fileURLToPath(new URL('../web/public', import.meta.url)))) - .use('/images', serveStatic(path.join(opts.database, 'images'))) - .use( - '/favicon.svg', - serveStatic(path.join(__dirname, 'resources', 'favicon.svg')), - ) - .use('/custom.css', serveStatic(path.join(opts.database, 'custom.css'))); - // API Routers await app + .register(fpStatic, { + root: path.join(currentDirectory, 'resources', 'images'), + prefix: '/images', + }) + .get('/favicon.svg', async (_, res) => { + return res.sendFile( + 'favicon.svg', + path.join(currentDirectory, 'resources', 'images'), + ); + }) + .get('/favicon.ico', async (_, res) => { + return res.sendFile( + 'favicon.ico', + path.join(currentDirectory, 'resources', 'images'), + ); + }) .register(async (f) => { await f.register(fpStatic, { root: path.join(opts.database, 'cache', 'images'), + decorateReply: false, }); // f.addHook('onRequest', async (req, res) => ctx.cacheImageService.routerInterceptor(req, res)); f.get<{ Params: { hash: string } }>( @@ -220,16 +226,27 @@ export async function initServer(opts: ServerOptions) { prefix: '/api/cache/images', }) .register(videoRouter) - .register(ctx.hdhrService.createRouter()); + .register(ctx.hdhrService.createRouter()) + .register(async (f) => { + await f.register(fpStatic, { + root: path.join(currentDirectory, 'web'), + prefix: '/web', + }); + f.get('/web', async (_, res) => + res.sendFile('index.html', path.join(currentDirectory, 'web')), + ); + }); await updateXMLPromise; + const host = process.env['TUNARR_BIND_ADDR'] ?? 'localhost'; app.listen( { + host, port: opts.port, }, () => { - logger.info(`HTTP server running on port: http://*:${opts.port}`); + logger.info(`HTTP server running on port: http://${host}:${opts.port}`); const hdhrSettings = ctx.settings.hdhrSettings(); if (hdhrSettings.autoDiscoveryEnabled) { // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any @@ -249,24 +266,3 @@ export async function initServer(opts: ServerOptions) { return app; } - -onShutdown('log', [], async () => { - const ctx = await serverContext(); - const t = new Date().getTime(); - ctx.eventService.push({ - type: 'lifecycle', - message: `Initiated Server Shutdown`, - detail: { - time: t, - }, - level: 'warning', - }); - - logger.info('Received exit signal, attempting graceful shutdonw...'); - await wait(2000); -}); - -onShutdown('xmltv-writer', [], async () => { - const ctx = await serverContext(); - await ctx.xmltv.shutdown(); -}); diff --git a/server/serverContext.ts b/server/src/serverContext.ts similarity index 65% rename from server/serverContext.ts rename to server/src/serverContext.ts index f291a59b9..a2e5bc72a 100644 --- a/server/serverContext.ts +++ b/server/src/serverContext.ts @@ -1,12 +1,11 @@ -import fs, { promises as fsPromises } from 'fs'; import { once } from 'lodash-es'; import path from 'path'; import { ChannelCache } from './channelCache.js'; import { ChannelDB } from './dao/channelDb.js'; import { CustomShowDB } from './dao/customShowDb.js'; -import { Settings, getSettings } from './dao/settings.js'; import { FillerDB } from './dao/fillerDb.js'; import { PlexServerDB } from './dao/plexServerDb.js'; +import { Settings, getSettings } from './dao/settings.js'; import { serverOptions } from './globals.js'; import { HdhrService } from './hdhr.js'; import { CacheImageService } from './services/cacheImageService.js'; @@ -16,43 +15,6 @@ import { M3uService } from './services/m3uService.js'; import { TVGuideService } from './services/tvGuideService.js'; import { XmlTvWriter } from './xmltv.js'; -async function copyIfMissingFromDatabase( - targetPath: string, - resourcePath: string, -): Promise { - const opts = serverOptions(); - if (!fs.existsSync(path.join(opts.database, targetPath))) { - await fsPromises.copyFile( - new URL('../' + resourcePath, import.meta.url), - path.join(opts.database, targetPath), - ); - } -} - -function initDBDirectory() { - return Promise.all([ - copyIfMissingFromDatabase('images/dizquetv.png', 'resources/dizquetv.png'), - copyIfMissingFromDatabase('font.ttf', 'resources/font.ttf'), - copyIfMissingFromDatabase( - 'images/generic-error-screen.png', - 'resources/generic-error-screen.png', - ), - copyIfMissingFromDatabase( - 'images/generic-offline-screen.png', - 'resources/generic-offline-screen.png', - ), - copyIfMissingFromDatabase( - 'images/generic-music-screen.png', - 'resources/generic-music-screen.png', - ), - copyIfMissingFromDatabase( - 'images/loading-screen.png', - 'resources/loading-screen.png', - ), - copyIfMissingFromDatabase('custom.css', 'resources/default-custom.css'), - ]); -} - export type ServerContext = { channelDB: ChannelDB; fillerDB: FillerDB; @@ -83,8 +45,6 @@ export const serverContext: () => Promise = once(async () => { const eventService = new EventService(); const xmltv = new XmlTvWriter(); - await initDBDirectory(); - const guideService = new TVGuideService( xmltv, cacheImageService, diff --git a/server/services/cacheImageService.ts b/server/src/services/cacheImageService.ts similarity index 100% rename from server/services/cacheImageService.ts rename to server/src/services/cacheImageService.ts diff --git a/server/services/eventService.ts b/server/src/services/eventService.ts similarity index 100% rename from server/services/eventService.ts rename to server/src/services/eventService.ts diff --git a/server/services/fileCacheService.ts b/server/src/services/fileCacheService.ts similarity index 100% rename from server/services/fileCacheService.ts rename to server/src/services/fileCacheService.ts diff --git a/server/services/getShowData.ignore.ts b/server/src/services/getShowData.ignore.ts similarity index 100% rename from server/services/getShowData.ignore.ts rename to server/src/services/getShowData.ignore.ts diff --git a/server/services/m3uService.ts b/server/src/services/m3uService.ts similarity index 100% rename from server/services/m3uService.ts rename to server/src/services/m3uService.ts diff --git a/server/services/randomSlotsService.ignore.ts b/server/src/services/randomSlotsService.ignore.ts similarity index 100% rename from server/services/randomSlotsService.ignore.ts rename to server/src/services/randomSlotsService.ignore.ts diff --git a/server/services/scheduler.ts b/server/src/services/scheduler.ts similarity index 100% rename from server/services/scheduler.ts rename to server/src/services/scheduler.ts diff --git a/server/services/throttle.ts b/server/src/services/throttle.ts similarity index 100% rename from server/services/throttle.ts rename to server/src/services/throttle.ts diff --git a/server/services/tvGuideService.ts b/server/src/services/tvGuideService.ts similarity index 100% rename from server/services/tvGuideService.ts rename to server/src/services/tvGuideService.ts diff --git a/server/services/tvGuideService2.ts b/server/src/services/tvGuideService2.ts similarity index 100% rename from server/services/tvGuideService2.ts rename to server/src/services/tvGuideService2.ts diff --git a/server/stream/session.ts b/server/src/stream/session.ts similarity index 100% rename from server/stream/session.ts rename to server/src/stream/session.ts diff --git a/server/stream/sessionManager.ts b/server/src/stream/sessionManager.ts similarity index 100% rename from server/stream/sessionManager.ts rename to server/src/stream/sessionManager.ts diff --git a/server/tasks/cleanupSessionsTask.ts b/server/src/tasks/cleanupSessionsTask.ts similarity index 100% rename from server/tasks/cleanupSessionsTask.ts rename to server/src/tasks/cleanupSessionsTask.ts diff --git a/server/tasks/fixers/fixer.ts b/server/src/tasks/fixers/fixer.ts similarity index 100% rename from server/tasks/fixers/fixer.ts rename to server/src/tasks/fixers/fixer.ts diff --git a/server/tasks/fixers/index.ts b/server/src/tasks/fixers/index.ts similarity index 100% rename from server/tasks/fixers/index.ts rename to server/src/tasks/fixers/index.ts diff --git a/server/tasks/fixers/missingSeasonNumbersFixer.ts b/server/src/tasks/fixers/missingSeasonNumbersFixer.ts similarity index 100% rename from server/tasks/fixers/missingSeasonNumbersFixer.ts rename to server/src/tasks/fixers/missingSeasonNumbersFixer.ts diff --git a/server/tasks/task.ts b/server/src/tasks/task.ts similarity index 100% rename from server/tasks/task.ts rename to server/src/tasks/task.ts diff --git a/server/tasks/updateXmlTvTask.ts b/server/src/tasks/updateXmlTvTask.ts similarity index 100% rename from server/tasks/updateXmlTvTask.ts rename to server/src/tasks/updateXmlTvTask.ts diff --git a/server/throttler.ts b/server/src/throttler.ts similarity index 100% rename from server/throttler.ts rename to server/src/throttler.ts diff --git a/server/types.ts b/server/src/types.ts similarity index 99% rename from server/types.ts rename to server/src/types.ts index 5893eb778..f1d000869 100644 --- a/server/types.ts +++ b/server/src/types.ts @@ -11,6 +11,7 @@ export type GlobalOptions = { export type ServerOptions = GlobalOptions & { port: number; + printRoutes: boolean; }; export type Maybe = T | undefined; diff --git a/server/types/eventEmitter.ts b/server/src/types/eventEmitter.ts similarity index 100% rename from server/types/eventEmitter.ts rename to server/src/types/eventEmitter.ts diff --git a/server/types/express.d.ts b/server/src/types/express.d.ts similarity index 100% rename from server/types/express.d.ts rename to server/src/types/express.d.ts diff --git a/server/types/fastify.d.ts b/server/src/types/fastify.d.ts similarity index 100% rename from server/types/fastify.d.ts rename to server/src/types/fastify.d.ts diff --git a/server/src/types/knex.d.ts b/server/src/types/knex.d.ts new file mode 100644 index 000000000..3a0844bef --- /dev/null +++ b/server/src/types/knex.d.ts @@ -0,0 +1,5 @@ +// declare module 'knex/lib/dialects/sqlite3' { +// import { Knex } from 'knex'; +// const client: Knex.Client; +// export = client; +// } diff --git a/server/types/lineupItem.ts b/server/src/types/lineupItem.ts similarity index 100% rename from server/types/lineupItem.ts rename to server/src/types/lineupItem.ts diff --git a/server/types/plexApiTypes.ts b/server/src/types/plexApiTypes.ts similarity index 100% rename from server/types/plexApiTypes.ts rename to server/src/types/plexApiTypes.ts diff --git a/server/types/serverType.ts b/server/src/types/serverType.ts similarity index 92% rename from server/types/serverType.ts rename to server/src/types/serverType.ts index 9391fc6a3..85bc790d3 100644 --- a/server/types/serverType.ts +++ b/server/src/types/serverType.ts @@ -1,4 +1,5 @@ -import fastify, { +import { + FastifyBaseLogger, FastifyInstance, FastifyPluginAsync, FastifyPluginCallback, @@ -11,7 +12,7 @@ export type ServerType = FastifyInstance< RawServerDefault, IncomingMessage, ServerResponse, - fastify.FastifyBaseLogger, + FastifyBaseLogger, ZodTypeProvider >; diff --git a/server/util.ts b/server/src/util.ts similarity index 93% rename from server/util.ts rename to server/src/util.ts index 593bbf86b..c8975556f 100644 --- a/server/util.ts +++ b/server/src/util.ts @@ -9,10 +9,12 @@ import { isPlainObject, isString, isUndefined, + once, reduce, } from 'lodash-es'; -import fs from 'fs/promises'; +import fs from 'node:fs/promises'; import { isPromise } from 'node:util/types'; +import { fileURLToPath } from 'node:url'; declare global { interface Array { @@ -293,3 +295,15 @@ export function emptyStringToUndefined( return s.length === 0 ? undefined : s; } + +export const filename = (path: string) => fileURLToPath(path); +// const dirname = (path: string) => dirname(filename(path)); + +export const currentEnv = once(() => { + const env = process.env['NODE_ENV']; + return env ?? 'production'; +}); + +export const isProduction = currentEnv() === 'production'; +export const isDev = currentEnv() === 'development'; +export const isTest = currentEnv() === 'test'; diff --git a/server/util/binarySearch.test.ts b/server/src/util/binarySearch.test.ts similarity index 100% rename from server/util/binarySearch.test.ts rename to server/src/util/binarySearch.test.ts diff --git a/server/util/binarySearch.ts b/server/src/util/binarySearch.ts similarity index 100% rename from server/util/binarySearch.ts rename to server/src/util/binarySearch.ts diff --git a/server/util/dayjsExtensions.ts b/server/src/util/dayjsExtensions.ts similarity index 100% rename from server/util/dayjsExtensions.ts rename to server/src/util/dayjsExtensions.ts diff --git a/server/util/fsUtil.ts b/server/src/util/fsUtil.ts similarity index 100% rename from server/util/fsUtil.ts rename to server/src/util/fsUtil.ts diff --git a/server/util/programMinter.ts b/server/src/util/programMinter.ts similarity index 100% rename from server/util/programMinter.ts rename to server/src/util/programMinter.ts diff --git a/server/util/runWorker.ts b/server/src/util/runWorker.ts similarity index 100% rename from server/util/runWorker.ts rename to server/src/util/runWorker.ts diff --git a/server/util/scheduleTimeSlotsWorker.ts b/server/src/util/scheduleTimeSlotsWorker.ts similarity index 100% rename from server/util/scheduleTimeSlotsWorker.ts rename to server/src/util/scheduleTimeSlotsWorker.ts diff --git a/server/video.ts b/server/src/video.ts similarity index 100% rename from server/video.ts rename to server/src/video.ts diff --git a/server/xmltv.ts b/server/src/xmltv.ts similarity index 100% rename from server/xmltv.ts rename to server/src/xmltv.ts diff --git a/server/tsconfig.build.json b/server/tsconfig.build.json index bd602e604..3f63c8e29 100644 --- a/server/tsconfig.build.json +++ b/server/tsconfig.build.json @@ -1,12 +1,14 @@ { "extends": "./tsconfig.json", "include": [ - "./**/*.ts", + "./src/**/*.ts", ], "exclude": [ "./build/**/*", "./**/*.test.ts", "./**/*.ignore.ts", - "./streams/**/*.ts" + "./**/streams/**/*.ts", + "./scripts", + "./esbuild" ] } \ No newline at end of file diff --git a/server/tsconfig.json b/server/tsconfig.json index a6c8e52c9..bce692216 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -1,11 +1,11 @@ { "compilerOptions": { - "target": "es2022", - "module": "node16", + "target": "ESNext", + "module": "ESNext", "lib": [ "ES2022" ], - "moduleResolution": "node16", + "moduleResolution": "Bundler", "rootDir": ".", "outDir": "build", "allowSyntheticDefaultImports": true, @@ -31,12 +31,13 @@ "noErrorTruncation": true }, "files": [ - "./types/fastify.d.ts" + "src/types/fastify.d.ts" ], "include": [ - "./**/*.ts", + "./src/**/*.ts", + "./scripts/**/*.ts", "__tests__/**/*", - "api/channelToolsApi.ts.ignore" + "mikro-orm.prod.config.ts" ], "exclude": [ "./build/**/*", diff --git a/server/tsup.config.ts b/server/tsup.config.ts new file mode 100644 index 000000000..4127d284d --- /dev/null +++ b/server/tsup.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['index.ts'], + splitting: false, + sourcemap: true, + clean: true, + format: 'esm', +}); diff --git a/shared/package.json b/shared/package.json index a4b4ae367..83d5e58c3 100644 --- a/shared/package.json +++ b/shared/package.json @@ -7,15 +7,20 @@ "author": "", "type": "module", "exports": { - ".": "./common/index.js", - "./constants": "./common/util/constants.js", - "./node": "./node/index.js", - "./browser": "./browser/index.js" + ".": { + "types": "./build/src/index.d.ts", + "default": "./build/src/index.js" + }, + "./constants": { + "types": "./build/src/util/constants.d.ts", + "default": "./build/src/util/constants.js" + } }, "main": "index.ts", "scripts": { - "build": "tsc -p tsconfig.json", - "buildw": "nodemon -e ts --watch . --watch index.ts --ignore build/ -e .json,.ts,.yml,.yaml,.js -x tsc --project tsconfig.build.json" + "build": "tsc -p tsconfig.build.json", + "clean": "rimraf build/", + "dev": "nodemon -e ts --watch src --ignore build/ -e .json,.ts,.yml,.yaml,.js -x tsc --project tsconfig.build.json" }, "dependencies": { "@tunarr/types": "workspace:*", @@ -28,6 +33,7 @@ "@types/lodash-es": "^4.17.10", "@types/node": "18.18.0", "nodemon": "3.0.2", + "rimraf": "^5.0.5", "typescript": "5.2.2" } } diff --git a/shared/common/index.ts b/shared/src/index.ts similarity index 100% rename from shared/common/index.ts rename to shared/src/index.ts diff --git a/shared/common/services/randomSlotsService.ts b/shared/src/services/randomSlotsService.ts similarity index 97% rename from shared/common/services/randomSlotsService.ts rename to shared/src/services/randomSlotsService.ts index 46fd5d4d0..b0e916a8c 100644 --- a/shared/common/services/randomSlotsService.ts +++ b/shared/src/services/randomSlotsService.ts @@ -254,7 +254,9 @@ export default async function scheduleRandomSlots( ) { // Load programs // TODO include redirects and custom programs! - const allPrograms = reject(channelProgramming.programs, isFlexProgram); + const allPrograms = reject(channelProgramming.programs, (p) => + isFlexProgram(p), + ); const programBySlotType = createProgramMap(allPrograms); const programmingIteratorsById = reduce( @@ -327,7 +329,7 @@ export default async function scheduleRandomSlots( // let dayTime = timeCursor.mod(periodDuration).asMilliseconds(); let currSlot: RandomSlot | null = null; - let slotIndex: number | null = null; + // let slotIndex: number | null = null; let remaining: number = 0; // Pad time @@ -342,11 +344,11 @@ export default async function scheduleRandomSlots( const slot = schedule.slots[i]; const slotLastPlayed = slotsLastPlayedMap[i]; if (!isNil(slotLastPlayed)) { - const nextPlay = dayjs(slotLastPlayed + slot.cooldown); + const nextPlay = dayjs(slotLastPlayed + slot.cooldownMs); minNextTime = minNextTime.isBefore(nextPlay) ? minNextTime : nextPlay; if ( dayjs.duration(timeCursor.diff(slotLastPlayed)).asMilliseconds() < - slot.cooldown - constants.SLACK + slot.cooldownMs - constants.SLACK ) { continue; } @@ -356,7 +358,7 @@ export default async function scheduleRandomSlots( if (random.bool(slot.weight!, n)) { currSlot = slot; - slotIndex = i; + // slotIndex = i; remaining = slot.durationMs; } } diff --git a/shared/common/services/timeSlotService.ts b/shared/src/services/timeSlotService.ts similarity index 100% rename from shared/common/services/timeSlotService.ts rename to shared/src/services/timeSlotService.ts diff --git a/shared/common/services/timeSlotsService.test.ts b/shared/src/services/timeSlotsService.test.ts similarity index 100% rename from shared/common/services/timeSlotsService.test.ts rename to shared/src/services/timeSlotsService.test.ts diff --git a/shared/common/util/constants.ts b/shared/src/util/constants.ts similarity index 100% rename from shared/common/util/constants.ts rename to shared/src/util/constants.ts diff --git a/shared/common/util/dayjsExtensions.ts b/shared/src/util/dayjsExtensions.ts similarity index 100% rename from shared/common/util/dayjsExtensions.ts rename to shared/src/util/dayjsExtensions.ts diff --git a/types/index.ts b/types/index.ts deleted file mode 100644 index 5c9f0f149..000000000 --- a/types/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from './src/Program.js'; -export * from './src/Channel.js'; -export * from './src/XmlTvSettings.js'; -export * from './src/GuideApi.js'; -export * from './src/FfmpegSettings.js'; -export * from './src/misc.js'; -export * from './src/PlexSettings.js'; -export * from './src/HdhrSettings.js'; -export * from './src/CustomShow.js'; -export * from './src/Event.js'; -export * from './src/FillerList.js'; -export * from './src/Tasks.js'; -export * from './src/Theme.js'; diff --git a/types/package.json b/types/package.json index ac2f49531..70dd28bfa 100644 --- a/types/package.json +++ b/types/package.json @@ -3,9 +3,11 @@ "version": "1.0.0", "description": "", "scripts": { - "build": "tsc -p tsconfig.json" + "build": "tsc -p tsconfig.json", + "clean": "rimraf build", + "dev": "nodemon -e ts --watch src --ignore build/ -e .json,.ts,.yml,.yaml,.js -x tsc --project tsconfig.json" }, - "main": "index.js", + "main": "build/index.js", "keywords": [], "author": "chrisbenincasa", "type": "module", @@ -14,6 +16,8 @@ "@typescript-eslint/eslint-plugin": "6.0.0", "@typescript-eslint/parser": "6.0.0", "eslint": "8.45.0", + "nodemon": "^3.1.0", + "rimraf": "^5.0.5", "typescript": "5.2.2" }, "dependencies": { @@ -21,16 +25,21 @@ }, "exports": { ".": { - "import": "./index.js" + "types": "./build/src/index.d.ts", + "default": "./build/src/index.js" }, + "./package.json": "./package.json", "./schemas": { - "import": "./src/schemas/index.js" + "types": "./build/src/schemas/index.d.ts", + "default": "./build/src/schemas/index.js" }, "./plex": { - "import": "./src/plex/index.js" + "types": "./build/src/plex/index.d.ts", + "default": "./build/src/plex/index.js" }, "./api": { - "import": "./src/api/index.js" + "types": "./build/src/api/index.d.ts", + "default": "./build/src/api/index.js" } } } diff --git a/types/src/index.ts b/types/src/index.ts new file mode 100644 index 000000000..1de697433 --- /dev/null +++ b/types/src/index.ts @@ -0,0 +1,13 @@ +export * from './Program.js'; +export * from './Channel.js'; +export * from './XmlTvSettings.js'; +export * from './GuideApi.js'; +export * from './FfmpegSettings.js'; +export * from './misc.js'; +export * from './PlexSettings.js'; +export * from './HdhrSettings.js'; +export * from './CustomShow.js'; +export * from './Event.js'; +export * from './FillerList.js'; +export * from './Tasks.js'; +export * from './Theme.js'; diff --git a/types/tsconfig.json b/types/tsconfig.json index 2098d1adf..618a6ab3c 100644 --- a/types/tsconfig.json +++ b/types/tsconfig.json @@ -5,6 +5,7 @@ "lib": [ "ES2022" ], + "declaration": true, "moduleResolution": "node16", "rootDir": ".", "outDir": "build", @@ -26,6 +27,7 @@ "__tests__/**/*" ], "exclude": [ - "./**/*.test.ts" + "./**/*.test.ts", + "./build/**" ] } \ No newline at end of file diff --git a/web2/src/components/channel_config/ChannelTranscodingConfig.tsx b/web2/src/components/channel_config/ChannelTranscodingConfig.tsx index c2a25a472..63cb03077 100644 --- a/web2/src/components/channel_config/ChannelTranscodingConfig.tsx +++ b/web2/src/components/channel_config/ChannelTranscodingConfig.tsx @@ -12,16 +12,15 @@ import { } from '@mui/material'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; -import { Channel, SaveChannelRequest } from '@tunarr/types'; +import { SaveChannelRequest } from '@tunarr/types'; import { isNil, isUndefined, map } from 'lodash-es'; +import { useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { resolutionFromAnyString, - resolutionFromString, resolutionToString, } from '../../helpers/util.ts'; import { useFfmpegSettings } from '../../hooks/settingsHooks.ts'; -import { useState } from 'react'; const resolutionOptions = [ { value: '420x420', label: '420x420 (1:1)' }, diff --git a/web2/src/components/channel_config/ProgrammingSelector.tsx b/web2/src/components/channel_config/ProgrammingSelector.tsx index 01f5f2373..6e1bac21b 100644 --- a/web2/src/components/channel_config/ProgrammingSelector.tsx +++ b/web2/src/components/channel_config/ProgrammingSelector.tsx @@ -147,7 +147,7 @@ export default function ProgrammingSelector() { }, }); - const { isLoading: collectionsLoading, data: collectionsData } = useQuery({ + const { data: collectionsData } = useQuery({ queryKey: [ 'plex', selectedServer?.name, diff --git a/web2/src/components/util/TypedController.tsx b/web2/src/components/util/TypedController.tsx index 47d9ac3b5..80e492e70 100644 --- a/web2/src/components/util/TypedController.tsx +++ b/web2/src/components/util/TypedController.tsx @@ -1,4 +1,10 @@ -import { get, has, isFinite, isNil, isUndefined } from 'lodash-es'; +import { + Checkbox, + CheckboxProps, + TextField, + TextFieldProps, +} from '@mui/material'; +import { get, has, isFinite, isNil } from 'lodash-es'; import { useCallback } from 'react'; import { Controller, @@ -11,14 +17,7 @@ import { UseControllerProps, UseFormStateReturn, } from 'react-hook-form'; -import { ErrorMessage } from '@hookform/error-message'; import { handleNumericFormValue } from '../../helpers/util.ts'; -import { - Checkbox, - CheckboxProps, - TextField, - TextFieldProps, -} from '@mui/material'; type RenderFunc< TFieldValues extends FieldValues = FieldValues, diff --git a/web2/src/helpers/util.ts b/web2/src/helpers/util.ts index 9cef6cd54..363a4e91a 100644 --- a/web2/src/helpers/util.ts +++ b/web2/src/helpers/util.ts @@ -1,8 +1,7 @@ -import { ChangeEvent } from 'react'; +import { ChannelProgram, FlexProgram, Resolution } from '@tunarr/types'; import dayjs from 'dayjs'; import duration from 'dayjs/plugin/duration'; import { isNumber, range, zipWith } from 'lodash-es'; -import { ChannelProgram, FlexProgram, Resolution } from '@tunarr/types'; dayjs.extend(duration); diff --git a/web2/src/pages/channels/ChannelsPage.tsx b/web2/src/pages/channels/ChannelsPage.tsx index 908a09db4..677cc8b44 100644 --- a/web2/src/pages/channels/ChannelsPage.tsx +++ b/web2/src/pages/channels/ChannelsPage.tsx @@ -1,7 +1,8 @@ +import { Delete, Tv } from '@mui/icons-material'; import AddCircleIcon from '@mui/icons-material/AddCircle'; -import TextSnippetIcon from '@mui/icons-material/TextSnippet'; import EditIcon from '@mui/icons-material/Edit'; import SettingsRemoteIcon from '@mui/icons-material/SettingsRemote'; +import TextSnippetIcon from '@mui/icons-material/TextSnippet'; import { Box, Button, @@ -23,16 +24,15 @@ import { useMediaQuery, } from '@mui/material'; import { useTheme } from '@mui/material/styles'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Channel } from '@tunarr/types'; import dayjs from 'dayjs'; import { isEmpty } from 'lodash-es'; +import { useState } from 'react'; import { Link as RouterLink, useNavigate } from 'react-router-dom'; import PaddedPaper from '../../components/base/PaddedPaper.tsx'; -import { useChannels } from '../../hooks/useChannels.ts'; -import { Delete, Tv } from '@mui/icons-material'; -import { useState } from 'react'; -import { useQueryClient, useMutation } from '@tanstack/react-query'; import { apiClient } from '../../external/api.ts'; +import { useChannels } from '../../hooks/useChannels.ts'; export default function ChannelsPage() { const now = dayjs(); @@ -50,7 +50,7 @@ export default function ChannelsPage() { >(undefined); const handleChannelNavigation = ( - event: React.MouseEvent, + _: React.MouseEvent, id: string, ) => { navigate(`/channels/${id}/programming`); diff --git a/web2/src/pages/settings/PlexSettingsPage.tsx b/web2/src/pages/settings/PlexSettingsPage.tsx index a421cc418..9d79e08e6 100644 --- a/web2/src/pages/settings/PlexSettingsPage.tsx +++ b/web2/src/pages/settings/PlexSettingsPage.tsx @@ -1,6 +1,5 @@ import { AddCircle, - Cancel, CancelOutlined, CloudDoneOutlined, CloudOff, @@ -59,6 +58,7 @@ import { import { InsertPlexServerRequest } from '@tunarr/types/api'; import { fill, isNil, isNull, isUndefined } from 'lodash-es'; import React, { Fragment, useCallback, useEffect, useState } from 'react'; +import { Controller, SubmitHandler, useForm } from 'react-hook-form'; import { apiClient } from '../../external/api.ts'; import { checkNewPlexServers, plexLoginFlow } from '../../helpers/plexLogin.ts'; import { @@ -70,7 +70,6 @@ import { usePlexServerSettings, usePlexStreamSettings, } from '../../hooks/settingsHooks.ts'; -import { Controller, SubmitHandler, useForm } from 'react-hook-form'; const supportedResolutions = [ '420x420', diff --git a/web2/src/router.tsx b/web2/src/router.tsx index 1cf346d22..1041d232a 100644 --- a/web2/src/router.tsx +++ b/web2/src/router.tsx @@ -6,21 +6,6 @@ import ChannelsPage from './pages/channels/ChannelsPage.tsx'; import EditChannelPage from './pages/channels/EditChannelPage.tsx'; import ProgrammingSelectorPage from './pages/channels/ProgrammingSelectorPage.tsx'; import TimeSlotEditorPage from './pages/channels/TimeSlotEditorPage.tsx'; -import { - channelLoader, - editProgrammingLoader, -} from './preloaders/channelLoaders.ts'; -import { editChannelLoader } from './preloaders/channelLoaders.ts'; -import { customShowsLoader } from './preloaders/customShowLoaders.ts'; -import { - existingCustomShowLoader, - newCustomShowLoader, -} from './preloaders/customShowLoaders.ts'; -import { - existingFillerListLoader, - fillerListsLoader, - newFillerListLoader, -} from './preloaders/fillerListLoader.ts'; import GuidePage from './pages/guide/GuidePage.tsx'; import CustomShowsPage from './pages/library/CustomShowsPage.tsx'; import EditCustomShowPage from './pages/library/EditCustomShowPage.tsx'; @@ -36,137 +21,157 @@ import TaskSettingsPage from './pages/settings/TaskSettingsPage.tsx'; import XmlTvSettingsPage from './pages/settings/XmlTvSettingsPage.tsx'; import ChannelWatchPage from './pages/watch/ChannelWatchPage.tsx'; import WelcomePage from './pages/welcome/WelcomePage.tsx'; +import { + channelLoader, + editChannelLoader, + editProgrammingLoader, +} from './preloaders/channelLoaders.ts'; +import { + customShowsLoader, + existingCustomShowLoader, + newCustomShowLoader, +} from './preloaders/customShowLoaders.ts'; +import { + existingFillerListLoader, + fillerListsLoader, + newFillerListLoader, +} from './preloaders/fillerListLoader.ts'; import { queryCache } from './queryClient.ts'; const queryClient = new QueryClient({ queryCache }); -export const router = createBrowserRouter([ - { - path: '/', - element: , - ErrorBoundary: function Error() { - return
Error
; - }, - children: [ - { - element: , - index: true, - }, - { - path: '/welcome', - element: , - }, - { - path: '/channels', - element: , - }, - { - path: '/channels/:id/edit', - element: , - loader: editChannelLoader(false)(queryClient), - }, - { - path: '/channels/new', - element: , - loader: editChannelLoader(true)(queryClient), +export const router = createBrowserRouter( + [ + { + path: '/', + element: , + ErrorBoundary: function Error() { + return
Error
; }, - { - path: '/channels/:id/programming', - element: , - loader: editProgrammingLoader(queryClient), - }, - { - path: '/channels/:id/programming/add', - element: , - }, - { - path: '/channels/:id/programming/time-slot-editor', - element: , - loader: editProgrammingLoader(queryClient), - }, - { - path: '/channels/:id/watch', - element: , - loader: channelLoader(queryClient), - }, - { - path: '/guide', - element: , - }, - { - path: '/watch', - element: , - }, - { - path: '/settings', - element: , - children: [ - { - path: '/settings/general', - element: , - }, - { - path: '/settings/xmltv', - element: , - }, - { - path: '/settings/ffmpeg', - element: , - }, - { - path: '/settings/plex', - element: , - }, - { - path: '/settings/hdhr', - element: , - }, - { - path: '/settings/tasks', - element: , - }, - ], - }, - { - path: '/library', - children: [ - { - path: '/library', - index: true, - element: , - }, - { - path: '/library/custom-shows', - element: , - loader: customShowsLoader(queryClient), - }, - { - path: '/library/custom-shows/new', - element: , - loader: newCustomShowLoader(queryClient), - }, - { - path: '/library/custom-shows/:id/edit', - element: , - loader: existingCustomShowLoader(queryClient), - }, - { - path: '/library/fillers', - element: , - loader: fillerListsLoader(queryClient), - }, - { - path: '/library/fillers/new', - element: , - loader: newFillerListLoader(queryClient), - }, - { - path: '/library/fillers/:id/edit', - element: , - loader: existingFillerListLoader(queryClient), - }, - ], - }, - ], + children: [ + { + element: , + index: true, + }, + { + path: '/welcome', + element: , + }, + { + path: '/channels', + element: , + }, + { + path: '/channels/:id/edit', + element: , + loader: editChannelLoader(false)(queryClient), + }, + { + path: '/channels/new', + element: , + loader: editChannelLoader(true)(queryClient), + }, + { + path: '/channels/:id/programming', + element: , + loader: editProgrammingLoader(queryClient), + }, + { + path: '/channels/:id/programming/add', + element: , + }, + { + path: '/channels/:id/programming/time-slot-editor', + element: , + loader: editProgrammingLoader(queryClient), + }, + { + path: '/channels/:id/watch', + element: , + loader: channelLoader(queryClient), + }, + { + path: '/guide', + element: , + }, + { + path: '/watch', + element: , + }, + { + path: '/settings', + element: , + children: [ + { + path: '/settings/general', + element: , + }, + { + path: '/settings/xmltv', + element: , + }, + { + path: '/settings/ffmpeg', + element: , + }, + { + path: '/settings/plex', + element: , + }, + { + path: '/settings/hdhr', + element: , + }, + { + path: '/settings/tasks', + element: , + }, + ], + }, + { + path: '/library', + children: [ + { + path: '/library', + index: true, + element: , + }, + { + path: '/library/custom-shows', + element: , + loader: customShowsLoader(queryClient), + }, + { + path: '/library/custom-shows/new', + element: , + loader: newCustomShowLoader(queryClient), + }, + { + path: '/library/custom-shows/:id/edit', + element: , + loader: existingCustomShowLoader(queryClient), + }, + { + path: '/library/fillers', + element: , + loader: fillerListsLoader(queryClient), + }, + { + path: '/library/fillers/new', + element: , + loader: newFillerListLoader(queryClient), + }, + { + path: '/library/fillers/:id/edit', + element: , + loader: existingFillerListLoader(queryClient), + }, + ], + }, + ], + }, + ], + { + basename: import.meta.env.BASE_URL, }, -]); +); diff --git a/web2/src/store/index.ts b/web2/src/store/index.ts index b90c9cfdb..54218d8ab 100644 --- a/web2/src/store/index.ts +++ b/web2/src/store/index.ts @@ -3,14 +3,13 @@ import { StateCreator, create } from 'zustand'; import { devtools, persist } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; import { - ProgrammingListingsState, - createProgrammingListingsState, -} from './programmingSelector/store.ts'; -import { - ChannelEditorState, EditorsState, createChannelEditorState, } from './channelEditor/store.ts'; +import { + ProgrammingListingsState, + createProgrammingListingsState, +} from './programmingSelector/store.ts'; import { ThemeEditorState, createThemeEditorState, diff --git a/web2/vite.config.ts b/web2/vite.config.ts index 6341e12c0..74eba045c 100644 --- a/web2/vite.config.ts +++ b/web2/vite.config.ts @@ -1,5 +1,5 @@ -import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; +import { defineConfig } from 'vite'; // https://vitejs.dev/config/ export default defineConfig({ @@ -7,4 +7,5 @@ export default defineConfig({ build: { sourcemap: true, }, + base: '/web', });