diff --git a/.agents/rules/antigravity-rtk-rules.md b/.agents/rules/antigravity-rtk-rules.md new file mode 100644 index 00000000..8ee44bcd --- /dev/null +++ b/.agents/rules/antigravity-rtk-rules.md @@ -0,0 +1,32 @@ +# RTK - Rust Token Killer (Google Antigravity) + +**Usage**: Token-optimized CLI proxy for shell commands. + +## Rule + +Always prefix shell commands with `rtk` to minimize token consumption. + +Examples: + +```bash +rtk git status +rtk cargo test +rtk ls src/ +rtk grep "pattern" src/ +rtk find "*.rs" . +rtk docker ps +rtk gh pr list +``` + +## Meta Commands + +```bash +rtk gain # Show token savings +rtk gain --history # Command history with savings +rtk discover # Find missed RTK opportunities +rtk proxy # Run raw (no filtering, for debugging) +``` + +## Why + +RTK filters and compresses command output before it reaches the LLM context, saving 60-90% tokens on common operations. Always use `rtk ` instead of raw commands. diff --git a/.changeset/brave-weeks-relax.md b/.changeset/brave-weeks-relax.md new file mode 100644 index 00000000..060dfe60 --- /dev/null +++ b/.changeset/brave-weeks-relax.md @@ -0,0 +1,5 @@ +--- +"@pipelab/plugin-electron": patch +--- + +fix shim diff --git a/.changeset/brown-nights-stop.md b/.changeset/brown-nights-stop.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/brown-nights-stop.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/bumpy-falcons-obey.md b/.changeset/bumpy-falcons-obey.md new file mode 100644 index 00000000..2da68837 --- /dev/null +++ b/.changeset/bumpy-falcons-obey.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sdsd diff --git a/.changeset/busy-trains-guess.md b/.changeset/busy-trains-guess.md new file mode 100644 index 00000000..0d61a24e --- /dev/null +++ b/.changeset/busy-trains-guess.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +bump diff --git a/.changeset/chatty-ways-happen.md b/.changeset/chatty-ways-happen.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/chatty-ways-happen.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/config.json b/.changeset/config.json index 11fb2a9b..8d365c08 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -2,7 +2,9 @@ "$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json", "_changelog": [ "@changesets/changelog-github", - { "repo": "CynToolkit/pipelab" } + { + "repo": "CynToolkit/pipelab" + } ], "privatePackages": { "tag": true, @@ -11,9 +13,8 @@ "changelog": "@changesets/changelog-git", "commit": false, "access": "public", - "fixed": [], + "fixed": [["@pipelab/ui", "@pipelab/cli"]], "linked": [], "baseBranch": "main", - "updateInternalDependencies": "patch", - "ignore": [] + "updateInternalDependencies": "patch" } diff --git a/.changeset/cute-chicken-hunt.md b/.changeset/cute-chicken-hunt.md new file mode 100644 index 00000000..7fad53d8 --- /dev/null +++ b/.changeset/cute-chicken-hunt.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +update diff --git a/.changeset/easy-parents-accept.md b/.changeset/easy-parents-accept.md new file mode 100644 index 00000000..671b03a3 --- /dev/null +++ b/.changeset/easy-parents-accept.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +improve dark theme and improve build history diff --git a/.changeset/eighty-sites-drop.md b/.changeset/eighty-sites-drop.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/eighty-sites-drop.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/eleven-yaks-visit.md b/.changeset/eleven-yaks-visit.md new file mode 100644 index 00000000..801c094d --- /dev/null +++ b/.changeset/eleven-yaks-visit.md @@ -0,0 +1,6 @@ +--- +"@pipelab/shared": patch +"@pipelab/ui": patch +--- + +fix slashes diff --git a/.changeset/fair-lights-jump.md b/.changeset/fair-lights-jump.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/fair-lights-jump.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/fast-ghosts-like.md b/.changeset/fast-ghosts-like.md new file mode 100644 index 00000000..0ba3519b --- /dev/null +++ b/.changeset/fast-ghosts-like.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +changes diff --git a/.changeset/fluffy-taxes-thank.md b/.changeset/fluffy-taxes-thank.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/fluffy-taxes-thank.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/free-animals-bet.md b/.changeset/free-animals-bet.md new file mode 100644 index 00000000..634b6844 --- /dev/null +++ b/.changeset/free-animals-bet.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": major +"@pipelab/plugin-construct": major +"@pipelab/plugin-electron": major +"@pipelab/plugin-discord": major +"@pipelab/plugin-netlify": major +"@pipelab/plugin-nvpatch": major +"@pipelab/asset-electron": major +"@pipelab/plugin-minify": major +"@pipelab/plugin-system": major +"@pipelab/asset-discord": major +"@pipelab/asset-netlify": major +"@pipelab/cloud-azure": major +"@pipelab/plugin-steam": major +"@pipelab/plugin-tauri": major +"@pipelab/test-utils": major +"@pipelab/plugin-core": major +"@pipelab/plugin-itch": major +"@pipelab/plugin-poki": major +"@pipelab/asset-tauri": major +"@pipelab/constants": major +"@pipelab/core-node": major +"@pipelab/migration": major +"@pipelab/tsconfig": major +"@pipelab/shared": major +"@pipelab/cloud": major +"@pipelab/app": major +"@pipelab/cli": major +"@pipelab/ui": major +--- + +initial release diff --git a/.changeset/free-comics-cover.md b/.changeset/free-comics-cover.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/free-comics-cover.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/funny-clubs-flash.md b/.changeset/funny-clubs-flash.md new file mode 100644 index 00000000..0f0a32f7 --- /dev/null +++ b/.changeset/funny-clubs-flash.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +- diff --git a/.changeset/hot-turkeys-cough.md b/.changeset/hot-turkeys-cough.md new file mode 100644 index 00000000..0d61a24e --- /dev/null +++ b/.changeset/hot-turkeys-cough.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +bump diff --git a/.changeset/kind-dryers-cheer.md b/.changeset/kind-dryers-cheer.md new file mode 100644 index 00000000..f4e14e0f --- /dev/null +++ b/.changeset/kind-dryers-cheer.md @@ -0,0 +1,6 @@ +--- +"@pipelab/core-node": patch +"@pipelab/app": patch +--- + +improve update checks diff --git a/.changeset/late-chairs-beam.md b/.changeset/late-chairs-beam.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/late-chairs-beam.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/lazy-cloths-prove.md b/.changeset/lazy-cloths-prove.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/lazy-cloths-prove.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/light-clubs-cheer.md b/.changeset/light-clubs-cheer.md new file mode 100644 index 00000000..4bb4177a --- /dev/null +++ b/.changeset/light-clubs-cheer.md @@ -0,0 +1,5 @@ +--- +"@pipelab/core-node": patch +--- + +fix install diff --git a/.changeset/modern-roses-stick.md b/.changeset/modern-roses-stick.md new file mode 100644 index 00000000..0d61a24e --- /dev/null +++ b/.changeset/modern-roses-stick.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +bump diff --git a/.changeset/new-feet-brush.md b/.changeset/new-feet-brush.md new file mode 100644 index 00000000..2da68837 --- /dev/null +++ b/.changeset/new-feet-brush.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sdsd diff --git a/.changeset/nice-streets-smell.md b/.changeset/nice-streets-smell.md new file mode 100644 index 00000000..522fea0c --- /dev/null +++ b/.changeset/nice-streets-smell.md @@ -0,0 +1,5 @@ +--- +"@pipelab/plugin-electron": patch +--- + +fix electron copy diff --git a/.changeset/nine-spiders-sit.md b/.changeset/nine-spiders-sit.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/nine-spiders-sit.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/ninety-squids-post.md b/.changeset/ninety-squids-post.md new file mode 100644 index 00000000..d90b3f21 --- /dev/null +++ b/.changeset/ninety-squids-post.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +df diff --git a/.changeset/orange-wombats-call.md b/.changeset/orange-wombats-call.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/orange-wombats-call.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/plain-otters-yawn.md b/.changeset/plain-otters-yawn.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/plain-otters-yawn.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 00000000..71fe76e1 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,80 @@ +{ + "mode": "pre", + "tag": "beta", + "initialVersions": { + "@pipelab/cli": "1.9.9", + "@pipelab/app": "1.9.9", + "@pipelab/ui": "1.9.9", + "@pipelab/asset-discord": "0.9.9", + "@pipelab/asset-electron": "0.9.9", + "@pipelab/asset-netlify": "0.9.9", + "@pipelab/asset-tauri": "0.9.9", + "@pipelab/cloud": "0.9.9", + "@pipelab/cloud-azure": "0.9.9", + "@pipelab/constants": "0.9.9", + "@pipelab/core-node": "0.9.9", + "@pipelab/migration": "0.9.9", + "@pipelab/shared": "0.9.9", + "@pipelab/test-utils": "0.9.9", + "@pipelab/tsconfig": "0.9.9", + "@pipelab/plugin-construct": "0.9.9", + "@pipelab/plugin-core": "0.9.9", + "@pipelab/plugin-discord": "0.9.9", + "@pipelab/plugin-electron": "0.9.9", + "@pipelab/plugin-filesystem": "0.9.9", + "@pipelab/plugin-itch": "0.9.9", + "@pipelab/plugin-minify": "0.9.9", + "@pipelab/plugin-netlify": "0.9.9", + "@pipelab/plugin-nvpatch": "0.9.9", + "@pipelab/plugin-poki": "0.9.9", + "@pipelab/plugin-steam": "0.9.9", + "@pipelab/plugin-system": "0.9.9", + "@pipelab/plugin-tauri": "0.9.9", + "mini-c3-electron": "0.0.0" + }, + "changesets": [ + "brave-weeks-relax", + "brown-nights-stop", + "bumpy-falcons-obey", + "busy-trains-guess", + "chatty-ways-happen", + "cute-chicken-hunt", + "easy-parents-accept", + "eighty-sites-drop", + "eleven-yaks-visit", + "fair-lights-jump", + "fast-ghosts-like", + "fluffy-taxes-thank", + "free-animals-bet", + "free-comics-cover", + "funny-clubs-flash", + "hot-turkeys-cough", + "kind-dryers-cheer", + "late-chairs-beam", + "lazy-cloths-prove", + "light-clubs-cheer", + "modern-roses-stick", + "new-feet-brush", + "nice-streets-smell", + "nine-spiders-sit", + "ninety-squids-post", + "orange-wombats-call", + "plain-otters-yawn", + "real-suns-run", + "red-lions-live", + "ripe-trams-hug", + "shaky-moments-crash", + "silent-taxis-cry", + "silver-eels-cough", + "smooth-memes-sit", + "sparkly-seals-listen", + "sunny-rats-wash", + "tall-pens-wait", + "tasty-cities-drum", + "tasty-meteors-shout", + "ten-ties-brush", + "true-carpets-lead", + "twenty-falcons-swim", + "yummy-streets-tie" + ] +} diff --git a/.changeset/real-suns-run.md b/.changeset/real-suns-run.md new file mode 100644 index 00000000..176ac953 --- /dev/null +++ b/.changeset/real-suns-run.md @@ -0,0 +1,17 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +--- + +add shims diff --git a/.changeset/red-lions-live.md b/.changeset/red-lions-live.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/red-lions-live.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/ripe-trams-hug.md b/.changeset/ripe-trams-hug.md new file mode 100644 index 00000000..fb5ccabd --- /dev/null +++ b/.changeset/ripe-trams-hug.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +general improvements diff --git a/.changeset/shaky-moments-crash.md b/.changeset/shaky-moments-crash.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/shaky-moments-crash.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/silent-taxis-cry.md b/.changeset/silent-taxis-cry.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/silent-taxis-cry.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/silver-eels-cough.md b/.changeset/silver-eels-cough.md new file mode 100644 index 00000000..c455b42b --- /dev/null +++ b/.changeset/silver-eels-cough.md @@ -0,0 +1,5 @@ +--- +"@pipelab/constants": patch +--- + +fix ci diff --git a/.changeset/smooth-memes-sit.md b/.changeset/smooth-memes-sit.md new file mode 100644 index 00000000..bebdc100 --- /dev/null +++ b/.changeset/smooth-memes-sit.md @@ -0,0 +1,5 @@ +--- +"@pipelab/constants": patch +--- + +Fix beta directory diff --git a/.changeset/sparkly-seals-listen.md b/.changeset/sparkly-seals-listen.md new file mode 100644 index 00000000..f41f9d3e --- /dev/null +++ b/.changeset/sparkly-seals-listen.md @@ -0,0 +1,5 @@ +--- +"@pipelab/plugin-electron": patch +--- + +sd diff --git a/.changeset/sunny-rats-wash.md b/.changeset/sunny-rats-wash.md new file mode 100644 index 00000000..233dd224 --- /dev/null +++ b/.changeset/sunny-rats-wash.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +s diff --git a/.changeset/tall-pens-wait.md b/.changeset/tall-pens-wait.md new file mode 100644 index 00000000..77fdaabd --- /dev/null +++ b/.changeset/tall-pens-wait.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +sd diff --git a/.changeset/tasty-cities-drum.md b/.changeset/tasty-cities-drum.md new file mode 100644 index 00000000..87507a49 --- /dev/null +++ b/.changeset/tasty-cities-drum.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +beta tag diff --git a/.changeset/tasty-meteors-shout.md b/.changeset/tasty-meteors-shout.md new file mode 100644 index 00000000..3277b220 --- /dev/null +++ b/.changeset/tasty-meteors-shout.md @@ -0,0 +1,5 @@ +--- +"@pipelab/core-node": patch +--- + +fix package installation diff --git a/.changeset/ten-ties-brush.md b/.changeset/ten-ties-brush.md new file mode 100644 index 00000000..58ee05c4 --- /dev/null +++ b/.changeset/ten-ties-brush.md @@ -0,0 +1,5 @@ +--- +"@pipelab/plugin-electron": patch +--- + +fix pnpm shimming diff --git a/.changeset/true-carpets-lead.md b/.changeset/true-carpets-lead.md new file mode 100644 index 00000000..ecf7547b --- /dev/null +++ b/.changeset/true-carpets-lead.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +fg diff --git a/.changeset/twenty-falcons-swim.md b/.changeset/twenty-falcons-swim.md new file mode 100644 index 00000000..034a6a0a --- /dev/null +++ b/.changeset/twenty-falcons-swim.md @@ -0,0 +1,32 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +fixes diff --git a/.changeset/yummy-streets-tie.md b/.changeset/yummy-streets-tie.md new file mode 100644 index 00000000..dd271f43 --- /dev/null +++ b/.changeset/yummy-streets-tie.md @@ -0,0 +1,33 @@ +--- +"@pipelab/plugin-filesystem": patch +"@pipelab/plugin-construct": patch +"@pipelab/plugin-electron": patch +"@pipelab/plugin-discord": patch +"@pipelab/plugin-netlify": patch +"@pipelab/plugin-nvpatch": patch +"mini-c3-electron": patch +"@pipelab/asset-electron": patch +"@pipelab/plugin-minify": patch +"@pipelab/plugin-system": patch +"@pipelab/asset-discord": patch +"@pipelab/asset-netlify": patch +"@pipelab/cloud-azure": patch +"@pipelab/plugin-steam": patch +"@pipelab/plugin-tauri": patch +"@pipelab/test-utils": patch +"@pipelab/plugin-core": patch +"@pipelab/plugin-itch": patch +"@pipelab/plugin-poki": patch +"@pipelab/asset-tauri": patch +"@pipelab/constants": patch +"@pipelab/core-node": patch +"@pipelab/migration": patch +"@pipelab/tsconfig": patch +"@pipelab/shared": patch +"@pipelab/cloud": patch +"@pipelab/app": patch +"@pipelab/cli": patch +"@pipelab/ui": patch +--- + +qs diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7fb32ef9..0595b8d0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,12 +10,10 @@ "ghcr.io/sebst/devcontainer-features/desktop-fluxbox:0": {}, "ghcr.io/devcontainers/features/desktop-lite:1": {} }, - "forwardPorts": [ - 6080 - ], + "forwardPorts": [6080], "portsAttributes": { "6080": { "label": "desktop" } } -} \ No newline at end of file +} diff --git a/.env.example b/.env.example deleted file mode 100644 index 0b1c7eef..00000000 --- a/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -SUPABASE_URL= -SUPABASE_ANON_KEY= -SUPABASE_PROJECT_ID= -EDGE_FUNCTION_ROOT= -POSTHOG_API_KEY= diff --git a/.gemini/settings.json b/.gemini/settings.json index 7bd98b24..c2691c88 100644 --- a/.gemini/settings.json +++ b/.gemini/settings.json @@ -2,13 +2,10 @@ "mcpServers": { "primevue": { "command": "npx", - "args": [ - "-y", - "@primevue/mcp" - ] + "args": ["-y", "@primevue/mcp"] }, "supabase": { "httpUrl": "https://mcp.supabase.com/mcp?project_ref=uehmyyeqheqnxmzhctcd" } } -} \ No newline at end of file +} diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml new file mode 100644 index 00000000..f73d6daa --- /dev/null +++ b/.github/workflows/pipeline.yml @@ -0,0 +1,443 @@ +name: Pipeline + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + workflow_dispatch: + inputs: + forcePublish: + description: "Force publish apps" + required: false + type: boolean + default: false + prerelease: + description: "Mark as pre-release" + required: false + type: boolean + default: true + +permissions: + contents: write + pull-requests: write + id-token: write + +jobs: + changes: + name: Detect Changes + runs-on: ubuntu-latest + outputs: + affected: ${{ steps.detect.outputs.affected }} + needs_build: ${{ steps.detect.outputs.needs_build }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + run_install: false + + - name: Use Node.js 24 + uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + + - name: Detect Changes + id: detect + run: | + if [ "${{ github.ref_name }}" == "main" ] || [ "${{ github.ref_name }}" == "develop" ]; then + echo "affected=['ALL']" >> $GITHUB_OUTPUT + echo "needs_build=true" >> $GITHUB_OUTPUT + echo "Bypassing change detection for release branch: ${{ github.ref_name }}" + exit 0 + fi + + if [ "${{ github.event_name }}" == "pull_request" ]; then + BASE_REF="origin/${{ github.base_ref }}" + else + # On feature push, only compare against the previous commit (delta) + BASE_REF="${{ github.event.before }}" + fi + + # Fallback if BASE_REF is null or empty (initial push) + if [ -z "$BASE_REF" ] || [ "$BASE_REF" == "0000000000000000000000000000000000000000" ]; then + BASE_REF=$(git describe --tags --abbrev=0 2>/dev/null || echo "HEAD~10") + fi + + echo "Comparing against: $BASE_REF" + + # Use turbo to list affected packages + npx turbo ls -F "[$BASE_REF]" --output=json > affected.json + + # Run our detection script + npx tsx scripts/detect-changes.ts affected.json + + verify-lint: + name: Verify Lint + needs: changes + if: needs.changes.outputs.affected != '[]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + run_install: false + - name: Use Node.js 24 + uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + cache: "pnpm" + - name: Install dependencies + run: pnpm install + - name: Cache Turbo + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.job }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo-${{ github.job }}- + - name: Lint + run: pnpm turbo lint --cache-dir=".turbo" + continue-on-error: true + + verify-typecheck: + name: Verify Typecheck + needs: changes + if: needs.changes.outputs.affected != '[]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + run_install: false + - name: Use Node.js 24 + uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + cache: "pnpm" + - name: Install dependencies + run: pnpm install + - name: Cache Turbo + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.job }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo-${{ github.job }}- + - name: Typecheck + run: pnpm turbo typecheck --cache-dir=".turbo" + continue-on-error: true + + build-all: + name: Build All + needs: [verify-lint, verify-typecheck, test-matrix, changes] + if: needs.changes.outputs.affected != '[]' && needs.changes.outputs.needs_build == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + run_install: false + - name: Use Node.js 24 + uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + cache: "pnpm" + - name: Install dependencies + run: pnpm install + - name: Cache Turbo + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.job }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo-${{ github.job }}- + - name: Build packages + env: + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} + SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }} + POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + run: pnpm build --cache-dir=".turbo" + - name: Upload monorepo-dist + uses: actions/upload-artifact@v4 + with: + name: monorepo-dist + path: | + packages/*/dist/** + plugins/*/dist/** + apps/*/dist/** + apps/desktop/.vite/** + apps/ui/dist/** + + publish-preview: + name: Publish Preview + needs: build-all + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + run_install: false + - name: Use Node.js 24 + uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + cache: "pnpm" + - name: Install dependencies + run: pnpm install + - name: Download monorepo-dist + uses: actions/download-artifact@v4 + with: + name: monorepo-dist + path: . + - name: Publish to pkg.pr.new + run: | + npx pkg-pr-new publish \ + packages/shared \ + packages/core-node \ + plugins/plugin-* \ + assets/asset-* \ + packages/migration \ + packages/constants \ + apps/cli \ + --comment=update + + release: + name: Release & Deploy + needs: [build-all, verify-lint, verify-typecheck, test-matrix, changes, build-desktop] + if: | + always() && + (needs.build-desktop.result == 'success' || needs.build-desktop.result == 'skipped') && + (needs.build-all.result == 'success' || needs.build-all.result == 'skipped') && + needs.verify-lint.result == 'success' && + needs.verify-typecheck.result == 'success' && + needs.test-matrix.result == 'success' && + (github.event_name == 'workflow_dispatch' || + (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop'))) + runs-on: ubuntu-latest + outputs: + published: ${{ steps.changesets.outputs.published }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v4 + with: + run_install: false + + - name: Use Node.js 24 + uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install + + - name: Download monorepo-dist + if: needs.changes.outputs.needs_build == 'true' + uses: actions/download-artifact@v4 + with: + name: monorepo-dist + path: . + + - name: Publish to NPM & Create GitHub Release + id: changesets + uses: changesets/action@v1 + with: + publish: pnpm changeset publish --provenance + createGithubReleases: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: true + + - name: Download all artifacts + if: steps.changesets.outputs.published == 'true' || github.event.inputs.forcePublish == 'true' + uses: actions/download-artifact@v4 + with: + path: artifacts + continue-on-error: true + + - name: Debug Artifacts + run: ls -R artifacts + continue-on-error: true + + - name: Get Versions + id: versions + run: | + APP_VERSION=$(node -p "require('./apps/desktop/package.json').version") + CLI_VERSION=$(node -p "require('./apps/cli/package.json').version") + ASSET_ELECTRON_VERSION=$(node -p "require('./assets/asset-electron/package.json').version") + ASSET_DISCORD_VERSION=$(node -p "require('./assets/asset-discord/package.json').version") + ASSET_NETLIFY_VERSION=$(node -p "require('./assets/asset-netlify/package.json').version") + ASSET_TAURI_VERSION=$(node -p "require('./assets/asset-tauri/package.json').version") + UI_VERSION=$(node -p "require('./apps/ui/package.json').version") + echo "app_version=$APP_VERSION" >> $GITHUB_OUTPUT + echo "cli_version=$CLI_VERSION" >> $GITHUB_OUTPUT + echo "asset_electron_version=$ASSET_ELECTRON_VERSION" >> $GITHUB_OUTPUT + echo "asset_discord_version=$ASSET_DISCORD_VERSION" >> $GITHUB_OUTPUT + echo "asset_netlify_version=$ASSET_NETLIFY_VERSION" >> $GITHUB_OUTPUT + echo "asset_tauri_version=$ASSET_TAURI_VERSION" >> $GITHUB_OUTPUT + echo "ui_version=$UI_VERSION" >> $GITHUB_OUTPUT + + IS_PRERELEASE="false" + if [[ $APP_VERSION == *"-"* ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.prerelease }}" == "true" ]]; then + IS_PRERELEASE="true" + fi + + echo "prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT + + - name: Upload Desktop Binaries + if: steps.changesets.outputs.published == 'true' || github.event.inputs.forcePublish == 'true' + uses: softprops/action-gh-release@v2 + with: + tag_name: "@pipelab/app@${{ steps.versions.outputs.app_version }}" + prerelease: ${{ steps.versions.outputs.prerelease == 'true' }} + files: | + artifacts/**/*.dmg + artifacts/**/*.exe + artifacts/**/*.zip + artifacts/**/RELEASES + artifacts/**/*.nupkg + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish @pipelab/ui dynamically + if: steps.changesets.outputs.published == 'true' || github.event_name == 'workflow_dispatch' + run: node scripts/publish-app.mjs ui + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + + - name: Publish @pipelab/cli dynamically + if: steps.changesets.outputs.published == 'true' || github.event_name == 'workflow_dispatch' + run: node scripts/publish-app.mjs cli + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + + build-desktop: + name: Build Desktop (${{ matrix.os }} - ${{ matrix.arch }}) + needs: [build-all, test-matrix, changes] + if: | + always() && + (needs.build-all.result == 'success') && + (needs.test-matrix.result == 'success' || needs.test-matrix.result == 'skipped') && + (contains(needs.changes.outputs.affected, 'ALL') || contains(fromJson(needs.changes.outputs.affected), '@pipelab/app') || github.event.inputs.forcePublish == 'true') + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + arch: x64 + - os: windows-latest + arch: x64 + - os: macos-26-intel + arch: x64 + - os: macos-26 + arch: arm64 + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + run_install: false + - uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + cache: "pnpm" + - run: pnpm install + + - name: Download monorepo-dist + if: needs.changes.outputs.needs_build == 'true' + uses: actions/download-artifact@v4 + with: + name: monorepo-dist + path: . + + - name: Import Apple Code Signing Certificate + uses: apple-actions/import-codesign-certs@v3 + if: startsWith(matrix.os, 'macos-') + with: + p12-file-base64: ${{ secrets.CERTIFICATE_OSX_APPLICATION }} + p12-password: ${{ secrets.CERTIFICATE_OSX_APPLICATION_PASSWORD }} + + - name: Debug Architectures + run: | + echo "Host Architecture (uname -m): $(uname -m)" + echo "Host Architecture (node process.arch): $(node -p 'process.arch')" + echo "Target Architecture (matrix.arch): ${{ matrix.arch }}" + echo "Target Architecture (env.TARGET_ARCH): $TARGET_ARCH" + echo "Target Architecture (env.npm_config_arch): $npm_config_arch" + env: + TARGET_ARCH: ${{ matrix.arch }} + npm_config_arch: ${{ matrix.arch }} + + - name: Package & Make Desktop + env: + DEBUG: "electron-osx-sign*,electron-forge:*" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} + SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }} + POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + TARGET_ARCH: ${{ matrix.arch }} + npm_config_arch: ${{ matrix.arch }} + run: | + cd apps/desktop + pnpm run make -- --arch=${{ matrix.arch }} + + - name: Debug Output + run: ls -R apps/desktop/out/make + continue-on-error: true + + - uses: actions/upload-artifact@v4 + with: + name: desktop-artifacts-${{ matrix.os }}-${{ matrix.arch }} + path: apps/desktop/out/make/**/* + + test-matrix: + name: Test Matrix (${{ matrix.os }}) + needs: [changes] + if: | + always() && + needs.changes.outputs.affected != '[]' + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-26-intel, macos-26] + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + run_install: false + - uses: actions/setup-node@v4 + with: + node-version: 24.15.0 + cache: "pnpm" + - run: pnpm install + + - name: Cache Turbo + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.job }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo-${{ github.job }}- + - name: Run Tests + run: pnpm turbo test --cache-dir=".turbo" --log-order=grouped --concurrency 1 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml deleted file mode 100644 index 58d89887..00000000 --- a/.github/workflows/push.yml +++ /dev/null @@ -1,161 +0,0 @@ -name: Electron Forge CI/CD - -on: - push: - tags: - - "*" - branches: - - main - - develop - pull_request: - branches: [main, develop] - merge_group: - workflow_dispatch: - -jobs: - build-and-test: - runs-on: ${{ matrix.os }} - env: - CI: true - DEBUG: "*" - - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - arch: [x64, arm64] - exclude: - - os: ubuntu-latest - arch: arm64 - - os: windows-latest - arch: arm64 - - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v4 - name: Install pnpm - with: - run_install: false - - - name: Use Node.js 22.5.1 - uses: actions/setup-node@v4 - with: - node-version: "22.5.1" - cache: "pnpm" - - - name: Set up Python 3.10 - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Install dependencies - run: pnpm install - - - name: rebuild - run: npm rebuild - - - name: Import Apple Code Signing Certificate - uses: apple-actions/import-codesign-certs@v3 - if: matrix.os == 'macos-latest' - with: - p12-file-base64: ${{ secrets.CERTIFICATE_OSX_APPLICATION }} - p12-password: ${{ secrets.CERTIFICATE_OSX_APPLICATION_PASSWORD }} - - - name: Verify certificates - if: matrix.os == 'macos-latest' - run: | - security find-identity -v -p codesigning - codesign --verify --verbose /Applications/Xcode.app - - - name: Package application - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - SUPABASE_URL: ${{ secrets.SUPABASE_URL }} - SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} - SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }} - POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: pnpm electron-forge publish --dry-run --arch ${{ matrix.arch }} - - - name: Disable AppArmor restriction - if: matrix.os == 'ubuntu-latest' - run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 - - - name: Run tests - uses: coactions/setup-xvfb@v1 - continue-on-error: true - with: - run: pnpm test:e2e:raw - - - name: Upload Playwright artifacts - uses: actions/upload-artifact@v4 - continue-on-error: true - with: - name: ${{ matrix.os }}-playwright - path: playwright/**/* - - - name: windows workaround - if: matrix.os == 'windows-latest' - run: rd -r "out/Pipelab-win32-x64/resources/app/node_modules" - - - name: Upload artifacts - if: success() - continue-on-error: true - uses: actions/upload-artifact@v4 - with: - name: artifact-${{ matrix.os }}-${{ matrix.arch }}-out - path: out/**/* - - release: - permissions: - contents: write - discussions: write - needs: build-and-test - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - arch: [x64, arm64] - exclude: - - os: ubuntu-latest - arch: arm64 - - os: windows-latest - arch: arm64 - if: | - !cancelled() && - (startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch') - - steps: - - uses: actions/checkout@v4 - - - name: Download artifacts - uses: actions/download-artifact@v5 - with: - name: artifact-${{ matrix.os }}-${{ matrix.arch }}-out - path: out - - - uses: pnpm/action-setup@v4 - name: Install pnpm - with: - run_install: false - - - name: Use Node.js 22.5.1 - uses: actions/setup-node@v4 - with: - node-version: "22.5.1" - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --prod=false - - - name: windows workaround - if: matrix.os == 'windows-latest' - run: cd out/Pipelab-win32-x64/resources/app && pnpm i - - - name: Publish release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: pnpm electron-forge publish --from-dry-run diff --git a/.gitignore b/.gitignore index 3a025da9..919a21cd 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,9 @@ typings/ # Vite .vite/ +# Build output +dist/ + # Electron-Forge out/ @@ -106,3 +109,8 @@ assets/tauri/template/app/src/app # Local Netlify folder .netlify +apps/cli/bin + +.turbo +apps/desktop/bin/ +apps/cli/assets/ui \ No newline at end of file diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 00000000..7acca809 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,10 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "ignorePatterns": [ + "dist", + "out", + "node_modules", + "bin", + "**/*.d.ts" + ] +} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 9c6b791d..00000000 --- a/.prettierignore +++ /dev/null @@ -1,6 +0,0 @@ -out -dist -pnpm-lock.yaml -LICENSE.md -tsconfig.json -tsconfig.*.json diff --git a/.prettierrc.yaml b/.prettierrc.yaml deleted file mode 100644 index 35893b3b..00000000 --- a/.prettierrc.yaml +++ /dev/null @@ -1,4 +0,0 @@ -singleQuote: true -semi: false -printWidth: 100 -trailingComma: none diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..17fb80cb --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,91 @@ +# Pipelab Architecture + +Pipelab has a modular architecture designed to support both a rich desktop experience and standalone execution in headless environments (like CI/CD pipelines). + +## High-Level Diagram + +The following diagram illustrates how the different packages in the monorepo interact, especially in the context of the Desktop Application. + +```mermaid +graph TD + %% Define Packages + subgraph apps["Apps Workspace"] + Desktop["@pipelab/app
(Electron Shell)"] + UI["@pipelab/ui
(Vue 3 Web App)"] + CLI["@pipelab/cli
(Node.js Server/CLI)"] + end + + subgraph packages["Packages Workspace"] + CoreNode["@pipelab/core-node
(Business Logic & Plugins)"] + Shared["@pipelab/shared
(Types, APIs, Utilities)"] + Constants["@pipelab/constants"] + end + + %% Dependencies & Data Flow + User([User]) -->|Interacts with| UI + + UI -->|1. Native Dialogs/OS Integration| Desktop + note1[IPC via Preload] -.-> UI + + UI -->|2. Graph Execution & File IO| CLI + note2[WebSocket Connection] -.-> UI + + Desktop -->|Spawns & Manages Lifecycle| CLI + + CLI -->|Executes Logic| CoreNode + Desktop -->|Hooks Native Capabilities| CoreNode + + %% Shared Dependencies + UI -.-> Shared + Desktop -.-> Shared + CLI -.-> Shared + CoreNode -.-> Shared + + UI -.-> Constants + Desktop -.-> Constants + CLI -.-> Constants + CoreNode -.-> Constants +``` + +## Core Components + +### 1. `@pipelab/ui` (The Frontend) + +A standalone Vite + Vue 3 Single Page Application (SPA). + +- **Responsibility**: Rendering the visual node editor, settings, and pipeline management interfaces. +- **Agnostic**: It does not import any Node.js or Electron-specific code. +- **Routing**: It uses an intelligent API composable (`useAPI`) that routes requests: + - **Native OS Tasks** (e.g., Opening a file picker dialog) are sent to the Electron shell via IPC. + - **Core Tasks** (e.g., Executing a pipeline, reading/writing project files) are sent to the standalone CLI server via WebSockets. + +### 2. `@pipelab/app` (The Desktop Shell) + +A thin Electron wrapper around the UI and the CLI. + +- **Responsibility**: Providing OS-level integration (File Dialogs, Auto-updates, System Tray) and managing the lifecycle of the underlying CLI server. +- **Startup Flow**: + 1. Electron starts up extremely fast as it loads minimal dependencies. + 2. It spawns the `@pipelab/cli` server as a background child process. + 3. It loads the `@pipelab/ui` web application in a `BrowserWindow`. +- **Context Injection**: It injects native Electron capabilities (like `BrowserWindow` focus and `dialog` modules) into the shared `SystemContext` so the core logic can request UI prompts if necessary. + +### 3. `@pipelab/cli` (The Standalone Server & CLI) + +A Node.js command-line interface, bundled into standalone binaries using `pkg` for production. + +- **Responsibility**: Running the WebSocket server that the UI connects to, and eventually serving as a headless runner for CI/CD environments. +- **Capabilities**: It has full file-system access and runs the heavy Node.js plugins (Docker, zip extraction, external command execution). + +### 4. `@pipelab/core-node` (The Brains) + +A shared library containing all the Node.js specific business logic. + +- **Responsibility**: Defining the WebSocket server, IPC handlers, plugin execution engine, and file system operations. +- **Environment Agnostic**: It relies on an injected `SystemContext` to abstract away whether it is running inside an Electron main process or a headless CLI. + +### 5. `@pipelab/shared` & `@pipelab/constants` + +Shared libraries containing code that is safe to run in both Node.js and Browser environments. + +- **Responsibility**: Defining data models, IPC definitions, validation schemas, and common utilities used across the entire monorepo. diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index cbe78641..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,58 +0,0 @@ -# @pipelab/app - -## 1.4.6 - -### Patch Changes - -- 94778b9: improvements - add log support - fix config loading - fix step placeholder in parameter editor - improved new project creation - add steam & steam overlay support - -## 1.4.5 - -### Patch Changes - -- 3ea4f00: fix tests - -## 1.4.4 - -### Patch Changes - -- a2489dd: fix electron configuration - -## 1.4.3 - -### Patch Changes - -- improvements - add log support - fix config loading - fix step placeholder in parameter editor - -## 1.4.1 - -### Patch Changes - -- 48a3569: feat(plugin-construct): add throttle zip log - feat(plugin-construct): add click on addon installation prompts - feat(plugin-construct): add loading project progress -- d1f68b8: feat(electron): support url preview (fix #32) - feat(app): add dialog prompt - feat(app): improve ui -- 665562c: fix(app): fix adding node wrong offset - feat(app): hide sidebar when editing project -- 48a3569: fix(app): add live logs hooks support - fix(plugin-steam): fix steam permission, general improvements & logged out detection - -## 1.1.26 - -### Patch Changes - -- 25e6bb0: path picker now support options from plugins -- 26be9b1: feat(electron): add custom main code support - feat(electron): add "configure" action - feat: improve display strings -- fadc3cc: Improved boolean parameter diff --git a/GEMINI.md b/GEMINI.md index cbce0ca2..9f341c7a 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -1,73 +1,35 @@ # Pipelab - AI Context -Pipelab is a visual automation tool designed to create task automation workflows and cross-platform desktop applications. It provides a visual interface for building pipelines that can automate repetitive tasks, deploy to various platforms (Steam, Itch.io, etc.), and more. - -## Architecture Overview - -The project is an Electron-based application built with Vue 3 and TypeScript. - -- **Main Process (`src/main.ts`)**: Manages the Electron lifecycle, IPC handlers, a WebSocket server for real-time communication, and handles headless pipeline execution via command-line arguments. -- **Renderer Process (`src/renderer/`)**: A Vue 3 application using PrimeVue for UI components. It communicates with the main process via IPC and WebSockets. -- **Shared (`src/shared/`)**: Contains models, types, and utilities shared between the main and renderer processes. -- **Core Engine**: Leverages `@pipelab/core` and QuickJS (via WebAssembly) for executing automation logic. - -## Tech Stack - -- **Framework**: [Electron](https://www.electronjs.org/) -- **Frontend**: [Vue 3](https://vuejs.org/) (Composition API) -- **UI Library**: [PrimeVue v4](https://primevue.org/) with Tailwind/PrimeFlex -- **State Management**: [Pinia](https://pinia.vuejs.org/) -- **Build Tool**: [Vite](https://vitejs.dev/) with [Electron Forge](https://www.electronforge.io/) -- **Database/Backend**: [Supabase](https://supabase.com/) -- **Testing**: [Vitest](https://vitest.dev/) (Unit), [Playwright](https://playwright.dev/) (E2E) -- **Analytics/Monitoring**: [PostHog](https://posthog.com/), [Sentry](https://sentry.io/) - -## Key Directories - -- `src/main/`: Electron main process logic, IPC handlers, and API. -- `src/renderer/`: Vue application source code (components, pages, store, etc.). -- `src/shared/`: Shared types, constants, and utilities. -- `assets/`: Static assets and build-related resources (icons, entitlements). -- `scripts/`: Maintenance and migration scripts. -- `tests/`: Unit and E2E tests. - -## Building and Running - -The project uses `pnpm` as its package manager. - -| Task | Command | -| :--- | :--- | -| **Development** | `pnpm dev` (starts Electron with source maps enabled) | -| **Build (All)** | `pnpm build` | -| **Build (Linux)** | `pnpm build:linux` | -| **Build (Windows)** | `pnpm build:win` | -| **Build (Mac)** | `pnpm build:mac` | -| **Package** | `pnpm package` | -| **Unit Tests** | `pnpm test:unit` | -| **E2E Tests** | `pnpm test:e2e:local` | -| **Linting** | `pnpm lint` | -| **Type Checking**| `pnpm typecheck` | - -## Development Conventions - -- **Typing**: Strict TypeScript usage across the codebase. -- **Components**: Functional and modular Vue components. PrimeVue is used for most UI elements. -- **State**: Persistent state management using Pinia with `pinia-plugin-persistedstate`. -- **Communication**: Use the defined IPC handlers (`src/main/handlers.ts`) and the WebSocket manager for renderer-to-main or external communication. -- **Versioning**: Uses [Changesets](https://github.com/changesets/changesets) for managing versions and changelogs. -- **Code Style**: Enforced by ESLint and Prettier. Run `pnpm format` to auto-format. - -## Common Workflows - -- **Adding a new Node/Block**: Investigate `src/shared/model.ts` and how nodes are registered in the core engine. -- **Modifying the UI**: Most views are located in `src/renderer/pages/` or `src/renderer/components/`. -- **Database Changes**: Update Supabase types using `pnpm supa:types` after modifying the remote schema. -- **Releases**: - 1. `pnpm changeset` to document changes. - 2. `pnpm changeset version` to bump versions. - 3. `pnpm changeset tag` to tag the release. - - -# General recomandations -- When modifying code, do not attempt to typecheck it. -- When modifying code, do not attempt to lint it. +## Architecture +- **Desktop (`apps/desktop/`)**: Electron main process, IPC, WebSocket server, and headless execution. +- **UI (`apps/ui/`)**: Vue 3 (Composition API) & PrimeVue v4. Communicates via IPC & WebSockets. +- **CLI (`apps/cli/`)**: CLI entrypoints and commands. +- **Packages (`packages/`)**: Shared utilities, constants, migrations, and plugins. +- **Core Engine (`packages/core-node/` & `@pipelab/plugin-core`)**: Executed using QuickJS (via WebAssembly). + +## Tech Stack & CLI Tasks +Uses `pnpm` and Turborepo. +- **Dev**: `pnpm dev` +- **Build**: `pnpm build` +- **Typecheck**: `pnpm typecheck` +- **Format**: `pnpm format` (runs `oxfmt .`) +- **Lint**: `pnpm lint` (runs `oxlint`) + +## Core Workflows +- **Nodes/Blocks**: Register and define nodes inside `plugins/`. +- **UI Views**: Located in `apps/ui/src/pages/` and `apps/ui/src/components/`. +- **Database**: Remote schema is powered by Supabase. Update Supabase types after remote schema modifications. +- **Releases**: Managed via Changesets (`pnpm changeset` -> `pnpm changeset version` -> `pnpm changeset tag`). + +## Development Rules & Conventions + +### Typing & Code Quality +- **Never use `as any`**: Do not use `as any` or `as XXX` or `as unknown` or loose `any` casts. Always use strict, proper TypeScript types or safe conversions. +- **No typecheck/lint on modify**: Do not attempt to run typecheck or lint commands during modification. +- **Packages**: Never import workspace packages via subpaths (e.g. `import { useAPI } from "@pipelab/shared/api"` is forbidden; use package exports). + +### Workspace Operations +- Do not read docs from packages directly; use context7 mcp. +- Prefer native file read tools over `cat` command. +- Do not grep unless strictly necessary. Never grep in gitignored directories. Use `rg` instead of `grep`. +- Think twice before proposing a solution/plan to identify evident flaws or simpler alternatives. diff --git a/LICENSE.md b/LICENSE similarity index 98% rename from LICENSE.md rename to LICENSE index bc7df19b..3f204d7d 100644 --- a/LICENSE.md +++ b/LICENSE @@ -6,7 +6,7 @@ FSL-1.1-MIT ## Notice -Copyright 2024-present Quentin Goinaud - Armaldio +Copyright 2026 CynToolkit ## Terms and Conditions diff --git a/README.md b/README.md index 87217926..649a0b9f 100644 --- a/README.md +++ b/README.md @@ -2,83 +2,92 @@ ![logo](./readme/full_white_bg_black_text.png) -## What is Pipelab? +Pipelab is a visual automation tool designed to create task automation workflows and cross-platform desktop applications. -A visual tool to create task automation workflows. +## 🏗️ Orchestration Overview -## Why use Pipelab? +Pipelab is built as a monorepo with three primary application layers that work together to provide a seamless automation experience: -- Create cross-platform desktop applications -- Deploy to popular platforms (Steam, Itch.io, etc.) -- Automate repetitive tasks +```mermaid +graph TD + classDef main fill:#0096FF,stroke:#333,stroke-width:2px; -# Getting Started + subgraph UserInterface["User Interface"] + UI["@pipelab/ui (Vue 3)"] + end -# Making a release -``` -pnpm changeset version -pnpm changeset tag + subgraph Container["Desktop Container"] + Electron["@pipelab/app (Electron)"] + end + + subgraph Engine["The Engine"] + CLI["@pipelab/cli (Node.js)"] + end + + UI <-->|WebSocket| CLI + UI <-->|IPC| Electron + Electron ---|Spawns Sidecar| CLI + CLI ---|Executes| Pipelines[Automation Pipelines] + + class UI,Electron,CLI main; ``` -# Architecture -```mermaid -graph TD - classDef pipelab fill:#0096FF,stroke:#333,stroke-width:4px; - classDef todo stroke:#333,stroke-width:4px, stroke-dasharray: 4px; +- **The Engine (@pipelab/cli)**: A standalone Node.js server that handles the heavy lifting. It executes pipelines, manages plugin logic, and exposes a WebSocket API. +- **The Interface (@pipelab/ui)**: A Vue 3 application that provides the visual graph editor. It connects to the CLI via WebSockets for real-time execution feedback. +- **The Container (@pipelab/app)**: An Electron wrapper that provides native OS integration (file dialogs, system tray). In production, it automatically manages the CLI as a "sidecar" process. - DesktopApp[Desktop App - Pipelab] - GameBundle[Game Editor output] +--- - subgraph GameEditors - Construct3[Construct 3] - Godot[Godot] - GDevelop[GDevelop] - end +## 🛠️ Setup & Development - PipelabPlugin[Pipelab Plugin] - SteamPlugin[Steam Plugin] - CoreMessaging[Core Messaging Library] - Renderers[Renderers] +### 1. Prerequisites - subgraph Runtime - Electron - Tauri - Webview - end +Tool versions are managed via **mise**. Check [`.mise.toml`](.mise.toml) for the current requirements. - subgraph Platforms - Steam - Itch - Poki - end +### 2. Environment Configuration - Steamworks[steamworks.js Library] +Create a `.env` file in the **root directory**. This is the single source of truth for all packages: - GameEditors -->|Bundles to| GameBundle - GameBundle -->|Is imported into| DesktopApp - GameEditors -->|Includes| PipelabPlugin +```env +SUPABASE_URL=your_project_url +SUPABASE_ANON_KEY=your_key +POSTHOG_API_KEY=your_key +``` - PipelabPlugin -->|Is included in| GameBundle - PipelabPlugin -->|Implements| CoreMessaging +### 3. Installation - SteamPlugin -->|Is included in| GameBundle - SteamPlugin -->|Implements| CoreMessaging - SteamPlugin -->|Uses| Steamworks +```bash +pnpm install +``` - CoreMessaging -->|Passes messages to| Renderers - Runtime -->|Is embedded in| Renderers - DesktopApp -->|Packages to| Runtime - Runtime -->|Handles events from| CoreMessaging +### 4. Running Development Mode - DesktopApp -->|Deploys to| Platforms - Platforms -->|Uses| Runtime +The fastest way to start the entire ecosystem is from the root: - class DesktopApp,PipelabPlugin,SteamPlugin,CoreMessaging pipelab; - class SteamPlugin,Godot,GDevelop,Tauri,Webview,Itch,Poki todo; +```bash +pnpm dev ``` -# Development -## Enable source maps +> [!TIP] +> This command uses **Turborepo** to start the UI dev server, the Electron process, and the CLI server concurrently. + +--- + +## 📦 Project Structure + +- **`apps/cli`**: The headless engine and WebSocket server. +- **`apps/desktop`**: The Electron lifecycle and IPC handlers. +- **`apps/ui`**: Rendering and visual graph interaction. +- **`packages/*`**: Shared logic, standard constants, and modular plugins (Steam, Discord, etc.). + +--- + +## 🚀 Releases & Versioning + +We use **Changesets** to manage versions and changelogs: + ```bash -NODE_OPTIONS=--enable-source-maps pnpm xxx +pnpm changeset # Document a change +pnpm changeset version # Bump versions +pnpm changeset tag # Create git tags ``` diff --git a/TODO b/TODO deleted file mode 100644 index 157eb323..00000000 --- a/TODO +++ /dev/null @@ -1,74 +0,0 @@ -☐ IMPORTANT - ☐ To cross compile tauri or electron, I don't want a backend or my own CI - ☐ The idea is to have confgurations store online on your account - ☐ On Github Actions or any other CI service, have an action that is - ☐ pipelab/setup and pipelab/run that install all dependencies and that run a config - ☐ Infos are from the variables: account, pipeline & api key - ☐ It will run the pipeline as if it was your computer - -process.noAsar = true is here because electron fs can't deal correctly with asar (for example, like when copying an asar archive) - -https://github.com/nocode-js/sequential-workflow-editor -https://github.com/xyflow/awesome-node-based-uis -https://github.com/CatalystCode/windows-registry-node -https://github.com/tympanix/electron-regedit - -☐ Target: - Stage 1: - ☐ Autosave - ☐ Optimize/minimize images - ☐ https://www.google.com/search?q=sharp+lossless+compression+png&client=firefox-b-d&sxsrf=AB5stBg5O1Uihp_JBHyJnrcJEeF5sm2ZAg%3A1690961809752&ei=kQfKZImzLc2JkdUPqKWVkAs&ved=0ahUKEwjJv_7Pu72AAxXNRKQEHahSBbIQ4dUDCA4&uact=5&oq=sharp+lossless+compression+png&gs_lp=Egxnd3Mtd2l6LXNlcnAiHnNoYXJwIGxvc3NsZXNzIGNvbXByZXNzaW9uIHBuZzIKEAAYRxjWBBiwAzIKEAAYRxjWBBiwAzIKEAAYRxjWBBiwAzIKEAAYRxjWBBiwAzIKEAAYRxjWBBiwAzIKEAAYRxjWBBiwAzIKEAAYRxjWBBiwAzIKEAAYRxjWBBiwA0i5GVDSBFixGHABeAGQAQCYAQCgAQCqAQC4AQPIAQD4AQHiAwQYACBBiAYBkAYI&sclient=gws-wiz-serp - ☐ Package as electron (+ notarize + sign + expose api) - Stage 2: - ☐ CLI - ☐ Github Action integration - ☐ Online Account - ☐ Package as tauri - ☐ Godot export - ☐ Package to playable ad - ☐ Package as discord activity - ☐ Load sensible datas from environnement variables for security purposes - ☐ Command palette - ☐ Undo/Redo - ☐ Upload to - ☐ poki - ☐ itch -. - -EULA -https://codemirror.net/examples/lint/ -https://remixicon.com/ - - ---- - -Tests: -☐ View logs in realtime: started -☐ env (= copy variables) -☐ handle pipeline error gracefully - ☐ display what happened in dialog -☐ process quickjs in webworker - -New version of the c3 export addons for improved version selection -Edge case: old version of the app vs new version of c3p -Activate save only when needed -Active cancel button to not be locked out -Simple mode: also allow to pick variables & such -QuickJS: memory leak, open close action -Add own timers for electorn export & such -C3 Preview ne fonctionne pas -Steam achievement test c3 example -Filesystem plugin: overwrite parameter + better sentences/descriptions -cancel running -cleanup temp directories - -Convert dektop app to web app + node backend -Communication via rest api (for now) or websocket - -vérifier que le fichier custom main existe sinon ca lance une erreur -https://playwright.dev/docs/browsers#opt-in-to-new-headless-mode -Docs sur Electron -Docs sur les logs - -Support path `.local/share`: https://www.construct.net/en/make-games/manuals/construct-3/plugin-reference/filesystem -Personalize tmp folder diff --git a/TODO_MONOREPO.md b/TODO_MONOREPO.md new file mode 100644 index 00000000..c6f33fd8 --- /dev/null +++ b/TODO_MONOREPO.md @@ -0,0 +1,141 @@ +# Pipelab Monorepo Migration - Roadmap & TODO + +The project has undergone a major architectural shift: splitting the monolithic Electron app into a standalone UI package (`@pipelab/ui`), a headless Node.js logic package (`@pipelab/core-node`), and a thin Electron shell (`@pipelab/app`). + +--- + +pipielab run, must return the output as json if "--json" otherwise just return 0 if all done or number for error codee +define a list of error codes + +## 🟢 Phase 1: Stabilization (CURRENT PRIORITY) + +Goal: Ensure the application remains 100% functional in both development and production environments. + +### 1. Dev Workflow Verification + +- [ ] Run `pnpm dev` from the root. +- [ ] Verify UI server starts on `http://localhost:5173`. +- [ ] Verify Electron window opens and successfully loads the UI. +- [ ] Verify "Core" connection: Create a new pipeline and save it (should go through CLI server via WebSocket). +- [ ] Verify "Shell" connection: Use "Choose a new path" in settings/project creation (should trigger Electron's native dialog via IPC). + +### 2. Production Build Verification + +- [ ] Run `pnpm turbo build`. +- [ ] Run `pnpm --filter @pipelab/app package` (Electron Forge). +- [ ] Verify that the `prePackage` hook correctly builds CLI binaries in `apps/cli/bin`. +- [ ] Verify that CLI binaries are copied into the Electron `out/` resource folder. +- [ ] Install/Run the packaged app and verify it can spawn the embedded CLI server. + +### 3. Critical Fixes + +- [ ] **Template Prefetch**: Implement prefetching of all necessary templates (`@pipelab/asset-electron`, etc.) before pipeline execution starts to fail fast with clear errors instead of failing mid-pipeline. +- [ ] **Type Safety**: Resolve the 8 remaining type errors in `apps/ui` reported during `turbo typecheck` (mostly related to PrimeVue components and optional refs). +- [ ] **External Deps**: Audit `apps/desktop/vite.base.config.mts`'s `external` list. Ensure no `@pipelab/*` packages are accidentally externalized in the bundle. +- [ ] **IPC Routing**: Ensure `dialog:showOpenDialog` and `dialog:showSaveDialog` are correctly routed to Electron even when the UI is loaded from a remote URL. +- [ ] **Offline Boot & UI Reflection**: Load the complete interface even when no agents are connected, and reflect the offline state in the UI (hide or disable relevant UI items). + +--- + +## 🟡 Phase 2: Monorepo Excellence + +Goal: Improve build speed, enforce boundaries, and standardize the developer experience. + +### 1. Centralized Configuration + +- [ ] Create `packages/tsconfig` to store base `tsconfig.json` configurations. +- [ ] Create `packages/eslint-config` to share linting rules between UI and Node packages. +- [ ] Update all `package.json` files to use these shared configs. + +### 2. TS Project References + +- [x] Enable `composite: true` in all packages. +- [x] Add `references` arrays to `tsconfig.json` files to reflect the actual dependency graph. +- [x] Switch to `tsc --build` for lightning-fast incremental typechecking. + +### 4. Quality Gates + +- [ ] Implement `syncpack` to keep dependency versions identical across all packages. +- [ ] Set up a GitHub Actions workflow to run `turbo build lint typecheck test` on every PR. +- [x] Ensure `pnpm run typecheck` passes with 0 errors at the root level. +- [ ] Define `typecheck` scripts for the remaining 22 plugins (`plugins/*`) and assets (`assets/*`) to ensure 100% typecheck coverage. + +--- + +## 🔵 Phase 3: Architecture & Communication + +Goal: Modernize internal communication between UI, Core-Node, and Shell. + +### 1. HTTP & WebSocket Migration (Hono + tRPC) + +- [ ] **Hono & tRPC Server Integration** + - Integrate `@hono/node-server` into `@pipelab/core-node` to replace raw `http.createServer` handling. + - Mount a tRPC server on `@pipelab/core-node` (e.g., at `/trpc`) alongside Hono. + - Port existing local file serving logic (SPA assets, plugin resources, templates, and `/media-file/`) into clean Hono route handlers. +- [ ] **Type-Safe RPC Migration via tRPC** + - Define shared tRPC schemas/routers in `@pipelab/shared` (or export from `core-node`). + - Migrate all WebSocket-based RPC commands (saving pipelines, fetching configurations, listing plugins) to type-safe tRPC queries and mutations. +- [ ] **tRPC Subscriptions & Dynamic Rooms for Live Updates** + - Implement a tRPC subscription handler over WebSockets. + - Implement a room-based event pattern: + - Calling a mutation (e.g., `client.pipeline.run.mutate({ id })`) returns a unique execution/subscription `roomId`. + - The client subscribes to that `roomId` via a tRPC subscription (`client.pipeline.onProgress.subscribe({ roomId })`) to stream logs and progress. +- [ ] **Security Enforcement & Best Practices** + - **CORS Protection**: Enforce strict CORS origins in Hono (restricting access to the UI dev server `http://localhost:5173` and local electron origin). + - **Path Traversal Prevention**: Add robust path validation for all Hono file-serving routes to prevent directory traversal (`..`). + - **Handshake Authentication**: Secure the tRPC/Hono endpoints using a local session token handshake generated on startup, protecting the host system from unauthorized local execution. + +### 2. CLI Authentication & Backend-First Auth [IN PROGRESS] + +- [ ] Implement `pipelab login` command for interactive CLI authentication. +- [ ] Implement `pipelab login --token ` command for headless/CI environments. +- [ ] Implement database schema/API for generating and validating long-lived Personal Access Tokens (PATs). + +### 3. Benefits Management Centralization + +- [ ] Move benefits mapping (IDs to names) and entitlement logic to `@pipelab/core-node`. +- [ ] Implement `BenefitsManager` in the backend to calculate user entitlements based on Supabase subscriptions. +- [ ] Implement persistent dev overrides in the backend (stored in a JSON file instead of `localStorage`). +- [ ] Define IPC channels (`benefits:get`, `benefits:setOverride`) for UI interaction. +- [ ] Update UI (`useAuth` store) to react to `benefits:updated` WebSocket events from the backend. + +--- + +## 🟣 Phase 4: Feature Parity & Stability + +Goal: Reach feature parity with the legacy monolithic app and improve core functionality. + +### 1. Core Engine Improvements + +- [ ] **Autosave**: Implement automatic pipeline saving. +- [ ] **Undo/Redo**: Add history support for the node editor. +- [ ] **Error Handling**: Gracefully handle and display pipeline execution errors in dialogs. +- [ ] **Async Execution**: Investigate processing QuickJS logic in Web Workers to prevent UI blocking. +- [ ] **Memory Management**: Audit and resolve potential memory leaks in QuickJS (open/close actions). +- [ ] **Cleanup**: Implement automatic temporary directory cleanup (`tmp/`). +- [ ] **ASAR Handling**: Ensure `process.noAsar = true` is correctly set and handled for cross-app file copies. + +### 2. Node & Plugin Enhancements + +- [ ] **Image Optimization**: Integrate `sharp` for lossless compression in relevant nodes. +- [ ] **Filesystem Expansion**: Support `.local/share` paths and better overwrite parameters. +- [ ] **C3 Integration**: Fix C3 Preview issues and improve version selection for C3P exports. +- [ ] **Steam/Discord**: Verify Steam achievement integrations and investigate "Discord Activity" packaging. + +--- + +## ☁️ Phase 5: Cloud & Ecosystem + +Goal: Expand Pipelab beyond the local desktop environment. + +### 1. CI/CD Integration + +- [ ] **GitHub Actions**: Create `pipelab/setup` and `pipelab/run` actions for automated pipeline runs. +- [ ] **Interactive CLI**: Implement `pipelab login` for local CLI authentication. +- [ ] **Headless Execution**: Ensure pipelines can run in CI environments using environment variables/PATs for sensitive data. + +### 2. Cross-Platform & Distribution + +- [ ] **Cloud Sync**: Store configurations and pipelines in the user's online account for cross-machine access. +- [ ] **Alternative Packaging**: Investigate packaging as **Tauri** for smaller binary sizes or **Godot Export** for game-integrated pipelines. +- [ ] **Publishing**: Expand specialized upload nodes for **Poki**, **Itch**, etc. diff --git a/apps/cli/.npmrc b/apps/cli/.npmrc new file mode 100644 index 00000000..c483022c --- /dev/null +++ b/apps/cli/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true \ No newline at end of file diff --git a/apps/cli/.oxfmtrc.json b/apps/cli/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/apps/cli/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md new file mode 100644 index 00000000..d692a9c4 --- /dev/null +++ b/apps/cli/CHANGELOG.md @@ -0,0 +1,369 @@ +# @pipelab/cli + +## 2.0.0-beta.37 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/constants@1.0.0-beta.33 + - @pipelab/core-node@1.0.0-beta.37 + - @pipelab/shared@1.0.0-beta.32 + +## 2.0.0-beta.36 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/constants@1.0.0-beta.32 + - @pipelab/core-node@1.0.0-beta.36 + - @pipelab/shared@1.0.0-beta.31 + +## 2.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.31 + - @pipelab/core-node@1.0.0-beta.35 + - @pipelab/shared@1.0.0-beta.30 + +## 2.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.30 + - @pipelab/core-node@1.0.0-beta.34 + - @pipelab/shared@1.0.0-beta.29 + +## 2.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.29 + - @pipelab/core-node@1.0.0-beta.33 + - @pipelab/shared@1.0.0-beta.28 + +## 2.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.28 + - @pipelab/core-node@1.0.0-beta.32 + - @pipelab/shared@1.0.0-beta.27 + +## 2.0.0-beta.31 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.27 + - @pipelab/core-node@1.0.0-beta.31 + - @pipelab/shared@1.0.0-beta.26 + +## 2.0.0-beta.30 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.26 + - @pipelab/core-node@1.0.0-beta.30 + - @pipelab/shared@1.0.0-beta.25 + +## 2.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.25 + - @pipelab/core-node@1.0.0-beta.29 + - @pipelab/shared@1.0.0-beta.24 + +## 2.0.0-beta.28 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.24 + - @pipelab/core-node@1.0.0-beta.28 + - @pipelab/shared@1.0.0-beta.23 + +## 2.0.0-beta.27 + +### Patch Changes + +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.27 + +## 2.0.0-beta.26 + +### Patch Changes + +- Updated dependencies + - @pipelab/shared@1.0.0-beta.22 + - @pipelab/core-node@1.0.0-beta.26 + +## 2.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.23 + - @pipelab/core-node@1.0.0-beta.25 + - @pipelab/shared@1.0.0-beta.21 + +## 2.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.22 + - @pipelab/core-node@1.0.0-beta.24 + - @pipelab/shared@1.0.0-beta.20 + +## 2.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.21 + - @pipelab/core-node@1.0.0-beta.23 + - @pipelab/shared@1.0.0-beta.19 + +## 2.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.20 + - @pipelab/core-node@1.0.0-beta.22 + - @pipelab/shared@1.0.0-beta.18 + +## 2.0.0-beta.21 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.19 + - @pipelab/core-node@1.0.0-beta.21 + - @pipelab/shared@1.0.0-beta.17 + +## 2.0.0-beta.20 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/constants@1.0.0-beta.18 + - @pipelab/core-node@1.0.0-beta.20 + - @pipelab/shared@1.0.0-beta.16 + +## 2.0.0-beta.19 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.17 + - @pipelab/core-node@1.0.0-beta.19 + - @pipelab/shared@1.0.0-beta.15 + +## 2.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.16 + - @pipelab/core-node@1.0.0-beta.18 + - @pipelab/shared@1.0.0-beta.14 + +## 2.0.0-beta.17 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.15 + - @pipelab/core-node@1.0.0-beta.17 + - @pipelab/shared@1.0.0-beta.13 + +## 2.0.0-beta.16 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/constants@1.0.0-beta.14 + - @pipelab/core-node@1.0.0-beta.16 + - @pipelab/shared@1.0.0-beta.12 + +## 2.0.0-beta.15 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.13 + - @pipelab/core-node@1.0.0-beta.15 + - @pipelab/shared@1.0.0-beta.11 + +## 2.0.0-beta.14 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/constants@1.0.0-beta.12 + - @pipelab/core-node@1.0.0-beta.14 + - @pipelab/shared@1.0.0-beta.10 + +## 2.0.0-beta.13 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/constants@1.0.0-beta.11 + - @pipelab/core-node@1.0.0-beta.13 + - @pipelab/shared@1.0.0-beta.9 + +## 2.0.0-beta.12 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/constants@1.0.0-beta.10 + - @pipelab/core-node@1.0.0-beta.12 + - @pipelab/shared@1.0.0-beta.8 + +## 2.0.0-beta.11 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.9 + - @pipelab/core-node@1.0.0-beta.11 + - @pipelab/shared@1.0.0-beta.7 + +## 2.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/constants@1.0.0-beta.8 + - @pipelab/core-node@1.0.0-beta.10 + - @pipelab/shared@1.0.0-beta.6 + +## 2.0.0-beta.9 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.7 + - @pipelab/core-node@1.0.0-beta.9 + +## 2.0.0-beta.8 + +### Patch Changes + +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.8 + +## 2.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.6 + - @pipelab/core-node@1.0.0-beta.7 + - @pipelab/shared@1.0.0-beta.5 + +## 2.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/constants@1.0.0-beta.5 + - @pipelab/core-node@1.0.0-beta.6 + - @pipelab/shared@1.0.0-beta.4 + +## 2.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.4 + - @pipelab/core-node@1.0.0-beta.5 + - @pipelab/shared@1.0.0-beta.3 + +## 2.0.0-beta.4 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.3 + - @pipelab/core-node@1.0.0-beta.4 + +## 2.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/constants@1.0.0-beta.2 + - @pipelab/core-node@1.0.0-beta.3 + - @pipelab/shared@1.0.0-beta.2 + +## 2.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/constants@1.0.0-beta.1 + - @pipelab/core-node@1.0.0-beta.2 + - @pipelab/shared@1.0.0-beta.1 + +## 2.0.0-beta.1 + +### Patch Changes + +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.1 + +## 2.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/constants@1.0.0-beta.0 + - @pipelab/core-node@1.0.0-beta.0 + - @pipelab/shared@1.0.0-beta.0 diff --git a/apps/cli/README.md b/apps/cli/README.md new file mode 100644 index 00000000..cdf3922a --- /dev/null +++ b/apps/cli/README.md @@ -0,0 +1,23 @@ +# @pipelab/cli (The Engine) + +The standalone engine of Pipelab. It provides the core automation logic and serves as the backend for the visual editor. + +## ⚙️ Core Roles + +1. **WebSocket Server**: When started with `serve`, it acts as a backend for the `@pipelab/ui`. It handles graph execution, real-time logging, and state synchronization. +2. **Headless runner**: When started with `run `, it can execute a Pipelab pipeline (.json) directly from the terminal without any UI. +3. **Plugin Host**: Manages the execution context for all Pipelab plugins, including the QuickJS-based virtual environment. + +## 🛠️ Development + +### Setup + +The CLI requires Supabase variables to be "baked in" during the build process. Ensure your root `.env` is populated before building or running `pnpm dev`. + +### Commands + +```bash +pnpm dev # Start the server in development mode +pnpm build # Generate the production CJS bundle +pnpm pkg # Create a standalone executable in the /bin folder +``` diff --git a/apps/cli/package.json b/apps/cli/package.json new file mode 100644 index 00000000..0628c0d1 --- /dev/null +++ b/apps/cli/package.json @@ -0,0 +1,54 @@ +{ + "name": "@pipelab/cli", + "version": "2.0.0-beta.37", + "private": true, + "description": "The command line interface for Pipelab", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "apps/cli" + }, + "bin": { + "pipelab": "./src/index.ts", + "plab": "./src/index.ts" + }, + "type": "module", + "scripts": { + "build": "cross-env NODE_ENV=production tsdown", + "dev": "cross-env NODE_ENV=development tsx watch src/index.ts serve", + "watch": "tsdown --watch", + "start": "tsx src/index.ts", + "test": "vitest run -c tests/e2e/vitest.config.mts", + "format": "oxfmt .", + "lint": "oxlint .", + "typecheck": "tsc --noEmit -p tsconfig.json --composite false" + }, + "dependencies": { + "@clack/prompts": "1.2.0", + "@pipelab/constants": "workspace:*", + "@pipelab/core-node": "workspace:*", + "@pipelab/shared": "workspace:*", + "commander": "^12.1.0", + "dotenv": "17.4.2", + "execa": "9.5.1", + "nanoid": "5.0.8", + "posthog-node": "5.30.6", + "serve-handler": "6.1.7" + }, + "devDependencies": { + "@pipelab/test-utils": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "@types/node": "24.12.2", + "cross-env": "7.0.3", + "tsdown": "0.21.2", + "typescript": "^5.0.0", + "vitest": "3.1.4" + }, + "test": { + "env": { + "NODE_ENV": "development" + } + } +} diff --git a/apps/cli/src/commands/history.ts b/apps/cli/src/commands/history.ts new file mode 100644 index 00000000..0dc73c59 --- /dev/null +++ b/apps/cli/src/commands/history.ts @@ -0,0 +1,43 @@ +import { PipelabContext, BuildHistoryStorage } from "@pipelab/core-node"; +import { getDefaultUserDataPath } from "../paths"; +import { BuildHistoryEntry } from "@pipelab/shared"; + +export async function historyCommand( + pipelineId: string | undefined, + options: { get?: string; userData?: string; limit?: number }, +) { + const userDataPath = options.userData || getDefaultUserDataPath(); + const context = new PipelabContext({ userDataPath }); + const storage = new BuildHistoryStorage(context); + + if (options.get) { + const entry = await storage.get(options.get, pipelineId); + if (entry) { + console.log(JSON.stringify(entry, null, 2)); + } else { + console.error(`Build history entry with ID "${options.get}" not found.`); + process.exit(1); + } + } else if (pipelineId) { + const entries = await storage.getByPipeline(pipelineId); + if (entries.length > 0) { + const limit = options.limit || 10; + const recentEntries = entries.slice(-limit); + + const formatted = recentEntries.map((e: BuildHistoryEntry) => ({ + ID: e.id, + Status: e.status, + "Start Time": new Date(e.startTime).toLocaleString(), + Duration: e.duration ? `${(e.duration / 1000).toFixed(2)}s` : "N/A", + })); + console.table(formatted); + } else { + console.log(`No history found for pipeline "${pipelineId}".`); + } + } else { + console.error( + "Please provide a pipeline ID to list its history, or use the --get option with a build ID.", + ); + process.exit(1); + } +} diff --git a/apps/cli/src/commands/maintenance.ts b/apps/cli/src/commands/maintenance.ts new file mode 100644 index 00000000..87fd0f6b --- /dev/null +++ b/apps/cli/src/commands/maintenance.ts @@ -0,0 +1,55 @@ +import { PipelabContext, BuildHistoryStorage } from "@pipelab/core-node"; +import { getDefaultUserDataPath } from "../paths"; +import { join } from "node:path"; + +function formatBytes(bytes: number, decimals = 2) { + if (bytes === 0) return "0 Bytes"; + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; +} + +export async function usageCommand(options: { userData?: string }) { + const userDataPath = options.userData || getDefaultUserDataPath(); + const context = new PipelabContext({ userDataPath }); + const storage = new BuildHistoryStorage(context); + + const info = await storage.getStorageInfo(); + + console.log("Build History Storage Usage:"); + console.table({ + "Total Entries": info.totalEntries, + "Pipelines with History": info.numberOfPipelines, + "Total Size": formatBytes(info.totalSize), + "Oldest Entry": info.oldestEntry ? new Date(info.oldestEntry).toLocaleString() : "N/A", + "Newest Entry": info.newestEntry ? new Date(info.newestEntry).toLocaleString() : "N/A", + "User Data Path": info.userDataPath, + "Cache Path": context.getBuildHistoryPath(), + }); +} + +export async function purgeCommand( + pipelineId: string | undefined, + options: { force?: boolean; userData?: string }, +) { + if (!options.force) { + console.error( + "This is a destructive operation. Please use the --force flag to confirm you want to purge the history.", + ); + process.exit(1); + } + + const userDataPath = options.userData || getDefaultUserDataPath(); + const context = new PipelabContext({ userDataPath }); + const storage = new BuildHistoryStorage(context); + + if (pipelineId) { + await storage.clearByPipeline(pipelineId); + console.log(`Successfully purged history for pipeline: ${pipelineId}`); + } else { + await storage.clear(); + console.log("Successfully purged all build history."); + } +} diff --git a/apps/cli/src/commands/pipelines.ts b/apps/cli/src/commands/pipelines.ts new file mode 100644 index 00000000..eb9d7792 --- /dev/null +++ b/apps/cli/src/commands/pipelines.ts @@ -0,0 +1,261 @@ +import { + PipelabContext, + setupProjectsConfigFile, + deletePipelineConfigFileByName, +} from "@pipelab/core-node"; +import { FileRepo, SaveLocation } from "@pipelab/shared"; +import { readFile, unlink, readdir } from "node:fs/promises"; +import { getDefaultUserDataPath } from "../paths"; +import path from "node:path"; + +export async function listPipelinesCommand(options: { userData?: string }) { + const userDataPath = options.userData || getDefaultUserDataPath(); + const context = new PipelabContext({ userDataPath }); + + try { + const projectsConfig = await setupProjectsConfigFile(context); + const repo = await projectsConfig.getConfig(); + + if (!repo.pipelines || repo.pipelines.length === 0) { + console.log("No pipelines found."); + return; + } + + console.log(`Found ${repo.pipelines.length} pipelines:\n`); + + for (const pipeline of repo.pipelines) { + let content: any; + try { + if (pipeline.type === "internal") { + const path = context.getConfigPath(`${pipeline.configName}.json`); + content = JSON.parse(await readFile(path, "utf-8")); + } else if (pipeline.type === "external") { + content = JSON.parse(await readFile(pipeline.path, "utf-8")); + } + } catch (e: any) { + console.log( + `--------------------------------------------------------------------------------`, + ); + console.log(`Error: Could not read pipeline ${pipeline.id}`); + if (pipeline.type === "external") { + console.log(` Expected Path: ${pipeline.path}`); + } + console.log(` Reason: ${e.message}`); + continue; + } + + const plugins = new Set(); + if (content?.canvas?.blocks) { + for (const block of content.canvas.blocks) { + if (block.origin?.pluginId) { + plugins.add(block.origin.pluginId); + } + } + } + + const name = content?.name || "Unnamed Pipeline"; + + console.log( + `--------------------------------------------------------------------------------`, + ); + console.log(`${name} (${pipeline.id})`); + if (pipeline.type === "external") { + console.log(` Path: ${pipeline.path}`); + } + console.log(` Plugins: ${Array.from(plugins).join(", ") || "None"}`); + } + } catch (error: any) { + console.error("Failed to list pipelines:", error.message); + } +} + +export async function showPipelineCommand( + idOrName: string, + options: { detailed?: boolean; userData?: string }, +) { + const userDataPath = options.userData || getDefaultUserDataPath(); + const context = new PipelabContext({ userDataPath }); + + try { + const projectsConfig = await setupProjectsConfigFile(context); + const repo = await projectsConfig.getConfig(); + + const pipeline = repo.pipelines?.find( + (p) => + p.id === idOrName || + (p.type === "internal" && p.configName === idOrName) || + (p.type === "external" && p.path.includes(idOrName)), + ); + + if (!pipeline) { + console.error(`Pipeline "${idOrName}" not found.`); + process.exit(1); + } + + let content: any; + try { + if (pipeline.type === "internal") { + const path = context.getConfigPath(`${pipeline.configName}.json`); + content = JSON.parse(await readFile(path, "utf-8")); + } else if (pipeline.type === "external") { + content = JSON.parse(await readFile(pipeline.path, "utf-8")); + } + } catch (e: any) { + console.error(`Error: Could not read pipeline file: ${e.message}`); + process.exit(1); + } + + console.log(`\nPipeline: ${content?.name || "Unnamed"}`); + console.log(`ID: ${pipeline.id}`); + console.log(`Type: ${pipeline.type}`); + if (pipeline.type === "external") { + console.log(`Path: ${pipeline.path}`); + } else if (pipeline.type === "internal") { + console.log(`Config: ${pipeline.configName}.json`); + } + + const plugins = new Set(); + const blockCount = content?.canvas?.blocks?.length || 0; + const triggerCount = content?.canvas?.triggers?.length || 0; + + if (content?.canvas?.blocks) { + for (const block of content.canvas.blocks) { + if (block.origin?.pluginId) { + plugins.add(block.origin.pluginId); + } + } + } + + console.log(`Plugins: ${Array.from(plugins).join(", ") || "None"}`); + console.log(`Blocks: ${blockCount}`); + console.log(`Triggers: ${triggerCount}`); + + if (options.detailed) { + console.log(`\n--- Detailed Information ---`); + console.log(`Version: ${content?.version || "Unknown"}`); + console.log(`Description: ${content?.description || "No description"}`); + + if (content?.variables && content.variables.length > 0) { + console.log(`\nVariables:`); + for (const v of content.variables) { + console.log(` - ${v.name} (${v.type}): ${v.value}`); + } + } else { + console.log(`\nVariables: None`); + } + + if (content?.canvas?.blocks && content.canvas.blocks.length > 0) { + console.log(`\nBlock Breakdown:`); + const counts: Record = {}; + for (const block of content.canvas.blocks) { + const pid = block.origin?.pluginId || "core"; + counts[pid] = (counts[pid] || 0) + 1; + } + for (const [pid, count] of Object.entries(counts)) { + console.log(` - ${pid}: ${count} blocks`); + } + } + + const triggers = content?.canvas?.triggers || []; + const blocks = content?.canvas?.blocks || []; + + const humanize = (origin: any, customName?: string) => { + if (customName) return customName; + if (!origin) return "Unknown"; + const parts = origin.nodeId + .split(":") + .filter((p: string) => !(p.startsWith("v") && !isNaN(parseInt(p.substring(1))))); + + const nodeName = parts + .map((p: string) => p.replace(/-/g, " ").replace(/_/g, " ")) + .map((p: string) => p.replace(/\b\w/g, (c: string) => c.toUpperCase())) + .join(": "); + + return `${nodeName} [${origin.pluginId}]`; + }; + + console.log(`\nWorkflow:`); + if (triggers.length > 0) { + for (const t of triggers) { + console.log(` (Trigger) ${humanize(t.origin, t.name)}`); + } + } else { + console.log(` (No triggers defined)`); + } + + if (blocks.length > 0) { + for (let i = 0; i < blocks.length; i++) { + const b = blocks[i]; + const status = b.disabled ? " [DISABLED]" : ""; + console.log(` │`); + console.log(` ▼`); + console.log(` (Action) ${humanize(b.origin, b.name)}${status}`); + if (b.description) { + console.log(` ${b.description}`); + } + } + } else { + console.log(` │`); + console.log(` ▼`); + console.log(` (No actions defined)`); + } + } + } catch (error: any) { + console.error("Failed to show pipeline:", error.message); + process.exit(1); + } +} + +export async function deletePipelineCommand( + id: string, + options: { force?: boolean; userData?: string }, +) { + if (!options.force) { + console.error( + "This is a destructive operation. Please use the --force flag to confirm you want to delete the pipeline.", + ); + process.exit(1); + } + + const userDataPath = options.userData || getDefaultUserDataPath(); + const context = new PipelabContext({ userDataPath }); + + try { + const projectsConfig = await setupProjectsConfigFile(context); + const repo = await projectsConfig.getConfig(); + + if (!repo.pipelines) { + console.error(`Pipeline "${id}" not found.`); + process.exit(1); + } + + const index = repo.pipelines.findIndex( + (p) => p.id === id || (p.type === "internal" && p.configName === id), + ); + + if (index === -1) { + console.error(`Pipeline "${id}" not found.`); + process.exit(1); + } + + const pipeline = repo.pipelines[index] as SaveLocation; + + // 1. Delete internal file if applicable + if (pipeline.type === "internal") { + try { + await deletePipelineConfigFileByName(pipeline.configName, context); + console.log(`Deleted pipeline file: ${pipeline.configName}.json`); + } catch (e: any) { + console.warn(`Warning: Could not delete pipeline file: ${e.message}`); + } + } + + // 2. Remove from projects.json + repo.pipelines.splice(index, 1); + await projectsConfig.setConfig(repo); + console.log(`Successfully removed pipeline "${id}" from Pipelab.`); + } catch (error: any) { + console.error("Failed to delete pipeline:", error.message); + process.exit(1); + } +} diff --git a/apps/cli/src/commands/setup.ts b/apps/cli/src/commands/setup.ts new file mode 100644 index 00000000..308c3c0f --- /dev/null +++ b/apps/cli/src/commands/setup.ts @@ -0,0 +1,121 @@ +import * as p from "@clack/prompts"; +import { setTimeout } from "node:timers/promises"; +import { PipelabContext } from "@pipelab/core-node"; +import { setupSettingsConfigFile } from "@pipelab/core-node"; +import { AppConfig } from "@pipelab/shared"; +import { getDefaultUserDataPath } from "../paths"; + +export async function setupCommand(options: { userData?: string }) { + p.intro(`Welcome to Pipelab CLI Setup Wizard`); + + const userDataPath = options.userData || getDefaultUserDataPath(); + const context = new PipelabContext({ userDataPath }); + + // 1. Authentication + const authType = await p.select({ + message: "How would you like to authenticate?", + options: [ + { value: "token", label: "Access Token (Recommended)" }, + { value: "credentials", label: "Email & Password" }, + { value: "skip", label: "Skip for now" }, + ], + }); + + if (p.isCancel(authType)) { + p.cancel("Setup cancelled."); + process.exit(0); + } + + if (authType === "token") { + const token = await p.password({ + message: "Enter your Pipelab Access Token", + validate: (value) => { + if (!value) return "Token is required"; + if (value.length < 10) return "Token is too short"; + }, + }); + if (p.isCancel(token)) return; + + const s = p.spinner(); + s.start("Authenticating with Pipelab..."); + await setTimeout(1500); // Fake delay + s.stop("Authenticated successfully!"); + } + + // 2. Configuration + const settings = await setupSettingsConfigFile(context); + const config = await settings.getConfig(); + + const configChanges = await p.group({ + theme: () => + p.select({ + message: "Select your preferred theme:", + initialValue: config.theme, + options: [ + { value: "dark", label: "Dark" }, + { value: "light", label: "Light" }, + ], + }), + locale: () => + p.select({ + message: "Select your language:", + initialValue: config.locale, + options: [ + { value: "en-US", label: "English" }, + { value: "fr-FR", label: "French" }, + { value: "pt-BR", label: "Portuguese" }, + ], + }), + }); + + if (p.isCancel(configChanges)) { + p.cancel("Setup aborted."); + process.exit(0); + } + + const theme = configChanges.theme === "light" ? "light" : "dark"; + const localeValue = configChanges.locale; + const locale = isLocale(localeValue) ? localeValue : "en-US"; + + // Save config (Fake save for now to avoid side effects in this demo if needed, but let's do it real) + await settings.setConfig({ + ...config, + theme, + locale, + }); + + // 3. Integrations + const integrations = await p.multiselect({ + message: "Which integrations would you like to enable?", + options: [ + { value: "path", label: "Add 'pipelab' to your PATH", hint: "recommended" }, + { value: "completion", label: "Enable shell autocompletion" }, + { value: "telemetry", label: "Anonymous telemetry", hint: "helps us improve" }, + ], + }); + + if (p.isCancel(integrations)) return; + + if (integrations.length > 0) { + const s = p.spinner(); + s.start("Setting up integrations..."); + await setTimeout(2000); // Fake delay + s.stop("Integrations configured!"); + } + + p.note( + `You're all set! You can now use Pipelab CLI to manage your automation.\n\nType 'pipelab --help' to get started.`, + "Setup Complete", + ); + + p.outro("Happy automating! 🚀"); +} + +function isLocale( + value: unknown, +): value is "en-US" | "fr-FR" | "pt-BR" | "zh-CN" | "es-ES" | "de-DE" { + return ( + typeof value === "string" && + ["en-US", "fr-FR", "pt-BR", "zh-CN", "es-ES", "de-DE"].includes(value) + ); +} diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts new file mode 100644 index 00000000..fd915adf --- /dev/null +++ b/apps/cli/src/index.ts @@ -0,0 +1,235 @@ +#!/usr/bin/env node +import { isDev, runPipelineCommand, serveCommand } from "@pipelab/core-node"; +import { historyCommand } from "./commands/history"; +import { usageCommand, purgeCommand } from "./commands/maintenance"; +import { + listPipelinesCommand, + deletePipelineCommand, + showPipelineCommand, +} from "./commands/pipelines"; +import { setupCommand } from "./commands/setup"; +import { readFileSync, existsSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { isSupabaseAvailable } from "@pipelab/shared"; +import { config } from "dotenv"; +import { PostHog } from "posthog-node"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// Only load .env in development as values are bundled in production by tsdown +if (isDev) { + const envPath = join(__dirname, "../../../.env"); + if (existsSync(envPath)) { + config({ path: envPath }); + } +} + +const isProduction = !isDev && process.env.TEST !== "true"; + +let posthog: PostHog | undefined; +if (isProduction && process.env.POSTHOG_API_KEY) { + posthog = new PostHog(process.env.POSTHOG_API_KEY, { + host: "https://eu.i.posthog.com", + }); +} +import { Command } from "commander"; +import { getDefaultUserDataPath } from "./paths"; + +// Resolve version from injected env or package.json with fallbacks for production +let version = process.env.CLI_VERSION || "0.0.0"; +if (isDev) { + version = "workspace"; +} else if (version === "0.0.0") { + try { + const packageJsonPath = existsSync(join(__dirname, "package.json")) + ? join(__dirname, "package.json") + : join(__dirname, "..", "package.json"); + + if (existsSync(packageJsonPath)) { + const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")); + version = packageJson.version; + } + } catch (e) { + console.warn("[CLI] Could not resolve version from package.json, using fallback."); + } +} + +const program = new Command(); + +program.name("pipelab").description("The command line interface for Pipelab").version(version); + +if (!isSupabaseAvailable()) { + console.warn( + "\x1b[33m%s\x1b[0m", + "Warning: Authentication is currently disabled (Cloud services not configured).", + ); +} + +program + .command("serve") + .description("Start the standalone WebSocket server") + .option("-p, --port ", "Port to listen on", "33753") + .option("--user-data ", "Custom user data path") + .action(async (options) => { + try { + options.userData = options.userData || getDefaultUserDataPath(); + await serveCommand(options, version, __dirname); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +program + .command("run ") + .description("Run a pipeline from a JSON file") + .option("--user-data ", "Custom user data path") + .option("--variables ", "JSON string of variables to override") + .option("-o, --output ", "Path to write the result file") + .option("--cloud", "Run the pipeline in a cloud environment") + .action(async (file, options) => { + try { + options.userData = options.userData || getDefaultUserDataPath(); + await runPipelineCommand(file, options, version); + process.exit(0); + } catch (e) { + console.error("Pipeline execution failed:", e); + process.exit(1); + } + }); + +program + .command("history [pipeline-id]") + .description("View build history for a pipeline") + .option("--get ", "Get a specific build entry by ID") + .option("--user-data ", "Custom user data path") + .option("--limit ", "Limit the number of history entries to show", "10") + .action(async (pipelineId, options) => { + try { + await historyCommand(pipelineId, options); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +program + .command("usage") + .description("Show build history storage usage") + .option("--user-data ", "Custom user data path") + .action(async (options) => { + try { + await usageCommand(options); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +program + .command("purge [pipeline-id]") + .description("Purge build history") + .option("--user-data ", "Custom user data path") + .option("-f, --force", "Force the destructive operation") + .action(async (pipelineId, options) => { + try { + await purgeCommand(pipelineId, options); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +program + .command("setup") + .description("Run the interactive setup wizard") + .option("--user-data ", "Custom user data path") + .action(async (options) => { + try { + await setupCommand(options); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +const pipelines = program.command("pipelines").alias("pipeline").description("Manage pipelines"); + +pipelines + .command("ls") + .alias("list") + .description("List all pipelines") + .option("--user-data ", "Custom user data path") + .action(async (options) => { + try { + await listPipelinesCommand(options); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +pipelines + .command("show ") + .alias("shw") + .description("Display basic information about a pipeline") + .option("--user-data ", "Custom user data path") + .action(async (idOrName, options) => { + try { + await showPipelineCommand(idOrName, { ...options, detailed: false }); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +pipelines + .command("detail ") + .alias("details") + .description("Display detailed information about a pipeline") + .option("--user-data ", "Custom user data path") + .action(async (idOrName, options) => { + try { + await showPipelineCommand(idOrName, { ...options, detailed: true }); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +pipelines + .command("rm ") + .alias("remove") + .alias("delete") + .description("Delete a pipeline") + .option("--user-data ", "Custom user data path") + .option("-f, --force", "Force the destructive operation") + .action(async (id, options) => { + try { + await deletePipelineCommand(id, options); + } catch (e) { + console.error(e); + process.exit(1); + } + }); + +program.hook("postAction", (thisCommand) => { + if (posthog) { + posthog.capture({ + distinctId: "cli-user", + event: "command_executed", + properties: { + command: thisCommand.name(), + args: thisCommand.args, + }, + }); + } +}); + +program.parse(process.argv); + +if (!process.argv.slice(2).length) { + program.outputHelp(); +} diff --git a/apps/cli/src/paths.ts b/apps/cli/src/paths.ts new file mode 100644 index 00000000..a28a9edd --- /dev/null +++ b/apps/cli/src/paths.ts @@ -0,0 +1,9 @@ +import { getDefaultUserDataPath as getCorePath } from "@pipelab/core-node"; +import pkg from "../package.json" with { type: "json" }; + +const isDev = process.env.NODE_ENV === "development"; + +export const getDefaultUserDataPath = () => { + const mode = isDev ? "dev" : pkg.version.includes("beta") ? "beta" : "prod"; + return getCorePath(mode); +}; diff --git a/apps/cli/tests/e2e/tests/history.spec.ts b/apps/cli/tests/e2e/tests/history.spec.ts new file mode 100644 index 00000000..5f6a6bbe --- /dev/null +++ b/apps/cli/tests/e2e/tests/history.spec.ts @@ -0,0 +1,62 @@ +import { expect, test, describe, afterEach } from "vitest"; +import { writeFile, access, readFile } from "node:fs/promises"; +import { join } from "node:path"; +import { createSandbox, runCLI } from "@pipelab/test-utils"; + +describe("End-to-End: Build History", () => { + let sandbox: Awaited>; + + afterEach(async () => { + if (sandbox) { + await sandbox.remove(); + } + }); + + test( + "should generate and save a build history when PIPELAB_DISABLE_HISTORY is false", + async () => { + sandbox = await createSandbox("history-e2e"); + + const pipelineId = "test-history-pipeline"; + const pipeline = { + graph: [], // Empty graph will execute successfully + projectPath: sandbox.path, + projectName: "History E2E Test", + pipelineId, + }; + + const pipelineFile = join(sandbox.path, "pipeline.json"); + await writeFile(pipelineFile, JSON.stringify(pipeline, null, 2)); + + // Run the CLI using the helper but explicitly set disable history to false + await runCLI(["run", pipelineFile, "--user-data", sandbox.paths.userData], { + env: { + PIPELAB_DISABLE_HISTORY: "false", + }, + }); + + // The build history should be generated in the user-data folder + // Based on BuildHistoryStorage.getPipelinePath, the filename should be config/pipelines/.history.json + const historyFile = join( + sandbox.paths.userData, + "config", + "pipelines", + `${pipelineId}.history.json`, + ); + + // Verification: file must exist + await expect(access(historyFile)).resolves.not.toThrow(); + + const historyContent = await readFile(historyFile, "utf-8"); + const history = JSON.parse(historyContent); + + expect(Array.isArray(history)).toBe(true); + expect(history.length).toBeGreaterThan(0); + + const lastEntry = history[history.length - 1]; + expect(lastEntry.pipelineId).toBe(pipelineId); + expect(lastEntry.status).toBe("completed"); + }, + 30 * 60 * 1000, + ); +}); diff --git a/apps/cli/tests/e2e/tests/integration.spec.ts b/apps/cli/tests/e2e/tests/integration.spec.ts new file mode 100644 index 00000000..9e68cf51 --- /dev/null +++ b/apps/cli/tests/e2e/tests/integration.spec.ts @@ -0,0 +1,73 @@ +import { expect, test, describe, afterEach } from "vitest"; +import { writeFile, access, readFile, mkdir } from "node:fs/promises"; +import { join } from "node:path"; +import { createSandbox, runCLI } from "@pipelab/test-utils"; + +describe("End-to-End: Multi-Plugin Integration Test", () => { + let sandbox: Awaited>; + + afterEach(async () => { + if (sandbox) { + await sandbox.remove(); + } + }); + + test( + "should run a pipeline with filesystem nodes", + async () => { + sandbox = await createSandbox("integration-e2e"); + const { paths } = sandbox; + + const projectSourcePath = join(sandbox.path, "my-app-source"); + const projectStagingPath = join(sandbox.path, "my-app-staging"); + await mkdir(projectSourcePath, { recursive: true }); + + // Create initial source files + await writeFile( + join(projectSourcePath, "package.json"), + JSON.stringify({ name: "my-app", version: "1.0.0", main: "index.js" }), + ); + await writeFile(join(projectSourcePath, "index.js"), "console.log('hello integration test')"); + + const pipeline = { + graph: [ + { + uid: "copy-to-staging", + name: "Copy to Staging", + type: "action", + origin: { pluginId: "@pipelab/plugin-filesystem", nodeId: "fs:copy" }, + params: { + from: { value: JSON.stringify(projectSourcePath) }, + to: { value: JSON.stringify(projectStagingPath) }, + recursive: { value: JSON.stringify(true) }, + overwrite: { value: JSON.stringify(true) }, + cleanup: { value: JSON.stringify(false) }, + }, + }, + ], + projectPath: sandbox.path, + projectName: "Integration E2E Test", + }; + + const pipelineFile = join(sandbox.path, "pipeline.json"); + const resultFile = join(sandbox.path, "result.json"); + await writeFile(pipelineFile, JSON.stringify(pipeline, null, 2)); + + // Run the CLI using the helper + await runCLI(["run", pipelineFile, "--output", resultFile]); + + const resultJson = JSON.parse(await readFile(resultFile, "utf-8")); + + // Verification + expect(resultJson.steps["copy-to-staging"]).toBeDefined(); + + const outputs = resultJson.steps["copy-to-staging"].outputs; + expect(outputs).toBeDefined(); + expect(outputs.output).toEqual(projectStagingPath); + + // Verify output exists + await expect(access(outputs.output as string)).resolves.not.toThrow(); + }, + 30 * 60 * 1000, + ); +}); diff --git a/apps/cli/tests/e2e/vitest.config.mts b/apps/cli/tests/e2e/vitest.config.mts new file mode 100644 index 00000000..148278ad --- /dev/null +++ b/apps/cli/tests/e2e/vitest.config.mts @@ -0,0 +1,20 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + fileParallelism: false, + testTimeout: 1800000, + hookTimeout: 60000, + maxWorkers: 1, + minWorkers: 1, + poolOptions: { + forks: { + singleFork: true, + }, + }, + include: ["**/*.spec.ts"], + root: "tests/e2e", + environment: "node", + env: { NODE_ENV: "development", PIPELAB_DISABLE_HISTORY: "true" }, + }, +}); diff --git a/apps/cli/tsconfig.json b/apps/cli/tsconfig.json new file mode 100644 index 00000000..64dc9057 --- /dev/null +++ b/apps/cli/tsconfig.json @@ -0,0 +1,29 @@ +{ + "extends": "../../packages/tsconfig/node.json", + "compilerOptions": { + "composite": false, + "moduleResolution": "bundler", + "outDir": "dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "baseUrl": ".", + "paths": { + "@pipelab/*": ["../../packages/shared/src/libs/*"], + "@core-node/*": ["../../packages/core-node/src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"], + "references": [ + { + "path": "../../packages/constants" + }, + { + "path": "../../packages/shared" + }, + { + "path": "../../packages/core-node" + } + ] +} diff --git a/apps/cli/tsdown.config.ts b/apps/cli/tsdown.config.ts new file mode 100644 index 00000000..f5e449d0 --- /dev/null +++ b/apps/cli/tsdown.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from "tsdown"; +import { resolve } from "path"; +import { existsSync, readFileSync } from "node:fs"; +import { config } from "dotenv"; + +const envFile = resolve(import.meta.dirname, "../../.env"); + +config({ path: envFile }); + +const pkgPath = resolve(import.meta.dirname, "./package.json"); +const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")); + +export default defineConfig({ + entry: ["src/index.ts"], + shims: true, + env: { + NODE_ENV: process.env.NODE_ENV || "production", + SUPABASE_URL: process.env.SUPABASE_URL || "", + SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY || "", + POSTHOG_API_KEY: process.env.POSTHOG_API_KEY || "", + CLI_VERSION: pkg.version, + }, + envFile: existsSync(envFile) ? envFile : undefined, + envPrefix: ["SUPABASE_", "POSTHOG_", "NODE_ENV", "CLI_VERSION"], + deps: { + alwaysBundle: [/.*/], + }, +}); diff --git a/.editorconfig b/apps/desktop/.editorconfig similarity index 100% rename from .editorconfig rename to apps/desktop/.editorconfig diff --git a/.hintrc b/apps/desktop/.hintrc similarity index 100% rename from .hintrc rename to apps/desktop/.hintrc diff --git a/.mise.toml b/apps/desktop/.mise.toml similarity index 77% rename from .mise.toml rename to apps/desktop/.mise.toml index 394be3e8..8754dd96 100644 --- a/.mise.toml +++ b/apps/desktop/.mise.toml @@ -1,5 +1,4 @@ [tools] -node = "22" [env] _.file = '.env' @@ -16,5 +15,5 @@ run = "pnpm package" depends = ["install"] [tasks.test-e2e-local] -run = "pnpm test:e2e:raw" -depends = ["package"] \ No newline at end of file +run = "pnpm test:e2e" +depends = ["package"] diff --git a/apps/desktop/.npmrc b/apps/desktop/.npmrc new file mode 100644 index 00000000..d67f3748 --- /dev/null +++ b/apps/desktop/.npmrc @@ -0,0 +1 @@ +node-linker=hoisted diff --git a/apps/desktop/.oxfmtrc.json b/apps/desktop/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/apps/desktop/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/apps/desktop/CHANGELOG.md b/apps/desktop/CHANGELOG.md new file mode 100644 index 00000000..8cc9fc2a --- /dev/null +++ b/apps/desktop/CHANGELOG.md @@ -0,0 +1,199 @@ +# @pipelab/app + +## 2.0.0-beta.32 + +### Patch Changes + +- - + +## 2.0.0-beta.31 + +### Patch Changes + +- improve dark theme and improve build history + +## 2.0.0-beta.30 + +### Patch Changes + +- sd + +## 2.0.0-beta.29 + +### Patch Changes + +- sd + +## 2.0.0-beta.28 + +### Patch Changes + +- sd + +## 2.0.0-beta.27 + +### Patch Changes + +- sd + +## 2.0.0-beta.26 + +### Patch Changes + +- sd + +## 2.0.0-beta.25 + +### Patch Changes + +- sdsd + +## 2.0.0-beta.24 + +### Patch Changes + +- sd + +## 2.0.0-beta.23 + +### Patch Changes + +- sd + +## 2.0.0-beta.22 + +### Patch Changes + +- sd + +## 2.0.0-beta.21 + +### Patch Changes + +- sd + +## 2.0.0-beta.20 + +### Patch Changes + +- sd + +## 2.0.0-beta.19 + +### Patch Changes + +- sd + +## 2.0.0-beta.18 + +### Patch Changes + +- sd + +## 2.0.0-beta.17 + +### Patch Changes + +- df + +## 2.0.0-beta.16 + +### Patch Changes + +- sdsd + +## 2.0.0-beta.15 + +### Patch Changes + +- sd + +## 2.0.0-beta.14 + +### Patch Changes + +- sd + +## 2.0.0-beta.13 + +### Patch Changes + +- qs + +## 2.0.0-beta.12 + +### Patch Changes + +- sd + +## 2.0.0-beta.11 + +### Patch Changes + +- s + +## 2.0.0-beta.10 + +### Patch Changes + +- fg + +## 2.0.0-beta.9 + +### Patch Changes + +- changes + +## 2.0.0-beta.8 + +### Patch Changes + +- bump + +## 2.0.0-beta.7 + +### Patch Changes + +- fixes + +## 2.0.0-beta.6 + +### Patch Changes + +- bump + +## 2.0.0-beta.5 + +### Patch Changes + +- beta tag + +## 2.0.0-beta.4 + +### Patch Changes + +- bump + +## 2.0.0-beta.3 + +### Patch Changes + +- update + +## 2.0.0-beta.2 + +### Patch Changes + +- general improvements + +## 2.0.0-beta.1 + +### Patch Changes + +- improve update checks + +## 2.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/FAQ.md b/apps/desktop/FAQ.md similarity index 100% rename from FAQ.md rename to apps/desktop/FAQ.md diff --git a/apps/desktop/README.md b/apps/desktop/README.md new file mode 100644 index 00000000..be87c3fb --- /dev/null +++ b/apps/desktop/README.md @@ -0,0 +1,30 @@ +# @pipelab/app (Desktop) + +The Desktop version of Pipelab, built with Electron. + +## 🔄 Lifecycle & Orchestration + +The Desktop application serves as the native shell for the Pipelab ecosystem. Its responsibilities include: + +1. **Process Management**: In production, the main process is responsible for spawning and managing the `@pipelab/cli` server as a "sidecar" process. +2. **Native Bridge**: Provides IPC handlers for native OS features (file system dialogs, system notifications, auto-updates) that are not available to the web renderer. +3. **UI Container**: Loads and displays the `@pipelab/ui` interface. + +### Communication Flow + +- **Main to UI**: Via standard Electron IPC. +- **UI to CLI**: Via WebSockets (even when running inside the desktop app). + +## 🛠️ Development + +### Setup + +Ensure you have the root-level `.env` file configured. + +### Commands + +```bash +pnpm dev # Starts the Electron app in development mode +pnpm package # Packages the application for the current platform (production) +pnpm make # Creates installers (dmg, exe, deb, zip) +``` diff --git a/assets/build/entitlements.mac.plist b/apps/desktop/assets/build/entitlements.mac.plist similarity index 100% rename from assets/build/entitlements.mac.plist rename to apps/desktop/assets/build/entitlements.mac.plist diff --git a/assets/build/icon.icns b/apps/desktop/assets/build/icon.icns similarity index 100% rename from assets/build/icon.icns rename to apps/desktop/assets/build/icon.icns diff --git a/assets/build/icon.ico b/apps/desktop/assets/build/icon.ico similarity index 100% rename from assets/build/icon.ico rename to apps/desktop/assets/build/icon.ico diff --git a/assets/build/icon.png b/apps/desktop/assets/build/icon.png similarity index 100% rename from assets/build/icon.png rename to apps/desktop/assets/build/icon.png diff --git a/apps/desktop/assets/build/notarize.cjs b/apps/desktop/assets/build/notarize.cjs new file mode 100644 index 00000000..0e96c5b9 --- /dev/null +++ b/apps/desktop/assets/build/notarize.cjs @@ -0,0 +1,36 @@ +const { notarize } = require("@electron/notarize"); + +module.exports = async (context) => { + if (process.platform !== "darwin") return; + + console.log("aftersign hook triggered, start to notarize app."); + + if (!process.env.CI) { + console.log(`skipping notarizing, not in CI.`); + return; + } + + if (!("APPLE_ID" in process.env && "APPLE_ID_PASS" in process.env)) { + console.warn("skipping notarizing, APPLE_ID and APPLE_ID_PASS env variables must be set."); + return; + } + + const appId = "com.electron.app"; + + const { appOutDir } = context; + + const appName = context.packager.appInfo.productFilename; + + try { + await notarize({ + appBundleId: appId, + appPath: `${appOutDir}/${appName}.app`, + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLEIDPASS, + }); + } catch (error) { + console.error(error); + } + + console.log(`done notarizing ${appId}.`); +}; diff --git a/crowdin.yml b/apps/desktop/crowdin.yml similarity index 100% rename from crowdin.yml rename to apps/desktop/crowdin.yml diff --git a/apps/desktop/forge.config.ts b/apps/desktop/forge.config.ts new file mode 100644 index 00000000..bc9aa026 --- /dev/null +++ b/apps/desktop/forge.config.ts @@ -0,0 +1,132 @@ +import type { ForgeConfig } from "@electron-forge/shared-types"; +import { MakerSquirrel } from "@electron-forge/maker-squirrel"; +import { MakerZIP } from "@electron-forge/maker-zip"; +import { VitePlugin } from "@electron-forge/plugin-vite"; +import { FusesPlugin } from "@electron-forge/plugin-fuses"; +import { MakerDMG } from "@electron-forge/maker-dmg"; +import { FuseV1Options, FuseVersion } from "@electron/fuses"; +import { name } from "@pipelab/constants"; +import fs from "node:fs/promises"; +import path from "path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +console.log(`[Forge Config] Host arch: ${process.arch}`); +console.log(`[Forge Config] Target arch (env.TARGET_ARCH): ${process.env.TARGET_ARCH}`); +console.log(`[Forge Config] npm_config_arch: ${process.env.npm_config_arch}`); + +const getStandardOs = (p: string) => ({ win32: "win", darwin: "macos", linux: "linux" })[p] || p; + +/** + * Renames Forge-generated installers in /out/make. + */ +async function renameInstallers(platform: string, arch: string) { + const pkgPath = path.join(__dirname, "package.json"); + const { version } = JSON.parse(await fs.readFile(pkgPath, "utf-8")); + const os = getStandardOs(platform); + const makeDir = path.join(__dirname, "out/make"); + + const exists = await fs + .access(makeDir) + .then(() => true) + .catch(() => false); + if (!exists) return; + + const files = await fs.readdir(makeDir, { recursive: true }); + + for (const relFile of files) { + const file = path.join(makeDir, relFile); + if ((await fs.stat(file)).isDirectory()) continue; + + const ext = path.extname(file); + const basename = path.basename(file); + if ([".zip", ".dmg", ".exe", ".deb", ".rpm"].includes(ext) && !basename.includes("-v")) { + const newName = `pipelab-desktop-v${version}-${os}-${arch}${ext}`; + await fs.rename(file, path.join(path.dirname(file), newName)); + } + } +} + +import { getAppBundleId, getProductName } from "@pipelab/constants"; +import { version } from "./package.json"; + +const productName = getProductName(version); +const bundleId = getAppBundleId(version); + +const config: ForgeConfig = { + packagerConfig: { + // @ts-expect-error - Force architecture as Forge CLI sometimes ignores --arch flag in CI + arch: process.env.TARGET_ARCH || process.env.npm_config_arch || process.arch, + prune: false, + appBundleId: bundleId, + asar: true, + extraResource: [], + name: productName, + icon: path.join(__dirname, "assets/build/icon"), + extendInfo: { + NSAppleEventsUsageDescription: "This app need to run commands through Terminal.", + }, + osxNotarize: { + appleId: process.env.APPLE_ID || "", + appleIdPassword: process.env.APPLE_ID_PASSWORD || "", + teamId: process.env.APPLE_TEAM_ID || "", + }, + osxSign: { + identity: `Developer ID Application: Quentin Goinaud (${process.env.APPLE_TEAM_ID})`, + hardenedRuntime: true, + entitlements: path.join(__dirname, "assets/build/entitlements.mac.plist"), + "entitlements-inherit": path.join(__dirname, "assets/build/entitlements.mac.plist"), + strictVerify: false, + } as any, + }, + makers: [ + new MakerSquirrel({ + name: productName, + setupIcon: path.join(__dirname, "assets/build/icon.ico"), + }), + new MakerZIP(undefined, ["linux", "win32"]), + new MakerDMG({ name: productName }), + ], + publishers: [ + { + name: "@electron-forge/publisher-github", + config: { + repository: { owner: "CynToolkit", name: "pipelab" }, + prerelease: process.env.PRERELEASE === "true", + draft: false, + generateReleaseNotes: true, + }, + }, + ], + hooks: { + postMake: async (_, makeResults) => { + for (const target of new Set(makeResults.map((r) => `${r.platform}:${r.arch}`))) { + const [p, a] = target.split(":"); + await renameInstallers(p, a); + } + return makeResults; + }, + }, + plugins: [ + new VitePlugin({ + build: [ + { entry: "src/main.ts", config: "vite.main.config.mts" }, + { entry: "src/preload.ts", config: "vite.preload.config.mts" }, + ], + renderer: [{ name: "main_window", config: "vite.renderer.config.mts" }], + }), + new FusesPlugin({ + version: FuseVersion.V1, + [FuseV1Options.RunAsNode]: true, + [FuseV1Options.EnableCookieEncryption]: true, + [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: true, + [FuseV1Options.EnableNodeCliInspectArguments]: false, + [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: false, + [FuseV1Options.OnlyLoadAppFromAsar]: false, + }), + ], +}; + +export default config; diff --git a/apps/desktop/forge.env.d.ts b/apps/desktop/forge.env.d.ts new file mode 100644 index 00000000..ff48335b --- /dev/null +++ b/apps/desktop/forge.env.d.ts @@ -0,0 +1,44 @@ +export {}; // Make this a module + +declare global { + // This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Vite + // plugin that tells the Electron app where to look for the Vite-bundled app code (depending on + // whether you're running in development or production). + const MAIN_WINDOW_VITE_DEV_SERVER_URL: string; + const MAIN_WINDOW_VITE_NAME: string; + + type ElectronAPI = import("@electron-toolkit/preload").ElectronAPI; + + namespace NodeJS { + interface Process { + // Used for hot reload after preload scripts. + viteDevServers: Record; + } + } + + interface Window { + version: string; + electron: ElectronAPI; + api: any; + isPackaged: boolean; + isTest: boolean; + isCI: boolean; + } + + type VitePluginConfig = ConstructorParameters< + typeof import("@electron-forge/plugin-vite").VitePlugin + >[0]; + + interface VitePluginRuntimeKeys { + VITE_DEV_SERVER_URL: `${string}_VITE_DEV_SERVER_URL`; + VITE_NAME: `${string}_VITE_NAME`; + } +} + +declare module "vite" { + interface ConfigEnv { + root: string; + forgeConfig: VitePluginConfig; + forgeConfigSelf: VitePluginConfig[K][number]; + } +} diff --git a/apps/desktop/index.html b/apps/desktop/index.html new file mode 100644 index 00000000..9666b78f --- /dev/null +++ b/apps/desktop/index.html @@ -0,0 +1,53 @@ + + + + + Pipelab + + + + + + + + + +
+ + + diff --git a/apps/desktop/package.json b/apps/desktop/package.json new file mode 100644 index 00000000..17e1f1e3 --- /dev/null +++ b/apps/desktop/package.json @@ -0,0 +1,60 @@ +{ + "name": "@pipelab/app", + "version": "2.0.0-beta.32", + "private": true, + "description": "-", + "homepage": "https://pipelab.app", + "license": "FSL-1.1-MIT", + "author": "Armaldio", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "apps/desktop" + }, + "main": ".vite/build/main.js", + "scripts": { + "format": "oxfmt .", + "lint": "oxlint .", + "typecheck": "tsc --noEmit -p tsconfig.json --composite false", + "start": "electron-forge start", + "start:args": "electron-forge start -- --project ./tests/e2e/fixtures/folder-to-electron.json --action run", + "dev": "cross-env NODE_OPTIONS=--enable-source-maps electron-forge start", + "package": "cross-env DEBUG='electron-osx-sign*,electron-forge:*' electron-forge package", + "make": "electron-forge make", + "publish": "electron-forge publish", + "make-dev-prerelease": "pnpm version prerelease --preid=dev", + "migrate-file": "tsx scripts/migrate-file.mts" + }, + "dependencies": { + "electron-squirrel-startup": "1.0.1", + "posthog-node": "5.30.6" + }, + "devDependencies": { + "@electron-forge/cli": "7.11.1", + "@electron-forge/maker-dmg": "7.11.1", + "@electron-forge/maker-squirrel": "7.11.1", + "@electron-forge/maker-zip": "7.11.1", + "@electron-forge/plugin-fuses": "7.11.1", + "@electron-forge/plugin-vite": "7.11.1", + "@electron-forge/publisher-github": "7.11.1", + "@electron-toolkit/preload": "3.0.2", + "@electron-toolkit/utils": "4.0.0", + "@electron/fuses": "1.8.0", + "@electron/notarize": "2.5.0", + "@pipelab/constants": "workspace:*", + "@pipelab/core-node": "workspace:*", + "@pipelab/plugin-core": "workspace:*", + "@pipelab/shared": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "@types/electron-squirrel-startup": "1.0.2", + "@types/node": "24.12.2", + "@types/semver": "7.7.1", + "cross-env": "7.0.3", + "electron": "32.1.2", + "semver": "7.8.0", + "tsx": "4.19.1", + "typescript": "5.8.3", + "vite": "6.3.3", + "vite-tsconfig-paths": "5.1.4" + } +} diff --git a/apps/desktop/scripts/headless-electron-tester.mts b/apps/desktop/scripts/headless-electron-tester.mts new file mode 100644 index 00000000..b72b53a4 --- /dev/null +++ b/apps/desktop/scripts/headless-electron-tester.mts @@ -0,0 +1,10 @@ +import { execa } from "execa"; +import { join } from "path"; +import { cwd, stdin } from "process"; + +await execa({ + cwd: join(import.meta.dirname, ".."), + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", +})`./assets/electron/template/app/node_modules/.bin/electron-forge start -- --headless --port=3000`; diff --git a/apps/desktop/scripts/migrate-file.mts b/apps/desktop/scripts/migrate-file.mts new file mode 100644 index 00000000..befdd9be --- /dev/null +++ b/apps/desktop/scripts/migrate-file.mts @@ -0,0 +1,40 @@ +import { savedFileMigrator } from "@pipelab/shared"; +import * as fs from "fs/promises"; +import { join } from "path"; +import { tmpdir } from "os"; +import { nanoid } from "nanoid"; +import { execa } from "execa"; + +const args = process.argv.slice(2); +if (args.length !== 1) { + console.error("Usage: node script.ts "); + process.exit(1); +} + +const filePath = args[0]; + +async function migrateFile() { + try { + // const tmpFile = join(tmpdir(), nanoid() + '.json') + + const data = await fs.readFile(filePath, "utf8"); + const json = JSON.parse(data); + const migratedData = await savedFileMigrator.migrate(json); + const str = JSON.stringify(migratedData, null, 2); + console.log("data", data); + console.log("str", str); + await fs.writeFile(filePath, str, "utf8"); + console.log("File successfully migrated to the latest version of the model."); + + // await execa('delta', [filePath, tmpFile], { + // env: { + // DELTA_FEATURES: '+side-by-side' + // } + // }) + } catch (error) { + console.error(`Error migrating the file: ${error}`); + process.exit(1); + } +} + +await migrateFile(); diff --git a/apps/desktop/scripts/test-github-releases.mts b/apps/desktop/scripts/test-github-releases.mts new file mode 100644 index 00000000..1c0da557 --- /dev/null +++ b/apps/desktop/scripts/test-github-releases.mts @@ -0,0 +1,13 @@ +import { fetchLatestDesktopRelease } from "../../../packages/core-node/src/utils/github"; + +async function test() { + console.log("--- Testing Release Fetcher (Stable) ---"); + const stable = await fetchLatestDesktopRelease({ allowPrerelease: false }); + console.log("Result:", stable ? stable.tag_name : "None found"); + + console.log("\n--- Testing Release Fetcher (Beta) ---"); + const beta = await fetchLatestDesktopRelease({ allowPrerelease: true }); + console.log("Result:", beta ? beta.tag_name : "None found"); +} + +test().catch(console.error); diff --git a/apps/desktop/scripts/test-update-server.mts b/apps/desktop/scripts/test-update-server.mts new file mode 100644 index 00000000..42e5e4e5 --- /dev/null +++ b/apps/desktop/scripts/test-update-server.mts @@ -0,0 +1,101 @@ +import http from "node:http"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const PORT = 8080; + +// Path to the 'make' directory where forge puts build artifacts +const MAKE_DIR = path.resolve(__dirname, "..", "out", "make"); + +const server = http.createServer((req, res) => { + console.log(`[Mock Server] Requested: ${req.url}`); + + const url = new URL(req.url || "/", `http://localhost:${PORT}`); + const pathname = url.pathname; + + // 1. Handle Squirrel.Windows RELEASES file + if (pathname === "/RELEASES" || pathname.endsWith("/RELEASES")) { + // Try to find the RELEASES file in the squirrel directory + const squirrelDir = path.join(MAKE_DIR, "squirrel.windows", "x64"); + const releasesPath = path.join(squirrelDir, "RELEASES"); + + if (fs.existsSync(releasesPath)) { + res.writeHead(200, { "Content-Type": "text/plain" }); + fs.createReadStream(releasesPath).pipe(res); + return; + } + } + + // 2. Handle macOS Update JSON (Native autoUpdater protocol) + if (pathname === "/update/macos") { + // This is a simplified mock for macOS native protocol + // It expects a JSON with a 'url' property if an update is available + // or a 204 No Content if no update. + const version = process.env.APP_VERSION || "1.0.1"; + const dmgPath = path.join(MAKE_DIR, "zip", "darwin", "x64", `pipelab-v${version}.zip`); + + if (fs.existsSync(dmgPath)) { + res.writeHead(200, { "Content-Type": "application/json" }); + res.end( + JSON.stringify({ + url: `http://localhost:${PORT}/download/macos/pipelab-v${version}.zip`, + }), + ); + } else { + res.writeHead(204); + res.end(); + } + return; + } + + // 3. Serve static files (.nupkg, .zip, .exe, etc.) + // We search recursively in the MAKE_DIR for the file basename + const basename = path.basename(pathname); + const findFile = (dir: string): string | null => { + const files = fs.readdirSync(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + if (fs.statSync(fullPath).isDirectory()) { + const found = findFile(fullPath); + if (found) return found; + } else if (file === basename) { + return fullPath; + } + } + return null; + }; + + try { + const filePath = findFile(MAKE_DIR); + if (filePath) { + const ext = path.extname(filePath); + const contentType = + { + ".nupkg": "application/zip", + ".zip": "application/zip", + ".exe": "application/x-msdownload", + ".dmg": "application/x-apple-diskimage", + }[ext] || "application/octet-stream"; + + res.writeHead(200, { "Content-Type": contentType }); + fs.createReadStream(filePath).pipe(res); + return; + } + } catch (e) { + console.error(`[Mock Server] Error searching for file: ${e}`); + } + + res.writeHead(404); + res.end("Not Found"); +}); + +server.listen(PORT, () => { + console.log(`\n🚀 Mock Update Server running at http://localhost:${PORT}`); + console.log(`📂 Serving artifacts from: ${MAKE_DIR}`); + console.log(`\nInstructions for Windows VM:`); + console.log(`1. Identify your Host IP (e.g., 10.0.2.2 or 192.168.x.x)`); + console.log(`2. Run Pipelab in VM with env: APP_UPDATE_URL=http://:${PORT}`); + console.log(`\nPress Ctrl+C to stop.\n`); +}); diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts new file mode 100644 index 00000000..481b930b --- /dev/null +++ b/apps/desktop/src/main.ts @@ -0,0 +1,465 @@ +import { app, shell, BrowserWindow, dialog, autoUpdater, screen, protocol, net } from "electron"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { platform } from "node:os"; +import { electronApp, optimizer, is } from "@electron-toolkit/utils"; +import { startServer, stopServer } from "./main/server-process"; +import { websocketPort, uiDevPort, getProtocolName, getAppBundleId } from "@pipelab/constants"; +import { registerIpcHandlers } from "./main/ipc-handlers"; +import { getDefaultUserDataPath, fetchLatestDesktopRelease } from "@pipelab/core-node"; +import started from "electron-squirrel-startup"; +import { PostHog } from "posthog-node"; +import { parseArgs } from "node:util"; +import semver from "semver"; + +const isProduction = app.isPackaged && process.env.TEST !== "true"; + +let posthog: PostHog | undefined; +if (isProduction) { + posthog = new PostHog(process.env.POSTHOG_API_KEY || "", { + host: "https://eu.i.posthog.com", + }); +} + +process.on("uncaughtException", (error) => { + console.error("Uncaught Exception in Main Process:", error); + if (posthog) { + posthog.capture({ + distinctId: "desktop-main-process", + event: "uncaught_exception", + properties: { + message: error.message, + stack: error.stack, + platform: process.platform, + version: app.getVersion(), + }, + }); + } +}); + +const getEnv = () => { + if (is.dev) return "dev"; + if (app.getVersion().includes("beta")) return "beta"; + return "prod"; +}; + +const customUserDataPath = getDefaultUserDataPath(getEnv()); +app.setPath("userData", join(customUserDataPath, "desktop")); + +protocol.registerSchemesAsPrivileged([ + { + scheme: "media", + privileges: { + secure: true, + standard: true, + supportFetchAPI: true, + corsEnabled: true, + stream: true, + }, + }, +]); + +function getIconPath() { + let ext = ".png"; + if (platform() === "win32") ext = ".ico"; + else if (platform() === "darwin") ext = ".icns"; + return join("./assets", "build", `icon${ext}`); +} + +let pendingUrl: string | null = null; + +function findProtocolUrl(args: string[], values: any, positionals: string[]): string | null { + const pUrl = positionals.find( + (arg) => arg.startsWith("pipelab://") || arg.startsWith("pipelab-beta://"), + ); + if (pUrl) return pUrl; + + const startArgs = values["process-start-args"]; + if (typeof startArgs === "string" && startArgs) { + if (startArgs.startsWith("pipelab://") || startArgs.startsWith("pipelab-beta://")) { + return startArgs; + } + const parts = startArgs.split(/\s+/); + const partUrl = parts.find( + (arg) => arg.startsWith("pipelab://") || arg.startsWith("pipelab-beta://"), + ); + if (partUrl) return partUrl; + } + + const anyUrl = args.find( + (arg) => arg.startsWith("pipelab://") || arg.startsWith("pipelab-beta://"), + ); + if (anyUrl) return anyUrl; + + return null; +} + +function handleProtocolUrl(url: string) { + if (!url) return; + console.info(`[Main] Handling protocol URL: ${url}`); + if (mainWindow && !mainWindow.webContents.isLoading()) { + mainWindow.webContents.send("protocol-url", url); + } else { + pendingUrl = url; + } +} + +// Register macOS open-url handler +app.on("open-url", (event, url) => { + event.preventDefault(); + handleProtocolUrl(url); +}); + +// Single Instance Lock setup +const gotTheLock = app.requestSingleInstanceLock(); +if (!gotTheLock) { + console.info("[Main] Another instance is already running. Quitting."); + app.exit(0); +} else { + app.on("second-instance", (event, commandLine) => { + console.info(`[Main] Second instance started with command line: ${commandLine.join(" ")}`); + if (mainWindow) { + if (mainWindow.isMinimized()) mainWindow.restore(); + mainWindow.focus(); + } + + try { + const config = { + options: { + "process-start-args": { type: "string" as const }, + }, + strict: false, + }; + const { values, positionals } = parseArgs({ + ...config, + args: commandLine.slice(1), + }); + + const url = findProtocolUrl(commandLine, values, positionals); + if (url) { + handleProtocolUrl(url); + } + } catch (err) { + console.error("[Main] Failed to parse second-instance arguments:", err); + } + }); +} + +if (process.platform === "win32" && process.env.TEST !== "true" && app.isPackaged) { + if (started) { + app.quit(); + } +} + +let mainWindow: BrowserWindow | undefined; + +function createWindow(): void { + const displays = screen.getAllDisplays(); + const externalDisplay = displays.find((display) => { + return display.bounds.x !== 0 || display.bounds.y !== 0; + }); + + const position = + externalDisplay && is.dev + ? { + x: externalDisplay.bounds.x + 50, + y: externalDisplay.bounds.y + 50, + } + : {}; + + mainWindow = new BrowserWindow({ + width: 1280, + height: 720, + show: true, // Show the window immediately on startup + icon: getIconPath(), + autoHideMenuBar: true, + ...position, + webPreferences: { + preload: join(__dirname, "preload.cjs"), + sandbox: false, + devTools: is.dev, + additionalArguments: [`--app-version=${app.getVersion()}`], + }, + }); + + if (is.dev) { + mainWindow.webContents.openDevTools(); + } + + mainWindow.webContents.on("did-finish-load", () => { + if (pendingUrl) { + mainWindow?.webContents.send("protocol-url", pendingUrl); + pendingUrl = null; + } + }); + + mainWindow.on("close", function () { + app.exit(0); + }); + + mainWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url); + return { action: "deny" }; + }); +} + +const protocolName = getProtocolName(app.getVersion()); + +if (is.dev && process.platform === "win32") { + app.setAsDefaultProtocolClient(protocolName, process.execPath, [resolve(process.argv[1])]); +} else { + app.setAsDefaultProtocolClient(protocolName); +} + +const sendUpdateStatus = (status: string, downloadUrl?: string, version?: string) => { + mainWindow?.webContents.send("update:set-status", { + data: { status, downloadUrl, version }, + requestId: "shell-update", + }); +}; + +app.whenReady().then(async () => { + protocol.handle("media", (request) => { + const path = decodeURIComponent(request.url.replace(/^media:\/\/+/, "/")); + return net.fetch(pathToFileURL(path).toString()); + }); + + // Check if launched via protocol URL on startup + const startupArgs = is.dev ? process.argv.slice(2) : process.argv.slice(1); + try { + const config = { + options: { + "process-start-args": { type: "string" as const }, + }, + strict: false, + }; + const { values, positionals } = parseArgs({ + ...config, + args: startupArgs, + }); + const url = findProtocolUrl(process.argv, values, positionals); + if (url) { + handleProtocolUrl(url); + } + } catch (err) { + console.error("[Main] Failed to parse startup protocol URL:", err); + } + + const supportsAutoUpdate = process.platform === "win32" || process.platform === "darwin"; + + if ( + !is.dev || + process.env.APP_UPDATE_URL || + process.env.PIPELAB_OVERRIDE_RELEASE || + process.env.FORCE_UPDATE_CHECK === "true" + ) { + console.log("[Update] --- Auto-Updater Debug Info ---"); + console.log(`[Update] Platform: ${process.platform}`); + console.log(`[Update] Arch: ${process.arch}`); + console.log(`[Update] Current Version: ${app.getVersion()}`); + console.log(`[Update] Is Packaged: ${app.isPackaged}`); + console.log(`[Update] FORCE_UPDATE_CHECK: ${process.env.FORCE_UPDATE_CHECK}`); + console.log(`[Update] Supports Auto-Update: ${supportsAutoUpdate}`); + + let updateUrl = + process.env.APP_UPDATE_URL || + "https://github.com/CynToolkit/pipelab/releases/latest/download"; + + let latestRelease: any = null; + + // 1. Try to resolve the latest desktop-specific release from GitHub + if (!process.env.APP_UPDATE_URL) { + const currentVersion = app.getVersion(); + const isPrerelease = currentVersion.includes("-") || process.env.PRERELEASE === "true"; + + console.log( + `[Update] Fetching ${isPrerelease ? "beta" : "stable"} releases from GitHub API...`, + ); + + const release = await fetchLatestDesktopRelease({ allowPrerelease: isPrerelease }); + if (release) { + latestRelease = release; + updateUrl = `https://github.com/CynToolkit/pipelab/releases/download/${release.tag_name}`; + console.log(`[Update] Target Tag: ${release.tag_name}`); + console.log(`[Update] Release API URL: ${release.html_url}`); + } else { + console.warn("[Update] No desktop release found, using fallback URL"); + } + } + + // Helper to resolve manual download details for the platform + const resolveManualDownloadUrl = ( + release: any, + ): { downloadUrl: string; version: string } | null => { + if (!release) return null; + const latestVersion = release.tag_name.split("@").pop(); + if (!latestVersion) return null; + + let asset; + if (process.platform === "linux") { + asset = + release.assets?.find((a: any) => a.name.endsWith(".AppImage")) || + release.assets?.find((a: any) => a.name.endsWith(".deb")); + } else if (process.platform === "darwin") { + asset = + release.assets?.find((a: any) => a.name.endsWith(".dmg")) || + release.assets?.find((a: any) => a.name.endsWith(".zip")); + } else if (process.platform === "win32") { + asset = release.assets?.find((a: any) => a.name.endsWith(".exe")); + } + + return { + downloadUrl: asset ? asset.browser_download_url : release.html_url, + version: latestVersion, + }; + }; + + if (supportsAutoUpdate) { + console.log(`[Update] Final Feed URL: ${updateUrl}`); + if (process.platform === "win32") { + console.log(`[Update] (Windows) Squirrel will request: ${updateUrl}/RELEASES`); + } + + try { + autoUpdater.setFeedURL({ + url: updateUrl, + headers: { + "Cache-Control": "no-cache", + }, + }); + + autoUpdater.on("checking-for-update", () => { + console.log("[Update] Checking for update..."); + sendUpdateStatus("checking-for-update"); + }); + autoUpdater.on("update-available", () => { + console.log("[Update] Update available!"); + sendUpdateStatus("update-available"); + }); + autoUpdater.on("update-not-available", () => { + console.log("[Update] Update not available."); + sendUpdateStatus("update-not-available"); + }); + + autoUpdater.on("update-downloaded", (event, releaseNotes, releaseName) => { + console.log("[Update] Update downloaded:", releaseName); + sendUpdateStatus("update-downloaded"); + + const dialogOpts: Electron.MessageBoxOptions = { + type: "info", + buttons: ["Restart", "Later"], + title: "Application Update", + message: process.platform === "win32" ? releaseNotes : releaseName, + detail: + "A new version has been downloaded. Restart the application to apply the updates.", + }; + + dialog.showMessageBox(dialogOpts).then((returnValue) => { + if (returnValue.response === 0) autoUpdater.quitAndInstall(); + }); + }); + + autoUpdater.on("error", (message) => { + console.error("[Update] AutoUpdater encountered an error:", message); + // Fallback to manual update indicator if an update is actually available + const manualInfo = resolveManualDownloadUrl(latestRelease); + const currentVersion = app.getVersion(); + if ( + manualInfo && + semver.valid(manualInfo.version) && + semver.gt(manualInfo.version, currentVersion) + ) { + console.log( + `[Update] AutoUpdater failed, falling back to manual update for v${manualInfo.version}`, + ); + sendUpdateStatus("update-available", manualInfo.downloadUrl, manualInfo.version); + } else { + sendUpdateStatus("error"); + } + }); + } catch (err) { + console.error("[Update] Failed to setup autoUpdater:", err); + } + } else { + // Manual update check path for Linux and other unsupported platforms + console.log("[Update] Auto-updater is not supported. Running manual check..."); + const manualInfo = resolveManualDownloadUrl(latestRelease); + const currentVersion = app.getVersion(); + if ( + manualInfo && + semver.valid(manualInfo.version) && + semver.gt(manualInfo.version, currentVersion) + ) { + console.log(`[Update] Manual update available: v${manualInfo.version}`); + sendUpdateStatus("update-available", manualInfo.downloadUrl, manualInfo.version); + } else { + console.log("[Update] Manual check: No newer version available."); + sendUpdateStatus("update-not-available"); + } + } + } + + const appBundleId = getAppBundleId(app.getVersion()); + electronApp.setAppUserModelId(appBundleId); + registerIpcHandlers(); + createWindow(); + + if (mainWindow) { + if (is.dev) { + // In dev, we load the dev server up immediately but do not show it yet + mainWindow.loadURL(`http://localhost:${uiDevPort}`); + } + } + + // Start the background server (this might include downloading the CLI on first run) + try { + console.info("[Main] Starting standalone server..."); + await startServer(); + console.info("[Main] Standalone server is ready"); + + // Once server is ready, load the real UI + if (!is.dev) { + console.info(`[Main] Loading production UI from localhost:${websocketPort}`); + mainWindow?.loadURL(`http://localhost:${websocketPort}`); + } + } catch (error) { + console.error("Failed to start standalone server:", error); + dialog.showErrorBox( + "Startup Error", + "Failed to start the background server. This is required for Pipelab to function.\n\n" + + (error instanceof Error ? error.message : String(error)), + ); + app.quit(); + return; + } + + if (app.isPackaged || process.env.FORCE_UPDATE_CHECK === "true") { + setTimeout(() => { + if (supportsAutoUpdate) { + console.log("[Update] Triggering autoUpdater.checkForUpdates()..."); + autoUpdater.checkForUpdates(); + } + }, 10000); + } + + app.on("browser-window-created", (_, window) => { + optimizer.watchWindowShortcuts(window); + }); + + app.on("activate", function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow(); + }); +}); + +app.on("window-all-closed", async () => { + if (process.platform !== "darwin") { + stopServer(); + app.quit(); + } +}); + +app.on("before-quit", async (event) => { + event.preventDefault(); + stopServer(); + app.exit(0); +}); diff --git a/apps/desktop/src/main/ipc-handlers.ts b/apps/desktop/src/main/ipc-handlers.ts new file mode 100644 index 00000000..d251caa1 --- /dev/null +++ b/apps/desktop/src/main/ipc-handlers.ts @@ -0,0 +1,61 @@ +import { ipcMain, dialog, BrowserWindow, shell, app } from "electron"; +import { isPathBlacklisted } from "@pipelab/plugin-core"; + +export const registerIpcHandlers = () => { + console.log("[Main] Registering IPC handlers"); + + const OPEN_DIALOG_CHANNEL = "dialog:showOpenDialog"; + const SAVE_DIALOG_CHANNEL = "dialog:showSaveDialog"; + + ipcMain.removeHandler(OPEN_DIALOG_CHANNEL); + ipcMain.handle(OPEN_DIALOG_CHANNEL, async (event, options) => { + const win = BrowserWindow.fromWebContents(event.sender) || undefined; + const result = await dialog.showOpenDialog(win!, options); + return { + canceled: result.canceled, + filePaths: result.filePaths, + }; + }); + + ipcMain.removeHandler(SAVE_DIALOG_CHANNEL); + ipcMain.handle(SAVE_DIALOG_CHANNEL, async (event, options) => { + const win = BrowserWindow.fromWebContents(event.sender) || undefined; + const result = await dialog.showSaveDialog(win!, options); + return { + canceled: result.canceled, + filePath: result.filePath, + }; + }); + + ipcMain.handle("shell:openExternal", async (event, url) => { + return await shell.openExternal(url); + }); + + ipcMain.handle("shell:showItemInFolder", (event, path) => { + shell.showItemInFolder(path); + }); + + ipcMain.handle("window:show", (event) => { + const win = BrowserWindow.fromWebContents(event.sender); + if (win) { + console.info("[Main] Received window:show request, showing and maximizing window"); + win.show(); + win.maximize(); + } else { + console.error("[Main] Received window:show request but could not resolve window from sender"); + } + }); + + ipcMain.handle("app:version:get", () => { + return app.getVersion(); + }); + + ipcMain.handle("path:isBlacklisted", (event, pathToCheck: string) => { + return isPathBlacklisted(pathToCheck); + }); + + ipcMain.handle("app:relaunch", () => { + app.relaunch(); + app.exit(0); + }); +}; diff --git a/apps/desktop/src/main/server-process.ts b/apps/desktop/src/main/server-process.ts new file mode 100644 index 00000000..2704237b --- /dev/null +++ b/apps/desktop/src/main/server-process.ts @@ -0,0 +1,133 @@ +import { spawn, ChildProcess } from "node:child_process"; +import { join, dirname } from "node:path"; +import { app } from "electron"; +import { is } from "@electron-toolkit/utils"; +import http from "node:http"; +import fs from "node:fs"; +import { websocketPort, uiDevPort, getUiDevServerFatalError } from "@pipelab/constants"; +import { + fetchPipelabCli, + projectRoot, + PipelabContext, + getDefaultUserDataPath, +} from "@pipelab/core-node"; + +let serverProcess: ChildProcess | null = null; + +const isUp = ( + port: number, + delay = 1000, + shouldContinue?: () => boolean, + silent = false, +): Promise => + new Promise((resolve) => { + const attempt = () => { + const req = http.get(`http://localhost:${port}`, (res) => { + res.resume(); + if (!silent) console.info(`[Server Check] Server is up on port ${port}`); + resolve(true); + }); + + req.on("error", () => { + if (!shouldContinue || shouldContinue()) { + if (!silent) { + console.info(`[Server Check] Waiting for server on port ${port}...`); + } + setTimeout(attempt, delay); + } else { + if (!silent) { + console.error(`[Server Check] Server check aborted for port ${port}`); + } + resolve(false); + } + }); + }; + attempt(); + }); + +export const startServer = async () => { + if (serverProcess) { + return; + } + + // 0. In dev mode, ensure UI dev server is running BEFORE anything else + if (is.dev) { + let retries = 5; + const isUIUp = await isUp(uiDevPort, 500, () => retries-- > 0, true); + if (!isUIUp) { + console.error(getUiDevServerFatalError(uiDevPort)); + throw new Error("UI dev server not found. App cannot start in development mode."); + } + } + + // 1. Check if server is already running + let initialRetries = 1; + const alreadyUp = await isUp(websocketPort, 500, () => initialRetries-- > 0, true); + if (alreadyUp) { + console.info(`[Server] Server already running on port ${websocketPort}`); + return; + } + + if (is.dev) { + console.info(" [DEVELOPMENT MODE] CLI server is starting automatically."); + } + + // 2. Resolve the CLI + const releaseTag = app.getVersion().includes("beta") ? "beta" : "latest"; + const userDataPath = getDefaultUserDataPath(releaseTag === "beta" ? "beta" : "prod"); + const context = new PipelabContext({ userDataPath, releaseTag }); + const cliVersion = is.dev ? "local" : releaseTag; + const { entryPoint, isLocal, packageDir } = await fetchPipelabCli(cliVersion, { context }); + + let serverPath = process.execPath; + let args = [entryPoint, "serve"]; + + if (isLocal && entryPoint.endsWith(".ts")) { + console.info( + `[Server] Local CLI detected at ${packageDir}, starting with hot-reload (tsx watch)`, + ); + const tsxPath = projectRoot ? join(projectRoot, "node_modules", ".bin", "tsx") : "tsx"; + // When using tsx, we still use Electron as the runner + args = [tsxPath, "watch", entryPoint, "serve"]; + } else { + console.info(`[Server] Starting CLI server from: ${entryPoint}`); + } + + let isServerRunning = true; + serverProcess = spawn(serverPath, args, { + env: { + ...process.env, + ELECTRON_RUN_AS_NODE: "1", + NODE_ENV: is.dev ? "development" : "production", + PORT: websocketPort.toString(), + IS_SERVER: "true", + }, + stdio: ["inherit", "inherit", "inherit"], + }); + + serverProcess.on("error", (err) => console.error("ERROR: Failed to spawn server:", err)); + serverProcess.stdout?.on("data", (d) => console.info(`[Server] ${d.toString().trim()}`)); + serverProcess.stderr?.on("data", (d) => console.error(`[Server Error] ${d.toString().trim()}`)); + + serverProcess.on("close", (code) => { + console.info(`Server process exited with code ${code}`); + serverProcess = null; + isServerRunning = false; + }); + + // Wait for the server to be listening on the port + console.log(`[Server] Waiting for server on port ${websocketPort}...`); + // Wait indefinitely as long as the server process is running + const up = await isUp(websocketPort, 1000, () => isServerRunning); + if (!up) { + throw new Error(`Server failed to start on port ${websocketPort} (process exited)`); + } + console.log(`[Server] CLI server is listening!`); +}; + +export const stopServer = () => { + if (serverProcess) { + serverProcess.kill(); + serverProcess = null; + } +}; diff --git a/apps/desktop/src/preload.ts b/apps/desktop/src/preload.ts new file mode 100644 index 00000000..ae78826c --- /dev/null +++ b/apps/desktop/src/preload.ts @@ -0,0 +1,76 @@ +import { contextBridge, ipcRenderer } from "electron"; +import { electronAPI } from "@electron-toolkit/preload"; + +declare global { + interface Window { + electron: any; + pipelab: any; + version: string; + isPackaged: boolean; + } +} + +let version = "1.0.0"; +try { + if (process.env.NODE_ENV === "development") { + version = "workspace"; + } else { + const versionArg = process.argv.find((arg) => arg.startsWith("--app-version=")); + version = versionArg ? versionArg.split("=")[1] : "1.0.0"; + } +} catch (error) { + console.error("Failed to parse version in preload:", error); +} + +// Custom APIs for renderer +// TODO: unify window and contextBridge + +// Use `contextBridge` APIs to expose Electron APIs to +// renderer only if context isolation is enabled, otherwise +// just add to the DOM global. +if (process.contextIsolated) { + try { + contextBridge.exposeInMainWorld("electron", electronAPI); + + const versions = { + electron: process.versions.electron, + chrome: process.versions.chrome, + node: process.versions.node, + app: version, + }; + console.log("[Preload] Exposing versions:", versions); + + contextBridge.exposeInMainWorld("pipelab", { + versions, + showOpenDialog: (options: any) => ipcRenderer.invoke("dialog:showOpenDialog", options), + showSaveDialog: (options: any) => ipcRenderer.invoke("dialog:showSaveDialog", options), + openExternal: (url: string) => ipcRenderer.invoke("shell:openExternal", url), + showItemInFolder: (path: string) => ipcRenderer.invoke("shell:showItemInFolder", path), + isPathBlacklisted: (path: string) => ipcRenderer.invoke("path:isBlacklisted", path), + relaunch: () => ipcRenderer.invoke("app:relaunch"), + }); + contextBridge.exposeInMainWorld("version", version); + contextBridge.exposeInMainWorld("isPackaged", process.env.NODE_ENV !== "development"); + } catch (error) { + console.error(error); + } +} else { + window.electron = electronAPI; + const versions = { + electron: process.versions.electron, + chrome: process.versions.chrome, + node: process.versions.node, + app: version, + }; + window.pipelab = { + versions, + showOpenDialog: (options: any) => ipcRenderer.invoke("dialog:showOpenDialog", options), + showSaveDialog: (options: any) => ipcRenderer.invoke("dialog:showSaveDialog", options), + openExternal: (url: string) => ipcRenderer.invoke("shell:openExternal", url), + showItemInFolder: (path: string) => ipcRenderer.invoke("shell:showItemInFolder", path), + isPathBlacklisted: (path: string) => ipcRenderer.invoke("path:isBlacklisted", path), + relaunch: () => ipcRenderer.invoke("app:relaunch"), + }; + window.version = version; + window.isPackaged = process.env.NODE_ENV !== "development"; +} diff --git a/apps/desktop/tsconfig.json b/apps/desktop/tsconfig.json new file mode 100644 index 00000000..80b1c960 --- /dev/null +++ b/apps/desktop/tsconfig.json @@ -0,0 +1,37 @@ +{ + "extends": "@pipelab/tsconfig/commonjs.json", + "compilerOptions": { + "emitDeclarationOnly": true, + "baseUrl": ".", + "outDir": "dist", + "inlineSourceMap": true, + "paths": { + "@pipelab/*": ["../../packages/shared/src/libs/*"] + } + }, + "include": ["src/**/*", "tests/**/*", "*.ts", "*.mts", "package.json"], + "exclude": [ + "node_modules", + "./assets/tauri/template/app/src-tauri", + "dist", + "out", + "scripts", + "./assets", + "vite.base.config.mts", + "vite.main.config.mts", + "vite.preload.config.mts", + "vite.renderer.config.mts", + "forge.config.ts" + ], + "references": [ + { + "path": "../../packages/constants" + }, + { + "path": "../../packages/shared" + }, + { + "path": "../../packages/migration" + } + ] +} diff --git a/apps/desktop/vite.base.config.mts b/apps/desktop/vite.base.config.mts new file mode 100644 index 00000000..0bb17acd --- /dev/null +++ b/apps/desktop/vite.base.config.mts @@ -0,0 +1,103 @@ +import { builtinModules } from "node:module"; +import type { AddressInfo } from "node:net"; +import { loadEnv, type ConfigEnv, type Plugin, type UserConfig } from "vite"; +import pkg from "./package.json" with { type: "json" }; + +export const builtins = ["electron", ...builtinModules.map((m) => [m, `node:${m}`]).flat()]; + +export const external = [ + ...builtins, + ...Object.keys("dependencies" in pkg ? (pkg.dependencies as Record) : {}), +]; + +export function getBuildConfig(env: ConfigEnv<"build">): UserConfig { + const { root, mode, command } = env; + + return { + root, + mode, + build: { + // Prevent multiple builds from interfering with each other. + emptyOutDir: false, + // 🚧 Multiple builds may conflict. + outDir: ".vite/build", + watch: command === "serve" ? {} : null, + minify: command === "build", + }, + clearScreen: false, + }; +} + +export function getDefineKeys(names: string[]) { + const define: { [name: string]: VitePluginRuntimeKeys } = {}; + + return names.reduce((acc, name) => { + const NAME = name.toUpperCase(); + const keys: VitePluginRuntimeKeys = { + VITE_DEV_SERVER_URL: `${NAME}_VITE_DEV_SERVER_URL`, + VITE_NAME: `${NAME}_VITE_NAME`, + }; + + return { ...acc, [name]: keys }; + }, define); +} + +export function getBuildDefine(env: ConfigEnv<"build">) { + const { command, forgeConfig } = env; + const names = + forgeConfig?.renderer?.filter(({ name }) => name != null).map(({ name }) => name!) || []; + const defineKeys = getDefineKeys(names); + const define = Object.entries(defineKeys).reduce( + (acc, [name, keys]) => { + const { VITE_DEV_SERVER_URL, VITE_NAME } = keys; + const def = { + [VITE_DEV_SERVER_URL]: + command === "serve" ? JSON.stringify(process.env[VITE_DEV_SERVER_URL]) : undefined, + [VITE_NAME]: JSON.stringify(name), + }; + return { ...acc, ...def }; + }, + {} as Record, + ); + + return define; +} + +export function pluginExposeRenderer(name: string): Plugin { + const { VITE_DEV_SERVER_URL } = getDefineKeys([name])[name]; + + return { + name: "@electron-forge/plugin-vite:expose-renderer", + configureServer(server) { + process.viteDevServers ??= {}; + // Expose server for preload scripts hot reload. + process.viteDevServers[name] = server; + + server.httpServer?.once("listening", () => { + const addressInfo = server.httpServer!.address() as AddressInfo; + // Expose env constant for main process use. + process.env[VITE_DEV_SERVER_URL] = `http://localhost:${addressInfo?.port}`; + }); + }, + }; +} + +export function pluginHotRestart(command: "reload" | "restart"): Plugin { + return { + name: "@electron-forge/plugin-vite:hot-restart", + closeBundle() { + if (command === "reload") { + if (process.viteDevServers) { + for (const server of Object.values(process.viteDevServers)) { + // Preload scripts hot reload. + server.ws.send({ type: "full-reload" }); + } + } + } else { + // Main process hot restart. + // https://github.com/electron/forge/blob/v7.2.0/packages/api/core/src/api/start.ts#L216-L223 + process.stdin.emit("data", "rs"); + } + }, + }; +} diff --git a/apps/desktop/vite.main.config.mts b/apps/desktop/vite.main.config.mts new file mode 100644 index 00000000..1fe4f1a1 --- /dev/null +++ b/apps/desktop/vite.main.config.mts @@ -0,0 +1,70 @@ +import type { ConfigEnv, UserConfig } from "vite"; +import { defineConfig, loadEnv, mergeConfig } from "vite"; +import { getBuildConfig, getBuildDefine, external, pluginHotRestart } from "./vite.base.config.mts"; +import tsconfigPaths from "vite-tsconfig-paths"; +import { resolve } from "path"; + +// https://vitejs.dev/config +export default defineConfig((env) => { + const forgeEnv = env as ConfigEnv<"build">; + const { forgeConfigSelf } = forgeEnv; + const define = getBuildDefine(forgeEnv); + const rootPath = resolve(__dirname, "../../"); + const environment = loadEnv(env.mode, rootPath, ""); + + const plugins = [ + pluginHotRestart("restart"), + tsconfigPaths({ + projects: ["./tsconfig.json"], + }), + ]; + + // check if we are in a tag + const tag = process.env.GITHUB_REF?.includes("refs/tags/"); + console.log("tag", tag); + + const config: UserConfig = { + envDir: rootPath, + build: { + sourcemap: true, + rollupOptions: { + input: forgeConfigSelf?.entry || "src/main.ts", + output: { + format: "cjs", + entryFileNames: "[name].js", + chunkFileNames: "[name].js", + assetFileNames: "[name].[ext]", + }, + external: [ + ...external.filter((dep) => { + const isPipelab = dep.startsWith("@pipelab/"); + const isElectronToolkit = dep.startsWith("@electron-toolkit/"); + const isSquirrel = dep === "electron-squirrel-startup"; + const isPosthog = dep === "posthog-node"; + return !isPipelab && !isElectronToolkit && !isSquirrel && !isPosthog; + }), + "bufferutil", + "utf-8-validate", + ], + }, + }, + plugins, + define: { + ...define, + "process.env.POSTHOG_API_KEY": JSON.stringify(environment.POSTHOG_API_KEY), + "process.env.SUPABASE_URL": JSON.stringify(environment.SUPABASE_URL), + "process.env.SUPABASE_ANON_KEY": JSON.stringify(environment.SUPABASE_ANON_KEY), + }, + ssr: { + // Ensure we target Node.js for the main process + target: "node", + }, + resolve: { + // Load the Node.js entry. + mainFields: ["module", "jsnext:main", "jsnext"], + conditions: ["node"], + }, + }; + + return mergeConfig(getBuildConfig(forgeEnv), config); +}); diff --git a/apps/desktop/vite.preload.config.mts b/apps/desktop/vite.preload.config.mts new file mode 100644 index 00000000..7cf77ef7 --- /dev/null +++ b/apps/desktop/vite.preload.config.mts @@ -0,0 +1,37 @@ +import type { ConfigEnv, UserConfig } from "vite"; +import { defineConfig, mergeConfig } from "vite"; +import { getBuildConfig, external, pluginHotRestart } from "./vite.base.config.mts"; +import tsconfigPaths from "vite-tsconfig-paths"; +import { resolve } from "path"; + +// https://vitejs.dev/config +export default defineConfig((env) => { + const forgeEnv = env as ConfigEnv<"build">; + const { forgeConfigSelf } = forgeEnv; + const config: UserConfig = { + build: { + rollupOptions: { + external: external.filter((dep) => !dep.startsWith("@pipelab/")), + // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`. + input: forgeConfigSelf?.entry || "src/preload.ts", + output: { + format: "cjs", + // It should not be split chunks. + inlineDynamicImports: true, + entryFileNames: "[name].cjs", + chunkFileNames: "[name].js", + assetFileNames: "[name].[ext]", + }, + }, + }, + plugins: [ + pluginHotRestart("reload"), + tsconfigPaths({ + projects: ["./tsconfig.json"], + }), + ], + resolve: {}, + }; + + return mergeConfig(getBuildConfig(forgeEnv), config); +}); diff --git a/apps/desktop/vite.renderer.config.mts b/apps/desktop/vite.renderer.config.mts new file mode 100644 index 00000000..0ca6f959 --- /dev/null +++ b/apps/desktop/vite.renderer.config.mts @@ -0,0 +1,33 @@ +import type { ConfigEnv, UserConfig } from "vite"; +import { defineConfig, loadEnv } from "vite"; +import { pluginExposeRenderer } from "./vite.base.config.mts"; +import tsconfigPaths from "vite-tsconfig-paths"; + +export default defineConfig((env) => { + const forgeEnv = env as ConfigEnv<"renderer">; + const { root, mode, forgeConfigSelf } = forgeEnv; + const name = forgeConfigSelf.name ?? ""; + + const plugins = [ + pluginExposeRenderer(name), + tsconfigPaths({ + projects: ["./tsconfig.json"], + }), + ]; + + return { + root, + mode, + base: "./", + build: { + outDir: `.vite/renderer/${name}`, + sourcemap: true, + }, + server: { + port: 5183, + strictPort: true, + }, + plugins, + clearScreen: false, + } as UserConfig; +}); diff --git a/assets/tauri/template/app/.gitignore b/apps/mini-c3-electron/.gitignore similarity index 96% rename from assets/tauri/template/app/.gitignore rename to apps/mini-c3-electron/.gitignore index a19a83aa..a547bf36 100644 --- a/assets/tauri/template/app/.gitignore +++ b/apps/mini-c3-electron/.gitignore @@ -22,4 +22,3 @@ dist-ssr *.njsproj *.sln *.sw? -src/app diff --git a/apps/mini-c3-electron/CHANGELOG.md b/apps/mini-c3-electron/CHANGELOG.md new file mode 100644 index 00000000..02f6353a --- /dev/null +++ b/apps/mini-c3-electron/CHANGELOG.md @@ -0,0 +1,145 @@ +# mini-c3-electron + +## 0.0.1-beta.23 + +### Patch Changes + +- - + +## 0.0.1-beta.22 + +### Patch Changes + +- improve dark theme and improve build history + +## 0.0.1-beta.21 + +### Patch Changes + +- sd + +## 0.0.1-beta.20 + +### Patch Changes + +- sd + +## 0.0.1-beta.19 + +### Patch Changes + +- sd + +## 0.0.1-beta.18 + +### Patch Changes + +- sd + +## 0.0.1-beta.17 + +### Patch Changes + +- sd + +## 0.0.1-beta.16 + +### Patch Changes + +- sdsd + +## 0.0.1-beta.15 + +### Patch Changes + +- sd + +## 0.0.1-beta.14 + +### Patch Changes + +- sd + +## 0.0.1-beta.13 + +### Patch Changes + +- sd + +## 0.0.1-beta.12 + +### Patch Changes + +- sd + +## 0.0.1-beta.11 + +### Patch Changes + +- sd + +## 0.0.1-beta.10 + +### Patch Changes + +- sd + +## 0.0.1-beta.9 + +### Patch Changes + +- sd + +## 0.0.1-beta.8 + +### Patch Changes + +- df + +## 0.0.1-beta.7 + +### Patch Changes + +- sdsd + +## 0.0.1-beta.6 + +### Patch Changes + +- sd + +## 0.0.1-beta.5 + +### Patch Changes + +- sd + +## 0.0.1-beta.4 + +### Patch Changes + +- qs + +## 0.0.1-beta.3 + +### Patch Changes + +- sd + +## 0.0.1-beta.2 + +### Patch Changes + +- s + +## 0.0.1-beta.1 + +### Patch Changes + +- fg + +## 0.0.1-beta.0 + +### Patch Changes + +- changes diff --git a/apps/mini-c3-electron/README.md b/apps/mini-c3-electron/README.md new file mode 100644 index 00000000..ce0035d7 --- /dev/null +++ b/apps/mini-c3-electron/README.md @@ -0,0 +1,29 @@ +# Pipelab - Construct 3 Electron Exporter + +A lightweight, single-page web utility that lets game developers package their HTML5 Construct 3 exports into desktop applications. + +## Overview + +This tool provides a simple interface where users can upload their C3 export ZIP file, name their application, specify a version, and package it into an Electron framework executable. + +- **Frontend**: A custom Vue 3 Single Page Application using glassmorphism, responsive drag-and-drop components, and canvas confetti effects. +- **Backend**: Executes as a serverless Deno-based Supabase Edge Function (`c3-export`). It downloads the correct precompiled Electron base binaries, injects the user's HTML5 game files along with standard entrypoints, renames the executable, and compiles a final ZIP package in-memory. +- **Marketing Nudge**: A built-in feature comparison table designed to encourage developers to migrate to the native Pipelab desktop app for auto-signing, Steam publishing, and full workflow automation. + +## Development + +To run the dev server: + +```bash +pnpm dev +# or from monorepo root: +pnpm --filter mini-c3-electron dev +``` + +To compile/build: + +```bash +pnpm build +# or from monorepo root: +pnpm --filter mini-c3-electron build +``` diff --git a/apps/mini-c3-electron/index.html b/apps/mini-c3-electron/index.html new file mode 100644 index 00000000..a264eda1 --- /dev/null +++ b/apps/mini-c3-electron/index.html @@ -0,0 +1,25 @@ + + + + + + + Pipelab - Construct 3 Electron Exporter + + + + + + + +
+ + + + diff --git a/apps/mini-c3-electron/package.json b/apps/mini-c3-electron/package.json new file mode 100644 index 00000000..60090749 --- /dev/null +++ b/apps/mini-c3-electron/package.json @@ -0,0 +1,24 @@ +{ + "name": "mini-c3-electron", + "private": true, + "version": "0.0.1-beta.23", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "canvas-confetti": "1.9.4", + "vue": "^3.5.34" + }, + "devDependencies": { + "@types/canvas-confetti": "1.9.0", + "@types/node": "^24.12.3", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "typescript": "~6.0.2", + "vite": "^8.0.12", + "vue-tsc": "^3.2.8" + } +} diff --git a/apps/mini-c3-electron/public/favicon.svg b/apps/mini-c3-electron/public/favicon.svg new file mode 100644 index 00000000..6893eb13 --- /dev/null +++ b/apps/mini-c3-electron/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/mini-c3-electron/public/icons.svg b/apps/mini-c3-electron/public/icons.svg new file mode 100644 index 00000000..e9522193 --- /dev/null +++ b/apps/mini-c3-electron/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/mini-c3-electron/src/App.vue b/apps/mini-c3-electron/src/App.vue new file mode 100644 index 00000000..f57c58c7 --- /dev/null +++ b/apps/mini-c3-electron/src/App.vue @@ -0,0 +1,490 @@ + + + + + diff --git a/apps/mini-c3-electron/src/assets/hero.png b/apps/mini-c3-electron/src/assets/hero.png new file mode 100644 index 00000000..02251f4b Binary files /dev/null and b/apps/mini-c3-electron/src/assets/hero.png differ diff --git a/apps/mini-c3-electron/src/assets/vite.svg b/apps/mini-c3-electron/src/assets/vite.svg new file mode 100644 index 00000000..5101b674 --- /dev/null +++ b/apps/mini-c3-electron/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/apps/mini-c3-electron/src/assets/vue.svg b/apps/mini-c3-electron/src/assets/vue.svg new file mode 100644 index 00000000..770e9d33 --- /dev/null +++ b/apps/mini-c3-electron/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/mini-c3-electron/src/main.ts b/apps/mini-c3-electron/src/main.ts new file mode 100644 index 00000000..2425c0f7 --- /dev/null +++ b/apps/mini-c3-electron/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/apps/mini-c3-electron/src/style.css b/apps/mini-c3-electron/src/style.css new file mode 100644 index 00000000..b6cc8b98 --- /dev/null +++ b/apps/mini-c3-electron/src/style.css @@ -0,0 +1,711 @@ +:root { + --bg-primary: #0b0f19; + --bg-card: rgba(17, 24, 39, 0.7); + --border-color: rgba(255, 255, 255, 0.08); + --border-hover: rgba(99, 102, 241, 0.4); + --text-primary: #f3f4f6; + --text-secondary: #9ca3af; + --text-muted: #6b7280; + + --primary: #6366f1; + --primary-glow: rgba(99, 102, 241, 0.15); + --primary-hover: #4f46e5; + --accent: #8b5cf6; + + --success: #10b981; + --success-glow: rgba(16, 185, 129, 0.1); + --danger: #ef4444; + --danger-glow: rgba(239, 68, 68, 0.1); + + --font-sans: 'Inter', system-ui, -apple-system, sans-serif; + --font-heading: 'Outfit', system-ui, -apple-system, sans-serif; + + --shadow-lg: 0 10px 25px -5px rgba(0, 0, 0, 0.3), 0 8px 10px -6px rgba(0, 0, 0, 0.3); + --shadow-glow: 0 0 30px rgba(99, 102, 241, 0.15); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + background-color: var(--bg-primary); + color: var(--text-primary); + font-family: var(--font-sans); + min-height: 100vh; + display: flex; + justify-content: center; + align-items: center; + overflow-x: hidden; + padding: 2rem 1rem; + background-image: + radial-gradient(at 0% 0%, rgba(99, 102, 241, 0.1) 0px, transparent 50%), + radial-gradient(at 100% 100%, rgba(139, 92, 246, 0.1) 0px, transparent 50%); +} + +#app { + width: 100%; + max-width: 640px; + margin: 0 auto; +} + +/* Typography */ +h1, h2, h3, h4 { + font-family: var(--font-heading); + font-weight: 600; + letter-spacing: -0.02em; +} + +/* Glassmorphic Container */ +.glass-container { + background: var(--bg-card); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid var(--border-color); + border-radius: 20px; + padding: 2.5rem; + box-shadow: var(--shadow-lg), var(--shadow-glow); + position: relative; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +/* App Logo & Header */ +.app-header { + text-align: center; + margin-bottom: 2rem; +} + +.logo-container { + display: inline-flex; + align-items: center; + justify-content: center; + width: 64px; + height: 64px; + border-radius: 16px; + background: linear-gradient(135deg, var(--primary), var(--accent)); + box-shadow: 0 0 20px rgba(99, 102, 241, 0.4); + margin-bottom: 1rem; + position: relative; +} + +.logo-container::after { + content: ''; + position: absolute; + inset: -2px; + border-radius: 18px; + background: linear-gradient(135deg, var(--primary), var(--accent)); + z-index: -1; + opacity: 0.5; + filter: blur(8px); +} + +.logo-icon { + width: 36px; + height: 36px; + fill: #fff; +} + +.app-title { + font-size: 2rem; + color: var(--text-primary); + margin-bottom: 0.25rem; +} + +.app-subtitle { + font-size: 0.95rem; + color: var(--text-secondary); +} + +.badge { + display: inline-block; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 0.25rem 0.6rem; + border-radius: 9999px; + background: rgba(99, 102, 241, 0.15); + color: #a5b4fc; + border: 1px solid rgba(99, 102, 241, 0.3); + margin-top: 0.5rem; +} + +/* File Dropzone */ +.dropzone { + border: 2px dashed var(--border-color); + border-radius: 12px; + padding: 2.5rem 1.5rem; + text-align: center; + cursor: pointer; + background: rgba(255, 255, 255, 0.02); + transition: all 0.2s ease; + margin-bottom: 1.5rem; + position: relative; + overflow: hidden; +} + +.dropzone:hover, .dropzone.drag-active { + border-color: var(--primary); + background: rgba(99, 102, 241, 0.04); +} + +.dropzone-icon { + width: 48px; + height: 48px; + stroke: var(--text-secondary); + stroke-width: 1.5; + margin-bottom: 1rem; + transition: transform 0.2s ease, stroke 0.2s ease; +} + +.dropzone:hover .dropzone-icon, .dropzone.drag-active .dropzone-icon { + transform: translateY(-4px); + stroke: #a5b4fc; +} + +.dropzone-text { + font-size: 1rem; + font-weight: 500; + color: var(--text-primary); + margin-bottom: 0.25rem; +} + +.dropzone-hint { + font-size: 0.85rem; + color: var(--text-secondary); +} + +.file-selected-box { + display: flex; + align-items: center; + justify-content: space-between; + background: rgba(99, 102, 241, 0.08); + border: 1px solid rgba(99, 102, 241, 0.25); + border-radius: 8px; + padding: 0.75rem 1rem; + margin-bottom: 1.5rem; +} + +.file-info { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.file-icon { + width: 24px; + height: 24px; + stroke: var(--primary); +} + +.file-name { + font-size: 0.95rem; + font-weight: 500; + color: var(--text-primary); +} + +.file-size { + font-size: 0.8rem; + color: var(--text-secondary); +} + +.remove-file-btn { + background: transparent; + border: none; + color: var(--text-muted); + cursor: pointer; + padding: 0.25rem; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; +} + +.remove-file-btn:hover { + color: var(--danger); + background: rgba(239, 68, 68, 0.1); +} + +/* Forms & Inputs */ +.form-group { + margin-bottom: 1.25rem; +} + +.form-label { + display: block; + font-size: 0.9rem; + font-weight: 500; + color: var(--text-secondary); + margin-bottom: 0.5rem; + text-align: left; +} + +.form-input { + width: 100%; + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 0.75rem 1rem; + font-family: var(--font-sans); + font-size: 0.95rem; + color: var(--text-primary); + transition: all 0.2s; +} + +.form-input:focus { + outline: none; + border-color: var(--primary); + background: rgba(255, 255, 255, 0.05); + box-shadow: 0 0 10px rgba(99, 102, 241, 0.15); +} + +/* Platform Select Tabs */ +.platform-tabs { + display: flex; + gap: 0.75rem; +} + +.platform-tab { + flex: 1; + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 0.75rem; + font-family: var(--font-sans); + font-size: 0.95rem; + font-weight: 500; + color: var(--text-secondary); + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.platform-tab:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.15); +} + +.platform-tab.active { + background: rgba(99, 102, 241, 0.1); + border-color: var(--primary); + color: var(--text-primary); + box-shadow: 0 0 10px rgba(99, 102, 241, 0.1); +} + +.platform-tab svg { + width: 18px; + height: 18px; +} + +/* Buttons */ +.btn-primary { + width: 100%; + background: linear-gradient(135deg, var(--primary), var(--accent)); + color: #fff; + border: none; + border-radius: 10px; + padding: 1rem; + font-family: var(--font-heading); + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); + margin-top: 1.5rem; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.btn-primary:hover:not(:disabled) { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(99, 102, 241, 0.5); + background: linear-gradient(135deg, var(--primary-hover), #7c3aed); +} + +.btn-primary:active:not(:disabled) { + transform: translateY(0); +} + +.btn-primary:disabled { + opacity: 0.5; + cursor: not-allowed; + box-shadow: none; +} + +.btn-secondary { + width: 100%; + background: rgba(255, 255, 255, 0.05); + color: var(--text-primary); + border: 1px solid var(--border-color); + border-radius: 10px; + padding: 0.75rem 1rem; + font-family: var(--font-heading); + font-size: 1rem; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + margin-top: 1rem; +} + +.btn-secondary:hover { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); +} + +/* Loader Layout */ +.loader-layout { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 1.5rem 0; +} + +.loader-title { + font-size: 1.25rem; + margin-bottom: 1.5rem; +} + +/* Custom Circular Spinner */ +.spinner-container { + position: relative; + width: 80px; + height: 80px; + margin-bottom: 2rem; +} + +.spinner-outer { + width: 100%; + height: 100%; + border-radius: 50%; + border: 4px solid rgba(255, 255, 255, 0.03); + border-top-color: var(--primary); + border-right-color: var(--accent); + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.spinner-inner-pct { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-family: var(--font-heading); + font-size: 1.25rem; + font-weight: 700; + color: var(--text-primary); +} + +/* Simulated Steps */ +.progress-container { + width: 100%; + background: rgba(255, 255, 255, 0.03); + border-radius: 9999px; + height: 8px; + overflow: hidden; + margin-bottom: 2rem; + border: 1px solid var(--border-color); +} + +.progress-bar { + height: 100%; + background: linear-gradient(90deg, var(--primary), var(--accent)); + transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 0 8px rgba(99, 102, 241, 0.6); +} + +.steps-list { + width: 100%; + display: flex; + flex-direction: column; + gap: 0.85rem; + text-align: left; +} + +.step-item { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1rem; + background: rgba(255, 255, 255, 0.01); + border: 1px solid transparent; + border-radius: 8px; + transition: all 0.3s ease; +} + +.step-item.active { + background: rgba(99, 102, 241, 0.04); + border-color: rgba(99, 102, 241, 0.15); +} + +.step-item.completed { + opacity: 0.7; +} + +.step-icon-wrapper { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + font-size: 0.8rem; + font-weight: 600; + color: var(--text-secondary); + transition: all 0.3s ease; +} + +.step-item.active .step-icon-wrapper { + background: var(--primary); + border-color: var(--primary); + color: #fff; + box-shadow: 0 0 10px rgba(99, 102, 241, 0.4); +} + +.step-item.completed .step-icon-wrapper { + background: var(--success); + border-color: var(--success); + color: #fff; +} + +.step-label { + font-size: 0.95rem; + color: var(--text-secondary); + font-weight: 500; + transition: color 0.3s ease; +} + +.step-item.active .step-label { + color: var(--text-primary); +} + +.step-item.completed .step-label { + color: var(--text-secondary); + text-decoration: line-through; + text-decoration-color: rgba(255, 255, 255, 0.15); +} + +/* Success Layout */ +.success-layout { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.success-icon-container { + width: 72px; + height: 72px; + border-radius: 50%; + background: var(--success-glow); + border: 2px solid var(--success); + display: flex; + align-items: center; + justify-content: center; + color: var(--success); + margin-bottom: 1.5rem; + animation: scaleIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +@keyframes scaleIn { + from { transform: scale(0); opacity: 0; } + to { transform: scale(1); opacity: 1; } +} + +.success-icon { + width: 36px; + height: 36px; + stroke-width: 2.5; +} + +.success-title { + font-size: 1.75rem; + margin-bottom: 0.5rem; +} + +.success-desc { + font-size: 0.95rem; + color: var(--text-secondary); + margin-bottom: 2rem; + max-width: 480px; +} + +/* Nudge Section */ +.nudge-card { + margin-top: 2.5rem; + padding-top: 2.5rem; + border-top: 1px solid var(--border-color); + text-align: left; + animation: fadeInUp 0.6s ease; +} + +@keyframes fadeInUp { + from { transform: translateY(20px); opacity: 0; } + to { transform: translateY(0); opacity: 1; } +} + +.nudge-title { + font-size: 1.25rem; + margin-bottom: 0.5rem; + color: var(--text-primary); +} + +.nudge-subtitle { + font-size: 0.9rem; + color: var(--text-secondary); + margin-bottom: 1.5rem; +} + +.nudge-features-table { + width: 100%; + border-collapse: collapse; + margin-bottom: 1.5rem; + font-size: 0.85rem; +} + +.nudge-features-table th { + text-align: left; + padding: 0.5rem 0.75rem; + color: var(--text-muted); + font-weight: 500; + border-bottom: 1px solid var(--border-color); +} + +.nudge-features-table td { + padding: 0.75rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); +} + +.nudge-features-table tr:last-child td { + border-bottom: none; +} + +.feature-col { + color: var(--text-primary); + font-weight: 500; +} + +.web-col { + color: var(--text-secondary); +} + +.native-col { + color: #a5b4fc; + font-weight: 600; +} + +.nudge-cta-box { + background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.1)); + border: 1px solid rgba(99, 102, 241, 0.2); + border-radius: 12px; + padding: 1.25rem; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.nudge-cta-text { + font-size: 0.9rem; + line-height: 1.4; + color: var(--text-primary); +} + +.nudge-btn { + background: var(--primary); + color: #fff; + border: none; + border-radius: 8px; + padding: 0.75rem 1.25rem; + font-family: var(--font-heading); + font-weight: 600; + font-size: 0.95rem; + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + text-decoration: none; +} + +.nudge-btn:hover { + background: var(--primary-hover); + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); +} + +/* Error Layout */ +.error-layout { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 1rem 0; +} + +.error-icon-container { + width: 72px; + height: 72px; + border-radius: 50%; + background: var(--danger-glow); + border: 2px solid var(--danger); + display: flex; + align-items: center; + justify-content: center; + color: var(--danger); + margin-bottom: 1.5rem; +} + +.error-icon { + width: 36px; + height: 36px; + stroke-width: 2.5; +} + +.error-title { + font-size: 1.5rem; + margin-bottom: 0.5rem; + color: var(--text-primary); +} + +.error-message { + background: rgba(239, 68, 68, 0.05); + border: 1px solid rgba(239, 68, 68, 0.2); + border-radius: 8px; + padding: 1rem; + color: #fca5a5; + font-family: monospace; + font-size: 0.85rem; + max-width: 100%; + word-break: break-all; + margin-bottom: 1.5rem; + text-align: left; +} + +/* Responsive Overrides */ +@media (max-width: 640px) { + .glass-container { + padding: 1.5rem; + } + + .app-title { + font-size: 1.75rem; + } +} diff --git a/apps/mini-c3-electron/tsconfig.app.json b/apps/mini-c3-electron/tsconfig.app.json new file mode 100644 index 00000000..5c750c5d --- /dev/null +++ b/apps/mini-c3-electron/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/apps/mini-c3-electron/tsconfig.json b/apps/mini-c3-electron/tsconfig.json new file mode 100644 index 00000000..1ffef600 --- /dev/null +++ b/apps/mini-c3-electron/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/apps/mini-c3-electron/tsconfig.node.json b/apps/mini-c3-electron/tsconfig.node.json new file mode 100644 index 00000000..d3c52ea6 --- /dev/null +++ b/apps/mini-c3-electron/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "es2023", + "lib": ["ES2023"], + "module": "esnext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/apps/mini-c3-electron/vite.config.ts b/apps/mini-c3-electron/vite.config.ts new file mode 100644 index 00000000..bbcf80cc --- /dev/null +++ b/apps/mini-c3-electron/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue()], +}) diff --git a/apps/ui/.gitignore b/apps/ui/.gitignore new file mode 100644 index 00000000..e604997a --- /dev/null +++ b/apps/ui/.gitignore @@ -0,0 +1,4 @@ +dist +auto-imports.d.ts +components.d.ts +src/auto-imports.d.ts \ No newline at end of file diff --git a/apps/ui/.oxfmtrc.json b/apps/ui/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/apps/ui/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/apps/ui/CHANGELOG.md b/apps/ui/CHANGELOG.md new file mode 100644 index 00000000..ac7326f2 --- /dev/null +++ b/apps/ui/CHANGELOG.md @@ -0,0 +1,320 @@ +# @pipelab/ui + +## 2.0.0-beta.37 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/constants@1.0.0-beta.33 + - @pipelab/shared@1.0.0-beta.32 + +## 2.0.0-beta.36 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/constants@1.0.0-beta.32 + - @pipelab/shared@1.0.0-beta.31 + +## 2.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.31 + - @pipelab/shared@1.0.0-beta.30 + +## 2.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.30 + - @pipelab/shared@1.0.0-beta.29 + +## 2.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.29 + - @pipelab/shared@1.0.0-beta.28 + +## 2.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.28 + - @pipelab/shared@1.0.0-beta.27 + +## 2.0.0-beta.31 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.27 + - @pipelab/shared@1.0.0-beta.26 + +## 2.0.0-beta.30 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.26 + - @pipelab/shared@1.0.0-beta.25 + +## 2.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.25 + - @pipelab/shared@1.0.0-beta.24 + +## 2.0.0-beta.28 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.24 + - @pipelab/shared@1.0.0-beta.23 + +## 2.0.0-beta.27 + +## 2.0.0-beta.26 + +### Patch Changes + +- fix slashes +- Updated dependencies + - @pipelab/shared@1.0.0-beta.22 + +## 2.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.23 + - @pipelab/shared@1.0.0-beta.21 + +## 2.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.22 + - @pipelab/shared@1.0.0-beta.20 + +## 2.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.21 + - @pipelab/shared@1.0.0-beta.19 + +## 2.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.20 + - @pipelab/shared@1.0.0-beta.18 + +## 2.0.0-beta.21 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.19 + - @pipelab/shared@1.0.0-beta.17 + +## 2.0.0-beta.20 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/constants@1.0.0-beta.18 + - @pipelab/shared@1.0.0-beta.16 + +## 2.0.0-beta.19 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.17 + - @pipelab/shared@1.0.0-beta.15 + +## 2.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.16 + - @pipelab/shared@1.0.0-beta.14 + +## 2.0.0-beta.17 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.15 + - @pipelab/shared@1.0.0-beta.13 + +## 2.0.0-beta.16 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/constants@1.0.0-beta.14 + - @pipelab/shared@1.0.0-beta.12 + +## 2.0.0-beta.15 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.13 + - @pipelab/shared@1.0.0-beta.11 + +## 2.0.0-beta.14 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/constants@1.0.0-beta.12 + - @pipelab/shared@1.0.0-beta.10 + +## 2.0.0-beta.13 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/constants@1.0.0-beta.11 + - @pipelab/shared@1.0.0-beta.9 + +## 2.0.0-beta.12 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/constants@1.0.0-beta.10 + - @pipelab/shared@1.0.0-beta.8 + +## 2.0.0-beta.11 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.9 + - @pipelab/shared@1.0.0-beta.7 + +## 2.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/constants@1.0.0-beta.8 + - @pipelab/shared@1.0.0-beta.6 + +## 2.0.0-beta.9 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.7 + +## 2.0.0-beta.8 + +## 2.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.6 + - @pipelab/shared@1.0.0-beta.5 + +## 2.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/constants@1.0.0-beta.5 + - @pipelab/shared@1.0.0-beta.4 + +## 2.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.4 + - @pipelab/shared@1.0.0-beta.3 + +## 2.0.0-beta.4 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.3 + +## 2.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/constants@1.0.0-beta.2 + - @pipelab/shared@1.0.0-beta.2 + +## 2.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/constants@1.0.0-beta.1 + - @pipelab/shared@1.0.0-beta.1 + +## 2.0.0-beta.1 + +## 2.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/constants@1.0.0-beta.0 + - @pipelab/shared@1.0.0-beta.0 diff --git a/apps/ui/README.md b/apps/ui/README.md new file mode 100644 index 00000000..1d977c6a --- /dev/null +++ b/apps/ui/README.md @@ -0,0 +1,34 @@ +# @pipelab/ui (The Interface) + +The main visual interface for Pipelab, built with Vue 3 and PrimeVue. + +## 🎨 Role & Connectivity + +The UI is a "thin client" designed to visualize and edit automation pipelines. It does not execute logic directly; instead, it orchestrates the `@pipelab/cli` engine. + +### Connection Discovery + +When the UI starts, it attempts to connect to the Pipelab Engine (CLI process): + +1. **Discovery**: It looks for a running engine on the configured port (default: `33753`). +2. **Streaming**: Once connected, it receives real-time execution logs and progress updates via WebSockets. +3. **Authentication**: Syncs its authentication state with the engine's Supabase instance. + +## 🛠️ Development + +### Tech Stack + +- **Framework**: Vue 3 (Composition API) +- **UI Library**: PrimeVue v4 +- **State**: Pinia +- **Icons**: PrimeIcons / Lucide + +### Commands + +```bash +pnpm dev # Starts the Vite development server (port 5173) +pnpm build # Generates the production assets in the /dist folder +``` + +> [!NOTE] +> During development, the UI expects the `@pipelab/cli` to be running separately (via `pnpm dev` at the root). diff --git a/apps/ui/index.html b/apps/ui/index.html new file mode 100644 index 00000000..4a0ca470 --- /dev/null +++ b/apps/ui/index.html @@ -0,0 +1,34 @@ + + + + + + + Pipelab UI + + + + + + +
+ + + diff --git a/apps/ui/package.json b/apps/ui/package.json new file mode 100644 index 00000000..773753eb --- /dev/null +++ b/apps/ui/package.json @@ -0,0 +1,97 @@ +{ + "name": "@pipelab/ui", + "version": "2.0.0-beta.37", + "private": true, + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "apps/ui" + }, + "type": "module", + "main": "src/main.ts", + "scripts": { + "dev": "vite", + "build": "vite build", + "typecheck": "vue-tsc --noEmit -p tsconfig.json --composite false", + "preview": "vite preview", + "format": "oxfmt .", + "lint": "oxlint .", + "test": "vitest run" + }, + "dependencies": { + "@codemirror/autocomplete": "6.18.1", + "@codemirror/commands": "6.6.2", + "@codemirror/lang-javascript": "6.2.2", + "@codemirror/lang-liquid": "6.2.1", + "@codemirror/lint": "6.8.2", + "@codemirror/state": "6.4.1", + "@codemirror/view": "6.34.0", + "@floating-ui/vue": "1.1.5", + "@jitl/quickjs-wasmfile-release-sync": "0.31.0", + "@mdi/font": "7.4.47", + "@pipelab/constants": "workspace:*", + "@pipelab/shared": "workspace:*", + "@polar-sh/sdk": "0.47.1", + "@primevue/themes": "4.1.1", + "@trpc/client": "10.45.2", + "@vee-validate/valibot": "4.13.2", + "@vuelidate/core": "2.0.3", + "@vuelidate/validators": "2.0.4", + "@vueuse/components": "11.1.0", + "@vueuse/core": "11.1.0", + "@vueuse/router": "11.1.0", + "change-case": "5.4.4", + "date-fns": "4.1.0", + "dompurify": "3.1.7", + "driver.js": "1.4.0", + "es-toolkit": "1.25.2", + "fancy-ansi": "0.1.3", + "geist": "1.3.1", + "get-value": "3.0.1", + "klona": "2.0.6", + "mutative": "1.0.11", + "nanoid": "5.0.7", + "path-browserify": "1.0.1", + "pinia": "2.2.4", + "pinia-plugin-persistedstate": "4.1.1", + "polished": "4.3.1", + "posthog-js": "1.215.0", + "primeflex": "4.0.0", + "primeicons": "7.0.0", + "primevue": "4.5.4", + "quickjs-emscripten": "0.31.0", + "quickjs-emscripten-sync": "1.6.0", + "semver": "7.8.1", + "set-value": "4.1.0", + "slash": "3.0.0", + "string-strip-html": "13.4.8", + "thememirror": "2.0.1", + "tinykeys": "2.1.0", + "ts-pattern": "5.5.0", + "tslog": "4.9.3", + "type-fest": "4.26.1", + "valibot": "0.42.1", + "vee-validate": "4.14.4", + "vue": "3.5.13", + "vue-dompurify-html": "5.1.0", + "vue-i18n": "10", + "vue-router": "4.4.5" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "@primevue/auto-import-resolver": "4.1.1", + "@types/node": "24.12.2", + "@types/semver": "7.7.1", + "@vitejs/devtools": "0.1.13", + "@vitejs/plugin-vue": "6.0.5", + "sass-embedded": "^1.83.4", + "typescript": "5.8.3", + "unplugin-auto-import": "0.18.3", + "unplugin-vue-components": "0.27.4", + "vite": "8.0.8", + "vite-plugin-vue-devtools": "8.1.1", + "vitest": "3.1.4", + "vue-tsc": "2.1.6" + } +} diff --git a/apps/ui/public/_redirects b/apps/ui/public/_redirects new file mode 100644 index 00000000..7797f7c6 --- /dev/null +++ b/apps/ui/public/_redirects @@ -0,0 +1 @@ +/* /index.html 200 diff --git a/apps/ui/public/icon.png b/apps/ui/public/icon.png new file mode 100644 index 00000000..ac95e195 Binary files /dev/null and b/apps/ui/public/icon.png differ diff --git a/apps/ui/src/App.vue b/apps/ui/src/App.vue new file mode 100644 index 00000000..0e6a3b51 --- /dev/null +++ b/apps/ui/src/App.vue @@ -0,0 +1,295 @@ + + + + + diff --git a/src/renderer/Root.vue b/apps/ui/src/Root.vue similarity index 78% rename from src/renderer/Root.vue rename to apps/ui/src/Root.vue index 014536e6..b0b1d134 100644 --- a/src/renderer/Root.vue +++ b/apps/ui/src/Root.vue @@ -3,7 +3,7 @@ diff --git a/src/renderer/agent/log.ts b/apps/ui/src/agent/log.ts similarity index 100% rename from src/renderer/agent/log.ts rename to apps/ui/src/agent/log.ts diff --git a/src/renderer/agent/trpc.ts b/apps/ui/src/agent/trpc.ts similarity index 74% rename from src/renderer/agent/trpc.ts rename to apps/ui/src/agent/trpc.ts index 9ba7243a..56fa3b0f 100644 --- a/src/renderer/agent/trpc.ts +++ b/apps/ui/src/agent/trpc.ts @@ -1,4 +1,4 @@ -import { initTRPC } from '@trpc/server'; +import { initTRPC } from "@trpc/server"; /** * Initialization of tRPC backend @@ -11,4 +11,4 @@ const t = initTRPC.create(); * that can be used throughout the router */ export const router = t.router; -export const publicProcedure = t.procedure; \ No newline at end of file +export const publicProcedure = t.procedure; diff --git a/apps/ui/src/agent/utils/json.ts b/apps/ui/src/agent/utils/json.ts new file mode 100644 index 00000000..85a02202 --- /dev/null +++ b/apps/ui/src/agent/utils/json.ts @@ -0,0 +1,7 @@ +export const safeParse = (str: string): T | undefined => { + try { + return JSON.parse(str); + } catch (e) { + return undefined; + } +}; diff --git a/src/renderer/assets/css/styles.less b/apps/ui/src/assets/css/styles.less similarity index 94% rename from src/renderer/assets/css/styles.less rename to apps/ui/src/assets/css/styles.less index 2cf09d25..3a08b314 100644 --- a/src/renderer/assets/css/styles.less +++ b/apps/ui/src/assets/css/styles.less @@ -5,12 +5,12 @@ body { Roboto, -apple-system, BlinkMacSystemFont, - 'Helvetica Neue', - 'Segoe UI', - 'Oxygen', - 'Ubuntu', - 'Cantarell', - 'Open Sans', + "Helvetica Neue", + "Segoe UI", + "Oxygen", + "Ubuntu", + "Cantarell", + "Open Sans", sans-serif; color: #86a5b1; background-color: #2f3241; @@ -67,7 +67,7 @@ a:hover { float: none; clear: both; overflow: hidden; - font-family: 'Menlo', 'Lucida Console', monospace; + font-family: "Menlo", "Lucida Console", monospace; color: #c2f5ff; line-height: 1; transition: all 0.3s; diff --git a/src/renderer/assets/icons.svg b/apps/ui/src/assets/icons.svg similarity index 100% rename from src/renderer/assets/icons.svg rename to apps/ui/src/assets/icons.svg diff --git a/apps/ui/src/components/AddNodeButton.model.ts b/apps/ui/src/components/AddNodeButton.model.ts new file mode 100644 index 00000000..ab6b43ac --- /dev/null +++ b/apps/ui/src/components/AddNodeButton.model.ts @@ -0,0 +1,15 @@ +import { PipelabNode, Event, RendererPluginDefinition } from "@pipelab/shared"; + +export interface AddNodeEvent { + node: PipelabNode; + plugin: RendererPluginDefinition; + path: string[]; + insertAt: number; +} + +export interface AddTriggerEvent { + trigger: Event; + plugin: RendererPluginDefinition; + path: string[]; + insertAt: number; +} diff --git a/apps/ui/src/components/AddNodeButton.vue b/apps/ui/src/components/AddNodeButton.vue new file mode 100644 index 00000000..a0a895e7 --- /dev/null +++ b/apps/ui/src/components/AddNodeButton.vue @@ -0,0 +1,848 @@ + + + + + diff --git a/src/renderer/components/AddTriggerButton.vue b/apps/ui/src/components/AddTriggerButton.vue similarity index 71% rename from src/renderer/components/AddTriggerButton.vue rename to apps/ui/src/components/AddTriggerButton.vue index 5aefb5b8..a7023d54 100644 --- a/src/renderer/components/AddTriggerButton.vue +++ b/apps/ui/src/components/AddTriggerButton.vue @@ -49,10 +49,10 @@ > @@ -90,134 +90,135 @@ diff --git a/apps/ui/src/components/AuthDialog.vue b/apps/ui/src/components/AuthDialog.vue new file mode 100644 index 00000000..49bba31c --- /dev/null +++ b/apps/ui/src/components/AuthDialog.vue @@ -0,0 +1,855 @@ + + + + + diff --git a/apps/ui/src/components/BuildDetails.vue b/apps/ui/src/components/BuildDetails.vue new file mode 100644 index 00000000..1ec88477 --- /dev/null +++ b/apps/ui/src/components/BuildDetails.vue @@ -0,0 +1,523 @@ + + + + + diff --git a/src/renderer/components/BuildHistoryDialog.vue b/apps/ui/src/components/BuildHistoryDialog.vue similarity index 50% rename from src/renderer/components/BuildHistoryDialog.vue rename to apps/ui/src/components/BuildHistoryDialog.vue index 0c49a876..dec5e23a 100644 --- a/src/renderer/components/BuildHistoryDialog.vue +++ b/apps/ui/src/components/BuildHistoryDialog.vue @@ -14,8 +14,16 @@

Loading build history...

- -
+ +
+
+
+

Preview Mode

+

Upgrade to Premium for full execution steps, detailed logs, and advanced analytics.

+
+
+
- -
-
- -
-

Premium Feature

-

Build history tracking is available with a premium subscription.

-
-
-
- - - - - + diff --git a/src/renderer/components/BuildHistoryList.vue b/apps/ui/src/components/BuildHistoryList.vue similarity index 64% rename from src/renderer/components/BuildHistoryList.vue rename to apps/ui/src/components/BuildHistoryList.vue index d9e1ef35..5977fd08 100644 --- a/src/renderer/components/BuildHistoryList.vue +++ b/apps/ui/src/components/BuildHistoryList.vue @@ -39,52 +39,17 @@ Showing {{ entries.length }} of {{ totalCount }} entries -
-
- - -
-
-
- - -
- -
@@ -101,7 +66,6 @@ :expandable="true" :show-actions="true" :can-delete="canDelete" - @view-details="onViewDetails" @delete="onDeleteEntry" @toggle="onEntryToggle" /> @@ -117,7 +81,6 @@ :expandable="false" :show-actions="true" :can-delete="canDelete" - @view-details="onViewDetails" @delete="onDeleteEntry" /> @@ -129,29 +92,31 @@ diff --git a/src/renderer/components/DevBenefitsOverride.vue b/apps/ui/src/components/DevBenefitsOverride.vue similarity index 77% rename from src/renderer/components/DevBenefitsOverride.vue rename to apps/ui/src/components/DevBenefitsOverride.vue index c6404382..c199c557 100644 --- a/src/renderer/components/DevBenefitsOverride.vue +++ b/apps/ui/src/components/DevBenefitsOverride.vue @@ -25,10 +25,10 @@
- Actual: {{ actualStatus[benefit.key] ? 'Active' : 'Inactive' }} + Actual: {{ actualStatus[benefit.key] ? "Active" : "Inactive" }} - Effective: {{ effectiveStatus[benefit.key] ? 'Active' : 'Inactive' }} + Effective: {{ effectiveStatus[benefit.key] ? "Active" : "Inactive" }}
@@ -38,40 +38,40 @@ diff --git a/apps/ui/src/components/FileInput.vue b/apps/ui/src/components/FileInput.vue new file mode 100644 index 00000000..90b12d22 --- /dev/null +++ b/apps/ui/src/components/FileInput.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/apps/ui/src/components/Layout.vue b/apps/ui/src/components/Layout.vue new file mode 100644 index 00000000..d40ea691 --- /dev/null +++ b/apps/ui/src/components/Layout.vue @@ -0,0 +1,918 @@ + + + + + diff --git a/apps/ui/src/components/MigrationModal.vue b/apps/ui/src/components/MigrationModal.vue new file mode 100644 index 00000000..2140b30c --- /dev/null +++ b/apps/ui/src/components/MigrationModal.vue @@ -0,0 +1,636 @@ + + + + + diff --git a/src/renderer/components/ScenarioListItem.vue b/apps/ui/src/components/ScenarioListItem.vue similarity index 60% rename from src/renderer/components/ScenarioListItem.vue rename to apps/ui/src/components/ScenarioListItem.vue index 0b7d82e4..a3439bd4 100644 --- a/src/renderer/components/ScenarioListItem.vue +++ b/apps/ui/src/components/ScenarioListItem.vue @@ -4,84 +4,84 @@ diff --git a/src/renderer/components/ScenarioListItemRecent.vue b/apps/ui/src/components/ScenarioListItemRecent.vue similarity index 67% rename from src/renderer/components/ScenarioListItemRecent.vue rename to apps/ui/src/components/ScenarioListItemRecent.vue index 63cf2afb..e2ef7cb1 100644 --- a/src/renderer/components/ScenarioListItemRecent.vue +++ b/apps/ui/src/components/ScenarioListItemRecent.vue @@ -1,5 +1,5 @@ diff --git a/apps/ui/src/components/Settings.vue b/apps/ui/src/components/Settings.vue new file mode 100644 index 00000000..3466f933 --- /dev/null +++ b/apps/ui/src/components/Settings.vue @@ -0,0 +1,1744 @@ + + + + + diff --git a/src/renderer/components/SubscriptionLoadingIndicator.vue b/apps/ui/src/components/SubscriptionLoadingIndicator.vue similarity index 87% rename from src/renderer/components/SubscriptionLoadingIndicator.vue rename to apps/ui/src/components/SubscriptionLoadingIndicator.vue index b36e5959..c8c3d28e 100644 --- a/src/renderer/components/SubscriptionLoadingIndicator.vue +++ b/apps/ui/src/components/SubscriptionLoadingIndicator.vue @@ -7,16 +7,16 @@ \ No newline at end of file + diff --git a/src/renderer/components/UpgradeDialog.vue b/apps/ui/src/components/UpgradeDialog.vue similarity index 72% rename from src/renderer/components/UpgradeDialog.vue rename to apps/ui/src/components/UpgradeDialog.vue index 3c464235..1066e68c 100644 --- a/src/renderer/components/UpgradeDialog.vue +++ b/apps/ui/src/components/UpgradeDialog.vue @@ -29,9 +29,9 @@

{{ plan.name }}

Free - + {{ price.priceAmount / 100 }} {{ price.priceCurrency }} / - {{ price.recurringInterval }} + {{ plan.recurringInterval }}
@@ -58,115 +58,130 @@ diff --git a/src/renderer/components/__tests__/HelloWorld.spec.ts b/apps/ui/src/components/__tests__/HelloWorld.spec.ts similarity index 54% rename from src/renderer/components/__tests__/HelloWorld.spec.ts rename to apps/ui/src/components/__tests__/HelloWorld.spec.ts index cb81e4f2..79442e4e 100644 --- a/src/renderer/components/__tests__/HelloWorld.spec.ts +++ b/apps/ui/src/components/__tests__/HelloWorld.spec.ts @@ -1,8 +1,8 @@ -import { describe, it } from 'vitest' +import { describe, it } from "vitest"; -describe('HelloWorld', () => { - it('renders properly', () => { +describe("HelloWorld", () => { + it("renders properly", () => { // const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } }) // expect(wrapper.text()).toContain('Hello Vitest') - }) -}) + }); +}); diff --git a/src/renderer/components/nodes/EditorNodeAction.vue b/apps/ui/src/components/nodes/EditorNodeAction.vue similarity index 70% rename from src/renderer/components/nodes/EditorNodeAction.vue rename to apps/ui/src/components/nodes/EditorNodeAction.vue index 09edef4c..1c158b18 100644 --- a/src/renderer/components/nodes/EditorNodeAction.vue +++ b/apps/ui/src/components/nodes/EditorNodeAction.vue @@ -7,7 +7,7 @@ active: activeNode?.uid === value.uid, error: hasErrors, disabled: value.disabled || isRunning, - selected: isNodeSelected + selected: isNodeSelected, }" @click="onNodeClick" > @@ -23,7 +23,9 @@
{{ title }}
-
{{ nodeDefinition.name }}
+
+ {{ nodeDefinition.name }} +
@@ -113,124 +115,125 @@ + diff --git a/src/renderer/components/nodes/PluginIcon.vue b/apps/ui/src/components/nodes/PluginIcon.vue similarity index 65% rename from src/renderer/components/nodes/PluginIcon.vue rename to apps/ui/src/components/nodes/PluginIcon.vue index f7f6823a..31ba1858 100644 --- a/src/renderer/components/nodes/PluginIcon.vue +++ b/apps/ui/src/components/nodes/PluginIcon.vue @@ -4,30 +4,35 @@ diff --git a/apps/ui/src/composables/api.ts b/apps/ui/src/composables/api.ts new file mode 100644 index 00000000..ed8cd045 --- /dev/null +++ b/apps/ui/src/composables/api.ts @@ -0,0 +1,196 @@ +import { Channels, Data, End, Events, ShellChannels } from "@pipelab/shared"; +import { useLogger } from "@pipelab/shared"; +import { useWebSocketAPI } from "./websocket-client"; +import { WebSocketListener } from "@pipelab/shared"; +import { useUIStore } from "../store/ui"; + +// Re-export for backwards compatibility +export type { WebSocketListener }; + +export const useAPI = () => { + const { logger } = useLogger(); + const { execute: wsExecute, isConnected, on: wsOn } = useWebSocketAPI(); + const uiStore = useUIStore(); + + /** + * Send an order and wait for its execution + */ + const execute = async ( + channel: KEY, + data?: Data, + listener?: WebSocketListener, + ): Promise> => { + // If it's a shell channel and we are in Electron, use IPC + if (ShellChannels.includes(channel)) { + if (window.electron) { + logger().debug("Routing to Electron IPC:", channel); + try { + const result = await window.electron.ipcRenderer.invoke(channel, data); + return { + type: "success", + result, + } as any; + } catch (error: any) { + logger().error("Shell channel IPC invoke error:", error); + return { + type: "error", + ipcError: error.message, + } as any; + } + } else { + // Fallback for headless mode + if (channel === "dialog:showOpenDialog") { + logger().debug("Falling back to web file picker (open):", data); + const result = await uiStore.showFilePicker({ + ...(data as any), + mode: "open", + }); + return { + type: "success", + result, + } as any; + } else if (channel === "dialog:showSaveDialog") { + logger().debug("Falling back to web file picker (save):", data); + const result = await uiStore.showFilePicker({ + ...(data as any), + mode: "save", + }); + return { + type: "success", + result, + } as any; + } + } + } + + try { + if (channel === "graph:execute" && !window.electron && !isConnected()) { + logger().info("Routing graph:execute to Cloud Orchestrator"); + return (await runInCloud(data as any, listener as any)) as any; + } + + const result = await wsExecute(channel, data, listener); + + return result; + } catch (error) { + logger().error("API execution error:", error); + throw error; + } + }; + + /** + * Transparently run a pipeline in the cloud via Supabase Edge Functions + */ + const runInCloud = async (data: any, listener?: WebSocketListener<"graph:execute">) => { + const { supabase: getSupabase } = await import("@pipelab/shared"); + const supabase = getSupabase(); + if (!supabase) throw new Error("Supabase is not available for cloud execution"); + + // 1. Invoke the Edge Function + const { data: runData, error: functionError } = await supabase.functions.invoke("cloud-run", { + body: { + pipeline: data.graph, + options: { + os: "windows", // Default to windows for now as per requirements + }, + }, + }); + + if (functionError) throw functionError; + const { runId } = runData; + + return new Promise((resolve, reject) => { + // 2. Subscribe to logs via Supabase Realtime + const channel = supabase + .channel(`cloud-logs-${runId}`) + .on( + "postgres_changes", + { + event: "INSERT", + schema: "public", + table: "cloud_run_logs", + filter: `run_id=eq.${runId}`, + }, + (payload) => { + const log = payload.new; + if (log.type === "node-enter") { + listener?.({ + type: "node-enter", + data: { nodeUid: log.node_uid, nodeName: log.node_name || "" }, + }); + } else if (log.type === "node-exit") { + listener?.({ + type: "node-exit", + data: { nodeUid: log.node_uid, nodeName: log.node_name || "" }, + }); + } else if (log.type === "log") { + listener?.({ + type: "node-log", + data: { + nodeUid: log.node_uid, + logData: { + message: [log.message], + timestamp: new Date(log.created_at).getTime(), + }, + }, + }); + } + }, + ) + .subscribe(); + + // 3. Monitor run status + const statusSubscription = supabase + .channel(`cloud-status-${runId}`) + .on( + "postgres_changes", + { + event: "UPDATE", + schema: "public", + table: "cloud_runs", + filter: `id=eq.${runId}`, + }, + (payload) => { + const run = payload.new; + if (run.status === "success") { + statusSubscription.unsubscribe(); + channel.unsubscribe(); + resolve({ type: "success", result: {} }); + } else if (run.status === "failed") { + statusSubscription.unsubscribe(); + channel.unsubscribe(); + resolve({ type: "error", code: "error", ipcError: "Cloud execution failed" }); + } + }, + ) + .subscribe(); + }); + }; + + /** + * Send an order (for backwards compatibility) + */ + const send = (channel: KEY, data?: Data) => { + logger().warn("useAPI.send() is deprecated. Use useAPI.execute() instead."); + return execute(channel, data); + }; + + /** + * On method (placeholder for backwards compatibility) + */ + const on = ( + channel: KEY | string, + listener: (data: Events) => void, + ) => { + return wsOn(channel, listener); + }; + + return { + send, + on, + execute, + isConnected, + }; +}; + +export type UseAPI = ReturnType; diff --git a/src/renderer/composables/handlers.ts b/apps/ui/src/composables/handlers.ts similarity index 52% rename from src/renderer/composables/handlers.ts rename to apps/ui/src/composables/handlers.ts index 3c906a98..7a248b45 100644 --- a/src/renderer/composables/handlers.ts +++ b/apps/ui/src/composables/handlers.ts @@ -1,26 +1,35 @@ // renderer handler -import { useLogger } from "@@/logger"; -import { RendererChannels, RendererEvents, RendererData, RendererMessage } from "@main/api"; +import { useLogger } from "@pipelab/shared"; +import { RendererChannels, RendererEvents, RendererData, RendererMessage } from "@pipelab/shared"; -export type HandleListenerRendererSendFn = (events: RendererEvents) => void +export type HandleListenerRendererSendFn = ( + events: RendererEvents, +) => void; export type HandleListenerRenderer = ( event: Electron.IpcRendererEvent, - data: { value: RendererData; send: HandleListenerRendererSendFn } -) => Promise + data: { value: RendererData; send: HandleListenerRendererSendFn }, +) => Promise; -export const handle = (channel: KEY, listener: HandleListenerRenderer) => { +export const handle = ( + channel: KEY, + listener: HandleListenerRenderer, +) => { + if (!window.electron) { + console.warn(`[Handlers] Electron not available, skipping handler for channel: ${channel}`); + return () => {}; + } return window.electron.ipcRenderer.on(channel, (event, message: RendererMessage) => { - const { data, requestId } = message + const { data, requestId } = message; const send: HandleListenerRendererSendFn = (events) => { - return window.electron.ipcRenderer.send(requestId, events) - } + return window.electron.ipcRenderer.send(requestId, events); + }; return listener(event, { send, - value: data - }) - }) -} + value: data, + }); + }); +}; diff --git a/src/renderer/composables/middleware.ts b/apps/ui/src/composables/middleware.ts similarity index 60% rename from src/renderer/composables/middleware.ts rename to apps/ui/src/composables/middleware.ts index c0bf5fd2..01bbb641 100644 --- a/src/renderer/composables/middleware.ts +++ b/apps/ui/src/composables/middleware.ts @@ -1,41 +1,41 @@ -import type { Awaitable } from '@vueuse/core' -import { nanoid } from 'nanoid' -import type { Ref } from 'vue' -import { ref } from 'vue' +import type { Awaitable } from "@vueuse/core"; +import { nanoid } from "nanoid"; +import type { Ref } from "vue"; +import { ref } from "vue"; export const useMiddleware = Awaitable>() => { type Handler = { - id: string - fn: HANDLER - } + id: string; + fn: HANDLER; + }; - const handlers = ref([]) as unknown as Ref + const handlers = ref([]) as unknown as Ref; const handlerFn = async (...args: Parameters) => { for (const handler of handlers.value) { - await handler.fn(...args) + await handler.fn(...args); } - } + }; const cancel = (id: string) => { - handlers.value = handlers.value.filter(h => h.id !== id) - } + handlers.value = handlers.value.filter((h) => h.id !== id); + }; const use = (callback: HANDLER) => { - const id = nanoid() + const id = nanoid(); handlers.value.push({ id, fn: callback, - }) + }); return { cancel: () => cancel(id), - } - } + }; + }; return { handler: handlerFn, use, - } -} + }; +}; diff --git a/apps/ui/src/composables/use-shell.ts b/apps/ui/src/composables/use-shell.ts new file mode 100644 index 00000000..eac45a10 --- /dev/null +++ b/apps/ui/src/composables/use-shell.ts @@ -0,0 +1,147 @@ +import { useUIStore } from "../store/ui"; +import { useAPI } from "./api"; + +/** + * Composable for interacting with the shell (Electron or Web fallback) + */ +export const useShell = () => { + const { execute } = useAPI(); + const uiStore = useUIStore(); + + /** + * Open a file dialog + */ + const openFile = async (options: any = {}) => { + if ((window as any).electron) { + try { + // De-proxy reactive objects for Electron IPC + const plainOptions = JSON.parse(JSON.stringify(options)); + + const result = await (window as any).pipelab.showOpenDialog({ + ...plainOptions, + properties: ["openFile", ...(plainOptions.properties || [])], + }); + return { type: "success", result }; + } catch (e: any) { + return { + type: "error", + ipcError: e.message, + }; + } + } + + const result = await uiStore.showFilePicker({ + ...options, + mode: "open", + }); + return { + type: "success", + result, + }; + }; + + /** + * Open a directory dialog + */ + const openDirectory = async (options: any = {}) => { + if ((window as any).electron) { + try { + const plainOptions = JSON.parse(JSON.stringify(options)); + const result = await (window as any).pipelab.showOpenDialog({ + ...plainOptions, + properties: ["openDirectory", ...(plainOptions.properties || [])], + }); + return { + type: "success", + result, + }; + } catch (e: any) { + return { + type: "error", + ipcError: e.message, + }; + } + } + + const result = await uiStore.showFilePicker({ + ...options, + mode: "open", + }); + return { + type: "success", + result, + }; + }; + + /** + * Open a save file dialog + */ + const saveFile = async (options: any = {}) => { + if ((window as any).electron) { + try { + const result = await (window as any).pipelab.showSaveDialog( + JSON.parse(JSON.stringify(options)), + ); + return { + type: "success", + result, + }; + } catch (e: any) { + return { + type: "error", + ipcError: e.message, + }; + } + } + + const result = await uiStore.showFilePicker({ + ...options, + mode: "save", + }); + return { + type: "success", + result, + }; + }; + + /** + * Open an external URL + */ + const openExternal = async (url: string) => { + if ((window as any).electron) { + return await (window as any).pipelab.openExternal(url); + } + window.open(url, "_blank"); + }; + + /** + * Show a file in the system file explorer + */ + const showItemInFolder = (path: string) => { + if ((window as any).electron) { + return (window as any).pipelab.showItemInFolder(path); + } + console.warn("showItemInFolder not supported on web"); + }; + + /** + * Relaunch the application + */ + const relaunch = async () => { + if ((window as any).electron) { + await (window as any).pipelab.relaunch(); + } else { + console.warn("relaunch not supported on web, reloading page..."); + window.location.reload(); + } + }; + + return { + openFile, + openDirectory, + saveFile, + openExternal, + showItemInFolder, + relaunch, + }; +}; diff --git a/apps/ui/src/composables/useConfig.ts b/apps/ui/src/composables/useConfig.ts new file mode 100644 index 00000000..4864d0af --- /dev/null +++ b/apps/ui/src/composables/useConfig.ts @@ -0,0 +1,130 @@ +import { ref, readonly } from "vue"; +import { useAPI } from "./api"; +import { + AppConfig, + ConnectionsConfig, + FileRepo, + defaultAppSettings, + defaultConnections, + defaultFileRepo, +} from "@pipelab/shared"; + +const isElectron = typeof window !== "undefined" && !!window.electron; + +function createConfigComposable( + loadChannel: "settings:load" | "connections:load" | "projects:load", + saveChannel: "settings:save" | "connections:save" | "projects:save", + resetChannel: "settings:reset" | "connections:reset" | "projects:reset", + defaultValue: T, +) { + const api = useAPI(); + const data = ref(defaultValue); + const loading = ref(false); + let loadedPromise: Promise | null = null; + + const load = async (force = false): Promise => { + if (loadedPromise && !force) { + return loadedPromise; + } + + loadedPromise = (async () => { + console.log(`[useConfig] load "${loadChannel}": isElectron =`, isElectron); + if (!isElectron) { + return; + } + + if (!api.isConnected()) { + console.warn(`[useConfig] API not connected for loading "${loadChannel}"`); + loadedPromise = null; + return; + } + + loading.value = true; + try { + const result = await api.execute(loadChannel as any); + if (result.type === "success") { + const loadedValue: T = result.result; + data.value = loadedValue; + } else { + console.error(`[useConfig] failed to load "${loadChannel}":`, result.ipcError); + } + } catch (err) { + console.error(`[useConfig] error loading "${loadChannel}":`, err); + } finally { + loading.value = false; + } + })(); + + return loadedPromise; + }; + + const save = async (newValue: T): Promise => { + data.value = newValue; + if (isElectron && api.isConnected()) { + try { + const result = await api.execute(saveChannel as any, { data: newValue }); + if (result.type === "error") { + console.error(`[useConfig] failed to save "${saveChannel}":`, result.ipcError); + } + } catch (err) { + console.error(`[useConfig] error saving "${saveChannel}":`, err); + } + } + }; + + const reset = async (key: keyof T): Promise => { + if (isElectron && api.isConnected()) { + try { + const result = await api.execute(resetChannel as any, { key: String(key) }); + if (result.type === "success") { + await load(true); + } else { + console.error( + `[useConfig] failed to reset key "${String(key)}" of "${resetChannel}":`, + result.ipcError, + ); + } + } catch (err) { + console.error( + `[useConfig] error resetting key "${String(key)}" of "${resetChannel}":`, + err, + ); + } + } + }; + + return { + data, + loading: readonly(loading), + load, + save, + reset, + }; +} + +export const useSettingsConfig = () => { + return createConfigComposable( + "settings:load", + "settings:save", + "settings:reset", + defaultAppSettings, + ); +}; + +export const useConnectionsConfig = () => { + return createConfigComposable( + "connections:load", + "connections:save", + "connections:reset", + defaultConnections, + ); +}; + +export const useProjectsConfig = () => { + return createConfigComposable( + "projects:load", + "projects:save", + "projects:reset", + defaultFileRepo, + ); +}; diff --git a/apps/ui/src/composables/usePipeline.ts b/apps/ui/src/composables/usePipeline.ts new file mode 100644 index 00000000..e2c253a8 --- /dev/null +++ b/apps/ui/src/composables/usePipeline.ts @@ -0,0 +1,60 @@ +import { EnhancedFile, SavedFile } from "@pipelab/shared"; +import { AppStore, useAppStore } from "@renderer/store/app"; + +export function isDefaultPipeline( + pipeline: EnhancedFile, +): pipeline is EnhancedFile { + return !(pipeline.content as any).type || (pipeline.content as any).type === "default"; +} + +export const usePipeline = () => { + const appStore = useAppStore(); + const { getPluginDefinition } = appStore; + + const context: Context = { + getPluginDefinition, + }; + + function createPipeline(pipeline: EnhancedFile) { + return useDefaultPipeline(pipeline, context); + } + + return { + createPipeline, + }; +}; + +interface UsePipeline { + getIcons: () => any[]; +} + +interface Context { + getPluginDefinition: AppStore["getPluginDefinition"]; +} + +export const useDefaultPipeline = ( + pipeline: EnhancedFile, + context: Context, +): UsePipeline => { + const getIcons = () => { + const icons: any[] = []; + if (!pipeline?.content?.canvas?.blocks) return icons; + const blocks = pipeline.content.canvas.blocks; + for (const node of blocks) { + const def = context.getPluginDefinition(node.origin.pluginId); + if (def && def.icon) { + icons.push({ origin: node.origin, ...def.icon }); + } + } + if (icons.length > 4) { + return icons + .slice(0, 3) + .concat({ type: "icon", icon: "mdi-plus", origin: { nodeId: "0", pluginId: "0" } }); + } + return icons; + }; + + return { + getIcons, + }; +}; diff --git a/apps/ui/src/composables/usePostHog.ts b/apps/ui/src/composables/usePostHog.ts new file mode 100644 index 00000000..0f6e5323 --- /dev/null +++ b/apps/ui/src/composables/usePostHog.ts @@ -0,0 +1,9 @@ +import posthog from "posthog-js"; + +export function usePostHog() { + posthog.init(process.env.POSTHOG_API_KEY as string, { + api_host: "https://eu.i.posthog.com", + }); + + return { posthog }; +} diff --git a/apps/ui/src/composables/useTour.ts b/apps/ui/src/composables/useTour.ts new file mode 100644 index 00000000..a5858bb1 --- /dev/null +++ b/apps/ui/src/composables/useTour.ts @@ -0,0 +1,36 @@ +import { driver, DriveStep } from "driver.js"; +import { useAppSettings } from "@renderer/store/settings"; +import { storeToRefs } from "pinia"; + +export function useTour(tourId: "dashboard" | "editor") { + const settingsStore = useAppSettings(); + const { settings } = storeToRefs(settingsStore); + const { updateSettings } = settingsStore; + + const startTour = (tourSteps: DriveStep[], force = false) => { + const d = driver({ + showProgress: true, + steps: tourSteps, + onHighlighted: (element, tourStep, { state }) => { + const tours = { ...settings.value.tours }; + tours[tourId] = { + step: state.activeIndex ?? 0, + completed: state.activeIndex === tourSteps.length - 1, + }; + + updateSettings({ + ...settings.value, + tours, + }); + }, + }); + + const currentStep = settings.value.tours[tourId]?.step ?? 0; + d.drive(force ? 0 : currentStep); + }; + + return { + startTour, + isCompleted: () => settings.value.tours[tourId]?.completed ?? false, + }; +} diff --git a/apps/ui/src/composables/websocket-client.ts b/apps/ui/src/composables/websocket-client.ts new file mode 100644 index 00000000..b798aed6 --- /dev/null +++ b/apps/ui/src/composables/websocket-client.ts @@ -0,0 +1,438 @@ +import { Channels, Data, End, Events, RequestId } from "@pipelab/shared"; +import { useLogger } from "@pipelab/shared"; +import { klona } from "klona"; +import { toRaw } from "vue"; +import { + WebSocketSendFunction, + WebSocketClientConfig, + WebSocketConnectionState, + WebSocketError, + WebSocketConnectionError, + WebSocketMessage, + isWebSocketRequestMessage, + isWebSocketResponseMessage, + isWebSocketErrorMessage, +} from "@pipelab/shared"; +import { websocketPort } from "@pipelab/constants"; +import { nanoid } from "nanoid"; + +export type WebSocketSendFn = WebSocketSendFunction; + +// Message queue item interface +interface QueuedMessage { + channel: Channels; + data?: any; + resolve: (value: any) => void; + reject: (reason: any) => void; + requestId: RequestId; + listener?: (event: any) => void; +} + +export class WebSocketClient { + private ws: WebSocket | null = null; + private listeners: Map void> = new Map(); + private eventListeners: Map void>> = new Map(); + private reconnectAttempts = 0; + private maxReconnectAttempts = Infinity; + private reconnectDelay = 1000; + private maxReconnectDelay = 30000; // Cap at 30 seconds + private isConnecting = false; + private connectionState: WebSocketConnectionState = "disconnected"; + private stateChangeListeners: Set<(state: WebSocketConnectionState) => void> = new Set(); + private messageQueue: QueuedMessage[] = []; + private reconnectTimeout: any = null; + public currentUrl: string; + private isRenderer = false; + + constructor(private config: WebSocketClientConfig = {}) { + let defaultUrl = `ws://localhost:${websocketPort}`; + + if (typeof window !== "undefined") { + const isDev = process.env.NODE_ENV === "development"; + if (!isDev) { + const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; + defaultUrl = `${protocol}//${window.location.host}`; + } + } + + const { url = defaultUrl, maxReconnectAttempts = Infinity, reconnectDelay = 1000 } = config; + this.maxReconnectAttempts = maxReconnectAttempts; + this.reconnectDelay = reconnectDelay; + this.currentUrl = url; + + // Check if running in browser/renderer environment + this.isRenderer = typeof window !== "undefined"; + } + + public connect(url?: string) { + const targetUrl = url || this.currentUrl; + this.currentUrl = targetUrl; + + // Clear any pending reconnection attempt + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + this.reconnectTimeout = null; + } + + if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) { + return; + } + + this.isConnecting = true; + this.connectionState = "connecting"; + this.notifyStateChange(); + + try { + this.ws = new WebSocket(targetUrl); + + this.ws.onopen = () => { + console.log("WebSocket connected to", targetUrl); + this.isConnecting = false; + this.reconnectAttempts = 0; + this.connectionState = "connected"; + + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + this.reconnectTimeout = null; + } + + this.notifyStateChange(); + + const { logger } = useLogger(); + logger().debug("WebSocket client connected successfully"); + + // Flush any queued messages now that connection is ready + this.flushQueue(); + }; + + this.ws.onmessage = (event) => { + this.handleMessage(event); + }; + + this.ws.onclose = (event) => { + console.log("WebSocket disconnected", { code: event.code, reason: event.reason }); + this.isConnecting = false; + this.connectionState = "disconnected"; + this.notifyStateChange(); + + this.scheduleReconnect(); + }; + + this.ws.onerror = (error) => { + console.error("WebSocket error:", error); + this.isConnecting = false; + this.connectionState = "error"; + this.notifyStateChange(); + }; + } catch (error) { + console.error("Failed to create WebSocket connection:", error); + this.isConnecting = false; + this.connectionState = "error"; + this.notifyStateChange(); + this.scheduleReconnect(); + } + } + + private notifyStateChange() { + this.stateChangeListeners.forEach((listener) => { + try { + listener(this.connectionState); + } catch (error) { + console.error("Error in state change listener:", error); + } + }); + } + + private scheduleReconnect() { + if (this.reconnectAttempts >= this.maxReconnectAttempts) { + console.error("Max reconnection attempts reached"); + this.clearQueue(); + return; + } + + this.reconnectAttempts++; + // Exponential backoff, capped at maxReconnectDelay + const delay = Math.min( + this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1), + this.maxReconnectDelay, + ); + + const maxAttemptsStr = this.maxReconnectAttempts === Infinity ? "∞" : this.maxReconnectAttempts; + + this.reconnectTimeout = setTimeout(() => { + this.reconnectTimeout = null; + console.log( + `Attempting to reconnect (${this.reconnectAttempts}/${maxAttemptsStr}) in ${delay}ms`, + ); + this.connect(); + }, delay); + } + + private handleMessage(event: MessageEvent) { + try { + const message: WebSocketMessage | { type: "event"; channel: string; data: any } = JSON.parse( + event.data, + ); + + if (isWebSocketResponseMessage(message) || isWebSocketErrorMessage(message)) { + if (this.listeners.has(message.requestId)) { + this.listeners.get(message.requestId)!(message); + } + } else if ("type" in message && message.type === "event" && "channel" in message) { + const channel = message.channel; + const listeners = this.eventListeners.get(channel); + if (listeners) { + listeners.forEach((listener) => { + try { + listener(message.data); + } catch (error) { + console.error(`Error in event listener for channel ${channel}:`, error); + } + }); + } + } else if (isWebSocketRequestMessage(message)) { + // Handle incoming request messages if needed + console.log("Received request message:", message); + } + } catch (error) { + console.error("Failed to parse WebSocket message:", error); + } + } + + public send( + channel: KEY, + data?: Data, + listener?: (event: any) => void, + ): Promise> { + return new Promise(async (resolve, reject) => { + const { logger } = useLogger(); + + // If connection is not ready, queue the message + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + logger().debug("WebSocket not ready, queuing message:", { channel, hasData: !!data }); + + const requestId = nanoid() as RequestId; + this.messageQueue.push({ + channel, + data: toRaw(klona(data)), + resolve, + reject, + requestId, + listener, + }); + + return; + } + + // Connection is ready, send immediately + this.sendMessage(channel, data, resolve, reject, nanoid, listener); + }); + } + + private sendMessage( + channel: KEY, + data: Data | undefined, + resolve: (value: End) => void, + reject: (reason: any) => void, + nanoidFn: () => string, + listener?: (event: any) => void, + ): void { + const { logger } = useLogger(); + + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + logger().error("WebSocket send failed: connection not open"); + reject(new WebSocketConnectionError("WebSocket is not connected")); + return; + } + + const requestId = nanoidFn() as RequestId; + const message: WebSocketMessage = { + channel, + requestId, + data: toRaw(klona(data)), + }; + + logger().debug("Sending WebSocket message:", { + channel, + requestId, + hasData: !!data, + }); + + this.listeners.set(requestId, (response: WebSocketMessage) => { + if (isWebSocketErrorMessage(response)) { + // Handle error messages immediately + this.listeners.delete(requestId); + reject(new WebSocketError(response.error, response.code, response.requestId)); + } else if (isWebSocketResponseMessage(response)) { + // Handle the response events + const endEvent = response.events; + + if (endEvent.type === "end") { + // Only resolve and cleanup when we receive the final 'end' message + this.listeners.delete(requestId); + resolve(endEvent.data); + } else { + // Handle intermediate events - call the provided listener if available + if (listener) { + listener(endEvent); + } else { + logger().info("Received intermediate event:", { + requestId, + eventType: endEvent.type, + hasData: !!endEvent.data, + }); + } + } + } + }); + + try { + this.ws.send(JSON.stringify(message)); + } catch (error) { + this.listeners.delete(requestId); + reject( + new WebSocketError( + `Failed to send message: ${error instanceof Error ? error.message : "Unknown error"}`, + ), + ); + } + } + + private async flushQueue(): Promise { + const { logger } = useLogger(); + + if (this.messageQueue.length === 0) { + return; + } + + logger().debug(`Flushing ${this.messageQueue.length} queued messages`); + + // copy of the queue and clear it + const queuedMessages = [...this.messageQueue]; + this.messageQueue = []; + + // Send all queued messages + for (const queuedMessage of queuedMessages) { + this.sendMessage( + queuedMessage.channel, + queuedMessage.data, + queuedMessage.resolve, + queuedMessage.reject, + nanoid, + queuedMessage.listener, + ); + } + } + + private clearQueue(): void { + const { logger } = useLogger(); + + if (this.messageQueue.length === 0) { + return; + } + + logger().debug( + `Clearing ${this.messageQueue.length} queued messages due to connection error/disconnect`, + ); + + // Reject all queued messages + for (const queuedMessage of this.messageQueue) { + queuedMessage.reject(new WebSocketConnectionError("WebSocket connection lost")); + } + + this.messageQueue = []; + } + + public isConnected(): boolean { + return this.ws?.readyState === WebSocket.OPEN; + } + + public disconnect(options: { clearQueue?: boolean } = { clearQueue: true }) { + this.connectionState = "disconnected"; + this.notifyStateChange(); + + // Clear any pending reconnection attempt + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + this.reconnectTimeout = null; + } + + // Clear any queued messages since we're disconnecting + if (options.clearQueue) { + this.clearQueue(); + } + + if (this.ws) { + this.ws.close(); + this.ws = null; + } + this.listeners.clear(); + this.reconnectAttempts = 0; + } + + public getConnectionState(): WebSocketConnectionState { + return this.connectionState; + } + + public onStateChange(callback: (state: WebSocketConnectionState) => void): () => void { + this.stateChangeListeners.add(callback); + return () => { + this.stateChangeListeners.delete(callback); + }; + } + + public reconnect(url?: string) { + this.disconnect({ clearQueue: false }); + this.connect(url); + } + public on( + channel: KEY | string, + listener: (data: Events) => void, + ): () => void { + if (!this.eventListeners.has(channel)) { + this.eventListeners.set(channel, new Set()); + } + this.eventListeners.get(channel)!.add(listener); + return () => { + this.eventListeners.get(channel)?.delete(listener); + }; + } +} + +// Global WebSocket client instance +let wsClient: WebSocketClient | null = null; + +export const getWebSocketClient = (): WebSocketClient => { + if (!wsClient) { + wsClient = new WebSocketClient(); + } + return wsClient; +}; + +export const useWebSocketAPI = () => { + const { logger } = useLogger(); + const client = getWebSocketClient(); + + /** + * Send an order and wait for its execution + */ + const execute = async ( + channel: KEY, + data?: Data, + listener?: (event: any) => void, + ): Promise> => { + try { + return await client.send(channel, data, listener); + } catch (error) { + logger().error("WebSocket API error:", error); + throw error; + } + }; + + return { + execute, + isConnected: client.isConnected.bind(client), + disconnect: client.disconnect.bind(client), + on: client.on.bind(client), + }; +}; diff --git a/apps/ui/src/composables/websocket-manager.ts b/apps/ui/src/composables/websocket-manager.ts new file mode 100644 index 00000000..12d3accd --- /dev/null +++ b/apps/ui/src/composables/websocket-manager.ts @@ -0,0 +1,143 @@ +import { Channels, Data, End } from "@pipelab/shared"; +import { useLogger } from "@pipelab/shared"; +import { getWebSocketClient, WebSocketClient } from "./websocket-client"; +import { ref } from "vue"; +import { + WebSocketManager, + WebSocketConnectionState, + WebSocketClientConfig, + WebSocketError, + WebSocketConnectionError, +} from "@pipelab/shared"; + +class WebSocketManagerImpl implements WebSocketManager { + private client: WebSocketClient | null = null; + private stateChangeListeners: Set<(state: WebSocketConnectionState) => void> = new Set(); + private isInitialized = false; + public connectionState = ref("disconnected"); + + async initialize(config?: WebSocketClientConfig): Promise { + if (this.isInitialized) { + return; + } + + const { logger } = useLogger(); + + try { + this.client = getWebSocketClient(); + this.connectionState.value = this.client.getConnectionState(); + + // Set up state change listener + this.client.onStateChange((state) => { + this.connectionState.value = state; + this.stateChangeListeners.forEach((listener) => { + try { + listener(state); + } catch (error) { + logger().error("Error in WebSocket state change listener:", error); + } + }); + }); + + this.isInitialized = true; + logger().info("WebSocket manager initialized"); + } catch (error) { + logger().error("Failed to initialize WebSocket manager:", error); + throw new WebSocketConnectionError( + `Initialization failed: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } + } + + async connect(url?: string): Promise { + if (!this.client) { + await this.initialize(); + } + + if (!this.client) { + throw new WebSocketConnectionError("WebSocket client not available"); + } + + const { logger } = useLogger(); + + try { + if (url) { + this.client.reconnect(url); + } else { + this.client.connect(); + } + + logger().info("WebSocket connection initiated", { url }); + } catch (error) { + logger().error("Failed to connect WebSocket:", error); + throw error; + } + } + + disconnect(): void { + if (this.client) { + this.client.disconnect(); + } + } + + send(channel: KEY, data?: Data): Promise> { + if (!this.client) { + throw new WebSocketConnectionError("WebSocket client not initialized"); + } + + if (!this.client.isConnected()) { + throw new WebSocketConnectionError("WebSocket is not connected"); + } + + return this.client.send(channel, data); + } + + isConnected(): boolean { + return this.client?.isConnected() ?? false; + } + + getConnectionState(): WebSocketConnectionState { + return this.client?.getConnectionState() ?? "disconnected"; + } + + onStateChange(callback: (state: WebSocketConnectionState) => void): () => void { + this.stateChangeListeners.add(callback); + return () => { + this.stateChangeListeners.delete(callback); + }; + } + + getClient(): WebSocketClient | null { + return this.client; + } + + async ensureConnection(url?: string): Promise { + const { logger } = useLogger(); + + logger().debug("Ensuring WebSocket connection...", { + hasClient: !!this.client, + isConnected: this.client?.isConnected() ?? false, + targetUrl: url, + }); + + if (!this.client) { + logger().debug("Initializing WebSocket client..."); + await this.initialize(); + } + + if (!this.client) { + throw new WebSocketConnectionError("WebSocket client not available"); + } + + if (!this.client.isConnected()) { + logger().debug("Connecting WebSocket client..."); + await this.connect(url); + logger().info("WebSocket connection established successfully"); + } else { + logger().debug("WebSocket already connected"); + } + } +} + +// Export singleton instance +export const websocketManager = new WebSocketManagerImpl(); diff --git a/apps/ui/src/env.d.ts b/apps/ui/src/env.d.ts new file mode 100644 index 00000000..4af4bfd4 --- /dev/null +++ b/apps/ui/src/env.d.ts @@ -0,0 +1,8 @@ +/// + +declare module "*.vue" { + import type { DefineComponent } from "vue"; + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/apps/ui/src/i18n.ts b/apps/ui/src/i18n.ts new file mode 100644 index 00000000..de896e22 --- /dev/null +++ b/apps/ui/src/i18n.ts @@ -0,0 +1,16 @@ +import { MessageSchema, Locales, en_US, fr_FR, pt_BR, zh_CN, es_ES, de_DE } from "@pipelab/shared"; +import { createI18n } from "vue-i18n"; + +export const i18n = createI18n<[MessageSchema], Locales>({ + legacy: false, + locale: "en-US", + fallbackLocale: "en-US", + messages: { + "en-US": en_US, + "fr-FR": fr_FR, + "pt-BR": pt_BR, + "zh-CN": zh_CN, + "es-ES": es_ES, + "de-DE": de_DE, + }, +}); diff --git a/apps/ui/src/main.ts b/apps/ui/src/main.ts new file mode 100644 index 00000000..e9e544ab --- /dev/null +++ b/apps/ui/src/main.ts @@ -0,0 +1,146 @@ +import { createApp } from "vue"; +import Root from "./Root.vue"; +import { router } from "./router/router"; + +import { createPinia } from "pinia"; +import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; +import { createI18n } from "vue-i18n"; + +import PrimeVue from "primevue/config"; +import Lara from "@primevue/themes/lara"; +import "primeicons/primeicons.css"; +import "primeflex/primeflex.css"; +import "@mdi/font/css/materialdesignicons.css"; +import "driver.js/dist/driver.css"; +import { definePreset } from "@primevue/themes"; +import "./style/main.scss"; +import VueDOMPurifyHTML from "vue-dompurify-html"; + +import ToastService from "primevue/toastservice"; +import ConfirmationService from "primevue/confirmationservice"; +import posthogPlugin from "./plugins/posthog"; //import the plugin. +import posthog from "posthog-js"; +import { i18n } from "./i18n"; + +import { websocketManager } from "./composables/websocket-manager"; +import { useLogger } from "@pipelab/shared"; +import Tooltip from "primevue/tooltip"; + +const isPackaged = window.isPackaged || false; +const isTest = window.isTest || false; +const isCI = window.isCI || false; + +const pinia = createPinia(); +pinia.use(piniaPluginPersistedstate); + +const PipelabPreset = definePreset(Lara, { + semantic: { + transitionDuration: "0.2s", + focusRing: { + width: "1px", + style: "solid", + color: "{primary.color}", + offset: "2px", + shadow: "none", + }, + disabledOpacity: "0.6", + iconSize: "1rem", + anchorGutter: "2px", + primary: { + 50: "{zinc.50}", + 100: "{zinc.100}", + 200: "{zinc.200}", + 300: "{zinc.300}", + 400: "{zinc.400}", + 500: "{zinc.500}", + 600: "{zinc.600}", + 700: "{zinc.700}", + 800: "{zinc.800}", + 900: "{zinc.900}", + 950: "{zinc.950}", + }, + colorScheme: { + light: { + primary: { + color: "{zinc.950}", + inverseColor: "#ffffff", + hoverColor: "{zinc.900}", + activeColor: "{zinc.800}", + }, + highlight: { + background: "{zinc.950}", + focusBackground: "{zinc.700}", + color: "#ffffff", + focusColor: "#ffffff", + }, + }, + dark: { + primary: { + color: "{zinc.50}", + inverseColor: "{zinc.950}", + hoverColor: "{zinc.100}", + activeColor: "{zinc.200}", + }, + highlight: { + background: "rgba(250, 250, 250, .16)", + focusBackground: "rgba(250, 250, 250, .24)", + color: "rgba(255,255,255,.87)", + focusColor: "rgba(255,255,255,.87)", + }, + }, + }, + }, +}); + +// init({ +// vueInit, +// integrations: [ +// browserTracingIntegration({ router }), +// replayIntegration(), +// ], + +// // Set tracesSampleRate to 1.0 to capture 100% +// // of transactions for performance monitoring. +// // We recommend adjusting this value in production +// tracesSampleRate: 1.0, + +// // Capture Replay for 10% of all sessions, +// // plus for 100% of sessions with an error +// replaysSessionSampleRate: 0.1, +// replaysOnErrorSampleRate: 1.0, +// }); + +const app = createApp(Root); + +app.use(router); +app.use(pinia); +app.use(VueDOMPurifyHTML); +app.use(PrimeVue, { + theme: { + preset: PipelabPreset, + options: { + darkModeSelector: ".dark", + }, + }, +}); +app.use(ToastService); +app.use(ConfirmationService); +if (window.isPackaged && process.env.TEST !== "true") { + app.use(posthogPlugin); +} +app.use(i18n); +app.directive("tooltip", Tooltip); + +const { logger } = useLogger(); + +// Initialize WebSocket manager in background +websocketManager.initialize().catch((error) => { + logger().warn( + "WebSocket manager initialization failed, app will continue without WebSocket:", + error, + ); +}); +app.mount("#app"); +logger().info("App mounted"); + +// Connection logic is now handled by App.vue and agentsStore diff --git a/apps/ui/src/models/constants.ts b/apps/ui/src/models/constants.ts new file mode 100644 index 00000000..2a427426 --- /dev/null +++ b/apps/ui/src/models/constants.ts @@ -0,0 +1 @@ +export const PROJECT_EXTENSION = "plb"; diff --git a/apps/ui/src/models/controls.ts b/apps/ui/src/models/controls.ts new file mode 100644 index 00000000..121fee64 --- /dev/null +++ b/apps/ui/src/models/controls.ts @@ -0,0 +1,51 @@ +import { ControlType } from "@pipelab/shared"; +import { match } from "ts-pattern"; + +type PrimitiveConstructor = + | "string" + | "number" + | "boolean" + | "object" + | "symbol" + | "function" + | "bigint"; + +export const controlsToType = (control: ControlType) => { + return match(control) + .returnType() + .with({ type: "path" }, () => "string") + .with({ type: "input", options: { kind: "number" } }, () => "number") + .with({ type: "input", options: { kind: "text" } }, () => "string") + .with({ type: "boolean" }, () => "boolean") + .with({ type: "checkbox" }, () => "boolean") + .with({ type: "select" }, () => "string") + .with({ type: "multi-select" }, () => "object") + .with({ type: "json" }, () => "object") + .with({ type: "expression" }, () => "string") + .with({ type: "array", options: { kind: "number" } }, () => "object") + .with({ type: "array", options: { kind: "text" } }, () => "object") + .with({ type: "electron:configure:v2" }, () => "object") + .with({ type: "netlify-site" }, () => "string") + .with({ type: "color" }, () => "string") + .exhaustive(); +}; + +export const controlsToIcon = (control: ControlType) => { + return match(control) + .returnType() + .with({ type: "path" }, () => "mdi-alphabetical-variant") + .with({ type: "input", options: { kind: "number" } }, () => "mdi-numeric") + .with({ type: "input", options: { kind: "text" } }, () => "mdi-alphabetical-variant") + .with({ type: "boolean" }, () => "mdi-toggle-switch") + .with({ type: "checkbox" }, () => "mdi-toggle-switch") + .with({ type: "select" }, () => "mdi-alphabetical-variant") + .with({ type: "multi-select" }, () => "mdi-code-brackets") + .with({ type: "json" }, () => "mdi-code-braces") + .with({ type: "expression" }, () => "mdi-") + .with({ type: "array", options: { kind: "number" } }, () => "mdi-code-brackets") + .with({ type: "array", options: { kind: "text" } }, () => "mdi-code-brackets") + .with({ type: "electron:configure:v2" }, () => "mdi-code-braces") + .with({ type: "netlify-site" }, () => "mdi-code-braces") + .with({ type: "color" }, () => "mdi-palette") + .exhaustive(); +}; diff --git a/apps/ui/src/models/error.ts b/apps/ui/src/models/error.ts new file mode 100644 index 00000000..3b3b44dd --- /dev/null +++ b/apps/ui/src/models/error.ts @@ -0,0 +1,10 @@ +import { any, literal, object, optional, record, string, union, type InferOutput } from "valibot"; + +export const ValidationErrorValidator = object({ + type: union([literal("missing"), literal("blacklisted")]), + param: string(), + message: optional(string()), + meta: optional(record(string(), any())), +}); + +export type ValidationError = InferOutput; diff --git a/apps/ui/src/pages/connections.vue b/apps/ui/src/pages/connections.vue new file mode 100644 index 00000000..d43a9dd2 --- /dev/null +++ b/apps/ui/src/pages/connections.vue @@ -0,0 +1,1366 @@ + + + + + diff --git a/apps/ui/src/pages/editor.vue b/apps/ui/src/pages/editor.vue new file mode 100644 index 00000000..e0cca213 --- /dev/null +++ b/apps/ui/src/pages/editor.vue @@ -0,0 +1,1896 @@ + + + + + diff --git a/src/renderer/pages/environement-editor.vue b/apps/ui/src/pages/environement-editor.vue similarity index 75% rename from src/renderer/pages/environement-editor.vue rename to apps/ui/src/pages/environement-editor.vue index cdfa9d41..3828c882 100644 --- a/src/renderer/pages/environement-editor.vue +++ b/apps/ui/src/pages/environement-editor.vue @@ -58,81 +58,81 @@ diff --git a/apps/ui/src/pages/integrations.vue b/apps/ui/src/pages/integrations.vue new file mode 100644 index 00000000..9a5971b3 --- /dev/null +++ b/apps/ui/src/pages/integrations.vue @@ -0,0 +1,1250 @@ + + + + + diff --git a/src/renderer/pages/nodes-editor.vue b/apps/ui/src/pages/nodes-editor.vue similarity index 55% rename from src/renderer/pages/nodes-editor.vue rename to apps/ui/src/pages/nodes-editor.vue index dc9a9b1e..66ffa44d 100644 --- a/src/renderer/pages/nodes-editor.vue +++ b/apps/ui/src/pages/nodes-editor.vue @@ -13,21 +13,6 @@ :errors="errors" :is-running="isRunning" > - - @@ -35,53 +20,51 @@ diff --git a/src/renderer/pages/scenarios.vue b/apps/ui/src/pages/scenarios.vue similarity index 83% rename from src/renderer/pages/scenarios.vue rename to apps/ui/src/pages/scenarios.vue index 3e600daf..2497d88a 100644 --- a/src/renderer/pages/scenarios.vue +++ b/apps/ui/src/pages/scenarios.vue @@ -4,16 +4,16 @@ {{ headerSentence }}
- {{ $t('scenarios.scenarios') }} + {{ $t("pipelines.title") }}
+ + + + + + + + diff --git a/assets/discord/templates/nitro-app/tsconfig.json b/assets/asset-discord/template/tsconfig.json similarity index 100% rename from assets/discord/templates/nitro-app/tsconfig.json rename to assets/asset-discord/template/tsconfig.json diff --git a/assets/asset-electron/.oxfmtrc.json b/assets/asset-electron/.oxfmtrc.json new file mode 100644 index 00000000..3cd197af --- /dev/null +++ b/assets/asset-electron/.oxfmtrc.json @@ -0,0 +1,9 @@ +{ + "ignorePatterns": [ + "dist", + "out", + "node_modules", + "bin", + "**/*.d.ts" + ] +} diff --git a/assets/asset-electron/CHANGELOG.md b/assets/asset-electron/CHANGELOG.md new file mode 100644 index 00000000..dfeca4b6 --- /dev/null +++ b/assets/asset-electron/CHANGELOG.md @@ -0,0 +1,193 @@ +# @pipelab/asset-electron + +## 1.0.0-beta.31 + +### Patch Changes + +- - + +## 1.0.0-beta.30 + +### Patch Changes + +- improve dark theme and improve build history + +## 1.0.0-beta.29 + +### Patch Changes + +- sd + +## 1.0.0-beta.28 + +### Patch Changes + +- sd + +## 1.0.0-beta.27 + +### Patch Changes + +- sd + +## 1.0.0-beta.26 + +### Patch Changes + +- sd + +## 1.0.0-beta.25 + +### Patch Changes + +- sd + +## 1.0.0-beta.24 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.23 + +### Patch Changes + +- sd + +## 1.0.0-beta.22 + +### Patch Changes + +- sd + +## 1.0.0-beta.21 + +### Patch Changes + +- sd + +## 1.0.0-beta.20 + +### Patch Changes + +- sd + +## 1.0.0-beta.19 + +### Patch Changes + +- sd + +## 1.0.0-beta.18 + +### Patch Changes + +- sd + +## 1.0.0-beta.17 + +### Patch Changes + +- sd + +## 1.0.0-beta.16 + +### Patch Changes + +- df + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.14 + +### Patch Changes + +- sd + +## 1.0.0-beta.13 + +### Patch Changes + +- sd + +## 1.0.0-beta.12 + +### Patch Changes + +- qs + +## 1.0.0-beta.11 + +### Patch Changes + +- sd + +## 1.0.0-beta.10 + +### Patch Changes + +- s + +## 1.0.0-beta.9 + +### Patch Changes + +- fg + +## 1.0.0-beta.8 + +### Patch Changes + +- changes + +## 1.0.0-beta.7 + +### Patch Changes + +- bump + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes + +## 1.0.0-beta.5 + +### Patch Changes + +- bump + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag + +## 1.0.0-beta.3 + +### Patch Changes + +- bump + +## 1.0.0-beta.2 + +### Patch Changes + +- update + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/assets/asset-electron/package.json b/assets/asset-electron/package.json new file mode 100644 index 00000000..11317fde --- /dev/null +++ b/assets/asset-electron/package.json @@ -0,0 +1,18 @@ +{ + "name": "@pipelab/asset-electron", + "version": "1.0.0-beta.31", + "description": "Electron assets for pipelab", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "assets/asset-electron" + }, + "files": [ + "template" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/assets/electron/template/app/config.cjs b/assets/asset-electron/template/config.cjs similarity index 66% rename from assets/electron/template/app/config.cjs rename to assets/asset-electron/template/config.cjs index a3e3acb7..41f3b613 100644 --- a/assets/electron/template/app/config.cjs +++ b/assets/asset-electron/template/config.cjs @@ -9,14 +9,14 @@ /** @type {DesktopApp.Electron} */ const config = { alwaysOnTop: false, - appBundleId: 'com.pipelab.app', - appCategoryType: '', - appCopyright: 'Copyright © 2024 Pipelab', - appVersion: '1.0.0', - author: 'Pipelab', - customMainCode: '', - description: 'A simple Electron application', - electronVersion: '', + appBundleId: "com.pipelab.app", + appCategoryType: "", + appCopyright: "Copyright © 2024 Pipelab", + appVersion: "1.0.0", + author: "Pipelab", + customMainCode: "", + description: "A simple Electron application", + electronVersion: "", disableAsarPackaging: true, forceHighPerformanceGpu: false, enableExtraLogging: false, @@ -26,20 +26,20 @@ const config = { openDevtoolsOnStart: false, frame: true, fullscreen: false, - icon: '', + icon: "", height: 600, - name: 'Pipelab', + name: "Pipelab", toolbar: true, transparent: false, width: 800, enableSteamSupport: false, steamGameId: 480, enableDiscordSupport: false, - discordAppId: '', + discordAppId: "", enableDoctor: false, ignore: [], - serverMode: 'default', - backgroundColor: '#FFF' -} + serverMode: "default", + backgroundColor: "#FFF", +}; -module.exports = config +module.exports = config; diff --git a/assets/electron/template/app/forge.config.cjs b/assets/asset-electron/template/forge.config.cjs similarity index 65% rename from assets/electron/template/app/forge.config.cjs rename to assets/asset-electron/template/forge.config.cjs index b0c95190..7e9c8fe0 100644 --- a/assets/electron/template/app/forge.config.cjs +++ b/assets/asset-electron/template/forge.config.cjs @@ -1,27 +1,27 @@ // @ts-check -const { FusesPlugin } = require('@electron-forge/plugin-fuses') -const { FuseV1Options, FuseVersion } = require('@electron/fuses') -const { join } = require('path') +const { FusesPlugin } = require("@electron-forge/plugin-fuses"); +const { FuseV1Options, FuseVersion } = require("@electron/fuses"); +const { join } = require("path"); -const PipelabPlugin = require('./pipelab-plugin.cjs') +const PipelabPlugin = require("./pipelab-plugin.cjs"); -const config = require('./config.cjs') +const config = require("./config.cjs"); // Include all files in the dist directory regardless of OS (to support unpacking .so when built on windows) -const unpackFilter = join('**', 'steamworks.js', 'dist', '**', '*') +const unpackFilter = join("**", "steamworks.js", "dist", "**", "*"); /** * @type {import('@electron-forge/shared-types').ForgeConfig} */ module.exports = { - outDir: './out', + outDir: join(__dirname, "out"), packagerConfig: { asar: config.disableAsarPackaging ? false : { - unpack: unpackFilter - }, + unpack: unpackFilter, + }, name: config.name, appBundleId: config.appBundleId, appCopyright: config.appCopyright, @@ -29,25 +29,25 @@ module.exports = { // icon: './assets/icon', // file extension is ommited (auto completed by platform: darwin: icns, linux, win32) win32metadata: { CompanyName: config.author, - FileDescription: config.description + FileDescription: config.description, }, appCategoryType: config.appCategoryType, icon: config.icon, - ignore: config.ignore + ignore: config.ignore, }, rebuildConfig: {}, makers: [ { - name: '@electron-forge/maker-dmg', - config: {} + name: "@electron-forge/maker-dmg", + config: {}, }, { - name: '@electron-forge/maker-squirrel', - config: {} + name: "@electron-forge/maker-squirrel", + config: {}, }, { - name: '@electron-forge/maker-zip' - } + name: "@electron-forge/maker-zip", + }, ], plugins: [ // { @@ -63,8 +63,8 @@ module.exports = { [FuseV1Options.EnableNodeCliInspectArguments]: false, [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: config.disableAsarPackaging === true ? false : true, - [FuseV1Options.OnlyLoadAppFromAsar]: config.disableAsarPackaging === true ? false : true + [FuseV1Options.OnlyLoadAppFromAsar]: config.disableAsarPackaging === true ? false : true, }), - new PipelabPlugin() - ] -} + new PipelabPlugin(), + ], +}; diff --git a/assets/electron/template/app/package.json b/assets/asset-electron/template/package.json similarity index 63% rename from assets/electron/template/app/package.json rename to assets/asset-electron/template/package.json index 2e4998cf..1175670b 100644 --- a/assets/electron/template/app/package.json +++ b/assets/asset-electron/template/package.json @@ -1,42 +1,26 @@ { "name": "app", - "productName": "app", - "version": "1.0.0", + "version": "0.9.9", "description": "My Electron application description", + "keywords": [], + "license": "MIT", + "author": { + "name": "[NAME]", + "email": "[EMAIL_ADDRESS]" + }, "type": "module", "main": "src/index.js", "scripts": { "start": "electron-forge start", - "start:url": "electron-forge start -- --url=https://google.com", "package": "electron-forge package", "make": "electron-forge make", "publish": "electron-forge publish", "lint": "echo \"No linting configured\"" }, - "devDependencies": { - "@electron-forge/cli": "7.4.0", - "@electron-forge/maker-deb": "7.4.0", - "@electron-forge/maker-dmg": "7.4.0", - "@electron-forge/maker-rpm": "7.4.0", - "@electron-forge/maker-squirrel": "7.4.0", - "@electron-forge/maker-zip": "7.4.0", - "@electron-forge/plugin-auto-unpack-natives": "7.4.0", - "@electron-forge/plugin-fuses": "7.4.0", - "@electron/fuses": "1.8.0", - "@pipelab/core": "1.4.9", - "@types/mime-types": "^3.0.1", - "electron": "39.2.3" - }, - "keywords": [], - "author": { - "name": "Quentin Goinaud", - "email": "quentin.goinaud@gmail.com" - }, - "license": "MIT", "dependencies": { - "@electron-forge/plugin-base": "7.4.0", + "@electron-forge/plugin-base": "7.11.1", "@electron/asar": "3.2.13", - "@pipelab/steamworks.js": "^0.11.1", + "@pipelab/steamworks.js": "0.11.1", "discord-rpc": "^4.0.1", "electron-serve": "^2.1.1", "electron-squirrel-startup": "1.0.1", @@ -49,6 +33,20 @@ "slash": "^5.1.0", "ws": "^8.18.1" }, + "devDependencies": { + "@electron-forge/cli": "7.11.1", + "@electron-forge/maker-deb": "7.11.1", + "@electron-forge/maker-dmg": "7.11.1", + "@electron-forge/maker-rpm": "7.11.1", + "@electron-forge/maker-squirrel": "7.11.1", + "@electron-forge/maker-zip": "7.11.1", + "@electron-forge/plugin-auto-unpack-natives": "7.11.1", + "@electron-forge/plugin-fuses": "7.11.1", + "@electron/fuses": "1.8.0", + "@pipelab/core": "1.4.9", + "@types/mime-types": "^3.0.1", + "electron": "39.2.3" + }, "pnpm": { "overrides": { "discord-rpc>register-scheme": "-" @@ -59,5 +57,6 @@ "fs-xattr", "macos-alias" ] - } + }, + "productName": "app" } diff --git a/assets/electron/template/app/pipelab-plugin.cjs b/assets/asset-electron/template/pipelab-plugin.cjs similarity index 70% rename from assets/electron/template/app/pipelab-plugin.cjs rename to assets/asset-electron/template/pipelab-plugin.cjs index aee09439..2df55257 100644 --- a/assets/electron/template/app/pipelab-plugin.cjs +++ b/assets/asset-electron/template/pipelab-plugin.cjs @@ -1,4 +1,4 @@ -const { PluginBase } = require('@electron-forge/plugin-base') +const { PluginBase } = require("@electron-forge/plugin-base"); module.exports = class PipelabPlugin extends PluginBase { getHooks() { @@ -12,8 +12,8 @@ module.exports = class PipelabPlugin extends PluginBase { postPackage: [this.postPackage], preMake: [this.preMake], postMake: [this.postMake], - readPackageJson: [this.readPackageJson] - } + readPackageJson: [this.readPackageJson], + }; } prePackage() { @@ -26,22 +26,22 @@ module.exports = class PipelabPlugin extends PluginBase { // console.log('running postStart hook') } async packageAfterCopy(config, buildPath, electronVersion, platform, arch) { - console.log(`Platform: ${platform}`) - console.log(`Architecture: ${arch}`) - console.log(`Build path: ${buildPath}`) - console.log(`Config: ${JSON.stringify(config)}`) - console.log(`Electron version: ${electronVersion}`) - const fs = require('fs').promises - const path = require('path') - const pkg = require('./package.json') + console.log(`Platform: ${platform}`); + console.log(`Architecture: ${arch}`); + console.log(`Build path: ${buildPath}`); + console.log(`Config: ${JSON.stringify(config)}`); + console.log(`Electron version: ${electronVersion}`); + const fs = require("fs").promises; + const path = require("path"); + const pkg = require("./package.json"); - console.log('config', config) + console.log("config", config); - const outputFolder = path.resolve(buildPath, '..', '..') + const outputFolder = path.resolve(buildPath, "..", ".."); // Runtime JSON file - const pipelabJsonPath = path.join(outputFolder, 'pipelab.json') + const pipelabJsonPath = path.join(outputFolder, "pipelab.json"); await fs.writeFile( pipelabJsonPath, @@ -50,20 +50,20 @@ module.exports = class PipelabPlugin extends PluginBase { name: config.name || pkg.productName || pkg.name, version: config.appVersion || pkg.version, description: config.description || pkg.description, - author: config.author || (typeof pkg.author === 'object' ? pkg.author.name : pkg.author), + author: config.author || (typeof pkg.author === "object" ? pkg.author.name : pkg.author), homepage: pkg.homepage, - engine: 'Pipelab', - runtimeVersion: pkg.devDependencies['@pipelab/core'], + engine: "Pipelab", + runtimeVersion: pkg.devDependencies["@pipelab/core"], buildDate: new Date().toISOString(), platform: platform, arch: arch, - electron: electronVersion + electron: electronVersion, }, null, - 2 + 2, ), - 'utf8' - ) + "utf8", + ); } packageAfterPrune() { // console.log('running packageAfterPrune hook') @@ -72,16 +72,16 @@ module.exports = class PipelabPlugin extends PluginBase { // console.log('running packageAfterExtract hook') } async postPackage(config, result) { - const fs = require('fs').promises - const path = require('path') - const appConfig = require('./config.cjs') + const fs = require("fs").promises; + const path = require("path"); + const appConfig = require("./config.cjs"); - const outputFolder = result.outputPaths[0] + const outputFolder = result.outputPaths[0]; // Doctor - if (result.platform === 'win32' && appConfig.enableDoctor) { - const appName = config.packagerConfig.name - console.log('appName', appName) + if (result.platform === "win32" && appConfig.enableDoctor) { + const appName = config.packagerConfig.name; + console.log("appName", appName); const doctorBatContent = `@echo off pushd "%~dp0" @@ -143,9 +143,9 @@ if %ERRORLEVEL% NEQ 0 ( :end popd -pause` - const doctorBatPath = path.join(outputFolder, 'doctor.bat') - await fs.writeFile(doctorBatPath, doctorBatContent, 'utf8') +pause`; + const doctorBatPath = path.join(outputFolder, "doctor.bat"); + await fs.writeFile(doctorBatPath, doctorBatContent, "utf8"); } } preMake() { @@ -157,4 +157,4 @@ pause` readPackageJson() { // console.log('running readPackageJson hook') } -} +}; diff --git a/assets/electron/template/app/src/custom-main.js b/assets/asset-electron/template/src/custom-main.js similarity index 100% rename from assets/electron/template/app/src/custom-main.js rename to assets/asset-electron/template/src/custom-main.js diff --git a/assets/electron/template/app/src/handlers/dialog/folder.js b/assets/asset-electron/template/src/handlers/dialog/folder.js similarity index 73% rename from assets/electron/template/app/src/handlers/dialog/folder.js rename to assets/asset-electron/template/src/handlers/dialog/folder.js index bbd9e2e8..eabe4df3 100644 --- a/assets/electron/template/app/src/handlers/dialog/folder.js +++ b/assets/asset-electron/template/src/handlers/dialog/folder.js @@ -1,4 +1,4 @@ -import { dialog } from 'electron' +import { dialog } from "electron"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -6,8 +6,8 @@ import { dialog } from 'electron' */ export default async (json, ws) => { const openFolderDialogResponse = await dialog.showOpenDialog({ - properties: ['openDirectory', 'createDirectory'] - }) + properties: ["openDirectory", "createDirectory"], + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -18,8 +18,8 @@ export default async (json, ws) => { body: { success: true, canceled: openFolderDialogResponse.canceled, - paths: openFolderDialogResponse.filePaths - } - } - ws.send(JSON.stringify(dialogOpenResult)) -} + paths: openFolderDialogResponse.filePaths, + }, + }; + ws.send(JSON.stringify(dialogOpenResult)); +}; diff --git a/assets/electron/template/app/src/handlers/dialog/open.js b/assets/asset-electron/template/src/handlers/dialog/open.js similarity index 82% rename from assets/electron/template/app/src/handlers/dialog/open.js rename to assets/asset-electron/template/src/handlers/dialog/open.js index 1a46e175..8eb1fac5 100644 --- a/assets/electron/template/app/src/handlers/dialog/open.js +++ b/assets/asset-electron/template/src/handlers/dialog/open.js @@ -1,4 +1,4 @@ -import { dialog } from 'electron' +import { dialog } from "electron"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -6,8 +6,8 @@ import { dialog } from 'electron' */ export default async (json, ws) => { const openDialogResponse = await dialog.showOpenDialog({ - properties: ['openFile'] - }) + properties: ["openFile"], + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -18,8 +18,8 @@ export default async (json, ws) => { body: { success: true, canceled: openDialogResponse.canceled, - paths: openDialogResponse.filePaths - } - } + paths: openDialogResponse.filePaths, + }, + }; ws.send(JSON.stringify(dialogOpenResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/dialog/save.js b/assets/asset-electron/template/src/handlers/dialog/save.js similarity index 82% rename from assets/electron/template/app/src/handlers/dialog/save.js rename to assets/asset-electron/template/src/handlers/dialog/save.js index 99397cc8..6d5aecf9 100644 --- a/assets/electron/template/app/src/handlers/dialog/save.js +++ b/assets/asset-electron/template/src/handlers/dialog/save.js @@ -1,4 +1,4 @@ -import { dialog } from 'electron' +import { dialog } from "electron"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -6,8 +6,8 @@ import { dialog } from 'electron' */ export default async (json, ws) => { const saveDialogResponse = await dialog.showSaveDialog({ - properties: [] - }) + properties: [], + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -17,8 +17,8 @@ export default async (json, ws) => { url: json.url, body: { success: true, - path: saveDialogResponse.filePath - } - } + path: saveDialogResponse.filePath, + }, + }; ws.send(JSON.stringify(dialogOpenResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/discord/set-activity.js b/assets/asset-electron/template/src/handlers/discord/set-activity.js similarity index 63% rename from assets/electron/template/app/src/handlers/discord/set-activity.js rename to assets/asset-electron/template/src/handlers/discord/set-activity.js index b5e19a22..57a27954 100644 --- a/assets/electron/template/app/src/handlers/discord/set-activity.js +++ b/assets/asset-electron/template/src/handlers/discord/set-activity.js @@ -5,9 +5,9 @@ * @param {import('discord-rpc').Client} rpc */ export default async (json, ws, mainWindow, rpc) => { - console.log('json', json) + console.log("json", json); - const { body } = json + const { body } = json; const { details, largeImageKey, @@ -15,29 +15,29 @@ export default async (json, ws, mainWindow, rpc) => { smallImageKey, smallImageText, startTimestamp, - state - } = body + state, + } = body; if (!rpc || !mainWindow) { - return + return; } - const startTimestampAsNumber = Number.parseInt(startTimestamp) + const startTimestampAsNumber = Number.parseInt(startTimestamp); const payload = { - instance: false - } + instance: false, + }; - if (details) payload.details = details - if (state) payload.state = state - if (largeImageKey) payload.largeImageKey = largeImageKey - if (largeImageText) payload.largeImageText = largeImageText - if (smallImageKey) payload.smallImageKey = smallImageKey - if (smallImageText) payload.smallImageText = smallImageText - if (!Number.isNaN(startTimestampAsNumber)) payload.startTimestamp = startTimestampAsNumber + if (details) payload.details = details; + if (state) payload.state = state; + if (largeImageKey) payload.largeImageKey = largeImageKey; + if (largeImageText) payload.largeImageText = largeImageText; + if (smallImageKey) payload.smallImageKey = smallImageKey; + if (smallImageText) payload.smallImageText = smallImageText; + if (!Number.isNaN(startTimestampAsNumber)) payload.startTimestamp = startTimestampAsNumber; try { - await rpc.setActivity(payload) + await rpc.setActivity(payload); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -46,12 +46,12 @@ export default async (json, ws, mainWindow, rpc) => { url: json.url, correlationId: json.correlationId, body: { - success: true - } - } - ws.send(JSON.stringify(result)) + success: true, + }, + }; + ws.send(JSON.stringify(result)); } catch (e) { - console.error('e', e) + console.error("e", e); /** * @type {import('@pipelab/core').MakeInputOutput} */ @@ -60,9 +60,9 @@ export default async (json, ws, mainWindow, rpc) => { correlationId: json.correlationId, body: { success: false, - error: e.message - } - } - ws.send(JSON.stringify(result)) + error: e.message, + }, + }; + ws.send(JSON.stringify(result)); } -} +}; diff --git a/assets/electron/template/app/src/handlers/fs/copy.js b/assets/asset-electron/template/src/handlers/fs/copy.js similarity index 63% rename from assets/electron/template/app/src/handlers/fs/copy.js rename to assets/asset-electron/template/src/handlers/fs/copy.js index 0056d3ca..5ea9892e 100644 --- a/assets/electron/template/app/src/handlers/fs/copy.js +++ b/assets/asset-electron/template/src/handlers/fs/copy.js @@ -1,19 +1,19 @@ // @ts-check -import { cp, mkdir } from 'node:fs/promises' -import { dirname } from 'node:path' +import { cp, mkdir } from "node:fs/promises"; +import { dirname } from "node:path"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - const destDirName = dirname(json.body.destination) - await mkdir(destDirName, { recursive: true }) + const destDirName = dirname(json.body.destination); + await mkdir(destDirName, { recursive: true }); await cp(json.body.source, json.body.destination, { - force: json.body.overwrite - }) + force: json.body.overwrite, + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -23,7 +23,7 @@ export default async (json, ws) => { url: json.url, body: { success: true, - } - } - ws.send(JSON.stringify(readFileResult)) -} + }, + }; + ws.send(JSON.stringify(readFileResult)); +}; diff --git a/assets/electron/template/app/src/handlers/fs/delete.js b/assets/asset-electron/template/src/handlers/fs/delete.js similarity index 76% rename from assets/electron/template/app/src/handlers/fs/delete.js rename to assets/asset-electron/template/src/handlers/fs/delete.js index 13b53275..0f662ac0 100644 --- a/assets/electron/template/app/src/handlers/fs/delete.js +++ b/assets/asset-electron/template/src/handlers/fs/delete.js @@ -1,13 +1,13 @@ // @ts-check -import { unlink } from 'node:fs/promises' +import { unlink } from "node:fs/promises"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - await unlink(json.body.path) + await unlink(json.body.path); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -17,7 +17,7 @@ export default async (json, ws) => { url: json.url, body: { success: true, - } - } - ws.send(JSON.stringify(readFileResult)) -} + }, + }; + ws.send(JSON.stringify(readFileResult)); +}; diff --git a/assets/electron/template/app/src/handlers/fs/exist.js b/assets/asset-electron/template/src/handlers/fs/exist.js similarity index 73% rename from assets/electron/template/app/src/handlers/fs/exist.js rename to assets/asset-electron/template/src/handlers/fs/exist.js index c7d21834..94720cef 100644 --- a/assets/electron/template/app/src/handlers/fs/exist.js +++ b/assets/asset-electron/template/src/handlers/fs/exist.js @@ -1,6 +1,6 @@ // @ts-check -import { access } from 'node:fs/promises' +import { access } from "node:fs/promises"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -8,7 +8,7 @@ import { access } from 'node:fs/promises' */ export default async (json, ws) => { try { - await access(json.body.path) + await access(json.body.path); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -17,10 +17,10 @@ export default async (json, ws) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } - ws.send(JSON.stringify(existResult)) + success: true, + }, + }; + ws.send(JSON.stringify(existResult)); } catch (e) { /** * @type {import('@pipelab/core').MakeInputOutput} @@ -29,9 +29,9 @@ export default async (json, ws) => { correlationId: json.correlationId, url: json.url, body: { - success: false - } - } - ws.send(JSON.stringify(existResult)) + success: false, + }, + }; + ws.send(JSON.stringify(existResult)); } -} +}; diff --git a/assets/electron/template/app/src/handlers/fs/file-size.js b/assets/asset-electron/template/src/handlers/fs/file-size.js similarity index 76% rename from assets/electron/template/app/src/handlers/fs/file-size.js rename to assets/asset-electron/template/src/handlers/fs/file-size.js index 298b9ff7..9292220a 100644 --- a/assets/electron/template/app/src/handlers/fs/file-size.js +++ b/assets/asset-electron/template/src/handlers/fs/file-size.js @@ -1,13 +1,13 @@ // @ts-check -import { stat } from 'node:fs/promises' +import { stat } from "node:fs/promises"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - const stats = await stat(json.body.path) + const stats = await stat(json.body.path); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -18,7 +18,7 @@ export default async (json, ws) => { body: { success: true, size: stats.size, - } - } - ws.send(JSON.stringify(readFileResult)) -} + }, + }; + ws.send(JSON.stringify(readFileResult)); +}; diff --git a/assets/electron/template/app/src/handlers/fs/folder-create.js b/assets/asset-electron/template/src/handlers/fs/folder-create.js similarity index 79% rename from assets/electron/template/app/src/handlers/fs/folder-create.js rename to assets/asset-electron/template/src/handlers/fs/folder-create.js index bec41e18..3d4d4712 100644 --- a/assets/electron/template/app/src/handlers/fs/folder-create.js +++ b/assets/asset-electron/template/src/handlers/fs/folder-create.js @@ -1,6 +1,6 @@ // @ts-check -import { mkdir } from 'node:fs/promises' +import { mkdir } from "node:fs/promises"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -9,7 +9,7 @@ import { mkdir } from 'node:fs/promises' export default async (json, ws) => { await mkdir(json.body.path, { recursive: json.body.recursive, - }) + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -18,8 +18,8 @@ export default async (json, ws) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } - ws.send(JSON.stringify(folderCreateResult)) -} + success: true, + }, + }; + ws.send(JSON.stringify(folderCreateResult)); +}; diff --git a/assets/electron/template/app/src/handlers/fs/list.js b/assets/asset-electron/template/src/handlers/fs/list.js similarity index 70% rename from assets/electron/template/app/src/handlers/fs/list.js rename to assets/asset-electron/template/src/handlers/fs/list.js index b12ed079..aac7e4f7 100644 --- a/assets/electron/template/app/src/handlers/fs/list.js +++ b/assets/asset-electron/template/src/handlers/fs/list.js @@ -1,29 +1,27 @@ // @ts-check -import { readdir } from 'node:fs/promises' -import { join, dirname, relative } from 'node:path' -import slash from 'slash' - - +import { readdir } from "node:fs/promises"; +import { join, dirname, relative } from "node:path"; +import slash from "slash"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ -export default async (json, ws) => { +export default async (json, ws) => { // Custom recursive directory listing for Node 18 compatibility async function listDirRecursive(dir, parentPath) { let results = []; const entries = await readdir(dir, { withFileTypes: true }); for (const entry of entries) { const fullpath = join(dir, entry.name); - const type = entry.isDirectory() ? 'directory' : 'file'; + const type = entry.isDirectory() ? "directory" : "file"; const relPath = slash(fullpath); results.push({ type, name: entry.name, parent: slash(parentPath), - path: relPath + path: relPath, }); if (entry.isDirectory()) { const subResults = await listDirRecursive(fullpath, fullpath); @@ -37,12 +35,14 @@ export default async (json, ws) => { try { fileList = await listDirRecursive(json.body.path, dirname(json.body.path)); } catch (err) { - console.error('Error listing files:', err); - ws.send(JSON.stringify({ - correlationId: json.correlationId, - url: json.url, - body: { success: false, error: err.message } - })); + console.error("Error listing files:", err); + ws.send( + JSON.stringify({ + correlationId: json.correlationId, + url: json.url, + body: { success: false, error: err.message }, + }), + ); return; } @@ -54,8 +54,8 @@ export default async (json, ws) => { url: json.url, body: { success: true, - list: fileList - } + list: fileList, + }, }; ws.send(JSON.stringify(readFileResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/fs/move.js b/assets/asset-electron/template/src/handlers/fs/move.js similarity index 60% rename from assets/electron/template/app/src/handlers/fs/move.js rename to assets/asset-electron/template/src/handlers/fs/move.js index 73a0464a..f04cabaa 100644 --- a/assets/electron/template/app/src/handlers/fs/move.js +++ b/assets/asset-electron/template/src/handlers/fs/move.js @@ -1,20 +1,20 @@ // @ts-check -import { moveFile } from 'move-file'; -import { mkdir } from 'node:fs/promises'; -import { dirname } from 'node:path'; +import { moveFile } from "move-file"; +import { mkdir } from "node:fs/promises"; +import { dirname } from "node:path"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - const destDirName = dirname(json.body.destination) - await mkdir(destDirName, { recursive: true }) + const destDirName = dirname(json.body.destination); + await mkdir(destDirName, { recursive: true }); await moveFile(json.body.source, json.body.destination, { - overwrite: json.body.overwrite - }) + overwrite: json.body.overwrite, + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -24,7 +24,7 @@ export default async (json, ws) => { url: json.url, body: { success: true, - } - } - ws.send(JSON.stringify(readFileResult)) -} + }, + }; + ws.send(JSON.stringify(readFileResult)); +}; diff --git a/assets/electron/template/app/src/handlers/fs/read-binary.js b/assets/asset-electron/template/src/handlers/fs/read-binary.js similarity index 76% rename from assets/electron/template/app/src/handlers/fs/read-binary.js rename to assets/asset-electron/template/src/handlers/fs/read-binary.js index 8d8c7b9c..efa5571b 100644 --- a/assets/electron/template/app/src/handlers/fs/read-binary.js +++ b/assets/asset-electron/template/src/handlers/fs/read-binary.js @@ -1,13 +1,13 @@ // @ts-check -import { readFile } from 'node:fs/promises' +import { readFile } from "node:fs/promises"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - const file = await readFile(json.body.path) + const file = await readFile(json.body.path); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -18,7 +18,7 @@ export default async (json, ws) => { body: { success: true, content: [...file], - } - } - ws.send(JSON.stringify(readFileResult)) -} + }, + }; + ws.send(JSON.stringify(readFileResult)); +}; diff --git a/assets/electron/template/app/src/handlers/fs/read.js b/assets/asset-electron/template/src/handlers/fs/read.js similarity index 77% rename from assets/electron/template/app/src/handlers/fs/read.js rename to assets/asset-electron/template/src/handlers/fs/read.js index a0b31c58..52035dd7 100644 --- a/assets/electron/template/app/src/handlers/fs/read.js +++ b/assets/asset-electron/template/src/handlers/fs/read.js @@ -1,6 +1,6 @@ // @ts-check -import { readFile } from 'node:fs/promises' +import { readFile } from "node:fs/promises"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -9,8 +9,8 @@ import { readFile } from 'node:fs/promises' export default async (json, ws) => { try { const file = await readFile(json.body.path, { - encoding: json.body.encoding - }) + encoding: json.body.encoding, + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -21,11 +21,11 @@ export default async (json, ws) => { body: { success: true, content: file, - } - } - ws.send(JSON.stringify(readFileResult)) + }, + }; + ws.send(JSON.stringify(readFileResult)); } catch (e) { - console.error('e', e) + console.error("e", e); /** * @type {import('@pipelab/core').MakeInputOutput} */ @@ -35,8 +35,8 @@ export default async (json, ws) => { body: { success: false, error: e.message, - } - } - ws.send(JSON.stringify(readFileResult)) + }, + }; + ws.send(JSON.stringify(readFileResult)); } -} +}; diff --git a/assets/electron/template/app/src/handlers/fs/write-base64.js b/assets/asset-electron/template/src/handlers/fs/write-base64.js similarity index 57% rename from assets/electron/template/app/src/handlers/fs/write-base64.js rename to assets/asset-electron/template/src/handlers/fs/write-base64.js index 25b0dc34..c3a014db 100644 --- a/assets/electron/template/app/src/handlers/fs/write-base64.js +++ b/assets/asset-electron/template/src/handlers/fs/write-base64.js @@ -1,22 +1,22 @@ // @ts-check -import { mkdir, writeFile } from 'node:fs/promises' -import { dirname } from 'node:path' +import { mkdir, writeFile } from "node:fs/promises"; +import { dirname } from "node:path"; /** * @param {{url: string, correlationId?: string, body: {path: string, base64Data: string, flag?: string}}} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - const destDirName = dirname(json.body.path) - await mkdir(destDirName, { recursive: true }) + const destDirName = dirname(json.body.path); + await mkdir(destDirName, { recursive: true }); // Decode base64 string to buffer - const buffer = Buffer.from(json.body.base64Data, 'base64') + const buffer = Buffer.from(json.body.base64Data, "base64"); await writeFile(json.body.path, buffer, { - flag: json.body.flag - }) + flag: json.body.flag, + }); /** * @type {{url: string, correlationId?: string, body: {success: boolean}}} @@ -25,8 +25,8 @@ export default async (json, ws) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } - ws.send(JSON.stringify(writeFileResult)) -} + success: true, + }, + }; + ws.send(JSON.stringify(writeFileResult)); +}; diff --git a/assets/electron/template/app/src/handlers/fs/write.js b/assets/asset-electron/template/src/handlers/fs/write.js similarity index 63% rename from assets/electron/template/app/src/handlers/fs/write.js rename to assets/asset-electron/template/src/handlers/fs/write.js index 76d522db..389a8560 100644 --- a/assets/electron/template/app/src/handlers/fs/write.js +++ b/assets/asset-electron/template/src/handlers/fs/write.js @@ -1,20 +1,20 @@ // @ts-check -import { mkdir, writeFile } from 'node:fs/promises' -import { dirname } from 'node:path' +import { mkdir, writeFile } from "node:fs/promises"; +import { dirname } from "node:path"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - const destDirName = dirname(json.body.path) - await mkdir(destDirName, { recursive: true }) + const destDirName = dirname(json.body.path); + await mkdir(destDirName, { recursive: true }); await writeFile(json.body.path, json.body.contents, { encoding: json.body.encoding, - flag: json.body.flag - }) + flag: json.body.flag, + }); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -23,8 +23,8 @@ export default async (json, ws) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } - ws.send(JSON.stringify(writeFileResult)) -} + success: true, + }, + }; + ws.send(JSON.stringify(writeFileResult)); +}; diff --git a/assets/electron/template/app/src/handlers/general/engine.js b/assets/asset-electron/template/src/handlers/general/engine.js similarity index 91% rename from assets/electron/template/app/src/handlers/general/engine.js rename to assets/asset-electron/template/src/handlers/general/engine.js index d3a66e3b..704dcb36 100644 --- a/assets/electron/template/app/src/handlers/general/engine.js +++ b/assets/asset-electron/template/src/handlers/general/engine.js @@ -10,8 +10,8 @@ export default async (json, ws) => { correlationId: json.correlationId, url: json.url, body: { - engine: 'electron' - } - } + engine: "electron", + }, + }; ws.send(JSON.stringify(engineResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/general/exit.js b/assets/asset-electron/template/src/handlers/general/exit.js similarity index 74% rename from assets/electron/template/app/src/handlers/general/exit.js rename to assets/asset-electron/template/src/handlers/general/exit.js index bcfe524a..ebaef966 100644 --- a/assets/electron/template/app/src/handlers/general/exit.js +++ b/assets/asset-electron/template/src/handlers/general/exit.js @@ -1,4 +1,4 @@ -import { app } from 'electron' +import { app } from "electron"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws @@ -11,10 +11,10 @@ export default async (json, ws) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } - ws.send(JSON.stringify(engineResult)) + success: true, + }, + }; + ws.send(JSON.stringify(engineResult)); - app.exit(json.body.code) -} + app.exit(json.body.code); +}; diff --git a/assets/electron/template/app/src/handlers/general/infos.js b/assets/asset-electron/template/src/handlers/general/infos.js similarity index 71% rename from assets/electron/template/app/src/handlers/general/infos.js rename to assets/asset-electron/template/src/handlers/general/infos.js index fc4ed5e2..70cb87c6 100644 --- a/assets/electron/template/app/src/handlers/general/infos.js +++ b/assets/asset-electron/template/src/handlers/general/infos.js @@ -1,11 +1,11 @@ -import { arch, platform } from 'os' +import { arch, platform } from "os"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws */ export default async (json, ws) => { - const myArch = arch() - const myPlatform = platform() + const myArch = arch(); + const myPlatform = platform(); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -16,8 +16,8 @@ export default async (json, ws) => { body: { arch: myArch, platform: myPlatform, - version: '0.0.0' - } - } - ws.send(JSON.stringify(engineResult)) -} + version: "0.0.0", + }, + }; + ws.send(JSON.stringify(engineResult)); +}; diff --git a/assets/electron/template/app/src/handlers/general/open-in-explorer.js b/assets/asset-electron/template/src/handlers/general/open-in-explorer.js similarity index 82% rename from assets/electron/template/app/src/handlers/general/open-in-explorer.js rename to assets/asset-electron/template/src/handlers/general/open-in-explorer.js index feb9010b..e9a82d48 100644 --- a/assets/electron/template/app/src/handlers/general/open-in-explorer.js +++ b/assets/asset-electron/template/src/handlers/general/open-in-explorer.js @@ -1,11 +1,11 @@ -import { shell } from 'electron' +import { shell } from "electron"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws -*/ + */ export default async (json, ws) => { - await shell.showItemInFolder(json.body.path) + await shell.showItemInFolder(json.body.path); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -15,7 +15,7 @@ export default async (json, ws) => { url: json.url, body: { success: true, - } - } + }, + }; ws.send(JSON.stringify(runResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/general/open.js b/assets/asset-electron/template/src/handlers/general/open.js similarity index 82% rename from assets/electron/template/app/src/handlers/general/open.js rename to assets/asset-electron/template/src/handlers/general/open.js index dd363672..be43e9b1 100644 --- a/assets/electron/template/app/src/handlers/general/open.js +++ b/assets/asset-electron/template/src/handlers/general/open.js @@ -1,11 +1,11 @@ -import { shell } from 'electron' +import { shell } from "electron"; /** * @param {import('@pipelab/core').MakeInputOutput} json * @param {import('ws').WebSocket} ws -*/ + */ export default async (json, ws) => { - await shell.openPath(json.body.path) + await shell.openPath(json.body.path); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -15,7 +15,7 @@ export default async (json, ws) => { url: json.url, body: { success: true, - } - } + }, + }; ws.send(JSON.stringify(runResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/general/run.js b/assets/asset-electron/template/src/handlers/general/run.js similarity index 90% rename from assets/electron/template/app/src/handlers/general/run.js rename to assets/asset-electron/template/src/handlers/general/run.js index a1d29c1f..638e7ccb 100644 --- a/assets/electron/template/app/src/handlers/general/run.js +++ b/assets/asset-electron/template/src/handlers/general/run.js @@ -1,4 +1,4 @@ -import { execa } from 'execa'; +import { execa } from "execa"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -8,8 +8,8 @@ export default async (json, ws) => { const exec = execa({ cwd: json.body.cwd, env: json.body.env, - }) - const { stderr, stdout } = await exec(json.body.command, json.body.args) + }); + const { stderr, stdout } = await exec(json.body.command, json.body.args); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -21,7 +21,7 @@ export default async (json, ws) => { success: true, stdout, stderr, - } - } + }, + }; ws.send(JSON.stringify(execResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/steam/deleteItem.js b/assets/asset-electron/template/src/handlers/steam/deleteItem.js similarity index 69% rename from assets/electron/template/app/src/handlers/steam/deleteItem.js rename to assets/asset-electron/template/src/handlers/steam/deleteItem.js index 46450ddd..6929da9a 100644 --- a/assets/electron/template/app/src/handlers/steam/deleteItem.js +++ b/assets/asset-electron/template/src/handlers/steam/deleteItem.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop delete item logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The delete result */ const deleteItemHandler = async (client, json) => { - const { itemId } = json.body + const { itemId } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = await client.workshop.deleteItem(itemIdBigInt) + const result = await client.workshop.deleteItem(itemIdBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const deleteItemHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, deleteItemHandler) -} + await handleSteamRequest(client, json, ws, deleteItemHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/download.js b/assets/asset-electron/template/src/handlers/steam/download.js similarity index 75% rename from assets/electron/template/app/src/handlers/steam/download.js rename to assets/asset-electron/template/src/handlers/steam/download.js index 136da506..de82eab2 100644 --- a/assets/electron/template/app/src/handlers/steam/download.js +++ b/assets/asset-electron/template/src/handlers/steam/download.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop download logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The download result */ const downloadHandler = async (client, json) => { - const { itemId, highPriority } = json.body + const { itemId, highPriority } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = client.workshop.download(itemIdBigInt, highPriority) + const result = client.workshop.download(itemIdBigInt, highPriority); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const downloadHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, downloadHandler) -} + await handleSteamRequest(client, json, ws, downloadHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/downloadInfo.js b/assets/asset-electron/template/src/handlers/steam/downloadInfo.js similarity index 77% rename from assets/electron/template/app/src/handlers/steam/downloadInfo.js rename to assets/asset-electron/template/src/handlers/steam/downloadInfo.js index e579c9ff..b128e544 100644 --- a/assets/electron/template/app/src/handlers/steam/downloadInfo.js +++ b/assets/asset-electron/template/src/handlers/steam/downloadInfo.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop download info logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The download info result */ const downloadInfoHandler = async (client, json) => { - const { itemId } = json.body + const { itemId } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = client.workshop.downloadInfo(itemIdBigInt) + const result = client.workshop.downloadInfo(itemIdBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const downloadInfoHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, downloadInfoHandler) -} + await handleSteamRequest(client, json, ws, downloadInfoHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/downloadScore.js b/assets/asset-electron/template/src/handlers/steam/downloadScore.js similarity index 73% rename from assets/electron/template/app/src/handlers/steam/downloadScore.js rename to assets/asset-electron/template/src/handlers/steam/downloadScore.js index 6ef9bbe2..3e994253 100644 --- a/assets/electron/template/app/src/handlers/steam/downloadScore.js +++ b/assets/asset-electron/template/src/handlers/steam/downloadScore.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; // * @param {Omit} client /** @@ -8,21 +8,21 @@ import { handleSteamRequest } from './utils.js' */ export default async (json, ws, client) => { await handleSteamRequest(client, json, ws, async (client, json) => { - const { body } = json - const { name, type, start, end } = body + const { body } = json; + const { name, type, start, end } = body; - const leaderboard = await client.leaderboards.findLeaderboard(name) + const leaderboard = await client.leaderboards.findLeaderboard(name); /** @type {Awaited>} */ - const result = await client.leaderboards.downloadScores(leaderboard, type, start, end) + const result = await client.leaderboards.downloadScores(leaderboard, type, start, end); // Enhance each result with the Steam friend name const enhancedResult = await Promise.all( result.map(async (entry) => ({ ...entry, - name: await client.friends.getFriendName(entry.steamId) - })) - ) + name: await client.friends.getFriendName(entry.steamId), + })), + ); - return enhancedResult - }) -} + return enhancedResult; + }); +}; diff --git a/assets/electron/template/app/src/handlers/steam/getItem.js b/assets/asset-electron/template/src/handlers/steam/getItem.js similarity index 72% rename from assets/electron/template/app/src/handlers/steam/getItem.js rename to assets/asset-electron/template/src/handlers/steam/getItem.js index 0b0c1667..4e37252d 100644 --- a/assets/electron/template/app/src/handlers/steam/getItem.js +++ b/assets/asset-electron/template/src/handlers/steam/getItem.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop get item logic @@ -7,16 +7,16 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The item result */ const getItemHandler = async (client, json) => { - const { itemId } = json.body + const { itemId } = json.body; // Convert itemId from string to BigInt - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); // TODO: Handle queryConfig parameter when needed - const result = await client.workshop.getItem(itemIdBigInt) + const result = await client.workshop.getItem(itemIdBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -24,5 +24,5 @@ const getItemHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, getItemHandler) -} + await handleSteamRequest(client, json, ws, getItemHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/getItems.js b/assets/asset-electron/template/src/handlers/steam/getItems.js similarity index 71% rename from assets/electron/template/app/src/handlers/steam/getItems.js rename to assets/asset-electron/template/src/handlers/steam/getItems.js index f8186dc7..9a8ca568 100644 --- a/assets/electron/template/app/src/handlers/steam/getItems.js +++ b/assets/asset-electron/template/src/handlers/steam/getItems.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop get items logic @@ -7,16 +7,16 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The items result */ const getItemsHandler = async (client, json) => { - const { itemIds } = json.body + const { itemIds } = json.body; // Convert array of string itemIds to array of BigInts - const itemIdsBigInt = itemIds.map((id) => BigInt(id)) + const itemIdsBigInt = itemIds.map((id) => BigInt(id)); // TODO: Handle queryConfig parameter when needed - const result = await client.workshop.getItems(itemIdsBigInt) + const result = await client.workshop.getItems(itemIdsBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -24,5 +24,5 @@ const getItemsHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, getItemsHandler) -} + await handleSteamRequest(client, json, ws, getItemsHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/installInfo.js b/assets/asset-electron/template/src/handlers/steam/installInfo.js similarity index 77% rename from assets/electron/template/app/src/handlers/steam/installInfo.js rename to assets/asset-electron/template/src/handlers/steam/installInfo.js index 5d612f1c..09155a1f 100644 --- a/assets/electron/template/app/src/handlers/steam/installInfo.js +++ b/assets/asset-electron/template/src/handlers/steam/installInfo.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop install info logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The install info result */ const installInfoHandler = async (client, json) => { - const { itemId } = json.body + const { itemId } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = client.workshop.installInfo(itemIdBigInt) + const result = client.workshop.installInfo(itemIdBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const installInfoHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, installInfoHandler) -} + await handleSteamRequest(client, json, ws, installInfoHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/raw.js b/assets/asset-electron/template/src/handlers/steam/raw.js similarity index 77% rename from assets/electron/template/app/src/handlers/steam/raw.js rename to assets/asset-electron/template/src/handlers/steam/raw.js index 3f2ed2ee..6a185931 100644 --- a/assets/electron/template/app/src/handlers/steam/raw.js +++ b/assets/asset-electron/template/src/handlers/steam/raw.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -6,17 +6,17 @@ import { handleSteamRequest } from './utils.js' * @param {Omit} client */ export default async (json, ws, client) => { - console.log('json', json) + console.log("json", json); await handleSteamRequest( client, json, ws, async (client, json) => { - const { body } = json - const { args, method, namespace } = body + const { body } = json; + const { args, method, namespace } = body; - const result = await client[namespace][method](...args) + const result = await client[namespace][method](...args); // if (namespace === 'localplayer' && method === 'getSteamId') { // console.log('result', result) @@ -35,8 +35,8 @@ export default async (json, ws, client) => { // } // } - return result + return result; }, - true - ) -} + true, + ); +}; diff --git a/assets/electron/template/app/src/handlers/steam/saveScreenshot.js b/assets/asset-electron/template/src/handlers/steam/saveScreenshot.js similarity index 55% rename from assets/electron/template/app/src/handlers/steam/saveScreenshot.js rename to assets/asset-electron/template/src/handlers/steam/saveScreenshot.js index 193a9d73..c1fbe840 100644 --- a/assets/electron/template/app/src/handlers/steam/saveScreenshot.js +++ b/assets/asset-electron/template/src/handlers/steam/saveScreenshot.js @@ -1,8 +1,8 @@ -import { handleSteamRequest } from './utils.js' -import { writeFileSync, unlinkSync, mkdirSync, rmdirSync } from 'node:fs' -import { join } from 'node:path' -import { tmpdir } from 'node:os' -import { randomUUID } from 'node:crypto' +import { handleSteamRequest } from "./utils.js"; +import { writeFileSync, unlinkSync, mkdirSync, rmdirSync } from "node:fs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; +import { randomUUID } from "node:crypto"; /** * Save screenshot from base64 data URL to Steam library @@ -11,50 +11,50 @@ import { randomUUID } from 'node:crypto' * @returns {Promise} The screenshot handle */ const saveScreenshotHandler = async (client, json) => { - const { body } = json - const { dataUrl, width, height } = body + const { body } = json; + const { dataUrl, width, height } = body; // Validate input - if (!dataUrl || typeof dataUrl !== 'string') { - throw new Error('dataUrl is required and must be a string') + if (!dataUrl || typeof dataUrl !== "string") { + throw new Error("dataUrl is required and must be a string"); } - if (!dataUrl.startsWith('data:image/')) { - throw new Error('dataUrl must be a base64 data URL (data:image/...)') + if (!dataUrl.startsWith("data:image/")) { + throw new Error("dataUrl must be a base64 data URL (data:image/...)"); } // Extract base64 data - const matches = dataUrl.match(/^data:image\/(\w+);base64,(.+)$/) + const matches = dataUrl.match(/^data:image\/(\w+);base64,(.+)$/); if (!matches) { - throw new Error('Invalid base64 data URL format') + throw new Error("Invalid base64 data URL format"); } - const [, format, base64Data] = matches - const buffer = Buffer.from(base64Data, 'base64') + const [, format, base64Data] = matches; + const buffer = Buffer.from(base64Data, "base64"); // Create temp file - const tempDir = join(tmpdir(), 'pipelab-screenshots') - mkdirSync(tempDir, { recursive: true }) - const tempPath = join(tempDir, `screenshot-${randomUUID()}.${format}`) + const tempDir = join(tmpdir(), "pipelab-screenshots"); + mkdirSync(tempDir, { recursive: true }); + const tempPath = join(tempDir, `screenshot-${randomUUID()}.${format}`); // Write to temp file - writeFileSync(tempPath, buffer) + writeFileSync(tempPath, buffer); // Add to Steam library - const handle = client.screenshots.addScreenshotToLibrary(tempPath, null, width, height) + const handle = client.screenshots.addScreenshotToLibrary(tempPath, null, width, height); // Delete temp file after a delay to allow Steam to process it setTimeout(() => { try { - unlinkSync(tempPath) - rmdirSync(tempDir) + unlinkSync(tempPath); + rmdirSync(tempDir); } catch { // Ignore cleanup errors } - }, 5000) + }, 5000); - return handle -} + return handle; +}; /** * @param {Object} json @@ -62,5 +62,5 @@ const saveScreenshotHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, saveScreenshotHandler) -} + await handleSteamRequest(client, json, ws, saveScreenshotHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/state.js b/assets/asset-electron/template/src/handlers/steam/state.js similarity index 70% rename from assets/electron/template/app/src/handlers/steam/state.js rename to assets/asset-electron/template/src/handlers/steam/state.js index 81981da7..414eef87 100644 --- a/assets/electron/template/app/src/handlers/steam/state.js +++ b/assets/asset-electron/template/src/handlers/steam/state.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop state logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The state result */ const stateHandler = async (client, json) => { - const { itemId } = json.body + const { itemId } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = client.workshop.state(itemIdBigInt) + const result = client.workshop.state(itemIdBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const stateHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, stateHandler) -} + await handleSteamRequest(client, json, ws, stateHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/subscribe.js b/assets/asset-electron/template/src/handlers/steam/subscribe.js similarity index 69% rename from assets/electron/template/app/src/handlers/steam/subscribe.js rename to assets/asset-electron/template/src/handlers/steam/subscribe.js index 9765c69a..34ee8758 100644 --- a/assets/electron/template/app/src/handlers/steam/subscribe.js +++ b/assets/asset-electron/template/src/handlers/steam/subscribe.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop subscribe logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The subscribe result */ const subscribeHandler = async (client, json) => { - const { itemId } = json.body + const { itemId } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = await client.workshop.subscribe(itemIdBigInt) + const result = await client.workshop.subscribe(itemIdBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const subscribeHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, subscribeHandler) -} + await handleSteamRequest(client, json, ws, subscribeHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/unsubscribe.js b/assets/asset-electron/template/src/handlers/steam/unsubscribe.js similarity index 83% rename from assets/electron/template/app/src/handlers/steam/unsubscribe.js rename to assets/asset-electron/template/src/handlers/steam/unsubscribe.js index 91f8def6..a966b4b5 100644 --- a/assets/electron/template/app/src/handlers/steam/unsubscribe.js +++ b/assets/asset-electron/template/src/handlers/steam/unsubscribe.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop unsubscribe logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The unsubscribe result */ const unsubscribeHandler = async (client, json) => { - const { itemId } = json.body + const { itemId } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = await client.workshop.unsubscribe(itemIdBigInt) + const result = await client.workshop.unsubscribe(itemIdBigInt); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const unsubscribeHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, unsubscribeHandler) -} + await handleSteamRequest(client, json, ws, unsubscribeHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/updateItem.js b/assets/asset-electron/template/src/handlers/steam/updateItem.js similarity index 73% rename from assets/electron/template/app/src/handlers/steam/updateItem.js rename to assets/asset-electron/template/src/handlers/steam/updateItem.js index 6a93e10f..4189997d 100644 --- a/assets/electron/template/app/src/handlers/steam/updateItem.js +++ b/assets/asset-electron/template/src/handlers/steam/updateItem.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam workshop update item logic @@ -7,14 +7,14 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The update result */ const updateItemHandler = async (client, json) => { - const { itemId, updateDetails, appID } = json.body + const { itemId, updateDetails, appID } = json.body; - const itemIdBigInt = BigInt(itemId) + const itemIdBigInt = BigInt(itemId); - const result = await client.workshop.updateItem(itemIdBigInt, updateDetails, appID) + const result = await client.workshop.updateItem(itemIdBigInt, updateDetails, appID); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -22,5 +22,5 @@ const updateItemHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, updateItemHandler) -} + await handleSteamRequest(client, json, ws, updateItemHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/uploadScore.js b/assets/asset-electron/template/src/handlers/steam/uploadScore.js similarity index 81% rename from assets/electron/template/app/src/handlers/steam/uploadScore.js rename to assets/asset-electron/template/src/handlers/steam/uploadScore.js index 8e70caeb..6ff86878 100644 --- a/assets/electron/template/app/src/handlers/steam/uploadScore.js +++ b/assets/asset-electron/template/src/handlers/steam/uploadScore.js @@ -1,4 +1,4 @@ -import { handleSteamRequest } from './utils.js' +import { handleSteamRequest } from "./utils.js"; /** * Core Steam leaderboard upload logic @@ -7,15 +7,15 @@ import { handleSteamRequest } from './utils.js' * @returns {Promise} The upload result */ const uploadScoreHandler = async (client, json) => { - const { body } = json - const { name, score, type, metadata } = body + const { body } = json; + const { name, score, type, metadata } = body; - const leaderboard = await client.leaderboards.findLeaderboard(name) + const leaderboard = await client.leaderboards.findLeaderboard(name); - const result = await client.leaderboards.uploadScore(leaderboard, score, type, metadata) + const result = await client.leaderboards.uploadScore(leaderboard, score, type, metadata); - return result -} + return result; +}; /** * @param {import('@pipelab/core').MakeInputOutput} json @@ -23,5 +23,5 @@ const uploadScoreHandler = async (client, json) => { * @param {Omit} client */ export default async (json, ws, client) => { - await handleSteamRequest(client, json, ws, uploadScoreHandler) -} + await handleSteamRequest(client, json, ws, uploadScoreHandler); +}; diff --git a/assets/electron/template/app/src/handlers/steam/utils.js b/assets/asset-electron/template/src/handlers/steam/utils.js similarity index 70% rename from assets/electron/template/app/src/handlers/steam/utils.js rename to assets/asset-electron/template/src/handlers/steam/utils.js index e5034233..e5026dec 100644 --- a/assets/electron/template/app/src/handlers/steam/utils.js +++ b/assets/asset-electron/template/src/handlers/steam/utils.js @@ -7,11 +7,11 @@ function checkSteamClient(client) { if (client === undefined || client === null) { return { success: false, - error: 'Steam client is not initialized or available' - } + error: "Steam client is not initialized or available", + }; } - return null + return null; } /** @@ -25,21 +25,21 @@ function checkSteamClient(client) { */ function handleSteamRequest(client, json, ws, handlerFunction, useRawErrorFormat = false) { // Check if Steam client is initialized - const clientError = checkSteamClient(client) + const clientError = checkSteamClient(client); if (clientError) { const errorResult = { url: json.url, correlationId: json.correlationId, body: useRawErrorFormat ? { - data: null, - success: false, - error: clientError.error - } - : clientError - } - ws.send(JSON.stringify(errorResult)) - return Promise.resolve() + data: null, + success: false, + error: clientError.error, + } + : clientError, + }; + ws.send(JSON.stringify(errorResult)); + return Promise.resolve(); } // Execute the handler function and format the response @@ -50,29 +50,29 @@ function handleSteamRequest(client, json, ws, handlerFunction, useRawErrorFormat correlationId: json.correlationId, body: { data: result, - success: true - } - } - ws.send(JSON.stringify(steamResult, (_, v) => (typeof v === 'bigint' ? v.toString() : v))) + success: true, + }, + }; + ws.send(JSON.stringify(steamResult, (_, v) => (typeof v === "bigint" ? v.toString() : v))); }) .catch((error) => { - console.error('Error in Steam handler:', error) + console.error("Error in Steam handler:", error); const errorResult = { url: json.url, correlationId: json.correlationId, body: useRawErrorFormat ? { - data: null, - success: false, - error: error.message || 'Unknown error occurred' - } + data: null, + success: false, + error: error.message || "Unknown error occurred", + } : { - success: false, - error: error.message || 'Unknown error occurred' - } - } - ws.send(JSON.stringify(errorResult)) - }) + success: false, + error: error.message || "Unknown error occurred", + }, + }; + ws.send(JSON.stringify(errorResult)); + }); } -export { checkSteamClient, handleSteamRequest } +export { checkSteamClient, handleSteamRequest }; diff --git a/assets/asset-electron/template/src/handlers/user/folder.js b/assets/asset-electron/template/src/handlers/user/folder.js new file mode 100644 index 00000000..adf17b0d --- /dev/null +++ b/assets/asset-electron/template/src/handlers/user/folder.js @@ -0,0 +1,71 @@ +// @ts-check + +import { app } from "electron"; +import { join } from "path"; + +import slash from "slash"; +import { getAppName } from "../../utils.js"; + +/** + * @param {import('@pipelab/core').MakeInputOutput} json + * @param {import('ws').WebSocket} ws + * @param {ElectronAppConfig.Config} config + */ +export default (json, ws, config) => { + try { + const name = json.body.name; + + let folder; + + const { env } = process; + // windows linux + const { APPDATA, LOCALAPPDATA, XDG_DATA_HOME, XDG_CONFIG_HOME } = env; + const appDataBackup = app.getPath("appData"); + const localAppData = LOCALAPPDATA ?? XDG_DATA_HOME ?? appDataBackup; + const appData = APPDATA ?? XDG_CONFIG_HOME ?? appDataBackup; + + const appNameFolder = getAppName(config); + + const localUserData = join(localAppData, appNameFolder); + const userData = join(appData, appNameFolder); + + if (name === "app") { + folder = app.getAppPath(); + } else if (name === "project") { + folder = join(app.getAppPath(), "src", "app"); // path to construct files + } else if (name === "localAppData") { + folder = localAppData; + } else if (name === "localUserData") { + folder = localUserData; + } else if (name === "userData") { + folder = userData; + } else { + folder = app.getPath(name); + } + + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const userFolderResult = { + url: json.url, + correlationId: json.correlationId, + body: { + data: slash(folder), + }, + }; + ws.send(JSON.stringify(userFolderResult)); + } catch (e) { + console.error("e", e); + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const userFolderResult = { + url: json.url, + correlationId: json.correlationId, + body: { + error: e.message, + }, + }; + ws.send(JSON.stringify(userFolderResult)); + } +}; diff --git a/assets/electron/template/app/src/handlers/window/maximize.js b/assets/asset-electron/template/src/handlers/window/maximize.js similarity index 93% rename from assets/electron/template/app/src/handlers/window/maximize.js rename to assets/asset-electron/template/src/handlers/window/maximize.js index 390761be..a106ea1d 100644 --- a/assets/electron/template/app/src/handlers/window/maximize.js +++ b/assets/asset-electron/template/src/handlers/window/maximize.js @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(maximizeResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/minimize.js b/assets/asset-electron/template/src/handlers/window/minimize.js similarity index 93% rename from assets/electron/template/app/src/handlers/window/minimize.js rename to assets/asset-electron/template/src/handlers/window/minimize.js index 9b37840e..6a443f6c 100644 --- a/assets/electron/template/app/src/handlers/window/minimize.js +++ b/assets/asset-electron/template/src/handlers/window/minimize.js @@ -13,9 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(minimizeResult)); - -} +}; diff --git a/assets/electron/template/app/src/handlers/window/request-attention.js b/assets/asset-electron/template/src/handlers/window/request-attention.js similarity index 94% rename from assets/electron/template/app/src/handlers/window/request-attention.js rename to assets/asset-electron/template/src/handlers/window/request-attention.js index 11c0c9d5..9afc2ff3 100644 --- a/assets/electron/template/app/src/handlers/window/request-attention.js +++ b/assets/asset-electron/template/src/handlers/window/request-attention.js @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(requestAttentionResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/restore.js b/assets/asset-electron/template/src/handlers/window/restore.js similarity index 93% rename from assets/electron/template/app/src/handlers/window/restore.js rename to assets/asset-electron/template/src/handlers/window/restore.js index 02c38959..e839bca3 100644 --- a/assets/electron/template/app/src/handlers/window/restore.js +++ b/assets/asset-electron/template/src/handlers/window/restore.js @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(restoreResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-always-on-top.js b/assets/asset-electron/template/src/handlers/window/set-always-on-top.js similarity index 94% rename from assets/electron/template/app/src/handlers/window/set-always-on-top.js rename to assets/asset-electron/template/src/handlers/window/set-always-on-top.js index 75259517..0b1147aa 100644 --- a/assets/electron/template/app/src/handlers/window/set-always-on-top.js +++ b/assets/asset-electron/template/src/handlers/window/set-always-on-top.js @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setAlwaysOnTopResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-fullscreen.js b/assets/asset-electron/template/src/handlers/window/set-fullscreen.js similarity index 70% rename from assets/electron/template/app/src/handlers/window/set-fullscreen.js rename to assets/asset-electron/template/src/handlers/window/set-fullscreen.js index e6e550c2..108ac9ae 100644 --- a/assets/electron/template/app/src/handlers/window/set-fullscreen.js +++ b/assets/asset-electron/template/src/handlers/window/set-fullscreen.js @@ -4,12 +4,12 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - if (json.body.value === 'fullscreen') { - mainWindow.setFullScreen(true) - } else if (json.body.value === 'normal') { - mainWindow.setFullScreen(false) + if (json.body.value === "fullscreen") { + mainWindow.setFullScreen(true); + } else if (json.body.value === "normal") { + mainWindow.setFullScreen(false); } else { - throw new Error('Unsupported value ') + throw new Error("Unsupported value "); } /** @@ -19,8 +19,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(showsetFullscreenResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-height.js b/assets/asset-electron/template/src/handlers/window/set-height.js similarity index 88% rename from assets/electron/template/app/src/handlers/window/set-height.js rename to assets/asset-electron/template/src/handlers/window/set-height.js index 52fae98b..d63d6a86 100644 --- a/assets/electron/template/app/src/handlers/window/set-height.js +++ b/assets/asset-electron/template/src/handlers/window/set-height.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - const [width] = mainWindow.getSize() + const [width] = mainWindow.getSize(); mainWindow.setSize(width, json.body.value); /** @@ -14,8 +14,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setHeightResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-ignore-mouse-events.js b/assets/asset-electron/template/src/handlers/window/set-ignore-mouse-events.js similarity index 70% rename from assets/electron/template/app/src/handlers/window/set-ignore-mouse-events.js rename to assets/asset-electron/template/src/handlers/window/set-ignore-mouse-events.js index b499dcc1..0ce2e881 100644 --- a/assets/electron/template/app/src/handlers/window/set-ignore-mouse-events.js +++ b/assets/asset-electron/template/src/handlers/window/set-ignore-mouse-events.js @@ -7,16 +7,16 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - const { ignore, forward } = json.body + const { ignore, forward } = json.body; - mainWindow.setIgnoreMouseEvents(ignore, { forward }) + mainWindow.setIgnoreMouseEvents(ignore, { forward }); const result = { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } - ws.send(JSON.stringify(result)) -} + success: true, + }, + }; + ws.send(JSON.stringify(result)); +}; diff --git a/assets/electron/template/app/src/handlers/window/set-maximum-size.js b/assets/asset-electron/template/src/handlers/window/set-maximum-size.js similarity index 84% rename from assets/electron/template/app/src/handlers/window/set-maximum-size.js rename to assets/asset-electron/template/src/handlers/window/set-maximum-size.js index b31b8a27..564a9ef6 100644 --- a/assets/electron/template/app/src/handlers/window/set-maximum-size.js +++ b/assets/asset-electron/template/src/handlers/window/set-maximum-size.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - mainWindow.setMaximumSize(json.body.width, json.body.height) + mainWindow.setMaximumSize(json.body.width, json.body.height); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setMaximumSizeResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-minimum-size.js b/assets/asset-electron/template/src/handlers/window/set-minimum-size.js similarity index 84% rename from assets/electron/template/app/src/handlers/window/set-minimum-size.js rename to assets/asset-electron/template/src/handlers/window/set-minimum-size.js index df4ead32..bdc7b2a1 100644 --- a/assets/electron/template/app/src/handlers/window/set-minimum-size.js +++ b/assets/asset-electron/template/src/handlers/window/set-minimum-size.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - mainWindow.setMinimumSize(json.body.width, json.body.height) + mainWindow.setMinimumSize(json.body.width, json.body.height); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setMinimumSizeResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-resizable.js b/assets/asset-electron/template/src/handlers/window/set-resizable.js similarity index 88% rename from assets/electron/template/app/src/handlers/window/set-resizable.js rename to assets/asset-electron/template/src/handlers/window/set-resizable.js index bd24fe90..f639a73c 100644 --- a/assets/electron/template/app/src/handlers/window/set-resizable.js +++ b/assets/asset-electron/template/src/handlers/window/set-resizable.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - mainWindow.setResizable(true) + mainWindow.setResizable(true); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setResizableResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-title.js b/assets/asset-electron/template/src/handlers/window/set-title.js similarity index 87% rename from assets/electron/template/app/src/handlers/window/set-title.js rename to assets/asset-electron/template/src/handlers/window/set-title.js index e9a4229a..08e03b06 100644 --- a/assets/electron/template/app/src/handlers/window/set-title.js +++ b/assets/asset-electron/template/src/handlers/window/set-title.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - mainWindow.setTitle(json.body.value) + mainWindow.setTitle(json.body.value); /** * @type {import('@pipelab/core').MakeInputOutput} @@ -13,8 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setTitleResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-width.js b/assets/asset-electron/template/src/handlers/window/set-width.js similarity index 87% rename from assets/electron/template/app/src/handlers/window/set-width.js rename to assets/asset-electron/template/src/handlers/window/set-width.js index 83917bb9..32e72710 100644 --- a/assets/electron/template/app/src/handlers/window/set-width.js +++ b/assets/asset-electron/template/src/handlers/window/set-width.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - const [, height] = mainWindow.getSize() + const [, height] = mainWindow.getSize(); mainWindow.setSize(json.body.value, height); /** @@ -14,8 +14,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setWidthResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-x.js b/assets/asset-electron/template/src/handlers/window/set-x.js similarity index 87% rename from assets/electron/template/app/src/handlers/window/set-x.js rename to assets/asset-electron/template/src/handlers/window/set-x.js index f6691997..6d549f3b 100644 --- a/assets/electron/template/app/src/handlers/window/set-x.js +++ b/assets/asset-electron/template/src/handlers/window/set-x.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - const [x, y] = mainWindow.getPosition() + const [x, y] = mainWindow.getPosition(); mainWindow.setPosition(json.body.value, y); /** @@ -14,8 +14,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setXResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/set-y.js b/assets/asset-electron/template/src/handlers/window/set-y.js similarity index 87% rename from assets/electron/template/app/src/handlers/window/set-y.js rename to assets/asset-electron/template/src/handlers/window/set-y.js index c5be57dc..af88a011 100644 --- a/assets/electron/template/app/src/handlers/window/set-y.js +++ b/assets/asset-electron/template/src/handlers/window/set-y.js @@ -4,7 +4,7 @@ * @param {import('electron').BrowserWindow} mainWindow */ export default async (json, ws, mainWindow) => { - const [x, y] = mainWindow.getPosition() + const [x, y] = mainWindow.getPosition(); mainWindow.setPosition(x, json.body.value); /** @@ -14,8 +14,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(setYResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/show-dev-tools.js b/assets/asset-electron/template/src/handlers/window/show-dev-tools.js similarity index 82% rename from assets/electron/template/app/src/handlers/window/show-dev-tools.js rename to assets/asset-electron/template/src/handlers/window/show-dev-tools.js index bcc02856..2fc37e85 100644 --- a/assets/electron/template/app/src/handlers/window/show-dev-tools.js +++ b/assets/asset-electron/template/src/handlers/window/show-dev-tools.js @@ -5,9 +5,9 @@ */ export default async (json, ws, mainWindow) => { if (json.body.value === true) { - mainWindow.webContents.openDevTools() + mainWindow.webContents.openDevTools(); } else { - mainWindow.webContents.closeDevTools() + mainWindow.webContents.closeDevTools(); } /** @@ -17,8 +17,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(showDevtoolsResult)); -} +}; diff --git a/assets/electron/template/app/src/handlers/window/unmaximize.js b/assets/asset-electron/template/src/handlers/window/unmaximize.js similarity index 93% rename from assets/electron/template/app/src/handlers/window/unmaximize.js rename to assets/asset-electron/template/src/handlers/window/unmaximize.js index f244f326..8b79a35c 100644 --- a/assets/electron/template/app/src/handlers/window/unmaximize.js +++ b/assets/asset-electron/template/src/handlers/window/unmaximize.js @@ -13,9 +13,8 @@ export default async (json, ws, mainWindow) => { correlationId: json.correlationId, url: json.url, body: { - success: true - } - } + success: true, + }, + }; ws.send(JSON.stringify(unmaximizeResult)); - -} +}; diff --git a/assets/asset-electron/template/src/index.js b/assets/asset-electron/template/src/index.js new file mode 100644 index 00000000..95682d78 --- /dev/null +++ b/assets/asset-electron/template/src/index.js @@ -0,0 +1,958 @@ +// @ts-check + +import { app, BrowserWindow, ipcMain, safeStorage, session, shell } from "electron"; +import { dirname, join } from "node:path"; +import path from "node:path"; +import { createReadStream } from "node:fs"; +import { stat } from "node:fs/promises"; +import mime from "mime-types"; +import serve from "serve-handler"; +import { createServer } from "http"; +import { WebSocketServer, WebSocket } from "ws"; +import "./custom-main.js"; +import mri from "mri"; +import config from "../config.cjs"; +import steamworks from "@pipelab/steamworks.js"; +import DiscordRPC from "discord-rpc"; + +// user +import userFolder from "./handlers/user/folder.js"; + +// fs +import fsWrite from "./handlers/fs/write.js"; +import fsWriteBase64 from "./handlers/fs/write-base64.js"; +import fsRead from "./handlers/fs/read.js"; +import fsReadBinary from "./handlers/fs/read-binary.js"; +import fsFolderCreate from "./handlers/fs/folder-create.js"; +import fsList from "./handlers/fs/list.js"; +import fsMove from "./handlers/fs/move.js"; +import fsDelete from "./handlers/fs/delete.js"; +import fsCopy from "./handlers/fs/copy.js"; +import fsFileSize from "./handlers/fs/file-size.js"; +import fsExist from "./handlers/fs/exist.js"; + +// window +import windowMaximize from "./handlers/window/maximize.js"; +import windowMinimize from "./handlers/window/minimize.js"; +import windowRequestAttention from "./handlers/window/request-attention.js"; +import windowRestore from "./handlers/window/restore.js"; +import windowSetAlwaysOnTop from "./handlers/window/set-always-on-top.js"; +import windowSetHeight from "./handlers/window/set-height.js"; +import windowSetWidth from "./handlers/window/set-width.js"; +import windowSetMinimumSize from "./handlers/window/set-minimum-size.js"; +import windowSetMaximumSize from "./handlers/window/set-maximum-size.js"; +import windowSetResizable from "./handlers/window/set-resizable.js"; +import windowSetTitle from "./handlers/window/set-title.js"; +import windowSetX from "./handlers/window/set-x.js"; +import windowSetY from "./handlers/window/set-y.js"; +import windowShowDevTools from "./handlers/window/show-dev-tools.js"; +import windowUnmaximize from "./handlers/window/unmaximize.js"; +import windowSetFullscreen from "./handlers/window/set-fullscreen.js"; +import windowSetIgnoreMouseEvents from "./handlers/window/set-ignore-mouse-events.js"; + +// dialog +import dialogFolder from "./handlers/dialog/folder.js"; +import dialogOpen from "./handlers/dialog/open.js"; +import dialogSave from "./handlers/dialog/save.js"; + +// general +import engine from "./handlers/general/engine.js"; +import run from "./handlers/general/run.js"; +import open from "./handlers/general/open.js"; +import showInExplorer from "./handlers/general/open-in-explorer.js"; +import exit from "./handlers/general/exit.js"; + +// steam raw +import steamRaw from "./handlers/steam/raw.js"; +import steamUploadScore from "./handlers/steam/uploadScore.js"; +import steamDownloadScore from "./handlers/steam/downloadScore.js"; +import steamUpdateItem from "./handlers/steam/updateItem.js"; +import steamGetItem from "./handlers/steam/getItem.js"; +import steamGetItems from "./handlers/steam/getItems.js"; +import steamSubscribe from "./handlers/steam/subscribe.js"; +import steamUnsubscribe from "./handlers/steam/unsubscribe.js"; +import steamState from "./handlers/steam/state.js"; +import steamInstallInfo from "./handlers/steam/installInfo.js"; +import steamDownloadInfo from "./handlers/steam/downloadInfo.js"; +import steamDownload from "./handlers/steam/download.js"; +import steamDeleteItem from "./handlers/steam/deleteItem.js"; +import steamSaveScreenshot from "./handlers/steam/saveScreenshot.js"; + +// discord set activity +import discordSetActivity from "./handlers/discord/set-activity.js"; + +import { getAppName } from "./utils.js"; + +import infos from "./handlers/general/infos.js"; + +import semver from "semver"; +import { protocol } from "electron/main"; + +/** + * Assert switch is exhaustive + * @param {never} _x + * @returns {never} + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function assertUnreachable(_x) { + throw new Error("Didn't expect to get here"); +} + +safeStorage.setUsePlainTextEncryption(true); + +protocol.registerSchemesAsPrivileged([ + { + scheme: "app", + privileges: { + standard: true, // Permet de résoudre les origines correctement (corrige l'erreur 'null') + secure: true, // Traité comme une origine sécurisée (nécessaire pour Service Workers/Web Workers) + supportFetchAPI: true, // Active l'API Fetch pour ce protocole + corsEnabled: true, // Autorise les requêtes CORS si nécessaire + allowServiceWorkers: true, // Souvent requis par Construct 3 + }, + }, +]); + +function createErrorWindow(errorMessage) { + const errorWindow = new BrowserWindow({ + width: 600, + height: 250, + title: "Game Startup Error", + center: true, + resizable: false, + webPreferences: { + preload: join(metaDirname, "preload.js"), + }, + }); + + const htmlContent = ` + + + + Error + + + +

${errorMessage}

+
+ +
+ + + + `; + + // Encode the HTML and load it as a data URL + const encodedHtml = encodeURIComponent(htmlContent); + errorWindow.loadURL(`data:text/html,${encodedHtml}`); + return errorWindow; +} + +process.on("uncaughtException", async (error) => { + console.error("Uncaught Exception:", error, error.code); + + if (error.code === "EADDRINUSE") { + const errorWindow = await createErrorWindow( + "Unable to start the game.
Is another instance already running?", + ); + errorWindow.show(); + errorWindow.on("closed", () => { + app.quit(); + }); + } +}); +process.on("unhandledRejection", (reason) => { + console.error("Unhandled Promise Rejection:", reason); +}); + +console.log("process.argv", process.argv); +const argv = process.argv; + +/** + * @typedef {Object} Args + * + * @property {string} url + * @property {boolean} no-window + */ + +/** @type {mri.Argv} */ +const cliArgs = mri(argv, { + alias: { + u: "url", + }, +}); + +/** @type {undefined | Object} */ +let rpc; +if (config.enableDiscordSupport) { + DiscordRPC.register(config.discordAppId); + rpc = new DiscordRPC.Client({ transport: "ipc" }); + console.log("rpc", rpc); +} + +//region commandLine Flags +if (config.enableInProcessGPU) { + app.commandLine.appendSwitch("in-process-gpu"); +} +if (config.enableDisableRendererBackgrounding) { + app.commandLine.appendSwitch("disable-renderer-backgrounding"); +} +if (config.forceHighPerformanceGpu) { + app.commandLine.appendSwitch("force-high-performance-gpu"); +} + +// Fix steam remote play together +app.commandLine.appendSwitch("disable-features", "AudioServiceOutOfProcess"); + +app.commandLine.appendSwitch("force-high-performance-gpu"); +app.commandLine.appendSwitch("disable-gpu-sandbox"); +//endregion + +const hasElectronVersion = config.electronVersion !== undefined && config.electronVersion !== ""; +const isCJSOnly = + hasElectronVersion && semver.lt(semver.coerce(config.electronVersion) || "0.0.0", "28.0.0"); + +//region Steam + +/** @type {Omit} */ +let client; +console.log("config.enableSteamSupport", config.enableSteamSupport); +if (config.enableSteamSupport) { + app.commandLine.appendSwitch("in-process-gpu"); + //app.commandLine.appendSwitch('disable-direct-composition') + app.commandLine.appendSwitch("no-sandbox"); + + // const isNecessary = steamworks.restartAppIfNecessary(config.steamGameId) + // console.log('isNecessary', isNecessary) + + // if (isNecessary) { + + // } + + try { + client = steamworks.init(config.steamGameId); + console.log(client.localplayer.getName()); + client.callback.register(client.callback.SteamCallback.GameOverlayActivated, (data) => { + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const order = { + url: "/steam/overlay-activated", + body: data, + }; + broadcastMessage(JSON.stringify(order)); + }); + } catch (e) { + console.error("e", e); + } +} +//endregion + +const userData = app.getPath("userData"); +const userDataDirname = dirname(userData); +const appNameFolder = getAppName(config); +const sessionDataPath = join(userDataDirname, `cache_${appNameFolder}`); +console.log("sessionDataPath", sessionDataPath); +app.setPath("userData", sessionDataPath); + +/** + * @type {Set} + */ +const clients = new Set(); + +/** + * @type {import('http').Server | null} + */ +let httpServer = null; + +/** + * @type {import('ws').WebSocketServer | null} + */ +let wss = null; + +/** + * @type {boolean} + */ +let isQuitting = false; + +/** + * @type {Promise | null} + */ +let cleanupPromise = null; + +/** + * @param {string} message + */ +const broadcastMessage = (message) => { + for (const client of clients) { + if (client.readyState === WebSocket.OPEN) { + client.send(message); + } + } +}; + +const metaDirname = isCJSOnly ? __dirname : import.meta.dirname; +const dir = app.isPackaged ? join(metaDirname, "./app") : "./src/app"; + +/** + * @param {BrowserWindow} mainWindow + * @returns {Promise} + */ +const createAppServer = (mainWindow, serveStatic = true) => { + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { + httpServer = createServer(); + const server = httpServer; + + if (serveStatic) { + server.on("request", (req, res) => { + return serve(req, res, { + headers: [ + { + source: "**/*", + headers: [ + { + key: "Cache-Control", + value: "no-cache", + }, + { + key: "Access-Control-Allow-Origin", + value: "*", + }, + ], + }, + ], + public: dir, + }); + }); + } else { + server.on("request", (req, res) => { + res.setHeader("Access-Control-Allow-Origin", "*"); // or 'https://preview.construct.net' + res.setHeader("Access-Control-Allow-Private-Network", "true"); + res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); + res.setHeader("Access-Control-Allow-Headers", "Content-Type"); + if (req.method === "OPTIONS") { + res.writeHead(204); + res.end(); + return; + } + res.writeHead(200, { "Content-Type": "text/plain" }); + res.end("Pipelab Electron App Server\n"); + }); + } + + try { + wss = new WebSocketServer({ server }); + wss.on("connection", function connection(ws) { + clients.add(ws); + + ws.on("error", console.error); + + ws.on("message", async (data) => { + //region Message handlers + /** @type {import('@pipelab/core').Message} */ + const json = JSON.parse(data.toString()); + console.log("received:", json); + + try { + switch (json.url) { + case "/paths": + await userFolder(json, ws, config); + break; + + case "/fs/file/write": + await fsWrite(json, ws); + break; + + case "/fs/file/write-base64": + await fsWriteBase64(json, ws); + break; + + case "/fs/file/read": + await fsRead(json, ws); + break; + + case "/fs/file/read/binary": + await fsReadBinary(json, ws); + break; + + case "/fs/folder/create": + await fsFolderCreate(json, ws); + break; + + case "/window/maximize": + await windowMaximize(json, ws, mainWindow); + break; + + case "/window/minimize": + await windowMinimize(json, ws, mainWindow); + break; + case "/window/request-attention": + await windowRequestAttention(json, ws, mainWindow); + break; + case "/window/restore": + await windowRestore(json, ws, mainWindow); + break; + case "/dialog/folder": + await dialogFolder(json, ws); + break; + case "/dialog/open": + await dialogOpen(json, ws); + break; + case "/dialog/save": + await dialogSave(json, ws); + break; + case "/window/set-always-on-top": + await windowSetAlwaysOnTop(json, ws, mainWindow); + break; + case "/window/set-height": + await windowSetHeight(json, ws, mainWindow); + break; + case "/window/set-maximum-size": + await windowSetMaximumSize(json, ws, mainWindow); + break; + case "/window/set-minimum-size": + await windowSetMinimumSize(json, ws, mainWindow); + break; + case "/window/set-resizable": + await windowSetResizable(json, ws, mainWindow); + break; + case "/window/set-title": + await windowSetTitle(json, ws, mainWindow); + break; + case "/window/set-width": + await windowSetWidth(json, ws, mainWindow); + break; + case "/window/set-x": + await windowSetX(json, ws, mainWindow); + break; + case "/window/set-y": + await windowSetY(json, ws, mainWindow); + break; + case "/window/show-dev-tools": + await windowShowDevTools(json, ws, mainWindow); + break; + case "/window/unmaximize": + await windowUnmaximize(json, ws, mainWindow); + break; + case "/window/set-fullscreen": + await windowSetFullscreen(json, ws, mainWindow); + break; + case "/window/set-ignore-mouse-events": + await windowSetIgnoreMouseEvents(json, ws, mainWindow); + break; + case "/engine": + await engine(json, ws); + break; + case "/open": + await open(json, ws); + break; + case "/show-in-explorer": + await showInExplorer(json, ws); + break; + case "/run": + await run(json, ws); + break; + case "/fs/copy": + await fsCopy(json, ws); + break; + case "/fs/delete": + await fsDelete(json, ws); + break; + case "/fs/exist": + await fsExist(json, ws); + break; + case "/fs/list": + await fsList(json, ws); + break; + case "/fs/file/size": + await fsFileSize(json, ws); + break; + case "/fs/move": + await fsMove(json, ws); + break; + case "/steam/raw": + await steamRaw(json, ws, client); + break; + case "/steam/leaderboard/upload-score": + await steamUploadScore(json, ws, client); + break; + case "/steam/leaderboard/download-score": + await steamDownloadScore(json, ws, client); + break; + case "/steam/workshop/update-item": + await steamUpdateItem(json, ws, client); + break; + case "/steam/workshop/get-item": + await steamGetItem(json, ws, client); + break; + case "/steam/workshop/get-items": + await steamGetItems(json, ws, client); + break; + case "/steam/workshop/subscribe": + await steamSubscribe(json, ws, client); + break; + case "/steam/workshop/unsubscribe": + await steamUnsubscribe(json, ws, client); + break; + case "/steam/workshop/state": + await steamState(json, ws, client); + break; + case "/steam/workshop/install-info": + await steamInstallInfo(json, ws, client); + break; + case "/steam/workshop/download-info": + await steamDownloadInfo(json, ws, client); + break; + case "/steam/workshop/download": + await steamDownload(json, ws, client); + break; + case "/steam/workshop/delete-item": + await steamDeleteItem(json, ws, client); + break; + case "/steam/screenshots/save": + await steamSaveScreenshot(json, ws, client); + break; + case "/discord/set-activity": + await discordSetActivity(json, ws, mainWindow, rpc); + break; + case "/exit": + await exit(json, ws); + break; + case "/window/fullscreen-state": + // sent the other way around + break; + case "/infos": + await infos(json, ws); + break; + + default: + console.log("unsupported", data); + assertUnreachable(json); + break; + } + } catch (e) { + console.error("e", e); + ws.send( + JSON.stringify({ + url: json.url, + correlationId: json.correlationId, + body: { + success: false, + error: e.message, + }, + }), + ); + } + }); + + ws.on("close", () => { + clients.delete(ws); + }); + }); + } catch (e) { + console.error("Unable to create websocket server", e); + return reject(e); + } + + server.listen(31753, "127.0.0.1", () => { + const adress = server.address(); + if (adress && typeof adress !== "string") { + return resolve(adress.port); + } + return reject("Unable to bind server: adress is not an object"); + }); + }); +}; + +const createWindow = async () => { + const argUrl = cliArgs.url; + + // If there is a window + const mainWindow = new BrowserWindow({ + width: config.width, + height: config.height, + fullscreen: config.fullscreen, + fullscreenable: true, + frame: config.frame, + transparent: config.transparent, + alwaysOnTop: config.alwaysOnTop, + backgroundColor: config.backgroundColor, + icon: config.icon, + webPreferences: { + preload: join(metaDirname, "preload.js"), + }, + show: true, + }); + + if (!mainWindow) { + throw new Error("Unable to create window"); + } + + if (!config.toolbar) { + mainWindow.setMenu(null); + } + + if (config.openDevtoolsOnStart) { + mainWindow.webContents.openDevTools(); + } + + if (config.clearServiceWorkerOnBoot) { + // It's better to export apps without service worker support + // only use when needed + try { + // Clear service workers to prevent old versions of the app + await session.defaultSession.clearStorageData({ + storages: ["serviceworkers"], + }); + } catch (e) { + console.error("Error clearing service workers", e); + } + } + + // preview + if (argUrl) { + console.log("argUrl", argUrl); + await createAppServer(mainWindow, false); + + await mainWindow?.loadURL(argUrl); + console.log("URL loaded"); + } + // prod + else { + const isCustomProtocol = config.serverMode === "customProtocol"; + const port = await createAppServer(mainWindow, isCustomProtocol === false); + if (isCustomProtocol) { + await mainWindow?.loadURL("app://game/index.html"); + console.log("URL loaded (static)", "app://game/index.html"); + } else { + const url = `http://127.0.0.1:${port}`; + await mainWindow?.loadURL(url); + console.log("URL loaded", url); + } + } + + mainWindow.on("enter-full-screen", () => { + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const order = { + url: "/window/fullscreen-state", + body: { + state: "fullscreen", + }, + }; + broadcastMessage(JSON.stringify(order)); + }); + + mainWindow.on("leave-full-screen", () => { + /** + * @type {import('@pipelab/core').MakeInputOutput} + */ + const order = { + url: "/window/fullscreen-state", + body: { + state: "normal", + }, + }; + broadcastMessage(JSON.stringify(order)); + }); + + mainWindow.webContents?.setWindowOpenHandler(({ url }) => { + // Open the URL in the default browser + shell.openExternal(url); + return { action: "deny" }; // Prevent Electron from creating a new window + }); + + return mainWindow; +}; + +/** + * Cleanup all resources before quitting + */ +const cleanup = async () => { + if (cleanupPromise) { + return cleanupPromise; + } + + cleanupPromise = (async () => { + console.log("Cleaning up resources..."); + + for (const client of clients) { + try { + client.close(); + } catch (e) { + console.error("Error closing WebSocket client:", e); + } + } + clients.clear(); + + if (wss) { + try { + wss.close(); + } catch (e) { + console.error("Error closing WebSocket server:", e); + } + wss = null; + } + + if (rpc) { + try { + await rpc.clearActivity(); + } catch (e) { + console.error("Error clearing Discord RPC activity:", e); + } + + try { + rpc.destroy(); + } catch (e) { + console.error("Error destroying Discord RPC client:", e); + } + + rpc = undefined; + } + + try { + protocol.unhandle("app"); + } catch (e) { + console.error("Error unregistering app protocol:", e); + } + + if (httpServer) { + const server = httpServer; + httpServer = null; + + await new Promise((resolve) => { + let isSettled = false; + const done = () => { + if (!isSettled) { + isSettled = true; + resolve(); + } + }; + + server.close(() => { + console.log("HTTP server closed"); + done(); + }); + + setTimeout(done, 500); + }); + } + })().finally(() => { + cleanupPromise = null; + }); + + return cleanupPromise; +}; + +const registerHandlers = async () => { + ipcMain.on("exit", async (event, code) => { + console.log("exit", code); + isQuitting = true; + await cleanup(); + app.exit(code); + }); +}; + +const rpcLogin = async () => { + return new Promise((resolve, reject) => { + rpc.on("ready", () => { + console.log("rpc ready"); + return resolve(rpc); + }); + + rpc.login({ clientId: config.discordAppId }).catch((e) => { + return reject(e); + }); + }); +}; + +function registerCustomProtocol() { + const GAME_DIR = path.join(metaDirname, "app"); + + protocol.handle("app", async (request) => { + let internalPath = request.url.replace("app://game/", ""); + internalPath = internalPath.split("?")[0]; + internalPath = decodeURIComponent(internalPath); + + if (internalPath === "" || internalPath.endsWith("/")) { + internalPath = "index.html"; + } + + const finalPath = path.join(GAME_DIR, internalPath); + + try { + const stats = await stat(finalPath); + const mimeType = mime.lookup(finalPath) || "application/octet-stream"; + + const headers = new Headers(); + headers.set("Content-Type", mimeType); + headers.set("Access-Control-Allow-Origin", "*"); + headers.set("Accept-Ranges", "bytes"); + + const rangeHeader = request.headers.get("Range"); + + if (rangeHeader) { + const parts = rangeHeader.replace(/bytes=/, "").split("-"); + const start = parseInt(parts[0], 10); + const end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1; + const chunkSize = end - start + 1; + + const stream = createReadStream(finalPath, { start, end }); + + headers.set("Content-Range", `bytes ${start}-${end}/${stats.size}`); + headers.set("Content-Length", String(chunkSize)); + + // @ts-expect-error streams are accepted + return new Response(stream, { + status: 206, + statusText: "Partial Content", + headers: headers, + }); + } + // no range / streaming + else { + headers.set("Content-Length", String(stats.size)); + const stream = createReadStream(finalPath); + + // @ts-expect-error streams are accepted + return new Response(stream, { + status: 200, + headers: headers, + }); + } + } catch (error) { + console.error(`[App Protocol] Error serving ${finalPath}:`, error); + return new Response("Not Found", { status: 404 }); + } + }); +} + +app.whenReady().then(async () => { + await registerHandlers(); + + if (config.enableSteamSupport) { + console.log("Enabling steam overlay support"); + try { + steamworks.electronEnableSteamOverlay(); + } catch (e) { + console.error("e", e); + } + } + + registerCustomProtocol(); + + const mainWindow = await createWindow(); + + mainWindow.show(); + + if (config.enableDiscordSupport && rpc) { + try { + await rpcLogin(); + } catch (e) { + console.error("e", e); + } + } + + app.on("activate", async () => { + if (BrowserWindow.getAllWindows().length === 0) { + await createWindow(); + } + }); +}); + +app.on("before-quit", (event) => { + if (!isQuitting) { + event.preventDefault(); + isQuitting = true; + cleanup() + .catch((error) => { + console.error("Error while quitting application:", error); + }) + .finally(() => { + app.quit(); + }); + } +}); + +app.on("will-quit", () => { + for (const client of clients) { + try { + client.terminate(); + } catch (e) {} + } + clients.clear(); +}); + +app.on("window-all-closed", () => { + // On macOS, apps typically stay open until explicitly quit + // But for games, we usually want to quit when the window is closed + if (process.platform !== "darwin" || isQuitting) { + app.quit(); + } else { + // On macOS, trigger the quit process which will run cleanup + isQuitting = true; + cleanup().then(() => { + app.quit(); + }); + } +}); diff --git a/assets/asset-electron/template/src/preload.js b/assets/asset-electron/template/src/preload.js new file mode 100644 index 00000000..f853321c --- /dev/null +++ b/assets/asset-electron/template/src/preload.js @@ -0,0 +1,27 @@ +const { contextBridge, ipcRenderer } = require("electron"); + +// Expose a limited API to the renderer process +contextBridge.exposeInMainWorld("electronAPI", { + invoke: async (channel, data) => { + try { + return await ipcRenderer.invoke(channel, data); + } catch (error) { + console.error("IPC invocation error:", error); + throw error; + } + }, + handle: (message, handler) => { + ipcRenderer.on(message, (event, ...args) => handler(...args)); + }, + isElectron: () => true, + exit: (code) => { + ipcRenderer.send("exit", code); + }, +}); + +/** @deprecated */ +contextBridge.exposeInMainWorld("isElectron", true); +contextBridge.exposeInMainWorld("isPipelab", true); +contextBridge.exposeInMainWorld("pipelabEngine", "electron"); + +console.log("Preload script loaded"); diff --git a/assets/asset-electron/template/src/utils.js b/assets/asset-electron/template/src/utils.js new file mode 100644 index 00000000..7228e4db --- /dev/null +++ b/assets/asset-electron/template/src/utils.js @@ -0,0 +1,18 @@ +import pkg from "../package.json" with { type: "json" }; + +/** + * @param {ElectronAppConfig.Config} config + */ +export const getAppName = (config) => { + const platform = process.platform; + + let appNameFolder = config.name; + if (platform === "win32") { + appNameFolder = config.name ?? pkg.productName ?? pkg.name; + } else if (platform === "darwin") { + appNameFolder = config.appBundleId; + } else if (platform === "linux") { + appNameFolder = config.appBundleId; + } + return appNameFolder; +}; diff --git a/assets/asset-netlify/.oxfmtrc.json b/assets/asset-netlify/.oxfmtrc.json new file mode 100644 index 00000000..3cd197af --- /dev/null +++ b/assets/asset-netlify/.oxfmtrc.json @@ -0,0 +1,9 @@ +{ + "ignorePatterns": [ + "dist", + "out", + "node_modules", + "bin", + "**/*.d.ts" + ] +} diff --git a/assets/asset-netlify/CHANGELOG.md b/assets/asset-netlify/CHANGELOG.md new file mode 100644 index 00000000..242c0861 --- /dev/null +++ b/assets/asset-netlify/CHANGELOG.md @@ -0,0 +1,193 @@ +# @pipelab/asset-netlify + +## 1.0.0-beta.31 + +### Patch Changes + +- - + +## 1.0.0-beta.30 + +### Patch Changes + +- improve dark theme and improve build history + +## 1.0.0-beta.29 + +### Patch Changes + +- sd + +## 1.0.0-beta.28 + +### Patch Changes + +- sd + +## 1.0.0-beta.27 + +### Patch Changes + +- sd + +## 1.0.0-beta.26 + +### Patch Changes + +- sd + +## 1.0.0-beta.25 + +### Patch Changes + +- sd + +## 1.0.0-beta.24 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.23 + +### Patch Changes + +- sd + +## 1.0.0-beta.22 + +### Patch Changes + +- sd + +## 1.0.0-beta.21 + +### Patch Changes + +- sd + +## 1.0.0-beta.20 + +### Patch Changes + +- sd + +## 1.0.0-beta.19 + +### Patch Changes + +- sd + +## 1.0.0-beta.18 + +### Patch Changes + +- sd + +## 1.0.0-beta.17 + +### Patch Changes + +- sd + +## 1.0.0-beta.16 + +### Patch Changes + +- df + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.14 + +### Patch Changes + +- sd + +## 1.0.0-beta.13 + +### Patch Changes + +- sd + +## 1.0.0-beta.12 + +### Patch Changes + +- qs + +## 1.0.0-beta.11 + +### Patch Changes + +- sd + +## 1.0.0-beta.10 + +### Patch Changes + +- s + +## 1.0.0-beta.9 + +### Patch Changes + +- fg + +## 1.0.0-beta.8 + +### Patch Changes + +- changes + +## 1.0.0-beta.7 + +### Patch Changes + +- bump + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes + +## 1.0.0-beta.5 + +### Patch Changes + +- bump + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag + +## 1.0.0-beta.3 + +### Patch Changes + +- bump + +## 1.0.0-beta.2 + +### Patch Changes + +- update + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/assets/asset-netlify/package.json b/assets/asset-netlify/package.json new file mode 100644 index 00000000..e9cc3c3f --- /dev/null +++ b/assets/asset-netlify/package.json @@ -0,0 +1,18 @@ +{ + "name": "@pipelab/asset-netlify", + "version": "1.0.0-beta.31", + "description": "Netlify assets for pipelab", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "assets/asset-netlify" + }, + "files": [ + "template" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/assets/netlify/templates/static/.gitignore b/assets/asset-netlify/template/.gitignore similarity index 100% rename from assets/netlify/templates/static/.gitignore rename to assets/asset-netlify/template/.gitignore diff --git a/assets/netlify/templates/static/.npmrc b/assets/asset-netlify/template/.npmrc similarity index 100% rename from assets/netlify/templates/static/.npmrc rename to assets/asset-netlify/template/.npmrc diff --git a/assets/netlify/templates/static/netlify.toml b/assets/asset-netlify/template/netlify.toml similarity index 100% rename from assets/netlify/templates/static/netlify.toml rename to assets/asset-netlify/template/netlify.toml diff --git a/assets/netlify/templates/static/package.json b/assets/asset-netlify/template/package.json similarity index 100% rename from assets/netlify/templates/static/package.json rename to assets/asset-netlify/template/package.json diff --git a/assets/netlify/templates/static/pnpm-lock.yaml b/assets/asset-netlify/template/pnpm-lock.yaml similarity index 100% rename from assets/netlify/templates/static/pnpm-lock.yaml rename to assets/asset-netlify/template/pnpm-lock.yaml diff --git a/assets/netlify/templates/static/pnpm-workspace.yaml b/assets/asset-netlify/template/pnpm-workspace.yaml similarity index 77% rename from assets/netlify/templates/static/pnpm-workspace.yaml rename to assets/asset-netlify/template/pnpm-workspace.yaml index 4dbad1f4..4f8f3320 100644 --- a/assets/netlify/templates/static/pnpm-workspace.yaml +++ b/assets/asset-netlify/template/pnpm-workspace.yaml @@ -1,5 +1,5 @@ onlyBuiltDependencies: - - '@parcel/watcher' + - "@parcel/watcher" - esbuild - netlify-cli - sharp diff --git a/assets/asset-tauri/.oxfmtrc.json b/assets/asset-tauri/.oxfmtrc.json new file mode 100644 index 00000000..3cd197af --- /dev/null +++ b/assets/asset-tauri/.oxfmtrc.json @@ -0,0 +1,9 @@ +{ + "ignorePatterns": [ + "dist", + "out", + "node_modules", + "bin", + "**/*.d.ts" + ] +} diff --git a/assets/asset-tauri/CHANGELOG.md b/assets/asset-tauri/CHANGELOG.md new file mode 100644 index 00000000..672a55cd --- /dev/null +++ b/assets/asset-tauri/CHANGELOG.md @@ -0,0 +1,193 @@ +# @pipelab/asset-tauri + +## 1.0.0-beta.31 + +### Patch Changes + +- - + +## 1.0.0-beta.30 + +### Patch Changes + +- improve dark theme and improve build history + +## 1.0.0-beta.29 + +### Patch Changes + +- sd + +## 1.0.0-beta.28 + +### Patch Changes + +- sd + +## 1.0.0-beta.27 + +### Patch Changes + +- sd + +## 1.0.0-beta.26 + +### Patch Changes + +- sd + +## 1.0.0-beta.25 + +### Patch Changes + +- sd + +## 1.0.0-beta.24 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.23 + +### Patch Changes + +- sd + +## 1.0.0-beta.22 + +### Patch Changes + +- sd + +## 1.0.0-beta.21 + +### Patch Changes + +- sd + +## 1.0.0-beta.20 + +### Patch Changes + +- sd + +## 1.0.0-beta.19 + +### Patch Changes + +- sd + +## 1.0.0-beta.18 + +### Patch Changes + +- sd + +## 1.0.0-beta.17 + +### Patch Changes + +- sd + +## 1.0.0-beta.16 + +### Patch Changes + +- df + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.14 + +### Patch Changes + +- sd + +## 1.0.0-beta.13 + +### Patch Changes + +- sd + +## 1.0.0-beta.12 + +### Patch Changes + +- qs + +## 1.0.0-beta.11 + +### Patch Changes + +- sd + +## 1.0.0-beta.10 + +### Patch Changes + +- s + +## 1.0.0-beta.9 + +### Patch Changes + +- fg + +## 1.0.0-beta.8 + +### Patch Changes + +- changes + +## 1.0.0-beta.7 + +### Patch Changes + +- bump + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes + +## 1.0.0-beta.5 + +### Patch Changes + +- bump + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag + +## 1.0.0-beta.3 + +### Patch Changes + +- bump + +## 1.0.0-beta.2 + +### Patch Changes + +- update + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/assets/asset-tauri/package.json b/assets/asset-tauri/package.json new file mode 100644 index 00000000..ab9f7e64 --- /dev/null +++ b/assets/asset-tauri/package.json @@ -0,0 +1,18 @@ +{ + "name": "@pipelab/asset-tauri", + "version": "1.0.0-beta.31", + "description": "Tauri assets for pipelab", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "assets/asset-tauri" + }, + "files": [ + "template" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/assets/tauri/template/app/README.md b/assets/asset-tauri/template/README.md similarity index 100% rename from assets/tauri/template/app/README.md rename to assets/asset-tauri/template/README.md diff --git a/assets/asset-tauri/template/index.html b/assets/asset-tauri/template/index.html new file mode 100644 index 00000000..6d930115 --- /dev/null +++ b/assets/asset-tauri/template/index.html @@ -0,0 +1,45 @@ + + + + + + Document + + + + + + + + + + + + + + +
+ + + + diff --git a/assets/tauri/template/app/package.json b/assets/asset-tauri/template/package.json similarity index 73% rename from assets/tauri/template/app/package.json rename to assets/asset-tauri/template/package.json index 8070ce09..a3055d25 100644 --- a/assets/tauri/template/app/package.json +++ b/assets/asset-tauri/template/package.json @@ -1,7 +1,7 @@ { "name": "tauri", - "private": true, "version": "0.1.0", + "private": true, "type": "module", "scripts": { "dev": "vite", @@ -12,12 +12,12 @@ "dependencies": { "@tauri-apps/api": "^2", "@tauri-apps/plugin-fs": "~2", - "@tauri-apps/plugin-shell": "^2", - "@tauri-apps/plugin-opener": "^2" + "@tauri-apps/plugin-opener": "^2", + "@tauri-apps/plugin-shell": "^2" }, "devDependencies": { "@tauri-apps/cli": "^2", - "vite": "^6.2.4", - "typescript": "~5.8.2" + "typescript": "~5.8.2", + "vite": "^6.2.4" } } diff --git a/assets/tauri/template/app/pnpm-lock.yaml b/assets/asset-tauri/template/pnpm-lock.yaml similarity index 100% rename from assets/tauri/template/app/pnpm-lock.yaml rename to assets/asset-tauri/template/pnpm-lock.yaml diff --git a/assets/tauri/template/app/src-tauri/.gitignore b/assets/asset-tauri/template/src-tauri/.gitignore similarity index 100% rename from assets/tauri/template/app/src-tauri/.gitignore rename to assets/asset-tauri/template/src-tauri/.gitignore diff --git a/assets/tauri/template/app/src-tauri/Cargo.lock b/assets/asset-tauri/template/src-tauri/Cargo.lock similarity index 100% rename from assets/tauri/template/app/src-tauri/Cargo.lock rename to assets/asset-tauri/template/src-tauri/Cargo.lock diff --git a/assets/tauri/template/app/src-tauri/Cargo.toml b/assets/asset-tauri/template/src-tauri/Cargo.toml similarity index 100% rename from assets/tauri/template/app/src-tauri/Cargo.toml rename to assets/asset-tauri/template/src-tauri/Cargo.toml diff --git a/assets/tauri/template/app/src-tauri/build.rs b/assets/asset-tauri/template/src-tauri/build.rs similarity index 100% rename from assets/tauri/template/app/src-tauri/build.rs rename to assets/asset-tauri/template/src-tauri/build.rs diff --git a/assets/tauri/template/app/src-tauri/capabilities/default.json b/assets/asset-tauri/template/src-tauri/capabilities/default.json similarity index 58% rename from assets/tauri/template/app/src-tauri/capabilities/default.json rename to assets/asset-tauri/template/src-tauri/capabilities/default.json index f5c766d5..f7783640 100644 --- a/assets/tauri/template/app/src-tauri/capabilities/default.json +++ b/assets/asset-tauri/template/src-tauri/capabilities/default.json @@ -2,11 +2,6 @@ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "Capability for the main window", - "windows": [ - "main" - ], - "permissions": [ - "core:default", - "opener:default" - ] + "windows": ["main"], + "permissions": ["core:default", "opener:default"] } diff --git a/assets/tauri/template/app/src-tauri/icons/128x128.png b/assets/asset-tauri/template/src-tauri/icons/128x128.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/128x128.png rename to assets/asset-tauri/template/src-tauri/icons/128x128.png diff --git a/assets/tauri/template/app/src-tauri/icons/128x128@2x.png b/assets/asset-tauri/template/src-tauri/icons/128x128@2x.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/128x128@2x.png rename to assets/asset-tauri/template/src-tauri/icons/128x128@2x.png diff --git a/assets/tauri/template/app/src-tauri/icons/32x32.png b/assets/asset-tauri/template/src-tauri/icons/32x32.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/32x32.png rename to assets/asset-tauri/template/src-tauri/icons/32x32.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square107x107Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square107x107Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square107x107Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square107x107Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square142x142Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square142x142Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square142x142Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square142x142Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square150x150Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square150x150Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square150x150Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square150x150Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square284x284Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square284x284Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square284x284Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square284x284Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square30x30Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square30x30Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square30x30Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square30x30Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square310x310Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square310x310Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square310x310Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square310x310Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square44x44Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square44x44Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square44x44Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square44x44Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square71x71Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square71x71Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square71x71Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square71x71Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/Square89x89Logo.png b/assets/asset-tauri/template/src-tauri/icons/Square89x89Logo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/Square89x89Logo.png rename to assets/asset-tauri/template/src-tauri/icons/Square89x89Logo.png diff --git a/assets/tauri/template/app/src-tauri/icons/StoreLogo.png b/assets/asset-tauri/template/src-tauri/icons/StoreLogo.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/StoreLogo.png rename to assets/asset-tauri/template/src-tauri/icons/StoreLogo.png diff --git a/assets/tauri/template/app/src-tauri/icons/icon.icns b/assets/asset-tauri/template/src-tauri/icons/icon.icns similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/icon.icns rename to assets/asset-tauri/template/src-tauri/icons/icon.icns diff --git a/assets/tauri/template/app/src-tauri/icons/icon.ico b/assets/asset-tauri/template/src-tauri/icons/icon.ico similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/icon.ico rename to assets/asset-tauri/template/src-tauri/icons/icon.ico diff --git a/assets/tauri/template/app/src-tauri/icons/icon.png b/assets/asset-tauri/template/src-tauri/icons/icon.png similarity index 100% rename from assets/tauri/template/app/src-tauri/icons/icon.png rename to assets/asset-tauri/template/src-tauri/icons/icon.png diff --git a/assets/tauri/template/app/src-tauri/src/lib copy 2.rs b/assets/asset-tauri/template/src-tauri/src/lib copy 2.rs similarity index 100% rename from assets/tauri/template/app/src-tauri/src/lib copy 2.rs rename to assets/asset-tauri/template/src-tauri/src/lib copy 2.rs diff --git a/assets/tauri/template/app/src-tauri/src/lib copy.rs b/assets/asset-tauri/template/src-tauri/src/lib copy.rs similarity index 100% rename from assets/tauri/template/app/src-tauri/src/lib copy.rs rename to assets/asset-tauri/template/src-tauri/src/lib copy.rs diff --git a/assets/tauri/template/app/src-tauri/src/lib.rs b/assets/asset-tauri/template/src-tauri/src/lib.rs similarity index 100% rename from assets/tauri/template/app/src-tauri/src/lib.rs rename to assets/asset-tauri/template/src-tauri/src/lib.rs diff --git a/assets/tauri/template/app/src-tauri/src/lib_webview_screenshot.rs b/assets/asset-tauri/template/src-tauri/src/lib_webview_screenshot.rs similarity index 100% rename from assets/tauri/template/app/src-tauri/src/lib_webview_screenshot.rs rename to assets/asset-tauri/template/src-tauri/src/lib_webview_screenshot.rs diff --git a/assets/tauri/template/app/src-tauri/src/main.rs b/assets/asset-tauri/template/src-tauri/src/main.rs similarity index 100% rename from assets/tauri/template/app/src-tauri/src/main.rs rename to assets/asset-tauri/template/src-tauri/src/main.rs diff --git a/assets/tauri/template/app/src-tauri/tauri.conf.json b/assets/asset-tauri/template/src-tauri/tauri.conf.json similarity index 100% rename from assets/tauri/template/app/src-tauri/tauri.conf.json rename to assets/asset-tauri/template/src-tauri/tauri.conf.json diff --git a/assets/tauri/template/app/tsconfig.json b/assets/asset-tauri/template/tsconfig.json similarity index 100% rename from assets/tauri/template/app/tsconfig.json rename to assets/asset-tauri/template/tsconfig.json diff --git a/assets/build/notarize.cjs b/assets/build/notarize.cjs deleted file mode 100644 index f3a44b32..00000000 --- a/assets/build/notarize.cjs +++ /dev/null @@ -1,36 +0,0 @@ -const { notarize } = require('@electron/notarize') - -module.exports = async (context) => { - if (process.platform !== 'darwin') return - - console.log('aftersign hook triggered, start to notarize app.') - - if (!process.env.CI) { - console.log(`skipping notarizing, not in CI.`) - return - } - - if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) { - console.warn('skipping notarizing, APPLE_ID and APPLE_ID_PASS env variables must be set.') - return - } - - const appId = 'com.electron.app' - - const { appOutDir } = context - - const appName = context.packager.appInfo.productFilename - - try { - await notarize({ - appBundleId: appId, - appPath: `${appOutDir}/${appName}.app`, - appleId: process.env.APPLE_ID, - appleIdPassword: process.env.APPLEIDPASS - }) - } catch (error) { - console.error(error) - } - - console.log(`done notarizing ${appId}.`) -} diff --git a/assets/discord/templates/nitro-app/nitro.config.ts b/assets/discord/templates/nitro-app/nitro.config.ts deleted file mode 100644 index 304b0dd9..00000000 --- a/assets/discord/templates/nitro-app/nitro.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -//https://nitro.unjs.io/config -export default defineNitroConfig({ - srcDir: 'server', - compatibilityDate: '2025-04-03', - runtimeConfig: { - discordClientId: '', - discordClientSecret: '' - } -}) diff --git a/assets/discord/templates/nitro-app/server/middleware/security-header.ts b/assets/discord/templates/nitro-app/server/middleware/security-header.ts deleted file mode 100644 index 64bb9593..00000000 --- a/assets/discord/templates/nitro-app/server/middleware/security-header.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default eventHandler((event) => { - setResponseHeader(event, 'X-Frame-Options', '') - setResponseHeader( - event, - 'Content-Security-Policy', - "frame-ancestors 'self' https://*.discordsays.com" - ) -}) diff --git a/assets/discord/templates/nitro-app/server/public/index.html b/assets/discord/templates/nitro-app/server/public/index.html deleted file mode 100644 index d859f3f2..00000000 --- a/assets/discord/templates/nitro-app/server/public/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - Document - - - - - - - - - - diff --git a/assets/electron/template/app/.gitignore b/assets/electron/template/app/.gitignore deleted file mode 100644 index 8296128d..00000000 --- a/assets/electron/template/app/.gitignore +++ /dev/null @@ -1,92 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock -.DS_Store - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# Webpack -.webpack/ - -# Vite -.vite/ - -# Electron-Forge -out/ diff --git a/assets/electron/template/app/.npmrc b/assets/electron/template/app/.npmrc deleted file mode 100644 index cc8df9de..00000000 --- a/assets/electron/template/app/.npmrc +++ /dev/null @@ -1 +0,0 @@ -node-linker=hoisted \ No newline at end of file diff --git a/assets/electron/template/app/pnpm-lock.yaml b/assets/electron/template/app/pnpm-lock.yaml deleted file mode 100644 index e39c232f..00000000 --- a/assets/electron/template/app/pnpm-lock.yaml +++ /dev/null @@ -1,3982 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -overrides: - discord-rpc>register-scheme: '-' - -importers: - - .: - dependencies: - '@electron-forge/plugin-base': - specifier: 7.4.0 - version: 7.4.0 - '@electron/asar': - specifier: 3.2.13 - version: 3.2.13 - '@pipelab/steamworks.js': - specifier: ^0.11.1 - version: 0.11.1 - discord-rpc: - specifier: ^4.0.1 - version: 4.0.1(encoding@0.1.13) - electron-serve: - specifier: ^2.1.1 - version: 2.1.1 - electron-squirrel-startup: - specifier: 1.0.1 - version: 1.0.1 - execa: - specifier: ^9.4.0 - version: 9.5.2 - mime-types: - specifier: ^3.0.2 - version: 3.0.2 - move-file: - specifier: ^3.1.0 - version: 3.1.0 - mri: - specifier: 1.2.0 - version: 1.2.0 - semver: - specifier: ^7.7.2 - version: 7.7.2 - serve-handler: - specifier: ^6.1.6 - version: 6.1.6 - slash: - specifier: ^5.1.0 - version: 5.1.0 - ws: - specifier: ^8.18.1 - version: 8.18.1 - devDependencies: - '@electron-forge/cli': - specifier: 7.4.0 - version: 7.4.0(encoding@0.1.13) - '@electron-forge/maker-deb': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-dmg': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-rpm': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-squirrel': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-zip': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/plugin-auto-unpack-natives': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/plugin-fuses': - specifier: 7.4.0 - version: 7.4.0(@electron/fuses@1.8.0) - '@electron/fuses': - specifier: 1.8.0 - version: 1.8.0 - '@pipelab/core': - specifier: 1.4.9 - version: 1.4.9 - '@types/mime-types': - specifier: ^3.0.1 - version: 3.0.1 - electron: - specifier: 39.2.3 - version: 39.2.3 - -packages: - - '@electron-forge/cli@7.4.0': - resolution: {integrity: sha512-a+zZv3ja/IxkJzNyx4sOHSZv6DPV85S0PEVF6pcRjUpbDL5r+DxjRFsNc0Nq4UIWyFm1nw7RWoPdd9uDst4Tvg==} - engines: {node: '>= 16.4.0'} - hasBin: true - - '@electron-forge/core-utils@7.4.0': - resolution: {integrity: sha512-9RLG0F9SX466TpkaTcW+V15KmnGuTpmr7NKMRlngtHXmnkBUJz4Mxp1x33WZLgL90dJrxrRgHSfVBtA4lstDPw==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/core@7.4.0': - resolution: {integrity: sha512-pYHKpB2CKeQgWsb+gox+FPkEvP+6Q2zGj2eZtgZRtKppoWIXrHIpOtcm6FllJ/gZ5u4AsQzVIYReAHGaBa0osw==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/maker-base@7.4.0': - resolution: {integrity: sha512-LwWS4VPdwjISl1KpLhmM1Qr1M3sRTTQ/RsX+GlFd7cQ1W/FsgxMjaTG4Od1d+a5CGVTh3s6X2g99TSUfxjOveg==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/maker-deb@7.4.0': - resolution: {integrity: sha512-npWea3IpGeu96xNqJpsCOYX6V4E+HY6u/okeTUzUOMX96UteT14MecdUefMam158glRTX84k2ryh7WcBoOa4mg==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/maker-dmg@7.4.0': - resolution: {integrity: sha512-xRCMNtnpvQNwrDYvwbVFegnErnIMpHGZANrjwushlH9+Fsu60DFvf5s3AVkgsYdQTqlY7wYRG1mziYZmRlPAIw==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/maker-rpm@7.4.0': - resolution: {integrity: sha512-N64Yh/K/91GzIk28T1jKsCGgYaquDuhXcEJW+TkVyP5tPZ9aTz9SjXLBxAg8WhcroArAZEsVyPOFKthmFzAUuA==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/maker-squirrel@7.4.0': - resolution: {integrity: sha512-mCQyufnSNfjffiKho59ZqVg4W601zGOl6h01OyfDwjOU/G4iQtpnnDEOXGe26q7OVT5ORb1WDnfyGgBeJ6Ge7g==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/maker-zip@7.4.0': - resolution: {integrity: sha512-UGbMdpuK/P29x1FFRWNOs3bNz+7QNFWVWyTM5hcWqib66cNuUmoaPifQyuwW2POIrIohrxlzLK87/i9Zc8g4dA==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/plugin-auto-unpack-natives@7.4.0': - resolution: {integrity: sha512-jJ/v2blH32bcvdlJbeeW/yO99K9SduW8yrS7zuFN6y+B1cmzLd+S7L8oCcOghFDMAlYjQaBlnCe/nMJbT9mN4g==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/plugin-base@7.4.0': - resolution: {integrity: sha512-LcTNtEc2YaWvhhqWVIfdJ+J0/krSgc2dqYAHhOH2aLUSm9End3dKO/PZ1Y6DPsiPiJKHnSLBJ/XBN/16NY4Sjw==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/plugin-fuses@7.4.0': - resolution: {integrity: sha512-LKcyIaO0sUkzZdOB1PySjG1R9KAl5Vi453ZQcambBI7RpZtPKozluNd0zlXey1cf7ycTwhzvmrI6ss3LHQyjvw==} - engines: {node: '>= 16.4.0'} - peerDependencies: - '@electron/fuses': '>=1.0.0' - - '@electron-forge/publisher-base@7.4.0': - resolution: {integrity: sha512-PiJk4RfaC55SnVnteLW2ZIQNM9DpGOi6YoUn5t8i9UcVp2rFIdya7bJY/b9u1hwubm4d5+TdypMVEuJjM44CJQ==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/shared-types@7.4.0': - resolution: {integrity: sha512-5Ehy6enUjBaU08odf9u9TOhmOVXlqobzMvKUixtkdAWgV1XZAUJmn+p21xhj0IkO92MQiXMGv66w9pDNjRT8uQ==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/template-base@7.4.0': - resolution: {integrity: sha512-3YWdRSGzQfQPQkQxStn2wkJ/SuNGGKo9slwFJGvqMV+Pbx3/M/hYi9sMXOuaqVZgeaBp8Ap27yFPxaIIOC3vcA==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/template-vite-typescript@7.4.0': - resolution: {integrity: sha512-wdByG807VWcUd81E6572b/G/Ki8gb+GrCIWxO7Cl3qBa+yNaU1sHhBwB1RyTbQy1r8ubSBtsWrRD1J/yzHKWoQ==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/template-vite@7.4.0': - resolution: {integrity: sha512-YPVyCGiBKmZPCxK/Bd2louV3PBcxI2nT2+tRKP+mlEHOWrxbZIfmZSR2lIAFvK/ALKlwUKROdmlwyi7ZcdT7JQ==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/template-webpack-typescript@7.4.0': - resolution: {integrity: sha512-O5gwjNSGFNRdJWyiCtevcOBDPAMhgOPvLORh9qR1GcjyTutWwHWmZzycqH+MmkhpQPgrAYDEeipXcOQhSbzNZA==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/template-webpack@7.4.0': - resolution: {integrity: sha512-W558AEGwQrwEtKIbIJPPs0LIsaC/1Vncj5NgqKehEMJjBb0KQq4hwBu/6dauQrfun4jRCOp7LV+OVrf5XPJ7QA==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/tracer@7.4.0': - resolution: {integrity: sha512-F4jbnDn4yIZjmky1FZ6rgBKTM05AZQQfHkyJW2hdS4pDKJjdKAqWytoZKDi1/S6Cr6tN+DD0TFGD3V0i6HPHYQ==} - engines: {node: '>= 14.17.5'} - - '@electron/asar@3.2.13': - resolution: {integrity: sha512-pY5z2qQSwbFzJsBdgfJIzXf5ElHTVMutC2dxh0FD60njknMu3n1NnTABOcQwbb5/v5soqE79m9UjaJryBf3epg==} - engines: {node: '>=10.12.0'} - hasBin: true - - '@electron/fuses@1.8.0': - resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} - hasBin: true - - '@electron/get@2.0.3': - resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} - engines: {node: '>=12'} - - '@electron/get@3.1.0': - resolution: {integrity: sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==} - engines: {node: '>=14'} - - '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': - resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} - version: 10.2.0-electron.1 - engines: {node: '>=12.13.0'} - hasBin: true - - '@electron/notarize@2.5.0': - resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} - engines: {node: '>= 10.0.0'} - - '@electron/osx-sign@1.3.2': - resolution: {integrity: sha512-KqVlm9WMWq19lBpCXQoThC/Koaiji2zotUDYwZDaZlZZym+FXY9mQW8wN6sUQ93nkVc42f3TQ1S/XN9S1kjM5Q==} - engines: {node: '>=12.0.0'} - hasBin: true - - '@electron/packager@18.3.6': - resolution: {integrity: sha512-1eXHB5t+SQKvUiDpWGpvr90ZSSbXj+isrh3YbjCTjKT4bE4SQrKSBfukEAaBvp67+GXHFtCHjQgN9qSTFIge+Q==} - engines: {node: '>= 16.13.0'} - hasBin: true - - '@electron/rebuild@3.7.1': - resolution: {integrity: sha512-sKGD+xav4Gh25+LcLY0rjIwcCFTw+f/HU1pB48UVbwxXXRGaXEqIH0AaYKN46dgd/7+6kuiDXzoyAEvx1zCsdw==} - engines: {node: '>=12.13.0'} - hasBin: true - - '@electron/universal@2.0.1': - resolution: {integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==} - engines: {node: '>=16.4'} - - '@electron/windows-sign@1.2.0': - resolution: {integrity: sha512-5zfLHfD6kGgsXzuYlKwlWWO8w6dboKy4dhd7rGnR4rQYumuDgPAF2TYjEa8LUi89KdHxtDy2btq02KvbjhK9Iw==} - engines: {node: '>=14.14'} - hasBin: true - - '@gar/promisify@1.1.3': - resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - - '@malept/cross-spawn-promise@1.1.1': - resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} - engines: {node: '>= 10'} - - '@malept/cross-spawn-promise@2.0.0': - resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} - engines: {node: '>= 12.13.0'} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@npmcli/fs@2.1.2': - resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - '@npmcli/move-file@2.0.1': - resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This functionality has been moved to @npmcli/fs - - '@pipelab/core@1.4.9': - resolution: {integrity: sha512-eHz2UNZrDeaTUHS5BL4Mc6c2yBWt7N7xQ2hT0gu2UnAHsWO2QL/j2SVyyaYwGY9m6Ht6jXPXBwD0cngVWVy5vQ==} - - '@pipelab/steamworks.js@0.11.1': - resolution: {integrity: sha512-Owo03g8QmeDdiGRxPYfRQOhZ5oZ8GOTTP4LObGPqOSTvfENigzfKSDWbY9JFcd/3NJTXnvuUbktdqZtL+PPWJQ==} - engines: {node: '>= 14'} - - '@sec-ant/readable-stream@0.4.1': - resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@sindresorhus/merge-streams@4.0.0': - resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} - engines: {node: '>=18'} - - '@szmarczak/http-timer@4.0.6': - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} - - '@tootallnate/once@2.0.0': - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} - - '@types/cacheable-request@6.0.3': - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - - '@types/fs-extra@9.0.13': - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} - - '@types/glob@7.2.0': - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - - '@types/keyv@3.1.4': - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - - '@types/mime-types@3.0.1': - resolution: {integrity: sha512-xRMsfuQbnRq1Ef+C+RKaENOxXX87Ygl38W1vDfPHRku02TgQr+Qd8iivLtAMcR0KF5/29xlnFihkTlbqFrGOVQ==} - - '@types/minimatch@5.1.2': - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - - '@types/node@22.10.5': - resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} - - '@types/responselike@1.0.3': - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - - '@xmldom/xmldom@0.8.10': - resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} - engines: {node: '>=10.0.0'} - - abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - agentkeepalive@4.6.0: - resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} - engines: {node: '>= 8.0.0'} - - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - - ansi-escapes@5.0.0: - resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} - engines: {node: '>=12'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - appdmg@0.6.6: - resolution: {integrity: sha512-GRmFKlCG+PWbcYF4LUNonTYmy0GjguDy6Jh9WP8mpd0T6j80XIJyXBiWlD0U+MLNhqV9Nhx49Gl9GpVToulpLg==} - engines: {node: '>=8.5'} - os: [darwin] - hasBin: true - - async@1.5.2: - resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} - - at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - - author-regex@1.0.0: - resolution: {integrity: sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g==} - engines: {node: '>=0.8'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base32-encode@1.2.0: - resolution: {integrity: sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - - boolean@3.2.0: - resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - - bplist-creator@0.0.8: - resolution: {integrity: sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - bytes@3.0.0: - resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} - engines: {node: '>= 0.8'} - - cacache@16.1.3: - resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} - - cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - - chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - - cli-cursor@4.0.0: - resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - - cli-truncate@3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - - color-convert@0.5.3: - resolution: {integrity: sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - commander@5.1.0: - resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} - engines: {node: '>= 6'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - compare-version@0.1.2: - resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} - engines: {node: '>=0.10.0'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - content-disposition@0.5.2: - resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} - engines: {node: '>= 0.6'} - - cross-dirname@0.1.0: - resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} - - cross-spawn@6.0.6: - resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} - engines: {node: '>=4.8'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - cross-zip@4.0.1: - resolution: {integrity: sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==} - engines: {node: '>=12.10'} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - - defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} - - detect-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - - dir-compare@4.2.0: - resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} - - discord-rpc@4.0.1: - resolution: {integrity: sha512-HOvHpbq5STRZJjQIBzwoKnQ0jHplbEWFWlPDwXXKm/bILh4nzjcg7mNqll0UY7RsjFoaXA7e/oYb/4lvpda2zA==} - - ds-store@0.1.6: - resolution: {integrity: sha512-kY21M6Lz+76OS3bnCzjdsJSF7LBpLYGCVfavW8TgQD2XkcqIZ86W0y9qUDZu6fp7SIZzqosMDW2zi7zVFfv4hw==} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - electron-installer-common@0.10.4: - resolution: {integrity: sha512-8gMNPXfAqUE5CfXg8RL0vXpLE9HAaPkgLXVoHE3BMUzogMWenf4LmwQ27BdCUrEhkjrKl+igs2IHJibclR3z3Q==} - engines: {node: '>= 10.0.0'} - - electron-installer-debian@3.2.0: - resolution: {integrity: sha512-58ZrlJ1HQY80VucsEIG9tQ//HrTlG6sfofA3nRGr6TmkX661uJyu4cMPPh6kXW+aHdq/7+q25KyQhDrXvRL7jw==} - engines: {node: '>= 10.0.0'} - os: [darwin, linux] - hasBin: true - - electron-installer-dmg@4.0.0: - resolution: {integrity: sha512-g3W6XnyUa7QGrAF7ViewHdt6bXV2KYU1Pm1CY3pZpp+H6mOjCHHAhf/iZAxtaX1ERCb+SQHz7xSsAHuNH9I8ZQ==} - engines: {node: '>= 12.13.0'} - hasBin: true - - electron-installer-redhat@3.4.0: - resolution: {integrity: sha512-gEISr3U32Sgtj+fjxUAlSDo3wyGGq6OBx7rF5UdpIgbnpUvMN4W5uYb0ThpnAZ42VEJh/3aODQXHbFS4f5J3Iw==} - engines: {node: '>= 10.0.0'} - os: [darwin, linux] - hasBin: true - - electron-serve@2.1.1: - resolution: {integrity: sha512-SJdA7bfZuPODK9BkXTZ8EPsQlzg6yNSA0H6811DQvqzyDhPP8icIACA0bIA9aWeT+gmDB7V4eMg/wZhR+ijk6w==} - engines: {node: '>=18'} - - electron-squirrel-startup@1.0.1: - resolution: {integrity: sha512-sTfFIHGku+7PsHLJ7v0dRcZNkALrV+YEozINTW8X1nM//e5O3L+rfYuvSW00lmGHnYmUjARZulD8F2V8ISI9RA==} - - electron-winstaller@5.4.0: - resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} - engines: {node: '>=8.0.0'} - - electron@39.2.3: - resolution: {integrity: sha512-j7k7/bj3cNA29ty54FzEMRUoqirE+RBQPhPFP+XDuM93a1l2WcDPiYumxKWz+iKcXxBJLFdMIAlvtLTB/RfCkg==} - engines: {node: '>= 12.20.55'} - hasBin: true - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - encode-utf8@1.0.3: - resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} - - encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es6-error@4.1.1: - resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - - execa@1.0.0: - resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} - engines: {node: '>=6'} - - execa@9.5.2: - resolution: {integrity: sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==} - engines: {node: ^18.19.0 || >=20.5.0} - - expand-tilde@2.0.2: - resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} - engines: {node: '>=0.10.0'} - - exponential-backoff@3.1.1: - resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} - - extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fastq@1.18.0: - resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} - - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - - figures@6.1.0: - resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} - engines: {node: '>=18'} - - filename-reserved-regex@2.0.0: - resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} - engines: {node: '>=4'} - - filenamify@4.3.0: - resolution: {integrity: sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==} - engines: {node: '>=8'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@2.1.0: - resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} - engines: {node: '>=4'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flora-colossus@2.0.0: - resolution: {integrity: sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA==} - engines: {node: '>= 12'} - - fmix@0.1.0: - resolution: {integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==} - - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} - engines: {node: '>=14.14'} - - fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - - fs-temp@1.2.1: - resolution: {integrity: sha512-okTwLB7/Qsq82G6iN5zZJFsOfZtx2/pqrA7Hk/9fvy+c+eJS9CvgGXT2uNxwnI14BDY9L/jQPkaBgSvlKfSW9w==} - - fs-xattr@0.3.1: - resolution: {integrity: sha512-UVqkrEW0GfDabw4C3HOrFlxKfx0eeigfRne69FxSBdHIP8Qt5Sq6Pu3RM9KmMlkygtC4pPKkj5CiPO5USnj2GA==} - engines: {node: '>=8.6.0'} - os: ['!win32'] - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - galactus@1.0.0: - resolution: {integrity: sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ==} - engines: {node: '>= 12'} - - gar@1.0.4: - resolution: {integrity: sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - - generate-function@2.3.1: - resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} - - generate-object-property@1.2.0: - resolution: {integrity: sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-folder-size@2.0.1: - resolution: {integrity: sha512-+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==} - hasBin: true - - get-installed-path@2.1.1: - resolution: {integrity: sha512-Qkn9eq6tW5/q9BDVdMpB8tOHljX9OSP0jRC5TRNVA4qRc839t4g8KQaR8t0Uv0EFVL0MlyG7m/ofjEgAROtYsA==} - - get-package-info@1.0.0: - resolution: {integrity: sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw==} - engines: {node: '>= 4.0'} - - get-stream@4.1.0: - resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} - engines: {node: '>=6'} - - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - - get-stream@9.0.1: - resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} - engines: {node: '>=18'} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - global-agent@3.0.0: - resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} - engines: {node: '>=10.0'} - - global-modules@1.0.0: - resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} - engines: {node: '>=0.10.0'} - - global-prefix@1.0.2: - resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} - engines: {node: '>=0.10.0'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - homedir-polyfill@1.0.3: - resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} - engines: {node: '>=0.10.0'} - - hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - - http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - - http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} - - http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - - human-signals@8.0.0: - resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==} - engines: {node: '>=18.18.0'} - - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - image-size@0.7.5: - resolution: {integrity: sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==} - engines: {node: '>=6.9.0'} - hasBin: true - - imul@1.0.1: - resolution: {integrity: sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==} - engines: {node: '>=0.10.0'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - infer-owner@1.0.4: - resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - interpret@3.1.1: - resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} - engines: {node: '>=10.13.0'} - - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} - engines: {node: '>= 12'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-fullwidth-code-point@4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - - is-lambda@1.0.1: - resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} - - is-my-ip-valid@1.0.1: - resolution: {integrity: sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==} - - is-my-json-valid@2.20.6: - resolution: {integrity: sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - - is-property@1.0.2: - resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - - is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - - is-stream@4.0.1: - resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} - engines: {node: '>=18'} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - is-unicode-supported@2.1.0: - resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} - engines: {node: '>=18'} - - is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - - isbinaryfile@4.0.10: - resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} - engines: {node: '>= 8.0.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - - jsonpointer@5.0.1: - resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} - engines: {node: '>=0.10.0'} - - junk@3.1.0: - resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} - engines: {node: '>=8'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - listr2@7.0.2: - resolution: {integrity: sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==} - engines: {node: '>=16.0.0'} - - load-json-file@2.0.0: - resolution: {integrity: sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==} - engines: {node: '>=4'} - - locate-path@2.0.0: - resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} - engines: {node: '>=4'} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - log-update@5.0.1: - resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} - - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - - macos-alias@0.2.12: - resolution: {integrity: sha512-yiLHa7cfJcGRFq4FrR4tMlpNHb4Vy4mWnpajlSSIFM5k4Lv8/7BbbDLzCAVogWNl0LlLhizRp1drXv0hK9h0Yw==} - os: [darwin] - - make-fetch-happen@10.2.1: - resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - map-age-cleaner@0.1.3: - resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} - engines: {node: '>=6'} - - matcher@3.0.0: - resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} - engines: {node: '>=10'} - - mem@4.3.0: - resolution: {integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==} - engines: {node: '>=6'} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.33.0: - resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} - engines: {node: '>= 0.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@2.1.18: - resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass-collect@1.0.2: - resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} - engines: {node: '>= 8'} - - minipass-fetch@2.1.2: - resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - minipass-flush@1.0.5: - resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} - engines: {node: '>= 8'} - - minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} - - minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} - - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - move-file@3.1.0: - resolution: {integrity: sha512-4aE3U7CCBWgrQlQDMq8da4woBWDGHioJFiOZ8Ie6Yq2uwYQ9V2kGhTz4x3u6Wc+OU17nw0yc3rJ/lQ4jIiPe3A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - murmur-32@0.2.0: - resolution: {integrity: sha512-ZkcWZudylwF+ir3Ld1n7gL6bI2mQAzXvSobPwVtu8aYi2sbXeipeSkdcanRLzIofLcM5F53lGaKm2dk7orBi7Q==} - - nan@2.22.0: - resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} - - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - - nice-try@1.0.5: - resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - - node-abi@3.71.0: - resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} - engines: {node: '>=10'} - - node-api-version@0.2.0: - resolution: {integrity: sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==} - - 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 - - nopt@6.0.0: - resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - hasBin: true - - normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - - normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} - - npm-run-path@2.0.2: - resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} - engines: {node: '>=4'} - - npm-run-path@6.0.0: - resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} - engines: {node: '>=18'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - - p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} - - p-defer@1.0.0: - resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} - engines: {node: '>=4'} - - p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - - p-is-promise@2.1.0: - resolution: {integrity: sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==} - engines: {node: '>=6'} - - p-limit@1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@2.0.0: - resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} - engines: {node: '>=4'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - - p-try@1.0.0: - resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} - engines: {node: '>=4'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - parse-author@2.0.0: - resolution: {integrity: sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==} - engines: {node: '>=0.10.0'} - - parse-color@1.0.0: - resolution: {integrity: sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==} - - parse-json@2.2.0: - resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} - engines: {node: '>=0.10.0'} - - parse-ms@4.0.0: - resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} - engines: {node: '>=18'} - - parse-passwd@1.0.0: - resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} - engines: {node: '>=0.10.0'} - - path-exists@3.0.0: - resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} - engines: {node: '>=4'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-is-inside@1.0.2: - resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} - - path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-to-regexp@3.3.0: - resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} - - path-type@2.0.0: - resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} - engines: {node: '>=4'} - - pe-library@1.0.1: - resolution: {integrity: sha512-nh39Mo1eGWmZS7y+mK/dQIqg7S1lp38DpRxkyoHf0ZcUs/HDc+yyTjuOtTvSMZHmfSLuSQaX945u05Y2Q6UWZg==} - engines: {node: '>=14', npm: '>=7'} - - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - - pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - - plist@3.1.0: - resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} - engines: {node: '>=10.4.0'} - - postject@1.0.0-alpha.6: - resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} - engines: {node: '>=14.0.0'} - hasBin: true - - pretty-ms@9.2.0: - resolution: {integrity: sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==} - engines: {node: '>=18'} - - proc-log@2.0.1: - resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true - - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} - - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - random-path@0.1.2: - resolution: {integrity: sha512-4jY0yoEaQ5v9StCl5kZbNIQlg1QheIDBrdkDn53EynpPb9FgO6//p3X/tgMnrC45XN6QZCzU1Xz/+pSSsJBpRw==} - - range-parser@1.2.0: - resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} - engines: {node: '>= 0.6'} - - read-binary-file-arch@1.0.6: - resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} - hasBin: true - - read-pkg-up@2.0.0: - resolution: {integrity: sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==} - engines: {node: '>=4'} - - read-pkg@2.0.0: - resolution: {integrity: sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==} - engines: {node: '>=4'} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - rechoir@0.8.0: - resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} - engines: {node: '>= 10.13.0'} - - repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - resedit@2.0.3: - resolution: {integrity: sha512-oTeemxwoMuxxTYxXUwjkrOPfngTQehlv0/HoYFNkB4uzsP1Un1A9nI8JQKGOFkxpqkC7qkMs0lUsGrvUlbLNUA==} - engines: {node: '>=14', npm: '>=7'} - - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - - resolve-dir@1.0.1: - resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} - engines: {node: '>=0.10.0'} - - resolve-package@1.0.1: - resolution: {integrity: sha512-rzB7NnQpOkPHBWFPP3prUMqOP6yg3HkRGgcvR+lDyvyHoY3fZLFLYDkPXh78SPVBAE6VTCk/V+j8we4djg6o4g==} - engines: {node: '>=4', npm: '>=2'} - - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - - responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} - - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - - restore-cursor@4.0.0: - resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - - rimraf@2.6.3: - resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - roarr@2.15.4: - resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} - engines: {node: '>=8.0'} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - semver-compare@1.0.0: - resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - - serialize-error@7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} - - serve-handler@6.1.6: - resolution: {integrity: sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==} - - shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - slash@5.1.0: - resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} - engines: {node: '>=14.16'} - - slice-ansi@5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} - engines: {node: '>=12'} - - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socks-proxy-agent@7.0.0: - resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} - engines: {node: '>= 10'} - - socks@2.8.3: - resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-license-ids@3.0.20: - resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} - - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - - ssri@9.0.1: - resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - stream-buffers@2.2.0: - resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==} - engines: {node: '>= 0.10.0'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-eof@1.0.0: - resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} - engines: {node: '>=0.10.0'} - - strip-final-newline@4.0.0: - resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} - engines: {node: '>=18'} - - strip-outer@1.0.1: - resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} - engines: {node: '>=0.10.0'} - - sudo-prompt@9.2.1: - resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - - sumchecker@3.0.1: - resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} - engines: {node: '>= 8.0'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - temp@0.9.4: - resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} - engines: {node: '>=6.0.0'} - - tiny-each-async@2.0.3: - resolution: {integrity: sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==} - - tmp-promise@3.0.3: - resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} - - tmp@0.2.3: - resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} - engines: {node: '>=14.14'} - - tn1150@0.1.0: - resolution: {integrity: sha512-DbplOfQFkqG5IHcDyyrs/lkvSr3mPUVsFf/RbDppOshs22yTPnSJWEe6FkYd1txAwU/zcnR905ar2fi4kwF29w==} - engines: {node: '>=0.12'} - - to-data-view@1.1.0: - resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - trim-repeated@1.0.0: - resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} - engines: {node: '>=0.10.0'} - - type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - - type-fest@1.4.0: - resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} - engines: {node: '>=10'} - - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - - unicorn-magic@0.3.0: - resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} - engines: {node: '>=18'} - - unique-filename@2.0.1: - resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - unique-slug@3.0.0: - resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - unorm@1.6.0: - resolution: {integrity: sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==} - engines: {node: '>= 0.4.0'} - - username@5.1.0: - resolution: {integrity: sha512-PCKbdWw85JsYMvmCv5GH3kXmM66rCd9m1hBEDutPNv94b/pqCMT4NtcKyeWYvLFiE8b+ha1Jdl8XAaUdPn5QTg==} - engines: {node: '>=8'} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} - engines: {node: '>=8.0'} - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yarn-or-npm@3.0.1: - resolution: {integrity: sha512-fTiQP6WbDAh5QZAVdbMQkecZoahnbOjClTQhzv74WX5h2Uaidj1isf9FDes11TKtsZ0/ZVfZsqZ+O3x6aLERHQ==} - engines: {node: '>=8.6.0'} - hasBin: true - - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - yoctocolors@2.1.1: - resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} - engines: {node: '>=18'} - -snapshots: - - '@electron-forge/cli@7.4.0(encoding@0.1.13)': - dependencies: - '@electron-forge/core': 7.4.0(encoding@0.1.13) - '@electron-forge/shared-types': 7.4.0 - '@electron/get': 3.1.0 - chalk: 4.1.2 - commander: 4.1.1 - debug: 4.4.0 - fs-extra: 10.1.0 - listr2: 7.0.2 - semver: 7.7.2 - transitivePeerDependencies: - - bluebird - - encoding - - supports-color - - '@electron-forge/core-utils@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron/rebuild': 3.7.1 - '@malept/cross-spawn-promise': 2.0.0 - chalk: 4.1.2 - debug: 4.4.0 - find-up: 5.0.0 - fs-extra: 10.1.0 - log-symbols: 4.1.0 - semver: 7.7.2 - yarn-or-npm: 3.0.1 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/core@7.4.0(encoding@0.1.13)': - dependencies: - '@electron-forge/core-utils': 7.4.0 - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/plugin-base': 7.4.0 - '@electron-forge/publisher-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 - '@electron-forge/template-vite': 7.4.0 - '@electron-forge/template-vite-typescript': 7.4.0 - '@electron-forge/template-webpack': 7.4.0 - '@electron-forge/template-webpack-typescript': 7.4.0 - '@electron-forge/tracer': 7.4.0 - '@electron/get': 3.1.0 - '@electron/packager': 18.3.6 - '@electron/rebuild': 3.7.1 - '@malept/cross-spawn-promise': 2.0.0 - chalk: 4.1.2 - debug: 4.4.0 - fast-glob: 3.3.3 - filenamify: 4.3.0 - find-up: 5.0.0 - fs-extra: 10.1.0 - got: 11.8.6 - interpret: 3.1.1 - listr2: 7.0.2 - lodash: 4.17.21 - log-symbols: 4.1.0 - node-fetch: 2.7.0(encoding@0.1.13) - progress: 2.0.3 - rechoir: 0.8.0 - resolve-package: 1.0.1 - semver: 7.7.2 - source-map-support: 0.5.21 - sudo-prompt: 9.2.1 - username: 5.1.0 - yarn-or-npm: 3.0.1 - transitivePeerDependencies: - - bluebird - - encoding - - supports-color - - '@electron-forge/maker-base@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - fs-extra: 10.1.0 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-deb@7.4.0': - dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - optionalDependencies: - electron-installer-debian: 3.2.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-dmg@7.4.0': - dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - fs-extra: 10.1.0 - optionalDependencies: - electron-installer-dmg: 4.0.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-rpm@7.4.0': - dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - optionalDependencies: - electron-installer-redhat: 3.4.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-squirrel@7.4.0': - dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - fs-extra: 10.1.0 - optionalDependencies: - electron-winstaller: 5.4.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-zip@7.4.0': - dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - cross-zip: 4.0.1 - fs-extra: 10.1.0 - got: 11.8.6 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/plugin-auto-unpack-natives@7.4.0': - dependencies: - '@electron-forge/plugin-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/plugin-base@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/plugin-fuses@7.4.0(@electron/fuses@1.8.0)': - dependencies: - '@electron-forge/plugin-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - '@electron/fuses': 1.8.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/publisher-base@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/shared-types@7.4.0': - dependencies: - '@electron-forge/tracer': 7.4.0 - '@electron/packager': 18.3.6 - '@electron/rebuild': 3.7.1 - listr2: 7.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/template-base@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.0 - fs-extra: 10.1.0 - username: 5.1.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/template-vite-typescript@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 - fs-extra: 10.1.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/template-vite@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 - fs-extra: 10.1.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/template-webpack-typescript@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 - fs-extra: 10.1.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/template-webpack@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 - fs-extra: 10.1.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/tracer@7.4.0': - dependencies: - chrome-trace-event: 1.0.4 - - '@electron/asar@3.2.13': - dependencies: - '@types/glob': 7.2.0 - commander: 5.1.0 - glob: 7.2.3 - minimatch: 3.1.2 - - '@electron/fuses@1.8.0': - dependencies: - chalk: 4.1.2 - fs-extra: 9.1.0 - minimist: 1.2.8 - - '@electron/get@2.0.3': - dependencies: - debug: 4.4.0 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 - progress: 2.0.3 - semver: 6.3.1 - sumchecker: 3.0.1 - optionalDependencies: - global-agent: 3.0.0 - transitivePeerDependencies: - - supports-color - - '@electron/get@3.1.0': - dependencies: - debug: 4.4.0 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 - progress: 2.0.3 - semver: 6.3.1 - sumchecker: 3.0.1 - optionalDependencies: - global-agent: 3.0.0 - transitivePeerDependencies: - - supports-color - - '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': - dependencies: - env-paths: 2.2.1 - exponential-backoff: 3.1.1 - glob: 8.1.0 - graceful-fs: 4.2.11 - make-fetch-happen: 10.2.1 - nopt: 6.0.0 - proc-log: 2.0.1 - semver: 7.7.2 - tar: 6.2.1 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron/notarize@2.5.0': - dependencies: - debug: 4.4.0 - fs-extra: 9.1.0 - promise-retry: 2.0.1 - transitivePeerDependencies: - - supports-color - - '@electron/osx-sign@1.3.2': - dependencies: - compare-version: 0.1.2 - debug: 4.4.0 - fs-extra: 10.1.0 - isbinaryfile: 4.0.10 - minimist: 1.2.8 - plist: 3.1.0 - transitivePeerDependencies: - - supports-color - - '@electron/packager@18.3.6': - dependencies: - '@electron/asar': 3.2.13 - '@electron/get': 3.1.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.2 - '@electron/universal': 2.0.1 - '@electron/windows-sign': 1.2.0 - debug: 4.4.0 - extract-zip: 2.0.1 - filenamify: 4.3.0 - fs-extra: 11.2.0 - galactus: 1.0.0 - get-package-info: 1.0.0 - junk: 3.1.0 - parse-author: 2.0.0 - plist: 3.1.0 - resedit: 2.0.3 - resolve: 1.22.10 - semver: 7.7.2 - yargs-parser: 21.1.1 - transitivePeerDependencies: - - supports-color - - '@electron/rebuild@3.7.1': - dependencies: - '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 - '@malept/cross-spawn-promise': 2.0.0 - chalk: 4.1.2 - debug: 4.4.0 - detect-libc: 2.0.3 - fs-extra: 10.1.0 - got: 11.8.6 - node-abi: 3.71.0 - node-api-version: 0.2.0 - ora: 5.4.1 - read-binary-file-arch: 1.0.6 - semver: 7.7.2 - tar: 6.2.1 - yargs: 17.7.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron/universal@2.0.1': - dependencies: - '@electron/asar': 3.2.13 - '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.0 - dir-compare: 4.2.0 - fs-extra: 11.2.0 - minimatch: 9.0.5 - plist: 3.1.0 - transitivePeerDependencies: - - supports-color - - '@electron/windows-sign@1.2.0': - dependencies: - cross-dirname: 0.1.0 - debug: 4.4.0 - fs-extra: 11.2.0 - minimist: 1.2.8 - postject: 1.0.0-alpha.6 - transitivePeerDependencies: - - supports-color - - '@gar/promisify@1.1.3': {} - - '@malept/cross-spawn-promise@1.1.1': - dependencies: - cross-spawn: 7.0.6 - optional: true - - '@malept/cross-spawn-promise@2.0.0': - dependencies: - cross-spawn: 7.0.6 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.18.0 - - '@npmcli/fs@2.1.2': - dependencies: - '@gar/promisify': 1.1.3 - semver: 7.7.2 - - '@npmcli/move-file@2.0.1': - dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 - - '@pipelab/core@1.4.9': {} - - '@pipelab/steamworks.js@0.11.1': - dependencies: - '@types/node': 22.10.5 - - '@sec-ant/readable-stream@0.4.1': {} - - '@sindresorhus/is@4.6.0': {} - - '@sindresorhus/merge-streams@4.0.0': {} - - '@szmarczak/http-timer@4.0.6': - dependencies: - defer-to-connect: 2.0.1 - - '@tootallnate/once@2.0.0': {} - - '@types/cacheable-request@6.0.3': - dependencies: - '@types/http-cache-semantics': 4.0.4 - '@types/keyv': 3.1.4 - '@types/node': 22.10.5 - '@types/responselike': 1.0.3 - - '@types/fs-extra@9.0.13': - dependencies: - '@types/node': 22.10.5 - optional: true - - '@types/glob@7.2.0': - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 22.10.5 - - '@types/http-cache-semantics@4.0.4': {} - - '@types/keyv@3.1.4': - dependencies: - '@types/node': 22.10.5 - - '@types/mime-types@3.0.1': {} - - '@types/minimatch@5.1.2': {} - - '@types/node@22.10.5': - dependencies: - undici-types: 6.20.0 - - '@types/responselike@1.0.3': - dependencies: - '@types/node': 22.10.5 - - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 22.10.5 - optional: true - - '@xmldom/xmldom@0.8.10': {} - - abbrev@1.1.1: {} - - agent-base@6.0.2: - dependencies: - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - agentkeepalive@4.6.0: - dependencies: - humanize-ms: 1.2.1 - - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - - ansi-escapes@5.0.0: - dependencies: - type-fest: 1.4.0 - - ansi-regex@5.0.1: {} - - ansi-regex@6.1.0: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.1: {} - - appdmg@0.6.6: - dependencies: - async: 1.5.2 - ds-store: 0.1.6 - execa: 1.0.0 - fs-temp: 1.2.1 - fs-xattr: 0.3.1 - image-size: 0.7.5 - is-my-json-valid: 2.20.6 - minimist: 1.2.8 - parse-color: 1.0.0 - path-exists: 4.0.0 - repeat-string: 1.6.1 - optional: true - - async@1.5.2: - optional: true - - at-least-node@1.0.0: {} - - author-regex@1.0.0: {} - - balanced-match@1.0.2: {} - - base32-encode@1.2.0: - dependencies: - to-data-view: 1.1.0 - optional: true - - base64-js@1.5.1: {} - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - - bluebird@3.7.2: {} - - boolean@3.2.0: - optional: true - - bplist-creator@0.0.8: - dependencies: - stream-buffers: 2.2.0 - optional: true - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - buffer-crc32@0.2.13: {} - - buffer-from@1.1.2: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bytes@3.0.0: {} - - cacache@16.1.3: - dependencies: - '@npmcli/fs': 2.1.2 - '@npmcli/move-file': 2.0.1 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 8.1.0 - infer-owner: 1.0.4 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 - p-map: 4.0.0 - promise-inflight: 1.0.1 - rimraf: 3.0.2 - ssri: 9.0.1 - tar: 6.2.1 - unique-filename: 2.0.1 - transitivePeerDependencies: - - bluebird - - cacheable-lookup@5.0.4: {} - - cacheable-request@7.0.4: - dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.1.1 - keyv: 4.5.4 - lowercase-keys: 2.0.0 - normalize-url: 6.1.0 - responselike: 2.0.1 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chownr@2.0.0: {} - - chrome-trace-event@1.0.4: {} - - clean-stack@2.2.0: {} - - cli-cursor@3.1.0: - dependencies: - restore-cursor: 3.1.0 - - cli-cursor@4.0.0: - dependencies: - restore-cursor: 4.0.0 - - cli-spinners@2.9.2: {} - - cli-truncate@3.1.0: - dependencies: - slice-ansi: 5.0.0 - string-width: 5.1.2 - - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - optional: true - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - clone-response@1.0.3: - dependencies: - mimic-response: 1.0.1 - - clone@1.0.4: {} - - color-convert@0.5.3: - optional: true - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - colorette@2.0.20: {} - - commander@4.1.1: {} - - commander@5.1.0: {} - - commander@9.5.0: {} - - compare-version@0.1.2: {} - - concat-map@0.0.1: {} - - content-disposition@0.5.2: {} - - cross-dirname@0.1.0: {} - - cross-spawn@6.0.6: - dependencies: - nice-try: 1.0.5 - path-key: 2.0.1 - semver: 5.7.2 - shebang-command: 1.2.0 - which: 1.3.1 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - cross-zip@4.0.1: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@4.4.0: - dependencies: - ms: 2.1.3 - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - defaults@1.0.4: - dependencies: - clone: 1.0.4 - - defer-to-connect@2.0.1: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - optional: true - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - optional: true - - detect-libc@2.0.3: {} - - detect-node@2.1.0: - optional: true - - dir-compare@4.2.0: - dependencies: - minimatch: 3.1.2 - p-limit: 3.1.0 - - discord-rpc@4.0.1(encoding@0.1.13): - dependencies: - node-fetch: 2.7.0(encoding@0.1.13) - ws: 7.5.10 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - - ds-store@0.1.6: - dependencies: - bplist-creator: 0.0.8 - macos-alias: 0.2.12 - tn1150: 0.1.0 - optional: true - - eastasianwidth@0.2.0: {} - - electron-installer-common@0.10.4: - dependencies: - '@electron/asar': 3.2.13 - '@malept/cross-spawn-promise': 1.1.1 - debug: 4.4.0 - fs-extra: 9.1.0 - glob: 7.2.3 - lodash: 4.17.21 - parse-author: 2.0.0 - semver: 7.7.2 - tmp-promise: 3.0.3 - optionalDependencies: - '@types/fs-extra': 9.0.13 - transitivePeerDependencies: - - supports-color - optional: true - - electron-installer-debian@3.2.0: - dependencies: - '@malept/cross-spawn-promise': 1.1.1 - debug: 4.4.0 - electron-installer-common: 0.10.4 - fs-extra: 9.1.0 - get-folder-size: 2.0.1 - lodash: 4.17.21 - word-wrap: 1.2.5 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - optional: true - - electron-installer-dmg@4.0.0: - dependencies: - debug: 4.4.0 - minimist: 1.2.8 - optionalDependencies: - appdmg: 0.6.6 - transitivePeerDependencies: - - supports-color - optional: true - - electron-installer-redhat@3.4.0: - dependencies: - '@malept/cross-spawn-promise': 1.1.1 - debug: 4.4.0 - electron-installer-common: 0.10.4 - fs-extra: 9.1.0 - lodash: 4.17.21 - word-wrap: 1.2.5 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - optional: true - - electron-serve@2.1.1: {} - - electron-squirrel-startup@1.0.1: - dependencies: - debug: 2.6.9 - transitivePeerDependencies: - - supports-color - - electron-winstaller@5.4.0: - dependencies: - '@electron/asar': 3.2.13 - debug: 4.4.0 - fs-extra: 7.0.1 - lodash: 4.17.21 - temp: 0.9.4 - optionalDependencies: - '@electron/windows-sign': 1.2.0 - transitivePeerDependencies: - - supports-color - optional: true - - electron@39.2.3: - dependencies: - '@electron/get': 2.0.3 - '@types/node': 22.10.5 - extract-zip: 2.0.1 - transitivePeerDependencies: - - supports-color - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - encode-utf8@1.0.3: - optional: true - - encoding@0.1.13: - dependencies: - iconv-lite: 0.6.3 - optional: true - - end-of-stream@1.4.4: - dependencies: - once: 1.4.0 - - env-paths@2.2.1: {} - - err-code@2.0.3: {} - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - - es-define-property@1.0.1: - optional: true - - es-errors@1.3.0: - optional: true - - es6-error@4.1.1: - optional: true - - escalade@3.2.0: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: - optional: true - - eventemitter3@5.0.1: {} - - execa@1.0.0: - dependencies: - cross-spawn: 6.0.6 - get-stream: 4.1.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 - signal-exit: 3.0.7 - strip-eof: 1.0.0 - - execa@9.5.2: - dependencies: - '@sindresorhus/merge-streams': 4.0.0 - cross-spawn: 7.0.6 - figures: 6.1.0 - get-stream: 9.0.1 - human-signals: 8.0.0 - is-plain-obj: 4.1.0 - is-stream: 4.0.1 - npm-run-path: 6.0.0 - pretty-ms: 9.2.0 - signal-exit: 4.1.0 - strip-final-newline: 4.0.0 - yoctocolors: 2.1.1 - - expand-tilde@2.0.2: - dependencies: - homedir-polyfill: 1.0.3 - - exponential-backoff@3.1.1: {} - - extract-zip@2.0.1: - dependencies: - debug: 4.4.0 - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - - fast-glob@3.3.3: - 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.8 - - fastq@1.18.0: - dependencies: - reusify: 1.0.4 - - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - - figures@6.1.0: - dependencies: - is-unicode-supported: 2.1.0 - - filename-reserved-regex@2.0.0: {} - - filenamify@4.3.0: - dependencies: - filename-reserved-regex: 2.0.0 - strip-outer: 1.0.1 - trim-repeated: 1.0.0 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@2.1.0: - dependencies: - locate-path: 2.0.0 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flora-colossus@2.0.0: - dependencies: - debug: 4.4.0 - fs-extra: 10.1.0 - transitivePeerDependencies: - - supports-color - - fmix@0.1.0: - dependencies: - imul: 1.0.1 - optional: true - - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-extra@11.2.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - optional: true - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@9.1.0: - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - - fs-temp@1.2.1: - dependencies: - random-path: 0.1.2 - optional: true - - fs-xattr@0.3.1: - optional: true - - fs.realpath@1.0.0: {} - - function-bind@1.1.2: {} - - galactus@1.0.0: - dependencies: - debug: 4.4.0 - flora-colossus: 2.0.0 - fs-extra: 10.1.0 - transitivePeerDependencies: - - supports-color - - gar@1.0.4: - optional: true - - generate-function@2.3.1: - dependencies: - is-property: 1.0.2 - optional: true - - generate-object-property@1.2.0: - dependencies: - is-property: 1.0.2 - optional: true - - get-caller-file@2.0.5: {} - - get-folder-size@2.0.1: - dependencies: - gar: 1.0.4 - tiny-each-async: 2.0.3 - optional: true - - get-installed-path@2.1.1: - dependencies: - global-modules: 1.0.0 - - get-package-info@1.0.0: - dependencies: - bluebird: 3.7.2 - debug: 2.6.9 - lodash.get: 4.4.2 - read-pkg-up: 2.0.0 - transitivePeerDependencies: - - supports-color - - get-stream@4.1.0: - dependencies: - pump: 3.0.2 - - get-stream@5.2.0: - dependencies: - pump: 3.0.2 - - get-stream@9.0.1: - dependencies: - '@sec-ant/readable-stream': 0.4.1 - is-stream: 4.0.1 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - global-agent@3.0.0: - dependencies: - boolean: 3.2.0 - es6-error: 4.1.1 - matcher: 3.0.0 - roarr: 2.15.4 - semver: 7.7.2 - serialize-error: 7.0.1 - optional: true - - global-modules@1.0.0: - dependencies: - global-prefix: 1.0.2 - is-windows: 1.0.2 - resolve-dir: 1.0.1 - - global-prefix@1.0.2: - dependencies: - expand-tilde: 2.0.2 - homedir-polyfill: 1.0.3 - ini: 1.3.8 - is-windows: 1.0.2 - which: 1.3.1 - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - optional: true - - gopd@1.2.0: - optional: true - - got@11.8.6: - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 4.0.6 - '@types/cacheable-request': 6.0.3 - '@types/responselike': 1.0.3 - cacheable-lookup: 5.0.4 - cacheable-request: 7.0.4 - decompress-response: 6.0.0 - http2-wrapper: 1.0.3 - lowercase-keys: 2.0.0 - p-cancelable: 2.1.1 - responselike: 2.0.1 - - graceful-fs@4.2.11: {} - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - optional: true - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - homedir-polyfill@1.0.3: - dependencies: - parse-passwd: 1.0.0 - - hosted-git-info@2.8.9: {} - - http-cache-semantics@4.1.1: {} - - http-proxy-agent@5.0.0: - dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - http2-wrapper@1.0.3: - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - human-signals@8.0.0: {} - - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - optional: true - - ieee754@1.2.1: {} - - image-size@0.7.5: - optional: true - - imul@1.0.1: - optional: true - - imurmurhash@0.1.4: {} - - indent-string@4.0.0: {} - - infer-owner@1.0.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ini@1.3.8: {} - - interpret@3.1.1: {} - - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - - is-arrayish@0.2.1: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-fullwidth-code-point@4.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-interactive@1.0.0: {} - - is-lambda@1.0.1: {} - - is-my-ip-valid@1.0.1: - optional: true - - is-my-json-valid@2.20.6: - dependencies: - generate-function: 2.3.1 - generate-object-property: 1.2.0 - is-my-ip-valid: 1.0.1 - jsonpointer: 5.0.1 - xtend: 4.0.2 - optional: true - - is-number@7.0.0: {} - - is-plain-obj@4.1.0: {} - - is-property@1.0.2: - optional: true - - is-stream@1.1.0: {} - - is-stream@4.0.1: {} - - is-unicode-supported@0.1.0: {} - - is-unicode-supported@2.1.0: {} - - is-windows@1.0.2: {} - - isbinaryfile@4.0.10: {} - - isexe@2.0.0: {} - - jsbn@1.1.0: {} - - json-buffer@3.0.1: {} - - json-stringify-safe@5.0.1: - optional: true - - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - jsonpointer@5.0.1: - optional: true - - junk@3.1.0: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - listr2@7.0.2: - dependencies: - cli-truncate: 3.1.0 - colorette: 2.0.20 - eventemitter3: 5.0.1 - log-update: 5.0.1 - rfdc: 1.4.1 - wrap-ansi: 8.1.0 - - load-json-file@2.0.0: - dependencies: - graceful-fs: 4.2.11 - parse-json: 2.2.0 - pify: 2.3.0 - strip-bom: 3.0.0 - - locate-path@2.0.0: - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.get@4.4.2: {} - - lodash@4.17.21: {} - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - log-update@5.0.1: - dependencies: - ansi-escapes: 5.0.0 - cli-cursor: 4.0.0 - slice-ansi: 5.0.0 - strip-ansi: 7.1.0 - wrap-ansi: 8.1.0 - - lowercase-keys@2.0.0: {} - - lru-cache@7.18.3: {} - - macos-alias@0.2.12: - dependencies: - nan: 2.22.0 - optional: true - - make-fetch-happen@10.2.1: - dependencies: - agentkeepalive: 4.6.0 - cacache: 16.1.3 - http-cache-semantics: 4.1.1 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 - is-lambda: 1.0.1 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 2.1.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - negotiator: 0.6.4 - promise-retry: 2.0.1 - socks-proxy-agent: 7.0.0 - ssri: 9.0.1 - transitivePeerDependencies: - - bluebird - - supports-color - - map-age-cleaner@0.1.3: - dependencies: - p-defer: 1.0.0 - - matcher@3.0.0: - dependencies: - escape-string-regexp: 4.0.0 - optional: true - - mem@4.3.0: - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 2.1.0 - p-is-promise: 2.1.0 - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mime-db@1.33.0: {} - - mime-db@1.54.0: {} - - mime-types@2.1.18: - dependencies: - mime-db: 1.33.0 - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - - mimic-fn@2.1.0: {} - - mimic-response@1.0.1: {} - - mimic-response@3.1.0: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.1 - - minimist@1.2.8: {} - - minipass-collect@1.0.2: - dependencies: - minipass: 3.3.6 - - minipass-fetch@2.1.2: - dependencies: - minipass: 3.3.6 - minipass-sized: 1.0.3 - minizlib: 2.1.2 - optionalDependencies: - encoding: 0.1.13 - - minipass-flush@1.0.5: - dependencies: - minipass: 3.3.6 - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - optional: true - - mkdirp@1.0.4: {} - - move-file@3.1.0: - dependencies: - path-exists: 5.0.0 - - mri@1.2.0: {} - - ms@2.0.0: {} - - ms@2.1.3: {} - - murmur-32@0.2.0: - dependencies: - encode-utf8: 1.0.3 - fmix: 0.1.0 - imul: 1.0.1 - optional: true - - nan@2.22.0: - optional: true - - negotiator@0.6.4: {} - - nice-try@1.0.5: {} - - node-abi@3.71.0: - dependencies: - semver: 7.7.2 - - node-api-version@0.2.0: - dependencies: - semver: 7.7.2 - - node-fetch@2.7.0(encoding@0.1.13): - dependencies: - whatwg-url: 5.0.0 - optionalDependencies: - encoding: 0.1.13 - - nopt@6.0.0: - dependencies: - abbrev: 1.1.1 - - normalize-package-data@2.5.0: - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.10 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - - normalize-url@6.1.0: {} - - npm-run-path@2.0.2: - dependencies: - path-key: 2.0.1 - - npm-run-path@6.0.0: - dependencies: - path-key: 4.0.0 - unicorn-magic: 0.3.0 - - object-keys@1.1.1: - optional: true - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - - p-cancelable@2.1.1: {} - - p-defer@1.0.0: {} - - p-finally@1.0.0: {} - - p-is-promise@2.1.0: {} - - p-limit@1.3.0: - dependencies: - p-try: 1.0.0 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@2.0.0: - dependencies: - p-limit: 1.3.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - - p-try@1.0.0: {} - - p-try@2.2.0: {} - - parse-author@2.0.0: - dependencies: - author-regex: 1.0.0 - - parse-color@1.0.0: - dependencies: - color-convert: 0.5.3 - optional: true - - parse-json@2.2.0: - dependencies: - error-ex: 1.3.2 - - parse-ms@4.0.0: {} - - parse-passwd@1.0.0: {} - - path-exists@3.0.0: {} - - path-exists@4.0.0: {} - - path-exists@5.0.0: {} - - path-is-absolute@1.0.1: {} - - path-is-inside@1.0.2: {} - - path-key@2.0.1: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - path-parse@1.0.7: {} - - path-to-regexp@3.3.0: {} - - path-type@2.0.0: - dependencies: - pify: 2.3.0 - - pe-library@1.0.1: {} - - pend@1.2.0: {} - - picomatch@2.3.1: {} - - pify@2.3.0: {} - - pkg-dir@4.2.0: - dependencies: - find-up: 4.1.0 - - plist@3.1.0: - dependencies: - '@xmldom/xmldom': 0.8.10 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - postject@1.0.0-alpha.6: - dependencies: - commander: 9.5.0 - - pretty-ms@9.2.0: - dependencies: - parse-ms: 4.0.0 - - proc-log@2.0.1: {} - - progress@2.0.3: {} - - promise-inflight@1.0.1: {} - - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - - pump@3.0.2: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - queue-microtask@1.2.3: {} - - quick-lru@5.1.1: {} - - random-path@0.1.2: - dependencies: - base32-encode: 1.2.0 - murmur-32: 0.2.0 - optional: true - - range-parser@1.2.0: {} - - read-binary-file-arch@1.0.6: - dependencies: - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - read-pkg-up@2.0.0: - dependencies: - find-up: 2.1.0 - read-pkg: 2.0.0 - - read-pkg@2.0.0: - dependencies: - load-json-file: 2.0.0 - normalize-package-data: 2.5.0 - path-type: 2.0.0 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - rechoir@0.8.0: - dependencies: - resolve: 1.22.10 - - repeat-string@1.6.1: - optional: true - - require-directory@2.1.1: {} - - resedit@2.0.3: - dependencies: - pe-library: 1.0.1 - - resolve-alpn@1.2.1: {} - - resolve-dir@1.0.1: - dependencies: - expand-tilde: 2.0.2 - global-modules: 1.0.0 - - resolve-package@1.0.1: - dependencies: - get-installed-path: 2.1.1 - - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - responselike@2.0.1: - dependencies: - lowercase-keys: 2.0.0 - - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - - restore-cursor@4.0.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - - retry@0.12.0: {} - - reusify@1.0.4: {} - - rfdc@1.4.1: {} - - rimraf@2.6.3: - dependencies: - glob: 7.2.3 - optional: true - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - roarr@2.15.4: - dependencies: - boolean: 3.2.0 - detect-node: 2.1.0 - globalthis: 1.0.4 - json-stringify-safe: 5.0.1 - semver-compare: 1.0.0 - sprintf-js: 1.1.3 - optional: true - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: - optional: true - - semver-compare@1.0.0: - optional: true - - semver@5.7.2: {} - - semver@6.3.1: {} - - semver@7.7.2: {} - - serialize-error@7.0.1: - dependencies: - type-fest: 0.13.1 - optional: true - - serve-handler@6.1.6: - dependencies: - bytes: 3.0.0 - content-disposition: 0.5.2 - mime-types: 2.1.18 - minimatch: 3.1.2 - path-is-inside: 1.0.2 - path-to-regexp: 3.3.0 - range-parser: 1.2.0 - - shebang-command@1.2.0: - dependencies: - shebang-regex: 1.0.0 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@1.0.0: {} - - shebang-regex@3.0.0: {} - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - slash@5.1.0: {} - - slice-ansi@5.0.0: - dependencies: - ansi-styles: 6.2.1 - is-fullwidth-code-point: 4.0.0 - - smart-buffer@4.2.0: {} - - socks-proxy-agent@7.0.0: - dependencies: - agent-base: 6.0.2 - debug: 4.4.0 - socks: 2.8.3 - transitivePeerDependencies: - - supports-color - - socks@2.8.3: - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.20 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 - - spdx-license-ids@3.0.20: {} - - sprintf-js@1.1.3: {} - - ssri@9.0.1: - dependencies: - minipass: 3.3.6 - - stream-buffers@2.2.0: - optional: true - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.1.0 - - strip-bom@3.0.0: {} - - strip-eof@1.0.0: {} - - strip-final-newline@4.0.0: {} - - strip-outer@1.0.1: - dependencies: - escape-string-regexp: 1.0.5 - - sudo-prompt@9.2.1: {} - - sumchecker@3.0.1: - dependencies: - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - - temp@0.9.4: - dependencies: - mkdirp: 0.5.6 - rimraf: 2.6.3 - optional: true - - tiny-each-async@2.0.3: - optional: true - - tmp-promise@3.0.3: - dependencies: - tmp: 0.2.3 - optional: true - - tmp@0.2.3: - optional: true - - tn1150@0.1.0: - dependencies: - unorm: 1.6.0 - optional: true - - to-data-view@1.1.0: - optional: true - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tr46@0.0.3: {} - - trim-repeated@1.0.0: - dependencies: - escape-string-regexp: 1.0.5 - - type-fest@0.13.1: - optional: true - - type-fest@1.4.0: {} - - undici-types@6.20.0: {} - - unicorn-magic@0.3.0: {} - - unique-filename@2.0.1: - dependencies: - unique-slug: 3.0.0 - - unique-slug@3.0.0: - dependencies: - imurmurhash: 0.1.4 - - universalify@0.1.2: {} - - universalify@2.0.1: {} - - unorm@1.6.0: - optional: true - - username@5.1.0: - dependencies: - execa: 1.0.0 - mem: 4.3.0 - - util-deprecate@1.0.2: {} - - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - - wcwidth@1.0.1: - dependencies: - defaults: 1.0.4 - - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which@1.3.1: - dependencies: - isexe: 2.0.0 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: - optional: true - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - wrappy@1.0.2: {} - - ws@7.5.10: {} - - ws@8.18.1: {} - - xmlbuilder@15.1.1: {} - - xtend@4.0.2: - optional: true - - y18n@5.0.8: {} - - yallist@4.0.0: {} - - yargs-parser@20.2.9: - optional: true - - yargs-parser@21.1.1: {} - - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - optional: true - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yarn-or-npm@3.0.1: - dependencies: - cross-spawn: 6.0.6 - pkg-dir: 4.2.0 - - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - - yocto-queue@0.1.0: {} - - yoctocolors@2.1.1: {} diff --git a/assets/electron/template/app/src/handlers/user/folder.js b/assets/electron/template/app/src/handlers/user/folder.js deleted file mode 100644 index 1f8e8337..00000000 --- a/assets/electron/template/app/src/handlers/user/folder.js +++ /dev/null @@ -1,71 +0,0 @@ -// @ts-check - -import { app } from 'electron' -import { join } from 'path' - -import slash from 'slash'; -import { getAppName } from '../../utils.js'; - -/** - * @param {import('@pipelab/core').MakeInputOutput} json - * @param {import('ws').WebSocket} ws - * @param {ElectronAppConfig.Config} config - */ -export default (json, ws, config) => { - try { - const name = json.body.name - - let folder - - const { env } = process - // windows linux - const { APPDATA, LOCALAPPDATA, XDG_DATA_HOME, XDG_CONFIG_HOME } = env - const appDataBackup = app.getPath('appData') - const localAppData = LOCALAPPDATA ?? XDG_DATA_HOME ?? appDataBackup - const appData = APPDATA ?? XDG_CONFIG_HOME ?? appDataBackup - - const appNameFolder = getAppName(config) - - const localUserData = join(localAppData, appNameFolder) - const userData = join(appData, appNameFolder) - - if (name === 'app') { - folder = app.getAppPath() - } else if (name === 'project') { - folder = join(app.getAppPath(), 'src', 'app') // path to construct files - } else if (name === 'localAppData') { - folder = localAppData - } else if (name === 'localUserData') { - folder = localUserData - } else if (name === 'userData') { - folder = userData - } else { - folder = app.getPath(name) - } - - /** - * @type {import('@pipelab/core').MakeInputOutput} - */ - const userFolderResult = { - url: json.url, - correlationId: json.correlationId, - body: { - data: slash(folder) - } - } - ws.send(JSON.stringify(userFolderResult)) - } catch (e) { - console.error('e', e) - /** - * @type {import('@pipelab/core').MakeInputOutput} - */ - const userFolderResult = { - url: json.url, - correlationId: json.correlationId, - body: { - error: e.message - } - } - ws.send(JSON.stringify(userFolderResult)) - } -} diff --git a/assets/electron/template/app/src/index.js b/assets/electron/template/app/src/index.js deleted file mode 100644 index 1443a248..00000000 --- a/assets/electron/template/app/src/index.js +++ /dev/null @@ -1,958 +0,0 @@ -// @ts-check - -import { app, BrowserWindow, ipcMain, safeStorage, session, shell } from 'electron' -import { dirname, join } from 'node:path' -import path from 'node:path' -import { createReadStream } from 'node:fs' -import { stat } from 'node:fs/promises' -import mime from 'mime-types' -import serve from 'serve-handler' -import { createServer } from 'http' -import { WebSocketServer, WebSocket } from 'ws' -import './custom-main.js' -import mri from 'mri' -import config from '../config.cjs' -import steamworks from '@pipelab/steamworks.js' -import DiscordRPC from 'discord-rpc' - -// user -import userFolder from './handlers/user/folder.js' - -// fs -import fsWrite from './handlers/fs/write.js' -import fsWriteBase64 from './handlers/fs/write-base64.js' -import fsRead from './handlers/fs/read.js' -import fsReadBinary from './handlers/fs/read-binary.js' -import fsFolderCreate from './handlers/fs/folder-create.js' -import fsList from './handlers/fs/list.js' -import fsMove from './handlers/fs/move.js' -import fsDelete from './handlers/fs/delete.js' -import fsCopy from './handlers/fs/copy.js' -import fsFileSize from './handlers/fs/file-size.js' -import fsExist from './handlers/fs/exist.js' - -// window -import windowMaximize from './handlers/window/maximize.js' -import windowMinimize from './handlers/window/minimize.js' -import windowRequestAttention from './handlers/window/request-attention.js' -import windowRestore from './handlers/window/restore.js' -import windowSetAlwaysOnTop from './handlers/window/set-always-on-top.js' -import windowSetHeight from './handlers/window/set-height.js' -import windowSetWidth from './handlers/window/set-width.js' -import windowSetMinimumSize from './handlers/window/set-minimum-size.js' -import windowSetMaximumSize from './handlers/window/set-maximum-size.js' -import windowSetResizable from './handlers/window/set-resizable.js' -import windowSetTitle from './handlers/window/set-title.js' -import windowSetX from './handlers/window/set-x.js' -import windowSetY from './handlers/window/set-y.js' -import windowShowDevTools from './handlers/window/show-dev-tools.js' -import windowUnmaximize from './handlers/window/unmaximize.js' -import windowSetFullscreen from './handlers/window/set-fullscreen.js' -import windowSetIgnoreMouseEvents from './handlers/window/set-ignore-mouse-events.js' - -// dialog -import dialogFolder from './handlers/dialog/folder.js' -import dialogOpen from './handlers/dialog/open.js' -import dialogSave from './handlers/dialog/save.js' - -// general -import engine from './handlers/general/engine.js' -import run from './handlers/general/run.js' -import open from './handlers/general/open.js' -import showInExplorer from './handlers/general/open-in-explorer.js' -import exit from './handlers/general/exit.js' - -// steam raw -import steamRaw from './handlers/steam/raw.js' -import steamUploadScore from './handlers/steam/uploadScore.js' -import steamDownloadScore from './handlers/steam/downloadScore.js' -import steamUpdateItem from './handlers/steam/updateItem.js' -import steamGetItem from './handlers/steam/getItem.js' -import steamGetItems from './handlers/steam/getItems.js' -import steamSubscribe from './handlers/steam/subscribe.js' -import steamUnsubscribe from './handlers/steam/unsubscribe.js' -import steamState from './handlers/steam/state.js' -import steamInstallInfo from './handlers/steam/installInfo.js' -import steamDownloadInfo from './handlers/steam/downloadInfo.js' -import steamDownload from './handlers/steam/download.js' -import steamDeleteItem from './handlers/steam/deleteItem.js' -import steamSaveScreenshot from './handlers/steam/saveScreenshot.js' - -// discord set activity -import discordSetActivity from './handlers/discord/set-activity.js' - -import { getAppName } from './utils.js' - -import infos from './handlers/general/infos.js' - -import semver from 'semver' -import { protocol } from 'electron/main' - -/** - * Assert switch is exhaustive - * @param {never} _x - * @returns {never} - */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function assertUnreachable(_x) { - throw new Error("Didn't expect to get here") -} - -safeStorage.setUsePlainTextEncryption(true) - -protocol.registerSchemesAsPrivileged([ - { - scheme: 'app', - privileges: { - standard: true, // Permet de résoudre les origines correctement (corrige l'erreur 'null') - secure: true, // Traité comme une origine sécurisée (nécessaire pour Service Workers/Web Workers) - supportFetchAPI: true, // Active l'API Fetch pour ce protocole - corsEnabled: true, // Autorise les requêtes CORS si nécessaire - allowServiceWorkers: true // Souvent requis par Construct 3 - } - } -]) - -function createErrorWindow(errorMessage) { - const errorWindow = new BrowserWindow({ - width: 600, - height: 250, - title: 'Game Startup Error', - center: true, - resizable: false, - webPreferences: { - preload: join(metaDirname, 'preload.js') - } - }) - - const htmlContent = ` - - - - Error - - - -

${errorMessage}

-
- -
- - - - ` - - // Encode the HTML and load it as a data URL - const encodedHtml = encodeURIComponent(htmlContent) - errorWindow.loadURL(`data:text/html,${encodedHtml}`) - return errorWindow -} - -process.on('uncaughtException', async (error) => { - console.error('Uncaught Exception:', error, error.code) - - if (error.code === 'EADDRINUSE') { - const errorWindow = await createErrorWindow( - 'Unable to start the game.
Is another instance already running?' - ) - errorWindow.show() - errorWindow.on('closed', () => { - app.quit() - }) - } -}) -process.on('unhandledRejection', (reason) => { - console.error('Unhandled Promise Rejection:', reason) -}) - -console.log('process.argv', process.argv) -const argv = process.argv - -/** - * @typedef {Object} Args - * - * @property {string} url - * @property {boolean} no-window - */ - -/** @type {mri.Argv} */ -const cliArgs = mri(argv, { - alias: { - u: 'url' - } -}) - -/** @type {undefined | Object} */ -let rpc -if (config.enableDiscordSupport) { - DiscordRPC.register(config.discordAppId) - rpc = new DiscordRPC.Client({ transport: 'ipc' }) - console.log('rpc', rpc) -} - -//region commandLine Flags -if (config.enableInProcessGPU) { - app.commandLine.appendSwitch('in-process-gpu') -} -if (config.enableDisableRendererBackgrounding) { - app.commandLine.appendSwitch('disable-renderer-backgrounding') -} -if (config.forceHighPerformanceGpu) { - app.commandLine.appendSwitch('force-high-performance-gpu') -} - -// Fix steam remote play together -app.commandLine.appendSwitch('disable-features', 'AudioServiceOutOfProcess') - -app.commandLine.appendSwitch('force-high-performance-gpu') -app.commandLine.appendSwitch('disable-gpu-sandbox') -//endregion - -const hasElectronVersion = config.electronVersion !== undefined && config.electronVersion !== '' -const isCJSOnly = - hasElectronVersion && semver.lt(semver.coerce(config.electronVersion) || '0.0.0', '28.0.0') - -//region Steam - -/** @type {Omit} */ -let client -console.log('config.enableSteamSupport', config.enableSteamSupport) -if (config.enableSteamSupport) { - app.commandLine.appendSwitch('in-process-gpu') - //app.commandLine.appendSwitch('disable-direct-composition') - app.commandLine.appendSwitch('no-sandbox') - - // const isNecessary = steamworks.restartAppIfNecessary(config.steamGameId) - // console.log('isNecessary', isNecessary) - - // if (isNecessary) { - - // } - - try { - client = steamworks.init(config.steamGameId) - console.log(client.localplayer.getName()) - client.callback.register(client.callback.SteamCallback.GameOverlayActivated, (data) => { - /** - * @type {import('@pipelab/core').MakeInputOutput} - */ - const order = { - url: '/steam/overlay-activated', - body: data - } - broadcastMessage(JSON.stringify(order)) - }) - } catch (e) { - console.error('e', e) - } -} -//endregion - -const userData = app.getPath('userData') -const userDataDirname = dirname(userData) -const appNameFolder = getAppName(config) -const sessionDataPath = join(userDataDirname, `cache_${appNameFolder}`) -console.log('sessionDataPath', sessionDataPath) -app.setPath('userData', sessionDataPath) - -/** - * @type {Set} - */ -const clients = new Set() - -/** - * @type {import('http').Server | null} - */ -let httpServer = null - -/** - * @type {import('ws').WebSocketServer | null} - */ -let wss = null - -/** - * @type {boolean} - */ -let isQuitting = false - -/** - * @type {Promise | null} - */ -let cleanupPromise = null - -/** - * @param {string} message - */ -const broadcastMessage = (message) => { - for (const client of clients) { - if (client.readyState === WebSocket.OPEN) { - client.send(message) - } - } -} - -const metaDirname = isCJSOnly ? __dirname : import.meta.dirname -const dir = app.isPackaged ? join(metaDirname, './app') : './src/app' - -/** - * @param {BrowserWindow} mainWindow - * @returns {Promise} - */ -const createAppServer = (mainWindow, serveStatic = true) => { - // eslint-disable-next-line no-async-promise-executor - return new Promise(async (resolve, reject) => { - httpServer = createServer() - const server = httpServer - - if (serveStatic) { - server.on('request', (req, res) => { - return serve(req, res, { - headers: [ - { - source: '**/*', - headers: [ - { - key: 'Cache-Control', - value: 'no-cache' - }, - { - key: 'Access-Control-Allow-Origin', - value: '*' - } - ] - } - ], - public: dir - }) - }) - } else { - server.on('request', (req, res) => { - res.setHeader('Access-Control-Allow-Origin', '*') // or 'https://preview.construct.net' - res.setHeader('Access-Control-Allow-Private-Network', 'true') - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') - res.setHeader('Access-Control-Allow-Headers', 'Content-Type') - if (req.method === 'OPTIONS') { - res.writeHead(204) - res.end() - return - } - res.writeHead(200, { 'Content-Type': 'text/plain' }) - res.end('Pipelab Electron App Server\n') - }) - } - - try { - wss = new WebSocketServer({ server }) - wss.on('connection', function connection(ws) { - clients.add(ws) - - ws.on('error', console.error) - - ws.on('message', async (data) => { - //region Message handlers - /** @type {import('@pipelab/core').Message} */ - const json = JSON.parse(data.toString()) - console.log('received:', json) - - try { - switch (json.url) { - case '/paths': - await userFolder(json, ws, config) - break - - case '/fs/file/write': - await fsWrite(json, ws) - break - - case '/fs/file/write-base64': - await fsWriteBase64(json, ws) - break - - case '/fs/file/read': - await fsRead(json, ws) - break - - case '/fs/file/read/binary': - await fsReadBinary(json, ws) - break - - case '/fs/folder/create': - await fsFolderCreate(json, ws) - break - - case '/window/maximize': - await windowMaximize(json, ws, mainWindow) - break - - case '/window/minimize': - await windowMinimize(json, ws, mainWindow) - break - case '/window/request-attention': - await windowRequestAttention(json, ws, mainWindow) - break - case '/window/restore': - await windowRestore(json, ws, mainWindow) - break - case '/dialog/folder': - await dialogFolder(json, ws) - break - case '/dialog/open': - await dialogOpen(json, ws) - break - case '/dialog/save': - await dialogSave(json, ws) - break - case '/window/set-always-on-top': - await windowSetAlwaysOnTop(json, ws, mainWindow) - break - case '/window/set-height': - await windowSetHeight(json, ws, mainWindow) - break - case '/window/set-maximum-size': - await windowSetMaximumSize(json, ws, mainWindow) - break - case '/window/set-minimum-size': - await windowSetMinimumSize(json, ws, mainWindow) - break - case '/window/set-resizable': - await windowSetResizable(json, ws, mainWindow) - break - case '/window/set-title': - await windowSetTitle(json, ws, mainWindow) - break - case '/window/set-width': - await windowSetWidth(json, ws, mainWindow) - break - case '/window/set-x': - await windowSetX(json, ws, mainWindow) - break - case '/window/set-y': - await windowSetY(json, ws, mainWindow) - break - case '/window/show-dev-tools': - await windowShowDevTools(json, ws, mainWindow) - break - case '/window/unmaximize': - await windowUnmaximize(json, ws, mainWindow) - break - case '/window/set-fullscreen': - await windowSetFullscreen(json, ws, mainWindow) - break - case '/window/set-ignore-mouse-events': - await windowSetIgnoreMouseEvents(json, ws, mainWindow) - break - case '/engine': - await engine(json, ws) - break - case '/open': - await open(json, ws) - break - case '/show-in-explorer': - await showInExplorer(json, ws) - break - case '/run': - await run(json, ws) - break - case '/fs/copy': - await fsCopy(json, ws) - break - case '/fs/delete': - await fsDelete(json, ws) - break - case '/fs/exist': - await fsExist(json, ws) - break - case '/fs/list': - await fsList(json, ws) - break - case '/fs/file/size': - await fsFileSize(json, ws) - break - case '/fs/move': - await fsMove(json, ws) - break - case '/steam/raw': - await steamRaw(json, ws, client) - break - case '/steam/leaderboard/upload-score': - await steamUploadScore(json, ws, client) - break - case '/steam/leaderboard/download-score': - await steamDownloadScore(json, ws, client) - break - case '/steam/workshop/update-item': - await steamUpdateItem(json, ws, client) - break - case '/steam/workshop/get-item': - await steamGetItem(json, ws, client) - break - case '/steam/workshop/get-items': - await steamGetItems(json, ws, client) - break - case '/steam/workshop/subscribe': - await steamSubscribe(json, ws, client) - break - case '/steam/workshop/unsubscribe': - await steamUnsubscribe(json, ws, client) - break - case '/steam/workshop/state': - await steamState(json, ws, client) - break - case '/steam/workshop/install-info': - await steamInstallInfo(json, ws, client) - break - case '/steam/workshop/download-info': - await steamDownloadInfo(json, ws, client) - break - case '/steam/workshop/download': - await steamDownload(json, ws, client) - break - case '/steam/workshop/delete-item': - await steamDeleteItem(json, ws, client) - break - case '/steam/screenshots/save': - await steamSaveScreenshot(json, ws, client) - break - case '/discord/set-activity': - await discordSetActivity(json, ws, mainWindow, rpc) - break - case '/exit': - await exit(json, ws) - break - case '/window/fullscreen-state': - // sent the other way around - break - case '/infos': - await infos(json, ws) - break - - default: - console.log('unsupported', data) - assertUnreachable(json) - break - } - } catch (e) { - console.error('e', e) - ws.send( - JSON.stringify({ - url: json.url, - correlationId: json.correlationId, - body: { - success: false, - error: e.message - } - }) - ) - } - }) - - ws.on('close', () => { - clients.delete(ws) - }) - }) - } catch (e) { - console.error('Unable to create websocket server', e) - return reject(e) - } - - server.listen(31753, '127.0.0.1', () => { - const adress = server.address() - if (adress && typeof adress !== 'string') { - return resolve(adress.port) - } - return reject('Unable to bind server: adress is not an object') - }) - }) -} - -const createWindow = async () => { - const argUrl = cliArgs.url - - // If there is a window - const mainWindow = new BrowserWindow({ - width: config.width, - height: config.height, - fullscreen: config.fullscreen, - fullscreenable: true, - frame: config.frame, - transparent: config.transparent, - alwaysOnTop: config.alwaysOnTop, - backgroundColor: config.backgroundColor, - icon: config.icon, - webPreferences: { - preload: join(metaDirname, 'preload.js') - }, - show: true - }) - - if (!mainWindow) { - throw new Error('Unable to create window') - } - - if (!config.toolbar) { - mainWindow.setMenu(null) - } - - if (config.openDevtoolsOnStart) { - mainWindow.webContents.openDevTools() - } - - if (config.clearServiceWorkerOnBoot) { - // It's better to export apps without service worker support - // only use when needed - try { - // Clear service workers to prevent old versions of the app - await session.defaultSession.clearStorageData({ - storages: ['serviceworkers'] - }) - } catch (e) { - console.error('Error clearing service workers', e) - } - } - - // preview - if (argUrl) { - console.log('argUrl', argUrl) - await createAppServer(mainWindow, false) - - await mainWindow?.loadURL(argUrl) - console.log('URL loaded') - } - // prod - else { - const isCustomProtocol = config.serverMode === 'customProtocol' - const port = await createAppServer(mainWindow, isCustomProtocol === false) - if (isCustomProtocol) { - await mainWindow?.loadURL('app://game/index.html') - console.log('URL loaded (static)', 'app://game/index.html') - } else { - const url = `http://127.0.0.1:${port}` - await mainWindow?.loadURL(url) - console.log('URL loaded', url) - } - } - - mainWindow.on('enter-full-screen', () => { - /** - * @type {import('@pipelab/core').MakeInputOutput} - */ - const order = { - url: '/window/fullscreen-state', - body: { - state: 'fullscreen' - } - } - broadcastMessage(JSON.stringify(order)) - }) - - mainWindow.on('leave-full-screen', () => { - /** - * @type {import('@pipelab/core').MakeInputOutput} - */ - const order = { - url: '/window/fullscreen-state', - body: { - state: 'normal' - } - } - broadcastMessage(JSON.stringify(order)) - }) - - mainWindow.webContents?.setWindowOpenHandler(({ url }) => { - // Open the URL in the default browser - shell.openExternal(url) - return { action: 'deny' } // Prevent Electron from creating a new window - }) - - return mainWindow -} - -/** - * Cleanup all resources before quitting - */ -const cleanup = async () => { - if (cleanupPromise) { - return cleanupPromise - } - - cleanupPromise = (async () => { - console.log('Cleaning up resources...') - - for (const client of clients) { - try { - client.close() - } catch (e) { - console.error('Error closing WebSocket client:', e) - } - } - clients.clear() - - if (wss) { - try { - wss.close() - } catch (e) { - console.error('Error closing WebSocket server:', e) - } - wss = null - } - - if (rpc) { - try { - await rpc.clearActivity() - } catch (e) { - console.error('Error clearing Discord RPC activity:', e) - } - - try { - rpc.destroy() - } catch (e) { - console.error('Error destroying Discord RPC client:', e) - } - - rpc = undefined - } - - try { - protocol.unhandle('app') - } catch (e) { - console.error('Error unregistering app protocol:', e) - } - - if (httpServer) { - const server = httpServer - httpServer = null - - await new Promise((resolve) => { - let isSettled = false - const done = () => { - if (!isSettled) { - isSettled = true - resolve() - } - } - - server.close(() => { - console.log('HTTP server closed') - done() - }) - - setTimeout(done, 500) - }) - } - })().finally(() => { - cleanupPromise = null - }) - - return cleanupPromise -} - -const registerHandlers = async () => { - ipcMain.on('exit', async (event, code) => { - console.log('exit', code) - isQuitting = true - await cleanup() - app.exit(code) - }) -} - -const rpcLogin = async () => { - return new Promise((resolve, reject) => { - rpc.on('ready', () => { - console.log('rpc ready') - return resolve(rpc) - }) - - rpc.login({ clientId: config.discordAppId }).catch((e) => { - return reject(e) - }) - }) -} - -function registerCustomProtocol() { - const GAME_DIR = path.join(metaDirname, 'app') - - protocol.handle('app', async (request) => { - let internalPath = request.url.replace('app://game/', '') - internalPath = internalPath.split('?')[0] - internalPath = decodeURIComponent(internalPath) - - if (internalPath === '' || internalPath.endsWith('/')) { - internalPath = 'index.html' - } - - const finalPath = path.join(GAME_DIR, internalPath) - - try { - const stats = await stat(finalPath) - const mimeType = mime.lookup(finalPath) || 'application/octet-stream' - - const headers = new Headers() - headers.set('Content-Type', mimeType) - headers.set('Access-Control-Allow-Origin', '*') - headers.set('Accept-Ranges', 'bytes') - - const rangeHeader = request.headers.get('Range') - - if (rangeHeader) { - const parts = rangeHeader.replace(/bytes=/, '').split('-') - const start = parseInt(parts[0], 10) - const end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1 - const chunkSize = end - start + 1 - - const stream = createReadStream(finalPath, { start, end }) - - headers.set('Content-Range', `bytes ${start}-${end}/${stats.size}`) - headers.set('Content-Length', String(chunkSize)) - - // @ts-expect-error streams are accepted - return new Response(stream, { - status: 206, - statusText: 'Partial Content', - headers: headers - }) - } - // no range / streaming - else { - headers.set('Content-Length', String(stats.size)) - const stream = createReadStream(finalPath) - - // @ts-expect-error streams are accepted - return new Response(stream, { - status: 200, - headers: headers - }) - } - } catch (error) { - console.error(`[App Protocol] Error serving ${finalPath}:`, error) - return new Response('Not Found', { status: 404 }) - } - }) -} - -app.whenReady().then(async () => { - await registerHandlers() - - if (config.enableSteamSupport) { - console.log('Enabling steam overlay support') - try { - steamworks.electronEnableSteamOverlay() - } catch (e) { - console.error('e', e) - } - } - - registerCustomProtocol() - - const mainWindow = await createWindow() - - mainWindow.show() - - if (config.enableDiscordSupport && rpc) { - try { - await rpcLogin() - } catch (e) { - console.error('e', e) - } - } - - app.on('activate', async () => { - if (BrowserWindow.getAllWindows().length === 0) { - await createWindow() - } - }) -}) - -app.on('before-quit', (event) => { - if (!isQuitting) { - event.preventDefault() - isQuitting = true - cleanup() - .catch((error) => { - console.error('Error while quitting application:', error) - }) - .finally(() => { - app.quit() - }) - } -}) - -app.on('will-quit', () => { - for (const client of clients) { - try { - client.terminate() - } catch (e) {} - } - clients.clear() -}) - -app.on('window-all-closed', () => { - // On macOS, apps typically stay open until explicitly quit - // But for games, we usually want to quit when the window is closed - if (process.platform !== 'darwin' || isQuitting) { - app.quit() - } else { - // On macOS, trigger the quit process which will run cleanup - isQuitting = true - cleanup().then(() => { - app.quit() - }) - } -}) diff --git a/assets/electron/template/app/src/preload.js b/assets/electron/template/app/src/preload.js deleted file mode 100644 index fd9b6419..00000000 --- a/assets/electron/template/app/src/preload.js +++ /dev/null @@ -1,27 +0,0 @@ -const { contextBridge, ipcRenderer } = require('electron') - -// Expose a limited API to the renderer process -contextBridge.exposeInMainWorld('electronAPI', { - invoke: async (channel, data) => { - try { - return await ipcRenderer.invoke(channel, data) - } catch (error) { - console.error('IPC invocation error:', error) - throw error - } - }, - handle: (message, handler) => { - ipcRenderer.on(message, (event, ...args) => handler(...args)) - }, - isElectron: () => true, - exit: (code) => { - ipcRenderer.send('exit', code) - } -}) - -/** @deprecated */ -contextBridge.exposeInMainWorld('isElectron', true) -contextBridge.exposeInMainWorld('isPipelab', true) -contextBridge.exposeInMainWorld('pipelabEngine', 'electron') - -console.log('Preload script loaded') diff --git a/assets/electron/template/app/src/utils.js b/assets/electron/template/app/src/utils.js deleted file mode 100644 index f43a2db4..00000000 --- a/assets/electron/template/app/src/utils.js +++ /dev/null @@ -1,18 +0,0 @@ -import pkg from '../package.json' with { type: "json" }; - -/** - * @param {ElectronAppConfig.Config} config - */ -export const getAppName = (config) => { - const platform = process.platform - - let appNameFolder = config.name - if (platform === 'win32') { - appNameFolder = config.name ?? pkg.productName ?? pkg.name - } else if (platform === 'darwin') { - appNameFolder = config.appBundleId - } else if (platform === 'linux') { - appNameFolder = config.appBundleId - } - return appNameFolder -} diff --git a/assets/tauri/template/app/index.html b/assets/tauri/template/app/index.html deleted file mode 100644 index 125c96fe..00000000 --- a/assets/tauri/template/app/index.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - Document - - - - - - - - - - - - - - -
- - - - - diff --git a/components.d.ts b/components.d.ts deleted file mode 100644 index 43a9cbb2..00000000 --- a/components.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable */ -// @ts-nocheck -// Generated by unplugin-vue-components -// Read more: https://github.com/vuejs/core/pull/3399 -export {} - -/* prettier-ignore */ -declare module 'vue' { - export interface GlobalComponents { - BuildHistoryView: typeof import('./src/components/BuildHistoryView.vue')['default'] - Button: typeof import('primevue/button')['default'] - ButtonGroup: typeof import('primevue/buttongroup')['default'] - Checkbox: typeof import('primevue/checkbox')['default'] - Chip: typeof import('primevue/chip')['default'] - Column: typeof import('primevue/column')['default'] - ConfirmDialog: typeof import('primevue/confirmdialog')['default'] - ConfirmPopup: typeof import('primevue/confirmpopup')['default'] - DataTable: typeof import('primevue/datatable')['default'] - Dialog: typeof import('primevue/dialog')['default'] - Divider: typeof import('primevue/divider')['default'] - Drawer: typeof import('primevue/drawer')['default'] - Dropdown: typeof import('primevue/dropdown')['default'] - IconField: typeof import('primevue/iconfield')['default'] - Inplace: typeof import('primevue/inplace')['default'] - InputGroup: typeof import('primevue/inputgroup')['default'] - InputIcon: typeof import('primevue/inputicon')['default'] - InputNumber: typeof import('primevue/inputnumber')['default'] - InputText: typeof import('primevue/inputtext')['default'] - Listbox: typeof import('primevue/listbox')['default'] - Menu: typeof import('primevue/menu')['default'] - Message: typeof import('primevue/message')['default'] - Panel: typeof import('primevue/panel')['default'] - Password: typeof import('primevue/password')['default'] - ProgressBar: typeof import('primevue/progressbar')['default'] - ProgressSpinner: typeof import('primevue/progressspinner')['default'] - RouterLink: typeof import('vue-router')['RouterLink'] - RouterView: typeof import('vue-router')['RouterView'] - Select: typeof import('primevue/select')['default'] - SelectButton: typeof import('primevue/selectbutton')['default'] - Skeleton: typeof import('primevue/skeleton')['default'] - TabPanel: typeof import('primevue/tabpanel')['default'] - TabView: typeof import('primevue/tabview')['default'] - Toast: typeof import('primevue/toast')['default'] - ToggleSwitch: typeof import('primevue/toggleswitch')['default'] - } - export interface ComponentCustomProperties { - Tooltip: typeof import('primevue/tooltip')['default'] - } -} diff --git a/conductor/fix-forge-product-name.md b/conductor/fix-forge-product-name.md new file mode 100644 index 00000000..44f72b3b --- /dev/null +++ b/conductor/fix-forge-product-name.md @@ -0,0 +1,20 @@ +# Plan: Fix Invalid Characters in Electron Forge Product Name + +The `productName` generated by `getProductName` includes a space ("Pipelab Beta"), which is being rejected by Electron Forge during the packaging process. + +## Changes + +### 1. Update `packages/constants/src/index.ts` +Modify the `getProductName` function to return "Pipelab-Beta" (replacing the space with a hyphen) for beta versions. + +```typescript +export const getProductName = (version: string) => + version.includes("beta") ? "Pipelab-Beta" : "Pipelab"; +``` + +## Verification + +1. Run `pnpm build` in the root of the project to ensure the constants package is rebuilt. +2. Navigate to `apps/desktop`. +3. Attempt to run `pnpm package` to verify that the error regarding invalid characters is resolved. +4. Confirm that the output package name adheres to the new naming convention. diff --git a/conductor/fix-plugin-beta-tag.md b/conductor/fix-plugin-beta-tag.md new file mode 100644 index 00000000..053e2146 --- /dev/null +++ b/conductor/fix-plugin-beta-tag.md @@ -0,0 +1,41 @@ +# Plan: Fix Beta Publication Tags for Plugins + +The plugins are currently being published as `latest` even on the `develop` branch because the Changesets `publish` command may not be correctly picking up the `NPM_CONFIG_TAG` environment variable defined in the GitHub Action step. + +## Changes + +### 1. Modify `.github/workflows/pipeline.yml` +Update the `Publish to NPM & Create GitHub Release` step to explicitly set the `--tag` argument based on the branch name. + +Current step: +```yaml + - name: Publish to NPM & Create GitHub Release + id: changesets + uses: changesets/action@v1 + with: + publish: pnpm changeset publish --provenance + createGithubReleases: true + env: + ... +``` + +Proposed change: +```yaml + - name: Publish to NPM & Create GitHub Release + id: changesets + uses: changesets/action@v1 + with: + publish: >- + pnpm changeset publish --provenance --tag ${{ (github.ref_name == 'develop' || github.event.inputs.prerelease == 'true') && 'beta' || 'latest' }} + createGithubReleases: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: true +``` + +## Verification + +1. Monitor the next release on the `develop` branch. +2. Verify in the GitHub Action logs that the command executed is `pnpm changeset publish --provenance --tag beta`. +3. Check npm registry to ensure the plugins are now tagged as `beta` instead of `latest`. diff --git a/conductor/fix-test-env.md b/conductor/fix-test-env.md new file mode 100644 index 00000000..4045cb8d --- /dev/null +++ b/conductor/fix-test-env.md @@ -0,0 +1,16 @@ +# Fix: Resolve Test Environment Misconfiguration in Desktop App + +## Background & Motivation +The recent changes introduced dynamic release tagging and environment-aware data paths in the desktop application. The check `process.env.TEST !== "true"` in `apps/desktop/src/main.ts` is likely causing unexpected behavior during tests where this environment variable might not be set as expected or handled correctly. + +## Scope & Impact +The fix will focus on `apps/desktop/src/main.ts` to ensure the testing environment is correctly detected and handled without interfering with the production release logic. + +## Implementation Steps +1. **Refine Environment Detection:** Update the `isProduction` check in `apps/desktop/src/main.ts` to be more robust for testing environments. +2. **Verify Test Execution:** Ensure that `pnpm turbo test` correctly sets the `TEST` environment variable for all relevant packages, especially `apps/desktop`. +3. **Validate:** Run `pnpm turbo test` and verify that the tests pass without being impacted by the production release logic. + +## Verification & Testing +- Run `pnpm turbo test` and check for any failures. +- Manually run the desktop app test suite: `pnpm test --filter=@pipelab/desktop` (if applicable). diff --git a/declaration.d.ts b/declaration.d.ts deleted file mode 100644 index d44defbb..00000000 --- a/declaration.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare module 'mock-fs' -declare module 'memfs' -declare module 'set-value' -declare module 'get-value' - -declare const __SUPABASE_URL__: string -declare const __SUPABASE_ANON_KEY__: string diff --git a/docs/expression.md b/docs/expression.md index d2296fb0..a99b6940 100644 --- a/docs/expression.md +++ b/docs/expression.md @@ -1,4 +1,5 @@ # Expressions + An expression is of type string that can include any data - a number: @@ -15,4 +16,4 @@ An expression is of type string that can include any data - a custom expression -`System.Step('aaa') + 12` \ No newline at end of file +`System.Step('aaa') + 12` diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 9f2e8d78..00000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,73 +0,0 @@ -import globals from 'globals' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import js from '@eslint/js' -import { FlatCompat } from '@eslint/eslintrc' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all -}) - -export default [ - { - ignores: ['**/node_modules', '**/dist', '**/out', '**/.gitignore'] - }, - ...compat.extends( - 'plugin:vue/vue3-recommended', - 'eslint:recommended', - '@vue/eslint-config-typescript/recommended', - '@vue/eslint-config-prettier' - ), - { - files: ['**/src/**/*.ts', '**/src/**/*.vue'], - - rules: { - 'no-console': [process.env.NODE_ENV === "production" ? "error" : "warn"] - } - }, - { - languageOptions: { - globals: { - ...globals.browser, - ...globals.commonjs, - ...globals.node - // ...vue.environments["setup-compiler-macros"]["setup-compiler-macros"], - } - }, - - rules: { - '@typescript-eslint/ban-ts-comment': [ - 'error', - { - 'ts-ignore': 'allow-with-description' - } - ], - - '@typescript-eslint/explicit-module-boundary-types': 'off', - - '@typescript-eslint/no-empty-function': [ - 'error', - { - allow: ['arrowFunctions'] - } - ], - - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-var-requires': 'off', - 'vue/require-default-prop': 'off', - 'vue/multi-word-component-names': 'off' - } - }, - { - files: ['**/*.js'], - - rules: { - '@typescript-eslint/explicit-function-return-type': 'off' - } - } -] diff --git a/forge.config.ts b/forge.config.ts deleted file mode 100644 index 1438717a..00000000 --- a/forge.config.ts +++ /dev/null @@ -1,137 +0,0 @@ -import type { ForgeConfig } from '@electron-forge/shared-types' -import { MakerSquirrel } from '@electron-forge/maker-squirrel' -import { MakerZIP } from '@electron-forge/maker-zip' -import { VitePlugin } from '@electron-forge/plugin-vite' -import { FusesPlugin } from '@electron-forge/plugin-fuses' -import { MakerDMG } from '@electron-forge/maker-dmg' -import { MakerPKG } from '@electron-forge/maker-pkg' -import { FuseV1Options, FuseVersion } from '@electron/fuses' -import { name } from './src/constants' -import * as fs from 'fs-extra' -import * as path from 'path' -/** @type {*} */ -const config: ForgeConfig = { - packagerConfig: { - appBundleId: 'app.pipelab.desktop', - // asar: { - // // unpack: '*.{node,dll,so,lib,dylib,exe}' - // }, - asar: false, - extraResource: ['assets'], - // extraResource: ['.vite/build/assets'], - name, - icon: 'assets/build/icon', - extendInfo: { - NSAppleEventsUsageDescription: - 'This app need to run commands through Terminal for specific tasks such as steamcmd.sh.' - }, - osxNotarize: { - appleId: process.env.APPLE_ID, - appleIdPassword: process.env.APPLE_ID_PASSWORD, - teamId: process.env.APPLE_TEAM_ID - }, - osxSign: { - strictVerify: false, - identity: `Developer ID Application: Quentin Goinaud (${process.env.APPLE_TEAM_ID})`, - optionsForFile: (filePath) => { - return { - 'entitlements-inherit': './assets/build/entitlements.mac.plist', - entitlements: './assets/build/entitlements.mac.plist' - } - } - } - }, - rebuildConfig: {}, - makers: [ - new MakerSquirrel({ - name, - setupIcon: 'assets/build/icon.ico' - }), - new MakerZIP(undefined, ['linux', 'win32']), - new MakerDMG(), - // TODO: need to regenerate the certificate - // new MakerPKG({ - // identity: `Developer ID Installer: Quentin Goinaud (${process.env.APPLE_TEAM_ID})`, - // }), - ], - publishers: [ - { - name: '@electron-forge/publisher-github', - config: { - repository: { - owner: 'CynToolkit', - name: 'pipelab' - }, - prerelease: true, - draft: false, - generateReleaseNotes: true - } - } - ], - hooks: { - packageAfterCopy: async (forgeConfig, buildPath, electronVersion, platform, arch) => { - console.log('INFO: Running packageAfterCopy hook...'); - const projectRoot = path.resolve(__dirname); - const packagesToCopy = [ - '@esbuild', - '@lydell' - ]; - - for (const packageName of packagesToCopy) { - const srcDir = path.join(projectRoot, 'node_modules', packageName); - const destDir = path.join(buildPath, 'node_modules', packageName); - - try { - if (await fs.pathExists(srcDir)) { - console.log(`INFO: Copying ${srcDir} to ${destDir}`); - await fs.copy(srcDir, destDir, { overwrite: true, dereference: true }); - console.log(`INFO: Successfully copied ${packageName}.`); - } else { - console.warn(`WARN: Source directory ${srcDir} does not exist. Skipping copy for ${packageName}.`); - } - } catch (err) { - console.error(`ERROR: Failed to copy ${packageName}:`, err); - // Optionally, re-throw the error if this should halt the build - // throw err; - } - } - console.log('INFO: packageAfterCopy hook finished.'); - } - }, - plugins: [ - new VitePlugin({ - // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc. - // If you are familiar with Vite configuration, it will look really familiar. - build: [ - { - // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`. - entry: 'src/main.ts', - config: 'vite.main.config.mts' - }, - { - entry: 'src/preload.ts', - config: 'vite.preload.config.mts' - } - ], - renderer: [ - { - name: 'main_window', - config: 'vite.renderer.config.mts' - } - ] - }), - // Fuses are used to enable/disable various Electron functionality - // at package time, before code signing the application - new FusesPlugin({ - version: FuseVersion.V1, - [FuseV1Options.RunAsNode]: true, // needed - [FuseV1Options.EnableCookieEncryption]: true, - [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: true, - [FuseV1Options.EnableNodeCliInspectArguments]: false, - [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: false, // must enable again, broken for windows build on linux - [FuseV1Options.OnlyLoadAppFromAsar]: false // need tesing - }) - ] -} - -export default config diff --git a/forge.env.d.ts b/forge.env.d.ts deleted file mode 100644 index f1d2a61f..00000000 --- a/forge.env.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -export {} // Make this a module - -declare global { - // This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Vite - // plugin that tells the Electron app where to look for the Vite-bundled app code (depending on - // whether you're running in development or production). - const MAIN_WINDOW_VITE_DEV_SERVER_URL: string - const MAIN_WINDOW_VITE_NAME: string - - type ElectronAPI = import('@electron-toolkit/preload').ElectronAPI - - namespace NodeJS { - interface Process { - // Used for hot reload after preload scripts. - viteDevServers: Record - } - } - - interface Window { - version: string - electron: ElectronAPI - api: any - isPackaged: boolean - isTest: boolean - isCI: boolean - } - - type VitePluginConfig = ConstructorParameters< - typeof import('@electron-forge/plugin-vite').VitePlugin - >[0] - - interface VitePluginRuntimeKeys { - VITE_DEV_SERVER_URL: `${string}_VITE_DEV_SERVER_URL` - VITE_NAME: `${string}_VITE_NAME` - } -} - -declare module 'vite' { - interface ConfigEnv { - root: string - forgeConfig: VitePluginConfig - forgeConfigSelf: VitePluginConfig[K][number] - } -} diff --git a/index.html b/index.html deleted file mode 100644 index 25a713c3..00000000 --- a/index.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - Pipelab - - - - - - - - - -
- - - - diff --git a/mise.toml b/mise.toml new file mode 100644 index 00000000..09c0297f --- /dev/null +++ b/mise.toml @@ -0,0 +1,3 @@ +[tools] +node = "24" +pnpm = "10.33.0" diff --git a/package.json b/package.json index 71cb0845..46e9afb5 100644 --- a/package.json +++ b/package.json @@ -1,201 +1,44 @@ { - "name": "@pipelab/app", - "version": "1.37.4", - "description": "-", - "main": ".vite/build/main.js", - "author": "Armaldio", + "name": "pipelab-monorepo", "private": true, - "repository": { - "type": "git", - "url": "https://github.com/CynToolkit/pipelab.git" - }, - "homepage": "https://pipelab.app", - "packageManager": "pnpm@10.12.0", + "license": "FSL-1.1-MIT", "scripts": { - "format": "prettier --write .", - "lint": "eslint .", - "typecheck:node": "tsc --noEmit -p tsconfig.json --composite false", - "typecheck:web": "vue-tsc --noEmit -p tsconfig.json --composite false", - "typecheck": "npm run typecheck:node && npm run typecheck:web", - "start": "electron-forge start", - "start:args": "electron-forge start -- --project ./tests/e2e/fixtures/folder-to-electron.json --action run", - "dev": "pnpx cross-env NODE_OPTIONS=--enable-source-maps pnpm start", - "_dev": "pnpm start", - "test:unit": "vitest run -c vitest.config.mts", - "test:unit:watch": "vitest watch -c vitest.config.mts", - "test:e2e:raw": "vitest run -c tests/e2e/vitest.config.mts", - "test:e2e:local": "pnpm package && pnpm test:e2e:raw", - "test:e2e:pw": "echo 1", - "build": "npm run typecheck && electron-vite build", - "build:no-check": "electron-vite build", - "build:win": "npm run build:no-check && electron-builder --win --config", - "build:mac": "npm run build:no-check && electron-builder --mac --config", - "build:linux": "npm run build:no-check && electron-builder --linux --config", - "package": "electron-forge package", - "make": "electron-forge make", - "publish": "electron-forge publish", - "make-dev-prerelease": "pnpm version prerelease --preid=dev", - "supa:types": "supabase gen types typescript --project-id $VITE_SUPABASE_PROJECT_ID > src/shared/database.types.ts", - "migrate-file": "pnpm tsx scripts/migrate-file.mts" - }, - "dependencies": { - "@changesets/cli": "2.27.11", - "@codemirror/autocomplete": "6.18.1", - "@codemirror/commands": "6.6.2", - "@codemirror/lang-liquid": "6.2.1", - "@codemirror/lint": "6.8.2", - "@codemirror/state": "6.4.1", - "@codemirror/view": "6.34.0", - "@electron-toolkit/preload": "3.0.2", - "@electron-toolkit/utils": "4.0.0", - "@floating-ui/vue": "1.1.5", - "@jitl/quickjs-wasmfile-release-sync": "0.31.0", - "@lydell/node-pty": "1.0.3", - "@lydell/node-pty-win32-x64": "1.1.0", - "@pipelab/core": "1.4.9", - "@poki/cli": "0.1.16", - "@polar-sh/sdk": "0.34.8", - "@primevue/themes": "4.1.1", - "@sentry/electron": "5.4.0", - "@sentry/vue": "8.32.0", - "@supabase/supabase-js": "2.45.6", - "@trpc/client": "10.45.2", - "@types/archiver": "6.0.3", - "@types/date-fns": "2.6.3", - "@types/dompurify": "3.0.5", - "@types/ws": "8.18.1", - "@vee-validate/valibot": "4.13.2", - "@vuelidate/core": "2.0.3", - "@vuelidate/validators": "2.0.4", - "@vueuse/components": "11.1.0", - "@vueuse/core": "11.1.0", - "@vueuse/router": "11.1.0", - "archiver": "7.0.1", - "change-case": "5.4.4", - "code-tag": "1.2.0", - "confbox": "0.2.2", - "d3-shape": "3.2.0", - "date-fns": "4.1.0", - "dompurify": "3.1.7", - "driver.js": "1.4.0", - "ejs": "3.1.10", - "electron-squirrel-startup": "1.0.1", - "elkjs": "0.9.3", - "es-toolkit": "1.25.2", - "esbuild": "0.25.5", - "esm": "3.2.25", - "execa": "9.4.1", - "fancy-ansi": "0.1.3", - "geist": "1.3.1", - "get-value": "3.0.1", - "klona": "2.0.6", - "mutative": "1.0.11", - "nanoid": "5.0.7", - "node-stream-zip": "1.15.0", - "path-browserify": "1.0.1", - "pinia": "2.2.4", - "pinia-plugin-persistedstate": "4.1.1", - "playwright": "1.48.1", - "playwright-core": "1.48.1", - "pnpm": "9.12.2", - "polished": "4.3.1", - "posthog-js": "1.215.0", - "posthog-node": "4.4.1", - "primeicons": "7.0.0", - "primevue": "4.1.1", - "quickjs-emscripten": "0.31.0", - "quickjs-emscripten-sync": "1.6.0", - "semver": "7.6.3", - "serve-handler": "6.1.6", - "set-value": "4.1.0", - "slash": "5.1.0", - "string-strip-html": "13.4.8", - "thememirror": "2.0.1", - "tinykeys": "2.1.0", - "ts-deepmerge": "7.0.1", - "ts-essentials": "10.0.2", - "ts-pattern": "5.5.0", - "tslog": "4.9.3", - "type-fest": "4.26.1", - "untun": "0.1.3", - "update-electron-app": "3.0.0", - "valibot": "0.42.1", - "vee-validate": "4.14.4", - "vue-dompurify-html": "5.1.0", - "vue-i18n": "10", - "web-worker": "1.3.0", - "ws": "8.18.3", - "zod": "3.23.8" + "build": "turbo build", + "dev": "turbo dev", + "lint": "turbo lint", + "test": "turbo test", + "typecheck": "turbo typecheck", + "format": "turbo format", + "changeset": "changeset", + "supa:types": "supabase gen types typescript --project-id $SUPABASE_PROJECT_ID > packages/shared/src/database.types.ts" }, "devDependencies": { - "@changesets/changelog-git": "0.2.0", - "@changesets/changelog-github": "0.5.0", - "@electron-forge/cli": "7.4.0", - "@electron-forge/maker-deb": "7.4.0", - "@electron-forge/maker-dmg": "7.4.0", - "@electron-forge/maker-flatpak": "7.4.0", - "@electron-forge/maker-pkg": "7.8.1", - "@electron-forge/maker-squirrel": "7.4.0", - "@electron-forge/maker-zip": "7.4.0", - "@electron-forge/plugin-fuses": "7.4.0", - "@electron-forge/plugin-vite": "7.4.0", - "@electron-forge/publisher-github": "7.4.0", - "@electron-toolkit/tsconfig": "1.0.1", - "@electron/fuses": "1.8.0", - "@electron/notarize": "2.5.0", - "@eslint/eslintrc": "3.1.0", - "@eslint/js": "9.13.0", - "@mdi/font": "7.4.47", - "@playwright/test": "1.48.1", - "@primevue/auto-import-resolver": "4.1.1", - "@rushstack/eslint-patch": "1.10.4", - "@sentry/vite-plugin": "2.22.6", - "@types/d3-shape": "3.1.6", - "@types/fs-extra": "11.0.4", - "@types/jsdom": "21.1.7", - "@types/node": "22.7.9", - "@types/path-browserify": "1.0.3", - "@types/semver": "7.5.8", - "@typescript-eslint/parser": "8.11.0", - "@vitejs/plugin-vue": "5.2.3", - "@vue/eslint-config-prettier": "9.0.0", - "@vue/eslint-config-typescript": "13.0.0", - "@vue/test-utils": "2.4.6", - "editorconfig": "2.0.0", - "electron": "32.1.2", - "electron-vite": "2.3.0", - "eslint": "9.13.0", - "eslint-plugin-vue": "9.29.1", - "fs-extra": "11.3.0", - "globals": "15.11.0", - "jsdom": "25.0.1", - "less": "4.2.0", - "npm-run-all": "4.1.5", - "npm-upgrade": "3.1.0", - "prettier": "3.3.3", - "primeflex": "3.3.1", - "sass": "1.80.4", - "ts-node": "10.9.2", - "tsx": "4.19.1", - "typescript": "5.8.3", - "unplugin-auto-import": "0.18.3", - "unplugin-vue-components": "0.27.4", - "vite": "6.3.3", - "vite-plugin-node-polyfills": "0.23.0", - "vite-plugin-static-copy": "2.3.1", - "vite-plugin-vue-devtools": "7.7.5", - "vite-plugin-wasm": "3.4.1", - "vite-tsconfig-paths": "5.1.4", - "vitest": "3.1.4", - "vue": "3.5.13", - "vue-router": "4.4.5", - "vue-tsc": "2.1.6" + "@changesets/cli": "^2.27.11", + "@pipelab/constants": "workspace:*", + "@pipelab/core-node": "workspace:*", + "@pipelab/plugin-core": "workspace:*", + "@pipelab/shared": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "@types/node": "24.12.2", + "@types/tar": "^6.1.13", + "cross-env": "7.0.3", + "execa": "9.5.1", + "nanoid": "5.0.8", + "oxfmt": "0.40.0", + "oxlint": "1.55.0", + "turbo": "^2.8.15", + "typescript": "5.9.3", + "vitest": "3.1.4" }, "resolutions": { "@codemirror/state": "6.4.1", "vue-demi": "0.14.10" }, + "packageManager": "pnpm@10.33.0", "pnpm": { + "overrides": { + "@codemirror/state": "6.4.1" + }, "onlyBuiltDependencies": [ "@parcel/watcher", "@sentry/cli", @@ -205,6 +48,7 @@ "esbuild", "fs-xattr", "macos-alias", + "msw", "sharp", "vue-demi" ] diff --git a/packages/cloud-azure/.oxfmtrc.json b/packages/cloud-azure/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/cloud-azure/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/cloud-azure/CHANGELOG.md b/packages/cloud-azure/CHANGELOG.md new file mode 100644 index 00000000..6eb9d64b --- /dev/null +++ b/packages/cloud-azure/CHANGELOG.md @@ -0,0 +1,299 @@ +# @pipelab/cloud-azure + +## 1.0.0-beta.32 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/shared@1.0.0-beta.32 + - @pipelab/cloud@1.0.0-beta.31 + +## 1.0.0-beta.31 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/shared@1.0.0-beta.31 + - @pipelab/cloud@1.0.0-beta.30 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.30 + - @pipelab/cloud@1.0.0-beta.29 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.29 + - @pipelab/cloud@1.0.0-beta.28 + +## 1.0.0-beta.28 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.28 + - @pipelab/cloud@1.0.0-beta.27 + +## 1.0.0-beta.27 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.27 + - @pipelab/cloud@1.0.0-beta.26 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.26 + - @pipelab/cloud@1.0.0-beta.25 + +## 1.0.0-beta.25 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.25 + - @pipelab/cloud@1.0.0-beta.24 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.24 + - @pipelab/cloud@1.0.0-beta.23 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.23 + - @pipelab/cloud@1.0.0-beta.22 + +## 1.0.0-beta.22 + +### Patch Changes + +- Updated dependencies + - @pipelab/shared@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.21 + - @pipelab/cloud@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.20 + - @pipelab/cloud@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.19 + - @pipelab/cloud@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.18 + - @pipelab/cloud@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.17 + - @pipelab/cloud@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/shared@1.0.0-beta.16 + - @pipelab/cloud@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.15 + - @pipelab/cloud@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.14 + - @pipelab/cloud@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.13 + - @pipelab/cloud@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/shared@1.0.0-beta.12 + - @pipelab/cloud@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/shared@1.0.0-beta.11 + - @pipelab/cloud@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/shared@1.0.0-beta.10 + - @pipelab/cloud@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/shared@1.0.0-beta.9 + - @pipelab/cloud@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/shared@1.0.0-beta.8 + - @pipelab/cloud@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/shared@1.0.0-beta.7 + - @pipelab/cloud@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/shared@1.0.0-beta.6 + - @pipelab/cloud@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/shared@1.0.0-beta.5 + - @pipelab/cloud@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/shared@1.0.0-beta.4 + - @pipelab/cloud@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/shared@1.0.0-beta.3 + - @pipelab/cloud@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/shared@1.0.0-beta.2 + - @pipelab/cloud@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/shared@1.0.0-beta.1 + - @pipelab/cloud@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/shared@1.0.0-beta.0 + - @pipelab/cloud@1.0.0-beta.0 diff --git a/packages/cloud-azure/package.json b/packages/cloud-azure/package.json new file mode 100644 index 00000000..cc8046be --- /dev/null +++ b/packages/cloud-azure/package.json @@ -0,0 +1,34 @@ +{ + "name": "@pipelab/cloud-azure", + "version": "1.0.0-beta.32", + "private": true, + "description": "Azure ACI provider for Pipelab", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "format": "oxfmt .", + "lint": "oxlint ." + }, + "dependencies": { + "@azure/arm-containerinstance": "9.1.0", + "@azure/identity": "4.0.1", + "@azure/storage-file-share": "12.15.0", + "@pipelab/cloud": "workspace:*", + "@pipelab/shared": "workspace:*" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "typescript": "5.9.3" + } +} diff --git a/packages/cloud-azure/src/azure-provider.ts b/packages/cloud-azure/src/azure-provider.ts new file mode 100644 index 00000000..966a11f7 --- /dev/null +++ b/packages/cloud-azure/src/azure-provider.ts @@ -0,0 +1,134 @@ +import { CloudProvider, CloudRun, CloudRunOptions } from "@pipelab/cloud"; +import { ContainerInstanceManagementClient } from "@azure/arm-containerinstance"; +import { DefaultAzureCredential } from "@azure/identity"; +import { ShareServiceClient, StorageSharedKeyCredential } from "@azure/storage-file-share"; + +export interface AzureProviderOptions { + subscriptionId: string; + resourceGroup: string; + location: string; + storageAccountName: string; + storageAccountKey: string; + fileShareName: string; + image: string; +} + +export class AzureProvider implements CloudProvider { + id = "azure-aci"; + name = "Azure Container Instances"; + supportedOS: ("windows" | "linux" | "macos")[] = ["windows", "linux"]; + + private client: ContainerInstanceManagementClient; + private shareClient: ShareServiceClient; + + constructor(private options: AzureProviderOptions) { + const credential = new DefaultAzureCredential(); + this.client = new ContainerInstanceManagementClient(credential, options.subscriptionId); + + const storageCredential = new StorageSharedKeyCredential( + options.storageAccountName, + options.storageAccountKey, + ); + this.shareClient = new ShareServiceClient( + `https://${options.storageAccountName}.file.core.windows.net`, + storageCredential, + ); + } + + async run(pipeline: any, options: CloudRunOptions): Promise { + const runId = `run-${Math.random().toString(36).substring(7)}`; + const fileName = `${runId}.json`; + + // 1. Upload pipeline to File Share + const shareName = this.options.fileShareName; + const shareClient = this.shareClient.getShareClient(shareName); + await shareClient.createIfNotExists(); + + const directoryClient = shareClient.getDirectoryClient(""); + const fileClient = directoryClient.getFileClient(fileName); + const content = JSON.stringify(pipeline); + await fileClient.uploadData(Buffer.from(content)); + + // 2. Create Container Group + const containerGroupName = `pipelab-${runId}`; + const osType = options.os === "windows" ? "Windows" : "Linux"; + + const containerGroup = { + location: this.options.location, + osType, + containers: [ + { + name: "pipelab-cli", + image: this.options.image, + resources: { + requests: { + cpu: options.cpu || 1, + memoryInGB: options.memoryInGB || 1.5, + }, + }, + environmentVariables: [ + { name: "SUPABASE_URL", value: process.env.SUPABASE_URL }, + { name: "SUPABASE_SERVICE_ROLE_KEY", value: process.env.SUPABASE_SERVICE_ROLE_KEY }, + { name: "CLOUD_RUN_ID", value: options.cloudRunId }, + ], + volumeMounts: [ + { + name: "pipeline-storage", + mountPath: "C:\\pipelab", + }, + ], + command: [ + "pipelab", + "run", + `C:\\pipelab\\${fileName}`, + "--cloud", + "--output", + `C:\\pipelab\\result-${runId}.json`, + ], + }, + ], + volumes: [ + { + name: "pipeline-storage", + azureFile: { + shareName: shareName, + storageAccountName: this.options.storageAccountName, + storageAccountKey: this.options.storageAccountKey, + }, + }, + ], + restartPolicy: "Never", + }; + + const result = await this.client.containerGroups.beginCreateOrUpdateAndWait( + this.options.resourceGroup, + containerGroupName, + containerGroup as any, + ); + + return { + id: containerGroupName, + providerId: this.id, + status: "running", + startTime: Date.now(), + }; + } + + async getLogs(runId: string): Promise { + const containerGroupName = runId; + const logs = await this.client.containerGroups.listLogs( + this.options.resourceGroup, + containerGroupName, + "pipelab-cli", + ); + return logs.content ? logs.content.split("\n") : []; + } + + async cleanup(runId: string): Promise { + const containerGroupName = runId; + await this.client.containerGroups.beginDeleteAndWait( + this.options.resourceGroup, + containerGroupName, + ); + } +} diff --git a/packages/cloud-azure/src/index.ts b/packages/cloud-azure/src/index.ts new file mode 100644 index 00000000..f00a94c3 --- /dev/null +++ b/packages/cloud-azure/src/index.ts @@ -0,0 +1 @@ +export * from "./azure-provider"; diff --git a/packages/cloud/.oxfmtrc.json b/packages/cloud/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/cloud/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/cloud/CHANGELOG.md b/packages/cloud/CHANGELOG.md new file mode 100644 index 00000000..fa897f74 --- /dev/null +++ b/packages/cloud/CHANGELOG.md @@ -0,0 +1,193 @@ +# @pipelab/cloud + +## 1.0.0-beta.31 + +### Patch Changes + +- - + +## 1.0.0-beta.30 + +### Patch Changes + +- improve dark theme and improve build history + +## 1.0.0-beta.29 + +### Patch Changes + +- sd + +## 1.0.0-beta.28 + +### Patch Changes + +- sd + +## 1.0.0-beta.27 + +### Patch Changes + +- sd + +## 1.0.0-beta.26 + +### Patch Changes + +- sd + +## 1.0.0-beta.25 + +### Patch Changes + +- sd + +## 1.0.0-beta.24 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.23 + +### Patch Changes + +- sd + +## 1.0.0-beta.22 + +### Patch Changes + +- sd + +## 1.0.0-beta.21 + +### Patch Changes + +- sd + +## 1.0.0-beta.20 + +### Patch Changes + +- sd + +## 1.0.0-beta.19 + +### Patch Changes + +- sd + +## 1.0.0-beta.18 + +### Patch Changes + +- sd + +## 1.0.0-beta.17 + +### Patch Changes + +- sd + +## 1.0.0-beta.16 + +### Patch Changes + +- df + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.14 + +### Patch Changes + +- sd + +## 1.0.0-beta.13 + +### Patch Changes + +- sd + +## 1.0.0-beta.12 + +### Patch Changes + +- qs + +## 1.0.0-beta.11 + +### Patch Changes + +- sd + +## 1.0.0-beta.10 + +### Patch Changes + +- s + +## 1.0.0-beta.9 + +### Patch Changes + +- fg + +## 1.0.0-beta.8 + +### Patch Changes + +- changes + +## 1.0.0-beta.7 + +### Patch Changes + +- bump + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes + +## 1.0.0-beta.5 + +### Patch Changes + +- bump + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag + +## 1.0.0-beta.3 + +### Patch Changes + +- bump + +## 1.0.0-beta.2 + +### Patch Changes + +- update + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/packages/cloud/package.json b/packages/cloud/package.json new file mode 100644 index 00000000..f15e7dea --- /dev/null +++ b/packages/cloud/package.json @@ -0,0 +1,27 @@ +{ + "name": "@pipelab/cloud", + "version": "1.0.0-beta.31", + "private": true, + "description": "Cloud provider interfaces for Pipelab", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "format": "oxfmt .", + "lint": "oxlint ." + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "typescript": "5.9.3" + } +} diff --git a/packages/cloud/src/index.ts b/packages/cloud/src/index.ts new file mode 100644 index 00000000..1a8f850f --- /dev/null +++ b/packages/cloud/src/index.ts @@ -0,0 +1 @@ +export * from "./provider"; diff --git a/packages/cloud/src/provider.ts b/packages/cloud/src/provider.ts new file mode 100644 index 00000000..a1aca143 --- /dev/null +++ b/packages/cloud/src/provider.ts @@ -0,0 +1,29 @@ +export interface CloudRun { + id: string; + providerId: string; + status: "initializing" | "running" | "success" | "failed"; + startTime: number; +} + +export interface CloudRunOptions { + os: "windows" | "linux" | "macos"; + cpu?: number; + memoryInGB?: number; + cloudRunId?: string; + [key: string]: any; +} + +export interface CloudProvider { + id: string; + name: string; + supportedOS: ("windows" | "linux" | "macos")[]; + + /** Trigger a new run */ + run(pipeline: any, options: CloudRunOptions): Promise; + + /** Get current logs (for polling or initialization) */ + getLogs(runId: string): Promise; + + /** Cleanup resources */ + cleanup(runId: string): Promise; +} diff --git a/packages/constants/.oxfmtrc.json b/packages/constants/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/constants/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/constants/CHANGELOG.md b/packages/constants/CHANGELOG.md new file mode 100644 index 00000000..ba3258b3 --- /dev/null +++ b/packages/constants/CHANGELOG.md @@ -0,0 +1,205 @@ +# @pipelab/constants + +## 1.0.0-beta.33 + +### Patch Changes + +- - + +## 1.0.0-beta.32 + +### Patch Changes + +- improve dark theme and improve build history + +## 1.0.0-beta.31 + +### Patch Changes + +- sd + +## 1.0.0-beta.30 + +### Patch Changes + +- sd + +## 1.0.0-beta.29 + +### Patch Changes + +- sd + +## 1.0.0-beta.28 + +### Patch Changes + +- sd + +## 1.0.0-beta.27 + +### Patch Changes + +- sd + +## 1.0.0-beta.26 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.25 + +### Patch Changes + +- sd + +## 1.0.0-beta.24 + +### Patch Changes + +- sd + +## 1.0.0-beta.23 + +### Patch Changes + +- sd + +## 1.0.0-beta.22 + +### Patch Changes + +- sd + +## 1.0.0-beta.21 + +### Patch Changes + +- sd + +## 1.0.0-beta.20 + +### Patch Changes + +- sd + +## 1.0.0-beta.19 + +### Patch Changes + +- sd + +## 1.0.0-beta.18 + +### Patch Changes + +- df + +## 1.0.0-beta.17 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.16 + +### Patch Changes + +- sd + +## 1.0.0-beta.15 + +### Patch Changes + +- sd + +## 1.0.0-beta.14 + +### Patch Changes + +- qs + +## 1.0.0-beta.13 + +### Patch Changes + +- sd + +## 1.0.0-beta.12 + +### Patch Changes + +- s + +## 1.0.0-beta.11 + +### Patch Changes + +- fg + +## 1.0.0-beta.10 + +### Patch Changes + +- changes + +## 1.0.0-beta.9 + +### Patch Changes + +- bump + +## 1.0.0-beta.8 + +### Patch Changes + +- fixes + +## 1.0.0-beta.7 + +### Patch Changes + +- Fix beta directory + +## 1.0.0-beta.6 + +### Patch Changes + +- bump + +## 1.0.0-beta.5 + +### Patch Changes + +- beta tag + +## 1.0.0-beta.4 + +### Patch Changes + +- bump + +## 1.0.0-beta.3 + +### Patch Changes + +- fix ci + +## 1.0.0-beta.2 + +### Patch Changes + +- update + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/packages/constants/README.md b/packages/constants/README.md new file mode 100644 index 00000000..f10902d8 --- /dev/null +++ b/packages/constants/README.md @@ -0,0 +1,3 @@ +# @pipelab/constants + +Shared constants and configuration values used across the Pipelab monorepo. diff --git a/packages/constants/package.json b/packages/constants/package.json new file mode 100644 index 00000000..db5e1988 --- /dev/null +++ b/packages/constants/package.json @@ -0,0 +1,52 @@ +{ + "name": "@pipelab/constants", + "version": "1.0.0-beta.33", + "private": false, + "description": "Shared constants for the Pipelab ecosystem", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "packages/constants" + }, + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "build": "tsdown", + "format": "oxfmt .", + "lint": "oxlint .", + "typecheck": "tsc -b" + }, + "dependencies": { + "@types/node": "^24.12.2" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "^5.0.0" + } +} diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts new file mode 100644 index 00000000..c34ef3d4 --- /dev/null +++ b/packages/constants/src/index.ts @@ -0,0 +1,94 @@ +export const name = "Pipelab"; +export const appIdentifier = "pipelab"; + +export const getAppBundleId = (version: string) => + version.includes("beta") ? "app.pipelab.desktop.beta" : "app.pipelab.desktop"; + +export const getProductName = (version: string) => + version.includes("beta") ? "PipelabBeta" : "Pipelab"; + +export const getProtocolName = (version: string) => + version.includes("beta") ? "pipelab-beta" : "pipelab"; + +export const outFolderName = (binName: string, platform: string, arch: string) => { + let platformName = ""; + let archName = ""; + + console.log("platform", platform); + + if (platform === "linux") { + platformName = "linux"; + } else if (platform === "win32") { + platformName = "win32"; + } else if (platform === "darwin") { + platformName = "darwin"; + } else { + throw new Error("Unsupported platform"); + } + + if (arch === "x64") { + archName = "x64"; + } else if (arch === "arm") { + archName = "arm"; + } else if (arch === "arm64") { + archName = "arm64"; + } else if (arch === "ia32") { + archName = "ia32"; + } else { + throw new Error("Unsupported architecture"); + } + + return `${binName}-${platformName}-${archName}`; +}; + +/** + * Get the binary name for a given platform + * @param name + * @param platform If not provided, it will try to use process.platform (Node.js only) + * @returns + */ +export const getBinName = (name: string, platform?: string) => { + const p = platform || (typeof process !== "undefined" ? process.platform : "unknown"); + if (p === "win32") { + return `${name}.exe`; + } + if (p === "darwin") { + return `${name}.app/Contents/MacOS/${name}`; + } + return name; +}; + +export const websocketPort = 33753; +export const uiDevPort = 5173; + +export const uiDevServerInstruction = "pnpm dev --filter=@pipelab/ui"; + +export const getUiDevServerFatalError = (port: number) => ` +-------------------------------------------------------------------------------- + [FATAL ERROR] UI dev server is NOT running on port ${port} + Please start it manually before running the desktop app: + '${uiDevServerInstruction}' +--------------------------------------------------------------------------------`; + +export const getUiDevServerMissingWarning = () => ` +-------------------------------------------------------------------------------- + [DEVELOPMENT MODE] CLI server started (API/WebSocket). + NOTE: The UI is NOT served from this process in development. + Please ensure the UI dev server is running: + '${uiDevServerInstruction}' +--------------------------------------------------------------------------------`; + +export const SandboxFolder = { + Packages: "packages", + ThirdParty: "thirdparty", + Config: "config", + Temp: "temp", + Cache: "cache", + Pnpm: "pnpm", + Artifacts: "artifacts", +} as const; + +export type SandboxFolder = (typeof SandboxFolder)[keyof typeof SandboxFolder]; + +export const DEFAULT_NODE_VERSION = "24.14.1"; +export const DEFAULT_PNPM_VERSION = "10.12.0"; diff --git a/packages/constants/tsconfig.json b/packages/constants/tsconfig.json new file mode 100644 index 00000000..93217e56 --- /dev/null +++ b/packages/constants/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig/node.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": "." + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/core-node/.oxfmtrc.json b/packages/core-node/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/core-node/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/core-node/CHANGELOG.md b/packages/core-node/CHANGELOG.md new file mode 100644 index 00000000..89874897 --- /dev/null +++ b/packages/core-node/CHANGELOG.md @@ -0,0 +1,331 @@ +# @pipelab/core-node + +## 1.0.0-beta.37 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/constants@1.0.0-beta.33 + - @pipelab/shared@1.0.0-beta.32 + +## 1.0.0-beta.36 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/constants@1.0.0-beta.32 + - @pipelab/shared@1.0.0-beta.31 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.31 + - @pipelab/shared@1.0.0-beta.30 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.30 + - @pipelab/shared@1.0.0-beta.29 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.29 + - @pipelab/shared@1.0.0-beta.28 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.28 + - @pipelab/shared@1.0.0-beta.27 + +## 1.0.0-beta.31 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.27 + - @pipelab/shared@1.0.0-beta.26 + +## 1.0.0-beta.30 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.26 + - @pipelab/shared@1.0.0-beta.25 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.25 + - @pipelab/shared@1.0.0-beta.24 + +## 1.0.0-beta.28 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.24 + - @pipelab/shared@1.0.0-beta.23 + +## 1.0.0-beta.27 + +### Patch Changes + +- fix install + +## 1.0.0-beta.26 + +### Patch Changes + +- Updated dependencies + - @pipelab/shared@1.0.0-beta.22 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.23 + - @pipelab/shared@1.0.0-beta.21 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.22 + - @pipelab/shared@1.0.0-beta.20 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.21 + - @pipelab/shared@1.0.0-beta.19 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.20 + - @pipelab/shared@1.0.0-beta.18 + +## 1.0.0-beta.21 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.19 + - @pipelab/shared@1.0.0-beta.17 + +## 1.0.0-beta.20 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/constants@1.0.0-beta.18 + - @pipelab/shared@1.0.0-beta.16 + +## 1.0.0-beta.19 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.17 + - @pipelab/shared@1.0.0-beta.15 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.16 + - @pipelab/shared@1.0.0-beta.14 + +## 1.0.0-beta.17 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.15 + - @pipelab/shared@1.0.0-beta.13 + +## 1.0.0-beta.16 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/constants@1.0.0-beta.14 + - @pipelab/shared@1.0.0-beta.12 + +## 1.0.0-beta.15 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.13 + - @pipelab/shared@1.0.0-beta.11 + +## 1.0.0-beta.14 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/constants@1.0.0-beta.12 + - @pipelab/shared@1.0.0-beta.10 + +## 1.0.0-beta.13 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/constants@1.0.0-beta.11 + - @pipelab/shared@1.0.0-beta.9 + +## 1.0.0-beta.12 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/constants@1.0.0-beta.10 + - @pipelab/shared@1.0.0-beta.8 + +## 1.0.0-beta.11 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.9 + - @pipelab/shared@1.0.0-beta.7 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/constants@1.0.0-beta.8 + - @pipelab/shared@1.0.0-beta.6 + +## 1.0.0-beta.9 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.7 + +## 1.0.0-beta.8 + +### Patch Changes + +- fix package installation + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.6 + - @pipelab/shared@1.0.0-beta.5 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/constants@1.0.0-beta.5 + - @pipelab/shared@1.0.0-beta.4 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/constants@1.0.0-beta.4 + - @pipelab/shared@1.0.0-beta.3 + +## 1.0.0-beta.4 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.3 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/constants@1.0.0-beta.2 + - @pipelab/shared@1.0.0-beta.2 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/constants@1.0.0-beta.1 + - @pipelab/shared@1.0.0-beta.1 + +## 1.0.0-beta.1 + +### Patch Changes + +- improve update checks + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/constants@1.0.0-beta.0 + - @pipelab/shared@1.0.0-beta.0 diff --git a/packages/core-node/README.md b/packages/core-node/README.md new file mode 100644 index 00000000..de58d0e1 --- /dev/null +++ b/packages/core-node/README.md @@ -0,0 +1,10 @@ +# @pipelab/core-node + +The backend execution engine for Pipelab. + +## Responsibilities + +- **Graph Execution**: Handles the logic for running automation pipelines. +- **WebSocket Server**: Real-time communication between UI and backend. +- **Environment Management**: Ensures required runtimes (like Node.js) are available. +- **System Integration**: File system utilities, terminal emulation (PTY), and build history management. diff --git a/packages/core-node/package.json b/packages/core-node/package.json new file mode 100644 index 00000000..cb4abea3 --- /dev/null +++ b/packages/core-node/package.json @@ -0,0 +1,78 @@ +{ + "name": "@pipelab/core-node", + "version": "1.0.0-beta.37", + "private": false, + "description": "The Pipelab automation engine for Node.js", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "packages/core-node" + }, + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "build": "tsdown", + "format": "oxfmt .", + "lint": "oxlint .", + "typecheck": "tsc -b", + "test": "vitest run" + }, + "dependencies": { + "@pipelab/constants": "workspace:*", + "@pipelab/shared": "workspace:*", + "@supabase/supabase-js": "2.99.3", + "adm-zip": "0.5.16", + "archiver": "7.0.1", + "check-disk-space": "3.4.0", + "es-toolkit": "1.25.2", + "execa": "9.5.2", + "nanoid": "5.0.7", + "pacote": "21.5.0", + "semver": "^7.7.4", + "slash": "3.0.0", + "tar": "6.2.1", + "type-fest": "4.39.0", + "ws": "8.18.3", + "yauzl": "2.10.0" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "@types/adm-zip": "0.5.7", + "@types/archiver": "7.0.0", + "@types/node": "24.12.2", + "@types/pacote": "11.1.8", + "@types/semver": "^7.7.1", + "@types/tar": "7.0.87", + "@types/ws": "8.18.1", + "@types/yauzl": "2.10.3", + "memfs": "4.57.6", + "tsdown": "0.21.2", + "typescript": "^5.0.0", + "vitest": "3.1.4" + } +} diff --git a/packages/core-node/src/api.ts b/packages/core-node/src/api.ts new file mode 100644 index 00000000..135828a1 --- /dev/null +++ b/packages/core-node/src/api.ts @@ -0,0 +1,115 @@ +import { nanoid } from "nanoid"; +import { klona } from "klona"; +import { toRaw } from "vue"; + +import type { Tagged } from "type-fest"; +import { ILogObjMeta } from "tslog"; +import { useLogger } from "@pipelab/shared"; + +import { + UpdateStatus, + RendererChannels, + RendererData, + RendererEvents, + RendererEnd, + RendererMessage, + RequestId, + HandleListenerRendererSendFn, + HandleListenerRenderer as BaseHandleListenerRenderer, +} from "@pipelab/shared"; + +export type { + UpdateStatus, + RendererChannels, + RendererData, + RendererEvents, + RendererEnd, + RendererMessage, + RequestId, + HandleListenerRendererSendFn, +}; + +export type HandleListenerRenderer = ( + event: Electron.IpcMainInvokeEvent, + data: { value: RendererData; send: HandleListenerRendererSendFn }, +) => Promise; + +export type ListenerMain = ( + event: Electron.IpcMainEvent, + data: RendererEvents, +) => Promise; + +export const usePluginAPI = (browserWindow: any) => { + const { logger } = useLogger(); + /** + * Send an order + */ + const send = (channel: KEY, args?: RendererData) => { + if (!browserWindow || browserWindow.isDestroyed()) return; + browserWindow.webContents.send(channel, args); + }; + + const on = ( + channel: KEY | string, + listener: (event: any, data: RendererEvents) => void, + ) => { + if (!browserWindow || browserWindow.isDestroyed()) return () => {}; + const ipcMain = browserWindow.webContents.ipc.on(channel, listener); + + const cancel = () => { + if (browserWindow.isDestroyed()) return; + ipcMain.removeListener(channel, listener); + }; + + return cancel; + }; + + /** + * Send an order and wait for it's execution + */ + const execute = async ( + channel: KEY, + data?: RendererData, + listener?: ListenerMain, + ) => { + const newId = nanoid() as RequestId; + // eslint-disable-next-line no-async-promise-executor + return new Promise>(async (resolve, reject) => { + const message: RendererMessage = { + requestId: newId, + data: toRaw(klona(data)), + }; + + if (!browserWindow || browserWindow.isDestroyed()) { + return reject(new Error("Browser window is destroyed")); + } + + const cancel = on(newId, async (event, data) => { + // console.log('receiving event', event, data) + if (data.type === "end") { + cancel(); + return resolve(data.data); + } else { + await listener?.(event, data); + } + }); + + // send the message + try { + browserWindow.webContents.send(channel, message); + } catch (e) { + logger().error(e); + logger().error(channel, message); + reject(e); + } + }); + }; + + return { + send, + on, + execute, + }; +}; + +export type UseMainAPI = ReturnType; diff --git a/packages/core-node/src/config.test.ts b/packages/core-node/src/config.test.ts new file mode 100644 index 00000000..7ebd24fb --- /dev/null +++ b/packages/core-node/src/config.test.ts @@ -0,0 +1,229 @@ +import { describe, test, expect, beforeEach, vi } from "vitest"; +import { + setupConfigFile, + setupProjectsConfigFile, + deletePipelineConfigFileByName, + deletePipelineConfigFileByPath, +} from "./config"; +import { FileRepo } from "@pipelab/shared"; +import { PipelabContext } from "./context"; +import fs from "node:fs/promises"; +import { existsSync } from "node:fs"; +import path from "node:path"; +import { vol } from "memfs"; + +// Mock the node:fs and node:fs/promises modules to use memfs +vi.mock("node:fs", async () => { + const memfs = await import("memfs"); + return { + ...memfs.fs, + default: memfs.fs, + }; +}); + +vi.mock("node:fs/promises", async () => { + const memfs = await import("memfs"); + return { + ...memfs.fs.promises, + default: memfs.fs.promises, + }; +}); + +describe("setupConfigFile & Backup Creation", () => { + let tempDir: string; + let context: PipelabContext; + + beforeEach(() => { + vol.reset(); + tempDir = "/tmp/pipelab-test-config"; + context = new PipelabContext({ userDataPath: tempDir }); + }); + + test("should migrate config and create backup files on disk", async () => { + // 1. Setup V1 configuration file in the context's config path + const configDir = context.getConfigPath(); + await fs.mkdir(configDir, { recursive: true }); + + const projectsFilePath = context.getProjectsPath(); + + const v1Config = { + version: "1.0.0", + data: { + "pipeline-1": { + project: "main", + type: "internal", + configName: "pipeline-1", + lastModified: "2026-06-04", + }, + }, + }; + + await fs.writeFile(projectsFilePath, JSON.stringify(v1Config)); + + // 2. Initialize setupConfigFile + const configInstance = await setupProjectsConfigFile(context); + + // Verify file exists + expect(existsSync(projectsFilePath)).toBe(true); + + // 3. Retrieve config (this triggers the migration process and onStep callback) + const migratedConfig = await configInstance.getConfig(); + + // 4. Assert the main config is updated on disk to version 3.0.0 + expect(migratedConfig.version).toBe("3.0.0"); + + const updatedContent = JSON.parse(await fs.readFile(projectsFilePath, "utf8")); + expect(updatedContent.version).toBe("3.0.0"); + + // 5. Assert that the intermediate backup file was created on disk + const backupFilePath = path.join(configDir, "projects.v2.0.0.json"); + expect(existsSync(backupFilePath)).toBe(true); + + const backupContent = JSON.parse(await fs.readFile(backupFilePath, "utf8")); + expect(backupContent.version).toBe("2.0.0"); + expect(backupContent.projects).toHaveLength(1); + expect(backupContent.pipelines).toHaveLength(1); + }); + + test("should create default config file if missing on setup", async () => { + const configDir = context.getConfigPath(); + const projectsFilePath = context.getProjectsPath(); + + expect(existsSync(projectsFilePath)).toBe(false); + + // Initialize setupConfigFile + await setupProjectsConfigFile(context); + + // Should create file with default value + expect(existsSync(projectsFilePath)).toBe(true); + const content = JSON.parse(await fs.readFile(projectsFilePath, "utf8")); + expect(content.version).toBe("3.0.0"); + expect(content.projects).toHaveLength(1); + expect(content.pipelines).toEqual([]); + }); + + test("should fallback to default config and preserve corrupted file if parsing fails", async () => { + const configDir = context.getConfigPath(); + await fs.mkdir(configDir, { recursive: true }); + const projectsFilePath = context.getProjectsPath(); + + await fs.writeFile(projectsFilePath, "{ corrupted json... }"); + + const configInstance = await setupProjectsConfigFile(context); + const config = await configInstance.getConfig(); + + expect(config.version).toBe("3.0.0"); + expect(config.projects).toHaveLength(1); + expect(config.pipelines).toEqual([]); + + // Verify a timestamped corrupted backup file exists + const files = await fs.readdir(configDir); + const corruptedFile = files.find( + (f) => f.startsWith("projects.corrupted.") && f.endsWith(".json"), + ); + expect(corruptedFile).toBeDefined(); + const corruptedContent = await fs.readFile(path.join(configDir, corruptedFile!), "utf8"); + expect(corruptedContent).toBe("{ corrupted json... }"); + }); + + test("should fallback to default config and preserve file if migration throws", async () => { + const configDir = context.getConfigPath(); + await fs.mkdir(configDir, { recursive: true }); + const projectsFilePath = context.getProjectsPath(); + + const customMigrator = { + defaultValue: { version: "2.0.0", projects: [], pipelines: [] } as any, + migrate: async () => { + throw new Error("Migration failed!"); + }, + }; + + await fs.writeFile(projectsFilePath, JSON.stringify({ version: "1.0.0", invalidData: true })); + + const configInstance = await setupConfigFile(context.getProjectsPath(), { + context, + migrator: customMigrator, + }); + const config = await configInstance.getConfig(); + + expect(config.version).toBe("2.0.0"); + + // Verify a timestamped corrupted backup file exists + const files = await fs.readdir(configDir); + const corruptedFile = files.find( + (f) => f.startsWith("projects.corrupted.") && f.endsWith(".json"), + ); + expect(corruptedFile).toBeDefined(); + const corruptedContent = JSON.parse( + await fs.readFile(path.join(configDir, corruptedFile!), "utf8"), + ); + expect(corruptedContent.invalidData).toBe(true); + }); + + test("should save config to disk via setConfig", async () => { + const configInstance = await setupProjectsConfigFile(context); + const initialConfig = await configInstance.getConfig(); + + const newConfig: FileRepo = { + ...initialConfig, + pipelines: [ + { + id: "pipeline-new", + project: "main", + type: "internal", + configName: "pipeline-new", + lastModified: "2026-06-05", + }, + ], + }; + + const success = await configInstance.setConfig(newConfig); + expect(success).toBe(true); + + const savedContent = JSON.parse(await fs.readFile(context.getProjectsPath(), "utf8")); + expect(savedContent.pipelines).toHaveLength(1); + expect(savedContent.pipelines[0].id).toBe("pipeline-new"); + }); +}); + +describe("deletePipelineConfigFile", () => { + let tempDir: string; + let context: PipelabContext; + + beforeEach(() => { + vol.reset(); + tempDir = "/tmp/pipelab-test-config"; + context = new PipelabContext({ userDataPath: tempDir }); + }); + + test("should delete pipeline config file using relative name", async () => { + const configDir = context.getConfigPath(); + await fs.mkdir(configDir, { recursive: true }); + + const pipelineFilePath = path.join(configDir, "my-pipeline.json"); + await fs.writeFile(pipelineFilePath, JSON.stringify({ name: "My Pipeline" })); + expect(existsSync(pipelineFilePath)).toBe(true); + + await deletePipelineConfigFileByName("my-pipeline", context); + expect(existsSync(pipelineFilePath)).toBe(false); + }); + + test("should delete pipeline config file using absolute path", async () => { + const configDir = context.getConfigPath(); + await fs.mkdir(configDir, { recursive: true }); + + const pipelineFilePath = path.join(configDir, "another-pipeline.json"); + await fs.writeFile(pipelineFilePath, JSON.stringify({ name: "Another Pipeline" })); + expect(existsSync(pipelineFilePath)).toBe(true); + + await deletePipelineConfigFileByPath(pipelineFilePath, context); + expect(existsSync(pipelineFilePath)).toBe(false); + }); + + test("should not throw error when attempting to delete non-existent pipeline file", async () => { + const nonExistentPath = context.getConfigPath("does-not-exist.json"); + expect(existsSync(nonExistentPath)).toBe(false); + + await expect(deletePipelineConfigFileByName("does-not-exist", context)).resolves.not.toThrow(); + }); +}); diff --git a/packages/core-node/src/config.ts b/packages/core-node/src/config.ts new file mode 100644 index 00000000..d1779d88 --- /dev/null +++ b/packages/core-node/src/config.ts @@ -0,0 +1,174 @@ +import { PipelabContext } from "./context"; +import path from "node:path"; +import { ensure } from "./utils/fs-extras"; +import fs from "node:fs/promises"; +import { + useLogger, + Migrator, + AppConfig, + ConnectionsConfig, + FileRepo, + SavedFile, + appSettingsMigrator, + connectionsMigrator, + fileRepoMigrations, + savedFileMigrator, +} from "@pipelab/shared"; + +export const setupConfigFile = async ( + filesPath: string, + options: { context: PipelabContext; migrator: Migrator }, +) => { + const ctx = options.context; + const parsedPath = path.parse(filesPath); + const migrator = options.migrator; + + await ensure(filesPath, JSON.stringify(migrator.defaultValue)); + + return { + setConfig: async (config: T) => { + const { logger } = useLogger(); + try { + await fs.writeFile(filesPath, JSON.stringify(config)); + return true; + } catch (e) { + logger().error(`Error saving config ${parsedPath.name}:`, e); + return false; + } + }, + getConfig: async () => { + const { logger } = useLogger(); + let content = undefined; + let originalJson: any = undefined; + let parseFailed = false; + + try { + content = await fs.readFile(filesPath, "utf8"); + if (content !== undefined) { + originalJson = JSON.parse(content); + } + } catch (e) { + logger().error(`Error reading or parsing config ${parsedPath.name}:`, e); + parseFailed = true; + } + + let json: any = undefined; + let migrationFailed = false; + try { + if (!parseFailed) { + json = await migrator.migrate(originalJson, { + debug: false, + onStep: async (state: any, version: string) => { + const versionedPath = path.join( + parsedPath.dir, + `${parsedPath.name}.v${version}.json`, + ); + try { + await fs.writeFile(versionedPath, JSON.stringify(state)); + logger().info( + `Intermediate backup created for ${parsedPath.name} at ${versionedPath}`, + ); + } catch (e) { + logger().error( + `Failed to create intermediate backup for ${parsedPath.name} at v${version}:`, + e, + ); + } + }, + }); + } else { + json = migrator.defaultValue; + } + } catch (e) { + logger().error(`Error migrating config ${parsedPath.name}:`, e); + migrationFailed = true; + json = migrator.defaultValue; + } + + const originalVersion = originalJson?.version; + const newVersion = json?.version; + + const shouldSaveBack = + originalVersion !== newVersion || content === undefined || parseFailed || migrationFailed; + + if (shouldSaveBack) { + if (parseFailed || migrationFailed) { + try { + const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); + const corruptedPath = path.join( + parsedPath.dir, + `${parsedPath.name}.corrupted.${timestamp}.json`, + ); + const backupContent = parseFailed + ? content || "" + : JSON.stringify(originalJson, null, 2); + await fs.writeFile(corruptedPath, backupContent); + logger().info(`Corrupted config file preserved at ${corruptedPath}`); + } catch (e) { + logger().error(`Failed to backup corrupted config ${parsedPath.name}:`, e); + } + } + + try { + await fs.writeFile(filesPath, JSON.stringify(json)); + } catch (e) { + logger().error(`Error saving migrated config ${parsedPath.name}:`, e); + } + } + + return json as T; + }, + }; +}; + +export const setupSettingsConfigFile = (context: PipelabContext) => { + return setupConfigFile(context.getSettingsPath(), { + context, + migrator: appSettingsMigrator, + }); +}; + +export const setupConnectionsConfigFile = (context: PipelabContext) => { + return setupConfigFile(context.getConnectionsPath(), { + context, + migrator: connectionsMigrator, + }); +}; + +export const setupProjectsConfigFile = (context: PipelabContext) => { + return setupConfigFile(context.getProjectsPath(), { + context, + migrator: fileRepoMigrations, + }); +}; + +export const setupPipelineConfigFileByName = (name: string, context: PipelabContext) => { + const filesPath = context.getConfigPath(`${name}.json`); + return setupConfigFile(filesPath, { + context, + migrator: savedFileMigrator, + }); +}; + +export const setupPipelineConfigFileByPath = (absolutePath: string, context: PipelabContext) => { + return setupConfigFile(absolutePath, { + context, + migrator: savedFileMigrator, + }); +}; + +const deleteConfigFile = async (filesPath: string) => { + await fs.rm(filesPath, { force: true }); +}; + +export const deletePipelineConfigFileByName = async (name: string, context: PipelabContext) => { + const filesPath = context.getConfigPath(`${name}.json`); + await deleteConfigFile(filesPath); +}; + +export const deletePipelineConfigFileByPath = async ( + absolutePath: string, + context: PipelabContext, +) => { + await deleteConfigFile(absolutePath); +}; diff --git a/packages/core-node/src/context.ts b/packages/core-node/src/context.ts new file mode 100644 index 00000000..27de431a --- /dev/null +++ b/packages/core-node/src/context.ts @@ -0,0 +1,210 @@ +import { join, dirname, resolve } from "node:path"; +import { homedir, platform } from "node:os"; +import { fileURLToPath } from "node:url"; +import { existsSync, readFileSync } from "node:fs"; +import { mkdir, realpath, mkdtemp } from "node:fs/promises"; +import { SandboxFolder, DEFAULT_NODE_VERSION, DEFAULT_PNPM_VERSION } from "@pipelab/constants"; + +// @ts-ignore import.meta is only allowed in ES Modules +const metaUrl = typeof import.meta !== "undefined" ? import.meta.url : undefined; + +const _dirname = + typeof __dirname !== "undefined" + ? __dirname + : metaUrl + ? dirname(fileURLToPath(metaUrl)) + : process.cwd(); + +export const isDev = process.env.NODE_ENV === "development"; + +export type PipelabEnv = "dev" | "beta" | "prod"; + +export const getDefaultUserDataPath = (env?: PipelabEnv) => { + const base = (() => { + switch (platform()) { + case "win32": + return process.env.APPDATA || join(homedir(), "AppData", "Roaming"); + case "darwin": + return join(homedir(), "Library", "Application Support"); + default: + return process.env.XDG_CONFIG_HOME || join(homedir(), ".config"); + } + })(); + + const mode = env ?? (isDev ? "dev" : "prod"); + const folder = mode === "dev" ? "app-dev" : mode === "beta" ? "app-beta" : "app"; + + return join(base, "@pipelab", folder); +}; + +/** + * Finds the monorepo root by looking for pnpm-workspace.yaml. + */ +function findProjectRoot(startDir: string): string | null { + let curr = startDir; + while (curr !== dirname(curr)) { + if (existsSync(join(curr, "pnpm-workspace.yaml"))) { + return curr; + } + curr = dirname(curr); + } + return null; +} + +export const projectRoot = findProjectRoot(_dirname); + +export const CacheFolder = { + Actions: "actions", + Pipelines: "pipelines", + Pacote: "pacote", +} as const; + +export type CacheFolderType = (typeof CacheFolder)[keyof typeof CacheFolder]; + +export interface PipelabContextOptions { + userDataPath: string; + releaseTag?: string; +} + +type Join = T extends [] + ? "" + : T extends [infer F extends string] + ? F + : T extends [infer F extends string, ...infer R extends string[]] + ? `${F}${D}${Join}` + : string; + +export class PipelabContext { + public readonly userDataPath: string; + public readonly releaseTag: string; + + constructor(options: PipelabContextOptions) { + this.userDataPath = options.userDataPath; + this.releaseTag = options.releaseTag || "latest"; + } + + getPackagesPath(...subpaths: S): `PACKAGES/${Join}`; + getPackagesPath(...subpaths: string[]): string { + return join(this.userDataPath, "packages", ...subpaths); + } + + getThirdPartyPath(...subpaths: S): `THIRDPARTY/${Join}`; + getThirdPartyPath(...subpaths: string[]): string { + return join(this.userDataPath, "thirdparty", ...subpaths); + } + + getConfigPath(...subpaths: S): `CONFIG/${Join}`; + getConfigPath(...subpaths: string[]): string { + return join(this.userDataPath, "config", ...subpaths); + } + + getSettingsPath(): `CONFIG/settings.json` { + return this.getConfigPath("settings.json"); + } + + getConnectionsPath(): `CONFIG/connections.json` { + return this.getConfigPath("connections.json"); + } + + getProjectsPath(): `CONFIG/projects.json` { + return this.getConfigPath("projects.json"); + } + + private _cachedSettings: any = null; + private _cachedSettingsTime: number = 0; + + private getSettings() { + const settingsPath = this.getSettingsPath(); + if (!existsSync(settingsPath)) { + return null; + } + const now = Date.now(); + if (this._cachedSettings && now - this._cachedSettingsTime < 2000) { + return this._cachedSettings; + } + try { + const content = readFileSync(settingsPath, "utf8"); + this._cachedSettings = JSON.parse(content); + this._cachedSettingsTime = now; + return this._cachedSettings; + } catch (e) { + return this._cachedSettings; + } + } + + getTempPath(...subpaths: S): `TEMP/${Join}`; + getTempPath(...subpaths: string[]): string { + const settings = this.getSettings(); + const base = settings?.tempFolder || join(this.userDataPath, "temp"); + return join(base, ...subpaths); + } + + createTempFolder(prefix?: T): Promise<`TEMP/${T}${string}`>; + async createTempFolder(prefix = "pipelab-"): Promise { + const baseDir = this.getTempPath(); + await mkdir(baseDir, { recursive: true }); + const realBaseDir = await realpath(baseDir); + return mkdtemp(join(realBaseDir, prefix)); + } + + getCachePath(): `CACHE/`; + getCachePath( + folder: F, + ...subpaths: S + ): `CACHE/${F}/${Join}`; + getCachePath(folder?: CacheFolderType, ...subpaths: string[]): string { + const settings = this.getSettings(); + const base = settings?.cacheFolder || join(this.userDataPath, "cache"); + if (!folder) { + return base; + } + return join(base, folder, ...subpaths); + } + + getPnpmPath(...subpaths: S): `PNPM/${Join}`; + getPnpmPath(...subpaths: string[]): string { + return join(this.userDataPath, "pnpm", ...subpaths); + } + + getBuildHistoryPath(...subpaths: S): `BUILD_HISTORY/${Join}`; + getBuildHistoryPath(...subpaths: string[]): string { + return join(this.userDataPath, "build-history", ...subpaths); + } + + getArtifactsPath(...subpaths: S): `ARTIFACTS/${Join}`; + getArtifactsPath(...subpaths: string[]): string { + return join(this.userDataPath, "artifacts", ...subpaths); + } + + getNodePath( + version?: V, + ): `THIRDPARTY/node/${V}/${string}`; + getNodePath(version = DEFAULT_NODE_VERSION): string { + const isWindows = process.platform === "win32"; + return this.getThirdPartyPath("node", version, isWindows ? "node.exe" : "bin/node"); + } + + getPnpmBinPath( + version?: V, + ): `PACKAGES/pnpm/${V}/bin/pnpm.cjs`; + getPnpmBinPath(version = DEFAULT_PNPM_VERSION): string { + return this.getPackagesPath("pnpm", version, "bin", "pnpm.cjs"); + } + + getSandboxFolders(): Array<{ name: SandboxFolder; label: string; path: string }> { + const foldersRecord: Record = { + [SandboxFolder.Packages]: { label: "Packages", path: this.getPackagesPath() }, + [SandboxFolder.ThirdParty]: { label: "Third-Party Tools", path: this.getThirdPartyPath() }, + [SandboxFolder.Config]: { label: "Configuration", path: this.getConfigPath() }, + [SandboxFolder.Temp]: { label: "Temporary Files", path: this.getTempPath() }, + [SandboxFolder.Cache]: { label: "Cache", path: this.getCachePath() }, + [SandboxFolder.Pnpm]: { label: "PNPM Home", path: this.getPnpmPath() }, + [SandboxFolder.Artifacts]: { label: "Artifacts", path: this.getArtifactsPath() }, + }; + + return (Object.keys(foldersRecord) as SandboxFolder[]).map((key) => ({ + name: key, + ...foldersRecord[key], + })); + } +} diff --git a/packages/core-node/src/fs-utils.test.ts b/packages/core-node/src/fs-utils.test.ts new file mode 100644 index 00000000..d89adf5c --- /dev/null +++ b/packages/core-node/src/fs-utils.test.ts @@ -0,0 +1,125 @@ +import { describe, test, expect } from "vitest"; +import { homedir } from "node:os"; +import { resolve, join } from "node:path"; +import slash from "slash"; +import { isPathBlacklisted } from "./fs-utils"; +import { getDefaultUserDataPath, projectRoot } from "./context"; + +const isWindows = process.platform === "win32"; + +describe("isPathBlacklisted", () => { + test("should return false for empty or falsy paths", () => { + expect(isPathBlacklisted("")).toBe(false); + expect(isPathBlacklisted(undefined as any)).toBe(false); + expect(isPathBlacklisted(null as any)).toBe(false); + }); + + test("should return false for safe user workspace paths", () => { + const safePath = join(homedir(), "my-custom-projects", "project-1"); + expect(isPathBlacklisted(safePath)).toBe(false); + }); + + test("should blacklist user home directory", () => { + expect(isPathBlacklisted(homedir())).toBe(true); + expect(isPathBlacklisted(homedir() + "/")).toBe(true); + }); + + test.skipIf(isWindows)("should blacklist common system paths on Unix-like systems", () => { + // These Unix paths are checked as absolute paths starting with / + expect(isPathBlacklisted("/usr")).toBe(true); + expect(isPathBlacklisted("/var")).toBe(true); + expect(isPathBlacklisted("/etc")).toBe(true); + expect(isPathBlacklisted("/bin")).toBe(true); + expect(isPathBlacklisted("/sbin")).toBe(true); + expect(isPathBlacklisted("/lib")).toBe(true); + expect(isPathBlacklisted("/lib64")).toBe(true); + expect(isPathBlacklisted("/boot")).toBe(true); + expect(isPathBlacklisted("/sys")).toBe(true); + expect(isPathBlacklisted("/proc")).toBe(true); + expect(isPathBlacklisted("/dev")).toBe(true); + expect(isPathBlacklisted("/run")).toBe(true); + expect(isPathBlacklisted("/home")).toBe(true); + expect(isPathBlacklisted("/root")).toBe(true); + expect(isPathBlacklisted("/mnt")).toBe(true); + expect(isPathBlacklisted("/media")).toBe(true); + expect(isPathBlacklisted("/srv")).toBe(true); + expect(isPathBlacklisted("/applications")).toBe(true); + expect(isPathBlacklisted("/library")).toBe(true); + expect(isPathBlacklisted("/system")).toBe(true); + expect(isPathBlacklisted("/volumes")).toBe(true); + expect(isPathBlacklisted("/snap")).toBe(true); + expect(isPathBlacklisted("/")).toBe(true); + }); + + test.runIf(isWindows)( + "should blacklist common Windows directories dynamically on any drive (Windows-only)", + () => { + // Windows drive roots + expect(isPathBlacklisted("c:")).toBe(true); + expect(isPathBlacklisted("d:")).toBe(true); + expect(isPathBlacklisted("Z:")).toBe(true); + expect(isPathBlacklisted("C:\\")).toBe(true); + expect(isPathBlacklisted("d:/")).toBe(true); + + // Windows system directories on any drive letter + expect(isPathBlacklisted("c:/windows")).toBe(true); + expect(isPathBlacklisted("D:\\Windows\\")).toBe(true); + expect(isPathBlacklisted("e:/program files")).toBe(true); + expect(isPathBlacklisted("f:/program files (x86)")).toBe(true); + expect(isPathBlacklisted("g:/users")).toBe(true); + expect(isPathBlacklisted("h:/programdata")).toBe(true); + expect(isPathBlacklisted("i:/perflogs")).toBe(true); + + // Should NOT blacklist normal subfolders on other drives + expect(isPathBlacklisted("d:/my-folder")).toBe(false); + expect(isPathBlacklisted("c:/windows-backup")).toBe(false); + }, + ); + + test("should blacklist standard user profile directories", () => { + expect(isPathBlacklisted(join(homedir(), "Downloads"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Documents"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Desktop"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Pictures"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Music"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Videos"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Saved Games"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Contacts"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Searches"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "Links"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), "3D Objects"))).toBe(true); + }); + + test("should blacklist developer settings and credentials", () => { + expect(isPathBlacklisted(join(homedir(), ".ssh"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".gnupg"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".aws"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".docker"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".kube"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".vscode"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".cursor"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".npm"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".pnpm-state"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".yarn"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".cargo"))).toBe(true); + expect(isPathBlacklisted(join(homedir(), ".rustup"))).toBe(true); + }); + + test("should blacklist Pipelab-specific directories", () => { + expect(isPathBlacklisted(getDefaultUserDataPath("prod"))).toBe(true); + expect(isPathBlacklisted(getDefaultUserDataPath("dev"))).toBe(true); + expect(isPathBlacklisted(getDefaultUserDataPath("beta"))).toBe(true); + if (projectRoot) { + expect(isPathBlacklisted(projectRoot)).toBe(true); + } + expect(isPathBlacklisted(process.cwd())).toBe(true); + }); + + test("should handle case-insensitive paths and slash normalization", () => { + const mixedPath = join(homedir(), "DoWnLoAdS"); + expect(isPathBlacklisted(mixedPath)).toBe(true); + + const trailingSlashPath = homedir() + "/"; + expect(isPathBlacklisted(trailingSlashPath)).toBe(true); + }); +}); diff --git a/packages/core-node/src/fs-utils.ts b/packages/core-node/src/fs-utils.ts new file mode 100644 index 00000000..befe8ee6 --- /dev/null +++ b/packages/core-node/src/fs-utils.ts @@ -0,0 +1,142 @@ +import { homedir } from "node:os"; +import { resolve, join } from "node:path"; +import slash from "slash"; + +function removeTrailingSlash(path: string): string { + return path.replace(/[\\/]+$/, ""); +} + +function isWindowsDriveRoot(path: string): boolean { + return /^[a-z]:$/.test(path); +} + +import { getDefaultUserDataPath, projectRoot } from "./context"; + +const windowsSystemFolders = [ + "windows", + "program files", + "program files (x86)", + "users", + "programdata", + "perflogs", +]; + +function isWindowsSystemDirectory(path: string): boolean { + const driveRoot = path.substring(0, 2); + if (!isWindowsDriveRoot(driveRoot) || path.charAt(2) !== "/") return false; + const folder = path.substring(3); + return windowsSystemFolders.includes(folder); +} + +// Static Unix/Linux/macOS system directories (normalized) +const unixSystemDirectories = new Set([ + "", // represents "/" after removeTrailingSlash + "/usr", + "/var", + "/opt", + "/etc", + "/bin", + "/sbin", + "/lib", + "/lib64", + "/boot", + "/sys", + "/proc", + "/dev", + "/run", + "/home", + "/root", + "/mnt", + "/media", + "/srv", + "/applications", + "/library", + "/system", + "/volumes", + "/snap", +]); + +// Statically resolved home directory, user directories, temp directories, and Pipelab's AppData +const homeDirectory = removeTrailingSlash(slash(resolve(homedir()))).toLowerCase(); + +const additionalProtectedPaths = [ + // Pipelab user data directories (dev, beta, prod) + getDefaultUserDataPath("dev"), + getDefaultUserDataPath("beta"), + getDefaultUserDataPath("prod"), + // Pipelab source directory if available + projectRoot, + // Current working directory of the process + process.cwd(), + // System temp directories + "/tmp", + "/var/tmp", + process.env.TEMP, + process.env.TMP, + // Windows AppData roots + join(homedir(), "AppData"), + join(homedir(), "AppData", "Local"), + join(homedir(), "AppData", "Roaming"), + // macOS / Unix config roots + join(homedir(), "Library"), + join(homedir(), "Library", "Application Support"), + join(homedir(), ".config"), + join(homedir(), ".local"), + join(homedir(), ".local", "share"), + join(homedir(), ".cache"), + // Cloud directories + join(homedir(), "OneDrive"), + join(homedir(), "Dropbox"), + // Critical SSH/GPG credentials folders + join(homedir(), ".ssh"), + join(homedir(), ".gnupg"), + // Developer CLI configurations + join(homedir(), ".aws"), + join(homedir(), ".docker"), + join(homedir(), ".kube"), + // IDE environments + join(homedir(), ".vscode"), + join(homedir(), ".vscode-insiders"), + join(homedir(), ".cursor"), + // Package manager / toolchain directories + join(homedir(), ".npm"), + join(homedir(), ".pnpm-state"), + join(homedir(), ".yarn"), + join(homedir(), ".cargo"), + join(homedir(), ".rustup"), + join(homedir(), ".m2"), + join(homedir(), ".gradle"), +].filter((p): p is string => typeof p === "string" && p.length > 0); + +const userSubdirectories = new Set( + [ + join(homedir(), "Downloads"), + join(homedir(), "Documents"), + join(homedir(), "Desktop"), + join(homedir(), "Pictures"), + join(homedir(), "Music"), + join(homedir(), "Videos"), + join(homedir(), "Saved Games"), + join(homedir(), "Contacts"), + join(homedir(), "Searches"), + join(homedir(), "Links"), + join(homedir(), "3D Objects"), + ...additionalProtectedPaths, + ].map((p) => removeTrailingSlash(slash(resolve(p))).toLowerCase()), +); + +/** + * Checks if a path matches a critical user or system directory. + */ +export function isPathBlacklisted(pathToCheck: string): boolean { + if (!pathToCheck) return false; + const normalized = removeTrailingSlash(slash(resolve(pathToCheck))).toLowerCase(); + + return ( + normalized === homeDirectory || + unixSystemDirectories.has(normalized) || + userSubdirectories.has(normalized) || + isWindowsDriveRoot(normalized) || + isWindowsSystemDirectory(normalized) + ); +} diff --git a/packages/core-node/src/handler-func.ts b/packages/core-node/src/handler-func.ts new file mode 100644 index 00000000..3469e244 --- /dev/null +++ b/packages/core-node/src/handler-func.ts @@ -0,0 +1,176 @@ +import { End } from "@pipelab/shared"; +import { ensureNodeJS, ensurePNPM } from "./utils/remote"; +import { Action, ActionRunner } from "./types/runner"; +import { InputsDefinition } from "@pipelab/shared"; +import { usePlugins } from "@pipelab/shared"; +import { isRequired } from "@pipelab/shared"; +import { mkdir, stat } from "node:fs/promises"; +import { PipelabContext } from "./context"; +import { useLogger } from "@pipelab/shared"; + +import { HandleListenerSendFn } from "./handlers"; +import path from "node:path"; +const { join } = path; + +const checkParams = (definitionParams: InputsDefinition, elementParams: Record) => { + // get a list of all required params + let expected = Object.keys(definitionParams); + + const found: string[] = []; + // for each param in elementParams + for (const param of Object.keys(elementParams)) { + // if the param is in the expected list + if (expected.includes(param)) { + // add to found + found.push(param); + // remove from expected + expected = expected.filter((x) => x !== param); + } else { + // throw new Error('Unexpected param "' + param + '"') + console.warn('Unexpected param "' + param + '"'); + } + } + + for (const param of expected) { + if (isRequired(definitionParams[param])) { + throw new Error('Missing param "' + param + '"'); + } + } +}; + +export const handleActionExecute = async ( + nodeId: string, + pluginId: string, + params: Record, + mainWindow: any | undefined, + send: HandleListenerSendFn<"action:execute">, + abortSignal: AbortSignal, + cwd: string, + cachePath: string, + context: PipelabContext, + onArtifact?: (name: string, path: string) => void, +): Promise> => { + const ctx = context; + const { plugins } = usePlugins(); + const { logger } = useLogger(); + + mainWindow?.setProgressBar(1, { + mode: "indeterminate", + }); + + const node = plugins.value + .find((plugin) => plugin.id === pluginId) + ?.nodes.find((node: any) => node.node.id === nodeId) as + | { + node: Action; + runner: ActionRunner; + } + | undefined; + + if (!node) { + mainWindow?.setProgressBar(1, { mode: "normal" }); + return { + type: "error", + ipcError: "Node not found", + }; + } + + const nodePath = await ensureNodeJS(ctx); + const pnpm = await ensurePNPM(ctx); + + const outputs: Record = {}; + + try { + try { + const s = await stat(cwd); + if (!s.isDirectory()) { + throw new Error(`Execution directory "${cwd}" exists but is not a directory.`); + } + } catch (e: any) { + if (e.code === "ENOENT") { + await mkdir(cwd, { recursive: true }); + } else { + throw e; + } + } + checkParams(node.node.params, params); + const resolvedInputs = params; // await resolveActionInputs(params, node.node, steps) + logger().info("resolvedInputs", resolvedInputs); + + await node.runner({ + inputs: resolvedInputs, + log: (...args) => { + const decorator = `[${node.node.name}]`; + const formattedArgs = args.map((arg) => { + if (arg instanceof Error) { + return arg.stack || arg.message || String(arg); + } + if (typeof arg === "object" && arg !== null) { + try { + return JSON.stringify(arg, null, 2); + } catch { + return String(arg); + } + } + return arg; + }); + const logArgs = [decorator, ...formattedArgs]; + logger().info(...logArgs); + send({ + type: "log", + data: { + decorator, + time: Date.now(), + message: formattedArgs, + }, + }); + }, + setOutput: (key: any, value: unknown) => { + outputs[key] = value; + }, + meta: { + definition: "", + }, + setMeta: () => { + logger().info("set meta defined here"); + }, + cwd: cwd, + paths: { + cache: cachePath, + node: nodePath, + pnpm, + modules: "", + userData: ctx.userDataPath, + thirdparty: ctx.getThirdPartyPath(), + }, + browserWindow: mainWindow, + abortSignal, + context: ctx, + setArtifact: (name: string, path: string) => { + onArtifact?.(name, path); + }, + }); + + mainWindow?.setProgressBar(1, { mode: "normal" }); + + return { + type: "success", + result: { outputs, tmp: cwd }, + }; + } catch (e) { + logger().error("Error in action execution:", e); + mainWindow?.setProgressBar(1, { mode: "normal" }); + + // If aborted, throw AbortError to distinguish from actual errors + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + return { + type: "error", + ipcError: String(e), + }; + } +}; diff --git a/packages/core-node/src/handlers.ts b/packages/core-node/src/handlers.ts new file mode 100644 index 00000000..e275e757 --- /dev/null +++ b/packages/core-node/src/handlers.ts @@ -0,0 +1,2 @@ +export * from "./ipc-core"; +export * from "./handlers/index"; diff --git a/packages/core-node/src/handlers/agents.ts b/packages/core-node/src/handlers/agents.ts new file mode 100644 index 00000000..1bd8fe60 --- /dev/null +++ b/packages/core-node/src/handlers/agents.ts @@ -0,0 +1,32 @@ +import { useAPI } from "../ipc-core"; +import { useLogger } from "@pipelab/shared"; +import { webSocketServer } from "../websocket-server"; +import { PipelabContext } from "../context"; + +export const registerAgentsHandlers = (_context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + + handle("agents:get", async (event, { send }) => { + try { + const agents = webSocketServer.getAgents(); + + send({ + type: "end", + data: { + type: "success", + result: { agents }, + }, + }); + } catch (error) { + logger().error("Failed to get agents:", error); + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Failed to get agents", + }, + }); + } + }); +}; diff --git a/packages/core-node/src/handlers/auth.ts b/packages/core-node/src/handlers/auth.ts new file mode 100644 index 00000000..28661500 --- /dev/null +++ b/packages/core-node/src/handlers/auth.ts @@ -0,0 +1,95 @@ +import { supabase, useLogger, isSupabaseAvailable } from "@pipelab/shared"; +import { useAPI } from "../ipc-core"; +import { JsonFileStorage } from "../utils/storage"; +import { PipelabContext } from "../context"; +import { webSocketServer } from "../websocket-server"; + +/** + * Registers authentication handlers for the CLI/system backend. + */ +export const registerAuthHandlers = (context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + + const supabaseAvailable = isSupabaseAvailable(); + if (!supabaseAvailable) { + logger().warn("[Auth] Supabase is not available. Auth handlers will not be functional."); + return; + } + + // Initialize the singleton Supabase client for the backend with the custom FileStorage + const client = supabase({ + auth: { + storage: new JsonFileStorage("auth-session.json", context), + persistSession: true, + autoRefreshToken: true, + detectSessionInUrl: false, + }, + }); + + handle("auth:getUser", async (_, { send }) => { + try { + const { data, error } = await client.auth.getUser(); + if (error) { + return send({ type: "end", data: { type: "success", result: { user: null } } }); + } + return send({ type: "end", data: { type: "success", result: { user: data.user } } }); + } catch (e) { + return send({ type: "end", data: { type: "success", result: { user: null } } }); + } + }); + + handle("auth:signInWithPassword", async (_, { value, send }) => { + const { email, password } = value; + logger().info("[Auth] signInWithPassword:", email); + const result = await client.auth.signInWithPassword({ email, password }); + return send({ type: "end", data: { type: "success", result: result as any } }); + }); + + handle("auth:signUp", async (_, { value, send }) => { + const { email, password } = value; + logger().info("[Auth] signUp:", email); + const result = await client.auth.signUp({ email, password }); + return send({ type: "end", data: { type: "success", result: result as any } }); + }); + + handle("auth:signOut", async (_, { send }) => { + logger().info("[Auth] signOut"); + await client.auth.signOut(); + return send({ type: "end", data: { type: "success", result: undefined } }); + }); + + handle("auth:resetPasswordForEmail", async (_, { value, send }) => { + const { email } = value; + logger().info("[Auth] resetPasswordForEmail:", email); + const { error } = await client.auth.resetPasswordForEmail(email); + return send({ type: "end", data: { type: "success", result: { error } } }); + }); + + handle("auth:invoke", async (_, { value, send }) => { + const { name, options } = value; + logger().info("[Auth] invoke function:", name); + try { + const result = await client.functions.invoke(name, options); + return send({ type: "end", data: { type: "success", result } }); + } catch (e) { + return send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Edge Function invocation failed", + }, + }); + } + }); + + // Maintain logs for the backend state change and broadcast to all clients + client.auth.onAuthStateChange(async (event, session) => { + logger().info( + "[Auth] State changed, broadcasting:", + event, + session?.user?.email || "anonymous", + ); + webSocketServer.broadcast("auth:getUser" as any, { user: session?.user || null } as any); + }); +}; diff --git a/packages/core-node/src/handlers/build-history.ts b/packages/core-node/src/handlers/build-history.ts new file mode 100644 index 00000000..8a3c20a0 --- /dev/null +++ b/packages/core-node/src/handlers/build-history.ts @@ -0,0 +1,351 @@ +import { PipelabContext } from "../context"; +import { join } from "node:path"; +import { writeFile, readFile, unlink, mkdir, stat, readdir, rm } from "node:fs/promises"; +import { useLogger, BuildHistoryEntry, IBuildHistoryStorage, AppConfig } from "@pipelab/shared"; +import checkDiskSpace from "check-disk-space"; +import { getFolderSize } from "../utils/fs-extras"; +import { SandboxFolder } from "@pipelab/constants"; + +// Simplified storage - one file per pipeline containing array of build entries + +export class BuildHistoryStorage implements IBuildHistoryStorage { + private logger = useLogger(); + + constructor(private context: PipelabContext) { + // Simple initialization - no complex setup needed + } + + private getStoragePath() { + return this.context.getConfigPath("pipelines"); + } + + private getPipelinePath(pipelineId: string): string { + return join(this.getStoragePath(), `${pipelineId}.history.json`); + } + + private async ensureStoragePath(): Promise { + try { + await mkdir(this.getStoragePath(), { recursive: true }); + } catch (error) { + this.logger.logger().error("Failed to create storage path:", error); + throw new Error(`Failed to create storage directory: ${error}`); + } + } + + private async loadPipelineHistory(pipelineId: string): Promise { + try { + const pipelinePath = this.getPipelinePath(pipelineId); + const data = await readFile(pipelinePath, "utf-8"); + return JSON.parse(data); + } catch (error) { + // File doesn't exist or is corrupted, return empty array + return []; + } + } + + private async savePipelineHistory( + pipelineId: string, + entries: BuildHistoryEntry[], + ): Promise { + try { + await this.ensureStoragePath(); + const pipelinePath = this.getPipelinePath(pipelineId); + await writeFile(pipelinePath, JSON.stringify(entries, null, 2), "utf-8"); + } catch (error) { + this.logger.logger().error("Failed to save pipeline history:", error); + throw new Error(`Failed to save pipeline history: ${error}`); + } + } + + async save(entry: BuildHistoryEntry): Promise { + try { + const entries = await this.loadPipelineHistory(entry.pipelineId); + const existingIndex = entries.findIndex((e) => e.id === entry.id); + + if (existingIndex >= 0) { + entries[existingIndex] = entry; + } else { + entries.push(entry); + } + + await this.savePipelineHistory(entry.pipelineId, entries); + this.logger + .logger() + .info(`Saved build history entry: ${entry.id} for pipeline: ${entry.pipelineId}`); + } catch (error) { + this.logger.logger().error("Failed to save build history entry:", error); + throw new Error(`Failed to save build history entry: ${error}`); + } + } + + async get(id: string, pipelineId?: string): Promise { + try { + if (pipelineId) { + const entries = await this.loadPipelineHistory(pipelineId); + return entries.find((e) => e.id === id); + } + + const files = await this.getAllPipelineFiles(); + for (const file of files) { + const pId = this.parsePipelineIdFromFilename(file); + if (!pId) continue; + const entries = await this.loadPipelineHistory(pId); + const entry = entries.find((e) => e.id === id); + if (entry) return entry; + } + return undefined; + } catch (error) { + this.logger.logger().error(`Failed to get build history entry ${id}:`, error); + return undefined; + } + } + + async getAll(): Promise { + try { + const files = await this.getAllPipelineFiles(); + const allEntries: BuildHistoryEntry[] = []; + for (const file of files) { + const pipelineId = this.parsePipelineIdFromFilename(file); + if (!pipelineId) continue; + const entries = await this.loadPipelineHistory(pipelineId); + allEntries.push(...entries); + } + return allEntries.sort((a, b) => b.createdAt - a.createdAt); + } catch (error) { + this.logger.logger().error("Failed to get all build history entries:", error); + throw new Error(`Failed to get all build history entries: ${error}`); + } + } + + async getByPipeline(pipelineId: string): Promise { + try { + const entries = await this.loadPipelineHistory(pipelineId); + return entries.sort((a, b) => b.createdAt - a.createdAt); + } catch (error) { + this.logger.logger().error(`Failed to get build history for pipeline ${pipelineId}:`, error); + throw new Error(`Failed to get build history for pipeline: ${error}`); + } + } + + async update( + id: string, + updates: Partial, + pipelineId?: string, + ): Promise { + try { + if (pipelineId) { + const entries = await this.loadPipelineHistory(pipelineId); + const entryIndex = entries.findIndex((e) => e.id === id); + if (entryIndex >= 0) { + entries[entryIndex] = { ...entries[entryIndex], ...updates, updatedAt: Date.now() }; + await this.savePipelineHistory(pipelineId, entries); + return; + } + } else { + const files = await this.getAllPipelineFiles(); + for (const file of files) { + const pId = this.parsePipelineIdFromFilename(file); + if (!pId) continue; + const entries = await this.loadPipelineHistory(pId); + const entryIndex = entries.findIndex((e) => e.id === id); + if (entryIndex >= 0) { + entries[entryIndex] = { ...entries[entryIndex], ...updates, updatedAt: Date.now() }; + await this.savePipelineHistory(pId, entries); + return; + } + } + } + throw new Error(`Build history entry ${id} not found`); + } catch (error) { + this.logger.logger().error(`Failed to update build history entry ${id}:`, error); + throw new Error(`Failed to update build history entry: ${error}`); + } + } + + async delete(id: string, pipelineId?: string): Promise { + try { + if (pipelineId) { + const entries = await this.loadPipelineHistory(pipelineId); + const entryIndex = entries.findIndex((e) => e.id === id); + if (entryIndex >= 0) { + entries.splice(entryIndex, 1); + await this.savePipelineHistory(pipelineId, entries); + this.logger.logger().info(`Deleted build history entry: ${id}`); + return; + } + } else { + const files = await this.getAllPipelineFiles(); + for (const file of files) { + const pId = this.parsePipelineIdFromFilename(file); + if (!pId) continue; + const entries = await this.loadPipelineHistory(pId); + const entryIndex = entries.findIndex((e) => e.id === id); + if (entryIndex >= 0) { + entries.splice(entryIndex, 1); + await this.savePipelineHistory(pId, entries); + this.logger.logger().info(`Deleted build history entry: ${id}`); + return; + } + } + } + this.logger.logger().info(`Build history entry ${id} not found for deletion`); + } catch (error) { + this.logger.logger().error(`Failed to delete build history entry ${id}:`, error); + throw new Error(`Failed to delete build history entry: ${error}`); + } + } + + async clear(): Promise { + try { + await this.ensureStoragePath(); + const files = await this.getAllPipelineFiles(); + const cachePathsToDelete = new Set(); + + for (const file of files) { + const pipelineId = this.parsePipelineIdFromFilename(file); + if (pipelineId) { + const entries = await this.loadPipelineHistory(pipelineId); + for (const entry of entries) { + if (entry.cachePath) { + cachePathsToDelete.add(entry.cachePath); + } + } + await rm(this.context.getArtifactsPath(pipelineId), { recursive: true, force: true }).catch(() => {}); + } + await unlink(join(this.getStoragePath(), file)); + } + + this.logger.logger().info("Cleared all build history"); + + for (const cachePath of cachePathsToDelete) { + await rm(cachePath, { recursive: true, force: true }).catch(() => {}); + } + } catch (error) { + this.logger.logger().error("Failed to clear build history:", error); + throw new Error(`Failed to clear build history: ${error}`); + } + } + + async clearByPipeline(pipelineId: string): Promise { + try { + const pipelinePath = this.getPipelinePath(pipelineId); + const entries = await this.loadPipelineHistory(pipelineId); + await unlink(pipelinePath); + this.logger.logger().info(`Cleared history for pipeline "${pipelineId}"`); + + const cachePathsToDelete = new Set(); + for (const entry of entries) { + if (entry.cachePath) { + cachePathsToDelete.add(entry.cachePath); + } + } + for (const cachePath of cachePathsToDelete) { + await rm(cachePath, { recursive: true, force: true }).catch(() => {}); + } + await rm(this.context.getArtifactsPath(pipelineId), { recursive: true, force: true }).catch(() => {}); + } catch (error: any) { + if (error.code === "ENOENT") { + this.logger + .logger() + .warn(`No history file found for pipeline "${pipelineId}". Nothing to clear.`); + return; + } + this.logger.logger().error(`Failed to clear history for pipeline "${pipelineId}":`, error); + throw new Error(`Failed to clear history for pipeline: ${error}`); + } + } + + async getStorageInfo(): Promise<{ + totalEntries: number; + totalSize: number; + oldestEntry?: number; + newestEntry?: number; + numberOfPipelines: number; + userDataPath: string; + disk: { + total: number; + free: number; + pipelab: number; + folders: Array<{ name: SandboxFolder; label: string; size: number }>; + }; + }> { + try { + const allEntries = await this.getAll(); + const files = await this.getAllPipelineFiles(); + + const diskSpace = await checkDiskSpace(this.context.userDataPath); + const pipelabSize = await getFolderSize(this.context.userDataPath); + + const folders = []; + for (const folder of this.context.getSandboxFolders()) { + const size = await getFolderSize(folder.path); + folders.push({ + name: folder.name, + label: folder.label, + size, + }); + } + + if (allEntries.length === 0) { + return { + totalEntries: 0, + totalSize: 0, + numberOfPipelines: files.length, + userDataPath: this.context.userDataPath, + disk: { + total: diskSpace.size, + free: diskSpace.free, + pipelab: pipelabSize, + folders, + }, + }; + } + + let totalSize = 0; + try { + for (const file of files) { + const filePath = join(this.getStoragePath(), file); + const stats = await stat(filePath); + totalSize += stats.size; + } + } catch (error) { + totalSize = allEntries.length * 1024; // Rough estimate + } + + const sortedEntries = allEntries.sort((a, b) => a.createdAt - b.createdAt); + + return { + totalEntries: allEntries.length, + totalSize, + oldestEntry: sortedEntries[0]?.createdAt, + newestEntry: sortedEntries[sortedEntries.length - 1]?.createdAt, + numberOfPipelines: files.length, + userDataPath: this.context.userDataPath, + disk: { + total: diskSpace.size, + free: diskSpace.free, + pipelab: pipelabSize, + folders, + }, + }; + } catch (error) { + this.logger.logger().error("Failed to get storage info:", error); + throw new Error(`Failed to get storage info: ${error}`); + } + } + + private async getAllPipelineFiles(): Promise { + try { + await this.ensureStoragePath(); + const files = await readdir(this.getStoragePath()); + return files.filter((file) => file.endsWith(".history.json")); + } catch (error) { + return []; + } + } + + private parsePipelineIdFromFilename(filename: string): string | null { + const match = filename.match(/^(.+)\.history\.json$/); + return match ? match[1] : null; + } +} diff --git a/packages/core-node/src/handlers/config.ts b/packages/core-node/src/handlers/config.ts new file mode 100644 index 00000000..e2badcf6 --- /dev/null +++ b/packages/core-node/src/handlers/config.ts @@ -0,0 +1,364 @@ +import { useAPI } from "../ipc-core"; +import { + useLogger, + appSettingsMigrator, + connectionsMigrator, + fileRepoMigrations, +} from "@pipelab/shared"; +import { + setupSettingsConfigFile, + setupConnectionsConfigFile, + setupProjectsConfigFile, + setupPipelineConfigFileByName, + setupPipelineConfigFileByPath, + deletePipelineConfigFileByName, + deletePipelineConfigFileByPath, +} from "../config"; +import { PipelabContext } from "../context"; + +export const registerConfigHandlers = (context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + + // Settings + handle("settings:load", async (_, { send }) => { + logger().info("settings:load"); + try { + const manager = await setupSettingsConfigFile(context); + const json = await manager.getConfig(); + send({ + type: "end", + data: { type: "success", result: json }, + }); + } catch (e) { + logger().error("settings:load error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to load settings", + }, + }); + } + }); + + handle("settings:save", async (_, { send, value }) => { + const { data } = value; + try { + const manager = await setupSettingsConfigFile(context); + const json = typeof data === "string" ? JSON.parse(data) : data; + await manager.setConfig(json); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error("settings:save error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to save settings", + }, + }); + } + }); + + handle("settings:reset", async (_, { send, value }) => { + const { key } = value; + try { + const manager = await setupSettingsConfigFile(context); + const currentConfig = await manager.getConfig(); + const defaultValue = (appSettingsMigrator.defaultValue as any)[key]; + await manager.setConfig({ + ...(currentConfig ? (currentConfig as any) : {}), + [key]: defaultValue, + } as any); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error("settings:reset error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to reset settings", + }, + }); + } + }); + + // Connections + handle("connections:load", async (_, { send }) => { + logger().info("connections:load"); + try { + const manager = await setupConnectionsConfigFile(context); + const json = await manager.getConfig(); + send({ + type: "end", + data: { type: "success", result: json }, + }); + } catch (e) { + logger().error("connections:load error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to load connections", + }, + }); + } + }); + + handle("connections:save", async (_, { send, value }) => { + const { data } = value; + try { + const manager = await setupConnectionsConfigFile(context); + const json = typeof data === "string" ? JSON.parse(data) : data; + await manager.setConfig(json); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error("connections:save error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to save connections", + }, + }); + } + }); + + handle("connections:reset", async (_, { send, value }) => { + const { key } = value; + try { + const manager = await setupConnectionsConfigFile(context); + const currentConfig = await manager.getConfig(); + const defaultValue = (connectionsMigrator.defaultValue as any)[key]; + await manager.setConfig({ + ...(currentConfig ? (currentConfig as any) : {}), + [key]: defaultValue, + } as any); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error("connections:reset error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to reset connections", + }, + }); + } + }); + + // Projects + handle("projects:load", async (_, { send }) => { + logger().info("projects:load"); + try { + const manager = await setupProjectsConfigFile(context); + const json = await manager.getConfig(); + send({ + type: "end", + data: { type: "success", result: json }, + }); + } catch (e) { + logger().error("projects:load error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to load projects", + }, + }); + } + }); + + handle("projects:save", async (_, { send, value }) => { + const { data } = value; + try { + const manager = await setupProjectsConfigFile(context); + const json = typeof data === "string" ? JSON.parse(data) : data; + await manager.setConfig(json); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error("projects:save error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to save projects", + }, + }); + } + }); + + handle("projects:reset", async (_, { send, value }) => { + const { key } = value; + try { + const manager = await setupProjectsConfigFile(context); + const currentConfig = await manager.getConfig(); + const defaultValue = (fileRepoMigrations.defaultValue as any)[key]; + await manager.setConfig({ + ...(currentConfig ? (currentConfig as any) : {}), + [key]: defaultValue, + } as any); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error("projects:reset error:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Unable to reset projects", + }, + }); + } + }); + + // Pipeline (ByName) + handle("pipeline:load-by-name", async (_, { send, value }) => { + const { name } = value; + logger().info("pipeline:load-by-name", name); + try { + const manager = await setupPipelineConfigFileByName(name, context); + const json = await manager.getConfig(); + send({ + type: "end", + data: { type: "success", result: json }, + }); + } catch (e) { + logger().error(`pipeline:load-by-name error for ${name}:`, e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : `Unable to load pipeline ${name}`, + }, + }); + } + }); + + // Pipeline (ByPath) + handle("pipeline:load-by-path", async (_, { send, value }) => { + const { path: absolutePath } = value; + logger().info("pipeline:load-by-path", absolutePath); + try { + const manager = await setupPipelineConfigFileByPath(absolutePath, context); + const json = await manager.getConfig(); + send({ + type: "end", + data: { type: "success", result: json }, + }); + } catch (e) { + logger().error(`pipeline:load-by-path error for ${absolutePath}:`, e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : `Unable to load pipeline ${absolutePath}`, + }, + }); + } + }); + + handle("pipeline:save-by-name", async (_, { send, value }) => { + const { data, name } = value; + try { + const manager = await setupPipelineConfigFileByName(name, context); + const json = typeof data === "string" ? JSON.parse(data) : data; + await manager.setConfig(json); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error(`pipeline:save-by-name error for ${name}:`, e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : `Unable to save pipeline ${name}`, + }, + }); + } + }); + + handle("pipeline:save-by-path", async (_, { send, value }) => { + const { data, path: absolutePath } = value; + try { + const manager = await setupPipelineConfigFileByPath(absolutePath, context); + const json = typeof data === "string" ? JSON.parse(data) : data; + await manager.setConfig(json); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error(`pipeline:save-by-path error for ${absolutePath}:`, e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : `Unable to save pipeline ${absolutePath}`, + }, + }); + } + }); + + handle("pipeline:delete-by-name", async (_, { send, value }) => { + const { name } = value; + logger().info("pipeline:delete-by-name", name); + try { + await deletePipelineConfigFileByName(name, context); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error(`pipeline:delete-by-name error for ${name}:`, e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : `Unable to delete pipeline ${name}`, + }, + }); + } + }); + + handle("pipeline:delete-by-path", async (_, { send, value }) => { + const { path: absolutePath } = value; + logger().info("pipeline:delete-by-path", absolutePath); + try { + await deletePipelineConfigFileByPath(absolutePath, context); + send({ + type: "end", + data: { type: "success", result: "ok" }, + }); + } catch (e) { + logger().error(`pipeline:delete-by-path error for ${absolutePath}:`, e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : `Unable to delete pipeline ${absolutePath}`, + }, + }); + } + }); +}; diff --git a/packages/core-node/src/handlers/engine.ts b/packages/core-node/src/handlers/engine.ts new file mode 100644 index 00000000..4b0d504b --- /dev/null +++ b/packages/core-node/src/handlers/engine.ts @@ -0,0 +1,243 @@ +import { useAPI, HandleListenerSendFn } from "../ipc-core"; +import { PipelabContext, CacheFolder } from "../context"; +import { useLogger } from "@pipelab/shared"; +import { getFinalPlugins, executeGraphWithHistory } from "../utils"; +import { presets } from "../presets/list"; +import { handleActionExecute } from "../handler-func"; +import { join } from "node:path"; +import { rm } from "node:fs/promises"; +import { setupSettingsConfigFile } from "../config"; +import { AppConfig } from "@pipelab/shared"; + +export const registerEngineHandlers = (context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + + handle("nodes:get", async (_, { send }) => { + const finalPlugins = getFinalPlugins(); + send({ + type: "end", + data: { + type: "success", + result: { + nodes: finalPlugins, + }, + }, + }); + }); + + handle("presets:get", async (_, { send }) => { + const presetData = await presets(); + send({ + type: "end", + data: { + type: "success", + result: presetData, + }, + }); + }); + + let abortControllerGraph: undefined | AbortController = undefined; + + const effectiveActionExecute = async ( + nodeId: string, + pluginId: string, + params: Record, + mainWindow: any | undefined, + send: HandleListenerSendFn<"action:execute">, + cwd: string, + cachePath: string, + ) => { + try { + const result = await handleActionExecute( + nodeId, + pluginId, + params, + mainWindow, + send, + abortControllerGraph!.signal, + cwd, + cachePath, + context, + ); + + await send({ + data: result, + type: "end", + }); + } catch (e) { + console.error("Error during action execution:", e); + await send({ + type: "end", + data: { + ipcError: e instanceof Error ? e.message : "Unknown error", + type: "error", + }, + }); + } + }; + + handle("action:execute", async (event, { send, value }) => { + const { nodeId, params, pluginId } = value; + const cachePath = context.getCachePath(CacheFolder.Actions, pluginId, nodeId); + const cwd = await context.createTempFolder("action-execute-"); + + try { + const mainWindow: undefined = undefined; + abortControllerGraph = new AbortController(); + + const signalPromise = new Promise((resolve, reject) => { + abortControllerGraph!.signal.addEventListener("abort", async () => { + await send({ + type: "end", + data: { + ipcError: "Action aborted", + type: "error", + }, + }); + return reject(new Error("Action interrupted")); + }); + }); + + await Promise.race([ + signalPromise, + effectiveActionExecute(nodeId, pluginId, params, mainWindow, send, cwd, cachePath), + ]); + } finally { + await rm(cwd, { recursive: true, force: true }).catch((err) => { + console.warn(`Failed to cleanup temp folder at ${cwd}:`, err); + }); + } + }); + + handle("constants:get", async (_, { send }) => { + const userData = context.userDataPath; + send({ + type: "end", + data: { + type: "success", + result: { + result: { + userData, + }, + }, + }, + }); + }); + + handle("action:cancel", async (_, { send }) => { + if (abortControllerGraph) { + abortControllerGraph.abort("Interrupted by user"); + } + send({ + type: "end", + data: { + type: "success", + result: { + result: "ok", + }, + }, + }); + }); + + handle("graph:execute", async (event, { send, value }) => { + const { graph, variables, projectName, projectPath, pipelineId } = value; + const settings = await setupSettingsConfigFile(context); + const config = await settings.getConfig(); + + const effectiveProjectName = projectName || "Unnamed Project"; + const effectiveProjectPath = projectPath || ""; + const effectivePipelineId = pipelineId || "unknown"; + const effectiveCachePath = context.getCachePath(CacheFolder.Pipelines, effectivePipelineId); + + const mainWindow: undefined = undefined; + abortControllerGraph = new AbortController(); + + try { + const { result, buildId } = await executeGraphWithHistory({ + graph, + variables, + projectName: effectiveProjectName, + projectPath: effectiveProjectPath, + pipelineId: effectivePipelineId, + mainWindow, + onNodeEnter: (node) => { + send({ + type: "node-enter", + data: { + nodeUid: node.uid, + nodeName: node.name, + }, + }); + }, + onNodeExit: (node) => { + send({ + type: "node-exit", + data: { + nodeUid: node.uid, + nodeName: node.name, + }, + }); + }, + onLog: (data, node) => { + if (data.type === "log") { + const sanitizedData = { + message: data.data.message, + timestamp: data.data.time, + }; + send({ + type: "node-log", + data: { + nodeUid: node?.uid || "unknown", + logData: sanitizedData, + }, + }); + } + }, + onArtifact: (name, path, node) => { + send({ + type: "node-artifact", + data: { + nodeUid: node?.uid || "unknown", + artifact: { name, path }, + }, + }); + }, + onArtifactsFinalized: (artifacts) => { + send({ + type: "node-artifacts-finalized", + data: { + artifacts, + }, + }); + }, + abortSignal: abortControllerGraph!.signal, + cachePath: effectiveCachePath, + context, + }); + + send({ + type: "end", + data: { + type: "success", + result: { + result, + buildId, + }, + }, + }); + } catch (e) { + console.error("Graph execution failed:", e); + logger().error("Graph execution failed:", e); + const isCanceled = e instanceof Error && e.name === "AbortError"; + send({ + type: "end", + data: { + type: "error", + code: isCanceled ? "canceled" : "error", + ipcError: e instanceof Error ? e.message : "Unknown error", + }, + }); + } + }); +}; diff --git a/packages/core-node/src/handlers/fs.ts b/packages/core-node/src/handlers/fs.ts new file mode 100644 index 00000000..37fd8ed0 --- /dev/null +++ b/packages/core-node/src/handlers/fs.ts @@ -0,0 +1,122 @@ +import { useAPI } from "../ipc-core"; +import { useLogger } from "@pipelab/shared"; +import { writeFile, readFile, readdir, stat } from "node:fs/promises"; +import { join } from "node:path"; +import { isPathBlacklisted } from "../fs-utils"; + +import { PipelabContext } from "../context"; + +export const registerFsHandlers = (_context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + + handle("fs:read", async (event, { value, send }) => { + logger().info("fs:read", value.path); + + try { + const data = await readFile(value.path, "utf-8"); + logger().info("fs:read success, content length:", data.length); + + send({ + type: "end", + data: { + type: "success", + result: { + content: data, + }, + }, + }); + } catch (e) { + logger().error("fs:read error for path:", value.path, e); + send({ + type: "end", + data: { + type: "error", + ipcError: "Unable to read file", + }, + }); + } + }); + + handle("fs:write", async (event, { value, send }) => { + await writeFile(value.path, value.content, "utf-8"); + + send({ + type: "end", + data: { + type: "success", + result: { + ok: true, + }, + }, + }); + }); + + handle("fs:listDirectory", async (event, { value, send }) => { + try { + const entries = await readdir(value.path, { withFileTypes: true }); + const files = await Promise.all( + entries.map(async (entry) => { + const fullPath = join(value.path, entry.name); + let stats: any = {}; + try { + stats = await stat(fullPath); + } catch (e) { + // Might happen for broken symlinks etc + } + + return { + name: entry.name, + isDirectory: entry.isDirectory(), + isSymbolicLink: entry.isSymbolicLink(), + size: stats.size || 0, + mtime: stats.mtime?.getTime() || 0, + }; + }), + ); + + send({ + type: "end", + data: { + type: "success", + result: { + files, + }, + }, + }); + } catch (error) { + logger().error("Failed to list directory:", error); + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Unable to list directory", + }, + }); + } + }); + + handle("fs:isPathBlacklisted", async (event, { value, send }) => { + try { + const isBlacklisted = isPathBlacklisted(value.path); + send({ + type: "end", + data: { + type: "success", + result: { + isBlacklisted, + }, + }, + }); + } catch (error) { + logger().error("Failed to check blacklist for path:", error); + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Unable to check path blacklist", + }, + }); + } + }); +}; diff --git a/packages/core-node/src/handlers/history.ts b/packages/core-node/src/handlers/history.ts new file mode 100644 index 00000000..4e0f13fe --- /dev/null +++ b/packages/core-node/src/handlers/history.ts @@ -0,0 +1,287 @@ +import { useAPI, WsEvent } from "../ipc-core"; +import { useLogger, AppConfig } from "@pipelab/shared"; +import { BuildHistoryStorage } from "./build-history"; +import { SubscriptionRequiredError } from "@pipelab/shared"; +import { PipelabContext } from "../context"; +import { setupConfigFile } from "../config"; + +// Helper function to check build history authorization +const checkBuildHistoryAuthorization = async (event: WsEvent): Promise => { + const { logger } = useLogger(); + logger().info("AUTH BYPASS: Skipping auth verification for build history access"); + + // Always authorize for now - relying on frontend auth checks only + const isAuthorized = true; + + if (!isAuthorized) { + throw new SubscriptionRequiredError("build-history"); + } + + return true; +}; + +export const registerHistoryHandlers = (context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + const buildHistoryStorage = new BuildHistoryStorage(context); + + // Build History Handlers + handle("build-history:save", async (event, { send, value }) => { + try { + // Check authorization before allowing save + logger().info("AUTH BYPASS: Processing build-history:save request"); + await checkBuildHistoryAuthorization(event); + + await buildHistoryStorage.save(value.entry); + send({ + type: "end", + data: { + type: "success", + result: { result: "ok" }, + }, + }); + } catch (error) { + logger().error("Failed to save build history entry:", error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Failed to save build history entry", + }, + }); + } + }); + + handle("build-history:get", async (event, { send, value }) => { + try { + logger().info("AUTH BYPASS: Processing build-history:get request"); + await checkBuildHistoryAuthorization(event); + + const entry = await buildHistoryStorage.get(value.id, value.pipelineId); + send({ + type: "end", + data: { type: "success", result: { entry } }, + }); + } catch (error) { + logger().error("Failed to get build history entry:", error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Failed to get build history entry", + }, + }); + } + }); + + handle("build-history:get-all", async (event, { send, value }) => { + try { + logger().info("AUTH BYPASS: Processing build-history:get-all request"); + await checkBuildHistoryAuthorization(event); + + const allEntries = await buildHistoryStorage.getAll(); + const filteredEntries = value?.query?.pipelineId + ? allEntries.filter((entry) => entry.pipelineId === value?.query?.pipelineId) + : allEntries; + + send({ + type: "end", + data: { + type: "success", + result: { + entries: filteredEntries, + total: filteredEntries.length, + }, + }, + }); + } catch (error) { + logger().error("Failed to get build history entries:", error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Failed to get build history entries", + }, + }); + } + }); + + handle("build-history:update", async (event, { send, value }) => { + try { + await checkBuildHistoryAuthorization(event); + + await buildHistoryStorage.update(value.id, value.updates, value.pipelineId); + send({ + type: "end", + data: { type: "success", result: { result: "ok" } }, + }); + } catch (error) { + logger().error("Failed to update build history entry:", error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Failed to update build history entry", + }, + }); + } + }); + + handle("build-history:delete", async (event, { send, value }) => { + try { + await checkBuildHistoryAuthorization(event); + + await buildHistoryStorage.delete(value.id, value.pipelineId); + send({ + type: "end", + data: { type: "success", result: { result: "ok" } }, + }); + } catch (error) { + logger().error("Failed to delete build history entry:", error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Failed to delete build history entry", + }, + }); + } + }); + + handle("build-history:clear", async (event, { send }) => { + try { + await checkBuildHistoryAuthorization(event); + + await buildHistoryStorage.clear(); + send({ + type: "end", + data: { type: "success", result: { result: "ok" } }, + }); + } catch (error) { + logger().error("Failed to clear build history:", error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: error instanceof Error ? error.message : "Failed to clear build history", + }, + }); + } + }); + + handle("build-history:clear-by-pipeline", async (event, { send, value }) => { + try { + await checkBuildHistoryAuthorization(event); + + await buildHistoryStorage.clearByPipeline(value.pipelineId); + send({ + type: "end", + data: { type: "success", result: { result: "ok" } }, + }); + } catch (error) { + logger().error(`Failed to clear build history for pipeline ${value.pipelineId}:`, error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: + error instanceof Error ? error.message : "Failed to clear build history for pipeline", + }, + }); + } + }); + + handle("build-history:get-storage-info", async (event, { send }) => { + try { + await checkBuildHistoryAuthorization(event); + + const info = await buildHistoryStorage.getStorageInfo(); + send({ + type: "end", + data: { type: "success", result: info }, + }); + } catch (error) { + logger().error("Failed to get build history storage info:", error); + + if (error instanceof SubscriptionRequiredError) { + send({ + type: "end", + data: { type: "error", ipcError: error.userMessage, code: error.code }, + }); + return; + } + + send({ + type: "end", + data: { + type: "error", + ipcError: + error instanceof Error ? error.message : "Failed to get build history storage info", + }, + }); + } + }); +}; diff --git a/packages/core-node/src/handlers/index.ts b/packages/core-node/src/handlers/index.ts new file mode 100644 index 00000000..33905a17 --- /dev/null +++ b/packages/core-node/src/handlers/index.ts @@ -0,0 +1,50 @@ +import { registerShellHandlers } from "./shell"; +import { registerFsHandlers } from "./fs"; +import { registerConfigHandlers } from "./config"; +import { registerHistoryHandlers } from "./history"; +import { registerEngineHandlers } from "./engine"; +import { registerAgentsHandlers } from "./agents"; +import { registerAuthHandlers } from "./auth"; +import { registerSystemHandlers } from "./system"; +import { registerPluginsHandlers } from "./plugins"; +import { registerMigrationHandlers } from "./migration"; +import { builtInPlugins } from "../plugins-registry"; +import { usePlugins } from "@pipelab/shared"; +import { PipelabContext } from "../context"; + +export const registerAllHandlers = async (options: { + version: string; + context: PipelabContext; + waitForPlugins?: boolean; +}) => { + const context = options.context; + + registerShellHandlers(context); + registerFsHandlers(context); + registerConfigHandlers(context); + registerHistoryHandlers(context); + registerEngineHandlers(context); + registerAgentsHandlers(context); + registerAuthHandlers(context); + registerSystemHandlers(options); + registerPluginsHandlers(context); + registerMigrationHandlers(context); + + const { registerPlugins } = usePlugins(); + // Execute in the background! The plugins will be dynamically registered and broadcasted to the UI. + const pluginsPromise = builtInPlugins({ + context, + }); + + if (options.waitForPlugins) { + await pluginsPromise; + } +}; + +export { registerShellHandlers } from "./shell"; +export { registerFsHandlers } from "./fs"; +export { registerConfigHandlers } from "./config"; +export { registerHistoryHandlers } from "./history"; +export { registerEngineHandlers } from "./engine"; +export { registerAgentsHandlers } from "./agents"; +export { BuildHistoryStorage } from "./build-history"; diff --git a/packages/core-node/src/handlers/migration.ts b/packages/core-node/src/handlers/migration.ts new file mode 100644 index 00000000..a8230877 --- /dev/null +++ b/packages/core-node/src/handlers/migration.ts @@ -0,0 +1,646 @@ +import { useAPI } from "../ipc-core"; +import { useLogger } from "@pipelab/shared"; +import { PipelabContext, getDefaultUserDataPath, isDev, PipelabEnv } from "../context"; +import fs from "node:fs/promises"; +import { existsSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { + FileRepo, + SaveLocation, + AppConfig, + ConnectionsConfig, + savedFileMigrator, +} from "@pipelab/shared"; +import semver from "semver"; + +interface MigrationPipelineItem { + id: string; + name: string; + description: string; + type: "internal" | "external" | "pipelab-cloud"; + lastModifiedStable?: string; + lastModifiedBeta?: string; + existsInBeta: boolean; +} + +interface MigrationProjectItem { + id: string; + name: string; + description: string; + pipelines: MigrationPipelineItem[]; +} + +export const registerMigrationHandlers = (context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + + const getFileMetadata = async (filePath: string) => { + const exists = existsSync(filePath); + let mtime = Date.now(); + let version: string | null = null; + + if (exists) { + try { + const stat = await fs.stat(filePath); + mtime = stat.mtime ? stat.mtime.getTime() : Date.now(); + } catch (e) { + mtime = Date.now(); + } + + try { + const content = await fs.readFile(filePath, "utf8"); + const json = JSON.parse(content); + version = json && typeof json.version === "string" ? json.version : null; + } catch (e) { + // Version remains null + } + } else { + mtime = Date.now(); + } + + return { exists, mtime, version }; + }; + + const isVersionImportable = (sourceVer: string | null, targetVer: string | null): boolean => { + if (!sourceVer) return false; + if (!targetVer) return true; + + try { + const coercedSource = semver.coerce(sourceVer); + const coercedTarget = semver.coerce(targetVer); + if (!coercedSource) return false; + if (!coercedTarget) return true; + return semver.lte(coercedSource, coercedTarget); + } catch { + return sourceVer <= targetVer; + } + }; + + handle("migration:scan-stable", async (_, { send, value }) => { + logger().info("[Migration] Scanning other channel database..."); + try { + let sourceEnv: PipelabEnv = "prod"; + if (value?.sourceChannel === "stable") { + sourceEnv = "prod"; + } else if (value?.sourceChannel === "beta") { + sourceEnv = "beta"; + } else { + const isStable = + context.userDataPath.endsWith("app") || !context.userDataPath.includes("app-beta"); + sourceEnv = isStable ? "beta" : "prod"; + } + const sourcePath = getDefaultUserDataPath(sourceEnv); + const targetPath = context.userDataPath; + + if (sourcePath === targetPath) { + logger().info("[Migration] Running in same channel. Disabling migration scan."); + return send({ + type: "end", + data: { + type: "success", + result: { + sourceChannel: sourceEnv === "prod" ? "Stable" : "Beta", + targetChannel: isDev + ? "Dev" + : context.userDataPath.endsWith("app") || !context.userDataPath.includes("app-beta") + ? "Stable" + : "Beta", + settingsExists: false, + settingsVersion: null, + settingsVersionTarget: null, + settingsMtimeSource: Date.now(), + settingsMtimeTarget: Date.now(), + settingsImportable: false, + connectionsExists: false, + connectionsCount: 0, + connectionsVersion: null, + connectionsVersionTarget: null, + connectionsMtimeSource: Date.now(), + connectionsMtimeTarget: Date.now(), + connectionsImportable: false, + projectsExists: false, + projectsVersion: null, + projectsVersionTarget: null, + projectsMtimeSource: Date.now(), + projectsMtimeTarget: Date.now(), + projectsImportable: false, + projects: [], + }, + }, + }); + } + + const sourceContext = new PipelabContext({ userDataPath: sourcePath, releaseTag: sourceEnv }); + + const sourceSettingsPath = sourceContext.getSettingsPath(); + const targetSettingsPath = context.getSettingsPath(); + + const sourceConnectionsPath = sourceContext.getConnectionsPath(); + const targetConnectionsPath = context.getConnectionsPath(); + + const sourceProjectsPath = sourceContext.getProjectsPath(); + const targetProjectsPath = context.getProjectsPath(); + + const sourceSettingsMeta = await getFileMetadata(sourceSettingsPath); + const targetSettingsMeta = await getFileMetadata(targetSettingsPath); + + const sourceConnectionsMeta = await getFileMetadata(sourceConnectionsPath); + const targetConnectionsMeta = await getFileMetadata(targetConnectionsPath); + + const sourceProjectsMeta = await getFileMetadata(sourceProjectsPath); + const targetProjectsMeta = await getFileMetadata(targetProjectsPath); + + const settingsExists = sourceSettingsMeta.exists; + const settingsVersion = sourceSettingsMeta.version; + const settingsMtimeSource = sourceSettingsMeta.mtime; + const settingsMtimeTarget = targetSettingsMeta.mtime; + const settingsImportable = isVersionImportable(settingsVersion, targetSettingsMeta.version); + + const connectionsExists = sourceConnectionsMeta.exists; + const connectionsVersion = sourceConnectionsMeta.version; + const connectionsMtimeSource = sourceConnectionsMeta.mtime; + const connectionsMtimeTarget = targetConnectionsMeta.mtime; + const connectionsImportable = isVersionImportable( + connectionsVersion, + targetConnectionsMeta.version, + ); + + const projectsExists = sourceProjectsMeta.exists; + const projectsVersion = sourceProjectsMeta.version; + const projectsMtimeSource = sourceProjectsMeta.mtime; + const projectsMtimeTarget = targetProjectsMeta.mtime; + const projectsImportable = isVersionImportable(projectsVersion, targetProjectsMeta.version); + + let connectionsCount = 0; + try { + if (sourceConnectionsMeta.exists) { + const connContent = await fs.readFile(sourceConnectionsPath, "utf8"); + const connJson = JSON.parse(connContent) as ConnectionsConfig; + if (connJson && Array.isArray(connJson.connections)) { + connectionsCount = connJson.connections.length; + } + } + } catch (err) { + logger().error("[Migration] Error parsing source connections.json:", err); + } + + let sourceProjectsList: FileRepo["projects"] = []; + let sourcePipelinesList: SaveLocation[] = []; + try { + if (sourceProjectsMeta.exists) { + const projContent = await fs.readFile(sourceProjectsPath, "utf8"); + const projJson = JSON.parse(projContent) as FileRepo; + sourceProjectsList = projJson.projects || []; + sourcePipelinesList = projJson.pipelines || []; + } + } catch (err) { + logger().error("[Migration] Error parsing source projects.json:", err); + } + + let targetPipelinesList: SaveLocation[] = []; + try { + if (targetProjectsMeta.exists) { + const targetProjContent = await fs.readFile(targetProjectsPath, "utf8"); + const targetProjJson = JSON.parse(targetProjContent) as FileRepo; + targetPipelinesList = targetProjJson.pipelines || []; + } + } catch (err) { + // Safe to ignore if target hasn't initialized projects yet + } + + const projectsReport: MigrationProjectItem[] = []; + for (const proj of sourceProjectsList) { + const projPipelines = sourcePipelinesList.filter((p) => p.project === proj.id); + const pipelinesReport: MigrationPipelineItem[] = []; + + for (const pipe of projPipelines) { + const targetPipe = targetPipelinesList.find((bp) => bp.id === pipe.id); + const existsInBeta = !!targetPipe; + + let pipeName = pipe.id; + let pipeDesc = ""; + if (pipe.type === "internal") { + const sourcePipeFile = sourceContext.getConfigPath(`${pipe.configName}.json`); + try { + if (existsSync(sourcePipeFile)) { + const pipeContent = await fs.readFile(sourcePipeFile, "utf8"); + const rawJson = JSON.parse(pipeContent); + const pipeJson = await savedFileMigrator.migrate(rawJson); + pipeName = pipeJson.name || pipeName; + pipeDesc = pipeJson.description || pipeDesc; + } + } catch (err) { + logger().error( + `[Migration] Error reading source pipeline file ${sourcePipeFile}:`, + err, + ); + } + } else if (pipe.type === "external") { + pipeName = pipe.summary?.name || pipeName; + pipeDesc = pipe.summary?.description || pipeDesc; + } + + pipelinesReport.push({ + id: pipe.id, + name: pipeName, + description: pipeDesc, + type: pipe.type, + lastModifiedStable: pipe.type !== "pipelab-cloud" ? pipe.lastModified : undefined, + lastModifiedBeta: + targetPipe && targetPipe.type !== "pipelab-cloud" + ? targetPipe.lastModified + : undefined, + existsInBeta, + }); + } + + projectsReport.push({ + id: proj.id, + name: proj.name, + description: proj.description || "", + pipelines: pipelinesReport, + }); + } + + send({ + type: "end", + data: { + type: "success", + result: { + sourceChannel: sourceEnv === "prod" ? "Stable" : "Beta", + targetChannel: isDev + ? "Dev" + : context.userDataPath.endsWith("app") || !context.userDataPath.includes("app-beta") + ? "Stable" + : "Beta", + settingsExists, + settingsVersion, + settingsVersionTarget: targetSettingsMeta.version, + settingsMtimeSource, + settingsMtimeTarget, + settingsImportable, + connectionsExists, + connectionsCount, + connectionsVersion, + connectionsVersionTarget: targetConnectionsMeta.version, + connectionsMtimeSource, + connectionsMtimeTarget, + connectionsImportable, + projectsExists, + projectsVersion, + projectsVersionTarget: targetProjectsMeta.version, + projectsMtimeSource, + projectsMtimeTarget, + projectsImportable, + projects: projectsReport, + }, + }, + }); + } catch (e) { + logger().error("[Migration] Error scanning other channel folder:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Failed to scan other channel database", + }, + }); + } + }); + + handle("migration:perform", async (_, { send, value }) => { + logger().info("[Migration] Performing migration..."); + try { + const { + migrateSettings, + migrateConnections, + selectedProjects, + selectedPipelines, + sourceChannel, + } = value; + + let sourceEnv: PipelabEnv = "prod"; + if (sourceChannel === "stable") { + sourceEnv = "prod"; + } else if (sourceChannel === "beta") { + sourceEnv = "beta"; + } else { + const isStable = + context.userDataPath.endsWith("app") || !context.userDataPath.includes("app-beta"); + sourceEnv = isStable ? "beta" : "prod"; + } + const sourcePath = getDefaultUserDataPath(sourceEnv); + const sourceContext = new PipelabContext({ userDataPath: sourcePath, releaseTag: sourceEnv }); + + const sourceConfigDir = sourceContext.getConfigPath(); + const targetConfigDir = context.getConfigPath(); + + // 1. Check folder validity + if (sourcePath === context.userDataPath) { + throw new Error("Cannot migrate data: Source and target directories are identical."); + } + + // 2. Create backup of target's config directory (excluding backups folder itself) + if (existsSync(targetConfigDir)) { + const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); + const backupDir = context.getConfigPath("backups", `backup_${timestamp}`); + await fs.mkdir(backupDir, { recursive: true }); + + const entries = await fs.readdir(targetConfigDir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.name === "backups") continue; + const srcPath = join(targetConfigDir, entry.name); + const destPath = join(backupDir, entry.name); + try { + await fs.cp(srcPath, destPath, { recursive: true }); + } catch (copyErr) { + logger().error(`[Migration] Failed to backup ${entry.name}:`, copyErr); + } + } + logger().info(`[Migration] Config backup successfully created at ${backupDir}`); + } + + // 3. Settings migration (Merge) + if (migrateSettings) { + const sourceSettingsFile = sourceContext.getSettingsPath(); + const targetSettingsFile = context.getSettingsPath(); + + const sourceMeta = await getFileMetadata(sourceSettingsFile); + const targetMeta = await getFileMetadata(targetSettingsFile); + if (!isVersionImportable(sourceMeta.version, targetMeta.version)) { + throw new Error("Cannot migrate settings: Source version is newer than current version."); + } + + if (existsSync(sourceSettingsFile)) { + let stableSettings: AppConfig = { + version: "7.0.0", + locale: "en-US", + theme: "light", + autosave: true, + agents: [], + plugins: [], + tours: { + dashboard: { step: 0, completed: false }, + editor: { step: 0, completed: false }, + }, + }; + try { + const stableContent = await fs.readFile(sourceSettingsFile, "utf8"); + stableSettings = JSON.parse(stableContent) as AppConfig; + } catch (e) { + logger().error("[Migration] Failed to read source settings.json:", e); + } + + let betaSettings: AppConfig = { + version: "7.0.0", + locale: "en-US", + theme: "light", + autosave: true, + agents: [], + plugins: [], + tours: { + dashboard: { step: 0, completed: false }, + editor: { step: 0, completed: false }, + }, + }; + if (existsSync(targetSettingsFile)) { + try { + const betaContent = await fs.readFile(targetSettingsFile, "utf8"); + betaSettings = JSON.parse(betaContent) as AppConfig; + } catch (e) { + // Keep default + } + } + + // Merge primitives + betaSettings.theme = stableSettings.theme ?? betaSettings.theme; + betaSettings.locale = stableSettings.locale ?? betaSettings.locale; + betaSettings.autosave = stableSettings.autosave ?? betaSettings.autosave; + + // Merge tours + if (stableSettings.tours) { + betaSettings.tours = betaSettings.tours || { + dashboard: { step: 0, completed: false }, + editor: { step: 0, completed: false }, + }; + if (stableSettings.tours.dashboard) { + betaSettings.tours.dashboard = stableSettings.tours.dashboard; + } + if (stableSettings.tours.editor) { + betaSettings.tours.editor = stableSettings.tours.editor; + } + } + + // Merge agents (by id) + const betaAgents = betaSettings.agents || []; + const stableAgents = stableSettings.agents || []; + for (const sAgent of stableAgents) { + const existingIdx = betaAgents.findIndex((a) => a.id === sAgent.id); + if (existingIdx >= 0) { + betaAgents[existingIdx] = { ...sAgent }; + } else { + betaAgents.push({ ...sAgent }); + } + } + betaSettings.agents = betaAgents; + + // Merge plugins (by name) + const betaPlugins = betaSettings.plugins || []; + const stablePlugins = stableSettings.plugins || []; + for (const sPlugin of stablePlugins) { + const existingIdx = betaPlugins.findIndex((p) => p.name === sPlugin.name); + if (existingIdx >= 0) { + betaPlugins[existingIdx] = { ...sPlugin }; + } else { + betaPlugins.push({ ...sPlugin }); + } + } + betaSettings.plugins = betaPlugins; + + await fs.mkdir(dirname(targetSettingsFile), { recursive: true }); + await fs.writeFile(targetSettingsFile, JSON.stringify(betaSettings, null, 2)); + logger().info("[Migration] Settings merged successfully"); + } + } + + // 4. Connections migration (Merge) + if (migrateConnections) { + const sourceConnectionsFile = sourceContext.getConnectionsPath(); + const targetConnectionsFile = context.getConnectionsPath(); + + const sourceMeta = await getFileMetadata(sourceConnectionsFile); + const targetMeta = await getFileMetadata(targetConnectionsFile); + if (!isVersionImportable(sourceMeta.version, targetMeta.version)) { + throw new Error( + "Cannot migrate connections: Source version is newer than current version.", + ); + } + + if (existsSync(sourceConnectionsFile)) { + let stableConnections: ConnectionsConfig = { version: "1.0.0", connections: [] }; + try { + const stableContent = await fs.readFile(sourceConnectionsFile, "utf8"); + stableConnections = JSON.parse(stableContent) as ConnectionsConfig; + } catch (e) { + logger().error("[Migration] Failed to read source connections.json:", e); + } + + let betaConnections: ConnectionsConfig = { version: "1.0.0", connections: [] }; + if (existsSync(targetConnectionsFile)) { + try { + const betaContent = await fs.readFile(targetConnectionsFile, "utf8"); + betaConnections = JSON.parse(betaContent) as ConnectionsConfig; + } catch (e) { + // Keep default + } + } + + betaConnections.connections = betaConnections.connections || []; + stableConnections.connections = stableConnections.connections || []; + + for (const sConn of stableConnections.connections) { + const existingIdx = betaConnections.connections.findIndex((c) => c.id === sConn.id); + if (existingIdx >= 0) { + betaConnections.connections[existingIdx] = { ...sConn }; + } else { + betaConnections.connections.push({ ...sConn }); + } + } + + await fs.mkdir(dirname(targetConnectionsFile), { recursive: true }); + await fs.writeFile(targetConnectionsFile, JSON.stringify(betaConnections, null, 2)); + logger().info("[Migration] Connections merged successfully"); + } + } + + // 5. Projects and Pipelines migration + if (selectedPipelines.length > 0 || selectedProjects.length > 0) { + const sourceProjectsFile = sourceContext.getProjectsPath(); + const targetProjectsFile = context.getProjectsPath(); + + const sourceMeta = await getFileMetadata(sourceProjectsFile); + const targetMeta = await getFileMetadata(targetProjectsFile); + if (!isVersionImportable(sourceMeta.version, targetMeta.version)) { + throw new Error("Cannot migrate projects: Source version is newer than current version."); + } + + // Read source projects + let stableFileRepo: FileRepo = { version: "3.0.0", projects: [], pipelines: [] }; + if (existsSync(sourceProjectsFile)) { + const stableContent = await fs.readFile(sourceProjectsFile, "utf8"); + stableFileRepo = JSON.parse(stableContent) as FileRepo; + } + + // Read or initialize current target projects + let betaFileRepo: FileRepo = { version: "3.0.0", projects: [], pipelines: [] }; + if (existsSync(targetProjectsFile)) { + try { + const betaContent = await fs.readFile(targetProjectsFile, "utf8"); + betaFileRepo = JSON.parse(betaContent) as FileRepo; + } catch (readErr) { + logger().warn( + "[Migration] Failed to parse existing target projects.json, starting fresh:", + readErr, + ); + } + } + + betaFileRepo.projects = betaFileRepo.projects || []; + betaFileRepo.pipelines = betaFileRepo.pipelines || []; + + // Copy selected projects metadata + for (const projId of selectedProjects) { + const stableProj = stableFileRepo.projects.find((p) => p.id === projId); + if (stableProj) { + const existingProjIdx = betaFileRepo.projects.findIndex((p) => p.id === projId); + if (existingProjIdx >= 0) { + betaFileRepo.projects[existingProjIdx] = { ...stableProj }; + } else { + betaFileRepo.projects.push({ ...stableProj }); + } + } + } + + // Copy selected pipelines metadata and copy the pipeline config files + for (const pipeId of selectedPipelines) { + const stablePipe = (stableFileRepo.pipelines || []).find((p) => p.id === pipeId); + if (stablePipe) { + // Ensure the parent project metadata exists in target + const parentProjId = stablePipe.project; + const projectExists = betaFileRepo.projects.some((p) => p.id === parentProjId); + if (!projectExists) { + const stableProj = stableFileRepo.projects.find((p) => p.id === parentProjId); + if (stableProj) { + betaFileRepo.projects.push({ ...stableProj }); + } + } + + // Copy and migrate pipeline file if internal + if (stablePipe.type === "internal") { + const stablePipeFile = sourceContext.getConfigPath(`${stablePipe.configName}.json`); + const betaPipeFile = context.getConfigPath(`${stablePipe.configName}.json`); + if (existsSync(stablePipeFile)) { + await fs.mkdir(dirname(betaPipeFile), { recursive: true }); + try { + const pipeContent = await fs.readFile(stablePipeFile, "utf8"); + const rawJson = JSON.parse(pipeContent); + const migratedJson = await savedFileMigrator.migrate(rawJson); + await fs.writeFile(betaPipeFile, JSON.stringify(migratedJson, null, 2)); + logger().info( + `[Migration] Migrated and copied pipeline file: ${stablePipe.configName}`, + ); + } catch (err) { + await fs.copyFile(stablePipeFile, betaPipeFile); + logger().error( + `[Migration] Error migrating during copy of ${stablePipe.configName}, fallback to direct copy:`, + err, + ); + } + } + } + + // Create updated pipeline metadata with modification date set to now timestamp + const updatedPipe = { + ...stablePipe, + }; + if (updatedPipe.type !== "pipelab-cloud") { + (updatedPipe as any).lastModified = new Date().toISOString(); + } + + // Update target projects.json + const existingPipeIdx = betaFileRepo.pipelines.findIndex((p) => p.id === pipeId); + if (existingPipeIdx >= 0) { + betaFileRepo.pipelines[existingPipeIdx] = updatedPipe; + } else { + betaFileRepo.pipelines.push(updatedPipe); + } + } + } + + // Save projects.json + await fs.mkdir(dirname(targetProjectsFile), { recursive: true }); + await fs.writeFile(targetProjectsFile, JSON.stringify(betaFileRepo, null, 2)); + logger().info("[Migration] Merged and saved projects.json successfully"); + } + + send({ + type: "end", + data: { + type: "success", + result: { + result: "ok", + }, + }, + }); + } catch (e) { + logger().error("[Migration] Error performing migration:", e); + send({ + type: "end", + data: { + type: "error", + ipcError: e instanceof Error ? e.message : "Failed to migrate selected data", + }, + }); + } + }); +}; diff --git a/packages/core-node/src/handlers/plugins.ts b/packages/core-node/src/handlers/plugins.ts new file mode 100644 index 00000000..28e2d14a --- /dev/null +++ b/packages/core-node/src/handlers/plugins.ts @@ -0,0 +1,282 @@ +import { useAPI } from "../ipc-core"; +import { PipelabContext, isDev, projectRoot } from "../context"; +import pacote from "pacote"; +import { rm } from "node:fs/promises"; +import { existsSync, readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import { usePlugins } from "@pipelab/shared"; +import { webSocketServer } from "../websocket-server"; +import { fetchPipelabPlugin } from "../utils/remote"; +import { loadCustomPlugin, findInstalledPlugins } from "../plugins-registry"; + +// Maps workspace plugin package names (e.g. "@pipelab/plugin-steam") to their physical directory paths. +// This is populated at startup in dev mode, supporting plugin folders whose directory names +// differ from their actual package.json name. +const localPluginsMap = new Map(); + +if (isDev && projectRoot) { + const pluginsDir = join(projectRoot, "plugins"); + if (existsSync(pluginsDir)) { + try { + const entries = readdirSync(pluginsDir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const pkgPath = join(pluginsDir, entry.name, "package.json"); + if (existsSync(pkgPath)) { + try { + const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")); + if (pkg.name) { + localPluginsMap.set(pkg.name, join(pluginsDir, entry.name)); + } + } catch (e) { + console.error(`[Plugins] Failed to parse package.json for ${entry.name}:`, e); + } + } + } + } + } catch (e) { + console.error(`[Plugins] Failed to scan local workspace plugins directory:`, e); + } + } +} + +/** + * Resolves a requested plugin version. + * If the plugin is present in the local workspace map during development, + * its version is overridden to "local" so Pipelab loads it from the source files. + */ +export function resolvePluginVersion(packageName: string, requestedVersion?: string): string { + if ( + isDev && + projectRoot && + process.env.PIPELAB_FORCE_NPM !== "true" && + localPluginsMap.has(packageName) + ) { + return "local"; + } + return requestedVersion || "latest"; +} + +export const registerPluginsHandlers = (context: PipelabContext) => { + const { handle } = useAPI(); + + handle("plugin:search", async (_, { send, value }) => { + try { + const query = value.query || ""; + const text = query ? `${query} keywords:pipelab-plugin` : "keywords:pipelab-plugin"; + const url = `https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(text)}&size=50`; + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`NPM registry search failed with status ${response.status}`); + } + + const data = await response.json(); + const results = (data.objects || []).map((obj: any) => ({ + name: obj.package.name, + version: obj.package.version, + description: obj.package.description, + keywords: obj.package.keywords, + date: obj.package.date, + })); + + send({ + type: "end", + data: { + type: "success", + result: { results }, + }, + }); + } catch (e: any) { + send({ + type: "end", + data: { + type: "error", + ipcError: e.message || "Failed to search npm registry", + }, + }); + } + }); + + handle("plugin:get-details", async (_, { send, value }) => { + try { + const { packageName } = value; + const packument = await pacote.packument(packageName, { fullMetadata: true }); + const latestVersion = + packument["dist-tags"]?.latest || Object.keys(packument.versions).pop() || "0.0.0"; + const latestPkg = packument.versions[latestVersion]; + + send({ + type: "end", + data: { + type: "success", + result: { + name: packument.name, + latestVersion, + versions: Object.keys(packument.versions).reverse(), + description: latestPkg?.description, + }, + }, + }); + } catch (e: any) { + send({ + type: "end", + data: { + type: "error", + ipcError: e.message || "Failed to get plugin details", + }, + }); + } + }); + + handle("plugin:install", async (_, { send, value }) => { + try { + const { packageName, version } = value; + const mappedVersion = resolvePluginVersion(packageName, version); + console.log(`[Plugins] Installing ${packageName}@${mappedVersion}...`); + + const { packageDir } = await fetchPipelabPlugin(packageName, mappedVersion, { + context, + installDeps: false, + }); + + const plugin = await loadCustomPlugin(packageName, mappedVersion, { context }); + if (!plugin) { + throw new Error("Failed to load installed plugin module."); + } + + const { registerPlugins } = usePlugins(); + registerPlugins([plugin]); + + webSocketServer.broadcast("plugin:loaded", { plugin }); + + send({ + type: "end", + data: { + type: "success", + result: { result: "ok" }, + }, + }); + } catch (e: any) { + console.error(`[Plugins] Installation failed for ${value.packageName}:`, e); + send({ + type: "end", + data: { + type: "error", + ipcError: e.message || "Failed to install plugin", + }, + }); + } + }); + + handle("plugin:uninstall", async (_, { send, value }) => { + try { + const { packageName } = value; + console.log(`[Plugins] Uninstalling plugin ${packageName}...`); + const targetDir = context.getPackagesPath(packageName); + + if (existsSync(targetDir)) { + await rm(targetDir, { recursive: true, force: true }); + } + + send({ + type: "end", + data: { + type: "success", + result: { result: "ok" }, + }, + }); + } catch (e: any) { + send({ + type: "end", + data: { + type: "error", + ipcError: e.message || "Failed to uninstall plugin", + }, + }); + } + }); + + handle("plugin:list-installed", async (_, { send }) => { + try { + const packagesDir = context.getPackagesPath(); + const rawInstalled = await findInstalledPlugins(packagesDir); + + const { DEFAULT_PLUGIN_IDS, DEV_ONLY_PLUGIN_IDS } = await import("@pipelab/shared"); + const defaultPluginIds = [...DEFAULT_PLUGIN_IDS]; + + if (isDev) { + defaultPluginIds.push(...DEV_ONLY_PLUGIN_IDS); + } + + const installed = rawInstalled + .filter((item) => { + const isDefault = defaultPluginIds.some((id) => item.name === `@pipelab/plugin-${id}`); + return !isDefault; + }) + .map((item) => ({ + name: item.name, + version: item.version, + description: item.description, + })); + + send({ + type: "end", + data: { + type: "success", + result: { installed }, + }, + }); + } catch (e: any) { + send({ + type: "end", + data: { + type: "error", + ipcError: e.message || "Failed to list installed plugins", + }, + }); + } + }); + + // Ensures all required plugin IDs are loaded, JIT-installing any that are missing. + // Called before opening a pipeline in the editor. + handle("plugin:ensure-loaded", async (_, { send, value }) => { + const { plugins } = value; + const { plugins: registeredPlugins, registerPlugins } = usePlugins(); + const loaded: string[] = []; + const failed: string[] = []; + + const pluginsToEnsure = new Set(); + if (plugins && typeof plugins === "object") { + for (const id of Object.keys(plugins)) { + if (id) pluginsToEnsure.add(id); + } + } + + for (const packageName of pluginsToEnsure) { + const mappedVersion = resolvePluginVersion(packageName); + + const isRegistered = registeredPlugins.value.some((p) => { + if (p.packageName !== packageName) return false; + if (mappedVersion === "latest") return true; + return p.version === mappedVersion; + }); + + if (isRegistered) { + loaded.push(packageName); + continue; + } + + console.warn(`[Plugins] Plugin "${packageName}" is required but not loaded at startup.`); + failed.push(packageName); + } + + send({ + type: "end", + data: { + type: "success", + result: { loaded, failed }, + }, + }); + }); +}; diff --git a/packages/core-node/src/handlers/shell.ts b/packages/core-node/src/handlers/shell.ts new file mode 100644 index 00000000..2fd81e9f --- /dev/null +++ b/packages/core-node/src/handlers/shell.ts @@ -0,0 +1,57 @@ +import { useAPI } from "../ipc-core"; +import { useLogger } from "@pipelab/shared"; +import { PipelabContext } from "../context"; +import { homedir } from "node:os"; + +export const registerShellHandlers = (_context: PipelabContext) => { + const { handle } = useAPI(); + const { logger } = useLogger(); + + handle("dialog:showOpenDialog", async (event, { value, send }) => { + logger().info("value", value); + logger().info("dialog:showOpenDialog"); + + // Since we are in a standalone server, we cannot show Electron dialogs. + // In the future, this could be handled by the UI or a separate GUI process. + send({ + type: "end", + data: { + type: "success", + result: { + filePaths: [], + canceled: true, + }, + }, + }); + }); + + handle("dialog:showSaveDialog", async (event, { value, send }) => { + const { logger } = useLogger(); + + logger().info("value", value); + logger().info("dialog:showSaveDialog"); + + send({ + type: "end", + data: { + type: "success", + result: { + filePath: undefined, + canceled: true, + }, + }, + }); + }); + + handle("fs:getHomeDirectory", async (event, { send }) => { + send({ + type: "end", + data: { + type: "success", + result: { + path: homedir(), + }, + }, + }); + }); +}; diff --git a/packages/core-node/src/handlers/system.ts b/packages/core-node/src/handlers/system.ts new file mode 100644 index 00000000..d6bbfeca --- /dev/null +++ b/packages/core-node/src/handlers/system.ts @@ -0,0 +1,49 @@ +import { useAPI } from "../ipc-core"; +import { PipelabContext, isDev } from "../context"; + +export const registerSystemHandlers = (options: { version: string; context: PipelabContext }) => { + const { handle } = useAPI(); + + handle("agent:version:get", async (_, { send }) => { + const isStable = + options.context.userDataPath.endsWith("app") || + !options.context.userDataPath.includes("app-beta"); + + send({ + type: "end", + data: { + type: "success", + result: { + version: isDev ? "workspace" : options.version, + channel: isDev ? "dev" : isStable ? "stable" : "beta", + }, + }, + }); + }); + + handle("system:packages:cleanup", async (_, { send }) => { + try { + const packagesDir = options.context.getPackagesPath(); + const { existsSync } = await import("fs"); + const { rm } = await import("fs/promises"); + if (existsSync(packagesDir)) { + await rm(packagesDir, { recursive: true, force: true }); + } + send({ + type: "end", + data: { + type: "success", + result: true, + }, + }); + } catch (e: any) { + send({ + type: "end", + data: { + type: "error", + ipcError: e.message, + }, + }); + } + }); +}; diff --git a/packages/core-node/src/heavy.ts b/packages/core-node/src/heavy.ts new file mode 100644 index 00000000..6a688453 --- /dev/null +++ b/packages/core-node/src/heavy.ts @@ -0,0 +1,4 @@ +export * from "./websocket-server"; +export * from "./handler-func"; +export * from "./utils"; +export * from "./handlers/index"; diff --git a/packages/core-node/src/index.ts b/packages/core-node/src/index.ts new file mode 100644 index 00000000..ced45985 --- /dev/null +++ b/packages/core-node/src/index.ts @@ -0,0 +1,25 @@ +export * from "./context"; +export * from "./websocket-server"; +export * from "./ipc-core"; +export * from "./handlers/index"; +export { + setupSettingsConfigFile, + setupConnectionsConfigFile, + setupProjectsConfigFile, + setupPipelineConfigFileByName, + setupPipelineConfigFileByPath, + deletePipelineConfigFileByName, + deletePipelineConfigFileByPath, +} from "./config"; +export * from "./paths"; +export * from "./api"; +export * from "./heavy"; +export * from "./plugins-registry"; +export * from "./utils/remote"; +export * from "./utils/fs-extras"; +export * from "./types/runner"; +export * from "./runner"; +export * from "./server"; +export * from "./utils"; +export * from "./utils/github"; +export * from "./fs-utils"; diff --git a/packages/core-node/src/ipc-core.ts b/packages/core-node/src/ipc-core.ts new file mode 100644 index 00000000..bc34a7a5 --- /dev/null +++ b/packages/core-node/src/ipc-core.ts @@ -0,0 +1,77 @@ +import { Channels, IpcMessage } from "@pipelab/shared"; +import { WebSocket as WSWebSocket } from "ws"; +import { useLogger } from "@pipelab/shared"; +import { WebSocketEvent, WebSocketHandler, WebSocketSendFunction } from "@pipelab/shared"; + +export type HandleListenerSendFn = WebSocketSendFunction; + +export type WsEvent = WebSocketEvent; + +export type HandleListener = WebSocketHandler; + +const handlers: Record> = {}; + +export const useAPI = () => { + const { logger } = useLogger(); + + const handle = (channel: KEY, listener: WebSocketHandler) => { + handlers[channel] = listener; + + return { + channel, + listener, + }; + }; + + const processWebSocketMessage = (ws: WSWebSocket, channel: string, message: IpcMessage) => { + const { data, requestId } = message; + + if (handlers[channel]) { + logger().debug("Executing handler for channel:", channel, "with data:", JSON.stringify(data)); + const event: WsEvent = { + sender: ws.url || "websocket-client", + }; + + const send: HandleListenerSendFn = (events) => { + const serialized = JSON.stringify(events); + logger().debug( + "sending response to", + requestId, + ":", + serialized.length > 500 ? serialized.substring(0, 500) + "..." : serialized, + ); + const response = { + type: "response", + requestId, + events, + }; + + if (ws.readyState === WSWebSocket.OPEN) { + ws.send(JSON.stringify(response), (error) => { + if (error) { + logger().error("Failed to send WebSocket response:", error); + } + }); + } else { + logger().debug( + `Cannot send response to ${requestId}: WebSocket is not open (state: ${ws.readyState})`, + ); + } + return Promise.resolve(); + }; + + return handlers[channel](event, { + send, + value: data, + }); + } else { + logger().warn("No handler found for channel:", channel); + } + }; + + return { + handle, + processWebSocketMessage, + handlers, + }; +}; diff --git a/packages/core-node/src/paths.ts b/packages/core-node/src/paths.ts new file mode 100644 index 00000000..2edd280c --- /dev/null +++ b/packages/core-node/src/paths.ts @@ -0,0 +1 @@ +export * from "./context"; diff --git a/packages/core-node/src/plugins-registry.ts b/packages/core-node/src/plugins-registry.ts new file mode 100644 index 00000000..69beb639 --- /dev/null +++ b/packages/core-node/src/plugins-registry.ts @@ -0,0 +1,321 @@ +import { ensureNodeJS, ensurePNPM, fetchPipelabPlugin } from "./utils/remote"; +import { pathToFileURL } from "node:url"; +import { readdir, readFile } from "node:fs/promises"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { PipelabContext, isDev, projectRoot } from "./context"; +import { sendStartupProgress } from "./server"; + +const enhancePluginDefinition = async ( + plugin: any, + packageDir: string, + fallbackName: string, + fallbackVersion: string, +) => { + if (!plugin) return plugin; + + let packageName = fallbackName; + let version = fallbackVersion; + let pipelabMeta: any = null; + let pkgDescription = ""; + + try { + const pkgJsonPath = join(packageDir, "package.json"); + if (existsSync(pkgJsonPath)) { + const pkgContent = await readFile(pkgJsonPath, "utf8"); + const pkg = JSON.parse(pkgContent); + if (pkg.name) packageName = pkg.name; + if (pkg.version) version = pkg.version; + if (pkg.description) pkgDescription = pkg.description; + if (pkg.pipelab) pipelabMeta = pkg.pipelab; + } + } catch (e) { + console.error(`[Plugins] Failed to read package.json in ${packageDir}:`, e); + } + + plugin.packageName = packageName; + plugin.id = packageName; + plugin.version = fallbackVersion === "local" ? "local" : version; + plugin.isOfficial = packageName.startsWith("@pipelab/"); + + // Dynamically resolve name, description, and icon from package.json + plugin.name = pipelabMeta?.name || packageName; + plugin.description = pipelabMeta?.description || pkgDescription || ""; + + if (pipelabMeta?.icon) { + if (typeof pipelabMeta.icon === "string") { + let iconPath = pipelabMeta.icon; + if (iconPath.startsWith(".")) { + iconPath = pathToFileURL(join(packageDir, iconPath)).href; + } + plugin.icon = { + type: "image", + image: iconPath, + }; + } else { + plugin.icon = pipelabMeta.icon; + } + } else { + plugin.icon = { + type: "icon", + icon: "pi pi-box", + }; + } + + return plugin; +}; + +export const loadPipelabPlugin = async (id: string, options: { context: PipelabContext }) => { + const start = Date.now(); + try { + const packageName = id; + const fetchStart = Date.now(); + const { packageDir, entryPoint } = await fetchPipelabPlugin( + packageName, + options.context.releaseTag, + { + context: options.context, + installDeps: false, + }, + ); + const fetchDuration = Date.now() - fetchStart; + + console.debug(`[Plugins] [${id}] Attempting to import from: ${entryPoint}`); + if (!existsSync(entryPoint)) { + console.error(`[Plugins] [${id}] CRITICAL: Plugin entry point not found at ${entryPoint}`); + try { + const files = await readdir(packageDir, { recursive: true }); + console.debug(`[Plugins] [${id}] Directory contents:`, files); + } catch (e) {} + } + + const importStart = Date.now(); + const pluginModule = await import(pathToFileURL(entryPoint).href); + const importDuration = Date.now() - importStart; + const totalDuration = Date.now() - start; + console.debug(`[Plugins] [${id}] Successfully loaded from: ${packageDir} (fetch: ${fetchDuration}ms, import: ${importDuration}ms, total: ${totalDuration}ms)`, + ); + + const plugin = pluginModule.default; + await enhancePluginDefinition(plugin, packageDir, packageName, options.context.releaseTag); + return plugin; + } catch (e: any) { + console.error(`[Plugins] [${id}] CRITICAL: Failed to load after ${Date.now() - start}ms:`, e); + if (e.code === "ERR_MODULE_NOT_FOUND") { + console.error( + `[Plugins] [${id}] This usually means a dependency is missing in the plugin's node_modules.`, + ); + } + return null; + } +}; + +export const loadCustomPlugin = async ( + packageName: string, + version: string, + options: { context: PipelabContext }, +) => { + const start = Date.now(); + try { + const fetchStart = Date.now(); + const { packageDir, entryPoint } = await fetchPipelabPlugin(packageName, version, { + context: options.context, + installDeps: false, + }); + const fetchDuration = Date.now() - fetchStart; + + console.debug(`[Plugins] [${packageName}] Attempting to import custom plugin from: ${entryPoint}`, + ); + if (!existsSync(entryPoint)) { + console.error( + `[Plugins] [${packageName}] CRITICAL: Plugin entry point not found at ${entryPoint}`, + ); + return null; + } + + const importStart = Date.now(); + const pluginModule = await import(pathToFileURL(entryPoint).href); + const importDuration = Date.now() - importStart; + const totalDuration = Date.now() - start; + console.debug(`[Plugins] [${packageName}] Successfully loaded custom plugin from: ${packageDir} (fetch: ${fetchDuration}ms, import: ${importDuration}ms, total: ${totalDuration}ms)`, + ); + + const plugin = pluginModule.default; + await enhancePluginDefinition(plugin, packageDir, packageName, version); + return plugin; + } catch (e: any) { + console.error( + `[Plugins] [${packageName}] CRITICAL: Failed to load after ${Date.now() - start}ms:`, + e, + ); + return null; + } +}; + +export async function findInstalledPlugins( + packagesDir: string, +): Promise> { + const installed: Array<{ + name: string; + version: string; + packageDir: string; + description: string; + }> = []; + if (!existsSync(packagesDir)) return installed; + + async function scan(dir: string, depth = 0) { + if (depth > 4) return; + try { + const entries = await readdir(dir, { withFileTypes: true }); + const hasPkgJson = entries.some((e) => e.isFile() && e.name === "package.json"); + if (hasPkgJson) { + try { + const content = await readFile(join(dir, "package.json"), "utf8"); + const pkg = JSON.parse(content); + if ( + pkg.name && + pkg.name !== "pnpm" && + (pkg.pipelab || (pkg.keywords && pkg.keywords.includes("pipelab-plugin"))) + ) { + installed.push({ + name: pkg.name, + version: pkg.version || "0.0.0", + packageDir: dir, + description: pkg.description || "", + }); + } + } catch (e) { + // ignore invalid package.json + } + return; + } + + for (const entry of entries) { + if (entry.isDirectory() && entry.name !== "node_modules" && !entry.name.startsWith(".")) { + await scan(join(dir, entry.name), depth + 1); + } + } + } catch (e) { + // ignore errors + } + } + + await scan(packagesDir); + return installed; +} + +export const builtInPlugins = async (options: { context: PipelabContext }): Promise => { + console.debug("[Plugins] Starting background plugin loading..."); + + // Pre-ensure Node.js and PNPM once in parallel so plugins don't have to wait for them + sendStartupProgress("Preparing environment..."); + const envStart = Date.now(); + await Promise.all([ensureNodeJS(options.context), ensurePNPM(options.context)]); + console.debug(`[Plugins] Environment preparation took ${Date.now() - envStart}ms`); + + const { usePlugins } = await import("@pipelab/shared"); + const { registerPlugins } = usePlugins(); + const { webSocketServer } = await import("./index"); + + // Broadcast ready signal immediately so the UI launches while plugins load in the background + webSocketServer.broadcast("startup:progress", { type: "ready" }); + + // Load plugins asynchronously in the background + return (async () => { + const totalStart = Date.now(); + const pluginsToLoad = new Map(); // packageName -> version + + // Load default/native plugins by default + const { DEFAULT_PLUGIN_IDS, DEV_ONLY_PLUGIN_IDS } = await import("@pipelab/shared"); + const defaultPlugins = [...DEFAULT_PLUGIN_IDS].map((id) => `@pipelab/plugin-${id}`); + + if (isDev) { + defaultPlugins.push(...DEV_ONLY_PLUGIN_IDS.map((id) => `@pipelab/plugin-${id}`)); + } + for (const name of defaultPlugins) { + pluginsToLoad.set(name, "latest"); + } + + if (isDev && projectRoot) { + const pluginsDir = join(projectRoot, "plugins"); + if (existsSync(pluginsDir)) { + try { + const entries = await readdir(pluginsDir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const pkgPath = join(pluginsDir, entry.name, "package.json"); + if (existsSync(pkgPath)) { + try { + const pkgContent = await readFile(pkgPath, "utf-8"); + const pkg = JSON.parse(pkgContent); + if ( + pkg.name && + pkg.name.startsWith("@pipelab/plugin-") && + pkg.name !== "@pipelab/plugin-core" + ) { + pluginsToLoad.set(pkg.name, "local"); + } + } catch (e) { + console.error(`[Plugins] Failed to parse package.json for ${entry.name}:`, e); + } + } + } + } + } catch (e) { + console.error(`[Plugins] Failed to scan local workspace plugins directory:`, e); + } + } + } + + try { + const { setupSettingsConfigFile } = await import("./config"); + const settingsManager = await setupSettingsConfigFile(options.context); + const settingsConfig = await settingsManager.getConfig(); + const settingsPlugins = settingsConfig?.plugins || []; + + for (const plugin of settingsPlugins) { + if (plugin.name) { + if (plugin.enabled) { + if (!pluginsToLoad.has(plugin.name)) { + pluginsToLoad.set(plugin.name, "latest"); + } + } else { + // If explicitly disabled in settings, remove it from the loading list + pluginsToLoad.delete(plugin.name); + } + } + } + } catch (e) { + console.error(`[Plugins] Failed to load settings config on startup:`, e); + } + + const pluginList = Array.from(pluginsToLoad.keys()) + .map((p) => ` - ${p}`) + .join("\n"); + console.log(`\n[Plugins] Loading plugins in background:\n${pluginList}\n`); + + // Now load all collected plugins in parallel + const loadPromises = Array.from(pluginsToLoad.entries()).map(async ([packageName, version]) => { + sendStartupProgress(`Loading plugin: ${packageName}`); + const pluginStart = Date.now(); + try { + const plugin = await loadCustomPlugin(packageName, version, options); + if (plugin) { + registerPlugins([plugin]); + webSocketServer.broadcast("plugin:loaded", { plugin }); + console.debug(`[Plugins] Loaded ${packageName}@${version} in ${Date.now() - pluginStart}ms`, + ); + } + } catch (err) { + console.error(`[Plugins] Failed to load plugin ${packageName} at startup:`, err); + } + }); + await Promise.all(loadPromises); + + console.log(`\n[Plugins] All startup plugins loaded in ${Date.now() - totalStart}ms.\n`); + sendStartupProgress("All plugins loaded."); + setTimeout(() => { + webSocketServer.broadcast("startup:progress", { type: "done" }); + }, 2000); + })(); +}; diff --git a/packages/core-node/src/presets/c3toSteam.ts b/packages/core-node/src/presets/c3toSteam.ts new file mode 100644 index 00000000..826572d5 --- /dev/null +++ b/packages/core-node/src/presets/c3toSteam.ts @@ -0,0 +1,278 @@ +import { PresetFn, SavedFile } from "@pipelab/shared"; + +export const c3toSteamPreset: PresetFn = async () => { + const startId = "manual-start"; + + const data: SavedFile = { + version: "5.0.0", + name: "Construct 3 to Steam", + description: "A basic project to get you started with Construct 3 and Steam", + variables: [], + canvas: { + triggers: [ + { + type: "event", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "manual", + version: "latest", + }, + uid: startId, + params: {}, + }, + ], + blocks: [ + { + uid: "3oHbOKmCXo6NSjmrn0tHG", + type: "action", + origin: { + nodeId: "export-construct-project", + pluginId: "@pipelab/plugin-construct", + version: "latest", + }, + params: { + file: { + editor: "simple", + value: "", + }, + username: { + editor: "simple", + value: '""', + }, + password: { + editor: "simple", + value: '""', + }, + version: { + editor: "simple", + value: "", + }, + headless: { + editor: "simple", + value: "true", + }, + timeout: { + editor: "simple", + value: "120", + }, + customProfile: { + editor: "simple", + value: "", + }, + }, + }, + { + uid: "6s1uYWDi2XbRriBpvQSBS", + type: "action", + origin: { + nodeId: "unzip-file-node", + pluginId: "@pipelab/plugin-filesystem", + version: "latest", + }, + params: { + file: { + editor: "editor", + value: "steps['3oHbOKmCXo6NSjmrn0tHG']['outputs']['zipFile']", + }, + }, + }, + { + uid: "cvxzwBfXPZhH1RbmmxBdG", + type: "action", + origin: { + nodeId: "electron:package:v2", + pluginId: "@pipelab/plugin-electron", + version: "latest", + }, + params: { + arch: { + editor: "simple", + value: "", + }, + platform: { + editor: "simple", + value: "", + }, + "input-folder": { + editor: "editor", + value: "steps['6s1uYWDi2XbRriBpvQSBS']['outputs']['output']", + }, + name: { + editor: "simple", + value: '"Pipelab"', + }, + appBundleId: { + editor: "simple", + value: '"com.pipelab.app"', + }, + appCopyright: { + editor: "simple", + value: '"Copyright © 2024 Pipelab"', + }, + appVersion: { + editor: "simple", + value: '"1.0.0"', + }, + icon: { + editor: "simple", + value: "", + }, + author: { + editor: "simple", + value: '"Pipelab"', + }, + description: { + editor: "simple", + value: '"A sample application"', + }, + appCategoryType: { + editor: "simple", + value: '"public.app-category.developer-tools"', + }, + width: { + editor: "simple", + value: 800, + }, + height: { + editor: "simple", + value: 600, + }, + fullscreen: { + editor: "simple", + value: "false", + }, + frame: { + editor: "simple", + value: "true", + }, + transparent: { + editor: "simple", + value: "false", + }, + toolbar: { + editor: "simple", + value: "true", + }, + alwaysOnTop: { + editor: "simple", + value: "false", + }, + electronVersion: { + editor: "simple", + value: '""', + }, + customMainCode: { + editor: "simple", + value: "", + }, + disableAsarPackaging: { + editor: "simple", + value: "true", + }, + enableExtraLogging: { + editor: "simple", + value: "false", + }, + clearServiceWorkerOnBoot: { + editor: "simple", + value: "false", + }, + enableInProcessGPU: { + editor: "simple", + value: "false", + }, + enableDisableRendererBackgrounding: { + editor: "simple", + value: "false", + }, + forceHighPerformanceGpu: { + editor: "simple", + value: "false", + }, + websocketApi: { + editor: "simple", + value: "[]", + }, + ignore: { + editor: "simple", + value: "[\n // use 'src/app/' as starting point\n]", + }, + enableSteamSupport: { + editor: "simple", + value: "true", + }, + steamGameId: { + editor: "simple", + value: "480", + }, + }, + }, + { + uid: "1pJrNARroFnuY9DfiC56r", + type: "action", + origin: { + nodeId: "steam-upload", + pluginId: "@pipelab/plugin-steam", + version: "latest", + }, + params: { + sdk: { + editor: "simple", + value: "", + }, + username: { + editor: "simple", + value: "", + }, + appId: { + editor: "simple", + value: "", + }, + depotId: { + editor: "simple", + value: "", + }, + description: { + editor: "simple", + value: "", + }, + folder: { + editor: "editor", + value: "steps['cvxzwBfXPZhH1RbmmxBdG']['outputs']['output']", + }, + enableDRM: { + editor: "simple", + value: "false", + }, + binaryToPatch: { + editor: "simple", + value: "", + }, + }, + disabled: false, + }, + { + uid: "gnTsA6oO49ySfetxUf-0K", + type: "action", + origin: { + nodeId: "fs:open-in-explorer", + pluginId: "@pipelab/plugin-filesystem", + version: "latest", + }, + params: { + path: { + editor: "editor", + value: "steps['cvxzwBfXPZhH1RbmmxBdG']['outputs']['output']", + }, + }, + disabled: false, + }, + ], + }, + }; + + return { + data, + hightlight: true, + }; +}; diff --git a/packages/core-node/src/presets/demo.ts b/packages/core-node/src/presets/demo.ts new file mode 100644 index 00000000..3b21671e --- /dev/null +++ b/packages/core-node/src/presets/demo.ts @@ -0,0 +1,123 @@ +// @ts-nocheck + +import { PresetFn, SavedFile } from "@pipelab/shared"; + +export const demoPreset: PresetFn = async () => { + const startId = "manual-start"; + const exportConstructProjectId = "export-construct-project"; + const listFilesNodeId = "list-files-node"; + const logOkId = "log-ok"; + + const data: SavedFile = { + version: "5.0.0", + variables: [], + name: "demo", + description: "demo", + canvas: { + blocks: [ + { + type: "event", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "manual", + }, + uid: startId, + params: {}, + }, + { + type: "action", + origin: { + pluginId: "@pipelab/plugin-construct", + nodeId: "export-construct-project", + }, + uid: exportConstructProjectId, + params: { + version: "300", + username: "quentin", + password: "aaa", + headless: false, + }, + }, + { + type: "action", + origin: { + pluginId: "@pipelab/plugin-filesystem", + nodeId: "list-files-node", + }, + uid: listFilesNodeId, + params: { + folder: "/home/quentin/Téléchargements/sourcegit/", + recursive: true, + }, + }, + { + type: "loop", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "for", + }, + + params: { + value: `{{ steps['${listFilesNodeId}']['outputs']['paths'] }}`, + }, + children: [ + { + type: "condition", + origin: { + pluginId: "@pipelab/plugin-filesystem", + nodeId: "is-file", + }, + uid: "is-file-condition", + + params: { + path: `{{ steps['${listFilesNodeId}']['outputs']['paths'][context.loopindex] }}`, + }, + branchTrue: [ + { + type: "action", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "log", + }, + params: { + message: `File: {{ steps['${listFilesNodeId}']['outputs']['paths'] }}`, + }, + uid: "log-ok-in-foreach", + }, + ], + branchFalse: [ + { + type: "action", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "log", + }, + params: { + message: `Folder: {{ steps['${listFilesNodeId}']['outputs']['paths'] }}`, + }, + uid: "log-ko-in-foreach", + }, + ], + }, + ], + uid: "for-each-file", + }, + { + type: "action", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "log", + }, + uid: logOkId, + params: { + message: "{{ Filesystem.Join() }}", + }, + }, + ], + }, + }; + + return { + data, + }; +}; diff --git a/src/main/presets/list.ts b/packages/core-node/src/presets/list.ts similarity index 51% rename from src/main/presets/list.ts rename to packages/core-node/src/presets/list.ts index d5c368b7..a5b3f3a3 100644 --- a/src/main/presets/list.ts +++ b/packages/core-node/src/presets/list.ts @@ -1,20 +1,16 @@ // import { demoPreset } from './demo' -// import { ifPreset } from './if' -// import { loopPreset } from './loop' // import { testC3Unzip } from './test-c3-unzip' // import { testC3Offline } from './test-c3-offline' -import { c3toSteamPreset } from './c3toSteam' -import { newProjectPreset } from './newProject' -import { moreToCome } from './moreToCome' +import { c3toSteamPreset } from "./c3toSteam"; +import { newProjectPreset } from "./newProject"; +import { moreToCome } from "./moreToCome"; export const presets = async () => { - const newProjectVal = await newProjectPreset() - const c3toSteamVal = await c3toSteamPreset() - const moreToComeVal = await moreToCome() + const newProjectVal = await newProjectPreset(); + const c3toSteamVal = await c3toSteamPreset(); + const moreToComeVal = await moreToCome(); // const demoPresetVal = await demoPreset() - // const ifPresetVal = await ifPreset() - // const loopPresetVal = await loopPreset() // const testC3UnzipVal = await testC3Unzip() // const testC3OfflineVal = await testC3Offline() return { @@ -22,9 +18,7 @@ export const presets = async () => { c3toSteam: c3toSteamVal, moreToCome: moreToComeVal, // demo: demoPresetVal, - // if: ifPresetVal, - // loop: loopPresetVal, // testC3Unzip: testC3UnzipVal, // testC3Offline: testC3OfflineVal, - } -} + }; +}; diff --git a/packages/core-node/src/presets/moreToCome.ts b/packages/core-node/src/presets/moreToCome.ts new file mode 100644 index 00000000..290d077a --- /dev/null +++ b/packages/core-node/src/presets/moreToCome.ts @@ -0,0 +1,33 @@ +import { PresetFn, SavedFile } from "@pipelab/shared"; + +export const moreToCome: PresetFn = async () => { + const startId = "manual-start"; + + const data: SavedFile = { + version: "5.0.0", + name: "More to come!", + description: "Do not hesitate to suggest templates you would see here", + variables: [], + canvas: { + triggers: [ + { + type: "event", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "manual", + version: "latest", + }, + uid: startId, + params: {}, + }, + ], + blocks: [], + }, + }; + + return { + data, + disabled: true, + hightlight: false, + }; +}; diff --git a/packages/core-node/src/presets/newProject.ts b/packages/core-node/src/presets/newProject.ts new file mode 100644 index 00000000..c09529c6 --- /dev/null +++ b/packages/core-node/src/presets/newProject.ts @@ -0,0 +1,32 @@ +import { PresetFn, SavedFile } from "@pipelab/shared"; + +export const newProjectPreset: PresetFn = async () => { + const startId = "manual-start"; + + const data: SavedFile = { + version: "5.0.0", + name: "Empty project", + description: "A default project with no tasks added", + variables: [], + canvas: { + triggers: [ + { + type: "event", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "manual", + version: "latest", + }, + uid: startId, + params: {}, + }, + ], + blocks: [], + }, + }; + + return { + data, + hightlight: true, + }; +}; diff --git a/src/main/presets/preset.model.ts b/packages/core-node/src/presets/preset.model.ts similarity index 100% rename from src/main/presets/preset.model.ts rename to packages/core-node/src/presets/preset.model.ts diff --git a/packages/core-node/src/presets/test-c3-offline.ts b/packages/core-node/src/presets/test-c3-offline.ts new file mode 100644 index 00000000..10fb00f9 --- /dev/null +++ b/packages/core-node/src/presets/test-c3-offline.ts @@ -0,0 +1,87 @@ +import { PresetFn, SavedFile } from "@pipelab/shared"; + +export const testC3Offline: PresetFn = async () => { + const packageWithElecton = "electron-package-node"; + const steamUpload = "steam-upload-node"; + + const data: SavedFile = { + version: "5.0.0", + variables: [], + name: "C3 test without export", + description: "C3 test without export", + canvas: { + triggers: [ + { + type: "event", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "manual", + version: "latest", + }, + uid: "manual-start", + params: {}, + }, + ], + blocks: [ + { + uid: packageWithElecton, + type: "action", + origin: { + nodeId: "package-to-electron", + pluginId: "@pipelab/plugin-electron", + version: "latest", + }, + params: { + "input-folder": { + editor: "editor", + value: `/home/quentin/Documents/Cyn Assets/app`, + }, + arch: { + editor: "simple", + value: undefined, + }, + platform: { + editor: "simple", + value: undefined, + }, + }, + }, + { + uid: steamUpload, + type: "action", + origin: { + nodeId: "steam-upload", + pluginId: "@pipelab/plugin-steam", + version: "latest", + }, + params: { + folder: { + editor: "editor", + value: `{{ steps['${packageWithElecton}']['outputs']['output'] }}`, + }, + appId: { + editor: "editor", + value: "3047200", + }, + depotId: { + editor: "editor", + value: "3047201", + }, + sdk: { + editor: "editor", + value: "/home/quentin/Documents/steamworkssdk/sdk", + }, + username: { + editor: "editor", + value: "armaldio", + }, + }, + }, + ], + }, + }; + + return { + data, + }; +}; diff --git a/packages/core-node/src/presets/test-c3-unzip.ts b/packages/core-node/src/presets/test-c3-unzip.ts new file mode 100644 index 00000000..1a49573e --- /dev/null +++ b/packages/core-node/src/presets/test-c3-unzip.ts @@ -0,0 +1,135 @@ +import { PresetFn, SavedFile } from "@pipelab/shared"; + +export const testC3Unzip: PresetFn = async () => { + const exportConstructProjectId = "export-construct-project"; + const unzipFileId = "unzip-file-node"; + const packageWithElecton = "electron-package-node"; + const steamUpload = "steam-upload-node"; + + const data: SavedFile = { + version: "5.0.0", + name: "From Construct to Steam", + description: "Export from Construct, package with Electron, then upload to Steam", + variables: [], + canvas: { + triggers: [ + { + type: "event", + origin: { + pluginId: "@pipelab/plugin-system", + nodeId: "manual", + version: "latest", + }, + uid: "manual-start", + params: {}, + }, + ], + blocks: [ + { + uid: exportConstructProjectId, + type: "action", + origin: { + nodeId: "export-construct-project", + pluginId: "@pipelab/plugin-construct", + version: "latest", + }, + params: { + file: { + editor: "editor", + value: `'/home/armaldio/Téléchargements/test.c3p'`, + }, + username: { + editor: "editor", + value: '"a"', + }, + password: { + editor: "editor", + value: '"a"', + }, + version: { + editor: "editor", + value: '"395"', + }, + headless: { + editor: "editor", + value: false, + }, + }, + }, + { + uid: unzipFileId, + type: "action", + origin: { + nodeId: "unzip-file-node", + pluginId: "@pipelab/plugin-filesystem", + version: "latest", + }, + params: { + file: { + editor: "editor", + value: `steps['${exportConstructProjectId}']['outputs']['folder']`, + }, + }, + }, + { + uid: packageWithElecton, + type: "action", + origin: { + nodeId: "electron:package", + pluginId: "@pipelab/plugin-electron", + version: "latest", + }, + params: { + "input-folder": { + editor: "editor", + value: `steps['${unzipFileId}']['outputs']['output']`, + }, + arch: { + editor: "simple", + value: undefined, + }, + platform: { + editor: "simple", + value: undefined, + }, + }, + }, + { + uid: steamUpload, + type: "action", + origin: { + nodeId: "steam-upload", + pluginId: "@pipelab/plugin-steam", + version: "latest", + }, + params: { + folder: { + editor: "editor", + value: `steps['${packageWithElecton}']['outputs']['output']`, + }, + appId: { + editor: "editor", + value: "'3047200'", + }, + depotId: { + editor: "editor", + value: "'3047201'", + }, + sdk: { + editor: "editor", + value: "'/home/armaldio/Documents/steamworkssdk/sdk'", + }, + username: { + editor: "editor", + value: "'armaldio'", + }, + }, + }, + ], + }, + }; + + return { + data, + }; +}; diff --git a/packages/core-node/src/runner.ts b/packages/core-node/src/runner.ts new file mode 100644 index 00000000..90002d24 --- /dev/null +++ b/packages/core-node/src/runner.ts @@ -0,0 +1,162 @@ +import { executeGraphWithHistory } from "./utils"; +import { setupConfigFile } from "./config"; +import { isDev, PipelabContext, CacheFolder } from "./context"; +import { readFile, access, writeFile, mkdir } from "node:fs/promises"; +import { resolve, isAbsolute, join, dirname } from "node:path"; +import { savedFileMigrator } from "@pipelab/shared"; +import { registerAllHandlers } from "./handlers/index"; + +export interface RunOptions { + userData?: string; + variables?: string; + output?: string; + cloud?: boolean; +} + +export async function runPipelineCommand(file: string, options: RunOptions, version: string) { + const pipelinePath = isAbsolute(file) ? file : resolve(process.cwd(), file); + + try { + await access(pipelinePath); + } catch (e) { + throw new Error(`Pipeline file not found at ${pipelinePath}`); + } + + const pipelineContent = await readFile(pipelinePath, "utf-8"); + const pipeline = JSON.parse(pipelineContent); + + let finalPipeline = pipeline; + if (pipeline.version) { + finalPipeline = await savedFileMigrator.migrate(pipeline); + } + + const { + graph: rawGraph, + variables: pipelineVariables, + projectName, + projectPath, + pipelineId, + canvas, + name, + } = finalPipeline; + + const graph = rawGraph || canvas?.blocks; + + if (!graph) { + throw new Error("Pipeline does not contain a valid graph or canvas.blocks"); + } + + let vars = pipelineVariables || finalPipeline.variables || []; + if (options.variables) { + vars = JSON.parse(options.variables); + } + + const effectiveProjectName = projectName || name || "CLI Run"; + const effectiveProjectPath = projectPath || process.cwd(); + const effectivePipelineId = pipelineId || "cli-run"; + + console.log(`Executing pipeline: ${effectiveProjectName} (${effectivePipelineId})`); + + if (!options.userData) throw new Error("userDataPath is required for runPipelineCommand"); + const releaseTag = version.includes("beta") ? "beta" : "latest"; + const context = new PipelabContext({ + userDataPath: options.userData, + releaseTag, + }); + + await registerAllHandlers({ version, context, waitForPlugins: true }); + + const cachePath = context.getCachePath(CacheFolder.Pipelines, effectivePipelineId); + await mkdir(cachePath, { recursive: true }); + + const abortController = new AbortController(); + + let supabase: any; + const cloudRunId = process.env.CLOUD_RUN_ID; + if (options.cloud && cloudRunId) { + const { createClient } = await import("@supabase/supabase-js"); + supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!); + console.log(`Cloud mode enabled. Streaming logs for run: ${cloudRunId}`); + } + + try { + const { result, buildId } = await executeGraphWithHistory({ + graph, + variables: vars, + projectName: effectiveProjectName, + projectPath: effectiveProjectPath, + pipelineId: effectivePipelineId, + cachePath: cachePath, + onNodeEnter: (node) => { + console.log(`[ENTER] ${node.name} (${node.uid})`); + if (supabase) { + supabase + .from("cloud_run_logs") + .insert({ + run_id: cloudRunId, + message: `[ENTER] ${node.name} (${node.uid})`, + node_uid: node.uid, + type: "node-enter", + }) + .then(); + } + }, + onNodeExit: (node) => { + console.log(`[EXIT] ${node.name} (${node.uid})`); + if (supabase) { + supabase + .from("cloud_run_logs") + .insert({ + run_id: cloudRunId, + message: `[EXIT] ${node.name} (${node.uid})`, + node_uid: node.uid, + type: "node-exit", + }) + .then(); + } + }, + onLog: (data, node) => { + if (data.type === "log") { + const message = data.data.message.join(" "); + console.log(`[LOG] ${message}`); + if (supabase) { + supabase + .from("cloud_run_logs") + .insert({ + run_id: cloudRunId, + message: message, + node_uid: node?.uid, + type: "log", + }) + .then(); + } + } + }, + abortSignal: abortController.signal, + context, + }); + + console.log(`Pipeline execution finished. Build ID: ${buildId}`); + + if (supabase) { + await supabase.from("cloud_runs").update({ status: "success" }).eq("id", cloudRunId); + } + + if (options.output) { + const outputPath = isAbsolute(options.output) + ? options.output + : resolve(process.cwd(), options.output); + + await mkdir(dirname(outputPath), { recursive: true }); + await writeFile(outputPath, JSON.stringify(result, null, 2), "utf-8"); + console.log(`Result saved to ${outputPath}`); + } + + return result; + } catch (e) { + if (supabase) { + await supabase.from("cloud_runs").update({ status: "failed" }).eq("id", cloudRunId); + } + throw e; + } +} diff --git a/packages/core-node/src/server.ts b/packages/core-node/src/server.ts new file mode 100644 index 00000000..c88c7a00 --- /dev/null +++ b/packages/core-node/src/server.ts @@ -0,0 +1,140 @@ +import { + ensurePNPM, + PipelabContext, + isDev, + fetchPipelabAsset, + registerAllHandlers, + webSocketServer, +} from "./index"; +import { getUiDevServerMissingWarning, uiDevPort } from "@pipelab/constants"; +import { existsSync } from "node:fs"; +import { readFile } from "node:fs/promises"; +import http from "http"; +// @ts-expect-error serve-handler has no type definitions +import handler from "serve-handler"; + +export interface ServeOptions { + port: string | number; + userData?: string; + nodePath?: string; + pnpmPath?: string; +} + +export const sendStartupProgress = (message: string) => { + webSocketServer.broadcast("startup:progress", { + type: "progress", + data: { message }, + }); +}; + +export const sendStartupReady = () => { + console.log(`[Startup Progress] Ready!`); + webSocketServer.broadcast("startup:progress", { + type: "ready", + }); +}; + +export async function serveCommand(options: ServeOptions, version: string, _dirname: string) { + if (!options.userData) throw new Error("userDataPath is required for serveCommand"); + const releaseTag = version.includes("beta") ? "beta" : "latest"; + const context = new PipelabContext({ + userDataPath: options.userData, + releaseTag, + }); + + let rawAssetFolder: string | undefined; + if (!isDev) { + rawAssetFolder = await fetchPipelabAsset("@pipelab/ui", releaseTag, { context }); + } + + const server = http.createServer(async (request, response) => { + // Serve local media files securely via HTTP + const urlObj = request.url ? new URL(request.url, "http://localhost") : null; + if (urlObj && urlObj.pathname.startsWith("/media-file/")) { + const prefix = "/media-file/"; + const encodedPath = urlObj.pathname.substring(prefix.length); + const filePath = decodeURIComponent(encodedPath); + // Strip leading slash on Windows if followed by a drive letter (e.g. /C:/...) + const normalizedPath = + filePath.startsWith("/") && filePath.match(/^\/[a-zA-Z]:/) + ? filePath.substring(1) + : filePath; + + if (existsSync(normalizedPath)) { + try { + const content = await readFile(normalizedPath); + let contentType = "application/octet-stream"; + if (normalizedPath.endsWith(".png")) contentType = "image/png"; + else if (normalizedPath.endsWith(".jpg") || normalizedPath.endsWith(".jpeg")) + contentType = "image/jpeg"; + else if (normalizedPath.endsWith(".svg")) contentType = "image/svg+xml"; + else if (normalizedPath.endsWith(".gif")) contentType = "image/gif"; + else if (normalizedPath.endsWith(".webp")) contentType = "image/webp"; + + response.writeHead(200, { + "Content-Type": contentType, + "Access-Control-Allow-Origin": "*", + }); + response.end(content); + return; + } catch (e) { + response.writeHead(500, { "Content-Type": "text/plain" }); + response.end(`Error reading file: ${e}`); + return; + } + } else { + response.writeHead(404, { "Content-Type": "text/plain" }); + response.end(`File not found: ${normalizedPath}`); + return; + } + } + + if (isDev) { + response.writeHead(200, { "Content-Type": "text/html" }); + response.end(` + + +

Pipelab Dev Mode

+

The CLI server is running (API/WebSocket), but the UI is not served here in development.

+
+ + + `); + return; + } + + if (!rawAssetFolder || !existsSync(rawAssetFolder)) { + response.writeHead(404, { "Content-Type": "text/plain" }); + response.end( + `Error: UI directory not found at ${rawAssetFolder}.\n` + + "Please run 'pnpm build' in apps/ui to generate the distribution.", + ); + return; + } + + return handler(request, response, { + public: rawAssetFolder, + rewrites: [{ source: "/**", destination: "/index.html" }], + }); + }); + + console.log(`Starting Pipelab server on port ${options.port}...`); + if (isDev) { + console.info(getUiDevServerMissingWarning()); + console.log(`UI available at http://localhost:${uiDevPort}`); + } else { + console.log(`UI available at http://localhost:${options.port}`); + } + + // Start the server EARLY so the UI can connect and receive progress updates + await webSocketServer.start(Number(options.port), server); + + await registerAllHandlers({ + version, + context, + }); + + sendStartupReady(); + + return server; +} diff --git a/packages/core-node/src/types/runner.ts b/packages/core-node/src/types/runner.ts new file mode 100644 index 00000000..f526ef62 --- /dev/null +++ b/packages/core-node/src/types/runner.ts @@ -0,0 +1,74 @@ +import type { BrowserWindow } from "electron"; +import type { PipelabContext } from "../context"; +import type { + Action, + Expression, + Event, + SetOutputActionFn, + SetOutputExpressionFn, + ExtractInputsFromAction, + ExtractInputsFromEvent, + ExtractInputsFromExpression, +} from "@pipelab/shared"; + +export type { + Action, + Expression, + Event, + SetOutputActionFn, + SetOutputExpressionFn, + ExtractInputsFromAction, + ExtractInputsFromEvent, + ExtractInputsFromExpression, +}; + +export type RunnerCallbackFnArgument = { + done: () => void; + id: string; + log: (...args: Parameters<(typeof console)["log"]>) => void; +}; + +export type ActionRunnerData = { + log: typeof console.log; + setOutput: SetOutputActionFn; + inputs: ExtractInputsFromAction; + setMeta: (callback: (data: ACTION["meta"]) => ACTION["meta"]) => void; + meta: ACTION["meta"]; + cwd: string; + /** @deprecated Use `context` instead to resolve sandboxed folders and binary paths. */ + paths: { + cache: string; + pnpm: string; + node: string; + userData: string; + modules: string; + thirdparty: string; + }; + browserWindow: BrowserWindow; + abortSignal: AbortSignal; + context: PipelabContext; + setArtifact: (name: string, path: string) => void; +}; + +export type ActionRunner = (data: ActionRunnerData) => Promise; + +export type ExpressionRunner = (data: { + log: typeof console.log; + setOutput: SetOutputExpressionFn; + inputs: ExtractInputsFromExpression; + setMeta: (callback: (data: EXPRESSION["meta"]) => EXPRESSION["meta"]) => void; + meta: EXPRESSION["meta"]; + cwd: string; + context: PipelabContext; +}) => Promise; + +export type EventRunner = (data: { + log: typeof console.log; + inputs: ExtractInputsFromEvent; + setMeta: (callback: (data: EVENT["meta"]) => EVENT["meta"]) => void; + meta: EVENT["meta"]; + cwd: string; + context: PipelabContext; +}) => Promise; + +export type Runner = ActionRunner | EventRunner; diff --git a/packages/core-node/src/utils.ts b/packages/core-node/src/utils.ts new file mode 100644 index 00000000..000b0bd0 --- /dev/null +++ b/packages/core-node/src/utils.ts @@ -0,0 +1,375 @@ +import { nanoid } from "nanoid"; +import { + usePlugins, + RendererPluginDefinition, + processGraph, + useLogger, + BuildHistoryEntry, + Variable, + transformUrl, +} from "@pipelab/shared"; +import { mkdir, rm, cp, stat } from "node:fs/promises"; +import { join } from "node:path"; +import { PipelabContext } from "./context"; +import { handleActionExecute } from "./handler-func"; +import { BuildHistoryStorage } from "./handlers/build-history"; + +import { getFolderSize } from "./utils/fs-extras"; +import { setupSettingsConfigFile } from "./config"; + +export const getFinalPlugins = () => { + const { plugins } = usePlugins(); + // console.log('plugins.value', plugins.value) + + const finalPlugins: RendererPluginDefinition[] = []; + + for (const plugin of plugins.value) { + const finalNodes = []; + + const finalIcon = + plugin.icon?.type === "image" + ? { + ...plugin.icon, + image: transformUrl(plugin.icon.image), + } + : plugin.icon; + + for (const nodeDef of plugin.nodes) { + const node = nodeDef.node; + finalNodes.push({ + ...nodeDef, + node: { + ...node, + icon: transformUrl(node.icon), + }, + }); + } + + finalPlugins.push({ + ...plugin, + icon: finalIcon, + nodes: finalNodes, + }); + } + + return finalPlugins; +}; + + +export const executeGraphWithHistory = async ({ + graph, + variables, + projectName, + projectPath, + pipelineId, + onNodeEnter, + onNodeExit, + onLog, + onArtifact, + onArtifactsFinalized, + abortSignal, + mainWindow, + cachePath, + context, +}: { + graph: any; + variables: Variable[]; + projectName: string; + projectPath: string; + pipelineId: string; + onNodeEnter?: (node: any) => void; + onNodeExit?: (node: any) => void; + onLog?: (data: any, node?: any) => void; + onArtifact?: (name: string, path: string, node?: any) => void; + onArtifactsFinalized?: (artifacts: import("@pipelab/shared").Artifact[]) => void; + abortSignal: AbortSignal; + mainWindow?: any; + cachePath: string; + context: PipelabContext; +}) => { + const ctx = context; + const buildHistoryStorage = new BuildHistoryStorage(ctx); + const buildId = nanoid(); + const startTime = Date.now(); + + // Save initial build history entry + const now = Date.now(); + const initialEntry: BuildHistoryEntry = { + id: buildId, + projectName, + projectPath, + pipelineId, + cachePath, + startTime, + status: "running", + logs: [], + steps: [], + metadata: { + os: process.platform, + arch: process.arch, + nodeVersion: process.version, + }, + totalSteps: graph.length, + completedSteps: 0, + failedSteps: 0, + cancelledSteps: 0, + createdAt: now, + updatedAt: now, + }; + const executionSteps = initialEntry.steps; + const shouldDisableHistory = process.env.PIPELAB_DISABLE_HISTORY === "true"; + + if (!shouldDisableHistory) { + await buildHistoryStorage.save(initialEntry); + } + + const logs: any[] = []; + const sandboxPath = await ctx.createTempFolder("pipeline-sandbox-"); + const { logger } = useLogger(); + let completedSteps = 0; + let failedSteps = 0; + let cancelledSteps = 0; + const collectedArtifacts: import("@pipelab/shared").Artifact[] = []; + + // Ensure all plugins used in the graph are downloaded and registered + const { registerPlugins, plugins: registeredPlugins } = usePlugins(); + // JIT loading is intentionally removed here so plugins must be loaded at app startup. + // Fail-fast if any required plugin is not loaded + const pluginIds = new Set( + graph.map((node: any) => node.origin?.pluginId).filter(Boolean), + ) as Set; + + const missingPlugins: string[] = []; + for (const pluginId of pluginIds) { + const isRegistered = registeredPlugins.value.some((p) => p.id === pluginId); + if (!isRegistered) { + missingPlugins.push(pluginId); + } + } + + if (missingPlugins.length > 0) { + const errorMsg = `Fail-fast: The following required plugins are not loaded: ${missingPlugins.join(", ")}. Please ensure they are installed and enabled in settings.`; + logger().error(`[Runner] ${errorMsg}`); + throw new Error(errorMsg); + } + + logger().info(`[Sandbox] Execution sandbox created at: ${sandboxPath}`); + const settingsFile = await setupSettingsConfigFile(ctx); + const config = await settingsFile.getConfig(); + const shouldCleanup = true; + + try { + const result = await processGraph({ + graph, + definitions: getFinalPlugins(), + variables, + steps: {}, + context: {}, + onExecuteItem: async (node, params, steps) => { + if (node.type === "action") { + return await handleActionExecute( + node.origin.nodeId, + node.origin.pluginId, + params, + mainWindow, + async (data) => { + if (data.type === "log") { + const logEntry = { + id: nanoid(), + level: "info" as const, + message: data.data.message, + timestamp: data.data.time, + }; + logs.push(logEntry); + const step = executionSteps.find(s => s.id === node.uid); + if (step) { + step.logs.push(logEntry); + } + onLog?.(data, node); + } + }, + abortSignal, + sandboxPath, + cachePath, + ctx, + (name, path) => { + collectedArtifacts.push({ + id: nanoid(), + name, + path, + size: 0, + type: "folder", // we'll determine type and size later + }); + onArtifact?.(name, path, node); + }, + ); + } + throw new Error(`Execution of node type ${node.type} not implemented in utils.ts`); + }, + onNodeEnter: (node) => { + executionSteps.push({ + id: node.uid, + name: node.origin?.nodeId || node.uid, + status: "running", + startTime: Date.now(), + logs: [], + }); + onNodeEnter?.(node); + }, + onNodeExit: async (node) => { + completedSteps++; + const step = executionSteps.find(s => s.id === node.uid); + if (step) { + step.status = "completed"; + step.endTime = Date.now(); + step.duration = step.endTime - step.startTime; + } + if (!shouldDisableHistory) { + // Update progress in the background + buildHistoryStorage.update(buildId, { completedSteps, steps: executionSteps }, pipelineId).catch((err) => { + logger().error(`Failed to update progress for build ${buildId}:`, err); + }); + } + onNodeExit?.(node); + }, + abortSignal, + }); + + const endTime = Date.now(); + if (!shouldDisableHistory) { + // Process artifacts + if (collectedArtifacts.length > 0) { + const artifactsDir = ctx.getArtifactsPath(pipelineId, buildId); + await mkdir(artifactsDir, { recursive: true }); + for (const artifact of collectedArtifacts) { + try { + const destPath = join(artifactsDir, artifact.name); + const originalNoAsar = process.noAsar; + process.noAsar = true; + try { + await cp(artifact.path, destPath, { recursive: true }); + } finally { + process.noAsar = originalNoAsar; + } + + // update size and type + try { + const s = await stat(destPath); + artifact.type = s.isDirectory() ? "folder" : "file"; + artifact.size = s.isDirectory() ? await getFolderSize(destPath) : s.size; + artifact.path = destPath; // update path to persistent location + } catch (e) { + logger().warn(`Failed to get size for artifact ${artifact.name}:`, e); + } + } catch (e) { + logger().error(`Failed to copy artifact ${artifact.name}:`, e); + } + } + } + + onArtifactsFinalized?.(collectedArtifacts); + + await buildHistoryStorage.update( + buildId, + { + status: "completed", + endTime, + duration: endTime - startTime, + output: result.steps, + logs, + steps: executionSteps, + completedSteps, + artifacts: collectedArtifacts, + }, + pipelineId, + ); + } + + return { result, buildId }; + } catch (error) { + const endTime = Date.now(); + const isCanceled = error instanceof Error && error.name === "AbortError"; + + if (!shouldDisableHistory) { + // Process artifacts even on failure + if (collectedArtifacts.length > 0) { + const artifactsDir = ctx.getArtifactsPath(pipelineId, buildId); + await mkdir(artifactsDir, { recursive: true }); + for (const artifact of collectedArtifacts) { + try { + const destPath = join(artifactsDir, artifact.name); + const originalNoAsar = process.noAsar; + process.noAsar = true; + try { + await cp(artifact.path, destPath, { recursive: true }); + } finally { + process.noAsar = originalNoAsar; + } + + // update size and type + try { + const s = await stat(destPath); + artifact.type = s.isDirectory() ? "folder" : "file"; + artifact.size = s.isDirectory() ? await getFolderSize(destPath) : s.size; + artifact.path = destPath; // update path to persistent location + } catch (e) { + logger().warn(`Failed to get size for artifact ${artifact.name}:`, e); + } + } catch (e) { + logger().error(`Failed to copy artifact ${artifact.name}:`, e); + } + } + } + + onArtifactsFinalized?.(collectedArtifacts); + + for (const step of executionSteps) { + if (step.status === "running") { + step.status = isCanceled ? "cancelled" : "failed"; + step.endTime = endTime; + step.duration = endTime - step.startTime; + step.error = { + message: error instanceof Error ? error.message : String(error), + timestamp: endTime, + }; + } + } + + await buildHistoryStorage.update( + buildId, + { + status: isCanceled ? "cancelled" : "failed", + endTime, + duration: endTime - startTime, + error: { + message: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined, + timestamp: endTime, + }, + logs, + steps: executionSteps, + completedSteps, + failedSteps: isCanceled ? 0 : 1, + cancelledSteps: isCanceled ? 1 : 0, + artifacts: collectedArtifacts, + }, + pipelineId, + ); + } + + throw error; + } finally { + if (shouldCleanup) { + try { + await rm(sandboxPath, { recursive: true, force: true }); + } catch (e) { + console.warn(`Failed to cleanup sandbox at ${sandboxPath}:`, e); + } + try { + await rm(cachePath, { recursive: true, force: true }); + } catch (e) { + console.warn(`Failed to cleanup cache at ${cachePath}:`, e); + } + } + } +}; diff --git a/packages/core-node/src/utils/fs-extras.ts b/packages/core-node/src/utils/fs-extras.ts new file mode 100644 index 00000000..8dd0fc61 --- /dev/null +++ b/packages/core-node/src/utils/fs-extras.ts @@ -0,0 +1,241 @@ +import { createWriteStream } from "node:fs"; +import { execa, Options, Subprocess } from "execa"; +import { mkdir as mkdirP, writeFile, stat, readdir } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import tar from "tar"; +import yauzl from "yauzl"; +import archiver from "archiver"; +import { pipeline } from "node:stream/promises"; + +/** + * Ensures a directory exists and a file is created with default content if missing. + */ +export const ensure = async (filesPath: string, defaultContent = "{}") => { + await mkdirP(dirname(filesPath), { recursive: true }); + try { + const s = await stat(filesPath); + if (s.size === 0) { + await writeFile(filesPath, defaultContent); + } + } catch { + await writeFile(filesPath, defaultContent); + } +}; + +/** + * Extracts a .tar.gz archive. + */ +export async function extractTarGz(archivePath: string, destinationDir: string): Promise { + await mkdirP(destinationDir, { recursive: true }); + await tar.x({ + file: archivePath, + cwd: destinationDir, + }); +} + +/** + * Extracts a .zip archive. + */ +export async function extractZip(archivePath: string, destinationDir: string): Promise { + await mkdirP(destinationDir, { recursive: true }); + return new Promise((resolve, reject) => { + yauzl.open(archivePath, { lazyEntries: true }, (err, zipfile) => { + if (err || !zipfile) return reject(err || new Error("Could not open zip file")); + zipfile.on("error", reject); + zipfile.readEntry(); + zipfile.on("entry", (entry) => { + const entryPath = join(destinationDir, entry.fileName); + if (/\/$/.test(entry.fileName)) { + mkdirP(entryPath, { recursive: true }) + .then(() => zipfile.readEntry()) + .catch(reject); + } else { + mkdirP(dirname(entryPath), { recursive: true }) + .then(() => { + zipfile.openReadStream(entry, (err, readStream) => { + if (err || !readStream) + return reject(err || new Error("Could not open read stream")); + readStream.on("error", reject); + const writeStream = createWriteStream(entryPath); + writeStream.on("error", reject); + writeStream.on("close", () => zipfile.readEntry()); + readStream.pipe(writeStream); + }); + }) + .catch(reject); + } + }); + zipfile.on("end", () => resolve()); + }); + }); +} + +/** + * Zips a folder. + */ +export const zipFolder = async ( + from: string, + to: string, + log: typeof console.log = console.log, + abortSignal?: AbortSignal, +) => { + if (abortSignal?.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + const output = createWriteStream(to); + const archive = archiver("zip", { zlib: { level: 9 } }); + + return new Promise((resolve, reject) => { + const onAbort = () => { + try { + archive.abort(); + } catch {} + try { + output.destroy(); + } catch {} + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + reject(abortError); + }; + + if (abortSignal) { + abortSignal.addEventListener("abort", onAbort); + } + + output.on("close", () => { + if (abortSignal) { + abortSignal.removeEventListener("abort", onAbort); + } + log(archive.pointer() + " total bytes"); + resolve(to); + }); + + archive.on("error", (err) => { + if (abortSignal) { + abortSignal.removeEventListener("abort", onAbort); + } + reject(err); + }); + + archive.pipe(output); + archive.directory(from, false); + archive.finalize().catch((err) => { + if (abortSignal) { + abortSignal.removeEventListener("abort", onAbort); + } + reject(err); + }); + }); +}; + +/** + * Downloads a file with progress tracking. + */ +export interface DownloadHooks { + onProgress?: (data: { progress: number; downloadedSize: number }) => void; +} + +export const downloadFile = async ( + url: string, + localPath: string, + hooks?: DownloadHooks, + abortSignal?: AbortSignal, +): Promise => { + const response = await fetch(url, { signal: abortSignal }); + if (!response.ok) throw new Error(`Failed to fetch file: ${response.statusText}`); + const contentLength = response.headers.get("content-length"); + if (!contentLength) throw new Error("Content-Length header is missing"); + const totalSize = parseInt(contentLength, 10); + let downloadedSize = 0; + const fileStream = createWriteStream(localPath); + const progressStream = new TransformStream({ + transform(chunk, controller) { + downloadedSize += chunk.length; + const progress = (downloadedSize / totalSize) * 100; + hooks?.onProgress?.({ progress, downloadedSize }); + controller.enqueue(chunk); + }, + }); + const readable = response.body?.pipeThrough(progressStream); + if (!readable) throw new Error("Failed to create a readable stream"); + await pipeline(readable, fileStream); +}; + +export const runWithLiveLogs = async ( + command: string, + args: string[], + execaOptions: Options, + log: typeof console.log, + hooks?: { + onStdout?: (data: string, subprocess: Subprocess) => void; + onStderr?: (data: string, subprocess: Subprocess) => void; + onExit?: (code: number) => void; + onCreated?: (subprocess: Subprocess) => void; + }, + abortSignal?: AbortSignal, +): Promise => { + const subprocess = execa(command, args, { + ...execaOptions, + stdout: "pipe", + stderr: "pipe", + stdin: "pipe", + env: { + ...process.env, + ...execaOptions.env, + TERM: "xterm-256color", + FORCE_STDERR_LOGGING: "1", + }, + cancelSignal: abortSignal ?? execaOptions.cancelSignal, + }); + + hooks?.onCreated?.(subprocess); + + subprocess.stdout?.on("data", (data: Buffer) => { + hooks?.onStdout?.(data.toString(), subprocess); + }); + + subprocess.stderr?.on("data", (data: Buffer) => { + hooks?.onStderr?.(data.toString(), subprocess); + }); + + try { + const { exitCode } = await subprocess; + hooks?.onExit?.(exitCode ?? 0); + } catch (error: any) { + const code = error.exitCode ?? 1; + hooks?.onExit?.(code); + throw new Error(`Command failed with exit code ${code}: ${error.message}`); + } +}; + +/** + * Calculates the total size of a directory recursively. + */ +export async function getFolderSize(dirPath: string): Promise { + try { + const files = await readdir(dirPath, { withFileTypes: true }); + const ArrayOfPromises = files.map(async (file) => { + const path = join(dirPath, file.name); + if (file.isDirectory()) { + try { + return await getFolderSize(path); + } catch { + return 0; + } + } + try { + const { size } = await stat(path); + return size; + } catch { + return 0; + } + }); + const results = await Promise.all(ArrayOfPromises); + return results.reduce((acc, size) => acc + size, 0); + } catch { + return 0; + } +} diff --git a/packages/core-node/src/utils/github.test.ts b/packages/core-node/src/utils/github.test.ts new file mode 100644 index 00000000..fd034961 --- /dev/null +++ b/packages/core-node/src/utils/github.test.ts @@ -0,0 +1,217 @@ +import { describe, test, expect, beforeEach, afterEach, vi } from "vitest"; +import { + fetchPackageReleases, + fetchLatestPackageRelease, + fetchLatestDesktopRelease, +} from "./github"; + +describe("GitHub Release Updates API", () => { + let fetchSpy: any; + let consoleLogSpy: any; + let consoleWarnSpy: any; + let consoleErrorSpy: any; + + beforeEach(() => { + fetchSpy = vi.spyOn(global, "fetch"); + consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {}); + consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); + consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + // Clean up environment variables + delete process.env.PIPELAB_OVERRIDE_RELEASE; + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + test("fetchPackageReleases - returns empty array when git matching-refs fails", async () => { + fetchSpy.mockResolvedValueOnce({ + ok: false, + status: 404, + statusText: "Not Found", + } as any); + + const releases = await fetchPackageReleases("@pipelab/app"); + expect(releases).toEqual([]); + expect(fetchSpy).toHaveBeenCalledWith( + expect.stringContaining("matching-refs/tags/%40pipelab%2Fapp"), + expect.any(Object), + ); + }); + + test("fetchPackageReleases - returns empty array when no tags match package", async () => { + fetchSpy.mockResolvedValueOnce({ + ok: true, + json: async () => [], + } as any); + + const releases = await fetchPackageReleases("@pipelab/app"); + expect(releases).toEqual([]); + }); + + test("fetchPackageReleases - correctly filters prereleases when allowPrerelease is false", async () => { + // 1. mock matching refs + fetchSpy.mockResolvedValueOnce({ + ok: true, + json: async () => [ + { ref: "refs/tags/@pipelab/app@1.0.0-beta.1" }, + { ref: "refs/tags/@pipelab/app@1.0.0" }, + ], + } as any); + + // 2. mock tag lookup for 1.0.0 (since 1.0.0-beta.1 is filtered out) + fetchSpy.mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ + tag_name: "@pipelab/app@1.0.0", + prerelease: false, + published_at: "2026-06-04T00:00:00Z", + html_url: "https://github.com/CynToolkit/pipelab/releases/tag/%40pipelab%2Fapp%401.0.0", + assets: [], + }), + } as any); + + const releases = await fetchPackageReleases("@pipelab/app", { allowPrerelease: false }); + expect(releases).toHaveLength(1); + expect(releases[0].tag_name).toBe("@pipelab/app@1.0.0"); + }); + + test("fetchPackageReleases - includes prereleases when allowPrerelease is true", async () => { + // 1. mock matching refs + fetchSpy.mockResolvedValueOnce({ + ok: true, + json: async () => [ + { ref: "refs/tags/@pipelab/app@1.0.0-beta.1" }, + { ref: "refs/tags/@pipelab/app@1.0.0" }, + ], + } as any); + + // 2. mock tag lookup for 1.0.0 (since sorting puts 1.0.0 first) + fetchSpy.mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ + tag_name: "@pipelab/app@1.0.0", + prerelease: false, + published_at: "2026-06-04T00:00:00Z", + html_url: "https://github.com/CynToolkit/pipelab/releases/tag/%40pipelab%2Fapp%401.0.0", + assets: [], + }), + } as any); + + const releases = await fetchPackageReleases("@pipelab/app", { allowPrerelease: true }); + expect(releases).toHaveLength(1); + expect(releases[0].tag_name).toBe("@pipelab/app@1.0.0"); + }); + + test("fetchPackageReleases - handles tag that has no release (skips and falls back to older tag)", async () => { + // 1. mock matching refs + fetchSpy.mockResolvedValueOnce({ + ok: true, + json: async () => [ + { ref: "refs/tags/@pipelab/app@1.1.0" }, + { ref: "refs/tags/@pipelab/app@1.0.0" }, + ], + } as any); + + // 2. mock tag lookup for 1.1.0 (returns 404 - no release yet, tag exists) + fetchSpy.mockResolvedValueOnce({ + status: 404, + ok: false, + statusText: "Not Found", + } as any); + + // 3. mock tag lookup for 1.0.0 (returns 200 - release exists) + fetchSpy.mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ + tag_name: "@pipelab/app@1.0.0", + prerelease: false, + published_at: "2026-06-04T00:00:00Z", + assets: [], + }), + } as any); + + const releases = await fetchPackageReleases("@pipelab/app"); + expect(releases).toHaveLength(1); + expect(releases[0].tag_name).toBe("@pipelab/app@1.0.0"); + }); + + test("fetchPackageReleases - handles environment variable PIPELAB_OVERRIDE_RELEASE override", async () => { + process.env.PIPELAB_OVERRIDE_RELEASE = "1.2.3"; + + // Mock direct tag retrieval + fetchSpy.mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ + tag_name: "@pipelab/app@1.2.3", + prerelease: false, + published_at: "2026-06-04T00:00:00Z", + assets: [], + }), + } as any); + + const releases = await fetchPackageReleases("@pipelab/app"); + expect(releases).toHaveLength(1); + expect(releases[0].tag_name).toBe("@pipelab/app@1.2.3"); + expect(fetchSpy).toHaveBeenCalledWith( + expect.stringContaining("releases/tags/%40pipelab%2Fapp%401.2.3"), + expect.any(Object), + ); + }); + + test("fetchLatestPackageRelease - selects newest matching release", async () => { + // Mock matching refs + fetchSpy.mockResolvedValueOnce({ + ok: true, + json: async () => [ + { ref: "refs/tags/@pipelab/app@1.0.0" }, + { ref: "refs/tags/@pipelab/app@2.0.0" }, + { ref: "refs/tags/@pipelab/app@1.5.0" }, + ], + } as any); + + // Mock release lookup for 2.0.0 (since 2.0.0 is highest version) + fetchSpy.mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ + tag_name: "@pipelab/app@2.0.0", + prerelease: false, + published_at: "2026-06-04T00:00:00Z", + assets: [], + }), + } as any); + + const latest = await fetchLatestPackageRelease("@pipelab/app"); + expect(latest).not.toBeNull(); + expect(latest?.tag_name).toBe("@pipelab/app@2.0.0"); + }); + + test("fetchLatestDesktopRelease - queries the @pipelab/app package specifically", async () => { + // Mock matching refs + fetchSpy.mockResolvedValueOnce({ + ok: true, + json: async () => [{ ref: "refs/tags/@pipelab/app@3.0.0" }], + } as any); + + // Mock release lookup + fetchSpy.mockResolvedValueOnce({ + ok: true, + status: 200, + json: async () => ({ + tag_name: "@pipelab/app@3.0.0", + prerelease: false, + published_at: "2026-06-04T00:00:00Z", + assets: [], + }), + } as any); + + const latest = await fetchLatestDesktopRelease(); + expect(latest).not.toBeNull(); + expect(latest?.tag_name).toBe("@pipelab/app@3.0.0"); + }); +}); diff --git a/packages/core-node/src/utils/github.ts b/packages/core-node/src/utils/github.ts new file mode 100644 index 00000000..25a47799 --- /dev/null +++ b/packages/core-node/src/utils/github.ts @@ -0,0 +1,199 @@ +import semver from "semver"; + +export interface GitHubRelease { + tag_name: string; + prerelease: boolean; + published_at: string; + html_url: string; + assets: Array<{ + name: string; + browser_download_url: string; + }>; +} + +export interface FetchReleaseOptions { + repo?: string; + allowPrerelease?: boolean; +} + +/** + * Fetches all releases for a specific package from GitHub. + * Tags are expected to follow the pattern "{packageName}@{version}" + */ +export async function fetchPackageReleases( + packageName: string, + options: FetchReleaseOptions = {}, +): Promise { + const { repo = "CynToolkit/pipelab", allowPrerelease = false } = options; + + try { + const override = process.env.PIPELAB_OVERRIDE_RELEASE; + if (override) { + const targetTag = override.includes("@") ? override : `${packageName}@${override}`; + console.log(`[GitHub] Fetching specific override release: ${targetTag}`); + const response = await fetch( + `https://api.github.com/repos/${repo}/releases/tags/${encodeURIComponent(targetTag)}`, + { + headers: { + "User-Agent": "Pipelab-Desktop-Updater", + Accept: "application/vnd.github.v3+json", + }, + signal: AbortSignal.timeout(10000), + }, + ); + if (response.ok) { + const release: GitHubRelease = await response.json(); + return [release]; + } + console.warn(`[GitHub] Override release tag ${targetTag} not found or error occurred`); + } + + const matchingRefsUrl = `https://api.github.com/repos/${repo}/git/matching-refs/tags/${encodeURIComponent(packageName)}`; + console.log(`[GitHub] Querying matching tags from ${matchingRefsUrl}...`); + + const response = await fetch(matchingRefsUrl, { + headers: { + "User-Agent": "Pipelab-Desktop-Updater", + Accept: "application/vnd.github.v3+json", + }, + signal: AbortSignal.timeout(10000), + }); + + if (!response.ok) { + throw new Error(`GitHub API error: ${response.status} ${response.statusText}`); + } + + const refs = await response.json(); + if (!Array.isArray(refs)) { + return []; + } + + // Extract tags matching the packageName@ pattern + const matchingTags = refs + .map((r: any) => r.ref.replace("refs/tags/", "")) + .filter((tag: string) => tag.startsWith(`${packageName}@`)); + + // Filter by semver and prerelease options + const filteredTags = matchingTags.filter((tag: string) => { + const version = tag.split("@").pop(); + if (!version || !semver.valid(version)) { + return false; + } + const isPrerelease = semver.prerelease(version) !== null; + return allowPrerelease || !isPrerelease; + }); + + if (filteredTags.length === 0) { + return []; + } + + // Sort by version (newest/highest first) + filteredTags.sort((a, b) => { + const vA = a.split("@").pop() || "0.0.0"; + const vB = b.split("@").pop() || "0.0.0"; + return semver.rcompare(vA, vB); + }); + + // Walk tags from newest to oldest, skipping any that have no GitHub Release attached. + // A bare git tag (no release) returns 404 from the releases/tags endpoint. + for (const tag of filteredTags) { + console.log(`[GitHub] Fetching release details for tag: ${tag}`); + + const releaseResponse = await fetch( + `https://api.github.com/repos/${repo}/releases/tags/${encodeURIComponent(tag)}`, + { + headers: { + "User-Agent": "Pipelab-Desktop-Updater", + Accept: "application/vnd.github.v3+json", + }, + signal: AbortSignal.timeout(10000), + }, + ); + + if (releaseResponse.status === 404) { + // Tag exists but no Release was published for it — skip and try older tag + console.warn(`[GitHub] Tag "${tag}" has no associated Release, skipping.`); + continue; + } + + if (!releaseResponse.ok) { + throw new Error( + `GitHub API error: ${releaseResponse.status} ${releaseResponse.statusText}`, + ); + } + + const release: GitHubRelease = await releaseResponse.json(); + return [release]; + } + + // All tags were bare (no Release found) + console.warn(`[GitHub] No published Release found for any matching tag of "${packageName}".`); + return []; + } catch (error) { + console.error(`[GitHub] Failed to fetch releases for ${packageName}:`, error); + return []; + } +} + +/** + * Fetches the latest release for a specific package. + * Supports PIPELAB_OVERRIDE_RELEASE environment variable. + */ +export async function fetchLatestPackageRelease( + packageName: string, + options: FetchReleaseOptions = {}, +): Promise { + const releases = await fetchPackageReleases(packageName, options); + + if (releases.length === 0) { + return null; + } + + // Handle environment variable override + const override = process.env.PIPELAB_OVERRIDE_RELEASE; + if (override) { + const targetTag = override.includes("@") ? override : `${packageName}@${override}`; + const release = releases.find((r) => r.tag_name === targetTag); + if (release) { + console.log( + `[GitHub] Using release override from PIPELAB_OVERRIDE_RELEASE: ${release.tag_name}`, + ); + return release; + } + console.warn(`[GitHub] Override release ${override} not found for package ${packageName}`); + } + + // Sort by semver + const getVersion = (tagName: string) => tagName.split("@").pop() || "0.0.0"; + + releases.sort((a, b) => { + const vA = getVersion(a.tag_name); + const vB = getVersion(b.tag_name); + if (semver.valid(vA) && semver.valid(vB)) { + return semver.rcompare(vA, vB); + } + return new Date(b.published_at).getTime() - new Date(a.published_at).getTime(); + }); + + return releases[0]; +} + +/** + * Fetches all releases from GitHub and finds the latest one that matches the Pipelab Desktop app tag. + * This ensures we don't accidentally pick a package release (e.g. @pipelab/shared) as the "latest". + */ +export async function fetchLatestDesktopRelease( + options: FetchReleaseOptions = {}, +): Promise { + const latest = await fetchLatestPackageRelease("@pipelab/app", options); + + if (latest) { + console.log( + `[GitHub] Found latest desktop release: ${latest.tag_name} (${latest.prerelease ? "pre-release" : "stable"})`, + ); + } else { + console.warn(`[GitHub] No desktop releases found`); + } + + return latest; +} diff --git a/packages/core-node/src/utils/remote.test.ts b/packages/core-node/src/utils/remote.test.ts new file mode 100644 index 00000000..e88be350 --- /dev/null +++ b/packages/core-node/src/utils/remote.test.ts @@ -0,0 +1,209 @@ +import { describe, test, expect, beforeEach, afterEach, vi } from "vitest"; +import { isOnline, fetchPackage, fetchPipelabPlugin } from "./remote"; +import dns from "node:dns/promises"; +import pacote from "pacote"; +import { vol } from "memfs"; +import { PipelabContext } from "../context"; +import fs from "node:fs/promises"; +import path from "node:path"; +import { existsSync } from "node:fs"; + +vi.mock("node:dns/promises", () => ({ + default: { + lookup: vi.fn(), + }, +})); + +vi.mock("node:fs", async () => { + const memfs = await import("memfs"); + return { + ...memfs.fs, + default: memfs.fs, + existsSync: (p: string) => memfs.fs.existsSync(p), + }; +}); + +vi.mock("node:fs/promises", async () => { + const memfs = await import("memfs"); + return { + ...memfs.fs.promises, + default: memfs.fs.promises, + }; +}); + +vi.mock("pacote", () => ({ + default: { + packument: vi.fn(), + extract: vi.fn(), + }, +})); + +describe("remote utilities & offline mode", () => { + beforeEach(() => { + vi.useFakeTimers(); + vol.reset(); + vi.restoreAllMocks(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + test("isOnline returns true when dns.lookup succeeds", async () => { + vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any); + const online = await isOnline(); + expect(online).toBe(true); + }); + + test("isOnline returns false when dns.lookup throws", async () => { + vi.advanceTimersByTime(11000); // Bypass 10s caching + vi.spyOn(dns, "lookup").mockRejectedValue(new Error("ENOTFOUND")); + const online = await isOnline(); + expect(online).toBe(false); + }); + + test("fetchPackage falls back to local packages when offline", async () => { + // 1. Force offline status + vi.advanceTimersByTime(11000); // Bypass 10s caching + vi.spyOn(dns, "lookup").mockRejectedValue(new Error("Offline")); + + const context = new PipelabContext({ userDataPath: "/tmp/pipelab-test-remote" }); + const packageName = "my-plugin"; + const packageBaseDir = context.getPackagesPath(packageName); + const cachedVersionDir = path.join(packageBaseDir, "1.0.0"); + + await fs.mkdir(cachedVersionDir, { recursive: true }); + await fs.writeFile( + path.join(cachedVersionDir, "package.json"), + JSON.stringify({ + name: packageName, + version: "1.0.0", + main: "index.mjs", + }), + ); + + // 2. Call fetchPackage + const result = await fetchPackage(packageName, "latest", { context }); + + // 3. Verify it resolved to local cached version without calling pacote + expect(result.resolvedVersion).toBe("1.0.0"); + expect(result.packageDir).toBe(cachedVersionDir); + expect(pacote.packument).not.toHaveBeenCalled(); + }); + + test("fetchPipelabPlugin maps latest to releaseTag for official plugins", async () => { + vi.advanceTimersByTime(30000); // Bypass 10s caching + const context = new PipelabContext({ + userDataPath: "/tmp/pipelab-test-remote", + releaseTag: "beta", + }); + const pluginName = "@pipelab/plugin-poki"; + const packageBaseDir = context.getPackagesPath(pluginName); + const cachedVersionDir = path.join(packageBaseDir, "1.0.0-beta.15"); + + vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any); + + vi.mocked(pacote.packument).mockResolvedValue({ + name: pluginName, + versions: { + "1.0.0-beta.15": {}, + }, + "dist-tags": { + beta: "1.0.0-beta.15", + }, + } as any); + + await fs.mkdir(cachedVersionDir, { recursive: true }); + await fs.writeFile( + path.join(cachedVersionDir, "package.json"), + JSON.stringify({ + name: pluginName, + version: "1.0.0-beta.15", + main: "dist/index.mjs", + }), + ); + + const result = await fetchPipelabPlugin(pluginName, "latest", { context }); + + expect(pacote.packument).toHaveBeenCalledWith(pluginName, expect.any(Object)); + expect(result.packageDir).toBe(cachedVersionDir); + }); + + test("fetchPipelabPlugin maps latest to releaseTag for custom plugins and falls back to latest if tag is missing", async () => { + vi.advanceTimersByTime(40000); // Bypass 10s caching + const context = new PipelabContext({ + userDataPath: "/tmp/pipelab-test-remote-custom", + releaseTag: "beta", + }); + const pluginName = "custom-cool-plugin"; + const packageBaseDir = context.getPackagesPath(pluginName); + const cachedVersionDir = path.join(packageBaseDir, "2.0.0"); + + vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any); + + vi.mocked(pacote.packument).mockResolvedValue({ + name: pluginName, + versions: { + "2.0.0": {}, + }, + "dist-tags": { + latest: "2.0.0", + }, + } as any); + + await fs.mkdir(cachedVersionDir, { recursive: true }); + await fs.writeFile( + path.join(cachedVersionDir, "package.json"), + JSON.stringify({ + name: pluginName, + version: "2.0.0", + main: "dist/index.mjs", + }), + ); + + const result = await fetchPipelabPlugin(pluginName, "latest", { context }); + + expect(pacote.packument).toHaveBeenCalledWith(pluginName, expect.any(Object)); + expect(result.packageDir).toBe(cachedVersionDir); + }); + + test("fetchPipelabPlugin maps latest to releaseTag for custom plugins and falls back to latest if beta is stale", async () => { + vi.advanceTimersByTime(50000); // Bypass 10s caching + const context = new PipelabContext({ + userDataPath: "/tmp/pipelab-test-remote-stale", + releaseTag: "beta", + }); + const pluginName = "stale-beta-plugin"; + const packageBaseDir = context.getPackagesPath(pluginName); + const cachedVersionDir = path.join(packageBaseDir, "2.0.0"); + + vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any); + + vi.mocked(pacote.packument).mockResolvedValue({ + name: pluginName, + versions: { + "1.0.0-beta.1": {}, + "2.0.0": {}, + }, + "dist-tags": { + beta: "1.0.0-beta.1", + latest: "2.0.0", + }, + } as any); + + await fs.mkdir(cachedVersionDir, { recursive: true }); + await fs.writeFile( + path.join(cachedVersionDir, "package.json"), + JSON.stringify({ + name: pluginName, + version: "2.0.0", + main: "dist/index.mjs", + }), + ); + + const result = await fetchPipelabPlugin(pluginName, "latest", { context }); + + expect(pacote.packument).toHaveBeenCalledWith(pluginName, expect.any(Object)); + expect(result.packageDir).toBe(cachedVersionDir); + }); +}); diff --git a/packages/core-node/src/utils/remote.ts b/packages/core-node/src/utils/remote.ts new file mode 100644 index 00000000..e996daee --- /dev/null +++ b/packages/core-node/src/utils/remote.ts @@ -0,0 +1,766 @@ +import { dirname, delimiter, join } from "node:path"; +import { + mkdir, + readdir, + readFile, + writeFile, + access, + chmod, + rm, + cp, + rename, +} from "node:fs/promises"; +import { existsSync, constants, statSync, readdirSync } from "node:fs"; +import dns from "node:dns/promises"; +import pacote from "pacote"; +import semver from "semver"; +import { isDev, projectRoot, PipelabContext, CacheFolder } from "../context"; +import { execa } from "execa"; +import { sendStartupProgress } from "../server"; +import { downloadFile, extractZip, extractTarGz } from "./fs-extras"; + +import { DEFAULT_NODE_VERSION, DEFAULT_PNPM_VERSION } from "@pipelab/constants"; + +function isPackageComplete(packageDir: string): boolean { + return existsSync(join(packageDir, "package.json")); +} + +function isNodeJSComplete(nodePath: string): boolean { + try { + return existsSync(nodePath) && statSync(nodePath).size > 0; + } catch { + return false; + } +} + +function isDependenciesInstalledSync(packageDir: string): boolean { + const nodeModulesPath = join(packageDir, "node_modules"); + if (!existsSync(nodeModulesPath)) return false; + try { + const files = readdirSync(nodeModulesPath); + return files.length > 0; + } catch { + return false; + } +} + +/** + * In-memory lock to prevent concurrent operations on the same resource (e.g., downloading Node.js). + */ +const activeOperations = new Map>(); +const packumentRequests = new Map>(); + +async function withLock(key: string, fn: () => Promise): Promise { + const existing = activeOperations.get(key); + if (existing) { + console.log(`[Lock] Waiting for concurrent operation on: ${key}`); + return existing; + } + + const promise = (async () => { + try { + return await fn(); + } finally { + activeOperations.delete(key); + } + })(); + + activeOperations.set(key, promise); + return promise; +} + +let isOnlineCached: boolean | null = null; +let lastCheckTime = 0; + +export async function isOnline(): Promise { + const now = Date.now(); + if (isOnlineCached !== null && now - lastCheckTime < 10000) { + return isOnlineCached; + } + try { + await Promise.race([ + dns.lookup("registry.npmjs.org"), + new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 1500)), + ]); + isOnlineCached = true; + } catch { + isOnlineCached = false; + } + lastCheckTime = now; + return isOnlineCached; +} + +export type FetchOptions = { + installDeps?: boolean; + signal?: AbortSignal; + context: PipelabContext; +}; + +function allowPrereleaseInRange(rangeStr: string): string { + try { + const r = new semver.Range(rangeStr); + return r.set + .map((conj) => + conj + .map((c) => { + const v = c.semver; + if (v.prerelease && v.prerelease.length) { + return c.operator + v.format(); + } + return c.operator + v.major + "." + v.minor + "." + v.patch + "-0"; + }) + .join(" "), + ) + .join(" || "); + } catch { + return rangeStr; + } +} + +/** + * Robust utility to fetch, cache, and resolve an NPM package. + * Centralized in core-node to avoid circular dependencies. + */ +export async function fetchPackage( + packageName: string, + versionOrRange: string, + options: FetchOptions, +): Promise<{ + packageDir: string; + resolvedVersion: string; + isLocal?: boolean; + entryPoint?: string; +}> { + const start = Date.now(); + // 0. Check for local monorepo package in development + if (isDev && projectRoot && process.env.PIPELAB_FORCE_NPM !== "true") { + if (packageName.startsWith("@pipelab/")) { + const localStart = Date.now(); + const local = await tryResolveMonorepoPackage(packageName); + if (local) { + console.debug(`[Fetcher] ${packageName}: Resolved to local source at ${local.packageDir} (${Date.now() - localStart}ms)`, + ); + return { + ...local, + resolvedVersion: "workspace", + }; + } + } + } + + const ctx = options.context; + const baseDir = ctx.getPackagesPath(packageName); + let resolvedVersion: string; + const includePrerelease = !!(ctx.releaseTag && ctx.releaseTag !== "latest"); + + let resolvedVersionOrRange = versionOrRange; + if (resolvedVersionOrRange === "local") { + resolvedVersionOrRange = "latest"; + } + + console.debug(`[Fetcher] Resolving ${packageName}@${resolvedVersionOrRange || "latest"}...`); + const resolveStart = Date.now(); + + const online = await isOnline(); + if (!online) { + console.warn( + `[Fetcher] ${packageName}: offline mode detected (${Date.now() - resolveStart}ms), trying local fallback...`, + ); + const fallbackStart = Date.now(); + const fallbackVersion = await tryLocalFallback( + resolvedVersionOrRange, + new Error("Offline"), + baseDir, + packageName, + includePrerelease, + ); + if (fallbackVersion) { + resolvedVersion = fallbackVersion; + console.debug(`[Fetcher] ${packageName}: Resolved to local fallback ${resolvedVersion} (${Date.now() - fallbackStart}ms)`, + ); + } else { + throw new Error(`Offline and no local fallback version available for ${packageName}`); + } + } else { + try { + // 1. Resolve version/range using npm with session-wide memoization and disk cache + const cachePath = ctx.getCachePath(CacheFolder.Pacote); + let packumentPromise = packumentRequests.get(packageName); + if (!packumentPromise) { + packumentPromise = pacote.packument(packageName, { cache: cachePath }); + packumentRequests.set(packageName, packumentPromise); + } + + const packument = await packumentPromise; + const versions = Object.keys(packument.versions); + const range = resolvedVersionOrRange || "latest"; + + // Prioritize tags (like 'latest', 'beta', etc.) over semver ranges + let foundVersion = + packument["dist-tags"]?.[range] || + semver.maxSatisfying(versions, range, { includePrerelease }); + + // If we are in a non-latest releaseTag channel (like "beta" or "dev"), + // and we are resolving a range, we can prefer the releaseTag version if it exists + // and satisfies the range (ignoring strict prerelease constraints if includePrerelease is true). + if (!foundVersion && ctx.releaseTag && ctx.releaseTag !== "latest") { + const releaseTagVersion = packument["dist-tags"]?.[ctx.releaseTag]; + if (releaseTagVersion && semver.valid(releaseTagVersion)) { + const rewrittenRangeForCheck = allowPrereleaseInRange(range); + if ( + semver.satisfies(releaseTagVersion, rewrittenRangeForCheck, { includePrerelease: true }) + ) { + console.debug(`[Fetcher] Using release tag "${ctx.releaseTag}" (${releaseTagVersion}) for ${packageName}@${range} because it satisfies the range`, + ); + foundVersion = releaseTagVersion; + } + } + } + + // If we still don't have a version, and includePrerelease is true, try rewriting the range to allow prerelease matching + if (!foundVersion && includePrerelease) { + const rewrittenRange = allowPrereleaseInRange(range); + if (rewrittenRange !== range) { + const matched = semver.maxSatisfying(versions, rewrittenRange, { includePrerelease }); + if (matched) { + console.debug(`[Fetcher] Resolved ${packageName}@${range} to ${matched} via rewritten range ${rewrittenRange}`, + ); + foundVersion = matched; + } + } + } + + // If we are in a non-latest releaseTag channel (like "beta" or "dev"), + // and we are resolving "latest", we prefer the releaseTag version if it exists + // and is newer than (or equal to) the latest stable version. + if (range === "latest" && ctx.releaseTag && ctx.releaseTag !== "latest") { + const releaseTagVersion = packument["dist-tags"]?.[ctx.releaseTag]; + if (releaseTagVersion && semver.valid(releaseTagVersion)) { + if ( + !foundVersion || + (semver.valid(foundVersion) && semver.gte(releaseTagVersion, foundVersion)) + ) { + console.debug(`[Fetcher] Using release tag "${ctx.releaseTag}" (${releaseTagVersion}) instead of "latest" (${foundVersion || "none"}) for ${packageName}`, + ); + foundVersion = releaseTagVersion; + } else if (foundVersion) { + console.warn( + `[Fetcher] Tag "${ctx.releaseTag}" (${releaseTagVersion}) is older than "latest" (${foundVersion}) for ${packageName}, keeping "latest"`, + ); + } + } + } + + if (!foundVersion) { + throw new Error( + `Package ${packageName}@${range} not found on npm (available tags: ${Object.keys(packument["dist-tags"] || {}).join(", ")})`, + ); + } + resolvedVersion = foundVersion; + console.debug(`[Fetcher] ${packageName}: Resolved to v${resolvedVersion} via npm (${Date.now() - resolveStart}ms)`, + ); + } catch (error) { + console.warn( + `[Fetcher] ${packageName}: remote resolution failed (${Date.now() - resolveStart}ms), trying local fallback...`, + ); + const fallbackStart = Date.now(); + const fallbackVersion = await tryLocalFallback( + resolvedVersionOrRange, + error, + baseDir, + packageName, + includePrerelease, + ); + if (fallbackVersion) { + resolvedVersion = fallbackVersion; + console.debug(`[Fetcher] ${packageName}: Resolved to local fallback ${resolvedVersion} (${Date.now() - fallbackStart}ms)`, + ); + } else { + throw error; + } + } + } + + const cachePath = ctx.getCachePath(CacheFolder.Pacote); + const packageDir = join(baseDir, resolvedVersion); + + const checkStart = Date.now(); + // If the package already exists and we don't need to install dependencies (or they are already installed), return immediately + const isInstalled = options?.installDeps + ? isPackageComplete(packageDir) && isDependenciesInstalledSync(packageDir) + : isPackageComplete(packageDir); + const checkDuration = Date.now() - checkStart; + + if (isInstalled) { + console.debug(`[Fetcher] ${packageName}@${resolvedVersion}: Already installed (check took ${checkDuration}ms, fetchPackage took ${Date.now() - start}ms)`, + ); + return { packageDir, resolvedVersion }; + } + + const lockKey = `package:${packageName}:${resolvedVersion}`; + return withLock(lockKey, async () => { + if (!isPackageComplete(packageDir)) { + console.debug(`[Fetcher] ${packageName}@${resolvedVersion}: Downloading to ${packageDir}...`); + const downloadStart = Date.now(); + + const tempDir = join( + baseDir, + `.tmp-${resolvedVersion}-${Math.random().toString(36).slice(2)}`, + ); + await mkdir(tempDir, { recursive: true }); + try { + await pacote.extract(`${packageName}@${resolvedVersion}`, tempDir, { + cache: cachePath, + }); + + // Resolve entryPoint from package.json inside the temp directory first to ensure everything works + await resolveEntryPoint(tempDir, packageName); + + // Remove existing incomplete packageDir if any + if (existsSync(packageDir)) { + await rm(packageDir, { recursive: true, force: true }).catch(() => {}); + } + + // Atomically rename the temp directory to the target packageDir + try { + await rename(tempDir, packageDir); + } catch (err: any) { + if (isPackageComplete(packageDir)) { + console.debug(`[Fetcher] Destination ${packageDir} already exists and is valid.`); + } else { + throw err; + } + } + console.debug(`[Fetcher] ${packageName}@${resolvedVersion}: Downloaded and extracted in ${Date.now() - downloadStart}ms`, + ); + } catch (err) { + await rm(tempDir, { recursive: true, force: true }).catch(() => {}); + throw err; + } + } + + // 2. Resolve entry point from package.json for downloaded package + const entryStart = Date.now(); + const entryPoint = await resolveEntryPoint(packageDir, packageName); + console.debug(`[Fetcher] ${packageName}@${resolvedVersion}: Resolved entry point in ${Date.now() - entryStart}ms`, + ); + + if (options?.installDeps) { + const depsStart = Date.now(); + await installDependencies(packageDir, packageName, options); + console.debug(`[Fetcher] ${packageName}@${resolvedVersion}: Installed dependencies in ${Date.now() - depsStart}ms`, + ); + } + + console.debug(`[Fetcher] ${packageName}@${resolvedVersion}: FetchPackage complete in ${Date.now() - start}ms`, + ); + return { packageDir, resolvedVersion, entryPoint }; + }); +} + +/** + * Executes a pnpm install in a specific directory with a portable environment. + */ +export async function runPnpm( + cwd: string, + options: { + args?: string[]; + extraEnv?: Record; + signal?: AbortSignal; + context: PipelabContext; + }, +) { + const { + args = [ + "install", + "--prod", + "--no-lockfile", + "--prefer-offline", + "--no-verify-store-integrity", + ], + extraEnv = {}, + signal, + context: ctx, + } = options; + + const [nodePath, pnpmPath] = await Promise.all([ + ensureNodeJS(ctx).catch(() => process.execPath), + ensurePNPM(ctx).catch(() => "pnpm"), + ]); + + const isScript = pnpmPath.endsWith(".cjs") || pnpmPath.endsWith(".js"); + const command = isScript ? nodePath : pnpmPath; + const finalArgs = isScript ? [pnpmPath, ...args] : args; + + return execa(command, finalArgs, { + cwd, + all: true, + cancelSignal: signal, + env: { + ...process.env, + NODE_ENV: "production", + PATH: nodePath ? `${dirname(nodePath)}${delimiter}${process.env.PATH}` : process.env.PATH, + PNPM_HOME: ctx.getPnpmPath(), + PNPM_ONLY_ALLOW_TRUSTED_DEPENDENCIES: "false", + ...extraEnv, + }, + }); +} + +/** + * Installs a specific version of Node.js if not already present. + */ +export async function ensureNodeJS(context: PipelabContext, version = DEFAULT_NODE_VERSION) { + const checkStart = Date.now(); + const isWindows = process.platform === "win32"; + const nodeDir = context.getThirdPartyPath("node", version); + const finalNodePath = join(nodeDir, isWindows ? "node.exe" : "bin/node"); + + if (isNodeJSComplete(finalNodePath)) { + console.debug(`[Environment] Node.js check took ${Date.now() - checkStart}ms (found at ${finalNodePath})`, + ); + return finalNodePath; + } + + const lockKey = `node:${version}`; + return withLock(lockKey, async () => { + if (isNodeJSComplete(finalNodePath)) return finalNodePath; + + const arch = process.arch === "x64" ? "x64" : process.arch === "arm64" ? "arm64" : "x86"; + const platform = isWindows ? "win" : process.platform === "darwin" ? "osx" : "linux"; + const extension = isWindows ? "zip" : "tar.gz"; + const downloadPlatform = platform === "osx" ? "darwin" : platform; + + const fileName = `node-v${version}-${downloadPlatform}-${arch}.${extension}`; + const downloadUrl = `https://nodejs.org/dist/v${version}/${fileName}`; + const tempDir = await context.createTempFolder("node-download-"); + const archivePath = join(tempDir, fileName); + + sendStartupProgress(`Downloading Node.js v${version}...`); + console.log(`Downloading Node.js from ${downloadUrl}...`); + const dlStart = Date.now(); + await downloadFile(downloadUrl, archivePath); + console.debug(`[Environment] Node.js download took ${Date.now() - dlStart}ms`); + + sendStartupProgress(`Extracting Node.js v${version}...`); + console.log(`Extracting Node.js to ${tempDir}...`); + const extStart = Date.now(); + const extractTempDir = join(tempDir, "extracted"); + await mkdir(extractTempDir, { recursive: true }); + + if (extension === "zip") { + await extractZip(archivePath, extractTempDir); + } else { + await extractTarGz(archivePath, extractTempDir); + } + + const extractedEntries = await readdir(extractTempDir); + const nodeSubDir = extractedEntries.find((entry) => entry.startsWith(`node-v${version}`)); + if (!nodeSubDir) throw new Error(`Could not find extracted Node.js directory`); + + const sourceDir = join(extractTempDir, nodeSubDir); + const parentDir = dirname(nodeDir); + await mkdir(parentDir, { recursive: true }); + + const tempNodeDir = join( + parentDir, + `.tmp-node-${version}-${Math.random().toString(36).slice(2)}`, + ); + await mkdir(tempNodeDir, { recursive: true }); + + try { + await cp(sourceDir, tempNodeDir, { recursive: true }); + if (!isWindows) { + const tempNodePath = join(tempNodeDir, "bin/node"); + await chmod(tempNodePath, 0o755).catch(() => {}); + } + + if (existsSync(nodeDir)) { + await rm(nodeDir, { recursive: true, force: true }).catch(() => {}); + } + + try { + await rename(tempNodeDir, nodeDir); + } catch (err: any) { + if (isNodeJSComplete(finalNodePath)) { + console.debug(`[Fetcher] Node.js directory already exists and is valid.`); + } else { + throw err; + } + } + console.debug(`[Environment] Node.js extraction took ${Date.now() - extStart}ms`); + } finally { + await rm(tempNodeDir, { recursive: true, force: true }).catch(() => {}); + await rm(tempDir, { recursive: true, force: true }).catch(() => {}); + } + + console.debug(`[Environment] Node.js set up complete in ${Date.now() - checkStart}ms`); + return finalNodePath; + }); +} + +/** + * Installs the PNPM package from npm if not already present. + */ +export async function ensurePNPM(context: PipelabContext, version = DEFAULT_PNPM_VERSION) { + const checkStart = Date.now(); + const pnpmDir = context.getPackagesPath("pnpm", version); + const pnpmPath = join(pnpmDir, "bin", "pnpm.cjs"); + + if (existsSync(pnpmPath)) { + console.debug(`[Environment] PNPM check took ${Date.now() - checkStart}ms (found at ${pnpmPath})`, + ); + return pnpmPath; + } + + const lockKey = `pnpm:${version}`; + return withLock(lockKey, async () => { + if (existsSync(pnpmPath)) return pnpmPath; + sendStartupProgress(`Checking PNPM v${version}...`); + const { packageDir } = await fetchPackage("pnpm", version, { + context, + }); + console.debug(`[Environment] PNPM set up complete in ${Date.now() - checkStart}ms`); + return join(packageDir, "bin", "pnpm.cjs"); + }); +} + +async function installDependencies(packageDir: string, packageName: string, options: FetchOptions) { + const start = Date.now(); + const nodeModulesPath = join(packageDir, "node_modules"); + + if (isDependenciesInstalledSync(packageDir)) { + console.debug(`[Fetcher] ${packageName}: Dependencies already installed, skipping.`); + return; + } + + try { + console.debug(`[Fetcher] ${packageName}: Ensuring dependencies are installed...`); + const pnpmStart = Date.now(); + const { all } = await runPnpm(packageDir, { + signal: options.signal, + context: options.context, + }); + console.debug(`[Fetcher] ${packageName}: pnpm install command took ${Date.now() - pnpmStart}ms`); + + if (all) console.debug(`[Fetcher] ${packageName}: Installation trace:\n${all}`); + + console.debug(`[Fetcher] ${packageName}: Dependencies installed successfully (total installDependencies took ${Date.now() - start}ms).`, + ); + } catch (err: any) { + console.error( + `[Fetcher] ${packageName}: CRITICAL ERROR during dependency installation: ${err.message}`, + ); + if (err.all) console.error(`[Fetcher] ${packageName}: Error details:\n${err.all}`); + // Clean up node_modules on error to allow retries + await rm(nodeModulesPath, { recursive: true, force: true }).catch(() => {}); + throw new Error(`Failed to install dependencies for ${packageName}. See logs for details.`); + } +} + +export async function fetchPipelabAsset( + packageName: string, + versionOrRange: string, + options: FetchOptions, +): Promise { + if (isDev && projectRoot) { + const assetId = packageName.replace("@pipelab/asset-", ""); + const localPath = join(projectRoot, "assets", `asset-${assetId}`); + if (existsSync(localPath)) return localPath; + } + const { packageDir } = await fetchPackage(packageName, versionOrRange, options); + return packageDir; +} + +export async function fetchPipelabPlugin( + pluginName: string, + versionOrRange: string, + options: FetchOptions, +): Promise<{ packageDir: string; entryPoint: string; isLocal: boolean }> { + const { packageDir, isLocal, entryPoint } = await fetchPackage(pluginName, versionOrRange, { + installDeps: false, + ...options, + }); + + // Default entry point if not provided by fetchPackage + let finalEntryPoint = entryPoint; + if (!finalEntryPoint) { + const patterns = [join(packageDir, "dist", "index.mjs"), join(packageDir, "index.mjs")]; + finalEntryPoint = patterns.find((p) => existsSync(p)) || patterns[0]; + } + + return { packageDir, entryPoint: finalEntryPoint, isLocal: !!isLocal }; +} + +export async function fetchPipelabCli( + versionOrRange: string, + options: FetchOptions, +): Promise<{ packageDir: string; entryPoint: string; isLocal: boolean }> { + const { packageDir, isLocal, entryPoint } = await fetchPackage( + "@pipelab/cli", + versionOrRange, + options, + ); + + // Default entry point for CLI if not provided + let finalEntryPoint = entryPoint; + if (!finalEntryPoint) { + const patterns = [join(packageDir, "dist", "index.mjs"), join(packageDir, "index.mjs")]; + finalEntryPoint = patterns.find((p) => existsSync(p)) || patterns[0]; + } + + return { packageDir, entryPoint: finalEntryPoint, isLocal: !!isLocal }; +} + +/** + * Cache for monorepo package locations to avoid repeated disk crawling. + */ +let monorepoCache: Record | null = null; + +async function tryResolveMonorepoPackage( + packageName: string, +): Promise<{ packageDir: string; isLocal: boolean; entryPoint: string } | null> { + if (!monorepoCache) { + monorepoCache = await crawlMonorepoPackages(); + } + + const packageDir = monorepoCache[packageName]; + if (!packageDir) return null; + + // Find best entry point from package.json + let entryPoint: string | undefined; + try { + const pkgPath = join(packageDir, "package.json"); + const pkg = JSON.parse(await readFile(pkgPath, "utf-8")); + + // 1. Try to find the entry point from package.json + // User tip: main is usually source in dev, publishConfig.main is compiled for prod + const publishMain = pkg.publishConfig?.module || pkg.publishConfig?.main; + const devMain = pkg.module || pkg.main; + + // Check bin field if it's a CLI + const binField = + typeof pkg.bin === "string" + ? pkg.bin + : pkg.bin?.[packageName.replace("@pipelab/", "")] || + (pkg.bin ? pkg.bin[Object.keys(pkg.bin)[0]] : undefined); + + // In dev, we prefer the "main" field if it points to TS, or a hardcoded src/index.ts + const tsSource = join(packageDir, "src", "index.ts"); + + if (devMain && devMain.endsWith(".ts")) { + entryPoint = join(packageDir, devMain); + } else if (existsSync(tsSource)) { + entryPoint = tsSource; + } else if (binField) { + entryPoint = join(packageDir, binField); + } else if (publishMain) { + entryPoint = join(packageDir, publishMain); + } else if (devMain) { + entryPoint = join(packageDir, devMain); + } + } catch (e) { + console.warn(`[Fetcher] Failed to parse package.json for ${packageName}:`, e); + } + + return { + packageDir, + isLocal: true, + entryPoint: entryPoint || join(packageDir, "dist", "index.mjs"), + }; +} + +async function crawlMonorepoPackages(): Promise> { + const cache: Record = {}; + if (!projectRoot) return cache; + + const searchDirs = ["plugins", "packages", "apps"]; + for (const dir of searchDirs) { + const fullDir = join(projectRoot, dir); + if (!existsSync(fullDir)) continue; + + try { + const entries = await readdir(fullDir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory()) { + const pkgPath = join(fullDir, entry.name, "package.json"); + if (existsSync(pkgPath)) { + try { + const pkg = JSON.parse(await readFile(pkgPath, "utf-8")); + if (pkg.name) { + cache[pkg.name] = join(fullDir, entry.name); + } + } catch (e) {} + } + } + } + } catch (e) {} + } + return cache; +} + +async function tryLocalFallback( + versionOrRange: string | undefined, + _error: unknown, + baseDir: string, + logPrefix: string, + includePrerelease = false, +): Promise { + if (!existsSync(baseDir)) return null; + try { + const entries = await readdir(baseDir, { withFileTypes: true }); + const localVersions = entries + .filter((e) => e.isDirectory() || e.isSymbolicLink()) + .map((e) => e.name) + .filter((name) => !!semver.valid(name)); + + if (localVersions.length === 0) return null; + + const range = versionOrRange || "latest"; + + if (range === "latest") { + const sorted = localVersions.sort((a, b) => semver.rcompare(a, b)); + const latestLocal = sorted[0] || null; + if (latestLocal) { + console.info(`[Fetcher] ${logPrefix}: Using locally cached latest version: ${latestLocal}`); + return latestLocal; + } + } else { + const matched = semver.maxSatisfying(localVersions, range, { includePrerelease }); + if (matched) { + console.info( + `[Fetcher] ${logPrefix}: Using locally cached matching version: ${matched} for range ${range}`, + ); + return matched; + } + } + } catch (e) { + console.warn(`[Fetcher] ${logPrefix}: Error during local fallback resolution:`, e); + } + return null; +} + +/** + * Resolves the entry point of a package by looking at its package.json. + */ +async function resolveEntryPoint(packageDir: string, packageName: string) { + try { + const pkgPath = join(packageDir, "package.json"); + if (!existsSync(pkgPath)) return undefined; + + const pkg = JSON.parse(await readFile(pkgPath, "utf-8")); + const main = pkg.module || pkg.main || pkg.publishConfig?.module || pkg.publishConfig?.main; + + if (main) { + return join(packageDir, main); + } + + if (pkg.bin) { + const binFile = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0]; + if (binFile) return join(packageDir, binFile as string); + } + } catch (e) { + console.warn(`[Fetcher] ${packageName}: Failed to resolve entry point:`, e); + } + return undefined; +} diff --git a/packages/core-node/src/utils/storage.ts b/packages/core-node/src/utils/storage.ts new file mode 100644 index 00000000..986e86f7 --- /dev/null +++ b/packages/core-node/src/utils/storage.ts @@ -0,0 +1,100 @@ +import fs from "node:fs"; +import path from "node:path"; +import { useLogger } from "@pipelab/shared"; +import { PipelabContext } from "../context"; + +/** + * A generic file-based storage implementation for persisting JSON data. + * Useful for Supabase Auth and other CLI-specific persistent data. + */ +export class JsonFileStorage { + private filePath: string; + private logger = useLogger().logger; + + constructor(fileName: string, context: PipelabContext) { + this.filePath = context.getConfigPath(fileName); + + const dir = path.dirname(this.filePath); + if (!fs.existsSync(dir)) { + try { + fs.mkdirSync(dir, { recursive: true }); + } catch (e) { + this.logger().error(`[Storage] Failed to create directory ${dir}:`, e); + throw e; + } + } + } + + getItem(key: string): string | null { + try { + if (!fs.existsSync(this.filePath)) return null; + const content = fs.readFileSync(this.filePath, "utf8"); + if (!content) return null; + const data = JSON.parse(content); + return data[key] || null; + } catch (e) { + this.logger().error(`[Storage] Failed to read or parse ${this.filePath}:`, e); + // We throw here because the user explicitly asked NOT to ignore errors + throw e; + } + } + + setItem(key: string, value: string): void { + try { + let data: any = {}; + if (fs.existsSync(this.filePath)) { + const content = fs.readFileSync(this.filePath, "utf8"); + if (content) { + data = JSON.parse(content); + } + } + data[key] = value; + fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf8"); + } catch (e) { + this.logger().error(`[Storage] Failed to write to ${this.filePath}:`, e); + throw e; + } + } + + removeItem(key: string): void { + try { + if (!fs.existsSync(this.filePath)) return; + const content = fs.readFileSync(this.filePath, "utf8"); + if (!content) return; + const data = JSON.parse(content); + delete data[key]; + fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf8"); + } catch (e) { + this.logger().error(`[Storage] Failed to remove key from ${this.filePath}:`, e); + throw e; + } + } + + /** + * Helper to get the entire data object + */ + getAll(): Record { + try { + if (!fs.existsSync(this.filePath)) return {}; + const content = fs.readFileSync(this.filePath, "utf8"); + return content ? JSON.parse(content) : {}; + } catch (e) { + this.logger().error(`[Storage] Failed to read all data from ${this.filePath}:`, e); + throw e; + } + } + + /** + * Helper to clear the entire storage file + */ + clear(): void { + try { + if (fs.existsSync(this.filePath)) { + fs.unlinkSync(this.filePath); + } + } catch (e) { + this.logger().error(`[Storage] Failed to clear ${this.filePath}:`, e); + throw e; + } + } +} diff --git a/packages/core-node/src/websocket-server.ts b/packages/core-node/src/websocket-server.ts new file mode 100644 index 00000000..b0be4abe --- /dev/null +++ b/packages/core-node/src/websocket-server.ts @@ -0,0 +1,288 @@ +import { WebSocketServer as WSWebSocketServer, WebSocket as WSWebSocket } from "ws"; +import http, { IncomingMessage } from "node:http"; +import { nanoid } from "nanoid"; +import { useAPI } from "./ipc-core"; +import { useLogger } from "@pipelab/shared"; +import { + WebSocketServerConfig, + WebSocketServerEvents, + WebSocketConnectionState, + WebSocketError, + WebSocketMessage, + isWebSocketRequestMessage, + Agent, + Channels, + Events, +} from "@pipelab/shared"; +import { websocketPort } from "@pipelab/constants"; + +export interface ConnectedClient { + id: string; + name: string; + ws: WSWebSocket; + connectedAt: number; +} + +export class WebSocketServer { + private wss: WSWebSocketServer | null = null; + private server: import("http").Server | null = null; + private isReady = false; + private readyResolve: (() => void) | null = null; + private connectionState: WebSocketConnectionState = "disconnected"; + private clients: Map = new Map(); + private lastBroadcasts: Map = new Map(); + + async start(port: number = websocketPort, existingServer?: import("http").Server): Promise { + const { logger } = useLogger(); + + return new Promise((resolve, reject) => { + try { + logger().info("Starting WebSocket server on port", port); + + // Create HTTP server for WebSocket if not provided + const server = existingServer || http.createServer(); + this.server = server; + + // Create WebSocket server + this.wss = new WSWebSocketServer({ server }); + + this.wss.on("connection", (ws: WSWebSocket, request: IncomingMessage) => { + const clientId = nanoid(); + const clientName = `Agent ${clientId.substring(0, 4)}`; + const connectedAt = Date.now(); + + const client: ConnectedClient = { + id: clientId, + name: clientName, + ws, + connectedAt, + }; + + this.clients.set(ws, client); + console.log("WebSocket client connected", { + id: clientId, + name: clientName, + url: request.url, + }); + + // Replay last known state for each channel that has been broadcasted + for (const messageStr of this.lastBroadcasts.values()) { + try { + ws.send(messageStr); + } catch (error) { + logger().error("[WebSocket] Failed to replay sticky event to new client:", error); + } + } + + ws.on("message", (data: Buffer) => { + try { + const message = JSON.parse(data.toString()); + logger().debug("Received WebSocket message:", message); + this.handleWebSocketMessage(ws, message); + } catch (error) { + logger().error("Failed to parse WebSocket message:", error); + this.sendError(ws, undefined, "Invalid message format"); + } + }); + + ws.on("close", (code: number, reason: Buffer) => { + const client = this.clients.get(ws); + if (client) { + logger().info("WebSocket client disconnected", { + id: client.id, + name: client.name, + code, + reason: reason.toString(), + }); + this.clients.delete(ws); + } + }); + + ws.on("error", (error: Error) => { + logger().error("WebSocket client error:", error); + }); + }); + + this.wss.on("error", (error: Error) => { + logger().error("WebSocket server error:", error); + }); + + if (!server.listening) { + server.listen(port, "127.0.0.1", () => { + this.connectionState = "connected"; + logger().info(`WebSocket server listening on port ${port}`); + this.isReady = true; + if (this.readyResolve) { + this.readyResolve(); + } + resolve(); + }); + } else { + this.connectionState = "connected"; + logger().info(`WebSocket server attached to existing listening server`); + this.isReady = true; + if (this.readyResolve) { + this.readyResolve(); + } + resolve(); + } + + server.on("error", (error: Error) => { + this.connectionState = "error"; + logger().error("WebSocket server HTTP error:", error); + reject(new WebSocketError(`Server error: ${error.message}`)); + }); + } catch (error) { + this.connectionState = "error"; + logger().error("Failed to start WebSocket server:", error); + reject( + new WebSocketError( + `Failed to start server: ${error instanceof Error ? error.message : "Unknown error"}`, + ), + ); + } + }); + } + + private async handleWebSocketMessage(ws: WSWebSocket, message: WebSocketMessage) { + const { logger } = useLogger(); + const { processWebSocketMessage } = useAPI(); + + try { + if (isWebSocketRequestMessage(message)) { + logger().debug("Processing WebSocket request message:", { + channel: message.channel, + requestId: message.requestId, + hasData: !!message.data, + }); + + logger().debug("Routing message to handler:", message.channel); + await processWebSocketMessage(ws, message.channel, message); + logger().debug("Handler processed message successfully"); + } else { + logger().warn("Invalid message format received:", { + type: message.type, + requestId: message.requestId, + hasError: "error" in message, + }); + this.sendError( + ws, + message.requestId, + "Invalid message format: missing channel or requestId", + ); + } + } catch (error) { + logger().error("Error processing WebSocket message:", error); + this.sendError( + ws, + message.requestId, + error instanceof Error ? error.message : "Unknown error", + ); + } + } + + private sendError( + ws: WSWebSocket, + requestId: string | undefined, + errorMessage: string, + code?: string, + ) { + try { + const errorResponse: any = { + type: "error", + requestId, + error: errorMessage, + ...(code && { code }), + }; + ws.send(JSON.stringify(errorResponse)); + } catch (error) { + console.error("Failed to send error response:", error); + } + } + + async stop(): Promise { + const { logger } = useLogger(); + + return new Promise((resolve) => { + this.isReady = false; + this.connectionState = "disconnected"; + + if (this.wss) { + this.wss.close(() => { + logger().info("WebSocket server closed"); + resolve(); + }); + } else { + resolve(); + } + + if (this.server) { + this.server.close(); + } + }); + } + + waitForReady(): Promise { + if (this.isReady) { + return Promise.resolve(); + } + + return new Promise((resolve) => { + this.readyResolve = resolve; + }); + } + + isServerReady(): boolean { + return this.isReady; + } + + getConnectionState(): WebSocketConnectionState { + return this.connectionState; + } + + getAgents(): Agent[] { + return Array.from(this.clients.values()).map((client) => ({ + id: client.id, + name: client.name, + isSelf: false, // This will be set by the client itself when receiving the list + connectedAt: client.connectedAt, + })); + } + + getClient(ws: WSWebSocket): ConnectedClient | undefined { + return this.clients.get(ws); + } + + /** + * Broadcasts a message to all connected clients. + * Useful for push notifications like auth state changes. + */ + broadcast(channel: KEY, data: Events): void { + const { logger } = useLogger(); + + const message = { + type: "event", + channel, + data, + }; + + const messageStr = JSON.stringify(message); + this.lastBroadcasts.set(channel, messageStr); + + if (!this.wss || this.clients.size === 0) return; + logger().debug(`[WebSocket] Broadcasting to all clients on channel: ${channel}`); + + for (const client of this.clients.values()) { + try { + if (client.ws.readyState === WSWebSocket.OPEN) { + client.ws.send(messageStr); + } + } catch (error) { + logger().error(`[WebSocket] Failed to broadcast to client ${client.id}:`, error); + } + } + } +} + +// Export singleton instance +export const webSocketServer = new WebSocketServer(); diff --git a/packages/core-node/tsconfig.json b/packages/core-node/tsconfig.json new file mode 100644 index 00000000..c0104fd5 --- /dev/null +++ b/packages/core-node/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../tsconfig/node.json", + "compilerOptions": { + "moduleResolution": "bundler", + "outDir": "dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "baseUrl": ".", + "paths": { + "@pipelab/*": ["../shared/src/libs/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"], + "references": [{ "path": "../constants" }, { "path": "../shared" }] +} diff --git a/packages/core-node/tsdown.config.ts b/packages/core-node/tsdown.config.ts new file mode 100644 index 00000000..7ba5c08d --- /dev/null +++ b/packages/core-node/tsdown.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, +}); diff --git a/packages/migration/.oxfmtrc.json b/packages/migration/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/migration/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/migration/CHANGELOG.md b/packages/migration/CHANGELOG.md new file mode 100644 index 00000000..c970b236 --- /dev/null +++ b/packages/migration/CHANGELOG.md @@ -0,0 +1,193 @@ +# @pipelab/migration + +## 1.0.0-beta.31 + +### Patch Changes + +- - + +## 1.0.0-beta.30 + +### Patch Changes + +- improve dark theme and improve build history + +## 1.0.0-beta.29 + +### Patch Changes + +- sd + +## 1.0.0-beta.28 + +### Patch Changes + +- sd + +## 1.0.0-beta.27 + +### Patch Changes + +- sd + +## 1.0.0-beta.26 + +### Patch Changes + +- sd + +## 1.0.0-beta.25 + +### Patch Changes + +- sd + +## 1.0.0-beta.24 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.23 + +### Patch Changes + +- sd + +## 1.0.0-beta.22 + +### Patch Changes + +- sd + +## 1.0.0-beta.21 + +### Patch Changes + +- sd + +## 1.0.0-beta.20 + +### Patch Changes + +- sd + +## 1.0.0-beta.19 + +### Patch Changes + +- sd + +## 1.0.0-beta.18 + +### Patch Changes + +- sd + +## 1.0.0-beta.17 + +### Patch Changes + +- sd + +## 1.0.0-beta.16 + +### Patch Changes + +- df + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.14 + +### Patch Changes + +- sd + +## 1.0.0-beta.13 + +### Patch Changes + +- sd + +## 1.0.0-beta.12 + +### Patch Changes + +- qs + +## 1.0.0-beta.11 + +### Patch Changes + +- sd + +## 1.0.0-beta.10 + +### Patch Changes + +- s + +## 1.0.0-beta.9 + +### Patch Changes + +- fg + +## 1.0.0-beta.8 + +### Patch Changes + +- changes + +## 1.0.0-beta.7 + +### Patch Changes + +- bump + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes + +## 1.0.0-beta.5 + +### Patch Changes + +- bump + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag + +## 1.0.0-beta.3 + +### Patch Changes + +- bump + +## 1.0.0-beta.2 + +### Patch Changes + +- update + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/packages/migration/README.md b/packages/migration/README.md new file mode 100644 index 00000000..1879b3bc --- /dev/null +++ b/packages/migration/README.md @@ -0,0 +1,3 @@ +# @pipelab/migration + +Handles version migration for Pipelab project files and database schemas. diff --git a/packages/migration/package.json b/packages/migration/package.json new file mode 100644 index 00000000..669bd785 --- /dev/null +++ b/packages/migration/package.json @@ -0,0 +1,58 @@ +{ + "name": "@pipelab/migration", + "version": "1.0.0-beta.31", + "private": false, + "description": "Migration utilities for Pipelab data structures", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "packages/migration" + }, + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "build": "tsdown", + "format": "oxfmt .", + "lint": "oxlint .", + "typecheck": "tsc -b", + "test": "vitest run" + }, + "dependencies": { + "@types/node": "^24.12.2", + "klona": "2.0.6", + "semver": "^7.6.3", + "valibot": "0.42.1" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "@types/semver": "^7.5.8", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + } +} diff --git a/packages/migration/src/index.ts b/packages/migration/src/index.ts new file mode 100644 index 00000000..033b3d1b --- /dev/null +++ b/packages/migration/src/index.ts @@ -0,0 +1,12 @@ +export * from "./models/createMigration"; +export * from "./models/createMigrator"; +export type { + MigrationSchema, + Migrator, + MigratorConfig, + MigrationFn, + SemVer, + OmitVersion, + Awaitable, +} from "./models/migration"; +export { createVersionSchema } from "./models/migration"; diff --git a/packages/migration/src/models/createMigration.ts b/packages/migration/src/models/createMigration.ts new file mode 100644 index 00000000..06fe6bfa --- /dev/null +++ b/packages/migration/src/models/createMigration.ts @@ -0,0 +1,27 @@ +import { + MigrationFn, + MigrationObjInput, + MigrationClass, + MigrationSchema, + OmitVersion, + SemVer, +} from "./migration"; + +export function createMigration( + migration: MigrationObjInput, +): MigrationClass { + return { + version: migration.version, + up: async (state, nextVersion) => { + const newState = migration.up + ? ((await migration.up(state, nextVersion)) as unknown as Up) + : (state as unknown as Up); + newState.version = nextVersion as SemVer; + return newState; + }, + }; +} + +export const finalVersion = () => { + throw new Error("Unable to go up on the final version!"); +}; diff --git a/packages/migration/src/models/createMigrator.ts b/packages/migration/src/models/createMigrator.ts new file mode 100644 index 00000000..c73ba751 --- /dev/null +++ b/packages/migration/src/models/createMigrator.ts @@ -0,0 +1,22 @@ +import { MigratorConfig, Migrator, MigrationSchema } from "./migration"; + +export const createMigrator = < + InitialState extends MigrationSchema, + FinalState extends MigrationSchema, +>() => { + return { + createDefault(defaultState: FinalState): FinalState { + return defaultState; + }, + createMigrations( + config: MigratorConfig, + ): Migrator { + return new Migrator(config); + }, + }; +}; + +export type MigratorFactory< + InitialState extends MigrationSchema, + FinalState extends MigrationSchema, +> = ReturnType>; diff --git a/packages/migration/src/models/migration.spec.ts b/packages/migration/src/models/migration.spec.ts new file mode 100644 index 00000000..d2472396 --- /dev/null +++ b/packages/migration/src/models/migration.spec.ts @@ -0,0 +1,283 @@ +import { describe, test, expect, beforeAll, beforeEach, afterEach, vi } from "vitest"; +import { createMigration, finalVersion } from "./createMigration"; +import { createMigrator, MigratorFactory } from "./createMigrator"; +import { Migrator, MigrationSchema } from "./migration"; +import { z } from "zod"; + +export const withMigration = (obj: z.ZodObject) => + z + .object({ + version: z.string(), + }) + .merge(obj); + +interface V1 extends MigrationSchema { + dummyV1: string; +} + +interface V2 extends MigrationSchema { + dummyV2: string; +} + +interface V3 extends MigrationSchema { + dummyV3: string; +} + +interface V4 extends MigrationSchema { + dummy: string; +} + +const outputV1: V1 = { + dummyV1: "aaa", + version: "1.0.0", +}; + +const outputV2: V2 = { + dummyV2: "aaa", + version: "2.0.0", +}; + +const outputV3: V3 = { + dummyV3: "aaa", + version: "3.0.0", +}; + +const outputV4: V4 = { + dummy: "aaa", + version: "4.0.0", +}; + +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +describe("migrator", () => { + let migratorInstance: MigratorFactory; + let migratorMigrations: Migrator; + beforeAll(() => { + migratorInstance = createMigrator(); + migratorMigrations = migratorInstance.createMigrations({ + defaultValue: outputV4, + migrations: [ + createMigration({ + version: "1.0.0", + up: (state) => ({ + dummyV2: state.dummyV1, + }), + }), + createMigration({ + version: "2.0.0", + up: (state) => ({ + dummyV3: state.dummyV2, + }), + }), + createMigration({ + version: "3.0.0", + up: (state) => ({ + dummy: state.dummyV3, + }), + }), + createMigration({ + version: "4.0.0", + up: finalVersion, + }), + ], + }); + }); + + test("should not need migration", () => { + expect(migratorMigrations.needMigration("4.0.0")).toBe(false); + expect(migratorMigrations.needMigration("5.0.0")).toBe(false); + expect(migratorMigrations.needMigration("4.1.0")).toBe(false); + expect(migratorMigrations.needMigration("4.0.1")).toBe(false); + expect(migratorMigrations.needMigration("5.0.1")).toBe(false); + }); + + test("should need migration", () => { + expect(migratorMigrations.needMigration("0.0.0")).toBe(true); + expect(migratorMigrations.needMigration("0.1.0")).toBe(true); + expect(migratorMigrations.needMigration("0.0.1")).toBe(true); + expect(migratorMigrations.needMigration("1.0.1")).toBe(true); + expect(migratorMigrations.needMigration("2.3.1")).toBe(true); + expect(migratorMigrations.needMigration("3.4.1")).toBe(true); + }); + + test("should migrate", async () => { + const input: V1 = { + dummyV1: "aaa", + version: "1.0.0", + }; + const result = await migratorMigrations.migrate(input); + expect(result).toStrictEqual(outputV4); + }); + + test("should return instance if same target version", async () => { + const input: V4 = { + dummy: "aaa", + version: "4.0.0", + }; + const result = await migratorMigrations.migrate(input); + expect(result).toStrictEqual(outputV4); + }); + + test("should not do anything if migrate up but nothing more", () => { + const input: V4 = { + dummy: "aaa", + version: "4.0.0", + }; + return expect(migratorMigrations.migrate(input)).resolves.toStrictEqual(outputV4); + }); + + test("should skip downgrades silently / not support them", async () => { + const input: V4 = { + dummy: "aaa", + version: "4.0.0", + }; + // Migrate should return the exact state since downgrades are bypassed + const result = await migratorMigrations.migrate(input, { + target: "3.0.0", + }); + expect(result).toEqual(input); + }); + + test("should support onStep callback during migration", async () => { + const input: V1 = { + dummyV1: "aaa", + version: "1.0.0", + }; + + const steps: any[] = []; + await migratorMigrations.migrate(input, { + onStep: async (state, version) => { + steps.push({ ...state, version }); + }, + }); + + expect(steps).toHaveLength(3); // 1 -> 2, 2 -> 3, 3 -> 4 + expect(steps[0]).toEqual(expect.objectContaining({ dummyV2: "aaa", version: "2.0.0" })); + expect(steps[1]).toEqual(expect.objectContaining({ dummyV3: "aaa", version: "3.0.0" })); + expect(steps[2]).toEqual(expect.objectContaining({ dummy: "aaa", version: "4.0.0" })); + }); + + test("should throw if target is not in migrations", async () => { + const input: V4 = { + dummy: "aaa", + version: "1.2.0", + }; + + const badMigratorInstance = createMigrator().createMigrations({ + migrations: [ + createMigration({ + version: "1.0.0", + up: (state) => ({ + dummyV2: state.dummyV1, + }), + }), + createMigration({ + version: "4.0.0", + up: finalVersion, + }), + ], + }); + + return expect(badMigratorInstance.migrate(input)).rejects.toThrow(); + }); + + test("should migrate an incomplete version (loose)", async () => { + const input: V1 = { + dummyV1: "aaa", + // @ts-expect-error specific to the test + version: "1", + }; + + const migrator = createMigrator().createMigrations({ + migrations: [ + createMigration({ + version: "1.0.0", + up: (state) => ({ + dummyV2: state.dummyV1, + }), + }), + createMigration({ + version: "2.0.0", + up: finalVersion, + }), + ], + }); + + const result = await migrator.migrate(input); + + expect(result).toEqual(expect.objectContaining({ version: "2.0.0" })); + }); + + test("should not migrate an incomplete version when coerce option disabled", async () => { + const input: V1 = { + dummyV1: "aaa", + // @ts-expect-error specific to the test + version: "1", + }; + + const migrator = createMigrator().createMigrations({ + migrations: [ + createMigration({ + version: "1.0.0", + up: (state) => ({ + dummyV2: state.dummyV1, + }), + }), + createMigration({ + version: "2.0.0", + up: finalVersion, + }), + ], + coerce: false, + }); + + await expect(migrator.migrate(input)).rejects.toThrow( + 'Current version "1" not found in migrations', + ); + }); +}); + +describe("async", () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + afterEach(() => { + vi.restoreAllMocks(); + }); + + test("should support async migration", async () => { + const input: V1 = { + dummyV1: "aaa", + version: "1.0.0", + }; + + const migrator = createMigrator().createMigrations({ + migrations: [ + createMigration({ + version: "1.0.0", + up: async (state) => { + await sleep(1000); + return { + dummyV2: state.dummyV1, + }; + }, + }), + createMigration({ + version: "2.0.0", + up: finalVersion, + }), + ], + }); + + const promise = migrator.migrate(input); + + vi.advanceTimersByTime(1000); + + const result = await promise; + + expect(result).toStrictEqual({ + dummyV2: "aaa", + version: "2.0.0", + }); + }); +}); diff --git a/packages/migration/src/models/migration.ts b/packages/migration/src/models/migration.ts new file mode 100644 index 00000000..c8c8f6dc --- /dev/null +++ b/packages/migration/src/models/migration.ts @@ -0,0 +1,160 @@ +import * as semver from "semver"; +import { coerce } from "semver"; +import { objectKeys } from "../utils/object-keys"; +import { klona } from "klona"; +import { custom, InferOutput, object, ObjectEntries } from "valibot"; + +export type Awaitable = Promise | T; + +export type MigrationFn = (state: From, targetVersion: string) => Awaitable; + +export type MigrateOptions = { + debug?: boolean; + target?: SemVer; + onStep?: (state: any, version: SemVer) => Promise | void; +}; + +const SemverValidator = custom((input) => + typeof input === "string" ? /^\d+\.\d+\.\d+$/.test(input) : false, +); + +export const SemverVersionValidator = SemverValidator; +// export const SemverVersionValidator = optional(SemverValidator, '1.0.0') + +export const MigrationSchemaValidator = object({ + version: SemverVersionValidator, +}); + +export const createVersionSchema = (schema: OBJECTENTRIES) => + object({ + ...schema, + }); + +export type MigrationSchema = InferOutput; + +export type OmitVersion = Omit; + +export type SemVer = `${number}.${number}.${number}`; + +export interface MigrationClass { + version: SemVer; + up: MigrationFn; +} + +export interface MigrationObjInput { + version: SemVer; + up: MigrationFn, OmitVersion>; +} + +export interface MigratorConfig { + migrations: MigrationClass[]; + coerce?: boolean; + defaultValue?: FinalState; +} + +export class Migrator { + current: SemVer; + + migrations: Record> = {}; + + coerce: boolean; + defaultValue: OutputState; + + constructor(config: MigratorConfig) { + config.migrations.forEach((migration) => { + this.migrations[migration.version] = migration; + }); + + this.defaultValue = config?.defaultValue ?? ({} as OutputState); + + const versions = this.getVersions(); + this.current = versions[versions.length - 1]; + this.coerce = config?.coerce ?? true; + } + + getVersions() { + const keys = objectKeys(this.migrations); + return semver.sort(keys); + } + + async migrate( + _state: MigrationSchema | undefined, + options?: MigrateOptions, + ): Promise { + const state = _state ?? this.defaultValue; + const currentVersion = this.tryCoerce(state.version); + const targetVersion = this.tryCoerce(options?.target ?? this.current); + + if (options?.debug) { + console.log("Migrating from", currentVersion, "to", targetVersion); + } + + let finalState = klona(state) as any; // Using any here because we'll be transforming between versions + const versions = this.getVersions(); + const currentIndex = versions.indexOf(currentVersion); + const targetIndex = versions.indexOf(targetVersion); + + if (currentIndex === -1) { + throw new Error(`Current version "${currentVersion}" not found in migrations`); + } + if (targetIndex === -1) { + throw new Error(`Target version "${targetVersion}" not found in migrations`); + } + + // If we're already at the target version, return the state + if (currentIndex === targetIndex) { + return finalState as OutputState; + } + + // Get the migration path + const isUpgrade = currentIndex < targetIndex; + + if (!isUpgrade) { + return finalState as OutputState; + } + + // Perform migrations + for (let i = currentIndex; i < targetIndex; i++) { + const currentVersion = versions[i]; + const nextVersion = versions[i + 1]; + + if (options?.debug) { + console.log("\tMigrating to version:", nextVersion); + } + + const migrationVersion = currentVersion; + const migration = this.migrations[migrationVersion]; + + // Remove version before migration + const { version: _, ...stateWithoutVersion } = finalState; + + // Perform migration + const migratedState = await migration.up(stateWithoutVersion, currentVersion); + + // Add new version + finalState = { + ...migratedState, + version: nextVersion, + }; + + if (options?.onStep) { + await options.onStep(finalState, nextVersion); + } + + if (options?.debug) { + console.log("\tMigrated state:", finalState); + } + } + + return finalState as OutputState; + } + + tryCoerce(version: SemVer): SemVer { + return this.coerce ? ((coerce(version)?.version as SemVer | undefined) ?? version) : version; + } + + needMigration(version: SemVer) { + const newVersion = this.tryCoerce(version); + return semver.lt(newVersion, this.current); + } +} diff --git a/src/shared/libs/migration/utils/object-keys.ts b/packages/migration/src/utils/object-keys.ts similarity index 63% rename from src/shared/libs/migration/utils/object-keys.ts rename to packages/migration/src/utils/object-keys.ts index 80f9ba4a..cc21652b 100644 --- a/src/shared/libs/migration/utils/object-keys.ts +++ b/packages/migration/src/utils/object-keys.ts @@ -1,8 +1,8 @@ -export type ObjectKeys = `${Exclude}` +export type ObjectKeys = `${Exclude}`; export const objectKeys = Object.keys as ( - value: Type -) => Array> + value: Type, +) => Array>; export const objectEntries = Object.entries as >( - value: Type -) => Array<[ObjectKeys, Type[ObjectKeys]]> + value: Type, +) => Array<[ObjectKeys, Type[ObjectKeys]]>; diff --git a/packages/migration/tsconfig.json b/packages/migration/tsconfig.json new file mode 100644 index 00000000..65489927 --- /dev/null +++ b/packages/migration/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig/commonjs.json", + "compilerOptions": { + "emitDeclarationOnly": true, + "outDir": "dist", + "baseUrl": ".", + "paths": { + "@pipelab/migration": ["./src"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/shared/.oxfmtrc.json b/packages/shared/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/shared/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/shared/CHANGELOG.md b/packages/shared/CHANGELOG.md new file mode 100644 index 00000000..daecce32 --- /dev/null +++ b/packages/shared/CHANGELOG.md @@ -0,0 +1,288 @@ +# @pipelab/shared + +## 1.0.0-beta.32 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/constants@1.0.0-beta.33 + - @pipelab/migration@1.0.0-beta.31 + +## 1.0.0-beta.31 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/constants@1.0.0-beta.32 + - @pipelab/migration@1.0.0-beta.30 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.31 + - @pipelab/migration@1.0.0-beta.29 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.30 + - @pipelab/migration@1.0.0-beta.28 + +## 1.0.0-beta.28 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.29 + - @pipelab/migration@1.0.0-beta.27 + +## 1.0.0-beta.27 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.28 + - @pipelab/migration@1.0.0-beta.26 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.27 + - @pipelab/migration@1.0.0-beta.25 + +## 1.0.0-beta.25 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.26 + - @pipelab/migration@1.0.0-beta.24 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.25 + - @pipelab/migration@1.0.0-beta.23 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.24 + - @pipelab/migration@1.0.0-beta.22 + +## 1.0.0-beta.22 + +### Patch Changes + +- fix slashes + +## 1.0.0-beta.21 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.23 + - @pipelab/migration@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.22 + - @pipelab/migration@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.21 + - @pipelab/migration@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.20 + - @pipelab/migration@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.19 + - @pipelab/migration@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/constants@1.0.0-beta.18 + - @pipelab/migration@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.17 + - @pipelab/migration@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.16 + - @pipelab/migration@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.15 + - @pipelab/migration@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/constants@1.0.0-beta.14 + - @pipelab/migration@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/constants@1.0.0-beta.13 + - @pipelab/migration@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/constants@1.0.0-beta.12 + - @pipelab/migration@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/migration@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/migration@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/migration@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/migration@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/migration@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/migration@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/migration@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/migration@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/migration@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/migration@1.0.0-beta.0 diff --git a/packages/shared/README.md b/packages/shared/README.md new file mode 100644 index 00000000..211e38a6 --- /dev/null +++ b/packages/shared/README.md @@ -0,0 +1,3 @@ +# @pipelab/shared + +Shared models, types, and utility functions used by both the frontend and backend of Pipelab. diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 00000000..ae6647fe --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,67 @@ +{ + "name": "@pipelab/shared", + "version": "1.0.0-beta.32", + "private": false, + "description": "Shared logic and types for the Pipelab ecosystem", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "packages/shared" + }, + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "build": "tsdown", + "format": "oxfmt .", + "lint": "oxlint .", + "typecheck": "tsc -b", + "test": "vitest run" + }, + "dependencies": { + "@jitl/quickjs-singlefile-mjs-release-sync": "0.31.0", + "@jitl/quickjs-wasmfile-release-sync": "0.31.0", + "@pipelab/constants": "workspace:*", + "@pipelab/migration": "workspace:*", + "@supabase/supabase-js": "2.99.3", + "@types/node": "^24.12.2", + "klona": "2.0.6", + "nanoid": "5.0.7", + "quickjs-emscripten": "0.31.0", + "quickjs-emscripten-sync": "1.6.0", + "tslog": "4.9.3", + "type-fest": "4.26.1", + "valibot": "0.42.1" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "esbuild-plugin-wasm": "1.1.0", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + } +} diff --git a/packages/shared/src/apis.ts b/packages/shared/src/apis.ts new file mode 100644 index 00000000..163ce69d --- /dev/null +++ b/packages/shared/src/apis.ts @@ -0,0 +1,290 @@ +import { RendererPluginDefinition } from "./plugins/definitions"; +import { User, UserResponse } from "@supabase/supabase-js"; +import type { Tagged } from "type-fest"; +import { PresetResult, Steps, SavedFile } from "./model"; +import { AppConfig, ConnectionsConfig } from "./config.schema"; +import { FileRepo } from "./config/projects-definition"; +import { Agent } from "./websocket.types"; +import { BuildHistoryEntry, BuildHistoryQuery, BuildHistoryResponse } from "./build-history"; + +type Event = + | { type: TYPE; data: DATA } + | { type: "log"; data: { decorator: string; message: unknown[]; time: number } }; +type EndEvent = { + type: "end"; + data: + | { + type: "success"; + result: DATA; + } + | { + type: "error"; + ipcError: string; + code?: string; + }; +}; + +export type Presets = Record; + +export type StableDataReport = { + sourceChannel: "Stable" | "Beta" | "Dev"; + targetChannel: "Stable" | "Beta" | "Dev"; + + // Settings + settingsExists: boolean; + settingsVersion: string | null; + settingsVersionTarget: string | null; + settingsMtimeSource: number; + settingsMtimeTarget: number; + settingsImportable: boolean; + + // Connections + connectionsExists: boolean; + connectionsCount: number; + connectionsVersion: string | null; + connectionsVersionTarget: string | null; + connectionsMtimeSource: number; + connectionsMtimeTarget: number; + connectionsImportable: boolean; + + // Projects + projectsExists: boolean; + projectsVersion: string | null; + projectsVersionTarget: string | null; + projectsMtimeSource: number; + projectsMtimeTarget: number; + projectsImportable: boolean; + + projects: Array<{ + id: string; + name: string; + description: string; + pipelines: Array<{ + id: string; + name: string; + description: string; + type: "internal" | "external" | "pipelab-cloud"; + lastModifiedStable?: string; + lastModifiedBeta?: string; + existsInBeta: boolean; + }>; + }>; +}; + +export type ReleaseChannel = "stable" | "beta" | "dev"; +export type MigrationChannel = "stable" | "beta"; + +export type MigrationOptions = { + migrateSettings: boolean; + migrateConnections: boolean; + selectedProjects: string[]; + selectedPipelines: string[]; + sourceChannel?: MigrationChannel; +}; + +export type IpcDefinition = { + "fs:read": [ + // input + { path: string }, + EndEvent<{ content: string }>, + ]; + "fs:remove": [ + // input + { path: string }, + EndEvent, + ]; + "fs:write": [ + // input + { + path: string; + content: string; + }, + EndEvent<{ ok: boolean }>, + ]; + "fs:rm": [ + // input + { + path: string; + recursive: boolean; + force: boolean; + }, + EndEvent<{ ok: boolean }>, + ]; + "fs:listDirectory": [ + // input + { path: string }, + EndEvent<{ + files: { + name: string; + isDirectory: boolean; + isSymbolicLink: boolean; + size: number; + mtime: number; + }[]; + }>, + ]; + "fs:isPathBlacklisted": [{ path: string }, EndEvent<{ isBlacklisted: boolean }>]; + "fs:getHomeDirectory": [void, EndEvent<{ path: string }>]; + "dialog:showOpenDialog": [ + // input + Electron.OpenDialogOptions, + EndEvent<{ canceled: boolean; filePaths: string[] }>, + ]; + "dialog:showSaveDialog": [ + // input + Electron.SaveDialogOptions, + EndEvent<{ canceled: boolean; filePath: string | undefined }>, + ]; + "nodes:get": [void, EndEvent<{ nodes: RendererPluginDefinition[] }>]; + "presets:get": [void, EndEvent]; + "action:execute": [ + { + pluginId: string; + nodeId: string; + params: any; + steps: Steps; + }, + ( + | Event<"progress", unknown> + | Event<"progress", unknown> + | EndEvent<{ outputs: Record; tmp: string }> + ), + ]; + + "constants:get": [void, EndEvent<{ result: { userData: string } }>]; + + "settings:load": [void, EndEvent]; + "settings:save": [{ data: AppConfig }, EndEvent<"ok">]; + "settings:reset": [{ key: string }, EndEvent<"ok">]; + + "connections:load": [void, EndEvent]; + "connections:save": [{ data: ConnectionsConfig }, EndEvent<"ok">]; + "connections:reset": [{ key: string }, EndEvent<"ok">]; + + "projects:load": [void, EndEvent]; + "projects:save": [{ data: FileRepo }, EndEvent<"ok">]; + "projects:reset": [{ key: string }, EndEvent<"ok">]; + + "pipeline:load-by-name": [{ name: string }, EndEvent]; + "pipeline:load-by-path": [{ path: string }, EndEvent]; + "pipeline:save-by-name": [{ name: string; data: string }, EndEvent<"ok">]; + "pipeline:save-by-path": [{ path: string; data: string }, EndEvent<"ok">]; + "pipeline:delete-by-name": [{ name: string }, EndEvent<"ok">]; + "pipeline:delete-by-path": [{ path: string }, EndEvent<"ok">]; + "action:cancel": [void, EndEvent<{ result: "ok" | "ko" }>]; + + // Build History APIs + "build-history:save": [{ entry: BuildHistoryEntry }, EndEvent<{ result: "ok" | "ko" }>]; + "build-history:get": [ + { id: string; pipelineId?: string }, + EndEvent<{ entry?: BuildHistoryEntry }>, + ]; + "build-history:get-all": [{ query?: BuildHistoryQuery }, EndEvent]; + "build-history:update": [ + { id: string; updates: Partial; pipelineId?: string }, + EndEvent<{ result: "ok" | "ko" }>, + ]; + "build-history:delete": [{ id: string; pipelineId?: string }, EndEvent<{ result: "ok" | "ko" }>]; + "build-history:clear": [void, EndEvent<{ result: "ok" | "ko" }>]; + "build-history:clear-by-pipeline": [{ pipelineId: string }, EndEvent<{ result: "ok" | "ko" }>]; + "build-history:get-storage-info": [ + void, + EndEvent<{ + totalEntries: number; + totalSize: number; + oldestEntry?: number; + newestEntry?: number; + }>, + ]; + "agents:get": [void, EndEvent<{ agents: Agent[] }>]; + "graph:execute": [ + { + graph: any[]; + variables: any[]; + pipelineId?: string; + projectId?: string; + projectName?: string; + projectPath?: string; + }, + ( + | { type: "node-enter"; data: { nodeUid: string; nodeName: string } } + | { type: "node-exit"; data: { nodeUid: string; nodeName: string } } + | { type: "node-log"; data: { nodeUid: string; logData: any } } + | { type: "node-artifact"; data: { nodeUid: string; artifact: { name: string; path: string } } } + | { type: "node-artifacts-finalized"; data: { artifacts: import("@pipelab/shared").Artifact[] } } + | EndEvent<{ result: any; buildId: string }> + ), + ]; + "auth:getUser": [void, EndEvent<{ user: User | null }>]; + "auth:signInWithPassword": [{ email: string; password: string }, EndEvent]; + "auth:signUp": [{ email: string; password: string }, EndEvent]; + "auth:signOut": [void, EndEvent]; + "auth:resetPasswordForEmail": [{ email: string }, EndEvent<{ error: any | null }>]; + "auth:invoke": [ + { name: string; options?: any }, + EndEvent<{ data: any | null; error: any | null }>, + ]; + "agent:version:get": [void, EndEvent<{ version: string; channel: ReleaseChannel }>]; + "system:packages:cleanup": [void, EndEvent]; + "startup:progress": [ + void, + { type: "progress"; data: { message: string } } | { type: "ready" } | { type: "done" }, + ]; + "plugin:loaded": [void, { plugin: RendererPluginDefinition }]; + "plugin:search": [ + { query: string }, + EndEvent<{ + results: Array<{ + name: string; + version: string; + description?: string; + keywords?: string[]; + date?: string; + }>; + }>, + ]; + "plugin:get-details": [ + { packageName: string }, + EndEvent<{ + name: string; + latestVersion: string; + versions: string[]; + description?: string; + }>, + ]; + "plugin:install": [{ packageName: string; version: string }, EndEvent<{ result: "ok" }>]; + "plugin:uninstall": [{ packageName: string }, EndEvent<{ result: "ok" }>]; + "plugin:list-installed": [ + void, + EndEvent<{ + installed: Array<{ + name: string; + version: string; + description?: string; + }>; + }>, + ]; + "plugin:ensure-loaded": [ + { plugins: Record }, + EndEvent<{ loaded: string[]; failed: string[] }>, + ]; + "migration:scan-stable": [{ sourceChannel?: MigrationChannel }, EndEvent]; + "migration:perform": [MigrationOptions, EndEvent<{ result: "ok" }>]; +}; + +export type Channels = keyof IpcDefinition; + +export const ShellChannels: Channels[] = ["dialog:showOpenDialog", "dialog:showSaveDialog"]; + +export type Data = IpcDefinition[KEY][0]; +export type Events = IpcDefinition[KEY][1]; +export type End = Extract["data"]; + +export type IpcMessage = { + // the channel to communicate + requestId: RequestId; + data: any; +}; +export type RequestId = Tagged; + +// type Output = End<'fs:openFolder'> diff --git a/packages/shared/src/build-history.ts b/packages/shared/src/build-history.ts new file mode 100644 index 00000000..e2e2bfe6 --- /dev/null +++ b/packages/shared/src/build-history.ts @@ -0,0 +1,120 @@ +// Build History Storage Types and Interfaces +import { SandboxFolder } from "@pipelab/constants"; + +export interface ExecutionStep { + id: string; + name: string; + status: "pending" | "running" | "completed" | "failed" | "cancelled"; + startTime: number; + endTime?: number; + duration?: number; + logs: LogEntry[]; + error?: ExecutionError; + output?: Record; +} + +export interface ExecutionError { + message: string; + stack?: string; + code?: string; + timestamp: number; +} + +export interface LogEntry { + id: string; + timestamp: number; + level: "debug" | "info" | "warn" | "error"; + message: string; + source?: string; + data?: Record; +} + +export interface Artifact { + id: string; + name: string; + path: string; + size: number; + type: "file" | "folder"; +} + +export interface BuildHistoryEntry { + id: string; + pipelineId: string; + projectName: string; + projectPath: string; + cachePath?: string; + status: "running" | "completed" | "failed" | "cancelled"; + startTime: number; + endTime?: number; + duration?: number; + steps: ExecutionStep[]; + totalSteps: number; + completedSteps: number; + failedSteps: number; + cancelledSteps: number; + logs: LogEntry[]; + error?: ExecutionError; + output?: Record; + metadata?: Record; + userId?: string; + createdAt: number; + updatedAt: number; + artifacts?: Artifact[]; +} + +// Query interface supporting both pipeline and scenario filtering +export interface BuildHistoryQuery { + pipelineId?: string; +} + +export interface BuildHistoryResponse { + entries: BuildHistoryEntry[]; + total: number; +} + +// Storage interfaces - Simplified for pipeline-specific storage +export interface IBuildHistoryStorage { + save(entry: BuildHistoryEntry): Promise; + get(id: string, pipelineId?: string): Promise; + getAll(): Promise; + getByPipeline(pipelineId: string): Promise; + update(id: string, updates: Partial, pipelineId?: string): Promise; + delete(id: string, pipelineId?: string): Promise; + clear(): Promise; + getStorageInfo(): Promise<{ + totalEntries: number; + totalSize: number; + oldestEntry?: number; + newestEntry?: number; + numberOfPipelines: number; + userDataPath: string; + disk: { + total: number; + free: number; + pipelab: number; + folders: Array<{ name: SandboxFolder; label: string; size: number }>; + }; + }>; +} + +// Authorization and subscription types +export interface SubscriptionBenefit { + id: string; + name: string; + description?: string; +} + +export interface SubscriptionError extends Error { + code: "SUBSCRIPTION_REQUIRED" | "SUBSCRIPTION_EXPIRED" | "BENEFIT_NOT_FOUND" | "UNAUTHORIZED"; + benefit?: string; + userMessage: string; +} + +export interface AuthorizationContext { + userId?: string; + hasBenefit: (benefitId: string) => boolean; + isPaidUser: boolean; +} + +// Authorization check function type +export type AuthorizationCheck = (context: AuthorizationContext) => void; diff --git a/packages/shared/src/config.schema.ts b/packages/shared/src/config.schema.ts new file mode 100644 index 00000000..a49b8f68 --- /dev/null +++ b/packages/shared/src/config.schema.ts @@ -0,0 +1,171 @@ +import { + union, + literal, + InferInput, + string, + boolean, + object, + number, + array, + GenericSchema, + optional, + looseObject, +} from "valibot"; + +export const createVersionSchema = >(schema: T) => schema; + +export const AppSettingsValidatorV1 = object({ + cacheFolder: string(), + theme: union([literal("light"), literal("dark")]), + version: literal("1.0.0"), +}); + +export const AppSettingsValidatorV2 = object({ + cacheFolder: string(), + theme: union([literal("light"), literal("dark")]), + version: literal("2.0.0"), +}); + +export const AppSettingsValidatorV3 = object({ + cacheFolder: string(), + theme: union([literal("light"), literal("dark")]), + version: literal("3.0.0"), + clearTemporaryFoldersOnPipelineEnd: boolean(), +}); + +export const AppSettingsValidatorV4 = object({ + theme: union([literal("light"), literal("dark")]), + version: literal("4.0.0"), + cacheFolder: string(), + clearTemporaryFoldersOnPipelineEnd: boolean(), + locale: union([ + literal("en-US"), + literal("fr-FR"), + literal("pt-BR"), + literal("zh-CN"), + literal("es-ES"), + literal("de-DE"), + ]), +}); + +export const AppSettingsValidatorV5 = object({ + theme: union([literal("light"), literal("dark")]), + version: literal("5.0.0"), + cacheFolder: string(), + clearTemporaryFoldersOnPipelineEnd: boolean(), + locale: union([ + literal("en-US"), + literal("fr-FR"), + literal("pt-BR"), + literal("zh-CN"), + literal("es-ES"), + literal("de-DE"), + ]), + tours: object({ + dashboard: object({ + step: number(), + completed: boolean(), + }), + editor: object({ + step: number(), + completed: boolean(), + }), + }), +}); + +export const AppSettingsValidatorV6 = object({ + theme: union([literal("light"), literal("dark")]), + version: literal("6.0.0"), + cacheFolder: string(), + clearTemporaryFoldersOnPipelineEnd: boolean(), + locale: union([ + literal("en-US"), + literal("fr-FR"), + literal("pt-BR"), + literal("zh-CN"), + literal("es-ES"), + literal("de-DE"), + ]), + tours: object({ + dashboard: object({ + step: number(), + completed: boolean(), + }), + editor: object({ + step: number(), + completed: boolean(), + }), + }), + autosave: boolean(), +}); + +export const AppSettingsValidatorV7 = object({ + theme: union([literal("light"), literal("dark")]), + version: literal("7.0.0"), + locale: union([ + literal("en-US"), + literal("fr-FR"), + literal("pt-BR"), + literal("zh-CN"), + literal("es-ES"), + literal("de-DE"), + ]), + tours: object({ + dashboard: object({ + step: number(), + completed: boolean(), + }), + editor: object({ + step: number(), + completed: boolean(), + }), + }), + autosave: boolean(), + agents: array( + object({ + id: string(), + name: string(), + url: string(), + }), + ), + // Metadata list of plugins the user has enabled (official + community). + // No binaries are stored here — versions are resolved JIT at node-add time. + plugins: array( + object({ + name: string(), + enabled: boolean(), + description: string(), + }), + ), + cacheFolder: optional(string()), + tempFolder: optional(string()), +}); + +export const ConnectionValidator = looseObject({ + id: string(), + pluginName: string(), + name: string(), + createdAt: string(), + isDefault: boolean(), +}); + +export const ConnectionsValidatorV1 = object({ + version: literal("1.0.0"), + connections: array(ConnectionValidator), +}); + +export type Connection = InferInput; +export type ConnectionsConfigV1 = InferInput; +export type ConnectionsConfig = ConnectionsConfigV1; +export const ConnectionsValidator = ConnectionsValidatorV1; + +export type AppConfigV1 = InferInput; +export type AppConfigV2 = InferInput; +export type AppConfigV3 = InferInput; +export type AppConfigV4 = InferInput; +export type AppConfigV5 = InferInput; +export type AppConfigV6 = InferInput; +export type AppConfigV7 = InferInput; + +export type AppConfig = AppConfigV7; +export const AppSettingsValidator = AppSettingsValidatorV7; diff --git a/packages/shared/src/config/connections-definition.ts b/packages/shared/src/config/connections-definition.ts new file mode 100644 index 00000000..6c6158f8 --- /dev/null +++ b/packages/shared/src/config/connections-definition.ts @@ -0,0 +1,3 @@ +import type { ConnectionsConfig, ConnectionsConfigV1, Connection } from "../config.schema"; + +export type { ConnectionsConfig, ConnectionsConfigV1, Connection }; diff --git a/packages/shared/src/config/migrators.ts b/packages/shared/src/config/migrators.ts new file mode 100644 index 00000000..3293c312 --- /dev/null +++ b/packages/shared/src/config/migrators.ts @@ -0,0 +1,442 @@ +import { + createMigration as createMigrationBase, + createMigrator, + finalVersion, + OmitVersion, + SemVer, + Awaitable, + MigrationSchema, +} from "@pipelab/migration"; +import { + AppConfig, + AppConfigV1, + AppConfigV2, + AppConfigV3, + AppConfigV4, + AppConfigV5, + AppConfigV6, + AppConfigV7, + ConnectionsConfig, + ConnectionsConfigV1, +} from "../config.schema"; + +const DEFAULT_PLUGINS: AppConfig["plugins"] = [ + { + name: "@pipelab/plugin-construct", + enabled: true, + description: "Construct 3 export & packaging", + }, + { name: "@pipelab/plugin-filesystem", enabled: true, description: "Filesystem utilities" }, + { name: "@pipelab/plugin-system", enabled: true, description: "System & shell commands" }, + { name: "@pipelab/plugin-steam", enabled: true, description: "Steam publishing" }, + { name: "@pipelab/plugin-itch", enabled: true, description: "Itch.io publishing" }, + { name: "@pipelab/plugin-electron", enabled: true, description: "Electron packaging" }, + { name: "@pipelab/plugin-discord", enabled: true, description: "Discord Rich Presence" }, + { name: "@pipelab/plugin-poki", enabled: true, description: "Poki publishing" }, + { name: "@pipelab/plugin-nvpatch", enabled: true, description: "NW.js patching" }, + { name: "@pipelab/plugin-tauri", enabled: true, description: "Tauri packaging" }, + { name: "@pipelab/plugin-minify", enabled: true, description: "Asset minification" }, + { name: "@pipelab/plugin-netlify", enabled: true, description: "Netlify deployment" }, +]; +import { FileRepoV1, FileRepoV2, FileRepoV3, FileRepo } from "./projects-types"; +import { + SavedFileV1, + SavedFileV2, + SavedFileV3, + SavedFileV4, + SavedFileV5, + SavedFile, +} from "../model"; + +// --- Types --- + +export type Additive = OmitVersion & OmitVersion

; + +type DistributiveOmit = T extends any ? Omit : never; +type DistributiveOmitVersion = DistributiveOmit; + +const createMigration = (config: { + version: SemVer; + up: (state: OmitVersion, targetVersion: string) => Awaitable>; +}) => createMigrationBase(config); + +export interface Migrator { + migrate: (data: any, options?: any) => Promise; + defaultValue: T; +} + +// --- Settings Migrator --- + +const settingsMigratorInternal = createMigrator(); + +export const defaultAppSettings = settingsMigratorInternal.createDefault({ + locale: "en-US", + theme: "light", + version: "7.0.0", + autosave: true, + agents: [], + tours: { + dashboard: { + step: 0, + completed: false, + }, + editor: { + step: 0, + completed: false, + }, + }, + plugins: DEFAULT_PLUGINS, +}); + +export const appSettingsMigrator = settingsMigratorInternal.createMigrations({ + defaultValue: defaultAppSettings, + migrations: [ + createMigration({ + version: "1.0.0" as SemVer, + up: (state) => state, + }), + createMigration({ + version: "2.0.0" as SemVer, + up: (state) => { + return { + ...state, + clearTemporaryFoldersOnPipelineEnd: false, + }; + }, + }), + createMigration({ + version: "3.0.0" as SemVer, + up: (state) => ({ + ...state, + locale: "en-US" as const, + }), + }), + createMigration({ + version: "4.0.0" as SemVer, + up: (state) => ({ + ...state, + tours: { + dashboard: { + step: 0, + completed: false, + }, + editor: { + step: 0, + completed: false, + }, + }, + }), + }), + createMigration({ + version: "5.0.0" as SemVer, + up: (state) => ({ + ...state, + autosave: true, + }), + }), + createMigration({ + version: "6.0.0" as SemVer, + up: (state) => { + const { cacheFolder, clearTemporaryFoldersOnPipelineEnd: __, ...rest } = state; + return { + ...rest, + cacheFolder, + agents: [], + plugins: DEFAULT_PLUGINS, + }; + }, + }), + createMigration({ + version: "7.0.0" as SemVer, + up: finalVersion, + }), + ], +}); + +// --- Connections Migrator --- + +const connectionsMigratorInternal = createMigrator(); + +export const defaultConnections = connectionsMigratorInternal.createDefault({ + version: "1.0.0", + connections: [], +}); + +export const connectionsMigrator = connectionsMigratorInternal.createMigrations({ + defaultValue: defaultConnections, + migrations: [ + createMigration({ + version: "1.0.0" as SemVer, + up: finalVersion, + }), + ], +}); + +// --- Projects Migrator --- + +const fileRepoMigratorInternal = createMigrator(); + +export const defaultFileRepo = fileRepoMigratorInternal.createDefault({ + version: "3.0.0", + projects: [ + { + id: "main", + name: "Default project", + description: "The initial default project", + }, + ], + pipelines: [], +}); + +export const fileRepoMigrations = fileRepoMigratorInternal.createMigrations({ + defaultValue: defaultFileRepo, + migrations: [ + createMigration({ + version: "1.0.0", + up: (state) => { + const pipelines: FileRepoV2["pipelines"] = Object.entries(state.data || {}).map( + ([id, file]) => { + return { + ...file, + id, + project: "main", + }; + }, + ); + return { + ...state, + projects: [ + { + id: "main", + name: "Default project", + description: "The initial default project", + }, + ], + pipelines: pipelines, + }; + }, + }), + createMigration({ + version: "2.0.0", + up: (state) => { + return { + ...state, + }; + }, + }), + createMigration({ + version: "3.0.0", + up: finalVersion, + }), + ], +}); + +// --- Saved File Migrator --- + +const savedFileMigratorInternal = createMigrator(); +const savedFileDefaultValue = savedFileMigratorInternal.createDefault({ + canvas: { + triggers: [], + blocks: [], + }, + description: "", + name: "", + variables: [], + version: "5.0.0", +}); + +export const savedFileMigrator = savedFileMigratorInternal.createMigrations({ + defaultValue: savedFileDefaultValue, + migrations: [ + createMigration({ + version: "1.0.0" as SemVer, + up: (state) => { + const blocks = state.canvas.blocks; + + const triggers: SavedFileV2["canvas"]["triggers"] = []; + const newBlocks: SavedFileV2["canvas"]["blocks"] = []; + + for (const block of blocks) { + if (block.type === "event") { + triggers.push(block); + } else { + newBlocks.push(block); + } + } + + return { + ...state, + canvas: { + ...state.canvas, + blocks: newBlocks, + triggers: triggers, + }, + }; + }, + }), + createMigration({ + version: "2.0.0" as SemVer, + up: (state) => { + const { canvas } = state; + const { blocks, triggers } = canvas; + + const newBlocks: SavedFileV3["canvas"]["blocks"] = []; + + for (const block of blocks) { + const newParams: SavedFileV3["canvas"]["blocks"][number]["params"] = {}; + + for (const data of Object.entries(block.params)) { + if (data === undefined) { + throw new Error("Can't migrate block with undefined params"); + } else { + const [key, value] = data; + newParams[key] = { + editor: "editor", + value, + }; + } + } + + newBlocks.push({ + ...block, + params: newParams, + }); + } + + return { + ...state, + canvas: { + ...canvas, + triggers, + blocks: newBlocks, + }, + }; + }, + }), + createMigration({ + version: "3.0.0" as SemVer, + up: (state) => ({ + ...state, + type: "default", + }), + }), + createMigration({ + version: "4.0.0" as SemVer, + up: (_state) => { + const state = _state as DistributiveOmitVersion; + if (state.type === "simple") { + return { + name: state.name, + description: state.description, + canvas: { + blocks: [], + triggers: [], + }, + variables: [], + }; + } + + const migrateBlock = (block: any, pluginsMap: Record) => { + if (!block) return; + if (block.origin?.pluginId) { + block.origin.pluginId = getStrictPluginId(block.origin.pluginId); + // Stamp the version from the old top-level plugins map, falling back to "latest" + block.origin.version = pluginsMap[block.origin.pluginId] ?? "latest"; + } + }; + + // Normalise the old plugins map's keys first so lookups are consistent + const normalizedPlugins: Record = {}; + if (state.plugins) { + for (const [key, val] of Object.entries(state.plugins)) { + normalizedPlugins[getStrictPluginId(key)] = val; + } + } + + // Stamp origin.version on every block and trigger + if (state.canvas) { + for (const block of state.canvas.blocks ?? []) { + migrateBlock(block, normalizedPlugins); + } + for (const trigger of state.canvas.triggers ?? []) { + migrateBlock(trigger, normalizedPlugins); + } + } + + // Drop the top-level plugins map — version is now per-block. Omit type. + const { plugins: _dropped, type: _type, ...rest } = state; + return rest; + }, + }), + createMigration({ + version: "5.0.0" as SemVer, + up: finalVersion, + }), + ], +}); + +const LEGACY_ID_MAP: Record = { + construct: "@pipelab/plugin-construct", + filesystem: "@pipelab/plugin-filesystem", + system: "@pipelab/plugin-system", + steam: "@pipelab/plugin-steam", + itch: "@pipelab/plugin-itch", + electron: "@pipelab/plugin-electron", + discord: "@pipelab/plugin-discord", + dicord: "@pipelab/plugin-discord", + "@pipelab/plugin-dicord": "@pipelab/plugin-discord", + poki: "@pipelab/plugin-poki", + nvpatch: "@pipelab/plugin-nvpatch", + tauri: "@pipelab/plugin-tauri", + minify: "@pipelab/plugin-minify", + netlify: "@pipelab/plugin-netlify", +}; + +export const getStrictPluginId = (pluginId: string): string => { + if (!pluginId) return pluginId; + return LEGACY_ID_MAP[pluginId] || pluginId; +}; + +const normalizeBlockPluginId = (block: any): boolean => { + if (!block) return false; + let changed = false; + if (block.origin?.pluginId) { + const strictId = getStrictPluginId(block.origin.pluginId); + if (block.origin.pluginId !== strictId) { + block.origin.pluginId = strictId; + changed = true; + } + } + return changed; +}; + +export const normalizePipelineConfig = (state: any): boolean => { + if (!state) return false; + let changed = false; + + // Normalise plugin IDs in block and trigger origins (pluginId field only; + // version strings don't need normalisation) + if (state.canvas) { + if (Array.isArray(state.canvas.blocks)) { + for (const block of state.canvas.blocks) { + if (normalizeBlockPluginId(block)) changed = true; + } + } + if (Array.isArray(state.canvas.triggers)) { + for (const trigger of state.canvas.triggers) { + if (normalizeBlockPluginId(trigger)) changed = true; + } + } + } + + return changed; +}; + +// --- Registry --- + +export const configRegistry: Record> = { + settings: appSettingsMigrator, + projects: fileRepoMigrations, + pipeline: savedFileMigrator, + connections: connectionsMigrator, +}; diff --git a/packages/shared/src/config/projects-definition.ts b/packages/shared/src/config/projects-definition.ts new file mode 100644 index 00000000..d34ab20c --- /dev/null +++ b/packages/shared/src/config/projects-definition.ts @@ -0,0 +1,32 @@ +import { SaveLocationValidator } from "../save-location"; +import { object, string, optional, record, InferInput, literal, array } from "valibot"; + +export const FileRepoValidatorV1 = object({ + version: literal("1.0.0"), + data: optional(record(string(), SaveLocationValidator), {}), +}); + +export const FileRepoProjectValidatorV2 = object({ + id: string(), + name: string(), + description: string(), +}); + +export const FileRepoValidatorV2 = object({ + version: literal("2.0.0"), + projects: array(FileRepoProjectValidatorV2), + pipelines: optional(array(SaveLocationValidator), []), +}); + +export const FileRepoValidatorV3 = object({ + version: literal("3.0.0"), + projects: array(FileRepoProjectValidatorV2), + pipelines: optional(array(SaveLocationValidator), []), +}); + +export type FileRepoV1 = InferInput; +export type FileRepoV2 = InferInput; +export type FileRepoV3 = InferInput; + +export const FileRepoValidator = FileRepoValidatorV3; +export type FileRepo = InferInput; diff --git a/packages/shared/src/config/projects-types.ts b/packages/shared/src/config/projects-types.ts new file mode 100644 index 00000000..65c38e3a --- /dev/null +++ b/packages/shared/src/config/projects-types.ts @@ -0,0 +1 @@ +export * from "./projects-definition"; diff --git a/packages/shared/src/config/projects.ts b/packages/shared/src/config/projects.ts new file mode 100644 index 00000000..55929c26 --- /dev/null +++ b/packages/shared/src/config/projects.ts @@ -0,0 +1 @@ +export * from "./projects-types"; diff --git a/packages/shared/src/config/settings-definition.ts b/packages/shared/src/config/settings-definition.ts new file mode 100644 index 00000000..58d7d23b --- /dev/null +++ b/packages/shared/src/config/settings-definition.ts @@ -0,0 +1,21 @@ +import type { + AppConfig, + AppConfigV1, + AppConfigV2, + AppConfigV3, + AppConfigV4, + AppConfigV5, + AppConfigV6, + AppConfigV7, +} from "../config.schema"; + +export type { + AppConfig, + AppConfigV1, + AppConfigV2, + AppConfigV3, + AppConfigV4, + AppConfigV5, + AppConfigV6, + AppConfigV7, +}; diff --git a/packages/shared/src/config/settings.ts b/packages/shared/src/config/settings.ts new file mode 100644 index 00000000..58d7d23b --- /dev/null +++ b/packages/shared/src/config/settings.ts @@ -0,0 +1,21 @@ +import type { + AppConfig, + AppConfigV1, + AppConfigV2, + AppConfigV3, + AppConfigV4, + AppConfigV5, + AppConfigV6, + AppConfigV7, +} from "../config.schema"; + +export type { + AppConfig, + AppConfigV1, + AppConfigV2, + AppConfigV3, + AppConfigV4, + AppConfigV5, + AppConfigV6, + AppConfigV7, +}; diff --git a/src/shared/database.types.ts b/packages/shared/src/database.types.ts similarity index 70% rename from src/shared/database.types.ts rename to packages/shared/src/database.types.ts index 548d080b..d951b529 100644 --- a/src/shared/database.types.ts +++ b/packages/shared/src/database.types.ts @@ -1,32 +1,26 @@ -export type Json = - | string - | number - | boolean - | null - | { [key: string]: Json | undefined } - | Json[] +export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]; export type Database = { public: { Tables: { - [_ in never]: never - } + [_ in never]: never; + }; Views: { - [_ in never]: never - } + [_ in never]: never; + }; Functions: { - [_ in never]: never - } + [_ in never]: never; + }; Enums: { - [_ in never]: never - } + [_ in never]: never; + }; CompositeTypes: { - [_ in never]: never - } - } -} + [_ in never]: never; + }; + }; +}; -type PublicSchema = Database[Extract] +type PublicSchema = Database[Extract]; export type Tables< PublicTableNameOrOptions extends @@ -39,66 +33,58 @@ export type Tables< > = PublicTableNameOrOptions extends { schema: keyof Database } ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] & Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends { - Row: infer R + Row: infer R; } ? R : never - : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & - PublicSchema["Views"]) - ? (PublicSchema["Tables"] & - PublicSchema["Views"])[PublicTableNameOrOptions] extends { - Row: infer R + : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & PublicSchema["Views"]) + ? (PublicSchema["Tables"] & PublicSchema["Views"])[PublicTableNameOrOptions] extends { + Row: infer R; } ? R : never - : never + : never; export type TablesInsert< - PublicTableNameOrOptions extends - | keyof PublicSchema["Tables"] - | { schema: keyof Database }, + PublicTableNameOrOptions extends keyof PublicSchema["Tables"] | { schema: keyof Database }, TableName extends PublicTableNameOrOptions extends { schema: keyof Database } ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] : never = never, > = PublicTableNameOrOptions extends { schema: keyof Database } ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Insert: infer I + Insert: infer I; } ? I : never : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { - Insert: infer I + Insert: infer I; } ? I : never - : never + : never; export type TablesUpdate< - PublicTableNameOrOptions extends - | keyof PublicSchema["Tables"] - | { schema: keyof Database }, + PublicTableNameOrOptions extends keyof PublicSchema["Tables"] | { schema: keyof Database }, TableName extends PublicTableNameOrOptions extends { schema: keyof Database } ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] : never = never, > = PublicTableNameOrOptions extends { schema: keyof Database } ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Update: infer U + Update: infer U; } ? U : never : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { - Update: infer U + Update: infer U; } ? U : never - : never + : never; export type Enums< - PublicEnumNameOrOptions extends - | keyof PublicSchema["Enums"] - | { schema: keyof Database }, + PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] | { schema: keyof Database }, EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"] : never = never, @@ -106,4 +92,4 @@ export type Enums< ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName] : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] ? PublicSchema["Enums"][PublicEnumNameOrOptions] - : never + : never; diff --git a/packages/shared/src/errors.ts b/packages/shared/src/errors.ts new file mode 100644 index 00000000..d3cff9e6 --- /dev/null +++ b/packages/shared/src/errors.ts @@ -0,0 +1,11 @@ +/** + * Defines standardized exit codes for the Pipelab CLI. + */ +export enum CLIExitCode { + Success = 0, + UnknownError = 1, + PipelineNotFound = 2, + InvalidPipelineFile = 3, + PipelineExecutionError = 4, + InvalidArguments = 5, +} diff --git a/packages/shared/src/evaluator.ts b/packages/shared/src/evaluator.ts new file mode 100644 index 00000000..0045f829 --- /dev/null +++ b/packages/shared/src/evaluator.ts @@ -0,0 +1,57 @@ +import { BlockAction, Steps } from "./model"; +import { createQuickJs, CreateQuickJSFn } from "./quickjs"; +import { useLogger } from "./logger"; + +export const makeResolvedParams = async ( + data: { + params: BlockAction["params"]; + steps: Steps; + variables: Record; + context: Record; + }, + onItem: (item: any) => string = (item: any) => item, + _vm?: Awaited | undefined, +) => { + const { logger } = useLogger(); + const vm = _vm ?? (await createQuickJs()); + + const result: Record = {}; + + const ctx = "createContext" in vm ? (vm as any).createContext() : null; + + for (const [paramName, param] of Object.entries(data.params)) { + try { + const parameterCodeValue = (param.value ?? "").toString(); + // Bypass QuickJS for simple static values + try { + result[paramName] = JSON.parse(parameterCodeValue); + continue; + } catch (e) { + // Not a simple JSON value, proceed to QuickJS evaluation + } + + const runParams = { + steps: data.steps, + params: {}, + variables: data.variables, + }; + + const output = ctx + ? ctx.run(parameterCodeValue, runParams) + : await vm.run(parameterCodeValue, runParams); + + const outputResult = onItem(output); + + result[paramName] = outputResult; + } catch (e) { + logger().error("error", e); + result[paramName] = ""; + } + } + + if (ctx) { + ctx.dispose(); + } + + return result; +}; diff --git a/packages/shared/src/fmt.ts b/packages/shared/src/fmt.ts new file mode 100644 index 00000000..3f1cb91b --- /dev/null +++ b/packages/shared/src/fmt.ts @@ -0,0 +1,5 @@ +export const fmt = { + param: (value: string, variant?: "primary" | "secondary" | undefined, ifEmpty: string = "") => { + return `${value ? value : ifEmpty}`; + }, +}; diff --git a/packages/shared/src/graph.ts b/packages/shared/src/graph.ts new file mode 100644 index 00000000..3fad6a39 --- /dev/null +++ b/packages/shared/src/graph.ts @@ -0,0 +1,139 @@ +import { makeResolvedParams } from "./evaluator"; +import { Steps } from "./model"; +import { Variable } from "./variables"; +import { RendererPluginDefinition } from "./plugins/definitions"; +import { Block } from "./model"; +import { Context } from "./types"; +import { End } from "./apis"; +import { useLogger } from "./logger"; +import { variableToFormattedVariable } from "./variables"; +import { createQuickJs } from "./quickjs"; + +const getPluginDefinition = (pluginId: string, definitions: Array) => { + const result = definitions.find((nodeDef) => { + return nodeDef.id === pluginId; + }); + return result; +}; + +const getNodeDefinition = ( + nodeId: string, + pluginId: string, + definitions: Array, +) => { + // const getNodeDefinition = (node: T extends Block ? T : never) => { + const plugin = getPluginDefinition(pluginId, definitions); + if (plugin) { + return plugin.nodes.find((pluginNode) => pluginNode.node.id === nodeId); + } + return undefined; +}; + +export const processGraph = async (options: { + graph: Array; + definitions: Array; + // editor user defined variables + variables: Array; + // steps outputs + steps: Steps; + // context like loopindex + context: Context; + onExecuteItem: ( + node: Block, + params: Record, + steps: Steps, + ) => Promise>; + onNodeEnter: (node: Block) => void; + onNodeExit: (node: Block) => void; + abortSignal?: AbortSignal; +}) => { + const { logger } = useLogger(); + + console.log("options.graph", options.graph); + + for (const node of options.graph) { + // Check if operation was aborted + if (options.abortSignal?.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + const rawNode = node; + + const pluginDefinition = getPluginDefinition(node.origin.pluginId, options.definitions); + const nodeDefinition = getNodeDefinition( + node.origin.nodeId, + node.origin.pluginId, + options.definitions, + ); + + if (rawNode.type === "action") { + if (rawNode.disabled === true) { + console.warn( + `Node ${rawNode.uid} (${rawNode.origin.pluginId}::${rawNode.origin.nodeId}) is disabled`, + ); + continue; + } + + options.onNodeEnter(rawNode); + + const vm = await createQuickJs(); + + const variables = await variableToFormattedVariable(vm, options.variables); + console.log("variables", variables); + + const newParams = await makeResolvedParams( + { + params: rawNode.params, + variables, + steps: options.steps, + context: options.context, + }, + undefined, + vm, + ); + + const result = (await options.onExecuteItem( + node, + newParams, + options.steps, + )) as End<"action:execute">; + + if (result.type === "error") { + logger().error(result.ipcError); + options.onNodeExit(rawNode); + // Check if it's an AbortError from cancellation + if ( + result.ipcError && + typeof result.ipcError === "object" && + (result.ipcError as Error).name === "AbortError" + ) { + throw result.ipcError; + } + throw new Error(`"${nodeDefinition.node.name}" action error: ${result.ipcError}`); + } + + if (result.type === "success") { + if (!options.steps[rawNode.uid]) { + options.steps[rawNode.uid] = { + outputs: {}, + }; + } + options.steps[rawNode.uid].outputs = result.result.outputs; + } + options.onNodeExit(rawNode); + } else if (rawNode.type === "comment") { + // pass + } else if (rawNode.type === "event") { + options.onNodeEnter(rawNode); + // pass + options.onNodeExit(rawNode); + } else { + logger().error("Unknown node type", rawNode.type); + } + + logger().info("steps", options.steps); + } + return options; +}; diff --git a/packages/shared/src/i18n-utils.ts b/packages/shared/src/i18n-utils.ts new file mode 100644 index 00000000..e5ba814b --- /dev/null +++ b/packages/shared/src/i18n-utils.ts @@ -0,0 +1,10 @@ +import en_US from "./i18n/en_US.json"; +import fr_FR from "./i18n/fr_FR.json"; +import pt_BR from "./i18n/pt_BR.json"; +import zh_CN from "./i18n/zh_CN.json"; +import es_ES from "./i18n/es_ES.json"; +import de_DE from "./i18n/de_DE.json"; + +type MessageSchema = typeof en_US; +export type Locales = "en-US" | "fr-FR" | "pt-BR" | "zh-CN" | "es-ES" | "de-DE"; +export { MessageSchema, en_US, fr_FR, pt_BR, zh_CN, es_ES, de_DE }; diff --git a/packages/shared/src/i18n/de_DE.json b/packages/shared/src/i18n/de_DE.json new file mode 100644 index 00000000..162df5d6 --- /dev/null +++ b/packages/shared/src/i18n/de_DE.json @@ -0,0 +1,173 @@ +{ + "settings": { + "darkTheme": "Dunkles Design", + "autosave": "Automatisch speichern", + "autosaveDescription": "Änderungen an Ihren Pipelines automatisch in Echtzeit speichern.", + "language": "Sprache", + "languageOptions": { + "en-US": "English", + "fr-FR": "French", + "pt-BR": "Portuguese", + "zh-CN": "Chinese", + "es-ES": "Spanish", + "de-DE": "German" + }, + "tabs": { + "general": "Allgemein", + "storage": "Speicher", + "integrations": "Integrationen", + "advanced": "Erweitert", + "billing": "Abrechnung", + "plugins": "Erweiterungen", + "core-plugins": "Kern-Erweiterungen", + "community-plugins": "Community-Erweiterungen", + "versions": "Versionen" + }, + "pipeline-cache-folder": "Pipeline-Cache-Ordner:", + "enter-or-browse-for-a-folder": "Ordner eingeben oder auswählen", + "browse": "Durchsuchen", + "manage-where-the-app-stores-temporary-and-cache-files": "Konfigurieren Sie lokale Ordner für temporäre Dateien und Anwendungs-Cache.", + "clear-cache": "Cache leeren", + "reset-to-default": "Auf Standard zurücksetzen", + "manage-subscription": "Abonnement verwalten", + "renewal-date": "Verlängerungsdatum", + "start-date": "Startdatum:", + "cache-cleared-successfully": "Cache erfolgreich geleert", + "failed-to-clear-cache-error-message": "Cache konnte nicht geleert werden: {0}", + "failed-to-reset-cache-folder-error-message": "Cache-Ordner konnte nicht zurückgesetzt werden: {0}", + "select-cache-folder": "Cache-Ordner auswählen", + "restart-dashboard-tour": "Dashboard-Anleitung zurücksetzen", + "restart-editor-tour": "Editor-Anleitung zurücksetzen", + "tour-reset-success": "Anleitungen wurden zurückgesetzt. Sie werden bei Ihrem nächsten Besuch wieder angezeigt.", + "storage-pipelab": "Pipelab", + "storage-other": "Andere Apps", + "storage-free": "Freier Speicher", + "disk-usage": "Festplattennutzung", + "free": "Frei", + "other": "Sonstige" + }, + "headers": { + "dashboard": "Dashboard", + "pipelines": "Pipelines", + "editor": "Editor", + "billing": "@:settings.tabs.billing", + "team": "Team" + }, + "base": { + "close": "Schließen", + "save": "Speichern", + "run": "Ausführen", + "cancel": "Abbrechen", + "end": "Ende", + "delete": "Löschen", + "logs": "Protokolle", + "ok": "OK", + "add": "Hinzufügen", + "search": "Suchen...", + "success": "Erfolg", + "error": "Fehler" + }, + "editor": { + "invalid-file-content": "Ungültiger Dateiinhalt", + "welcome-back": "Willkommen zurück!", + "please-log-in-to-run-a-pipeline": "Bitte melden Sie sich an, um diese Pipeline auszuführen.", + "execution-done": "Ausführung erfolgreich abgeschlossen", + "your-project-has-been-executed-successfully": "Ihre Pipeline wurde erfolgreich ausgeführt.", + "execution-failed": "Ausführung fehlgeschlagen", + "project-has-encountered-an-error": "Die Pipeline hat einen Fehler festgestellt:", + "project-saved": "Pipeline gespeichert", + "your-project-has-be-saved-successfully": "Ihre Pipeline wurde erfolgreich gespeichert.", + "view-history": "Verlauf", + "add-plugin": "Erweiterung hinzufügen", + "display-advanced-nodes": "Erweiterte Blöcke anzeigen", + "project-settings": "Pipeline-Einstellungen", + "jit-loading-title": "Erweiterungen werden vorbereitet", + "jit-loading-subtitle": "Bitte warten Sie, während Pipelab die für diese Pipeline erforderlichen Erweiterungen herunterlädt und konfigures.", + "jit-loading-status": "Herunterladen und Einrichten von Erweiterungspaketen...", + "validation-failed": "Validierung fehlgeschlagen", + "validation-plugin-disabled-or-missing": "Der Block \"{nodeName}\" erfordert die Erweiterung \"{pluginId}\", die derzeit nicht installiert oder aktiviert ist.", + "validation-missing-param": "Bitte konfigurieren Sie das erforderliche Feld \"{paramName}\" im Block \"{nodeName}\"." + }, + "home": { + "invalid-preset": "Ungültige Vorlage", + "store-project-on-the-cloud": "Projekt in der Cloud speichern", + "cloud": "Cloud", + "store-project-locally": "Projekt lokal speichern", + "local": "Lokal", + "invalid-number-of-paths-selected": "Ungültige Anzahl ausgewählter Pfade", + "pipelab-project": "Pipelab-Projekt", + "choose-a-new-path": "Wählen Sie einen neuen Pfad", + "invalid-file-type": "Ungültiger Dateityp", + "create-project": "Projekt erstellen", + "create-pipeline": "Pipeline erstellen", + "duplicate-project": "Projekt duplizieren", + "duplicate-pipeline": "Pipeline duplizieren", + "project-name": "Projektname", + "new-project": "Neues Projekt", + "new-pipeline": "Neue Pipeline", + "open": "Öffnen", + "import": "Importieren", + "pipeline-name": "Pipelinename", + "your-projects": "Ihre Projekte", + "no-projects-yet": "Noch keine Projekte", + "no-pipelines-yet": "Noch keine Pipelines", + "delete-project": "Projekt löschen", + "confirm-delete-project": "Sind Sie sicher, dass Sie dieses Projekt löschen möchten? Dies kann nicht rückgängig gemacht werden.", + "cannot-delete-project": "Projekt kann nicht gelöscht werden", + "project-not-empty": "Dieses Projekt enthält Pipelines. Bitte löschen Sie diese zuerst.", + "transfer": "Übertragen", + "transfer-successful": "Übertragung erfolgreich", + "pipeline-transferred": "Pipeline erfolgreich übertragen", + "select-project": "Projekt auswählen", + "build-history": "Ausführungsverlauf", + "duplicate": "Duplizieren", + "rename-project": "Projekt umbenennen", + "new-project-name": "Neuer Projektname", + "premium-feature": "Dies ist eine Premium-Funktion", + "migrate-warning": "Dieses Dateiformat wird bald nicht mehr unterstützt. Bitte migrieren Sie es in den neuen lokalen Arbeitsbereich.", + "simple-pipeline": "Einfache Pipeline", + "advanced-pipeline": "Erweiterte Pipeline", + "new-simple-project": "Neues einfaches Projekt", + "new-advanced-project": "Neues erweitertes Projekt", + "store-project-internally": "Projekt lokal speichern", + "internal": "Intern", + "confirm-migration-message": "Sind Sie sicher, dass Sie diese Pipeline in den lokalen Arbeitsbereich verschieben möchten? Pipelab wird diese Pipeline intern verwalten.", + "migrate-pipeline": "Pipeline migrieren", + "migration-success": "Pipeline erfolgreich migriert", + "migrate-to-internal": "In Arbeitsbereich verschieben", + "only-internal-supported-notice": "Pipelab verwaltet jetzt alle Pipelines im Arbeitsbereich der Anwendung. Externe Dateien sind veraltet, können aber weiterhin importiert werden.", + "import-pipeline": "Pipeline importieren", + "import-from-stable": "Aus Stable importieren...", + "import-from-beta": "Aus Beta importieren...", + "import-pipeline-file": "Pipeline-Datei importieren (.pipelab)...", + "import-success": "Pipeline erfolgreich importiert", + "failed-to-read-file": "Ausgewählte Datei konnte nicht gelesen werden", + "export-pipeline": "Pipeline exportieren...", + "export-success": "Pipeline erfolgreich exportiert", + "export-failed": "Fehler beim Exportieren der Pipeline" + }, + "pipelines": { + "title": "@:headers.pipelines" + }, + "tour": { + "start-tour": "Anleitung starten", + "projects-list-title": "Projekt-Navigator", + "projects-list-description": "Diese Seitenleiste zeigt Ihre Projekte. Durch Auswahl eines Projekts werden dessen Pipelines im Hauptbereich angezeigt.", + "add-project-title": "Neues Projekt erstellen", + "add-project-description": "Projekte organisieren Ihre Pipelines nach Thema oder Kunde. Klicken Sie hier, um ein neues Projekt zu starten.", + "new-pipeline-title": "Pipeline erstellen", + "new-pipeline-description": "Bereit zur Automatisierung? Erstellen Sie eine neue Pipeline, um Aktionen und Logik hinzuzufügen.", + "project-actions-title": "Projektverwaltung", + "project-actions-description": "Verwenden Sie diese Schaltflächen, um das derzeit ausgewählte Projekt umzubenennen oder zu löschen.", + "editor-canvas-title": "Der visuelle Editor", + "editor-canvas-description": "Dies ist Ihr Arbeitsbereich. Ziehen Sie Aktionsblöcke hierher, um Ihren Automatisierungsfluss zu erstellen.", + "editor-save-title": "Fortschritt speichern", + "editor-save-description": "Schützen Sie Ihre Änderungen. Wir empfehlen, Ihre Pipeline häufig zu speichern.", + "editor-run-title": "Pipeline testen", + "editor-run-description": "Klicken Sie auf Ausführen, um Ihre Pipeline zu testen. Pipelab führt jeden Block in Echtzeit aus.", + "editor-logs-title": "Ausführungsprotokolle", + "editor-logs-description": "Das Protokollfenster zeigt die Ausführungsschritte in Echtzeit, um Sie bei der Überwachung und Fehlersuche zu unterstützen.", + "editor-close-title": "Editor schließen", + "editor-close-description": "Fertig für heute? Kehren Sie zum Dashboard zurück, um andere Projekte und Pipelines zu verwalten." + } +} diff --git a/packages/shared/src/i18n/en_US.json b/packages/shared/src/i18n/en_US.json new file mode 100644 index 00000000..46a1be29 --- /dev/null +++ b/packages/shared/src/i18n/en_US.json @@ -0,0 +1,173 @@ +{ + "settings": { + "darkTheme": "Dark theme", + "autosave": "Autosave", + "autosaveDescription": "Automatically save changes to your pipelines in real-time.", + "language": "Language", + "languageOptions": { + "en-US": "English", + "fr-FR": "French", + "pt-BR": "Portuguese", + "zh-CN": "Chinese", + "es-ES": "Spanish", + "de-DE": "German" + }, + "tabs": { + "general": "General", + "storage": "Storage", + "integrations": "Integrations", + "advanced": "Advanced", + "billing": "Billing", + "plugins": "Plugins", + "core-plugins": "Core Plugins", + "community-plugins": "Community Plugins", + "versions": "Versions" + }, + "pipeline-cache-folder": "Pipeline Cache Folder:", + "enter-or-browse-for-a-folder": "Enter or browse for a folder", + "browse": "Browse", + "manage-where-the-app-stores-temporary-and-cache-files": "Configure local directories for temporary files and application cache.", + "clear-cache": "Clear cache", + "reset-to-default": "Reset to default", + "manage-subscription": "Manage Subscription", + "renewal-date": "Renewal Date", + "start-date": "Start Date:", + "cache-cleared-successfully": "Cache cleared successfully", + "failed-to-clear-cache-error-message": "Failed to clear cache: {0}", + "failed-to-reset-cache-folder-error-message": "Failed to reset cache folder: {0}", + "select-cache-folder": "Select Cache Folder", + "restart-dashboard-tour": "Reset Dashboard Guide", + "restart-editor-tour": "Reset Editor Guide", + "tour-reset-success": "Help guides have been reset. They will reappear on your next visit.", + "storage-pipelab": "Pipelab", + "storage-other": "Other Apps", + "storage-free": "Free Space", + "disk-usage": "Disk Usage", + "free": "Free", + "other": "Other" + }, + "headers": { + "dashboard": "Dashboard", + "pipelines": "Pipelines", + "editor": "Editor", + "billing": "@:settings.tabs.billing", + "team": "Team" + }, + "base": { + "close": "Close", + "save": "Save", + "run": "Run", + "cancel": "Cancel", + "end": "End", + "delete": "Delete", + "logs": "Logs", + "ok": "OK", + "add": "Add", + "search": "Search...", + "success": "Success", + "error": "Error" + }, + "editor": { + "invalid-file-content": "Invalid file content", + "welcome-back": "Welcome back!", + "please-log-in-to-run-a-pipeline": "Please sign in to run this pipeline.", + "execution-done": "Run completed successfully", + "your-project-has-been-executed-successfully": "Your pipeline ran and completed successfully.", + "execution-failed": "Run failed", + "project-has-encountered-an-error": "The pipeline encountered an error:", + "project-saved": "Pipeline saved", + "your-project-has-be-saved-successfully": "Your pipeline has been saved successfully.", + "view-history": "History", + "add-plugin": "Add plugin", + "display-advanced-nodes": "Display advanced nodes", + "project-settings": "Pipeline Settings", + "jit-loading-title": "Preparing Plugins", + "jit-loading-subtitle": "Please wait while Pipelab downloads and configures the required plugins for this pipeline.", + "jit-loading-status": "Downloading and setting up plugin packages...", + "validation-failed": "Validation Failed", + "validation-plugin-disabled-or-missing": "The block \"{nodeName}\" requires the \"{pluginId}\" plugin, which is not currently installed or enabled.", + "validation-missing-param": "Please configure the required field \"{paramName}\" in the \"{nodeName}\" block." + }, + "home": { + "invalid-preset": "Invalid preset", + "store-project-on-the-cloud": "Save project to Cloud", + "cloud": "Cloud", + "store-project-locally": "Save project locally", + "local": "Local", + "invalid-number-of-paths-selected": "Invalid number of paths selected", + "pipelab-project": "Pipelab Project", + "choose-a-new-path": "Choose a new path", + "invalid-file-type": "Invalid file type", + "create-project": "Create Project", + "create-pipeline": "Create Pipeline", + "duplicate-project": "Duplicate Project", + "duplicate-pipeline": "Duplicate Pipeline", + "project-name": "Project Name", + "new-project": "New Project", + "new-pipeline": "New Pipeline", + "open": "Open", + "import": "Import", + "pipeline-name": "Pipeline Name", + "your-projects": "Your projects", + "no-projects-yet": "No projects yet", + "no-pipelines-yet": "No pipelines yet", + "delete-project": "Delete Project", + "confirm-delete-project": "Are you sure you want to delete this project? This action cannot be undone.", + "cannot-delete-project": "Cannot delete project", + "project-not-empty": "This project contains pipelines. Please delete them first.", + "transfer": "Transfer", + "transfer-successful": "Transfer Successful", + "pipeline-transferred": "Pipeline transferred successfully", + "select-project": "Select Project", + "build-history": "Build History", + "duplicate": "Duplicate", + "rename-project": "Rename Project", + "new-project-name": "New Project Name", + "premium-feature": "This is a premium feature", + "migrate-warning": "This file format will soon be deprecated. Please migrate it to the new local workspace storage.", + "simple-pipeline": "Basic pipeline", + "advanced-pipeline": "Advanced pipeline", + "new-simple-project": "New simple project", + "new-advanced-project": "New advanced project", + "store-project-internally": "Save project locally", + "internal": "Internal", + "confirm-migration-message": "Are you sure you want to move this pipeline to local workspace storage? Pipelab will manage this pipeline internally.", + "migrate-pipeline": "Migrate Pipeline", + "migration-success": "Pipeline migrated successfully", + "migrate-to-internal": "Move to Workspace", + "only-internal-supported-notice": "Pipelab now manages all pipelines within the application workspace. External files are deprecated, but can be imported into your workspace.", + "import-pipeline": "Import Pipeline", + "import-from-stable": "Import from Stable...", + "import-from-beta": "Import from Beta...", + "import-pipeline-file": "Import pipeline file (.pipelab)...", + "import-success": "Pipeline imported successfully", + "failed-to-read-file": "Failed to read the selected file", + "export-pipeline": "Export Pipeline...", + "export-success": "Pipeline exported successfully", + "export-failed": "Failed to export pipeline" + }, + "pipelines": { + "title": "@:headers.pipelines" + }, + "tour": { + "start-tour": "Start Tour", + "projects-list-title": "Project Navigator", + "projects-list-description": "This sidebar lists your projects. Selecting a project will show its pipelines in the main area.", + "add-project-title": "Create New Project", + "add-project-description": "Projects organize your pipelines by topic or client. Click here to start a new project.", + "new-pipeline-title": "Create a Pipeline", + "new-pipeline-description": "Ready to automate? Create a new pipeline to start adding actions and logic.", + "project-actions-title": "Project Management", + "project-actions-description": "Use these buttons to rename or delete the currently selected project.", + "editor-canvas-title": "The Visual Canvas", + "editor-canvas-description": "This is your canvas. Drag and drop action blocks here to build your automation flow.", + "editor-save-title": "Save Progress", + "editor-save-description": "Keep your changes safe. We recommend saving your pipeline frequently.", + "editor-run-title": "Test Pipeline", + "editor-run-description": "Click Run to test your pipeline. Pipelab will execute each block in real-time.", + "editor-logs-title": "Run Logs", + "editor-logs-description": "The log panel shows real-time execution steps, helping you monitor and debug.", + "editor-close-title": "Close Editor", + "editor-close-description": "Done for now? Return to the dashboard to manage other projects and pipelines." + } +} diff --git a/packages/shared/src/i18n/es_ES.json b/packages/shared/src/i18n/es_ES.json new file mode 100644 index 00000000..ad065d6e --- /dev/null +++ b/packages/shared/src/i18n/es_ES.json @@ -0,0 +1,173 @@ +{ + "settings": { + "darkTheme": "Tema oscuro", + "autosave": "Guardado automático", + "autosaveDescription": "Guarda automáticamente los cambios en tus pipelines en tiempo real.", + "language": "Idioma", + "languageOptions": { + "en-US": "English", + "fr-FR": "French", + "pt-BR": "Portuguese", + "zh-CN": "Chinese", + "es-ES": "Spanish", + "de-DE": "German" + }, + "tabs": { + "general": "General", + "storage": "Almacenamiento", + "integrations": "Integraciones", + "advanced": "Avanzado", + "billing": "Facturación", + "plugins": "Complementos", + "core-plugins": "Complementos principales", + "community-plugins": "Complementos de la comunidad", + "versions": "Versiones" + }, + "pipeline-cache-folder": "Carpeta de caché de pipelines:", + "enter-or-browse-for-a-folder": "Escribe o busca una carpeta", + "browse": "Buscar", + "manage-where-the-app-stores-temporary-and-cache-files": "Configura carpetas locales para archivos temporales y caché de la aplicación.", + "clear-cache": "Limpiar caché", + "reset-to-default": "Restablecer por defecto", + "manage-subscription": "Gestionar suscripción", + "renewal-date": "Fecha de renovación", + "start-date": "Fecha de inicio:", + "cache-cleared-successfully": "Caché limpia con éxito", + "failed-to-clear-cache-error-message": "Error al limpiar la caché: {0}", + "failed-to-reset-cache-folder-error-message": "Error al restablecer la carpeta de caché: {0}", + "select-cache-folder": "Seleccionar carpeta de caché", + "restart-dashboard-tour": "Restablecer guía de inicio", + "restart-editor-tour": "Restablecer guía del editor", + "tour-reset-success": "Las guías de ayuda se han restablecido. Volverán a aparecer en tu próxima visita.", + "storage-pipelab": "Pipelab", + "storage-other": "Otras aplicaciones", + "storage-free": "Espacio libre", + "disk-usage": "Uso del disco", + "free": "Libre", + "other": "Otro" + }, + "headers": { + "dashboard": "Inicio", + "pipelines": "Pipelines", + "editor": "Editor", + "billing": "@:settings.tabs.billing", + "team": "Equipo" + }, + "base": { + "close": "Cerrar", + "save": "Guardar", + "run": "Ejecutar", + "cancel": "Cancelar", + "end": "Fin", + "delete": "Eliminar", + "logs": "Registros", + "ok": "Aceptar", + "add": "Añadir", + "search": "Buscar...", + "success": "Éxito", + "error": "Error" + }, + "editor": { + "invalid-file-content": "Contenido de archivo no válido", + "welcome-back": "¡Bienvenido de nuevo!", + "please-log-in-to-run-a-pipeline": "Inicia sesión para ejecutar este pipeline.", + "execution-done": "Ejecución completada con éxito", + "your-project-has-been-executed-successfully": "Tu pipeline se ha ejecutado correctamente.", + "execution-failed": "Ejecución fallida", + "project-has-encountered-an-error": "El pipeline ha encontrado un error:", + "project-saved": "Pipeline guardado", + "your-project-has-be-saved-successfully": "Tu pipeline se ha guardado correctamente.", + "view-history": "Historial", + "add-plugin": "Añadir complemento", + "display-advanced-nodes": "Mostrar bloques avanzados", + "project-settings": "Ajustes del pipeline", + "jit-loading-title": "Preparando complementos", + "jit-loading-subtitle": "Espera mientras Pipelab descarga y configura los complementos necesarios para este pipeline.", + "jit-loading-status": "Descargando y configurando paquetes de complementos...", + "validation-failed": "Validación fallida", + "validation-plugin-disabled-or-missing": "El bloque \"{nodeName}\" requiere el complemento \"{pluginId}\", que no está instalado o activo.", + "validation-missing-param": "Configura el campo obligatorio \"{paramName}\" en el bloque \"{nodeName}\"." + }, + "home": { + "invalid-preset": "Plantilla no válida", + "store-project-on-the-cloud": "Guardar proyecto en la nube", + "cloud": "Nube", + "store-project-locally": "Guardar proyecto localmente", + "local": "Local", + "invalid-number-of-paths-selected": "Número de rutas seleccionado no válido", + "pipelab-project": "Proyecto Pipelab", + "choose-a-new-path": "Elige una nueva ruta", + "invalid-file-type": "Tipo de archivo no válido", + "create-project": "Crear Proyecto", + "create-pipeline": "Crear Pipeline", + "duplicate-project": "Duplicar Proyecto", + "duplicate-pipeline": "Duplicar Pipeline", + "project-name": "Nombre del proyecto", + "new-project": "Nuevo Proyecto", + "new-pipeline": "Nuevo Pipeline", + "open": "Abrir", + "import": "Importar", + "pipeline-name": "Nombre del pipeline", + "your-projects": "Tus proyectos", + "no-projects-yet": "Aún no hay proyectos", + "no-pipelines-yet": "Aún no hay pipelines", + "delete-project": "Eliminar Proyecto", + "confirm-delete-project": "¿Estás seguro de que quieres eliminar este proyecto? Esta acción no se puede deshacer.", + "cannot-delete-project": "No se puede eliminar el proyecto", + "project-not-empty": "Este proyecto contiene pipelines. Elíminalos primero.", + "transfer": "Transferir", + "transfer-successful": "Transferencia completada", + "pipeline-transferred": "Pipeline transferido con éxito", + "select-project": "Seleccionar Proyecto", + "build-history": "Historial de ejecuciones", + "duplicate": "Duplicar", + "rename-project": "Renombrar Proyecto", + "new-project-name": "Nuevo nombre del proyecto", + "premium-feature": "Esta es una función premium", + "migrate-warning": "Este formato de archivo pronto quedará obsoleto. Mígralo al nuevo almacenamiento local de la aplicación.", + "simple-pipeline": "Pipeline básico", + "advanced-pipeline": "Pipeline avanzado", + "new-simple-project": "Nuevo proyecto simple", + "new-advanced-project": "Nuevo proyecto avanzado", + "store-project-internally": "Guardar proyecto localmente", + "internal": "Interno", + "confirm-migration-message": "¿Estás seguro de que quieres mover este pipeline al almacenamiento local de la aplicación? Pipelab gérera este pipeline internamente.", + "migrate-pipeline": "Migrar Pipeline", + "migration-success": "Pipeline migrado con éxito", + "migrate-to-internal": "Mover al espacio de trabajo", + "only-internal-supported-notice": "Pipelab ahora gestiona todos los pipelines dentro del espacio de trabajo. Los archivos externos están obsoletos, pero pueden importarse.", + "import-pipeline": "Importar Pipeline", + "import-from-stable": "Importar desde Stable...", + "import-from-beta": "Importar desde Beta...", + "import-pipeline-file": "Importar archivo de pipeline (.pipelab)...", + "import-success": "Pipeline importado con éxito", + "failed-to-read-file": "Error al leer el archivo seleccionado", + "export-pipeline": "Exportar pipeline...", + "export-success": "Pipeline exportado correctamente", + "export-failed": "Error al exportar el pipeline" + }, + "pipelines": { + "title": "@:headers.pipelines" + }, + "tour": { + "start-tour": "Iniciar guía", + "projects-list-title": "Navegador de proyectos", + "projects-list-description": "Esta barra lateral muestra tus proyectos. Al seleccionar uno se mostrarán sus pipelines en el área principal.", + "add-project-title": "Crear nuevo proyecto", + "add-project-description": "Los proyectos organizan tus pipelines por tema o cliente. Haz clic aquí para crear uno.", + "new-pipeline-title": "Crear un pipeline", + "new-pipeline-description": "¿Listo para automatizar? Crea un nuevo pipeline para empezar a añadir acciones y lógica.", + "project-actions-title": "Gestión de proyectos", + "project-actions-description": "Usa estos botones para renombrar o eliminar el proyecto seleccionado.", + "editor-canvas-title": "El lienzo visual", + "editor-canvas-description": "Este es tu lienzo. Arrastra y suelta bloques de acción aquí para construir tu flujo.", + "editor-save-title": "Guardar progreso", + "editor-save-description": "Mantén tus cambios seguros. Te recomendamos guardar tu pipeline con frecuencia.", + "editor-run-title": "Probar pipeline", + "editor-run-description": "Haz clic en Ejecutar para probar tu pipeline. Pipelab ejecutará cada bloque en tiempo real.", + "editor-logs-title": "Registros de ejecución", + "editor-logs-description": "El panel de registros muestra los pasos en tiempo real, ayudándote a supervisar y depurar.", + "editor-close-title": "Cerrar editor", + "editor-close-description": "¿Has terminado? Vuelve al panel de inicio para gestionar otros proyectos y pipelines." + } +} diff --git a/packages/shared/src/i18n/fr_FR.json b/packages/shared/src/i18n/fr_FR.json new file mode 100644 index 00000000..62e70974 --- /dev/null +++ b/packages/shared/src/i18n/fr_FR.json @@ -0,0 +1,173 @@ +{ + "settings": { + "darkTheme": "Thème sombre", + "autosave": "Enregistrement automatique", + "autosaveDescription": "Enregistrez automatiquement les modifications de vos pipelines en temps réel.", + "language": "Langue", + "languageOptions": { + "en-US": "English", + "fr-FR": "Français", + "pt-BR": "Português", + "zh-CN": "Chinois", + "es-ES": "Espagnol", + "de-DE": "Allemand" + }, + "tabs": { + "general": "Général", + "storage": "Stockage", + "integrations": "Intégrations", + "advanced": "Avancé", + "billing": "Facturation", + "plugins": "Extensions", + "core-plugins": "Extensions de base", + "community-plugins": "Extensions de la communauté", + "versions": "Versions" + }, + "pipeline-cache-folder": "Dossier cache des pipelines :", + "enter-or-browse-for-a-folder": "Saisir ou parcourir pour choisir un dossier", + "browse": "Parcourir", + "manage-where-the-app-stores-temporary-and-cache-files": "Configurez les dossiers locaux pour les fichiers temporaires et le cache de l'application.", + "clear-cache": "Vider le cache", + "reset-to-default": "Réinitialiser par défaut", + "manage-subscription": "Gérer l'abonnement", + "renewal-date": "Date de renouvellement", + "start-date": "Date de début :", + "cache-cleared-successfully": "Cache vidé avec succès", + "failed-to-clear-cache-error-message": "Échec du vidage du cache : {0}", + "failed-to-reset-cache-folder-error-message": "Échec de la réinitialisation du dossier cache : {0}", + "select-cache-folder": "Sélectionner le dossier cache", + "restart-dashboard-tour": "Réinitialiser le guide du tableau de bord", + "restart-editor-tour": "Réinitialiser le guide de l'éditeur", + "tour-reset-success": "Les guides d'aide ont été réinitialisés. Ils réapparaîtront lors de votre prochaine visite.", + "storage-pipelab": "Pipelab", + "storage-other": "Autres applications", + "storage-free": "Espace libre", + "disk-usage": "Utilisation du disque", + "free": "Libre", + "other": "Autre" + }, + "headers": { + "dashboard": "Tableau de bord", + "pipelines": "Pipelines", + "editor": "Éditeur", + "billing": "@:settings.tabs.billing", + "team": "Équipe" + }, + "base": { + "close": "Fermer", + "save": "Enregistrer", + "run": "Exécuter", + "cancel": "Annuler", + "end": "Fin", + "delete": "Supprimer", + "logs": "Journaux", + "ok": "OK", + "add": "Ajouter", + "search": "Rechercher...", + "success": "Succès", + "error": "Erreur" + }, + "editor": { + "invalid-file-content": "Contenu du fichier invalide", + "welcome-back": "Bon retour !", + "please-log-in-to-run-a-pipeline": "Veuillez vous connecter pour exécuter ce pipeline.", + "execution-done": "Exécution terminée avec succès", + "your-project-has-been-executed-successfully": "Votre pipeline s'est exécuté et s'est terminé avec succès.", + "execution-failed": "Échec de l'exécution", + "project-has-encountered-an-error": "Le pipeline a rencontré une erreur :", + "project-saved": "Pipeline enregistré", + "your-project-has-be-saved-successfully": "Votre pipeline a été enregistré avec succès.", + "view-history": "Historique", + "add-plugin": "Ajouter une extension", + "display-advanced-nodes": "Afficher les nœuds avancés", + "project-settings": "Paramètres du pipeline", + "jit-loading-title": "Préparation des extensions", + "jit-loading-subtitle": "Veuillez patienter pendant que Pipelab télécharge et configure les extensions requises pour ce pipeline.", + "jit-loading-status": "Téléchargement et configuration des paquets d'extension...", + "validation-failed": "Échec de la validation", + "validation-plugin-disabled-or-missing": "Le bloc \"{nodeName}\" requiert l'extension \"{pluginId}\", qui n'est pas installée ou activée actuellement.", + "validation-missing-param": "Veuillez configurer le champ requis \"{paramName}\" dans le bloc \"{nodeName}\"." + }, + "home": { + "invalid-preset": "Modèle invalide", + "store-project-on-the-cloud": "Enregistrer le projet dans le Cloud", + "cloud": "Cloud", + "store-project-locally": "Enregistrer le projet localement", + "local": "Local", + "invalid-number-of-paths-selected": "Nombre de chemins sélectionné invalide", + "pipelab-project": "Projet Pipelab", + "choose-a-new-path": "Choisir un nouveau chemin", + "invalid-file-type": "Type de fichier invalide", + "create-project": "Créer le Projet", + "create-pipeline": "Créer le Pipeline", + "duplicate-project": "Dupliquer le Projet", + "duplicate-pipeline": "Dupliquer le Pipeline", + "project-name": "Nom du projet", + "new-project": "Nouveau Projet", + "new-pipeline": "Nouveau Pipeline", + "open": "Ouvrir", + "import": "Importer", + "pipeline-name": "Nom du pipeline", + "your-projects": "Vos projets", + "no-projects-yet": "Aucun projet pour le moment", + "no-pipelines-yet": "Aucun pipeline pour le moment", + "delete-project": "Supprimer le Projet", + "confirm-delete-project": "Êtes-vous sûr de vouloir supprimer ce projet ? Cette action est irréversible.", + "cannot-delete-project": "Impossible de supprimer le projet", + "project-not-empty": "Ce projet contient des pipelines. Veuillez d'abord les supprimer.", + "transfer": "Transférer", + "transfer-successful": "Transfert réussi", + "pipeline-transferred": "Pipeline transféré avec succès", + "select-project": "Sélectionner le Projet", + "build-history": "Historique des exécutions", + "duplicate": "Dupliquer", + "rename-project": "Renommer le Projet", + "new-project-name": "Nouveau nom du projet", + "premium-feature": "Ceci est une fonctionnalité premium", + "migrate-warning": "Ce format de fichier sera bientôt obsolète. Veuillez le migrer vers le nouveau stockage local.", + "simple-pipeline": "Pipeline basique", + "advanced-pipeline": "Pipeline avancé", + "new-simple-project": "Nouveau projet simple", + "new-advanced-project": "Nouveau projet avancé", + "store-project-internally": "Enregistrer le projet localement", + "internal": "Interne", + "confirm-migration-message": "Êtes-vous sûr de vouloir déplacer ce pipeline vers le stockage local de l'application ? Pipelab gérera ce pipeline en interne.", + "migrate-pipeline": "Migrer le Pipeline", + "migration-success": "Pipeline migré avec succès", + "migrate-to-internal": "Déplacer vers l'espace de travail", + "only-internal-supported-notice": "Pipelab gère désormais tous les pipelines au sein de l'espace de travail de l'application. Les fichiers externes sont obsolètes, mais peuvent toujours être importés.", + "import-pipeline": "Importer le Pipeline", + "import-from-stable": "Importer depuis Stable...", + "import-from-beta": "Importer depuis Beta...", + "import-pipeline-file": "Importer un fichier de pipeline (.pipelab)...", + "import-success": "Pipeline importé avec succès", + "failed-to-read-file": "Échec de la lecture du fichier sélectionné", + "export-pipeline": "Exporter le pipeline...", + "export-success": "Pipeline exporté avec succès", + "export-failed": "Échec de l'exportation du pipeline" + }, + "pipelines": { + "title": "@:headers.pipelines" + }, + "tour": { + "start-tour": "Démarrer le guide", + "projects-list-title": "Navigateur de projets", + "projects-list-description": "Cette barre latérale liste vos projets. En sélectionnant un projet, ses pipelines s'afficheront dans la zone principale.", + "add-project-title": "Créer un nouveau projet", + "add-project-description": "Les projets organisent vos pipelines par sujet ou client. Cliquez ici pour commencer un nouveau projet.", + "new-pipeline-title": "Créer un pipeline", + "new-pipeline-description": "Prêt à automatiser ? Créez un nouveau pipeline pour commencer à ajouter des actions et de la logique.", + "project-actions-title": "Gestion du projet", + "project-actions-description": "Utilisez ces boutons pour renommer ou supprimer le projet actuellement sélectionné.", + "editor-canvas-title": "Le canevas visuel", + "editor-canvas-description": "Ceci est votre canevas. Glissez-déposez des blocs d'action ici pour construire votre flux d'automatisation.", + "editor-save-title": "Enregistrer la progression", + "editor-save-description": "Protégez vos modifications. Nous vous recommandons d'enregistrer fréquemment votre pipeline.", + "editor-run-title": "Tester le pipeline", + "editor-run-description": "Cliquez sur Exécuter pour tester votre pipeline. Pipelab exécutera chaque bloc en temps réel.", + "editor-logs-title": "Journaux d'exécution", + "editor-logs-description": "Le panneau des journaux affiche les étapes d'exécution en temps réel, vous aidant à surveiller et déboguer.", + "editor-close-title": "Fermer l'éditeur", + "editor-close-description": "Terminé pour le moment ? Retournez au tableau de bord pour gérer d'autres projets et pipelines." + } +} diff --git a/packages/shared/src/i18n/pt_BR.json b/packages/shared/src/i18n/pt_BR.json new file mode 100644 index 00000000..a03c4c24 --- /dev/null +++ b/packages/shared/src/i18n/pt_BR.json @@ -0,0 +1,173 @@ +{ + "settings": { + "darkTheme": "Tema escuro", + "autosave": "Salvar automaticamente", + "autosaveDescription": "Salvar alterações em suas pipelines automaticamente em tempo real.", + "language": "Idioma", + "languageOptions": { + "en-US": "English", + "fr-FR": "French", + "pt-BR": "Portuguese", + "zh-CN": "Chinese", + "es-ES": "Spanish", + "de-DE": "German" + }, + "tabs": { + "general": "Geral", + "storage": "Armazenamento", + "integrations": "Integrações", + "advanced": "Avançado", + "billing": "Faturamento", + "plugins": "Extensões", + "core-plugins": "Extensões nativas", + "community-plugins": "Extensões da comunidade", + "versions": "Versões" + }, + "pipeline-cache-folder": "Pasta de cache de pipelines:", + "enter-or-browse-for-a-folder": "Digite ou procure uma pasta", + "browse": "Procurar", + "manage-where-the-app-stores-temporary-and-cache-files": "Configurar pastas locais para arquivos temporários e cache do aplicativo.", + "clear-cache": "Limpar cache", + "reset-to-default": "Redefinir para o padrão", + "manage-subscription": "Gerenciar assinatura", + "renewal-date": "Data de renovação", + "start-date": "Data de início:", + "cache-cleared-successfully": "Cache limpo com sucesso", + "failed-to-clear-cache-error-message": "Falha ao limpar cache: {0}", + "failed-to-reset-cache-folder-error-message": "Falha ao redefinir pasta de cache: {0}", + "select-cache-folder": "Selecionar pasta de cache", + "restart-dashboard-tour": "Redefinir guia de início", + "restart-editor-tour": "Redefinir guia do editor", + "tour-reset-success": "Os guias de ajuda foram redefinidos. Eles reaparecerão em sua próxima visita.", + "storage-pipelab": "Pipelab", + "storage-other": "Outros aplicativos", + "storage-free": "Espaço livre", + "disk-usage": "Uso do disco", + "free": "Livre", + "other": "Outro" + }, + "headers": { + "dashboard": "Início", + "pipelines": "Pipelines", + "editor": "Editor", + "billing": "@:settings.tabs.billing", + "team": "Equipe" + }, + "base": { + "close": "Fechar", + "save": "Salvar", + "run": "Executar", + "cancel": "Cancelar", + "end": "Fim", + "delete": "Excluir", + "logs": "Registros", + "ok": "OK", + "add": "Adicionar", + "search": "Buscar...", + "success": "Sucesso", + "error": "Erro" + }, + "editor": { + "invalid-file-content": "Conteúdo do arquivo inválido", + "welcome-back": "Bem-vindo de volta!", + "please-log-in-to-run-a-pipeline": "Por favor, faça login para executar esta pipeline.", + "execution-done": "Execução concluída com sucesso", + "your-project-has-been-executed-successfully": "Sua pipeline foi executada e concluída com sucesso.", + "execution-failed": "Falha na execução", + "project-has-encountered-an-error": "A pipeline encontrou um erro:", + "project-saved": "Pipeline salva", + "your-project-has-be-saved-successfully": "Sua pipeline foi salva com sucesso.", + "view-history": "Histórico", + "add-plugin": "Adicionar extensão", + "display-advanced-nodes": "Exibir blocos avançados", + "project-settings": "Ajustes da pipeline", + "jit-loading-title": "Preparando extensões", + "jit-loading-subtitle": "Aguarde enquanto o Pipelab baixa e configura as extensões necessárias para esta pipeline.", + "jit-loading-status": "Baixando e configurando pacotes de extensões...", + "validation-failed": "Falha na validação", + "validation-plugin-disabled-or-missing": "O bloco \"{nodeName}\" requer a extensão \"{pluginId}\", que não está instalada ou ativada.", + "validation-missing-param": "Por favor, configure o campo obrigatório \"{paramName}\" no bloco \"{nodeName}\"." + }, + "home": { + "invalid-preset": "Modelo inválido", + "store-project-on-the-cloud": "Salvar projeto na nuvem", + "cloud": "Nuvem", + "store-project-locally": "Salvar projeto localmente", + "local": "Local", + "invalid-number-of-paths-selected": "Número de caminhos selecionado inválido", + "pipelab-project": "Projeto Pipelab", + "choose-a-new-path": "Escolha um novo caminho", + "invalid-file-type": "Tipo de arquivo inválido", + "create-project": "Criar Projeto", + "create-pipeline": "Criar Pipeline", + "duplicate-project": "Duplicar Projeto", + "duplicate-pipeline": "Duplicar Pipeline", + "project-name": "Nome do projeto", + "new-project": "Novo Projeto", + "new-pipeline": "Nova Pipeline", + "open": "Abrir", + "import": "Importar", + "pipeline-name": "Nome da pipeline", + "your-projects": "Seus projetos", + "no-projects-yet": "Nenhum projeto ainda", + "no-pipelines-yet": "Nenhuma pipeline ainda", + "delete-project": "Excluir Projeto", + "confirm-delete-project": "Tem certeza de que deseja excluir este projeto? Esta ação não pode ser desfeita.", + "cannot-delete-project": "Não é possível excluir o projeto", + "project-not-empty": "Este projeto contém pipelines. Por favor, exclua-os primeiro.", + "transfer": "Transferir", + "transfer-successful": "Transferência bem-sucedida", + "pipeline-transferred": "Pipeline transferida com sucesso", + "select-project": "Selecionar Projeto", + "build-history": "Histórico de execuções", + "duplicate": "Duplicar", + "rename-project": "Renomear Projeto", + "new-project-name": "Novo nome do projeto", + "premium-feature": "Este é um recurso premium", + "migrate-warning": "Este formato de arquivo em prazo curto será descontinuado. Por favor, migre-o para o novo armazenamento local do aplicativo.", + "simple-pipeline": "Pipeline básica", + "advanced-pipeline": "Pipeline avançada", + "new-simple-project": "Novo projeto simples", + "new-advanced-project": "Novo projeto avançado", + "store-project-internally": "Salvar projeto localmente", + "internal": "Interno", + "confirm-migration-message": "Tem certeza de que deseja mover esta pipeline para o armazenamento local do aplicativo? O Pipelab gerenciará esta pipeline internamente.", + "migrate-pipeline": "Migrar Pipeline", + "migration-success": "Pipeline migrada com sucesso", + "migrate-to-internal": "Mover para o espaço de trabalho", + "only-internal-supported-notice": "O Pipelab agora gerencia todas as pipelines dentro do espaço de trabalho do aplicativo. Arquivos externos foram descontinuados, mas podem ser importados.", + "import-pipeline": "Importar Pipeline", + "import-from-stable": "Importar do Stable...", + "import-from-beta": "Importar do Beta...", + "import-pipeline-file": "Importar arquivo de pipeline (.pipelab)...", + "import-success": "Pipeline importada com sucesso", + "failed-to-read-file": "Falha ao ler o arquivo selecionado", + "export-pipeline": "Exportar pipeline...", + "export-success": "Pipeline exportado com sucesso", + "export-failed": "Falha ao exportar pipeline" + }, + "pipelines": { + "title": "@:headers.pipelines" + }, + "tour": { + "start-tour": "Iniciar guia", + "projects-list-title": "Navegador de projetos", + "projects-list-description": "Esta barra lateral mostra seus projetos. Ao selecionar um, suas pipelines serão exibidas na área principal.", + "add-project-title": "Criar novo projeto", + "add-project-description": "Os projetos organizam suas pipelines por tópico ou cliente. Clique aqui para criar um novo projeto.", + "new-pipeline-title": "Criar uma pipeline", + "new-pipeline-description": "Pronto para automatizar? Crie uma nova pipeline para começar a adicionar ações e lógica.", + "project-actions-title": "Gerenciamento de projetos", + "project-actions-description": "Use estes botões para renomear ou excluir o projeto selecionado.", + "editor-canvas-title": "O painel visual", + "editor-canvas-description": "Este é o seu painel. Arraste e solte blocos de ação aqui para construir seu fluxo.", + "editor-save-title": "Salvar progresso", + "editor-save-description": "Mantenha suas alterações seguras. Recomendamos salvar sua pipeline frequentemente.", + "editor-run-title": "Testar pipeline", + "editor-run-description": "Clique em Executar para testar sua pipeline. O Pipelab executará cada bloco em tempo real.", + "editor-logs-title": "Registros de execução", + "editor-logs-description": "O painel de registros exibe as etapas de execução em tempo real, ajudando você a monitorar e depurar.", + "editor-close-title": "Fechar editor", + "editor-close-description": "Terminou por agora? Volte para o painel principal para gerenciar outros projetos e pipelines." + } +} diff --git a/packages/shared/src/i18n/zh_CN.json b/packages/shared/src/i18n/zh_CN.json new file mode 100644 index 00000000..1aa708c4 --- /dev/null +++ b/packages/shared/src/i18n/zh_CN.json @@ -0,0 +1,173 @@ +{ + "settings": { + "darkTheme": "深色主题", + "autosave": "自动保存", + "autosaveDescription": "自动保存流水线修改,省心省力。", + "language": "语言", + "languageOptions": { + "en-US": "English", + "fr-FR": "French", + "pt-BR": "Portuguese", + "zh-CN": "Chinese", + "es-ES": "Spanish", + "de-DE": "German" + }, + "tabs": { + "general": "常规", + "storage": "存储", + "integrations": "集成", + "advanced": "高级", + "billing": "计费", + "plugins": "插件", + "core-plugins": "核心插件", + "community-plugins": "社区插件", + "versions": "版本" + }, + "pipeline-cache-folder": "流水线缓存文件夹:", + "enter-or-browse-for-a-folder": "输入或浏览选择文件夹", + "browse": "浏览", + "manage-where-the-app-stores-temporary-and-cache-files": "配置用于存储临时文件和应用程序缓存的本地目录。", + "clear-cache": "清除缓存", + "reset-to-default": "恢复默认", + "manage-subscription": "管理订阅", + "renewal-date": "续订日期", + "start-date": "开始日期:", + "cache-cleared-successfully": "缓存清除成功", + "failed-to-clear-cache-error-message": "清除缓存失败: {0}", + "failed-to-reset-cache-folder-error-message": "重置缓存文件夹失败: {0}", + "select-cache-folder": "选择缓存文件夹", + "restart-dashboard-tour": "重置仪表盘指南", + "restart-editor-tour": "重置编辑器指南", + "tour-reset-success": "帮助指南已重置。将在您下次访问时重新显示。", + "storage-pipelab": "Pipelab", + "storage-other": "其他应用", + "storage-free": "空闲空间", + "disk-usage": "磁盘使用情况", + "free": "空闲", + "other": "其他" + }, + "headers": { + "dashboard": "仪表盘", + "pipelines": "流水线", + "editor": "编辑器", + "billing": "@:settings.tabs.billing", + "team": "团队" + }, + "base": { + "close": "关闭", + "save": "保存", + "run": "运行", + "cancel": "取消", + "end": "结束", + "delete": "删除", + "logs": "日志", + "ok": "确定", + "add": "添加", + "search": "搜索...", + "success": "成功", + "error": "错误" + }, + "editor": { + "invalid-file-content": "无效的文件内容", + "welcome-back": "欢迎回来!", + "please-log-in-to-run-a-pipeline": "请登录后运行此流水线。", + "execution-done": "运行成功完成", + "your-project-has-been-executed-successfully": "您的流水线已成功运行完成。", + "execution-failed": "运行失败", + "project-has-encountered-an-error": "流水线遇到错误:", + "project-saved": "流水线已保存", + "your-project-has-be-saved-successfully": "您的流水线已成功保存。", + "view-history": "历史记录", + "add-plugin": "添加插件", + "display-advanced-nodes": "显示高级节点", + "project-settings": "流水线设置", + "jit-loading-title": "正在准备插件", + "jit-loading-subtitle": "请稍候,Pipelab 正在下载并配置此流水线所需的插件。", + "jit-loading-status": "正在下载并安装插件包...", + "validation-failed": "验证失败", + "validation-plugin-disabled-or-missing": "节点 \"{nodeName}\" 需要插件 \"{pluginId}\",该插件目前未安装或未启用。", + "validation-missing-param": "请配置节点 \"{nodeName}\" 中的必填字段 \"{paramName}\"。" + }, + "home": { + "invalid-preset": "无效的预设", + "store-project-on-the-cloud": "保存项目到云端", + "cloud": "云端", + "store-project-locally": "本地保存项目", + "local": "本地", + "invalid-number-of-paths-selected": "选择的路径数量无效", + "pipelab-project": "Pipelab 项目", + "choose-a-new-path": "选择新路径", + "invalid-file-type": "无效的文件类型", + "create-project": "创建项目", + "create-pipeline": "创建流水线", + "duplicate-project": "复制项目", + "duplicate-pipeline": "复制流水线", + "project-name": "项目名称", + "new-project": "新建项目", + "new-pipeline": "新建流水线", + "open": "打开", + "import": "导入", + "pipeline-name": "流水线名称", + "your-projects": "您的项目", + "no-projects-yet": "暂无项目", + "no-pipelines-yet": "暂无流水线", + "delete-project": "删除项目", + "confirm-delete-project": "您确定要删除此项目吗?此操作无法撤销。", + "cannot-delete-project": "无法删除项目", + "project-not-empty": "此项目包含流水线。请先删除它们。", + "transfer": "转移", + "transfer-successful": "转移成功", + "pipeline-transferred": "流水线已成功转移", + "select-project": "选择项目", + "build-history": "运行历史", + "duplicate": "复制", + "rename-project": "重命名项目", + "new-project-name": "新项目名称", + "premium-feature": "这是高级会员功能", + "migrate-warning": "此文件格式即将被弃用。请将其迁移到新的本地工作区存储。", + "simple-pipeline": "基础流水线", + "advanced-pipeline": "高级流水线", + "new-simple-project": "新建简单项目", + "new-advanced-project": "新建高级项目", + "store-project-internally": "本地保存项目", + "internal": "内部", + "confirm-migration-message": "您确定要将此流水线移动到本地工作区存储吗?Pipelab 将在内部管理此流水线。", + "migrate-pipeline": "迁移流水线", + "migration-success": "流水线已成功迁移", + "migrate-to-internal": "移动到工作区", + "only-internal-supported-notice": "Pipelab 现在管理应用工作区内的所有流水线。外部文件已被弃用,但仍可以导入。", + "import-pipeline": "导入流水线", + "import-from-stable": "从 Stable 导入...", + "import-from-beta": "从 Beta 导入...", + "import-pipeline-file": "导入管道文件 (.pipelab)...", + "import-success": "流水线已成功导入", + "failed-to-read-file": "读取所选文件失败", + "export-pipeline": "导出流水线...", + "export-success": "流水线导出成功", + "export-failed": "导出流水线失败" + }, + "pipelines": { + "title": "@:headers.pipelines" + }, + "tour": { + "start-tour": "开始向导", + "projects-list-title": "项目导航器", + "projects-list-description": "此侧边栏列出您的项目。选择一个项目将在主区域显示其包含的流水线。", + "add-project-title": "创建新项目", + "add-project-description": "项目可以按主题或客户组织您的流水线。点击这里开始一个新项目。", + "new-pipeline-title": "创建流水线", + "new-pipeline-description": "准备好自动化了吗?创建一个新流水线开始添加操作和逻辑。", + "project-actions-title": "项目管理", + "project-actions-description": "使用这些按钮重命名或删除当前选择的项目。", + "editor-canvas-title": "可视化画布", + "editor-canvas-description": "这是您的画布。拖放操作块到这里以构建您的自动化流程。", + "editor-save-title": "保存进度", + "editor-save-description": "确保您的更改已安全保存。我们建议您经常保存流水线。", + "editor-run-title": "测试流水线", + "editor-run-description": "点击“运行”测试流水线。Pipelab 将实时执行每个步骤。", + "editor-logs-title": "运行日志", + "editor-logs-description": "日志面板实时显示执行步骤,帮助您监控和调试。", + "editor-close-title": "关闭编辑器", + "editor-close-description": "今天的工作完成了吗?返回仪表盘以管理其他项目和流水线。" + } +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts new file mode 100644 index 00000000..935bd598 --- /dev/null +++ b/packages/shared/src/index.ts @@ -0,0 +1,71 @@ +// 1. Critical Migrators - Explicitly imported then exported to satisfy Node.js ESM scanner +import { + appSettingsMigrator as _appSettingsMigrator, + defaultAppSettings as _defaultAppSettings, + fileRepoMigrations as _fileRepoMigrations, + defaultFileRepo as _defaultFileRepo, + savedFileMigrator as _savedFileMigrator, + configRegistry as _configRegistry, + normalizePipelineConfig as _normalizePipelineConfig, + connectionsMigrator as _connectionsMigrator, + defaultConnections as _defaultConnections, +} from "./config/migrators"; + +export const appSettingsMigrator = _appSettingsMigrator; +export const defaultAppSettings = _defaultAppSettings; +export const fileRepoMigrations = _fileRepoMigrations; +export const defaultFileRepo = _defaultFileRepo; +export const savedFileMigrator = _savedFileMigrator; +export const configRegistry = _configRegistry; +export const normalizePipelineConfig = _normalizePipelineConfig; +export const connectionsMigrator = _connectionsMigrator; +export const defaultConnections = _defaultConnections; + +// 2. Types +export type { Migrator } from "./config/migrators"; +export type { IpcDefinition } from "./apis"; +export type { IpcDefinition as RendererIpcDefinition } from "./ipc.types"; +export type { RequestId } from "./apis"; +export type { RequestId as RendererRequestId } from "./ipc.types"; +export type { NodeId } from "./model"; +export type { FileRepo, FileRepoV1, FileRepoV2, FileRepoV3 } from "./config/projects-definition"; +export { + FileRepoValidator, + FileRepoValidatorV1, + FileRepoValidatorV2, + FileRepoValidatorV3, + FileRepoProjectValidatorV2, +} from "./config/projects-definition"; + +// 3. Core Library exports (Systematic restoration) +export * from "./apis"; +export * from "./build-history"; +export * from "./config.schema"; +export * from "./database.types"; +export * from "./evaluator"; +export * from "./fmt"; +export * from "./graph"; +export * from "./i18n-utils"; +export * from "./ipc.types"; +export * from "./logger"; +export * from "./model"; +export * from "./plugins"; +export * from "./plugins-list"; +export * from "./plugins/definitions"; // <-- RE-ADDED +export * from "./quickjs"; +export * from "./save-location"; +export * from "./subscription-errors"; +export * from "./supabase"; +export * from "./types"; +export * from "./utils"; +export * from "./validation"; +export * from "./variables"; +export * from "./websocket.types"; + +// 4. Configuration Sub-packages +export * from "./config/projects-definition"; // <-- RE-ADDED +export * from "./config/settings-definition"; // <-- RE-ADDED +export * from "./config/connections-definition"; + +// NOTE: We avoid "export * from './config'" to prevent nested re-export circles. +// All necessary members from the config subfolder are explicitly exported above. diff --git a/packages/shared/src/ipc.types.ts b/packages/shared/src/ipc.types.ts new file mode 100644 index 00000000..595a83e7 --- /dev/null +++ b/packages/shared/src/ipc.types.ts @@ -0,0 +1,75 @@ +import type { Tagged } from "type-fest"; +import type { ILogObjMeta } from "tslog"; + +export type UpdateStatus = + | "update-available" + | "update-downloaded" + | "checking-for-update" + | "update-not-available" + | "error"; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export type IpcEvent = { type: TYPE; data: DATA }; +export type EndEvent = { + type: "end"; + data: + | { + type: "success"; + result: DATA; + } + | { + type: "error"; + ipcError: string; + }; +}; + +export type IpcDefinition = { + "dialog:alert": [ + // input + { message: string; buttons?: { title: string; value: string }[] }, + EndEvent<{ answer: string }>, + ]; + "dialog:prompt": [ + // input + { message: string; buttons?: { title: string; value: string }[] }, + EndEvent<{ answer: string }>, + ]; + "log:message": [ + // input + ILogObjMeta, + EndEvent, + ]; + "update:set-status": [ + // input + { + status: UpdateStatus; + downloadUrl?: string; + version?: string; + }, + EndEvent, + ]; +}; + +export type RendererChannels = keyof IpcDefinition; +export type RendererData = IpcDefinition[KEY][0]; +export type RendererEvents = IpcDefinition[KEY][1]; +export type RendererEnd = Extract< + IpcDefinition[KEY][1], + { type: "end" } +>["data"]; + +export type RendererMessage = { + // the channel to communicate + requestId: RequestId; + data: any; +}; +export type RequestId = Tagged; + +export type HandleListenerRendererSendFn = ( + events: RendererEvents, +) => void; + +export type HandleListenerRenderer = ( + event: any, + data: { value: RendererData; send: HandleListenerRendererSendFn }, +) => Promise; diff --git a/packages/shared/src/logger.ts b/packages/shared/src/logger.ts new file mode 100644 index 00000000..a6f73677 --- /dev/null +++ b/packages/shared/src/logger.ts @@ -0,0 +1,20 @@ +import { Logger } from "tslog"; + +const createDefaultLogger = () => + new Logger({ + minLevel: 3, // INFO + hideLogPositionForProduction: false, + }); + +let _logger = createDefaultLogger(); + +export const useLogger = () => { + const attachTransport = (transport: (logObj: unknown) => void) => { + _logger.attachTransport(transport as any); + }; + + return { + logger: () => _logger, + attachTransport, + }; +}; diff --git a/packages/shared/src/migrations/model.ts b/packages/shared/src/migrations/model.ts new file mode 100644 index 00000000..b96196af --- /dev/null +++ b/packages/shared/src/migrations/model.ts @@ -0,0 +1 @@ +export * from "../config/migrators"; diff --git a/packages/shared/src/migrations/projects.ts b/packages/shared/src/migrations/projects.ts new file mode 100644 index 00000000..b96196af --- /dev/null +++ b/packages/shared/src/migrations/projects.ts @@ -0,0 +1 @@ +export * from "../config/migrators"; diff --git a/packages/shared/src/migrations/settings.ts b/packages/shared/src/migrations/settings.ts new file mode 100644 index 00000000..b96196af --- /dev/null +++ b/packages/shared/src/migrations/settings.ts @@ -0,0 +1 @@ +export * from "../config/migrators"; diff --git a/packages/shared/src/model.test.ts b/packages/shared/src/model.test.ts new file mode 100644 index 00000000..7352cb6b --- /dev/null +++ b/packages/shared/src/model.test.ts @@ -0,0 +1,519 @@ +import { describe, expect, it } from "vitest"; +import { SavedFileV1, SavedFileV2, SavedFileV3, SavedFileV4, SavedFileV5 } from "./model"; +import { + savedFileMigrator, + normalizePipelineConfig, + appSettingsMigrator, + fileRepoMigrations, + connectionsMigrator, +} from "./config/migrators"; +import { AppConfigV6, AppConfigV7 } from "./config.schema"; + +describe("model", () => { + it("should migrate 1.0.0 to 2.0.0", async () => { + const v1: SavedFileV1 = { + version: "1.0.0", + canvas: { + blocks: [ + { + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + foo: "bar", + }, + nodata: undefined, + }, + type: "action", + uid: "aaa", + disabled: false, + }, + { + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + foo: "bar", + }, + }, + type: "event", + uid: "aaa", + }, + ], + }, + description: "aaa", + name: "aaa", + variables: [ + { + description: "aaa", + id: "aaa", + name: "aaa", + value: "aaa", + }, + ], + }; + + const v2 = await savedFileMigrator.migrate(v1, { + debug: true, + target: "2.0.0", + }); + + expect(v2).toStrictEqual({ + canvas: { + blocks: [ + { + disabled: false, + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + foo: "bar", + }, + nodata: undefined, + }, + type: "action", + uid: "aaa", + }, + ], + triggers: [ + { + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + foo: "bar", + }, + }, + type: "event", + uid: "aaa", + }, + ], + }, + description: "aaa", + name: "aaa", + variables: [ + { + description: "aaa", + id: "aaa", + name: "aaa", + value: "aaa", + }, + ], + version: "2.0.0", + } satisfies SavedFileV2); + }); + + it("should migrate 2.0.0 to 3.0.0", async () => { + const v2: SavedFileV2 = { + canvas: { + blocks: [ + { + disabled: false, + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + foo: "bar", + }, + nodata: undefined, + }, + type: "action", + uid: "aaa", + }, + ], + triggers: [ + { + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + foo: "bar", + }, + }, + type: "event", + uid: "aaa", + }, + ], + }, + description: "aaa", + name: "aaa", + variables: [ + { + description: "aaa", + id: "aaa", + name: "aaa", + value: "aaa", + }, + ], + version: "2.0.0", + }; + + const v3 = await savedFileMigrator.migrate(v2, { + debug: true, + target: "3.0.0", + }); + + expect(v3).toStrictEqual({ + canvas: { + blocks: [ + { + disabled: false, + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + editor: "editor", + value: { + foo: "bar", + }, + }, + nodata: { + editor: "editor", + value: undefined, + }, + }, + type: "action", + uid: "aaa", + }, + ], + triggers: [ + { + origin: { + nodeId: "aaa", + pluginId: "aaa", + }, + params: { + aaa: { + foo: "bar", + }, + }, + type: "event", + uid: "aaa", + }, + ], + }, + description: "aaa", + name: "aaa", + variables: [ + { + description: "aaa", + id: "aaa", + name: "aaa", + value: "aaa", + }, + ], + version: "3.0.0", + } satisfies SavedFileV3); + }); + + it("should migrate 3.0.0 to 4.0.0", async () => { + const v3: SavedFileV3 = { + version: "3.0.0", + canvas: { + blocks: [], + triggers: [], + }, + description: "desc", + name: "name", + variables: [], + }; + + const v4 = await savedFileMigrator.migrate(v3, { + debug: true, + target: "4.0.0", + }); + + expect(v4).toStrictEqual({ + version: "4.0.0", + type: "default", + canvas: { + blocks: [], + triggers: [], + }, + description: "desc", + name: "name", + variables: [], + } satisfies SavedFileV4); + }); + + it("should migrate 4.0.0 to 5.0.0", async () => { + const v4: SavedFileV4 = { + version: "4.0.0", + type: "default", + canvas: { + blocks: [ + { + uid: "b1", + type: "action", + origin: { + pluginId: "electron", + nodeId: "open", + }, + params: {}, + }, + { + uid: "b2", + type: "action", + origin: { + pluginId: "dicord", + nodeId: "send", + }, + params: {}, + }, + ], + triggers: [], + }, + description: "desc", + name: "name", + variables: [], + plugins: { + discord: "1.0.0", + }, + }; + + const v5 = await savedFileMigrator.migrate(v4, { + debug: true, + target: "5.0.0", + }); + + expect(v5).toStrictEqual({ + version: "5.0.0", + canvas: { + blocks: [ + { + uid: "b1", + type: "action", + origin: { + pluginId: "@pipelab/plugin-electron", + nodeId: "open", + // "electron" wasn't in the old plugins map, so version falls back to "latest" + version: "latest", + }, + params: {}, + }, + { + uid: "b2", + type: "action", + origin: { + pluginId: "@pipelab/plugin-discord", + nodeId: "send", + // "dicord" mapped to "@pipelab/plugin-discord" which had version "1.0.0" in the old map + version: "1.0.0", + }, + params: {}, + }, + ], + triggers: [], + }, + description: "desc", + name: "name", + variables: [], + // plugins top-level map is dropped in V5 for default pipelines + } satisfies SavedFileV5); + }); + + it("should migrate AppConfigV6 to AppConfigV7", async () => { + const v6: AppConfigV6 = { + version: "6.0.0", + theme: "dark", + cacheFolder: "/some/path", + clearTemporaryFoldersOnPipelineEnd: true, + locale: "fr-FR", + tours: { + dashboard: { step: 1, completed: true }, + editor: { step: 2, completed: false }, + }, + autosave: false, + }; + + const v7 = await appSettingsMigrator.migrate(v6, { target: "7.0.0" }); + + expect(v7).toStrictEqual({ + version: "7.0.0", + theme: "dark", + locale: "fr-FR", + tours: { + dashboard: { step: 1, completed: true }, + editor: { step: 2, completed: false }, + }, + autosave: false, + agents: [], + plugins: expect.any(Array), + cacheFolder: "/some/path", + }); + }); + + describe("normalizePipelineConfig", () => { + it("should normalize typo and legacy plugin IDs in block origins", () => { + const config = { + version: "5.0.0", + type: "default", + canvas: { + blocks: [ + { + uid: "b1", + type: "action", + origin: { + pluginId: "dicord", + nodeId: "send", + }, + }, + ], + }, + }; + + const changed = normalizePipelineConfig(config); + expect(changed).toBe(true); + expect(config.canvas.blocks[0].origin.pluginId).toBe("@pipelab/plugin-discord"); + }); + }); + + describe("fileRepoMigrations", () => { + it("should migrate FileRepoV1 (data record) to FileRepoV3 (pipelines array)", async () => { + const v1 = { + version: "1.0.0" as const, + data: { + "pipeline-1": { + project: "main", + type: "internal" as const, + configName: "pipeline-1", + lastModified: "2026-06-04", + }, + "pipeline-2": { + project: "main", + type: "external" as const, + path: "/path/to/pipeline-2.json", + lastModified: "2026-06-04", + summary: { + plugins: ["steam"], + name: "Test Pipeline 2", + description: "Legacy external pipeline", + }, + }, + }, + }; + + const v3 = await fileRepoMigrations.migrate(v1, { target: "3.0.0" }); + + expect(v3).toStrictEqual({ + version: "3.0.0", + data: v1.data, + projects: [ + { + id: "main", + name: "Default project", + description: "The initial default project", + }, + ], + pipelines: [ + { + id: "pipeline-1", + project: "main", + type: "internal", + configName: "pipeline-1", + lastModified: "2026-06-04", + }, + { + id: "pipeline-2", + project: "main", + type: "external", + path: "/path/to/pipeline-2.json", + lastModified: "2026-06-04", + summary: { + plugins: ["steam"], + name: "Test Pipeline 2", + description: "Legacy external pipeline", + }, + }, + ], + }); + }); + + it("should fallback to default value for corrupted config", async () => { + const corrupted: any = { + version: "1.0.0", + data: null, + }; + + const result = await fileRepoMigrations.migrate(corrupted, { target: "3.0.0" }); + expect(result.version).toBe("3.0.0"); + expect(result.projects).toHaveLength(1); + expect(result.pipelines).toEqual([]); + }); + }); + + describe("connectionsMigrator", () => { + it("should initialize default connections", async () => { + const result = await connectionsMigrator.migrate(undefined, { target: "1.0.0" }); + expect(result).toStrictEqual({ + version: "1.0.0", + connections: [], + }); + }); + }); + + describe("savedFileMigrator - edge cases", () => { + it("should normalize unmapped legacy plugin names and typos during migration to 5.0.0", async () => { + const v4: SavedFileV4 = { + version: "4.0.0", + type: "default", + canvas: { + blocks: [ + { + uid: "b1", + type: "action", + origin: { + pluginId: "filesystem", + nodeId: "copy", + }, + params: {}, + }, + { + uid: "b2", + type: "action", + origin: { + pluginId: "dicord", + nodeId: "send", + }, + params: {}, + }, + { + uid: "b3", + type: "action", + origin: { + pluginId: "custom-cool", + nodeId: "run", + }, + params: {}, + }, + ], + triggers: [], + }, + description: "Edge case plugin names test", + name: "Edge Case", + variables: [], + plugins: {}, + }; + + const v5 = await savedFileMigrator.migrate(v4, { target: "5.0.0" }); + + expect(v5.canvas.blocks[0].origin.pluginId).toBe("@pipelab/plugin-filesystem"); + expect(v5.canvas.blocks[1].origin.pluginId).toBe("@pipelab/plugin-discord"); + expect(v5.canvas.blocks[2].origin.pluginId).toBe("custom-cool"); + }); + }); +}); diff --git a/packages/shared/src/model.ts b/packages/shared/src/model.ts new file mode 100644 index 00000000..419d9122 --- /dev/null +++ b/packages/shared/src/model.ts @@ -0,0 +1,244 @@ +import { Variable } from "./variables"; +import { WithId } from "./utils"; +import { SaveLocation } from "./save-location"; +import type { Simplify } from "type-fest"; +import { + any, + array, + boolean, + custom, + description, + GenericSchema, + InferOutput, + lazy, + literal, + object, + optional, + pipe, + record, + string, + union, + unknown, + variant, +} from "valibot"; + +export type NodeId = string; + +export type Position = { + x: number; + y: number; +}; + +export const OriginValidator = object({ + pluginId: string(), + nodeId: string(), + version: optional( + pipe( + string(), + description( + 'Pinned version of the plugin for this block. Falls back to "latest" when absent.', + ), + ), + ), +}); + +export type Origin = InferOutput; + +const BlockActionValidatorV1 = object({ + type: literal("action"), + uid: string(), + disabled: optional(boolean()), + params: record(string(), any()), + origin: OriginValidator, +}); + +export const EditorParamValidatorV3 = union([literal("simple"), literal("editor")]); +export type EditorParam = InferOutput; +const BlockActionValidatorV3 = object({ + type: literal("action"), + uid: string(), + name: optional(pipe(string(), description("A custom name provided by the user"))), + disabled: optional(boolean()), + params: record( + string(), + object({ + editor: EditorParamValidatorV3, + value: unknown(), + }), + ), + origin: OriginValidator, +}); + +const BlockEventValidator = object({ + type: literal("event"), + uid: string(), + origin: OriginValidator, + params: record(string(), any()), +}); + +const BlockCommentValidator = object({ + type: literal("comment"), + uid: string(), + origin: OriginValidator, + comment: string(), +}); + +const BlockValidatorV1 = variant("type", [ + BlockActionValidatorV1, + // BlockConditionValidator, + BlockEventValidator, + // BlockLoopValidator, + // BlockCommentValidator +]); + +const BlockValidatorV2 = variant("type", [ + BlockActionValidatorV1, + // BlockConditionValidator, + // BlockEventValidator, + // BlockLoopValidator, + // BlockCommentValidator +]); + +const BlockValidatorV3 = variant("type", [ + BlockActionValidatorV3, + // BlockConditionValidator, + // BlockEventValidator, + // BlockLoopValidator, + // BlockCommentValidator +]); + +const BlockValidator = BlockValidatorV3; + +export type BlockAction = Simplify>; +export type BlockEvent = InferOutput; +export type BlockComment = InferOutput; + +export type Block = InferOutput; + +const CanvasValidatorV1 = object({ + blocks: array(BlockValidatorV1), +}); + +const CanvasValidatorV2 = object({ + blocks: array(BlockValidatorV2), + triggers: array(BlockEventValidator), +}); + +const CanvasValidatorV3 = object({ + blocks: array(BlockValidatorV3), + triggers: array(BlockEventValidator), +}); + +export const VariableValidatorV1 = custom(() => true); + +export const SavedFileValidatorV1 = object({ + version: literal("1.0.0"), + name: string(), + description: string(), + canvas: CanvasValidatorV1, + variables: array(VariableValidatorV1), +}); + +export const SavedFileValidatorV2 = object({ + version: literal("2.0.0"), + name: string(), + description: string(), + canvas: CanvasValidatorV2, + variables: array(VariableValidatorV1), +}); + +export const SavedFileValidatorV3 = object({ + version: literal("3.0.0"), + name: string(), + description: string(), + canvas: CanvasValidatorV3, + variables: array(VariableValidatorV1), +}); + +export const SavedFileDefaultValidatorV4 = object({ + version: literal("4.0.0"), + type: literal("default"), + name: string(), + description: string(), + plugins: optional(record(string(), string())), + canvas: CanvasValidatorV3, + variables: array(VariableValidatorV1), +}); + +export const SavedFileSimpleValidatorV4 = object({ + version: literal("4.0.0"), + type: literal("simple"), + name: string(), + description: string(), + plugins: optional(record(string(), string())), + source: object({ + type: union([literal("c3-html"), literal("c3-nwjs"), literal("godot"), literal("html")]), + path: string(), + }), + packaging: object({ + enabled: boolean(), + }), + publishing: object({ + steam: object({ enabled: boolean(), appId: optional(string()) }), + itch: object({ enabled: boolean(), project: optional(string()) }), + poki: object({ enabled: boolean(), gameId: optional(string()) }), + }), +}); + +export const SavedFileDefaultValidatorV5 = object({ + version: literal("5.0.0"), + name: string(), + description: string(), + canvas: CanvasValidatorV3, + variables: array(VariableValidatorV1), +}); + +export const SavedFileSimpleValidatorV5 = object({ + version: literal("5.0.0"), + type: literal("simple"), + name: string(), + description: string(), + plugins: record(string(), string()), + source: object({ + type: union([literal("c3-html"), literal("c3-nwjs"), literal("godot"), literal("html")]), + path: string(), + }), + packaging: object({ + enabled: boolean(), + }), + publishing: object({ + steam: object({ enabled: boolean(), appId: optional(string()) }), + itch: object({ enabled: boolean(), project: optional(string()) }), + poki: object({ enabled: boolean(), gameId: optional(string()) }), + }), +}); + +export type SavedFileDefault = InferOutput; +export type SavedFileSimple = InferOutput; + +export const SavedFileValidatorV4 = union([ + SavedFileDefaultValidatorV4, + SavedFileSimpleValidatorV4, +]); +export const SavedFileValidatorV5 = SavedFileDefaultValidatorV5; + +export type SavedFileV1 = InferOutput; +export type SavedFileV2 = InferOutput; +export type SavedFileV3 = InferOutput; +export type SavedFileV4 = InferOutput; +export type SavedFileV5 = InferOutput; +export type SavedFile = SavedFileV5; +export const SavedFileValidator = SavedFileValidatorV5; + +export type Preset = SavedFile; +export type PresetResult = { data: Preset; hightlight?: boolean; disabled?: boolean }; +export type PresetFn = () => Promise; + +export type Steps = Record< + string, + { + outputs: Record; + } +>; + +export type EnhancedFile = WithId & { content: T }; diff --git a/packages/shared/src/plugins-list.ts b/packages/shared/src/plugins-list.ts new file mode 100644 index 00000000..b313d217 --- /dev/null +++ b/packages/shared/src/plugins-list.ts @@ -0,0 +1,17 @@ +export const DEFAULT_PLUGIN_IDS = [ + "construct", + "filesystem", + "system", + "steam", + "itch", + "electron", + "discord", + "poki", + "nvpatch", + "netlify", +]; + +export const DEV_ONLY_PLUGIN_IDS = [ + "tauri", + "minify", +]; diff --git a/packages/shared/src/plugins.ts b/packages/shared/src/plugins.ts new file mode 100644 index 00000000..7bdfc9ae --- /dev/null +++ b/packages/shared/src/plugins.ts @@ -0,0 +1,29 @@ +import { shallowRef } from "vue"; +import type { RendererPluginDefinition } from "./plugins/definitions.js"; + +type Plugin = RendererPluginDefinition; + +const plugins = shallowRef([]); + +export const usePlugins = () => { + const load = () => {}; + + const registerPlugins = (newPlugins: Plugin[]) => { + const current = [...plugins.value]; + for (const np of newPlugins) { + const idx = current.findIndex((p) => p.id === np.id); + if (idx !== -1) { + current[idx] = np; + } else { + current.push(np); + } + } + plugins.value = current; + }; + + return { + load, + registerPlugins, + plugins, + }; +}; diff --git a/packages/shared/src/plugins/definitions.ts b/packages/shared/src/plugins/definitions.ts new file mode 100644 index 00000000..6d851d85 --- /dev/null +++ b/packages/shared/src/plugins/definitions.ts @@ -0,0 +1,443 @@ +import type { ConditionalPick } from "type-fest"; +import type { BrowserWindow, OpenDialogOptions } from "electron"; + +export type PathOptions = { + filter?: RegExp; + type?: "file" | "folder"; +}; + +export type PropType = + | "string" + | "number" + | "boolean" + | "array" + | { + type: "array"; + of: PropType; + } + | "any" + | PropType[]; + +export interface ControlTypeBase { + type: string; +} + +export interface ControlTypeInput extends ControlTypeBase { + type: "input"; + options: { + kind: "number" | "text"; + validator?: string; + placeholder?: string; + password?: boolean; + }; +} + +export interface ControlTypeExpression extends ControlTypeBase { + type: "expression"; + options: {}; +} + +export interface ControlTypeNetlifySite extends ControlTypeBase { + type: "netlify-site"; + options: { + allowCreate?: boolean; + placeholder?: string; + tokenKey: string; + }; +} + +export interface PipelabSelectOption { + label: string; + value: string; +} + +export interface ControlTypeSelect extends ControlTypeBase { + type: "select"; + options: { + options: Array; + placeholder: string; + }; +} + +export interface ControlTypeMultiSelect extends ControlTypeBase { + type: "multi-select"; + options: { + options: Array; + placeholder: string; + }; +} + +export interface ControlTypeBoolean extends ControlTypeBase { + type: "boolean"; +} + +export interface ControlTypeCheckbox extends ControlTypeBase { + type: "checkbox"; +} + +export interface ControlTypePath extends ControlTypeBase { + type: "path"; + options: OpenDialogOptions; + label?: string; + warnIfBlacklisted?: boolean; +} + +export interface ControlTypeJSON extends ControlTypeBase { + type: "json"; +} + +export interface ControlTypeArray extends ControlTypeBase { + type: "array"; + options: { + kind: "number" | "text"; + }; +} + +export interface ControlTypeColor extends ControlTypeBase { + type: "color"; +} + +export interface ControlTypeElectronConfigureV2 extends ControlTypeBase { + type: "electron:configure:v2"; +} + +export type ControlType = + | ControlTypeInput + | ControlTypeSelect + | ControlTypeMultiSelect + | ControlTypeBoolean + | ControlTypeCheckbox + | ControlTypePath + | ControlTypeJSON + | ControlTypeExpression + | ControlTypeNetlifySite + | ControlTypeArray + | ControlTypeColor + | ControlTypeElectronConfigureV2; + +export type InputDefinition = { + label: string; + description?: string; + validator?: () => any; + required: boolean; + control: T; + value: unknown; + platforms?: NodeJS.Platform[]; + onNodeUpdate?: (value: any, settings: InputDefinition) => void; +}; + +export type InputsDefinition = Record; +export type Meta = Record; + +export interface OutputDefinition { + label: string; + description?: string; + deprecated?: boolean; + validator?: (value: any) => any; + control?: ControlType; + value: unknown; +} + +export type OutputsDefinition = Record; + +export type InputOutputDefinition = InputDefinition | OutputDefinition; + +export type IconType = + | { + type: "image"; + /** + * base64 image + */ + image: string; + } + | { + type: "icon"; + icon: string; + }; +export interface PluginDefinition { + packageName?: string; + version?: string; +} + +export type RendererNodeDefinition = { + node: PipelabNode; +}; + +export interface IntegrationField { + key: string; + label: string; + type: "text" | "password" | "file" | "directory"; + placeholder?: string; +} + +export interface IntegrationDefinition { + name: string; + fields: IntegrationField[]; +} + +export interface RendererPluginDefinition extends PluginDefinition { + id: string; + name: string; + icon: IconType; + description: string; + isOfficial: boolean; + packageName: string; + version: string; + nodes: Array; + integrations?: Array; +} + +export interface MainPluginDefinition extends PluginDefinition { + nodes: ({ + runner: any; // We use 'any' here to avoid importing Node runners in the safe definition + } & RendererNodeDefinition)[]; + validators?: Array<{ + id: string; + description: string; + validator: (options: any) => any; + }>; + integrations?: Array; +} + +export const createNodeDefinition = (def: MainPluginDefinition) => { + return def; +}; + +export type InputsOutputsDefinition = InputsDefinition | OutputsDefinition; + +export type GetFlowEntries = ConditionalPick< + T, + { type: "flow" } +>; +export type GetDataEntries = ConditionalPick< + T, + { type: "data" } +>; + +export type GetFlowKeys = keyof GetFlowEntries; +export type GetDataKeys = keyof GetDataEntries; + +export type DataResult = Record; + +export type SetOutputActionFn = ( + key: keyof T["outputs"], + value: T["outputs"][typeof key]["value"], +) => void; + +export type SetOutputExpressionFn = ( + key: keyof T["outputs"], + value: T["outputs"][typeof key]["value"], +) => void; + +export type ParamsToInput = { + [index in keyof PARAMS]: PARAMS[index]["required"] extends true + ? PARAMS[index]["value"] + : PARAMS[index]["value"] | null; +}; + +export interface BaseNode { + disabled?: boolean | string; + advanced?: boolean | string; + updateAvailable?: boolean | string; +} + +export interface Action extends BaseNode { + id: string; + type: "action"; + version?: number; + displayString: string; + icon: string; + name: string; + description: string; + params: InputsDefinition; + meta: Meta; + outputs: OutputsDefinition; + platforms?: NodeJS.Platform[]; + deprecated?: boolean; + deprecatedMessage?: string; +} + +export type ExtractInputsFromAction = { + [index in keyof ACTION["params"]]: ACTION["params"][index]["value"]; +}; + +export type ExtractInputsFromEvent = { + [index in keyof EVENT["params"]]: EVENT["params"][index]["value"]; +}; +export type ExtractInputsFromExpression = { + [index in keyof EXPRESSION["params"]]: EXPRESSION["params"][index]["value"]; +}; + +export interface Expression extends BaseNode { + id: string; + type: "expression"; + displayString: string; + version?: number; + icon: string; + name: string; + description: string; + params: InputsDefinition; + meta?: Meta; + outputs: OutputsDefinition; +} + +export interface Event extends BaseNode { + id: string; + type: "event"; + version?: number; + displayString: string; + icon: string; + name: string; + description: string; + params: InputsDefinition; + meta?: Meta; + platforms?: NodeJS.Platform[]; +} + +export type PipelabNode = Event | Expression | Action; + +export const createDefinition = (definition: T) => { + return definition satisfies T; +}; + +export const createAction = >(action: T) => { + return { + ...action, + type: "action", + } satisfies Action; +}; + +export const createStringParam = ( + value: string, + definition: Omit, "value" | "control">, +) => { + return { + ...definition, + control: { + type: "input", + options: { + kind: "text", + }, + }, + value: `"${value}"`, + } satisfies InputDefinition; +}; + +export const createColorPicker = ( + value: string, + definition: Omit, "value" | "control">, +) => { + return { + ...definition, + control: { + type: "color", + }, + value: `"${value}"`, + } satisfies InputDefinition; +}; + +export const createPasswordParam = ( + value: string, + definition: Omit, "value" | "control">, +) => { + return { + ...definition, + control: { + type: "input", + options: { + kind: "text", + password: true, + }, + }, + value: `"${value}"`, + } satisfies InputDefinition; +}; + +export const createPathParam = ( + value: string | undefined, + definition: Omit, "value">, +) => { + return { + ...definition, + value: value ? `"${value}"` : value, + } satisfies InputDefinition; +}; + +export const createArray = ( + value: string | Array, + definition: Omit, "value">, +) => { + return { + ...definition, + value: (Array.isArray(value) ? `"${value}"` : value) as unknown as T, + } satisfies InputDefinition; +}; + +export const createNetlifySiteParam = ( + value: string, + tokenKey: string, + definition: Omit, "value" | "control">, +) => { + return { + ...definition, + control: { + type: "netlify-site", + options: { + allowCreate: true, + placeholder: "Select a site", + tokenKey, + }, + }, + value: `"${value}"`, + } satisfies InputDefinition; +}; + +export const createNumberParam = ( + value: number, + definition: Omit, "value" | "control">, +) => { + return { + ...definition, + control: { + type: "input", + options: { + kind: "number", + }, + }, + value, + } satisfies InputDefinition; +}; + +export const createBooleanParam = ( + value: boolean, + definition: Omit, "value" | "control">, +) => { + return { + ...definition, + control: { + type: "boolean", + }, + value, + } satisfies InputDefinition; +}; + +export const createRawParam = (value: T, definition: Omit) => { + return { + ...definition, + value, + }; +}; + +export const createExpression = >(expression: T) => { + return { + ...expression, + type: "expression", + } satisfies Expression; +}; + +export const createEvent = >(event: T) => { + return { + ...event, + type: "event", + } satisfies Event; +}; diff --git a/packages/shared/src/quickjs.ts b/packages/shared/src/quickjs.ts new file mode 100644 index 00000000..37541356 --- /dev/null +++ b/packages/shared/src/quickjs.ts @@ -0,0 +1,98 @@ +import { useLogger } from "./logger"; +import { newQuickJSWASMModuleFromVariant, newVariant, RELEASE_SYNC } from "quickjs-emscripten"; +import { Arena } from "quickjs-emscripten-sync"; +import { fmt } from "./fmt"; + +class EvaluationError extends Error { + constructor( + public name: string, + public description: string, + ) { + super(description); + this.name = name; + } +} + +/** + * Creates a QuickJS instance from an already-resolved variant. + * Callers are responsible for importing and passing the correct variant + * for their environment (Node vs browser) using a static import. + */ +export const createQuickJsFromVariant = async (variant: any) => { + const { logger } = useLogger(); + + const quickjs = await newQuickJSWASMModuleFromVariant(variant); + + const createContext = () => { + const vm = quickjs.newContext(); + const arena = new Arena(vm, { isMarshalable: true }); + + const run = (code: string, params: Record) => { + const exposed = { + fmt, + ...params, + }; + arena.expose(exposed); + + const finalCode = `(() => { + return ${code}; + })()`; + + try { + return arena.evalCode(finalCode); + } catch (e) { + logger().error("error", e); + logger().error("Final code was", finalCode); + throw new EvaluationError(e.name, e.message); + } + }; + + return { + run, + dispose: () => { + try { + arena.dispose(); + } catch (e) { + logger().error("Failed to dispose arena", e); + } + try { + vm.dispose(); + } catch (e) { + logger().error("Failed to dispose VM", e); + } + }, + }; + }; + + const run = (code: string, params: Record) => { + const ctx = createContext(); + try { + return ctx.run(code, params); + } finally { + try { + ctx.dispose(); + } catch (e) { + logger().error("Failed to dispose context", e); + } + } + }; + + return { + run, + createContext, + }; +}; + +// --------------------------------------------------------------------------- +// Node.js variant — statically imported, safe in the Electron main process +// --------------------------------------------------------------------------- +import nodeVariant from "@jitl/quickjs-singlefile-mjs-release-sync"; + +export const createQuickJs = () => createQuickJsFromVariant(nodeVariant); + +export type CreateQuickJSFn = ReturnType; + +// --------------------------------------------------------------------------- +// newVariant / RELEASE_SYNC re-exported for callers that build their own variant +// --------------------------------------------------------------------------- +export { newVariant, RELEASE_SYNC }; diff --git a/src/shared/save-location.ts b/packages/shared/src/save-location.ts similarity index 63% rename from src/shared/save-location.ts rename to packages/shared/src/save-location.ts index 342953f7..371e855d 100644 --- a/src/shared/save-location.ts +++ b/packages/shared/src/save-location.ts @@ -1,40 +1,42 @@ -import { array, literal, object, string, union, type InferInput } from 'valibot' +import { array, literal, object, string, union, type InferInput } from "valibot"; export const SaveLocationInternalValidator = object({ id: string(), project: string(), lastModified: string(), - type: literal('internal'), - configName: string() -}) -export type SaveLocationInternal = InferInput + type: literal("internal"), + configName: string(), +}); +export type SaveLocationInternal = InferInput; +/** @deprecated External pipeline files are deprecated and will be removed in future versions. */ export const SaveLocationExternalValidator = object({ id: string(), project: string(), path: string(), lastModified: string(), - type: literal('external'), + type: literal("external"), summary: object({ plugins: array(string()), name: string(), - description: string() - }) -}) -export type SaveLocationExternal = InferInput + description: string(), + }), +}); +/** @deprecated External pipeline files are deprecated and will be removed in future versions. */ +export type SaveLocationExternal = InferInput; export const SaveLocationPipelabCloudValidator = object({ id: string(), project: string(), - type: literal('pipelab-cloud') -}) + type: literal("pipelab-cloud"), +}); -export type SaveLocationPipelabCloud = InferInput +export type SaveLocationPipelabCloud = InferInput; export const SaveLocationValidator = union([ SaveLocationExternalValidator, SaveLocationInternalValidator, - SaveLocationPipelabCloudValidator -]) + SaveLocationPipelabCloudValidator, +]); -export type SaveLocation = InferInput +export type SaveLocation = InferInput; diff --git a/packages/shared/src/subscription-errors.ts b/packages/shared/src/subscription-errors.ts new file mode 100644 index 00000000..18edff81 --- /dev/null +++ b/packages/shared/src/subscription-errors.ts @@ -0,0 +1,87 @@ +import { SubscriptionError } from "./build-history"; + +export class SubscriptionRequiredError extends Error implements SubscriptionError { + public readonly code = "SUBSCRIPTION_REQUIRED" as const; + public benefit: string; + public userMessage: string; + + constructor(benefit?: string) { + super(`Subscription required${benefit ? ` for benefit: ${benefit}` : ""}`); + this.name = "SubscriptionRequiredError"; + this.benefit = benefit || "build-history"; + this.userMessage = `Build history is a premium feature. Please upgrade your subscription to access this feature.`; + } +} + +export class SubscriptionExpiredError extends Error implements SubscriptionError { + public readonly code = "SUBSCRIPTION_EXPIRED" as const; + public benefit: string; + public userMessage: string; + + constructor(benefit?: string) { + super(`Subscription expired${benefit ? ` for benefit: ${benefit}` : ""}`); + this.name = "SubscriptionExpiredError"; + this.benefit = benefit || "build-history"; + this.userMessage = `Your subscription has expired. Please renew your subscription to continue using build history.`; + } +} + +export class BenefitNotFoundError extends Error implements SubscriptionError { + public readonly code = "BENEFIT_NOT_FOUND" as const; + public benefit: string; + public userMessage: string; + + constructor(benefit: string) { + super(`Benefit not found: ${benefit}`); + this.name = "BenefitNotFoundError"; + this.benefit = benefit; + this.userMessage = `The requested feature (${benefit}) is not available in your current subscription.`; + } +} + +export class UnauthorizedError extends Error implements SubscriptionError { + public readonly code = "UNAUTHORIZED" as const; + public benefit?: string; + public userMessage: string; + + constructor(message?: string, benefit?: string) { + super(message || "Unauthorized access"); + this.name = "UnauthorizedError"; + this.benefit = benefit; + this.userMessage = message || "You do not have permission to access this feature."; + } +} + +export function createSubscriptionError( + code: SubscriptionError["code"], + benefit?: string, + customMessage?: string, +): SubscriptionError { + switch (code) { + case "SUBSCRIPTION_REQUIRED": + return new SubscriptionRequiredError(benefit); + case "SUBSCRIPTION_EXPIRED": + return new SubscriptionExpiredError(benefit); + case "BENEFIT_NOT_FOUND": + if (!benefit) throw new Error("Benefit is required for BENEFIT_NOT_FOUND error"); + return new BenefitNotFoundError(benefit); + case "UNAUTHORIZED": + return new UnauthorizedError(customMessage, benefit); + default: + throw new Error(`Unknown subscription error code: ${code}`); + } +} + +export function isSubscriptionError(error: unknown): error is SubscriptionError { + return error instanceof Error && "code" in error && "userMessage" in error; +} + +export function getSubscriptionErrorMessage(error: unknown): string { + if (isSubscriptionError(error)) { + return error.userMessage; + } + if (error instanceof Error) { + return error.message; + } + return "An unknown error occurred"; +} diff --git a/packages/shared/src/supabase.ts b/packages/shared/src/supabase.ts new file mode 100644 index 00000000..00d1a179 --- /dev/null +++ b/packages/shared/src/supabase.ts @@ -0,0 +1,28 @@ +import { createClient } from "@supabase/supabase-js"; +import { Database } from "./database.types"; + +const getSupabaseConfig = () => { + const url = process.env.SUPABASE_URL || ""; + const anonKey = process.env.SUPABASE_ANON_KEY || ""; + return { url, anonKey }; +}; + +export const isSupabaseAvailable = () => { + const { url, anonKey } = getSupabaseConfig(); + const available = !!(url && anonKey); + + return available; +}; + +export const supabase = (options?: any) => { + const { url, anonKey } = getSupabaseConfig(); + if (!url || !anonKey) { + if (process.env.NODE_ENV !== "test") { + console.warn( + "Supabase environment variables are not configured. Supabase will not be available.", + ); + } + return null; + } + return createClient(url, anonKey, options); +}; diff --git a/src/shared/tests/helpers.ts b/packages/shared/src/tests/helpers.ts similarity index 56% rename from src/shared/tests/helpers.ts rename to packages/shared/src/tests/helpers.ts index 47e84b63..238e3bd0 100644 --- a/src/shared/tests/helpers.ts +++ b/packages/shared/src/tests/helpers.ts @@ -1,5 +1,5 @@ -import { vi } from 'vitest' +import { vi } from "vitest"; export const browserWindow = { - setProgressBar: vi.fn() -} satisfies Partial as unknown as Electron.BrowserWindow + setProgressBar: vi.fn(), +} satisfies Partial as unknown as Electron.BrowserWindow; diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts new file mode 100644 index 00000000..3139cc97 --- /dev/null +++ b/packages/shared/src/types.ts @@ -0,0 +1,3 @@ +export type NodeId = string; // keyof typeof nodes + +export type Context = Record; diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts new file mode 100644 index 00000000..7fac1f23 --- /dev/null +++ b/packages/shared/src/utils.ts @@ -0,0 +1,29 @@ +export const foo = "bar"; + +export type WithId = T extends string | number ? never : T & { id: string }; + +export const transformUrl = (url: string | undefined | null): string => { + if (url && typeof url === "string") { + const getHost = (): string => { + if (typeof window !== "undefined") { + const isDev = process.env.NODE_ENV === "development"; + if (isDev) { + return `http://${window.location.hostname}:33753`; + } else { + return `${window.location.protocol}//${window.location.host}`; + } + } + return "http://localhost:33753"; + }; + + if (url.startsWith("file://")) { + const filePath = decodeURIComponent(url.substring("file://".length)); + return `${getHost()}/media-file/${encodeURIComponent(filePath)}`; + } + if (url.startsWith("media://")) { + const filePath = decodeURIComponent(url.replace(/^media:\/\/+/, "/")); + return `${getHost()}/media-file/${encodeURIComponent(filePath)}`; + } + } + return url || ""; +}; diff --git a/packages/shared/src/validation.ts b/packages/shared/src/validation.ts new file mode 100644 index 00000000..3af04764 --- /dev/null +++ b/packages/shared/src/validation.ts @@ -0,0 +1,16 @@ +import { InputDefinition } from "./plugins/definitions"; + +export const isRequired = (param: InputDefinition) => { + return param.required === true; +}; + +export const isRenderer = () => { + // running in a web browser + if (typeof process === "undefined") return true; + + // node-integration is disabled + if (!process) return true; + + // @ts-expect-error + return process.browser === true || process.title === "browser"; +}; diff --git a/packages/shared/src/variables.ts b/packages/shared/src/variables.ts new file mode 100644 index 00000000..7afb3f77 --- /dev/null +++ b/packages/shared/src/variables.ts @@ -0,0 +1,27 @@ +import { CreateQuickJSFn } from "./quickjs"; + +export interface VariableBase { + value: string; + id: string; + name: string; + description: string; +} + +export type Variable = VariableBase; + +export const variableToFormattedVariable = async ( + vm: Awaited, + variables: Variable[], +) => { + const result: Record = {}; + for (const variable of variables) { + console.log("variable.value", variable.value); + const variableResult = await vm.run(variable.value, { + params: {}, + }); + + result[variable.id] = variableResult; + // result[variable.id] = variable.value + } + return result; +}; diff --git a/packages/shared/src/wasm.d.ts b/packages/shared/src/wasm.d.ts new file mode 100644 index 00000000..c2ac13ca --- /dev/null +++ b/packages/shared/src/wasm.d.ts @@ -0,0 +1,9 @@ +declare module "@jitl/quickjs-wasmfile-release-sync/wasm" { + const wasm: string; + export default wasm; +} + +declare module "@jitl/quickjs-wasmfile-release-sync/wasm?url" { + const wasm: string; + export default wasm; +} diff --git a/src/shared/websocket.types.ts b/packages/shared/src/websocket.types.ts similarity index 50% rename from src/shared/websocket.types.ts rename to packages/shared/src/websocket.types.ts index 8125afa1..2ddd886a 100644 --- a/src/shared/websocket.types.ts +++ b/packages/shared/src/websocket.types.ts @@ -1,119 +1,126 @@ -import { Channels, Data, Events, End, Message, RequestId } from './apis' -import { WebSocket as WSWebSocket } from 'ws' +import { Channels, Data, Events, End, IpcMessage, RequestId } from "./apis"; +import { WebSocket as WSWebSocket } from "ws"; // WebSocket connection states export type WebSocketConnectionState = - | 'connecting' - | 'connected' - | 'disconnected' - | 'error' - | 'reconnecting' + | "connecting" + | "connected" + | "disconnected" + | "error" + | "reconnecting"; // WebSocket server types export interface WebSocketServerConfig { - port?: number - host?: string - maxReconnectAttempts?: number - reconnectDelay?: number + port?: number; + host?: string; + maxReconnectAttempts?: number; + reconnectDelay?: number; } export interface WebSocketServerEvents { - connection: (ws: WSWebSocket, request: IncomingMessage) => void - message: (ws: WSWebSocket, data: Buffer) => void - close: (ws: WSWebSocket) => void - error: (ws: WSWebSocket, error: Error) => void + connection: (ws: WSWebSocket, request: IncomingMessage) => void; + message: (ws: WSWebSocket, data: Buffer) => void; + close: (ws: WSWebSocket) => void; + error: (ws: WSWebSocket, error: Error) => void; } // WebSocket client types export interface WebSocketClientConfig { - url?: string - maxReconnectAttempts?: number - reconnectDelay?: number - timeout?: number + url?: string; + maxReconnectAttempts?: number; + reconnectDelay?: number; + timeout?: number; } export interface WebSocketClientEvents { - open: () => void - message: (event: MessageEvent) => void - close: (event: CloseEvent) => void - error: (error: Event) => void + open: () => void; + message: (event: MessageEvent) => void; + close: (event: CloseEvent) => void; + error: (error: Event) => void; } // Unified WebSocket event types export interface WebSocketEvent { - sender: string - timestamp?: number + sender: string; + timestamp?: number; } // WebSocket message types export interface WebSocketRequestMessage { - channel: Channels - requestId: RequestId - data: any + channel: Channels; + requestId: RequestId; + data: any; } export interface WebSocketResponseMessage { - type: 'response' - requestId: RequestId - events: Events + type: "response"; + requestId: RequestId; + events: Events; } export interface WebSocketErrorMessage { - type: 'error' - requestId: RequestId - error: string - code?: string + type: "error"; + requestId: RequestId; + error: string; + code?: string; } export type WebSocketMessage = | WebSocketRequestMessage | WebSocketResponseMessage - | WebSocketErrorMessage + | WebSocketErrorMessage; // WebSocket connection info export interface WebSocketConnectionInfo { - id: string - state: WebSocketConnectionState - url: string - connectedAt?: Date - lastActivity?: Date + id: string; + state: WebSocketConnectionState; + url: string; + connectedAt?: Date; + lastActivity?: Date; +} + +export interface Agent { + id: string; + name: string; + isSelf: boolean; + connectedAt?: number; } // Handler function types export type WebSocketHandler = ( event: WebSocketEvent, - data: { value: Data; send: WebSocketSendFunction } -) => Promise + data: { value: Data; send: WebSocketSendFunction }, +) => Promise; -export type WebSocketSendFunction = (events: Events) => Promise +export type WebSocketSendFunction = (events: Events) => Promise; // WebSocket listener types -export type WebSocketListener = (event: Events) => Promise +export type WebSocketListener = (event: Events) => Promise; // WebSocket API interface export interface WebSocketAPI { execute: ( channel: KEY, data?: Data, - listener?: WebSocketListener - ) => Promise> - send: (channel: KEY, data?: Data) => Promise> + listener?: WebSocketListener, + ) => Promise>; + send: (channel: KEY, data?: Data) => Promise>; on: ( channel: KEY, - listener: (event: WebSocketEvent, data: Events) => void - ) => () => void - isConnected: () => boolean - disconnect: () => void + listener: (event: WebSocketEvent, data: Events) => void, + ) => () => void; + isConnected: () => boolean; + disconnect: () => void; } // WebSocket manager interface export interface WebSocketManager { - connect: (url?: string) => Promise - disconnect: () => void - send: (channel: KEY, data?: Data) => Promise> - isConnected: () => boolean - getConnectionState: () => WebSocketConnectionState - onStateChange: (callback: (state: WebSocketConnectionState) => void) => () => void + connect: (url?: string) => Promise; + disconnect: () => void; + send: (channel: KEY, data?: Data) => Promise>; + isConnected: () => boolean; + getConnectionState: () => WebSocketConnectionState; + onStateChange: (callback: (state: WebSocketConnectionState) => void) => () => void; } // Error types @@ -121,20 +128,20 @@ export class WebSocketError extends Error { constructor( message: string, public code?: string, - public requestId?: RequestId + public requestId?: RequestId, ) { - super(message) - this.name = 'WebSocketError' + super(message); + this.name = "WebSocketError"; } } export class WebSocketConnectionError extends WebSocketError { constructor( message: string, - public url?: string + public url?: string, ) { - super(message) - this.name = 'WebSocketConnectionError' + super(message); + this.name = "WebSocketConnectionError"; } } @@ -142,38 +149,38 @@ export class WebSocketTimeoutError extends WebSocketError { constructor( message: string, public timeout: number, - requestId?: RequestId + requestId?: RequestId, ) { - super(message) - this.name = 'WebSocketTimeoutError' + super(message); + this.name = "WebSocketTimeoutError"; } } // Type guards export const isWebSocketRequestMessage = (message: any): message is WebSocketRequestMessage => { - return message && typeof message.channel === 'string' && message.requestId -} + return message && typeof message.channel === "string" && message.requestId; +}; export const isWebSocketResponseMessage = (message: any): message is WebSocketResponseMessage => { - return message && message.type === 'response' && message.requestId && message.events -} + return message && message.type === "response" && message.requestId && message.events; +}; export const isWebSocketErrorMessage = (message: any): message is WebSocketErrorMessage => { - return message && message.type === 'error' && message.requestId && message.error -} + return message && message.type === "error" && message.requestId && message.error; +}; // Utility types for better type inference export type WebSocketMessageType = { - channel: T - requestId: RequestId - data: Data -} + channel: T; + requestId: RequestId; + data: Data; +}; export type WebSocketResponseType = { - type: 'response' - requestId: RequestId - events: Events -} + type: "response"; + requestId: RequestId; + events: Events; +}; // Import for Node.js HTTP server -import { IncomingMessage } from 'http' +import { IncomingMessage } from "http"; diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 00000000..83f866de --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig/commonjs.json", + "compilerOptions": { + "emitDeclarationOnly": true, + "outDir": "dist", + "baseUrl": "." + }, + "include": ["src/**/*", "src/**/*.json"], + "exclude": ["node_modules", "dist"], + "references": [{ "path": "../migration" }] +} diff --git a/packages/shared/tsconfig.test.json b/packages/shared/tsconfig.test.json new file mode 100644 index 00000000..181ff8b4 --- /dev/null +++ b/packages/shared/tsconfig.test.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": false, + "noEmit": true + }, + "include": ["src/**/*", "tests/**/*", "*.ts"] +} diff --git a/packages/shared/tsdown.config.ts b/packages/shared/tsdown.config.ts new file mode 100644 index 00000000..7ba5c08d --- /dev/null +++ b/packages/shared/tsdown.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, +}); diff --git a/packages/test-utils/.oxfmtrc.json b/packages/test-utils/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/test-utils/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md new file mode 100644 index 00000000..f3624629 --- /dev/null +++ b/packages/test-utils/CHANGELOG.md @@ -0,0 +1,303 @@ +# @pipelab/test-utils + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json new file mode 100644 index 00000000..037637c7 --- /dev/null +++ b/packages/test-utils/package.json @@ -0,0 +1,54 @@ +{ + "name": "@pipelab/test-utils", + "version": "1.0.0-beta.38", + "private": false, + "description": "Testing utilities for Pipelab plugins and monorepo", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "packages/test-utils" + }, + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "build": "tsdown", + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint ." + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "execa": "9.5.1" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "@types/node": "24.12.2", + "tsdown": "0.21.2", + "typescript": "^5.0.0" + } +} diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts new file mode 100644 index 00000000..a07815b7 --- /dev/null +++ b/packages/test-utils/src/index.ts @@ -0,0 +1,249 @@ +import { resolve, dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { mkdir, writeFile, chmod, rm } from "node:fs/promises"; +import { existsSync as existsSyncSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { + type ActionRunner, + type ActionRunnerData, + type Action, + PipelabContext, +} from "@pipelab/plugin-core"; +import { execa } from "execa"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** + * Finds the monorepo root by looking for pnpm-workspace.yaml. + */ +export function findProjectRoot(startDir: string): string { + let curr = startDir; + while (curr !== dirname(curr)) { + if (existsSyncSync(join(curr, "pnpm-workspace.yaml"))) { + return curr; + } + curr = dirname(curr); + } + throw new Error("Could not find project root (pnpm-workspace.yaml)"); +} + +export const isWindows = process.platform === "win32"; +export const isMac = process.platform === "darwin"; +export const isLinux = process.platform === "linux"; + +/** + * Creates a unique sandbox directory and returns a bundle containing its path + * and a pre-filled remove utility. + */ +export const createSandbox = async (prefix: string) => { + const sandboxPath = join(tmpdir(), `${prefix}-${Math.random().toString(36).substring(7)}`); + + const paths = { + input: join(sandboxPath, "input"), + output: join(sandboxPath, "output"), + userData: join(sandboxPath, "user-data"), + project: join(sandboxPath, "project"), + thirdparty: join(sandboxPath, "thirdparty"), + }; + + await mkdir(sandboxPath, { recursive: true }); + await Promise.all([ + mkdir(paths.input, { recursive: true }), + mkdir(paths.output, { recursive: true }), + mkdir(paths.userData, { recursive: true }), + ]); + + return { + path: sandboxPath, + paths, + /** + * Creates a mock binary/script in the sandbox. + */ + mockBinary: async ( + relativePath: string, + content?: string, + options: { extension?: string | false } = {}, + ) => { + const fullPath = join(sandboxPath, relativePath); + let platformPath = fullPath; + + if (options.extension === false) { + // Use exactly the path provided + } else if (options.extension) { + platformPath = `${fullPath}.${options.extension}`; + } else { + const hasExtension = /\.[a-z0-9]+$/i.test(relativePath); + platformPath = hasExtension ? fullPath : isWindows ? `${fullPath}.cmd` : `${fullPath}.sh`; + } + + const defaultContent = isWindows + ? `@echo off\necho Mock Binary Execution: %*\nexit /b 0` + : `#!/bin/bash\necho "Mock Binary Execution: $@"\nexit 0`; + + await mkdir(dirname(platformPath), { recursive: true }); + await writeFile(platformPath, content || defaultContent); + + if (!isWindows) { + await chmod(platformPath, 0o755); + } + + return platformPath; + }, + remove: async () => { + await rm(sandboxPath, { + recursive: true, + force: true, + maxRetries: 20, + retryDelay: 500, + }); + }, + }; +}; + +/** + * Runs the Pipelab CLI out-of-process. + */ +export const runCLI = async ( + args: string[], + options: { + cwd?: string; + env?: Record; + } = {}, +) => { + const projectRoot = findProjectRoot(__dirname); + const cliPath = resolve(projectRoot, "apps/cli/src/index.ts"); + + return execa("tsx", [cliPath, ...args], { + cwd: options.cwd || projectRoot, + env: { + ...process.env, + PIPELAB_DISABLE_HISTORY: "true", + ...options.env, + }, + }); +}; + +/** + * Runs a Pipelab action runner directly in-process for focused testing. + */ +export const runAction = async ( + runner: ActionRunner, + options: { + inputs: ActionRunnerData["inputs"]; + sandboxPath: string; + extraEnv?: Record; + }, +): Promise<{ outputs: Record }> => { + const outputs: Record = {}; + + let realPnpm = "pnpm"; + try { + const { execSync } = require("child_process"); + const isWindows = process.platform === "win32"; + const cmd = isWindows ? "where pnpm" : "which pnpm"; + const stdout = execSync(cmd, { encoding: "utf8" }); + const lines = stdout.split(/\r?\n/).map(l => l.trim()).filter(Boolean); + if (isWindows) { + realPnpm = lines.find(l => l.endsWith(".cmd") || l.endsWith(".exe")) || lines[0] || "pnpm"; + } else { + realPnpm = lines[0] || "pnpm"; + } + // Need to escape backslashes for JS string literal + realPnpm = realPnpm.replace(/\\/g, "\\\\"); + } catch (e) { + // fallback + } + + // Create a pnpm shim because ensureNPMPackage expects a JS file runnable by node + const pnpmShimPath = join(options.sandboxPath, "pnpm-shim.cjs"); + await writeFile( + pnpmShimPath, + `const { spawnSync } = require('child_process'); +const result = spawnSync('${realPnpm}', process.argv.slice(2), { stdio: 'inherit', shell: true }); +process.exit(result.status ?? 0);`, + ); + + const context: ActionRunnerData = { + inputs: options.inputs, + log: (...args: any[]) => { + console.log("[Runner Log]", ...args); + }, + setOutput: (key: any, value: any) => { + console.log(`[Runner Output] ${key} = ${value}`); + outputs[key] = value; + }, + setArtifact: (key: string, path: string) => { + console.log(`[Runner Artifact] ${key} = ${path}`); + }, + cwd: options.sandboxPath, + paths: { + cache: join(options.sandboxPath, "cache"), + pnpm: pnpmShimPath, + node: process.execPath, + userData: join(options.sandboxPath, "user-data"), + modules: join(options.sandboxPath, "modules"), + thirdparty: join(options.sandboxPath, "thirdparty"), + }, + api: { + fetchAsset: async (packageName: string) => { + const sandboxAssetPath = join(options.sandboxPath, "assets", packageName); + if (existsSyncSync(sandboxAssetPath)) { + return sandboxAssetPath; + } + // Fallback to real monorepo assets + // Normalize: remove @pipelab/ prefix if present + const folderName = packageName.startsWith("@pipelab/") + ? packageName.replace("@pipelab/", "") + : packageName; + + const projectRoot = findProjectRoot(__dirname); + return join(projectRoot, "assets", folderName); + }, + }, + // @ts-ignore - Mocking BrowserWindow + browserWindow: undefined, + abortSignal: new AbortController().signal, + context: new PipelabContext({ + userDataPath: join(options.sandboxPath, "user-data"), + }), + // @ts-ignore - Mocking setMeta + setMeta: () => {}, + meta: {} as any, + }; + + // Set environment variables for the test if provided + const originalEnv = { ...process.env }; + if (options.extraEnv) { + Object.assign(process.env, options.extraEnv); + } + + try { + await runner(context); + } finally { + // Restore original environment + if (options.extraEnv) { + // Remove keys that were added + for (const key in options.extraEnv) { + if (!(key in originalEnv)) { + delete process.env[key]; + } + } + // Restore original values + Object.assign(process.env, originalEnv); + } + } + + return { outputs }; +}; + +/** + * Runs the packaged electron app (smoke test) + */ +export const runElectronApp = async (app_path: string, options: { timeoutMs?: number } = {}) => { + const child = execa(app_path, [], { + cleanup: true, + timeout: options.timeoutMs || 120000, + }); + return child; +}; diff --git a/packages/test-utils/tsconfig.json b/packages/test-utils/tsconfig.json new file mode 100644 index 00000000..a61db8d6 --- /dev/null +++ b/packages/test-utils/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../tsconfig/node.json", + "compilerOptions": { + "moduleResolution": "bundler", + "outDir": "dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "baseUrl": "." + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"], + "references": [{ "path": "../../plugins/plugin-core" }] +} diff --git a/packages/test-utils/tsdown.config.ts b/packages/test-utils/tsdown.config.ts new file mode 100644 index 00000000..7ba5c08d --- /dev/null +++ b/packages/test-utils/tsdown.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, +}); diff --git a/packages/tsconfig/.oxfmtrc.json b/packages/tsconfig/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/packages/tsconfig/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/packages/tsconfig/CHANGELOG.md b/packages/tsconfig/CHANGELOG.md new file mode 100644 index 00000000..94e52274 --- /dev/null +++ b/packages/tsconfig/CHANGELOG.md @@ -0,0 +1,193 @@ +# @pipelab/tsconfig + +## 1.0.0-beta.31 + +### Patch Changes + +- - + +## 1.0.0-beta.30 + +### Patch Changes + +- improve dark theme and improve build history + +## 1.0.0-beta.29 + +### Patch Changes + +- sd + +## 1.0.0-beta.28 + +### Patch Changes + +- sd + +## 1.0.0-beta.27 + +### Patch Changes + +- sd + +## 1.0.0-beta.26 + +### Patch Changes + +- sd + +## 1.0.0-beta.25 + +### Patch Changes + +- sd + +## 1.0.0-beta.24 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.23 + +### Patch Changes + +- sd + +## 1.0.0-beta.22 + +### Patch Changes + +- sd + +## 1.0.0-beta.21 + +### Patch Changes + +- sd + +## 1.0.0-beta.20 + +### Patch Changes + +- sd + +## 1.0.0-beta.19 + +### Patch Changes + +- sd + +## 1.0.0-beta.18 + +### Patch Changes + +- sd + +## 1.0.0-beta.17 + +### Patch Changes + +- sd + +## 1.0.0-beta.16 + +### Patch Changes + +- df + +## 1.0.0-beta.15 + +### Patch Changes + +- sdsd + +## 1.0.0-beta.14 + +### Patch Changes + +- sd + +## 1.0.0-beta.13 + +### Patch Changes + +- sd + +## 1.0.0-beta.12 + +### Patch Changes + +- qs + +## 1.0.0-beta.11 + +### Patch Changes + +- sd + +## 1.0.0-beta.10 + +### Patch Changes + +- s + +## 1.0.0-beta.9 + +### Patch Changes + +- fg + +## 1.0.0-beta.8 + +### Patch Changes + +- changes + +## 1.0.0-beta.7 + +### Patch Changes + +- bump + +## 1.0.0-beta.6 + +### Patch Changes + +- fixes + +## 1.0.0-beta.5 + +### Patch Changes + +- bump + +## 1.0.0-beta.4 + +### Patch Changes + +- beta tag + +## 1.0.0-beta.3 + +### Patch Changes + +- bump + +## 1.0.0-beta.2 + +### Patch Changes + +- update + +## 1.0.0-beta.1 + +### Patch Changes + +- general improvements + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release diff --git a/packages/tsconfig/README.md b/packages/tsconfig/README.md new file mode 100644 index 00000000..41ab0d3d --- /dev/null +++ b/packages/tsconfig/README.md @@ -0,0 +1,3 @@ +# @pipelab/tsconfig + +Base TypeScript configurations for different parts of the Pipelab monorepo (Node, Vue, CommonJS, etc.). diff --git a/packages/tsconfig/base.json b/packages/tsconfig/base.json new file mode 100644 index 00000000..8bca30cd --- /dev/null +++ b/packages/tsconfig/base.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "composite": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "tsBuildInfoFile": "${configDir}/dist/tsconfig.tsbuildinfo", + "target": "ESNext", + "module": "ESNext", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "resolveJsonModule": true + } +} diff --git a/packages/tsconfig/commonjs.json b/packages/tsconfig/commonjs.json new file mode 100644 index 00000000..0779882b --- /dev/null +++ b/packages/tsconfig/commonjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./base.json", + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": true + } +} diff --git a/packages/tsconfig/node.json b/packages/tsconfig/node.json new file mode 100644 index 00000000..e5a4c493 --- /dev/null +++ b/packages/tsconfig/node.json @@ -0,0 +1,7 @@ +{ + "extends": "./base.json", + "compilerOptions": { + "moduleResolution": "node", + "strict": true + } +} diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json new file mode 100644 index 00000000..669ea6a0 --- /dev/null +++ b/packages/tsconfig/package.json @@ -0,0 +1,23 @@ +{ + "name": "@pipelab/tsconfig", + "version": "1.0.0-beta.31", + "private": false, + "description": "Shared TypeScript configurations for Pipelab", + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "packages/tsconfig" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "format": "oxfmt .", + "lint": "oxlint ." + }, + "dependencies": { + "@types/node": "^24.12.2" + } +} diff --git a/packages/tsconfig/vue.json b/packages/tsconfig/vue.json new file mode 100644 index 00000000..9f9eb95b --- /dev/null +++ b/packages/tsconfig/vue.json @@ -0,0 +1,11 @@ +{ + "extends": "./base.json", + "compilerOptions": { + "moduleResolution": "bundler", + "strict": true, + "jsx": "preserve", + "importHelpers": true, + "moduleDetection": "force", + "lib": ["ESNext", "DOM"] + } +} diff --git a/plugins/plugin-construct/.oxfmtrc.json b/plugins/plugin-construct/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-construct/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-construct/CHANGELOG.md b/plugins/plugin-construct/CHANGELOG.md new file mode 100644 index 00000000..0cad8334 --- /dev/null +++ b/plugins/plugin-construct/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-construct + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-construct/README.md b/plugins/plugin-construct/README.md new file mode 100644 index 00000000..92a96365 --- /dev/null +++ b/plugins/plugin-construct/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-construct + +Pipelab plugin for automating Construct 3 project exports. diff --git a/plugins/plugin-construct/package.json b/plugins/plugin-construct/package.json new file mode 100644 index 00000000..e06e3e6d --- /dev/null +++ b/plugins/plugin-construct/package.json @@ -0,0 +1,75 @@ +{ + "name": "@pipelab/plugin-construct", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for exporting and packaging Construct 3 projects", + "keywords": [ + "automation", + "c3", + "construct", + "construct3", + "game-development", + "game-export", + "html5-game", + "pipelab", + "pipelab-plugin", + "pipeline" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-construct" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown", + "test": "vitest run -c tests/e2e/vitest.config.mts" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "es-toolkit": "1.25.2", + "playwright": "1.48.2", + "valibot": "0.42.1" + }, + "devDependencies": { + "@pipelab/test-utils": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "@types/node": "24", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + }, + "pipelab": { + "name": "Construct", + "description": "Pipelab plugin for exporting and packaging Construct 3 projects", + "icon": "./dist/assets/construct.webp" + }, + "test": { + "env": { + "NODE_ENV": "development" + } + } +} diff --git a/src/shared/libs/plugin-construct/assets/construct.webp b/plugins/plugin-construct/src/assets/construct.webp similarity index 100% rename from src/shared/libs/plugin-construct/assets/construct.webp rename to plugins/plugin-construct/src/assets/construct.webp diff --git a/plugins/plugin-construct/src/assets/listeners.ts b/plugins/plugin-construct/src/assets/listeners.ts new file mode 100644 index 00000000..fae6fe6e --- /dev/null +++ b/plugins/plugin-construct/src/assets/listeners.ts @@ -0,0 +1,145 @@ +import type { Page } from "playwright"; + +export const registerInstallButtonListener = (page: Page, log: typeof console.log) => { + const installDialog = page.locator("#addonConfirmInstallDialog"); + const installBtn = installDialog.locator(".okButton"); + installBtn + .waitFor({ + timeout: 0, + }) + .then(async () => { + await installBtn.click(); + log("installBtn clicked"); + registerInstallButtonListener(page, log); + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("installBtn.click() failed", e.message); + }); +}; + +export const registerSaveLoginExpiredistener = (page: Page, log: typeof console.log) => { + const installDialog = page.locator("#confirmDialog"); + const cancelBtn = installDialog.locator(".cancelConfirmButton"); + cancelBtn + .waitFor({ + timeout: 0, + }) + .then(async () => { + await cancelBtn.click(); + log("cancelBtn clicked"); + registerSaveLoginExpiredistener(page, log); + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("cancelBtn.click() failed", e.message); + }); +}; + +export const registerWebglErrorListener = (page: Page, log: typeof console.log) => { + const okDialog = page.locator("#okDialog"); + const webglErrorButton = okDialog.locator(".okButton"); + webglErrorButton + .waitFor({ + timeout: 0, + }) + .then(async () => { + const text = await okDialog.allInnerTexts(); + + if (text.join().toLowerCase().includes("webgl")) { + await webglErrorButton.click(); + log("webglErrorButton clicked"); + registerWebglErrorListener(page, log); + } + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("webglErrorButton.click() failed", e.message); + }); +}; + +export const registerDeprecatedFeatures = (page: Page, log: typeof console.log) => { + const deprecatedFeaturesDialog = page.locator("#deprecatedFeaturesDialog"); + const okButton = deprecatedFeaturesDialog.locator(".okButton"); + okButton + .waitFor({ + timeout: 0, + }) + .then(async () => { + await okButton.click(); + log("okButton clicked"); + registerDeprecatedFeatures(page, log); + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("deprecatedFeatures.okButton.click() failed", e.message); + }); +}; + +export const registerWelcomeToConstructListener = (page: Page, log: typeof console.log) => { + const welcomeTourDialog = page.locator("#welcomeTourDialog"); + const okButton = welcomeTourDialog.locator(".noThanksLink"); + okButton + .waitFor({ + timeout: 0, + }) + .then(async () => { + await okButton.click(); + log("okButton clicked"); + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("welcomeTour.okButton.click() failed", e.message); + }); +}; + +export const registerMissingAddonErrorListener = (page: Page, log: typeof console.log) => { + const okDialog = page.locator("#missingAddonsDialog"); + const webglErrorButton = okDialog.locator(".okButton"); + webglErrorButton + .waitFor({ + timeout: 0, + }) + .then(async () => { + throw new Error("Missing addon. You should bundle addons with your project"); + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("missingAddon.okButton.waitFor() failed", e.message); + }); +}; + +export const registerNewVersionAvailableListener = (page: Page, log: typeof console.log) => { + const newVersionAvailableDialog = page.locator("#confirmDialog"); + const cancelButton = newVersionAvailableDialog.locator(".cancelConfirmButton"); + cancelButton + .waitFor({ + timeout: 0, + }) + .then(async () => { + await cancelButton.click(); + log("cancelButton clicked"); + registerNewVersionAvailableListener(page, log); + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("cancelButton.click() failed", e.message); + }); +}; + +export const registerNotNowListener = (page: Page, log: typeof console.log) => { + const notNowBtn = page.getByText("Not now"); + notNowBtn + .waitFor({ + timeout: 0, + }) + .then(async () => { + await notNowBtn.click(); + log("notNowBtn clicked"); + registerNotNowListener(page, log); + }) + .catch(async (e) => { + if (e.message.includes("Target page, context or browser has been closed")) return; + log("notNowBtn.click() failed", e.message); + }); +}; diff --git a/plugins/plugin-construct/src/assets/script.ts b/plugins/plugin-construct/src/assets/script.ts new file mode 100644 index 00000000..31127e7f --- /dev/null +++ b/plugins/plugin-construct/src/assets/script.ts @@ -0,0 +1,153 @@ +import { Page } from "playwright"; +import { join } from "node:path"; +import { + registerInstallButtonListener, + registerSaveLoginExpiredistener, + registerWebglErrorListener, + registerDeprecatedFeatures, + registerWelcomeToConstructListener, + registerMissingAddonErrorListener, + registerNewVersionAvailableListener, + registerNotNowListener, +} from "./listeners.js"; + +export const script = async ( + page: Page, + log: typeof console.log, + filePath: string, + username: string | undefined, + password: string | undefined, + version: string | undefined, + downloadDir: string, +) => { + let url = "https://editor.construct.net/"; + if (version) { + url += version; + } + log("Navigating to URL", url); + await page.goto(url, { waitUntil: "load" }); + log("after navigating, current URL:", page.url()); + + if (username && password) { + log("Directly authenticating via Construct 3 account API..."); + const formData = new FormData(); + formData.append("username", username); + formData.append("password", password); + formData.append("productType", "games"); + + const res = await fetch("https://account.construct.net/login.json", { + method: "POST", + body: formData, + }); + const json = (await res.json()) as any; + if (json.request.status !== "ok") { + throw new Error(json.request.errorMessage || "Invalid credentials"); + } + + const { userID, token } = json.response; + log("API login successful, injecting credentials into browser context..."); + log("Current URL before injection:", page.url()); + + // Wait for localforage to be available (initialized by the editor's JS) + await page.waitForFunction(() => typeof localforage !== "undefined", { timeout: 30000 }); + log("localforage is available"); + + // Inject credentials using the editor's own localforage instance + await page.evaluate( + async ({ userID, token }) => { + await localforage.setItem("login-data", { userID, token }); + }, + { userID, token }, + ); + log("Credentials injected successfully."); + + // Reload to pick up the new login state + log("Reloading page to apply login state..."); + await page.reload(); + log("Page reloaded."); + } + + registerWelcomeToConstructListener(page, log); + registerNewVersionAvailableListener(page, log); + registerNotNowListener(page, log); + registerInstallButtonListener(page, log); + registerWebglErrorListener(page, log); + registerMissingAddonErrorListener(page, log); + registerDeprecatedFeatures(page, log); + registerSaveLoginExpiredistener(page, log); + + log("after event"); + + // Wait for filesystem API (Ctrl+O handler) to be registered + await page.waitForTimeout(2000); + + const [fileChooser] = await Promise.all([ + page.waitForEvent("filechooser"), + page.keyboard.press("ControlOrMeta+O"), + ]); + log("filechooser"); + + console.log("filePath", filePath); + await fileChooser.setFiles([filePath]); + log("Set file"); + + const progressDialog = page.locator("#progressDialog"); + const progessBar = progressDialog.locator(".progressBar"); + + log("Waiting for progress dialog"); + await progressDialog.waitFor({ + timeout: 0, + }); + log("Got loading progress dialog"); + + const progressInterval = setInterval(async () => { + try { + const text = await progessBar.getAttribute("value", { timeout: 100 }); + if (text === null) return; + const textAsNumber = parseFloat(text); + const finalText = Number.isNaN(textAsNumber) ? 0 : textAsNumber; + log("progress", `${finalText * 100}%`); + } catch { + clearInterval(progressInterval); + } + }, 500); + + log("Waiting for progress dialog to disapear"); + await progressDialog.waitFor({ + state: "detached", + timeout: 0, + }); + log("Got progress dialog to disapear"); + clearInterval(progressInterval); + + await page.getByRole("button", { name: "Menu" }).click(); + await page.getByRole("menuitem", { name: "Project" }).click(); + await page.getByRole("menuitem", { name: "Export" }).click(); + log('"Export" clicked'); + await page + .locator("ui-iconviewitem") + .filter({ hasText: "Web (HTML5)" }) + .locator("ui-icon") + .click(); + log('"Web" clicked'); + + await page.locator("#exportSelectPlatformDialog").getByRole("button", { name: "Next" }).click(); + + await page.getByLabel("Offline support").uncheck(); + log("Disabled offline support"); + + await page.locator("#exportStandardOptionsDialog").getByRole("button", { name: "Next" }).click(); + log('"Next" clicked'); + const downloadPromise = page.waitForEvent("download"); + await page.locator(".downloadExportedProject").click(); + const download = await downloadPromise; + await page.getByRole("button", { name: "OK" }).click(); + log('"Download" clicked'); + + const finalPath = join(downloadDir, download.suggestedFilename()); + await download.saveAs(finalPath); + log("File Downloaded"); + + await page.close(); + return finalPath; +}; diff --git a/plugins/plugin-construct/src/declarations.d.ts b/plugins/plugin-construct/src/declarations.d.ts new file mode 100644 index 00000000..c5608a8a --- /dev/null +++ b/plugins/plugin-construct/src/declarations.d.ts @@ -0,0 +1 @@ +declare module "*.webp"; diff --git a/src/shared/libs/plugin-construct/export-c3p.ts b/plugins/plugin-construct/src/export-c3p.ts similarity index 50% rename from src/shared/libs/plugin-construct/export-c3p.ts rename to plugins/plugin-construct/src/export-c3p.ts index 07303887..8d13954e 100644 --- a/src/shared/libs/plugin-construct/export-c3p.ts +++ b/plugins/plugin-construct/src/export-c3p.ts @@ -3,73 +3,73 @@ import { createAction, createActionRunner, createPathParam, - fileExists -} from '@pipelab/plugin-core' -import { exportc3p, sharedParams } from './export-shared.js' + fileExists, +} from "@pipelab/plugin-core"; +import { exportc3p, sharedParams } from "./export-shared.js"; -export const ID = 'export-construct-project' +export const ID = "export-construct-project"; export const exportAction = createAction({ id: ID, - name: 'Export .c3p', + name: "Export .c3p", displayString: "`Export project ${fmt.param(params.file, 'primary', 'No path selected')} with version ${params.version ? params.version : 'stable'}`", meta: {}, params: { - file: createPathParam('', { - label: 'File (.c3p)', + file: createPathParam("", { + label: "File (.c3p)", required: true, control: { - type: 'path', - label: 'Pick a file (.c3p)', + type: "path", + label: "Pick a file (.c3p)", options: { - properties: ['openFile'], - filters: [{ name: 'Construct Project', extensions: ['c3p'] }], - title: 'aaaa', - message: 'bbbb' - } - } + properties: ["openFile"], + filters: [{ name: "Construct Project", extensions: ["c3p"] }], + title: "aaaa", + message: "bbbb", + }, + }, }), - ...sharedParams + ...sharedParams, }, outputs: { folder: { - type: 'path', + type: "path", deprecated: true, value: undefined as undefined | string, - label: 'Exported zip' + label: "Exported zip", // schema: schema.string() }, parentFolder: { - type: 'path', + type: "path", deprecated: false, value: undefined as undefined | string, - label: 'Path to parent folder of exported zip' + label: "Path to parent folder of exported zip", // schema: schema.string() }, zipFile: { - type: 'path', + type: "path", deprecated: false, value: undefined as undefined | string, - label: 'Exported zip' + label: "Exported zip", // schema: schema.string() - } + }, }, - description: 'Export construct project from .c3p file', - icon: '' -}) + description: "Export construct project from .c3p file", + icon: "", +}); export const ExportActionRunner = createActionRunner(async (options) => { - const file = options.inputs.file + const file = options.inputs.file; - const c3pFileExists = await fileExists(file) + const c3pFileExists = await fileExists(file); if (!c3pFileExists) { - throw new Error('You must specify a valid .c3p file') + throw new Error("You must specify a valid .c3p file"); } - await exportc3p(file, options) - options.log('exportc3p done') -}) + await exportc3p(file, options); + options.log("exportc3p done"); +}); -export type Params = ExtractInputsFromAction +export type Params = ExtractInputsFromAction; diff --git a/plugins/plugin-construct/src/export-project.ts b/plugins/plugin-construct/src/export-project.ts new file mode 100644 index 00000000..07faeb04 --- /dev/null +++ b/plugins/plugin-construct/src/export-project.ts @@ -0,0 +1,80 @@ +import { join } from "node:path"; +import { + ExtractInputsFromAction, + createAction, + createActionRunner, + createPathParam, + fileExists, +} from "@pipelab/plugin-core"; +import { exportc3p, sharedParams } from "./export-shared.js"; +import { throttle } from "es-toolkit"; +import { zipFolder } from "@pipelab/plugin-core"; + +export const ID = "export-construct-project-folder"; + +export const exportProjectAction = createAction({ + id: ID, + name: "Export folder", + displayString: "`Export project ${params.version ? `r${params.version}` : ''}`", + meta: {}, + params: { + folder: createPathParam("", { + required: true, + label: "Folder", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + ...sharedParams, + }, + outputs: { + folder: { + type: "path", + deprecated: true, + value: undefined as undefined | string, + label: "Exported zip", + // schema: schema.string() + }, + parentFolder: { + type: "path", + deprecated: false, + value: undefined as undefined | string, + label: "Path to parent folder of exported zip", + // schema: schema.string() + }, + zipFile: { + type: "path", + deprecated: false, + value: undefined as undefined | string, + label: "Exported zip", + // schema: schema.string() + }, + }, + description: "Export construct project from folder", + icon: "", +}); + +export const ExportProjectActionRunner = createActionRunner( + async (options) => { + const folder = options.inputs.folder; + if (!folder) { + throw new Error("You must specify a valid construct project folder"); + } + + const c3pFolderExists = await fileExists(folder); + if (!c3pFolderExists) { + throw new Error("You must specify a valid construct project folder"); + } + + const outputPath = join(options.cwd, "c3_tmp_proj.c3p"); + + const to = await zipFolder(folder, outputPath, options.log, options.abortSignal); + + await exportc3p(to, options); + }, +); + +export type Params = ExtractInputsFromAction; diff --git a/plugins/plugin-construct/src/export-shared.ts b/plugins/plugin-construct/src/export-shared.ts new file mode 100644 index 00000000..cabb7a23 --- /dev/null +++ b/plugins/plugin-construct/src/export-shared.ts @@ -0,0 +1,325 @@ +import { + Action, + ActionRunnerData, + createNumberParam, + createPasswordParam, + createPathParam, + createStringParam, + InputsDefinition, + ParamsToInput, + runWithLiveLogs, + fetchPackage, +} from "@pipelab/plugin-core"; +import { script } from "./assets/script.js"; +import * as v from "valibot"; +import { BrowserContext } from "playwright"; +import { dirname, join, delimiter } from "node:path"; +import { cp, mkdir } from "node:fs/promises"; +import { existsSync } from "node:fs"; +import { homedir } from "node:os"; +import { createRequire } from "node:module"; + +const platform = process.platform; +const { LOCALAPPDATA, XDG_CONFIG_HOME } = process.env; + +const isCI = process.env.CI === "true"; + +let baseProfile; +if (platform === "win32") { + baseProfile = join(LOCALAPPDATA ?? "", "Google", "Chrome", "User Data"); +} else if (platform === "linux") { + const configHome = + XDG_CONFIG_HOME && XDG_CONFIG_HOME.trim() !== "" ? XDG_CONFIG_HOME : join(homedir(), ".config"); + baseProfile = join(configHome, "google-chrome"); +} else if (platform === "darwin") { + baseProfile = join(homedir(), "Library", "Application Support", "Google", "Chrome"); +} + +export const sharedParams = { + username: createStringParam("", { + label: "Username", + required: false, + description: "Your Construct username", + }), + password: createPasswordParam("", { + description: + "Your Construct password. Will only be used locally to automate the export on Construct website via a local browser. Will not be sent to any server.", + required: false, + label: "Password", + }), + version: createStringParam("", { + description: "The Construct version you want to use", + label: "Version", + required: false, + }), + headless: { + description: "Whether to show the browser while export", + required: false, + control: { + type: "boolean", + }, + value: false, + label: "Start headless", + }, + timeout: createNumberParam(120, { + description: "The timeout (in seconds) to close the browser if it's stuck", + required: false, + label: "Timeout", + }), + // customBrowser: { + // description: 'Start your own browser rather than the predefined one', + // control: { + // type: 'path', + // options: { + // properties: ['openFile'] + // } + // }, + // label: 'Custom browser', + // value: '' + // }, + customProfile: createPathParam(undefined, { + required: false, + description: + "Use your own profile (X:\\Users\\XXX\\AppData\\Local\\Google\\Chrome\\User Data). Useful if you want to reuse plugins installed in your current browser", + control: { + type: "path", + options: { + properties: ["openDirectory"], + defaultPath: baseProfile, + }, + }, + label: "Custom profile", + }), + // addonsFolder: { + // description: 'Folder containing addons to import in the editor', + // required: false, + // control: { + // type: 'path', + // options: { + // buttonLabel: 'Addons folder', + // properties: ['openDirectory'] + // } + // }, + // value: '', + // label: 'Addons folder' + // } +} satisfies InputsDefinition; + +type Inputs = ParamsToInput; + +export const exportc3p = async ( + file: string, + { cwd, log, inputs, setOutput, paths, abortSignal, context: ctx }: ActionRunnerData, +) => { + let browserContext: BrowserContext | undefined = undefined; + let browser: any | undefined = undefined; + + const onAbort = () => { + console.error("aborted"); + + browserContext?.close(); + }; + abortSignal.addEventListener("abort", onAbort); + const newInputs = inputs as Inputs; + + // const { addonsFolder } = newInputs + + const { thirdparty, node, pnpm } = paths; + + const browserName: "chromium" | "firefox" | "webkit" = "chromium"; + + const { packageDir: playwrightPkgPath } = await fetchPackage("playwright-core", "1.48.2", { + installDeps: true, + context: ctx, + }); + const playwrightCli = join(playwrightPkgPath, "cli.js"); + const browsersPath = + process.env.PLAYWRIGHT_BROWSERS_PATH || join(thirdparty, "playwright-browsers"); + + process.env.PLAYWRIGHT_BROWSERS_PATH = browsersPath; + + const chromeBinary = join(browsersPath, "chromium-1140", "chrome-linux", "chrome"); + if (existsSync(chromeBinary)) { + log("Browser already exists at", browsersPath, "- skipping download"); + } else { + log("Downloading browser to", browsersPath); + await runWithLiveLogs( + node, + [playwrightCli, "install", browserName], + { + env: { + ...process.env, + PLAYWRIGHT_BROWSERS_PATH: browsersPath, + PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, + }, + cancelSignal: abortSignal, + }, + log, + { + onStdout(data) { + log(data); + }, + onStderr(data) { + log(data); + }, + }, + ); + } + + const require = createRequire(import.meta.url); + const playwrightModule = require(join(playwrightPkgPath, "index.js")); + const playwright = playwrightModule.default || playwrightModule; + + const downloadDir = join(cwd, "playwright"); + + log("Browser downloaded to", downloadDir); + + log("Exporting construct project"); + + console.log("newInputs", newInputs); + + const browserInstance = playwright[browserName]; + + let version = newInputs.version; + // if version is full digit, prepend "r", otherwise, use as is + if (version && /^\d+$/.test(version as string)) { + version = `r${version}`; + } + const headless = newInputs.headless; + + // if (newInputs.customBrowser && !newInputs.customProfile) { + // throw new Error('You must specify a custom profile when using a custom browser') + // } + + // if (!newInputs.customBrowser && newInputs.customProfile) { + // throw new Error('You must specify a custom browser when using a custom profile') + // } + + // if (newInputs.customBrowser && newInputs.customProfile) { + if (newInputs.customProfile) { + const customProfile = join(cwd, "playwright-profile"); + log("Setting up Playwright profile from custom Chrome profile..."); + log(` - Target playwright-profile folder: ${customProfile}`); + + await mkdir(customProfile, { + recursive: true, + }); + + const indexedDbPathSource = join(newInputs.customProfile, "Default", "IndexedDB"); + const indexedDbPathDestination = join(customProfile, "Default", "IndexedDB"); + log(` - Source IndexedDB folder: ${indexedDbPathSource}`); + log(` - Destination IndexedDB folder: ${indexedDbPathDestination}`); + + if (!existsSync(indexedDbPathSource)) { + log( + ` [WARNING] Source IndexedDB directory does not exist: "${indexedDbPathSource}". Verify your custom profile path.`, + ); + } + + await mkdir(indexedDbPathDestination, { recursive: true }); + + const pathsToCopy = [ + "https_editor.construct.net_0.indexeddb.blob", + "https_editor.construct.net_0.indexeddb.leveldb", + "https_preview.construct.net_0.indexeddb.leveldb", + "https_account.construct.net_0.indexeddb.leveldb", + ]; + + for (const p of pathsToCopy) { + const from = join(indexedDbPathSource, p); + const to = join(indexedDbPathDestination, p); + if (existsSync(from)) { + log(` - Copying: "${p}" to "${indexedDbPathDestination}"`); + try { + await cp(from, to, { recursive: true }); + log(` [OK] Successfully copied "${p}"`); + } catch (e) { + log( + ` [ERROR] Failed to copy "${p}":`, + e instanceof Error ? `${e.message}\n${e.stack}` : String(e), + ); + } + } else { + log(` - Skipping: "${p}" (does not exist in source profile)`); + } + } + + browserContext = await browserInstance.launchPersistentContext(customProfile, { + headless: headless as boolean, + locale: "en-US", + recordVideo: isCI + ? { + dir: join(process.cwd(), "playwright"), + } + : undefined, + }); + } else { + browser = await browserInstance.launch({ + headless: headless as boolean, + }); + + browserContext = await browser.newContext({ + locale: "en-US", + recordVideo: isCI + ? { + dir: join(process.cwd(), "playwright"), + } + : undefined, + }); + await browserContext?.clearPermissions(); + } + + if (!browserContext) { + throw new Error("Failed to initialize browser context"); + } + + const page = await browserContext.newPage(); + + page.setDefaultTimeout((newInputs.timeout as number) * 1000); + + // this exact sequn=ence make it work + await page.addInitScript(() => { + // @ts-expect-error dds + delete self.showOpenFilePicker; + }); + page.on("filechooser", (worker) => { + console.log("filechooser created: " + worker.page.name); + }); + // --------------------------------- + + try { + const result = await script( + page, + log, + file, + newInputs.username as string, + newInputs.password as string, + version as string, + downloadDir, + // addonsFolder, + ); + + log("Setting output result to ", result); + + setOutput("folder", result); // deprecated + + setOutput("parentFolder", dirname(result)); + setOutput("zipFile", result); + } catch (e: any) { + log("error, no result, crashed", e); + throw new Error("ConstructExport failed: " + e.message); + } finally { + abortSignal.removeEventListener("abort", onAbort); + if (browserContext) { + await browserContext.close(); + } + if (browser) { + await browser.close(); + } + } +}; + +export const constructVersionValidator = (options: any) => { + void options; + return v.pipe(v.string(), v.regex(/^\d+(-\d+)?$/, "Invalid version")); +}; diff --git a/src/shared/libs/plugin-construct/export.test.ts b/plugins/plugin-construct/src/export.test.ts similarity index 65% rename from src/shared/libs/plugin-construct/export.test.ts rename to plugins/plugin-construct/src/export.test.ts index 913af81f..66a12b43 100644 --- a/src/shared/libs/plugin-construct/export.test.ts +++ b/plugins/plugin-construct/src/export.test.ts @@ -1,9 +1,7 @@ -import { expect, test } from 'vitest' -import { ExportActionRunner } from './export-c3p.js' -import { browserWindow } from '@@/tests/helpers.js' +import { expect, test } from "vitest"; -test('adds 1 + 2 to equal 3', async () => { - const outputs: Record = {} +test("adds 1 + 2 to equal 3", async () => { + const outputs: Record = {}; // await ExportActionRunner({ // inputs: { // password: '123', @@ -32,6 +30,6 @@ test('adds 1 + 2 to equal 3', async () => { // api: undefined, // browserWindow // }) - console.log('outputs', outputs) - expect(true).toBe(true) -}, 120_000) + console.log("outputs", outputs); + expect(true).toBe(true); +}, 120_000); diff --git a/plugins/plugin-construct/src/index.ts b/plugins/plugin-construct/src/index.ts new file mode 100644 index 00000000..71d759c4 --- /dev/null +++ b/plugins/plugin-construct/src/index.ts @@ -0,0 +1,39 @@ +import { createNodeDefinition } from "@pipelab/plugin-core"; +import { exportAction, ExportActionRunner } from "./export-c3p"; +import { exportProjectAction, ExportProjectActionRunner } from "./export-project"; +import { constructVersionValidator } from "./export-shared"; + +export default createNodeDefinition({ + nodes: [ + { + node: exportAction, + runner: ExportActionRunner, + }, + { + node: exportProjectAction, + runner: ExportProjectActionRunner, + }, + ], + validators: [ + // { + // id: 'construct-version', + // description: 'Version must be a valid semver', + // validator: constructVersionValidator + // } + ], + integrations: [ + { + name: "Browser Executable", + fields: [ + { + key: "path", + label: "Browser Executable Path", + type: "file", + placeholder: "e.g., /usr/bin/google-chrome", + }, + ], + }, + ], +}); + +export type { Params as ExportParams } from "./export-c3p"; diff --git a/plugins/plugin-construct/tests/e2e/construct.spec.ts b/plugins/plugin-construct/tests/e2e/construct.spec.ts new file mode 100644 index 00000000..63f6e45d --- /dev/null +++ b/plugins/plugin-construct/tests/e2e/construct.spec.ts @@ -0,0 +1,162 @@ +import { expect, test, describe, afterEach } from "vitest"; +import { readFile, access, mkdir, writeFile } from "node:fs/promises"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { createSandbox, runAction } from "@pipelab/test-utils"; +import { ExportActionRunner } from "../../src/export-c3p"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const fixturesPath = join(__dirname, "fixtures"); + +describe("End-to-End: Construct 3 Export Pipeline", () => { + let sandbox: Awaited>; + + afterEach(async () => { + if (sandbox) { + await sandbox.remove(); + } + }); + + test( + "should run the full C3 export action", + async () => { + sandbox = await createSandbox("c3-pipeline-e2e"); + const fixtures = fixturesPath; + + // 1. Prepare inputs + const testC3pPath = resolve(fixtures, "c3-export/test.c3p"); + + const inputs = { + file: testC3pPath, + version: "stable", + username: "", + password: "", + headless: true, + timeout: 300, + customProfile: undefined, + }; + + // 2. Run the action directly + const result = await runAction(ExportActionRunner, { + inputs, + sandboxPath: sandbox.path, + }); + + // 3. Verification + const outputs = result.outputs; + expect(outputs).toBeDefined(); + + expect(outputs.folder).toEqual(expect.any(String)); + expect(outputs.parentFolder).toEqual(expect.any(String)); + expect(outputs.zipFile).toEqual(expect.any(String)); + + // Verify that the output files/folders actually exist + await expect(access(outputs.folder as string)).resolves.not.toThrow(); + await expect(access(outputs.parentFolder as string)).resolves.not.toThrow(); + await expect(access(outputs.zipFile as string)).resolves.not.toThrow(); + }, + 30 * 60 * 1000, + ); + + test( + "should export with login credentials from env vars", + async () => { + const username = process.env.C3_USERNAME; + const password = process.env.C3_PASSWORD; + + if (!username || !password) { + console.log("Skipping login test: C3_USERNAME and C3_PASSWORD not set"); + return; + } + + sandbox = await createSandbox("c3-login-e2e"); + const fixtures = fixturesPath; + + const testC3pPath = resolve(fixtures, "c3-export/test.c3p"); + + const inputs = { + file: testC3pPath, + version: "stable", + username, + password, + headless: true, + timeout: 300, + customProfile: undefined, + }; + + const result = await runAction(ExportActionRunner, { + inputs, + sandboxPath: sandbox.path, + }); + + const outputs = result.outputs; + expect(outputs).toBeDefined(); + + expect(outputs.folder).toEqual(expect.any(String)); + expect(outputs.parentFolder).toEqual(expect.any(String)); + expect(outputs.zipFile).toEqual(expect.any(String)); + + await expect(access(outputs.folder as string)).resolves.not.toThrow(); + await expect(access(outputs.parentFolder as string)).resolves.not.toThrow(); + await expect(access(outputs.zipFile as string)).resolves.not.toThrow(); + }, + 30 * 60 * 1000, + ); + + test( + "should copy the custom Chrome profile IndexedDB databases to the Playwright profile", + async () => { + sandbox = await createSandbox("c3-profile-clone-e2e"); + const fixtures = fixturesPath; + + // 1. Seed a mock custom Chrome profile with dummy Construct 3 addon databases + const mockProfileDir = join(sandbox.path, "mock-chrome-profile"); + const sourceDbDir = join( + mockProfileDir, + "Default", + "IndexedDB", + "https_editor.construct.net_0.indexeddb.leveldb", + ); + await mkdir(sourceDbDir, { recursive: true }); + await writeFile(join(sourceDbDir, "test-addon-file-clone.txt"), "addon-database-data"); + + // 2. Prepare inputs + const testC3pPath = resolve(fixtures, "c3-export/test.c3p"); + + const inputs = { + file: testC3pPath, + version: "stable", + username: "", + password: "", + headless: true, + timeout: 300, + customProfile: mockProfileDir, + }; + + // 3. Run the action + const result = await runAction(ExportActionRunner, { + inputs, + sandboxPath: sandbox.path, + }); + + // 4. Verification + const outputs = result.outputs; + expect(outputs).toBeDefined(); + + // Assert that the generated folders were cloned to playwright-profile/Default/IndexedDB/ + const clonedEditorDbFile = join( + sandbox.path, + "playwright-profile", + "Default", + "IndexedDB", + "https_editor.construct.net_0.indexeddb.leveldb", + "test-addon-file-clone.txt", + ); + + await expect(access(clonedEditorDbFile)).resolves.not.toThrow(); + expect(await readFile(clonedEditorDbFile, "utf-8")).toBe("addon-database-data"); + }, + 30 * 60 * 1000, + ); +}); diff --git a/tests/e2e/fixtures/c3-export.json b/plugins/plugin-construct/tests/e2e/fixtures/c3-export.json similarity index 99% rename from tests/e2e/fixtures/c3-export.json rename to plugins/plugin-construct/tests/e2e/fixtures/c3-export.json index c7b24684..a252bdc1 100644 --- a/tests/e2e/fixtures/c3-export.json +++ b/plugins/plugin-construct/tests/e2e/fixtures/c3-export.json @@ -48,4 +48,4 @@ ] }, "version": "3.0.0" -} \ No newline at end of file +} diff --git a/tests/e2e/fixtures/c3-export/test.c3p b/plugins/plugin-construct/tests/e2e/fixtures/c3-export/test.c3p similarity index 100% rename from tests/e2e/fixtures/c3-export/test.c3p rename to plugins/plugin-construct/tests/e2e/fixtures/c3-export/test.c3p diff --git a/tests/e2e/fixtures/html-export/index.html b/plugins/plugin-construct/tests/e2e/fixtures/html-export/index.html similarity index 71% rename from tests/e2e/fixtures/html-export/index.html rename to plugins/plugin-construct/tests/e2e/fixtures/html-export/index.html index 522270b0..07e13a7a 100644 --- a/tests/e2e/fixtures/html-export/index.html +++ b/plugins/plugin-construct/tests/e2e/fixtures/html-export/index.html @@ -10,20 +10,20 @@ diff --git a/plugins/plugin-construct/tests/e2e/vitest.config.mts b/plugins/plugin-construct/tests/e2e/vitest.config.mts new file mode 100644 index 00000000..148278ad --- /dev/null +++ b/plugins/plugin-construct/tests/e2e/vitest.config.mts @@ -0,0 +1,20 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + fileParallelism: false, + testTimeout: 1800000, + hookTimeout: 60000, + maxWorkers: 1, + minWorkers: 1, + poolOptions: { + forks: { + singleFork: true, + }, + }, + include: ["**/*.spec.ts"], + root: "tests/e2e", + environment: "node", + env: { NODE_ENV: "development", PIPELAB_DISABLE_HISTORY: "true" }, + }, +}); diff --git a/plugins/plugin-construct/tsconfig.json b/plugins/plugin-construct/tsconfig.json new file mode 100644 index 00000000..bdcaa84d --- /dev/null +++ b/plugins/plugin-construct/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"], + "skipLibCheck": true + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-construct/tsdown.config.ts b/plugins/plugin-construct/tsdown.config.ts new file mode 100644 index 00000000..b3f281ba --- /dev/null +++ b/plugins/plugin-construct/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/assets"], +}); diff --git a/plugins/plugin-core/.oxfmtrc.json b/plugins/plugin-core/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-core/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-core/CHANGELOG.md b/plugins/plugin-core/CHANGELOG.md new file mode 100644 index 00000000..ed0f4cd3 --- /dev/null +++ b/plugins/plugin-core/CHANGELOG.md @@ -0,0 +1,305 @@ +# @pipelab/plugin-core + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.37 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.36 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.35 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.34 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.33 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.32 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.31 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.30 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.29 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.28 + +## 1.0.0-beta.28 + +### Patch Changes + +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.27 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/core-node@1.0.0-beta.26 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.25 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.24 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.23 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.22 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.21 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.20 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.19 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.18 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.17 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.16 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.15 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.14 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.13 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.12 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.11 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/core-node@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/core-node@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- Updated dependencies + - @pipelab/core-node@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/core-node@1.0.0-beta.0 diff --git a/plugins/plugin-core/README.md b/plugins/plugin-core/README.md new file mode 100644 index 00000000..6e5c8936 --- /dev/null +++ b/plugins/plugin-core/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-core + +Base abstractions and utilities for creating Pipelab plugins. Provides the standard interfaces for actions, conditions, and events. diff --git a/plugins/plugin-core/package.json b/plugins/plugin-core/package.json new file mode 100644 index 00000000..a5755530 --- /dev/null +++ b/plugins/plugin-core/package.json @@ -0,0 +1,79 @@ +{ + "name": "@pipelab/plugin-core", + "version": "1.0.0-beta.38", + "description": "Core library and helpers for building Pipelab plugins", + "keywords": [ + "automation", + "pipelab", + "pipelab-plugin", + "pipeline", + "plugin-api", + "plugin-sdk", + "sdk" + ], + "license": "FSL-1.1-MIT", + "author": "CynToolkit", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-core" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "browser": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "build": "tsdown", + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint ." + }, + "dependencies": { + "@pipelab/core-node": "workspace:*", + "@types/node": "^24.12.2", + "archiver": "7.0.1", + "electron": "32.1.2", + "execa": "9.4.1", + "pacote": "21.5.0", + "tar": "6.2.1", + "type-fest": "4.26.1", + "yauzl": "2.10.0", + "zod": "4.3.6" + }, + "devDependencies": { + "@pipelab/constants": "workspace:*", + "@pipelab/shared": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "@types/archiver": "7.0.0", + "@types/pacote": "11.1.8", + "@types/tar": "7.0.87", + "@types/yauzl": "2.10.3", + "tsdown": "0.21.2", + "typescript": "5.9.3" + } +} diff --git a/plugins/plugin-core/src/archive-utils.ts b/plugins/plugin-core/src/archive-utils.ts new file mode 100644 index 00000000..4632f627 --- /dev/null +++ b/plugins/plugin-core/src/archive-utils.ts @@ -0,0 +1,156 @@ +import { mkdir, createReadStream, createWriteStream } from "node:fs"; +import { mkdir as mkdirP } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import zlib from "zlib"; +import tar from "tar"; +import yauzl from "yauzl"; +import archiver from "archiver"; + +/** + * Extracts a .tar.gz archive. + * @param archivePath The full path to the .tar.gz file. + * @param destinationDir The directory to extract contents into. + * @returns A Promise that resolves when extraction is complete. + */ +export async function extractTarGz(archivePath: string, destinationDir: string): Promise { + console.log(`Extracting ${archivePath} to ${destinationDir}...`); + + // Ensure the destination directory exists + await mkdirP(destinationDir, { recursive: true }); + + await tar.x({ + file: archivePath, + cwd: destinationDir, + }); + + console.log("Extraction finished."); +} + +/** + * Extracts a .zip archive. + * @param archivePath The full path to the .zip file. + * @param destinationDir The directory to extract contents into. + * @returns A Promise that resolves when extraction is complete. + */ +export async function extractZip(archivePath: string, destinationDir: string): Promise { + console.log(`Extracting ${archivePath} to ${destinationDir}...`); + + // Ensure the destination directory exists + await mkdirP(destinationDir, { recursive: true }); + + return new Promise((resolve, reject) => { + yauzl.open(archivePath, { lazyEntries: true }, (err, zipfile) => { + if (err || !zipfile) { + return reject(err || new Error("Could not open zip file")); + } + + zipfile.on("error", reject); + + zipfile.readEntry(); // Start reading entries + + zipfile.on("entry", (entry) => { + const entryPath = join(destinationDir, entry.fileName); + + if (/\/$/.test(entry.fileName)) { + // It's a directory + mkdirP(entryPath, { recursive: true }) + .then(() => zipfile.readEntry()) + .catch(reject); + } else { + // It's a file + // Ensure parent directory exists (just in case) + mkdirP(dirname(entryPath), { recursive: true }) + .then(() => { + zipfile.openReadStream(entry, (err, readStream) => { + if (err || !readStream) { + return reject(err || new Error("Could not open read stream")); + } + + readStream.on("error", reject); + const writeStream = createWriteStream(entryPath); + writeStream.on("error", reject); + writeStream.on("close", () => { + zipfile.readEntry(); + }); + readStream.pipe(writeStream); + }); + }) + .catch(reject); + } + }); + + zipfile.on("end", () => { + console.log("Zip extraction finished."); + resolve(); + }); + }); + }); +} + +export const zipFolder = async ( + from: string, + to: string, + log: typeof console.log, + abortSignal?: AbortSignal, +) => { + if (abortSignal?.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + const output = createWriteStream(to); + + const archive = archiver("zip", { + zlib: { level: 9 }, // Sets the compression level. + }); + + return new Promise((resolve, reject) => { + const onAbort = () => { + try { + archive.abort(); + } catch {} + try { + output.destroy(); + } catch {} + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + reject(abortError); + }; + + if (abortSignal) { + abortSignal.addEventListener("abort", onAbort); + } + + output.on("close", function () { + if (abortSignal) { + abortSignal.removeEventListener("abort", onAbort); + } + log(archive.pointer() + " total bytes"); + log("archiver has been finalized and the output file descriptor has closed."); + resolve(to); + }); + + output.on("end", function () { + log("Data has been drained"); + }); + + archive.on("error", function (err) { + if (abortSignal) { + abortSignal.removeEventListener("abort", onAbort); + } + reject(err); + }); + + archive.pipe(output); + + archive.directory(from, false); + + archive.finalize().catch((err) => { + if (abortSignal) { + abortSignal.removeEventListener("abort", onAbort); + } + reject(err); + }); + }); +}; diff --git a/plugins/plugin-core/src/create-plugin.ts b/plugins/plugin-core/src/create-plugin.ts new file mode 100644 index 00000000..f5d4ef76 --- /dev/null +++ b/plugins/plugin-core/src/create-plugin.ts @@ -0,0 +1,8 @@ +export type Plugin = { + nodes: Record; + runtime: () => Promise; +}; + +export const createPlugin = (plugin: Plugin) => { + return plugin; +}; diff --git a/plugins/plugin-core/src/custom-errors.ts b/plugins/plugin-core/src/custom-errors.ts new file mode 100644 index 00000000..9c2ab1f3 --- /dev/null +++ b/plugins/plugin-core/src/custom-errors.ts @@ -0,0 +1,11 @@ +export class ExternalCommandError extends Error { + code: number; + + constructor(message: string, code: number) { + super(message); + + this.code = code; + + Object.setPrototypeOf(this, ExternalCommandError.prototype); + } +} diff --git a/plugins/plugin-core/src/desktop-app.d.ts b/plugins/plugin-core/src/desktop-app.d.ts new file mode 100644 index 00000000..94549ccf --- /dev/null +++ b/plugins/plugin-core/src/desktop-app.d.ts @@ -0,0 +1,52 @@ +declare namespace DesktopApp { + interface Config { + width: number; + height: number; + fullscreen: boolean; + frame: boolean; + transparent: boolean; + toolbar: boolean; + alwaysOnTop: boolean; + name: string; + appBundleId: string; + appCopyright: string; + appVersion: string; + author: string; + description: string; + appCategoryType: string; + icon: string; + enableExtraLogging: boolean; + clearServiceWorkerOnBoot: boolean; + + enableSteamSupport: boolean; + steamGameId: number; + + enableDiscordSupport: boolean; + discordAppId: string; + + ignore: (string | RegExp)[]; + openDevtoolsOnStart: boolean; + + /** + * User-defined npm packages to install (format: "package[@version]") + */ + customPackages?: string[]; + backgroundColor: string; + enableDoctor: boolean; + serverMode: "default" | "customProtocol"; + } + + interface Electron extends Config { + enableInProcessGPU: boolean; + enableDisableRendererBackgrounding: boolean; + customMainCode: string; + electronVersion: string; + disableAsarPackaging: boolean; + forceHighPerformanceGpu: boolean; + clearServiceWorkerOnBoot: boolean; + } + + interface Tauri extends Config { + tauriVersion: string; + } +} diff --git a/plugins/plugin-core/src/fs-utils.ts b/plugins/plugin-core/src/fs-utils.ts new file mode 100644 index 00000000..96c02b16 --- /dev/null +++ b/plugins/plugin-core/src/fs-utils.ts @@ -0,0 +1,55 @@ +import { homedir } from "node:os"; +import { resolve, join } from "node:path"; +import { stat, readdir, writeFile, mkdir } from "node:fs/promises"; + +import { ensure, isPathBlacklisted } from "@pipelab/core-node"; +export { ensure, isPathBlacklisted }; + +/** + * Asserts that a directory is safe to be deleted/cleaned up. + * Throws an error if the directory is protected or is not empty and lacks the Pipelab folder marker. + */ +export async function assertSafeDirectoryCleanup(directoryPath: string): Promise { + if (!directoryPath) return; + const resolvedPath = resolve(directoryPath); + + if (isPathBlacklisted(resolvedPath)) { + throw new Error(`Cannot cleanup/delete protected system or user directory: ${resolvedPath}`); + } + + try { + const destStats = await stat(resolvedPath); + if (destStats.isDirectory()) { + const files = await readdir(resolvedPath); + if (files.length > 0) { + const hasMarker = files.includes(".pipelab"); + if (!hasMarker) { + throw new Error( + `Directory is not empty and was not created by Pipelab: ${resolvedPath}. Aborting to prevent data loss.`, + ); + } + } + } + } catch (e: any) { + if (e.code !== "ENOENT") { + throw e; + } + } +} + +/** + * Creates a hidden Pipelab marker directory with metadata.json at the specified destination path. + */ +export async function writePipelabFolderMarker( + directoryPath: string, + generator = "unknown", +): Promise { + if (!directoryPath) return; + const markerDir = join(directoryPath, ".pipelab"); + await mkdir(markerDir, { recursive: true }); + await writeFile( + join(markerDir, "metadata.json"), + JSON.stringify({ createdBy: generator, timestamp: Date.now() }, null, 2), + "utf-8", + ); +} diff --git a/plugins/plugin-core/src/index.ts b/plugins/plugin-core/src/index.ts new file mode 100644 index 00000000..b8b693b7 --- /dev/null +++ b/plugins/plugin-core/src/index.ts @@ -0,0 +1,10 @@ +export * from "./pipelab"; +export * from "./create-plugin"; +export * from "./utils"; +export * from "./fs-utils"; +export * from "./archive-utils"; +export * from "./custom-errors"; +export * from "./node-utils"; + +export { z as schema } from "zod"; +export type NoData = { [index in string]?: unknown }; diff --git a/plugins/plugin-core/src/node-utils.ts b/plugins/plugin-core/src/node-utils.ts new file mode 100644 index 00000000..3dc62fc3 --- /dev/null +++ b/plugins/plugin-core/src/node-utils.ts @@ -0,0 +1,52 @@ +import { access } from "node:fs/promises"; +import { join } from "node:path"; + +export type OutputRuntimes = "construct" | "godot"; + +const fileExists = async (path: string): Promise => { + try { + await access(path); + return true; + } catch { + return false; + } +}; + +/** + * Detects the runtime of an app folder by checking for specific files. + * This function depends on Node.js APIs and should only be used in Node environments. + */ +export const detectRuntime = async ( + appFolder: string | undefined, +): Promise => { + if (!appFolder) { + return undefined; + } + + const indexExist = await fileExists(join(appFolder, "index.html")); + const swExist = await fileExists(join(appFolder, "sw.js")); + const offlineJSON = await fileExists(join(appFolder, "offline.json")); + const dataJSON = await fileExists(join(appFolder, "data.json")); + const scriptsFolder = await fileExists(join(appFolder, "scripts")); + const workermainJs = await fileExists(join(appFolder, "workermain.js")); + + if (!indexExist) { + throw new Error("The input folder does not contain an index.html file"); + } + + let detectedRuntime: OutputRuntimes | undefined = undefined; + + if (swExist || dataJSON || workermainJs || scriptsFolder) { + detectedRuntime = "construct"; + } + + console.log("Detected runtime", detectedRuntime); + + if (detectedRuntime === "construct" && offlineJSON && swExist) { + throw new Error( + "Construct runtime detected, please disable offline capabilties when using HTML5 export. Offline is already supported by default.", + ); + } + + return detectedRuntime; +}; diff --git a/plugins/plugin-core/src/pipelab.ts b/plugins/plugin-core/src/pipelab.ts new file mode 100644 index 00000000..d169ae29 --- /dev/null +++ b/plugins/plugin-core/src/pipelab.ts @@ -0,0 +1,65 @@ +import type { BrowserWindow } from "electron"; +import type { + Action, + Expression, + Event, + SetOutputActionFn, + SetOutputExpressionFn, + ExtractInputsFromAction, + ExtractInputsFromEvent, + ExtractInputsFromExpression, +} from "@pipelab/shared"; + +export * from "@pipelab/shared"; +import { + type RunnerCallbackFnArgument, + type ActionRunnerData, + type ActionRunner, + type ExpressionRunner, + type EventRunner, + type Runner, + PipelabContext, + usePluginAPI, +} from "@pipelab/core-node"; + +export { + type RunnerCallbackFnArgument, + type ActionRunnerData, + type ActionRunner, + type ExpressionRunner, + type EventRunner, + type Runner, + PipelabContext, + usePluginAPI, +}; + +export const createActionRunner = ( + runner: (data: ActionRunnerData) => Promise, +) => runner; + +export const createExpressionRunner = ( + runner: (data: { + log: typeof console.log; + setOutput: SetOutputExpressionFn; + inputs: ExtractInputsFromExpression; + setMeta: (callback: (data: EXPRESSION["meta"]) => EXPRESSION["meta"]) => void; + meta: EXPRESSION["meta"]; + cwd: string; + context: PipelabContext; + }) => Promise, +) => runner; + +export const createEventRunner = ( + runner: (data: { + log: typeof console.log; + inputs: ExtractInputsFromEvent; + setMeta: (callback: (data: EVENT["meta"]) => EVENT["meta"]) => void; + meta: EVENT["meta"]; + cwd: string; + context: PipelabContext; + }) => Promise, +) => runner; + +export const sleep = (duration: number) => { + return new Promise((resolve) => setTimeout(resolve, duration)); +}; diff --git a/plugins/plugin-core/src/utils.ts b/plugins/plugin-core/src/utils.ts new file mode 100644 index 00000000..b4ff8e82 --- /dev/null +++ b/plugins/plugin-core/src/utils.ts @@ -0,0 +1,26 @@ +import { Options, Subprocess } from "execa"; +export { + fetchPackage, + fetchPipelabAsset, + fetchPipelabPlugin, + fetchPipelabCli, + runPnpm, + downloadFile, + runWithLiveLogs, +} from "@pipelab/core-node"; + +/** + * Re-exporting hooks type for backward compatibility + */ +export type { DownloadHooks as Hooks } from "@pipelab/core-node"; + +// Keep runtime-only utilities that don't depend on complex engine state +export const fileExists = async (path: string): Promise => { + try { + const { access } = await import("node:fs/promises"); + await access(path); + return true; + } catch { + return false; + } +}; diff --git a/plugins/plugin-core/tsconfig.json b/plugins/plugin-core/tsconfig.json new file mode 100644 index 00000000..29b49c3f --- /dev/null +++ b/plugins/plugin-core/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"] + }, + "include": ["src"], + "references": [ + { + "path": "../../packages/core-node" + }, + { + "path": "../../packages/constants" + }, + { + "path": "../../packages/shared" + } + ] +} diff --git a/plugins/plugin-core/tsdown.config.ts b/plugins/plugin-core/tsdown.config.ts new file mode 100644 index 00000000..dfbf1dde --- /dev/null +++ b/plugins/plugin-core/tsdown.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, +}); diff --git a/plugins/plugin-discord/.oxfmtrc.json b/plugins/plugin-discord/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-discord/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-discord/CHANGELOG.md b/plugins/plugin-discord/CHANGELOG.md new file mode 100644 index 00000000..96a00dfb --- /dev/null +++ b/plugins/plugin-discord/CHANGELOG.md @@ -0,0 +1,338 @@ +# @pipelab/plugin-discord + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + - @pipelab/shared@1.0.0-beta.32 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + - @pipelab/shared@1.0.0-beta.31 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + - @pipelab/shared@1.0.0-beta.30 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + - @pipelab/shared@1.0.0-beta.29 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + - @pipelab/shared@1.0.0-beta.28 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + - @pipelab/shared@1.0.0-beta.27 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + - @pipelab/shared@1.0.0-beta.26 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + - @pipelab/shared@1.0.0-beta.25 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + - @pipelab/shared@1.0.0-beta.24 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + - @pipelab/shared@1.0.0-beta.23 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- Updated dependencies + - @pipelab/shared@1.0.0-beta.22 + - @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + - @pipelab/shared@1.0.0-beta.21 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + - @pipelab/shared@1.0.0-beta.20 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + - @pipelab/shared@1.0.0-beta.19 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + - @pipelab/shared@1.0.0-beta.18 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + - @pipelab/shared@1.0.0-beta.17 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + - @pipelab/shared@1.0.0-beta.16 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + - @pipelab/shared@1.0.0-beta.15 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + - @pipelab/shared@1.0.0-beta.14 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + - @pipelab/shared@1.0.0-beta.13 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + - @pipelab/shared@1.0.0-beta.12 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + - @pipelab/shared@1.0.0-beta.11 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + - @pipelab/shared@1.0.0-beta.10 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + - @pipelab/shared@1.0.0-beta.9 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + - @pipelab/shared@1.0.0-beta.8 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + - @pipelab/shared@1.0.0-beta.7 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + - @pipelab/shared@1.0.0-beta.6 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + - @pipelab/shared@1.0.0-beta.5 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + - @pipelab/shared@1.0.0-beta.4 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + - @pipelab/shared@1.0.0-beta.3 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + - @pipelab/shared@1.0.0-beta.2 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + - @pipelab/shared@1.0.0-beta.1 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 + - @pipelab/shared@1.0.0-beta.0 diff --git a/plugins/plugin-discord/README.md b/plugins/plugin-discord/README.md new file mode 100644 index 00000000..5f34044d --- /dev/null +++ b/plugins/plugin-discord/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-discord + +Pipelab plugin for Discord integration and Nitro App management. diff --git a/plugins/plugin-discord/package.json b/plugins/plugin-discord/package.json new file mode 100644 index 00000000..de76846a --- /dev/null +++ b/plugins/plugin-discord/package.json @@ -0,0 +1,67 @@ +{ + "name": "@pipelab/plugin-discord", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for Discord Rich Presence and notifications", + "keywords": [ + "automation", + "discord", + "game-development", + "notifications", + "pipelab", + "pipelab-plugin", + "rich-presence" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-discord" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown", + "test": "vitest run" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "@pipelab/shared": "workspace:*", + "@types/node": "^24.12.2", + "electron": "32.1.2", + "ts-deepmerge": "7.0.1", + "untun": "0.1.3" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + }, + "pipelab": { + "name": "Discord", + "description": "Pipelab plugin for Discord Rich Presence and notifications", + "icon": "./dist/public/discord.webp" + } +} diff --git a/plugins/plugin-discord/src/declarations.d.ts b/plugins/plugin-discord/src/declarations.d.ts new file mode 100644 index 00000000..97847104 --- /dev/null +++ b/plugins/plugin-discord/src/declarations.d.ts @@ -0,0 +1,3 @@ +/// +declare module "*.webp"; +declare module "serve-handler"; diff --git a/plugins/plugin-discord/src/discord.ts b/plugins/plugin-discord/src/discord.ts new file mode 100644 index 00000000..59071532 --- /dev/null +++ b/plugins/plugin-discord/src/discord.ts @@ -0,0 +1,341 @@ +import { + ActionRunnerData, + createAction, + createPathParam, + createStringParam, + detectRuntime, + InputsDefinition, + OutputsDefinition, + runWithLiveLogs, + fetchPipelabAsset, + runPnpm, +} from "@pipelab/plugin-core"; +import { dirname, join, basename, delimiter } from "node:path"; +import { cp, readFile, writeFile } from "node:fs/promises"; +import { platform as osPlatform, arch as osArch } from "node:os"; +import { kebabCase } from "change-case"; +import { createServer } from "node:http"; +import serve from "serve-handler"; +import { startTunnel } from "untun"; + +export const IDPackage = "discord:package"; +export const IDPreview = "discord:preview"; + +const paramsInputFolder = { + "input-folder": createPathParam("", { + label: "Folder to package", + required: true, + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), +} satisfies InputsDefinition; + +// const paramsInputURL = { +// 'input-url': createStringParam('', { +// label: 'URL to preview', +// required: true +// }) +// } satisfies InputsDefinition + +export const configureParams = { + name: createStringParam("Pipelab", { + label: "Application name", + description: "The name of the application", + required: true, + }), +} satisfies InputsDefinition; + +const outputs = { + outputDir: { + label: "Output folder", + value: "", + description: "The folder where the packaged application is located", + }, +} satisfies OutputsDefinition; + +export const createPackageProps = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, + advanced?: boolean, + deprecated?: boolean, + deprecatedMessage?: string, + disabled?: false, + updateAvailable?: boolean, +) => { + return createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + advanced, + deprecated, + deprecatedMessage, + disabled, + updateAvailable, + params: { + ...paramsInputFolder, + ...configureParams, + }, + outputs: { + outputDir: outputs.outputDir, + }, + }); +}; + +export const createPreviewProps = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, +) => + createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + params: { + ...paramsInputFolder, + ...configureParams, + customHostname: createStringParam("", { + required: false, + label: "Custom hostname", + description: "The hostname to use for the preview", + }), + }, + outputs: { + // ...outputs.outputDir + }, + }); + +const createAppServer = async (folder: string) => { + try { + const server = createServer(); + + server.on("request", (req, res) => { + return serve(req, res, { + maxAge: 0, + public: folder, + headers: { + "bypass-tunnel-reminder": "false", + }, + }); + }); + + const listen = async () => { + return new Promise((resolve, reject) => { + server.listen(40400, "127.0.0.1", () => { + return resolve(server); + }); + }); + }; + + await listen(); + console.log("listening2"); + console.log("address", server.address); + const addressRes = server.address(); + console.log("addressRes", addressRes); + if (addressRes && typeof addressRes !== "string") { + return { port: addressRes.port }; + } + throw new Error("Unable to bind server: adress is not an object"); + } catch (e) { + console.error(e); + throw e; + } +}; + +export const waitForAbort = (signal: AbortSignal): Promise => { + return new Promise((resolve, reject) => { + if (signal.aborted) { + return resolve(); // Already aborted + } + + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + resolve(); + }; + + signal.addEventListener("abort", onAbort); + }); +}; + +export const discord = async ( + action: "package" | "preview", + appFolder: string | undefined, + { + cwd, + log, + inputs, + setOutput, + paths, + abortSignal, + context, + }: + | ActionRunnerData> + | ActionRunnerData>, + completeConfiguration: DesktopApp.Config, +): Promise<{ folder: string; binary: string | undefined } | undefined> => { + console.log("appFolder", appFolder); + + log("Building discord"); + + const runtime = await detectRuntime(appFolder); + + const { modules, cache, node } = paths; + + const destinationFolder = join(cwd, "build"); + + const rawAssetFolder = await fetchPipelabAsset("@pipelab/asset-discord", "^1.0.0", { context }); + const templateFolder = join(rawAssetFolder, "template"); + + // copy template to destination + await cp(templateFolder, destinationFolder, { + recursive: true, + filter: (src) => { + log("src", src); + // log('dest', dest) + // TODO: support other oses + return ( + basename(src) !== "node_modules" && + !src.includes(".nitro") && + !src.includes(".output") && + !src.includes(".env") + ); + }, + }); + + const placeAppFolder = join(destinationFolder, "src", "app"); + + // if input is folder, copy folder to destination + if (appFolder) { + // copy app to template + await cp(appFolder, placeAppFolder, { recursive: true }); + } + + writeFile( + join(destinationFolder, ".env"), + `DISCORD_CLIENT_ID=1357217738241736724 +DISCORD_CLIENT_SECRET=yJ4vRnzDtKAqg2Le3_Sap2CqHybkTp2U`, + "utf8", + ); + + const sanitizedName = kebabCase(completeConfiguration.name); + + // package.json update + // const pkgJSONPath = join(destinationFolder, 'package.json') + // const pkgJSONContent = await readFile(pkgJSONPath, 'utf8') + // const pkgJSON = JSON.parse(pkgJSONContent) + // log('Setting name to', sanitizedName) + // pkgJSON.name = sanitizedName + // log('Setting productName to', completeConfiguration.name) + // pkgJSON.productName = completeConfiguration.name + // await writeFile(pkgJSONPath, JSON.stringify(pkgJSON, null, 2)) + + // discord.conf.json update + // const tauriConfJSONPath = join(destinationFolder, 'src-discord', 'discord.conf.json') + // const tauriConfJSONContent = await readFile(tauriConfJSONPath, 'utf8') + // const tauriConfJSON = JSON.parse(tauriConfJSONContent) + // log('Setting productName to', completeConfiguration.name) + // tauriConfJSON.productName = completeConfiguration.name + // log('Setting version to', completeConfiguration.appVersion) + // tauriConfJSON.version = completeConfiguration.appVersion + // log('Setting identifier to', completeConfiguration.appBundleId) + // tauriConfJSON.identifier = completeConfiguration.appBundleId + // log('Setting build.devUrl to', appFolder) + // tauriConfJSON.build.devUrl = appFolder + // await writeFile(tauriConfJSONPath, JSON.stringify(tauriConfJSON, null, 2)) + + log("Installing packages"); + const { all: installOut } = await runPnpm(destinationFolder, { + args: ["install", "--prefer-offline"], + signal: abortSignal, + context, + }); + if (installOut) log(installOut); + + // override discord version + // if (completeConfiguration.electronVersion && completeConfiguration.electronVersion !== '') { + // log(`Installing discord@${completeConfiguration.electronVersion}`) + // await runWithLiveLogs( + // process.execPath, + // [pnpm, 'install', `discord@${completeConfiguration.electronVersion}`, '--prefer-offline'], + // { + // cwd: destinationFolder, + // env: { + // // DEBUG: '*', + // PNPM_HOME: pnpmHome + // }, + // cancelSignal: abortSignal + // }, + // log, + // { + // onStderr(data) { + // log(data) + // }, + // onStdout(data) { + // log(data) + // } + // } + // ) + // } + + try { + if (action === "preview") { + const port = 14141; + + const modulesPath = modules; + const nitro = join(modulesPath, "nitropack", "dist", "cli", "index.mjs"); + + console.log("nitro", nitro); + + await Promise.allSettled([ + runPnpm(destinationFolder, { + args: ["dlx", "nitropack", "dev"], + extraEnv: { + PORT: port.toString(), + }, + signal: abortSignal, + context, + }).then(({ all }) => { + if (all) log(all); + }), + (async () => { + const tunnel = await startTunnel({ port, acceptCloudflareNotice: true }); + console.log("tunnel", tunnel); + if (!tunnel) { + throw new Error("Failed to start tunnel"); + } + const url = await tunnel.getURL(); + console.log("Public URL:", url); + })(), + ]); + } else { + throw new Error("TODO"); + } + + return undefined; + } catch (e) { + if (e instanceof Error) { + if (e.name === "RequestError") { + log("Request error"); + } + if (e.name === "RequestError") { + log("Request error"); + } + } + log(e); + return undefined; + } +}; diff --git a/plugins/plugin-discord/src/index.ts b/plugins/plugin-discord/src/index.ts new file mode 100644 index 00000000..a408dd50 --- /dev/null +++ b/plugins/plugin-discord/src/index.ts @@ -0,0 +1,48 @@ +import { previewRunner } from "./preview"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; +import { createPackageProps, createPreviewProps, IDPreview, IDPackage } from "./discord"; +import { packageV2Runner } from "./package"; + +export default createNodeDefinition({ + nodes: [ + { + node: createPackageProps( + IDPackage, + "Package as Discord Activity", + "Package your app as a Discord Activity", + "", + "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", + false, + false, + undefined, + false, + false, + ), + runner: packageV2Runner, + }, + { + node: createPreviewProps( + IDPreview, + "Preview Discord Acitivity app", + "Package and preview your app as a Discord Activity", + "", + "`Preview app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", + ), + runner: previewRunner, + }, + ], + integrations: [ + { + name: "Discord Connection", + fields: [ + { + key: "apiKey", + label: "Webhook URL", + type: "text", + placeholder: "https://discord.com/api/webhooks/...", + }, + ], + }, + ], +}); diff --git a/src/shared/libs/plugin-tauri/make.spec.ts b/plugins/plugin-discord/src/make.spec.ts similarity index 55% rename from src/shared/libs/plugin-tauri/make.spec.ts rename to plugins/plugin-discord/src/make.spec.ts index 79fe60e2..faa9fc10 100644 --- a/src/shared/libs/plugin-tauri/make.spec.ts +++ b/plugins/plugin-discord/src/make.spec.ts @@ -1,9 +1,7 @@ -import { expect, test, vi } from 'vitest' -import { makeRunner } from './make.js' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { type fs } from 'memfs' -import { browserWindow } from '@@/tests/helpers.js' +import { expect, test, vi } from "vitest"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { type fs } from "memfs"; // ... @@ -13,17 +11,17 @@ import { browserWindow } from '@@/tests/helpers.js' // return memfs.fs.promises // }) -test('adds 1 + 2 to equal 3', async () => { - const outputs: Record = {} +test("adds 1 + 2 to equal 3", async () => { + const outputs: Record = {}; - const id = 'ut-electron-build' - const tmpDir = join(tmpdir(), id) + const id = "ut-electron-build"; + const tmpDir = join(tmpdir(), id); - console.log('tmpDir', tmpDir) + console.log("tmpDir", tmpDir); - const inputFolder = join(process.cwd(), 'fixtures', 'build') + const inputFolder = join(process.cwd(), "fixtures", "build"); - console.log('inputFolder', inputFolder) + console.log("inputFolder", inputFolder); // await makeRunner({ // inputs: { @@ -52,6 +50,6 @@ test('adds 1 + 2 to equal 3', async () => { // api: undefined, // browserWindow // }) - console.log('outputs', outputs) - expect(true).toBe(true) -}, 120_000) + console.log("outputs", outputs); + expect(true).toBe(true); +}, 120_000); diff --git a/plugins/plugin-discord/src/package.ts b/plugins/plugin-discord/src/package.ts new file mode 100644 index 00000000..41af21ce --- /dev/null +++ b/plugins/plugin-discord/src/package.ts @@ -0,0 +1,37 @@ +import { createActionRunner, fetchPipelabAsset } from "@pipelab/plugin-core"; +import { createPackageProps, discord } from "./discord"; +import { merge } from "ts-deepmerge"; +import { defaultTauriConfig } from "./utils"; +import { basename, join } from "path"; +import { cp } from "fs/promises"; + +export const packageV2Runner = createActionRunner>( + async ({ inputs, cwd, paths, log, setOutput, context }) => { + const appFolder = inputs["input-folder"]; + + const { cache, node, pnpm } = paths; + const destinationFolder = join(cwd); + const rawAssetFolder = await fetchPipelabAsset("@pipelab/asset-discord", "^1.0.0", { context }); + const templateFolder = join(rawAssetFolder, "template"); + + // copy template to destination + await cp(templateFolder, destinationFolder, { + recursive: true, + filter: (src) => { + log("src", src); + // log('dest', dest) + // TODO: support other oses + return basename(src) !== "node_modules" && !src.includes(".nitro") && !src.includes("dist"); + }, + }); + const placeAppFolder = join(destinationFolder, "server", "public", ".proxy"); + if (appFolder) { + // copy app to template + await cp(appFolder, placeAppFolder, { recursive: true }); + } + + log("destinationFolder", destinationFolder); + + setOutput("outputDir", destinationFolder); + }, +); diff --git a/plugins/plugin-discord/src/preview.ts b/plugins/plugin-discord/src/preview.ts new file mode 100644 index 00000000..3cca838c --- /dev/null +++ b/plugins/plugin-discord/src/preview.ts @@ -0,0 +1,25 @@ +import { createActionRunner } from "@pipelab/plugin-core"; +import { createPreviewProps, discord } from "./discord"; +import { merge } from "ts-deepmerge"; + +export const previewRunner = createActionRunner>( + async (options) => { + const inputFolder = options.inputs["input-folder"]; + if (inputFolder === "") { + throw new Error("URL can't be empty"); + } + + // if (!options.inputs.configuration) { + // throw new Error('Missing tauri configuration') + // } + + const completeConfiguration = merge({}, { + ...options.inputs, + } satisfies any) as any; + + console.log("completeConfiguration", completeConfiguration); + + await discord("preview", inputFolder, options, completeConfiguration); + return; + }, +); diff --git a/src/shared/libs/plugin-discord/public/discord.webp b/plugins/plugin-discord/src/public/discord.webp similarity index 100% rename from src/shared/libs/plugin-discord/public/discord.webp rename to plugins/plugin-discord/src/public/discord.webp diff --git a/plugins/plugin-discord/src/utils.ts b/plugins/plugin-discord/src/utils.ts new file mode 100644 index 00000000..9520f0c2 --- /dev/null +++ b/plugins/plugin-discord/src/utils.ts @@ -0,0 +1,29 @@ +export const defaultTauriConfig = { + alwaysOnTop: false, + appBundleId: "com.pipelab.app", + appCategoryType: "", + appCopyright: "Copyright © 2024 Pipelab", + appVersion: "1.0.0", + author: "Pipelab", + description: "A simple Electron application", + tauriVersion: "", + enableExtraLogging: false, + clearServiceWorkerOnBoot: false, + frame: true, + fullscreen: false, + icon: "", + height: 600, + name: "Pipelab", + toolbar: true, + transparent: false, + width: 800, + enableSteamSupport: false, + steamGameId: 480, + enableDiscordSupport: false, + discordAppId: "", + ignore: [] as string[], + backgroundColor: "#FFF", + openDevtoolsOnStart: false, + enableDoctor: false, + serverMode: "default" as const, +} satisfies DesktopApp.Tauri; diff --git a/plugins/plugin-discord/tsconfig.json b/plugins/plugin-discord/tsconfig.json new file mode 100644 index 00000000..8948bb7e --- /dev/null +++ b/plugins/plugin-discord/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"], + "skipLibCheck": true + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + }, + { + "path": "../../packages/shared" + } + ] +} diff --git a/plugins/plugin-discord/tsdown.config.ts b/plugins/plugin-discord/tsdown.config.ts new file mode 100644 index 00000000..327c61b7 --- /dev/null +++ b/plugins/plugin-discord/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/public"], +}); diff --git a/plugins/plugin-electron/.oxfmtrc.json b/plugins/plugin-electron/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-electron/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-electron/CHANGELOG.md b/plugins/plugin-electron/CHANGELOG.md new file mode 100644 index 00000000..ca23c492 --- /dev/null +++ b/plugins/plugin-electron/CHANGELOG.md @@ -0,0 +1,398 @@ +# @pipelab/plugin-electron + +## 1.0.0-beta.42 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + - @pipelab/constants@1.0.0-beta.33 + - @pipelab/shared@1.0.0-beta.32 + +## 1.0.0-beta.41 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + - @pipelab/constants@1.0.0-beta.32 + - @pipelab/shared@1.0.0-beta.31 + +## 1.0.0-beta.40 + +### Patch Changes + +- fix electron copy + +## 1.0.0-beta.39 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + - @pipelab/constants@1.0.0-beta.31 + - @pipelab/shared@1.0.0-beta.30 + +## 1.0.0-beta.38 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + - @pipelab/constants@1.0.0-beta.30 + - @pipelab/shared@1.0.0-beta.29 + +## 1.0.0-beta.37 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + - @pipelab/constants@1.0.0-beta.29 + - @pipelab/shared@1.0.0-beta.28 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + - @pipelab/constants@1.0.0-beta.28 + - @pipelab/shared@1.0.0-beta.27 + +## 1.0.0-beta.34 + +### Patch Changes + +- fix shim + +## 1.0.0-beta.33 + +### Patch Changes + +- fix pnpm shimming + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + - @pipelab/constants@1.0.0-beta.27 + - @pipelab/shared@1.0.0-beta.26 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + - @pipelab/constants@1.0.0-beta.26 + - @pipelab/shared@1.0.0-beta.25 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + - @pipelab/constants@1.0.0-beta.25 + - @pipelab/shared@1.0.0-beta.24 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + - @pipelab/constants@1.0.0-beta.24 + - @pipelab/shared@1.0.0-beta.23 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- Updated dependencies + - @pipelab/shared@1.0.0-beta.22 + - @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + - @pipelab/constants@1.0.0-beta.23 + - @pipelab/shared@1.0.0-beta.21 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + - @pipelab/constants@1.0.0-beta.22 + - @pipelab/shared@1.0.0-beta.20 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + - @pipelab/constants@1.0.0-beta.21 + - @pipelab/shared@1.0.0-beta.19 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + - @pipelab/constants@1.0.0-beta.20 + - @pipelab/shared@1.0.0-beta.18 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + - @pipelab/constants@1.0.0-beta.19 + - @pipelab/shared@1.0.0-beta.17 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + - @pipelab/constants@1.0.0-beta.18 + - @pipelab/shared@1.0.0-beta.16 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + - @pipelab/constants@1.0.0-beta.17 + - @pipelab/shared@1.0.0-beta.15 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + - @pipelab/constants@1.0.0-beta.16 + - @pipelab/shared@1.0.0-beta.14 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + - @pipelab/constants@1.0.0-beta.15 + - @pipelab/shared@1.0.0-beta.13 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + - @pipelab/constants@1.0.0-beta.14 + - @pipelab/shared@1.0.0-beta.12 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + - @pipelab/constants@1.0.0-beta.13 + - @pipelab/shared@1.0.0-beta.11 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + - @pipelab/constants@1.0.0-beta.12 + - @pipelab/shared@1.0.0-beta.10 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + - @pipelab/constants@1.0.0-beta.11 + - @pipelab/shared@1.0.0-beta.9 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + - @pipelab/constants@1.0.0-beta.10 + - @pipelab/shared@1.0.0-beta.8 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + - @pipelab/constants@1.0.0-beta.9 + - @pipelab/shared@1.0.0-beta.7 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + - @pipelab/constants@1.0.0-beta.8 + - @pipelab/shared@1.0.0-beta.6 + +## 1.0.0-beta.9 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.7 + - @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + - @pipelab/constants@1.0.0-beta.6 + - @pipelab/shared@1.0.0-beta.5 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + - @pipelab/constants@1.0.0-beta.5 + - @pipelab/shared@1.0.0-beta.4 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + - @pipelab/constants@1.0.0-beta.4 + - @pipelab/shared@1.0.0-beta.3 + +## 1.0.0-beta.4 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.3 + - @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + - @pipelab/constants@1.0.0-beta.2 + - @pipelab/shared@1.0.0-beta.2 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + - @pipelab/constants@1.0.0-beta.1 + - @pipelab/shared@1.0.0-beta.1 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 + - @pipelab/constants@1.0.0-beta.0 + - @pipelab/shared@1.0.0-beta.0 diff --git a/plugins/plugin-electron/README.md b/plugins/plugin-electron/README.md new file mode 100644 index 00000000..54158c31 --- /dev/null +++ b/plugins/plugin-electron/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-electron + +Pipelab plugin for building and packaging Electron applications. diff --git a/plugins/plugin-electron/package.json b/plugins/plugin-electron/package.json new file mode 100644 index 00000000..54360ede --- /dev/null +++ b/plugins/plugin-electron/package.json @@ -0,0 +1,75 @@ +{ + "name": "@pipelab/plugin-electron", + "version": "1.0.0-beta.42", + "description": "Pipelab plugin for packaging apps with Electron", + "keywords": [ + "automation", + "cross-platform", + "desktop-app", + "electron", + "nwjs", + "packaging", + "pipelab", + "pipelab-plugin", + "pipeline" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-electron" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown", + "test": "vitest run -c tests/e2e/vitest.config.mts" + }, + "dependencies": { + "@pipelab/constants": "workspace:*", + "@pipelab/plugin-core": "workspace:*", + "@pipelab/shared": "workspace:*", + "@types/node": "^24.12.2", + "electron": "32.1.2", + "ts-deepmerge": "7.0.1" + }, + "devDependencies": { + "@pipelab/test-utils": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + }, + "pipelab": { + "name": "Electron", + "description": "Pipelab plugin for packaging apps with Electron", + "icon": "./dist/public/electron.webp" + }, + "test": { + "env": { + "NODE_ENV": "development" + } + } +} diff --git a/plugins/plugin-electron/src/configure.ts b/plugins/plugin-electron/src/configure.ts new file mode 100644 index 00000000..aa5b570e --- /dev/null +++ b/plugins/plugin-electron/src/configure.ts @@ -0,0 +1,23 @@ +import { createAction, createActionRunner } from "@pipelab/plugin-core"; +import { configureParams } from "./forge"; + +export const props = createAction({ + id: "electron:configure", + description: "Configure electron", + displayString: "'Configure Electron'", + icon: "", + meta: {}, + name: "Configure Electron", + advanced: true, + outputs: { + configuration: { + label: "Configuration", + value: {} as Partial, + }, + }, + params: configureParams, +}); + +export const configureRunner = createActionRunner(async ({ setOutput, inputs }) => { + setOutput("configuration", inputs); +}); diff --git a/plugins/plugin-electron/src/declarations.d.ts b/plugins/plugin-electron/src/declarations.d.ts new file mode 100644 index 00000000..9b40a85c --- /dev/null +++ b/plugins/plugin-electron/src/declarations.d.ts @@ -0,0 +1,2 @@ +/// +declare module "*.webp"; diff --git a/src/shared/libs/plugin-tauri/fixtures/build/index.html b/plugins/plugin-electron/src/fixtures/build/index.html similarity index 54% rename from src/shared/libs/plugin-tauri/fixtures/build/index.html rename to plugins/plugin-electron/src/fixtures/build/index.html index 22946b96..869fb664 100644 --- a/src/shared/libs/plugin-tauri/fixtures/build/index.html +++ b/plugins/plugin-electron/src/fixtures/build/index.html @@ -1,11 +1,11 @@ - + - - - + + + Document - - + +

Hello

- - \ No newline at end of file + + diff --git a/plugins/plugin-electron/src/forge.ts b/plugins/plugin-electron/src/forge.ts new file mode 100644 index 00000000..083d0c1b --- /dev/null +++ b/plugins/plugin-electron/src/forge.ts @@ -0,0 +1,895 @@ +import { getBinName, outFolderName } from "@pipelab/constants"; +import { + ActionRunnerData, + createAction, + createArray, + createBooleanParam, + createColorPicker, + createNumberParam, + createPathParam, + createStringParam, + detectRuntime, + InputsDefinition, + OutputsDefinition, + runPnpm, + runWithLiveLogs, + fetchPipelabAsset, +} from "@pipelab/plugin-core"; + +import { dirname, join, basename, delimiter } from "node:path"; +import { cp, readFile, writeFile, rm, mkdir, appendFile } from "node:fs/promises"; +import { existsSync } from "node:fs"; +import { platform as osPlatform, arch as osArch } from "node:os"; +import { kebabCase } from "change-case"; +import semver from "semver"; +import { pathToFileURL } from "node:url"; + +// TODO: https://js.electronforge.io/modules/_electron_forge_core.html + +export const IDMake = "electron:make"; +export const IDPackage = "electron:package"; +export const IDPackageV2 = "electron:package:v2"; +export const IDPackageV3 = "electron:package:v3"; +export const IDPreview = "electron:preview"; + +const paramsInputFolder = { + "input-folder": createPathParam("", { + label: "Folder to package", + required: true, + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), +} satisfies InputsDefinition; + +const paramsInputURL = { + "input-url": createStringParam("", { + label: "URL to preview", + required: true, + }), +} satisfies InputsDefinition; + +const params = { + arch: { + value: "" as NodeJS.Architecture | "", // MakeOptions['arch'], + label: "Architecture", + required: false, + control: { + type: "select", + options: { + placeholder: "Architecture", + options: [ + { + label: "Older PCs (ia32)", + value: "ia32", + }, + { + label: "Modern PCs (x64)", + value: "x64", + }, + { + label: "Older Mobile/Pi (armv7l)", + value: "armv7l", + }, + { + label: "New Mobile/Apple Silicon (arm64)", + value: "arm64", + }, + { + label: "Mac Universal (universal)", + value: "universal", + }, + { + label: "Special Systems (mips64el)", + value: "mips64el", + }, + ], + }, + }, + }, + platform: { + value: "" as NodeJS.Platform | "", // MakeOptions['platform'], + label: "Platform", + required: false, + control: { + type: "select", + options: { + placeholder: "Platform", + options: [ + { + label: "Windows (win32)", + value: "win32", + }, + { + label: "macOS (darwin)", + value: "darwin", + }, + { + label: "Linux (linux)", + value: "linux", + }, + ], + }, + }, + }, + configuration: { + label: "Electron configuration", + value: undefined as Partial | undefined, + required: true, + control: { + type: "json", + }, + }, +} satisfies InputsDefinition; + +export const configureParams = { + name: createStringParam("Pipelab", { + label: "Application name", + description: "The name of the application", + required: true, + }), + appBundleId: createStringParam("com.pipelab.app", { + label: "Application bundle ID", + description: "The bundle ID of the application", + required: true, + }), + appCopyright: createStringParam("Copyright © 2024 Pipelab", { + label: "Application copyright", + description: "The copyright of the application", + required: false, + }), + appVersion: createStringParam("1.0.0", { + label: "Application version", + description: "The version of the application", + required: true, + }), + icon: createPathParam("", { + label: "Application icon", + description: "The icon of the application. macOS: .icns. Windows: .ico", + required: false, + control: { + type: "path", + options: { + filters: [ + { name: "Image", extensions: ["png", "jpg", "jpeg", "gif", "bmp", "ico", "icns"] }, + ], + }, + label: "Path to an image file", + }, + }), + author: createStringParam("Pipelab", { + label: "Application author", + description: "The author of the application", + required: true, + }), + description: createStringParam("A simple Electron application", { + label: "Application description", + description: "The description of the application", + required: false, + }), + customPackages: createArray( + `[ + // e.g. "lodash" or "express@4.17.1" +]`, + { + label: "Custom npm packages", + description: + 'A list of additional npm packages to install (format: "package" or "package@version")', + required: false, + control: { + type: "array", + options: { + kind: "text", + }, + }, + }, + ), + + appCategoryType: createStringParam("public.app-category.developer-tools", { + platforms: ["darwin"], + label: "Application category type", + description: "The category type of the application", + required: false, + }), + + // window + width: createNumberParam(800, { + label: "Window width", + description: "The width of the window", + required: false, + }), + height: createNumberParam(600, { + label: "Window height", + description: "The height of the window", + required: false, + }), + fullscreen: { + label: "Fullscreen", + value: false, + description: "Whether to start the application in fullscreen mode", + required: false, + control: { + type: "boolean", + }, + }, + frame: { + label: "Frame", + value: true, + description: "Whether to show the window frame", + required: false, + control: { + type: "boolean", + }, + }, + transparent: { + label: "Transparent", + value: false, + description: "Whether to make the window transparent", + required: false, + control: { + type: "boolean", + }, + }, + toolbar: { + label: "Toolbar", + value: true, + description: "Whether to show the toolbar", + required: false, + control: { + type: "boolean", + }, + }, + alwaysOnTop: { + label: "Always on top", + value: false, + description: "Whether to always keep the window on top", + required: false, + control: { + type: "boolean", + }, + }, + + backgroundColor: createColorPicker("#ffffff", { + label: "Background Color", + description: "The background color of the window", + required: false, + }), + + electronVersion: createStringParam("", { + label: "Electron version", + description: + "The version of Electron to use. If no version specified, it will use the latest one.", + required: false, + }), + customMainCode: createPathParam("", { + required: false, + label: "Custom main code", + control: { + type: "path", + options: { + filters: [{ name: "JavaScript", extensions: ["js"] }], + }, + label: "Path to a file containing custom main code", + }, + }), + disableAsarPackaging: { + required: false, + label: "Disable ASAR packaging", + value: true, + control: { + type: "boolean", + }, + description: "Whether to disable packaging project files in a single binary or not", + }, + enableExtraLogging: { + required: false, + label: "Enable extra logging", + value: false, + control: { + type: "boolean", + }, + description: "Whether to enable extra logging of internal tools while bundling", + }, + clearServiceWorkerOnBoot: { + required: false, + label: "Clear service worker on boot", + value: false, + control: { + type: "boolean", + }, + description: "Whether to clear service worker on boot", + }, + openDevtoolsOnStart: createBooleanParam(false, { + label: "Open devtools on app start", + required: false, + description: "Whether to open devtools on app start", + }), + + // Flags + + enableInProcessGPU: { + required: false, + label: "Enable in-process GPU", + description: + "When enabled, the GPU process runs inside the main browser process instead of a separate one. This can reduce overhead but may lead to instability or crashes if the GPU process fails.", + value: false, + control: { + type: "boolean", + }, + }, + enableDisableRendererBackgrounding: { + required: false, + description: + "Enabling this prevents background tabs from being throttled, which can be useful for web apps that need continuous performance.", + label: "Disable renderer backgrounding", + value: false, + control: { + type: "boolean", + }, + }, + forceHighPerformanceGpu: { + required: false, + description: + "Enabling this forces the app to always use the high-performance GPU, which can improve rendering but may increase power consumption.", + label: "Force high performance GPU", + value: false, + control: { + type: "boolean", + }, + }, + + // websocket apis + websocketApi: { + required: false, + label: "WebSocket APIs to allow (empty = all)", + value: "[]", + control: { + type: "array", + options: { + kind: "text", + }, + }, + }, + ignore: createArray<(string | RegExp)[]>( + `[ + // use 'src/app/' as starting point +]`, + { + required: false, + label: "Folders to ignore", + description: + "An array of string or Regex that allow ignoring certain files or folders from being packaged", + control: { + type: "array", + options: { + kind: "text", + }, + }, + }, + ), + + // integrations + + enableSteamSupport: { + required: false, + label: "Enable steam support", + description: "Whether to enable Steam support", + value: false, + control: { + type: "boolean", + }, + }, + steamGameId: createNumberParam(480, { + required: false, + label: "Steam game ID", + description: "The Steam game ID", + }), + enableDiscordSupport: { + required: false, + label: "Enable Discord support", + description: "Whether to enable Discord support", + value: false, + control: { + type: "boolean", + }, + }, + discordAppId: createStringParam("", { + required: false, + label: "Discord application ID", + description: "The Discord application ID", + }), + enableDoctor: createBooleanParam(true, { + required: false, + label: "Enable doctor file", + description: + "Whether to include the doctor.bat file in Windows builds for prerequisite checking and app launching", + }), + serverMode: { + value: '"default"' as "default" | "customProtocol", + required: false, + label: "Server mode", + description: "The server mode to use", + control: { + type: "select", + options: { + placeholder: "Mode", + options: [ + { + value: "default", + label: "Default", + }, + { + value: "customProtocol", + label: "Custom Protocol", + }, + ], + }, + }, + }, +} satisfies InputsDefinition; + +const outputs = { + output: { + label: "Output", + value: "", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }, +} satisfies OutputsDefinition; + +// type Inputs = ParamsToInput + +export const createMakeProps = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, +) => + createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + params: { + ...params, + ...paramsInputFolder, + }, + outputs, + }); + +export const createPackageProps = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, + advanced?: boolean, + deprecated?: boolean, + deprecatedMessage?: string, + disabled?: false, + updateAvailable?: boolean, +) => + createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + advanced, + deprecated, + deprecatedMessage, + disabled, + updateAvailable, + params: { + ...params, + ...paramsInputFolder, + }, + outputs: outputs, + }); +export const createPackageV2Props = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, + advanced?: boolean, + deprecated?: boolean, + deprecatedMessage?: string, + disabled?: false, + updateAvailable?: boolean, +) => { + const { arch, platform } = params; + return createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + advanced, + deprecated, + deprecatedMessage, + disabled, + updateAvailable, + params: { + arch, + platform, + ...paramsInputFolder, + ...configureParams, + }, + outputs: outputs, + }); +}; + +export const createPreviewProps = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, +) => + createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + params: { + ...params, + ...paramsInputURL, + }, + outputs: outputs, + }); + +export const forge = async ( + action: "make" | "package" | "preview", + appFolder: string | undefined, + { cwd, log, inputs, setOutput, paths, abortSignal, context, setArtifact }: ActionRunnerData, + completeConfiguration: DesktopApp.Electron, +): Promise<{ folder: string; binary: string | undefined } | undefined> => { + log("Building electron"); + + if (action !== "preview") { + await detectRuntime(appFolder); + } + + const { modules, node } = paths; + const destinationFolder = await context.createTempFolder("electron-forge-"); + log(`Staging build in ${destinationFolder}`); + + try { + const shimDir = join(destinationFolder, ".bin"); + await mkdir(shimDir, { recursive: true }); + + const pnpmCjsPath = paths.pnpm; + + if (osPlatform() === "win32") { + // Write pnpm.cmd for Windows support + await writeFile( + join(shimDir, "pnpm.cmd"), + `@echo off\r\n"${node}" "${pnpmCjsPath}" %*\r\n`, + "utf8", + ); + } else { + // Write pnpm shell script for Unix/Linux/macOS support + await writeFile( + join(shimDir, "pnpm"), + `#!/bin/sh\nexec "${node}" "${pnpmCjsPath}" "$@"\n`, + { encoding: "utf8", mode: 0o755 }, + ); + } + + const forge = join( + destinationFolder, + "node_modules", + "@electron-forge", + "cli", + "dist", + "electron-forge.js", + ); + + const rawAssetFolder = await fetchPipelabAsset("@pipelab/asset-electron", "^1.0.0", { + context, + }); + const templateFolder = join(rawAssetFolder, "template"); + console.log("templateFolder", templateFolder); + console.log("destinationFolder", destinationFolder); + + // copy template to destination + await cp(templateFolder, destinationFolder, { + recursive: true, + filter: (src) => { + return basename(src) !== "node_modules"; + }, + }); + + console.log("copy done"); + + // Force hoisted node-linker for pnpm to avoid electron-forge errors + await appendFile(join(destinationFolder, ".npmrc"), "\nnode-linker=hoisted\n", "utf-8"); + + const pkgJSONPath = join(destinationFolder, "package.json"); + const pkgJSONContent = await readFile(pkgJSONPath, "utf8"); + const sanitizedName = kebabCase(completeConfiguration.name); + + const originalIconPath = completeConfiguration.icon; + const hasIcon = completeConfiguration.icon !== undefined && completeConfiguration.icon !== ""; + const iconFilename = hasIcon ? basename(completeConfiguration.icon) : ""; + const newIconPath = hasIcon ? join(destinationFolder, iconFilename) : ""; + const relativeIconPath = hasIcon ? join("./", "build", iconFilename) : ""; + const relativeIconPath1 = hasIcon ? join("./", iconFilename) : ""; + + log("relativeIconPath", relativeIconPath); + log("relativeIconPath1", relativeIconPath1); + + const hasElectronVersion = + completeConfiguration.electronVersion !== undefined && + completeConfiguration.electronVersion !== ""; + const isCJSOnly = + hasElectronVersion && + semver.lt(semver.coerce(completeConfiguration.electronVersion) || "0.0.0", "28.0.0"); + + const pkgJSON = JSON.parse(pkgJSONContent); + log("Setting name to", sanitizedName); + pkgJSON.name = sanitizedName; + log("Setting productName to", completeConfiguration.name); + pkgJSON.productName = completeConfiguration.name; + + completeConfiguration.icon = relativeIconPath1; + + await writeFile( + join(destinationFolder, "config.cjs"), + `module.exports = ${JSON.stringify(completeConfiguration, undefined, 2)}`, + "utf8", + ); + + if (isCJSOnly) { + log("Setting type to", "commonjs"); + pkgJSON.type = "commonjs"; + } else { + log("Setting type to", "module"); + pkgJSON.type = "module"; + } + + await writeFile(pkgJSONPath, JSON.stringify(pkgJSON, null, 2)); + + log("Installing packages"); + const { all: installAll } = await runPnpm(destinationFolder, { + args: ["install", "--prefer-offline"], + signal: abortSignal, + context, + }); + if (installAll) log(installAll); + + console.log("done install"); + + // install user-defined custom packages + if ( + Array.isArray(completeConfiguration.customPackages) && + completeConfiguration.customPackages.length > 0 + ) { + log(`Installing custom packages: ${completeConfiguration.customPackages.join(", ")}`); + const { all: customAll } = await runPnpm(destinationFolder, { + args: ["install", ...completeConfiguration.customPackages, "--prefer-offline"], + signal: abortSignal, + context, + }); + if (customAll) log(customAll); + } + + // override electron version + if (completeConfiguration.electronVersion && completeConfiguration.electronVersion !== "") { + log(`Installing electron@${completeConfiguration.electronVersion}`); + const { all: electronAll } = await runPnpm(destinationFolder, { + args: ["install", `electron@${completeConfiguration.electronVersion}`, "--prefer-offline"], + signal: abortSignal, + context, + }); + if (electronAll) log(electronAll); + } + + if (isCJSOnly) { + log(`Installing execa@8`); + const { all: execaAll } = await runPnpm(destinationFolder, { + args: ["install", `execa@8`, "--prefer-offline"], + signal: abortSignal, + context, + }); + if (execaAll) log(execaAll); + } + + console.log("completeConfiguration.icon", completeConfiguration.icon); + + // copy icon + if (hasIcon) { + await cp(originalIconPath, newIconPath, { recursive: true }); + } + + // copy custom main code + const destinationFile = join(destinationFolder, "src", "custom-main.js"); + if (completeConfiguration.customMainCode) { + await cp(completeConfiguration.customMainCode, destinationFile, { recursive: true }); + } else { + await writeFile(destinationFile, 'console.log("No custom main code provided")', { + signal: abortSignal, + }); + } + + if (isCJSOnly) { + log(`Installing native esbuild for transpilation...`); + const { all: esbuildAll } = await runPnpm(destinationFolder, { + args: ["install", "-D", "esbuild@0.24.0", "--prefer-offline"], + signal: abortSignal, + context, + }); + if (esbuildAll) log(esbuildAll); + + const esbuildPath = pathToFileURL( + join(destinationFolder, "node_modules", "esbuild", "lib", "main.js"), + ).href; + const esbuild = await import(esbuildPath); + + /* ESBUILD transpilation */ + const external = [ + "electron", + "@pipelab/steamworks.js", + "electron", + "node:*", + "http", + "node:stream", + ]; + await esbuild.build({ + entryPoints: [join(destinationFolder, "src", "index.js")], + bundle: true, + write: true, + format: "cjs", + platform: "node", + external, + outfile: join(destinationFolder, "dist", "index.js"), + }); + await esbuild.build({ + entryPoints: [join(destinationFolder, "src", "preload.js")], + bundle: true, + platform: "node", + external, + format: "cjs", + write: true, + outfile: join(destinationFolder, "dist", "preload.js"), + }); + await esbuild.build({ + entryPoints: [join(destinationFolder, "src", "custom-main.js")], + bundle: true, + platform: "node", + external, + format: "cjs", + write: true, + outfile: join(destinationFolder, "dist", "custom-main.js"), + }); + await rm(join(destinationFolder, "src"), { recursive: true }); + await cp(join(destinationFolder, "dist"), join(destinationFolder, "src"), { + recursive: true, + }); + await rm(join(destinationFolder, "dist"), { recursive: true }); + /* ESBUILD transpilation */ + } + + const placeAppFolder = join(destinationFolder, "src", "app"); + + // if input is folder, copy folder to destination + if (appFolder && action !== "preview") { + // copy app to template + await cp(appFolder, placeAppFolder, { recursive: true }); + } + + const inputPlatform = inputs.platform === "" ? undefined : inputs.platform; + const inputArch = inputs.arch === "" ? undefined : inputs.arch; + + try { + log("typeof inputs.platform", typeof inputs.platform); + const finalPlatform = inputPlatform ?? osPlatform() ?? ""; + log("finalPlatform", finalPlatform); + const finalArch = inputArch ?? osArch() ?? ""; + + await runWithLiveLogs( + node, + [forge, action, /* '--', */ "--arch", finalArch, "--platform", finalPlatform], + { + cwd: destinationFolder, + env: { + DEBUG: completeConfiguration.enableExtraLogging ? "*" : "", + ELECTRON_NO_ASAR: "1", + PATH: `${shimDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}`, + // DEBUG: "electron-packager" + }, + cancelSignal: abortSignal, + }, + log, + { + onStderr(data) { + log(data); + }, + onStdout(data) { + log(data); + }, + }, + ); + + if (action === "package") { + const outName = outFolderName( + completeConfiguration.name, + finalPlatform as NodeJS.Platform, + finalArch as NodeJS.Architecture, + ); + const binName = getBinName(completeConfiguration.name); + + const output = join(cwd, "out", outName); + setOutput("output", output); + setArtifact("electron-build", output); + return { + folder: output, + binary: join(output, binName), + }; + } else { + const output = join(cwd, "out", "make"); + setOutput("output", output); + setArtifact("electron-build", output); + return { + folder: output, + binary: undefined, + }; + } + } catch (e) { + if (e instanceof Error) { + if (e.name === "RequestError") { + log("Request error"); + } + if (e.name === "RequestError") { + log("Request error"); + } + } + log(e instanceof Error ? `${e.message}\n${e.stack}` : String(e)); + throw e; + } + } finally { + const originalNoAsar = process.noAsar; + process.noAsar = true; + try { + if (action !== "preview") { + const outDir = join(destinationFolder, "out"); + const finalOutDir = join(cwd, "out"); + if (existsSync(outDir)) { + await cp(outDir, finalOutDir, { recursive: true }); + } else { + log("Warning: Build output directory 'out' was not found in staging folder."); + } + } + } catch (e) { + log( + "Failed to copy build output back to cwd:", + e instanceof Error ? `${e.message}\n${e.stack}` : String(e), + ); + } + try { + await rm(destinationFolder, { recursive: true, force: true }); + } catch (e) { + log( + "Failed to clean up staging directory:", + e instanceof Error ? `${e.message}\n${e.stack}` : String(e), + ); + } finally { + process.noAsar = originalNoAsar; + } + } +}; diff --git a/plugins/plugin-electron/src/index.ts b/plugins/plugin-electron/src/index.ts new file mode 100644 index 00000000..1fe68f28 --- /dev/null +++ b/plugins/plugin-electron/src/index.ts @@ -0,0 +1,86 @@ +import { makeRunner } from "./make"; +import { packageRunner } from "./package"; +import { previewRunner } from "./preview"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; +import { + createMakeProps, + createPackageProps, + createPackageV2Props, + createPreviewProps, + IDMake, + IDPackage, + IDPackageV2, + IDPreview, +} from "./forge"; +import { configureRunner, props } from "./configure"; +import { packageV2Runner } from "./package-v2"; + +export default createNodeDefinition({ + nodes: [ + // make and package + { + node: createMakeProps( + IDMake, + "Create Installer", + "Create a distributable installer for your chosen platform", + "", + "`Build package for ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", + ), + runner: makeRunner, + // disabled: platform === 'linux' ? 'Electron is not supported on Linux' : undefined + }, + // package + // v1 + { + node: createPackageProps( + IDPackage, + "Package app", + "Gather all necessary files and prepare your app for distribution, creating a platform-specific bundle.", + "", + "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", + true, + ), + runner: packageRunner, + }, + // v2 + { + node: createPackageV2Props( + IDPackageV2, + "Package app with configuration", + "Gather all necessary files and prepare your app for distribution, creating a platform-specific bundle.", + "", + "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", + false, + false, + undefined, + false, + false, + ), + runner: packageV2Runner, + }, + { + node: createPreviewProps( + IDPreview, + "Preview app", + "Package and preview your app from an URL", + "", + "`Preview app from ${fmt.param(params['input-url'], 'primary', 'URL not set')}`", + ), + runner: previewRunner, + }, + { + node: props, + runner: configureRunner, + }, + // { + // node: propsConfigureV2, + // runner: configureV2Runner + // } + // make without package + // { + // node: packageApp, + // runner: packageRunner, + // }, + ], +}); diff --git a/src/shared/libs/plugin-electron/make.spec.ts b/plugins/plugin-electron/src/make.spec.ts similarity index 55% rename from src/shared/libs/plugin-electron/make.spec.ts rename to plugins/plugin-electron/src/make.spec.ts index 79fe60e2..0e103ce7 100644 --- a/src/shared/libs/plugin-electron/make.spec.ts +++ b/plugins/plugin-electron/src/make.spec.ts @@ -1,9 +1,8 @@ -import { expect, test, vi } from 'vitest' -import { makeRunner } from './make.js' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { type fs } from 'memfs' -import { browserWindow } from '@@/tests/helpers.js' +import { expect, test, vi } from "vitest"; +import { makeRunner } from "./make.js"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { type fs } from "memfs"; // ... @@ -13,17 +12,17 @@ import { browserWindow } from '@@/tests/helpers.js' // return memfs.fs.promises // }) -test('adds 1 + 2 to equal 3', async () => { - const outputs: Record = {} +test("adds 1 + 2 to equal 3", async () => { + const outputs: Record = {}; - const id = 'ut-electron-build' - const tmpDir = join(tmpdir(), id) + const id = "ut-electron-build"; + const tmpDir = join(tmpdir(), id); - console.log('tmpDir', tmpDir) + console.log("tmpDir", tmpDir); - const inputFolder = join(process.cwd(), 'fixtures', 'build') + const inputFolder = join(process.cwd(), "fixtures", "build"); - console.log('inputFolder', inputFolder) + console.log("inputFolder", inputFolder); // await makeRunner({ // inputs: { @@ -52,6 +51,6 @@ test('adds 1 + 2 to equal 3', async () => { // api: undefined, // browserWindow // }) - console.log('outputs', outputs) - expect(true).toBe(true) -}, 120_000) + console.log("outputs", outputs); + expect(true).toBe(true); +}, 120_000); diff --git a/plugins/plugin-electron/src/make.ts b/plugins/plugin-electron/src/make.ts new file mode 100644 index 00000000..3060597c --- /dev/null +++ b/plugins/plugin-electron/src/make.ts @@ -0,0 +1,21 @@ +import { createActionRunner } from "@pipelab/plugin-core"; +import { forge, createMakeProps } from "./forge"; +import { merge } from "ts-deepmerge"; +import { defaultElectronConfig } from "./utils"; + +export const makeRunner = createActionRunner>( + async (options) => { + const appFolder = options.inputs["input-folder"]; + + if (!options.inputs.configuration) { + throw new Error("Missing electron configuration"); + } + + const completeConfiguration = merge( + defaultElectronConfig, + options.inputs.configuration, + ) as DesktopApp.Electron; + + await forge("make", appFolder, options, completeConfiguration); + }, +); diff --git a/plugins/plugin-electron/src/package-v2.ts b/plugins/plugin-electron/src/package-v2.ts new file mode 100644 index 00000000..b01397c3 --- /dev/null +++ b/plugins/plugin-electron/src/package-v2.ts @@ -0,0 +1,51 @@ +import { createActionRunner } from "@pipelab/plugin-core"; +import { forge } from "./forge"; +import { createPackageV2Props } from "./forge"; +import { merge } from "ts-deepmerge"; +import { defaultElectronConfig } from "./utils"; + +export const packageV2Runner = createActionRunner>( + async (options) => { + const appFolder = options.inputs["input-folder"]; + + const completeConfiguration = merge(defaultElectronConfig, { + alwaysOnTop: options.inputs["alwaysOnTop"], + appBundleId: options.inputs["appBundleId"], + appCategoryType: options.inputs["appCategoryType"], + appCopyright: options.inputs["appCopyright"], + appVersion: options.inputs["appVersion"], + author: options.inputs["author"], + customMainCode: options.inputs["customMainCode"], + description: options.inputs["description"], + electronVersion: options.inputs["electronVersion"], + disableAsarPackaging: options.inputs["disableAsarPackaging"], + forceHighPerformanceGpu: options.inputs["forceHighPerformanceGpu"], + enableExtraLogging: options.inputs["enableExtraLogging"], + clearServiceWorkerOnBoot: options.inputs["clearServiceWorkerOnBoot"], + enableDisableRendererBackgrounding: options.inputs["enableDisableRendererBackgrounding"], + enableInProcessGPU: options.inputs["enableInProcessGPU"], + frame: options.inputs["frame"], + fullscreen: options.inputs["fullscreen"], + icon: options.inputs["icon"], + height: options.inputs["height"], + name: options.inputs["name"], + toolbar: options.inputs["toolbar"], + transparent: options.inputs["transparent"], + width: options.inputs["width"], + enableSteamSupport: options.inputs["enableSteamSupport"], + steamGameId: options.inputs["steamGameId"], + ignore: options.inputs["ignore"], + openDevtoolsOnStart: options.inputs["openDevtoolsOnStart"], + enableDiscordSupport: options.inputs["enableDiscordSupport"], + discordAppId: options.inputs["discordAppId"], + customPackages: options.inputs["customPackages"], + backgroundColor: options.inputs["backgroundColor"], + enableDoctor: options.inputs["enableDoctor"], + serverMode: options.inputs["serverMode"], + } satisfies DesktopApp.Electron) as DesktopApp.Electron; + + options.log("completeConfiguration", completeConfiguration); + + await forge("package", appFolder, options, completeConfiguration); + }, +); diff --git a/plugins/plugin-electron/src/package.ts b/plugins/plugin-electron/src/package.ts new file mode 100644 index 00000000..93e04987 --- /dev/null +++ b/plugins/plugin-electron/src/package.ts @@ -0,0 +1,21 @@ +import { createActionRunner } from "@pipelab/plugin-core"; +import { createPackageProps, forge } from "./forge"; +import { merge } from "ts-deepmerge"; +import { defaultElectronConfig } from "./utils"; + +export const packageRunner = createActionRunner>( + async (options) => { + const appFolder = options.inputs["input-folder"]; + + if (!options.inputs.configuration) { + throw new Error("Missing electron configuration"); + } + + const completeConfiguration = merge( + defaultElectronConfig, + options.inputs.configuration, + ) as DesktopApp.Electron; + + await forge("package", appFolder, options, completeConfiguration); + }, +); diff --git a/plugins/plugin-electron/src/preview.ts b/plugins/plugin-electron/src/preview.ts new file mode 100644 index 00000000..c7291950 --- /dev/null +++ b/plugins/plugin-electron/src/preview.ts @@ -0,0 +1,38 @@ +import { createActionRunner, runWithLiveLogs } from "@pipelab/plugin-core"; +import { createPreviewProps, forge } from "./forge"; +import { merge } from "ts-deepmerge"; +import { defaultElectronConfig } from "./utils"; + +export const previewRunner = createActionRunner>( + async (options) => { + const url = options.inputs["input-url"]; + if (url === "") { + throw new Error("URL can't be empty"); + } + + if (!options.inputs.configuration) { + throw new Error("Missing electron configuration"); + } + + const completeConfiguration = merge( + defaultElectronConfig, + options.inputs.configuration, + ) as DesktopApp.Electron; + + const output = await forge("package", undefined, options, completeConfiguration); + if (!output || !output.binary) { + throw new Error("Failed to build electron package for preview"); + } + options.log("Opening preview", JSON.stringify(output)); + options.log("Opening url", url); + await runWithLiveLogs( + output.binary, + ["--url", url], + { + cancelSignal: options.abortSignal, + }, + options.log, + ); + return; + }, +); diff --git a/src/shared/libs/plugin-electron/public/electron.webp b/plugins/plugin-electron/src/public/electron.webp similarity index 100% rename from src/shared/libs/plugin-electron/public/electron.webp rename to plugins/plugin-electron/src/public/electron.webp diff --git a/src/shared/libs/plugin-electron/utils.ts b/plugins/plugin-electron/src/utils.ts similarity index 59% rename from src/shared/libs/plugin-electron/utils.ts rename to plugins/plugin-electron/src/utils.ts index 33a0e42d..88e54f23 100644 --- a/src/shared/libs/plugin-electron/utils.ts +++ b/plugins/plugin-electron/src/utils.ts @@ -1,13 +1,13 @@ export const defaultElectronConfig = { alwaysOnTop: false, - appBundleId: 'com.pipelab.app', - appCategoryType: '', - appCopyright: 'Copyright © 2024 Pipelab', - appVersion: '1.0.0', - author: 'Pipelab', - customMainCode: '', - description: 'A simple Electron application', - electronVersion: '', + appBundleId: "com.pipelab.app", + appCategoryType: "", + appCopyright: "Copyright © 2024 Pipelab", + appVersion: "1.0.0", + author: "Pipelab", + customMainCode: "", + description: "A simple Electron application", + electronVersion: "", disableAsarPackaging: true, forceHighPerformanceGpu: false, enableExtraLogging: false, @@ -16,20 +16,20 @@ export const defaultElectronConfig = { enableInProcessGPU: false, frame: true, fullscreen: false, - icon: '', + icon: "", height: 600, - name: 'Pipelab', + name: "Pipelab", toolbar: true, transparent: false, width: 800, enableSteamSupport: false, steamGameId: 480, enableDiscordSupport: false, - discordAppId: '', + discordAppId: "", ignore: [] as string[], - backgroundColor: '#FFF', + backgroundColor: "#FFF", openDevtoolsOnStart: false, enableDoctor: false, customPackages: [] as string[], - serverMode: 'default' -} satisfies DesktopApp.Electron + serverMode: "default", +} satisfies DesktopApp.Electron; diff --git a/plugins/plugin-electron/tests/e2e/electron.spec.ts b/plugins/plugin-electron/tests/e2e/electron.spec.ts new file mode 100644 index 00000000..eb03945b --- /dev/null +++ b/plugins/plugin-electron/tests/e2e/electron.spec.ts @@ -0,0 +1,68 @@ +import { expect, test, describe, afterEach } from "vitest"; +import { mkdir, writeFile, access } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { createSandbox, runAction } from "@pipelab/test-utils"; +import { getBinName } from "@pipelab/constants"; +import { packageRunner } from "../../src/package"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +describe("End-to-End: Electron Plugin", () => { + let sandbox: Awaited>; + + afterEach(async () => { + if (sandbox) { + await sandbox.remove(); + } + }); + + test( + "should package a project using 'electron-package' node", + async () => { + sandbox = await createSandbox("electron-e2e"); + // 1. Setup a dummy project to package + const projectToPackage = join(sandbox.path, "my-app"); + await mkdir(projectToPackage, { recursive: true }); + await writeFile( + join(projectToPackage, "package.json"), + JSON.stringify({ name: "my-app", version: "1.0.0", main: "index.js" }), + ); + await writeFile(join(projectToPackage, "index.js"), "console.log('hello electron')"); + await writeFile(join(projectToPackage, "index.html"), "

Hello Electron

"); + + // 2. Run the action directly + const inputs = { + "input-folder": projectToPackage, + configuration: { + name: "my-app", + }, + arch: "" as const, + platform: "" as const, + }; + + const result = await runAction(packageRunner, { + inputs, + sandboxPath: sandbox.path, + }); + + // 3. Verification + const outputs = result.outputs; + expect(outputs).toBeDefined(); + expect(outputs.output).toEqual(expect.any(String)); + + // Verify output exists in the dynamically generated output folder + await expect(access(outputs.output as string)).resolves.not.toThrow(); + + // Verify and run the binary + const platform = process.platform; + const binName = getBinName("my-app", platform); + const binaryPath = join(outputs.output as string, binName); + + console.log("Calculated binary path:", binaryPath); + await expect(access(binaryPath)).resolves.not.toThrow(); + }, + 30 * 60 * 1000, + ); // 30 minutes timeout for real build +}); diff --git a/tests/e2e/fixtures/folder-to-electron.json b/plugins/plugin-electron/tests/e2e/fixtures/folder-to-electron.json similarity index 100% rename from tests/e2e/fixtures/folder-to-electron.json rename to plugins/plugin-electron/tests/e2e/fixtures/folder-to-electron.json diff --git a/tests/e2e/fixtures/folder-to-tauri.json b/plugins/plugin-electron/tests/e2e/fixtures/folder-to-tauri.json similarity index 100% rename from tests/e2e/fixtures/folder-to-tauri.json rename to plugins/plugin-electron/tests/e2e/fixtures/folder-to-tauri.json diff --git a/plugins/plugin-electron/tests/e2e/vitest.config.mts b/plugins/plugin-electron/tests/e2e/vitest.config.mts new file mode 100644 index 00000000..148278ad --- /dev/null +++ b/plugins/plugin-electron/tests/e2e/vitest.config.mts @@ -0,0 +1,20 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + fileParallelism: false, + testTimeout: 1800000, + hookTimeout: 60000, + maxWorkers: 1, + minWorkers: 1, + poolOptions: { + forks: { + singleFork: true, + }, + }, + include: ["**/*.spec.ts"], + root: "tests/e2e", + environment: "node", + env: { NODE_ENV: "development", PIPELAB_DISABLE_HISTORY: "true" }, + }, +}); diff --git a/plugins/plugin-electron/tsconfig.json b/plugins/plugin-electron/tsconfig.json new file mode 100644 index 00000000..26ef4817 --- /dev/null +++ b/plugins/plugin-electron/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"], + "skipLibCheck": true + }, + "include": ["src"], + "references": [ + { + "path": "../../packages/constants" + }, + { + "path": "../plugin-core" + }, + { + "path": "../../packages/shared" + } + ] +} diff --git a/plugins/plugin-electron/tsdown.config.ts b/plugins/plugin-electron/tsdown.config.ts new file mode 100644 index 00000000..327c61b7 --- /dev/null +++ b/plugins/plugin-electron/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/public"], +}); diff --git a/plugins/plugin-filesystem/.oxfmtrc.json b/plugins/plugin-filesystem/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-filesystem/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-filesystem/CHANGELOG.md b/plugins/plugin-filesystem/CHANGELOG.md new file mode 100644 index 00000000..16703228 --- /dev/null +++ b/plugins/plugin-filesystem/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-filesystem + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-filesystem/README.md b/plugins/plugin-filesystem/README.md new file mode 100644 index 00000000..908c1d6d --- /dev/null +++ b/plugins/plugin-filesystem/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-filesystem + +Pipelab plugin for file and directory operations. diff --git a/plugins/plugin-filesystem/package.json b/plugins/plugin-filesystem/package.json new file mode 100644 index 00000000..fbbf0b5b --- /dev/null +++ b/plugins/plugin-filesystem/package.json @@ -0,0 +1,77 @@ +{ + "name": "@pipelab/plugin-filesystem", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for filesystem operations (copy, move, delete, zip)", + "keywords": [ + "archive", + "automation", + "copy", + "files", + "filesystem", + "io", + "move", + "pipelab", + "pipelab-plugin", + "pipeline", + "zip" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-filesystem" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown", + "test": "vitest run -c tests/e2e/vitest.config.mts" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "@types/node": "^24.12.2", + "node-stream-zip": "1.15.0" + }, + "devDependencies": { + "@pipelab/test-utils": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + }, + "pipelab": { + "name": "Filesystem", + "description": "Pipelab plugin for filesystem operations (copy, move, delete, zip)", + "icon": { + "type": "icon", + "icon": "mdi-folder-zip-outline" + } + }, + "test": { + "env": { + "NODE_ENV": "development" + } + } +} diff --git a/src/shared/libs/plugin-filesystem/copy.spec.ts b/plugins/plugin-filesystem/src/copy.spec.ts similarity index 66% rename from src/shared/libs/plugin-filesystem/copy.spec.ts rename to plugins/plugin-filesystem/src/copy.spec.ts index cb10e4b4..2701cd57 100644 --- a/src/shared/libs/plugin-filesystem/copy.spec.ts +++ b/plugins/plugin-filesystem/src/copy.spec.ts @@ -1,21 +1,17 @@ -import { describe, expect, test } from 'vitest' -import { copyRunner } from './copy.js' -import mock from 'mock-fs' -import { readFile } from 'node:fs/promises' -import { browserWindow } from '@@/tests/helpers.js' +import { describe, expect, test } from "vitest"; -describe('copy', () => { - test('copy file to file', async () => { - const outputs: Record = {} +describe("copy", () => { + test("copy file to file", async () => { + const outputs: Record = {}; - const sourcePath = '/source/source-file.txt' - const sourceContent = 'text' + const sourcePath = "/source/source-file.txt"; + const sourceContent = "text"; - const destinationPath = '/destination/destination-file.txt' + const destinationPath = "/destination/destination-file.txt"; const files = { [sourcePath]: sourceContent, - '/destination': {} - } + "/destination": {}, + }; // mock(files) @@ -49,19 +45,19 @@ describe('copy', () => { // const data = await readFile(destinationPath, 'utf-8') // expect(data).toBe(sourceContent) - expect(true).toBe(true) - }) + expect(true).toBe(true); + }); test("copy file to file where parent folder doesn't exist", async () => { - const outputs: Record = {} + const outputs: Record = {}; - const sourcePath = '/source/source-file.txt' - const sourceContent = 'text' + const sourcePath = "/source/source-file.txt"; + const sourceContent = "text"; - const destinationPath = '/destination/destination-file.txt' + const destinationPath = "/destination/destination-file.txt"; const files = { - [sourcePath]: sourceContent - } + [sourcePath]: sourceContent, + }; // mock(files) @@ -95,6 +91,6 @@ describe('copy', () => { // const data = await readFile(destinationPath, 'utf-8') // expect(data).toBe(sourceContent) - expect(true).toBe(true) - }) -}) + expect(true).toBe(true); + }); +}); diff --git a/plugins/plugin-filesystem/src/copy.ts b/plugins/plugin-filesystem/src/copy.ts new file mode 100644 index 00000000..4f827f09 --- /dev/null +++ b/plugins/plugin-filesystem/src/copy.ts @@ -0,0 +1,169 @@ +import { cp, mkdir, rm, stat } from "node:fs/promises"; +import { basename, join, dirname } from "node:path"; +import { + createAction, + createActionRunner, + createPathParam, + assertSafeDirectoryCleanup, + writePipelabFolderMarker, +} from "@pipelab/plugin-core"; + +export const ID = "fs:copy"; + +export const copy = createAction({ + id: ID, + name: "Copy file/folder", + displayString: + '`Copy ${fmt.param(params.from, "primary", "Source")} to ${fmt.param(params.to, "primary", "Destination")}`', + params: { + from: createPathParam("", { + label: "From", + required: true, + control: { + type: "path", + options: { + properties: ["openFile", "openDirectory"], + }, + }, + }), + to: createPathParam("", { + label: "To", + required: true, + control: { + type: "path", + warnIfBlacklisted: true, + options: { + properties: ["openFile", "openDirectory", "createDirectory", "promptToCreate"], + }, + }, + }), + recursive: { + label: "Recursive", + required: true, + value: true, + control: { + type: "boolean", + }, + }, + overwrite: { + label: "Overwrite", + required: true, + value: true, + control: { + type: "boolean", + }, + }, + cleanup: { + label: "Cleanup", + required: true, + description: "Delete existing files at destination before copying", + value: true, + control: { + type: "boolean", + }, + }, + }, + + outputs: { + output: { + label: "Output", + value: "", + description: "The copied file/folder", + }, + input: { + label: "Input", + value: "", + description: "The original file/folder", + }, + parentDirectory: { + label: "Parent directory", + value: "", + description: "The parent directory of the copied file/folder", + }, + }, + description: "Copy a file or a folder from one location to another", + icon: "", + meta: {}, +}); + +export const copyRunner = createActionRunner( + async ({ log, inputs, setOutput, abortSignal }) => { + log(""); + + const from = inputs.from; + let to = inputs.to; + + if (!from) { + log("From", from); + throw new Error("Missing source"); + } + + if (!to) { + log("To", to); + throw new Error("Missing destination"); + } + + let fromIsAFile = false; + try { + const stats = await stat(from); + if (stats.isFile()) { + fromIsAFile = true; + } + } catch (e) { + log("Error getting file stats", e); + throw e; + } + const fromFileName = fromIsAFile ? basename(from) : ""; + + // if from is a file, we only add the file name to the destination if 'to' is an existing directory + if (fromIsAFile) { + try { + const toStats = await stat(to); + if (toStats.isDirectory()) { + to = join(to, fromFileName); + } + } catch (e) { + // If 'to' doesn't exist, we assume the user provided the full destination path (including filename) + } + } + + log("Copying", from, "to", to, "recursive", inputs.recursive, "overwrite", inputs.overwrite); + + if (inputs.cleanup) { + try { + await assertSafeDirectoryCleanup(to); + log("Cleaning up", to); + process.noAsar = true; + await rm(to, { recursive: true, force: true, maxRetries: 3 }); + if (!fromIsAFile) { + await mkdir(to, { recursive: true }); + } + process.noAsar = false; + } catch (e) { + log("Error cleaning up file", e); + throw e; + } + } + + try { + process.noAsar = true; + await cp(from, to, { + recursive: inputs.recursive && !fromIsAFile, + force: inputs.overwrite, + }); + + if (!fromIsAFile) { + await writePipelabFolderMarker(to, "fs:copy"); + } + + process.noAsar = false; + setOutput("output", to); + setOutput("input", from); + setOutput("parentDirectory", dirname(to)); + log("Copied", from, "to", to); + } catch (e) { + log("Error copying file", e); + throw e; + } + }, +); diff --git a/plugins/plugin-filesystem/src/index.ts b/plugins/plugin-filesystem/src/index.ts new file mode 100644 index 00000000..d8dd7bb2 --- /dev/null +++ b/plugins/plugin-filesystem/src/index.ts @@ -0,0 +1,46 @@ +import { createNodeDefinition } from "@pipelab/plugin-core"; +import { ListFilesAction, ListFilesActionRun } from "./list-files"; +import { zipRunner, zip } from "./zip"; +import { zipV2Runner, zipV2 } from "./zip-v2"; +import { unzipRunner, unzip } from "./unzip"; +import { copy, copyRunner } from "./copy"; +import { remove, removeRunner } from "./remove"; +import { run, runRunner } from "./run"; +import { openInExplorer, openInExplorerRunner } from "./open"; + +export default createNodeDefinition({ + nodes: [ + // { + // node: ListFilesAction, + // runner: ListFilesActionRun + // }, + { + node: zip, + runner: zipRunner, + }, + { + node: zipV2, + runner: zipV2Runner, + }, + { + node: unzip, + runner: unzipRunner, + }, + { + node: copy, + runner: copyRunner, + }, + { + node: remove, + runner: removeRunner, + }, + { + node: run, + runner: runRunner, + }, + { + node: openInExplorer, + runner: openInExplorerRunner, + }, + ], +}); diff --git a/plugins/plugin-filesystem/src/list-files.ts b/plugins/plugin-filesystem/src/list-files.ts new file mode 100644 index 00000000..9eff2228 --- /dev/null +++ b/plugins/plugin-filesystem/src/list-files.ts @@ -0,0 +1,80 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { createAction, createActionRunner } from "@pipelab/plugin-core"; +export const ID = "list-files-node"; + +export const ListFilesAction = createAction({ + id: ID, + name: "List files", + displayString: + "`List files \"${params.recursive ? 'recursively' : ''}\" from \"${params.folder}`", + params: { + folder: { + required: true, + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + value: "", + label: "Folder", + }, + recursive: { + required: true, + control: { + type: "boolean", + }, + value: false, + label: "Recursive", + }, + }, + + outputs: { + paths: { + value: [] as Array, + label: "Paths", + }, + }, + description: "List files from a folder", + icon: "", + meta: {}, +}); + +export const ListFilesActionRun = createActionRunner( + async ({ log, inputs, setOutput, abortSignal }) => { + const readdir = fs.readdir; + + log(""); + + log("inputs", inputs); + + const folder = inputs.folder; + if (typeof folder !== "string") { + throw new Error("Folder path must be a string"); + } + + const recursive = typeof inputs.recursive === "boolean" ? inputs.recursive : false; + + log("folder", folder); + + abortSignal?.throwIfAborted(); + + const response = await readdir(folder, { + withFileTypes: true, + recursive, + }); + + abortSignal?.throwIfAborted(); + + log("response", response); + + const files = response; + + log("-- setValue('paths')"); + setOutput( + "paths", + files.map((x) => path.join(x.parentPath ?? (x as any).path, x.name)), + ); + }, +); diff --git a/plugins/plugin-filesystem/src/open.ts b/plugins/plugin-filesystem/src/open.ts new file mode 100644 index 00000000..057835c9 --- /dev/null +++ b/plugins/plugin-filesystem/src/open.ts @@ -0,0 +1,73 @@ +import { exec } from "node:child_process"; +import { platform } from "node:os"; +import { createRequire } from "node:module"; +import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core"; + +const require = createRequire(import.meta.url); +// import displayString from './displayStringRun.lua?raw' + +export const ID = "fs:open-in-explorer"; + +export const openInExplorer = createAction({ + id: ID, + name: "Open path in explorer", + displayString: "`Open ${fmt.param(params.path, 'primary', 'No path set')} in explorer`", + params: { + path: createPathParam("", { + required: true, + label: "Path", + control: { + type: "path", + options: { + properties: ["openDirectory", "openFile"], + }, + }, + }), + }, + + outputs: { + message: { + label: "Message", + value: "", + }, + }, + description: "Open a file or folder in your explorer", + icon: "", + meta: {}, +}); + +export const openInExplorerRunner = createActionRunner( + async ({ log, inputs, setOutput, abortSignal }) => { + log(`Opening ${inputs.path}`); + + return new Promise((resolve, reject) => { + let command = ""; + const p = platform(); + + if (p === "win32") { + command = `start "" "${inputs.path}"`; + } else if (p === "darwin") { + command = `open "${inputs.path}"`; + } else { + command = `xdg-open "${inputs.path}"`; + } + + const child = exec(command, { signal: abortSignal }, (error) => { + if (error) { + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + reject(abortError); + return; + } + log(`Error opening path: ${error.message}`); + setOutput("message", error.message); + resolve(); + } else { + setOutput("message", "success"); + resolve(); + } + }); + }); + }, +); diff --git a/plugins/plugin-filesystem/src/remove.ts b/plugins/plugin-filesystem/src/remove.ts new file mode 100644 index 00000000..927d7905 --- /dev/null +++ b/plugins/plugin-filesystem/src/remove.ts @@ -0,0 +1,67 @@ +import { rm } from "node:fs/promises"; +import { + createAction, + createActionRunner, + createPathParam, + assertSafeDirectoryCleanup, +} from "@pipelab/plugin-core"; + +export const ID = "fs:remove"; + +export const remove = createAction({ + id: ID, + name: "Remove file/folder", + displayString: '`Remove ${fmt.param(params.from, "primary")}`', + params: { + from: createPathParam("", { + label: "Path", + required: true, + control: { + type: "path", + warnIfBlacklisted: true, + options: { + properties: ["openFile"], + }, + }, + }), + recursive: { + label: "Recursive", + required: true, + value: true, + control: { + type: "boolean", + }, + }, + }, + + outputs: {}, + description: "Remove a file or a folder", + icon: "", + meta: {}, +}); + +export const removeRunner = createActionRunner( + async ({ log, inputs, abortSignal }) => { + log(""); + + const from = inputs.from; + + log("Removing", from, inputs.recursive); + + if (!from) { + log("From", from); + throw new Error("Missing source"); + } + + try { + await assertSafeDirectoryCleanup(from); + process.noAsar = true; + await rm(from, { recursive: true, force: true, maxRetries: 3 }); + process.noAsar = false; + log("Removed", from); + } catch (e) { + log("Error removeing file", e); + throw e; + } + }, +); diff --git a/plugins/plugin-filesystem/src/run.ts b/plugins/plugin-filesystem/src/run.ts new file mode 100644 index 00000000..83eb9ad9 --- /dev/null +++ b/plugins/plugin-filesystem/src/run.ts @@ -0,0 +1,139 @@ +import { + createAction, + createActionRunner, + createPathParam, + createStringParam, + runWithLiveLogs, +} from "@pipelab/plugin-core"; + +export const ID = "fs:run"; + +export const run = createAction({ + id: ID, + name: "Run Command", + displayString: + "`Run command ${fmt.param(params.command, 'primary')} ${(params.parameters ?? []).map(x => fmt.param(x)).join(' ')}`", + // displayString: displayString, + params: { + command: createStringParam("", { + required: true, + description: "The command to run", + label: "Command", + }), + parameters: { + required: true, + description: "The command's parameters", + label: "Arguments", + value: [], + control: { + type: "array", + options: { + kind: "text", + }, + }, + }, + workingDirectory: createPathParam("", { + required: false, + description: "The local folder where the command should execute.", + label: "Working directory", + control: { + type: "path", + options: { + properties: ["createDirectory", "openDirectory"], + }, + }, + }), + stopOnError: { + required: false, + description: "Stop the task if the command fails", + label: "Stop on error", + value: false, + control: { + type: "boolean", + }, + }, + }, + + outputs: { + stdout: { + label: "Standard output", + description: "Standard output of the command", + value: "", + }, + stderr: { + label: "Error output", + value: "", + }, + exitCode: { + label: "Exit code", + value: 0, + }, + duration: { + label: "Duration", + value: 0, + }, + }, + description: "Run a custom system command or executable.", + icon: "", + meta: {}, +}); + +export const runRunner = createActionRunner( + async ({ log, inputs, setOutput, abortSignal }) => { + const str = `${inputs.command} ${inputs.parameters.join(" ")}`; + + log(`Running ${str}`); + + let stdout: string = ""; + let stderr: string = ""; + let exitCode: number = 0; + const durationMs: number = 0; + + const wd = inputs.workingDirectory ?? process.cwd(); + log(`Working directory: ${wd}`); + + try { + await runWithLiveLogs( + inputs.command, + inputs.parameters, + { + cwd: wd, + cancelSignal: abortSignal, + }, + log, + { + onStdout: (data) => { + stdout += data.toString(); + log(data.toString()); + }, + onStderr: (data) => { + stderr += data.toString(); + log(data.toString()); + }, + onExit(code) { + exitCode = code; + }, + }, + ); + + setOutput("exitCode", exitCode === undefined ? -1 : exitCode); + setOutput("stdout", stdout); + setOutput("stderr", stderr); + setOutput("duration", durationMs); + if ((exitCode > 0 || exitCode === undefined) && inputs.stopOnError === true) { + throw new Error(`Command failed with exit code ${exitCode}`); + } + } catch (error) { + console.log("error", error); + if (inputs.stopOnError === true) { + throw error; + } else if (error) { + const err = error as any; + setOutput("exitCode", err.exitCode === undefined ? -1 : err.exitCode); + setOutput("stdout", err.stdout ?? ""); + setOutput("stderr", err.stderr ?? ""); + setOutput("duration", err.durationMs ?? 0); + } + } + }, +); diff --git a/src/shared/libs/plugin-filesystem/temporary-folder.ts b/plugins/plugin-filesystem/src/temporary-folder.ts similarity index 100% rename from src/shared/libs/plugin-filesystem/temporary-folder.ts rename to plugins/plugin-filesystem/src/temporary-folder.ts diff --git a/src/shared/libs/plugin-filesystem/unzip.spec.ts b/plugins/plugin-filesystem/src/unzip.spec.ts similarity index 62% rename from src/shared/libs/plugin-filesystem/unzip.spec.ts rename to plugins/plugin-filesystem/src/unzip.spec.ts index 8f5060a6..091dc888 100644 --- a/src/shared/libs/plugin-filesystem/unzip.spec.ts +++ b/plugins/plugin-filesystem/src/unzip.spec.ts @@ -1,9 +1,8 @@ -import { expect, test } from 'vitest' -import { unzipRunner } from './unzip.js' -import { browserWindow } from '@@/tests/helpers.js' +import { expect, test } from "vitest"; +import { unzipRunner } from "./unzip.js"; -test('adds 1 + 2 to equal 3', async () => { - const outputs: Record = {} +test("adds 1 + 2 to equal 3", async () => { + const outputs: Record = {}; // await unzipRunner({ // inputs: { // file: '' @@ -28,6 +27,6 @@ test('adds 1 + 2 to equal 3', async () => { // api: undefined, // browserWindow, // }) - console.log('outputs', outputs) - expect(true).toBe(true) -}, 120_000) + console.log("outputs", outputs); + expect(true).toBe(true); +}, 120_000); diff --git a/plugins/plugin-filesystem/src/unzip.ts b/plugins/plugin-filesystem/src/unzip.ts new file mode 100644 index 00000000..1898e7ef --- /dev/null +++ b/plugins/plugin-filesystem/src/unzip.ts @@ -0,0 +1,71 @@ +import StreamZip from "node-stream-zip"; +import { join } from "node:path"; +import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core"; + +export const ID = "unzip-file-node"; + +export const unzip = createAction({ + id: ID, + name: "Unzip file", + displayString: '`Unzip ${fmt.param(params.file, "primary", "No file specified")}`', + params: { + file: createPathParam("", { + required: true, + control: { + type: "path", + options: { + properties: ["openFile"], + }, + }, + label: "File", + }), + }, + + outputs: { + output: { + value: "", + label: "Output", + }, + }, + description: "Unzip a file to a specified folder", + icon: "", + meta: {}, +}); + +export const unzipRunner = createActionRunner( + async ({ log, inputs, setOutput, cwd, abortSignal }) => { + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + const file = inputs.file; + const output = join(cwd); + + log("Unzip file", inputs.file, "to", output); + + const zip = new StreamZip.async({ file }); + + const onAbort = () => { + zip.close().catch(() => {}); + }; + + abortSignal.addEventListener("abort", onAbort); + + try { + await zip.extract(null, output); + await zip.close(); + setOutput("output", output); + } catch (e: any) { + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + throw e; + } finally { + abortSignal.removeEventListener("abort", onAbort); + } + }, +); diff --git a/plugins/plugin-filesystem/src/zip-v2.ts b/plugins/plugin-filesystem/src/zip-v2.ts new file mode 100644 index 00000000..135230d1 --- /dev/null +++ b/plugins/plugin-filesystem/src/zip-v2.ts @@ -0,0 +1,137 @@ +import { createWriteStream } from "node:fs"; +import { join } from "node:path"; +import archiver from "archiver"; +import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core"; + +export const ID = "zip-v2-node"; + +export type MaybeArray = T | T[]; + +export const getValue = (array: MaybeArray): T => { + if (Array.isArray(array)) { + return array[0]; + } else { + return array; + } +}; + +export const zipV2 = createAction({ + id: ID, + name: "Zip", + version: 2, + displayString: '`Zip ${fmt.param(params.folder, "primary", "No folder specified")}`', + params: { + folder: createPathParam("", { + required: true, + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + label: "Folder", + }), + }, + + outputs: { + path: { + value: "", + label: "Path", + }, + }, + description: "Zip a folder into a .zip file", + icon: "", + meta: {}, +}); + +export const zipV2Runner = createActionRunner( + async ({ log, inputs, setOutput, abortSignal, paths }) => { + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + const outputDir = paths.cache; + const outputFile = join(outputDir, "output.zip"); + + console.log("outputFile", outputFile); + + const output = createWriteStream(outputFile); + + const archive = archiver("zip", { + zlib: { level: 9 }, // Sets the compression level. + }); + + return new Promise((resolve, reject) => { + const onAbort = () => { + try { + archive.abort(); + } catch {} + try { + output.destroy(); + } catch {} + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + reject(abortError); + }; + + abortSignal.addEventListener("abort", onAbort); + + output.on("close", function () { + abortSignal.removeEventListener("abort", onAbort); + setOutput("path", outputFile); + resolve(); + }); + + output.on("end", function () { + console.log("Data has been drained"); + }); + + archive.on("warning", function (err) { + if (err.code === "ENOENT") { + console.log("Archiver warning: ENOENT"); + } else { + abortSignal.removeEventListener("abort", onAbort); + reject(err); + } + }); + + archive.on("error", function (err) { + abortSignal.removeEventListener("abort", onAbort); + reject(err); + }); + + // archive.on('data', function (data) { + // log('data', data) + // }) + // archive.on('progress', function (data) { + // /* { + // entries: + // { + // total: 5012, + // processed: 5012 + // }, + // fs: + // { + // totalBytes: 318794388, + // processedBytes: 318794388 + // } + // } */ + // // log('progress', data.entries.processed + '/' + data.entries.total) + // }) + archive.on("entry", function (data) { + log("Adding", data.name); + }); + archive.on("finish", function () { + log("finish"); + }); + + archive.pipe(output); + + archive.directory(inputs.folder, false); + + archive.finalize(); + }); + }, +); diff --git a/plugins/plugin-filesystem/src/zip.ts b/plugins/plugin-filesystem/src/zip.ts new file mode 100644 index 00000000..b2a7e2a9 --- /dev/null +++ b/plugins/plugin-filesystem/src/zip.ts @@ -0,0 +1,162 @@ +import { createWriteStream } from "node:fs"; +import archiver from "archiver"; +import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core"; + +export const ID = "zip-node"; + +export type MaybeArray = T | T[]; + +export const getValue = (array: MaybeArray): T => { + if (Array.isArray(array)) { + return array[0]; + } else { + return array; + } +}; + +export const zip = createAction({ + id: ID, + name: "Zip", + version: 1, + deprecated: true, + deprecatedMessage: "Use the new Zip V2 block instead.", + updateAvailable: true, + displayString: + '`Zip ${fmt.param(params.folder, "primary", "No folder specified")} to ${fmt.param(params.output, "secondary", "No output specified")}`', + params: { + folder: createPathParam("", { + required: true, + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + label: "Folder", + }), + output: createPathParam("", { + required: true, + control: { + type: "path", + options: { + properties: ["openFile", "promptToCreate"], + // must be zip file + filters: [ + { + extensions: ["zip"], + name: "Zip file", + }, + ], + }, + }, + label: "Folder", + }), + }, + + outputs: { + path: { + value: "", + label: "Path", + }, + }, + description: "Zip a folder into a .zip file", + icon: "", + meta: {}, +}); + +export const zipRunner = createActionRunner( + async ({ log, inputs, setOutput, abortSignal }) => { + const { folder, output: outputPath } = inputs; + + if (!folder) { + throw new Error("Missing folder"); + } + + if (!outputPath) { + throw new Error("Missing output path"); + } + + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + const output = createWriteStream(outputPath); + + const archive = archiver("zip", { + zlib: { level: 9 }, // Sets the compression level. + }); + + return new Promise((resolve, reject) => { + const onAbort = () => { + try { + archive.abort(); + } catch {} + try { + output.destroy(); + } catch {} + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + reject(abortError); + }; + + abortSignal.addEventListener("abort", onAbort); + + output.on("close", function () { + abortSignal.removeEventListener("abort", onAbort); + setOutput("path", outputPath); + resolve(); + }); + + output.on("end", function () { + console.log("Data has been drained"); + }); + + archive.on("warning", function (err) { + if (err.code === "ENOENT") { + console.log("Archiver warning: ENOENT"); + } else { + abortSignal.removeEventListener("abort", onAbort); + reject(err); + } + }); + + archive.on("error", function (err) { + abortSignal.removeEventListener("abort", onAbort); + reject(err); + }); + + // archive.on('data', function (data) { + // log('data', data) + // }) + // archive.on('progress', function (data) { + // /* { + // entries: + // { + // total: 5012, + // processed: 5012 + // }, + // fs: + // { + // totalBytes: 318794388, + // processedBytes: 318794388 + // } + // } */ + // // log('progress', data.entries.processed + '/' + data.entries.total) + // }) + archive.on("entry", function (data) { + log("Adding", data.name); + }); + archive.on("finish", function () { + log("finish"); + }); + + archive.pipe(output); + + archive.directory(folder, false); + + archive.finalize(); + }); + }, +); diff --git a/plugins/plugin-filesystem/tests/e2e/filesystem.spec.ts b/plugins/plugin-filesystem/tests/e2e/filesystem.spec.ts new file mode 100644 index 00000000..c95570a0 --- /dev/null +++ b/plugins/plugin-filesystem/tests/e2e/filesystem.spec.ts @@ -0,0 +1,217 @@ +import { expect, test, describe, beforeAll, afterAll, afterEach } from "vitest"; +import { mkdir, writeFile, readFile, access } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { createSandbox, runAction } from "@pipelab/test-utils"; +import { copyRunner } from "../../src/copy"; +import { removeRunner } from "../../src/remove"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +describe("End-to-End: Filesystem Plugin", () => { + let sandbox: Awaited>; + + afterEach(async () => { + if (sandbox) { + await sandbox.remove(); + } + }); + + test("should copy a file using 'copy' action", { timeout: 1800000 }, async () => { + sandbox = await createSandbox("fs-copy-e2e"); + const testPath = sandbox.path; + const sourcePath = join(testPath, "source"); + const destPath = join(testPath, "destination"); + await mkdir(sourcePath, { recursive: true }); + await mkdir(destPath, { recursive: true }); + + const sourceFile = join(sourcePath, "file.txt"); + const destFile = join(destPath, "file.txt"); + await writeFile(sourceFile, "Hello World"); + + await runAction(copyRunner, { + inputs: { + from: sourceFile, + to: destFile, + recursive: false, + overwrite: false, + cleanup: false, + }, + sandboxPath: testPath, + }); + + await expect(access(destFile)).resolves.not.toThrow(); + const content = await readFile(destFile, "utf-8"); + expect(content).toBe("Hello World"); + }); + + test("should move a file using 'copy' then 'remove' actions", { timeout: 1800000 }, async () => { + sandbox = await createSandbox("fs-move-e2e"); + const testPath = sandbox.path; + const sourcePath = join(testPath, "source"); + const destPath = join(testPath, "destination"); + await mkdir(sourcePath, { recursive: true }); + await mkdir(destPath, { recursive: true }); + + const sourceFile = join(sourcePath, "file.txt"); + const destFile = join(destPath, "file.txt"); + await writeFile(sourceFile, "File to move"); + + // Copy + await runAction(copyRunner, { + inputs: { + from: sourceFile, + to: destFile, + recursive: false, + overwrite: false, + cleanup: false, + }, + sandboxPath: testPath, + }); + + // Remove + await runAction(removeRunner, { + inputs: { + from: sourceFile, + recursive: true, + }, + sandboxPath: testPath, + }); + + await expect(access(destFile)).resolves.not.toThrow(); + await expect(access(sourceFile)).rejects.toThrow(); + }); + + test("should delete a file using 'remove' action", { timeout: 1800000 }, async () => { + sandbox = await createSandbox("fs-remove-e2e"); + const testPath = sandbox.path; + await mkdir(testPath, { recursive: true }); + const fileToDelete = join(testPath, "file_to_delete.txt"); + await writeFile(fileToDelete, "Delete me"); + + await runAction(removeRunner, { + inputs: { + from: fileToDelete, + recursive: true, + }, + sandboxPath: testPath, + }); + + await expect(access(fileToDelete)).rejects.toThrow(); + }); + + test( + "should refuse to cleanup or remove a blacklisted path (e.g. user home directory)", + { timeout: 1800000 }, + async () => { + sandbox = await createSandbox("fs-blacklist-e2e"); + const testPath = sandbox.path; + const home = process.env.HOME || process.env.USERPROFILE || ""; + + await expect( + runAction(copyRunner, { + inputs: { + from: testPath, + to: home, + recursive: true, + overwrite: true, + cleanup: true, + }, + sandboxPath: testPath, + }), + ).rejects.toThrow(/Cannot cleanup\/delete protected system or user directory/); + + await expect( + runAction(removeRunner, { + inputs: { + from: home, + recursive: true, + }, + sandboxPath: testPath, + }), + ).rejects.toThrow(/Cannot cleanup\/delete protected system or user directory/); + }, + ); + + test( + "should refuse to delete a non-empty directory if the .pipelab folder marker is missing", + { timeout: 1800000 }, + async () => { + sandbox = await createSandbox("fs-marker-missing-e2e"); + const testPath = sandbox.path; + const sourceDir = join(testPath, "source"); + const targetDir = join(testPath, "target"); + + await mkdir(sourceDir, { recursive: true }); + await mkdir(targetDir, { recursive: true }); + + // Seed files + await writeFile(join(sourceDir, "file1.txt"), "source file"); + await writeFile(join(targetDir, "personal_photo.png"), "important user file"); + + await expect( + runAction(copyRunner, { + inputs: { + from: sourceDir, + to: targetDir, + recursive: true, + overwrite: true, + cleanup: true, + }, + sandboxPath: testPath, + }), + ).rejects.toThrow(/Directory is not empty and was not created by Pipelab/); + }, + ); + + test( + "should allow cleanup and overwrite if the directory has the .pipelab folder marker", + { timeout: 1800000 }, + async () => { + sandbox = await createSandbox("fs-marker-present-e2e"); + const testPath = sandbox.path; + const sourceDir = join(testPath, "source"); + const targetDir = join(testPath, "target"); + + await mkdir(sourceDir, { recursive: true }); + await mkdir(targetDir, { recursive: true }); + + await writeFile(join(sourceDir, "file1.txt"), "source content"); + + // Run 1: Copy to target (this should create the marker) + await runAction(copyRunner, { + inputs: { + from: sourceDir, + to: targetDir, + recursive: true, + overwrite: true, + cleanup: false, + }, + sandboxPath: testPath, + }); + + // Check that .pipelab directory was created + const markerPath = join(targetDir, ".pipelab"); + await expect(access(markerPath)).resolves.not.toThrow(); + + // Run 2: Copy again with cleanup = true (should succeed because marker exists) + await expect( + runAction(copyRunner, { + inputs: { + from: sourceDir, + to: targetDir, + recursive: true, + overwrite: true, + cleanup: true, + }, + sandboxPath: testPath, + }), + ).resolves.not.toThrow(); + + // Verify copy succeeded + const copiedFile = join(targetDir, "file1.txt"); + await expect(access(copiedFile)).resolves.not.toThrow(); + }, + ); +}); diff --git a/plugins/plugin-filesystem/tests/e2e/vitest.config.mts b/plugins/plugin-filesystem/tests/e2e/vitest.config.mts new file mode 100644 index 00000000..148278ad --- /dev/null +++ b/plugins/plugin-filesystem/tests/e2e/vitest.config.mts @@ -0,0 +1,20 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + fileParallelism: false, + testTimeout: 1800000, + hookTimeout: 60000, + maxWorkers: 1, + minWorkers: 1, + poolOptions: { + forks: { + singleFork: true, + }, + }, + include: ["**/*.spec.ts"], + root: "tests/e2e", + environment: "node", + env: { NODE_ENV: "development", PIPELAB_DISABLE_HISTORY: "true" }, + }, +}); diff --git a/plugins/plugin-filesystem/tsconfig.json b/plugins/plugin-filesystem/tsconfig.json new file mode 100644 index 00000000..91cbdd09 --- /dev/null +++ b/plugins/plugin-filesystem/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-filesystem/tsdown.config.ts b/plugins/plugin-filesystem/tsdown.config.ts new file mode 100644 index 00000000..7147099e --- /dev/null +++ b/plugins/plugin-filesystem/tsdown.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, +}); diff --git a/plugins/plugin-itch/.oxfmtrc.json b/plugins/plugin-itch/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-itch/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-itch/CHANGELOG.md b/plugins/plugin-itch/CHANGELOG.md new file mode 100644 index 00000000..a9546061 --- /dev/null +++ b/plugins/plugin-itch/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-itch + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-itch/README.md b/plugins/plugin-itch/README.md new file mode 100644 index 00000000..433f67ae --- /dev/null +++ b/plugins/plugin-itch/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-itch + +Pipelab plugin for automating deployments to Itch.io using Butler. diff --git a/plugins/plugin-itch/package.json b/plugins/plugin-itch/package.json new file mode 100644 index 00000000..bbdee706 --- /dev/null +++ b/plugins/plugin-itch/package.json @@ -0,0 +1,65 @@ +{ + "name": "@pipelab/plugin-itch", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for publishing games to itch.io", + "keywords": [ + "automation", + "butler", + "deployment", + "game-publishing", + "indie-game", + "itch", + "itch.io", + "pipelab", + "pipelab-plugin", + "pipeline" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-itch" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "node-stream-zip": "1.15.0" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "@types/node": "24", + "tsdown": "0.21.2", + "typescript": "5.9.3" + }, + "pipelab": { + "name": "Itch.io", + "description": "Pipelab plugin for publishing games to itch.io", + "icon": "./dist/assets/itch-icon.webp" + } +} diff --git a/src/shared/libs/plugin-itch/assets/itch-icon.webp b/plugins/plugin-itch/src/assets/itch-icon.webp similarity index 100% rename from src/shared/libs/plugin-itch/assets/itch-icon.webp rename to plugins/plugin-itch/src/assets/itch-icon.webp diff --git a/plugins/plugin-itch/src/ensure.ts b/plugins/plugin-itch/src/ensure.ts new file mode 100644 index 00000000..80967996 --- /dev/null +++ b/plugins/plugin-itch/src/ensure.ts @@ -0,0 +1,63 @@ +import { join } from "node:path"; +import { access, mkdir, chmod, rm } from "node:fs/promises"; +import { constants } from "node:fs"; +import { downloadFile, extractZip, PipelabContext } from "@pipelab/plugin-core"; + +/** + * Installs itch.io butler CLI if not already present. + * @param context The PipelabContext instance. + * @param version The version of butler to install. + * @returns A Promise that resolves to the path of the butler executable. + */ +export const ensureButler = async (context: PipelabContext, version = "LATEST") => { + const thirdpartyDir = context.getThirdPartyPath(); + const butlerDir = join(thirdpartyDir, "butler", version); + const isWindows = process.platform === "win32"; + const executableName = isWindows ? "butler.exe" : "butler"; + const finalButlerPath = join(butlerDir, executableName); + + try { + await access(finalButlerPath, constants.X_OK); + return finalButlerPath; + } catch (e) { + console.log(`Butler not found at ${finalButlerPath}, installing...`); + } + + const localOs = process.platform; + const localArch = process.arch; + + let butlerName = ""; + if (localOs === "darwin") { + butlerName += "darwin"; + } else if (localOs === "linux") { + butlerName += "linux"; + } else if (localOs === "win32") { + butlerName += "windows"; + } + + butlerName += "-"; + + if (localArch === "x64" || localArch === "arm64") { + butlerName += "amd64"; + } else { + throw new Error(`Unsupported architecture for butler: ${localArch}`); + } + + const downloadUrl = `https://broth.itch.zone/butler/${butlerName}/${version}/archive/default`; + const tempDir = await context.createTempFolder("butler-setup-"); + const archivePath = join(tempDir, "butler.zip"); + + console.log(`Downloading butler from ${downloadUrl}...`); + await downloadFile(downloadUrl, archivePath); + + console.log(`Extracting butler to ${butlerDir}...`); + await mkdir(butlerDir, { recursive: true }); + await extractZip(archivePath, butlerDir); + + if (!isWindows) { + await chmod(finalButlerPath, 0o755); + } + + await rm(tempDir, { recursive: true, force: true }); + return finalButlerPath; +}; diff --git a/plugins/plugin-itch/src/export.ts b/plugins/plugin-itch/src/export.ts new file mode 100644 index 00000000..82604ce8 --- /dev/null +++ b/plugins/plugin-itch/src/export.ts @@ -0,0 +1,116 @@ +import { join, dirname, delimiter } from "node:path"; +import { ensureButler } from "./ensure.js"; +import { extractZip } from "@pipelab/plugin-core"; +import { + createAction, + createActionRunner, + createPathParam, + createStringParam, + downloadFile, + runWithLiveLogs, +} from "@pipelab/plugin-core"; + +export const ID = "itch-upload"; + +export interface ButlerJSONOutputLog { + level: "info"; + message: string; + time: number; + type: "log"; +} + +export interface ButlerJSONOutputProgress { + bps: number; + eta: number; + progress: number; + time: 1736873335; + type: "progress"; +} + +export type ButlerJSONOutput = ButlerJSONOutputLog | ButlerJSONOutputProgress; + +export const uploadToItch = createAction({ + id: ID, + name: "Upload to Itch.io", + description: "Upload your build directory to Itch.io.", + icon: "", + displayString: + "`Upload ${fmt.param(params['input-folder'], 'primary', 'No path selected')} to ${fmt.param(params['user'], 'primary', 'No project')}/${fmt.param(params['project'], 'primary', 'No project')}:${fmt.param(params['channel'], 'primary', 'No channel')}`", + meta: {}, + params: { + "input-folder": createPathParam("", { + required: true, + label: "Folder to upload", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + user: createStringParam("", { + required: true, + label: "Username", + }), + project: createStringParam("", { + required: true, + label: "Project", + }), + channel: createStringParam("", { + required: true, + label: "Channel (e.g., windows, mac, web)", + }), + "api-key": createStringParam("", { + required: true, + label: "API Key", + }), + }, + outputs: {}, +}); + +export const uploadToItchRunner = createActionRunner( + async ({ log, inputs, cwd, abortSignal, context }) => { + const node = context.getNodePath(); + const butlerPath = await ensureButler(context); + + log("Uploading to itch"); + + await runWithLiveLogs( + butlerPath, + [ + "push", + inputs["input-folder"] as string, + `${inputs.user as string}/${inputs.project as string}:${inputs.channel as string}`, + "--json", + ], + { + env: { + ...process.env, + // DEBUG: '*', + PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, + BUTLER_API_KEY: inputs["api-key"] as string, + }, + cancelSignal: abortSignal, + }, + log, + { + onStdout(data, subprocess) { + const jsons = data.trim().split("\n"); + for (const jsonData of jsons) { + const json = JSON.parse(jsonData) as ButlerJSONOutput; + switch (json.type) { + case "log": + log(json.message); + break; + case "progress": + log(`${json.progress}% - ETA: ${json.eta}s`); + break; + } + } + }, + }, + ); + + log("Uploaded to itch"); + }, +); diff --git a/plugins/plugin-itch/src/index.ts b/plugins/plugin-itch/src/index.ts new file mode 100644 index 00000000..29b0b430 --- /dev/null +++ b/plugins/plugin-itch/src/index.ts @@ -0,0 +1,26 @@ +import { uploadToItch, uploadToItchRunner } from "./export"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; + +export default createNodeDefinition({ + nodes: [ + // make and package + { + node: uploadToItch, + runner: uploadToItchRunner, + }, + ], + integrations: [ + { + name: "Itch Butler Account", + fields: [ + { + key: "apiKey", + label: "Butler API Key", + type: "password", + placeholder: "butler API key", + }, + ], + }, + ], +}); diff --git a/plugins/plugin-itch/tsconfig.json b/plugins/plugin-itch/tsconfig.json new file mode 100644 index 00000000..bdcaa84d --- /dev/null +++ b/plugins/plugin-itch/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"], + "skipLibCheck": true + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-itch/tsdown.config.ts b/plugins/plugin-itch/tsdown.config.ts new file mode 100644 index 00000000..b3f281ba --- /dev/null +++ b/plugins/plugin-itch/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/assets"], +}); diff --git a/plugins/plugin-minify/.oxfmtrc.json b/plugins/plugin-minify/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-minify/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-minify/CHANGELOG.md b/plugins/plugin-minify/CHANGELOG.md new file mode 100644 index 00000000..41cd31d5 --- /dev/null +++ b/plugins/plugin-minify/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-minify + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-minify/README.md b/plugins/plugin-minify/README.md new file mode 100644 index 00000000..78c33a29 --- /dev/null +++ b/plugins/plugin-minify/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-minify + +Pipelab plugin for code minification. diff --git a/plugins/plugin-minify/package.json b/plugins/plugin-minify/package.json new file mode 100644 index 00000000..af782340 --- /dev/null +++ b/plugins/plugin-minify/package.json @@ -0,0 +1,68 @@ +{ + "name": "@pipelab/plugin-minify", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for minifying HTML, CSS, and JavaScript assets", + "keywords": [ + "automation", + "build", + "css", + "html", + "javascript", + "minification", + "minify", + "optimization", + "pipelab", + "pipelab-plugin", + "pipeline" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-minify" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "@types/node": "^24.12.2" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3" + }, + "pipelab": { + "name": "Minifyer", + "description": "Pipelab plugin for minifying HTML, CSS, and JavaScript assets", + "icon": { + "type": "icon", + "icon": "mdi-zip-box" + } + } +} diff --git a/plugins/plugin-minify/src/code.ts b/plugins/plugin-minify/src/code.ts new file mode 100644 index 00000000..7f456517 --- /dev/null +++ b/plugins/plugin-minify/src/code.ts @@ -0,0 +1,77 @@ +import { readdir, mkdir, access, chmod } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import esbuild from "esbuild"; +import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core"; + +export const ID = "minify:code"; + +export const minifyCode = createAction({ + id: ID, + name: "Minify code", + description: "Compress and optimize JavaScript code files inside a folder.", + icon: "", + displayString: + "`Optimize code in ${fmt.param(params['input-folder'], 'primary', 'No folder selected')}`", + meta: {}, + params: { + "input-folder": createPathParam("", { + required: true, + label: "Folder to optimize", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + }, + outputs: {}, +}); + +const getAllJsFiles = async (dir: string): Promise => { + const files = await readdir(dir, { withFileTypes: true }); + const results = await Promise.all( + files.map(async (file) => { + const fullPath = join(dir, file.name); + if (file.isDirectory()) { + return getAllJsFiles(fullPath); + } else if (file.isFile() && fullPath.endsWith(".js")) { + return [fullPath]; + } + return []; + }), + ); + return results.flat(); +}; + +export const minifyCodeRunner = createActionRunner( + async ({ log, inputs, cwd, abortSignal }) => { + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + const jsFiles = await getAllJsFiles(inputs["input-folder"]); + + for (const file of jsFiles) { + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + await esbuild.build({ + entryPoints: [file], // Process one file at a time + outfile: file, // Write directly to the original file + minify: true, // Minify the content + bundle: false, // Don't bundle dependencies + sourcemap: false, // No source maps (optional) + format: "esm", // Optional: Specify output format + write: true, // Ensure the file is overwritten + }); + console.log(`Minified: ${file}`); + } + + log("Minified code"); + }, +); diff --git a/plugins/plugin-minify/src/images.ts b/plugins/plugin-minify/src/images.ts new file mode 100644 index 00000000..778223f7 --- /dev/null +++ b/plugins/plugin-minify/src/images.ts @@ -0,0 +1,36 @@ +import { join, dirname } from "node:path"; +import { mkdir, access, chmod } from "node:fs/promises"; +import { createAction, createActionRunner, createPathParam } from "@pipelab/plugin-core"; + +export const ID = "minify:images"; + +export const minifyImages = createAction({ + id: ID, + name: "Minify images", + description: "Optimize and reduce the file size of images in a folder.", + icon: "", + displayString: + "`Optimize images in ${fmt.param(params['input-folder'], 'primary', 'No folder selected')}`", + meta: {}, + params: { + "input-folder": createPathParam("", { + required: true, + label: "Folder to optimize", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + }, + outputs: {}, +}); + +export const minifyImagesRunner = createActionRunner( + async ({ log, inputs, cwd, abortSignal }) => { + // TODO: https://github.com/imagemin/imagemin + + log("Minified images"); + }, +); diff --git a/plugins/plugin-minify/src/index.ts b/plugins/plugin-minify/src/index.ts new file mode 100644 index 00000000..9b825ca8 --- /dev/null +++ b/plugins/plugin-minify/src/index.ts @@ -0,0 +1,18 @@ +import { minifyCode, minifyCodeRunner } from "./code"; +import { minifyImages, minifyImagesRunner } from "./images"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; + +export default createNodeDefinition({ + nodes: [ + // make and package + { + node: minifyCode, + runner: minifyCodeRunner, + }, + { + node: minifyImages, + runner: minifyImagesRunner, + }, + ], +}); diff --git a/plugins/plugin-minify/tsconfig.json b/plugins/plugin-minify/tsconfig.json new file mode 100644 index 00000000..91cbdd09 --- /dev/null +++ b/plugins/plugin-minify/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-minify/tsdown.config.ts b/plugins/plugin-minify/tsdown.config.ts new file mode 100644 index 00000000..7147099e --- /dev/null +++ b/plugins/plugin-minify/tsdown.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, +}); diff --git a/plugins/plugin-netlify/.oxfmtrc.json b/plugins/plugin-netlify/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-netlify/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-netlify/CHANGELOG.md b/plugins/plugin-netlify/CHANGELOG.md new file mode 100644 index 00000000..d4fced90 --- /dev/null +++ b/plugins/plugin-netlify/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-netlify + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-netlify/README.md b/plugins/plugin-netlify/README.md new file mode 100644 index 00000000..c5152320 --- /dev/null +++ b/plugins/plugin-netlify/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-netlify + +Pipelab plugin for building and deploying sites to Netlify. diff --git a/plugins/plugin-netlify/package.json b/plugins/plugin-netlify/package.json new file mode 100644 index 00000000..4f76f5e8 --- /dev/null +++ b/plugins/plugin-netlify/package.json @@ -0,0 +1,66 @@ +{ + "name": "@pipelab/plugin-netlify", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for deploying web projects to Netlify", + "keywords": [ + "automation", + "cdn", + "deploy", + "deployment", + "hosting", + "netlify", + "pipelab", + "pipelab-plugin", + "pipeline", + "web" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-netlify" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "@types/node": "^24.12.2", + "electron": "32.1.2", + "untun": "0.1.3" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3" + }, + "pipelab": { + "name": "Netlify", + "description": "Pipelab plugin for deploying web projects to Netlify", + "icon": "./dist/assets/netlify-icon.webp" + } +} diff --git a/src/shared/libs/plugin-netlify/assets/netlify-icon.webp b/plugins/plugin-netlify/src/assets/netlify-icon.webp similarity index 100% rename from src/shared/libs/plugin-netlify/assets/netlify-icon.webp rename to plugins/plugin-netlify/src/assets/netlify-icon.webp diff --git a/plugins/plugin-netlify/src/build.ts b/plugins/plugin-netlify/src/build.ts new file mode 100644 index 00000000..61d083db --- /dev/null +++ b/plugins/plugin-netlify/src/build.ts @@ -0,0 +1,164 @@ +import { ensure, extractZip, zipFolder } from "@pipelab/plugin-core"; +import { + createAction, + createActionRunner, + createNetlifySiteParam, + createPathParam, + createStringParam, + downloadFile, + fileExists, + runWithLiveLogs, + runPnpm, +} from "@pipelab/plugin-core"; +import { createReadStream } from "node:fs"; +import { cp, mkdir, rm, writeFile } from "node:fs/promises"; +import { delimiter, dirname, join } from "node:path"; + +export const ID = "netlify-build"; + +export const buildNetlifySite = createAction({ + id: ID, + name: "Build Netlify site", + description: "Build your Netlify site.", + icon: "", + displayString: "`Build ${fmt.param(params['input-folder'], 'primary', 'No path selected')}`", + meta: {}, + params: { + "input-folder": createPathParam("", { + required: true, + label: "Folder to build", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + token: createStringParam("", { + required: true, + label: "Personal Access Token", + }), + site: createNetlifySiteParam("", "token", { + required: true, + label: "Netlify Site", + }), + }, + outputs: {}, +}); + +export const buildNetlifySiteRunner = createActionRunner( + async ({ log, inputs, cwd, abortSignal, paths, context }) => { + log("Building netlify site"); + + const { node } = paths; + + const buildDir = join(cwd, "build"); + + const inputFolder = inputs["input-folder"]; + // ensure input folder have apackage.json + const packageJsonPath = join(inputFolder, "package.json"); + const packageJson = await fileExists(packageJsonPath); + if (!packageJson) { + throw new Error("No package.json found in input folder"); + } + + await cp(inputs["input-folder"], buildDir, { recursive: true }); + + const netlifyDir = join(buildDir, ".netlify"); + const netlifyState = join(netlifyDir, "state.json"); + + await mkdir(netlifyDir, { recursive: true }); + + await writeFile(netlifyState, `{ "siteId": "${inputs.site}" }`, "utf-8"); + + // log('Installing packages') + // await runWithLiveLogs( + // node, + // [pnpm, 'install', '--prefer-offline'], + // { + // cwd: buildDir, + // env: { + // // DEBUG: '*', + // PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, + // PNPM_HOME: pnpmHome + // }, + // cancelSignal: abortSignal + // }, + // log, + // { + // onStderr(data) { + // log(data) + // }, + // onStdout(data) { + // log(data) + // } + // } + // ) + + // await runWithLiveLogs( + // node, + // [pnpm, 'build', '--preset', 'netlify'], + // { + // cwd: buildDir, + // env: { + // // DEBUG: '*', + // PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, + // PNPM_HOME: pnpmHome + // }, + // cancelSignal: abortSignal + // }, + // log, + // { + // onStderr(data) { + // log(data) + // }, + // onStdout(data) { + // log(data) + // } + // } + // ) + const { all: buildOut } = await runPnpm(buildDir, { + args: ["--package", "netlify-cli", "dlx", "netlify", "build"], + extraEnv: { + NETLIFY_AUTH_TOKEN: inputs.token, + }, + signal: abortSignal, + context, + }); + if (buildOut) log(buildOut); + + // const distDir = join(buildDir, 'dist') + + // const distZipPath = join(cwd, 'dist.zip') + // const zip = await zipFolder(distDir, distZipPath, log) + + // console.log('zip', zip) + // console.log('distZipPath', distZipPath) + + // const result = await fetch(`https://api.netlify.com/api/v1/sites/${inputs.site}/deploys`, { + // method: 'POST', + // body: createReadStream(distZipPath), + // headers: { + // 'Content-Type': 'application/zip', + // Authorization: `Bearer ${inputs.token}` + // }, + // duplex: 'half' + // }) + // + // const deploy = await result.json() + + const { all: deployOut } = await runPnpm(buildDir, { + args: ["--package", "netlify-cli", "dlx", "netlify", "deploy", "--prod"], + extraEnv: { + NETLIFY_AUTH_TOKEN: inputs.token, + }, + signal: abortSignal, + context, + }); + if (deployOut) log(deployOut); + + // log('Deployed to netlify', deploy) + + log("Uploaded to netlify"); + }, +); diff --git a/plugins/plugin-netlify/src/index.ts b/plugins/plugin-netlify/src/index.ts new file mode 100644 index 00000000..34de12bd --- /dev/null +++ b/plugins/plugin-netlify/src/index.ts @@ -0,0 +1,31 @@ +import { uploadToNetlify, uploadToNetlifyRunner } from "./publish"; +import { buildNetlifySite, buildNetlifySiteRunner } from "./build"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; + +export default createNodeDefinition({ + nodes: [ + // make and package + { + node: buildNetlifySite, + runner: buildNetlifySiteRunner, + }, + { + node: uploadToNetlify, + runner: uploadToNetlifyRunner, + }, + ], + integrations: [ + { + name: "Netlify Account", + fields: [ + { + key: "apiKey", + label: "Personal Access Token", + type: "password", + placeholder: "netlify API token", + }, + ], + }, + ], +}); diff --git a/src/shared/libs/plugin-netlify/publish.ts b/plugins/plugin-netlify/src/publish.ts similarity index 55% rename from src/shared/libs/plugin-netlify/publish.ts rename to plugins/plugin-netlify/src/publish.ts index 3c24c37a..27447bd9 100644 --- a/src/shared/libs/plugin-netlify/publish.ts +++ b/plugins/plugin-netlify/src/publish.ts @@ -1,4 +1,4 @@ -import { ensure, extractZip, zipFolder } from '@main/utils' +import { ensure, extractZip, zipFolder } from "@pipelab/plugin-core"; import { createAction, createActionRunner, @@ -7,171 +7,135 @@ import { createStringParam, downloadFile, fileExists, - runWithLiveLogs -} from '@pipelab/plugin-core' -import { app, shell } from 'electron' -import { createReadStream } from 'node:fs' -import { cp, mkdir, rm, writeFile } from 'node:fs/promises' -import { delimiter, dirname, join, basename } from 'node:path' + runWithLiveLogs, + runPnpm, + fetchPipelabAsset, +} from "@pipelab/plugin-core"; +import { createReadStream } from "node:fs"; +import { cp, mkdir, rm, writeFile } from "node:fs/promises"; +import { delimiter, dirname, join, basename } from "node:path"; -export const ID = 'netlify-upload' +export const ID = "netlify-upload"; export interface ButlerJSONOutputLog { - level: 'info' - message: string - time: number - type: 'log' + level: "info"; + message: string; + time: number; + type: "log"; } export interface ButlerJSONOutputProgress { - bps: number - eta: number - progress: number - time: 1736873335 - type: 'progress' + bps: number; + eta: number; + progress: number; + time: 1736873335; + type: "progress"; } -export type ButlerJSONOutput = ButlerJSONOutputLog | ButlerJSONOutputProgress +export type ButlerJSONOutput = ButlerJSONOutputLog | ButlerJSONOutputProgress; export const uploadToNetlify = createAction({ id: ID, - name: 'Upload to Netlify', - description: '', - icon: '', + name: "Upload to Netlify", + description: "Deploy your web application or static folder directly to Netlify.", + icon: "", displayString: "`Upload ${fmt.param(params['input-folder'], 'primary', 'No path selected')} to ${fmt.param(params['site'], 'primary', 'No site')}`", meta: {}, params: { - 'input-folder': createPathParam('', { + "input-folder": createPathParam("", { required: true, - label: 'Path to the folder to upload to netlify', + label: "Folder to deploy", control: { - type: 'path', + type: "path", options: { - properties: ['openDirectory'] - } - } + properties: ["openDirectory"], + }, + }, }), - token: createStringParam('', { + token: createStringParam("", { required: true, - label: 'Token' + label: "Personal Access Token", }), - site: createNetlifySiteParam('', 'token', { + site: createNetlifySiteParam("", "token", { required: true, - label: 'Site' - }) + label: "Netlify Site", + }), }, - outputs: {} -}) + outputs: {}, +}); export const uploadToNetlifyRunner = createActionRunner( - async ({ log, inputs, cwd, abortSignal, paths }) => { - log('Uploading to netlify') - - const { pnpm, node, assets } = paths + async ({ log, inputs, cwd, abortSignal, paths, context }) => { + log("Uploading to netlify"); - const userData = app.getPath('userData') - const pnpmHome = join(userData, 'config', 'pnpm') + const { node } = paths; const sitesResult = await fetch(`https://api.netlify.com/api/v1/sites/${inputs.site}`, { - method: 'GET', + method: "GET", headers: { - 'Content-Type': 'application/zip', - Authorization: `Bearer ${inputs.token}` - } - }) - const site = await sitesResult.json() + "Content-Type": "application/zip", + Authorization: `Bearer ${inputs.token}`, + }, + }); + const site = await sitesResult.json(); - log('site', site) + log("site", site); if (!site) { - throw new Error('Site does not exist') + throw new Error("Site does not exist"); } - const appFolder = inputs['input-folder'] + const appFolder = inputs["input-folder"]; // 1. Prepare input folder with temmplate // Assume input folder is always a static site - const destinationFolder = join(cwd) - const templateFolder = join(assets, 'netlify', 'templates', 'static') + const destinationFolder = join(cwd); + const rawAssetFolder = await fetchPipelabAsset("@pipelab/asset-netlify", "^1.0.0", { context }); + const templateFolder = join(rawAssetFolder, "template"); // copy template to destination await cp(templateFolder, destinationFolder, { recursive: true, filter: (src) => { - return basename(src) !== 'node_modules' - } - }) - const placeAppFolder = join(destinationFolder, 'dist') + return basename(src) !== "node_modules"; + }, + }); + const placeAppFolder = join(destinationFolder, "dist"); if (appFolder) { // copy app to template - await cp(appFolder, placeAppFolder, { - recursive: true - }) + await cp(appFolder, placeAppFolder, { recursive: true }); } // 2. Ensure correct configuration - const packageJsonPath = join(appFolder, 'package.json') - const packageJson = await fileExists(packageJsonPath) + const packageJsonPath = join(appFolder, "package.json"); + const packageJson = await fileExists(packageJsonPath); if (!packageJson) { - throw new Error('No package.json found in input folder') + throw new Error("No package.json found in input folder"); } - const netlifyDir = join(destinationFolder, '.netlify') - const netlifyState = join(netlifyDir, 'state.json') + const netlifyDir = join(destinationFolder, ".netlify"); + const netlifyState = join(netlifyDir, "state.json"); - await mkdir(netlifyDir, { recursive: true }) + await mkdir(netlifyDir, { recursive: true }); - await writeFile(netlifyState, `{ "siteId": "${inputs.site}" }`, 'utf-8') + await writeFile(netlifyState, `{ "siteId": "${inputs.site}" }`, "utf-8"); // 3. Package installation - log('Installing packages') - await runWithLiveLogs( - node, - [pnpm, 'install', '--prefer-offline'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - + log("Installing packages"); + const { all } = await runPnpm(destinationFolder, { + signal: abortSignal, + context, + }); // 4. netlify deploy - await runWithLiveLogs( - node, - [pnpm, '--package', 'netlify-cli', 'dlx', 'netlify', 'deploy', '--prod'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome, - NETLIFY_AUTH_TOKEN: inputs.token - }, - cancelSignal: abortSignal + const { all: deployOut } = await runPnpm(destinationFolder, { + args: ["--package", "netlify-cli", "dlx", "netlify", "deploy", "--prod"], + extraEnv: { + NETLIFY_AUTH_TOKEN: inputs.token, }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) + signal: abortSignal, + context, + }); + if (deployOut) log(deployOut); // ensure input folder have a package.json @@ -267,6 +231,6 @@ export const uploadToNetlifyRunner = createActionRunner( // log('Deployed to netlify', deploy) - log('Uploaded to netlify') - } -) + log("Uploaded to netlify"); + }, +); diff --git a/plugins/plugin-netlify/tsconfig.json b/plugins/plugin-netlify/tsconfig.json new file mode 100644 index 00000000..91cbdd09 --- /dev/null +++ b/plugins/plugin-netlify/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-netlify/tsdown.config.ts b/plugins/plugin-netlify/tsdown.config.ts new file mode 100644 index 00000000..b3f281ba --- /dev/null +++ b/plugins/plugin-netlify/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/assets"], +}); diff --git a/plugins/plugin-nvpatch/.oxfmtrc.json b/plugins/plugin-nvpatch/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-nvpatch/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-nvpatch/CHANGELOG.md b/plugins/plugin-nvpatch/CHANGELOG.md new file mode 100644 index 00000000..9b87a2b7 --- /dev/null +++ b/plugins/plugin-nvpatch/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-nvpatch + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-nvpatch/README.md b/plugins/plugin-nvpatch/README.md new file mode 100644 index 00000000..4a2ed4e1 --- /dev/null +++ b/plugins/plugin-nvpatch/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-nvpatch + +Pipelab plugin for managing NV patches. diff --git a/plugins/plugin-nvpatch/package.json b/plugins/plugin-nvpatch/package.json new file mode 100644 index 00000000..64ad2f98 --- /dev/null +++ b/plugins/plugin-nvpatch/package.json @@ -0,0 +1,68 @@ +{ + "name": "@pipelab/plugin-nvpatch", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for patching NW.js game exports", + "keywords": [ + "automation", + "construct3", + "desktop", + "game-export", + "nw.js", + "nwjs", + "patch", + "pipelab", + "pipelab-plugin", + "pipeline" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-nvpatch" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "@types/node": "^24.12.2", + "execa": "9.4.1" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3" + }, + "pipelab": { + "name": "NVPatch", + "description": "Pipelab plugin for patching NW.js game exports", + "icon": { + "type": "icon", + "icon": "mdi-wrench" + } + } +} diff --git a/plugins/plugin-nvpatch/src/ensure.ts b/plugins/plugin-nvpatch/src/ensure.ts new file mode 100644 index 00000000..e3ac66be --- /dev/null +++ b/plugins/plugin-nvpatch/src/ensure.ts @@ -0,0 +1,33 @@ +import { join } from "node:path"; +import { mkdir, access } from "node:fs/promises"; +import { constants } from "node:fs"; +import { execa } from "execa"; + +/** + * Installs NVPatch if not already present. + * @param thirdpartyDir The directory where third-party tools are stored. + * @returns A Promise that resolves to the path of the nvpatch executable. + */ +export const ensureNVPatch = async (thirdpartyDir: string, abortSignal?: AbortSignal) => { + const nvpatchDir = join(thirdpartyDir, "nvpatch"); + const isWindows = process.platform === "win32"; + const executableName = isWindows ? "nvpatch.exe" : "nvpatch"; + const finalPath = join(nvpatchDir, executableName); + + try { + await access(finalPath, constants.X_OK); + return finalPath; + } catch (e) { + console.log(`NVPatch not found at ${finalPath}, installing...`); + } + + await mkdir(nvpatchDir, { recursive: true }); + + console.log(`Installing nvpatch via dotnet tool to ${nvpatchDir}...`); + // This assumes 'dotnet' is available in the system PATH. + await execa("dotnet", ["tool", "install", "--tool-path", nvpatchDir, "Topten.nvpatch"], { + cancelSignal: abortSignal, + }); + + return finalPath; +}; diff --git a/plugins/plugin-nvpatch/src/index.ts b/plugins/plugin-nvpatch/src/index.ts new file mode 100644 index 00000000..0fa977a9 --- /dev/null +++ b/plugins/plugin-nvpatch/src/index.ts @@ -0,0 +1,13 @@ +import { NVPatch, NVPatchRunner } from "./nvpatch"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; + +export default createNodeDefinition({ + nodes: [ + // make and package + { + node: NVPatch, + runner: NVPatchRunner, + }, + ], +}); diff --git a/plugins/plugin-nvpatch/src/nvpatch.ts b/plugins/plugin-nvpatch/src/nvpatch.ts new file mode 100644 index 00000000..d1fd050b --- /dev/null +++ b/plugins/plugin-nvpatch/src/nvpatch.ts @@ -0,0 +1,87 @@ +import { execa } from "execa"; +import semver from "semver"; +import { + createAction, + createActionRunner, + createPathParam, + runWithLiveLogs, +} from "@pipelab/plugin-core"; +import { ensureNVPatch } from "./ensure.js"; + +export const ID = "nvpatch"; + +export const NVPatch = createAction({ + id: ID, + name: "Patch binary", + description: "Apply a compatibility patch to an executable binary file.", + icon: "", + displayString: "`Patch binary ${fmt.param(params['input'], 'primary')}`", + meta: {}, + params: { + input: createPathParam("", { + required: true, + label: "Binary file to patch", + control: { + type: "path", + options: { + properties: ["openFile"], + }, + }, + }), + }, + outputs: {}, +}); + +export const NVPatchRunner = createActionRunner( + async ({ log, inputs, paths, abortSignal, cwd }) => { + const checkDotnetVersion = async (command: string) => { + try { + const { stdout } = await execa(command, ["--version"]); + const version = stdout.trim(); + log(`.NET version found: ${version}`); + if (semver.lt(semver.coerce(version) || "0.0.0", "8.0.0")) { + throw new Error(`.NET version 8 or higher is required. Found version ${version}.`); + } + } catch (e: unknown) { + if (e instanceof Error && e.message?.includes(".NET version 8 or higher is required")) { + throw e; + } + throw new Error( + `.NET runtime not found (command: "${command}"). Please ensure .NET 8 or higher is installed.`, + ); + } + }; + + // run + + log("Ensuring nvpatch is installed..."); + const { thirdparty } = paths; + const nvpatchCommand = await ensureNVPatch(thirdparty, abortSignal); + + // Detect platform and set up platform-specific configuration + const isMacOS = process.platform === "darwin"; + + if (isMacOS) { + // macOS: Use arch -x86_64 with dotnet runtime if needed, + // but let's try the direct command first as ensureNVPatch should provide a working shim + log("Using nvpatch from", nvpatchCommand); + + // Still need to check dotnet as it's a dependency of the tool + await checkDotnetVersion("dotnet"); + } else { + log("Using nvpatch from", nvpatchCommand); + // ensure dotnet runtime is installed + await checkDotnetVersion("dotnet"); + } + + await runWithLiveLogs( + nvpatchCommand, + ["--enable", inputs["input"]], + { + cancelSignal: abortSignal, + }, + log, + ); + log("nvpatch done"); + }, +); diff --git a/plugins/plugin-nvpatch/tsconfig.json b/plugins/plugin-nvpatch/tsconfig.json new file mode 100644 index 00000000..91cbdd09 --- /dev/null +++ b/plugins/plugin-nvpatch/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-nvpatch/tsdown.config.ts b/plugins/plugin-nvpatch/tsdown.config.ts new file mode 100644 index 00000000..7147099e --- /dev/null +++ b/plugins/plugin-nvpatch/tsdown.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, +}); diff --git a/plugins/plugin-poki/.oxfmtrc.json b/plugins/plugin-poki/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-poki/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-poki/CHANGELOG.md b/plugins/plugin-poki/CHANGELOG.md new file mode 100644 index 00000000..e7ac73eb --- /dev/null +++ b/plugins/plugin-poki/CHANGELOG.md @@ -0,0 +1,318 @@ +# @pipelab/plugin-poki + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + - @pipelab/constants@1.0.0-beta.33 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + - @pipelab/constants@1.0.0-beta.32 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + - @pipelab/constants@1.0.0-beta.31 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + - @pipelab/constants@1.0.0-beta.30 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + - @pipelab/constants@1.0.0-beta.29 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + - @pipelab/constants@1.0.0-beta.28 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + - @pipelab/constants@1.0.0-beta.27 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + - @pipelab/constants@1.0.0-beta.26 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + - @pipelab/constants@1.0.0-beta.25 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + - @pipelab/constants@1.0.0-beta.24 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + - @pipelab/constants@1.0.0-beta.23 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + - @pipelab/constants@1.0.0-beta.22 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + - @pipelab/constants@1.0.0-beta.21 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + - @pipelab/constants@1.0.0-beta.20 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-poki/README.md b/plugins/plugin-poki/README.md new file mode 100644 index 00000000..e9a02760 --- /dev/null +++ b/plugins/plugin-poki/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-poki + +Pipelab plugin for Poki platform integration. diff --git a/plugins/plugin-poki/package.json b/plugins/plugin-poki/package.json new file mode 100644 index 00000000..f7c0e23b --- /dev/null +++ b/plugins/plugin-poki/package.json @@ -0,0 +1,69 @@ +{ + "name": "@pipelab/plugin-poki", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for publishing HTML5 games to Poki", + "keywords": [ + "automation", + "deployment", + "game-publishing", + "html5-game", + "pipelab", + "pipelab-plugin", + "pipeline", + "poki", + "web-game" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-poki" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "test": "vitest run", + "build": "tsdown" + }, + "dependencies": { + "@pipelab/constants": "workspace:*", + "@pipelab/plugin-core": "workspace:*" + }, + "devDependencies": { + "@pipelab/test-utils": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "@types/node": "24", + "electron": "32.1.2", + "msw": "2.7.5", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + }, + "pipelab": { + "name": "Poki", + "description": "Pipelab plugin for publishing HTML5 games to Poki", + "icon": "./dist/assets/poki-icon.webp" + } +} diff --git a/src/shared/libs/plugin-poki/assets/poki-icon.webp b/plugins/plugin-poki/src/assets/poki-icon.webp similarity index 100% rename from src/shared/libs/plugin-poki/assets/poki-icon.webp rename to plugins/plugin-poki/src/assets/poki-icon.webp diff --git a/plugins/plugin-poki/src/export.test.ts b/plugins/plugin-poki/src/export.test.ts new file mode 100644 index 00000000..1f065073 --- /dev/null +++ b/plugins/plugin-poki/src/export.test.ts @@ -0,0 +1,120 @@ +import { expect, test, describe, afterEach } from "vitest"; +import { uploadToPokiRunner, POKI_CLI_VERSION } from "./export.js"; +import { mkdir, writeFile, readFile, access, readdir } from "node:fs/promises"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { createSandbox, runAction } from "@pipelab/test-utils"; +import { SandboxFolder } from "@pipelab/constants"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +describe("End-to-End: Poki Upload Action", () => { + let sandbox: Awaited>; + + afterEach(async () => { + if (sandbox) { + await sandbox.remove(); + } + }); + + test( + "should upload to poki using mocked CLI", + async () => { + // 1. Setup Sandbox + sandbox = await createSandbox("poki-e2e"); + const { paths } = sandbox; + + // Seed dummy input assets + await writeFile(join(paths.input, "index.html"), "Test"); + + // 2. Pre-seed a mock Poki CLI to avoid downloads and network issues + // Path matches new flat fetchPackage structure + const relativePokiBin = join( + "user-data", + "packages", + "@poki/cli", + POKI_CLI_VERSION, + "bin", + "index.js", + ); + await sandbox.mockBinary( + relativePokiBin, + ` + const fs = require('fs'); + const path = require('path'); + fs.writeFileSync( + path.join(process.cwd(), 'mock-env.json'), + JSON.stringify({ + XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME, + LOCALAPPDATA: process.env.LOCALAPPDATA, + argv: process.argv + }, null, 2) + ); + console.log('Mock Poki CLI execution'); + process.exit(0); + `, + ); + // Pre-seed node_modules and package.json to skip installation or allow pnpm to run + const pokiDir = join(sandbox.path, "user-data", "packages", "@poki/cli", POKI_CLI_VERSION); + await mkdir(pokiDir, { recursive: true }); + await writeFile( + join(pokiDir, "package.json"), + JSON.stringify({ name: "@poki/cli", version: POKI_CLI_VERSION }), + ); + await mkdir(join(pokiDir, "node_modules"), { recursive: true }); + await writeFile(join(pokiDir, "node_modules", ".keep"), ""); + + // 3. Run Pipeline + try { + await runAction(uploadToPokiRunner, { + inputs: { + "input-folder": paths.input, + project: "poki-game-123", + name: "release-v1", + notes: "E2E test notes", + }, + sandboxPath: sandbox.path, + }); + } catch (e: any) { + console.error("Execution failed:", e.message); + throw e; + } + + // 4. Verification + const tempPath = join(sandbox.path, "user-data", "temp"); + const files = await readdir(tempPath); + const uploadFolder = files.find((f) => f.startsWith("poki-upload-")); + if (!uploadFolder) throw new Error("Temp upload folder not found"); + const tempUploadFolder = join(tempPath, uploadFolder); + + const pokiJsonPath = join(tempUploadFolder, "poki.json"); + console.log("pokiJsonPath test", pokiJsonPath); + await expect(access(pokiJsonPath)).resolves.not.toThrow(); + + const pokiJsonContent = JSON.parse(await readFile(pokiJsonPath, "utf-8")); + expect(pokiJsonContent.game_id).toBe("poki-game-123"); + + // Verify that the Poki CLI process was indeed run with the sandboxed thirdparty environment variables + const mockEnvPath = join(tempUploadFolder, "mock-env.json"); + await expect(access(mockEnvPath)).resolves.not.toThrow(); + const mockEnv = JSON.parse(await readFile(mockEnvPath, "utf-8")); + const expectedSandboxConfigDir = join(sandbox.path, SandboxFolder.ThirdParty); + expect(mockEnv.XDG_CONFIG_HOME).toBe(expectedSandboxConfigDir); + expect(mockEnv.LOCALAPPDATA).toBe(expectedSandboxConfigDir); + + // Verify command arguments + expect(mockEnv.argv).toContain("upload"); + expect(mockEnv.argv).toContain("release-v1"); + expect(mockEnv.argv).toContain("E2E test notes"); + + // Verify that the input files were copied to the dist directory + const absoluteBuildDir = join(tempUploadFolder, pokiJsonContent.build_dir); + const htmlPath = join(absoluteBuildDir, "index.html"); + await expect(access(htmlPath)).resolves.not.toThrow(); + const htmlContent = await readFile(htmlPath, "utf-8"); + expect(htmlContent).toBe("Test"); + }, + 30 * 60 * 1000, + ); +}); diff --git a/plugins/plugin-poki/src/export.ts b/plugins/plugin-poki/src/export.ts new file mode 100644 index 00000000..6a7dac44 --- /dev/null +++ b/plugins/plugin-poki/src/export.ts @@ -0,0 +1,174 @@ +import { + createAction, + createActionRunner, + createPathParam, + createStringParam, + fetchPackage, + runWithLiveLogs, +} from "@pipelab/plugin-core"; +import { dirname, join, delimiter, resolve, relative } from "node:path"; +import { writeFile, cp, access } from "node:fs/promises"; + +export const ID = "poki-upload"; +export const POKI_CLI_VERSION = "0.1.19"; + +export const uploadToPoki = createAction({ + id: ID, + name: "Upload to Poki", + description: "Upload and publish your build to the Poki Developer Portal.", + icon: "", + displayString: + "`Upload ${fmt.param(params['input-folder'], 'primary', 'No path selected')} to Poki game ID ${fmt.param(params['project'], 'primary', 'No project')} (${fmt.param(params['name'], 'primary', 'No version name')})`", + meta: {}, + params: { + "input-folder": createPathParam("", { + required: true, + label: "Folder to upload", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + project: createStringParam("", { + required: true, + label: "Poki Game ID", + description: "Your unique Poki game ID.", + }), + name: createStringParam("", { + required: true, + label: "Version name", + description: "The version label for this build.", + }), + notes: createStringParam("", { + required: true, + label: "Version notes", + description: "Release notes describing the changes in this version.", + }), + }, + outputs: {}, +}); + +export const uploadToPokiRunner = createActionRunner( + async ({ log, inputs, paths, abortSignal, cwd, context }) => { + const { node, thirdparty, pnpm, userData } = paths; + + const absoluteInputFolder = resolve(inputs["input-folder"] as string); + + log("Starting Poki upload action..."); + log(`- Game ID: ${inputs.project}`); + log(`- Version name: ${inputs.name}`); + log(`- Version notes: ${inputs.notes}`); + log(`- Input folder: ${absoluteInputFolder}`); + + log(`Fetching @poki/cli version ${POKI_CLI_VERSION}...`); + const { packageDir: pokiDir } = await fetchPackage("@poki/cli", POKI_CLI_VERSION, { + context, + installDeps: true, + }); + const poki = join(pokiDir, "bin", "index.js"); + log(`Successfully resolved @poki/cli. Executable: ${poki}`); + + const tempUploadFolder = await context.createTempFolder("poki-upload-"); + log(`Created temporary upload root directory: ${tempUploadFolder}`); + + const tempDistFolder = join(tempUploadFolder, "dist"); + log(`Copying build files from "${absoluteInputFolder}" to "${tempDistFolder}"...`); + await cp(absoluteInputFolder, tempDistFolder, { + recursive: true, + }); + + const pokiJsonPath = join(tempUploadFolder, "poki.json"); + + log(`Writing temporary poki.json configuration at: ${pokiJsonPath}`); + const pokiConfig = { + game_id: inputs.project, + build_dir: "dist", + }; + log(`poki.json configuration content:\n${JSON.stringify(pokiConfig, null, 2)}`); + + // create file at the same place the folder to upload + await writeFile(pokiJsonPath, JSON.stringify(pokiConfig, undefined, 2), "utf-8"); + + // Direct Poki CLI to read/write credentials inside Pipelab's thirdparty folder + const sandboxConfigDir = thirdparty; + + log("Checking for sandboxed authentication credentials..."); + const possibleAuthPaths = [ + join(sandboxConfigDir, "poki", "auth.json"), + join(sandboxConfigDir, "Poki", "auth.json"), + ]; + let authFileFound = false; + let foundPath = ""; + for (const p of possibleAuthPaths) { + try { + await access(p); + authFileFound = true; + foundPath = p; + break; + } catch {} + } + + if (authFileFound) { + log(`[Poki] Authentication file found at: ${foundPath}`); + } else { + log( + "[Poki] [WARNING] No authentication file (auth.json) found in the sandboxed config directory.", + ); + log( + "[Poki] [WARNING] Poki CLI might try to open a browser for interactive login, which could hang/fail in headless environments.", + ); + log( + `[Poki] Expected location: ${join(sandboxConfigDir, "poki", "auth.json")} or ${join(sandboxConfigDir, "Poki", "auth.json")}`, + ); + } + + log("Configuring environment variables:"); + log(` - XDG_CONFIG_HOME: ${sandboxConfigDir}`); + log(` - LOCALAPPDATA: ${sandboxConfigDir}`); + log(` - PATH: ${dirname(node)}${delimiter}${process.env.PATH}`); + log(` - MSW_BRIDGE_PORT: ${process.env.MSW_BRIDGE_PORT || "not set"}`); + log(` - NODE_OPTIONS: ${process.env.NODE_OPTIONS || "not set"}`); + + const env: Record = { + ...process.env, + XDG_CONFIG_HOME: sandboxConfigDir, + LOCALAPPDATA: sandboxConfigDir, + PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, + }; + + log( + `Running Poki CLI upload command: node ${poki} upload --name "${inputs.name}" --notes "${inputs.notes}"`, + ); + + await runWithLiveLogs( + node, + [poki, "upload", "--name", inputs.name as string, "--notes", inputs.notes as string], + { + cwd: tempUploadFolder, + env, + cancelSignal: abortSignal, + }, + log, + { + onStderr(data, subprocess) { + log(data); + }, + onStdout(data, subprocess) { + log(data); + }, + }, + ); + + /* + { + "game_id": "c7bfd2ba-e23b-486f-9504-a6f196cb44df", + "build_dir": "dist" + } + npx @poki/cli upload --name "$(git rev-parse --short HEAD)" --notes "$(git log -1 --pretty=%B)" + */ + + log("Uploaded to poki"); + }, +); diff --git a/plugins/plugin-poki/src/index.ts b/plugins/plugin-poki/src/index.ts new file mode 100644 index 00000000..173bd6f2 --- /dev/null +++ b/plugins/plugin-poki/src/index.ts @@ -0,0 +1,32 @@ +import { uploadToPoki, uploadToPokiRunner } from "./export"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; + +export default createNodeDefinition({ + nodes: [ + // make and package + { + node: uploadToPoki, + runner: uploadToPokiRunner, + }, + ], + integrations: [ + { + name: "Poki Developer Profile", + fields: [ + { + key: "gameId", + label: "Game ID", + type: "text", + placeholder: "e.g., poki-game-id", + }, + { + key: "apiKey", + label: "Developer Token", + type: "password", + placeholder: "Poki Developer Token", + }, + ], + }, + ], +}); diff --git a/plugins/plugin-poki/tsconfig.json b/plugins/plugin-poki/tsconfig.json new file mode 100644 index 00000000..b34b76c6 --- /dev/null +++ b/plugins/plugin-poki/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"], + "skipLibCheck": true + }, + "include": ["src"], + "references": [ + { + "path": "../../packages/constants" + }, + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-poki/tsdown.config.ts b/plugins/plugin-poki/tsdown.config.ts new file mode 100644 index 00000000..b3f281ba --- /dev/null +++ b/plugins/plugin-poki/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/assets"], +}); diff --git a/plugins/plugin-steam/.oxfmtrc.json b/plugins/plugin-steam/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-steam/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-steam/CHANGELOG.md b/plugins/plugin-steam/CHANGELOG.md new file mode 100644 index 00000000..0d92453e --- /dev/null +++ b/plugins/plugin-steam/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-steam + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-steam/README.md b/plugins/plugin-steam/README.md new file mode 100644 index 00000000..0c45f3a6 --- /dev/null +++ b/plugins/plugin-steam/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-steam + +Pipelab plugin for automating uploads to Steam using SteamCMD. diff --git a/plugins/plugin-steam/package.json b/plugins/plugin-steam/package.json new file mode 100644 index 00000000..1f1ba354 --- /dev/null +++ b/plugins/plugin-steam/package.json @@ -0,0 +1,73 @@ +{ + "name": "@pipelab/plugin-steam", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for publishing games to Steam via SteamCMD", + "keywords": [ + "automation", + "deployment", + "game-development", + "game-publishing", + "pipelab", + "pipelab-plugin", + "pipeline", + "steam", + "steamcmd", + "valve" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-steam" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown", + "test": "vitest run -c tests/e2e/vitest.config.mts" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "@types/node": "^24.12.2", + "execa": "9.4.1" + }, + "devDependencies": { + "@pipelab/test-utils": "workspace:*", + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + }, + "pipelab": { + "name": "Steam", + "description": "Pipelab plugin for publishing games to Steam via SteamCMD", + "icon": "./dist/steam.webp" + }, + "test": { + "env": { + "NODE_ENV": "development" + } + } +} diff --git a/plugins/plugin-steam/src/declarations.d.ts b/plugins/plugin-steam/src/declarations.d.ts new file mode 100644 index 00000000..c5608a8a --- /dev/null +++ b/plugins/plugin-steam/src/declarations.d.ts @@ -0,0 +1 @@ +declare module "*.webp"; diff --git a/plugins/plugin-steam/src/index.ts b/plugins/plugin-steam/src/index.ts new file mode 100644 index 00000000..7e1590af --- /dev/null +++ b/plugins/plugin-steam/src/index.ts @@ -0,0 +1,35 @@ +import { uploadToSteam, uploadToSteamRunner } from "./upload-to-steam"; +import { createNodeDefinition } from "@pipelab/plugin-core"; + +export default createNodeDefinition({ + nodes: [ + { + node: uploadToSteam, + runner: uploadToSteamRunner, + }, + ], + integrations: [ + { + name: "Steam SDK", + fields: [ + { + key: "sdk", + label: "Steam SDK Path", + type: "directory", + placeholder: "e.g., /home/user/steam-sdk", + }, + ], + }, + { + name: "Steam Account", + fields: [ + { + key: "username", + label: "Steam Username", + type: "text", + placeholder: "e.g., steam_user", + }, + ], + }, + ], +}); diff --git a/src/shared/libs/plugin-steam/steam.webp b/plugins/plugin-steam/src/steam.webp similarity index 100% rename from src/shared/libs/plugin-steam/steam.webp rename to plugins/plugin-steam/src/steam.webp diff --git a/plugins/plugin-steam/src/upload-to-steam.ts b/plugins/plugin-steam/src/upload-to-steam.ts new file mode 100644 index 00000000..2fd5aa87 --- /dev/null +++ b/plugins/plugin-steam/src/upload-to-steam.ts @@ -0,0 +1,308 @@ +import { join, dirname, basename } from "node:path"; +import { platform } from "node:os"; +import { chmod, mkdir, writeFile, cp } from "node:fs/promises"; +import { + createAction, + createActionRunner, + createPathParam, + createStringParam, + fileExists, + runWithLiveLogs, +} from "@pipelab/plugin-core"; +import { checkSteamAuth, openExternalTerminal } from "./utils"; +import { ExternalCommandError } from "@pipelab/plugin-core"; + +// https://github.com/ztgasdf/steampkg?tab=readme-ov-file#account-management + +// How to login +// Do it at least once +// sdk/tools/ContentBuilder/builder_linux/steamcmd.sh +login User +quit + +export const ID = "steam-upload"; + +export const uploadToSteam = createAction({ + id: ID, + name: "Upload to Steam", + description: "Upload your build directory directly to the Steamworks platform.", + icon: "", + displayString: "`Upload ${fmt.param(params['folder'], 'primary')} to steam`", + meta: {}, + params: { + sdk: createPathParam("", { + required: true, + label: "Steam SDK Folder", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + username: createStringParam("", { + required: true, + label: "Username", + }), + appId: createStringParam("", { + required: true, + label: "App ID", + }), + depotId: createStringParam("", { + required: true, + label: "Depot ID", + }), + description: createStringParam("", { + required: true, + label: "Build Description", + }), + folder: createPathParam("", { + required: true, + label: "Folder to upload", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), + // enableDRM: { + // value: false, + // label: 'Enable DRM', + // control: { + // type: 'boolean' + // } + // }, + // binaryToPatch: createPathParam('', { + // label: 'Binary to patch', + // control: { + // type: 'path', + // options: { + // properties: ['openFile'] + // } + // } + // }) + }, + outputs: { + "script-path": { + label: "Script path", + value: "", + }, + "output-folder": { + label: "Output folder", + value: "", + }, + status: { + label: "Status", + value: "", + }, + }, +}); + +export const uploadToSteamRunner = createActionRunner( + async ({ log, inputs, cwd, abortSignal, setOutput }) => { + const folder = inputs.folder as string; + const appId = inputs.appId as string; + const sdk = inputs.sdk as string; + const depotId = inputs.depotId as string; + const username = inputs.username as string; + const description = inputs.description as string; + + log(`uploading "${folder}" to steam`); + + const errorMap = { + 6: `No connection to content server. Your depot id (${depotId}) may be invalid`, + }; + + const isSDKExisting = await fileExists(sdk); + if (!isSDKExisting) { + throw new Error(`You must enter a valid path to the Steam SDK`); + } + + let builderFolder = "builder"; + if (platform() === "linux") { + builderFolder += "_linux"; + } else if (platform() === "darwin") { + builderFolder += "_osx"; + } + + const cmd = "steamcmd"; + const extensions = platform() === "win32" ? [".exe", ".cmd", ".bat"] : [".sh"]; + + let cmdFinal = ""; + let steamcmdPath = ""; + + for (const ext of extensions) { + const p = join(sdk as string, "tools", "ContentBuilder", builderFolder, cmd + ext); + if (await fileExists(p)) { + steamcmdPath = p; + cmdFinal = cmd + ext; + break; + } + } + + // Fallback if none found (to maintain previous behavior of joining default) + if (!steamcmdPath) { + if (platform() === "linux" || platform() === "darwin") { + cmdFinal = "steamcmd.sh"; + } else if (platform() === "win32") { + cmdFinal = "steamcmd.exe"; + } + steamcmdPath = join(sdk as string, "tools", "ContentBuilder", builderFolder, cmdFinal); + } + + console.log("steamcmdPath", steamcmdPath); + + if (platform() === "linux" || platform() === "darwin") { + if (platform() === "linux") { + log('Adding "execute" permissions to linux binary'); + const steamcmdBinaryPath = join( + sdk, + "tools", + "ContentBuilder", + builderFolder, + "linux32", + cmd, + ); + await chmod(steamcmdBinaryPath, 0o755); + const steamcmdBinaryErrorReporterPath = join( + sdk, + "tools", + "ContentBuilder", + builderFolder, + "linux32", + "steamerrorreporter", + ); + await chmod(steamcmdBinaryErrorReporterPath, 0o755); + } + + if (platform() === "darwin") { + const steamcmdBinaryPath = join(sdk, "tools", "ContentBuilder", builderFolder, cmd); + log('Adding "execute" permissions to darwin binary'); + await chmod(steamcmdBinaryPath, 0o755); + } + + log('Adding "execute" permissions to binary'); + await chmod(steamcmdPath, 0o755); + } + + const buildOutput = join(cwd, "steam", "output"); + const scriptPath = join(cwd, "steam", "script.vdf"); + + setOutput("script-path", scriptPath); + setOutput("output-folder", buildOutput); + + await mkdir(buildOutput, { + recursive: true, + }); + + await mkdir(dirname(scriptPath), { + recursive: true, + }); + + const script = `"AppBuild" +{ + "AppID" "${appId}" // your AppID + "Desc" "${description}" // internal description for this build + + "ContentRoot" "${folder}" // root content folder, relative to location of this file + "BuildOutput" "${buildOutput}" // build output folder for build logs and build cache files + + "Depots" + { + "${depotId}" // your DepotID + { + "FileMapping" + { + "LocalPath" "*" // all files from contentroot folder + "DepotPath" "." // mapped into the root of the depot + "recursive" "1" // include all subfolders + } + } + } +}`; + + console.log("script", script); + /* + // TEMPORARILY DISABLED AUTO-LOGIN + // Context: Pipelab should not try to interactively authenticate mid-pipeline execution. + // Opening an external terminal mid-run breaks automated CI/CD pipelines and causes hangs + // when SteamCMD waits for 2FA or password inputs. + // TODO: Move explicit authentication (openExternalTerminal) to a button in the Plugin Settings UI. + // The pipeline runner will now just attempt to run the build natively and fail fast if the cache is expired. + + const isAuthenticated = await checkSteamAuth({ + context: { + log, + abortSignal, + }, + scriptPath, + steamcmdPath, + username, + }); + + log("isAuthenticated", JSON.stringify(isAuthenticated)); + + if (isAuthenticated.success === false) { + log("Opening terminal with interactive login"); + await openExternalTerminal(steamcmdPath, ["+login", username, "+quit"], { + cancelSignal: abortSignal, + }); + const isAuthenticatedNow = await checkSteamAuth({ + context: { + log, + abortSignal, + }, + scriptPath, + steamcmdPath, + username, + }); + if (isAuthenticatedNow.success === false) { + throw new Error("Not authenticated"); + } + } + */ + + log("Writing script"); + await writeFile(scriptPath, script, { + encoding: "utf8", + signal: abortSignal, + }); + + log("Executing steamcmd"); + + // Should be authed here + try { + await runWithLiveLogs( + steamcmdPath, + ["+login", username, "+run_app_build", scriptPath, "+quit"], + { + shell: false, + }, + log, + { + onStdout: (data) => { + log("[steamcmd]", data); + }, + onStderr: (data) => { + log("[steamcmd]", data); + }, + }, + abortSignal, + ); + } catch (e) { + if (e instanceof ExternalCommandError) { + const code = e.code as keyof typeof errorMap; + const message = + code in errorMap ? errorMap[code] : "SteamCmd error:" + e.code + " " + e.message; + throw new Error(message); + } else if (e instanceof Error) { + console.error(e); + throw new Error("Error:" + e.message); + } else { + throw new Error("unknwon error"); + } + } + + setOutput("status", "success"); + log("Done uploading"); + }, +); diff --git a/src/shared/libs/plugin-steam/utils.ts b/plugins/plugin-steam/src/utils.ts similarity index 55% rename from src/shared/libs/plugin-steam/utils.ts rename to plugins/plugin-steam/src/utils.ts index f5fddf54..04232f10 100644 --- a/src/shared/libs/plugin-steam/utils.ts +++ b/plugins/plugin-steam/src/utils.ts @@ -1,74 +1,81 @@ -import { runWithLiveLogsPTY } from '../plugin-core' -import { Options as ExecaOptions } from 'execa' +import { runWithLiveLogs } from "@pipelab/plugin-core"; +import { execa, Options as ExecaOptions } from "execa"; +import os from "node:os"; export type Options = { - steamcmdPath: string - username: string - scriptPath: string + steamcmdPath: string; + username: string; + scriptPath: string; context: { - log: typeof console.log - abortSignal: AbortSignal - } -} + log: typeof console.log; + abortSignal: AbortSignal; + }; +}; export const checkSteamAuth = async (options: Options) => { - let error: 'LOGGED_OUT' | 'UNKNOWN' | undefined = undefined + let error: "LOGGED_OUT" | "UNKNOWN" | undefined = undefined; try { - await runWithLiveLogsPTY( + await runWithLiveLogs( options.steamcmdPath, - ['+login', options.username, '+quit'], - {}, + ["+login", options.username, "+quit"], + { + shell: false, + }, options.context.log, { onStdout: (data, subprocess) => { - options.context.log('[Steam Cmd]', data) - // TODO: handle password input dynamically - if (data.includes('Cached credentials not found')) { - error = 'LOGGED_OUT' - - subprocess.kill() + options.context.log("[Steam Cmd]", data); + // Detect if SteamCMD is prompting for input or failed to auth automatically + const lowercaseData = data.toLowerCase(); + if ( + lowercaseData.includes("cached credentials not found") || + lowercaseData.includes("password:") || + lowercaseData.includes("steam guard") || + lowercaseData.includes("two-factor code") || + lowercaseData.includes("failed (") || + lowercaseData.includes("failed to login") + ) { + error = "LOGGED_OUT"; + subprocess.kill(); } - } + }, }, - options.context.abortSignal - ) + options.context.abortSignal, + ); } catch (e) { - console.error('e', e) + console.error("e", e); if (!error) { - error = 'UNKNOWN' + error = "UNKNOWN"; } } if (error) { return { success: false, - error - } + error, + }; } return { - success: true - } -} + success: true, + }; +}; export const openExternalTerminal = async ( command: string, args: string[] = [], options: ExecaOptions = {}, - keepOpen = false + keepOpen = false, ) => { - const { execa } = await import('execa') - const os = await import('os') - - const platform = process.platform + const platform = process.platform; - if (platform === 'darwin') { + if (platform === "darwin") { // macOS: open in Terminal.app - const shellCommand = `${command} ${args.join(' ')}; echo "You can now close this window"`; + const shellCommand = `${command} ${args.join(" ")}; echo "You can now close this window"`; // Escape for AppleScript string literal const escapedShellCommand = shellCommand - .replace(/\\/g, '\\\\') // Must escape backslashes first + .replace(/\\/g, "\\\\") // Must escape backslashes first .replace(/"/g, '\\"'); // Then escape double quotes let osaScript: string; @@ -89,12 +96,12 @@ export const openExternalTerminal = async ( end tell`; } - return execa('osascript', ['-e', osaScript], options); - } else if (platform === 'linux') { + return execa("osascript", ["-e", osaScript], options); + } else if (platform === "linux") { // Linux: use $TERMINAL, $TERM, or fallback to xterm - const terminal = process.env.TERMINAL ?? process.env.TERM ?? 'xterm' - return execa(terminal, ['-e', command, ...args], options) - } else if (platform === 'win32') { + const terminal = process.env.TERMINAL ?? process.env.TERM ?? "xterm"; + return execa(terminal, ["-e", command, ...args], options); + } else if (platform === "win32") { // Windows: try PowerShell by default, fallback to CMD if needed // try { // console.log('verifying') @@ -114,12 +121,12 @@ end tell`; // } catch (error) { // Oops! No PowerShell? Fallback to CMD. return execa( - 'cmd.exe', - [keepOpen ? '/k' : '/c', 'start', 'cmd.exe', '/c', command, ...args], - options - ) + "cmd.exe", + [keepOpen ? "/k" : "/c", "start", '""', "/WAIT", "cmd.exe", "/c", command, ...args], + options, + ); // } } else { - throw new Error('Unsupported platform: ' + platform) + throw new Error("Unsupported platform: " + platform); } -} +}; diff --git a/plugins/plugin-steam/tests/e2e/steam.spec.ts b/plugins/plugin-steam/tests/e2e/steam.spec.ts new file mode 100644 index 00000000..0541a0dd --- /dev/null +++ b/plugins/plugin-steam/tests/e2e/steam.spec.ts @@ -0,0 +1,103 @@ +import { expect, test, describe, afterEach } from "vitest"; +import { mkdir, writeFile, access } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { createSandbox, runAction, isWindows, isLinux, isMac } from "@pipelab/test-utils"; +import { uploadToSteamRunner } from "../../src/upload-to-steam"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +describe("End-to-End: Steam Integration", () => { + let sandbox: Awaited>; + + afterEach(async () => { + if (sandbox) { + await sandbox.remove(); + } + }); + + test( + "should mock a steam upload action using a single file", + async () => { + sandbox = await createSandbox("steam-e2e"); + // 1. Setup mock Steam SDK + const mockSdkPath = join(sandbox.path, "mock-steam-sdk"); + let builderFolder = "builder"; + if (process.platform === "linux") { + builderFolder += "_linux"; + } else if (process.platform === "darwin") { + builderFolder += "_osx"; + } + + const relativeSteamCmd = join( + "mock-steam-sdk", + "tools", + "ContentBuilder", + builderFolder, + "steamcmd", + ); + + // Create the mock steamcmd script that simulates a successful login and build + const mockScript = isWindows + ? `@echo off\necho Authenticated\nexit /b 0` + : `#!/bin/bash\necho "Authenticated"\nexit 0`; + + await sandbox.mockBinary(relativeSteamCmd, mockScript); + + if (isLinux) { + const linux32Dir = join( + "mock-steam-sdk", + "tools", + "ContentBuilder", + builderFolder, + "linux32", + ); + await sandbox.mockBinary(join(linux32Dir, "steamcmd"), undefined, { extension: false }); + await sandbox.mockBinary(join(linux32Dir, "steamerrorreporter"), undefined, { + extension: false, + }); + } + + if (isMac) { + await sandbox.mockBinary( + join("mock-steam-sdk", "tools", "ContentBuilder", builderFolder, "steamcmd"), + undefined, + { extension: false }, + ); + } + + // 2. Setup a dummy single file to upload + const uploadFolder = join(sandbox.path, "to-upload"); + await mkdir(uploadFolder, { recursive: true }); + await writeFile(join(uploadFolder, "test-file.txt"), "This is a test file for steam upload."); + + // 3. Run the action directly + const inputs = { + sdk: mockSdkPath, + username: "testuser", + appId: "123456", + depotId: "654321", + description: "Test Build", + folder: uploadFolder, + }; + + const result = await runAction(uploadToSteamRunner, { + inputs, + sandboxPath: sandbox.path, + }); + + // 4. Verification + const outputs = result.outputs; + expect(outputs).toBeDefined(); + expect(outputs["script-path"]).toBeDefined(); + expect(outputs["output-folder"]).toBeDefined(); + expect(outputs["status"]).toBe("success"); + + // Verify files exist + await expect(access(outputs["script-path"] as string)).resolves.not.toThrow(); + await expect(access(outputs["output-folder"] as string)).resolves.not.toThrow(); + }, + 30 * 60 * 1000, + ); // 30 minutes timeout for real build +}); diff --git a/plugins/plugin-steam/tests/e2e/vitest.config.mts b/plugins/plugin-steam/tests/e2e/vitest.config.mts new file mode 100644 index 00000000..148278ad --- /dev/null +++ b/plugins/plugin-steam/tests/e2e/vitest.config.mts @@ -0,0 +1,20 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + fileParallelism: false, + testTimeout: 1800000, + hookTimeout: 60000, + maxWorkers: 1, + minWorkers: 1, + poolOptions: { + forks: { + singleFork: true, + }, + }, + include: ["**/*.spec.ts"], + root: "tests/e2e", + environment: "node", + env: { NODE_ENV: "development", PIPELAB_DISABLE_HISTORY: "true" }, + }, +}); diff --git a/plugins/plugin-steam/tsconfig.json b/plugins/plugin-steam/tsconfig.json new file mode 100644 index 00000000..91cbdd09 --- /dev/null +++ b/plugins/plugin-steam/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-steam/tsdown.config.ts b/plugins/plugin-steam/tsdown.config.ts new file mode 100644 index 00000000..8d9c6d91 --- /dev/null +++ b/plugins/plugin-steam/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/steam.webp"], +}); diff --git a/plugins/plugin-system/.oxfmtrc.json b/plugins/plugin-system/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-system/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-system/CHANGELOG.md b/plugins/plugin-system/CHANGELOG.md new file mode 100644 index 00000000..1949e079 --- /dev/null +++ b/plugins/plugin-system/CHANGELOG.md @@ -0,0 +1,304 @@ +# @pipelab/plugin-system + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + +## 1.0.0-beta.9 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + +## 1.0.0-beta.4 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 diff --git a/plugins/plugin-system/README.md b/plugins/plugin-system/README.md new file mode 100644 index 00000000..5dd5d214 --- /dev/null +++ b/plugins/plugin-system/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-system + +Pipelab plugin for system-level operations and environment info. diff --git a/plugins/plugin-system/package.json b/plugins/plugin-system/package.json new file mode 100644 index 00000000..c3a2fdea --- /dev/null +++ b/plugins/plugin-system/package.json @@ -0,0 +1,67 @@ +{ + "name": "@pipelab/plugin-system", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for running shell commands and system operations", + "keywords": [ + "automation", + "cli", + "command", + "exec", + "pipelab", + "pipelab-plugin", + "pipeline", + "scripting", + "shell", + "system" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-system" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown" + }, + "dependencies": { + "@pipelab/plugin-core": "workspace:*", + "@types/node": "^24.12.2" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3" + }, + "pipelab": { + "name": "System", + "description": "Pipelab plugin for running shell commands and system operations", + "icon": { + "type": "icon", + "icon": "mdi-cog-outline" + } + } +} diff --git a/plugins/plugin-system/src/alert.ts b/plugins/plugin-system/src/alert.ts new file mode 100644 index 00000000..8d6296d7 --- /dev/null +++ b/plugins/plugin-system/src/alert.ts @@ -0,0 +1,57 @@ +import { + createAction, + createActionRunner, + createStringParam, + usePluginAPI, +} from "@pipelab/plugin-core"; + +export const ID = "system:alert"; + +export type Data = { + text: string; +}; + +export const alertAction = createAction({ + id: ID, + name: "Alert", + description: "Display a popup alert dialog with a message.", + icon: "", + displayString: "`Show alert: ${fmt.param(params.message ?? 'No message')}`", + meta: {}, + params: { + message: createStringParam("", { + required: true, + label: "Message", + }), + }, + + outputs: { + answer: { + label: "Answer", + value: "", + }, + }, +}); + +export const alertActionRunner = createActionRunner( + async ({ log, inputs, setOutput, browserWindow }) => { + if (!browserWindow) { + log(`Alert (Headless): ${inputs.message}`); + setOutput("answer", "ok"); + return; + } + + browserWindow.flashFrame(true); + const api = usePluginAPI(browserWindow); + // 'cancel' | 'ok' + const _answer = await api.execute("dialog:alert", { + message: inputs.message, + }); + + if (_answer.type === "success") { + setOutput("answer", _answer.result.answer); + } else { + throw new Error(_answer.ipcError); + } + }, +); diff --git a/plugins/plugin-system/src/index.ts b/plugins/plugin-system/src/index.ts new file mode 100644 index 00000000..934e4aa5 --- /dev/null +++ b/plugins/plugin-system/src/index.ts @@ -0,0 +1,31 @@ +import { createNodeDefinition } from "@pipelab/plugin-core"; +import { logAction, logActionRunner } from "./log"; +import { manualEvent, manualEvaluator } from "./manual"; +import { alertAction, alertActionRunner } from "./alert"; +import { promptAction, promptActionRunner } from "./prompt"; +import { sleepAction, sleepActionRunner } from "./sleep"; + +export default createNodeDefinition({ + nodes: [ + { + node: logAction, + runner: logActionRunner, + }, + { + node: manualEvent, + runner: manualEvaluator, + }, + { + node: alertAction, + runner: alertActionRunner, + }, + { + node: promptAction, + runner: promptActionRunner, + }, + { + node: sleepAction, + runner: sleepActionRunner, + }, + ], +}); diff --git a/plugins/plugin-system/src/join.ts b/plugins/plugin-system/src/join.ts new file mode 100644 index 00000000..5731b01f --- /dev/null +++ b/plugins/plugin-system/src/join.ts @@ -0,0 +1,57 @@ +import { createExpression, createExpressionRunner } from "@pipelab/plugin-core"; + +export const ID = "join"; + +export type Data = { + value: string; +}; + +const DEFAULT_SEPARATOR = ", "; + +export const join = createExpression({ + id: ID, + name: "Join", + description: "Join values", + displayString: "Join {{ params.value }}", + icon: "", + meta: {}, + params: { + input: { + required: true, + label: "Input", + value: [] as string[], + control: { + type: "input", + options: { + kind: "text", + }, + }, + }, + separator: { + required: true, + label: "Separator", + value: DEFAULT_SEPARATOR, + control: { + type: "input", + options: { + kind: "text", + }, + }, + }, + }, + + outputs: { + value: { + label: "Value", + value: "", + }, + }, +}); + +export const evaluator = createExpressionRunner(async ({ inputs }) => { + const input = (inputs?.input ?? []) as unknown as string[]; + const separator = (inputs?.separator ?? DEFAULT_SEPARATOR) as unknown as string; + + const result = input.join(separator); + return result; +}); diff --git a/plugins/plugin-system/src/log.ts b/plugins/plugin-system/src/log.ts new file mode 100644 index 00000000..d3c3e17d --- /dev/null +++ b/plugins/plugin-system/src/log.ts @@ -0,0 +1,28 @@ +import { createAction, createActionRunner, createStringParam } from "@pipelab/plugin-core"; + +export const ID = "log"; + +export type Data = { + text: string; +}; + +export const logAction = createAction({ + id: ID, + name: "Log", + description: "Write a custom message to the execution log.", + icon: "", + displayString: '`Log message: "${fmt.param(params.message)}"`', + meta: {}, + params: { + message: createStringParam("", { + required: true, + label: "Message", + }), + }, + + outputs: {}, +}); + +export const logActionRunner = createActionRunner(async ({ log, inputs }) => { + log(`${inputs.message ?? ""}`); +}); diff --git a/src/shared/libs/plugin-system/manual.ts b/plugins/plugin-system/src/manual.ts similarity index 100% rename from src/shared/libs/plugin-system/manual.ts rename to plugins/plugin-system/src/manual.ts diff --git a/plugins/plugin-system/src/prompt.ts b/plugins/plugin-system/src/prompt.ts new file mode 100644 index 00000000..82bd3367 --- /dev/null +++ b/plugins/plugin-system/src/prompt.ts @@ -0,0 +1,57 @@ +import { + createAction, + createActionRunner, + createStringParam, + usePluginAPI, +} from "@pipelab/plugin-core"; + +export const ID = "system:prompt"; + +export type Data = { + text: string; +}; + +export const promptAction = createAction({ + id: ID, + name: "Prompt", + description: "Display a dialog box asking the user to input text.", + icon: "", + displayString: "`Ask for input: ${fmt.param(params.message ?? 'No message')}`", + meta: {}, + params: { + message: createStringParam("", { + required: true, + label: "Message", + }), + }, + + outputs: { + answer: { + label: "Answer", + value: "", + }, + }, +}); + +export const promptActionRunner = createActionRunner( + async ({ log, inputs, setOutput, browserWindow }) => { + if (!browserWindow) { + throw new Error("Prompt action cannot be executed in headless mode because it requires user input."); + } + + browserWindow.flashFrame(true); + const api = usePluginAPI(browserWindow); + // 'cancel' | 'ok' + const _answer = await api.execute("dialog:prompt", { + message: inputs.message, + }); + + log("_answer", _answer); + + if (_answer.type === "success") { + setOutput("answer", _answer.result.answer); + } else { + throw new Error(_answer.ipcError); + } + }, +); diff --git a/plugins/plugin-system/src/sleep.ts b/plugins/plugin-system/src/sleep.ts new file mode 100644 index 00000000..38beee01 --- /dev/null +++ b/plugins/plugin-system/src/sleep.ts @@ -0,0 +1,48 @@ +import { createAction, createActionRunner, createNumberParam } from "@pipelab/plugin-core"; + +export const ID = "system:sleep"; + +export const sleepAction = createAction({ + id: ID, + name: "Wait", + description: "Pause the pipeline execution for a specified duration.", + icon: "", + displayString: "`Wait for ${fmt.param(params.duration)}ms`", + meta: {}, + params: { + duration: createNumberParam(2000, { + required: true, + label: "Duration", + }), + }, + + outputs: {}, +}); + +const sleep = (duration: number) => new Promise((resolve) => setTimeout(resolve, duration)); + +export const sleepActionRunner = createActionRunner( + async ({ inputs, abortSignal }) => { + if (abortSignal.aborted) { + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + throw abortError; + } + + await new Promise((resolve, reject) => { + const onAbort = () => { + clearTimeout(timeout); + const abortError = new Error("Aborted"); + abortError.name = "AbortError"; + reject(abortError); + }; + + abortSignal.addEventListener("abort", onAbort); + + const timeout = setTimeout(() => { + abortSignal.removeEventListener("abort", onAbort); + resolve(); + }, inputs.duration); + }); + }, +); diff --git a/plugins/plugin-system/tsconfig.json b/plugins/plugin-system/tsconfig.json new file mode 100644 index 00000000..91cbdd09 --- /dev/null +++ b/plugins/plugin-system/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "references": [ + { + "path": "../plugin-core" + } + ] +} diff --git a/plugins/plugin-system/tsdown.config.ts b/plugins/plugin-system/tsdown.config.ts new file mode 100644 index 00000000..7147099e --- /dev/null +++ b/plugins/plugin-system/tsdown.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, +}); diff --git a/plugins/plugin-tauri/.oxfmtrc.json b/plugins/plugin-tauri/.oxfmtrc.json new file mode 100644 index 00000000..0b5c04cb --- /dev/null +++ b/plugins/plugin-tauri/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "ignorePatterns": ["dist", "out", "node_modules", "bin", "**/*.d.ts"] +} diff --git a/plugins/plugin-tauri/CHANGELOG.md b/plugins/plugin-tauri/CHANGELOG.md new file mode 100644 index 00000000..902df27b --- /dev/null +++ b/plugins/plugin-tauri/CHANGELOG.md @@ -0,0 +1,374 @@ +# @pipelab/plugin-tauri + +## 1.0.0-beta.38 + +### Patch Changes + +- - +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.38 + - @pipelab/constants@1.0.0-beta.33 + - @pipelab/shared@1.0.0-beta.32 + +## 1.0.0-beta.37 + +### Patch Changes + +- improve dark theme and improve build history +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.37 + - @pipelab/constants@1.0.0-beta.32 + - @pipelab/shared@1.0.0-beta.31 + +## 1.0.0-beta.36 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.36 + - @pipelab/constants@1.0.0-beta.31 + - @pipelab/shared@1.0.0-beta.30 + +## 1.0.0-beta.35 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.35 + - @pipelab/constants@1.0.0-beta.30 + - @pipelab/shared@1.0.0-beta.29 + +## 1.0.0-beta.34 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.34 + - @pipelab/constants@1.0.0-beta.29 + - @pipelab/shared@1.0.0-beta.28 + +## 1.0.0-beta.33 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.33 + - @pipelab/constants@1.0.0-beta.28 + - @pipelab/shared@1.0.0-beta.27 + +## 1.0.0-beta.32 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.32 + - @pipelab/constants@1.0.0-beta.27 + - @pipelab/shared@1.0.0-beta.26 + +## 1.0.0-beta.31 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.31 + - @pipelab/constants@1.0.0-beta.26 + - @pipelab/shared@1.0.0-beta.25 + +## 1.0.0-beta.30 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.30 + - @pipelab/constants@1.0.0-beta.25 + - @pipelab/shared@1.0.0-beta.24 + +## 1.0.0-beta.29 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.29 + - @pipelab/constants@1.0.0-beta.24 + - @pipelab/shared@1.0.0-beta.23 + +## 1.0.0-beta.28 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.28 + +## 1.0.0-beta.27 + +### Patch Changes + +- Updated dependencies + - @pipelab/shared@1.0.0-beta.22 + - @pipelab/plugin-core@1.0.0-beta.27 + +## 1.0.0-beta.26 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.26 + - @pipelab/constants@1.0.0-beta.23 + - @pipelab/shared@1.0.0-beta.21 + +## 1.0.0-beta.25 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.25 + - @pipelab/constants@1.0.0-beta.22 + - @pipelab/shared@1.0.0-beta.20 + +## 1.0.0-beta.24 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.24 + - @pipelab/constants@1.0.0-beta.21 + - @pipelab/shared@1.0.0-beta.19 + +## 1.0.0-beta.23 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.23 + - @pipelab/constants@1.0.0-beta.20 + - @pipelab/shared@1.0.0-beta.18 + +## 1.0.0-beta.22 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.22 + - @pipelab/constants@1.0.0-beta.19 + - @pipelab/shared@1.0.0-beta.17 + +## 1.0.0-beta.21 + +### Patch Changes + +- df +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.21 + - @pipelab/constants@1.0.0-beta.18 + - @pipelab/shared@1.0.0-beta.16 + +## 1.0.0-beta.20 + +### Patch Changes + +- sdsd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.20 + - @pipelab/constants@1.0.0-beta.17 + - @pipelab/shared@1.0.0-beta.15 + +## 1.0.0-beta.19 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.19 + - @pipelab/constants@1.0.0-beta.16 + - @pipelab/shared@1.0.0-beta.14 + +## 1.0.0-beta.18 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.18 + - @pipelab/constants@1.0.0-beta.15 + - @pipelab/shared@1.0.0-beta.13 + +## 1.0.0-beta.17 + +### Patch Changes + +- qs +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.17 + - @pipelab/constants@1.0.0-beta.14 + - @pipelab/shared@1.0.0-beta.12 + +## 1.0.0-beta.16 + +### Patch Changes + +- sd +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.16 + - @pipelab/constants@1.0.0-beta.13 + - @pipelab/shared@1.0.0-beta.11 + +## 1.0.0-beta.15 + +### Patch Changes + +- s +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.15 + - @pipelab/constants@1.0.0-beta.12 + - @pipelab/shared@1.0.0-beta.10 + +## 1.0.0-beta.14 + +### Patch Changes + +- fg +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.14 + - @pipelab/constants@1.0.0-beta.11 + - @pipelab/shared@1.0.0-beta.9 + +## 1.0.0-beta.13 + +### Patch Changes + +- changes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.13 + - @pipelab/constants@1.0.0-beta.10 + - @pipelab/shared@1.0.0-beta.8 + +## 1.0.0-beta.12 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.12 + - @pipelab/constants@1.0.0-beta.9 + - @pipelab/shared@1.0.0-beta.7 + +## 1.0.0-beta.11 + +### Patch Changes + +- add shims +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.11 + +## 1.0.0-beta.10 + +### Patch Changes + +- fixes +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.10 + - @pipelab/constants@1.0.0-beta.8 + - @pipelab/shared@1.0.0-beta.6 + +## 1.0.0-beta.9 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.7 + - @pipelab/plugin-core@1.0.0-beta.9 + +## 1.0.0-beta.8 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.8 + +## 1.0.0-beta.7 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.7 + - @pipelab/constants@1.0.0-beta.6 + - @pipelab/shared@1.0.0-beta.5 + +## 1.0.0-beta.6 + +### Patch Changes + +- beta tag +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.6 + - @pipelab/constants@1.0.0-beta.5 + - @pipelab/shared@1.0.0-beta.4 + +## 1.0.0-beta.5 + +### Patch Changes + +- bump +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.5 + - @pipelab/constants@1.0.0-beta.4 + - @pipelab/shared@1.0.0-beta.3 + +## 1.0.0-beta.4 + +### Patch Changes + +- Updated dependencies + - @pipelab/constants@1.0.0-beta.3 + - @pipelab/plugin-core@1.0.0-beta.4 + +## 1.0.0-beta.3 + +### Patch Changes + +- update +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.3 + - @pipelab/constants@1.0.0-beta.2 + - @pipelab/shared@1.0.0-beta.2 + +## 1.0.0-beta.2 + +### Patch Changes + +- general improvements +- Updated dependencies + - @pipelab/plugin-core@1.0.0-beta.2 + - @pipelab/constants@1.0.0-beta.1 + - @pipelab/shared@1.0.0-beta.1 + +## 1.0.0-beta.1 + +### Patch Changes + +- @pipelab/plugin-core@1.0.0-beta.1 + +## 1.0.0-beta.0 + +### Major Changes + +- e1befbf: initial release + +### Patch Changes + +- Updated dependencies [e1befbf] + - @pipelab/plugin-core@1.0.0-beta.0 + - @pipelab/constants@1.0.0-beta.0 + - @pipelab/shared@1.0.0-beta.0 diff --git a/plugins/plugin-tauri/README.md b/plugins/plugin-tauri/README.md new file mode 100644 index 00000000..4ae3c87a --- /dev/null +++ b/plugins/plugin-tauri/README.md @@ -0,0 +1,3 @@ +# @pipelab/plugin-tauri + +Pipelab plugin for building and packaging Tauri applications. diff --git a/plugins/plugin-tauri/package.json b/plugins/plugin-tauri/package.json new file mode 100644 index 00000000..56f39131 --- /dev/null +++ b/plugins/plugin-tauri/package.json @@ -0,0 +1,70 @@ +{ + "name": "@pipelab/plugin-tauri", + "version": "1.0.0-beta.38", + "description": "Pipelab plugin for packaging apps with Tauri", + "keywords": [ + "automation", + "cross-platform", + "desktop-app", + "packaging", + "pipelab", + "pipelab-plugin", + "pipeline", + "rust", + "tauri" + ], + "license": "FSL-1.1-MIT", + "repository": { + "type": "git", + "url": "https://github.com/CynToolkit/pipelab.git", + "directory": "plugins/plugin-tauri" + }, + "files": [ + "dist" + ], + "type": "module", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "default": "./dist/index.mjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "scripts": { + "format": "oxfmt .", + "typecheck": "tsc -b", + "lint": "oxlint .", + "build": "tsdown", + "test": "vitest run" + }, + "dependencies": { + "@pipelab/constants": "workspace:*", + "@pipelab/plugin-core": "workspace:*", + "@pipelab/shared": "workspace:*", + "@types/node": "^24.12.2", + "electron": "32.1.2", + "execa": "9.4.1", + "ts-deepmerge": "7.0.1" + }, + "devDependencies": { + "@pipelab/tsconfig": "workspace:*", + "tsdown": "0.21.2", + "typescript": "5.9.3", + "vitest": "3.1.4" + }, + "pipelab": { + "name": "Tauri", + "description": "Pipelab plugin for packaging apps with Tauri", + "icon": "./dist/public/tauri.webp" + } +} diff --git a/plugins/plugin-tauri/src/configure.ts b/plugins/plugin-tauri/src/configure.ts new file mode 100644 index 00000000..cc10cc68 --- /dev/null +++ b/plugins/plugin-tauri/src/configure.ts @@ -0,0 +1,23 @@ +import { createAction, createActionRunner } from "@pipelab/plugin-core"; +import { configureParams } from "./tauri"; + +export const props = createAction({ + id: "tauri:configure", + description: "Configure tauri", + displayString: "'Configure Tauri'", + icon: "", + meta: {}, + name: "Configure Tauri", + advanced: true, + outputs: { + configuration: { + label: "Configuration", + value: {} as Partial, + }, + }, + params: configureParams, +}); + +export const configureRunner = createActionRunner(async ({ setOutput, inputs }) => { + setOutput("configuration", inputs); +}); diff --git a/plugins/plugin-tauri/src/declarations.d.ts b/plugins/plugin-tauri/src/declarations.d.ts new file mode 100644 index 00000000..9b40a85c --- /dev/null +++ b/plugins/plugin-tauri/src/declarations.d.ts @@ -0,0 +1,2 @@ +/// +declare module "*.webp"; diff --git a/src/shared/libs/plugin-electron/fixtures/build/index.html b/plugins/plugin-tauri/src/fixtures/build/index.html similarity index 54% rename from src/shared/libs/plugin-electron/fixtures/build/index.html rename to plugins/plugin-tauri/src/fixtures/build/index.html index 22946b96..869fb664 100644 --- a/src/shared/libs/plugin-electron/fixtures/build/index.html +++ b/plugins/plugin-tauri/src/fixtures/build/index.html @@ -1,11 +1,11 @@ - + - - - + + + Document - - + +

Hello

- - \ No newline at end of file + + diff --git a/plugins/plugin-tauri/src/index.ts b/plugins/plugin-tauri/src/index.ts new file mode 100644 index 00000000..d0981587 --- /dev/null +++ b/plugins/plugin-tauri/src/index.ts @@ -0,0 +1,60 @@ +import { makeRunner } from "./make"; +import { previewRunner } from "./preview"; + +import { createNodeDefinition } from "@pipelab/plugin-core"; +import { + createMakeProps, + createPackageV2Props, + createPreviewProps, + IDMake, + IDPackageV2, + IDPreview, +} from "./tauri"; +import { configureRunner, props } from "./configure"; +import { packageV2Runner } from "./package"; + +export default createNodeDefinition({ + nodes: [ + // make and package + { + node: createMakeProps( + IDMake, + "Create Installer", + "Create a distributable installer for your chosen platform", + "", + "`Build package for ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", + ), + runner: makeRunner, + // disabled: platform === 'linux' ? 'Tauri is not supported on Linux' : undefined + }, + { + node: createPackageV2Props( + IDPackageV2, + "Package app with configuration", + "Gather all necessary files and prepare your app for distribution, creating a platform-specific bundle.", + "", + "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", + false, + false, + undefined, + false, + false, + ), + runner: packageV2Runner, + }, + { + node: createPreviewProps( + IDPreview, + "Preview app", + "Package and preview your app from an URL", + "", + "`Preview app from ${fmt.param(params['input-url'], 'primary', 'Input folder not set')}`", + ), + runner: previewRunner, + }, + { + node: props, + runner: configureRunner, + }, + ], +}); diff --git a/src/shared/libs/plugin-discord/make.spec.ts b/plugins/plugin-tauri/src/make.spec.ts similarity index 55% rename from src/shared/libs/plugin-discord/make.spec.ts rename to plugins/plugin-tauri/src/make.spec.ts index 79fe60e2..0e103ce7 100644 --- a/src/shared/libs/plugin-discord/make.spec.ts +++ b/plugins/plugin-tauri/src/make.spec.ts @@ -1,9 +1,8 @@ -import { expect, test, vi } from 'vitest' -import { makeRunner } from './make.js' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { type fs } from 'memfs' -import { browserWindow } from '@@/tests/helpers.js' +import { expect, test, vi } from "vitest"; +import { makeRunner } from "./make.js"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { type fs } from "memfs"; // ... @@ -13,17 +12,17 @@ import { browserWindow } from '@@/tests/helpers.js' // return memfs.fs.promises // }) -test('adds 1 + 2 to equal 3', async () => { - const outputs: Record = {} +test("adds 1 + 2 to equal 3", async () => { + const outputs: Record = {}; - const id = 'ut-electron-build' - const tmpDir = join(tmpdir(), id) + const id = "ut-electron-build"; + const tmpDir = join(tmpdir(), id); - console.log('tmpDir', tmpDir) + console.log("tmpDir", tmpDir); - const inputFolder = join(process.cwd(), 'fixtures', 'build') + const inputFolder = join(process.cwd(), "fixtures", "build"); - console.log('inputFolder', inputFolder) + console.log("inputFolder", inputFolder); // await makeRunner({ // inputs: { @@ -52,6 +51,6 @@ test('adds 1 + 2 to equal 3', async () => { // api: undefined, // browserWindow // }) - console.log('outputs', outputs) - expect(true).toBe(true) -}, 120_000) + console.log("outputs", outputs); + expect(true).toBe(true); +}, 120_000); diff --git a/plugins/plugin-tauri/src/make.ts b/plugins/plugin-tauri/src/make.ts new file mode 100644 index 00000000..612c9e97 --- /dev/null +++ b/plugins/plugin-tauri/src/make.ts @@ -0,0 +1,21 @@ +import { createActionRunner } from "@pipelab/plugin-core"; +import { createMakeProps, tauri } from "./tauri"; +import { merge } from "ts-deepmerge"; +import { defaultTauriConfig } from "./utils"; + +export const makeRunner = createActionRunner>( + async (options) => { + const appFolder = options.inputs["input-folder"]; + + if (!options.inputs.configuration) { + throw new Error("Missing tauri configuration"); + } + + const completeConfiguration = merge( + defaultTauriConfig, + options.inputs.configuration, + ) as DesktopApp.Tauri; + + await tauri("make", appFolder, options, completeConfiguration); + }, +); diff --git a/plugins/plugin-tauri/src/package.ts b/plugins/plugin-tauri/src/package.ts new file mode 100644 index 00000000..8ad502a6 --- /dev/null +++ b/plugins/plugin-tauri/src/package.ts @@ -0,0 +1,43 @@ +import { createActionRunner } from "@pipelab/plugin-core"; +import { createPackageV2Props, tauri } from "./tauri"; +import { merge } from "ts-deepmerge"; +import { defaultTauriConfig } from "./utils"; + +export const packageV2Runner = createActionRunner>( + async (options) => { + const appFolder = options.inputs["input-folder"]; + + const completeConfiguration = merge(defaultTauriConfig, { + alwaysOnTop: options.inputs["alwaysOnTop"], + appBundleId: options.inputs["appBundleId"], + appCategoryType: options.inputs["appCategoryType"], + appCopyright: options.inputs["appCopyright"], + appVersion: options.inputs["appVersion"], + author: options.inputs["author"], + description: options.inputs["description"], + tauriVersion: options.inputs["tauriVersion"], + enableExtraLogging: options.inputs["enableExtraLogging"], + clearServiceWorkerOnBoot: (options.inputs as any)["clearServiceWorkerOnBoot"], + frame: options.inputs["frame"], + fullscreen: options.inputs["fullscreen"], + icon: options.inputs["icon"], + height: options.inputs["height"], + name: options.inputs["name"], + toolbar: options.inputs["toolbar"], + transparent: options.inputs["transparent"], + width: options.inputs["width"], + enableSteamSupport: options.inputs["enableSteamSupport"], + steamGameId: options.inputs["steamGameId"], + ignore: options.inputs["ignore"], + openDevtoolsOnStart: options.inputs["openDevtoolsOnStart"], + enableDiscordSupport: options.inputs["enableDiscordSupport"], + discordAppId: options.inputs["discordAppId"], + customPackages: (options.inputs as any)["customPackages"], + backgroundColor: (options.inputs as any)["backgroundColor"], + }) as unknown as DesktopApp.Tauri; + + console.log("completeConfiguration", completeConfiguration); + + await tauri("package", appFolder, options, completeConfiguration); + }, +); diff --git a/plugins/plugin-tauri/src/preview.ts b/plugins/plugin-tauri/src/preview.ts new file mode 100644 index 00000000..77688c47 --- /dev/null +++ b/plugins/plugin-tauri/src/preview.ts @@ -0,0 +1,51 @@ +import { createActionRunner, runWithLiveLogs } from "@pipelab/plugin-core"; +import { createPreviewProps, tauri } from "./tauri"; +import { merge } from "ts-deepmerge"; +import { defaultTauriConfig } from "./utils"; + +export const previewRunner = createActionRunner>( + async (options) => { + const url = options.inputs["input-url"]; + if (url === "") { + throw new Error("URL can't be empty"); + } + + if (!options.inputs.configuration) { + throw new Error("Missing tauri configuration"); + } + + const completeConfiguration = merge(defaultTauriConfig, { + alwaysOnTop: options.inputs.configuration["alwaysOnTop"], + appBundleId: options.inputs.configuration["appBundleId"], + appCategoryType: options.inputs.configuration["appCategoryType"], + appCopyright: options.inputs.configuration["appCopyright"], + appVersion: options.inputs.configuration["appVersion"], + author: options.inputs.configuration["author"], + description: options.inputs.configuration["description"], + tauriVersion: options.inputs.configuration["tauriVersion"], + enableExtraLogging: options.inputs.configuration["enableExtraLogging"], + clearServiceWorkerOnBoot: options.inputs.configuration["clearServiceWorkerOnBoot"], + frame: options.inputs.configuration["frame"], + fullscreen: options.inputs.configuration["fullscreen"], + icon: options.inputs.configuration["icon"], + height: options.inputs.configuration["height"], + name: options.inputs.configuration["name"], + toolbar: options.inputs.configuration["toolbar"], + transparent: options.inputs.configuration["transparent"], + width: options.inputs.configuration["width"], + enableSteamSupport: options.inputs.configuration["enableSteamSupport"], + steamGameId: options.inputs.configuration["steamGameId"], + ignore: options.inputs.configuration["ignore"], + openDevtoolsOnStart: options.inputs.configuration["openDevtoolsOnStart"], + enableDiscordSupport: options.inputs.configuration["enableDiscordSupport"], + discordAppId: options.inputs.configuration["discordAppId"], + customPackages: options.inputs.configuration["customPackages"], + backgroundColor: options.inputs.configuration["backgroundColor"], + }) as unknown as DesktopApp.Tauri; + + console.log("completeConfiguration", completeConfiguration); + + await tauri("preview", url, options, completeConfiguration); + return; + }, +); diff --git a/src/shared/libs/plugin-tauri/public/tauri.webp b/plugins/plugin-tauri/src/public/tauri.webp similarity index 100% rename from src/shared/libs/plugin-tauri/public/tauri.webp rename to plugins/plugin-tauri/src/public/tauri.webp diff --git a/plugins/plugin-tauri/src/tauri.ts b/plugins/plugin-tauri/src/tauri.ts new file mode 100644 index 00000000..bdd4f07f --- /dev/null +++ b/plugins/plugin-tauri/src/tauri.ts @@ -0,0 +1,834 @@ +import { getBinName } from "@pipelab/constants"; +import { + ActionRunnerData, + createAction, + createArray, + createBooleanParam, + createNumberParam, + createPathParam, + createStringParam, + detectRuntime, + InputsDefinition, + OutputsDefinition, + runPnpm, + runWithLiveLogs, + fetchPipelabAsset, +} from "@pipelab/plugin-core"; +import { dirname, join, basename, delimiter } from "node:path"; +import { existsSync } from "node:fs"; +import { cp, readFile as readFilePromise, writeFile as writeFilePromise } from "node:fs/promises"; +import { homedir, platform as osPlatform, arch as osArch } from "node:os"; +import { execa } from "execa"; +import { kebabCase } from "change-case"; +import { parseTOML, stringifyTOML } from "confbox"; + +/** + * Searches for common cargo paths and resolves to a valid cargo executable path + * @returns The path to the cargo executable + * @throws Error if cargo cannot be found + */ +async function resolveCargoPath(): Promise { + const cargoBinName = osPlatform() === "win32" ? "cargo.exe" : "cargo"; + + // Common cargo paths by platform + const commonPaths: string[] = []; + const currentPlatform = osPlatform(); + + // Helper function to add paths if they exist + const addIfExists = (path: string) => { + if (existsSync(path)) { + commonPaths.push(path); + } + }; + + const rustupHome = process.env.RUSTUP_HOME || join(homedir(), ".rustup"); + const cargoHome = process.env.CARGO_HOME || join(homedir(), ".cargo"); + + if (currentPlatform === "win32") { + // Windows paths + addIfExists( + join(rustupHome, "toolchains", "stable-x86_64-pc-windows-msvc", "bin", cargoBinName), + ); + addIfExists( + join(rustupHome, "toolchains", "nightly-x86_64-pc-windows-msvc", "bin", cargoBinName), + ); + addIfExists(join(cargoHome, "bin", cargoBinName)); + } else if (currentPlatform === "linux") { + // Linux paths + addIfExists( + join(rustupHome, "toolchains", "stable-x86_64-unknown-linux-gnu", "bin", cargoBinName), + ); + addIfExists( + join(rustupHome, "toolchains", "nightly-x86_64-unknown-linux-gnu", "bin", cargoBinName), + ); + addIfExists(join(cargoHome, "bin", cargoBinName)); + addIfExists("/usr/bin/cargo"); + addIfExists("/usr/local/bin/cargo"); + } else if (currentPlatform === "darwin") { + // macOS paths + addIfExists(join(rustupHome, "toolchains", "stable-x86_64-apple-darwin", "bin", cargoBinName)); + addIfExists(join(rustupHome, "toolchains", "nightly-x86_64-apple-darwin", "bin", cargoBinName)); + addIfExists(join(cargoHome, "bin", cargoBinName)); + addIfExists("/usr/local/bin/cargo"); + addIfExists("/opt/homebrew/bin/cargo"); + } + + // Return first existing path found + if (commonPaths.length > 0) { + return commonPaths[0]; + } + + // Fallback: try to find cargo using system tools on Unix systems + if (currentPlatform !== "win32") { + try { + const whichResult = await execa("which", ["cargo"]); + const cargoPath = whichResult.stdout.trim(); + if (cargoPath && existsSync(cargoPath)) { + return cargoPath; + } + } catch { + // Ignore errors from which command + } + } + + throw new Error("Cargo not found. Please install it first"); +} + +// TODO: https://js.electronforge.io/modules/_electron_forge_core.html + +export const IDMake = "tauri:make"; +export const IDPackageV2 = "tauri:package:v2"; +export const IDPreview = "tauri:preview"; + +const paramsInputFolder = { + "input-folder": createPathParam("", { + label: "Folder to package", + required: true, + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }), +} satisfies InputsDefinition; + +const paramsInputURL = { + "input-url": createStringParam("", { + label: "URL to preview", + required: true, + }), +} satisfies InputsDefinition; + +const params = { + arch: { + value: "" as NodeJS.Architecture | "", // MakeOptions['arch'], + label: "Architecture", + required: false, + control: { + type: "select", + options: { + placeholder: "Architecture", + options: [ + { + label: "Older PCs (ia32)", + value: "ia32", + }, + { + label: "Modern PCs (x64)", + value: "x64", + }, + { + label: "Older Mobile/Pi (armv7l)", + value: "armv7l", + }, + { + label: "New Mobile/Apple Silicon (arm64)", + value: "arm64", + }, + { + label: "Mac Universal (universal)", + value: "universal", + }, + { + label: "Special Systems (mips64el)", + value: "mips64el", + }, + ], + }, + }, + }, + platform: { + value: "" as NodeJS.Platform | "", // MakeOptions['platform'], + label: "Platform", + required: false, + control: { + type: "select", + options: { + placeholder: "Platform", + options: [ + { + label: "Windows (win32)", + value: "win32", + }, + { + label: "macOS (darwin)", + value: "darwin", + }, + { + label: "Linux (linux)", + value: "linux", + }, + { + label: "Android", + value: "android", + }, + { + label: "iOS", + value: "ios", + }, + ], + }, + }, + }, + configuration: { + label: "Tauri configuration", + value: undefined as Partial | undefined, + required: true, + control: { + type: "json", + }, + }, +} satisfies InputsDefinition; + +export const configureParams = { + name: createStringParam("Pipelab", { + label: "Application name", + description: "The name of the application", + required: true, + }), + appBundleId: createStringParam("com.pipelab.app", { + label: "Application bundle ID", + description: "The bundle ID of the application", + required: true, + }), + appCopyright: createStringParam("Copyright © 2024 Pipelab", { + label: "Application copyright", + description: "The copyright of the application", + required: false, + }), + appVersion: createStringParam("1.0.0", { + label: "Application version", + description: "The version of the application", + required: true, + }), + icon: createPathParam("", { + label: "Application icon", + description: "The icon of the application. macOS: .icns. Windows: .ico", + required: false, + control: { + type: "path", + options: { + filters: [ + { name: "Image", extensions: ["png", "jpg", "jpeg", "gif", "bmp", "ico", "icns"] }, + ], + }, + label: "Path to an image file", + }, + }), + author: createStringParam("Pipelab", { + label: "Application author", + description: "The author of the application", + required: true, + }), + description: createStringParam("A simple Electron application", { + label: "Application description", + description: "The description of the application", + required: false, + }), + + appCategoryType: createStringParam("public.app-category.developer-tools", { + platforms: ["darwin"], + label: "Application category type", + description: "The category type of the application", + required: false, + }), + + // window + width: createNumberParam(800, { + label: "Window width", + description: "The width of the window", + required: false, + }), + height: createNumberParam(600, { + label: "Window height", + description: "The height of the window", + required: false, + }), + fullscreen: { + label: "Fullscreen", + value: false, + description: "Whether to start the application in fullscreen mode", + required: false, + control: { + type: "boolean", + }, + }, + frame: { + label: "Frame", + value: true, + description: "Whether to show the window frame", + required: false, + control: { + type: "boolean", + }, + }, + transparent: { + label: "Transparent", + value: false, + description: "Whether to make the window transparent", + required: false, + control: { + type: "boolean", + }, + }, + toolbar: { + label: "Toolbar", + value: true, + description: "Whether to show the toolbar", + required: false, + control: { + type: "boolean", + }, + }, + alwaysOnTop: { + label: "Always on top", + value: false, + description: "Whether to always keep the window on top", + required: false, + control: { + type: "boolean", + }, + }, + + tauriVersion: createStringParam("", { + label: "Tauri version", + description: + "The version of Tauri to use. If no version specified, it will use the latest one.", + required: false, + }), + enableExtraLogging: { + required: false, + label: "Enable extra logging", + value: false, + control: { + type: "boolean", + }, + description: "Whether to enable extra logging of internal tools while bundling", + }, + openDevtoolsOnStart: createBooleanParam(false, { + label: "Open devtools on app start", + required: false, + description: "Whether to open devtools on app start", + }), + + // websocket apis + websocketApi: { + required: false, + label: "WebSocket APIs to allow (empty = all)", + value: "[]", + control: { + type: "array", + options: { + kind: "text", + }, + }, + }, + ignore: createArray<(string | RegExp)[]>( + `[ + // use 'src/app/' as starting point +]`, + { + required: false, + label: "Folders to ignore", + description: + "An array of string or Regex that allow ignoring certain files or folders from being packaged", + control: { + type: "array", + options: { + kind: "text", + }, + }, + }, + ), + + // integrations + + enableSteamSupport: { + required: false, + label: "Enable steam support", + description: "Whether to enable Steam support", + value: false, + control: { + type: "boolean", + }, + }, + steamGameId: createNumberParam(480, { + required: false, + label: "Steam game ID", + description: "The Steam game ID", + }), + enableDiscordSupport: { + required: false, + label: "Enable Discord support", + description: "Whether to enable Discord support", + value: false, + control: { + type: "boolean", + }, + }, + discordAppId: createStringParam("", { + required: false, + label: "Discord application ID", + description: "The Discord application ID", + }), +} satisfies InputsDefinition; + +const outputs = { + output: { + label: "Output", + value: "", + control: { + type: "path", + options: { + properties: ["openDirectory"], + }, + }, + }, + binary: { + label: "Binary", + value: "", + control: { + type: "path", + options: { + properties: ["openFile"], + }, + }, + }, +} satisfies OutputsDefinition; + +// type Inputs = ParamsToInput + +export const createMakeProps = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, +) => + createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + params: { + ...params, + ...paramsInputFolder, + }, + outputs, + }); + +export const createPackageV2Props = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, + advanced?: boolean, + deprecated?: boolean, + deprecatedMessage?: string, + disabled?: false, + updateAvailable?: boolean, +) => { + const { arch, platform } = params; + return createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + advanced, + deprecated, + deprecatedMessage, + disabled, + updateAvailable, + params: { + arch, + platform, + ...paramsInputFolder, + ...configureParams, + }, + outputs: outputs, + }); +}; + +export const createPreviewProps = ( + id: string, + name: string, + description: string, + icon: string, + displayString: string, +) => + createAction({ + id, + name, + description, + icon, + displayString, + meta: {}, + params: { + ...params, + ...paramsInputURL, + }, + outputs: outputs, + }); + +export const tauri = async ( + action: "make" | "package" | "preview", + appFolder: string | undefined, + { cwd, log, inputs, setOutput, paths, abortSignal, context }: ActionRunnerData, + completeConfiguration: DesktopApp.Config, +): Promise<{ folder: string; binary: string | undefined } | undefined> => { + console.log("appFolder", appFolder); + + log("Building tauri"); + + if (action !== "preview") { + await detectRuntime(appFolder); + } + + const { modules, cache, node } = paths; + + const destinationFolder = join(cwd, "build"); + + const rawAssetFolder = await fetchPipelabAsset("@pipelab/asset-tauri", "^1.0.0", { context }); + const templateFolder = join(rawAssetFolder, "template"); + + // copy template to destination + await cp(templateFolder, destinationFolder, { + recursive: true, + filter: (src) => { + // log('src', src) + // log('dest', dest) + // TODO: support other oses + return ( + basename(src) !== "node_modules" && + !src.includes("src-tauri\\target") && + !src.includes("src-tauri\\gen") + ); + }, + }); + + const placeAppFolder = join(destinationFolder, "src", "app"); + + // if input is folder, copy folder to destination + if (appFolder && action !== "preview") { + // copy app to template + await cp(appFolder, placeAppFolder, { recursive: true }); + } + + writeFilePromise( + join(destinationFolder, "config.cjs"), + `module.exports = ${JSON.stringify(completeConfiguration, undefined, 2)}`, + "utf8", + ); + + const sanitizedName = kebabCase(completeConfiguration.name); + + // package.json update + log("Package.json update"); + const pkgJSONPath = join(destinationFolder, "package.json"); + const pkgJSONContent = await readFilePromise(pkgJSONPath, "utf8"); + const pkgJSON = JSON.parse(pkgJSONContent); + log("Setting name to", sanitizedName); + pkgJSON.name = sanitizedName; + log("Setting productName to", completeConfiguration.name); + pkgJSON.productName = completeConfiguration.name; + await writeFilePromise(pkgJSONPath, JSON.stringify(pkgJSON, null, 2)); + + // Cargo.toml update + log("Cargo.toml update"); + const cargoTomlPath = join(destinationFolder, "src-tauri", "Cargo.toml"); + const cargoTomlContent = await readFilePromise(cargoTomlPath, "utf8"); + const cargoToml = parseTOML(cargoTomlContent) as { name: string; version: string }; + log("Setting name to", sanitizedName); + console.log("cargoToml", cargoToml); + cargoToml.name = sanitizedName; + log("Setting version to", completeConfiguration.appVersion); + cargoToml.version = completeConfiguration.appVersion; + console.log("cargoToml", stringifyTOML(cargoToml)); + await writeFilePromise(cargoTomlPath, stringifyTOML(cargoToml)); + + // tauri.conf.json update + log("Tauri.conf.json update"); + const tauriConfJSONPath = join(destinationFolder, "src-tauri", "tauri.conf.json"); + const tauriConfJSONContent = await readFilePromise(tauriConfJSONPath, "utf8"); + const tauriConfJSON = JSON.parse(tauriConfJSONContent); + log("Setting productName to", completeConfiguration.name); + tauriConfJSON.productName = completeConfiguration.name; + log("Setting version to", completeConfiguration.appVersion); + tauriConfJSON.version = completeConfiguration.appVersion; + log("Setting identifier to", completeConfiguration.appBundleId); + tauriConfJSON.identifier = completeConfiguration.appBundleId; + if (action === "preview") { + log("Setting build.devUrl to", appFolder); + tauriConfJSON.build.devUrl = appFolder; + await writeFilePromise(tauriConfJSONPath, JSON.stringify(tauriConfJSON, null, 2)); + } + /* else { + log('Setting build.frontendDist to', appFolder) + tauriConfJSON.build.frontendDist = appFolder + await writeFile(tauriConfJSONPath, JSON.stringify(tauriConfJSON, null, 2)) + } */ + + log("Installing packages"); + const { all } = await runPnpm(destinationFolder, { + signal: abortSignal, + context, + }); + if (all) log(all); + + // override tauri version + // if (completeConfiguration.electronVersion && completeConfiguration.electronVersion !== '') { + // log(`Installing tauri@${completeConfiguration.electronVersion}`) + // await runWithLiveLogs( + // process.execPath, + // [pnpm, 'install', `tauri@${completeConfiguration.electronVersion}`, '--prefer-offline'], + // { + // cwd: destinationFolder, + // env: { + // // DEBUG: '*', + // PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, + // PNPM_HOME: pnpmHome + // }, + // cancelSignal: abortSignal + // }, + // log, + // { + // onStderr(data) { + // log(data) + // }, + // onStdout(data) { + // log(data) + // } + // } + // ) + // } + + const inputPlatform = inputs.platform === "" ? undefined : inputs.platform; + const inputArch = inputs.arch === "" ? undefined : inputs.arch; + + try { + log("typeof inputs.platform", typeof inputs.platform); + const finalPlatform: NodeJS.Platform = inputPlatform ?? osPlatform(); + log("finalPlatform", finalPlatform); + const finalArch: NodeJS.Architecture = inputArch ?? (osArch() as NodeJS.Architecture); + log("finalArch", finalArch); + + let tauriPlatform = ""; + if (finalPlatform === "win32") { + tauriPlatform = "pc-windows-msvc"; + } else if (finalPlatform === "linux") { + tauriPlatform = "unknown-linux-gnu"; + } else { + throw new Error("Unsupported platform"); + } + + let tauriArch = ""; + if (finalArch === "x64") { + tauriArch = "x86_64"; + } else { + throw new Error("Unsupported arch"); + } + + const target = `${tauriArch}-${tauriPlatform}`; + + // Resolve cargo path using the new function + const cargo = await resolveCargoPath(); + const cargoBinDir = dirname(cargo); + + log("cargoBinDir", cargoBinDir); + console.log("cargo", cargo); + + log("destinationFolder", destinationFolder); + + const cargoTargetDir = join(cache, "cargo", "target", completeConfiguration.appBundleId); + const cargoOutputPath = join(cargoTargetDir, target, "release"); + + log("cargoTargetDir", cargoTargetDir); + log("cargoOutputPath", cargoOutputPath); + + log("Starting compiling"); + + // by default add the tauri cli + await runWithLiveLogs( + cargo, + ["install", "tauri-cli", "--version", "^2.0.0", "--locked"], + { + cwd: join(destinationFolder, "src-tauri"), + env: { + ...process.env, + DEBUG: completeConfiguration.enableExtraLogging ? "*" : "", + ELECTRON_NO_ASAR: "1", + CARGO_TARGET_DIR: cargoTargetDir, + PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}`, + }, + cancelSignal: abortSignal, + }, + log, + { + onStderr(data) { + // on ci, do not log + if (!process.env.CI) { + log(data); + } + }, + onStdout(data) { + // on ci, do not log + if (!process.env.CI) { + log(data); + } + }, + }, + ); + + // if preview, run tauri dev + if (action === "preview") { + await runWithLiveLogs( + cargo, + ["tauri", "dev", "--target", target], + { + cwd: join(destinationFolder, "src-tauri"), + env: { + ...process.env, + DEBUG: completeConfiguration.enableExtraLogging ? "*" : "", + ELECTRON_NO_ASAR: "1", + CARGO_TARGET_DIR: cargoTargetDir, + PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}`, + }, + cancelSignal: abortSignal, + }, + log, + { + onStderr(data) { + log(data); + }, + onStdout(data) { + log(data); + }, + }, + ); + } else { + // otherwise build, but don't bundle + await runWithLiveLogs( + cargo, + ["tauri", "build", "--target", target, "--no-bundle"], + { + cwd: join(destinationFolder, "src-tauri"), + env: { + ...process.env, + DEBUG: completeConfiguration.enableExtraLogging ? "*" : "", + ELECTRON_NO_ASAR: "1", + CARGO_TARGET_DIR: cargoTargetDir, + PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}`, + }, + cancelSignal: abortSignal, + }, + log, + { + onStderr(data) { + // on ci, do not log + if (!process.env.CI) { + log(data); + } + }, + onStdout(data) { + // on ci, do not log + if (!process.env.CI) { + log(data); + } + }, + }, + ); + + // if make, bundle + if (action === "make") { + await runWithLiveLogs( + cargo, + // TODO: https://v2.tauri.app/fr/distribute/#bundling + ["tauri", "bundle", "--", "--bundles", "appimage"], + { + cwd: join(destinationFolder, "src-tauri"), + env: { + DEBUG: completeConfiguration.enableExtraLogging ? "*" : "", + ELECTRON_NO_ASAR: "1", + CARGO_TARGET_DIR: cargoTargetDir, + PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}`, + }, + cancelSignal: abortSignal, + }, + log, + { + onStderr(data) { + log(data); + }, + onStdout(data) { + log(data); + }, + }, + ); + } + } + + if (action === "package") { + const binName = getBinName(sanitizedName); + + log("cargoOutputPath", cargoOutputPath); + + setOutput("output", cargoOutputPath); + setOutput("binary", join(cargoOutputPath, binName)); + return { + folder: cargoOutputPath, + binary: join(cargoOutputPath, binName), + }; + } else if (action === "make") { + // TODO: + throw new Error("Unsupported action"); + } else if (action === "preview") { + // continue + } else { + throw new Error("Unsupported action"); + // const output = join(destinationFolder, 'out', 'make') + // setOutput('output', output) + // return { + // folder: output, + // binary: undefined + // } + } + } catch (e) { + if (e instanceof Error) { + if (e.name === "RequestError") { + log("Request error"); + } + if (e.name === "RequestError") { + log("Request error"); + } + throw e; + } + log(e); + return undefined; + } +}; diff --git a/plugins/plugin-tauri/src/utils.ts b/plugins/plugin-tauri/src/utils.ts new file mode 100644 index 00000000..9520f0c2 --- /dev/null +++ b/plugins/plugin-tauri/src/utils.ts @@ -0,0 +1,29 @@ +export const defaultTauriConfig = { + alwaysOnTop: false, + appBundleId: "com.pipelab.app", + appCategoryType: "", + appCopyright: "Copyright © 2024 Pipelab", + appVersion: "1.0.0", + author: "Pipelab", + description: "A simple Electron application", + tauriVersion: "", + enableExtraLogging: false, + clearServiceWorkerOnBoot: false, + frame: true, + fullscreen: false, + icon: "", + height: 600, + name: "Pipelab", + toolbar: true, + transparent: false, + width: 800, + enableSteamSupport: false, + steamGameId: 480, + enableDiscordSupport: false, + discordAppId: "", + ignore: [] as string[], + backgroundColor: "#FFF", + openDevtoolsOnStart: false, + enableDoctor: false, + serverMode: "default" as const, +} satisfies DesktopApp.Tauri; diff --git a/plugins/plugin-tauri/tsconfig.json b/plugins/plugin-tauri/tsconfig.json new file mode 100644 index 00000000..26ef4817 --- /dev/null +++ b/plugins/plugin-tauri/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@pipelab/tsconfig/vue.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"], + "skipLibCheck": true + }, + "include": ["src"], + "references": [ + { + "path": "../../packages/constants" + }, + { + "path": "../plugin-core" + }, + { + "path": "../../packages/shared" + } + ] +} diff --git a/plugins/plugin-tauri/tsdown.config.ts b/plugins/plugin-tauri/tsdown.config.ts new file mode 100644 index 00000000..327c61b7 --- /dev/null +++ b/plugins/plugin-tauri/tsdown.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: { + tsconfigRaw: { + references: [], + }, + }, + clean: true, + shims: true, + loader: { + ".webp": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".svg": "dataurl", + }, + deps: { + alwaysBundle: [/.*/], + }, + copy: ["src/public"], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d407176..75176761 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,16 +11,241 @@ overrides: importers: .: - dependencies: + devDependencies: '@changesets/cli': - specifier: 2.27.11 - version: 2.27.11 + specifier: ^2.27.11 + version: 2.30.0(@types/node@24.12.2) + '@pipelab/constants': + specifier: workspace:* + version: link:packages/constants + '@pipelab/core-node': + specifier: workspace:* + version: link:packages/core-node + '@pipelab/plugin-core': + specifier: workspace:* + version: link:plugins/plugin-core + '@pipelab/shared': + specifier: workspace:* + version: link:packages/shared + '@pipelab/tsconfig': + specifier: workspace:* + version: link:packages/tsconfig + '@types/node': + specifier: 24.12.2 + version: 24.12.2 + '@types/tar': + specifier: ^6.1.13 + version: 6.1.13 + cross-env: + specifier: 7.0.3 + version: 7.0.3 + execa: + specifier: 9.5.1 + version: 9.5.1 + nanoid: + specifier: 5.0.8 + version: 5.0.8 + oxfmt: + specifier: 0.40.0 + version: 0.40.0 + oxlint: + specifier: 1.55.0 + version: 1.55.0 + turbo: + specifier: ^2.8.15 + version: 2.9.6 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + apps/cli: + dependencies: + '@clack/prompts': + specifier: 1.2.0 + version: 1.2.0 + '@pipelab/constants': + specifier: workspace:* + version: link:../../packages/constants + '@pipelab/core-node': + specifier: workspace:* + version: link:../../packages/core-node + '@pipelab/shared': + specifier: workspace:* + version: link:../../packages/shared + commander: + specifier: ^12.1.0 + version: 12.1.0 + dotenv: + specifier: 17.4.2 + version: 17.4.2 + execa: + specifier: 9.5.1 + version: 9.5.1 + nanoid: + specifier: 5.0.8 + version: 5.0.8 + posthog-node: + specifier: 5.30.6 + version: 5.30.6(rxjs@7.8.2) + serve-handler: + specifier: 6.1.7 + version: 6.1.7 + devDependencies: + '@pipelab/test-utils': + specifier: workspace:* + version: link:../../packages/test-utils + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@types/node': + specifier: 24.12.2 + version: 24.12.2 + cross-env: + specifier: 7.0.3 + version: 7.0.3 + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: ^5.0.0 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + apps/desktop: + dependencies: + electron-squirrel-startup: + specifier: 1.0.1 + version: 1.0.1 + posthog-node: + specifier: 5.30.6 + version: 5.30.6(rxjs@7.8.2) + devDependencies: + '@electron-forge/cli': + specifier: 7.11.1 + version: 7.11.1(encoding@0.1.13) + '@electron-forge/maker-dmg': + specifier: 7.11.1 + version: 7.11.1 + '@electron-forge/maker-squirrel': + specifier: 7.11.1 + version: 7.11.1 + '@electron-forge/maker-zip': + specifier: 7.11.1 + version: 7.11.1 + '@electron-forge/plugin-fuses': + specifier: 7.11.1 + version: 7.11.1(@electron/fuses@1.8.0) + '@electron-forge/plugin-vite': + specifier: 7.11.1 + version: 7.11.1 + '@electron-forge/publisher-github': + specifier: 7.11.1 + version: 7.11.1 + '@electron-toolkit/preload': + specifier: 3.0.2 + version: 3.0.2(electron@32.1.2) + '@electron-toolkit/utils': + specifier: 4.0.0 + version: 4.0.0(electron@32.1.2) + '@electron/fuses': + specifier: 1.8.0 + version: 1.8.0 + '@electron/notarize': + specifier: 2.5.0 + version: 2.5.0 + '@pipelab/constants': + specifier: workspace:* + version: link:../../packages/constants + '@pipelab/core-node': + specifier: workspace:* + version: link:../../packages/core-node + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../../plugins/plugin-core + '@pipelab/shared': + specifier: workspace:* + version: link:../../packages/shared + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@types/electron-squirrel-startup': + specifier: 1.0.2 + version: 1.0.2 + '@types/node': + specifier: 24.12.2 + version: 24.12.2 + '@types/semver': + specifier: 7.7.1 + version: 7.7.1 + cross-env: + specifier: 7.0.3 + version: 7.0.3 + electron: + specifier: 32.1.2 + version: 32.1.2 + semver: + specifier: 7.8.0 + version: 7.8.0 + tsx: + specifier: 4.19.1 + version: 4.19.1 + typescript: + specifier: 5.8.3 + version: 5.8.3 + vite: + specifier: 6.3.3 + version: 6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vite-tsconfig-paths: + specifier: 5.1.4 + version: 5.1.4(typescript@5.8.3)(vite@6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1)) + + apps/mini-c3-electron: + dependencies: + canvas-confetti: + specifier: 1.9.4 + version: 1.9.4 + vue: + specifier: ^3.5.34 + version: 3.5.34(typescript@6.0.3) + devDependencies: + '@types/canvas-confetti': + specifier: 1.9.0 + version: 1.9.0 + '@types/node': + specifier: ^24.12.3 + version: 24.12.4 + '@vitejs/plugin-vue': + specifier: ^6.0.6 + version: 6.0.7(vite@8.0.14(@types/node@24.12.4)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1))(vue@3.5.34(typescript@6.0.3)) + '@vue/tsconfig': + specifier: ^0.9.1 + version: 0.9.1(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3)) + typescript: + specifier: ~6.0.2 + version: 6.0.3 + vite: + specifier: ^8.0.12 + version: 8.0.14(@types/node@24.12.4)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vue-tsc: + specifier: ^3.2.8 + version: 3.3.1(typescript@6.0.3) + + apps/ui: + dependencies: '@codemirror/autocomplete': specifier: 6.18.1 - version: 6.18.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.2.3) + version: 6.18.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.5.2) '@codemirror/commands': specifier: 6.6.2 version: 6.6.2 + '@codemirror/lang-javascript': + specifier: 6.2.2 + version: 6.2.2 '@codemirror/lang-liquid': specifier: 6.2.1 version: 6.2.1 @@ -33,60 +258,30 @@ importers: '@codemirror/view': specifier: 6.34.0 version: 6.34.0 - '@electron-toolkit/preload': - specifier: 3.0.2 - version: 3.0.2(electron@32.1.2) - '@electron-toolkit/utils': - specifier: 4.0.0 - version: 4.0.0(electron@32.1.2) '@floating-ui/vue': specifier: 1.1.5 version: 1.1.5(vue@3.5.13(typescript@5.8.3)) '@jitl/quickjs-wasmfile-release-sync': specifier: 0.31.0 version: 0.31.0 - '@lydell/node-pty': - specifier: 1.0.3 - version: 1.0.3 - '@lydell/node-pty-win32-x64': - specifier: 1.1.0 - version: 1.1.0 - '@pipelab/core': - specifier: 1.4.9 - version: 1.4.9 - '@poki/cli': - specifier: 0.1.16 - version: 0.1.16 + '@mdi/font': + specifier: 7.4.47 + version: 7.4.47 + '@pipelab/constants': + specifier: workspace:* + version: link:../../packages/constants + '@pipelab/shared': + specifier: workspace:* + version: link:../../packages/shared '@polar-sh/sdk': - specifier: 0.34.8 - version: 0.34.8(zod@3.23.8) + specifier: 0.47.1 + version: 0.47.1 '@primevue/themes': specifier: 4.1.1 version: 4.1.1 - '@sentry/electron': - specifier: 5.4.0 - version: 5.4.0 - '@sentry/vue': - specifier: 8.32.0 - version: 8.32.0(vue@3.5.13(typescript@5.8.3)) - '@supabase/supabase-js': - specifier: 2.45.6 - version: 2.45.6 '@trpc/client': specifier: 10.45.2 version: 10.45.2(@trpc/server@10.45.2) - '@types/archiver': - specifier: 6.0.3 - version: 6.0.3 - '@types/date-fns': - specifier: 2.6.3 - version: 2.6.3 - '@types/dompurify': - specifier: 3.0.5 - version: 3.0.5 - '@types/ws': - specifier: 8.18.1 - version: 8.18.1 '@vee-validate/valibot': specifier: 4.13.2 version: 4.13.2(vue@3.5.13(typescript@5.8.3)) @@ -105,21 +300,9 @@ importers: '@vueuse/router': specifier: 11.1.0 version: 11.1.0(vue-router@4.4.5(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3)) - archiver: - specifier: 7.0.1 - version: 7.0.1 change-case: specifier: 5.4.4 version: 5.4.4 - code-tag: - specifier: 1.2.0 - version: 1.2.0 - confbox: - specifier: 0.2.2 - version: 0.2.2 - d3-shape: - specifier: 3.2.0 - version: 3.2.0 date-fns: specifier: 4.1.0 version: 4.1.0 @@ -129,33 +312,15 @@ importers: driver.js: specifier: 1.4.0 version: 1.4.0 - ejs: - specifier: 3.1.10 - version: 3.1.10 - electron-squirrel-startup: - specifier: 1.0.1 - version: 1.0.1 - elkjs: - specifier: 0.9.3 - version: 0.9.3 es-toolkit: specifier: 1.25.2 version: 1.25.2 - esbuild: - specifier: 0.25.5 - version: 0.25.5 - esm: - specifier: 3.2.25 - version: 3.2.25 - execa: - specifier: 9.4.1 - version: 9.4.1 fancy-ansi: specifier: 0.1.3 version: 0.1.3 geist: specifier: 1.3.1 - version: 1.3.1(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.80.4)) + version: 1.3.1(next@16.2.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(sass@1.99.0)) get-value: specifier: 3.0.1 version: 3.0.1 @@ -168,9 +333,6 @@ importers: nanoid: specifier: 5.0.7 version: 5.0.7 - node-stream-zip: - specifier: 1.15.0 - version: 1.15.0 path-browserify: specifier: 1.0.1 version: 1.0.1 @@ -180,30 +342,21 @@ importers: pinia-plugin-persistedstate: specifier: 4.1.1 version: 4.1.1(pinia@2.2.4(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3))) - playwright: - specifier: 1.48.1 - version: 1.48.1 - playwright-core: - specifier: 1.48.1 - version: 1.48.1 - pnpm: - specifier: 9.12.2 - version: 9.12.2 polished: specifier: 4.3.1 version: 4.3.1 posthog-js: specifier: 1.215.0 version: 1.215.0 - posthog-node: - specifier: 4.4.1 - version: 4.4.1 + primeflex: + specifier: 4.0.0 + version: 4.0.0 primeicons: specifier: 7.0.0 version: 7.0.0 primevue: - specifier: 4.1.1 - version: 4.1.1(vue@3.5.13(typescript@5.8.3)) + specifier: 4.5.4 + version: 4.5.4(vue@3.5.13(typescript@5.8.3)) quickjs-emscripten: specifier: 0.31.0 version: 0.31.0 @@ -211,32 +364,23 @@ importers: specifier: 1.6.0 version: 1.6.0(quickjs-emscripten@0.31.0) semver: - specifier: 7.6.3 - version: 7.6.3 - serve-handler: - specifier: 6.1.6 - version: 6.1.6 + specifier: 7.8.1 + version: 7.8.1 set-value: specifier: 4.1.0 version: 4.1.0 slash: - specifier: 5.1.0 - version: 5.1.0 + specifier: 3.0.0 + version: 3.0.0 string-strip-html: specifier: 13.4.8 version: 13.4.8 thememirror: specifier: 2.0.1 - version: 2.0.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0) + version: 2.0.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0) tinykeys: specifier: 2.1.0 version: 2.1.0 - ts-deepmerge: - specifier: 7.0.1 - version: 7.0.1 - ts-essentials: - specifier: 10.0.2 - version: 10.0.2(typescript@5.8.3) ts-pattern: specifier: 5.5.0 version: 5.5.0 @@ -246,287 +390,874 @@ importers: type-fest: specifier: 4.26.1 version: 4.26.1 - untun: - specifier: 0.1.3 - version: 0.1.3 - update-electron-app: - specifier: 3.0.0 - version: 3.0.0 valibot: specifier: 0.42.1 version: 0.42.1(typescript@5.8.3) vee-validate: specifier: 4.14.4 version: 4.14.4(vue@3.5.13(typescript@5.8.3)) + vue: + specifier: 3.5.13 + version: 3.5.13(typescript@5.8.3) vue-dompurify-html: specifier: 5.1.0 version: 5.1.0(vue@3.5.13(typescript@5.8.3)) vue-i18n: specifier: '10' - version: 10.0.7(vue@3.5.13(typescript@5.8.3)) - web-worker: - specifier: 1.3.0 - version: 1.3.0 - ws: - specifier: 8.18.3 - version: 8.18.3 - zod: - specifier: 3.23.8 - version: 3.23.8 + version: 10.0.8(vue@3.5.13(typescript@5.8.3)) + vue-router: + specifier: 4.4.5 + version: 4.4.5(vue@3.5.13(typescript@5.8.3)) devDependencies: - '@changesets/changelog-git': - specifier: 0.2.0 - version: 0.2.0 - '@changesets/changelog-github': - specifier: 0.5.0 - version: 0.5.0(encoding@0.1.13) - '@electron-forge/cli': - specifier: 7.4.0 - version: 7.4.0(encoding@0.1.13) - '@electron-forge/maker-deb': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-dmg': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-flatpak': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-pkg': - specifier: 7.8.1 - version: 7.8.1 - '@electron-forge/maker-squirrel': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/maker-zip': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/plugin-fuses': - specifier: 7.4.0 - version: 7.4.0(@electron/fuses@1.8.0) - '@electron-forge/plugin-vite': - specifier: 7.4.0 - version: 7.4.0 - '@electron-forge/publisher-github': - specifier: 7.4.0 - version: 7.4.0(encoding@0.1.13) - '@electron-toolkit/tsconfig': - specifier: 1.0.1 - version: 1.0.1(@types/node@22.7.9) - '@electron/fuses': - specifier: 1.8.0 - version: 1.8.0 - '@electron/notarize': - specifier: 2.5.0 - version: 2.5.0 - '@eslint/eslintrc': - specifier: 3.1.0 - version: 3.1.0 - '@eslint/js': - specifier: 9.13.0 - version: 9.13.0 - '@mdi/font': - specifier: 7.4.47 - version: 7.4.47 - '@playwright/test': - specifier: 1.48.1 - version: 1.48.1 + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig '@primevue/auto-import-resolver': specifier: 4.1.1 version: 4.1.1 - '@rushstack/eslint-patch': - specifier: 1.10.4 - version: 1.10.4 - '@sentry/vite-plugin': - specifier: 2.22.6 - version: 2.22.6(encoding@0.1.13) - '@types/d3-shape': - specifier: 3.1.6 - version: 3.1.6 - '@types/fs-extra': - specifier: 11.0.4 - version: 11.0.4 - '@types/jsdom': - specifier: 21.1.7 - version: 21.1.7 '@types/node': - specifier: 22.7.9 - version: 22.7.9 - '@types/path-browserify': - specifier: 1.0.3 - version: 1.0.3 + specifier: 24.12.2 + version: 24.12.2 '@types/semver': - specifier: 7.5.8 - version: 7.5.8 - '@typescript-eslint/parser': - specifier: 8.11.0 - version: 8.11.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 7.7.1 + version: 7.7.1 + '@vitejs/devtools': + specifier: 0.1.13 + version: 0.1.13(@pnpm/logger@1001.0.1)(typescript@5.8.3)(vite@8.0.8) '@vitejs/plugin-vue': - specifier: 5.2.3 - version: 5.2.3(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1))(vue@3.5.13(typescript@5.8.3)) - '@vue/eslint-config-prettier': - specifier: 9.0.0 - version: 9.0.0(eslint@9.13.0(jiti@2.4.2))(prettier@3.3.3) - '@vue/eslint-config-typescript': - specifier: 13.0.0 - version: 13.0.0(eslint-plugin-vue@9.29.1(eslint@9.13.0(jiti@2.4.2)))(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) - '@vue/test-utils': - specifier: 2.4.6 - version: 2.4.6 - editorconfig: - specifier: 2.0.0 - version: 2.0.0 - electron: - specifier: 32.1.2 - version: 32.1.2 - electron-vite: - specifier: 2.3.0 - version: 2.3.0(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) - eslint: - specifier: 9.13.0 - version: 9.13.0(jiti@2.4.2) - eslint-plugin-vue: - specifier: 9.29.1 - version: 9.29.1(eslint@9.13.0(jiti@2.4.2)) - fs-extra: - specifier: 11.3.0 - version: 11.3.0 - globals: - specifier: 15.11.0 - version: 15.11.0 - jsdom: - specifier: 25.0.1 - version: 25.0.1 - less: - specifier: 4.2.0 - version: 4.2.0 - npm-run-all: - specifier: 4.1.5 - version: 4.1.5 - npm-upgrade: - specifier: 3.1.0 - version: 3.1.0 - prettier: - specifier: 3.3.3 - version: 3.3.3 - primeflex: - specifier: 3.3.1 - version: 3.3.1 - sass: - specifier: 1.80.4 - version: 1.80.4 - ts-node: - specifier: 10.9.2 - version: 10.9.2(@types/node@22.7.9)(typescript@5.8.3) - tsx: - specifier: 4.19.1 - version: 4.19.1 + specifier: 6.0.5 + version: 6.0.5(vite@8.0.8)(vue@3.5.13(typescript@5.8.3)) + sass-embedded: + specifier: ^1.83.4 + version: 1.99.0 typescript: specifier: 5.8.3 version: 5.8.3 unplugin-auto-import: specifier: 0.18.3 - version: 0.18.3(@nuxt/kit@3.17.5)(@vueuse/core@11.1.0(vue@3.5.13(typescript@5.8.3)))(rollup@4.42.0) + version: 0.18.3(@nuxt/kit@3.21.2)(@vueuse/core@11.1.0(vue@3.5.13(typescript@5.8.3)))(rollup@4.60.1) unplugin-vue-components: specifier: 0.27.4 - version: 0.27.4(@babel/parser@7.27.5)(@nuxt/kit@3.17.5)(rollup@4.42.0)(vue@3.5.13(typescript@5.8.3)) + version: 0.27.4(@babel/parser@7.29.3)(@nuxt/kit@3.21.2)(rollup@4.60.1)(vue@3.5.13(typescript@5.8.3)) vite: - specifier: 6.3.3 - version: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - vite-plugin-node-polyfills: - specifier: 0.23.0 - version: 0.23.0(rollup@4.42.0)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) - vite-plugin-static-copy: - specifier: 2.3.1 - version: 2.3.1(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) + specifier: 8.0.8 + version: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) vite-plugin-vue-devtools: - specifier: 7.7.5 - version: 7.7.5(@nuxt/kit@3.17.5)(rollup@4.42.0)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1))(vue@3.5.13(typescript@5.8.3)) - vite-plugin-wasm: - specifier: 3.4.1 - version: 3.4.1(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) - vite-tsconfig-paths: - specifier: 5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) + specifier: 8.1.1 + version: 8.1.1(@nuxt/kit@3.21.2)(vite@8.0.8)(vue@3.5.13(typescript@5.8.3)) vitest: specifier: 3.1.4 - version: 3.1.4(@types/node@22.7.9)(jiti@2.4.2)(jsdom@25.0.1)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - vue: - specifier: 3.5.13 - version: 3.5.13(typescript@5.8.3) - vue-router: - specifier: 4.4.5 - version: 4.4.5(vue@3.5.13(typescript@5.8.3)) + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.8.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) vue-tsc: specifier: 2.1.6 version: 2.1.6(typescript@5.8.3) -packages: - - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - - '@antfu/utils@0.7.10': - resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} - - '@asamuzakjp/css-color@3.2.0': - resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.27.5': - resolution: {integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==} - engines: {node: '>=6.9.0'} + assets/asset-discord: {} - '@babel/core@7.27.4': - resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} - engines: {node: '>=6.9.0'} + assets/asset-electron: {} - '@babel/generator@7.27.5': - resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==} - engines: {node: '>=6.9.0'} + assets/asset-netlify: {} - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} + assets/asset-tauri: {} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} + packages/cloud: + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../tsconfig + typescript: + specifier: 5.9.3 + version: 5.9.3 + + packages/cloud-azure: + dependencies: + '@azure/arm-containerinstance': + specifier: 9.1.0 + version: 9.1.0 + '@azure/identity': + specifier: 4.0.1 + version: 4.0.1 + '@azure/storage-file-share': + specifier: 12.15.0 + version: 12.15.0(encoding@0.1.13) + '@pipelab/cloud': + specifier: workspace:* + version: link:../cloud + '@pipelab/shared': + specifier: workspace:* + version: link:../shared + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../tsconfig + typescript: + specifier: 5.9.3 + version: 5.9.3 - '@babel/helper-create-class-features-plugin@7.27.1': - resolution: {integrity: sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + packages/constants: + dependencies: + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: ^5.0.0 + version: 5.9.3 - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} - engines: {node: '>=6.9.0'} + packages/core-node: + dependencies: + '@pipelab/constants': + specifier: workspace:* + version: link:../constants + '@pipelab/shared': + specifier: workspace:* + version: link:../shared + '@supabase/supabase-js': + specifier: 2.99.3 + version: 2.99.3 + adm-zip: + specifier: 0.5.16 + version: 0.5.16 + archiver: + specifier: 7.0.1 + version: 7.0.1 + check-disk-space: + specifier: 3.4.0 + version: 3.4.0 + es-toolkit: + specifier: 1.25.2 + version: 1.25.2 + execa: + specifier: 9.5.2 + version: 9.5.2 + nanoid: + specifier: 5.0.7 + version: 5.0.7 + pacote: + specifier: 21.5.0 + version: 21.5.0 + semver: + specifier: ^7.7.4 + version: 7.7.4 + slash: + specifier: 3.0.0 + version: 3.0.0 + tar: + specifier: 6.2.1 + version: 6.2.1 + type-fest: + specifier: 4.39.0 + version: 4.39.0 + ws: + specifier: 8.18.3 + version: 8.18.3 + yauzl: + specifier: 2.10.0 + version: 2.10.0 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../tsconfig + '@types/adm-zip': + specifier: 0.5.7 + version: 0.5.7 + '@types/archiver': + specifier: 7.0.0 + version: 7.0.0 + '@types/node': + specifier: 24.12.2 + version: 24.12.2 + '@types/pacote': + specifier: 11.1.8 + version: 11.1.8 + '@types/semver': + specifier: ^7.7.1 + version: 7.7.1 + '@types/tar': + specifier: 7.0.87 + version: 7.0.87 + '@types/ws': + specifier: 8.18.1 + version: 8.18.1 + '@types/yauzl': + specifier: 2.10.3 + version: 2.10.3 + memfs: + specifier: 4.57.6 + version: 4.57.6(tslib@2.8.1) + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: ^5.0.0 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} + packages/migration: + dependencies: + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + klona: + specifier: 2.0.6 + version: 2.0.6 + semver: + specifier: ^7.6.3 + version: 7.7.4 + valibot: + specifier: 0.42.1 + version: 0.42.1(typescript@5.9.3) + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../tsconfig + '@types/semver': + specifier: ^7.5.8 + version: 7.7.1 + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) - '@babel/helper-module-transforms@7.27.3': - resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + packages/shared: + dependencies: + '@jitl/quickjs-singlefile-mjs-release-sync': + specifier: 0.31.0 + version: 0.31.0 + '@jitl/quickjs-wasmfile-release-sync': + specifier: 0.31.0 + version: 0.31.0 + '@pipelab/constants': + specifier: workspace:* + version: link:../constants + '@pipelab/migration': + specifier: workspace:* + version: link:../migration + '@supabase/supabase-js': + specifier: 2.99.3 + version: 2.99.3 + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + klona: + specifier: 2.0.6 + version: 2.0.6 + nanoid: + specifier: 5.0.7 + version: 5.0.7 + quickjs-emscripten: + specifier: 0.31.0 + version: 0.31.0 + quickjs-emscripten-sync: + specifier: 1.6.0 + version: 1.6.0(quickjs-emscripten@0.31.0) + tslog: + specifier: 4.9.3 + version: 4.9.3 + type-fest: + specifier: 4.26.1 + version: 4.26.1 + valibot: + specifier: 0.42.1 + version: 0.42.1(typescript@5.9.3) + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../tsconfig + esbuild-plugin-wasm: + specifier: 1.1.0 + version: 1.1.0 + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + packages/test-utils: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../../plugins/plugin-core + execa: + specifier: 9.5.1 + version: 9.5.1 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../tsconfig + '@types/node': + specifier: 24.12.2 + version: 24.12.2 + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: ^5.0.0 + version: 5.9.3 + + packages/tsconfig: + dependencies: + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + + plugins/plugin-construct: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + es-toolkit: + specifier: 1.25.2 + version: 1.25.2 + playwright: + specifier: 1.48.2 + version: 1.48.2 + valibot: + specifier: 0.42.1 + version: 0.42.1(typescript@5.9.3) + devDependencies: + '@pipelab/test-utils': + specifier: workspace:* + version: link:../../packages/test-utils + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@types/node': + specifier: '24' + version: 24.12.2 + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + plugins/plugin-core: + dependencies: + '@pipelab/core-node': + specifier: workspace:* + version: link:../../packages/core-node + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + archiver: + specifier: 7.0.1 + version: 7.0.1 + electron: + specifier: 32.1.2 + version: 32.1.2 + execa: + specifier: 9.4.1 + version: 9.4.1 + pacote: + specifier: 21.5.0 + version: 21.5.0 + tar: + specifier: 6.2.1 + version: 6.2.1 + type-fest: + specifier: 4.26.1 + version: 4.26.1 + yauzl: + specifier: 2.10.0 + version: 2.10.0 + zod: + specifier: 4.3.6 + version: 4.3.6 + devDependencies: + '@pipelab/constants': + specifier: workspace:* + version: link:../../packages/constants + '@pipelab/shared': + specifier: workspace:* + version: link:../../packages/shared + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@types/archiver': + specifier: 7.0.0 + version: 7.0.0 + '@types/pacote': + specifier: 11.1.8 + version: 11.1.8 + '@types/tar': + specifier: 7.0.87 + version: 7.0.87 + '@types/yauzl': + specifier: 2.10.3 + version: 2.10.3 + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + + plugins/plugin-discord: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@pipelab/shared': + specifier: workspace:* + version: link:../../packages/shared + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + electron: + specifier: 32.1.2 + version: 32.1.2 + ts-deepmerge: + specifier: 7.0.1 + version: 7.0.1 + untun: + specifier: 0.1.3 + version: 0.1.3 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + plugins/plugin-electron: + dependencies: + '@pipelab/constants': + specifier: workspace:* + version: link:../../packages/constants + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@pipelab/shared': + specifier: workspace:* + version: link:../../packages/shared + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + electron: + specifier: 32.1.2 + version: 32.1.2 + ts-deepmerge: + specifier: 7.0.1 + version: 7.0.1 + devDependencies: + '@pipelab/test-utils': + specifier: workspace:* + version: link:../../packages/test-utils + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + plugins/plugin-filesystem: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + node-stream-zip: + specifier: 1.15.0 + version: 1.15.0 + devDependencies: + '@pipelab/test-utils': + specifier: workspace:* + version: link:../../packages/test-utils + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + plugins/plugin-itch: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + node-stream-zip: + specifier: 1.15.0 + version: 1.15.0 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@types/node': + specifier: '24' + version: 24.12.2 + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + + plugins/plugin-minify: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + + plugins/plugin-netlify: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + electron: + specifier: 32.1.2 + version: 32.1.2 + untun: + specifier: 0.1.3 + version: 0.1.3 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + + plugins/plugin-nvpatch: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + execa: + specifier: 9.4.1 + version: 9.4.1 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + + plugins/plugin-poki: + dependencies: + '@pipelab/constants': + specifier: workspace:* + version: link:../../packages/constants + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + devDependencies: + '@pipelab/test-utils': + specifier: workspace:* + version: link:../../packages/test-utils + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + '@types/node': + specifier: '24' + version: 24.12.2 + electron: + specifier: 32.1.2 + version: 32.1.2 + msw: + specifier: 2.7.5 + version: 2.7.5(@types/node@24.12.2)(typescript@5.9.3) + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + plugins/plugin-steam: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + execa: + specifier: 9.4.1 + version: 9.4.1 + devDependencies: + '@pipelab/test-utils': + specifier: workspace:* + version: link:../../packages/test-utils + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + plugins/plugin-system: + dependencies: + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + + plugins/plugin-tauri: + dependencies: + '@pipelab/constants': + specifier: workspace:* + version: link:../../packages/constants + '@pipelab/plugin-core': + specifier: workspace:* + version: link:../plugin-core + '@pipelab/shared': + specifier: workspace:* + version: link:../../packages/shared + '@types/node': + specifier: ^24.12.2 + version: 24.12.2 + electron: + specifier: 32.1.2 + version: 32.1.2 + execa: + specifier: 9.4.1 + version: 9.4.1 + ts-deepmerge: + specifier: 7.0.1 + version: 7.0.1 + devDependencies: + '@pipelab/tsconfig': + specifier: workspace:* + version: link:../../packages/tsconfig + tsdown: + specifier: 0.21.2 + version: 0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: 3.1.4 + version: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + +packages: + + '@antfu/utils@0.7.10': + resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} + + '@azure/abort-controller@1.1.0': + resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} + engines: {node: '>=12.0.0'} + + '@azure/abort-controller@2.1.2': + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + + '@azure/arm-containerinstance@9.1.0': + resolution: {integrity: sha512-N9T3/HJwWXvJuz7tin+nO+DYYCTGHILJ5Die3TtdF8Wd1ITfXGqB0vY/wOnspUu/AGojhaIKGmawAfPdw2kX8w==} + engines: {node: '>=14.0.0'} + + '@azure/core-auth@1.10.1': + resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} + engines: {node: '>=20.0.0'} + + '@azure/core-client@1.10.1': + resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} + engines: {node: '>=20.0.0'} + + '@azure/core-http@3.0.5': + resolution: {integrity: sha512-T8r2q/c3DxNu6mEJfPuJtptUVqwchxzjj32gKcnMi06rdiVONS9rar7kT9T2Am+XvER7uOzpsP79WsqNbdgdWg==} + engines: {node: '>=18.0.0'} + deprecated: This package is no longer supported. Please refer to https://github.com/Azure/azure-sdk-for-js/blob/490ce4dfc5b98ba290dee3b33a6d0876c5f138e2/sdk/core/README.md + + '@azure/core-lro@2.7.2': + resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} + engines: {node: '>=18.0.0'} + + '@azure/core-paging@1.6.2': + resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} + engines: {node: '>=18.0.0'} + + '@azure/core-rest-pipeline@1.23.0': + resolution: {integrity: sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-tracing@1.0.0-preview.13': + resolution: {integrity: sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==} + engines: {node: '>=12.0.0'} + + '@azure/core-tracing@1.3.1': + resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-util@1.13.1': + resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} + engines: {node: '>=20.0.0'} + + '@azure/identity@4.0.1': + resolution: {integrity: sha512-yRdgF03SFLqUMZZ1gKWt0cs0fvrDIkq2bJ6Oidqcoo5uM85YMBnXWMzYKK30XqIT76lkFyAaoAAy5knXhrG4Lw==} + engines: {node: '>=18.0.0'} + + '@azure/logger@1.3.0': + resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} + engines: {node: '>=20.0.0'} + + '@azure/msal-browser@3.30.0': + resolution: {integrity: sha512-I0XlIGVdM4E9kYP5eTjgW8fgATdzwxJvQ6bm2PNiHaZhEuUz47NYw1xHthC9R+lXz4i9zbShS0VdLyxd7n0GGA==} + engines: {node: '>=0.8.0'} + + '@azure/msal-common@14.16.1': + resolution: {integrity: sha512-nyxsA6NA4SVKh5YyRpbSXiMr7oQbwark7JU9LMeg6tJYTSPyAGkdx61wPT4gyxZfxlSxMMEyAsWaubBlNyIa1w==} + engines: {node: '>=0.8.0'} + + '@azure/msal-node@2.16.3': + resolution: {integrity: sha512-CO+SE4weOsfJf+C5LM8argzvotrXw252/ZU6SM2Tz63fEblhH1uuVaaO4ISYFuN4Q6BhTo7I3qIdi8ydUQCqhw==} + engines: {node: '>=16'} + + '@azure/storage-file-share@12.15.0': + resolution: {integrity: sha512-boaEKdunq33CdU/TBAao7Ilefni3KgZqmUzlVLufkykgwpNtIgcbGR2b/+T2T9K/4G2TfhhuOkzlSlsbvwIikg==} + engines: {node: '>=14.0.0'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@8.0.0-rc.2': + resolution: {integrity: sha512-oCQ1IKPwkzCeJzAPb7Fv8rQ9k5+1sG8mf2uoHiMInPYvkRfrDJxbTIbH51U+jstlkghus0vAi3EBvkfvEsYNLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 '@babel/helper-optimise-call-expression@7.27.1': resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -539,37 +1270,55 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-string-parser@8.0.0-rc.3': + resolution: {integrity: sha512-AmwWFx1m8G/a5cXkxLxTiWl+YEoWuoFLUCwqMlNuWO1tqAYITQAbCRPUkyBHv1VOFgfjVOqEj6L3u15J5ZCzTA==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@8.0.0-rc.2': + resolution: {integrity: sha512-xExUBkuXWJjVuIbO7z6q7/BA9bgfJDEhVL0ggrggLMbg0IzCUWGT1hZGE8qUH7Il7/RD/a6cZ3AAFrrlp1LF/A==} + engines: {node: ^20.19.0 || >=22.12.0} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.6': - resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.5': - resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-proposal-decorators@7.27.1': - resolution: {integrity: sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==} + '@babel/parser@8.0.0-rc.2': + resolution: {integrity: sha512-29AhEtcq4x8Dp3T72qvUMZHx0OMXCj4Jy/TEReQa+KWLln524Cj1fWb3QFi0l/xSpptQBR6y9RNEXuxpFvwiUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + '@babel/plugin-proposal-decorators@7.29.0': + resolution: {integrity: sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-decorators@7.27.1': - resolution: {integrity: sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==} + '@babel/plugin-syntax-decorators@7.28.6': + resolution: {integrity: sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -579,67 +1328,71 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.27.1': - resolution: {integrity: sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.13.7': - resolution: {integrity: sha512-h+ilqoX998mRVM5FtB5ijRuHUDVt5l3yfoOi2uh18Z/O3hvyaHQ39NpxVkCIG5yFs+mLq/ewFp8Bss6zmWv6ZA==} - '@babel/runtime@7.27.6': - resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.27.4': - resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@7.27.6': - resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==} - engines: {node: '>=6.9.0'} + '@babel/types@8.0.0-rc.2': + resolution: {integrity: sha512-91gAaWRznDwSX4E2tZ1YjBuIfnQVOFDCQ2r0Toby0gu4XEbyF623kXLMA8d4ZbCu+fINcrudkmEcwSUHgDDkNw==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@bufbuild/protobuf@2.11.0': + resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} + + '@bundled-es-modules/cookie@2.0.1': + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} - '@changesets/apply-release-plan@7.0.12': - resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==} + '@bundled-es-modules/statuses@1.0.1': + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} - '@changesets/assemble-release-plan@6.0.8': - resolution: {integrity: sha512-y8+8LvZCkKJdbUlpXFuqcavpzJR80PN0OIfn8HZdwK7Sh6MgLXm4hKY5vu6/NDoKp8lAlM4ERZCqRMLxP4m+MQ==} + '@bundled-es-modules/tough-cookie@0.1.6': + resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} - '@changesets/changelog-git@0.2.0': - resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==} + '@changesets/apply-release-plan@7.1.0': + resolution: {integrity: sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==} - '@changesets/changelog-github@0.5.0': - resolution: {integrity: sha512-zoeq2LJJVcPJcIotHRJEEA2qCqX0AQIeFE+L21L8sRLPVqDhSXY8ZWAt2sohtBpFZkBwu+LUwMSKRr2lMy3LJA==} + '@changesets/assemble-release-plan@6.0.9': + resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} - '@changesets/cli@2.27.11': - resolution: {integrity: sha512-1QislpE+nvJgSZZo9+Lj3Lno5pKBgN46dAV8IVxKJy9wX8AOrs9nn5pYVZuDpoxWJJCALmbfOsHkyxujgetQSg==} + '@changesets/changelog-git@0.2.1': + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + + '@changesets/cli@2.30.0': + resolution: {integrity: sha512-5D3Nk2JPqMI1wK25pEymeWRSlSMdo5QOGlyfrKg0AOufrUcjEE3RQgaCpHoBiM31CSNrtSgdJ0U6zL1rLDDfBA==} hasBin: true - '@changesets/config@3.1.1': - resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} + '@changesets/config@3.1.3': + resolution: {integrity: sha512-vnXjcey8YgBn2L1OPWd3ORs0bGC4LoYcK/ubpgvzNVr53JXV5GiTVj7fWdMRsoKUH7hhhMAQnsJUqLr21EncNw==} '@changesets/errors@0.2.0': resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} @@ -647,11 +1400,8 @@ packages: '@changesets/get-dependents-graph@2.1.3': resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} - '@changesets/get-github-info@0.6.0': - resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==} - - '@changesets/get-release-plan@4.0.12': - resolution: {integrity: sha512-KukdEgaafnyGryUwpHG2kZ7xJquOmWWWk5mmoeQaSvZTWH1DC5D/Sw6ClgGFYtQnOMSQhgoEbDxAbpIIayKH1g==} + '@changesets/get-release-plan@4.0.15': + resolution: {integrity: sha512-Q04ZaRPuEVZtA+auOYgFaVQQSA98dXiVe/yFaZfY7hoSmQICHGvP0TF4u3EDNHWmmCS4ekA/XSpKlSM2PyTS2g==} '@changesets/get-version-range-type@0.4.0': resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} @@ -662,14 +1412,14 @@ packages: '@changesets/logger@0.1.1': resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - '@changesets/parse@0.4.1': - resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} + '@changesets/parse@0.4.3': + resolution: {integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==} '@changesets/pre@2.0.2': resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} - '@changesets/read@0.6.5': - resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==} + '@changesets/read@0.6.7': + resolution: {integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==} '@changesets/should-skip-package@0.1.2': resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} @@ -680,8 +1430,14 @@ packages: '@changesets/types@6.1.0': resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} - '@changesets/write@0.3.2': - resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==} + '@changesets/write@0.4.0': + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + + '@clack/core@1.2.0': + resolution: {integrity: sha512-qfxof/3T3t9DPU/Rj3OmcFyZInceqj/NVtO9rwIuJqCUgh32gwPjpFQQp/ben07qKlhpwq7GzfWpST4qdJ5Drg==} + + '@clack/prompts@1.2.0': + resolution: {integrity: sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w==} '@codemirror/autocomplete@6.18.1': resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} @@ -697,17 +1453,17 @@ packages: '@codemirror/lang-css@6.3.1': resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==} - '@codemirror/lang-html@6.4.9': - resolution: {integrity: sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==} + '@codemirror/lang-html@6.4.11': + resolution: {integrity: sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==} - '@codemirror/lang-javascript@6.2.4': - resolution: {integrity: sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==} + '@codemirror/lang-javascript@6.2.2': + resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==} '@codemirror/lang-liquid@6.2.1': resolution: {integrity: sha512-J1Mratcm6JLNEiX+U2OlCDTysGuwbHD76XwuL5o5bo9soJtSbz2g6RU3vGHFyS5DC8rgVmFSzi7i6oBftm7tnA==} - '@codemirror/language@6.11.1': - resolution: {integrity: sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==} + '@codemirror/language@6.12.3': + resolution: {integrity: sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==} '@codemirror/lint@6.8.2': resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} @@ -718,155 +1474,90 @@ packages: '@codemirror/view@6.34.0': resolution: {integrity: sha512-2vKJ79tOcVfgPYVJM2XjcL1BH5Bsl7/tgn9ilBj3XWeCS5kTRy/NE4FHEj4aMylOl/D3IPNsmZH0WPlB+DyIdA==} - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - - '@csstools/color-helpers@5.0.2': - resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} - engines: {node: '>=18'} - - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-color-parser@3.0.10': - resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} - - '@electron-forge/cli@7.4.0': - resolution: {integrity: sha512-a+zZv3ja/IxkJzNyx4sOHSZv6DPV85S0PEVF6pcRjUpbDL5r+DxjRFsNc0Nq4UIWyFm1nw7RWoPdd9uDst4Tvg==} + '@electron-forge/cli@7.11.1': + resolution: {integrity: sha512-pk8AoLsr7t7LBAt0cFD06XFA6uxtPdvtLx06xeal7O9o7GHGCbj29WGwFoJ8Br/ENM0Ho868S3PrAn1PtBXt5g==} engines: {node: '>= 16.4.0'} hasBin: true - '@electron-forge/core-utils@7.4.0': - resolution: {integrity: sha512-9RLG0F9SX466TpkaTcW+V15KmnGuTpmr7NKMRlngtHXmnkBUJz4Mxp1x33WZLgL90dJrxrRgHSfVBtA4lstDPw==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/core@7.4.0': - resolution: {integrity: sha512-pYHKpB2CKeQgWsb+gox+FPkEvP+6Q2zGj2eZtgZRtKppoWIXrHIpOtcm6FllJ/gZ5u4AsQzVIYReAHGaBa0osw==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/maker-base@7.4.0': - resolution: {integrity: sha512-LwWS4VPdwjISl1KpLhmM1Qr1M3sRTTQ/RsX+GlFd7cQ1W/FsgxMjaTG4Od1d+a5CGVTh3s6X2g99TSUfxjOveg==} + '@electron-forge/core-utils@7.11.1': + resolution: {integrity: sha512-9UxRWVsfcziBsbAA2MS0Oz4yYovQCO2BhnGIfsbKNTBtMc/RcVSxAS0NMyymce44i43p1ZC/FqWhnt1XqYw3bQ==} engines: {node: '>= 16.4.0'} - '@electron-forge/maker-base@7.8.1': - resolution: {integrity: sha512-GUZqschGuEBzSzE0bMeDip65IDds48DZXzldlRwQ+85SYVA6RMU2AwDDqx3YiYsvP2OuxKruuqIJZtOF5ps4FQ==} + '@electron-forge/core@7.11.1': + resolution: {integrity: sha512-YtuPLzggPKPabFAD2rOZFE0s7f4KaUTpGRduhSMbZUqpqD1TIPyfoDBpYiZvao3Ht8pyZeOJjbzcC0LpFs9gIQ==} engines: {node: '>= 16.4.0'} - '@electron-forge/maker-deb@7.4.0': - resolution: {integrity: sha512-npWea3IpGeu96xNqJpsCOYX6V4E+HY6u/okeTUzUOMX96UteT14MecdUefMam158glRTX84k2ryh7WcBoOa4mg==} + '@electron-forge/maker-base@7.11.1': + resolution: {integrity: sha512-yhZrCGoN6bDeiB5DHFaueZ1h84AReElEj+f0hl2Ph4UbZnO0cnLpbx+Bs+XfMLAiA+beC8muB5UDK5ysfuT9BQ==} engines: {node: '>= 16.4.0'} - '@electron-forge/maker-dmg@7.4.0': - resolution: {integrity: sha512-xRCMNtnpvQNwrDYvwbVFegnErnIMpHGZANrjwushlH9+Fsu60DFvf5s3AVkgsYdQTqlY7wYRG1mziYZmRlPAIw==} + '@electron-forge/maker-dmg@7.11.1': + resolution: {integrity: sha512-7zs5/Ewz1PcOl4N1102stFgBiFGWxU18+UPFUSd/fgf9MErBl4HBWuVNMIHyeJ/56rdfkcmTxTqE+9TBEYrZcg==} engines: {node: '>= 16.4.0'} - '@electron-forge/maker-flatpak@7.4.0': - resolution: {integrity: sha512-YWmPBr8bbzEMD4Drar8KXE0A7phopcWWo/i1br44Aeg5soygmcWgatUYe1a5jKDPOgXiV7TfJUwhXbljYAhlFw==} + '@electron-forge/maker-squirrel@7.11.1': + resolution: {integrity: sha512-oSg7fgad6l+X0DjtRkSpMzB0AjzyDO4mb2gzM4kTodkP1ADeiMi08bxy0ZeCESqLm5+fG72cAPmEr3BAPvI1yw==} engines: {node: '>= 16.4.0'} - '@electron-forge/maker-pkg@7.8.1': - resolution: {integrity: sha512-MrlQfZx+9Y/OvsDy+lMVND+NjwF8SfTIRKOCaBGD6RTEhMwdcnFEfLa6fn2mtOcR7jLd6dAe3WIYqZ+4lQBPfg==} + '@electron-forge/maker-zip@7.11.1': + resolution: {integrity: sha512-30rcp0AbJLfkFBX2hmO14LKXx7z9V61LffTVbTCFMh5vUB2kZvcA5xAhsBk2oUJWfGVxe1DuSEU0rDR9bUMHUg==} engines: {node: '>= 16.4.0'} - '@electron-forge/maker-squirrel@7.4.0': - resolution: {integrity: sha512-mCQyufnSNfjffiKho59ZqVg4W601zGOl6h01OyfDwjOU/G4iQtpnnDEOXGe26q7OVT5ORb1WDnfyGgBeJ6Ge7g==} + '@electron-forge/plugin-base@7.11.1': + resolution: {integrity: sha512-lKpSOV1GA3FoYiD9k05i6v4KaQVmojnRgCr7d6VL1bFp13QOtXSaAWhFI9mtSY7rGElOacX6Zt7P7rPoB8T9eQ==} engines: {node: '>= 16.4.0'} - '@electron-forge/maker-zip@7.4.0': - resolution: {integrity: sha512-UGbMdpuK/P29x1FFRWNOs3bNz+7QNFWVWyTM5hcWqib66cNuUmoaPifQyuwW2POIrIohrxlzLK87/i9Zc8g4dA==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/plugin-base@7.4.0': - resolution: {integrity: sha512-LcTNtEc2YaWvhhqWVIfdJ+J0/krSgc2dqYAHhOH2aLUSm9End3dKO/PZ1Y6DPsiPiJKHnSLBJ/XBN/16NY4Sjw==} - engines: {node: '>= 16.4.0'} - - '@electron-forge/plugin-fuses@7.4.0': - resolution: {integrity: sha512-LKcyIaO0sUkzZdOB1PySjG1R9KAl5Vi453ZQcambBI7RpZtPKozluNd0zlXey1cf7ycTwhzvmrI6ss3LHQyjvw==} + '@electron-forge/plugin-fuses@7.11.1': + resolution: {integrity: sha512-Td517mHf+RjQAayFDM2kKb7NaGdRXrZfPbc7KOHlGbXthp5YTkFu2cCZGWokiqt1y1wsFaAodULhqBIg7vbbbw==} engines: {node: '>= 16.4.0'} peerDependencies: - '@electron/fuses': '>=1.0.0' - - '@electron-forge/plugin-vite@7.4.0': - resolution: {integrity: sha512-GZqBUsyNH0XCvQlBKMS0aOJM6PX80irijgPR9Lfl6ctYIuKTo+82td+nIK8Fef/qSDUEt/U1f4Qb9GfLfhRRig==} - engines: {node: '>= 16.4.0'} + '@electron/fuses': ^1.0.0 - '@electron-forge/publisher-base@7.4.0': - resolution: {integrity: sha512-PiJk4RfaC55SnVnteLW2ZIQNM9DpGOi6YoUn5t8i9UcVp2rFIdya7bJY/b9u1hwubm4d5+TdypMVEuJjM44CJQ==} + '@electron-forge/plugin-vite@7.11.1': + resolution: {integrity: sha512-kc/WQs/0+9VC9Q4oSSocMa02YxKDvAYxhWtNcL+qlswZMJlxe8gX7vl/yXq9AjPQxw7f3jzf7nruUPKQ+vyLLg==} engines: {node: '>= 16.4.0'} - '@electron-forge/publisher-github@7.4.0': - resolution: {integrity: sha512-hrxKNssJyU8Yuz0qv384y5RKojMG0nWeG7/kidjp8PX/RnqjGRU/JJ0Worl28g8LGiLt5R5JIfNLngLaFMn8tg==} + '@electron-forge/publisher-base@7.11.1': + resolution: {integrity: sha512-rXE9oMFGMtdQrixnumWYH5TTGsp99iPHZb3jI74YWq518ctCh6DlIgWlhf6ok2X0+lhWovcIb45KJucUFAQ13w==} engines: {node: '>= 16.4.0'} - '@electron-forge/shared-types@7.4.0': - resolution: {integrity: sha512-5Ehy6enUjBaU08odf9u9TOhmOVXlqobzMvKUixtkdAWgV1XZAUJmn+p21xhj0IkO92MQiXMGv66w9pDNjRT8uQ==} + '@electron-forge/publisher-github@7.11.1': + resolution: {integrity: sha512-3S7DS1NZRrYvf59eqH0F2ke9oLD5FQqW5+t6kY1EuEo6I8HF+u6dOkGnvzhRh+uvKkjy4ynV3j735PlqBbClGQ==} engines: {node: '>= 16.4.0'} - '@electron-forge/shared-types@7.8.1': - resolution: {integrity: sha512-guLyGjIISKQQRWHX+ugmcjIOjn2q/BEzCo3ioJXFowxiFwmZw/oCZ2KlPig/t6dMqgUrHTH5W/F0WKu0EY4M+Q==} + '@electron-forge/shared-types@7.11.1': + resolution: {integrity: sha512-vvBWdAEh53UJlDGUevpaJk1+sqDMQibfrbHR+0IPA4MPyQex7/Uhv3vYH9oGHujBVAChQahjAuJt0fG6IJBLZg==} engines: {node: '>= 16.4.0'} - '@electron-forge/template-base@7.4.0': - resolution: {integrity: sha512-3YWdRSGzQfQPQkQxStn2wkJ/SuNGGKo9slwFJGvqMV+Pbx3/M/hYi9sMXOuaqVZgeaBp8Ap27yFPxaIIOC3vcA==} + '@electron-forge/template-base@7.11.1': + resolution: {integrity: sha512-XpTaEf+EfQw+0BlSAtSpZKYIKYvKu4raNzSGHZZoSYHp+HDC7R+MlpFQmSJiGdYQzQ14C+uxO42tVjgM0DMbpw==} engines: {node: '>= 16.4.0'} - '@electron-forge/template-vite-typescript@7.4.0': - resolution: {integrity: sha512-wdByG807VWcUd81E6572b/G/Ki8gb+GrCIWxO7Cl3qBa+yNaU1sHhBwB1RyTbQy1r8ubSBtsWrRD1J/yzHKWoQ==} + '@electron-forge/template-vite-typescript@7.11.1': + resolution: {integrity: sha512-Us4AHXFb+4z+gXgZImSqMBS63oKnsQWLOhqRg321xiDzu2UcQPlwgWNb4rAEKNVC1e7LXrUNDHuBiTrQkvWXbg==} engines: {node: '>= 16.4.0'} - '@electron-forge/template-vite@7.4.0': - resolution: {integrity: sha512-YPVyCGiBKmZPCxK/Bd2louV3PBcxI2nT2+tRKP+mlEHOWrxbZIfmZSR2lIAFvK/ALKlwUKROdmlwyi7ZcdT7JQ==} + '@electron-forge/template-vite@7.11.1': + resolution: {integrity: sha512-Or8Lxf4awoeUZoMTKJEw5KQDIhqOFs24WhVka3yZXxc6VgVWN79KmYKYM6uM/YMQttmafhsBhY2t1Lxo1WR/ug==} engines: {node: '>= 16.4.0'} - '@electron-forge/template-webpack-typescript@7.4.0': - resolution: {integrity: sha512-O5gwjNSGFNRdJWyiCtevcOBDPAMhgOPvLORh9qR1GcjyTutWwHWmZzycqH+MmkhpQPgrAYDEeipXcOQhSbzNZA==} + '@electron-forge/template-webpack-typescript@7.11.1': + resolution: {integrity: sha512-6ExfFnFkHBz8rvRFTFg5HVGTC12uJpbVk4q8DVg0R8rhhxhqiVNh8lF2UPtZ2yT2UtGWjXNVlyP3Y3T6q6E3GQ==} engines: {node: '>= 16.4.0'} - '@electron-forge/template-webpack@7.4.0': - resolution: {integrity: sha512-W558AEGwQrwEtKIbIJPPs0LIsaC/1Vncj5NgqKehEMJjBb0KQq4hwBu/6dauQrfun4jRCOp7LV+OVrf5XPJ7QA==} + '@electron-forge/template-webpack@7.11.1': + resolution: {integrity: sha512-15lbXxi+er461MPk6sbwAOyjofAHwmQjTvxNCiNpaU2naEwbj3t0SlLq/BMr5HxnVOaMmA7+lKV9afkIom+d4Q==} engines: {node: '>= 16.4.0'} - '@electron-forge/tracer@7.4.0': - resolution: {integrity: sha512-F4jbnDn4yIZjmky1FZ6rgBKTM05AZQQfHkyJW2hdS4pDKJjdKAqWytoZKDi1/S6Cr6tN+DD0TFGD3V0i6HPHYQ==} + '@electron-forge/tracer@7.11.1': + resolution: {integrity: sha512-tiB6cglVQFcSw9N8GRwVwZUeB9u0DOx2Mj7aFXBUsFLUYQapvVGv51tUSy/UAW5lvmubGscYIILuVko+II3+NA==} engines: {node: '>= 14.17.5'} - '@electron-forge/tracer@7.8.1': - resolution: {integrity: sha512-r2i7aHVp2fylGQSPDw3aTcdNfVX9cpL1iL2MKHrCRNwgrfR+nryGYg434T745GGm1rNQIv5Egdkh5G9xf00oWA==} - engines: {node: '>= 14.17.5'} - - '@electron-forge/web-multi-logger@7.4.0': - resolution: {integrity: sha512-XHKs37q4S8BzH1lTKhuOFO6k4R7XdrsZfox+qlp4HpiYKw8yq4rcasB0zUO5YKZ2aTJ1t79X1jxSJb5qhImdHA==} - engines: {node: '>= 16.4.0'} - '@electron-toolkit/preload@3.0.2': resolution: {integrity: sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==} peerDependencies: electron: '>=13.0.0' - '@electron-toolkit/tsconfig@1.0.1': - resolution: {integrity: sha512-M0Mol3odspvtCuheyujLNAW7bXq7KFNYVMRtpjFa4ZfES4MuklXBC7Nli/omvc+PRKlrklgAGx3l4VakjNo8jg==} - peerDependencies: - '@types/node': '*' - '@electron-toolkit/utils@4.0.0': resolution: {integrity: sha512-qXSntwEzluSzKl4z5yFNBknmPGjPa3zFhE4mp9+h0cgokY5ornAeP+CJQDBhKsL1S58aOQfcwkD3NwLZCl+64g==} peerDependencies: @@ -904,8 +1595,8 @@ packages: engines: {node: '>=12.0.0'} hasBin: true - '@electron/packager@18.3.6': - resolution: {integrity: sha512-1eXHB5t+SQKvUiDpWGpvr90ZSSbXj+isrh3YbjCTjKT4bE4SQrKSBfukEAaBvp67+GXHFtCHjQgN9qSTFIge+Q==} + '@electron/packager@18.4.4': + resolution: {integrity: sha512-fTUCmgL25WXTcFpM1M72VmFP8w3E4d+KNzWxmTDRpvwkfn/S206MAtM2cy0GF78KS9AwASMOUmlOIzCHeNxcGQ==} engines: {node: '>= 16.13.0'} hasBin: true @@ -923,14 +1614,20 @@ packages: engines: {node: '>=14.14'} hasBin: true - '@emnapi/runtime@1.4.3': - resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@esbuild/aix-ppc64@0.23.1': resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} @@ -938,17 +1635,17 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.5': - resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] '@esbuild/android-arm64@0.23.1': resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} @@ -956,16 +1653,16 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.5': - resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} - cpu: [arm] + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] os: [android] '@esbuild/android-arm@0.23.1': @@ -974,16 +1671,16 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.5': - resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] os: [android] '@esbuild/android-x64@0.23.1': @@ -992,17 +1689,17 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.5': - resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] '@esbuild/darwin-arm64@0.23.1': resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} @@ -1010,16 +1707,16 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.5': - resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.23.1': @@ -1028,17 +1725,17 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.5': - resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] '@esbuild/freebsd-arm64@0.23.1': resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} @@ -1046,16 +1743,16 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.5': - resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.23.1': @@ -1064,17 +1761,17 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.5': - resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] '@esbuild/linux-arm64@0.23.1': resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} @@ -1082,16 +1779,16 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.5': - resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} - cpu: [arm] + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.23.1': @@ -1100,16 +1797,16 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.5': - resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} - cpu: [ia32] + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.23.1': @@ -1118,16 +1815,16 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.5': - resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} - cpu: [loong64] + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.23.1': @@ -1136,16 +1833,16 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.5': - resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} - cpu: [mips64el] + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.23.1': @@ -1154,16 +1851,16 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.5': - resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} - cpu: [ppc64] + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.23.1': @@ -1172,16 +1869,16 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.5': - resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} - cpu: [riscv64] + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.23.1': @@ -1190,16 +1887,16 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.5': - resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} - cpu: [s390x] + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.23.1': @@ -1208,16 +1905,16 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.5': - resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.23.1': @@ -1226,22 +1923,28 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.5': - resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.5': - resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] os: [netbsd] '@esbuild/netbsd-x64@0.23.1': @@ -1250,8 +1953,14 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.5': - resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1262,16 +1971,16 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.25.5': - resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] os: [openbsd] '@esbuild/openbsd-x64@0.23.1': @@ -1280,17 +1989,29 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.5': - resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} cpu: [x64] - os: [sunos] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] '@esbuild/sunos-x64@0.23.1': resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} @@ -1298,34 +2019,34 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.5': - resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.23.1': resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.5': - resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} - cpu: [ia32] + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.23.1': @@ -1334,16 +2055,16 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.5': - resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.23.1': @@ -1352,216 +2073,320 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.5': - resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.7.0': - resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.18.0': - resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.13.0': - resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.7.0': - resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.1.0': - resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.13.0': - resolution: {integrity: sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.2.8': - resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] - '@floating-ui/core@1.7.1': - resolution: {integrity: sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - '@floating-ui/dom@1.7.1': - resolution: {integrity: sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==} + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - '@floating-ui/utils@0.2.9': - resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} '@floating-ui/vue@1.1.5': resolution: {integrity: sha512-ynL1p5Z+woPVSwgMGqeDrx6HrJfGIDzFyESFkyqJKilGW1+h/8yVY29Khn0LaU6wHBRwZ13ntG6reiHWK6jyzw==} + '@gar/promise-retry@1.0.3': + resolution: {integrity: sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==} + engines: {node: ^20.17.0 || >=22.9.0} + '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + '@gwhitney/detect-indent@7.0.1': + resolution: {integrity: sha512-7bQW+gkKa2kKZPeJf6+c6gFK9ARxQfn+FKy9ScTBppyKRWH2KzsmweXUoklqeEiHiNVWaeP5csIdsNq6w7QhzA==} + engines: {node: '>=12.20'} - '@humanwhocodes/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.2': - resolution: {integrity: sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==} + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.2': - resolution: {integrity: sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.1.0': - resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.1.0': - resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.1.0': - resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-arm@1.1.0': - resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.1.0': - resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.1.0': - resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-x64@1.1.0': - resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.1.0': - resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.1.0': - resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] - '@img/sharp-linux-arm64@0.34.2': - resolution: {integrity: sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] - '@img/sharp-linux-arm@0.34.2': - resolution: {integrity: sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@img/sharp-linux-s390x@0.34.2': - resolution: {integrity: sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==} + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] - '@img/sharp-linux-x64@0.34.2': - resolution: {integrity: sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.2': - resolution: {integrity: sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.2': - resolution: {integrity: sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] - '@img/sharp-wasm32@0.34.2': - resolution: {integrity: sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.2': - resolution: {integrity: sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.2': - resolution: {integrity: sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==} + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.2': - resolution: {integrity: sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] - '@intlify/core-base@10.0.7': - resolution: {integrity: sha512-mE71aUH5baH0me8duB4FY5qevUJizypHsYw3eCvmOx07QvmKppgOONx3dYINxuA89Z2qkAGb/K6Nrpi7aAMwew==} + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/checkbox@3.0.1': + resolution: {integrity: sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@4.0.1': + resolution: {integrity: sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w==} + engines: {node: '>=18'} + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@9.2.1': + resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==} + engines: {node: '>=18'} + + '@inquirer/editor@3.0.1': + resolution: {integrity: sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q==} + engines: {node: '>=18'} + + '@inquirer/expand@3.0.1': + resolution: {integrity: sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ==} + engines: {node: '>=18'} + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/input@3.0.1': + resolution: {integrity: sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg==} + engines: {node: '>=18'} + + '@inquirer/number@2.0.1': + resolution: {integrity: sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ==} + engines: {node: '>=18'} + + '@inquirer/password@3.0.1': + resolution: {integrity: sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ==} + engines: {node: '>=18'} + + '@inquirer/prompts@6.0.1': + resolution: {integrity: sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==} + engines: {node: '>=18'} + + '@inquirer/rawlist@3.0.1': + resolution: {integrity: sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ==} + engines: {node: '>=18'} + + '@inquirer/search@2.0.1': + resolution: {integrity: sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg==} + engines: {node: '>=18'} + + '@inquirer/select@3.0.1': + resolution: {integrity: sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q==} + engines: {node: '>=18'} + + '@inquirer/type@1.5.5': + resolution: {integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==} + engines: {node: '>=18'} + + '@inquirer/type@2.0.0': + resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==} + engines: {node: '>=18'} + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@intlify/core-base@10.0.8': + resolution: {integrity: sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ==} engines: {node: '>= 16'} - '@intlify/message-compiler@10.0.7': - resolution: {integrity: sha512-nrC4cDL/UHZSUqd8sRbVz+DPukzZ8NnG5OK+EB/nlxsH35deyzyVkXP/QuR8mFZrISJ+4hCd6VtCQCcT+RO+5g==} + '@intlify/message-compiler@10.0.8': + resolution: {integrity: sha512-DV+sYXIkHVd5yVb2mL7br/NEUwzUoLBsMkV3H0InefWgmYa34NLZUvMCGi5oWX+Hqr2Y2qUxnVrnOWF4aBlgWg==} engines: {node: '>= 16'} - '@intlify/shared@10.0.7': - resolution: {integrity: sha512-oeoq0L5+5P4ShXa6jBQcx+BT+USe3MjX0xJexZO1y7rfDJdwZ9+QP3jO4tcS1nxhBYYdjvFTqe4bmnLijV0GxQ==} + '@intlify/shared@10.0.8': + resolution: {integrity: sha512-BcmHpb5bQyeVNrptC3UhzpBZB/YHHDoEREOUERrmF2BRxsyOEuRrq+Z96C/D4+2KJb8kuHiouzAei7BXlG0YYw==} engines: {node: '>= 16'} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@jitl/quickjs-ffi-types@0.31.0': resolution: {integrity: sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw==} + '@jitl/quickjs-singlefile-mjs-release-sync@0.31.0': + resolution: {integrity: sha512-VyN48sbNnlhvH/17xoy3Ck15Y9ChFg/e9hcLP/yFdwrGy/x2s1Hnbg0orL3OYiQYKRSpdecrB09rwEPUdDt8BA==} + '@jitl/quickjs-wasmfile-debug-asyncify@0.31.0': resolution: {integrity: sha512-YkdzQdr1uaftFhgEnTRjTTZHk2SFZdpWO7XhOmRVbi6CEVsH9g5oNF8Ta1q3OuSJHRwwT8YsuR1YzEiEIJEk6w==} @@ -1574,593 +2399,1150 @@ packages: '@jitl/quickjs-wasmfile-release-sync@0.31.0': resolution: {integrity: sha512-hYduecOByj9AsAfsJhZh5nA6exokmuFC8cls39+lYmTCGY51bgjJJJwReEu7Ff7vBWaQCL6TeDdVlnp2WYz0jw==} - '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jsonjoy.com/base64@1.1.2': + resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/base64@17.67.0': + resolution: {integrity: sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/buffers@1.2.1': + resolution: {integrity: sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/buffers@17.67.0': + resolution: {integrity: sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/codegen@1.0.0': + resolution: {integrity: sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/codegen@17.67.0': + resolution: {integrity: sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-core@4.57.6': + resolution: {integrity: sha512-uI++Wx6VkBJqVmkb4ZeExwAVpZiA2Do5NrEtXoDk0Pdvce3ytFXJoviT1sLOj16+qDIMnD5nWPfOhVpnDmRJKg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-fsa@4.57.6': + resolution: {integrity: sha512-pKkw/yC5CzSZKhIIUIsH1przOa+K5jGmZIg1sWaSF24JojyrUFbjcQv7QrcGAudriei6HQ6R0BFj+V8NbQinJw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-builtins@4.57.6': + resolution: {integrity: sha512-V4DgEFT3Cg5S9fCMOZSCVdTxdJWWLBO0WnAazV7hnCM96u5zXHyW/ubDAfcSVwqjkMJ50W1Y44IXtxRoIwaCVg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-to-fsa@4.57.6': + resolution: {integrity: sha512-+JptNw3iifihxH2rEXrninDzX4FFVW8JD/wPR8GbJPAeL9CQUSblrlumOPB5gZuS7tYRX+PJPLtT7XzKoRhv/Q==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-utils@4.57.6': + resolution: {integrity: sha512-foyUrfS7WmYEUzqYXSNxmJBcSj04TABrkpFabwO9SCDCpVCfJ+qG+2sk5FjfiflG2n0SDFZDCJ6vYlJAEpxJFg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node@4.57.6': + resolution: {integrity: sha512-Kbn1jdkvDN4F2+BhoB6mMu7NCbhP0bgA5NcI1aJj/Q5UcU+I1JLLW+dEQean33iV4tXv35AzBVKPICnDltBpxw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-print@4.57.6': + resolution: {integrity: sha512-96eAn4Dudtt67LTeuU47yUD+pg9/G/oKpI10zei9ljk3X3WK4lYKc+n3cpaPCAbKPzoyfxl0mXm8f8Y7BOSFXw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-snapshot@4.57.6': + resolution: {integrity: sha512-V57CMzbOgTzUWGOWQ8GzHQdpJP6JnrYVNCtTBNxVYEnlVRvo4uEJqHhtAT8vhDFrIuJOXLrTL1Fki4h5oI7xxg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@1.21.0': + resolution: {integrity: sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@17.67.0': + resolution: {integrity: sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pointer@1.0.2': + resolution: {integrity: sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pointer@17.67.0': + resolution: {integrity: sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jsonjoy.com/util@1.9.0': + resolution: {integrity: sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/util@17.67.0': + resolution: {integrity: sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@lezer/common@1.5.2': + resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==} + + '@lezer/css@1.3.3': + resolution: {integrity: sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==} + + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@lezer/html@1.3.13': + resolution: {integrity: sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==} + + '@lezer/javascript@1.5.4': + resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==} + + '@lezer/lr@1.4.8': + resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} + + '@listr2/prompt-adapter-inquirer@2.0.22': + resolution: {integrity: sha512-hV36ZoY+xKL6pYOt1nPNnkciFkn89KZwqLhAFzJvYysAvL5uBQdiADZx/8bIDXIukzzwG0QlPYolgMzQUtKgpQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@inquirer/prompts': '>= 3 < 8' + + '@malept/cross-spawn-promise@2.0.0': + resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} + engines: {node: '>= 12.13.0'} - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} - '@lezer/common@1.2.3': - resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@lezer/css@1.2.1': - resolution: {integrity: sha512-2F5tOqzKEKbCUNraIXc0f6HKeyKlmMWJnBB0i4XW6dJgssrZO/YlZ2pY5xgyqDleqqhiNJ3dQhbrV2aClZQMvg==} + '@mdi/font@7.4.47': + resolution: {integrity: sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==} - '@lezer/highlight@1.2.1': - resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + '@mswjs/interceptors@0.37.6': + resolution: {integrity: sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w==} + engines: {node: '>=18'} - '@lezer/html@1.3.10': - resolution: {integrity: sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==} + '@napi-rs/wasm-runtime@1.1.3': + resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 - '@lezer/javascript@1.5.1': - resolution: {integrity: sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==} + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 - '@lezer/lr@1.4.2': - resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + '@next/env@16.2.3': + resolution: {integrity: sha512-ZWXyj4uNu4GCWQw9cjRxWlbD+33mcDszIo9iQxFnBX3Wmgq9ulaSJcl6VhuWx5pCWqqD+9W6Wfz7N0lM5lYPMA==} - '@lydell/node-pty-darwin-arm64@1.0.3': - resolution: {integrity: sha512-cpLatXzGHds9fU6KSA+5jB4CRKqqK1ITerYlbucyhfsE0uksMVpzD6Ti6jMeEq7YM0N+c61q6EURl/pIwNYSqA==} + '@next/swc-darwin-arm64@16.2.3': + resolution: {integrity: sha512-u37KDKTKQ+OQLvY+z7SNXixwo4Q2/IAJFDzU1fYe66IbCE51aDSAzkNDkWmLN0yjTUh4BKBd+hb69jYn6qqqSg==} + engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@lydell/node-pty-darwin-x64@1.0.3': - resolution: {integrity: sha512-IuEf8TXwo+wzoUEhqv+LtznwW94gMm4V9XVFMisFh+oRz0TNtnWHtgTCdWCVn4Dm3dpEDAjiAlTLx0ayC5uMVA==} + '@next/swc-darwin-x64@16.2.3': + resolution: {integrity: sha512-gHjL/qy6Q6CG3176FWbAKyKh9IfntKZTB3RY/YOJdDFpHGsUDXVH38U4mMNpHVGXmeYW4wj22dMp1lTfmu/bTQ==} + engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@lydell/node-pty-linux-x64@1.0.3': - resolution: {integrity: sha512-tfj6Zg9F5KkyCQQ2wCUXUW/1lcNgdWAVJNtt6gQH3X+fUueSrRl+R7xoWTcl5NGcfn2l7QWgUrjZcVKP3/ljTg==} + '@next/swc-linux-arm64-gnu@16.2.3': + resolution: {integrity: sha512-U6vtblPtU/P14Y/b/n9ZY0GOxbbIhTFuaFR7F4/uMBidCi2nSdaOFhA0Go81L61Zd6527+yvuX44T4ksnf8T+Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.2.3': + resolution: {integrity: sha512-/YV0LgjHUmfhQpn9bVoGc4x4nan64pkhWR5wyEV8yCOfwwrH630KpvRg86olQHTwHIn1z59uh6JwKvHq1h4QEw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.2.3': + resolution: {integrity: sha512-/HiWEcp+WMZ7VajuiMEFGZ6cg0+aYZPqCJD3YJEfpVWQsKYSjXQG06vJP6F1rdA03COD9Fef4aODs3YxKx+RDQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.2.3': + resolution: {integrity: sha512-Kt44hGJfZSefebhk/7nIdivoDr3Ugp5+oNz9VvF3GUtfxutucUIHfIO0ZYO8QlOPDQloUVQn4NVC/9JvHRk9hw==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] - '@lydell/node-pty-win32-arm64@1.0.3': - resolution: {integrity: sha512-5MTd7hbrvmO/de/B2MDhxjh3E109i5bSds6JtIcVR1M6+uCvWJrON5ibbvWIAqTHpFup20IyDv0cQJxVv9o9nA==} + '@next/swc-win32-arm64-msvc@16.2.3': + resolution: {integrity: sha512-O2NZ9ie3Tq6xj5Z5CSwBT3+aWAMW2PIZ4egUi9MaWLkwaehgtB7YZjPm+UpcNpKOme0IQuqDcor7BsW6QBiQBw==} + engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@lydell/node-pty-win32-x64@1.0.3': - resolution: {integrity: sha512-XMANgXpBYGtKa5q+czro+TaJAyv3njbT7R81Pky+p7e4GwNdWtSUNBxtQm+O4ZLV0VJ1rNiMEHMyGOq8T9i4FA==} + '@next/swc-win32-x64-msvc@16.2.3': + resolution: {integrity: sha512-Ibm29/GgB/ab5n7XKqlStkm54qqZE8v2FnijUPBgrd67FWrac45o/RsNlaOWjme/B5UqeWt/8KM4aWBwA1D2Kw==} + engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@lydell/node-pty-win32-x64@1.1.0': - resolution: {integrity: sha512-3N56BZ+WDFnUMYRtsrr7Ky2mhWGl9xXcyqR6cexfuCqcz9RNWL+KoXRv/nZylY5dYaXkft4JaR1uVu+roiZDAw==} - cpu: [x64] - os: [win32] + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@npmcli/agent@4.0.0': + resolution: {integrity: sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/fs@2.1.2': + resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + '@npmcli/fs@5.0.0': + resolution: {integrity: sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/git@7.0.2': + resolution: {integrity: sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/installed-package-contents@4.0.0': + resolution: {integrity: sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + '@npmcli/move-file@2.0.1': + resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This functionality has been moved to @npmcli/fs + + '@npmcli/node-gyp@5.0.0': + resolution: {integrity: sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/package-json@7.0.5': + resolution: {integrity: sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/promise-spawn@9.0.1': + resolution: {integrity: sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/redact@4.0.0': + resolution: {integrity: sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/run-script@10.0.4': + resolution: {integrity: sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@nuxt/kit@3.21.2': + resolution: {integrity: sha512-Bd6m6mrDrqpBEbX+g0rc66/ALd1sxlgdx5nfK9MAYO0yKLTOSK7McSYz1KcOYn3LQFCXOWfvXwaqih/b+REI1g==} + engines: {node: '>=18.12.0'} + + '@octokit/auth-token@4.0.0': + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + + '@octokit/core@5.2.2': + resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==} + engines: {node: '>= 18'} + + '@octokit/endpoint@9.0.6': + resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==} + engines: {node: '>= 18'} + + '@octokit/graphql@7.1.1': + resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==} + engines: {node: '>= 18'} + + '@octokit/openapi-types@12.11.0': + resolution: {integrity: sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==} + + '@octokit/openapi-types@24.2.0': + resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==} + + '@octokit/plugin-paginate-rest@11.4.4-cjs.2': + resolution: {integrity: sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-request-log@4.0.1': + resolution: {integrity: sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1': + resolution: {integrity: sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': ^5 + + '@octokit/plugin-retry@6.1.0': + resolution: {integrity: sha512-WrO3bvq4E1Xh1r2mT9w6SDFg01gFmP81nIG77+p/MqW1JeXXgL++6umim3t6x0Zj5pZm3rXAN+0HEjmmdhIRig==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/request-error@5.1.1': + resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} + engines: {node: '>= 18'} + + '@octokit/request@8.4.1': + resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==} + engines: {node: '>= 18'} + + '@octokit/rest@20.1.2': + resolution: {integrity: sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==} + engines: {node: '>= 18'} + + '@octokit/types@13.10.0': + resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} + + '@octokit/types@6.41.0': + resolution: {integrity: sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==} - '@lydell/node-pty@1.0.3': - resolution: {integrity: sha512-nLTNwJXEPi1oMyzxRwqsLB4jCmhDrltQS/kAYhV05qbPo5NOIKpw2tb+Iok/yhd9zP9+E5Lu7sWDGD+G4fdKbQ==} + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} - '@malept/cross-spawn-promise@1.1.1': - resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} - engines: {node: '>= 10'} + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} - '@malept/cross-spawn-promise@2.0.0': - resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} - engines: {node: '>= 12.13.0'} + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} - '@malept/electron-installer-flatpak@0.11.4': - resolution: {integrity: sha512-ZdwhT4WeeJWdnsmALUtQ7bn4pzYVh0Vg+4NnF1S3n3OACc9IWg+B+LxI5gT3XSXIrxogouqkjM6gD8S592awyA==} - engines: {node: '>= 10.0.0'} - os: [darwin, linux] - hasBin: true + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} - '@malept/flatpak-bundler@0.4.0': - resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} - engines: {node: '>= 10.0.0'} + '@oxc-project/types@0.115.0': + resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==} - '@manypkg/find-root@1.1.0': - resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + '@oxc-project/types@0.124.0': + resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} - '@manypkg/get-packages@1.1.3': - resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@oxc-project/types@0.132.0': + resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} - '@mdi/font@7.4.47': - resolution: {integrity: sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==} + '@oxfmt/binding-android-arm-eabi@0.40.0': + resolution: {integrity: sha512-S6zd5r1w/HmqR8t0CTnGjFTBLDq2QKORPwriCHxo4xFNuhmOTABGjPaNvCJJVnrKBLsohOeiDX3YqQfJPF+FXw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] - '@next/env@15.3.3': - resolution: {integrity: sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==} + '@oxfmt/binding-android-arm64@0.40.0': + resolution: {integrity: sha512-/mbS9UUP/5Vbl2D6osIdcYiP0oie63LKMoTyGj5hyMCK/SFkl3EhtyRAfdjPvuvHC0SXdW6ePaTKkBSq1SNcIw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@next/swc-darwin-arm64@15.3.3': - resolution: {integrity: sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==} - engines: {node: '>= 10'} + '@oxfmt/binding-darwin-arm64@0.40.0': + resolution: {integrity: sha512-wRt8fRdfLiEhnRMBonlIbKrJWixoEmn6KCjKE9PElnrSDSXETGZfPb8ee+nQNTobXkCVvVLytp2o0obAsxl78Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.3.3': - resolution: {integrity: sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw==} - engines: {node: '>= 10'} + '@oxfmt/binding-darwin-x64@0.40.0': + resolution: {integrity: sha512-fzowhqbOE/NRy+AE5ob0+Y4X243WbWzDb00W+pKwD7d9tOqsAFbtWUwIyqqCoCLxj791m2xXIEeLH/3uz7zCCg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.3.3': - resolution: {integrity: sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw==} - engines: {node: '>= 10'} + '@oxfmt/binding-freebsd-x64@0.40.0': + resolution: {integrity: sha512-agZ9ITaqdBjcerRRFEHB8s0OyVcQW8F9ZxsszjxzeSthQ4fcN2MuOtQFWec1ed8/lDa50jSLHVE2/xPmTgtCfQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxfmt/binding-linux-arm-gnueabihf@0.40.0': + resolution: {integrity: sha512-ZM2oQ47p28TP1DVIp7HL1QoMUgqlBFHey0ksHct7tMXoU5BqjNvPWw7888azzMt25lnyPODVuye1wvNbvVUFOA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm-musleabihf@0.40.0': + resolution: {integrity: sha512-RBFPAxRAIsMisKM47Oe6Lwdv6agZYLz02CUhVCD1sOv5ajAcRMrnwCFBPWwGXpazToW2mjnZxFos8TuFjTU15A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm64-gnu@0.40.0': + resolution: {integrity: sha512-Nb2XbQ+wV3W2jSIihXdPj7k83eOxeSgYP3N/SRXvQ6ZYPIk6Q86qEh5Gl/7OitX3bQoQrESqm1yMLvZV8/J7dA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] - '@next/swc-linux-arm64-musl@15.3.3': - resolution: {integrity: sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA==} - engines: {node: '>= 10'} + '@oxfmt/binding-linux-arm64-musl@0.40.0': + resolution: {integrity: sha512-tGmWhLD/0YMotCdfezlT6tC/MJG/wKpo4vnQ3Cq+4eBk/BwNv7EmkD0VkD5F/dYkT3b8FNU01X2e8vvJuWoM1w==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] - '@next/swc-linux-x64-gnu@15.3.3': - resolution: {integrity: sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==} - engines: {node: '>= 10'} + '@oxfmt/binding-linux-ppc64-gnu@0.40.0': + resolution: {integrity: sha512-rVbFyM3e7YhkVnp0IVYjaSHfrBWcTRWb60LEcdNAJcE2mbhTpbqKufx0FrhWfoxOrW/+7UJonAOShoFFLigDqQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-gnu@0.40.0': + resolution: {integrity: sha512-3ZqBw14JtWeEoLiioJcXSJz8RQyPE+3jLARnYM1HdPzZG4vk+Ua8CUupt2+d+vSAvMyaQBTN2dZK+kbBS/j5mA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-musl@0.40.0': + resolution: {integrity: sha512-JJ4PPSdcbGBjPvb+O7xYm2FmAsKCyuEMYhqatBAHMp/6TA6rVlf9Z/sYPa4/3Bommb+8nndm15SPFRHEPU5qFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-s390x-gnu@0.40.0': + resolution: {integrity: sha512-Kp0zNJoX9Ik77wUya2tpBY3W9f40VUoMQLWVaob5SgCrblH/t2xr/9B2bWHfs0WCefuGmqXcB+t0Lq77sbBmZw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-gnu@0.40.0': + resolution: {integrity: sha512-7YTCNzleWTaQTqNGUNQ66qVjpoV6DjbCOea+RnpMBly2bpzrI/uu7Rr+2zcgRfNxyjXaFTVQKaRKjqVdeUfeVA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] - '@next/swc-linux-x64-musl@15.3.3': - resolution: {integrity: sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==} - engines: {node: '>= 10'} + '@oxfmt/binding-linux-x64-musl@0.40.0': + resolution: {integrity: sha512-hWnSzJ0oegeOwfOEeejYXfBqmnRGHusgtHfCPzmvJvHTwy1s3Neo59UKc1CmpE3zxvrCzJoVHos0rr97GHMNPw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] - '@next/swc-win32-arm64-msvc@15.3.3': - resolution: {integrity: sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ==} - engines: {node: '>= 10'} + '@oxfmt/binding-openharmony-arm64@0.40.0': + resolution: {integrity: sha512-28sJC1lR4qtBJGzSRRbPnSW3GxU2+4YyQFE6rCmsUYqZ5XYH8jg0/w+CvEzQ8TuAQz5zLkcA25nFQGwoU0PT3Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxfmt/binding-win32-arm64-msvc@0.40.0': + resolution: {integrity: sha512-cDkRnyT0dqwF5oIX1Cv59HKCeZQFbWWdUpXa3uvnHFT2iwYSSZspkhgjXjU6iDp5pFPaAEAe9FIbMoTgkTmKPg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.3.3': - resolution: {integrity: sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw==} - engines: {node: '>= 10'} + '@oxfmt/binding-win32-ia32-msvc@0.40.0': + resolution: {integrity: sha512-7rPemBJjqm5Gkv6ZRCPvK8lE6AqQ/2z31DRdWazyx2ZvaSgL7QGofHXHNouRpPvNsT9yxRNQJgigsWkc+0qg4w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxfmt/binding-win32-x64-msvc@0.40.0': + resolution: {integrity: sha512-/Zmj0yTYSvmha6TG1QnoLqVT7ZMRDqXvFXXBQpIjteEwx9qvUYMBH2xbiOFhDeMUJkGwC3D6fdKsFtaqUvkwNA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@oxlint/binding-android-arm-eabi@1.55.0': + resolution: {integrity: sha512-NhvgAhncTSOhRahQSCnkK/4YIGPjTmhPurQQ2dwt2IvwCMTvZRW5vF2K10UBOxFve4GZDMw6LtXZdC2qeuYIVQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + '@oxlint/binding-android-arm64@1.55.0': + resolution: {integrity: sha512-P9iWRh+Ugqhg+D7rkc7boHX8o3H2h7YPcZHQIgvVBgnua5tk4LR2L+IBlreZs58/95cd2x3/004p5VsQM9z4SA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@oxlint/binding-darwin-arm64@1.55.0': + resolution: {integrity: sha512-esakkJIt7WFAhT30P/Qzn96ehFpzdZ1mNuzpOb8SCW7lI4oB8VsyQnkSHREM671jfpuBb/o2ppzBCx5l0jpgMA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] - '@npmcli/ci-detect@1.4.0': - resolution: {integrity: sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==} - deprecated: this package has been deprecated, use `ci-info` instead + '@oxlint/binding-darwin-x64@1.55.0': + resolution: {integrity: sha512-xDMFRCCAEK9fOH6As2z8ELsC+VDGSFRHwIKVSilw+xhgLwTDFu37rtmRbmUlx8rRGS6cWKQPTc47AVxAZEVVPQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@npmcli/fs@1.1.1': - resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + '@oxlint/binding-freebsd-x64@1.55.0': + resolution: {integrity: sha512-mYZqnwUD7ALCRxGenyLd1uuG+rHCL+OTT6S8FcAbVm/ZT2AZMGjvibp3F6k1SKOb2aeqFATmwRykrE41Q0GWVw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] - '@npmcli/fs@2.1.2': - resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + '@oxlint/binding-linux-arm-gnueabihf@1.55.0': + resolution: {integrity: sha512-LcX6RYcF9vL9ESGwJW3yyIZ/d/ouzdOKXxCdey1q0XJOW1asrHsIg5MmyKdEBR4plQx+shvYeQne7AzW5f3T1w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@npmcli/git@2.1.0': - resolution: {integrity: sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==} + '@oxlint/binding-linux-arm-musleabihf@1.55.0': + resolution: {integrity: sha512-C+8GS1rPtK+dI7mJFkqoRBkDuqbrNihnyYQsJPS9ez+8zF9JzfvU19lawqt4l/Y23o5uQswE/DORa8aiXUih3w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@npmcli/installed-package-contents@1.0.7': - resolution: {integrity: sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==} - engines: {node: '>= 10'} - hasBin: true + '@oxlint/binding-linux-arm64-gnu@1.55.0': + resolution: {integrity: sha512-ErLE4XbmcCopA4/CIDiH6J1IAaDOMnf/KSx/aFObs4/OjAAM3sFKWGZ57pNOMxhhyBdcmcXwYymph9GwcpcqgQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@npmcli/move-file@1.1.2': - resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} - engines: {node: '>=10'} - deprecated: This functionality has been moved to @npmcli/fs + '@oxlint/binding-linux-arm64-musl@1.55.0': + resolution: {integrity: sha512-/kp65avi6zZfqEng56TTuhiy3P/3pgklKIdf38yvYeJ9/PgEeRA2A2AqKAKbZBNAqUzrzHhz9jF6j/PZvhJzTQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@npmcli/move-file@2.0.1': - resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This functionality has been moved to @npmcli/fs + '@oxlint/binding-linux-ppc64-gnu@1.55.0': + resolution: {integrity: sha512-A6pTdXwcEEwL/nmz0eUJ6WxmxcoIS+97GbH96gikAyre3s5deC7sts38ZVVowjS2QQFuSWkpA4ZmQC0jZSNvJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@npmcli/node-gyp@1.0.3': - resolution: {integrity: sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==} + '@oxlint/binding-linux-riscv64-gnu@1.55.0': + resolution: {integrity: sha512-clj0lnIN+V52G9tdtZl0LbdTSurnZ1NZj92Je5X4lC7gP5jiCSW+Y/oiDiSauBAD4wrHt2S7nN3pA0zfKYK/6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@npmcli/promise-spawn@1.3.2': - resolution: {integrity: sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==} + '@oxlint/binding-linux-riscv64-musl@1.55.0': + resolution: {integrity: sha512-NNu08pllN5x/O94/sgR3DA8lbrGBnTHsINZZR0hcav1sj79ksTiKKm1mRzvZvacwQ0hUnGinFo+JO75ok2PxYg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] - '@npmcli/run-script@1.8.6': - resolution: {integrity: sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==} + '@oxlint/binding-linux-s390x-gnu@1.55.0': + resolution: {integrity: sha512-BvfQz3PRlWZRoEZ17dZCqgQsMRdpzGZomJkVATwCIGhHVVeHJMQdmdXPSjcT1DCNUrOjXnVyj1RGDj5+/Je2+Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@nuxt/kit@3.17.5': - resolution: {integrity: sha512-NdCepmA+S/SzgcaL3oYUeSlXGYO6BXGr9K/m1D0t0O9rApF8CSq/QQ+ja5KYaYMO1kZAEWH4s2XVcE3uPrrAVg==} - engines: {node: '>=18.12.0'} + '@oxlint/binding-linux-x64-gnu@1.55.0': + resolution: {integrity: sha512-ngSOoFCSBMKVQd24H8zkbcBNc7EHhjnF1sv3mC9NNXQ/4rRjI/4Dj9+9XoDZeFEkF1SX1COSBXF1b2Pr9rqdEw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@octokit/auth-token@2.5.0': - resolution: {integrity: sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==} + '@oxlint/binding-linux-x64-musl@1.55.0': + resolution: {integrity: sha512-BDpP7W8GlaG7BR6QjGZAleYzxoyKc/D24spZIF2mB3XsfALQJJT/OBmP8YpeTb1rveFSBHzl8T7l0aqwkWNdGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@octokit/core@3.6.0': - resolution: {integrity: sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==} + '@oxlint/binding-openharmony-arm64@1.55.0': + resolution: {integrity: sha512-PS6GFvmde/pc3fCA2Srt51glr8Lcxhpf6WIBFfLphndjRrD34NEcses4TSxQrEcxYo6qVywGfylM0ZhSCF2gGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@octokit/endpoint@6.0.12': - resolution: {integrity: sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==} + '@oxlint/binding-win32-arm64-msvc@1.55.0': + resolution: {integrity: sha512-P6JcLJGs/q1UOvDLzN8otd9JsH4tsuuPDv+p7aHqHM3PrKmYdmUvkNj4K327PTd35AYcznOCN+l4ZOaq76QzSw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@octokit/graphql@4.8.0': - resolution: {integrity: sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==} + '@oxlint/binding-win32-ia32-msvc@1.55.0': + resolution: {integrity: sha512-gzkk4zE2zsE+WmRxFOiAZHpCpUNDFytEakqNXoNHW+PnYEOTPKDdW6nrzgSeTbGKVPXNAKQnRnMgrh7+n3Xueg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] - '@octokit/openapi-types@12.11.0': - resolution: {integrity: sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==} + '@oxlint/binding-win32-x64-msvc@1.55.0': + resolution: {integrity: sha512-ZFALNow2/og75gvYzNP7qe+rREQ5xunktwA+lgykoozHZ6hw9bqg4fn5j2UvG4gIn1FXqrZHkOAXuPf5+GOYTQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@octokit/plugin-paginate-rest@2.21.3': - resolution: {integrity: sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==} - peerDependencies: - '@octokit/core': '>=2' + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] - '@octokit/plugin-request-log@1.0.4': - resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==} - peerDependencies: - '@octokit/core': '>=3' + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] - '@octokit/plugin-rest-endpoint-methods@5.16.2': - resolution: {integrity: sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==} - peerDependencies: - '@octokit/core': '>=3' + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] - '@octokit/plugin-retry@3.0.9': - resolution: {integrity: sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==} + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] - '@octokit/request-error@2.1.0': - resolution: {integrity: sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==} + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] - '@octokit/request@5.6.3': - resolution: {integrity: sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==} + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] - '@octokit/rest@18.12.0': - resolution: {integrity: sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==} + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@octokit/types@6.41.0': - resolution: {integrity: sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==} + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] - '@one-ini/wasm@0.1.1': - resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] - '@opentelemetry/api-logs@0.52.1': - resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==} - engines: {node: '>=14'} + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] - '@opentelemetry/context-async-hooks@1.30.1': - resolution: {integrity: sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] - '@opentelemetry/core@1.25.1': - resolution: {integrity: sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] - '@opentelemetry/core@1.30.1': - resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} - '@opentelemetry/instrumentation-connect@0.38.0': - resolution: {integrity: sha512-2/nRnx3pjYEmdPIaBwtgtSviTKHWnDZN3R+TkRUnhIVrvBKVcq+I5B2rtd6mr6Fe9cHlZ9Ojcuh7pkNh/xdWWg==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-express@0.41.1': - resolution: {integrity: sha512-uRx0V3LPGzjn2bxAnV8eUsDT82vT7NTwI0ezEuPMBOTOsnPpGhWdhcdNdhH80sM4TrWrOfXm9HGEdfWE3TRIww==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/constants@1001.3.1': + resolution: {integrity: sha512-2hf0s4pVrVEH8RvdJJ7YRKjQdiG8m0iAT26TTqXnCbK30kKwJW69VLmP5tED5zstmDRXcOeH5eRcrpkdwczQ9g==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-fastify@0.38.0': - resolution: {integrity: sha512-HBVLpTSYpkQZ87/Df3N0gAw7VzYZV3n28THIBrJWfuqw3Or7UqdhnjeuMIPQ04BKk3aZc0cWn2naSQObbh5vXw==} - engines: {node: '>=14'} + '@pnpm/core-loggers@1001.0.9': + resolution: {integrity: sha512-pW58m3ssrwVjwhlmTXDW1dh1sv2y6R2Gl5YvQInjM2d01/5mre/sYAY4MK3XfgEShZJQxv6wVXDUvyHHJ0oizg==} + engines: {node: '>=18.12'} peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/logger': '>=1001.0.0 <1002.0.0' - '@opentelemetry/instrumentation-fs@0.14.0': - resolution: {integrity: sha512-pVc8P5AgliC1DphyyBUgsxXlm2XaPH4BpYvt7rAZDMIqUpRk8gs19SioABtKqqxvFzg5jPtgJfJsdxq0Y+maLw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/error@1000.1.0': + resolution: {integrity: sha512-Dqc2IJJPjUatwc9Letw+vG29rnaMrDGi5g6WCx1HiZYm0obXbTmLygeRafMbgf+sLKXrWE1shOeiayQuczBdoA==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-graphql@0.42.0': - resolution: {integrity: sha512-N8SOwoKL9KQSX7z3gOaw5UaTeVQcfDO1c21csVHnmnmGUoqsXbArK2B8VuwPWcv6/BC/i3io+xTo7QGRZ/z28Q==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/graceful-fs@1000.1.0': + resolution: {integrity: sha512-EsMX4slK0qJN2AR0/AYohY5m0HQNYGMNe+jhN74O994zp22/WbX+PbkIKyw3UQn39yQm2+z6SgwklDxbeapsmQ==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-hapi@0.40.0': - resolution: {integrity: sha512-8U/w7Ifumtd2bSN1OLaSwAAFhb9FyqWUki3lMMB0ds+1+HdSxYBe9aspEJEgvxAqOkrQnVniAPTEGf1pGM7SOw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/logger@1001.0.1': + resolution: {integrity: sha512-gdwlAMXC4Wc0s7Dmg/4wNybMEd/4lSd9LsXQxeg/piWY0PPXjgz1IXJWnVScx6dZRaaodWP3c1ornrw8mZdFZw==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-http@0.52.1': - resolution: {integrity: sha512-dG/aevWhaP+7OLv4BQQSEKMJv8GyeOp3Wxl31NHqE8xo9/fYMfEljiZphUHIfyg4gnZ9swMyWjfOQs5GUQe54Q==} - engines: {node: '>=14'} + '@pnpm/manifest-utils@1002.0.5': + resolution: {integrity: sha512-2DSwQ6pP73IuJS5mCCtPd5fibJwuAdufXKuSL/Oq1n6AggCqy8616Xea1X3RH3z5dL4mn7Z4EZ+vnX8jX3Wrfw==} + engines: {node: '>=18.12'} peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/logger': ^1001.0.1 - '@opentelemetry/instrumentation-ioredis@0.42.0': - resolution: {integrity: sha512-P11H168EKvBB9TUSasNDOGJCSkpT44XgoM6d3gRIWAa9ghLpYhl0uRkS8//MqPzcJVHr3h3RmfXIpiYLjyIZTw==} - engines: {node: '>=14'} + '@pnpm/read-project-manifest@1001.2.6': + resolution: {integrity: sha512-BcNO50lAkE4m9JaJ0WmG3m/DH/qLSvMgZywtmb/dfyyLVu5nDZfDqmOd8U+f1NhLcLMbBK6AnS3hyUqZYvw9Vg==} + engines: {node: '>=18.12'} peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/logger': ^1001.0.1 - '@opentelemetry/instrumentation-koa@0.42.0': - resolution: {integrity: sha512-H1BEmnMhho8o8HuNRq5zEI4+SIHDIglNB7BPKohZyWG4fWNuR7yM4GTlR01Syq21vODAS7z5omblScJD/eZdKw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/semver.peer-range@1000.0.0': + resolution: {integrity: sha512-r6VzkrdH7ZKjPmAogTNvxuV/UyS/xwHNme+ZuEFiG0UthZgqudDftYtKmG20fcfrjG1lgJbbWICA8KvZy7mmbw==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-mongodb@0.46.0': - resolution: {integrity: sha512-VF/MicZ5UOBiXrqBslzwxhN7TVqzu1/LN/QDpkskqM0Zm0aZ4CVRbUygL8d7lrjLn15x5kGIe8VsSphMfPJzlA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/text.comments-parser@1000.0.0': + resolution: {integrity: sha512-ivv/esrETOq9uMiKOC0ddVZ1BktEGsfsMQ9RWmrDpwPiqFSqWsIspnquxTBmm5GflC5N06fbqjGOpulZVYo3vQ==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-mongoose@0.40.0': - resolution: {integrity: sha512-niRi5ZUnkgzRhIGMOozTyoZIvJKNJyhijQI4nF4iFSb+FUx2v5fngfR+8XLmdQAO7xmsD8E5vEGdDVYVtKbZew==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/types@1001.3.0': + resolution: {integrity: sha512-NLTXheat/u7OEGg5M5vF6Z85zx8uKUZE0+whtX/sbFV2XL48RdnOWGPTKYuVVkv8M+launaLUTgGEXNs/ess2w==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-mysql2@0.40.0': - resolution: {integrity: sha512-0xfS1xcqUmY7WE1uWjlmI67Xg3QsSUlNT+AcXHeA4BDUPwZtWqF4ezIwLgpVZfHOnkAEheqGfNSWd1PIu3Wnfg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@pnpm/write-project-manifest@1000.0.16': + resolution: {integrity: sha512-zG68fk03ryot7TWUl9S/ShQ91uHWzIL9sVr2aQCuNHJo8G9kjsG6S0p58Zj/voahdDQeakZYYBSJ0mjNZeiJnw==} + engines: {node: '>=18.12'} - '@opentelemetry/instrumentation-mysql@0.40.0': - resolution: {integrity: sha512-d7ja8yizsOCNMYIJt5PH/fKZXjb/mS48zLROO4BzZTtDfhNCl2UM/9VIomP2qkGIFVouSJrGr/T00EzY7bPtKA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@polar-sh/sdk@0.47.1': + resolution: {integrity: sha512-fkz7wPLbqfuDmY9LxuXpE2uP2TAV6J0q/YN5hJ4UBxpjbkB0hKM6c4R35N89t83dfzMlG6EOlqOn+Rd1T6XrJQ==} - '@opentelemetry/instrumentation-nestjs-core@0.39.0': - resolution: {integrity: sha512-mewVhEXdikyvIZoMIUry8eb8l3HUjuQjSjVbmLVTt4NQi35tkpnHQrG9bTRBrl3403LoWZ2njMPJyg4l6HfKvA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@opentelemetry/instrumentation-pg@0.43.0': - resolution: {integrity: sha512-og23KLyoxdnAeFs1UWqzSonuCkePUzCX30keSYigIzJe/6WSYA8rnEI5lobcxPEzg+GcU06J7jzokuEHbjVJNw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@posthog/core@1.27.7': + resolution: {integrity: sha512-6rzOZajUkhuezgPeF+ReMMly0D9oiwIZtMQrsJtZcS/mwi5OtvuYgxeaohgP9PKOhkK1c7cvGskX0Y2YUtBYCw==} - '@opentelemetry/instrumentation-redis-4@0.41.0': - resolution: {integrity: sha512-H7IfGTqW2reLXqput4yzAe8YpDC0fmVNal95GHMLOrS89W+qWUKIqxolSh63hJyfmwPSFwXASzj7wpSk8Az+Dg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@posthog/types@1.372.3': + resolution: {integrity: sha512-4mkXC9AhsquJnvogWtWsCi+ReODj/jbK0d3fkwCNLLTOpaiAF125FJ6OJyRFax2u+dEKXAPA/dCTGx1S2WF0nw==} - '@opentelemetry/instrumentation@0.46.0': - resolution: {integrity: sha512-a9TijXZZbk0vI5TGLZl+0kxyFfrXHhX6Svtz7Pp2/VBlCSKrazuULEyoJQrOknJyFWNMEmbbJgOciHCCpQcisw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@primeuix/styled@0.2.0': + resolution: {integrity: sha512-3Q6bDrmwTW88tzJsFIFenC0VyXLj0+/wYw+TZnJ/4CCDfehR4WfTs4EZdpuFtYqvmbpJ6zWXAiwSCNdSYTZkyA==} + engines: {node: '>=12.11.0'} - '@opentelemetry/instrumentation@0.52.1': - resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@primeuix/styled@0.7.4': + resolution: {integrity: sha512-QSO/NpOQg8e9BONWRBx9y8VGMCMYz0J/uKfNJEya/RGEu7ARx0oYW0ugI1N3/KB1AAvyGxzKBzGImbwg0KUiOQ==} + engines: {node: '>=12.11.0'} - '@opentelemetry/redis-common@0.36.2': - resolution: {integrity: sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==} - engines: {node: '>=14'} + '@primeuix/styles@2.0.3': + resolution: {integrity: sha512-2ykAB6BaHzR/6TwF8ShpJTsZrid6cVIEBVlookSdvOdmlWuevGu5vWOScgIwqWwlZcvkFYAGR/SUV3OHCTBMdw==} - '@opentelemetry/resources@1.30.1': - resolution: {integrity: sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@primeuix/utils@0.2.0': + resolution: {integrity: sha512-AaDIeRFlsbkVTk2s0mlEjnGSLi31X669NVwo+n+AVAnBdDiQznjipNTpHbOobVBtjOKZize74PChK6uoaSBRUw==} + engines: {node: '>=12.11.0'} - '@opentelemetry/sdk-metrics@1.30.1': - resolution: {integrity: sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@primeuix/utils@0.6.4': + resolution: {integrity: sha512-pZ5f+vj7wSzRhC7KoEQRU5fvYAe+RP9+m39CTscZ3UywCD1Y2o6Fe1rRgklMPSkzUcty2jzkA0zMYkiJBD1hgg==} + engines: {node: '>=12.11.0'} - '@opentelemetry/sdk-trace-base@1.30.1': - resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} - engines: {node: '>=14'} + '@primevue/auto-import-resolver@4.1.1': + resolution: {integrity: sha512-IMRxgqgMFjtMJ6+pvGu98amnY44FUUhDyzk6CqEjMkirj0rI9t6aQFvKcBEyf0cwuIveeSggBHS8cbaytZNjuA==} + engines: {node: '>=12.11.0'} + + '@primevue/core@4.5.4': + resolution: {integrity: sha512-lYJJB3wTrDJ8MkLctzHfrPZAqXVxoatjIsswSJzupatf6ZogJHVYADUKcn1JAkLLk8dtV1FA2AxDek663fHO5Q==} + engines: {node: '>=12.11.0'} peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' + vue: ^3.5.0 - '@opentelemetry/semantic-conventions@1.25.1': - resolution: {integrity: sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==} - engines: {node: '>=14'} + '@primevue/icons@4.5.4': + resolution: {integrity: sha512-DxgryEc7ZmUqcEhYMcxGBRyFzdtLIoy3jLtlH1zsVSRZaG+iSAcjQ88nvfkZxGUZtZBFL7sRjF6KLq3bJZJwUw==} + engines: {node: '>=12.11.0'} - '@opentelemetry/semantic-conventions@1.28.0': - resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} - engines: {node: '>=14'} + '@primevue/metadata@4.1.1': + resolution: {integrity: sha512-5QQKjtNbgazpX1Q9z8Dc2szUEyvQcEif8kMOXmmWuIuUzCe3QkjbWyk29y7Cukkxk8B7iciDKLMzvGsWpwzsWA==} + engines: {node: '>=12.11.0'} - '@opentelemetry/semantic-conventions@1.34.0': - resolution: {integrity: sha512-aKcOkyrorBGlajjRdVoJWHTxfxO1vCNHLJVlSDaRHDIdjU+pX8IYQPvPDkYiujKLbRnWU+1TBwEt0QRgSm4SGA==} - engines: {node: '>=14'} + '@primevue/themes@4.1.1': + resolution: {integrity: sha512-ec2gBN2vP0ydGtGAzC0nYCFqYN7CzvXxnlJqcvcPIo3rP/pcdj+FkzAe3y2DMG3OorYtqdzoyGtBefQrx3v5ag==} + engines: {node: '>=12.11.0'} + deprecated: 'Deprecated. This package is no longer maintained. Please migrate to @primeuix/themes: https://www.npmjs.com/package/@primeuix/themes' - '@opentelemetry/sql-common@0.40.1': - resolution: {integrity: sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.1.0 + '@publint/pack@0.1.4': + resolution: {integrity: sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==} + engines: {node: '>=18'} + + '@quansync/fs@1.0.0': + resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + + '@rolldown/binding-android-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-android-arm64@1.0.0-rc.9': + resolution: {integrity: sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-android-arm64@1.0.2': + resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-darwin-arm64@1.0.0-rc.9': + resolution: {integrity: sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-arm64@1.0.2': + resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.15': + resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-darwin-x64@1.0.0-rc.9': + resolution: {integrity: sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.2': + resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-freebsd-x64@1.0.0-rc.9': + resolution: {integrity: sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-freebsd-x64@1.0.2': + resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9': + resolution: {integrity: sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': + resolution: {integrity: sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.2': + resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': + resolution: {integrity: sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] + '@rolldown/binding-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': + resolution: {integrity: sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] - os: [win32] + os: [linux] + libc: [musl] - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} - engines: {node: '>= 10.0.0'} + '@rolldown/binding-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@pipelab/core@1.4.9': - resolution: {integrity: sha512-eHz2UNZrDeaTUHS5BL4Mc6c2yBWt7N7xQ2hT0gu2UnAHsWO2QL/j2SVyyaYwGY9m6Ht6jXPXBwD0cngVWVy5vQ==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.9': + resolution: {integrity: sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@pkgr/core@0.2.7': - resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@rolldown/binding-openharmony-arm64@1.0.2': + resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@playwright/test@1.48.1': - resolution: {integrity: sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==} - engines: {node: '>=18'} - hasBin: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] - '@poki/cli@0.1.16': - resolution: {integrity: sha512-h6l7Z5izhhOkJYy8uGi90snsQr7rblFOysCXB2zcdJ13Kbdo4hR/rqFiaUZ59GOiTxj1sjhE1sIcY8mhOyEYFg==} - engines: {node: '>=12'} - hasBin: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.9': + resolution: {integrity: sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] - '@polar-sh/sdk@0.34.8': - resolution: {integrity: sha512-9GVBaB0XlSxS/0GTPThPkWWb31vPOZr67onMC772dKjzRd7o9WJ9WTXY1d2btmFFoxqdxJutGxXptI3mmFl0aw==} - hasBin: true - peerDependencies: - '@modelcontextprotocol/sdk': '>=1.5.0 <1.10.0' - zod: ^3 - peerDependenciesMeta: - '@modelcontextprotocol/sdk': - optional: true + '@rolldown/binding-wasm32-wasi@1.0.2': + resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] - '@polka/url@1.0.0-next.29': - resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@primeuix/styled@0.2.0': - resolution: {integrity: sha512-3Q6bDrmwTW88tzJsFIFenC0VyXLj0+/wYw+TZnJ/4CCDfehR4WfTs4EZdpuFtYqvmbpJ6zWXAiwSCNdSYTZkyA==} - engines: {node: '>=12.11.0'} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9': + resolution: {integrity: sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@primeuix/utils@0.2.0': - resolution: {integrity: sha512-AaDIeRFlsbkVTk2s0mlEjnGSLi31X669NVwo+n+AVAnBdDiQznjipNTpHbOobVBtjOKZize74PChK6uoaSBRUw==} - engines: {node: '>=12.11.0'} + '@rolldown/binding-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@primevue/auto-import-resolver@4.1.1': - resolution: {integrity: sha512-IMRxgqgMFjtMJ6+pvGu98amnY44FUUhDyzk6CqEjMkirj0rI9t6aQFvKcBEyf0cwuIveeSggBHS8cbaytZNjuA==} - engines: {node: '>=12.11.0'} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@primevue/core@4.1.1': - resolution: {integrity: sha512-jUDrTh3g0FskTdD6rCCsoWfxKky0R7959p7vnaNYI6wMLreaTL3yC3nzYlEniIpb+F51Sm3KJ1eSJBN6DnSB8Q==} - engines: {node: '>=12.11.0'} - peerDependencies: - vue: ^3.0.0 + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.9': + resolution: {integrity: sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@primevue/icons@4.1.1': - resolution: {integrity: sha512-Ybeb+AHUsVybITuYNwS7goqWcXLLgCDSiCPoymyYwYkzn5qLakvJbQH1EX8lGOsrvqK0hG+s+n7Wm2MHJ8A72w==} - engines: {node: '>=12.11.0'} + '@rolldown/binding-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@primevue/metadata@4.1.1': - resolution: {integrity: sha512-5QQKjtNbgazpX1Q9z8Dc2szUEyvQcEif8kMOXmmWuIuUzCe3QkjbWyk29y7Cukkxk8B7iciDKLMzvGsWpwzsWA==} - engines: {node: '>=12.11.0'} + '@rolldown/debug@1.0.0-rc.15': + resolution: {integrity: sha512-YlM1cMJEsGVCj9a5j7Nxw6mbnBCUdr5dbbhJdoqvxBp52BEODSKe+bBzSSIPxZIQCLggUEBdeM0652eN52IGRA==} - '@primevue/themes@4.1.1': - resolution: {integrity: sha512-ec2gBN2vP0ydGtGAzC0nYCFqYN7CzvXxnlJqcvcPIo3rP/pcdj+FkzAe3y2DMG3OorYtqdzoyGtBefQrx3v5ag==} - engines: {node: '>=12.11.0'} - deprecated: 'Deprecated. This package is no longer maintained. Please migrate to @primeuix/themes: https://www.npmjs.com/package/@primeuix/themes' + '@rolldown/pluginutils@1.0.0-rc.15': + resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} - '@prisma/instrumentation@5.17.0': - resolution: {integrity: sha512-c1Sle4ji8aasMcYfBBHFM56We4ljfenVtRmS8aY06BllS7SoU6SmJBwG7vil+GHiR0Yrh+t9iBwt4AY0Jr4KNQ==} + '@rolldown/pluginutils@1.0.0-rc.2': + resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} - '@rollup/plugin-inject@5.0.5': - resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true + '@rolldown/pluginutils@1.0.0-rc.9': + resolution: {integrity: sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==} + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/pluginutils@5.1.4': - resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -2168,266 +3550,170 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.42.0': - resolution: {integrity: sha512-gldmAyS9hpj+H6LpRNlcjQWbuKUtb94lodB9uCz71Jm+7BxK1VIOo7y62tZZwxhA7j1ylv/yQz080L5WkS+LoQ==} + '@rollup/rollup-android-arm-eabi@4.60.1': + resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.42.0': - resolution: {integrity: sha512-bpRipfTgmGFdCZDFLRvIkSNO1/3RGS74aWkJJTFJBH7h3MRV4UijkaEUeOMbi9wxtxYmtAbVcnMtHTPBhLEkaw==} + '@rollup/rollup-android-arm64@4.60.1': + resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.42.0': - resolution: {integrity: sha512-JxHtA081izPBVCHLKnl6GEA0w3920mlJPLh89NojpU2GsBSB6ypu4erFg/Wx1qbpUbepn0jY4dVWMGZM8gplgA==} + '@rollup/rollup-darwin-arm64@4.60.1': + resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.42.0': - resolution: {integrity: sha512-rv5UZaWVIJTDMyQ3dCEK+m0SAn6G7H3PRc2AZmExvbDvtaDc+qXkei0knQWcI3+c9tEs7iL/4I4pTQoPbNL2SA==} + '@rollup/rollup-darwin-x64@4.60.1': + resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.42.0': - resolution: {integrity: sha512-fJcN4uSGPWdpVmvLuMtALUFwCHgb2XiQjuECkHT3lWLZhSQ3MBQ9pq+WoWeJq2PrNxr9rPM1Qx+IjyGj8/c6zQ==} + '@rollup/rollup-freebsd-arm64@4.60.1': + resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.42.0': - resolution: {integrity: sha512-CziHfyzpp8hJpCVE/ZdTizw58gr+m7Y2Xq5VOuCSrZR++th2xWAz4Nqk52MoIIrV3JHtVBhbBsJcAxs6NammOQ==} + '@rollup/rollup-freebsd-x64@4.60.1': + resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.42.0': - resolution: {integrity: sha512-UsQD5fyLWm2Fe5CDM7VPYAo+UC7+2Px4Y+N3AcPh/LdZu23YcuGPegQly++XEVaC8XUTFVPscl5y5Cl1twEI4A==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} cpu: [arm] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.42.0': - resolution: {integrity: sha512-/i8NIrlgc/+4n1lnoWl1zgH7Uo0XK5xK3EDqVTf38KvyYgCU/Rm04+o1VvvzJZnVS5/cWSd07owkzcVasgfIkQ==} + '@rollup/rollup-linux-arm-musleabihf@4.60.1': + resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} cpu: [arm] os: [linux] + libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.42.0': - resolution: {integrity: sha512-eoujJFOvoIBjZEi9hJnXAbWg+Vo1Ov8n/0IKZZcPZ7JhBzxh2A+2NFyeMZIRkY9iwBvSjloKgcvnjTbGKHE44Q==} + '@rollup/rollup-linux-arm64-gnu@4.60.1': + resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} cpu: [arm64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.42.0': - resolution: {integrity: sha512-/3NrcOWFSR7RQUQIuZQChLND36aTU9IYE4j+TB40VU78S+RA0IiqHR30oSh6P1S9f9/wVOenHQnacs/Byb824g==} + '@rollup/rollup-linux-arm64-musl@4.60.1': + resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} cpu: [arm64] os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.60.1': + resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] - '@rollup/rollup-linux-loongarch64-gnu@4.42.0': - resolution: {integrity: sha512-O8AplvIeavK5ABmZlKBq9/STdZlnQo7Sle0LLhVA7QT+CiGpNVe197/t8Aph9bhJqbDVGCHpY2i7QyfEDDStDg==} + '@rollup/rollup-linux-loong64-musl@4.60.1': + resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} cpu: [loong64] os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.60.1': + resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@rollup/rollup-linux-powerpc64le-gnu@4.42.0': - resolution: {integrity: sha512-6Qb66tbKVN7VyQrekhEzbHRxXXFFD8QKiFAwX5v9Xt6FiJ3BnCVBuyBxa2fkFGqxOCSGGYNejxd8ht+q5SnmtA==} + '@rollup/rollup-linux-ppc64-musl@4.60.1': + resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} cpu: [ppc64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.42.0': - resolution: {integrity: sha512-KQETDSEBamQFvg/d8jajtRwLNBlGc3aKpaGiP/LvEbnmVUKlFta1vqJqTrvPtsYsfbE/DLg5CC9zyXRX3fnBiA==} + '@rollup/rollup-linux-riscv64-gnu@4.60.1': + resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} cpu: [riscv64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.42.0': - resolution: {integrity: sha512-qMvnyjcU37sCo/tuC+JqeDKSuukGAd+pVlRl/oyDbkvPJ3awk6G6ua7tyum02O3lI+fio+eM5wsVd66X0jQtxw==} + '@rollup/rollup-linux-riscv64-musl@4.60.1': + resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} cpu: [riscv64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.42.0': - resolution: {integrity: sha512-I2Y1ZUgTgU2RLddUHXTIgyrdOwljjkmcZ/VilvaEumtS3Fkuhbw4p4hgHc39Ypwvo2o7sBFNl2MquNvGCa55Iw==} + '@rollup/rollup-linux-s390x-gnu@4.60.1': + resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} cpu: [s390x] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.42.0': - resolution: {integrity: sha512-Gfm6cV6mj3hCUY8TqWa63DB8Mx3NADoFwiJrMpoZ1uESbK8FQV3LXkhfry+8bOniq9pqY1OdsjFWNsSbfjPugw==} + '@rollup/rollup-linux-x64-gnu@4.60.1': + resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==} cpu: [x64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.42.0': - resolution: {integrity: sha512-g86PF8YZ9GRqkdi0VoGlcDUb4rYtQKyTD1IVtxxN4Hpe7YqLBShA7oHMKU6oKTCi3uxwW4VkIGnOaH/El8de3w==} + '@rollup/rollup-linux-x64-musl@4.60.1': + resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==} cpu: [x64] os: [linux] + libc: [musl] - '@rollup/rollup-win32-arm64-msvc@4.42.0': - resolution: {integrity: sha512-+axkdyDGSp6hjyzQ5m1pgcvQScfHnMCcsXkx8pTgy/6qBmWVhtRVlgxjWwDp67wEXXUr0x+vD6tp5W4x6V7u1A==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.42.0': - resolution: {integrity: sha512-F+5J9pelstXKwRSDq92J0TEBXn2nfUrQGg+HK1+Tk7VOL09e0gBqUHugZv7SW4MGrYj41oNCUe3IKCDGVlis2g==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.42.0': - resolution: {integrity: sha512-LpHiJRwkaVz/LqjHjK8LCi8osq7elmpwujwbXKNW88bM8eeGxavJIKKjkjpMHAh/2xfnrt1ZSnhTv41WYUHYmA==} + '@rollup/rollup-openbsd-x64@4.60.1': + resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==} cpu: [x64] - os: [win32] - - '@rushstack/eslint-patch@1.10.4': - resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} - - '@sec-ant/readable-stream@0.4.1': - resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - - '@sentry-internal/browser-utils@8.26.0': - resolution: {integrity: sha512-O2Tj+WK33/ZVp5STnz6ZL0OO+/Idk2KqsH0ITQkQmyZ2z0kdzWOeqK7s7q3/My6rB1GfPcyqPcBBv4dVv92FYQ==} - engines: {node: '>=14.18'} - - '@sentry-internal/browser-utils@8.32.0': - resolution: {integrity: sha512-DpUGhk5O1OVjT0fo9wsbEdO1R/S9gGBRDtn9+FFVeRtieJHwXpeZiLK+tZhTOvaILmtSoTPUEY3L5sK4j5Xq9g==} - engines: {node: '>=14.18'} - - '@sentry-internal/feedback@8.26.0': - resolution: {integrity: sha512-hQtw1gg8n6ERK1UH47F7ZI1zOsbhu0J2VX+TrnkpaQR2FgxDW1oe9Ja6oCV4CQKuR4w+1ZI/Kj4imSt0K33kEw==} - engines: {node: '>=14.18'} - - '@sentry-internal/feedback@8.32.0': - resolution: {integrity: sha512-XB7hiVJQW1tNzpoXIHbvm3rjipIt7PZiJJtFg2vxaqu/FzdgOcYqQiwIKivJVAKuRZ9rIeJtK1jdXQFOc/TRJA==} - engines: {node: '>=14.18'} - - '@sentry-internal/replay-canvas@8.26.0': - resolution: {integrity: sha512-2CFQW6f9aJHIo/DqmqYa9PaYoLn1o36ywc0h8oyGrD4oPCbrnE5F++PmTdc71GBODu41HBn/yoCTLmxOD+UjpA==} - engines: {node: '>=14.18'} - - '@sentry-internal/replay-canvas@8.32.0': - resolution: {integrity: sha512-oBbhtDBkD+5z/T0NVJ5VenBWAid/S9QdVrod/UqxVqU7F8N+E9/INFQI48zCWr4iVlUMcszJPDElvJEsMDvvBQ==} - engines: {node: '>=14.18'} - - '@sentry-internal/replay@8.26.0': - resolution: {integrity: sha512-JDY7W2bswlp5c3483lKP4kcb75fHNwGNfwD8x8FsY9xMjv7nxeXjLpR5cCEk1XqPq2+n6w4j7mJOXhEXGiUIKg==} - engines: {node: '>=14.18'} - - '@sentry-internal/replay@8.32.0': - resolution: {integrity: sha512-yiEUnn2yyo1AIQIFNeRX3tdK8fmyKIkxdFS1WiVQmeYI/hFwYBTZPly0FcO/g3xnRMSA2tvrS+hZEaaXfK4WhA==} - engines: {node: '>=14.18'} - - '@sentry/babel-plugin-component-annotate@2.22.6': - resolution: {integrity: sha512-V2g1Y1I5eSe7dtUVMBvAJr8BaLRr4CLrgNgtPaZyMT4Rnps82SrZ5zqmEkLXPumlXhLUWR6qzoMNN2u+RXVXfQ==} - engines: {node: '>= 14'} - - '@sentry/browser@8.26.0': - resolution: {integrity: sha512-e5s6eKlwLZWzTwQcBwqyAGZMMuQROW9Z677VzwkSyREWAIkKjfH2VBxHATnNGc0IVkNHjD7iH3ixo3C0rLKM3w==} - engines: {node: '>=14.18'} - - '@sentry/browser@8.32.0': - resolution: {integrity: sha512-AEKFj64g4iYwEMRvVcxiY0FswmClRXCP1IEvCqujn8OBS8AjMOr1z/RwYieEs0D90yNNB3YEqF8adrKENblJmw==} - engines: {node: '>=14.18'} - - '@sentry/bundler-plugin-core@2.22.6': - resolution: {integrity: sha512-1esQdgSUCww9XAntO4pr7uAM5cfGhLsgTK9MEwAKNfvpMYJi9NUTYa3A7AZmdA8V6107Lo4OD7peIPrDRbaDCg==} - engines: {node: '>= 14'} - - '@sentry/cli-darwin@2.46.0': - resolution: {integrity: sha512-5Ll+e5KAdIk9OYiZO8aifMBRNWmNyPjSqdjaHlBC1Qfh7pE3b1zyzoHlsUazG0bv0sNrSGea8e7kF5wIO1hvyg==} - engines: {node: '>=10'} - os: [darwin] + os: [openbsd] - '@sentry/cli-linux-arm64@2.46.0': - resolution: {integrity: sha512-OEJN8yAjI9y5B4telyqzu27Hi3+S4T8VxZCqJz1+z2Mp0Q/MZ622AahVPpcrVq/5bxrnlZR16+lKh8L1QwNFPg==} - engines: {node: '>=10'} + '@rollup/rollup-openharmony-arm64@4.60.1': + resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==} cpu: [arm64] - os: [linux, freebsd, android] - - '@sentry/cli-linux-arm@2.46.0': - resolution: {integrity: sha512-WRrLNq/TEX/TNJkGqq6Ad0tGyapd5dwlxtsPbVBrIdryuL1mA7VCBoaHBr3kcwJLsgBHFH0lmkMee2ubNZZdkg==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux, freebsd, android] - - '@sentry/cli-linux-i686@2.46.0': - resolution: {integrity: sha512-xko3/BVa4LX8EmRxVOCipV+PwfcK5Xs8lP6lgF+7NeuAHMNL4DqF6iV9rrN8gkGUHCUI9RXSve37uuZnFy55+Q==} - engines: {node: '>=10'} - cpu: [x86, ia32] - os: [linux, freebsd, android] - - '@sentry/cli-linux-x64@2.46.0': - resolution: {integrity: sha512-hJ1g5UEboYcOuRia96LxjJ0jhnmk8EWLDvlGnXLnYHkwy3ree/L7sNgdp/QsY8Z4j2PGO5f22Va+UDhSjhzlfQ==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux, freebsd, android] + os: [openharmony] - '@sentry/cli-win32-arm64@2.46.0': - resolution: {integrity: sha512-mN7cpPoCv2VExFRGHt+IoK11yx4pM4ADZQGEso5BAUZ5duViXB2WrAXCLd8DrwMnP0OE978a7N8OtzsFqjkbNA==} - engines: {node: '>=10'} + '@rollup/rollup-win32-arm64-msvc@4.60.1': + resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==} cpu: [arm64] os: [win32] - '@sentry/cli-win32-i686@2.46.0': - resolution: {integrity: sha512-6F73AUE3lm71BISUO19OmlnkFD5WVe4/wA1YivtLZTc1RU3eUYJLYxhDfaH3P77+ycDppQ2yCgemLRaA4A8mNQ==} - engines: {node: '>=10'} - cpu: [x86, ia32] + '@rollup/rollup-win32-ia32-msvc@4.60.1': + resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==} + cpu: [ia32] os: [win32] - '@sentry/cli-win32-x64@2.46.0': - resolution: {integrity: sha512-yuGVcfepnNL84LGA0GjHzdMIcOzMe0bjPhq/rwPsPN+zu11N+nPR2wV2Bum4U0eQdqYH3iAlMdL5/BEQfuLJww==} - engines: {node: '>=10'} + '@rollup/rollup-win32-x64-gnu@4.60.1': + resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==} cpu: [x64] os: [win32] - '@sentry/cli@2.46.0': - resolution: {integrity: sha512-nqoPl7UCr446QFkylrsRrUXF51x8Z9dGquyf4jaQU+OzbOJMqclnYEvU6iwbwvaw3tu/2DnoZE/Og+Nq1h63sA==} - engines: {node: '>= 10'} - hasBin: true + '@rollup/rollup-win32-x64-msvc@4.60.1': + resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==} + cpu: [x64] + os: [win32] - '@sentry/core@8.26.0': - resolution: {integrity: sha512-g/tVmTZD4GNbLFf++hKJfBpcCAtduFEMLnbfa9iT/QEZjlmP+EzY+GsH9bafM5VsNe8DiOUp+kJKWtShzlVdBA==} - engines: {node: '>=14.18'} + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sentry/core@8.32.0': - resolution: {integrity: sha512-+xidTr0lZ0c755tq4k75dXPEb8PA+qvIefW3U9+dQMORLokBrYoKYMf5zZTG2k/OfSJS6OSxatUj36NFuCs3aA==} - engines: {node: '>=14.18'} + '@sigstore/bundle@4.0.0': + resolution: {integrity: sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sentry/electron@5.4.0': - resolution: {integrity: sha512-ViJJ/7nro/QZPPFsrnniXwHW6BxxKHm+Ec79tGEDrLdrNhd4KL0oMZJF1cH+rMsG45ymQ5bO+lpA7Yf0nC/gZg==} + '@sigstore/core@3.2.0': + resolution: {integrity: sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sentry/node@8.26.0': - resolution: {integrity: sha512-N9mNLzicnfGgsq6P10ckPdTzEFusjTC7gpqPopwq5eEMF7g798hH8CcE5o6FZ4iAAR3vWliAR/jgccdoMmJMpQ==} - engines: {node: '>=14.18'} + '@sigstore/protobuf-specs@0.5.1': + resolution: {integrity: sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==} + engines: {node: ^18.17.0 || >=20.5.0} - '@sentry/opentelemetry@8.26.0': - resolution: {integrity: sha512-HBDheM/+ysfIz8R1OH4bBIxdgD7ZbQkKLJAUXkdAbBcfbpK/CTtwcplbauF5wY7Q+GYvwL/ShuDwvXRfW+gFyQ==} - engines: {node: '>=14.18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.25.1 - '@opentelemetry/instrumentation': ^0.52.1 - '@opentelemetry/sdk-trace-base': ^1.25.1 - '@opentelemetry/semantic-conventions': ^1.25.1 - - '@sentry/types@8.26.0': - resolution: {integrity: sha512-zKmh6SWsJh630rpt7a9vP4Cm4m1C2gDTUqUiH565CajCL/4cePpNWYrNwalSqsOSL7B9OrczA1+n6a6XvND+ng==} - engines: {node: '>=14.18'} - - '@sentry/types@8.32.0': - resolution: {integrity: sha512-hxckvN2MzS5SgGDgVQ0/QpZXk13Vrq4BtZLwXhPhyeTmZtUiUfWvcL5TFQqLinfKdTKPe9q2MxeAJ0D4LalhMg==} - engines: {node: '>=14.18'} - - '@sentry/utils@8.26.0': - resolution: {integrity: sha512-xvlPU9Hd2BlyT+FhWHGNwnxWqdVRk2AHnDtVcW4Ma0Ri5EwS+uy4Jeik5UkSv8C5RVb9VlxFmS8LN3I1MPJsLw==} - engines: {node: '>=14.18'} - - '@sentry/utils@8.32.0': - resolution: {integrity: sha512-t1WVERhgmYURxbBj9J4/H2P2X+VKqm7B3ce9iQyrZbdf5NekhcU4jHIecPUWCPHjQkFIqkVTorqeBmDTlg/UmQ==} - engines: {node: '>=14.18'} - - '@sentry/vite-plugin@2.22.6': - resolution: {integrity: sha512-zIieP1VLWQb3wUjFJlwOAoaaJygJhXeUoGd0e/Ha2RLb2eW2S+4gjf6y6NqyY71tZ74LYVZKg/4prB6FAZSMXQ==} - engines: {node: '>= 14'} + '@sigstore/sign@4.1.1': + resolution: {integrity: sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sentry/vue@8.32.0': - resolution: {integrity: sha512-56cF0lHKhzjBuErU1Bo7rSTyWFAudrStpp7smIAtGBURS2Q0pDPnx1PAmV36IXfuMcClGVFBHiGB1zZWZ46W3w==} - engines: {node: '>=14.18'} - peerDependencies: - vue: 2.x || 3.x + '@sigstore/tuf@4.0.2': + resolution: {integrity: sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==} + engines: {node: ^20.17.0 || >=22.9.0} - '@sindresorhus/is@0.14.0': - resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==} - engines: {node: '>=6'} + '@sigstore/verify@3.1.0': + resolution: {integrity: sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==} + engines: {node: ^20.17.0 || >=22.9.0} '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} @@ -2440,46 +3726,37 @@ packages: '@stablelib/base64@1.0.1': resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} - '@supabase/auth-js@2.65.1': - resolution: {integrity: sha512-IA7i2Xq2SWNCNMKxwmPlHafBQda0qtnFr8QnyyBr+KaSxoXXqEzFCnQ1dGTy6bsZjVBgXu++o3qrDypTspaAPw==} + '@supabase/auth-js@2.99.3': + resolution: {integrity: sha512-vMEVLA1kGGYd/kdsJSwtjiFUZM1nGfrz2DWmgMBZtocV48qL+L2+4QpIkueXyBEumMQZFEyhz57i/5zGHjvdBw==} + engines: {node: '>=20.0.0'} - '@supabase/functions-js@2.4.3': - resolution: {integrity: sha512-sOLXy+mWRyu4LLv1onYydq+10mNRQ4rzqQxNhbrKLTLTcdcmS9hbWif0bGz/NavmiQfPs4ZcmQJp4WqOXlR4AQ==} + '@supabase/functions-js@2.99.3': + resolution: {integrity: sha512-6tk2zrcBkzKaaBXPOG5nshn30uJNFGOH9LxOnE8i850eQmsX+jVm7vql9kTPyvUzEHwU4zdjSOkXS9M+9ukMVA==} + engines: {node: '>=20.0.0'} - '@supabase/node-fetch@2.6.15': - resolution: {integrity: sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==} - engines: {node: 4.x || >=6.0.0} - - '@supabase/postgrest-js@1.16.3': - resolution: {integrity: sha512-HI6dsbW68AKlOPofUjDTaosiDBCtW4XAm0D18pPwxoW3zKOE2Ru13Z69Wuys9fd6iTpfDViNco5sgrtnP0666A==} + '@supabase/postgrest-js@2.99.3': + resolution: {integrity: sha512-8HxEf+zNycj7Z8+ONhhlu+7J7Ha+L6weyCtdEeK2mN5OWJbh6n4LPU4iuJ5UlCvvNnbSXMoutY7piITEEAgl2g==} + engines: {node: '>=20.0.0'} - '@supabase/realtime-js@2.10.7': - resolution: {integrity: sha512-OLI0hiSAqQSqRpGMTUwoIWo51eUivSYlaNBgxsXZE7PSoWh12wPRdVt0psUMaUzEonSB85K21wGc7W5jHnT6uA==} + '@supabase/realtime-js@2.99.3': + resolution: {integrity: sha512-c1azgZ2nZPczbY5k5u5iFrk1InpxN81IvNE+UBAkjrBz3yc5ALLJNkeTQwbJZT4PZBuYXEzqYGLMuh9fdTtTMg==} + engines: {node: '>=20.0.0'} - '@supabase/storage-js@2.7.1': - resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==} + '@supabase/storage-js@2.99.3': + resolution: {integrity: sha512-lOfIm4hInNcd8x0i1LWphnLKxec42wwbjs+vhaVAvR801Vda0UAMbTooUY6gfqgQb8v29GofqKuQMMTAsl6w/w==} + engines: {node: '>=20.0.0'} - '@supabase/supabase-js@2.45.6': - resolution: {integrity: sha512-qVXSSUhhIqdFnF2VUGgeecPvw1cDW6+avcTbRgur4LaGnzrJCbM3Rx7g81/SSZjjeqYOtmHuKWhiHzV/EN8Ktw==} - - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + '@supabase/supabase-js@2.99.3': + resolution: {integrity: sha512-GuPbzoEaI51AkLw9VGhLNvnzw4PHbS3p8j2/JlvLeZNQMKwZw4aEYQIDBRtFwL5Nv7/275n9m4DHtakY8nCvgg==} + engines: {node: '>=20.0.0'} '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@szmarczak/http-timer@1.1.2': - resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} - engines: {node: '>=6'} - '@szmarczak/http-timer@4.0.6': resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} - '@tootallnate/once@1.1.2': - resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} - engines: {node: '>= 6'} - '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -2492,96 +3769,130 @@ packages: '@trpc/server@10.45.2': resolution: {integrity: sha512-wOrSThNNE4HUnuhJG6PfDRp4L2009KDVxsd+2VYH8ro6o/7/jwYZ8Uu5j+VaW+mOmc8EHerHzGcdbGNQSAUPgg==} - '@tsconfig/node10@1.0.11': - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + '@tufjs/canonical-json@2.0.0': + resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==} + engines: {node: ^16.14.0 || >=18.0.0} + + '@tufjs/models@4.1.0': + resolution: {integrity: sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@turbo/darwin-64@2.9.6': + resolution: {integrity: sha512-X/56SnVXIQZBLKwniGTwEQTGmtE5brSACnKMBWpY3YafuxVYefrC2acamfjgxP7BG5w3I+6jf0UrLoSzgPcSJg==} + cpu: [x64] + os: [darwin] + + '@turbo/darwin-arm64@2.9.6': + resolution: {integrity: sha512-aalBeSl4agT/QtYGDyf/XLajedWzUC9Vg/pm/YO6QQ93vkQ91Vz5uK1ta5RbVRDozQSz4njxUNqRNmOXDzW+qw==} + cpu: [arm64] + os: [darwin] + + '@turbo/linux-64@2.9.6': + resolution: {integrity: sha512-YKi05jnNHaD7vevgYwahpzGwbsNNTwzU2c7VZdmdFm7+cGDP4oREUWSsainiMfRqjRuolQxBwRn8wf1jmu+YZA==} + cpu: [x64] + os: [linux] + + '@turbo/linux-arm64@2.9.6': + resolution: {integrity: sha512-02o/ZS69cOYEDczXvOB2xmyrtzjQ2hVFtWZK1iqxXUfzMmTjZK4UumrfNnjckSg+gqeBfnPRHa0NstA173Ik3g==} + cpu: [arm64] + os: [linux] - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + '@turbo/windows-64@2.9.6': + resolution: {integrity: sha512-wVdQjvnBI15wB6JrA+43CtUtagjIMmX6XYO758oZHAsCNSxqRlJtdyujih0D8OCnwCRWiGWGI63zAxR0hO6s9g==} + cpu: [x64] + os: [win32] + + '@turbo/windows-arm64@2.9.6': + resolution: {integrity: sha512-1XUUyWW0W6FTSqGEhU8RHVqb2wP1SPkr7hIvBlMEwH9jr+sJQK5kqeosLJ/QaUv4ecSAd1ZhIrLoW7qslAzT4A==} + cpu: [arm64] + os: [win32] + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + '@types/adm-zip@0.5.7': + resolution: {integrity: sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==} - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@types/appdmg@0.5.5': + resolution: {integrity: sha512-G+n6DgZTZFOteITE30LnWj+HRVIGr7wMlAiLWOO02uJFWVEitaPU9JVXm9wJokkgshBawb2O1OykdcsmkkZfgg==} - '@types/archiver@6.0.3': - resolution: {integrity: sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==} + '@types/archiver@7.0.0': + resolution: {integrity: sha512-/3vwGwx9n+mCQdYZ2IKGGHEFL30I96UgBlk8EtRDDFQ9uxM1l4O5Ci6r00EMAkiDaTqD9DQ6nVrWRICnBPtzzg==} '@types/cacheable-request@6.0.3': resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - '@types/connect@3.4.36': - resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} + '@types/canvas-confetti@1.9.0': + resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==} - '@types/d3-path@3.1.1': - resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} - '@types/d3-shape@3.1.6': - resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==} + '@types/electron-squirrel-startup@1.0.2': + resolution: {integrity: sha512-AzxnvBzNh8K/0SmxMmZtpJf1/IWoGXLP+pQDuUaVkPyotI8ryvAtBSqgxR/qOSvxWHYWrxkeNsJ+Ca5xOuUxJQ==} - '@types/date-fns@2.6.3': - resolution: {integrity: sha512-Ke1lw2Ni1t/wMUoLtKFmSNCLozcTBd6vmMqFP4hRzXn6qzkNt97bPAX0x5Y/c15DP43kKvwW1ycStD5+43jVQA==} - deprecated: This is a stub types definition. date-fns provides its own type definitions, so you do not need this installed. + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - '@types/dompurify@3.0.5': - resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==} - - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/fs-extra@11.0.4': - resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - - '@types/fs-extra@9.0.13': - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - - '@types/jsdom@21.1.7': - resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} + '@types/jsesc@2.5.1': + resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/jsonfile@6.1.4': - resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} - '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} '@types/lodash-es@4.17.12': resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - '@types/lodash@4.17.17': - resolution: {integrity: sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==} + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} - '@types/mysql@2.15.22': - resolution: {integrity: sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==} + '@types/mute-stream@0.0.4': + resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} + + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@20.19.0': - resolution: {integrity: sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q==} + '@types/node@20.19.39': + resolution: {integrity: sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==} '@types/node@22.7.9': resolution: {integrity: sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==} - '@types/path-browserify@1.0.3': - resolution: {integrity: sha512-ZmHivEbNCBtAfcrFeBCiTjdIc2dey0l7oCGNGpSuRTy8jP6UVND7oUowlvDujBy8r2Hoa8bfFUOCiPWfmtkfxw==} + '@types/node@24.12.2': + resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} + + '@types/node@24.12.4': + resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} - '@types/pg-pool@2.0.4': - resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==} + '@types/npm-package-arg@6.1.4': + resolution: {integrity: sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q==} - '@types/pg@8.6.1': - resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} + '@types/npm-registry-fetch@8.0.9': + resolution: {integrity: sha512-7NxvodR5Yrop3pb6+n8jhJNyzwOX0+6F+iagNEoi9u1CGxruYAwZD8pvGc9prIkL0+FdX5Xp0p80J9QPrGUp/g==} - '@types/phoenix@1.6.6': - resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==} + '@types/npmlog@7.0.0': + resolution: {integrity: sha512-hJWbrKFvxKyWwSUXjZMYTINsSOY6IclhvGOZ97M8ac2tmR9hMwmTnYaMdpGhvju9ctWLTPhCS+eLfQNluiEjQQ==} + + '@types/pacote@11.1.8': + resolution: {integrity: sha512-/XLR0VoTh2JEO0jJg1q/e6Rh9bxjBq9vorJuQmtT7rRrXSiWz7e7NsvXVYJQ0i8JxMlBMPPYDTnrRe7MZRFA8Q==} + + '@types/phoenix@1.6.7': + resolution: {integrity: sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==} '@types/readdir-glob@1.1.5': resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} @@ -2589,124 +3900,81 @@ packages: '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + + '@types/ssri@7.1.5': + resolution: {integrity: sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw==} + + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} - '@types/shimmer@1.2.0': - resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} + '@types/tar@6.1.13': + resolution: {integrity: sha512-IznnlmU5f4WcGTh2ltRu/Ijpmk8wiWXfF0VA4s+HPjHZgvFggk1YaIkbo5krX/zUCzWF8N/l4+W/LNxnvAJ8nw==} + + '@types/tar@7.0.87': + resolution: {integrity: sha512-3IxNBV8LeY5oi2ZFpvAhOtW1+mHswkzM7BuisVrwJgPv67GBO2rkLPQlEKtzfHuLdhDDczhkCZeT+RuizMay4A==} + deprecated: This is a stub types definition. tar provides its own type definitions, so you do not need this installed. '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - '@types/trusted-types@2.0.7': - resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/tunnel@0.0.3': + resolution: {integrity: sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==} '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - - '@typescript-eslint/eslint-plugin@7.18.0': - resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@types/wrap-ansi@3.0.0': + resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} - '@typescript-eslint/parser@8.11.0': - resolution: {integrity: sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/scope-manager@8.11.0': - resolution: {integrity: sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typespec/ts-http-runtime@0.3.5': + resolution: {integrity: sha512-yURCknZhvywvQItHMMmFSo+fq5arCUIyz/CVk7jD89MSai7dkaX8ufjCWp3NttLojoTVbcE72ri+be/TnEbMHw==} + engines: {node: '>=20.0.0'} - '@typescript-eslint/type-utils@7.18.0': - resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@vee-validate/valibot@4.13.2': + resolution: {integrity: sha512-Vz/sAJc0i1Z1zsXbER15/7EUcD2mYHCaBrmmFs6oFBSDFoDXwJYjPMSklHqyOUVEt15wBVd9HU52f+4cD/5kxw==} - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} - engines: {node: ^18.18.0 || >=20.0.0} + '@vitejs/devtools-kit@0.1.13': + resolution: {integrity: sha512-8TqyrrPTB8KNGb2ukVHNo4aMhGYJgUypVNMnqOvxaWYln3QAXK6CFxifK3lZGOHWKAUqWAiTmZUsYzV4S0Kn7g==} + peerDependencies: + vite: '*' - '@typescript-eslint/types@8.11.0': - resolution: {integrity: sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vitejs/devtools-rolldown@0.1.13': + resolution: {integrity: sha512-VScSr/0+1+s3TBt5RFhv1dcRJSjWDUH3yJ8nc9+8zTOijzuKTjVo5yqfx0ISBro9CCeoPyXHuXntPqBSIhTTCA==} - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@vitejs/devtools-rpc@0.1.13': + resolution: {integrity: sha512-IbYRlvVJMdlQiRPU5fDnIAwgTu43O7v5/a1cUFp8t77zXLvg+3g2hbqrYzoqxIgAyLTr2KMY7HoYm6j/kIMB6Q==} peerDependencies: - typescript: '*' + ws: '*' peerDependenciesMeta: - typescript: + ws: optional: true - '@typescript-eslint/typescript-estree@8.11.0': - resolution: {integrity: sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vitejs/devtools@0.1.13': + resolution: {integrity: sha512-0PWKOrYyDiP+UFI0Sfqn3uTxRwQMnvFyA6t4vnj+0SpCEk+XNEP2igqjCp7/F9wU0JDH3SiWhfMe41za9BtwkA==} + hasBin: true peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + vite: '*' - '@typescript-eslint/utils@7.18.0': - resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} - engines: {node: ^18.18.0 || >=20.0.0} + '@vitejs/plugin-vue@6.0.5': + resolution: {integrity: sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==} + engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - eslint: ^8.56.0 - - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/visitor-keys@8.11.0': - resolution: {integrity: sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@vee-validate/valibot@4.13.2': - resolution: {integrity: sha512-Vz/sAJc0i1Z1zsXbER15/7EUcD2mYHCaBrmmFs6oFBSDFoDXwJYjPMSklHqyOUVEt15wBVd9HU52f+4cD/5kxw==} + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.2.25 - '@vitejs/plugin-vue@5.2.3': - resolution: {integrity: sha512-IYSLEQj4LgZZuoVpdSUCw3dIynTWQgPlaRP6iAvMle4My0HdYwr5g5wQAfwOeHQBmYwEkqF70nRpSilr6PoUDg==} - engines: {node: ^18.0.0 || >=20.0.0} + '@vitejs/plugin-vue@6.0.7': + resolution: {integrity: sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==} + engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^5.0.0 || ^6.0.0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 '@vitest/expect@3.1.4': @@ -2726,8 +3994,8 @@ packages: '@vitest/pretty-format@3.1.4': resolution: {integrity: sha512-cqv9H9GvAEoTaoq+cYqUTCGscUjKqlJZC7PRwY5FMySVj5J+xOm1KQcCiYHJOEzOKRUhLH4R2pTwvFlWCEScsg==} - '@vitest/pretty-format@3.2.2': - resolution: {integrity: sha512-FY4o4U1UDhO9KMd2Wee5vumwcaHw7Vg4V7yR4Oq6uK34nhEJOmdRYrk3ClburPRUA09lXD/oXWZ8y/Sdma0aUQ==} + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} '@vitest/runner@3.1.4': resolution: {integrity: sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==} @@ -2741,54 +4009,69 @@ packages: '@vitest/utils@3.1.4': resolution: {integrity: sha512-yriMuO1cfFhmiGc8ataN51+9ooHRuURdfAZfwFd3usWynjzpLslZdYnRegTv32qdgtJTsj15FoeZe2g15fY1gg==} - '@volar/language-core@2.4.14': - resolution: {integrity: sha512-X6beusV0DvuVseaOEy7GoagS4rYHgDHnTrdOj5jeUb49fW5ceQyP9Ej5rBhqgz2wJggl+2fDbbojq1XKaxDi6w==} + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} - '@volar/source-map@2.4.14': - resolution: {integrity: sha512-5TeKKMh7Sfxo8021cJfmBzcjfY1SsXsPMMjMvjY7ivesdnybqqS+GxGAoXHAOUawQTwtdUxgP65Im+dEmvWtYQ==} + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} - '@volar/typescript@2.4.14': - resolution: {integrity: sha512-p8Z6f/bZM3/HyCdRNFZOEEzts51uV8WHeN8Tnfnm2EBv6FDB2TQLzfVx7aJvnl8ofKAOnS64B2O8bImBFaauRw==} + '@vscode/sudo-prompt@9.3.2': + resolution: {integrity: sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw==} - '@vue/babel-helper-vue-transform-on@1.4.0': - resolution: {integrity: sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==} + '@vue/babel-helper-vue-transform-on@1.5.0': + resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} - '@vue/babel-plugin-jsx@1.4.0': - resolution: {integrity: sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA==} + '@vue/babel-plugin-jsx@1.5.0': + resolution: {integrity: sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==} peerDependencies: '@babel/core': ^7.0.0-0 peerDependenciesMeta: '@babel/core': optional: true - '@vue/babel-plugin-resolve-type@1.4.0': - resolution: {integrity: sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ==} + '@vue/babel-plugin-resolve-type@1.5.0': + resolution: {integrity: sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==} peerDependencies: '@babel/core': ^7.0.0-0 '@vue/compiler-core@3.5.13': resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} - '@vue/compiler-core@3.5.16': - resolution: {integrity: sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==} + '@vue/compiler-core@3.5.32': + resolution: {integrity: sha512-4x74Tbtqnda8s/NSD6e1Dr5p1c8HdMU5RWSjMSUzb8RTcUQqevDCxVAitcLBKT+ie3o0Dl9crc/S/opJM7qBGQ==} + + '@vue/compiler-core@3.5.34': + resolution: {integrity: sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw==} '@vue/compiler-dom@3.5.13': resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} - '@vue/compiler-dom@3.5.16': - resolution: {integrity: sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==} + '@vue/compiler-dom@3.5.32': + resolution: {integrity: sha512-ybHAu70NtiEI1fvAUz3oXZqkUYEe5J98GjMDpTGl5iHb0T15wQYLR4wE3h9xfuTNA+Cm2f4czfe8B4s+CCH57Q==} + + '@vue/compiler-dom@3.5.34': + resolution: {integrity: sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw==} '@vue/compiler-sfc@3.5.13': resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} - '@vue/compiler-sfc@3.5.16': - resolution: {integrity: sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==} + '@vue/compiler-sfc@3.5.32': + resolution: {integrity: sha512-8UYUYo71cP/0YHMO814TRZlPuUUw3oifHuMR7Wp9SNoRSrxRQnhMLNlCeaODNn6kNTJsjFoQ/kqIj4qGvya4Xg==} + + '@vue/compiler-sfc@3.5.34': + resolution: {integrity: sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==} '@vue/compiler-ssr@3.5.13': resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} - '@vue/compiler-ssr@3.5.16': - resolution: {integrity: sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==} + '@vue/compiler-ssr@3.5.32': + resolution: {integrity: sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==} + + '@vue/compiler-ssr@3.5.34': + resolution: {integrity: sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ==} '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} @@ -2796,36 +4079,25 @@ packages: '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} - '@vue/devtools-api@7.7.6': - resolution: {integrity: sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==} + '@vue/devtools-api@7.7.9': + resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} - '@vue/devtools-core@7.7.6': - resolution: {integrity: sha512-ghVX3zjKPtSHu94Xs03giRIeIWlb9M+gvDRVpIZ/cRIxKHdW6HE/sm1PT3rUYS3aV92CazirT93ne+7IOvGUWg==} + '@vue/devtools-core@8.1.1': + resolution: {integrity: sha512-bCCsSABp1/ot4j8xJEycM6Mtt2wbuucfByr6hMgjbYhrtlscOJypZKvy8f1FyWLYrLTchB5Qz216Lm92wfbq0A==} peerDependencies: vue: ^3.0.0 - '@vue/devtools-kit@7.7.6': - resolution: {integrity: sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==} + '@vue/devtools-kit@7.7.9': + resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} - '@vue/devtools-shared@7.7.6': - resolution: {integrity: sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==} + '@vue/devtools-kit@8.1.1': + resolution: {integrity: sha512-gVBaBv++i+adg4JpH71k9ppl4soyR7Y2McEqO5YNgv0BI1kMZ7BDX5gnwkZ5COYgiCyhejZG+yGNrBAjj6Coqg==} - '@vue/eslint-config-prettier@9.0.0': - resolution: {integrity: sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==} - peerDependencies: - eslint: '>= 8.0.0' - prettier: '>= 3.0.0' + '@vue/devtools-shared@7.7.9': + resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} - '@vue/eslint-config-typescript@13.0.0': - resolution: {integrity: sha512-MHh9SncG/sfqjVqjcuFLOLD6Ed4dRAis4HNt0dXASeAuLqIAx4YMB1/m2o4pUKK1vCt8fUvYG8KKX2Ot3BVZTg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - eslint-plugin-vue: ^9.0.0 - typescript: '>=4.7.4' - peerDependenciesMeta: - typescript: - optional: true + '@vue/devtools-shared@8.1.1': + resolution: {integrity: sha512-+h4ttmJYl/txpxHKaoZcaKpC+pvckgLzIDiSQlaQ7kKthKh8KuwoLW2D8hPJEnqKzXOvu15UHEoGyngAXCz0EQ==} '@vue/language-core@2.1.6': resolution: {integrity: sha512-MW569cSky9R/ooKMh6xa2g1D0AtRKbL56k83dzus/bx//RDJk24RHWkMzbAlXjMdDNyxAaagKPRquBIxkxlCkg==} @@ -2835,28 +4107,56 @@ packages: typescript: optional: true + '@vue/language-core@3.3.1': + resolution: {integrity: sha512-NP8g6V7x81NVOXbLupUvYY6i6LqUkjkVowe2epRedmpgaFCOdjgWHE/rQBvEJ4r7koAYODIjGeBWEdt6n7jYXQ==} + '@vue/reactivity@3.5.13': resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + '@vue/reactivity@3.5.34': + resolution: {integrity: sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==} + '@vue/runtime-core@3.5.13': resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + '@vue/runtime-core@3.5.34': + resolution: {integrity: sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw==} + '@vue/runtime-dom@3.5.13': resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + '@vue/runtime-dom@3.5.34': + resolution: {integrity: sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg==} + '@vue/server-renderer@3.5.13': resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} peerDependencies: vue: 3.5.13 + '@vue/server-renderer@3.5.34': + resolution: {integrity: sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==} + peerDependencies: + vue: 3.5.34 + '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} - '@vue/shared@3.5.16': - resolution: {integrity: sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==} + '@vue/shared@3.5.32': + resolution: {integrity: sha512-ksNyrmRQzWJJ8n3cRDuSF7zNNontuJg1YHnmWRJd2AMu8Ij2bqwiiri2lH5rHtYPZjj4STkNcgcmiQqlOjiYGg==} + + '@vue/shared@3.5.34': + resolution: {integrity: sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==} - '@vue/test-utils@2.4.6': - resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} + '@vue/tsconfig@0.9.1': + resolution: {integrity: sha512-buvjm+9NzLCJL29KY1j1991YYJ5e6275OiK+G4jtmfIb+z4POywbdm0wXusT9adVWqe0xqg70TbI7+mRx4uU9w==} + peerDependencies: + typescript: '>= 5.8' + vue: ^3.4.0 + peerDependenciesMeta: + typescript: + optional: true + vue: + optional: true '@vuelidate/core@2.0.3': resolution: {integrity: sha512-AN6l7KF7+mEfyWG0doT96z+47ljwPpZfi9/JrNMkOGLFv27XVZvKzRLXlmDPQjPl/wOB1GNnHuc54jlCLRNqGA==} @@ -2893,56 +4193,93 @@ packages: '@vueuse/shared@11.1.0': resolution: {integrity: sha512-YUtIpY122q7osj+zsNMFAfMTubGz0sn5QzE5gPzAIiCmtt2ha3uQUY1+JPyL4gRCTsLPX82Y9brNbo/aqlA91w==} - '@xmldom/xmldom@0.8.10': - resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xmldom/xmldom@0.8.12': + resolution: {integrity: sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==} engines: {node: '>=10.0.0'} + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - abbrev@2.0.0: - resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abbrev@4.0.0: + resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} + engines: {node: ^20.17.0 || >=22.9.0} abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - - acorn-import-assertions@1.9.0: - resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} - deprecated: package has been renamed to acorn-import-attributes - peerDependencies: - acorn: ^8 - - acorn-import-attributes@1.9.5: - resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} - peerDependencies: - acorn: ^8 - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} + acorn: ^8.14.0 - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true + adm-zip@0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.3: - resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} agentkeepalive@4.6.0: @@ -2953,11 +4290,24 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + alien-signals@3.2.1: + resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} @@ -2971,30 +4321,26 @@ packages: resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} engines: {node: '>=12'} - ansi-regex@2.1.1: - resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} - engines: {node: '>=0.10.0'} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -3005,77 +4351,31 @@ packages: os: [darwin] hasBin: true - aproba@1.2.0: - resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} - - archiver-utils@2.1.0: - resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} - engines: {node: '>= 6'} - - archiver-utils@3.0.4: - resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} - engines: {node: '>= 10'} - archiver-utils@5.0.2: resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} engines: {node: '>= 14'} - archiver@5.3.2: - resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} - engines: {node: '>= 10'} - archiver@7.0.1: resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} engines: {node: '>= 14'} - are-we-there-yet@1.1.7: - resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==} - deprecated: This package is no longer supported. - - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} - - asn1.js@4.10.1: - resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} - - asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - - assert@2.1.0: - resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} + ast-kit@3.0.0-beta.1: + resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==} + engines: {node: '>=20.19.0'} async@1.5.2: resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} @@ -3094,27 +4394,61 @@ packages: resolution: {integrity: sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g==} engines: {node: '>=0.8'} - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + b4a@1.8.0: + resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} - aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true - aws4@1.13.2: - resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + bare-fs@4.7.0: + resolution: {integrity: sha512-xzqKsCFxAek9aezYhjJuJRXBIaYlg/0OGDTZp+T8eYmYMlm66cs6cYko02drIyjN2CBbi+I6L7YfXyqpqtKRXA==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true - axios@1.9.0: - resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + bare-os@3.8.7: + resolution: {integrity: sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==} + engines: {bare: '>=1.14.0'} - b4a@1.6.7: - resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-stream@2.13.0: + resolution: {integrity: sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==} + peerDependencies: + bare-abort-controller: '*' + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + bare-buffer: + optional: true + bare-events: + optional: true - bare-events@2.5.4: - resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} + bare-url@2.4.0: + resolution: {integrity: sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==} base32-encode@1.2.0: resolution: {integrity: sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A==} @@ -3122,8 +4456,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + baseline-browser-mapping@2.10.18: + resolution: {integrity: sha512-VSnGQAOLtP5mib/DPyg2/t+Tlv65NTBz83BJBJvmLVHHuKJVaDOBvJJykiT5TR++em5nfAySPccDZDa4oSrn8A==} + engines: {node: '>=6.0.0'} + hasBin: true before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} @@ -3136,8 +4472,11 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - birpc@2.3.0: - resolution: {integrity: sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==} + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -3145,18 +4484,8 @@ packages: bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - bn.js@4.12.2: - resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} - - bn.js@5.2.2: - resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} - - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bole@5.0.28: + resolution: {integrity: sha512-l+yybyZLV7zTD6EuGxoXsilpER1ctMCpdOqjSYNigJJma39ha85fzCtYccPx06oR1u7uCQLOcUAFFzvfXVBmuQ==} boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} @@ -3165,51 +4494,25 @@ packages: bottleneck@2.19.5: resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} - boxen@5.1.2: - resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} - engines: {node: '>=10'} - bplist-creator@0.0.8: resolution: {integrity: sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==} - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - - browser-resolve@2.0.0: - resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==} - - browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - - browserify-cipher@1.0.1: - resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} - - browserify-des@1.0.2: - resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - - browserify-rsa@4.1.1: - resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} - engines: {node: '>= 0.10'} - - browserify-sign@4.2.3: - resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} - engines: {node: '>= 0.12'} - - browserify-zlib@0.2.0: - resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - - browserslist@4.25.0: - resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -3220,44 +4523,30 @@ packages: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - builtin-status-codes@3.0.0: - resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} - - builtins@1.0.3: - resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} - bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - c12@3.0.4: - resolution: {integrity: sha512-t5FaZTYbbCtvxuZq9xxIruYydrAGsJ+8UdP0pZzMiK2xl/gNiSOy0OxhLzHUEEb0m1QXYqfzfvyIFEmz/g9lqg==} + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} peerDependencies: - magicast: ^0.3.5 + magicast: '*' peerDependenciesMeta: magicast: optional: true @@ -3266,22 +4555,22 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - cacache@15.3.0: - resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} - engines: {node: '>= 10'} + cac@7.0.0: + resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} + engines: {node: '>=20.19.0'} cacache@16.1.3: resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + cacache@20.0.4: + resolution: {integrity: sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==} + engines: {node: ^20.17.0 || >=22.9.0} + cacheable-lookup@5.0.4: resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} engines: {node: '>=10.6.0'} - cacheable-request@6.1.0: - resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==} - engines: {node: '>=8'} - cacheable-request@7.0.4: resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} engines: {node: '>=8'} @@ -3290,39 +4579,15 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - caniuse-lite@1.0.30001721: - resolution: {integrity: sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==} - - caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - - chai@5.2.0: - resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} - engines: {node: '>=12'} + caniuse-lite@1.0.30001788: + resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==} - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + canvas-confetti@1.9.4: + resolution: {integrity: sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==} - chalk@4.1.0: - resolution: {integrity: sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==} - engines: {node: '>=10'} + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -3334,8 +4599,15 @@ packages: chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + + check-disk-space@3.4.0: + resolution: {integrity: sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==} + engines: {node: '>=16'} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} chokidar@3.6.0: @@ -3346,42 +4618,29 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - cint@8.2.1: - resolution: {integrity: sha512-gyWqJHXgDFPNx7PEyFJotutav+al92TTC3dWlMFyTETlOyKBQMZb7Cetqmj3GlrnSILHwSJRwf4mIGzc7C5lXw==} - - cipher-base@1.0.6: - resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} - engines: {node: '>= 0.10'} - citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} - clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} - cli-boxes@2.2.1: - resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} - engines: {node: '>=6'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -3394,24 +4653,17 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table@0.3.5: - resolution: {integrity: sha512-7uo2+RMNQUZ13M199udxqwk1qxTOS53EUak4gmu/aioUpdH5RvBz0JkJslcWz6ABKedZNqXXzikMZgHh+qF16A==} - engines: {node: '>= 0.2.0'} - cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - cli-width@3.0.0: - resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} - engines: {node: '>= 10'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -3423,72 +4675,45 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - code-point-at@1.1.0: - resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} - engines: {node: '>=0.10.0'} - - code-tag@1.2.0: - resolution: {integrity: sha512-5O79BzMWQxXQKJiubtwtIXqXsgd9u90xvze+K5PLajtM4ewM2emlEvLBdvgviXORHrBmzijG9+6qPtt+xpkv9Q==} - engines: {node: '>=18'} - - codsen-utils@1.6.7: - resolution: {integrity: sha512-M+9D3IhFAk4T8iATX62herVuIx1sp5kskWgxEegKD/JwTTSSGjGQs5Q5J4vVJ4mLcn1uhfxDYv6Yzr8zleHF3w==} + codsen-utils@1.7.3: + resolution: {integrity: sha512-YIFQQ1n2NSgwoB3sCe7RpkZzsrPxTMek6jc7wC9fXOm1wwfWAKja9gLOMEjlXOUd3LKV3o6Jci7n9BoHs5Z8Sg==} engines: {node: '>=14.18.0'} color-convert@0.5.3: resolution: {integrity: sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==} - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - colors@1.0.3: - resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} - engines: {node: '>=0.1.90'} + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} - commander@6.2.1: - resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} - engines: {node: '>= 6'} - commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} @@ -3497,10 +4722,6 @@ packages: resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} engines: {node: '>=0.10.0'} - compress-commons@4.1.2: - resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} - engines: {node: '>= 10'} - compress-commons@6.0.2: resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} engines: {node: '>= 14'} @@ -3514,63 +4735,33 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - confbox@0.2.2: - resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - - config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - - configstore@5.0.1: - resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} - engines: {node: '>=8'} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - console-browserify@1.2.0: - resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} - - console-control-strings@1.1.0: - resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - - constants-browserify@1.0.0: - resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} - content-disposition@0.5.2: resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} engines: {node: '>= 0.6'} - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - copy-anything@2.0.6: - resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} - - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - - core-js@3.43.0: - resolution: {integrity: sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==} + copy-anything@4.0.5: + resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + engines: {node: '>=18'} - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + core-js@3.49.0: + resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -3580,32 +4771,21 @@ packages: engines: {node: '>=0.8'} hasBin: true - crc32-stream@4.0.3: - resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} - engines: {node: '>= 10'} - crc32-stream@6.0.0: resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} engines: {node: '>= 14'} - create-ecdh@4.0.4: - resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} - - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - - create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} cross-dirname@0.1.0: resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + cross-spawn@6.0.6: resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} engines: {node: '>=4.8'} @@ -3618,25 +4798,11 @@ packages: resolution: {integrity: sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==} engines: {node: '>=12.10'} - crypto-browserify@3.12.1: - resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} - engines: {node: '>= 0.10'} - - crypto-random-string@2.0.0: - resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} - engines: {node: '>=8'} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} - cssstyle@4.4.0: - resolution: {integrity: sha512-W0Y2HOXlPkb2yaKrCVRjinYKciu/qSLEmK0K9mcfDei3zwlnHFEHAs/Du3cIRwPqY+J4JsiBzUjoHyc8RsJ03A==} - engines: {node: '>=18'} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} d3-path@3.1.0: resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} @@ -3646,29 +4812,6 @@ packages: resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} engines: {node: '>=12'} - dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} - - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} - - dataloader@1.4.0: - resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} - date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} @@ -3683,8 +4826,8 @@ packages: supports-color: optional: true - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -3692,49 +4835,28 @@ packages: supports-color: optional: true - decimal.js@10.5.0: - resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} - - decompress-response@3.3.0: - resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} - engines: {node: '>=4'} - decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + engines: {node: '>=6'} deep-pick-omit@1.2.1: resolution: {integrity: sha512-2J6Kc/m3irCeqVG42T+SaUMesaK7oGWaedGnQQK/+O0gYc+2SP5bKh/KKTE7d7SJ+GCA9UUE1GRzh6oDe0EnGw==} - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - default-browser-id@5.0.0: - resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.2.1: - resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} engines: {node: '>=18'} defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - defer-to-connect@1.1.3: - resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==} - defer-to-connect@2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} engines: {node: '>=10'} @@ -3755,64 +4877,34 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - - del@6.0.0: - resolution: {integrity: sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==} - engines: {node: '>=10'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - delegates@1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} - des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - detect-indent@6.0.0: - resolution: {integrity: sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==} - engines: {node: '>=8'} - detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} - diffie-hellman@5.0.3: - resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} - dir-compare@4.2.0: resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} @@ -3820,93 +4912,48 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - domain-browser@4.22.0: - resolution: {integrity: sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==} - engines: {node: '>=10'} - dompurify@3.1.7: resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==} - dot-prop@5.3.0: - resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} - engines: {node: '>=8'} - - dotenv@16.5.0: - resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} - dotenv@8.6.0: - resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} - engines: {node: '>=10'} - driver.js@1.4.0: resolution: {integrity: sha512-Gm64jm6PmcU+si21sQhBrTAM1JvUrR0QhNmjkprNLxohOBzul9+pNHXgQaT9lW84gwg9GMLB3NZGuGolsz5uew==} ds-store@0.1.6: resolution: {integrity: sha512-kY21M6Lz+76OS3bnCzjdsJSF7LBpLYGCVfavW8TgQD2XkcqIZ86W0y9qUDZu6fp7SIZzqosMDW2zi7zVFfv4hw==} + dts-resolver@2.1.3: + resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} + engines: {node: '>=20.19.0'} + peerDependencies: + oxc-resolver: '>=11.0.0' + peerDependenciesMeta: + oxc-resolver: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - duplexer3@0.1.5: - resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} - - editorconfig@1.0.4: - resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} - engines: {node: '>=14'} - hasBin: true - - editorconfig@2.0.0: - resolution: {integrity: sha512-s1NQ63WQ7RNXH6Efb2cwuyRlfpbtdZubvfNe4vCuoyGPewNPY7vah8JUSOFBiJ+jr99Qh8t0xKv0oITc1dclgw==} - engines: {node: '>=16'} - hasBin: true - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - ejs@3.1.10: - resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} - engines: {node: '>=0.10.0'} - hasBin: true - - electron-installer-common@0.10.4: - resolution: {integrity: sha512-8gMNPXfAqUE5CfXg8RL0vXpLE9HAaPkgLXVoHE3BMUzogMWenf4LmwQ27BdCUrEhkjrKl+igs2IHJibclR3z3Q==} - engines: {node: '>= 10.0.0'} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - electron-installer-debian@3.2.0: - resolution: {integrity: sha512-58ZrlJ1HQY80VucsEIG9tQ//HrTlG6sfofA3nRGr6TmkX661uJyu4cMPPh6kXW+aHdq/7+q25KyQhDrXvRL7jw==} - engines: {node: '>= 10.0.0'} - os: [darwin, linux] - hasBin: true - - electron-installer-dmg@4.0.0: - resolution: {integrity: sha512-g3W6XnyUa7QGrAF7ViewHdt6bXV2KYU1Pm1CY3pZpp+H6mOjCHHAhf/iZAxtaX1ERCb+SQHz7xSsAHuNH9I8ZQ==} - engines: {node: '>= 12.13.0'} + electron-installer-dmg@5.0.1: + resolution: {integrity: sha512-qOa1aAQdX57C+vzhDk3549dd/PRlNL4F8y736MTD1a43qptD+PvHY97Bo9gSf+OZ8iUWE7BrYSpk/FgLUe40EA==} + engines: {node: '>= 16'} hasBin: true electron-squirrel-startup@1.0.1: resolution: {integrity: sha512-sTfFIHGku+7PsHLJ7v0dRcZNkALrV+YEozINTW8X1nM//e5O3L+rfYuvSW00lmGHnYmUjARZulD8F2V8ISI9RA==} - electron-to-chromium@1.5.165: - resolution: {integrity: sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==} - - electron-vite@2.3.0: - resolution: {integrity: sha512-lsN2FymgJlp4k6MrcsphGqZQ9fKRdJKasoaiwIrAewN1tapYI/KINLdfEL7n10LuF0pPSNf/IqjzZbB5VINctg==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@swc/core': ^1.0.0 - vite: ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - '@swc/core': - optional: true + electron-to-chromium@1.5.336: + resolution: {integrity: sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==} electron-winstaller@5.4.0: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} @@ -3917,34 +4964,28 @@ packages: engines: {node: '>= 12.20.55'} hasBin: true - elkjs@0.9.3: - resolution: {integrity: sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==} - - elliptic@6.6.1: - resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} - emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + encode-utf8@1.0.3: resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} @@ -3954,8 +4995,8 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} env-paths@2.2.1: @@ -3965,23 +5006,15 @@ packages: err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - errno@0.1.8: - resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} - hasBin: true - - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - error-stack-parser-es@0.1.5: - resolution: {integrity: sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==} + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} errx@0.1.0: resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==} - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} - engines: {node: '>= 0.4'} - es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -3993,6 +5026,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -4001,28 +5037,28 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} - es-toolkit@1.25.2: resolution: {integrity: sha512-zEh2aJUwnlDwashas6JN+oFVN08F2s2qBaEwTo6EOACjO9PdPH4eGRBZC2JP/3SDLeANiMTEtVnOGhoG7GwZcA==} es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true + esbuild-plugin-wasm@1.1.0: + resolution: {integrity: sha512-0bQ6+1tUbySSnxzn5jnXHMDvYnT0cN/Wd4Syk8g/sqAIJUg7buTIi22svS3Qz6ssx895NT+TgLPb33xi1OkZig==} + engines: {node: '>=0.10.0'} esbuild@0.23.1: resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} engines: {node: '>=18'} hasBin: true - esbuild@0.25.5: - resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true @@ -4030,10 +5066,6 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-goat@2.1.1: - resolution: {integrity: sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==} - engines: {node: '>=8'} - escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -4049,83 +5081,23 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-prettier@5.4.1: - resolution: {integrity: sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true - - eslint-plugin-vue@9.29.1: - resolution: {integrity: sha512-MH/MbVae4HV/tM8gKAVWMPJbYgW04CK7SuzYRrlNERpxbO0P3+Zdsa2oAcFBW6xNu7W6lIkGOsFAMCRTYmrlWQ==} - engines: {node: ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-scope@8.3.0: - resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.0: - resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.13.0: - resolution: {integrity: sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - esm@3.2.25: - resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} - engines: {node: '>=6'} - - espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -4136,28 +5108,20 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - execa@1.0.0: resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} engines: {node: '>=6'} @@ -4166,36 +5130,23 @@ packages: resolution: {integrity: sha512-5eo/BRqZm3GYce+1jqX/tJ7duA2AnE39i88fuedNFUV8XxGxUpF3aWkBRfbUcjV49gCkvS/pzc0YrCPhaIewdg==} engines: {node: ^18.19.0 || >=20.5.0} - execa@9.6.0: - resolution: {integrity: sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==} + execa@9.5.1: + resolution: {integrity: sha512-QY5PPtSonnGwhhHDNI7+3RvY285c7iuJFFB+lU+oEzMY/gEGJ808owqJsrr8Otd1E/x07po1LkUBmdAc5duPAg==} engines: {node: ^18.19.0 || >=20.5.0} - expand-tilde@2.0.2: - resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} - engines: {node: '>=0.10.0'} + execa@9.5.2: + resolution: {integrity: sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==} + engines: {node: ^18.19.0 || >=20.5.0} - expect-type@1.2.1: - resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} - - express-ws@5.0.2: - resolution: {integrity: sha512-0uvmuk61O9HXgLhGl3QhNSEtRsQevtmbL94/eILaliEADZBHZOQUAiHFrGPrgsjikohyrmSG5g+sCfASTt0lkQ==} - engines: {node: '>=4.5.0'} - peerDependencies: - express: ^4.0.0 || ^5.0.0-alpha.1 - - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} - engines: {node: '>= 0.10.0'} - - exsolve@1.0.5: - resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -4209,19 +5160,12 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true - extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - fancy-ansi@0.1.3: resolution: {integrity: sha512-tRQVTo5jjdSIiydqgzIIEZpKddzSsfGLsSVt6vWdjVm7fbvDTiQkyoPu6Z3dIPlAM4OZk0jP5jmTCX4G8WGgBw==} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} @@ -4229,23 +5173,33 @@ packages: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fast-string-truncated-width@1.2.1: + resolution: {integrity: sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow==} + + fast-string-width@1.1.0: + resolution: {integrity: sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fast-wrap-ansi@0.1.6: + resolution: {integrity: sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.4.5: - resolution: {integrity: sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -4255,25 +5209,10 @@ packages: fflate@0.4.8: resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} - figgy-pudding@3.5.2: - resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} - deprecated: This module is no longer supported. - - figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - figures@6.1.0: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - filename-reserved-regex@2.0.0: resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} engines: {node: '>=4'} @@ -4286,18 +5225,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} - find-up@2.1.0: resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} engines: {node: '>=4'} - find-up@3.0.0: - resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} - engines: {node: '>=6'} - find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -4306,13 +5237,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - flora-colossus@2.0.0: resolution: {integrity: sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA==} engines: {node: '>= 12'} @@ -4320,49 +5244,14 @@ packages: fmix@0.1.0: resolution: {integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - - form-data@2.3.3: - resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} - engines: {node: '>= 0.12'} - - form-data@4.0.3: - resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fp-and-or@0.1.4: - resolution: {integrity: sha512-+yRYRhpnFPWXSly/6V4Lw9IfOV26uu30kynGJ03PW+MnjOEQe45RZ141QcS0aJehYBYA50GfCDnsRbFJdhssRw==} - engines: {node: '>=10'} - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -4387,6 +5276,10 @@ packages: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} + fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + fs-temp@1.2.1: resolution: {integrity: sha512-okTwLB7/Qsq82G6iN5zZJFsOfZtx2/pqrA7Hk/9fvy+c+eJS9CvgGXT2uNxwnI14BDY9L/jQPkaBgSvlKfSW9w==} @@ -4411,25 +5304,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - galactus@1.0.0: resolution: {integrity: sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ==} engines: {node: '>= 12'} - gar@1.0.4: - resolution: {integrity: sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - - gauge@2.7.4: - resolution: {integrity: sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==} - deprecated: This package is no longer supported. - geist@1.3.1: resolution: {integrity: sha512-Q4gC1pBVPN+D579pBaz0TRRnGA4p9UK6elDY/xizXdFk/g4EKR5g0I+4p/Kj6gM0SajDBZ/0FvDV9ey9ud7BWw==} peerDependencies: @@ -4449,13 +5327,6 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-folder-size@2.0.1: - resolution: {integrity: sha512-+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==} - hasBin: true - - get-installed-path@2.1.1: - resolution: {integrity: sha512-Qkn9eq6tW5/q9BDVdMpB8tOHljX9OSP0jRC5TRNVA4qRc839t4g8KQaR8t0Uv0EFVL0MlyG7m/ofjEgAROtYsA==} - get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -4464,14 +5335,13 @@ packages: resolution: {integrity: sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw==} engines: {node: '>= 4.0'} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-stdin@8.0.0: - resolution: {integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==} - engines: {node: '>=10'} - get-stream@4.1.0: resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} engines: {node: '>=6'} @@ -4484,40 +5354,39 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} - - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.13.7: + resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} get-value@3.0.1: resolution: {integrity: sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==} engines: {node: '>=6.0'} - getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} - - giget@2.0.0: - resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + giget@3.2.0: + resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} hasBin: true - github-url-to-object@4.0.6: - resolution: {integrity: sha512-NaqbYHMUAlPcmWFdrAB7bcxrNIiiJWJe8s/2+iOc9vlcHlwHqSGrPk+Yi3nu6ebTwgsZEa7igz+NH2vEq3gYwQ==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + glob-to-regex.js@1.2.0: + resolution: {integrity: sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -4527,11 +5396,6 @@ packages: engines: {node: '>=12'} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - glob@9.3.5: - resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} - engines: {node: '>=16 || 14 >=14.17'} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - global-agent@3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} engines: {node: '>=10.0'} @@ -4540,30 +5404,6 @@ packages: resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} engines: {node: '>=10'} - global-modules@1.0.0: - resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} - engines: {node: '>=0.10.0'} - - global-prefix@1.0.2: - resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} - engines: {node: '>=0.10.0'} - - globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@15.11.0: - resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} - engines: {node: '>=18'} - globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -4579,40 +5419,19 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - got@11.8.1: - resolution: {integrity: sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q==} - engines: {node: '>=10.19.0'} - got@11.8.6: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} engines: {node: '>=10.19.0'} - got@9.6.0: - resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==} - engines: {node: '>=8.6'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql@16.13.2: + resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - har-schema@2.0.0: - resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} - engines: {node: '>=4'} - - har-validator@5.1.5: - resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} - engines: {node: '>=6'} - deprecated: this library is no longer supported - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -4621,10 +5440,6 @@ packages: has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -4633,20 +5448,6 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - has-unicode@2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - - has-yarn@2.1.0: - resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} - engines: {node: '>=8'} - - hash-base@3.0.5: - resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} - engines: {node: '>= 0.10'} - - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -4655,30 +5456,21 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - - homedir-polyfill@1.0.3: - resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} - engines: {node: '>=0.10.0'} + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + hookable@6.1.0: + resolution: {integrity: sha512-ZoKZSJgu8voGK2geJS+6YtYjvIzu9AOM/KZXsBxr83uhLL++e9pEv/dlgwgy3dvHg06kTz6JOh1hk3C8Ceiymw==} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - hosted-git-info@3.0.8: - resolution: {integrity: sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==} - engines: {node: '>=10'} - - hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} - - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + hosted-git-info@9.0.2: + resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} + engines: {node: ^20.17.0 || >=22.9.0} html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} @@ -4686,14 +5478,6 @@ packages: http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - http-proxy-agent@4.0.1: - resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} - engines: {node: '>= 6'} - http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -4702,17 +5486,10 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-signature@1.2.0: - resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} - engines: {node: '>=0.8', npm: '>=1.3.7'} - http2-wrapper@1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} - https-browserify@1.0.0: - resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} - https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -4721,8 +5498,9 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - human-id@1.0.2: - resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + hasBin: true human-signals@8.0.1: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} @@ -4731,6 +5509,14 @@ packages: humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + hyperdyperid@1.2.0: + resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} + engines: {node: '>=10.18'} + + iceberg-js@0.8.1: + resolution: {integrity: sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==} + engines: {node: '>=20.0.0'} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -4739,11 +5525,16 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore-walk@3.0.4: - resolution: {integrity: sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==} + ignore-walk@8.0.0: + resolution: {integrity: sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==} + engines: {node: ^20.17.0 || >=22.9.0} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} @@ -4753,32 +5544,20 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - image-size@0.5.5: - resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} - engines: {node: '>=0.10.0'} - hasBin: true - image-size@0.7.5: resolution: {integrity: sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==} engines: {node: '>=6.9.0'} hasBin: true - immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + immer@11.1.4: + resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==} - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - import-in-the-middle@1.14.0: - resolution: {integrity: sha512-g5zLT0HaztRJWysayWYiUq/7E5H825QIiecMD2pI5QO7Wzr847l6GDvPvmZaDIdrDtS2w7qRczywxiK6SL5vRw==} + immutable@5.1.5: + resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==} - import-in-the-middle@1.7.1: - resolution: {integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==} - - import-lazy@2.1.0: - resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==} - engines: {node: '>=4'} + import-without-cache@0.2.5: + resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==} + engines: {node: '>=20.19.0'} imul@1.0.1: resolution: {integrity: sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==} @@ -4792,6 +5571,9 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + individual@3.0.0: + resolution: {integrity: sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==} + infer-owner@1.0.4: resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} @@ -4802,87 +5584,36 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@2.0.0: resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} engines: {node: '>=10'} - inquirer@7.3.3: - resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} - engines: {node: '>=8.0.0'} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} interpret@3.1.1: resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} engines: {node: '>=10.13.0'} - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-ci@2.0.0: - resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} - hasBin: true - is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -4897,14 +5628,6 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - - is-fullwidth-code-point@1.0.0: - resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} - engines: {node: '>=0.10.0'} - is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -4913,23 +5636,19 @@ packages: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} hasBin: true - is-installed-globally@0.4.0: - resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} - engines: {node: '>=10'} - is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} @@ -4937,48 +5656,19 @@ packages: is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - is-my-ip-valid@1.0.1: resolution: {integrity: sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==} is-my-json-valid@2.20.6: resolution: {integrity: sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==} - is-nan@1.3.2: - resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-npm@5.0.0: - resolution: {integrity: sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==} - engines: {node: '>=10'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-obj@2.0.0: - resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} - engines: {node: '>=8'} - - is-path-cwd@2.2.0: - resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} - engines: {node: '>=6'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -4987,13 +5677,6 @@ packages: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} - is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-primitive@3.0.1: resolution: {integrity: sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==} engines: {node: '>=0.10.0'} @@ -5001,18 +5684,6 @@ packages: is-property@1.0.2: resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - is-stream@1.1.0: resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} engines: {node: '>=0.10.0'} @@ -5025,25 +5696,10 @@ packages: resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} engines: {node: '>=18'} - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -5052,27 +5708,9 @@ packages: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} - is-url@1.2.4: - resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - is-what@3.14.1: - resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} - - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} + is-what@5.5.0: + resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} + engines: {node: '>=18'} is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} @@ -5082,19 +5720,13 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} - is-yarn-global@0.3.0: - resolution: {integrity: sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isbinaryfile@4.0.10: resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} engines: {node: '>= 8.0.0'} @@ -5102,98 +5734,56 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@4.0.0: + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} + isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - isomorphic-timers-promises@1.0.1: - resolution: {integrity: sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==} - engines: {node: '>=10'} - - isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jake@10.9.2: - resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} - engines: {node: '>=10'} - hasBin: true - - jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} - hasBin: true - - jju@1.4.0: - resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} - js-beautify@1.15.4: - resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} - engines: {node: '>=14'} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - js-cookie@3.0.5: - resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} - engines: {node: '>=14'} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - - jsdom@25.0.1: - resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} - engines: {node: '>=18'} - peerDependencies: - canvas: ^2.11.2 - peerDependenciesMeta: - canvas: - optional: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true - json-buffer@3.0.0: - resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} - json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-better-errors@1.0.2: - resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-parse-helpfulerror@1.0.3: - resolution: {integrity: sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==} + json-parse-even-better-errors@5.0.0: + resolution: {integrity: sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==} + engines: {node: ^20.17.0 || >=22.9.0} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -5206,11 +5796,8 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - - jsonlines@0.1.1: - resolution: {integrity: sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} @@ -5220,54 +5807,116 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} - jsprim@1.4.2: - resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} - engines: {node: '>=0.6.0'} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} + engines: {node: '>=12', npm: '>=6'} junk@3.1.0: resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} engines: {node: '>=8'} - keyv@3.1.0: - resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - knitwork@1.2.0: - resolution: {integrity: sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==} + knitwork@1.3.0: + resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - latest-version@5.1.0: - resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==} - engines: {node: '>=8'} + launch-editor@2.13.2: + resolution: {integrity: sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==} lazystream@1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} - less@4.2.0: - resolution: {integrity: sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==} - engines: {node: '>=6'} - hasBin: true + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} - libnpmconfig@1.2.1: - resolution: {integrity: sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==} - deprecated: This module is not used anymore. npm config is parsed by npm itself and by @npmcli/config + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} listr2@7.0.2: resolution: {integrity: sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==} @@ -5277,26 +5926,22 @@ packages: resolution: {integrity: sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==} engines: {node: '>=4'} - load-json-file@4.0.0: - resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} - engines: {node: '>=4'} + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} + engines: {node: '>=6.11.5'} local-pkg@0.5.1: resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} engines: {node: '>=14'} - local-pkg@1.1.1: - resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} engines: {node: '>=14'} locate-path@2.0.0: resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} - locate-path@3.0.0: - resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} - engines: {node: '>=6'} - locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -5305,36 +5950,39 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - - lodash.defaults@4.2.0: - resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} - - lodash.difference@4.5.0: - resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} - - lodash.flatten@4.4.0: - resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - lodash.union@4.6.0: - resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} @@ -5344,12 +5992,8 @@ packages: resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - loupe@3.1.3: - resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} - - lowercase-keys@1.0.1: - resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==} - engines: {node: '>=0.10.0'} + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} @@ -5358,13 +6002,13 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.3.5: + resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} @@ -5373,31 +6017,16 @@ packages: resolution: {integrity: sha512-yiLHa7cfJcGRFq4FrR4tMlpNHb4Vy4mWnpajlSSIFM5k4Lv8/7BbbDLzCAVogWNl0LlLhizRp1drXv0hK9h0Yw==} os: [darwin] - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - - magic-string@0.30.8: - resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} - engines: {node: '>=12'} - - make-dir@2.1.0: - resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} - engines: {node: '>=6'} - - make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} make-fetch-happen@10.2.1: resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - make-fetch-happen@8.0.14: - resolution: {integrity: sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==} - engines: {node: '>= 10'} + make-fetch-happen@15.0.5: + resolution: {integrity: sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==} + engines: {node: ^20.17.0 || >=22.9.0} map-age-cleaner@0.1.3: resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} @@ -5411,44 +6040,26 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - mem@4.3.0: resolution: {integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==} engines: {node: '>=6'} - mem@8.1.1: - resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==} - engines: {node: '>=10'} - - memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} + memfs@4.57.6: + resolution: {integrity: sha512-WQK+DGjKCnPdpSyJUXphz+COF2uEhhsxQ3VIWBSbzpbbXuch3h4FePMqXrXGdLjsTgo4JFzBFsP6AWd9pVazGw==} + peerDependencies: + tslib: '2' - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - miller-rabin@4.0.1: - resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} - hasBin: true - mime-db@1.33.0: resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} engines: {node: '>= 0.6'} @@ -5465,19 +6076,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - mimic-fn@3.1.0: - resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} - engines: {node: '>=8'} - mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -5486,33 +6088,19 @@ packages: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} - minimatch@8.0.4: - resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} - engines: {node: '>=16 || 14 >=14.17'} - - minimatch@9.0.1: - resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} - engines: {node: '>=16 || 14 >=14.17'} - - minimatch@9.0.2: - resolution: {integrity: sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg==} - engines: {node: '>=16 || 14 >=14.17'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -5522,20 +6110,21 @@ packages: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} engines: {node: '>= 8'} - minipass-fetch@1.4.1: - resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} - engines: {node: '>=8'} + minipass-collect@2.0.1: + resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} + engines: {node: '>=16 || 14 >=14.17'} minipass-fetch@2.1.2: resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - minipass-flush@1.0.5: - resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} - engines: {node: '>= 8'} + minipass-fetch@5.0.2: + resolution: {integrity: sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==} + engines: {node: ^20.17.0 || >=22.9.0} - minipass-json-stream@1.0.2: - resolution: {integrity: sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==} + minipass-flush@1.0.7: + resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} + engines: {node: '>= 8'} minipass-pipeline@1.2.4: resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} @@ -5545,6 +6134,10 @@ packages: resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} engines: {node: '>=8'} + minipass-sized@2.0.0: + resolution: {integrity: sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==} + engines: {node: '>=8'} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -5557,14 +6150,21 @@ packages: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mitt@2.1.0: + resolution: {integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==} + mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} @@ -5577,11 +6177,8 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} - - module-details-from-path@1.0.4: - resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} @@ -5597,6 +6194,16 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msw@2.7.5: + resolution: {integrity: sha512-00MyTlY3TJutBa5kiU+jWiz2z5pNJDYHn2TgPkGkh92kMmNH43RqvMXd8y/7HxNn8RjzUbvZWYZjcS36fdb6sw==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} @@ -5607,50 +6214,55 @@ packages: resolution: {integrity: sha512-DfxsNvHfJlxp5yul7jhcNSI0EEWlP1vatiOr6Q7cvr8RNFBbIU5nENilUULbNJiOtbXznOxgbxHf4cYbqPDPlg==} engines: {node: '>=14.0'} - mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} - nan@2.22.2: - resolution: {integrity: sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==} + nan@2.26.2: + resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + nanoid@5.0.7: resolution: {integrity: sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==} engines: {node: ^18 || >=20} hasBin: true - nanoid@5.1.5: - resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} + nanoid@5.0.8: + resolution: {integrity: sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==} engines: {node: ^18 || >=20} hasBin: true - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - needle@3.3.1: - resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} - engines: {node: '>= 4.4.x'} - hasBin: true - - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - negotiator@0.6.4: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} - next@15.3.3: - resolution: {integrity: sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + next@16.2.3: + resolution: {integrity: sha512-9V3zV4oZFza3PVev5/poB9g0dEafVcgNyQ8eTRop8GvxZjV2G15FC5ARuG1eFD42QgeYkzJBJzHghNP8Ad9xtA==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 @@ -5668,8 +6280,8 @@ packages: nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - node-abi@3.75.0: - resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==} + node-abi@3.89.0: + resolution: {integrity: sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==} engines: {node: '>=10'} node-addon-api@7.1.1: @@ -5678,8 +6290,8 @@ packages: node-api-version@0.2.1: resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} - node-fetch-native@1.6.6: - resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} @@ -5690,35 +6302,29 @@ packages: encoding: optional: true - node-gyp@7.1.2: - resolution: {integrity: sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==} - engines: {node: '>= 10.12.0'} + node-gyp@12.2.0: + resolution: {integrity: sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ==} + engines: {node: ^20.17.0 || >=22.9.0} hasBin: true - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} - node-stdlib-browser@1.3.1: - resolution: {integrity: sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==} - engines: {node: '>=10'} + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} node-stream-zip@1.15.0: resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} engines: {node: '>=0.12.0'} - nopt@5.0.0: - resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} - engines: {node: '>=6'} - hasBin: true - nopt@6.0.0: resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} hasBin: true - nopt@7.2.1: - resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + nopt@9.0.0: + resolution: {integrity: sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==} + engines: {node: ^20.17.0 || >=22.9.0} hasBin: true normalize-package-data@2.5.0: @@ -5728,49 +6334,37 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-url@4.5.1: - resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==} - engines: {node: '>=8'} - normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} - npm-bundled@1.1.2: - resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==} - - npm-check-updates@11.1.9: - resolution: {integrity: sha512-Ztl5q785Hw+yiUUnlhN/lmrYdzDpH6Mopr0xtijb9t6ltS4RwkIU9qZXuYlOJtPyEXNdmEdmSc2NpfFFs/Nreg==} - engines: {node: '>=10.17'} - hasBin: true - - npm-install-checks@4.0.0: - resolution: {integrity: sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==} - engines: {node: '>=10'} + npm-bundled@5.0.0: + resolution: {integrity: sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-normalize-package-bin@1.0.1: - resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + npm-install-checks@8.0.0: + resolution: {integrity: sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-package-arg@8.1.5: - resolution: {integrity: sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==} - engines: {node: '>=10'} + npm-normalize-package-bin@5.0.0: + resolution: {integrity: sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-packlist@2.2.2: - resolution: {integrity: sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==} - engines: {node: '>=10'} - hasBin: true + npm-package-arg@13.0.2: + resolution: {integrity: sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-pick-manifest@6.1.1: - resolution: {integrity: sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==} + npm-packlist@10.0.4: + resolution: {integrity: sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-registry-fetch@9.0.0: - resolution: {integrity: sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==} - engines: {node: '>=10'} + npm-pick-manifest@11.0.3: + resolution: {integrity: sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==} + engines: {node: ^20.17.0 || >=22.9.0} - npm-run-all@4.1.5: - resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==} - engines: {node: '>= 4'} - hasBin: true + npm-registry-fetch@19.1.1: + resolution: {integrity: sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==} + engines: {node: ^20.17.0 || >=22.9.0} npm-run-path@2.0.2: resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} @@ -5780,60 +6374,19 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} - npm-upgrade@3.1.0: - resolution: {integrity: sha512-pz2U+WP2DL9voleOhGWshwxALn3YuRxp14VQR0/Y/vpNXjlUUD49p8w7HHxUlMeQiONGidrVvqalEX+PAXee7g==} - engines: {node: '>= 10.19'} - hasBin: true - - npmlog@4.1.2: - resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==} - deprecated: This package is no longer supported. - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - number-is-nan@1.0.1: - resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} - engines: {node: '>=0.10.0'} - - nwsapi@2.2.20: - resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==} - - nypm@0.6.0: - resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} - engines: {node: ^14.16.0 || >=16.10.0} - hasBin: true - - oauth-sign@0.9.0: - resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-is@1.1.6: - resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} - engines: {node: '>= 0.4'} - object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -5841,35 +6394,22 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - open@10.1.2: - resolution: {integrity: sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==} + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} - open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - opentelemetry-instrumentation-fetch-node@1.2.3: - resolution: {integrity: sha512-Qb11T7KvoCevMaSeuamcLsAD+pZnavkhDnlVL0kRozfhl42dKG5Q3anUklAFKJZjY3twLR+BnRa6DlwwkIE/+A==} - engines: {node: '>18.0.0'} - peerDependencies: - '@opentelemetry/api': ^1.6.0 - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} - os-browserify@0.3.0: - resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} - os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -5877,13 +6417,23 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} - p-cancelable@1.1.0: - resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==} - engines: {node: '>=6'} + oxfmt@0.40.0: + resolution: {integrity: sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + oxlint@1.55.0: + resolution: {integrity: sha512-T+FjepiyWpaZMhekqRpH8Z3I4vNM610p6w+Vjfqgj5TZUxHXl7N8N5IPvmOU8U4XdTRxqtNNTh9Y4hLtr7yvFg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + oxlint-tsgolint: '>=0.15.0' + peerDependenciesMeta: + oxlint-tsgolint: + optional: true p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} @@ -5917,14 +6467,14 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@7.3.0: + resolution: {integrity: sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==} + engines: {node: '>=20'} + p-locate@2.0.0: resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} engines: {node: '>=4'} - p-locate@3.0.0: - resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} - engines: {node: '>=6'} - p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -5941,8 +6491,8 @@ packages: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} - p-map@7.0.3: - resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} p-try@1.0.0: @@ -5956,28 +6506,16 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-json@6.5.0: - resolution: {integrity: sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==} - engines: {node: '>=8'} - package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} - pacote@11.2.7: - resolution: {integrity: sha512-ogxPor11v/rnU9ukwLlI2dPx22q9iob1+yZyqSwerKsOvBMhU9e+SJHtxY4y2N0MRH4/5jGsGiRLsZeJWyM4dQ==} - engines: {node: '>=10'} - hasBin: true - - pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} - parse-asn1@5.1.7: - resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} - engines: {node: '>= 0.10'} + pacote@21.5.0: + resolution: {integrity: sha512-VtZ0SB8mb5Tzw3dXDfVAIjhyVKUHZkS/ZH9/5mpKenwC9sFOXNI0JI7kEF7IMkwOnsWMFrvAZHzx1T5fmrp9FQ==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true parse-author@2.0.0: resolution: {integrity: sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==} @@ -5986,38 +6524,18 @@ packages: parse-color@1.0.0: resolution: {integrity: sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==} - parse-github-url@1.0.3: - resolution: {integrity: sha512-tfalY5/4SqGaV/GIGzWyHnFjlpTPTNpENR9Ea2lLldSJ8EWXMsvacWucqY3m3I4YPtas15IxTLQVQ5NSYXPrww==} - engines: {node: '>= 0.10'} - hasBin: true - parse-json@2.2.0: resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} engines: {node: '>=0.10.0'} - parse-json@4.0.0: - resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} - engines: {node: '>=4'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} - parse-node-version@1.0.1: - resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} - engines: {node: '>= 0.10'} - - parse-passwd@1.0.0: - resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} - engines: {node: '>=0.10.0'} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -6055,20 +6573,20 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-type@2.0.0: resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} engines: {node: '>=4'} - path-type@3.0.0: - resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} - engines: {node: '>=4'} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -6079,14 +6597,10 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.0: - resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} - pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} - pe-library@1.0.1: resolution: {integrity: sha512-nh39Mo1eGWmZS7y+mK/dQIqg7S1lp38DpRxkyoHf0ZcUs/HDc+yyTjuOtTvSMZHmfSLuSQaX945u05Y2Q6UWZg==} engines: {node: '>=14', npm: '>=7'} @@ -6097,44 +6611,24 @@ packages: perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-protocol@1.10.0: - resolution: {integrity: sha512-IpdytjudNuLv8nhlHs/UrVBhU0e78J0oIS/0AVdTbWxSOkFUVdsHC/NrorO6nXsQNDTT1kzDSOMJubBQviX18Q==} - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pidtree@0.3.1: - resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} - engines: {node: '>=0.10'} - hasBin: true - pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -6162,27 +6656,19 @@ packages: typescript: optional: true - pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - - pkg-dir@5.0.0: - resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} - engines: {node: '>=10'} - pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - pkg-types@2.1.0: - resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - playwright-core@1.48.1: - resolution: {integrity: sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==} + playwright-core@1.48.2: + resolution: {integrity: sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==} engines: {node: '>=18'} hasBin: true - playwright@1.48.1: - resolution: {integrity: sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==} + playwright@1.48.2: + resolution: {integrity: sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==} engines: {node: '>=18'} hasBin: true @@ -6190,102 +6676,78 @@ packages: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} - pnpm@9.12.2: - resolution: {integrity: sha512-InIbOhH4FmGuHsaM4ae4eUJaHKW5kcl1sHSsIgsYfOVscI/l22n0yWLJiUUu7nbIKHf07oD0dM69Ye4TRhtiKA==} - engines: {node: '>=18.12'} - hasBin: true - polished@4.3.1: resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} engines: {node: '>=10'} - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} - postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.4: - resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} - engines: {node: '>=0.10.0'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} + postcss@8.5.9: + resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} + engines: {node: ^10 || ^12 || >=14} posthog-js@1.215.0: resolution: {integrity: sha512-okdh+fOUZiWYMBmKd6Zm2rekgMAR8XdxinwFWlua6exx8IblKZuVO94OjQtoVAFwxmhH/i7UK/ANfohMeorS7Q==} - posthog-node@4.4.1: - resolution: {integrity: sha512-o9G9sSvwWITrfSJgIUrPLJd//AYPGJNu5D+pSLxqiBvhUeicc/i639FvU0DPr1OsHiLDE2zHNMmLpa0mw4kBCg==} - engines: {node: '>=15.0.0'} + posthog-node@5.30.6: + resolution: {integrity: sha512-deZuSiLkpdEipiywkww1FhQoKpVVFmJP6SAVQcZcMbugTLwJRYSGjgm+qV0Y91xghf2yP6Nr5Plfl52i9Qj15Q==} + engines: {node: ^20.20.0 || >=22.22.0} + peerDependencies: + rxjs: ^7.0.0 + peerDependenciesMeta: + rxjs: + optional: true postject@1.0.0-alpha.6: resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} engines: {node: '>=14.0.0'} hasBin: true - preact@10.26.8: - resolution: {integrity: sha512-1nMfdFjucm5hKvq0IClqZwK4FJkGXhRrQstOQ3P4vp8HxKrJEMFcY6RdBRVTdfQS/UlnX6gfbPuTvaqx/bDoeQ==} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} - prepend-http@2.0.0: - resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} - engines: {node: '>=4'} - - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} + preact@10.29.1: + resolution: {integrity: sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==} prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} hasBin: true - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + prettier@3.8.2: + resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==} engines: {node: '>=14'} hasBin: true - pretty-ms@9.2.0: - resolution: {integrity: sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==} + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} - primeflex@3.3.1: - resolution: {integrity: sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ==} + primeflex@4.0.0: + resolution: {integrity: sha512-UOEZCRjR36+sm5bUpDhS1xbA068l9VC6y1aTNVqQPtXuKIdPTqAWHRUxj3mKAoPrQ9W373ooJJMgNVXfiaw04g==} primeicons@7.0.0: resolution: {integrity: sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==} - primevue@4.1.1: - resolution: {integrity: sha512-FeJkv7FhfePfUBoApW0qAhid6Znq18VgbGFZdmhUcxvOD49Y2Eo/k2Yn7ypPhRbRApWiaSRN0v/2G1I4AMj3xg==} + primevue@4.5.4: + resolution: {integrity: sha512-nTyEohZABFJhVIpeUxgP0EJ8vKcJAhD+Z7DYj95e7ie/MNUCjRNcGjqmE1cXtXi4z54qDfTSI9h2uJ51qz2DIw==} engines: {node: '>=12.11.0'} proc-log@2.0.1: resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + proc-log@6.1.0: + resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} + engines: {node: ^20.17.0 || >=22.9.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -6309,61 +6771,29 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - prr@1.0.1: - resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - psl@1.15.0: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - public-encrypt@4.0.3: - resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} - - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + publint@0.3.18: + resolution: {integrity: sha512-JRJFeBTrfx4qLwEuGFPk+haJOJN97KnPuK01yj+4k/Wj5BgoOK5uNsivporiqBjk2JDaslg7qJOhGRnpltGeog==} + engines: {node: '>=18'} + hasBin: true - punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pupa@2.1.1: - resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==} - engines: {node: '>=8'} - - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - qs@6.5.3: - resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} - engines: {node: '>=0.6'} + quansync@1.0.0: + resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} - quansync@0.2.10: - resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} - - querystring-es3@0.2.1: - resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} - engines: {node: '>=0.4.x'} + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -6385,70 +6815,48 @@ packages: resolution: {integrity: sha512-K7Yt78aRPLjPcqv3fIuLW1jW3pvwO21B9pmFOolsjM/57ZhdVXBr51GqJpalgBlkPu9foAvhEAuuQPnvIGvLvQ==} engines: {node: '>=16.0.0'} + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + random-path@0.1.2: resolution: {integrity: sha512-4jY0yoEaQ5v9StCl5kZbNIQlg1QheIDBrdkDn53EynpPb9FgO6//p3X/tgMnrC45XN6QZCzU1Xz/+pSSsJBpRw==} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - randomfill@1.0.4: - resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} - range-parser@1.2.0: resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} engines: {node: '>= 0.6'} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - ranges-apply@7.0.19: - resolution: {integrity: sha512-imA03KuTSuSpQtq9SDhavUz7BtiddCPj+fsYM/XpdypRN/s8vyTayKzni6m5nYs7VMds1kSNK1V3jfwVrPUWBQ==} + ranges-apply@7.1.3: + resolution: {integrity: sha512-+dpc801TK6qUoMKU9dnwD0wH6XORtZicXLVm4p43jEp+te7Q+Tw0Pa4cHX9Mj1W0zshVYh1S4RIYI38ZUPglqQ==} engines: {node: '>=14.18.0'} - ranges-merge@9.0.18: - resolution: {integrity: sha512-2+6Eh4yxi5sudUmvCdvxVOSdXIXV+Brfutw8chhZmqkT0REqlzilpyQps1S5n8c7f0+idblqSAHGahTbf/Ar5g==} + ranges-merge@9.1.3: + resolution: {integrity: sha512-dPS11e7AHD1tnuzrboYa+n07JqbHccMqt94C3cSlJ9tTC/RN6P+iGePhTyvCPpoNDWVOEVX4JGyGH0oHjwas0g==} engines: {node: '>=14.18.0'} - ranges-push@7.0.18: - resolution: {integrity: sha512-wzGHipEklSlY0QloQ88PNt+PkTURIB42PLLcQGY+WyYBlNpnrzps6EYooD3RqNXtdqMQ9kR8IVaF9itRYtuzLA==} + ranges-push@7.1.3: + resolution: {integrity: sha512-3laGXNa4CW1vt6e2RqC35xRmxXpcWwLNpepTQJ+dkftc/7rH+d9pQ/UQgV6/peN6DsDcpJuu+PjLjWprz2UjDA==} engines: {node: '>=14.18.0'} - ranges-sort@6.0.13: - resolution: {integrity: sha512-M3P0/dUnU3ihLPX2jq0MT2NJA1ls/q6cUAUVPD28xdFFqm3VFarPjTKKhnsBSvYCpZD8HdiElAGAyoPu6uOQjA==} + ranges-sort@6.1.3: + resolution: {integrity: sha512-JsTMmurWEOPYowp1OwUbjcfXyDfaTB+AWoiZwjV+3qOv0uUI7A1CExGwyFwfXEO5HYThOTDC96qC9a6BYqFbyg==} engines: {node: '>=14.18.0'} - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - - rc-config-loader@4.1.3: - resolution: {integrity: sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==} + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - react-dom@19.1.0: - resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: - react: ^19.1.0 + react: ^19.2.5 - react@19.1.0: - resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} read-binary-file-arch@1.0.6: resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} hasBin: true - read-package-json-fast@2.0.3: - resolution: {integrity: sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==} - engines: {node: '>=10'} - read-pkg-up@2.0.0: resolution: {integrity: sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==} engines: {node: '>=4'} @@ -6457,14 +6865,14 @@ packages: resolution: {integrity: sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==} engines: {node: '>=4'} - read-pkg@3.0.0: - resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} - engines: {node: '>=4'} - read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + read-yaml-file@2.1.0: + resolution: {integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==} + engines: {node: '>=10.13'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -6487,46 +6895,18 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} rechoir@0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} - - regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - - registry-auth-token@4.2.2: - resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==} - engines: {node: '>=6.0.0'} - - registry-url@5.1.0: - resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==} - engines: {node: '>=8'} - - remote-git-tags@3.0.0: - resolution: {integrity: sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==} - engines: {node: '>=8'} - repeat-string@1.6.1: resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} engines: {node: '>=0.10'} - request@2.88.2: - resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} - engines: {node: '>= 6'} - deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -6535,9 +6915,8 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-in-the-middle@7.5.2: - resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} - engines: {node: '>=8.6.0'} + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} resedit@2.0.3: resolution: {integrity: sha512-oTeemxwoMuxxTYxXUwjkrOPfngTQehlv0/HoYFNkB4uzsP1Un1A9nI8JQKGOFkxpqkC7qkMs0lUsGrvUlbLNUA==} @@ -6546,33 +6925,18 @@ packages: resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - resolve-dir@1.0.1: - resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} - engines: {node: '>=0.10.0'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve-package@1.0.1: - resolution: {integrity: sha512-rzB7NnQpOkPHBWFPP3prUMqOP6yg3HkRGgcvR+lDyvyHoY3fZLFLYDkPXh78SPVBAE6VTCk/V+j8we4djg6o4g==} - engines: {node: '>=4', npm: '>=2'} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} hasBin: true - responselike@1.0.2: - resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} - responselike@2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} @@ -6605,42 +6969,62 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - roarr@2.15.4: resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} engines: {node: '>=8.0'} - rollup@4.42.0: - resolution: {integrity: sha512-LW+Vse3BJPyGJGAJt1j8pWDKPd73QM8cRXYK1IxOBgL2AGLu7Xd2YOW0M2sLUBCkF5MshXXtMApyEAEzMVMsnw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + rolldown-plugin-dts@0.22.5: + resolution: {integrity: sha512-M/HXfM4cboo+jONx9Z0X+CUf3B5tCi7ni+kR5fUW50Fp9AlZk0oVLesibGWgCXDKFp5lpgQ9yhKoImUFjl3VZw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@ts-macro/tsc': ^0.3.6 + '@typescript/native-preview': '>=7.0.0-dev.20250601.1' + rolldown: ^1.0.0-rc.3 + typescript: ^5.0.0 || ^6.0.0-beta + vue-tsc: ~3.2.0 + peerDependenciesMeta: + '@ts-macro/tsc': + optional: true + '@typescript/native-preview': + optional: true + typescript: + optional: true + vue-tsc: + optional: true + + rolldown@1.0.0-rc.15: + resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rrweb-cssom@0.7.1: - resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + rolldown@1.0.0-rc.9: + resolution: {integrity: sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true - rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + rolldown@1.0.2: + resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true - run-applescript@7.0.0: - resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} - engines: {node: '>=18'} + rollup@4.60.1: + resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true - run-async@2.4.1: - resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} - engines: {node: '>=0.12.0'} + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@6.6.7: - resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} - engines: {npm: '>=2.0.0'} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -6648,31 +7032,141 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.80.4: - resolution: {integrity: sha512-rhMQ2tSF5CsuuspvC94nPM9rToiAFw2h3JTrLlgmNw1MH79v8Cr3DH6KF6o6r+8oofY3iYVPUf66KzC8yuVN1w==} + sass-embedded-all-unknown@1.99.0: + resolution: {integrity: sha512-qPIRG8Uhjo6/OKyAKixTnwMliTz+t9K6Duk0mx5z+K7n0Ts38NSJz2sjDnc7cA/8V9Lb3q09H38dZ1CLwD+ssw==} + cpu: ['!arm', '!arm64', '!riscv64', '!x64'] + + sass-embedded-android-arm64@1.99.0: + resolution: {integrity: sha512-fNHhdnP23yqqieCbAdym4N47AleSwjbNt6OYIYx4DdACGdtERjQB4iOX/TaKsW034MupfF7SjnAAK8w7Ptldtg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + + sass-embedded-android-arm@1.99.0: + resolution: {integrity: sha512-EHvJ0C7/VuP78Qr6f8gIUVUmCqIorEQpw2yp3cs3SMg02ZuumlhjXvkTcFBxHmFdFR23vTNk1WnhY6QSeV1nFQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + + sass-embedded-android-riscv64@1.99.0: + resolution: {integrity: sha512-4zqDFRvgGDTL5vTHuIhRxUpXFoh0Cy7Gm5Ywk19ASd8Settmd14YdPRZPmMxfgS1GH292PofV1fq1ifiSEJWBw==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + + sass-embedded-android-x64@1.99.0: + resolution: {integrity: sha512-Uk53k/dGYt04RjOL4gFjZ0Z9DH9DKh8IA8WsXUkNqsxerAygoy3zqRBS2zngfE9K2jiOM87q+1R1p87ory9oQQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + + sass-embedded-darwin-arm64@1.99.0: + resolution: {integrity: sha512-u61/7U3IGLqoO6gL+AHeiAtlTPFwJK1+964U8gp45ZN0hzh1yrARf5O1mivXv8NnNgJvbG2wWJbiNZP0lG/lTg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + sass-embedded-darwin-x64@1.99.0: + resolution: {integrity: sha512-j/kkk/NcXdIameLezSfXjgCiBkVcA+G60AXrX768/3g0miK1g7M9dj7xOhCb1i7/wQeiEI3rw2LLuO63xRIn4A==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + sass-embedded-linux-arm64@1.99.0: + resolution: {integrity: sha512-btNcFpItcB56L40n8hDeL7sRSMLDXQ56nB5h2deddJx1n60rpKSElJmkaDGHtpkrY+CTtDRV0FZDjHeTJddYew==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + libc: glibc + + sass-embedded-linux-arm@1.99.0: + resolution: {integrity: sha512-d4IjJZrX2+AwB2YCy1JySwdptJECNP/WfAQLUl8txI3ka8/d3TUI155GtelnoZUkio211PwIeFvvAeZ9RXPQnw==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + libc: glibc + + sass-embedded-linux-musl-arm64@1.99.0: + resolution: {integrity: sha512-Hi2bt/IrM5P4FBKz6EcHAlniwfpoz9mnTdvSd58y+avA3SANM76upIkAdSayA8ZGwyL3gZokru1AKDPF9lJDNw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + libc: musl + + sass-embedded-linux-musl-arm@1.99.0: + resolution: {integrity: sha512-2gvHOupgIw3ytatXT4nFUow71LFbuOZPEwG+HUzcNQDH8ue4Ez8cr03vsv5MDv3lIjOKcXwDvWD980t18MwkoQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + libc: musl + + sass-embedded-linux-musl-riscv64@1.99.0: + resolution: {integrity: sha512-mKqGvVaJ9rHMqyZsF0kikQe4NO0f4osb67+X6nLhBiVDKvyazQHJ3zJQreNefIE36yL2sjHIclSB//MprzaQDg==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + libc: musl + + sass-embedded-linux-musl-x64@1.99.0: + resolution: {integrity: sha512-huhgOMmOc30r7CH7qbRbT9LerSEGSnWuS4CYNOskr9BvNeQp4dIneFufNRGZ7hkOAxUM8DglxIZJN/cyAT95Ew==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + libc: musl + + sass-embedded-linux-riscv64@1.99.0: + resolution: {integrity: sha512-mevFPIFAVhrH90THifxLfOntFmHtcEKOcdWnep2gJ0X4DVva4AiVIRlQe/7w9JFx5+gnDRE1oaJJkzuFUuYZsA==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + libc: glibc + + sass-embedded-linux-x64@1.99.0: + resolution: {integrity: sha512-9k7IkULqIZdCIVt4Mboryt6vN8Mjmm3EhI1P3mClU5y5i3wLK5ExC3cbVWk047KsID/fvB1RLslqghXJx5BoxA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + libc: glibc + + sass-embedded-unknown-all@1.99.0: + resolution: {integrity: sha512-P7MxiUtL/XzGo3PX0CaB8lNNEFLQWKikPA8pbKytx9ZCLZSDkt2NJcdAbblB/sqMs4AV3EK2NadV8rI/diq3xg==} + os: ['!android', '!darwin', '!linux', '!win32'] + + sass-embedded-win32-arm64@1.99.0: + resolution: {integrity: sha512-8whpsW7S+uO8QApKfQuc36m3P9EISzbVZOgC79goob4qGy09u8Gz/rYvw8h1prJDSjltpHGhOzBE6LDz7WvzVw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + sass-embedded-win32-x64@1.99.0: + resolution: {integrity: sha512-ipuOv1R2K4MHeuCEAZGpuUbAgma4gb0sdacyrTjJtMOy/OY9UvWfVlwErdB09KIkp4fPDpQJDJfvYN6bC8jeNg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + sass-embedded@1.99.0: + resolution: {integrity: sha512-gF/juR1aX02lZHkvwxdF80SapkQeg2fetoDF6gIQkNbSw5YEUFspMkyGTjPjgZSgIHuZpy+Wz4PlebKnLXMjdg==} + engines: {node: '>=16.0.0'} + hasBin: true + + sass@1.99.0: + resolution: {integrity: sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==} engines: {node: '>=14.0.0'} hasBin: true - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} + engines: {node: '>=11.0.0'} - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} scule@1.3.0: resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} @@ -6680,13 +7174,6 @@ packages: semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - semver-diff@3.1.1: - resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} - engines: {node: '>=8'} - - semver-utils@1.1.4: - resolution: {integrity: sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==} - semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -6695,67 +7182,34 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.3.4: - resolution: {integrity: sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} engines: {node: '>=10'} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} engines: {node: '>=10'} hasBin: true - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - serialize-error@7.0.1: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} - serve-handler@6.1.6: - resolution: {integrity: sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==} - - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} + serve-handler@6.1.7: + resolution: {integrity: sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==} set-value@4.1.0: resolution: {integrity: sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==} engines: {node: '>=11.0'} - setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - - sharp@0.34.2: - resolution: {integrity: sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@1.2.0: @@ -6778,30 +7232,6 @@ packages: resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} - shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true - - shimmer@1.2.1: - resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -6812,11 +7242,12 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sigstore@4.1.0: + resolution: {integrity: sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==} + engines: {node: ^20.17.0 || >=22.9.0} - sirv@3.0.1: - resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==} + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} sisteransi@1.0.5: @@ -6826,10 +7257,6 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - slash@5.1.0: - resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} - engines: {node: '>=14.16'} - slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -6838,16 +7265,16 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - socks-proxy-agent@5.0.1: - resolution: {integrity: sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==} - engines: {node: '>= 6'} - socks-proxy-agent@7.0.0: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} - socks@2.8.4: - resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} source-map-js@1.2.1: @@ -6861,10 +7288,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - spawn-please@1.0.0: - resolution: {integrity: sha512-Kz33ip6NRNKuyTRo3aDWyWxeGeM0ORDO552Fs6E1nj4pLWPkl37SrRtTnq+MEopVaqgmaO6bAvVS+v64BJ5M/A==} - engines: {node: '>=10'} - spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -6877,27 +7300,29 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.21: - resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} speakingurl@14.0.1: resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} engines: {node: '>=0.10.0'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - - sshpk@1.18.0: - resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} - engines: {node: '>=0.10.0'} - hasBin: true + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - ssri@8.0.1: - resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} - engines: {node: '>= 8'} + ssri@13.0.1: + resolution: {integrity: sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==} + engines: {node: ^20.17.0 || >=22.9.0} ssri@9.0.1: resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} @@ -6909,54 +7334,43 @@ packages: standardwebhooks@1.0.0: resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - stream-browserify@3.0.0: - resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} stream-buffers@2.2.0: resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==} engines: {node: '>= 0.10.0'} - stream-http@3.2.0: - resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + streamx@2.25.0: + resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - - streamx@2.22.1: - resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} - string-collapse-leading-whitespace@7.0.9: - resolution: {integrity: sha512-lEuTHlogBT9PWipfk0FOyvoMKX8syiE03QoFk5MDh8oS0AJ2C07IlstR5cGkxz48nKkOIuvkC28w9Rx/cVRNDg==} + string-collapse-leading-whitespace@7.1.3: + resolution: {integrity: sha512-bCgNODedM9daANnnNPOHuz++qUeVHgsPMghNPznbLLnBviNyuKt9vzHIa6OGTSpWzJUO4Rlffu4+RD47pSTq3g==} engines: {node: '>=14.18.0'} - string-left-right@6.0.20: - resolution: {integrity: sha512-dz2mUgmsI7m/FMe+BoxZ2+73X1TUoQvjCdnq8vbIAnHlvWfVZleNUR+lw+QgHA2dlJig+hUWC9bFYdNFGGy2bA==} + string-left-right@6.1.3: + resolution: {integrity: sha512-XPqLphMTTbPMRs4DPX0flLtVFsDWZ+Og3tyku1FiiE2b/+SUHmiO1KRg7NBlb5e9UrojE5F3ryXORL0VYhwwgA==} engines: {node: '>=14.18.0'} string-strip-html@13.4.8: resolution: {integrity: sha512-vlcRAtx5DN6zXGUx3EYGFg0/JOQWM65mqLgDaBHviQPP+ovUFzqZ30iQ+674JHWr9wNgnzFGxx9TGipPZMnZXg==} engines: {node: '>=14.18.0'} - string-trim-spaces-only@5.0.12: - resolution: {integrity: sha512-Un5nIO1av+hzfnKGmY+bWe0AD4WH37TuDW+jeMPm81rUvU2r3VPRj9vEKdZkPmuhYAMuKlzarm7jDSKwJKOcpQ==} + string-trim-spaces-only@5.1.3: + resolution: {integrity: sha512-Flb782YX49j4GkLv/M2rqJik/lUq+OJnT/q7kQ6byZtgknAo1wb1XFBN3b+7UMW5I6VB1QdNAoh9oiUa9izBpA==} engines: {node: '>=14.18.0'} - string-width@1.0.2: - resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} - engines: {node: '>=0.10.0'} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -6965,44 +7379,31 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string.prototype.padend@3.1.6: - resolution: {integrity: sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==} - engines: {node: '>= 0.4'} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - strip-ansi@3.0.1: - resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} - engines: {node: '>=0.10.0'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-comments-strings@1.2.0: + resolution: {integrity: sha512-zwF4bmnyEjZwRhaak9jUWNxc0DoeKBJ7lwSN/LEc8dQXZcUFG6auaaTQJokQWXopLdM3iTx01nQT8E4aL29DAQ==} + strip-eof@1.0.0: resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} engines: {node: '>=0.10.0'} @@ -7011,26 +7412,18 @@ packages: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} engines: {node: '>=18'} - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - strip-literal@2.1.1: resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} - strip-outer@1.0.1: resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} engines: {node: '>=0.10.0'} - style-mod@4.1.2: - resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + structured-clone-es@2.0.0: + resolution: {integrity: sha512-5UuAHmBLXYPCl22xWJrFuGmIhBKQzxISPVz6E7nmTmTcAOpUzlbjKJsRrCE4vADmMQ0dzeCnlWn9XufnAGf76Q==} + + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} @@ -7045,49 +7438,53 @@ packages: babel-plugin-macros: optional: true - sudo-prompt@9.2.1: - resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - sumchecker@3.0.1: resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} engines: {node: '>= 8.0'} - superjson@2.2.2: - resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} - synckit@0.11.8: - resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==} - engines: {node: ^14.18.0 || >=16.0.0} + sync-message-port@1.2.0: + resolution: {integrity: sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==} + engines: {node: '>=16.0.0'} - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar-stream@3.1.8: + resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + tar@7.5.13: + resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} + engines: {node: '>=18'} + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + temp@0.9.4: resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} engines: {node: '>=6.0.0'} @@ -7096,11 +7493,29 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + terser-webpack-plugin@5.4.0: + resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} + engines: {node: '>=10'} + hasBin: true - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} thememirror@2.0.1: resolution: {integrity: sha512-d5i6FVvWWPkwrm4cHLI3t9AT1OrkAt7Ig8dtdYSofgF7C/eiyNuq6zQzSTusWTde3jpW9WLvA9J/fzNKMUsd0w==} @@ -7109,15 +7524,11 @@ packages: '@codemirror/state': 6.4.1 '@codemirror/view': ^6.0.0 - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - - timers-browserify@2.0.12: - resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} - engines: {node: '>=0.6.0'} - - tiny-each-async@2.0.3: - resolution: {integrity: sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==} + thingies@2.6.0: + resolution: {integrity: sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==} + engines: {node: '>=10.18'} + peerDependencies: + tslib: ^2 tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -7128,17 +7539,25 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + engines: {node: '>=18'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} tinykeys@2.1.0: resolution: {integrity: sha512-/MESnqBD1xItZJn5oGQ4OsNORQgJfPP96XSGoyu4eLpwpL0ifO0SYR5OD76u0YMhMXsqkb0UqvI9+yXTh4xv8Q==} - tinypool@1.1.0: - resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} + tinypool@2.1.0: + resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} + engines: {node: ^20.0.0 || >=22.0.0} + tinyrainbow@2.0.0: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} @@ -7147,24 +7566,10 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} - tldts-core@6.1.86: - resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - - tldts@6.1.86: - resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} - hasBin: true - - tmp-promise@3.0.3: - resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} - tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} - tmp@0.2.3: - resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} - engines: {node: '>=14.14'} - tn1150@0.1.0: resolution: {integrity: sha512-DbplOfQFkqG5IHcDyyrs/lkvSr3mPUVsFf/RbDppOshs22yTPnSJWEe6FkYd1txAwU/zcnR905ar2fi4kwF29w==} engines: {node: '>=0.12'} @@ -7172,73 +7577,39 @@ packages: to-data-view@1.1.0: resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==} - to-readable-stream@1.0.0: - resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==} - engines: {node: '>=6'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@2.5.0: - resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} - engines: {node: '>=0.8'} - - tough-cookie@5.1.2: - resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} - engines: {node: '>=16'} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} + tree-dump@1.1.0: + resolution: {integrity: sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true trim-repeated@1.0.0: resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} engines: {node: '>=0.10.0'} - ts-api-utils@1.4.3: - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - ts-deepmerge@7.0.1: resolution: {integrity: sha512-JBFCmNenZdUCc+TRNCtXVM6N8y/nDQHAcpj5BlwXG/gnogjam1NunulB9ia68mnqYI446giMfpqeBFFkOleh+g==} engines: {node: '>=14.13.1'} - ts-essentials@10.0.2: - resolution: {integrity: sha512-Xwag0TULqriaugXqVdDiGZ5wuZpqABZlpwQ2Ho4GDyiu/R2Xjkp/9+zcFxL7uzeLl/QCPrflnvpVYyS3ouT7Zw==} - peerDependencies: - typescript: '>=4.5.0' - peerDependenciesMeta: - typescript: - optional: true - - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - ts-pattern@5.5.0: resolution: {integrity: sha512-jqbIpTsa/KKTJYWgPNsFNbLVpwCgzXfFJ1ukNn4I8hMwyQzHMJnk/BqWzggB0xpkILuKzaO/aMYhS0SkaJyKXg==} @@ -7252,8 +7623,33 @@ packages: typescript: optional: true - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tsdown@0.21.2: + resolution: {integrity: sha512-pP8eAcd1XAWjl5gjosuJs0BAuVoheUe3V8VDHx31QK7YOgXjcCMsBSyFWO3CMh/CSUkjRUzR96JtGH3WJFTExQ==} + engines: {node: '>=20.19.0'} + hasBin: true + peerDependencies: + '@arethetypeswrong/core': ^0.18.1 + '@tsdown/css': 0.21.2 + '@tsdown/exe': 0.21.2 + '@vitejs/devtools': '*' + publint: ^0.3.0 + typescript: ^5.0.0 + unplugin-unused: ^0.5.0 + peerDependenciesMeta: + '@arethetypeswrong/core': + optional: true + '@tsdown/css': + optional: true + '@tsdown/exe': + optional: true + '@vitejs/devtools': + optional: true + publint: + optional: true + typescript: + optional: true + unplugin-unused: + optional: true tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -7267,27 +7663,22 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - tty-browserify@0.0.1: - resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} - - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tuf-js@4.1.0: + resolution: {integrity: sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==} + engines: {node: ^20.17.0 || >=22.9.0} - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + turbo@2.9.6: + resolution: {integrity: sha512-+v2QJey7ZUeUiuigkU+uFfklvNUyPI2VO2vBpMYJA+a1hKFLFiKtUYlRHdb3P9CrAvMzi0upbjI4WT+zKtqkBg==} + hasBin: true type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -7300,43 +7691,44 @@ packages: resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} engines: {node: '>=16'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} + type-fest@4.39.0: + resolution: {integrity: sha512-w2IGJU1tIgcrepg9ZJ82d8UmItNQtOFJG0HCUE3SzMokKkTsruVDALl2fAdiEzJlfduoU+VyXJWIIUZ+6jV+nw==} + engines: {node: '>=16'} - typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + + unconfig-core@7.5.0: + resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} - unctx@2.4.1: - resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} + unconfig@7.5.0: + resolution: {integrity: sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + unctx@2.5.0: + resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} @@ -7344,6 +7736,9 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} @@ -7351,28 +7746,14 @@ packages: unimport@3.14.6: resolution: {integrity: sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==} - unimport@5.0.1: - resolution: {integrity: sha512-1YWzPj6wYhtwHE+9LxRlyqP4DiRrhGfJxdtH475im8ktyZXO3jHj/3PZ97zDdvkYoovFdi0K4SKl3a7l92v3sQ==} - engines: {node: '>=18.12.0'} - - unique-filename@1.1.1: - resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} - unique-filename@2.0.1: resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - unique-slug@2.0.2: - resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} - unique-slug@3.0.0: resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - unique-string@2.0.0: - resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} - engines: {node: '>=8'} - universal-user-agent@6.0.1: resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} @@ -7380,6 +7761,10 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -7388,10 +7773,6 @@ packages: resolution: {integrity: sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==} engines: {node: '>= 0.4.0'} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - unplugin-auto-import@0.18.3: resolution: {integrity: sha512-q3FUtGQjYA2e+kb1WumyiQMjHM27MrTQ05QfVwtLRVhyYe+KF6TblBYaEX9L6Z0EibsqaXAiW+RFfkcQpfaXzg==} engines: {node: '>=14'} @@ -7404,9 +7785,9 @@ packages: '@vueuse/core': optional: true - unplugin-utils@0.2.4: - resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} - engines: {node: '>=18.12.0'} + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} unplugin-vue-components@0.27.4: resolution: {integrity: sha512-1XVl5iXG7P1UrOMnaj2ogYa5YTq8aoh5jwDPQhemwO/OrXW+lPQKDXd1hMz15qxQPxgb/XXlbgo3HQ2rLEbmXQ==} @@ -7421,17 +7802,86 @@ packages: '@nuxt/kit': optional: true - unplugin@1.0.1: - resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} - unplugin@1.16.1: resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} engines: {node: '>=14.0.0'} - unplugin@2.3.5: - resolution: {integrity: sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==} + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} + unrun@0.2.35: + resolution: {integrity: sha512-nDP7mA4Fu5owDarQtLiiN3lq7tJZHFEAVIchnwP8U3wMeEkLoUNT37Hva85H05Rdw8CArpGmtY+lBjpk9fruVQ==} + engines: {node: '>=20.19.0'} + hasBin: true + peerDependencies: + synckit: ^0.11.11 + peerDependenciesMeta: + synckit: + optional: true + + unstorage@1.17.5: + resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + untun@0.1.3: resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} hasBin: true @@ -7440,29 +7890,14 @@ packages: resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} hasBin: true - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' - update-electron-app@3.0.0: - resolution: {integrity: sha512-Ccs46fgUEcMpSRPMNw82DFMux2MGi5tkKkEpV723JmtPNI3qAtxvTeiYkKczN2/LehA3U7JGrGr4MhraxGdRTw==} - - update-notifier@5.1.0: - resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==} - engines: {node: '>=10'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - url-parse-lax@3.0.0: - resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==} - engines: {node: '>=4'} - - url@0.11.4: - resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} - engines: {node: '>= 0.4'} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} username@5.1.0: resolution: {integrity: sha512-PCKbdWw85JsYMvmCv5GH3kXmM66rCd9m1hBEDutPNv94b/pqCMT4NtcKyeWYvLFiE8b+ha1Jdl8XAaUdPn5QTg==} @@ -7471,21 +7906,11 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true - v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - valibot@0.33.3: resolution: {integrity: sha512-/fuY1DlX8uiQ7aphlzrrI2DbG0YJk84JMgvz2qKpUIdXRNsS53varfo4voPjSrjUr5BSV2K0miSEJUOlA5fQFg==} @@ -7497,15 +7922,23 @@ packages: typescript: optional: true + valibot@1.3.1: + resolution: {integrity: sha512-sfdRir/QFM0JaF22hqTroPc5xy4DimuGQVKFrzF1YfGwaS1nJot3Y8VqMdLO2Lg27fMzat2yD3pY5PbAYO39Gg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - validate-npm-package-name@3.0.0: - resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==} + validate-npm-package-name@7.0.2: + resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} + engines: {node: ^20.17.0 || >=22.9.0} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} vee-validate@4.13.2: resolution: {integrity: sha512-HlpR/6MJ92TW9f135umMZKUqdd/tFQTxLNSf2ImbU4Y/MlLVAUpF1l64VdjTOhbClAqPjCb5p/SqHDxLpUHXrw==} @@ -7517,56 +7950,41 @@ packages: peerDependencies: vue: ^3.4.26 - verror@1.10.0: - resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - engines: {'0': node >=0.6.0} + vite-dev-rpc@1.1.0: + resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 - vite-hot-client@2.0.4: - resolution: {integrity: sha512-W9LOGAyGMrbGArYJN4LBCdOC5+Zwh7dHvOHC0KmGKkJhsOzaKbpo/jEjpPKVHIW0/jBWj8RZG0NUxfgA8BxgAg==} + vite-hot-client@2.1.0: + resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} peerDependencies: - vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 vite-node@3.1.4: resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite-plugin-inspect@0.8.9: - resolution: {integrity: sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==} + vite-plugin-inspect@11.3.3: + resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} engines: {node: '>=14'} peerDependencies: '@nuxt/kit': '*' - vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.1 + vite: ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: '@nuxt/kit': optional: true - vite-plugin-node-polyfills@0.23.0: - resolution: {integrity: sha512-4n+Ys+2bKHQohPBKigFlndwWQ5fFKwaGY6muNDMTb0fSQLyBzS+jjUNRZG9sKF0S/Go4ApG6LFnUGopjkILg3w==} - peerDependencies: - vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 - - vite-plugin-static-copy@2.3.1: - resolution: {integrity: sha512-EfsPcBm3ewg3UMG8RJaC0ADq6/qnUZnokXx4By4+2cAcipjT9i0Y0owIJGqmZI7d6nxk4qB1q5aXOwNuSyPdyA==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - - vite-plugin-vue-devtools@7.7.5: - resolution: {integrity: sha512-cSlQYI1E+8d0qubBg70suTBbXMFbTHLn7vLPYUPK9GjNNJ0nw+Yks0ZLOAp7/+PjmqSpN5fK1taor6HeAjKb1g==} + vite-plugin-vue-devtools@8.1.1: + resolution: {integrity: sha512-9qTpOmZ2vHpvlI9hdVXAQ1Ry4I8GcBArU7aPi0qfIaV7fQIXy0L1nb6X4mFY2Gw0dYshHuLbIl0Ulb572SCjsQ==} engines: {node: '>=v14.21.3'} peerDependencies: - vite: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 - - vite-plugin-vue-inspector@5.3.1: - resolution: {integrity: sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==} - peerDependencies: - vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - vite-plugin-wasm@3.4.1: - resolution: {integrity: sha512-ja3nSo2UCkVeitltJGkS3pfQHAanHv/DqGatdI39ja6McgABlpsZ5hVgl6wuR8Qx5etY3T5qgDQhOWzc5RReZA==} + vite-plugin-vue-inspector@5.4.0: + resolution: {integrity: sha512-Iq/024CydcE46FZqWPU4t4lw4uYOdLnFSO1RNxJVt2qY9zxIjmnkBqhHnYaReWM82kmNnaXs7OkfgRrV2GEjyw==} peerDependencies: - vite: ^2 || ^3 || ^4 || ^5 || ^6 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vite-tsconfig-paths@5.1.4: resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} @@ -7616,6 +8034,92 @@ packages: yaml: optional: true + vite@8.0.14: + resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vite@8.0.8: + resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitest@3.1.4: resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -7644,15 +8148,9 @@ packages: jsdom: optional: true - vm-browserify@1.1.2: - resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - vue-component-type-helpers@2.2.10: - resolution: {integrity: sha512-iDUO7uQK+Sab2tYuiP9D1oLujCWlhHELHMgV/cB13cuGbG4qwkLHvtfWb6FzvxrIOPDnU0oHsz2MlQjhYDeaHA==} - vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} engines: {node: '>=12'} @@ -7669,14 +8167,8 @@ packages: peerDependencies: vue: ^3.0.0 - vue-eslint-parser@9.4.3: - resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} - engines: {node: ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '>=6.0.0' - - vue-i18n@10.0.7: - resolution: {integrity: sha512-bKsk0PYwP9gdYF4nqSAT0kDpnLu1gZzlxFl885VH4mHVhEnqP16+/mAU05r1U6NIrc0fGDWP89tZ8GzeJZpe+w==} + vue-i18n@10.0.8: + resolution: {integrity: sha512-mIjy4utxMz9lMMo6G9vYePv7gUFt4ztOMhY9/4czDJxZ26xPeJ49MAGa9wBAE3XuXbYCrtVPmPxNjej7JJJkZQ==} engines: {node: '>= 16'} deprecated: v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html peerDependencies: @@ -7693,6 +8185,17 @@ packages: peerDependencies: typescript: '>=5.0.0' + vue-tsc@3.3.1: + resolution: {integrity: sha512-webBP3jhlxzhELZ2g+11KJ6pg5OVY1xWhWrj7N/yQMi1CrtxJnW+tUACyRVeDK0cQNLP2Va5HNYK8pe+7c+msw==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue-virtual-scroller@2.0.1: + resolution: {integrity: sha512-3Drq8C61C4B3reSaZJr5nXBf/B7Beq1+h5/kYZB25MLYljTy97ISeUufRX9z6ZSZlFDXyafAOLK9XwajOWJY1A==} + peerDependencies: + vue: ^3.3.0 + vue@3.5.13: resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} peerDependencies: @@ -7701,12 +8204,20 @@ packages: typescript: optional: true + vue@3.5.34: + resolution: {integrity: sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -7714,58 +8225,29 @@ packages: web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} - web-worker@1.3.0: - resolution: {integrity: sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - - webpack-sources@3.3.2: - resolution: {integrity: sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==} + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} engines: {node: '>=10.13.0'} - webpack-virtual-modules@0.5.0: - resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} - webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} + webpack@5.106.1: + resolution: {integrity: sha512-EW8af29ak8Oaf4T8k8YsajjrDBDYgnKZ5er6ljWFJsXABfTNowQfvHLftwcepVgdz+IoLSdEAbBiM9DFXoll9w==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} - which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -7775,22 +8257,20 @@ packages: engines: {node: '>= 8'} hasBin: true + which@6.0.1: + resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true - wide-align@1.1.5: - resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - - widest-line@3.1.0: - resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -7802,23 +8282,28 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@3.0.3: - resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + write-yaml-file@5.0.0: + resolution: {integrity: sha512-FdNA4RyH1L43TlvGG8qOMIfcEczwA5ij+zLXUy3Z83CjxhLvcV7/Q/8pk22wnCgYw7PJhtK+7lhO+qqyT4NdvQ==} + engines: {node: '>=16.14'} - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} - engines: {node: '>=8.3.0'} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -7829,45 +8314,30 @@ packages: utf-8-validate: optional: true - xdg-basedir@4.0.0: - resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} - engines: {node: '>=8'} + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} - xml-name-validator@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} xmlbuilder@15.1.1: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - xterm-addon-fit@0.5.0: - resolution: {integrity: sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==} - deprecated: This package is now deprecated. Move to @xterm/addon-fit instead. - peerDependencies: - xterm: ^4.0.0 - - xterm-addon-search@0.8.2: - resolution: {integrity: sha512-I1863mjn8P6uVrqm/X+btalVsqjAKLhnhpbP7SavAOpEkI1jJhbHU2UTp7NjeRtcKTks6UWk/ycgds5snDSejg==} - deprecated: This package is now deprecated. Move to @xterm/addon-search instead. - peerDependencies: - xterm: ^4.0.0 - - xterm@4.19.0: - resolution: {integrity: sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==} - deprecated: This package is now deprecated. Move to @xterm/xterm instead. - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -7878,273 +8348,438 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yarn-or-npm@3.0.1: - resolution: {integrity: sha512-fTiQP6WbDAh5QZAVdbMQkecZoahnbOjClTQhzv74WX5h2Uaidj1isf9FDes11TKtsZ0/ZVfZsqZ+O3x6aLERHQ==} - engines: {node: '>=8.6.0'} - hasBin: true - yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yoctocolors@2.1.1: - resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - zip-stream@4.1.1: - resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} - engines: {node: '>= 10'} + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: - '@ampproject/remapping@2.3.0': + '@antfu/utils@0.7.10': {} + + '@azure/abort-controller@1.1.0': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + tslib: 2.8.1 - '@antfu/utils@0.7.10': {} + '@azure/abort-controller@2.1.2': + dependencies: + tslib: 2.8.1 - '@asamuzakjp/css-color@3.2.0': + '@azure/arm-containerinstance@9.1.0': dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 10.4.3 + '@azure/abort-controller': 1.1.0 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-lro': 2.7.2 + '@azure/core-paging': 1.6.2 + '@azure/core-rest-pipeline': 1.23.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-auth@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-client@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-http@3.0.5(encoding@0.1.13)': + dependencies: + '@azure/abort-controller': 1.1.0 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.0.0-preview.13 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@types/node-fetch': 2.6.13 + '@types/tunnel': 0.0.3 + form-data: 4.0.5 + node-fetch: 2.7.0(encoding@0.1.13) + process: 0.11.10 + tslib: 2.8.1 + tunnel: 0.0.6 + uuid: 8.3.2 + xml2js: 0.5.0 + transitivePeerDependencies: + - encoding + - supports-color + + '@azure/core-lro@2.7.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-paging@1.6.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-rest-pipeline@1.23.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@typespec/ts-http-runtime': 0.3.5 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.0.0-preview.13': + dependencies: + '@opentelemetry/api': 1.9.1 + tslib: 2.8.1 + + '@azure/core-tracing@1.3.1': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@typespec/ts-http-runtime': 0.3.5 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color - '@babel/code-frame@7.27.1': + '@azure/identity@4.0.1': + dependencies: + '@azure/abort-controller': 1.1.0 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@azure/msal-browser': 3.30.0 + '@azure/msal-node': 2.16.3 + events: 3.3.0 + jws: 4.0.1 + open: 8.4.2 + stoppable: 1.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/logger@1.3.0': + dependencies: + '@typespec/ts-http-runtime': 0.3.5 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/msal-browser@3.30.0': + dependencies: + '@azure/msal-common': 14.16.1 + + '@azure/msal-common@14.16.1': {} + + '@azure/msal-node@2.16.3': + dependencies: + '@azure/msal-common': 14.16.1 + jsonwebtoken: 9.0.3 + uuid: 8.3.2 + + '@azure/storage-file-share@12.15.0(encoding@0.1.13)': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@azure/abort-controller': 1.1.0 + '@azure/core-http': 3.0.5(encoding@0.1.13) + '@azure/core-paging': 1.6.2 + '@azure/core-tracing': 1.0.0-preview.13 + '@azure/logger': 1.3.0 + events: 3.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - encoding + - supports-color + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.27.5': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.27.4': + '@babel/core@7.29.0': dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) - '@babel/helpers': 7.27.6 - '@babel/parser': 7.27.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.27.4 - '@babel/types': 7.27.6 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.27.5': + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@8.0.0-rc.2': dependencies: - '@babel/parser': 7.27.5 - '@babel/types': 7.27.6 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@babel/parser': 8.0.0-rc.2 + '@babel/types': 8.0.0-rc.2 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.27.6 + '@babel/types': 7.29.0 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.27.5 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.0 + browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.27.4)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.27.4) + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.27.4 + '@babel/traverse': 7.29.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-member-expression-to-functions@7.27.1': + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.27.4 - '@babel/types': 7.27.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.27.4 - '@babel/types': 7.27.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.4 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.27.6 + '@babel/types': 7.29.0 - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-replace-supers@7.27.1(@babel/core@7.27.4)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.27.4 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.27.4 - '@babel/types': 7.27.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-string-parser@8.0.0-rc.3': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-identifier@8.0.0-rc.2': {} '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.27.6': + '@babel/helpers@7.29.2': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.27.6 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.27.5': + '@babel/parser@7.29.2': dependencies: - '@babel/types': 7.27.6 + '@babel/types': 7.29.0 - '@babel/plugin-proposal-decorators@7.27.1(@babel/core@7.27.4)': + '@babel/parser@7.29.3': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.27.4) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-decorators': 7.27.1(@babel/core@7.27.4) - transitivePeerDependencies: - - supports-color + '@babel/types': 7.29.0 + + '@babel/parser@8.0.0-rc.2': + dependencies: + '@babel/types': 8.0.0-rc.2 - '@babel/plugin-syntax-decorators@7.27.1(@babel/core@7.27.4)': + '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.4)': + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.4)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.27.4)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.27.1(@babel/core@7.27.4)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.27.4 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.27.4) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/runtime@7.13.7': - dependencies: - regenerator-runtime: 0.13.11 - - '@babel/runtime@7.27.6': {} + '@babel/runtime@7.29.2': {} - '@babel/template@7.27.2': + '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.27.5 - '@babel/types': 7.27.6 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 - '@babel/traverse@7.27.4': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.5 - '@babel/parser': 7.27.5 - '@babel/template': 7.27.2 - '@babel/types': 7.27.6 - debug: 4.4.1 - globals: 11.12.0 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.27.6': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@babel/types@8.0.0-rc.2': + dependencies: + '@babel/helper-string-parser': 8.0.0-rc.3 + '@babel/helper-validator-identifier': 8.0.0-rc.2 + + '@bufbuild/protobuf@2.11.0': {} - '@changesets/apply-release-plan@7.0.12': + '@bundled-es-modules/cookie@2.0.1': dependencies: - '@changesets/config': 3.1.1 + cookie: 0.7.2 + + '@bundled-es-modules/statuses@1.0.1': + dependencies: + statuses: 2.0.2 + + '@bundled-es-modules/tough-cookie@0.1.6': + dependencies: + '@types/tough-cookie': 4.0.5 + tough-cookie: 4.1.4 + + '@changesets/apply-release-plan@7.1.0': + dependencies: + '@changesets/config': 3.1.3 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.4 '@changesets/should-skip-package': 0.1.2 @@ -8156,65 +8791,58 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.8.0 - '@changesets/assemble-release-plan@6.0.8': + '@changesets/assemble-release-plan@6.0.9': dependencies: '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 - semver: 7.6.3 - - '@changesets/changelog-git@0.2.0': - dependencies: - '@changesets/types': 6.1.0 + semver: 7.8.0 - '@changesets/changelog-github@0.5.0(encoding@0.1.13)': + '@changesets/changelog-git@0.2.1': dependencies: - '@changesets/get-github-info': 0.6.0(encoding@0.1.13) '@changesets/types': 6.1.0 - dotenv: 8.6.0 - transitivePeerDependencies: - - encoding - '@changesets/cli@2.27.11': + '@changesets/cli@2.30.0(@types/node@24.12.2)': dependencies: - '@changesets/apply-release-plan': 7.0.12 - '@changesets/assemble-release-plan': 6.0.8 - '@changesets/changelog-git': 0.2.0 - '@changesets/config': 3.1.1 + '@changesets/apply-release-plan': 7.1.0 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.3 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 - '@changesets/get-release-plan': 4.0.12 + '@changesets/get-release-plan': 4.0.15 '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 + '@changesets/read': 0.6.7 '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 - '@changesets/write': 0.3.2 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@24.12.2) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 - ci-info: 3.9.0 enquirer: 2.4.1 - external-editor: 3.1.0 fs-extra: 7.0.1 mri: 1.2.0 - p-limit: 2.3.0 package-manager-detector: 0.2.11 picocolors: 1.1.1 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.8.0 spawndamnit: 3.0.1 term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' - '@changesets/config@3.1.1': + '@changesets/config@3.1.3': dependencies: '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 '@changesets/logger': 0.1.1 + '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 @@ -8229,21 +8857,14 @@ snapshots: '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.6.3 - - '@changesets/get-github-info@0.6.0(encoding@0.1.13)': - dependencies: - dataloader: 1.4.0 - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding + semver: 7.8.0 - '@changesets/get-release-plan@4.0.12': + '@changesets/get-release-plan@4.0.15': dependencies: - '@changesets/assemble-release-plan': 6.0.8 - '@changesets/config': 3.1.1 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.3 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 + '@changesets/read': 0.6.7 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 @@ -8261,10 +8882,10 @@ snapshots: dependencies: picocolors: 1.1.1 - '@changesets/parse@0.4.1': + '@changesets/parse@0.4.3': dependencies: '@changesets/types': 6.1.0 - js-yaml: 3.14.1 + js-yaml: 4.1.1 '@changesets/pre@2.0.2': dependencies: @@ -8273,11 +8894,11 @@ snapshots: '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 - '@changesets/read@0.6.5': + '@changesets/read@0.6.7': dependencies: '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.1 + '@changesets/parse': 0.4.3 '@changesets/types': 6.1.0 fs-extra: 7.0.1 p-filter: 2.1.0 @@ -8292,78 +8913,90 @@ snapshots: '@changesets/types@6.1.0': {} - '@changesets/write@0.3.2': + '@changesets/write@0.4.0': dependencies: '@changesets/types': 6.1.0 fs-extra: 7.0.1 - human-id: 1.0.2 + human-id: 4.1.3 prettier: 2.8.8 - '@codemirror/autocomplete@6.18.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.2.3)': + '@clack/core@1.2.0': + dependencies: + fast-wrap-ansi: 0.1.6 + sisteransi: 1.0.5 + + '@clack/prompts@1.2.0': + dependencies: + '@clack/core': 1.2.0 + fast-string-width: 1.1.0 + fast-wrap-ansi: 0.1.6 + sisteransi: 1.0.5 + + '@codemirror/autocomplete@6.18.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.5.2)': dependencies: - '@codemirror/language': 6.11.1 + '@codemirror/language': 6.12.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.0 - '@lezer/common': 1.2.3 + '@lezer/common': 1.5.2 '@codemirror/commands@6.6.2': dependencies: - '@codemirror/language': 6.11.1 + '@codemirror/language': 6.12.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.0 - '@lezer/common': 1.2.3 + '@lezer/common': 1.5.2 '@codemirror/lang-css@6.3.1(@codemirror/view@6.34.0)': dependencies: - '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.2.3) - '@codemirror/language': 6.11.1 + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.5.2) + '@codemirror/language': 6.12.3 '@codemirror/state': 6.4.1 - '@lezer/common': 1.2.3 - '@lezer/css': 1.2.1 + '@lezer/common': 1.5.2 + '@lezer/css': 1.3.3 transitivePeerDependencies: - '@codemirror/view' - '@codemirror/lang-html@6.4.9': + '@codemirror/lang-html@6.4.11': dependencies: - '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.2.3) + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.5.2) '@codemirror/lang-css': 6.3.1(@codemirror/view@6.34.0) - '@codemirror/lang-javascript': 6.2.4 - '@codemirror/language': 6.11.1 + '@codemirror/lang-javascript': 6.2.2 + '@codemirror/language': 6.12.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.0 - '@lezer/common': 1.2.3 - '@lezer/css': 1.2.1 - '@lezer/html': 1.3.10 + '@lezer/common': 1.5.2 + '@lezer/css': 1.3.3 + '@lezer/html': 1.3.13 - '@codemirror/lang-javascript@6.2.4': + '@codemirror/lang-javascript@6.2.2': dependencies: - '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.2.3) - '@codemirror/language': 6.11.1 + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.5.2) + '@codemirror/language': 6.12.3 '@codemirror/lint': 6.8.2 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.0 - '@lezer/common': 1.2.3 - '@lezer/javascript': 1.5.1 + '@lezer/common': 1.5.2 + '@lezer/javascript': 1.5.4 '@codemirror/lang-liquid@6.2.1': dependencies: - '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.2.3) - '@codemirror/lang-html': 6.4.9 - '@codemirror/language': 6.11.1 + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0)(@lezer/common@1.5.2) + '@codemirror/lang-html': 6.4.11 + '@codemirror/language': 6.12.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.0 - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 - '@codemirror/language@6.11.1': + '@codemirror/language@6.12.3': dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.0 - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 - style-mod: 4.1.2 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + style-mod: 4.1.3 '@codemirror/lint@6.8.2': dependencies: @@ -8376,170 +9009,118 @@ snapshots: '@codemirror/view@6.34.0': dependencies: '@codemirror/state': 6.4.1 - style-mod: 4.1.2 + style-mod: 4.1.3 w3c-keyname: 2.2.8 - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - '@csstools/color-helpers@5.0.2': {} - - '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/color-helpers': 5.0.2 - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-tokenizer@3.0.4': {} - - '@electron-forge/cli@7.4.0(encoding@0.1.13)': + '@electron-forge/cli@7.11.1(encoding@0.1.13)': dependencies: - '@electron-forge/core': 7.4.0(encoding@0.1.13) - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/core': 7.11.1(encoding@0.1.13) + '@electron-forge/core-utils': 7.11.1 + '@electron-forge/shared-types': 7.11.1 '@electron/get': 3.1.0 + '@inquirer/prompts': 6.0.1 + '@listr2/prompt-adapter-inquirer': 2.0.22(@inquirer/prompts@6.0.1) chalk: 4.1.2 - commander: 4.1.1 - debug: 4.4.1 + commander: 11.1.0 + debug: 4.4.3 fs-extra: 10.1.0 listr2: 7.0.2 - semver: 7.6.3 + log-symbols: 4.1.0 + semver: 7.8.0 transitivePeerDependencies: + - '@swc/core' - bluebird - encoding + - esbuild - supports-color + - uglify-js + - webpack-cli - '@electron-forge/core-utils@7.4.0': + '@electron-forge/core-utils@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/shared-types': 7.11.1 '@electron/rebuild': 3.7.2 '@malept/cross-spawn-promise': 2.0.0 chalk: 4.1.2 - debug: 4.4.1 + debug: 4.4.3 find-up: 5.0.0 fs-extra: 10.1.0 log-symbols: 4.1.0 - semver: 7.6.3 - yarn-or-npm: 3.0.1 + parse-author: 2.0.0 + semver: 7.8.0 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/core@7.4.0(encoding@0.1.13)': - dependencies: - '@electron-forge/core-utils': 7.4.0 - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/plugin-base': 7.4.0 - '@electron-forge/publisher-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 - '@electron-forge/template-vite': 7.4.0 - '@electron-forge/template-vite-typescript': 7.4.0 - '@electron-forge/template-webpack': 7.4.0 - '@electron-forge/template-webpack-typescript': 7.4.0 - '@electron-forge/tracer': 7.4.0 + '@electron-forge/core@7.11.1(encoding@0.1.13)': + dependencies: + '@electron-forge/core-utils': 7.11.1 + '@electron-forge/maker-base': 7.11.1 + '@electron-forge/plugin-base': 7.11.1 + '@electron-forge/publisher-base': 7.11.1 + '@electron-forge/shared-types': 7.11.1 + '@electron-forge/template-base': 7.11.1 + '@electron-forge/template-vite': 7.11.1 + '@electron-forge/template-vite-typescript': 7.11.1 + '@electron-forge/template-webpack': 7.11.1 + '@electron-forge/template-webpack-typescript': 7.11.1 + '@electron-forge/tracer': 7.11.1 '@electron/get': 3.1.0 - '@electron/packager': 18.3.6 + '@electron/packager': 18.4.4 '@electron/rebuild': 3.7.2 '@malept/cross-spawn-promise': 2.0.0 + '@vscode/sudo-prompt': 9.3.2 chalk: 4.1.2 - debug: 4.4.1 + debug: 4.4.3 fast-glob: 3.3.3 filenamify: 4.3.0 find-up: 5.0.0 fs-extra: 10.1.0 + global-dirs: 3.0.1 got: 11.8.6 interpret: 3.1.1 + jiti: 2.6.1 listr2: 7.0.2 - lodash: 4.17.21 + lodash: 4.18.1 log-symbols: 4.1.0 node-fetch: 2.7.0(encoding@0.1.13) - progress: 2.0.3 rechoir: 0.8.0 - resolve-package: 1.0.1 - semver: 7.6.3 + semver: 7.8.0 source-map-support: 0.5.21 - sudo-prompt: 9.2.1 username: 5.1.0 - yarn-or-npm: 3.0.1 transitivePeerDependencies: + - '@swc/core' - bluebird - encoding + - esbuild - supports-color + - uglify-js + - webpack-cli - '@electron-forge/maker-base@7.4.0': - dependencies: - '@electron-forge/shared-types': 7.4.0 - fs-extra: 10.1.0 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-base@7.8.1': + '@electron-forge/maker-base@7.11.1': dependencies: - '@electron-forge/shared-types': 7.8.1 + '@electron-forge/shared-types': 7.11.1 fs-extra: 10.1.0 which: 2.0.2 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/maker-deb@7.4.0': - dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - optionalDependencies: - electron-installer-debian: 3.2.0 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-dmg@7.4.0': + '@electron-forge/maker-dmg@7.11.1': dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/maker-base': 7.11.1 + '@electron-forge/shared-types': 7.11.1 fs-extra: 10.1.0 optionalDependencies: - electron-installer-dmg: 4.0.0 + electron-installer-dmg: 5.0.1 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/maker-flatpak@7.4.0': + '@electron-forge/maker-squirrel@7.11.1': dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - fs-extra: 10.1.0 - optionalDependencies: - '@malept/electron-installer-flatpak': 0.11.4 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-pkg@7.8.1': - dependencies: - '@electron-forge/maker-base': 7.8.1 - '@electron-forge/shared-types': 7.8.1 - '@electron/osx-sign': 1.3.3 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron-forge/maker-squirrel@7.4.0': - dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/maker-base': 7.11.1 + '@electron-forge/shared-types': 7.11.1 fs-extra: 10.1.0 optionalDependencies: electron-winstaller: 5.4.0 @@ -8547,10 +9128,10 @@ snapshots: - bluebird - supports-color - '@electron-forge/maker-zip@7.4.0': + '@electron-forge/maker-zip@7.11.1': dependencies: - '@electron-forge/maker-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/maker-base': 7.11.1 + '@electron-forge/shared-types': 7.11.1 cross-zip: 4.0.1 fs-extra: 10.1.0 got: 11.8.6 @@ -8558,159 +9139,132 @@ snapshots: - bluebird - supports-color - '@electron-forge/plugin-base@7.4.0': + '@electron-forge/plugin-base@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/shared-types': 7.11.1 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/plugin-fuses@7.4.0(@electron/fuses@1.8.0)': + '@electron-forge/plugin-fuses@7.11.1(@electron/fuses@1.8.0)': dependencies: - '@electron-forge/plugin-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/plugin-base': 7.11.1 + '@electron-forge/shared-types': 7.11.1 '@electron/fuses': 1.8.0 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/plugin-vite@7.4.0': + '@electron-forge/plugin-vite@7.11.1': dependencies: - '@electron-forge/core-utils': 7.4.0 - '@electron-forge/plugin-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/web-multi-logger': 7.4.0 + '@electron-forge/plugin-base': 7.11.1 + '@electron-forge/shared-types': 7.11.1 chalk: 4.1.2 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 listr2: 7.0.2 transitivePeerDependencies: - bluebird - - bufferutil - supports-color - - utf-8-validate - '@electron-forge/publisher-base@7.4.0': + '@electron-forge/publisher-base@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/shared-types': 7.11.1 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/publisher-github@7.4.0(encoding@0.1.13)': + '@electron-forge/publisher-github@7.11.1': dependencies: - '@electron-forge/publisher-base': 7.4.0 - '@electron-forge/shared-types': 7.4.0 - '@octokit/core': 3.6.0(encoding@0.1.13) - '@octokit/plugin-retry': 3.0.9 - '@octokit/request-error': 2.1.0 - '@octokit/rest': 18.12.0(encoding@0.1.13) + '@electron-forge/publisher-base': 7.11.1 + '@electron-forge/shared-types': 7.11.1 + '@octokit/core': 5.2.2 + '@octokit/plugin-retry': 6.1.0(@octokit/core@5.2.2) + '@octokit/request-error': 5.1.1 + '@octokit/rest': 20.1.2 '@octokit/types': 6.41.0 chalk: 4.1.2 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 log-symbols: 4.1.0 mime-types: 2.1.35 - transitivePeerDependencies: - - bluebird - - encoding - - supports-color - - '@electron-forge/shared-types@7.4.0': - dependencies: - '@electron-forge/tracer': 7.4.0 - '@electron/packager': 18.3.6 - '@electron/rebuild': 3.7.2 - listr2: 7.0.2 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/shared-types@7.8.1': + '@electron-forge/shared-types@7.11.1': dependencies: - '@electron-forge/tracer': 7.8.1 - '@electron/packager': 18.3.6 + '@electron-forge/tracer': 7.11.1 + '@electron/packager': 18.4.4 '@electron/rebuild': 3.7.2 listr2: 7.0.2 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/template-base@7.4.0': + '@electron-forge/template-base@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 + '@electron-forge/core-utils': 7.11.1 + '@electron-forge/shared-types': 7.11.1 '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 + semver: 7.8.0 username: 5.1.0 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/template-vite-typescript@7.4.0': + '@electron-forge/template-vite-typescript@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 + '@electron-forge/shared-types': 7.11.1 + '@electron-forge/template-base': 7.11.1 fs-extra: 10.1.0 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/template-vite@7.4.0': + '@electron-forge/template-vite@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 + '@electron-forge/shared-types': 7.11.1 + '@electron-forge/template-base': 7.11.1 fs-extra: 10.1.0 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/template-webpack-typescript@7.4.0': + '@electron-forge/template-webpack-typescript@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 + '@electron-forge/shared-types': 7.11.1 + '@electron-forge/template-base': 7.11.1 fs-extra: 10.1.0 + typescript: 5.4.5 + webpack: 5.106.1 transitivePeerDependencies: + - '@swc/core' - bluebird + - esbuild - supports-color + - uglify-js + - webpack-cli - '@electron-forge/template-webpack@7.4.0': + '@electron-forge/template-webpack@7.11.1': dependencies: - '@electron-forge/shared-types': 7.4.0 - '@electron-forge/template-base': 7.4.0 + '@electron-forge/shared-types': 7.11.1 + '@electron-forge/template-base': 7.11.1 fs-extra: 10.1.0 transitivePeerDependencies: - bluebird - supports-color - '@electron-forge/tracer@7.4.0': - dependencies: - chrome-trace-event: 1.0.4 - - '@electron-forge/tracer@7.8.1': + '@electron-forge/tracer@7.11.1': dependencies: chrome-trace-event: 1.0.4 - '@electron-forge/web-multi-logger@7.4.0': - dependencies: - express: 4.21.2 - express-ws: 5.0.2(express@4.21.2) - xterm: 4.19.0 - xterm-addon-fit: 0.5.0(xterm@4.19.0) - xterm-addon-search: 0.8.2(xterm@4.19.0) - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - '@electron-toolkit/preload@3.0.2(electron@32.1.2)': dependencies: electron: 32.1.2 - '@electron-toolkit/tsconfig@1.0.1(@types/node@22.7.9)': - dependencies: - '@types/node': 22.7.9 - '@electron-toolkit/utils@4.0.0(electron@32.1.2)': dependencies: electron: 32.1.2 @@ -8719,7 +9273,7 @@ snapshots: dependencies: commander: 5.1.0 glob: 7.2.3 - minimatch: 3.1.2 + minimatch: 3.1.5 '@electron/fuses@1.8.0': dependencies: @@ -8729,7 +9283,7 @@ snapshots: '@electron/get@2.0.3': dependencies: - debug: 4.4.1 + debug: 4.4.3 env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 @@ -8743,7 +9297,7 @@ snapshots: '@electron/get@3.1.0': dependencies: - debug: 4.4.1 + debug: 4.4.3 env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 @@ -8758,13 +9312,13 @@ snapshots: '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': dependencies: env-paths: 2.2.1 - exponential-backoff: 3.1.2 + exponential-backoff: 3.1.3 glob: 8.1.0 graceful-fs: 4.2.11 make-fetch-happen: 10.2.1 nopt: 6.0.0 proc-log: 2.0.1 - semver: 7.6.3 + semver: 7.8.1 tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: @@ -8773,7 +9327,7 @@ snapshots: '@electron/notarize@2.5.0': dependencies: - debug: 4.4.1 + debug: 4.4.3 fs-extra: 9.1.0 promise-retry: 2.0.1 transitivePeerDependencies: @@ -8782,7 +9336,7 @@ snapshots: '@electron/osx-sign@1.3.3': dependencies: compare-version: 0.1.2 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -8790,7 +9344,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/packager@18.3.6': + '@electron/packager@18.4.4': dependencies: '@electron/asar': 3.4.1 '@electron/get': 3.1.0 @@ -8798,7 +9352,8 @@ snapshots: '@electron/osx-sign': 1.3.3 '@electron/universal': 2.0.3 '@electron/windows-sign': 1.2.2 - debug: 4.4.1 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.3 extract-zip: 2.0.1 filenamify: 4.3.0 fs-extra: 11.3.0 @@ -8807,9 +9362,10 @@ snapshots: junk: 3.1.0 parse-author: 2.0.0 plist: 3.1.0 + prettier: 3.8.2 resedit: 2.0.3 - resolve: 1.22.10 - semver: 7.6.3 + resolve: 1.22.12 + semver: 7.8.0 yargs-parser: 21.1.1 transitivePeerDependencies: - supports-color @@ -8819,15 +9375,15 @@ snapshots: '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 '@malept/cross-spawn-promise': 2.0.0 chalk: 4.1.2 - debug: 4.4.1 - detect-libc: 2.0.4 + debug: 4.4.3 + detect-libc: 2.1.2 fs-extra: 10.1.0 got: 11.8.6 - node-abi: 3.75.0 + node-abi: 3.89.0 node-api-version: 0.2.1 ora: 5.4.1 read-binary-file-arch: 1.0.6 - semver: 7.6.3 + semver: 7.8.0 tar: 6.2.1 yargs: 17.7.2 transitivePeerDependencies: @@ -8838,10 +9394,10 @@ snapshots: dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.1 + debug: 4.4.3 dir-compare: 4.2.0 fs-extra: 11.3.0 - minimatch: 9.0.5 + minimatch: 9.0.9 plist: 3.1.0 transitivePeerDependencies: - supports-color @@ -8849,415 +9405,555 @@ snapshots: '@electron/windows-sign@1.2.2': dependencies: cross-dirname: 0.1.0 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 11.3.0 minimist: 1.2.8 postject: 1.0.0-alpha.6 transitivePeerDependencies: - supports-color - '@emnapi/runtime@1.4.3': + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.2': dependencies: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.21.5': + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 optional: true '@esbuild/aix-ppc64@0.23.1': optional: true - '@esbuild/aix-ppc64@0.25.5': + '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/android-arm64@0.23.1': optional: true - '@esbuild/android-arm64@0.25.5': + '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm@0.23.1': optional: true - '@esbuild/android-arm@0.25.5': + '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-x64@0.23.1': optional: true - '@esbuild/android-x64@0.25.5': + '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/android-x64@0.27.7': optional: true '@esbuild/darwin-arm64@0.23.1': optional: true - '@esbuild/darwin-arm64@0.25.5': + '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-x64@0.23.1': optional: true - '@esbuild/darwin-x64@0.25.5': + '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.23.1': optional: true - '@esbuild/freebsd-arm64@0.25.5': + '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-x64@0.23.1': optional: true - '@esbuild/freebsd-x64@0.25.5': + '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/linux-arm64@0.23.1': optional: true - '@esbuild/linux-arm64@0.25.5': + '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm@0.23.1': optional: true - '@esbuild/linux-arm@0.25.5': + '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-ia32@0.23.1': optional: true - '@esbuild/linux-ia32@0.25.5': + '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-loong64@0.23.1': optional: true - '@esbuild/linux-loong64@0.25.5': + '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-mips64el@0.23.1': optional: true - '@esbuild/linux-mips64el@0.25.5': + '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-ppc64@0.23.1': optional: true - '@esbuild/linux-ppc64@0.25.5': + '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-riscv64@0.23.1': optional: true - '@esbuild/linux-riscv64@0.25.5': + '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-s390x@0.23.1': optional: true - '@esbuild/linux-s390x@0.25.5': + '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-x64@0.23.1': optional: true - '@esbuild/linux-x64@0.25.5': + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.25.5': + '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.21.5': + '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-x64@0.23.1': optional: true - '@esbuild/netbsd-x64@0.25.5': + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.27.7': optional: true '@esbuild/openbsd-arm64@0.23.1': optional: true - '@esbuild/openbsd-arm64@0.25.5': + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-x64@0.23.1': optional: true - '@esbuild/openbsd-x64@0.25.5': + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/sunos-x64@0.23.1': optional: true - '@esbuild/sunos-x64@0.25.5': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/win32-arm64@0.23.1': optional: true - '@esbuild/win32-arm64@0.25.5': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-ia32@0.23.1': optional: true - '@esbuild/win32-ia32@0.25.5': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-x64@0.21.5': + '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-x64@0.23.1': optional: true - '@esbuild/win32-x64@0.25.5': + '@esbuild/win32-x64@0.25.12': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@9.13.0(jiti@2.4.2))': - dependencies: - eslint: 9.13.0(jiti@2.4.2) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.1': {} - - '@eslint/config-array@0.18.0': - dependencies: - '@eslint/object-schema': 2.1.6 - debug: 4.4.1 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@eslint/core@0.13.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/core@0.7.0': {} - - '@eslint/eslintrc@3.1.0': - dependencies: - ajv: 6.12.6 - debug: 4.4.1 - espree: 10.3.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.13.0': {} - - '@eslint/object-schema@2.1.6': {} - - '@eslint/plugin-kit@0.2.8': - dependencies: - '@eslint/core': 0.13.0 - levn: 0.4.1 + '@esbuild/win32-x64@0.27.7': + optional: true - '@floating-ui/core@1.7.1': + '@floating-ui/core@1.7.5': dependencies: - '@floating-ui/utils': 0.2.9 + '@floating-ui/utils': 0.2.11 - '@floating-ui/dom@1.7.1': + '@floating-ui/dom@1.7.6': dependencies: - '@floating-ui/core': 1.7.1 - '@floating-ui/utils': 0.2.9 + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 - '@floating-ui/utils@0.2.9': {} + '@floating-ui/utils@0.2.11': {} '@floating-ui/vue@1.1.5(vue@3.5.13(typescript@5.8.3))': dependencies: - '@floating-ui/dom': 1.7.1 - '@floating-ui/utils': 0.2.9 + '@floating-ui/dom': 1.7.6 + '@floating-ui/utils': 0.2.11 vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.3)) transitivePeerDependencies: - '@vue/composition-api' - vue - '@gar/promisify@1.1.3': {} - - '@humanfs/core@0.19.1': {} + '@gar/promise-retry@1.0.3': {} - '@humanfs/node@0.16.6': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.3.1 + '@gar/promisify@1.1.3': {} - '@humanwhocodes/module-importer@1.0.1': {} + '@gwhitney/detect-indent@7.0.1': {} - '@humanwhocodes/retry@0.3.1': {} + '@img/colour@1.1.0': + optional: true - '@img/sharp-darwin-arm64@0.34.2': + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.1.0 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.34.2': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.1.0 + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-arm64@1.1.0': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.1.0': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.1.0': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.1.0': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.1.0': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.1.0': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.1.0': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.1.0': + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-libvips-linuxmusl-x64@1.1.0': + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-arm64@0.34.2': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.1.0 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.34.2': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.1.0 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.34.2': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.1.0 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linux-x64@0.34.2': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.1.0 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.2': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.34.2': + '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.1.0 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.34.2': + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.4.3 + '@emnapi/runtime': 1.10.0 optional: true - '@img/sharp-win32-arm64@0.34.2': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.34.2': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.34.2': + '@img/sharp-win32-x64@0.34.5': optional: true - '@intlify/core-base@10.0.7': + '@inquirer/ansi@1.0.2': {} + + '@inquirer/checkbox@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.3 + + '@inquirer/confirm@4.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/confirm@5.1.21(@types/node@24.12.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@24.12.2) + '@inquirer/type': 3.0.10(@types/node@24.12.2) + optionalDependencies: + '@types/node': 24.12.2 + + '@inquirer/core@10.3.2(@types/node@24.12.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.12.2) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 24.12.2 + + '@inquirer/core@9.2.1': + dependencies: + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + '@types/mute-stream': 0.0.4 + '@types/node': 22.7.9 + '@types/wrap-ansi': 3.0.0 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 1.0.0 + signal-exit: 4.1.0 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + + '@inquirer/editor@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + external-editor: 3.1.0 + + '@inquirer/expand@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.3 + + '@inquirer/external-editor@1.0.3(@types/node@24.12.2)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 24.12.2 + + '@inquirer/figures@1.0.15': {} + + '@inquirer/input@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/number@2.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + + '@inquirer/password@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + + '@inquirer/prompts@6.0.1': + dependencies: + '@inquirer/checkbox': 3.0.1 + '@inquirer/confirm': 4.0.1 + '@inquirer/editor': 3.0.1 + '@inquirer/expand': 3.0.1 + '@inquirer/input': 3.0.1 + '@inquirer/number': 2.0.1 + '@inquirer/password': 3.0.1 + '@inquirer/rawlist': 3.0.1 + '@inquirer/search': 2.0.1 + '@inquirer/select': 3.0.1 + + '@inquirer/rawlist@3.0.1': dependencies: - '@intlify/message-compiler': 10.0.7 - '@intlify/shared': 10.0.7 + '@inquirer/core': 9.2.1 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.3 - '@intlify/message-compiler@10.0.7': + '@inquirer/search@2.0.1': dependencies: - '@intlify/shared': 10.0.7 + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + yoctocolors-cjs: 2.1.3 + + '@inquirer/select@3.0.1': + dependencies: + '@inquirer/core': 9.2.1 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 2.0.0 + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.3 + + '@inquirer/type@1.5.5': + dependencies: + mute-stream: 1.0.0 + + '@inquirer/type@2.0.0': + dependencies: + mute-stream: 1.0.0 + + '@inquirer/type@3.0.10(@types/node@24.12.2)': + optionalDependencies: + '@types/node': 24.12.2 + + '@intlify/core-base@10.0.8': + dependencies: + '@intlify/message-compiler': 10.0.8 + '@intlify/shared': 10.0.8 + + '@intlify/message-compiler@10.0.8': + dependencies: + '@intlify/shared': 10.0.8 source-map-js: 1.2.1 - '@intlify/shared@10.0.7': {} + '@intlify/shared@10.0.8': {} '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + '@jitl/quickjs-ffi-types@0.31.0': {} + '@jitl/quickjs-singlefile-mjs-release-sync@0.31.0': + dependencies: + '@jitl/quickjs-ffi-types': 0.31.0 + '@jitl/quickjs-wasmfile-debug-asyncify@0.31.0': dependencies: '@jitl/quickjs-ffi-types': 0.31.0 @@ -9274,122 +9970,204 @@ snapshots: dependencies: '@jitl/quickjs-ffi-types': 0.31.0 - '@jridgewell/gen-mapping@0.3.8': + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.2.1': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.25': + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping@0.3.9': + '@jsonjoy.com/base64@1.1.2(tslib@2.8.1)': dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + tslib: 2.8.1 - '@lezer/common@1.2.3': {} + '@jsonjoy.com/base64@17.67.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 - '@lezer/css@1.2.1': + '@jsonjoy.com/buffers@1.2.1(tslib@2.8.1)': dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + tslib: 2.8.1 - '@lezer/highlight@1.2.1': + '@jsonjoy.com/buffers@17.67.0(tslib@2.8.1)': dependencies: - '@lezer/common': 1.2.3 + tslib: 2.8.1 - '@lezer/html@1.3.10': + '@jsonjoy.com/codegen@1.0.0(tslib@2.8.1)': dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + tslib: 2.8.1 - '@lezer/javascript@1.5.1': + '@jsonjoy.com/codegen@17.67.0(tslib@2.8.1)': dependencies: - '@lezer/common': 1.2.3 - '@lezer/highlight': 1.2.1 - '@lezer/lr': 1.4.2 + tslib: 2.8.1 - '@lezer/lr@1.4.2': + '@jsonjoy.com/fs-core@4.57.6(tslib@2.8.1)': dependencies: - '@lezer/common': 1.2.3 + '@jsonjoy.com/fs-node-builtins': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.6(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tslib: 2.8.1 - '@lydell/node-pty-darwin-arm64@1.0.3': - optional: true + '@jsonjoy.com/fs-fsa@4.57.6(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-core': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.6(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tslib: 2.8.1 - '@lydell/node-pty-darwin-x64@1.0.3': - optional: true + '@jsonjoy.com/fs-node-builtins@4.57.6(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 - '@lydell/node-pty-linux-x64@1.0.3': - optional: true + '@jsonjoy.com/fs-node-to-fsa@4.57.6(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-fsa': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.6(tslib@2.8.1) + tslib: 2.8.1 - '@lydell/node-pty-win32-arm64@1.0.3': - optional: true + '@jsonjoy.com/fs-node-utils@4.57.6(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-builtins': 4.57.6(tslib@2.8.1) + tslib: 2.8.1 - '@lydell/node-pty-win32-x64@1.0.3': - optional: true + '@jsonjoy.com/fs-node@4.57.6(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-core': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.57.6(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tslib: 2.8.1 - '@lydell/node-pty-win32-x64@1.1.0': {} + '@jsonjoy.com/fs-print@4.57.6(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-utils': 4.57.6(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 - '@lydell/node-pty@1.0.3': - optionalDependencies: - '@lydell/node-pty-darwin-arm64': 1.0.3 - '@lydell/node-pty-darwin-x64': 1.0.3 - '@lydell/node-pty-linux-x64': 1.0.3 - '@lydell/node-pty-win32-arm64': 1.0.3 - '@lydell/node-pty-win32-x64': 1.0.3 + '@jsonjoy.com/fs-snapshot@4.57.6(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/json-pack': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 - '@malept/cross-spawn-promise@1.1.1': + '@jsonjoy.com/json-pack@1.21.0(tslib@2.8.1)': dependencies: - cross-spawn: 7.0.6 - optional: true + '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 1.0.2(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 2.6.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 - '@malept/cross-spawn-promise@2.0.0': + '@jsonjoy.com/json-pack@17.67.0(tslib@2.8.1)': dependencies: - cross-spawn: 7.0.6 + '@jsonjoy.com/base64': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 2.6.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 - '@malept/electron-installer-flatpak@0.11.4': + '@jsonjoy.com/json-pointer@1.0.2(tslib@2.8.1)': dependencies: - '@malept/flatpak-bundler': 0.4.0 - debug: 4.4.1 - electron-installer-common: 0.10.4 - lodash: 4.17.21 - semver: 7.6.3 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - optional: true + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + tslib: 2.8.1 - '@malept/flatpak-bundler@0.4.0': + '@jsonjoy.com/json-pointer@17.67.0(tslib@2.8.1)': dependencies: - debug: 4.4.1 - fs-extra: 9.1.0 - lodash: 4.17.21 - tmp-promise: 3.0.3 - transitivePeerDependencies: - - supports-color - optional: true + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/util@1.9.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/util@17.67.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 + + '@lezer/common@1.5.2': {} + + '@lezer/css@1.3.3': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + + '@lezer/highlight@1.2.3': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/html@1.3.13': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + + '@lezer/javascript@1.5.4': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 + + '@lezer/lr@1.4.8': + dependencies: + '@lezer/common': 1.5.2 + + '@listr2/prompt-adapter-inquirer@2.0.22(@inquirer/prompts@6.0.1)': + dependencies: + '@inquirer/prompts': 6.0.1 + '@inquirer/type': 1.5.5 + + '@malept/cross-spawn-promise@2.0.0': + dependencies: + cross-spawn: 7.0.6 '@manypkg/find-root@1.1.0': dependencies: - '@babel/runtime': 7.27.6 + '@babel/runtime': 7.29.2 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 '@manypkg/get-packages@1.1.3': dependencies: - '@babel/runtime': 7.27.6 + '@babel/runtime': 7.29.2 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -9398,30 +10176,60 @@ snapshots: '@mdi/font@7.4.47': {} - '@next/env@15.3.3': {} + '@mswjs/interceptors@0.37.6': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + + '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.1 + optional: true - '@next/swc-darwin-arm64@15.3.3': + '@next/env@16.2.3': {} + + '@next/swc-darwin-arm64@16.2.3': optional: true - '@next/swc-darwin-x64@15.3.3': + '@next/swc-darwin-x64@16.2.3': optional: true - '@next/swc-linux-arm64-gnu@15.3.3': + '@next/swc-linux-arm64-gnu@16.2.3': optional: true - '@next/swc-linux-arm64-musl@15.3.3': + '@next/swc-linux-arm64-musl@16.2.3': optional: true - '@next/swc-linux-x64-gnu@15.3.3': + '@next/swc-linux-x64-gnu@16.2.3': optional: true - '@next/swc-linux-x64-musl@15.3.3': + '@next/swc-linux-x64-musl@16.2.3': optional: true - '@next/swc-win32-arm64-msvc@15.3.3': + '@next/swc-win32-arm64-msvc@16.2.3': optional: true - '@next/swc-win32-x64-msvc@15.3.3': + '@next/swc-win32-x64-msvc@16.2.3': optional: true '@nodelib/fs.scandir@2.1.5': @@ -9434,497 +10242,480 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@npmcli/ci-detect@1.4.0': {} + fastq: 1.20.1 - '@npmcli/fs@1.1.1': + '@npmcli/agent@4.0.0': dependencies: - '@gar/promisify': 1.1.3 - semver: 7.6.3 + agent-base: 7.1.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 11.3.5 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color '@npmcli/fs@2.1.2': dependencies: '@gar/promisify': 1.1.3 - semver: 7.6.3 + semver: 7.8.1 - '@npmcli/git@2.1.0(bluebird@3.7.2)': + '@npmcli/fs@5.0.0': dependencies: - '@npmcli/promise-spawn': 1.3.2 - lru-cache: 6.0.0 - mkdirp: 1.0.4 - npm-pick-manifest: 6.1.1 - promise-inflight: 1.0.1(bluebird@3.7.2) - promise-retry: 2.0.1 - semver: 7.6.3 - which: 2.0.2 - transitivePeerDependencies: - - bluebird + semver: 7.8.0 - '@npmcli/installed-package-contents@1.0.7': + '@npmcli/git@7.0.2': dependencies: - npm-bundled: 1.1.2 - npm-normalize-package-bin: 1.0.1 + '@gar/promise-retry': 1.0.3 + '@npmcli/promise-spawn': 9.0.1 + ini: 6.0.0 + lru-cache: 11.3.5 + npm-pick-manifest: 11.0.3 + proc-log: 6.1.0 + semver: 7.8.0 + which: 6.0.1 - '@npmcli/move-file@1.1.2': + '@npmcli/installed-package-contents@4.0.0': dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 + npm-bundled: 5.0.0 + npm-normalize-package-bin: 5.0.0 '@npmcli/move-file@2.0.1': dependencies: mkdirp: 1.0.4 rimraf: 3.0.2 - '@npmcli/node-gyp@1.0.3': {} + '@npmcli/node-gyp@5.0.0': {} - '@npmcli/promise-spawn@1.3.2': + '@npmcli/package-json@7.0.5': dependencies: - infer-owner: 1.0.4 + '@npmcli/git': 7.0.2 + glob: 13.0.6 + hosted-git-info: 9.0.2 + json-parse-even-better-errors: 5.0.0 + proc-log: 6.1.0 + semver: 7.8.0 + spdx-expression-parse: 4.0.0 + + '@npmcli/promise-spawn@9.0.1': + dependencies: + which: 6.0.1 + + '@npmcli/redact@4.0.0': {} - '@npmcli/run-script@1.8.6': + '@npmcli/run-script@10.0.4': dependencies: - '@npmcli/node-gyp': 1.0.3 - '@npmcli/promise-spawn': 1.3.2 - node-gyp: 7.1.2 - read-package-json-fast: 2.0.3 + '@npmcli/node-gyp': 5.0.0 + '@npmcli/package-json': 7.0.5 + '@npmcli/promise-spawn': 9.0.1 + node-gyp: 12.2.0 + proc-log: 6.1.0 + transitivePeerDependencies: + - supports-color - '@nuxt/kit@3.17.5': + '@nuxt/kit@3.21.2': dependencies: - c12: 3.0.4 + c12: 3.3.4 consola: 3.4.2 - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 errx: 0.1.0 - exsolve: 1.0.5 + exsolve: 1.0.8 ignore: 7.0.5 - jiti: 2.4.2 + jiti: 2.6.1 klona: 2.0.6 - knitwork: 1.2.0 - mlly: 1.7.4 + knitwork: 1.3.0 + mlly: 1.8.2 ohash: 2.0.11 pathe: 2.0.3 - pkg-types: 2.1.0 + pkg-types: 2.3.0 + rc9: 3.0.1 scule: 1.3.0 - semver: 7.7.2 - std-env: 3.9.0 - tinyglobby: 0.2.14 - ufo: 1.6.1 - unctx: 2.4.1 - unimport: 5.0.1 + semver: 7.8.1 + tinyglobby: 0.2.16 + ufo: 1.6.3 + unctx: 2.5.0 untyped: 2.0.0 transitivePeerDependencies: - magicast - '@octokit/auth-token@2.5.0': - dependencies: - '@octokit/types': 6.41.0 + '@octokit/auth-token@4.0.0': {} - '@octokit/core@3.6.0(encoding@0.1.13)': + '@octokit/core@5.2.2': dependencies: - '@octokit/auth-token': 2.5.0 - '@octokit/graphql': 4.8.0(encoding@0.1.13) - '@octokit/request': 5.6.3(encoding@0.1.13) - '@octokit/request-error': 2.1.0 - '@octokit/types': 6.41.0 + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.1.1 + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 before-after-hook: 2.2.3 universal-user-agent: 6.0.1 - transitivePeerDependencies: - - encoding - '@octokit/endpoint@6.0.12': + '@octokit/endpoint@9.0.6': dependencies: - '@octokit/types': 6.41.0 - is-plain-object: 5.0.0 + '@octokit/types': 13.10.0 universal-user-agent: 6.0.1 - '@octokit/graphql@4.8.0(encoding@0.1.13)': + '@octokit/graphql@7.1.1': dependencies: - '@octokit/request': 5.6.3(encoding@0.1.13) - '@octokit/types': 6.41.0 + '@octokit/request': 8.4.1 + '@octokit/types': 13.10.0 universal-user-agent: 6.0.1 - transitivePeerDependencies: - - encoding '@octokit/openapi-types@12.11.0': {} - '@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0(encoding@0.1.13))': + '@octokit/openapi-types@24.2.0': {} + + '@octokit/plugin-paginate-rest@11.4.4-cjs.2(@octokit/core@5.2.2)': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) - '@octokit/types': 6.41.0 + '@octokit/core': 5.2.2 + '@octokit/types': 13.10.0 - '@octokit/plugin-request-log@1.0.4(@octokit/core@3.6.0(encoding@0.1.13))': + '@octokit/plugin-request-log@4.0.1(@octokit/core@5.2.2)': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) + '@octokit/core': 5.2.2 - '@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0(encoding@0.1.13))': + '@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1(@octokit/core@5.2.2)': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) - '@octokit/types': 6.41.0 - deprecation: 2.3.1 + '@octokit/core': 5.2.2 + '@octokit/types': 13.10.0 - '@octokit/plugin-retry@3.0.9': + '@octokit/plugin-retry@6.1.0(@octokit/core@5.2.2)': dependencies: - '@octokit/types': 6.41.0 + '@octokit/core': 5.2.2 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 bottleneck: 2.19.5 - '@octokit/request-error@2.1.0': + '@octokit/request-error@5.1.1': dependencies: - '@octokit/types': 6.41.0 + '@octokit/types': 13.10.0 deprecation: 2.3.1 once: 1.4.0 - '@octokit/request@5.6.3(encoding@0.1.13)': + '@octokit/request@8.4.1': dependencies: - '@octokit/endpoint': 6.0.12 - '@octokit/request-error': 2.1.0 - '@octokit/types': 6.41.0 - is-plain-object: 5.0.0 - node-fetch: 2.7.0(encoding@0.1.13) + '@octokit/endpoint': 9.0.6 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 universal-user-agent: 6.0.1 - transitivePeerDependencies: - - encoding - '@octokit/rest@18.12.0(encoding@0.1.13)': + '@octokit/rest@20.1.2': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) - '@octokit/plugin-paginate-rest': 2.21.3(@octokit/core@3.6.0(encoding@0.1.13)) - '@octokit/plugin-request-log': 1.0.4(@octokit/core@3.6.0(encoding@0.1.13)) - '@octokit/plugin-rest-endpoint-methods': 5.16.2(@octokit/core@3.6.0(encoding@0.1.13)) - transitivePeerDependencies: - - encoding + '@octokit/core': 5.2.2 + '@octokit/plugin-paginate-rest': 11.4.4-cjs.2(@octokit/core@5.2.2) + '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.2) + '@octokit/plugin-rest-endpoint-methods': 13.3.2-cjs.1(@octokit/core@5.2.2) + + '@octokit/types@13.10.0': + dependencies: + '@octokit/openapi-types': 24.2.0 '@octokit/types@6.41.0': dependencies: '@octokit/openapi-types': 12.11.0 - '@one-ini/wasm@0.1.1': {} + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + + '@opentelemetry/api@1.9.1': {} + + '@oxc-project/types@0.115.0': {} + + '@oxc-project/types@0.124.0': {} + + '@oxc-project/types@0.132.0': {} + + '@oxfmt/binding-android-arm-eabi@0.40.0': + optional: true + + '@oxfmt/binding-android-arm64@0.40.0': + optional: true + + '@oxfmt/binding-darwin-arm64@0.40.0': + optional: true + + '@oxfmt/binding-darwin-x64@0.40.0': + optional: true + + '@oxfmt/binding-freebsd-x64@0.40.0': + optional: true + + '@oxfmt/binding-linux-arm-gnueabihf@0.40.0': + optional: true + + '@oxfmt/binding-linux-arm-musleabihf@0.40.0': + optional: true - '@opentelemetry/api-logs@0.52.1': - dependencies: - '@opentelemetry/api': 1.9.0 + '@oxfmt/binding-linux-arm64-gnu@0.40.0': + optional: true - '@opentelemetry/api@1.9.0': {} + '@oxfmt/binding-linux-arm64-musl@0.40.0': + optional: true - '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 + '@oxfmt/binding-linux-ppc64-gnu@0.40.0': + optional: true - '@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.25.1 + '@oxfmt/binding-linux-riscv64-gnu@0.40.0': + optional: true - '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.28.0 + '@oxfmt/binding-linux-riscv64-musl@0.40.0': + optional: true - '@opentelemetry/instrumentation-connect@0.38.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - '@types/connect': 3.4.36 - transitivePeerDependencies: - - supports-color + '@oxfmt/binding-linux-s390x-gnu@0.40.0': + optional: true - '@opentelemetry/instrumentation-express@0.41.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxfmt/binding-linux-x64-gnu@0.40.0': + optional: true - '@opentelemetry/instrumentation-fastify@0.38.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxfmt/binding-linux-x64-musl@0.40.0': + optional: true - '@opentelemetry/instrumentation-fs@0.14.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@oxfmt/binding-openharmony-arm64@0.40.0': + optional: true - '@opentelemetry/instrumentation-graphql@0.42.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@oxfmt/binding-win32-arm64-msvc@0.40.0': + optional: true - '@opentelemetry/instrumentation-hapi@0.40.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxfmt/binding-win32-ia32-msvc@0.40.0': + optional: true - '@opentelemetry/instrumentation-http@0.52.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.1 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color + '@oxfmt/binding-win32-x64-msvc@0.40.0': + optional: true - '@opentelemetry/instrumentation-ioredis@0.42.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/redis-common': 0.36.2 - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-android-arm-eabi@1.55.0': + optional: true - '@opentelemetry/instrumentation-koa@0.42.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-android-arm64@1.55.0': + optional: true - '@opentelemetry/instrumentation-mongodb@0.46.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-darwin-arm64@1.55.0': + optional: true - '@opentelemetry/instrumentation-mongoose@0.40.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-darwin-x64@1.55.0': + optional: true - '@opentelemetry/instrumentation-mysql2@0.40.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@oxlint/binding-freebsd-x64@1.55.0': + optional: true - '@opentelemetry/instrumentation-mysql@0.40.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - '@types/mysql': 2.15.22 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-linux-arm-gnueabihf@1.55.0': + optional: true - '@opentelemetry/instrumentation-nestjs-core@0.39.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-linux-arm-musleabihf@1.55.0': + optional: true - '@opentelemetry/instrumentation-pg@0.43.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) - '@types/pg': 8.6.1 - '@types/pg-pool': 2.0.4 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-linux-arm64-gnu@1.55.0': + optional: true - '@opentelemetry/instrumentation-redis-4@0.41.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/redis-common': 0.36.2 - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-linux-arm64-musl@1.55.0': + optional: true - '@opentelemetry/instrumentation@0.46.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@types/shimmer': 1.2.0 - import-in-the-middle: 1.7.1 - require-in-the-middle: 7.5.2 - semver: 7.6.3 - shimmer: 1.2.1 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-linux-ppc64-gnu@1.55.0': optional: true - '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.52.1 - '@types/shimmer': 1.2.0 - import-in-the-middle: 1.14.0 - require-in-the-middle: 7.5.2 - semver: 7.6.3 - shimmer: 1.2.1 - transitivePeerDependencies: - - supports-color + '@oxlint/binding-linux-riscv64-gnu@1.55.0': + optional: true - '@opentelemetry/redis-common@0.36.2': {} + '@oxlint/binding-linux-riscv64-musl@1.55.0': + optional: true - '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 + '@oxlint/binding-linux-s390x-gnu@1.55.0': + optional: true - '@opentelemetry/sdk-metrics@1.30.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) + '@oxlint/binding-linux-x64-gnu@1.55.0': + optional: true - '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 + '@oxlint/binding-linux-x64-musl@1.55.0': + optional: true - '@opentelemetry/semantic-conventions@1.25.1': {} + '@oxlint/binding-openharmony-arm64@1.55.0': + optional: true - '@opentelemetry/semantic-conventions@1.28.0': {} + '@oxlint/binding-win32-arm64-msvc@1.55.0': + optional: true - '@opentelemetry/semantic-conventions@1.34.0': {} + '@oxlint/binding-win32-ia32-msvc@1.55.0': + optional: true - '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@oxlint/binding-win32-x64-msvc@1.55.0': + optional: true - '@parcel/watcher-android-arm64@2.5.1': + '@parcel/watcher-android-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-arm64@2.5.1': + '@parcel/watcher-darwin-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-x64@2.5.1': + '@parcel/watcher-darwin-x64@2.5.6': optional: true - '@parcel/watcher-freebsd-x64@2.5.1': + '@parcel/watcher-freebsd-x64@2.5.6': optional: true - '@parcel/watcher-linux-arm-glibc@2.5.1': + '@parcel/watcher-linux-arm-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm-musl@2.5.1': + '@parcel/watcher-linux-arm-musl@2.5.6': optional: true - '@parcel/watcher-linux-arm64-glibc@2.5.1': + '@parcel/watcher-linux-arm64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm64-musl@2.5.1': + '@parcel/watcher-linux-arm64-musl@2.5.6': optional: true - '@parcel/watcher-linux-x64-glibc@2.5.1': + '@parcel/watcher-linux-x64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-x64-musl@2.5.1': + '@parcel/watcher-linux-x64-musl@2.5.6': optional: true - '@parcel/watcher-win32-arm64@2.5.1': + '@parcel/watcher-win32-arm64@2.5.6': optional: true - '@parcel/watcher-win32-ia32@2.5.1': + '@parcel/watcher-win32-ia32@2.5.6': optional: true - '@parcel/watcher-win32-x64@2.5.1': + '@parcel/watcher-win32-x64@2.5.6': optional: true - '@parcel/watcher@2.5.1': + '@parcel/watcher@2.5.6': dependencies: - detect-libc: 1.0.3 + detect-libc: 2.1.2 is-glob: 4.0.3 - micromatch: 4.0.8 node-addon-api: 7.1.1 + picomatch: 4.0.4 optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - - '@pipelab/core@1.4.9': {} + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + optional: true '@pkgjs/parseargs@0.11.0': optional: true - '@pkgr/core@0.2.7': {} + '@pnpm/constants@1001.3.1': {} - '@playwright/test@1.48.1': + '@pnpm/core-loggers@1001.0.9(@pnpm/logger@1001.0.1)': dependencies: - playwright: 1.48.1 + '@pnpm/logger': 1001.0.1 + '@pnpm/types': 1001.3.0 - '@poki/cli@0.1.16': + '@pnpm/error@1000.1.0': dependencies: - archiver: 5.3.2 - form-data: 4.0.3 - open: 8.4.2 - yargs: 17.7.2 + '@pnpm/constants': 1001.3.1 + + '@pnpm/graceful-fs@1000.1.0': + dependencies: + graceful-fs: 4.2.11 + + '@pnpm/logger@1001.0.1': + dependencies: + bole: 5.0.28 + split2: 4.2.0 + + '@pnpm/manifest-utils@1002.0.5(@pnpm/logger@1001.0.1)': + dependencies: + '@pnpm/core-loggers': 1001.0.9(@pnpm/logger@1001.0.1) + '@pnpm/error': 1000.1.0 + '@pnpm/logger': 1001.0.1 + '@pnpm/semver.peer-range': 1000.0.0 + '@pnpm/types': 1001.3.0 + semver: 7.8.1 + + '@pnpm/read-project-manifest@1001.2.6(@pnpm/logger@1001.0.1)': + dependencies: + '@gwhitney/detect-indent': 7.0.1 + '@pnpm/error': 1000.1.0 + '@pnpm/graceful-fs': 1000.1.0 + '@pnpm/logger': 1001.0.1 + '@pnpm/manifest-utils': 1002.0.5(@pnpm/logger@1001.0.1) + '@pnpm/text.comments-parser': 1000.0.0 + '@pnpm/types': 1001.3.0 + '@pnpm/write-project-manifest': 1000.0.16 + fast-deep-equal: 3.1.3 + is-windows: 1.0.2 + json5: 2.2.3 + parse-json: 5.2.0 + read-yaml-file: 2.1.0 + strip-bom: 4.0.0 + + '@pnpm/semver.peer-range@1000.0.0': + dependencies: + semver: 7.8.1 - '@polar-sh/sdk@0.34.8(zod@3.23.8)': + '@pnpm/text.comments-parser@1000.0.0': + dependencies: + strip-comments-strings: 1.2.0 + + '@pnpm/types@1001.3.0': {} + + '@pnpm/write-project-manifest@1000.0.16': + dependencies: + '@pnpm/text.comments-parser': 1000.0.0 + '@pnpm/types': 1001.3.0 + json5: 2.2.3 + write-file-atomic: 5.0.1 + write-yaml-file: 5.0.0 + + '@polar-sh/sdk@0.47.1': dependencies: standardwebhooks: 1.0.0 - zod: 3.23.8 + zod: 4.3.6 '@polka/url@1.0.0-next.29': {} + '@posthog/core@1.27.7': + dependencies: + '@posthog/types': 1.372.3 + + '@posthog/types@1.372.3': {} + '@primeuix/styled@0.2.0': dependencies: '@primeuix/utils': 0.2.0 + '@primeuix/styled@0.7.4': + dependencies: + '@primeuix/utils': 0.6.4 + + '@primeuix/styles@2.0.3': + dependencies: + '@primeuix/styled': 0.7.4 + '@primeuix/utils@0.2.0': {} + '@primeuix/utils@0.6.4': {} + '@primevue/auto-import-resolver@4.1.1': dependencies: '@primevue/metadata': 4.1.1 - '@primevue/core@4.1.1(vue@3.5.13(typescript@5.8.3))': + '@primevue/core@4.5.4(vue@3.5.13(typescript@5.8.3))': dependencies: - '@primeuix/styled': 0.2.0 - '@primeuix/utils': 0.2.0 + '@primeuix/styled': 0.7.4 + '@primeuix/utils': 0.6.4 vue: 3.5.13(typescript@5.8.3) - '@primevue/icons@4.1.1(vue@3.5.13(typescript@5.8.3))': + '@primevue/icons@4.5.4(vue@3.5.13(typescript@5.8.3))': dependencies: - '@primeuix/utils': 0.2.0 - '@primevue/core': 4.1.1(vue@3.5.13(typescript@5.8.3)) + '@primeuix/utils': 0.6.4 + '@primevue/core': 4.5.4(vue@3.5.13(typescript@5.8.3)) transitivePeerDependencies: - vue @@ -9934,323 +10725,286 @@ snapshots: dependencies: '@primeuix/styled': 0.2.0 - '@prisma/instrumentation@5.17.0': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@publint/pack@0.1.4': {} - '@rollup/plugin-inject@5.0.5(rollup@4.42.0)': + '@quansync/fs@1.0.0': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.42.0) - estree-walker: 2.0.2 - magic-string: 0.30.17 - optionalDependencies: - rollup: 4.42.0 + quansync: 1.0.0 - '@rollup/pluginutils@5.1.4(rollup@4.42.0)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.2 - optionalDependencies: - rollup: 4.42.0 + '@rolldown/binding-android-arm64@1.0.0-rc.15': + optional: true - '@rollup/rollup-android-arm-eabi@4.42.0': + '@rolldown/binding-android-arm64@1.0.0-rc.9': optional: true - '@rollup/rollup-android-arm64@4.42.0': + '@rolldown/binding-android-arm64@1.0.2': optional: true - '@rollup/rollup-darwin-arm64@4.42.0': + '@rolldown/binding-darwin-arm64@1.0.0-rc.15': optional: true - '@rollup/rollup-darwin-x64@4.42.0': + '@rolldown/binding-darwin-arm64@1.0.0-rc.9': optional: true - '@rollup/rollup-freebsd-arm64@4.42.0': + '@rolldown/binding-darwin-arm64@1.0.2': optional: true - '@rollup/rollup-freebsd-x64@4.42.0': + '@rolldown/binding-darwin-x64@1.0.0-rc.15': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.42.0': + '@rolldown/binding-darwin-x64@1.0.0-rc.9': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.42.0': + '@rolldown/binding-darwin-x64@1.0.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.42.0': + '@rolldown/binding-freebsd-x64@1.0.0-rc.15': optional: true - '@rollup/rollup-linux-arm64-musl@4.42.0': + '@rolldown/binding-freebsd-x64@1.0.0-rc.9': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.42.0': + '@rolldown/binding-freebsd-x64@1.0.2': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.42.0': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.42.0': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.9': optional: true - '@rollup/rollup-linux-riscv64-musl@4.42.0': + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.42.0': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': optional: true - '@rollup/rollup-linux-x64-gnu@4.42.0': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9': optional: true - '@rollup/rollup-linux-x64-musl@4.42.0': + '@rolldown/binding-linux-arm64-gnu@1.0.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.42.0': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': optional: true - '@rollup/rollup-win32-ia32-msvc@4.42.0': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': optional: true - '@rollup/rollup-win32-x64-msvc@4.42.0': + '@rolldown/binding-linux-arm64-musl@1.0.2': optional: true - '@rushstack/eslint-patch@1.10.4': {} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + optional: true - '@sec-ant/readable-stream@0.4.1': {} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': + optional: true - '@sentry-internal/browser-utils@8.26.0': - dependencies: - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + optional: true - '@sentry-internal/browser-utils@8.32.0': - dependencies: - '@sentry/core': 8.32.0 - '@sentry/types': 8.32.0 - '@sentry/utils': 8.32.0 + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + optional: true - '@sentry-internal/feedback@8.26.0': - dependencies: - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': + optional: true - '@sentry-internal/feedback@8.32.0': - dependencies: - '@sentry/core': 8.32.0 - '@sentry/types': 8.32.0 - '@sentry/utils': 8.32.0 + '@rolldown/binding-linux-s390x-gnu@1.0.2': + optional: true - '@sentry-internal/replay-canvas@8.26.0': - dependencies: - '@sentry-internal/replay': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + optional: true - '@sentry-internal/replay-canvas@8.32.0': - dependencies: - '@sentry-internal/replay': 8.32.0 - '@sentry/core': 8.32.0 - '@sentry/types': 8.32.0 - '@sentry/utils': 8.32.0 + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': + optional: true - '@sentry-internal/replay@8.26.0': - dependencies: - '@sentry-internal/browser-utils': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@rolldown/binding-linux-x64-gnu@1.0.2': + optional: true - '@sentry-internal/replay@8.32.0': - dependencies: - '@sentry-internal/browser-utils': 8.32.0 - '@sentry/core': 8.32.0 - '@sentry/types': 8.32.0 - '@sentry/utils': 8.32.0 + '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + optional: true - '@sentry/babel-plugin-component-annotate@2.22.6': {} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': + optional: true - '@sentry/browser@8.26.0': - dependencies: - '@sentry-internal/browser-utils': 8.26.0 - '@sentry-internal/feedback': 8.26.0 - '@sentry-internal/replay': 8.26.0 - '@sentry-internal/replay-canvas': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@rolldown/binding-linux-x64-musl@1.0.2': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.9': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.2': + optional: true - '@sentry/browser@8.32.0': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': dependencies: - '@sentry-internal/browser-utils': 8.32.0 - '@sentry-internal/feedback': 8.32.0 - '@sentry-internal/replay': 8.32.0 - '@sentry-internal/replay-canvas': 8.32.0 - '@sentry/core': 8.32.0 - '@sentry/types': 8.32.0 - '@sentry/utils': 8.32.0 + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + optional: true - '@sentry/bundler-plugin-core@2.22.6(encoding@0.1.13)': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.9(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@babel/core': 7.27.4 - '@sentry/babel-plugin-component-annotate': 2.22.6 - '@sentry/cli': 2.46.0(encoding@0.1.13) - dotenv: 16.5.0 - find-up: 5.0.0 - glob: 9.3.5 - magic-string: 0.30.8 - unplugin: 1.0.1 + '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) transitivePeerDependencies: - - encoding - - supports-color - - '@sentry/cli-darwin@2.46.0': + - '@emnapi/core' + - '@emnapi/runtime' optional: true - '@sentry/cli-linux-arm64@2.46.0': + '@rolldown/binding-wasm32-wasi@1.0.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@sentry/cli-linux-arm@2.46.0': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': optional: true - '@sentry/cli-linux-i686@2.46.0': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.9': optional: true - '@sentry/cli-linux-x64@2.46.0': + '@rolldown/binding-win32-arm64-msvc@1.0.2': optional: true - '@sentry/cli-win32-arm64@2.46.0': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': optional: true - '@sentry/cli-win32-i686@2.46.0': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.9': optional: true - '@sentry/cli-win32-x64@2.46.0': + '@rolldown/binding-win32-x64-msvc@1.0.2': optional: true - '@sentry/cli@2.46.0(encoding@0.1.13)': + '@rolldown/debug@1.0.0-rc.15': {} + + '@rolldown/pluginutils@1.0.0-rc.15': {} + + '@rolldown/pluginutils@1.0.0-rc.2': {} + + '@rolldown/pluginutils@1.0.0-rc.9': {} + + '@rolldown/pluginutils@1.0.1': {} + + '@rollup/pluginutils@5.3.0(rollup@4.60.1)': dependencies: - https-proxy-agent: 5.0.1 - node-fetch: 2.7.0(encoding@0.1.13) - progress: 2.0.3 - proxy-from-env: 1.1.0 - which: 2.0.2 + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.4 optionalDependencies: - '@sentry/cli-darwin': 2.46.0 - '@sentry/cli-linux-arm': 2.46.0 - '@sentry/cli-linux-arm64': 2.46.0 - '@sentry/cli-linux-i686': 2.46.0 - '@sentry/cli-linux-x64': 2.46.0 - '@sentry/cli-win32-arm64': 2.46.0 - '@sentry/cli-win32-i686': 2.46.0 - '@sentry/cli-win32-x64': 2.46.0 - transitivePeerDependencies: - - encoding - - supports-color + rollup: 4.60.1 - '@sentry/core@8.26.0': - dependencies: - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@rollup/rollup-android-arm-eabi@4.60.1': + optional: true - '@sentry/core@8.32.0': - dependencies: - '@sentry/types': 8.32.0 - '@sentry/utils': 8.32.0 + '@rollup/rollup-android-arm64@4.60.1': + optional: true - '@sentry/electron@5.4.0': - dependencies: - '@sentry/browser': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/node': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 - deepmerge: 4.3.1 - transitivePeerDependencies: - - supports-color + '@rollup/rollup-darwin-arm64@4.60.1': + optional: true - '@sentry/node@8.26.0': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-connect': 0.38.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-express': 0.41.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-fastify': 0.38.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-fs': 0.14.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-graphql': 0.42.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-hapi': 0.40.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-http': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-ioredis': 0.42.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-koa': 0.42.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongodb': 0.46.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongoose': 0.40.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql': 0.40.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql2': 0.40.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-nestjs-core': 0.39.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-pg': 0.43.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-redis-4': 0.41.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - '@prisma/instrumentation': 5.17.0 - '@sentry/core': 8.26.0 - '@sentry/opentelemetry': 8.26.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.34.0) - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 - import-in-the-middle: 1.14.0 - optionalDependencies: - opentelemetry-instrumentation-fetch-node: 1.2.3(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@rollup/rollup-darwin-x64@4.60.1': + optional: true - '@sentry/opentelemetry@8.26.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.34.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@rollup/rollup-freebsd-arm64@4.60.1': + optional: true - '@sentry/types@8.26.0': {} + '@rollup/rollup-freebsd-x64@4.60.1': + optional: true - '@sentry/types@8.32.0': {} + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + optional: true - '@sentry/utils@8.26.0': - dependencies: - '@sentry/types': 8.26.0 + '@rollup/rollup-linux-arm-musleabihf@4.60.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.1': + optional: true + + '@sec-ant/readable-stream@0.4.1': {} - '@sentry/utils@8.32.0': + '@sigstore/bundle@4.0.0': dependencies: - '@sentry/types': 8.32.0 + '@sigstore/protobuf-specs': 0.5.1 + + '@sigstore/core@3.2.0': {} - '@sentry/vite-plugin@2.22.6(encoding@0.1.13)': + '@sigstore/protobuf-specs@0.5.1': {} + + '@sigstore/sign@4.1.1': dependencies: - '@sentry/bundler-plugin-core': 2.22.6(encoding@0.1.13) - unplugin: 1.0.1 + '@gar/promise-retry': 1.0.3 + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.1 + make-fetch-happen: 15.0.5 + proc-log: 6.1.0 transitivePeerDependencies: - - encoding - supports-color - '@sentry/vue@8.32.0(vue@3.5.13(typescript@5.8.3))': + '@sigstore/tuf@4.0.2': dependencies: - '@sentry/browser': 8.32.0 - '@sentry/core': 8.32.0 - '@sentry/types': 8.32.0 - '@sentry/utils': 8.32.0 - vue: 3.5.13(typescript@5.8.3) + '@sigstore/protobuf-specs': 0.5.1 + tuf-js: 4.1.0 + transitivePeerDependencies: + - supports-color - '@sindresorhus/is@0.14.0': {} + '@sigstore/verify@3.1.0': + dependencies: + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.1 '@sindresorhus/is@4.6.0': {} @@ -10258,64 +11012,52 @@ snapshots: '@stablelib/base64@1.0.1': {} - '@supabase/auth-js@2.65.1': + '@supabase/auth-js@2.99.3': dependencies: - '@supabase/node-fetch': 2.6.15 - - '@supabase/functions-js@2.4.3': - dependencies: - '@supabase/node-fetch': 2.6.15 + tslib: 2.8.1 - '@supabase/node-fetch@2.6.15': + '@supabase/functions-js@2.99.3': dependencies: - whatwg-url: 5.0.0 + tslib: 2.8.1 - '@supabase/postgrest-js@1.16.3': + '@supabase/postgrest-js@2.99.3': dependencies: - '@supabase/node-fetch': 2.6.15 + tslib: 2.8.1 - '@supabase/realtime-js@2.10.7': + '@supabase/realtime-js@2.99.3': dependencies: - '@supabase/node-fetch': 2.6.15 - '@types/phoenix': 1.6.6 + '@types/phoenix': 1.6.7 '@types/ws': 8.18.1 + tslib: 2.8.1 ws: 8.18.3 transitivePeerDependencies: - bufferutil - utf-8-validate - '@supabase/storage-js@2.7.1': + '@supabase/storage-js@2.99.3': dependencies: - '@supabase/node-fetch': 2.6.15 + iceberg-js: 0.8.1 + tslib: 2.8.1 - '@supabase/supabase-js@2.45.6': + '@supabase/supabase-js@2.99.3': dependencies: - '@supabase/auth-js': 2.65.1 - '@supabase/functions-js': 2.4.3 - '@supabase/node-fetch': 2.6.15 - '@supabase/postgrest-js': 1.16.3 - '@supabase/realtime-js': 2.10.7 - '@supabase/storage-js': 2.7.1 + '@supabase/auth-js': 2.99.3 + '@supabase/functions-js': 2.99.3 + '@supabase/postgrest-js': 2.99.3 + '@supabase/realtime-js': 2.99.3 + '@supabase/storage-js': 2.99.3 transitivePeerDependencies: - bufferutil - utf-8-validate - '@swc/counter@0.1.3': {} - '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 - '@szmarczak/http-timer@1.1.2': - dependencies: - defer-to-connect: 1.1.3 - '@szmarczak/http-timer@4.0.6': dependencies: defer-to-connect: 2.0.1 - '@tootallnate/once@1.1.2': {} - '@tootallnate/once@2.0.0': {} '@trpc/client@10.45.2(@trpc/server@10.45.2)': @@ -10324,88 +11066,102 @@ snapshots: '@trpc/server@10.45.2': {} - '@tsconfig/node10@1.0.11': {} + '@tufjs/canonical-json@2.0.0': {} - '@tsconfig/node12@1.0.11': {} + '@tufjs/models@4.1.0': + dependencies: + '@tufjs/canonical-json': 2.0.0 + minimatch: 10.2.5 - '@tsconfig/node14@1.0.3': {} + '@turbo/darwin-64@2.9.6': + optional: true - '@tsconfig/node16@1.0.4': {} + '@turbo/darwin-arm64@2.9.6': + optional: true - '@types/archiver@6.0.3': - dependencies: - '@types/readdir-glob': 1.1.5 + '@turbo/linux-64@2.9.6': + optional: true - '@types/cacheable-request@6.0.3': - dependencies: - '@types/http-cache-semantics': 4.0.4 - '@types/keyv': 3.1.4 - '@types/node': 22.7.9 - '@types/responselike': 1.0.3 + '@turbo/linux-arm64@2.9.6': + optional: true - '@types/connect@3.4.36': + '@turbo/windows-64@2.9.6': + optional: true + + '@turbo/windows-arm64@2.9.6': + optional: true + + '@tybys/wasm-util@0.10.1': dependencies: - '@types/node': 22.7.9 + tslib: 2.8.1 + optional: true - '@types/d3-path@3.1.1': {} + '@types/adm-zip@0.5.7': + dependencies: + '@types/node': 24.12.4 - '@types/d3-shape@3.1.6': + '@types/appdmg@0.5.5': dependencies: - '@types/d3-path': 3.1.1 + '@types/node': 24.12.4 + optional: true - '@types/date-fns@2.6.3': + '@types/archiver@7.0.0': dependencies: - date-fns: 4.1.0 + '@types/readdir-glob': 1.1.5 - '@types/dompurify@3.0.5': + '@types/cacheable-request@6.0.3': dependencies: - '@types/trusted-types': 2.0.7 + '@types/http-cache-semantics': 4.2.0 + '@types/keyv': 3.1.4 + '@types/node': 24.12.4 + '@types/responselike': 1.0.3 - '@types/estree@1.0.7': {} + '@types/canvas-confetti@1.9.0': {} - '@types/estree@1.0.8': {} + '@types/cookie@0.6.0': {} - '@types/fs-extra@11.0.4': + '@types/electron-squirrel-startup@1.0.2': {} + + '@types/eslint-scope@3.7.7': dependencies: - '@types/jsonfile': 6.1.4 - '@types/node': 22.7.9 + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 - '@types/fs-extra@9.0.13': + '@types/eslint@9.6.1': dependencies: - '@types/node': 22.7.9 - optional: true + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 - '@types/http-cache-semantics@4.0.4': {} + '@types/estree@1.0.8': {} - '@types/jsdom@21.1.7': - dependencies: - '@types/node': 22.7.9 - '@types/tough-cookie': 4.0.5 - parse5: 7.3.0 + '@types/http-cache-semantics@4.2.0': {} - '@types/json-schema@7.0.15': {} + '@types/jsesc@2.5.1': {} - '@types/jsonfile@6.1.4': - dependencies: - '@types/node': 22.7.9 + '@types/json-schema@7.0.15': {} '@types/keyv@3.1.4': dependencies: - '@types/node': 22.7.9 + '@types/node': 24.12.4 '@types/lodash-es@4.17.12': dependencies: - '@types/lodash': 4.17.17 + '@types/lodash': 4.17.24 - '@types/lodash@4.17.17': {} + '@types/lodash@4.17.24': {} - '@types/mysql@2.15.22': + '@types/mute-stream@0.0.4': dependencies: - '@types/node': 22.7.9 + '@types/node': 24.12.4 + + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 24.12.4 + form-data: 4.0.5 '@types/node@12.20.55': {} - '@types/node@20.19.0': + '@types/node@20.19.39': dependencies: undici-types: 6.21.0 @@ -10413,201 +11169,386 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/path-browserify@1.0.3': {} + '@types/node@24.12.2': + dependencies: + undici-types: 7.16.0 - '@types/pg-pool@2.0.4': + '@types/node@24.12.4': dependencies: - '@types/pg': 8.6.1 + undici-types: 7.16.0 - '@types/pg@8.6.1': + '@types/npm-package-arg@6.1.4': {} + + '@types/npm-registry-fetch@8.0.9': dependencies: - '@types/node': 22.7.9 - pg-protocol: 1.10.0 - pg-types: 2.2.0 + '@types/node': 24.12.4 + '@types/node-fetch': 2.6.13 + '@types/npm-package-arg': 6.1.4 + '@types/npmlog': 7.0.0 + '@types/ssri': 7.1.5 + + '@types/npmlog@7.0.0': + dependencies: + '@types/node': 24.12.4 + + '@types/pacote@11.1.8': + dependencies: + '@types/node': 24.12.4 + '@types/npm-registry-fetch': 8.0.9 + '@types/npmlog': 7.0.0 + '@types/ssri': 7.1.5 - '@types/phoenix@1.6.6': {} + '@types/phoenix@1.6.7': {} '@types/readdir-glob@1.1.5': dependencies: - '@types/node': 22.7.9 + '@types/node': 24.12.4 '@types/responselike@1.0.3': dependencies: - '@types/node': 22.7.9 + '@types/node': 24.12.4 + + '@types/semver@7.7.1': {} + + '@types/ssri@7.1.5': + dependencies: + '@types/node': 24.12.4 + + '@types/statuses@2.0.6': {} - '@types/semver@7.5.8': {} + '@types/tar@6.1.13': + dependencies: + '@types/node': 24.12.4 + minipass: 4.2.8 - '@types/shimmer@1.2.0': {} + '@types/tar@7.0.87': + dependencies: + tar: 6.2.1 '@types/tough-cookie@4.0.5': {} - '@types/trusted-types@2.0.7': {} + '@types/tunnel@0.0.3': + dependencies: + '@types/node': 24.12.4 '@types/web-bluetooth@0.0.20': {} + '@types/wrap-ansi@3.0.0': {} + '@types/ws@8.18.1': dependencies: - '@types/node': 22.7.9 + '@types/node': 24.12.4 '@types/yauzl@2.10.3': dependencies: - '@types/node': 22.7.9 - optional: true + '@types/node': 24.12.4 - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3)': + '@typespec/ts-http-runtime@0.3.5': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/utils': 7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 9.13.0(jiti@2.4.2) - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@5.8.3) - optionalDependencies: - typescript: 5.8.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3)': + '@vee-validate/valibot@4.13.2(vue@3.5.13(typescript@5.8.3))': dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.1 - eslint: 9.13.0(jiti@2.4.2) - optionalDependencies: - typescript: 5.8.3 + type-fest: 4.39.0 + valibot: 0.33.3 + vee-validate: 4.13.2(vue@3.5.13(typescript@5.8.3)) transitivePeerDependencies: - - supports-color + - vue - '@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3)': + '@vitejs/devtools-kit@0.1.13(typescript@5.8.3)(vite@8.0.8)(ws@8.20.0)': dependencies: - '@typescript-eslint/scope-manager': 8.11.0 - '@typescript-eslint/types': 8.11.0 - '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.11.0 - debug: 4.4.1 - eslint: 9.13.0(jiti@2.4.2) - optionalDependencies: - typescript: 5.8.3 + '@vitejs/devtools-rpc': 0.1.13(typescript@5.8.3)(ws@8.20.0) + birpc: 4.0.0 + ohash: 2.0.11 + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@7.18.0': - dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - - '@typescript-eslint/scope-manager@8.11.0': - dependencies: - '@typescript-eslint/types': 8.11.0 - '@typescript-eslint/visitor-keys': 8.11.0 + - typescript + - ws - '@typescript-eslint/type-utils@7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3)': + '@vitejs/devtools-kit@0.1.13(typescript@5.9.3)(vite@8.0.14)(ws@8.20.0)': dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.8.3) - '@typescript-eslint/utils': 7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) - debug: 4.4.1 - eslint: 9.13.0(jiti@2.4.2) - ts-api-utils: 1.4.3(typescript@5.8.3) - optionalDependencies: - typescript: 5.8.3 + '@vitejs/devtools-rpc': 0.1.13(typescript@5.9.3)(ws@8.20.0) + birpc: 4.0.0 + ohash: 2.0.11 + vite: 8.0.14(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@7.18.0': {} + - typescript + - ws + optional: true + + '@vitejs/devtools-rolldown@0.1.13(@pnpm/logger@1001.0.1)(typescript@5.8.3)(vite@8.0.8)(vue@3.5.34(typescript@5.8.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@pnpm/read-project-manifest': 1001.2.6(@pnpm/logger@1001.0.1) + '@rolldown/debug': 1.0.0-rc.15 + '@vitejs/devtools-kit': 0.1.13(typescript@5.8.3)(vite@8.0.8)(ws@8.20.0) + '@vitejs/devtools-rpc': 0.1.13(typescript@5.8.3)(ws@8.20.0) + ansis: 4.2.0 + birpc: 4.0.0 + cac: 7.0.0 + d3-shape: 3.2.0 + diff: 8.0.4 + get-port-please: 3.2.0 + h3: 1.15.11 + mlly: 1.8.2 + mrmime: 2.0.1 + ohash: 2.0.11 + p-limit: 7.3.0 + pathe: 2.0.3 + publint: 0.3.18 + sirv: 3.0.2 + split2: 4.2.0 + structured-clone-es: 2.0.0 + tinyglobby: 0.2.16 + unconfig: 7.5.0 + unstorage: 1.17.5 + vue-virtual-scroller: 2.0.1(vue@3.5.34(typescript@5.8.3)) + ws: 8.20.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@pnpm/logger' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - idb-keyval + - ioredis + - typescript + - uploadthing + - utf-8-validate + - vite + - vue - '@typescript-eslint/types@8.11.0': {} + '@vitejs/devtools-rolldown@0.1.13(@pnpm/logger@1001.0.1)(typescript@5.9.3)(vite@8.0.14)(vue@3.5.34(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@pnpm/read-project-manifest': 1001.2.6(@pnpm/logger@1001.0.1) + '@rolldown/debug': 1.0.0-rc.15 + '@vitejs/devtools-kit': 0.1.13(typescript@5.9.3)(vite@8.0.14)(ws@8.20.0) + '@vitejs/devtools-rpc': 0.1.13(typescript@5.9.3)(ws@8.20.0) + ansis: 4.2.0 + birpc: 4.0.0 + cac: 7.0.0 + d3-shape: 3.2.0 + diff: 8.0.4 + get-port-please: 3.2.0 + h3: 1.15.11 + mlly: 1.8.2 + mrmime: 2.0.1 + ohash: 2.0.11 + p-limit: 7.3.0 + pathe: 2.0.3 + publint: 0.3.18 + sirv: 3.0.2 + split2: 4.2.0 + structured-clone-es: 2.0.0 + tinyglobby: 0.2.16 + unconfig: 7.5.0 + unstorage: 1.17.5 + vue-virtual-scroller: 2.0.1(vue@3.5.34(typescript@5.9.3)) + ws: 8.20.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@pnpm/logger' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - idb-keyval + - ioredis + - typescript + - uploadthing + - utf-8-validate + - vite + - vue + optional: true - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.8.3)': + '@vitejs/devtools-rpc@0.1.13(typescript@5.8.3)(ws@8.20.0)': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.1 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.4.3(typescript@5.8.3) + birpc: 4.0.0 + ohash: 2.0.11 + p-limit: 7.3.0 + structured-clone-es: 2.0.0 + valibot: 1.3.1(typescript@5.8.3) optionalDependencies: - typescript: 5.8.3 + ws: 8.20.0 transitivePeerDependencies: - - supports-color + - typescript - '@typescript-eslint/typescript-estree@8.11.0(typescript@5.8.3)': + '@vitejs/devtools-rpc@0.1.13(typescript@5.9.3)(ws@8.20.0)': dependencies: - '@typescript-eslint/types': 8.11.0 - '@typescript-eslint/visitor-keys': 8.11.0 - debug: 4.4.1 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.4.3(typescript@5.8.3) + birpc: 4.0.0 + ohash: 2.0.11 + p-limit: 7.3.0 + structured-clone-es: 2.0.0 + valibot: 1.3.1(typescript@5.9.3) optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.13.0(jiti@2.4.2)) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.8.3) - eslint: 9.13.0(jiti@2.4.2) + ws: 8.20.0 transitivePeerDependencies: - - supports-color - typescript + optional: true - '@typescript-eslint/visitor-keys@7.18.0': + '@vitejs/devtools@0.1.13(@pnpm/logger@1001.0.1)(typescript@5.8.3)(vite@8.0.8)': dependencies: - '@typescript-eslint/types': 7.18.0 - eslint-visitor-keys: 3.4.3 + '@vitejs/devtools-kit': 0.1.13(typescript@5.8.3)(vite@8.0.8)(ws@8.20.0) + '@vitejs/devtools-rolldown': 0.1.13(@pnpm/logger@1001.0.1)(typescript@5.8.3)(vite@8.0.8)(vue@3.5.34(typescript@5.8.3)) + '@vitejs/devtools-rpc': 0.1.13(typescript@5.8.3)(ws@8.20.0) + birpc: 4.0.0 + cac: 7.0.0 + h3: 1.15.11 + immer: 11.1.4 + launch-editor: 2.13.2 + mlly: 1.8.2 + obug: 2.1.1 + open: 11.0.0 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + tinyexec: 1.1.1 + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vue: 3.5.34(typescript@5.8.3) + ws: 8.20.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@pnpm/logger' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - idb-keyval + - ioredis + - typescript + - uploadthing + - utf-8-validate - '@typescript-eslint/visitor-keys@8.11.0': - dependencies: - '@typescript-eslint/types': 8.11.0 - eslint-visitor-keys: 3.4.3 + '@vitejs/devtools@0.1.13(@pnpm/logger@1001.0.1)(typescript@5.9.3)(vite@8.0.14)': + dependencies: + '@vitejs/devtools-kit': 0.1.13(typescript@5.9.3)(vite@8.0.14)(ws@8.20.0) + '@vitejs/devtools-rolldown': 0.1.13(@pnpm/logger@1001.0.1)(typescript@5.9.3)(vite@8.0.14)(vue@3.5.34(typescript@5.9.3)) + '@vitejs/devtools-rpc': 0.1.13(typescript@5.9.3)(ws@8.20.0) + birpc: 4.0.0 + cac: 7.0.0 + h3: 1.15.11 + immer: 11.1.4 + launch-editor: 2.13.2 + mlly: 1.8.2 + obug: 2.1.1 + open: 11.0.0 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + tinyexec: 1.1.1 + vite: 8.0.14(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vue: 3.5.34(typescript@5.9.3) + ws: 8.20.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@pnpm/logger' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - idb-keyval + - ioredis + - typescript + - uploadthing + - utf-8-validate + optional: true - '@vee-validate/valibot@4.13.2(vue@3.5.13(typescript@5.8.3))': + '@vitejs/plugin-vue@6.0.5(vite@8.0.8)(vue@3.5.13(typescript@5.8.3))': dependencies: - type-fest: 4.26.1 - valibot: 0.33.3 - vee-validate: 4.13.2(vue@3.5.13(typescript@5.8.3)) - transitivePeerDependencies: - - vue + '@rolldown/pluginutils': 1.0.0-rc.2 + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vue: 3.5.13(typescript@5.8.3) - '@vitejs/plugin-vue@5.2.3(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1))(vue@3.5.13(typescript@5.8.3))': + '@vitejs/plugin-vue@6.0.7(vite@8.0.14(@types/node@24.12.4)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1))(vue@3.5.34(typescript@6.0.3))': dependencies: - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - vue: 3.5.13(typescript@5.8.3) + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.14(@types/node@24.12.4)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vue: 3.5.34(typescript@6.0.3) '@vitest/expect@3.1.4': dependencies: '@vitest/spy': 3.1.4 '@vitest/utils': 3.1.4 - chai: 5.2.0 + chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.1.4(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1))': + '@vitest/mocker@3.1.4(msw@2.7.5(@types/node@24.12.2)(typescript@5.8.3))(vite@6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1))': + dependencies: + '@vitest/spy': 3.1.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + msw: 2.7.5(@types/node@24.12.2)(typescript@5.8.3) + vite: 6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + + '@vitest/mocker@3.1.4(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(vite@6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1))': dependencies: '@vitest/spy': 3.1.4 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.21 optionalDependencies: - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) + msw: 2.7.5(@types/node@24.12.2)(typescript@5.9.3) + vite: 6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) '@vitest/pretty-format@3.1.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@3.2.2': + '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 @@ -10619,7 +11560,7 @@ snapshots: '@vitest/snapshot@3.1.4': dependencies: '@vitest/pretty-format': 3.1.4 - magic-string: 0.30.17 + magic-string: 0.30.21 pathe: 2.0.3 '@vitest/spy@3.1.4': @@ -10629,63 +11570,73 @@ snapshots: '@vitest/utils@3.1.4': dependencies: '@vitest/pretty-format': 3.1.4 - loupe: 3.1.3 + loupe: 3.2.1 tinyrainbow: 2.0.0 - '@volar/language-core@2.4.14': + '@volar/language-core@2.4.28': dependencies: - '@volar/source-map': 2.4.14 + '@volar/source-map': 2.4.28 - '@volar/source-map@2.4.14': {} + '@volar/source-map@2.4.28': {} - '@volar/typescript@2.4.14': + '@volar/typescript@2.4.28': dependencies: - '@volar/language-core': 2.4.14 + '@volar/language-core': 2.4.28 path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/babel-helper-vue-transform-on@1.4.0': {} + '@vscode/sudo-prompt@9.3.2': {} - '@vue/babel-plugin-jsx@1.4.0(@babel/core@7.27.4)': + '@vue/babel-helper-vue-transform-on@1.5.0': {} + + '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.0)': dependencies: - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4) - '@babel/template': 7.27.2 - '@babel/traverse': 7.27.4 - '@babel/types': 7.27.6 - '@vue/babel-helper-vue-transform-on': 1.4.0 - '@vue/babel-plugin-resolve-type': 1.4.0(@babel/core@7.27.4) - '@vue/shared': 3.5.16 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@vue/babel-helper-vue-transform-on': 1.5.0 + '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.0) + '@vue/shared': 3.5.32 optionalDependencies: - '@babel/core': 7.27.4 + '@babel/core': 7.29.0 transitivePeerDependencies: - supports-color - '@vue/babel-plugin-resolve-type@1.4.0(@babel/core@7.27.4)': + '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.0)': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/core': 7.27.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/parser': 7.27.5 - '@vue/compiler-sfc': 3.5.16 + '@babel/code-frame': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/parser': 7.29.2 + '@vue/compiler-sfc': 3.5.32 transitivePeerDependencies: - supports-color '@vue/compiler-core@3.5.13': dependencies: - '@babel/parser': 7.27.5 + '@babel/parser': 7.29.2 '@vue/shared': 3.5.13 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-core@3.5.16': + '@vue/compiler-core@3.5.32': dependencies: - '@babel/parser': 7.27.5 - '@vue/shared': 3.5.16 - entities: 4.5.0 + '@babel/parser': 7.29.2 + '@vue/shared': 3.5.32 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-core@3.5.34': + dependencies: + '@babel/parser': 7.29.3 + '@vue/shared': 3.5.34 + entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 @@ -10694,33 +11645,50 @@ snapshots: '@vue/compiler-core': 3.5.13 '@vue/shared': 3.5.13 - '@vue/compiler-dom@3.5.16': + '@vue/compiler-dom@3.5.32': dependencies: - '@vue/compiler-core': 3.5.16 - '@vue/shared': 3.5.16 + '@vue/compiler-core': 3.5.32 + '@vue/shared': 3.5.32 + + '@vue/compiler-dom@3.5.34': + dependencies: + '@vue/compiler-core': 3.5.34 + '@vue/shared': 3.5.34 '@vue/compiler-sfc@3.5.13': dependencies: - '@babel/parser': 7.27.5 + '@babel/parser': 7.29.2 '@vue/compiler-core': 3.5.13 '@vue/compiler-dom': 3.5.13 '@vue/compiler-ssr': 3.5.13 '@vue/shared': 3.5.13 estree-walker: 2.0.2 - magic-string: 0.30.17 - postcss: 8.5.4 + magic-string: 0.30.21 + postcss: 8.5.9 + source-map-js: 1.2.1 + + '@vue/compiler-sfc@3.5.32': + dependencies: + '@babel/parser': 7.29.2 + '@vue/compiler-core': 3.5.32 + '@vue/compiler-dom': 3.5.32 + '@vue/compiler-ssr': 3.5.32 + '@vue/shared': 3.5.32 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.9 source-map-js: 1.2.1 - '@vue/compiler-sfc@3.5.16': + '@vue/compiler-sfc@3.5.34': dependencies: - '@babel/parser': 7.27.5 - '@vue/compiler-core': 3.5.16 - '@vue/compiler-dom': 3.5.16 - '@vue/compiler-ssr': 3.5.16 - '@vue/shared': 3.5.16 + '@babel/parser': 7.29.3 + '@vue/compiler-core': 3.5.34 + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 estree-walker: 2.0.2 - magic-string: 0.30.17 - postcss: 8.5.4 + magic-string: 0.30.21 + postcss: 8.5.15 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.13': @@ -10728,10 +11696,15 @@ snapshots: '@vue/compiler-dom': 3.5.13 '@vue/shared': 3.5.13 - '@vue/compiler-ssr@3.5.16': + '@vue/compiler-ssr@3.5.32': + dependencies: + '@vue/compiler-dom': 3.5.32 + '@vue/shared': 3.5.32 + + '@vue/compiler-ssr@3.5.34': dependencies: - '@vue/compiler-dom': 3.5.16 - '@vue/shared': 3.5.16 + '@vue/compiler-dom': 3.5.34 + '@vue/shared': 3.5.34 '@vue/compiler-vue2@2.7.16': dependencies: @@ -10740,85 +11713,93 @@ snapshots: '@vue/devtools-api@6.6.4': {} - '@vue/devtools-api@7.7.6': + '@vue/devtools-api@7.7.9': dependencies: - '@vue/devtools-kit': 7.7.6 + '@vue/devtools-kit': 7.7.9 - '@vue/devtools-core@7.7.6(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1))(vue@3.5.13(typescript@5.8.3))': + '@vue/devtools-core@8.1.1(vue@3.5.13(typescript@5.8.3))': dependencies: - '@vue/devtools-kit': 7.7.6 - '@vue/devtools-shared': 7.7.6 - mitt: 3.0.1 - nanoid: 5.1.5 - pathe: 2.0.3 - vite-hot-client: 2.0.4(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) + '@vue/devtools-kit': 8.1.1 + '@vue/devtools-shared': 8.1.1 vue: 3.5.13(typescript@5.8.3) - transitivePeerDependencies: - - vite - '@vue/devtools-kit@7.7.6': + '@vue/devtools-kit@7.7.9': dependencies: - '@vue/devtools-shared': 7.7.6 - birpc: 2.3.0 + '@vue/devtools-shared': 7.7.9 + birpc: 2.9.0 hookable: 5.5.3 mitt: 3.0.1 perfect-debounce: 1.0.0 speakingurl: 14.0.1 - superjson: 2.2.2 + superjson: 2.2.6 - '@vue/devtools-shared@7.7.6': + '@vue/devtools-kit@8.1.1': dependencies: - rfdc: 1.4.1 + '@vue/devtools-shared': 8.1.1 + birpc: 2.9.0 + hookable: 5.5.3 + perfect-debounce: 2.1.0 - '@vue/eslint-config-prettier@9.0.0(eslint@9.13.0(jiti@2.4.2))(prettier@3.3.3)': + '@vue/devtools-shared@7.7.9': dependencies: - eslint: 9.13.0(jiti@2.4.2) - eslint-config-prettier: 9.1.0(eslint@9.13.0(jiti@2.4.2)) - eslint-plugin-prettier: 5.4.1(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.2)))(eslint@9.13.0(jiti@2.4.2))(prettier@3.3.3) - prettier: 3.3.3 - transitivePeerDependencies: - - '@types/eslint' + rfdc: 1.4.1 - '@vue/eslint-config-typescript@13.0.0(eslint-plugin-vue@9.29.1(eslint@9.13.0(jiti@2.4.2)))(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/parser': 7.18.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.8.3) - eslint: 9.13.0(jiti@2.4.2) - eslint-plugin-vue: 9.29.1(eslint@9.13.0(jiti@2.4.2)) - vue-eslint-parser: 9.4.3(eslint@9.13.0(jiti@2.4.2)) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color + '@vue/devtools-shared@8.1.1': {} '@vue/language-core@2.1.6(typescript@5.8.3)': dependencies: - '@volar/language-core': 2.4.14 - '@vue/compiler-dom': 3.5.16 + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.32 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.16 + '@vue/shared': 3.5.32 computeds: 0.0.1 - minimatch: 9.0.5 + minimatch: 9.0.9 muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: typescript: 5.8.3 + '@vue/language-core@3.3.1': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.32 + '@vue/shared': 3.5.32 + alien-signals: 3.2.1 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.4 + '@vue/reactivity@3.5.13': dependencies: '@vue/shared': 3.5.13 + '@vue/reactivity@3.5.34': + dependencies: + '@vue/shared': 3.5.34 + '@vue/runtime-core@3.5.13': dependencies: '@vue/reactivity': 3.5.13 '@vue/shared': 3.5.13 + '@vue/runtime-core@3.5.34': + dependencies: + '@vue/reactivity': 3.5.34 + '@vue/shared': 3.5.34 + '@vue/runtime-dom@3.5.13': dependencies: '@vue/reactivity': 3.5.13 '@vue/runtime-core': 3.5.13 '@vue/shared': 3.5.13 - csstype: 3.1.3 + csstype: 3.2.3 + + '@vue/runtime-dom@3.5.34': + dependencies: + '@vue/reactivity': 3.5.34 + '@vue/runtime-core': 3.5.34 + '@vue/shared': 3.5.34 + csstype: 3.2.3 '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.3))': dependencies: @@ -10826,14 +11807,35 @@ snapshots: '@vue/shared': 3.5.13 vue: 3.5.13(typescript@5.8.3) - '@vue/shared@3.5.13': {} + '@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.8.3))': + dependencies: + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 + vue: 3.5.34(typescript@5.8.3) - '@vue/shared@3.5.16': {} + '@vue/server-renderer@3.5.34(vue@3.5.34(typescript@5.9.3))': + dependencies: + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 + vue: 3.5.34(typescript@5.9.3) + optional: true - '@vue/test-utils@2.4.6': + '@vue/server-renderer@3.5.34(vue@3.5.34(typescript@6.0.3))': dependencies: - js-beautify: 1.15.4 - vue-component-type-helpers: 2.2.10 + '@vue/compiler-ssr': 3.5.34 + '@vue/shared': 3.5.34 + vue: 3.5.34(typescript@6.0.3) + + '@vue/shared@3.5.13': {} + + '@vue/shared@3.5.32': {} + + '@vue/shared@3.5.34': {} + + '@vue/tsconfig@0.9.1(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3))': + optionalDependencies: + typescript: 6.0.3 + vue: 3.5.34(typescript@6.0.3) '@vuelidate/core@2.0.3(vue@3.5.13(typescript@5.8.3))': dependencies: @@ -10882,47 +11884,111 @@ snapshots: - '@vue/composition-api' - vue - '@xmldom/xmldom@0.8.10': {} + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - abbrev@1.1.1: {} + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - abbrev@2.0.0: {} + '@webassemblyjs/helper-api-error@1.13.2': {} - abort-controller@3.0.0: + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': dependencies: - event-target-shim: 5.0.1 + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 - accepts@1.3.8: + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 - acorn-import-assertions@1.9.0(acorn@8.15.0): + '@webassemblyjs/ieee754@1.13.2': dependencies: - acorn: 8.15.0 - optional: true + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - acorn-import-attributes@1.9.5(acorn@8.15.0): + '@webassemblyjs/wasm-opt@1.14.1': dependencies: - acorn: 8.15.0 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xmldom/xmldom@0.8.12': {} + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + abbrev@1.1.1: {} + + abbrev@4.0.0: {} - acorn-jsx@5.3.2(acorn@8.15.0): + abort-controller@3.0.0: dependencies: - acorn: 8.15.0 + event-target-shim: 5.0.1 - acorn-walk@8.3.4: + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} + + adm-zip@0.5.16: {} agent-base@6.0.2: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color - agent-base@7.1.3: {} + agent-base@7.1.4: {} agentkeepalive@4.6.0: dependencies: @@ -10933,16 +11999,23 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 - ajv@6.12.6: + ajv-formats@2.1.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-keywords@5.1.0(ajv@8.18.0): dependencies: + ajv: 8.18.0 fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - ansi-align@3.0.1: + ajv@8.18.0: dependencies: - string-width: 4.2.3 + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + alien-signals@3.2.1: {} ansi-colors@4.1.3: {} @@ -10954,26 +12027,22 @@ snapshots: dependencies: type-fest: 1.4.0 - ansi-regex@2.1.1: {} - ansi-regex@5.0.1: {} - ansi-regex@6.1.0: {} - - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 + ansi-regex@6.2.2: {} ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} + + ansis@4.2.0: {} anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 appdmg@0.6.6: dependencies: @@ -10990,54 +12059,16 @@ snapshots: repeat-string: 1.6.1 optional: true - aproba@1.2.0: {} - - archiver-utils@2.1.0: - dependencies: - glob: 7.2.3 - graceful-fs: 4.2.11 - lazystream: 1.0.1 - lodash.defaults: 4.2.0 - lodash.difference: 4.5.0 - lodash.flatten: 4.4.0 - lodash.isplainobject: 4.0.6 - lodash.union: 4.6.0 - normalize-path: 3.0.0 - readable-stream: 2.3.8 - - archiver-utils@3.0.4: - dependencies: - glob: 7.2.3 - graceful-fs: 4.2.11 - lazystream: 1.0.1 - lodash.defaults: 4.2.0 - lodash.difference: 4.5.0 - lodash.flatten: 4.4.0 - lodash.isplainobject: 4.0.6 - lodash.union: 4.6.0 - normalize-path: 3.0.0 - readable-stream: 3.6.2 - archiver-utils@5.0.2: dependencies: - glob: 10.4.5 + glob: 10.5.0 graceful-fs: 4.2.11 is-stream: 2.0.1 lazystream: 1.0.1 - lodash: 4.17.21 + lodash: 4.18.1 normalize-path: 3.0.0 readable-stream: 4.7.0 - archiver@5.3.2: - dependencies: - archiver-utils: 2.1.0 - async: 3.2.6 - buffer-crc32: 0.2.13 - readable-stream: 3.6.2 - readdir-glob: 1.1.3 - tar-stream: 2.2.0 - zip-stream: 4.1.1 - archiver@7.0.1: dependencies: archiver-utils: 5.0.2 @@ -11045,15 +12076,12 @@ snapshots: buffer-crc32: 1.0.0 readable-stream: 4.7.0 readdir-glob: 1.1.3 - tar-stream: 3.1.7 + tar-stream: 3.1.8 zip-stream: 6.0.1 - - are-we-there-yet@1.1.7: - dependencies: - delegates: 1.0.0 - readable-stream: 2.3.8 - - arg@4.1.3: {} + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a argparse@1.0.10: dependencies: @@ -11061,48 +12089,15 @@ snapshots: argparse@2.0.1: {} - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - array-flatten@1.1.1: {} - array-union@2.1.0: {} - arraybuffer.prototype.slice@1.0.4: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - - asn1.js@4.10.1: - dependencies: - bn.js: 4.12.2 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - asn1@0.2.6: - dependencies: - safer-buffer: 2.1.2 - - assert-plus@1.0.0: {} - - assert@2.1.0: - dependencies: - call-bind: 1.0.8 - is-nan: 1.3.2 - object-is: 1.1.6 - object.assign: 4.1.7 - util: 0.12.5 - assertion-error@2.0.1: {} - async-function@1.0.0: {} + ast-kit@3.0.0-beta.1: + dependencies: + '@babel/parser': 8.0.0-rc.2 + estree-walker: 3.0.3 + pathe: 2.0.3 async@1.5.2: optional: true @@ -11115,28 +12110,43 @@ snapshots: author-regex@1.0.0: {} - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 + b4a@1.8.0: {} - aws-sign2@0.7.0: {} + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} - aws4@1.13.2: {} + bare-events@2.8.2: {} - axios@1.9.0: + bare-fs@4.7.0: dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.3 - proxy-from-env: 1.1.0 + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.13.0(bare-events@2.8.2) + bare-url: 2.4.0 + fast-fifo: 1.3.2 transitivePeerDependencies: - - debug + - bare-abort-controller + - react-native-b4a - b4a@1.6.7: {} + bare-os@3.8.7: {} - balanced-match@1.0.2: {} + bare-path@3.0.0: + dependencies: + bare-os: 3.8.7 - bare-events@2.5.4: - optional: true + bare-stream@2.13.0(bare-events@2.8.2): + dependencies: + streamx: 2.25.0 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - react-native-b4a + + bare-url@2.4.0: + dependencies: + bare-path: 3.0.0 base32-encode@1.2.0: dependencies: @@ -11145,9 +12155,7 @@ snapshots: base64-js@1.5.1: {} - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 + baseline-browser-mapping@2.10.18: {} before-after-hook@2.2.3: {} @@ -11157,7 +12165,9 @@ snapshots: binary-extensions@2.3.0: {} - birpc@2.3.0: {} + birpc@2.9.0: {} + + birpc@4.0.0: {} bl@4.1.0: dependencies: @@ -11167,128 +12177,53 @@ snapshots: bluebird@3.7.2: {} - bn.js@4.12.2: {} - - bn.js@5.2.2: {} - - body-parser@1.20.3: + bole@5.0.28: dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - boolbase@1.0.0: {} + fast-safe-stringify: 2.1.1 + individual: 3.0.0 boolean@3.2.0: optional: true bottleneck@2.19.5: {} - boxen@5.1.2: - dependencies: - ansi-align: 3.0.1 - camelcase: 6.3.0 - chalk: 4.1.0 - cli-boxes: 2.2.1 - string-width: 4.2.3 - type-fest: 0.20.2 - widest-line: 3.1.0 - wrap-ansi: 7.0.0 - bplist-creator@0.0.8: dependencies: stream-buffers: 2.2.0 optional: true - brace-expansion@1.1.11: + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.1: + brace-expansion@2.1.0: dependencies: balanced-match: 1.0.2 - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - brorand@1.1.0: {} - - browser-resolve@2.0.0: - dependencies: - resolve: 1.22.10 - - browserify-aes@1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.6 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-cipher@1.0.1: - dependencies: - browserify-aes: 1.2.0 - browserify-des: 1.0.2 - evp_bytestokey: 1.0.3 - - browserify-des@1.0.2: - dependencies: - cipher-base: 1.0.6 - des.js: 1.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-rsa@4.1.1: - dependencies: - bn.js: 5.2.2 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - browserify-sign@4.2.3: + brace-expansion@5.0.5: dependencies: - bn.js: 5.2.2 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - create-hmac: 1.1.7 - elliptic: 6.6.1 - hash-base: 3.0.5 - inherits: 2.0.4 - parse-asn1: 5.1.7 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 + balanced-match: 4.0.4 - browserify-zlib@0.2.0: + braces@3.0.3: dependencies: - pako: 1.0.11 + fill-range: 7.1.1 - browserslist@4.25.0: + browserslist@4.28.2: dependencies: - caniuse-lite: 1.0.30001721 - electron-to-chromium: 1.5.165 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.0) + baseline-browser-mapping: 2.10.18 + caniuse-lite: 1.0.30001788 + electron-to-chromium: 1.5.336 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) buffer-crc32@0.2.13: {} buffer-crc32@1.0.0: {} - buffer-from@1.1.2: {} + buffer-equal-constant-time@1.0.1: {} - buffer-xor@1.0.3: {} + buffer-from@1.1.2: {} buffer@5.7.1: dependencies: @@ -11300,61 +12235,30 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - builtin-status-codes@3.0.0: {} - - builtins@1.0.3: {} - bundle-name@4.1.0: dependencies: - run-applescript: 7.0.0 - - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 + run-applescript: 7.1.0 bytes@3.0.0: {} - bytes@3.1.2: {} - - c12@3.0.4: + c12@3.3.4: dependencies: - chokidar: 4.0.3 - confbox: 0.2.2 - defu: 6.1.4 - dotenv: 16.5.0 - exsolve: 1.0.5 - giget: 2.0.0 - jiti: 2.4.2 + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 17.4.2 + exsolve: 1.0.8 + giget: 3.2.0 + jiti: 2.6.1 ohash: 2.0.11 pathe: 2.0.3 - perfect-debounce: 1.0.0 - pkg-types: 2.1.0 - rc9: 2.1.2 + perfect-debounce: 2.1.0 + pkg-types: 2.3.0 + rc9: 3.0.1 cac@6.7.14: {} - cacache@15.3.0(bluebird@3.7.2): - dependencies: - '@npmcli/fs': 1.1.1 - '@npmcli/move-file': 1.1.2 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 7.2.3 - infer-owner: 1.0.4 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 - p-map: 4.0.0 - promise-inflight: 1.0.1(bluebird@3.7.2) - rimraf: 3.0.2 - ssri: 8.0.1 - tar: 6.2.1 - unique-filename: 1.1.1 - transitivePeerDependencies: - - bluebird + cac@7.0.0: {} cacache@16.1.3: dependencies: @@ -11367,11 +12271,11 @@ snapshots: lru-cache: 7.18.3 minipass: 3.3.6 minipass-collect: 1.0.2 - minipass-flush: 1.0.5 + minipass-flush: 1.0.7 minipass-pipeline: 1.2.4 mkdirp: 1.0.4 p-map: 4.0.0 - promise-inflight: 1.0.1(bluebird@3.7.2) + promise-inflight: 1.0.1 rimraf: 3.0.2 ssri: 9.0.1 tar: 6.2.1 @@ -11379,17 +12283,20 @@ snapshots: transitivePeerDependencies: - bluebird - cacheable-lookup@5.0.4: {} - - cacheable-request@6.1.0: + cacache@20.0.4: dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.2.0 - keyv: 3.1.0 - lowercase-keys: 2.0.0 - normalize-url: 4.5.1 - responselike: 1.0.2 + '@npmcli/fs': 5.0.0 + fs-minipass: 3.0.3 + glob: 13.0.6 + lru-cache: 11.3.5 + minipass: 7.1.3 + minipass-collect: 2.0.1 + minipass-flush: 1.0.7 + minipass-pipeline: 1.2.4 + p-map: 7.0.4 + ssri: 13.0.1 + + cacheable-lookup@5.0.4: {} cacheable-request@7.0.4: dependencies: @@ -11406,44 +12313,17 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - camelcase@6.3.0: {} - - caniuse-lite@1.0.30001721: {} + caniuse-lite@1.0.30001788: {} - caseless@0.12.0: {} + canvas-confetti@1.9.4: {} - chai@5.2.0: + chai@5.3.3: dependencies: assertion-error: 2.0.1 - check-error: 2.1.1 + check-error: 2.1.3 deep-eql: 5.0.2 - loupe: 3.1.3 - pathval: 2.0.0 - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - chalk@4.1.0: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 + loupe: 3.2.1 + pathval: 2.0.1 chalk@4.1.2: dependencies: @@ -11454,7 +12334,11 @@ snapshots: chardet@0.7.0: {} - check-error@2.1.1: {} + chardet@2.1.1: {} + + check-disk-space@3.4.0: {} + + check-error@2.1.3: {} chokidar@3.6.0: dependencies: @@ -11471,32 +12355,24 @@ snapshots: chokidar@4.0.3: dependencies: readdirp: 4.1.2 + optional: true - chownr@2.0.0: {} - - chrome-trace-event@1.0.4: {} - - ci-info@2.0.0: {} + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 - ci-info@3.9.0: {} + chownr@2.0.0: {} - cint@8.2.1: {} + chownr@3.0.0: {} - cipher-base@1.0.6: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 + chrome-trace-event@1.0.4: {} citty@0.1.6: dependencies: consola: 3.4.2 - cjs-module-lexer@1.4.3: {} - clean-stack@2.2.0: {} - cli-boxes@2.2.1: {} - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -11507,25 +12383,15 @@ snapshots: cli-spinners@2.9.2: {} - cli-table@0.3.5: - dependencies: - colors: 1.0.3 - cli-truncate@3.1.0: dependencies: slice-ansi: 5.0.0 string-width: 5.1.2 - cli-width@3.0.0: {} + cli-width@4.1.0: {} client-only@0.0.1: {} - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -11538,70 +12404,39 @@ snapshots: clone@1.0.4: {} - code-point-at@1.1.0: {} - - code-tag@1.2.0: {} - - codsen-utils@1.6.7: + codsen-utils@1.7.3: dependencies: rfdc: 1.4.1 color-convert@0.5.3: optional: true - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - color-convert@2.0.1: dependencies: color-name: 1.1.4 - color-name@1.1.3: {} - color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} - colors@1.0.3: {} + colorjs.io@0.5.2: {} combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 - commander@10.0.1: {} - commander@11.1.0: {} - commander@4.1.1: {} + commander@12.1.0: {} - commander@5.1.0: {} + commander@2.20.3: {} - commander@6.2.1: {} + commander@5.1.0: {} commander@9.5.0: {} compare-version@0.1.2: {} - compress-commons@4.1.2: - dependencies: - buffer-crc32: 0.2.13 - crc32-stream: 4.0.3 - normalize-path: 3.0.0 - readable-stream: 3.6.2 - compress-commons@6.0.2: dependencies: crc-32: 1.2.2 @@ -11616,98 +12451,41 @@ snapshots: confbox@0.1.8: {} - confbox@0.2.2: {} - - config-chain@1.1.13: - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - - configstore@5.0.1: - dependencies: - dot-prop: 5.3.0 - graceful-fs: 4.2.11 - make-dir: 3.1.0 - unique-string: 2.0.0 - write-file-atomic: 3.0.3 - xdg-basedir: 4.0.0 + confbox@0.2.4: {} consola@3.4.2: {} - console-browserify@1.2.0: {} - - console-control-strings@1.1.0: {} - - constants-browserify@1.0.0: {} - content-disposition@0.5.2: {} - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - convert-source-map@2.0.0: {} - cookie-signature@1.0.6: {} + cookie-es@1.2.3: {} - cookie@0.7.1: {} - - copy-anything@2.0.6: - dependencies: - is-what: 3.14.1 + cookie@0.7.2: {} - copy-anything@3.0.5: + copy-anything@4.0.5: dependencies: - is-what: 4.1.16 + is-what: 5.5.0 - core-js@3.43.0: {} - - core-util-is@1.0.2: {} + core-js@3.49.0: {} core-util-is@1.0.3: {} crc-32@1.2.2: {} - crc32-stream@4.0.3: - dependencies: - crc-32: 1.2.2 - readable-stream: 3.6.2 - crc32-stream@6.0.0: dependencies: crc-32: 1.2.2 readable-stream: 4.7.0 - create-ecdh@4.0.4: - dependencies: - bn.js: 4.12.2 - elliptic: 6.6.1 - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.6 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - - create-hmac@1.1.7: - dependencies: - cipher-base: 1.0.6 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - - create-require@1.1.1: {} - crelt@1.0.6: {} cross-dirname@0.1.0: {} + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + cross-spawn@6.0.6: dependencies: nice-try: 1.0.5 @@ -11724,31 +12502,11 @@ snapshots: cross-zip@4.0.1: {} - crypto-browserify@3.12.1: - dependencies: - browserify-cipher: 1.0.1 - browserify-sign: 4.2.3 - create-ecdh: 4.0.4 - create-hash: 1.2.0 - create-hmac: 1.1.7 - diffie-hellman: 5.0.3 - hash-base: 3.0.5 - inherits: 2.0.4 - pbkdf2: 3.1.2 - public-encrypt: 4.0.3 - randombytes: 2.1.0 - randomfill: 1.0.4 - - crypto-random-string@2.0.0: {} - - cssesc@3.0.0: {} - - cssstyle@4.4.0: + crossws@0.3.5: dependencies: - '@asamuzakjp/css-color': 3.2.0 - rrweb-cssom: 0.8.0 + uncrypto: 0.1.3 - csstype@3.1.3: {} + csstype@3.2.3: {} d3-path@3.1.0: {} @@ -11756,35 +12514,6 @@ snapshots: dependencies: d3-path: 3.1.0 - dashdash@1.14.1: - dependencies: - assert-plus: 1.0.0 - - data-urls@5.0.0: - dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 - - data-view-buffer@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-offset@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - dataloader@1.4.0: {} - date-fns@4.1.0: {} de-indent@1.0.2: {} @@ -11793,43 +12522,29 @@ snapshots: dependencies: ms: 2.0.0 - debug@4.4.1: + debug@4.4.3: dependencies: ms: 2.1.3 - decimal.js@10.5.0: {} - - decompress-response@3.3.0: - dependencies: - mimic-response: 1.0.1 - decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 deep-eql@5.0.2: {} - deep-extend@0.6.0: {} - - deep-is@0.1.4: {} - deep-pick-omit@1.2.1: {} - deepmerge@4.3.1: {} - - default-browser-id@5.0.0: {} + default-browser-id@5.0.1: {} - default-browser@5.2.1: + default-browser@5.5.0: dependencies: bundle-name: 4.1.0 - default-browser-id: 5.0.0 + default-browser-id: 5.0.1 defaults@1.0.4: dependencies: clone: 1.0.4 - defer-to-connect@1.1.3: {} - defer-to-connect@2.0.1: {} define-data-property@1.1.4: @@ -11837,86 +12552,48 @@ snapshots: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + optional: true - define-lazy-prop@2.0.0: {} - - define-lazy-prop@3.0.0: {} - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - defu@6.1.4: {} - - del@6.0.0: - dependencies: - globby: 11.1.0 - graceful-fs: 4.2.11 - is-glob: 4.0.3 - is-path-cwd: 2.2.0 - is-path-inside: 3.0.3 - p-map: 4.0.0 - rimraf: 3.0.2 - slash: 3.0.0 - - delayed-stream@1.0.0: {} - - delegates@1.0.0: {} - - depd@2.0.0: {} + define-lazy-prop@2.0.0: {} - deprecation@2.3.1: {} + define-lazy-prop@3.0.0: {} - des.js@1.1.0: + define-properties@1.2.1: dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + optional: true - destr@2.0.5: {} + defu@6.1.7: {} + + delayed-stream@1.0.0: {} - destroy@1.2.0: {} + deprecation@2.3.1: {} - detect-indent@6.0.0: {} + destr@2.0.5: {} detect-indent@6.1.0: {} - detect-libc@1.0.3: {} - - detect-libc@2.0.4: {} + detect-libc@2.1.2: {} detect-node@2.1.0: optional: true - diff@4.0.2: {} - - diffie-hellman@5.0.3: - dependencies: - bn.js: 4.12.2 - miller-rabin: 4.0.1 - randombytes: 2.1.0 + diff@8.0.4: {} dir-compare@4.2.0: dependencies: - minimatch: 3.1.2 + minimatch: 3.1.5 p-limit: 3.1.0 dir-glob@3.0.1: dependencies: path-type: 4.0.0 - domain-browser@4.22.0: {} - dompurify@3.1.7: {} - dot-prop@5.3.0: - dependencies: - is-obj: 2.0.0 - - dotenv@16.5.0: {} - - dotenv@8.6.0: {} + dotenv@17.4.2: {} driver.js@1.4.0: {} @@ -11927,75 +12604,24 @@ snapshots: tn1150: 0.1.0 optional: true + dts-resolver@2.1.3: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 - duplexer3@0.1.5: {} - eastasianwidth@0.2.0: {} - ecc-jsbn@0.1.2: - dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 - - editorconfig@1.0.4: - dependencies: - '@one-ini/wasm': 0.1.1 - commander: 10.0.1 - minimatch: 9.0.1 - semver: 7.6.3 - - editorconfig@2.0.0: - dependencies: - '@one-ini/wasm': 0.1.1 - commander: 11.1.0 - minimatch: 9.0.2 - semver: 7.6.3 - - ee-first@1.1.1: {} - - ejs@3.1.10: + ecdsa-sig-formatter@1.0.11: dependencies: - jake: 10.9.2 - - electron-installer-common@0.10.4: - dependencies: - '@electron/asar': 3.4.1 - '@malept/cross-spawn-promise': 1.1.1 - debug: 4.4.1 - fs-extra: 9.1.0 - glob: 7.2.3 - lodash: 4.17.21 - parse-author: 2.0.0 - semver: 7.6.3 - tmp-promise: 3.0.3 - optionalDependencies: - '@types/fs-extra': 9.0.13 - transitivePeerDependencies: - - supports-color - optional: true - - electron-installer-debian@3.2.0: - dependencies: - '@malept/cross-spawn-promise': 1.1.1 - debug: 4.4.1 - electron-installer-common: 0.10.4 - fs-extra: 9.1.0 - get-folder-size: 2.0.1 - lodash: 4.17.21 - word-wrap: 1.2.5 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - optional: true + safe-buffer: 5.2.1 - electron-installer-dmg@4.0.0: + electron-installer-dmg@5.0.1: dependencies: - debug: 4.4.1 + '@types/appdmg': 0.5.5 + debug: 4.4.3 minimist: 1.2.8 optionalDependencies: appdmg: 0.6.6 @@ -12009,26 +12635,14 @@ snapshots: transitivePeerDependencies: - supports-color - electron-to-chromium@1.5.165: {} - - electron-vite@2.3.0(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): - dependencies: - '@babel/core': 7.27.4 - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.27.4) - cac: 6.7.14 - esbuild: 0.21.5 - magic-string: 0.30.17 - picocolors: 1.1.1 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - transitivePeerDependencies: - - supports-color + electron-to-chromium@1.5.336: {} electron-winstaller@5.4.0: dependencies: '@electron/asar': 3.4.1 - debug: 4.4.1 + debug: 4.4.3 fs-extra: 7.0.1 - lodash: 4.17.21 + lodash: 4.18.1 temp: 0.9.4 optionalDependencies: '@electron/windows-sign': 1.2.2 @@ -12039,43 +12653,34 @@ snapshots: electron@32.1.2: dependencies: '@electron/get': 2.0.3 - '@types/node': 20.19.0 + '@types/node': 20.19.39 extract-zip: 2.0.1 transitivePeerDependencies: - supports-color - elkjs@0.9.3: {} - - elliptic@6.6.1: - dependencies: - bn.js: 4.12.2 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + empathic@2.0.0: {} + encode-utf8@1.0.3: optional: true - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - encoding@0.1.13: dependencies: iconv-lite: 0.6.3 optional: true - end-of-stream@1.4.4: + end-of-stream@1.4.5: dependencies: once: 1.4.0 + enhanced-resolve@5.20.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.2 + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 @@ -12083,88 +12688,28 @@ snapshots: entities@4.5.0: {} - entities@6.0.1: {} + entities@7.0.1: {} env-paths@2.2.1: {} err-code@2.0.3: {} - errno@0.1.8: - dependencies: - prr: 1.0.1 - optional: true - - error-ex@1.3.2: + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 - error-stack-parser-es@0.1.5: {} + error-stack-parser-es@1.0.5: {} errx@0.1.0: {} - es-abstract@1.24.0: - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 - es-define-property@1.0.1: {} es-errors@1.3.0: {} es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -12176,42 +12721,12 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - es-to-primitive@1.3.0: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - es-toolkit@1.25.2: {} es6-error@4.1.1: optional: true - esbuild@0.21.5: - optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 + esbuild-plugin-wasm@1.1.0: {} esbuild@0.23.1: optionalDependencies: @@ -12240,153 +12755,89 @@ snapshots: '@esbuild/win32-ia32': 0.23.1 '@esbuild/win32-x64': 0.23.1 - esbuild@0.25.5: + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.5 - '@esbuild/android-arm': 0.25.5 - '@esbuild/android-arm64': 0.25.5 - '@esbuild/android-x64': 0.25.5 - '@esbuild/darwin-arm64': 0.25.5 - '@esbuild/darwin-x64': 0.25.5 - '@esbuild/freebsd-arm64': 0.25.5 - '@esbuild/freebsd-x64': 0.25.5 - '@esbuild/linux-arm': 0.25.5 - '@esbuild/linux-arm64': 0.25.5 - '@esbuild/linux-ia32': 0.25.5 - '@esbuild/linux-loong64': 0.25.5 - '@esbuild/linux-mips64el': 0.25.5 - '@esbuild/linux-ppc64': 0.25.5 - '@esbuild/linux-riscv64': 0.25.5 - '@esbuild/linux-s390x': 0.25.5 - '@esbuild/linux-x64': 0.25.5 - '@esbuild/netbsd-arm64': 0.25.5 - '@esbuild/netbsd-x64': 0.25.5 - '@esbuild/openbsd-arm64': 0.25.5 - '@esbuild/openbsd-x64': 0.25.5 - '@esbuild/sunos-x64': 0.25.5 - '@esbuild/win32-arm64': 0.25.5 - '@esbuild/win32-ia32': 0.25.5 - '@esbuild/win32-x64': 0.25.5 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + optional: true escalade@3.2.0: {} - escape-goat@2.1.1: {} - escape-html@1.0.3: {} escape-string-regexp@1.0.5: {} - escape-string-regexp@4.0.0: {} + escape-string-regexp@4.0.0: + optional: true escape-string-regexp@5.0.0: {} - eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.2)): - dependencies: - eslint: 9.13.0(jiti@2.4.2) - - eslint-plugin-prettier@5.4.1(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.2)))(eslint@9.13.0(jiti@2.4.2))(prettier@3.3.3): - dependencies: - eslint: 9.13.0(jiti@2.4.2) - prettier: 3.3.3 - prettier-linter-helpers: 1.0.0 - synckit: 0.11.8 - optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@9.13.0(jiti@2.4.2)) - - eslint-plugin-vue@9.29.1(eslint@9.13.0(jiti@2.4.2)): - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.13.0(jiti@2.4.2)) - eslint: 9.13.0(jiti@2.4.2) - globals: 13.24.0 - natural-compare: 1.4.0 - nth-check: 2.1.1 - postcss-selector-parser: 6.1.2 - semver: 7.6.3 - vue-eslint-parser: 9.4.3(eslint@9.13.0(jiti@2.4.2)) - xml-name-validator: 4.0.0 - transitivePeerDependencies: - - supports-color - - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-scope@8.3.0: + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.0: {} - - eslint@9.13.0(jiti@2.4.2): - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.13.0(jiti@2.4.2)) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.18.0 - '@eslint/core': 0.7.0 - '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.13.0 - '@eslint/plugin-kit': 0.2.8 - '@humanfs/node': 0.16.6 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.3.1 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1 - escape-string-regexp: 4.0.0 - eslint-scope: 8.3.0 - eslint-visitor-keys: 4.2.0 - espree: 10.3.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - text-table: 0.2.0 - optionalDependencies: - jiti: 2.4.2 - transitivePeerDependencies: - - supports-color - - esm@3.2.25: {} - - espree@10.3.0: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.0 - - espree@9.6.1: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 + estraverse: 4.3.0 esprima@4.0.1: {} - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - esrecurse@4.3.0: dependencies: estraverse: 5.3.0 + estraverse@4.3.0: {} + estraverse@5.3.0: {} estree-walker@2.0.2: {} @@ -12395,20 +12846,17 @@ snapshots: dependencies: '@types/estree': 1.0.8 - esutils@2.0.3: {} - - etag@1.8.1: {} - event-target-shim@5.0.1: {} - eventemitter3@5.0.1: {} + eventemitter3@5.0.4: {} - events@3.3.0: {} - - evp_bytestokey@1.0.3: + events-universal@1.0.1: dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + + events@3.3.0: {} execa@1.0.0: dependencies: @@ -12430,12 +12878,12 @@ snapshots: is-plain-obj: 4.1.0 is-stream: 4.0.1 npm-run-path: 6.0.0 - pretty-ms: 9.2.0 + pretty-ms: 9.3.0 signal-exit: 4.1.0 strip-final-newline: 4.0.0 - yoctocolors: 2.1.1 + yoctocolors: 2.1.2 - execa@9.6.0: + execa@9.5.1: dependencies: '@sindresorhus/merge-streams': 4.0.0 cross-spawn: 7.0.6 @@ -12445,66 +12893,31 @@ snapshots: is-plain-obj: 4.1.0 is-stream: 4.0.1 npm-run-path: 6.0.0 - pretty-ms: 9.2.0 + pretty-ms: 9.3.0 signal-exit: 4.1.0 strip-final-newline: 4.0.0 - yoctocolors: 2.1.1 - - expand-tilde@2.0.2: - dependencies: - homedir-polyfill: 1.0.3 + yoctocolors: 2.1.2 - expect-type@1.2.1: {} - - exponential-backoff@3.1.2: {} - - express-ws@5.0.2(express@4.21.2): + execa@9.5.2: dependencies: - express: 4.21.2 - ws: 7.5.10 - transitivePeerDependencies: - - bufferutil - - utf-8-validate + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.2 - express@4.21.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color + expect-type@1.3.0: {} - exsolve@1.0.5: {} + exponential-backoff@3.1.3: {} - extend@3.0.2: {} + exsolve@1.0.8: {} extendable-error@0.1.7: {} @@ -12516,7 +12929,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.1 + debug: 4.4.3 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -12524,16 +12937,12 @@ snapshots: transitivePeerDependencies: - supports-color - extsprintf@1.3.0: {} - fancy-ansi@0.1.3: dependencies: escape-html: 1.0.3 fast-deep-equal@3.1.3: {} - fast-diff@1.3.0: {} - fast-fifo@1.3.2: {} fast-glob@3.3.3: @@ -12544,13 +12953,23 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} + fast-safe-stringify@2.1.1: {} fast-sha256@1.3.0: {} - fastq@1.19.1: + fast-string-truncated-width@1.2.1: {} + + fast-string-width@1.1.0: + dependencies: + fast-string-truncated-width: 1.2.1 + + fast-uri@3.1.0: {} + + fast-wrap-ansi@0.1.6: + dependencies: + fast-string-width: 1.1.0 + + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -12558,30 +12977,16 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.4.5(picomatch@4.0.2): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.2 + picomatch: 4.0.4 fflate@0.4.8: {} - figgy-pudding@3.5.2: {} - - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - filelist@1.0.4: - dependencies: - minimatch: 5.1.6 - filename-reserved-regex@2.0.0: {} filenamify@4.3.0: @@ -12594,26 +12999,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - find-up@2.1.0: dependencies: locate-path: 2.0.0 - find-up@3.0.0: - dependencies: - locate-path: 3.0.0 - find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -12624,16 +13013,9 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@4.0.1: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - - flatted@3.3.3: {} - flora-colossus@2.0.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 fs-extra: 10.1.0 transitivePeerDependencies: - supports-color @@ -12643,26 +13025,12 @@ snapshots: imul: 1.0.1 optional: true - follow-redirects@1.15.9: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 - forever-agent@0.6.1: {} - - form-data@2.3.3: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - - form-data@4.0.3: + form-data@4.0.5: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -12670,24 +13038,16 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 - forwarded@0.2.0: {} - - fp-and-or@0.1.4: {} - - fresh@0.5.2: {} - - fs-constants@1.0.0: {} - fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 fs-extra@11.3.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 fs-extra@7.0.1: @@ -12706,13 +13066,17 @@ snapshots: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 fs-minipass@2.1.0: dependencies: minipass: 3.3.6 + fs-minipass@3.0.3: + dependencies: + minipass: 7.1.3 + fs-temp@1.2.1: dependencies: random-path: 0.1.2 @@ -12731,42 +13095,17 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.1.8: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.2 - is-callable: 1.2.7 - - functions-have-names@1.2.3: {} - galactus@1.0.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 flora-colossus: 2.0.0 fs-extra: 10.1.0 transitivePeerDependencies: - supports-color - gar@1.0.4: - optional: true - - gauge@2.7.4: + geist@1.3.1(next@16.2.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(sass@1.99.0)): dependencies: - aproba: 1.2.0 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - object-assign: 4.1.1 - signal-exit: 3.0.7 - string-width: 1.0.2 - strip-ansi: 3.0.1 - wide-align: 1.1.5 - - geist@1.3.1(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.80.4)): - dependencies: - next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.80.4) + next: 16.2.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(sass@1.99.0) generate-function@2.3.1: dependencies: @@ -12782,16 +13121,6 @@ snapshots: get-caller-file@2.0.5: {} - get-folder-size@2.0.1: - dependencies: - gar: 1.0.4 - tiny-each-async: 2.0.3 - optional: true - - get-installed-path@2.1.1: - dependencies: - global-modules: 1.0.0 - get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -12814,33 +13143,27 @@ snapshots: transitivePeerDependencies: - supports-color + get-port-please@3.2.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-stdin@8.0.0: {} - get-stream@4.1.0: dependencies: - pump: 3.0.2 + pump: 3.0.4 get-stream@5.2.0: dependencies: - pump: 3.0.2 + pump: 3.0.4 get-stream@9.0.1: dependencies: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 - get-symbol-description@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - - get-tsconfig@4.10.1: + get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 @@ -12848,46 +13171,39 @@ snapshots: dependencies: isobject: 3.0.1 - getpass@0.1.7: - dependencies: - assert-plus: 1.0.0 - - giget@2.0.0: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - defu: 6.1.4 - node-fetch-native: 1.6.6 - nypm: 0.6.0 - pathe: 2.0.3 - - github-url-to-object@4.0.6: - dependencies: - is-url: 1.2.4 + giget@3.2.0: {} glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - glob-parent@6.0.2: + glob-to-regex.js@1.2.0(tslib@2.8.1): dependencies: - is-glob: 4.0.3 + tslib: 2.8.1 - glob@10.4.5: + glob-to-regexp@0.4.1: {} + + glob@10.5.0: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 + minimatch: 9.0.9 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 @@ -12896,58 +13212,28 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.6 + minimatch: 5.1.9 once: 1.4.0 - glob@9.3.5: - dependencies: - fs.realpath: 1.0.0 - minimatch: 8.0.4 - minipass: 4.2.8 - path-scurry: 1.11.1 - global-agent@3.0.0: dependencies: boolean: 3.2.0 es6-error: 4.1.1 matcher: 3.0.0 roarr: 2.15.4 - semver: 7.6.3 + semver: 7.8.0 serialize-error: 7.0.1 optional: true - global-dirs@3.0.1: - dependencies: - ini: 2.0.0 - - global-modules@1.0.0: - dependencies: - global-prefix: 1.0.2 - is-windows: 1.0.2 - resolve-dir: 1.0.1 - - global-prefix@1.0.2: - dependencies: - expand-tilde: 2.0.2 - homedir-polyfill: 1.0.3 - ini: 1.3.8 - is-windows: 1.0.2 - which: 1.3.1 - - globals@11.12.0: {} - - globals@13.24.0: + global-dirs@3.0.1: dependencies: - type-fest: 0.20.2 - - globals@14.0.0: {} - - globals@15.11.0: {} + ini: 2.0.0 globalthis@1.0.4: dependencies: define-properties: 1.2.1 gopd: 1.2.0 + optional: true globby@11.1.0: dependencies: @@ -12962,20 +13248,6 @@ snapshots: gopd@1.2.0: {} - got@11.8.1: - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 4.0.6 - '@types/cacheable-request': 6.0.3 - '@types/responselike': 1.0.3 - cacheable-lookup: 5.0.4 - cacheable-request: 7.0.4 - decompress-response: 6.0.0 - http2-wrapper: 1.0.3 - lowercase-keys: 2.0.0 - p-cancelable: 2.1.1 - responselike: 2.0.1 - got@11.8.6: dependencies: '@sindresorhus/is': 4.6.0 @@ -12990,46 +13262,28 @@ snapshots: p-cancelable: 2.1.1 responselike: 2.0.1 - got@9.6.0: - dependencies: - '@sindresorhus/is': 0.14.0 - '@szmarczak/http-timer': 1.1.2 - '@types/keyv': 3.1.4 - '@types/responselike': 1.0.3 - cacheable-request: 6.1.0 - decompress-response: 3.3.0 - duplexer3: 0.1.5 - get-stream: 4.1.0 - lowercase-keys: 1.0.1 - mimic-response: 1.0.1 - p-cancelable: 1.1.0 - to-readable-stream: 1.0.0 - url-parse-lax: 3.0.0 - graceful-fs@4.2.11: {} - graphemer@1.4.0: {} + graphql@16.13.2: {} - har-schema@2.0.0: {} - - har-validator@5.1.5: + h3@1.15.11: dependencies: - ajv: 6.12.6 - har-schema: 2.0.0 - - has-bigints@1.1.0: {} - - has-flag@3.0.0: {} + cookie-es: 1.2.3 + crossws: 0.3.5 + defu: 6.1.7 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.3 + uncrypto: 0.1.3 has-flag@4.0.0: {} has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 - - has-proto@1.2.0: - dependencies: - dunder-proto: 1.0.1 + optional: true has-symbols@1.1.0: {} @@ -13037,115 +13291,63 @@ snapshots: dependencies: has-symbols: 1.1.0 - has-unicode@2.0.1: {} - - has-yarn@2.1.0: {} - - hash-base@3.0.5: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - hasown@2.0.2: dependencies: function-bind: 1.1.2 he@1.2.0: {} - hmac-drbg@1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - homedir-polyfill@1.0.3: - dependencies: - parse-passwd: 1.0.0 + headers-polyfill@4.0.3: {} hookable@5.5.3: {} - hosted-git-info@2.8.9: {} - - hosted-git-info@3.0.8: - dependencies: - lru-cache: 6.0.0 + hookable@6.1.0: {} - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 + hosted-git-info@2.8.9: {} - html-encoding-sniffer@4.0.0: + hosted-git-info@9.0.2: dependencies: - whatwg-encoding: 3.1.1 + lru-cache: 11.3.5 html-entities@2.6.0: {} http-cache-semantics@4.2.0: {} - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - http-proxy-agent@4.0.1: - dependencies: - '@tootallnate/once': 1.1.2 - agent-base: 6.0.2 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color http-proxy-agent@7.0.2: dependencies: - agent-base: 7.1.3 - debug: 4.4.1 + agent-base: 7.1.4 + debug: 4.4.3 transitivePeerDependencies: - supports-color - http-signature@1.2.0: - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.2 - sshpk: 1.18.0 - http2-wrapper@1.0.3: dependencies: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-browserify@1.0.0: {} - https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: - agent-base: 7.1.3 - debug: 4.4.1 + agent-base: 7.1.4 + debug: 4.4.3 transitivePeerDependencies: - supports-color - human-id@1.0.2: {} + human-id@4.1.3: {} human-signals@8.0.1: {} @@ -13153,6 +13355,10 @@ snapshots: dependencies: ms: 2.1.3 + hyperdyperid@1.2.0: {} + + iceberg-js@0.8.1: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -13160,46 +13366,30 @@ snapshots: iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + optional: true + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 ieee754@1.2.1: {} - ignore-walk@3.0.4: + ignore-walk@8.0.0: dependencies: - minimatch: 3.1.2 + minimatch: 10.2.5 ignore@5.3.2: {} ignore@7.0.5: {} - image-size@0.5.5: - optional: true - image-size@0.7.5: optional: true - immutable@4.3.7: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - import-in-the-middle@1.14.0: - dependencies: - acorn: 8.15.0 - acorn-import-attributes: 1.9.5(acorn@8.15.0) - cjs-module-lexer: 1.4.3 - module-details-from-path: 1.0.4 + immer@11.1.4: {} - import-in-the-middle@1.7.1: - dependencies: - acorn: 8.15.0 - acorn-import-assertions: 1.9.0(acorn@8.15.0) - cjs-module-lexer: 1.4.3 - module-details-from-path: 1.0.4 - optional: true + immutable@5.1.5: {} - import-lazy@2.1.0: {} + import-without-cache@0.2.5: {} imul@1.0.1: optional: true @@ -13208,6 +13398,8 @@ snapshots: indent-string@4.0.0: {} + individual@3.0.0: {} + infer-owner@1.0.4: {} inflight@1.0.6: @@ -13217,145 +13409,50 @@ snapshots: inherits@2.0.4: {} - ini@1.3.8: {} - ini@2.0.0: {} - inquirer@7.3.3: - dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.0 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - external-editor: 3.1.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - run-async: 2.4.1 - rxjs: 6.6.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 - - interpret@1.4.0: {} + ini@6.0.0: {} interpret@3.1.1: {} - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - - ipaddr.js@1.9.1: {} - - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 + ip-address@10.1.0: {} - is-array-buffer@3.0.5: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 + iron-webcrypto@1.2.1: {} is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - - is-async-function@2.1.1: - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-callable@1.2.7: {} - - is-ci@2.0.0: - dependencies: - ci-info: 2.0.0 - is-core-module@2.16.1: dependencies: hasown: 2.0.2 - is-data-view@1.0.2: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 - - is-date-object@1.1.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - is-docker@2.2.1: {} is-docker@3.0.0: {} is-extglob@2.1.1: {} - is-finalizationregistry@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-fullwidth-code-point@1.0.0: - dependencies: - number-is-nan: 1.0.1 - is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-in-ssh@1.0.0: {} + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 - is-installed-globally@0.4.0: - dependencies: - global-dirs: 3.0.1 - is-path-inside: 3.0.3 - is-interactive@1.0.0: {} is-lambda@1.0.1: {} - is-map@2.0.3: {} - is-my-ip-valid@1.0.1: optional: true @@ -13368,103 +13465,36 @@ snapshots: xtend: 4.0.2 optional: true - is-nan@1.3.2: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - - is-negative-zero@2.0.3: {} - - is-npm@5.0.0: {} - - is-number-object@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 + is-node-process@1.2.0: {} is-number@7.0.0: {} - is-obj@2.0.0: {} - - is-path-cwd@2.2.0: {} - - is-path-inside@3.0.3: {} - is-plain-obj@4.1.0: {} is-plain-object@2.0.4: dependencies: isobject: 3.0.1 - is-plain-object@5.0.0: {} - - is-potential-custom-element-name@1.0.1: {} - is-primitive@3.0.1: {} is-property@1.0.2: optional: true - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.4: - dependencies: - call-bound: 1.0.4 - is-stream@1.1.0: {} is-stream@2.0.1: {} is-stream@4.0.1: {} - is-string@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 - is-symbol@1.1.1: - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.19 - - is-typedarray@1.0.0: {} - is-unicode-supported@0.1.0: {} is-unicode-supported@2.1.0: {} - is-url@1.2.4: {} - - is-weakmap@2.0.2: {} - - is-weakref@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-weakset@2.0.4: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-what@3.14.1: {} - - is-what@4.1.16: {} + is-what@5.5.0: {} is-windows@1.0.2: {} @@ -13472,25 +13502,19 @@ snapshots: dependencies: is-docker: 2.2.1 - is-wsl@3.1.0: + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 - is-yarn-global@0.3.0: {} - isarray@1.0.0: {} - isarray@2.0.5: {} - isbinaryfile@4.0.10: {} isexe@2.0.0: {} - isobject@3.0.1: {} - - isomorphic-timers-promises@1.0.1: {} + isexe@4.0.0: {} - isstream@0.1.2: {} + isobject@3.0.1: {} jackspeak@3.4.3: dependencies: @@ -13498,93 +13522,39 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jake@10.9.2: - dependencies: - async: 3.2.6 - chalk: 4.1.2 - filelist: 1.0.4 - minimatch: 3.1.2 - - jiti@2.4.2: {} - - jju@1.4.0: {} - - js-beautify@1.15.4: + jest-worker@27.5.1: dependencies: - config-chain: 1.1.13 - editorconfig: 1.0.4 - glob: 10.4.5 - js-cookie: 3.0.5 - nopt: 7.2.1 + '@types/node': 24.12.4 + merge-stream: 2.0.0 + supports-color: 8.1.1 - js-cookie@3.0.5: {} + jiti@2.6.1: {} js-tokens@4.0.0: {} js-tokens@9.0.1: {} - js-yaml@3.14.1: + js-yaml@3.14.2: dependencies: argparse: 1.0.10 esprima: 4.0.1 - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 - jsbn@0.1.1: {} - - jsbn@1.1.0: {} - - jsdom@25.0.1: - dependencies: - cssstyle: 4.4.0 - data-urls: 5.0.0 - decimal.js: 10.5.0 - form-data: 4.0.3 - html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.20 - parse5: 7.3.0 - rrweb-cssom: 0.7.1 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 5.1.2 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 - ws: 8.18.3 - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - jsesc@3.1.0: {} - json-buffer@3.0.0: {} - json-buffer@3.0.1: {} - json-parse-better-errors@1.0.2: {} - json-parse-even-better-errors@2.3.1: {} - json-parse-helpfulerror@1.0.3: - dependencies: - jju: 1.4.0 - - json-schema-traverse@0.4.1: {} - - json-schema@0.4.0: {} + json-parse-even-better-errors@5.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} + json-schema-traverse@1.0.0: {} - json-stringify-safe@5.0.1: {} + json-stringify-safe@5.0.1: + optional: true json5@2.2.3: {} @@ -13592,82 +13562,118 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonfile@6.1.0: + jsonfile@6.2.0: dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - jsonlines@0.1.1: {} - jsonparse@1.3.1: {} jsonpointer@5.0.1: optional: true - jsprim@1.4.2: + jsonwebtoken@9.0.3: dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 + jws: 4.0.1 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.8.0 junk@3.1.0: {} - keyv@3.1.0: + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: dependencies: - json-buffer: 3.0.0 + jwa: 2.0.1 + safe-buffer: 5.2.1 keyv@4.5.4: dependencies: json-buffer: 3.0.1 - kleur@3.0.3: {} - klona@2.0.6: {} - knitwork@1.2.0: {} + knitwork@1.3.0: {} kolorist@1.8.0: {} - latest-version@5.1.0: + launch-editor@2.13.2: dependencies: - package-json: 6.5.0 + picocolors: 1.1.1 + shell-quote: 1.8.3 lazystream@1.0.1: dependencies: readable-stream: 2.3.8 - less@4.2.0: - dependencies: - copy-anything: 2.0.6 - parse-node-version: 1.0.1 - tslib: 2.8.1 - optionalDependencies: - errno: 0.1.8 - graceful-fs: 4.2.11 - image-size: 0.5.5 - make-dir: 2.1.0 - mime: 1.6.0 - needle: 3.3.1 - source-map: 0.6.1 + lightningcss-android-arm64@1.32.0: + optional: true - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true - libnpmconfig@1.2.1: + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: dependencies: - figgy-pudding: 3.5.2 - find-up: 3.0.0 - ini: 1.3.8 + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lines-and-columns@1.2.4: {} listr2@7.0.2: dependencies: cli-truncate: 3.1.0 colorette: 2.0.20 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 log-update: 5.0.1 rfdc: 1.4.1 wrap-ansi: 8.1.0 @@ -13679,34 +13685,24 @@ snapshots: pify: 2.3.0 strip-bom: 3.0.0 - load-json-file@4.0.0: - dependencies: - graceful-fs: 4.2.11 - parse-json: 4.0.0 - pify: 3.0.0 - strip-bom: 3.0.0 + loader-runner@4.3.1: {} local-pkg@0.5.1: dependencies: - mlly: 1.7.4 + mlly: 1.8.2 pkg-types: 1.3.1 - local-pkg@1.1.1: + local-pkg@1.1.2: dependencies: - mlly: 1.7.4 - pkg-types: 2.1.0 - quansync: 0.2.10 + mlly: 1.8.2 + pkg-types: 2.3.0 + quansync: 0.2.11 locate-path@2.0.0: dependencies: p-locate: 2.0.0 path-exists: 3.0.0 - locate-path@3.0.0: - dependencies: - p-locate: 3.0.0 - path-exists: 3.0.0 - locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -13715,25 +13711,27 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.21: {} + lodash-es@4.18.1: {} + + lodash.get@4.4.2: {} - lodash.defaults@4.2.0: {} + lodash.includes@4.3.0: {} - lodash.difference@4.5.0: {} + lodash.isboolean@3.0.3: {} - lodash.flatten@4.4.0: {} + lodash.isinteger@4.0.4: {} - lodash.get@4.4.2: {} + lodash.isnumber@3.0.3: {} lodash.isplainobject@4.0.6: {} - lodash.merge@4.6.2: {} + lodash.isstring@4.0.1: {} - lodash.startcase@4.4.0: {} + lodash.once@4.1.1: {} - lodash.union@4.6.0: {} + lodash.startcase@4.4.0: {} - lodash@4.17.21: {} + lodash@4.18.1: {} log-symbols@4.1.0: dependencies: @@ -13745,51 +13743,31 @@ snapshots: ansi-escapes: 5.0.0 cli-cursor: 4.0.0 slice-ansi: 5.0.0 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 wrap-ansi: 8.1.0 - loupe@3.1.3: {} - - lowercase-keys@1.0.1: {} + loupe@3.2.1: {} lowercase-keys@2.0.0: {} lru-cache@10.4.3: {} + lru-cache@11.3.5: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - lru-cache@7.18.3: {} macos-alias@0.2.12: dependencies: - nan: 2.22.2 - optional: true - - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - - magic-string@0.30.8: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - - make-dir@2.1.0: - dependencies: - pify: 4.0.1 - semver: 5.7.2 + nan: 2.26.2 optional: true - make-dir@3.1.0: + magic-string@0.30.21: dependencies: - semver: 6.3.1 - - make-error@1.3.6: {} + '@jridgewell/sourcemap-codec': 1.5.5 make-fetch-happen@10.2.1: dependencies: @@ -13803,7 +13781,7 @@ snapshots: minipass: 3.3.6 minipass-collect: 1.0.2 minipass-fetch: 2.1.2 - minipass-flush: 1.0.5 + minipass-flush: 1.0.7 minipass-pipeline: 1.2.4 negotiator: 0.6.4 promise-retry: 2.0.1 @@ -13813,25 +13791,21 @@ snapshots: - bluebird - supports-color - make-fetch-happen@8.0.14(bluebird@3.7.2): + make-fetch-happen@15.0.5: dependencies: - agentkeepalive: 4.6.0 - cacache: 15.3.0(bluebird@3.7.2) + '@gar/promise-retry': 1.0.3 + '@npmcli/agent': 4.0.0 + '@npmcli/redact': 4.0.0 + cacache: 20.0.4 http-cache-semantics: 4.2.0 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - is-lambda: 1.0.1 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 1.4.1 - minipass-flush: 1.0.5 + minipass: 7.1.3 + minipass-fetch: 5.0.2 + minipass-flush: 1.0.7 minipass-pipeline: 1.2.4 - promise-retry: 2.0.1 - socks-proxy-agent: 5.0.1 - ssri: 8.0.1 + negotiator: 1.0.0 + proc-log: 6.1.0 + ssri: 13.0.1 transitivePeerDependencies: - - bluebird - supports-color map-age-cleaner@0.1.3: @@ -13845,42 +13819,37 @@ snapshots: math-intrinsics@1.1.0: {} - md5.js@1.3.5: - dependencies: - hash-base: 3.0.5 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - media-typer@0.3.0: {} - mem@4.3.0: dependencies: map-age-cleaner: 0.1.3 mimic-fn: 2.1.0 p-is-promise: 2.1.0 - mem@8.1.1: - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 3.1.0 - - memorystream@0.3.1: {} + memfs@4.57.6(tslib@2.8.1): + dependencies: + '@jsonjoy.com/fs-core': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-fsa': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-to-fsa': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.57.6(tslib@2.8.1) + '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 - merge-descriptors@1.0.3: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} - methods@1.1.2: {} - micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 - - miller-rabin@4.0.1: - dependencies: - bn.js: 4.12.2 - brorand: 1.1.0 + picomatch: 2.3.2 mime-db@1.33.0: {} @@ -13894,43 +13863,27 @@ snapshots: dependencies: mime-db: 1.52.0 - mime@1.6.0: {} - mimic-fn@2.1.0: {} - mimic-fn@3.1.0: {} - mimic-response@1.0.1: {} mimic-response@3.1.0: {} - minimalistic-assert@1.0.1: {} - - minimalistic-crypto-utils@1.0.1: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@8.0.4: + minimatch@10.2.5: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 5.0.5 - minimatch@9.0.1: + minimatch@3.1.5: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 1.1.14 - minimatch@9.0.2: + minimatch@5.1.9: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.1.0 - minimatch@9.0.5: + minimatch@9.0.9: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.1.0 minimist@1.2.8: {} @@ -13938,13 +13891,9 @@ snapshots: dependencies: minipass: 3.3.6 - minipass-fetch@1.4.1: + minipass-collect@2.0.1: dependencies: - minipass: 3.3.6 - minipass-sized: 1.0.3 - minizlib: 2.1.2 - optionalDependencies: - encoding: 0.1.13 + minipass: 7.1.3 minipass-fetch@2.1.2: dependencies: @@ -13954,13 +13903,16 @@ snapshots: optionalDependencies: encoding: 0.1.13 - minipass-flush@1.0.5: + minipass-fetch@5.0.2: dependencies: - minipass: 3.3.6 + minipass: 7.1.3 + minipass-sized: 2.0.0 + minizlib: 3.1.0 + optionalDependencies: + iconv-lite: 0.7.2 - minipass-json-stream@1.0.2: + minipass-flush@1.0.7: dependencies: - jsonparse: 1.3.1 minipass: 3.3.6 minipass-pipeline@1.2.4: @@ -13971,6 +13923,10 @@ snapshots: dependencies: minipass: 3.3.6 + minipass-sized@2.0.0: + dependencies: + minipass: 7.1.3 + minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -13979,13 +13935,19 @@ snapshots: minipass@5.0.0: {} - minipass@7.1.2: {} + minipass@7.1.3: {} minizlib@2.1.2: dependencies: minipass: 3.3.6 yallist: 4.0.0 + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + mitt@2.1.0: {} + mitt@3.0.1: {} mkdirp@0.5.6: @@ -13995,14 +13957,12 @@ snapshots: mkdirp@1.0.4: {} - mlly@1.7.4: + mlly@1.8.2: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.1 - - module-details-from-path@1.0.4: {} + ufo: 1.6.3 mri@1.2.0: {} @@ -14012,6 +13972,57 @@ snapshots: ms@2.1.3: {} + msw@2.7.5(@types/node@24.12.2)(typescript@5.8.3): + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 5.1.21(@types/node@24.12.2) + '@mswjs/interceptors': 0.37.6 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.6 + graphql: 16.13.2 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.39.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - '@types/node' + optional: true + + msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3): + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 5.1.21(@types/node@24.12.2) + '@mswjs/interceptors': 0.37.6 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.6 + graphql: 16.13.2 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.39.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + muggle-string@0.4.1: {} murmur-32@0.2.0: @@ -14023,70 +14034,67 @@ snapshots: mutative@1.0.11: {} - mute-stream@0.0.8: {} + mute-stream@1.0.0: {} + + mute-stream@2.0.0: {} - nan@2.22.2: + nan@2.26.2: optional: true nanoid@3.3.11: {} - nanoid@5.0.7: {} + nanoid@3.3.12: {} - nanoid@5.1.5: {} + nanoid@5.0.7: {} - natural-compare@1.4.0: {} + nanoid@5.0.8: {} - needle@3.3.1: - dependencies: - iconv-lite: 0.6.3 - sax: 1.4.1 - optional: true + negotiator@0.6.4: {} - negotiator@0.6.3: {} + negotiator@1.0.0: {} - negotiator@0.6.4: {} + neo-async@2.6.2: {} - next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.80.4): + next@16.2.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(sass@1.99.0): dependencies: - '@next/env': 15.3.3 - '@swc/counter': 0.1.3 + '@next/env': 16.2.3 '@swc/helpers': 0.5.15 - busboy: 1.6.0 - caniuse-lite: 1.0.30001721 + baseline-browser-mapping: 2.10.18 + caniuse-lite: 1.0.30001788 postcss: 8.4.31 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.1.0) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.5) optionalDependencies: - '@next/swc-darwin-arm64': 15.3.3 - '@next/swc-darwin-x64': 15.3.3 - '@next/swc-linux-arm64-gnu': 15.3.3 - '@next/swc-linux-arm64-musl': 15.3.3 - '@next/swc-linux-x64-gnu': 15.3.3 - '@next/swc-linux-x64-musl': 15.3.3 - '@next/swc-win32-arm64-msvc': 15.3.3 - '@next/swc-win32-x64-msvc': 15.3.3 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.48.1 - sass: 1.80.4 - sharp: 0.34.2 + '@next/swc-darwin-arm64': 16.2.3 + '@next/swc-darwin-x64': 16.2.3 + '@next/swc-linux-arm64-gnu': 16.2.3 + '@next/swc-linux-arm64-musl': 16.2.3 + '@next/swc-linux-x64-gnu': 16.2.3 + '@next/swc-linux-x64-musl': 16.2.3 + '@next/swc-win32-arm64-msvc': 16.2.3 + '@next/swc-win32-x64-msvc': 16.2.3 + '@opentelemetry/api': 1.9.1 + sass: 1.99.0 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros nice-try@1.0.5: {} - node-abi@3.75.0: + node-abi@3.89.0: dependencies: - semver: 7.6.3 + semver: 7.8.0 - node-addon-api@7.1.1: {} + node-addon-api@7.1.1: + optional: true node-api-version@0.2.1: dependencies: - semver: 7.6.3 + semver: 7.8.0 - node-fetch-native@1.6.6: {} + node-fetch-native@1.6.7: {} node-fetch@2.7.0(encoding@0.1.13): dependencies: @@ -14094,166 +14102,88 @@ snapshots: optionalDependencies: encoding: 0.1.13 - node-gyp@7.1.2: + node-gyp@12.2.0: dependencies: env-paths: 2.2.1 - glob: 7.2.3 + exponential-backoff: 3.1.3 graceful-fs: 4.2.11 - nopt: 5.0.0 - npmlog: 4.1.2 - request: 2.88.2 - rimraf: 3.0.2 - semver: 7.6.3 - tar: 6.2.1 - which: 2.0.2 + make-fetch-happen: 15.0.5 + nopt: 9.0.0 + proc-log: 6.1.0 + semver: 7.8.0 + tar: 7.5.13 + tinyglobby: 0.2.16 + which: 6.0.1 + transitivePeerDependencies: + - supports-color - node-releases@2.0.19: {} + node-mock-http@1.0.4: {} - node-stdlib-browser@1.3.1: - dependencies: - assert: 2.1.0 - browser-resolve: 2.0.0 - browserify-zlib: 0.2.0 - buffer: 5.7.1 - console-browserify: 1.2.0 - constants-browserify: 1.0.0 - create-require: 1.1.1 - crypto-browserify: 3.12.1 - domain-browser: 4.22.0 - events: 3.3.0 - https-browserify: 1.0.0 - isomorphic-timers-promises: 1.0.1 - os-browserify: 0.3.0 - path-browserify: 1.0.1 - pkg-dir: 5.0.0 - process: 0.11.10 - punycode: 1.4.1 - querystring-es3: 0.2.1 - readable-stream: 3.6.2 - stream-browserify: 3.0.0 - stream-http: 3.2.0 - string_decoder: 1.3.0 - timers-browserify: 2.0.12 - tty-browserify: 0.0.1 - url: 0.11.4 - util: 0.12.5 - vm-browserify: 1.1.2 + node-releases@2.0.37: {} node-stream-zip@1.15.0: {} - nopt@5.0.0: - dependencies: - abbrev: 1.1.1 - nopt@6.0.0: dependencies: abbrev: 1.1.1 - nopt@7.2.1: + nopt@9.0.0: dependencies: - abbrev: 2.0.0 + abbrev: 4.0.0 normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.10 + resolve: 1.22.12 semver: 5.7.2 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} - normalize-url@4.5.1: {} - normalize-url@6.1.0: {} - npm-bundled@1.1.2: + npm-bundled@5.0.0: dependencies: - npm-normalize-package-bin: 1.0.1 - - npm-check-updates@11.1.9(bluebird@3.7.2): - dependencies: - chalk: 4.1.0 - cint: 8.2.1 - cli-table: 0.3.5 - commander: 6.2.1 - find-up: 5.0.0 - fp-and-or: 0.1.4 - get-stdin: 8.0.0 - globby: 11.1.0 - hosted-git-info: 3.0.8 - json-parse-helpfulerror: 1.0.3 - jsonlines: 0.1.1 - libnpmconfig: 1.2.1 - lodash: 4.17.21 - mem: 8.1.1 - p-map: 4.0.0 - pacote: 11.2.7(bluebird@3.7.2) - parse-github-url: 1.0.3 - progress: 2.0.3 - prompts: 2.4.2 - rc-config-loader: 4.1.3 - remote-git-tags: 3.0.0 - rimraf: 3.0.2 - semver: 7.6.3 - semver-utils: 1.1.4 - spawn-please: 1.0.0 - update-notifier: 5.1.0 - transitivePeerDependencies: - - bluebird - - supports-color + npm-normalize-package-bin: 5.0.0 - npm-install-checks@4.0.0: + npm-install-checks@8.0.0: dependencies: - semver: 7.6.3 + semver: 7.8.0 - npm-normalize-package-bin@1.0.1: {} + npm-normalize-package-bin@5.0.0: {} - npm-package-arg@8.1.5: + npm-package-arg@13.0.2: dependencies: - hosted-git-info: 4.1.0 - semver: 7.6.3 - validate-npm-package-name: 3.0.0 + hosted-git-info: 9.0.2 + proc-log: 6.1.0 + semver: 7.8.0 + validate-npm-package-name: 7.0.2 - npm-packlist@2.2.2: + npm-packlist@10.0.4: dependencies: - glob: 7.2.3 - ignore-walk: 3.0.4 - npm-bundled: 1.1.2 - npm-normalize-package-bin: 1.0.1 + ignore-walk: 8.0.0 + proc-log: 6.1.0 - npm-pick-manifest@6.1.1: + npm-pick-manifest@11.0.3: dependencies: - npm-install-checks: 4.0.0 - npm-normalize-package-bin: 1.0.1 - npm-package-arg: 8.1.5 - semver: 7.6.3 + npm-install-checks: 8.0.0 + npm-normalize-package-bin: 5.0.0 + npm-package-arg: 13.0.2 + semver: 7.8.0 - npm-registry-fetch@9.0.0(bluebird@3.7.2): + npm-registry-fetch@19.1.1: dependencies: - '@npmcli/ci-detect': 1.4.0 - lru-cache: 6.0.0 - make-fetch-happen: 8.0.14(bluebird@3.7.2) - minipass: 3.3.6 - minipass-fetch: 1.4.1 - minipass-json-stream: 1.0.2 - minizlib: 2.1.2 - npm-package-arg: 8.1.5 + '@npmcli/redact': 4.0.0 + jsonparse: 1.3.1 + make-fetch-happen: 15.0.5 + minipass: 7.1.3 + minipass-fetch: 5.0.2 + minizlib: 3.1.0 + npm-package-arg: 13.0.2 + proc-log: 6.1.0 transitivePeerDependencies: - - bluebird - supports-color - npm-run-all@4.1.5: - dependencies: - ansi-styles: 3.2.1 - chalk: 2.4.2 - cross-spawn: 6.0.6 - memorystream: 0.3.1 - minimatch: 3.1.2 - pidtree: 0.3.1 - read-pkg: 3.0.0 - shell-quote: 1.8.3 - string.prototype.padend: 3.1.6 - npm-run-path@2.0.2: dependencies: path-key: 2.0.1 @@ -14263,78 +14193,19 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 - npm-upgrade@3.1.0: - dependencies: - '@babel/runtime': 7.13.7 - bluebird: 3.7.2 - chalk: 4.1.0 - cli-table: 0.3.5 - del: 6.0.0 - detect-indent: 6.0.0 - got: 11.8.1 - inquirer: 7.3.3 - libnpmconfig: 1.2.1 - lodash: 4.17.21 - npm-check-updates: 11.1.9(bluebird@3.7.2) - open: 7.4.2 - pacote: 11.2.7(bluebird@3.7.2) - semver: 7.3.4 - shelljs: 0.8.5 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - - npmlog@4.1.2: - dependencies: - are-we-there-yet: 1.1.7 - console-control-strings: 1.1.0 - gauge: 2.7.4 - set-blocking: 2.0.0 - - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - - number-is-nan@1.0.1: {} - - nwsapi@2.2.20: {} - - nypm@0.6.0: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - pathe: 2.0.3 - pkg-types: 2.1.0 - tinyexec: 0.3.2 - - oauth-sign@0.9.0: {} - - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - object-is@1.1.6: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 + object-keys@1.1.1: + optional: true - object-keys@1.1.1: {} + obug@2.1.1: {} - object.assign@4.1.7: + ofetch@1.5.1: dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.3 ohash@2.0.11: {} - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -14343,17 +14214,21 @@ snapshots: dependencies: mimic-fn: 2.1.0 - open@10.1.2: + open@10.2.0: dependencies: - default-browser: 5.2.1 + default-browser: 5.5.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 - is-wsl: 3.1.0 + wsl-utils: 0.1.0 - open@7.4.2: + open@11.0.0: dependencies: - is-docker: 2.2.1 - is-wsl: 2.2.0 + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 open@8.4.2: dependencies: @@ -14361,24 +14236,6 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - opentelemetry-instrumentation-fetch-node@1.2.3(@opentelemetry/api@1.9.0): - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.46.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.34.0 - transitivePeerDependencies: - - supports-color - optional: true - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - ora@5.4.1: dependencies: bl: 4.1.0 @@ -14391,19 +14248,57 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 - os-browserify@0.3.0: {} - os-tmpdir@1.0.2: {} outdent@0.5.0: {} - own-keys@1.0.1: - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.0 + outvariant@1.4.3: {} - p-cancelable@1.1.0: {} + oxfmt@0.40.0: + dependencies: + tinypool: 2.1.0 + optionalDependencies: + '@oxfmt/binding-android-arm-eabi': 0.40.0 + '@oxfmt/binding-android-arm64': 0.40.0 + '@oxfmt/binding-darwin-arm64': 0.40.0 + '@oxfmt/binding-darwin-x64': 0.40.0 + '@oxfmt/binding-freebsd-x64': 0.40.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.40.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.40.0 + '@oxfmt/binding-linux-arm64-gnu': 0.40.0 + '@oxfmt/binding-linux-arm64-musl': 0.40.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.40.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.40.0 + '@oxfmt/binding-linux-riscv64-musl': 0.40.0 + '@oxfmt/binding-linux-s390x-gnu': 0.40.0 + '@oxfmt/binding-linux-x64-gnu': 0.40.0 + '@oxfmt/binding-linux-x64-musl': 0.40.0 + '@oxfmt/binding-openharmony-arm64': 0.40.0 + '@oxfmt/binding-win32-arm64-msvc': 0.40.0 + '@oxfmt/binding-win32-ia32-msvc': 0.40.0 + '@oxfmt/binding-win32-x64-msvc': 0.40.0 + + oxlint@1.55.0: + optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.55.0 + '@oxlint/binding-android-arm64': 1.55.0 + '@oxlint/binding-darwin-arm64': 1.55.0 + '@oxlint/binding-darwin-x64': 1.55.0 + '@oxlint/binding-freebsd-x64': 1.55.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.55.0 + '@oxlint/binding-linux-arm-musleabihf': 1.55.0 + '@oxlint/binding-linux-arm64-gnu': 1.55.0 + '@oxlint/binding-linux-arm64-musl': 1.55.0 + '@oxlint/binding-linux-ppc64-gnu': 1.55.0 + '@oxlint/binding-linux-riscv64-gnu': 1.55.0 + '@oxlint/binding-linux-riscv64-musl': 1.55.0 + '@oxlint/binding-linux-s390x-gnu': 1.55.0 + '@oxlint/binding-linux-x64-gnu': 1.55.0 + '@oxlint/binding-linux-x64-musl': 1.55.0 + '@oxlint/binding-openharmony-arm64': 1.55.0 + '@oxlint/binding-win32-arm64-msvc': 1.55.0 + '@oxlint/binding-win32-ia32-msvc': 1.55.0 + '@oxlint/binding-win32-x64-msvc': 1.55.0 p-cancelable@2.1.1: {} @@ -14429,13 +14324,13 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-locate@2.0.0: + p-limit@7.3.0: dependencies: - p-limit: 1.3.0 + yocto-queue: 1.2.2 - p-locate@3.0.0: + p-locate@2.0.0: dependencies: - p-limit: 2.3.0 + p-limit: 1.3.0 p-locate@4.1.0: dependencies: @@ -14451,7 +14346,7 @@ snapshots: dependencies: aggregate-error: 3.1.0 - p-map@7.0.3: {} + p-map@7.0.4: {} p-try@1.0.0: {} @@ -14459,57 +14354,34 @@ snapshots: package-json-from-dist@1.0.1: {} - package-json@6.5.0: - dependencies: - got: 9.6.0 - registry-auth-token: 4.2.2 - registry-url: 5.1.0 - semver: 6.3.1 - package-manager-detector@0.2.11: dependencies: - quansync: 0.2.10 - - pacote@11.2.7(bluebird@3.7.2): - dependencies: - '@npmcli/git': 2.1.0(bluebird@3.7.2) - '@npmcli/installed-package-contents': 1.0.7 - '@npmcli/promise-spawn': 1.3.2 - '@npmcli/run-script': 1.8.6 - cacache: 15.3.0(bluebird@3.7.2) - chownr: 2.0.0 - fs-minipass: 2.1.0 - infer-owner: 1.0.4 - minipass: 3.3.6 - mkdirp: 1.0.4 - npm-package-arg: 8.1.5 - npm-packlist: 2.2.2 - npm-pick-manifest: 6.1.1 - npm-registry-fetch: 9.0.0(bluebird@3.7.2) - promise-retry: 2.0.1 - read-package-json-fast: 2.0.3 - rimraf: 3.0.2 - ssri: 8.0.1 - tar: 6.2.1 + quansync: 0.2.11 + + package-manager-detector@1.6.0: {} + + pacote@21.5.0: + dependencies: + '@gar/promise-retry': 1.0.3 + '@npmcli/git': 7.0.2 + '@npmcli/installed-package-contents': 4.0.0 + '@npmcli/package-json': 7.0.5 + '@npmcli/promise-spawn': 9.0.1 + '@npmcli/run-script': 10.0.4 + cacache: 20.0.4 + fs-minipass: 3.0.3 + minipass: 7.1.3 + npm-package-arg: 13.0.2 + npm-packlist: 10.0.4 + npm-pick-manifest: 11.0.3 + npm-registry-fetch: 19.1.1 + proc-log: 6.1.0 + sigstore: 4.1.0 + ssri: 13.0.1 + tar: 7.5.13 transitivePeerDependencies: - - bluebird - supports-color - pako@1.0.11: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-asn1@5.1.7: - dependencies: - asn1.js: 4.10.1 - browserify-aes: 1.2.0 - evp_bytestokey: 1.0.3 - hash-base: 3.0.5 - pbkdf2: 3.1.2 - safe-buffer: 5.2.1 - parse-author@2.0.0: dependencies: author-regex: 1.0.0 @@ -14519,29 +14391,19 @@ snapshots: color-convert: 0.5.3 optional: true - parse-github-url@1.0.3: {} - parse-json@2.2.0: dependencies: - error-ex: 1.3.2 + error-ex: 1.3.4 - parse-json@4.0.0: + parse-json@5.2.0: dependencies: - error-ex: 1.3.2 - json-parse-better-errors: 1.0.2 + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 parse-ms@4.0.0: {} - parse-node-version@1.0.1: {} - - parse-passwd@1.0.0: {} - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - parseurl@1.3.3: {} - path-browserify@1.0.1: {} path-exists@3.0.0: {} @@ -14563,35 +14425,28 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 - path-to-regexp@0.1.12: {} + path-scurry@2.0.2: + dependencies: + lru-cache: 11.3.5 + minipass: 7.1.3 path-to-regexp@3.3.0: {} + path-to-regexp@6.3.0: {} + path-type@2.0.0: dependencies: pify: 2.3.0 - path-type@3.0.0: - dependencies: - pify: 3.0.0 - path-type@4.0.0: {} pathe@1.1.2: {} pathe@2.0.3: {} - pathval@2.0.0: {} - - pbkdf2@3.1.2: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 + pathval@2.0.1: {} pe-library@1.0.1: {} @@ -14599,39 +14454,23 @@ snapshots: perfect-debounce@1.0.0: {} - performance-now@2.1.0: {} - - pg-int8@1.0.1: {} - - pg-protocol@1.10.0: {} - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.0 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 + perfect-debounce@2.1.0: {} picocolors@1.1.1: {} - picomatch@2.3.1: {} - - picomatch@4.0.2: {} + picomatch@2.3.2: {} - pidtree@0.3.1: {} + picomatch@4.0.4: {} pify@2.3.0: {} - pify@3.0.0: {} - pify@4.0.1: {} pinia-plugin-persistedstate@4.1.1(pinia@2.2.4(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3))): dependencies: - '@nuxt/kit': 3.17.5 + '@nuxt/kit': 3.21.2 deep-pick-omit: 1.2.1 - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 optionalDependencies: pinia: 2.2.4(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3)) @@ -14646,196 +14485,137 @@ snapshots: optionalDependencies: typescript: 5.8.3 - pkg-dir@4.2.0: - dependencies: - find-up: 4.1.0 - - pkg-dir@5.0.0: - dependencies: - find-up: 5.0.0 - pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.7.4 + mlly: 1.8.2 pathe: 2.0.3 - pkg-types@2.1.0: + pkg-types@2.3.0: dependencies: - confbox: 0.2.2 - exsolve: 1.0.5 + confbox: 0.2.4 + exsolve: 1.0.8 pathe: 2.0.3 - playwright-core@1.48.1: {} + playwright-core@1.48.2: {} - playwright@1.48.1: + playwright@1.48.2: dependencies: - playwright-core: 1.48.1 + playwright-core: 1.48.2 optionalDependencies: fsevents: 2.3.2 plist@3.1.0: dependencies: - '@xmldom/xmldom': 0.8.10 + '@xmldom/xmldom': 0.8.12 base64-js: 1.5.1 xmlbuilder: 15.1.1 - pnpm@9.12.2: {} - polished@4.3.1: dependencies: - '@babel/runtime': 7.27.6 - - possible-typed-array-names@1.1.0: {} - - postcss-selector-parser@6.1.2: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 + '@babel/runtime': 7.29.2 postcss@8.4.31: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.4: + postcss@8.5.15: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 - postgres-array@2.0.0: {} - - postgres-bytea@1.0.0: {} - - postgres-date@1.0.7: {} - - postgres-interval@1.2.0: + postcss@8.5.9: dependencies: - xtend: 4.0.2 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 posthog-js@1.215.0: dependencies: - core-js: 3.43.0 + core-js: 3.49.0 fflate: 0.4.8 - preact: 10.26.8 + preact: 10.29.1 web-vitals: 4.2.4 - posthog-node@4.4.1: + posthog-node@5.30.6(rxjs@7.8.2): dependencies: - axios: 1.9.0 - transitivePeerDependencies: - - debug + '@posthog/core': 1.27.7 + optionalDependencies: + rxjs: 7.8.2 postject@1.0.0-alpha.6: dependencies: commander: 9.5.0 - preact@10.26.8: {} - - prelude-ls@1.2.1: {} + powershell-utils@0.1.0: {} - prepend-http@2.0.0: {} - - prettier-linter-helpers@1.0.0: - dependencies: - fast-diff: 1.3.0 + preact@10.29.1: {} prettier@2.8.8: {} - prettier@3.3.3: {} + prettier@3.8.2: {} - pretty-ms@9.2.0: + pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 - primeflex@3.3.1: {} + primeflex@4.0.0: {} primeicons@7.0.0: {} - primevue@4.1.1(vue@3.5.13(typescript@5.8.3)): + primevue@4.5.4(vue@3.5.13(typescript@5.8.3)): dependencies: - '@primeuix/styled': 0.2.0 - '@primeuix/utils': 0.2.0 - '@primevue/core': 4.1.1(vue@3.5.13(typescript@5.8.3)) - '@primevue/icons': 4.1.1(vue@3.5.13(typescript@5.8.3)) + '@primeuix/styled': 0.7.4 + '@primeuix/styles': 2.0.3 + '@primeuix/utils': 0.6.4 + '@primevue/core': 4.5.4(vue@3.5.13(typescript@5.8.3)) + '@primevue/icons': 4.5.4(vue@3.5.13(typescript@5.8.3)) transitivePeerDependencies: - vue proc-log@2.0.1: {} + proc-log@6.1.0: {} + process-nextick-args@2.0.1: {} process@0.11.10: {} progress@2.0.3: {} - promise-inflight@1.0.1(bluebird@3.7.2): - optionalDependencies: - bluebird: 3.7.2 + promise-inflight@1.0.1: {} promise-retry@2.0.1: dependencies: err-code: 2.0.3 retry: 0.12.0 - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - proto-list@1.2.4: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - proxy-from-env@1.1.0: {} - - prr@1.0.1: - optional: true - psl@1.15.0: dependencies: punycode: 2.3.1 - public-encrypt@4.0.3: + publint@0.3.18: dependencies: - bn.js: 4.12.2 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - parse-asn1: 5.1.7 - randombytes: 2.1.0 - safe-buffer: 5.2.1 + '@publint/pack': 0.1.4 + package-manager-detector: 1.6.0 + picocolors: 1.1.1 + sade: 1.8.1 - pump@3.0.2: + pump@3.0.4: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 - punycode@1.4.1: {} - punycode@2.3.1: {} - pupa@2.1.1: - dependencies: - escape-goat: 2.1.1 - - qs@6.13.0: - dependencies: - side-channel: 1.1.0 - - qs@6.14.0: - dependencies: - side-channel: 1.1.0 - - qs@6.5.3: {} + quansync@0.2.11: {} - quansync@0.2.10: {} + quansync@1.0.0: {} - querystring-es3@0.2.1: {} + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -14857,90 +14637,53 @@ snapshots: '@jitl/quickjs-wasmfile-release-sync': 0.31.0 quickjs-emscripten-core: 0.31.0 + radix3@1.1.2: {} + random-path@0.1.2: dependencies: base32-encode: 1.2.0 murmur-32: 0.2.0 optional: true - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - randomfill@1.0.4: - dependencies: - randombytes: 2.1.0 - safe-buffer: 5.2.1 - range-parser@1.2.0: {} - range-parser@1.2.1: {} - - ranges-apply@7.0.19: - dependencies: - ranges-merge: 9.0.18 - tiny-invariant: 1.3.3 - - ranges-merge@9.0.18: + ranges-apply@7.1.3: dependencies: - ranges-push: 7.0.18 - ranges-sort: 6.0.13 + ranges-merge: 9.1.3 + tiny-invariant: 1.3.3 - ranges-push@7.0.18: + ranges-merge@9.1.3: dependencies: - codsen-utils: 1.6.7 - ranges-sort: 6.0.13 - string-collapse-leading-whitespace: 7.0.9 - string-trim-spaces-only: 5.0.12 - - ranges-sort@6.0.13: {} + ranges-push: 7.1.3 + ranges-sort: 6.1.3 - raw-body@2.5.2: + ranges-push@7.1.3: dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 + codsen-utils: 1.7.3 + ranges-sort: 6.1.3 + string-collapse-leading-whitespace: 7.1.3 + string-trim-spaces-only: 5.1.3 - rc-config-loader@4.1.3: - dependencies: - debug: 4.4.1 - js-yaml: 4.1.0 - json5: 2.2.3 - require-from-string: 2.0.2 - transitivePeerDependencies: - - supports-color + ranges-sort@6.1.3: {} - rc9@2.1.2: + rc9@3.0.1: dependencies: - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 - rc@1.2.8: + react-dom@19.2.5(react@19.2.5): dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - - react-dom@19.1.0(react@19.1.0): - dependencies: - react: 19.1.0 - scheduler: 0.26.0 + react: 19.2.5 + scheduler: 0.27.0 - react@19.1.0: {} + react@19.2.5: {} read-binary-file-arch@1.0.6: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color - read-package-json-fast@2.0.3: - dependencies: - json-parse-even-better-errors: 2.3.1 - npm-normalize-package-bin: 1.0.1 - read-pkg-up@2.0.0: dependencies: find-up: 2.1.0 @@ -14952,19 +14695,18 @@ snapshots: normalize-package-data: 2.5.0 path-type: 2.0.0 - read-pkg@3.0.0: - dependencies: - load-json-file: 4.0.0 - normalize-package-data: 2.5.0 - path-type: 3.0.0 - read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 - js-yaml: 3.14.1 + js-yaml: 3.14.2 pify: 4.0.1 strip-bom: 3.0.0 + read-yaml-file@2.1.0: + dependencies: + js-yaml: 4.1.1 + strip-bom: 4.0.0 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -14991,91 +14733,29 @@ snapshots: readdir-glob@1.1.3: dependencies: - minimatch: 5.1.6 + minimatch: 5.1.9 readdirp@3.6.0: dependencies: - picomatch: 2.3.1 + picomatch: 2.3.2 - readdirp@4.1.2: {} + readdirp@4.1.2: + optional: true - rechoir@0.6.2: - dependencies: - resolve: 1.22.10 + readdirp@5.0.0: {} rechoir@0.8.0: dependencies: - resolve: 1.22.10 - - reflect.getprototypeof@1.0.10: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - - regenerator-runtime@0.13.11: {} - - regexp.prototype.flags@1.5.4: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - - registry-auth-token@4.2.2: - dependencies: - rc: 1.2.8 - - registry-url@5.1.0: - dependencies: - rc: 1.2.8 - - remote-git-tags@3.0.0: {} + resolve: 1.22.12 repeat-string@1.6.1: optional: true - request@2.88.2: - dependencies: - aws-sign2: 0.7.0 - aws4: 1.13.2 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.3.3 - har-validator: 5.1.5 - http-signature: 1.2.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.35 - oauth-sign: 0.9.0 - performance-now: 2.1.0 - qs: 6.5.3 - safe-buffer: 5.2.1 - tough-cookie: 2.5.0 - tunnel-agent: 0.6.0 - uuid: 3.4.0 - require-directory@2.1.1: {} require-from-string@2.0.2: {} - require-in-the-middle@7.5.2: - dependencies: - debug: 4.4.1 - module-details-from-path: 1.0.4 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color + requires-port@1.0.0: {} resedit@2.0.3: dependencies: @@ -15083,31 +14763,17 @@ snapshots: resolve-alpn@1.2.1: {} - resolve-dir@1.0.1: - dependencies: - expand-tilde: 2.0.2 - global-modules: 1.0.0 - - resolve-from@4.0.0: {} - resolve-from@5.0.0: {} - resolve-package@1.0.1: - dependencies: - get-installed-path: 2.1.1 - resolve-pkg-maps@1.0.0: {} - resolve@1.22.10: + resolve@1.22.12: dependencies: + es-errors: 1.3.0 is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - responselike@1.0.2: - dependencies: - lowercase-keys: 1.0.1 - responselike@2.0.1: dependencies: lowercase-keys: 2.0.0 @@ -15137,11 +14803,6 @@ snapshots: dependencies: glob: 7.2.3 - ripemd160@2.0.2: - dependencies: - hash-base: 3.0.5 - inherits: 2.0.4 - roarr@2.15.4: dependencies: boolean: 3.2.0 @@ -15152,219 +14813,312 @@ snapshots: sprintf-js: 1.1.3 optional: true - rollup@4.42.0: + rolldown-plugin-dts@0.22.5(rolldown@1.0.0-rc.9(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(typescript@5.9.3): dependencies: - '@types/estree': 1.0.7 + '@babel/generator': 8.0.0-rc.2 + '@babel/helper-validator-identifier': 8.0.0-rc.2 + '@babel/parser': 8.0.0-rc.2 + '@babel/types': 8.0.0-rc.2 + ast-kit: 3.0.0-beta.1 + birpc: 4.0.0 + dts-resolver: 2.1.3 + get-tsconfig: 4.13.7 + obug: 2.1.1 + rolldown: 1.0.0-rc.9(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.42.0 - '@rollup/rollup-android-arm64': 4.42.0 - '@rollup/rollup-darwin-arm64': 4.42.0 - '@rollup/rollup-darwin-x64': 4.42.0 - '@rollup/rollup-freebsd-arm64': 4.42.0 - '@rollup/rollup-freebsd-x64': 4.42.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.42.0 - '@rollup/rollup-linux-arm-musleabihf': 4.42.0 - '@rollup/rollup-linux-arm64-gnu': 4.42.0 - '@rollup/rollup-linux-arm64-musl': 4.42.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.42.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.42.0 - '@rollup/rollup-linux-riscv64-gnu': 4.42.0 - '@rollup/rollup-linux-riscv64-musl': 4.42.0 - '@rollup/rollup-linux-s390x-gnu': 4.42.0 - '@rollup/rollup-linux-x64-gnu': 4.42.0 - '@rollup/rollup-linux-x64-musl': 4.42.0 - '@rollup/rollup-win32-arm64-msvc': 4.42.0 - '@rollup/rollup-win32-ia32-msvc': 4.42.0 - '@rollup/rollup-win32-x64-msvc': 4.42.0 - fsevents: 2.3.3 - - rrweb-cssom@0.7.1: {} - - rrweb-cssom@0.8.0: {} + typescript: 5.9.3 + transitivePeerDependencies: + - oxc-resolver - run-applescript@7.0.0: {} + rolldown@1.0.0-rc.15: + dependencies: + '@oxc-project/types': 0.124.0 + '@rolldown/pluginutils': 1.0.0-rc.15 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.15 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 + '@rolldown/binding-darwin-x64': 1.0.0-rc.15 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 + + rolldown@1.0.0-rc.9(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): + dependencies: + '@oxc-project/types': 0.115.0 + '@rolldown/pluginutils': 1.0.0-rc.9 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.9 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.9 + '@rolldown/binding-darwin-x64': 1.0.0-rc.9 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.9 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.9 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.9 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.9 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.9 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.9 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.9(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.9 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.9 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + rolldown@1.0.2: + dependencies: + '@oxc-project/types': 0.132.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.2 + '@rolldown/binding-darwin-arm64': 1.0.2 + '@rolldown/binding-darwin-x64': 1.0.2 + '@rolldown/binding-freebsd-x64': 1.0.2 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 + '@rolldown/binding-linux-arm64-gnu': 1.0.2 + '@rolldown/binding-linux-arm64-musl': 1.0.2 + '@rolldown/binding-linux-ppc64-gnu': 1.0.2 + '@rolldown/binding-linux-s390x-gnu': 1.0.2 + '@rolldown/binding-linux-x64-gnu': 1.0.2 + '@rolldown/binding-linux-x64-musl': 1.0.2 + '@rolldown/binding-openharmony-arm64': 1.0.2 + '@rolldown/binding-wasm32-wasi': 1.0.2 + '@rolldown/binding-win32-arm64-msvc': 1.0.2 + '@rolldown/binding-win32-x64-msvc': 1.0.2 + + rollup@4.60.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.1 + '@rollup/rollup-android-arm64': 4.60.1 + '@rollup/rollup-darwin-arm64': 4.60.1 + '@rollup/rollup-darwin-x64': 4.60.1 + '@rollup/rollup-freebsd-arm64': 4.60.1 + '@rollup/rollup-freebsd-x64': 4.60.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.1 + '@rollup/rollup-linux-arm-musleabihf': 4.60.1 + '@rollup/rollup-linux-arm64-gnu': 4.60.1 + '@rollup/rollup-linux-arm64-musl': 4.60.1 + '@rollup/rollup-linux-loong64-gnu': 4.60.1 + '@rollup/rollup-linux-loong64-musl': 4.60.1 + '@rollup/rollup-linux-ppc64-gnu': 4.60.1 + '@rollup/rollup-linux-ppc64-musl': 4.60.1 + '@rollup/rollup-linux-riscv64-gnu': 4.60.1 + '@rollup/rollup-linux-riscv64-musl': 4.60.1 + '@rollup/rollup-linux-s390x-gnu': 4.60.1 + '@rollup/rollup-linux-x64-gnu': 4.60.1 + '@rollup/rollup-linux-x64-musl': 4.60.1 + '@rollup/rollup-openbsd-x64': 4.60.1 + '@rollup/rollup-openharmony-arm64': 4.60.1 + '@rollup/rollup-win32-arm64-msvc': 4.60.1 + '@rollup/rollup-win32-ia32-msvc': 4.60.1 + '@rollup/rollup-win32-x64-gnu': 4.60.1 + '@rollup/rollup-win32-x64-msvc': 4.60.1 + fsevents: 2.3.3 - run-async@2.4.1: {} + run-applescript@7.1.0: {} run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - rxjs@6.6.7: + rxjs@7.8.2: dependencies: - tslib: 1.14.1 + tslib: 2.8.1 - safe-array-concat@1.1.3: + sade@1.8.1: dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 + mri: 1.2.0 safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} - safe-push-apply@1.0.0: + safer-buffer@2.1.2: {} + + sass-embedded-all-unknown@1.99.0: dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 + sass: 1.99.0 + optional: true + + sass-embedded-android-arm64@1.99.0: + optional: true + + sass-embedded-android-arm@1.99.0: + optional: true + + sass-embedded-android-riscv64@1.99.0: + optional: true + + sass-embedded-android-x64@1.99.0: + optional: true + + sass-embedded-darwin-arm64@1.99.0: + optional: true + + sass-embedded-darwin-x64@1.99.0: + optional: true + + sass-embedded-linux-arm64@1.99.0: + optional: true + + sass-embedded-linux-arm@1.99.0: + optional: true + + sass-embedded-linux-musl-arm64@1.99.0: + optional: true + + sass-embedded-linux-musl-arm@1.99.0: + optional: true + + sass-embedded-linux-musl-riscv64@1.99.0: + optional: true + + sass-embedded-linux-musl-x64@1.99.0: + optional: true + + sass-embedded-linux-riscv64@1.99.0: + optional: true + + sass-embedded-linux-x64@1.99.0: + optional: true - safe-regex-test@1.1.0: + sass-embedded-unknown-all@1.99.0: dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 + sass: 1.99.0 + optional: true - safer-buffer@2.1.2: {} + sass-embedded-win32-arm64@1.99.0: + optional: true + + sass-embedded-win32-x64@1.99.0: + optional: true - sass@1.80.4: + sass-embedded@1.99.0: + dependencies: + '@bufbuild/protobuf': 2.11.0 + colorjs.io: 0.5.2 + immutable: 5.1.5 + rxjs: 7.8.2 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-all-unknown: 1.99.0 + sass-embedded-android-arm: 1.99.0 + sass-embedded-android-arm64: 1.99.0 + sass-embedded-android-riscv64: 1.99.0 + sass-embedded-android-x64: 1.99.0 + sass-embedded-darwin-arm64: 1.99.0 + sass-embedded-darwin-x64: 1.99.0 + sass-embedded-linux-arm: 1.99.0 + sass-embedded-linux-arm64: 1.99.0 + sass-embedded-linux-musl-arm: 1.99.0 + sass-embedded-linux-musl-arm64: 1.99.0 + sass-embedded-linux-musl-riscv64: 1.99.0 + sass-embedded-linux-musl-x64: 1.99.0 + sass-embedded-linux-riscv64: 1.99.0 + sass-embedded-linux-x64: 1.99.0 + sass-embedded-unknown-all: 1.99.0 + sass-embedded-win32-arm64: 1.99.0 + sass-embedded-win32-x64: 1.99.0 + + sass@1.99.0: dependencies: - '@parcel/watcher': 2.5.1 chokidar: 4.0.3 - immutable: 4.3.7 + immutable: 5.1.5 source-map-js: 1.2.1 - - sax@1.4.1: + optionalDependencies: + '@parcel/watcher': 2.5.6 optional: true - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 + sax@1.6.0: {} - scheduler@0.26.0: {} + scheduler@0.27.0: {} + + schema-utils@4.3.3: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.18.0 + ajv-formats: 2.1.1(ajv@8.18.0) + ajv-keywords: 5.1.0(ajv@8.18.0) scule@1.3.0: {} semver-compare@1.0.0: optional: true - semver-diff@3.1.1: - dependencies: - semver: 6.3.1 - - semver-utils@1.1.4: {} - semver@5.7.2: {} semver@6.3.1: {} - semver@7.3.4: - dependencies: - lru-cache: 6.0.0 - - semver@7.6.3: {} + semver@7.7.4: {} - semver@7.7.2: {} + semver@7.8.0: {} - send@0.19.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 + semver@7.8.1: {} serialize-error@7.0.1: dependencies: type-fest: 0.13.1 optional: true - serve-handler@6.1.6: + serve-handler@6.1.7: dependencies: bytes: 3.0.0 content-disposition: 0.5.2 mime-types: 2.1.18 - minimatch: 3.1.2 + minimatch: 3.1.5 path-is-inside: 1.0.2 path-to-regexp: 3.3.0 range-parser: 1.2.0 - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - - set-blocking@2.0.0: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - - set-proto@1.0.0: - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - set-value@4.1.0: dependencies: is-plain-object: 2.0.4 is-primitive: 3.0.1 - setimmediate@1.0.5: {} - - setprototypeof@1.2.0: {} - - sha.js@2.4.11: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - sharp@0.34.2: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.4 - semver: 7.7.2 + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.1 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.2 - '@img/sharp-darwin-x64': 0.34.2 - '@img/sharp-libvips-darwin-arm64': 1.1.0 - '@img/sharp-libvips-darwin-x64': 1.1.0 - '@img/sharp-libvips-linux-arm': 1.1.0 - '@img/sharp-libvips-linux-arm64': 1.1.0 - '@img/sharp-libvips-linux-ppc64': 1.1.0 - '@img/sharp-libvips-linux-s390x': 1.1.0 - '@img/sharp-libvips-linux-x64': 1.1.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 - '@img/sharp-libvips-linuxmusl-x64': 1.1.0 - '@img/sharp-linux-arm': 0.34.2 - '@img/sharp-linux-arm64': 0.34.2 - '@img/sharp-linux-s390x': 0.34.2 - '@img/sharp-linux-x64': 0.34.2 - '@img/sharp-linuxmusl-arm64': 0.34.2 - '@img/sharp-linuxmusl-x64': 0.34.2 - '@img/sharp-wasm32': 0.34.2 - '@img/sharp-win32-arm64': 0.34.2 - '@img/sharp-win32-ia32': 0.34.2 - '@img/sharp-win32-x64': 0.34.2 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@1.2.0: @@ -15381,54 +15135,24 @@ snapshots: shell-quote@1.8.3: {} - shelljs@0.8.5: - dependencies: - glob: 7.2.3 - interpret: 1.4.0 - rechoir: 0.6.2 - - shimmer@1.2.1: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - siginfo@2.0.0: {} signal-exit@3.0.7: {} signal-exit@4.1.0: {} - simple-swizzle@0.2.2: + sigstore@4.1.0: dependencies: - is-arrayish: 0.3.2 - optional: true + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.1 + '@sigstore/sign': 4.1.1 + '@sigstore/tuf': 4.0.2 + '@sigstore/verify': 3.1.0 + transitivePeerDependencies: + - supports-color - sirv@3.0.1: + sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 mrmime: 2.0.1 @@ -15438,34 +15162,32 @@ snapshots: slash@3.0.0: {} - slash@5.1.0: {} - slice-ansi@5.0.0: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 is-fullwidth-code-point: 4.0.0 smart-buffer@4.2.0: {} - socks-proxy-agent@5.0.1: + socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.4.1 - socks: 2.8.4 + debug: 4.4.3 + socks: 2.8.7 transitivePeerDependencies: - supports-color - socks-proxy-agent@7.0.0: + socks-proxy-agent@8.0.5: dependencies: - agent-base: 6.0.2 - debug: 4.4.1 - socks: 2.8.4 + agent-base: 7.1.4 + debug: 4.4.3 + socks: 2.8.7 transitivePeerDependencies: - supports-color - socks@2.8.4: + socks@2.8.7: dependencies: - ip-address: 9.0.5 + ip-address: 10.1.0 smart-buffer: 4.2.0 source-map-js@1.2.1: {} @@ -15477,8 +15199,6 @@ snapshots: source-map@0.6.1: {} - spawn-please@1.0.0: {} - spawndamnit@3.0.1: dependencies: cross-spawn: 7.0.6 @@ -15487,38 +15207,34 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.21 + spdx-license-ids: 3.0.23 spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.21 + spdx-license-ids: 3.0.23 + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 - spdx-license-ids@3.0.21: {} + spdx-license-ids@3.0.23: {} speakingurl@14.0.1: {} - sprintf-js@1.0.3: {} + split2@4.2.0: {} - sprintf-js@1.1.3: {} + sprintf-js@1.0.3: {} - sshpk@1.18.0: - dependencies: - asn1: 0.2.6 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 + sprintf-js@1.1.3: + optional: true - ssri@8.0.1: + ssri@13.0.1: dependencies: - minipass: 3.3.6 + minipass: 7.1.3 ssri@9.0.1: dependencies: @@ -15531,63 +15247,44 @@ snapshots: '@stablelib/base64': 1.0.1 fast-sha256: 1.3.0 - statuses@2.0.1: {} - - std-env@3.9.0: {} + statuses@2.0.2: {} - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 + std-env@3.10.0: {} - stream-browserify@3.0.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 + stoppable@1.1.0: {} stream-buffers@2.2.0: optional: true - stream-http@3.2.0: - dependencies: - builtin-status-codes: 3.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - xtend: 4.0.2 - - streamsearch@1.1.0: {} - - streamx@2.22.1: + streamx@2.25.0: dependencies: + events-universal: 1.0.1 fast-fifo: 1.3.2 - text-decoder: 1.2.3 - optionalDependencies: - bare-events: 2.5.4 + text-decoder: 1.2.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + strict-event-emitter@0.5.1: {} - string-collapse-leading-whitespace@7.0.9: {} + string-collapse-leading-whitespace@7.1.3: {} - string-left-right@6.0.20: + string-left-right@6.1.3: dependencies: - codsen-utils: 1.6.7 + codsen-utils: 1.7.3 rfdc: 1.4.1 string-strip-html@13.4.8: dependencies: '@types/lodash-es': 4.17.12 - codsen-utils: 1.6.7 + codsen-utils: 1.7.3 html-entities: 2.6.0 - lodash-es: 4.17.21 - ranges-apply: 7.0.19 - ranges-push: 7.0.18 - string-left-right: 6.0.20 + lodash-es: 4.18.1 + ranges-apply: 7.1.3 + ranges-push: 7.1.3 + string-left-right: 6.1.3 - string-trim-spaces-only@5.0.12: {} - - string-width@1.0.2: - dependencies: - code-point-at: 1.1.0 - is-fullwidth-code-point: 1.0.0 - strip-ansi: 3.0.1 + string-trim-spaces-only@5.1.3: {} string-width@4.2.3: dependencies: @@ -15599,37 +15296,7 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string.prototype.padend@3.1.6: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - - string.prototype.trim@1.2.10: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - has-property-descriptors: 1.0.2 - - string.prototype.trimend@1.0.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 + strip-ansi: 7.2.0 string_decoder@1.1.1: dependencies: @@ -15639,90 +15306,81 @@ snapshots: dependencies: safe-buffer: 5.2.1 - strip-ansi@3.0.1: - dependencies: - ansi-regex: 2.1.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.0: + strip-ansi@7.2.0: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 6.2.2 strip-bom@3.0.0: {} - strip-eof@1.0.0: {} + strip-bom@4.0.0: {} - strip-final-newline@4.0.0: {} + strip-comments-strings@1.2.0: {} - strip-json-comments@2.0.1: {} + strip-eof@1.0.0: {} - strip-json-comments@3.1.1: {} + strip-final-newline@4.0.0: {} strip-literal@2.1.1: dependencies: js-tokens: 9.0.1 - strip-literal@3.0.0: - dependencies: - js-tokens: 9.0.1 - strip-outer@1.0.1: dependencies: escape-string-regexp: 1.0.5 - style-mod@4.1.2: {} + structured-clone-es@2.0.0: {} + + style-mod@4.1.3: {} - styled-jsx@5.1.6(@babel/core@7.27.4)(react@19.1.0): + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.5): dependencies: client-only: 0.0.1 - react: 19.1.0 + react: 19.2.5 optionalDependencies: - '@babel/core': 7.27.4 - - sudo-prompt@9.2.1: {} + '@babel/core': 7.29.0 sumchecker@3.0.1: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color - superjson@2.2.2: + superjson@2.2.6: dependencies: - copy-anything: 3.0.5 + copy-anything: 4.0.5 - supports-color@5.5.0: + supports-color@7.2.0: dependencies: - has-flag: 3.0.0 + has-flag: 4.0.0 - supports-color@7.2.0: + supports-color@8.1.1: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} - symbol-tree@3.2.4: {} - - synckit@0.11.8: + sync-child-process@1.0.2: dependencies: - '@pkgr/core': 0.2.7 + sync-message-port: 1.2.0 - tar-stream@2.2.0: - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.4 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 + sync-message-port@1.2.0: {} + + tapable@2.3.2: {} - tar-stream@3.1.7: + tar-stream@3.1.8: dependencies: - b4a: 1.6.7 + b4a: 1.8.0 + bare-fs: 4.7.0 fast-fifo: 1.3.2 - streamx: 2.22.1 + streamx: 2.25.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a tar@6.2.1: dependencies: @@ -15733,6 +15391,21 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + tar@7.5.13: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + + teex@1.0.1: + dependencies: + streamx: 2.25.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + temp@0.9.4: dependencies: mkdirp: 0.5.6 @@ -15741,26 +15414,36 @@ snapshots: term-size@2.2.1: {} - text-decoder@1.2.3: + terser-webpack-plugin@5.4.0(webpack@5.106.1): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + terser: 5.46.1 + webpack: 5.106.1 + + terser@5.46.1: dependencies: - b4a: 1.6.7 + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 + commander: 2.20.3 + source-map-support: 0.5.21 - text-table@0.2.0: {} + text-decoder@1.2.7: + dependencies: + b4a: 1.8.0 + transitivePeerDependencies: + - react-native-b4a - thememirror@2.0.1(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0): + thememirror@2.0.1(@codemirror/language@6.12.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.0): dependencies: - '@codemirror/language': 6.11.1 + '@codemirror/language': 6.12.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.0 - through@2.3.8: {} - - timers-browserify@2.0.12: + thingies@2.6.0(tslib@2.8.1): dependencies: - setimmediate: 1.0.5 - - tiny-each-async@2.0.3: - optional: true + tslib: 2.8.1 tiny-invariant@1.3.3: {} @@ -15768,37 +15451,27 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.14: + tinyexec@1.1.1: {} + + tinyglobby@0.2.16: dependencies: - fdir: 6.4.5(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 tinykeys@2.1.0: {} - tinypool@1.1.0: {} + tinypool@1.1.1: {} + + tinypool@2.1.0: {} tinyrainbow@2.0.0: {} tinyspy@3.0.2: {} - tldts-core@6.1.86: {} - - tldts@6.1.86: - dependencies: - tldts-core: 6.1.86 - - tmp-promise@3.0.3: - dependencies: - tmp: 0.2.3 - optional: true - tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 - tmp@0.2.3: - optional: true - tn1150@0.1.0: dependencies: unorm: 1.6.0 @@ -15807,70 +15480,69 @@ snapshots: to-data-view@1.1.0: optional: true - to-readable-stream@1.0.0: {} - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} - totalist@3.0.1: {} - tough-cookie@2.5.0: + tough-cookie@4.1.4: dependencies: psl: 1.15.0 punycode: 2.3.1 - - tough-cookie@5.1.2: - dependencies: - tldts: 6.1.86 + universalify: 0.2.0 + url-parse: 1.5.10 tr46@0.0.3: {} - tr46@5.1.1: + tree-dump@1.1.0(tslib@2.8.1): dependencies: - punycode: 2.3.1 + tslib: 2.8.1 + + tree-kill@1.2.2: {} trim-repeated@1.0.0: dependencies: escape-string-regexp: 1.0.5 - ts-api-utils@1.4.3(typescript@5.8.3): - dependencies: - typescript: 5.8.3 - ts-deepmerge@7.0.1: {} - ts-essentials@10.0.2(typescript@5.8.3): - optionalDependencies: - typescript: 5.8.3 - - ts-node@10.9.2(@types/node@22.7.9)(typescript@5.8.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 22.7.9 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.8.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - ts-pattern@5.5.0: {} tsconfck@3.1.6(typescript@5.8.3): optionalDependencies: typescript: 5.8.3 - tslib@1.14.1: {} + tsdown@0.21.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@vitejs/devtools@0.1.13)(publint@0.3.18)(typescript@5.9.3): + dependencies: + ansis: 4.2.0 + cac: 7.0.0 + defu: 6.1.7 + empathic: 2.0.0 + hookable: 6.1.0 + import-without-cache: 0.2.5 + obug: 2.1.1 + picomatch: 4.0.4 + rolldown: 1.0.0-rc.9(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + rolldown-plugin-dts: 0.22.5(rolldown@1.0.0-rc.9(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(typescript@5.9.3) + semver: 7.8.0 + tinyexec: 1.1.1 + tinyglobby: 0.2.16 + tree-kill: 1.2.2 + unconfig-core: 7.5.0 + unrun: 0.2.35 + optionalDependencies: + '@vitejs/devtools': 0.1.13(@pnpm/logger@1001.0.1)(typescript@5.9.3)(vite@8.0.14) + publint: 0.3.18 + typescript: 5.9.3 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - '@ts-macro/tsc' + - '@typescript/native-preview' + - oxc-resolver + - synckit + - vue-tsc tslib@2.8.1: {} @@ -15879,111 +15551,92 @@ snapshots: tsx@4.19.1: dependencies: esbuild: 0.23.1 - get-tsconfig: 4.10.1 + get-tsconfig: 4.13.7 optionalDependencies: fsevents: 2.3.3 - tty-browserify@0.0.1: {} - - tunnel-agent@0.6.0: + tuf-js@4.1.0: dependencies: - safe-buffer: 5.2.1 + '@tufjs/models': 4.1.0 + debug: 4.4.3 + make-fetch-happen: 15.0.5 + transitivePeerDependencies: + - supports-color - tweetnacl@0.14.5: {} + tunnel@0.0.6: {} - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 + turbo@2.9.6: + optionalDependencies: + '@turbo/darwin-64': 2.9.6 + '@turbo/darwin-arm64': 2.9.6 + '@turbo/linux-64': 2.9.6 + '@turbo/linux-arm64': 2.9.6 + '@turbo/windows-64': 2.9.6 + '@turbo/windows-arm64': 2.9.6 type-fest@0.13.1: optional: true - type-fest@0.20.2: {} - type-fest@0.21.3: {} type-fest@1.4.0: {} type-fest@4.26.1: {} - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 + type-fest@4.39.0: {} - typed-array-byte-length@1.0.3: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 + typescript@5.4.5: {} - typed-array-byte-offset@1.0.4: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 + typescript@5.8.3: {} - typed-array-length@1.0.7: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 + typescript@5.9.3: {} - typedarray-to-buffer@3.1.5: - dependencies: - is-typedarray: 1.0.0 + typescript@6.0.3: {} - typescript@5.8.3: {} + ufo@1.6.3: {} - ufo@1.6.1: {} + unconfig-core@7.5.0: + dependencies: + '@quansync/fs': 1.0.0 + quansync: 1.0.0 - unbox-primitive@1.1.0: + unconfig@7.5.0: dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 + '@quansync/fs': 1.0.0 + defu: 6.1.7 + jiti: 2.6.1 + quansync: 1.0.0 + unconfig-core: 7.5.0 - unctx@2.4.1: + uncrypto@0.1.3: {} + + unctx@2.5.0: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 estree-walker: 3.0.3 - magic-string: 0.30.17 - unplugin: 2.3.5 + magic-string: 0.30.21 + unplugin: 2.3.11 undici-types@6.19.8: {} undici-types@6.21.0: {} + undici-types@7.16.0: {} + unicorn-magic@0.3.0: {} - unimport@3.14.6(rollup@4.42.0): + unimport@3.14.6(rollup@4.60.1): dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.42.0) - acorn: 8.15.0 + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) + acorn: 8.16.0 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 fast-glob: 3.3.3 - local-pkg: 1.1.1 - magic-string: 0.30.17 - mlly: 1.7.4 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.2 pathe: 2.0.3 - picomatch: 4.0.2 + picomatch: 4.0.4 pkg-types: 1.3.1 scule: 1.3.0 strip-literal: 2.1.1 @@ -15991,113 +15644,93 @@ snapshots: transitivePeerDependencies: - rollup - unimport@5.0.1: - dependencies: - acorn: 8.15.0 - escape-string-regexp: 5.0.0 - estree-walker: 3.0.3 - local-pkg: 1.1.1 - magic-string: 0.30.17 - mlly: 1.7.4 - pathe: 2.0.3 - picomatch: 4.0.2 - pkg-types: 2.1.0 - scule: 1.3.0 - strip-literal: 3.0.0 - tinyglobby: 0.2.14 - unplugin: 2.3.5 - unplugin-utils: 0.2.4 - - unique-filename@1.1.1: - dependencies: - unique-slug: 2.0.2 - unique-filename@2.0.1: dependencies: unique-slug: 3.0.0 - unique-slug@2.0.2: - dependencies: - imurmurhash: 0.1.4 - unique-slug@3.0.0: dependencies: imurmurhash: 0.1.4 - unique-string@2.0.0: - dependencies: - crypto-random-string: 2.0.0 - universal-user-agent@6.0.1: {} universalify@0.1.2: {} + universalify@0.2.0: {} + universalify@2.0.1: {} unorm@1.6.0: optional: true - unpipe@1.0.0: {} - - unplugin-auto-import@0.18.3(@nuxt/kit@3.17.5)(@vueuse/core@11.1.0(vue@3.5.13(typescript@5.8.3)))(rollup@4.42.0): + unplugin-auto-import@0.18.3(@nuxt/kit@3.21.2)(@vueuse/core@11.1.0(vue@3.5.13(typescript@5.8.3)))(rollup@4.60.1): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.4(rollup@4.42.0) + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) fast-glob: 3.3.3 local-pkg: 0.5.1 - magic-string: 0.30.17 - minimatch: 9.0.5 - unimport: 3.14.6(rollup@4.42.0) + magic-string: 0.30.21 + minimatch: 9.0.9 + unimport: 3.14.6(rollup@4.60.1) unplugin: 1.16.1 optionalDependencies: - '@nuxt/kit': 3.17.5 + '@nuxt/kit': 3.21.2 '@vueuse/core': 11.1.0(vue@3.5.13(typescript@5.8.3)) transitivePeerDependencies: - rollup - unplugin-utils@0.2.4: + unplugin-utils@0.3.1: dependencies: pathe: 2.0.3 - picomatch: 4.0.2 + picomatch: 4.0.4 - unplugin-vue-components@0.27.4(@babel/parser@7.27.5)(@nuxt/kit@3.17.5)(rollup@4.42.0)(vue@3.5.13(typescript@5.8.3)): + unplugin-vue-components@0.27.4(@babel/parser@7.29.3)(@nuxt/kit@3.21.2)(rollup@4.60.1)(vue@3.5.13(typescript@5.8.3)): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.4(rollup@4.42.0) + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) chokidar: 3.6.0 - debug: 4.4.1 + debug: 4.4.3 fast-glob: 3.3.3 local-pkg: 0.5.1 - magic-string: 0.30.17 - minimatch: 9.0.5 - mlly: 1.7.4 + magic-string: 0.30.21 + minimatch: 9.0.9 + mlly: 1.8.2 unplugin: 1.16.1 vue: 3.5.13(typescript@5.8.3) optionalDependencies: - '@babel/parser': 7.27.5 - '@nuxt/kit': 3.17.5 + '@babel/parser': 7.29.3 + '@nuxt/kit': 3.21.2 transitivePeerDependencies: - rollup - supports-color - unplugin@1.0.1: - dependencies: - acorn: 8.15.0 - chokidar: 3.6.0 - webpack-sources: 3.3.2 - webpack-virtual-modules: 0.5.0 - unplugin@1.16.1: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 webpack-virtual-modules: 0.6.2 - unplugin@2.3.5: + unplugin@2.3.11: dependencies: - acorn: 8.15.0 - picomatch: 4.0.2 + '@jridgewell/remapping': 2.3.5 + acorn: 8.16.0 + picomatch: 4.0.4 webpack-virtual-modules: 0.6.2 + unrun@0.2.35: + dependencies: + rolldown: 1.0.0-rc.15 + + unstorage@1.17.5: + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.3.5 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + untun@0.1.3: dependencies: citty: 0.1.6 @@ -16107,52 +15740,21 @@ snapshots: untyped@2.0.0: dependencies: citty: 0.1.6 - defu: 6.1.4 - jiti: 2.4.2 - knitwork: 1.2.0 + defu: 6.1.7 + jiti: 2.6.1 + knitwork: 1.3.0 scule: 1.3.0 - update-browserslist-db@1.1.3(browserslist@4.25.0): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.25.0 + browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 - update-electron-app@3.0.0: - dependencies: - github-url-to-object: 4.0.6 - is-url: 1.2.4 - ms: 2.1.3 - - update-notifier@5.1.0: - dependencies: - boxen: 5.1.2 - chalk: 4.1.0 - configstore: 5.0.1 - has-yarn: 2.1.0 - import-lazy: 2.1.0 - is-ci: 2.0.0 - is-installed-globally: 0.4.0 - is-npm: 5.0.0 - is-yarn-global: 0.3.0 - latest-version: 5.1.0 - pupa: 2.1.1 - semver: 7.6.3 - semver-diff: 3.1.1 - xdg-basedir: 4.0.0 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - url-parse-lax@3.0.0: - dependencies: - prepend-http: 2.0.0 - - url@0.11.4: + url-parse@1.5.10: dependencies: - punycode: 1.4.1 - qs: 6.14.0 + querystringify: 2.2.0 + requires-port: 1.0.0 username@5.1.0: dependencies: @@ -16161,19 +15763,7 @@ snapshots: util-deprecate@1.0.2: {} - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.2.0 - is-generator-function: 1.1.0 - is-typed-array: 1.1.15 - which-typed-array: 1.1.19 - - utils-merge@1.0.1: {} - - uuid@3.4.0: {} - - v8-compile-cache-lib@3.0.1: {} + uuid@8.3.2: {} valibot@0.33.3: {} @@ -16181,46 +15771,57 @@ snapshots: optionalDependencies: typescript: 5.8.3 + valibot@0.42.1(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + valibot@1.3.1(typescript@5.8.3): + optionalDependencies: + typescript: 5.8.3 + + valibot@1.3.1(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + optional: true + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - validate-npm-package-name@3.0.0: - dependencies: - builtins: 1.0.3 + validate-npm-package-name@7.0.2: {} - vary@1.1.2: {} + varint@6.0.0: {} vee-validate@4.13.2(vue@3.5.13(typescript@5.8.3)): dependencies: '@vue/devtools-api': 6.6.4 - type-fest: 4.26.1 + type-fest: 4.39.0 vue: 3.5.13(typescript@5.8.3) vee-validate@4.14.4(vue@3.5.13(typescript@5.8.3)): dependencies: - '@vue/devtools-api': 7.7.6 - type-fest: 4.26.1 + '@vue/devtools-api': 7.7.9 + type-fest: 4.39.0 vue: 3.5.13(typescript@5.8.3) - verror@1.10.0: + vite-dev-rpc@1.1.0(vite@8.0.8): dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.3.0 + birpc: 2.9.0 + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vite-hot-client: 2.1.0(vite@8.0.8) - vite-hot-client@2.0.4(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): + vite-hot-client@2.1.0(vite@8.0.8): dependencies: - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) - vite-node@3.1.4(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1): + vite-node@3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1): dependencies: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) + vite: 6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) transitivePeerDependencies: - '@types/node' - jiti @@ -16235,129 +15836,160 @@ snapshots: - tsx - yaml - vite-plugin-inspect@0.8.9(@nuxt/kit@3.17.5)(rollup@4.42.0)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): + vite-plugin-inspect@11.3.3(@nuxt/kit@3.21.2)(vite@8.0.8): dependencies: - '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.4(rollup@4.42.0) - debug: 4.4.1 - error-stack-parser-es: 0.1.5 - fs-extra: 11.3.0 - open: 10.1.2 - perfect-debounce: 1.0.0 - picocolors: 1.1.1 - sirv: 3.0.1 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) + ansis: 4.2.0 + debug: 4.4.3 + error-stack-parser-es: 1.0.5 + ohash: 2.0.11 + open: 10.2.0 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + unplugin-utils: 0.3.1 + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vite-dev-rpc: 1.1.0(vite@8.0.8) optionalDependencies: - '@nuxt/kit': 3.17.5 + '@nuxt/kit': 3.21.2 transitivePeerDependencies: - - rollup - supports-color - vite-plugin-node-polyfills@0.23.0(rollup@4.42.0)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): + vite-plugin-vue-devtools@8.1.1(@nuxt/kit@3.21.2)(vite@8.0.8)(vue@3.5.13(typescript@5.8.3)): dependencies: - '@rollup/plugin-inject': 5.0.5(rollup@4.42.0) - node-stdlib-browser: 1.3.1 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - transitivePeerDependencies: - - rollup - - vite-plugin-static-copy@2.3.1(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): - dependencies: - chokidar: 3.6.0 - fast-glob: 3.3.3 - fs-extra: 11.3.0 - p-map: 7.0.3 - picocolors: 1.1.1 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - - vite-plugin-vue-devtools@7.7.5(@nuxt/kit@3.17.5)(rollup@4.42.0)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1))(vue@3.5.13(typescript@5.8.3)): - dependencies: - '@vue/devtools-core': 7.7.6(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1))(vue@3.5.13(typescript@5.8.3)) - '@vue/devtools-kit': 7.7.6 - '@vue/devtools-shared': 7.7.6 - execa: 9.6.0 - sirv: 3.0.1 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.17.5)(rollup@4.42.0)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) - vite-plugin-vue-inspector: 5.3.1(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) + '@vue/devtools-core': 8.1.1(vue@3.5.13(typescript@5.8.3)) + '@vue/devtools-kit': 8.1.1 + '@vue/devtools-shared': 8.1.1 + sirv: 3.0.2 + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vite-plugin-inspect: 11.3.3(@nuxt/kit@3.21.2)(vite@8.0.8) + vite-plugin-vue-inspector: 5.4.0(vite@8.0.8) transitivePeerDependencies: - '@nuxt/kit' - - rollup - supports-color - vue - vite-plugin-vue-inspector@5.3.1(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): + vite-plugin-vue-inspector@5.4.0(vite@8.0.8): dependencies: - '@babel/core': 7.27.4 - '@babel/plugin-proposal-decorators': 7.27.1(@babel/core@7.27.4) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.4) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.4) - '@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.27.4) - '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.27.4) - '@vue/compiler-dom': 3.5.16 + '@babel/core': 7.29.0 + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) + '@vue/compiler-dom': 3.5.32 kolorist: 1.8.0 - magic-string: 0.30.17 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) + magic-string: 0.30.21 + vite: 8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) transitivePeerDependencies: - supports-color - vite-plugin-wasm@3.4.1(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): - dependencies: - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - - vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)): + vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1)): dependencies: - debug: 4.4.1 + debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.8.3) optionalDependencies: - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) + vite: 6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) transitivePeerDependencies: - supports-color - typescript - vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1): + vite@6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1): dependencies: - esbuild: 0.25.5 - fdir: 6.4.5(picomatch@4.0.2) - picomatch: 4.0.2 - postcss: 8.5.4 - rollup: 4.42.0 - tinyglobby: 0.2.14 + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.9 + rollup: 4.60.1 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 22.7.9 + '@types/node': 24.12.2 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.32.0 + sass: 1.99.0 + sass-embedded: 1.99.0 + terser: 5.46.1 + tsx: 4.19.1 + + vite@8.0.14(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.2 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 24.12.2 + '@vitejs/devtools': 0.1.13(@pnpm/logger@1001.0.1)(typescript@5.9.3)(vite@8.0.14) + esbuild: 0.27.7 + fsevents: 2.3.3 + jiti: 2.6.1 + sass: 1.99.0 + sass-embedded: 1.99.0 + terser: 5.46.1 + tsx: 4.19.1 + optional: true + + vite@8.0.14(@types/node@24.12.4)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.2 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 24.12.4 + esbuild: 0.27.7 + fsevents: 2.3.3 + jiti: 2.6.1 + sass: 1.99.0 + sass-embedded: 1.99.0 + terser: 5.46.1 + tsx: 4.19.1 + + vite@8.0.8(@types/node@24.12.2)(@vitejs/devtools@0.1.13)(esbuild@0.27.7)(jiti@2.6.1)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.9 + rolldown: 1.0.0-rc.15 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 24.12.2 + '@vitejs/devtools': 0.1.13(@pnpm/logger@1001.0.1)(typescript@5.8.3)(vite@8.0.8) + esbuild: 0.27.7 fsevents: 2.3.3 - jiti: 2.4.2 - less: 4.2.0 - sass: 1.80.4 + jiti: 2.6.1 + sass: 1.99.0 + sass-embedded: 1.99.0 + terser: 5.46.1 tsx: 4.19.1 - vitest@3.1.4(@types/node@22.7.9)(jiti@2.4.2)(jsdom@25.0.1)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1): + vitest@3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.8.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1): dependencies: '@vitest/expect': 3.1.4 - '@vitest/mocker': 3.1.4(vite@6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1)) - '@vitest/pretty-format': 3.2.2 + '@vitest/mocker': 3.1.4(msw@2.7.5(@types/node@24.12.2)(typescript@5.8.3))(vite@6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1)) + '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.1.4 '@vitest/snapshot': 3.1.4 '@vitest/spy': 3.1.4 '@vitest/utils': 3.1.4 - chai: 5.2.0 - debug: 4.4.1 - expect-type: 1.2.1 - magic-string: 0.30.17 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 pathe: 2.0.3 - std-env: 3.9.0 + std-env: 3.10.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 - tinypool: 1.1.0 + tinyglobby: 0.2.16 + tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.3.3(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) - vite-node: 3.1.4(@types/node@22.7.9)(jiti@2.4.2)(less@4.2.0)(sass@1.80.4)(tsx@4.19.1) + vite: 6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vite-node: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.7.9 - jsdom: 25.0.1 + '@types/node': 24.12.2 transitivePeerDependencies: - jiti - less @@ -16372,12 +16004,47 @@ snapshots: - tsx - yaml - vm-browserify@1.1.2: {} + vitest@3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1): + dependencies: + '@vitest/expect': 3.1.4 + '@vitest/mocker': 3.1.4(msw@2.7.5(@types/node@24.12.2)(typescript@5.9.3))(vite@6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.1.4 + '@vitest/snapshot': 3.1.4 + '@vitest/spy': 3.1.4 + '@vitest/utils': 3.1.4 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 2.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.16 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 6.3.3(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + vite-node: 3.1.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.19.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.12.2 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml vscode-uri@3.1.0: {} - vue-component-type-helpers@2.2.10: {} - vue-demi@0.14.10(vue@3.5.13(typescript@5.8.3)): dependencies: vue: 3.5.13(typescript@5.8.3) @@ -16387,23 +16054,10 @@ snapshots: dompurify: 3.1.7 vue: 3.5.13(typescript@5.8.3) - vue-eslint-parser@9.4.3(eslint@9.13.0(jiti@2.4.2)): - dependencies: - debug: 4.4.1 - eslint: 9.13.0(jiti@2.4.2) - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - lodash: 4.17.21 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color - - vue-i18n@10.0.7(vue@3.5.13(typescript@5.8.3)): + vue-i18n@10.0.8(vue@3.5.13(typescript@5.8.3)): dependencies: - '@intlify/core-base': 10.0.7 - '@intlify/shared': 10.0.7 + '@intlify/core-base': 10.0.8 + '@intlify/shared': 10.0.8 '@vue/devtools-api': 6.6.4 vue: 3.5.13(typescript@5.8.3) @@ -16414,11 +16068,28 @@ snapshots: vue-tsc@2.1.6(typescript@5.8.3): dependencies: - '@volar/typescript': 2.4.14 + '@volar/typescript': 2.4.28 '@vue/language-core': 2.1.6(typescript@5.8.3) - semver: 7.6.3 + semver: 7.8.1 typescript: 5.8.3 + vue-tsc@3.3.1(typescript@6.0.3): + dependencies: + '@volar/typescript': 2.4.28 + '@vue/language-core': 3.3.1 + typescript: 6.0.3 + + vue-virtual-scroller@2.0.1(vue@3.5.34(typescript@5.8.3)): + dependencies: + mitt: 2.1.0 + vue: 3.5.34(typescript@5.8.3) + + vue-virtual-scroller@2.0.1(vue@3.5.34(typescript@5.9.3)): + dependencies: + mitt: 2.1.0 + vue: 3.5.34(typescript@5.9.3) + optional: true + vue@3.5.13(typescript@5.8.3): dependencies: '@vue/compiler-dom': 3.5.13 @@ -16429,11 +16100,43 @@ snapshots: optionalDependencies: typescript: 5.8.3 + vue@3.5.34(typescript@5.8.3): + dependencies: + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-sfc': 3.5.34 + '@vue/runtime-dom': 3.5.34 + '@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@5.8.3)) + '@vue/shared': 3.5.34 + optionalDependencies: + typescript: 5.8.3 + + vue@3.5.34(typescript@5.9.3): + dependencies: + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-sfc': 3.5.34 + '@vue/runtime-dom': 3.5.34 + '@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@5.9.3)) + '@vue/shared': 3.5.34 + optionalDependencies: + typescript: 5.9.3 + optional: true + + vue@3.5.34(typescript@6.0.3): + dependencies: + '@vue/compiler-dom': 3.5.34 + '@vue/compiler-sfc': 3.5.34 + '@vue/runtime-dom': 3.5.34 + '@vue/server-renderer': 3.5.34(vue@3.5.34(typescript@6.0.3)) + '@vue/shared': 3.5.34 + optionalDependencies: + typescript: 6.0.3 + w3c-keyname@2.2.8: {} - w3c-xmlserializer@5.0.0: + watchpack@2.5.1: dependencies: - xml-name-validator: 5.0.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 wcwidth@1.0.1: dependencies: @@ -16441,75 +16144,49 @@ snapshots: web-vitals@4.2.4: {} - web-worker@1.3.0: {} - webidl-conversions@3.0.1: {} - webidl-conversions@7.0.0: {} - - webpack-sources@3.3.2: {} - - webpack-virtual-modules@0.5.0: {} + webpack-sources@3.3.4: {} webpack-virtual-modules@0.6.2: {} - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - - whatwg-mimetype@4.0.0: {} - - whatwg-url@14.2.0: + webpack@5.106.1: dependencies: - tr46: 5.1.1 - webidl-conversions: 7.0.0 + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) + browserslist: 4.28.2 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.20.1 + es-module-lexer: 2.0.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.1 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.2 + terser-webpack-plugin: 5.4.0(webpack@5.106.1) + watchpack: 2.5.1 + webpack-sources: 3.3.4 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js whatwg-url@5.0.0: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-builtin-type@1.2.1: - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.19 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-typed-array@1.1.19: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - which@1.3.1: dependencies: isexe: 2.0.0 @@ -16518,20 +16195,20 @@ snapshots: dependencies: isexe: 2.0.0 + which@6.0.1: + dependencies: + isexe: 4.0.0 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - wide-align@1.1.5: - dependencies: - string-width: 1.0.2 - - widest-line@3.1.0: + wrap-ansi@6.2.0: dependencies: + ansi-styles: 4.3.0 string-width: 4.2.3 - - word-wrap@1.2.5: {} + strip-ansi: 6.0.1 wrap-ansi@7.0.0: dependencies: @@ -16541,44 +16218,46 @@ snapshots: wrap-ansi@8.1.0: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 wrappy@1.0.2: {} - write-file-atomic@3.0.3: + write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 - is-typedarray: 1.0.0 - signal-exit: 3.0.7 - typedarray-to-buffer: 3.1.5 + signal-exit: 4.1.0 - ws@7.5.10: {} + write-yaml-file@5.0.0: + dependencies: + js-yaml: 4.1.1 + write-file-atomic: 5.0.1 ws@8.18.3: {} - xdg-basedir@4.0.0: {} - - xml-name-validator@4.0.0: {} + ws@8.20.0: {} - xml-name-validator@5.0.0: {} - - xmlbuilder@15.1.1: {} - - xmlchars@2.2.0: {} - - xtend@4.0.2: {} + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 - xterm-addon-fit@0.5.0(xterm@4.19.0): + wsl-utils@0.3.1: dependencies: - xterm: 4.19.0 + is-wsl: 3.1.1 + powershell-utils: 0.1.0 - xterm-addon-search@0.8.2(xterm@4.19.0): + xml2js@0.5.0: dependencies: - xterm: 4.19.0 + sax: 1.6.0 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + + xmlbuilder@15.1.1: {} - xterm@4.19.0: {} + xtend@4.0.2: + optional: true y18n@5.0.8: {} @@ -16586,20 +16265,10 @@ snapshots: yallist@4.0.0: {} - yargs-parser@20.2.9: {} + yallist@5.0.0: {} yargs-parser@21.1.1: {} - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -16610,27 +16279,18 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yarn-or-npm@3.0.1: - dependencies: - cross-spawn: 6.0.6 - pkg-dir: 4.2.0 - yauzl@2.10.0: dependencies: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 - yn@3.1.1: {} - yocto-queue@0.1.0: {} - yoctocolors@2.1.1: {} + yocto-queue@1.2.2: {} - zip-stream@4.1.1: - dependencies: - archiver-utils: 3.0.4 - compress-commons: 4.1.2 - readable-stream: 3.6.2 + yoctocolors-cjs@2.1.3: {} + + yoctocolors@2.1.2: {} zip-stream@6.0.1: dependencies: @@ -16638,4 +16298,4 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 - zod@3.23.8: {} + zod@4.3.6: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..c22428df --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +packages: + - "apps/*" + - "packages/*" + - "assets/*" + - "plugins/*" diff --git a/scripts/delete_tags.sh b/scripts/delete_tags.sh new file mode 100644 index 00000000..900e04da --- /dev/null +++ b/scripts/delete_tags.sh @@ -0,0 +1,159 @@ +#!/bin/bash + +# Configuration +REMOTE="origin" +DRY_RUN=false +TYPE="tags" +IGNORED_VERSIONS=() + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + -d|--dry-run) + DRY_RUN=true + shift + ;; + -t|--type) + TYPE="$2" + shift 2 + ;; + -i|--ignore) + IGNORED_VERSIONS+=("$2") + shift 2 + ;; + *) + shift + ;; + esac +done + +# Validate type +if [[ "$TYPE" != "tags" && "$TYPE" != "releases" ]]; then + echo "Error: Invalid type '$TYPE'. Must be 'tags' or 'releases'." + echo "Usage: $0 [--type tags|releases] [--dry-run] [--ignore version]" + exit 1 +fi + +# Dependency check +if ! command -v fzf &> /dev/null; then + echo "Error: 'fzf' is not installed." + exit 1 +fi + +if [[ "$TYPE" == "releases" ]] && ! command -v gh &> /dev/null; then + echo "Error: 'gh' (GitHub CLI) is not installed. Required for deleting releases." + exit 1 +fi + +# Step 1: Refresh data +if [[ "$TYPE" == "tags" ]]; then + echo "Fetching tags from $REMOTE..." + git fetch --tags --prune +else + echo "Fetching releases from GitHub..." +fi + +# Helper to filter ignored versions +filter_ignored() { + if [ ${#IGNORED_VERSIONS[@]} -eq 0 ]; then + cat + return + fi + + # Prepare ignored versions for node (escape quotes) + local json_ignored + json_ignored=$(printf '%s\n' "${IGNORED_VERSIONS[@]}" | jq -R . | jq -s . -c) + + node -e ' + const fs = require("fs"); + let semver; + try { semver = require("semver"); } catch(e) {} + + const ignored = JSON.parse(process.argv[1]); + const input = fs.readFileSync(0, "utf8").split("\n"); + + input.forEach(item => { + if (!item.trim()) return; + // Extract version: everything after the last @ + const version = item.includes("@") ? item.split("@").pop() : item; + + const shouldIgnore = ignored.some(pattern => { + // 1. Exact match + if (item === pattern || version === pattern) return true; + + // 2. Glob match (convert * to .*) + if (pattern.includes("*")) { + const regex = new RegExp("^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$"); + if (regex.test(item) || regex.test(version)) return true; + } + + // 3. Semver range + if (semver && (semver.validRange(pattern) || pattern.match(/[<>=\^~]/))) { + try { + const cleanVersion = semver.clean(version) || version; + if (semver.valid(cleanVersion) && semver.satisfies(cleanVersion, pattern)) return true; + } catch(e) {} + } + + return false; + }); + + if (!shouldIgnore) console.log(item); + }); + ' "$json_ignored" +} + +# Step 2: Fuzzy selection +if [[ "$TYPE" == "tags" ]]; then + selected_items=$(git tag -l | filter_ignored | fzf -m \ + --header "Select tags to DELETE (Tab to mark multiple, Enter to confirm)" \ + --preview "git show --summary {}" \ + --preview-window=right:50%) +else + selected_items=$(gh release list --limit 1000 --json tagName,name --jq '.[].tagName' | filter_ignored | fzf -m \ + --header "Select releases to DELETE (Tab to mark multiple, Enter to confirm)" \ + --preview "gh release view {}" \ + --preview-window=right:50%) +fi + +if [[ -z "$selected_items" ]]; then + echo "No $TYPE selected. Aborting." + exit 0 +fi + +# Step 3: Execution/Dry Run +if [ "$DRY_RUN" = true ]; then + echo -e "\n--- DRY RUN MODE: No changes will be made ---\n" + for item in $selected_items; do + if [[ "$TYPE" == "tags" ]]; then + echo "[DRY-RUN] git tag -d $item" + echo "[DRY-RUN] git push $REMOTE --delete $item" + else + echo "[DRY-RUN] gh release delete $item --yes --cleanup-tag" + echo "[DRY-RUN] git tag -d $item" + fi + done + echo -e "\nDry run finished." +else + # Confirmation for actual deletion + echo -e "\nSelected $TYPE for deletion:" + echo "$selected_items" + printf "\nAre you sure you want to delete these $TYPE (and associated tags)? (y/N): " + read -r confirm + + if [[ "$confirm" =~ ^[yY]$ ]]; then + for item in $selected_items; do + echo "Deleting: $item" + if [[ "$TYPE" == "tags" ]]; then + git tag -d "$item" + git push "$REMOTE" --delete "$item" + else + gh release delete "$item" --yes --cleanup-tag + git tag -d "$item" 2>/dev/null || true + fi + done + echo "Cleanup complete." + else + echo "Operation cancelled." + fi +fi \ No newline at end of file diff --git a/scripts/detect-changes.ts b/scripts/detect-changes.ts new file mode 100644 index 00000000..e90777ef --- /dev/null +++ b/scripts/detect-changes.ts @@ -0,0 +1,71 @@ +import { readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; + +/** + * This script parses the JSON output of `turbo ls --output=json` + * and exposes a single stringified JSON array of all affected package names. + * It also detects if any of the affected packages have a "build" script. + */ + +interface TurboPackage { + name: string; + path: string; +} + +interface TurboLsOutput { + packages: { + items: TurboPackage[]; + }; +} + +function main() { + const inputFile = process.argv[2]; + if (!inputFile) { + console.error("Usage: tsx detect-changes.ts "); + process.exit(1); + } + + try { + const rawData = readFileSync(inputFile, "utf-8"); + const data: TurboLsOutput = JSON.parse(rawData); + + // Extract all package names + const affectedPackages = data.packages.items.map((p) => p.name); + + // Check if any affected package needs a build + let needsBuild = false; + for (const p of data.packages.items) { + try { + const pkgJsonPath = join(process.cwd(), p.path, "package.json"); + const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8")); + if (pkgJson.scripts?.build) { + needsBuild = true; + break; + } + } catch (err) { + console.warn(`Could not read package.json for ${p.name} at ${p.path}`); + } + } + + console.log("--- Affected Packages Detected by Turbo ---"); + console.log(JSON.stringify(affectedPackages, null, 2)); + console.log(`Needs Build: ${needsBuild}`); + console.log("-------------------------------------------"); + + // Set GitHub Action outputs + const githubOutput = process.env.GITHUB_OUTPUT; + if (githubOutput) { + // The array needs to be stringified for GHA to handle it as a single string + writeFileSync(githubOutput, `affected=${JSON.stringify(affectedPackages)}\n`, { flag: "a" }); + writeFileSync(githubOutput, `needs_build=${needsBuild}\n`, { flag: "a" }); + console.log("Successfully set GITHUB_OUTPUT: affected, needs_build"); + } else { + console.log("Not running in GitHub Actions, skipping GITHUB_OUTPUT"); + } + } catch (error) { + console.error("Failed to parse turbo output:", error); + process.exit(1); + } +} + +main(); diff --git a/scripts/headless-electron-tester.mts b/scripts/headless-electron-tester.mts deleted file mode 100644 index 0e777144..00000000 --- a/scripts/headless-electron-tester.mts +++ /dev/null @@ -1,10 +0,0 @@ -import { execa } from 'execa' -import { join } from 'path' -import { cwd, stdin } from 'process' - -await execa({ - cwd: join(import.meta.dirname, '..'), - stdin: 'inherit', - stdout: 'inherit', - stderr: 'inherit' -})`./assets/electron/template/app/node_modules/.bin/electron-forge start -- --headless --port=3000` diff --git a/scripts/migrate-file.mts b/scripts/migrate-file.mts deleted file mode 100644 index ccceb6b1..00000000 --- a/scripts/migrate-file.mts +++ /dev/null @@ -1,40 +0,0 @@ -import { savedFileMigrator } from '@@/model' -import * as fs from 'fs/promises' -import { join } from 'path' -import { tmpdir } from 'os' -import { nanoid } from 'nanoid' -import { execa } from 'execa' - -const args = process.argv.slice(2) -if (args.length !== 1) { - console.error('Usage: node script.ts ') - process.exit(1) -} - -const filePath = args[0] - -async function migrateFile() { - try { - // const tmpFile = join(tmpdir(), nanoid() + '.json') - - const data = await fs.readFile(filePath, 'utf8') - const json = JSON.parse(data) - const migratedData = await savedFileMigrator.migrate(json) - const str = JSON.stringify(migratedData, null, 2) - console.log('data', data) - console.log('str', str) - await fs.writeFile(filePath, str, 'utf8') - console.log('File successfully migrated to the latest version of the model.') - - // await execa('delta', [filePath, tmpFile], { - // env: { - // DELTA_FEATURES: '+side-by-side' - // } - // }) - } catch (error) { - console.error(`Error migrating the file: ${error}`) - process.exit(1) - } -} - -await migrateFile() diff --git a/scripts/network-interceptor.mjs b/scripts/network-interceptor.mjs new file mode 100644 index 00000000..c86dfb33 --- /dev/null +++ b/scripts/network-interceptor.mjs @@ -0,0 +1,60 @@ +import http from "node:http"; +import https from "node:https"; + +const MSW_BRIDGE_PORT = process.env.MSW_BRIDGE_PORT; + +if (MSW_BRIDGE_PORT) { + const originalHttpRequest = http.request; + const originalHttpsRequest = https.request; + + const patchRequest = (original) => { + return function (options, callback) { + const isHttps = original === originalHttpsRequest; + const interceptedOptions = typeof options === "string" ? new URL(options) : { ...options }; + + const originalHost = interceptedOptions.hostname || interceptedOptions.host; + const originalProtocol = isHttps ? "https:" : "http:"; + + // 1. BYPASS: Only intercept specific services to avoid breaking pnpm/npm/etc. + // We only want to intercept things that we actually have MSW handlers for. + const shouldIntercept = + originalHost && + (originalHost.includes("poki.io") || + originalHost.includes("supabase") || + originalHost.includes("discord")); + + if (!shouldIntercept || originalHost === "localhost" || originalHost === "127.0.0.1") { + return originalHttpRequest(options, callback); + } + + process.stderr.write( + `[Interceptor] Redirecting ${originalProtocol}//${originalHost} to MSW Bridge\n`, + ); + + interceptedOptions.protocol = "http:"; + interceptedOptions.hostname = "localhost"; + interceptedOptions.port = MSW_BRIDGE_PORT; + interceptedOptions.headers = { + ...(interceptedOptions.headers || {}), + "x-msw-original-host": originalHost, + "x-msw-original-protocol": originalProtocol, + }; + + return originalHttpRequest(interceptedOptions, callback); + }; + }; + + http.request = patchRequest(originalHttpRequest); + https.request = patchRequest(originalHttpsRequest); + + http.get = function (options, callback) { + const req = http.request(options, callback); + req.end(); + return req; + }; + https.get = function (options, callback) { + const req = https.request(options, callback); + req.end(); + return req; + }; +} diff --git a/scripts/publish-app.mjs b/scripts/publish-app.mjs new file mode 100644 index 00000000..c882611e --- /dev/null +++ b/scripts/publish-app.mjs @@ -0,0 +1,118 @@ +import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, join, resolve } from "node:path"; +import { execa } from "execa"; + +const appName = process.argv[2]; +if (!appName) { + console.error("Please provide the app name to publish (e.g. ui, cli)"); + process.exit(1); +} + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const root = resolve(__dirname, ".."); + +const appPackageJsonPath = join(root, "apps", appName, "package.json"); +let appDistDir = join(root, "apps", appName, "dist"); + +// In CI, artifacts are downloaded to the "artifacts" directory +const ciDistDir = join(root, "artifacts", "monorepo-dist", "apps", appName, "dist"); +if (!existsSync(appDistDir) && existsSync(ciDistDir)) { + console.log(`Detected CI artifact directory at ${ciDistDir}`); + appDistDir = ciDistDir; +} + +if (!existsSync(appPackageJsonPath)) { + console.error(`Package.json not found for app: ${appName} at ${appPackageJsonPath}`); + process.exit(1); +} + +async function main() { + try { + const { stdout: whoami } = await execa("npm", ["whoami"]); + console.log(`Currently logged in as: ${whoami}`); + } catch (err) { + console.warn("Could not determine current npm user. Make sure you are logged in."); + } + + console.log(`Reading ${appName} package.json...`); + const appPackageJson = JSON.parse(readFileSync(appPackageJsonPath, "utf-8")); + const { version, license, author, repository, description } = appPackageJson; + + // Check if version is already published on npm to avoid E403/Forbidden errors + try { + const { stdout } = await execa("npm", ["view", `@pipelab/${appName}@${version}`, "version"]); + if (stdout.trim() === version) { + console.log(`@pipelab/${appName}@${version} is already published on npm. Skipping publish.`); + return; + } + } catch (err) { + console.log(`@pipelab/${appName}@${version} is not published on npm yet. Proceeding with publish...`); + } + + console.log(`Preparing @pipelab/${appName} v${version} for publishing...`); + + const dynamicPackageJson = { + name: `@pipelab/${appName}`, + version, + description: description || `The ${appName} assets for Pipelab`, + license, + author, + repository, + private: false, + type: "module", + publishConfig: { + access: "public", + registry: "https://registry.npmjs.org/", + }, + ...(appName === "cli" + ? { + bin: { + pipelab: "./index.mjs", + plab: "./index.mjs", + }, + } + : {}), + dependencies: {}, // Self-contained + }; + + const outputPath = join(appDistDir, "package.json"); + console.log(`Writing dynamic package.json to ${outputPath}...`); + if (!existsSync(appDistDir)) { + console.warn(`Warning: dist directory ${appDistDir} not found, creating it...`); + mkdirSync(appDistDir, { recursive: true }); + } + writeFileSync(outputPath, JSON.stringify(dynamicPackageJson, null, 2)); + + console.log("Publishing to npm..."); + + // Handle prerelease tags (e.g. 2.0.1-beta.12 -> tag: beta) + const args = ["publish", "--access", "public"]; + const prereleaseMatch = version.match(/-(.*?)(?:\.|$)/); + if (prereleaseMatch && prereleaseMatch[1]) { + const tag = prereleaseMatch[1]; + console.log(`Detected prerelease version, using tag: ${tag}`); + args.push("--tag", tag); + } else { + args.push("--tag", "latest"); + } + + try { + // Using standard npm for the publish as it sometimes handles scoped paths more reliably + await execa("npm", args, { + cwd: appDistDir, + stdio: "inherit", + }); + + console.log(`Successfully published @pipelab/${appName}!`); + } catch (error) { + console.error(`Failed to publish @pipelab/${appName}:`); + console.error(error.message); + if (process.env.CI) { + process.exit(1); + } + } +} + +main(); diff --git a/scripts/unpublish_modules.sh b/scripts/unpublish_modules.sh new file mode 100644 index 00000000..38fdce20 --- /dev/null +++ b/scripts/unpublish_modules.sh @@ -0,0 +1,169 @@ +#!/bin/bash + +# Configuration +DRY_RUN=false + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + -d|--dry-run) + DRY_RUN=true + shift + ;; + *) + shift + ;; + esac +done + +# Dependency check +if ! command -v fzf &> /dev/null; then + echo "Error: 'fzf' is not installed." + exit 1 +fi + +if ! command -v npm &> /dev/null; then + echo "Error: 'npm' is not installed." + exit 1 +fi + +# Authentication check +if [ "$DRY_RUN" = false ]; then + echo "Checking npm authentication..." + current_user=$(npm whoami 2>/dev/null) + if [ $? -ne 0 ] || [ -z "$current_user" ]; then + echo "Error: You are not logged in to npm. Please run 'npm login' first." + exit 1 + else + echo "Authenticated as: $current_user" + fi +fi + +# Step 1: Find all modules in the monorepo and choose one +echo "Scanning monorepo packages..." +packages_list=$(node -e " +const fs = require('fs'); +const path = require('path'); +const dirs = ['apps', 'packages', 'assets', 'plugins']; +const names = new Set(); +dirs.forEach(dir => { + if (!fs.existsSync(dir)) return; + fs.readdirSync(dir).forEach(sub => { + const pkgPath = path.join(dir, sub, 'package.json'); + if (fs.existsSync(pkgPath)) { + try { + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + if (pkg.name) names.add(pkg.name); + } catch (e) {} + } + }); +}); +console.log(Array.from(names).join('\n')); +") + +if [ -z "$packages_list" ]; then + echo "Error: No packages found in the monorepo." + exit 1 +fi + +selected_package=$(echo "$packages_list" | fzf \ + --header "Select a module to unpublish (Enter to confirm)" \ + --height 40% \ + --layout=reverse) + +if [ -z "$selected_package" ]; then + echo "No package selected. Aborting." + exit 0 +fi + +# Step 2: Fetch and list versions +echo "Fetching published versions of '$selected_package' from npm registry..." +versions_json=$(npm view "$selected_package" versions --json 2>/dev/null) +status=$? + +if [ $status -ne 0 ] || [ -z "$versions_json" ]; then + echo "Error: Could not retrieve versions for package '$selected_package'. Is it published on npm?" + exit 1 +fi + +versions=$(echo "$versions_json" | node -e " +try { + const d = JSON.parse(require('fs').readFileSync(0, 'utf8')); + console.log(Array.isArray(d) ? d.reverse().join('\n') : d); +} catch (e) { + process.exit(1); +} +") + +if [ -z "$versions" ]; then + echo "Error: No versions found for '$selected_package'." + exit 1 +fi + +selected_versions=$(echo "$versions" | fzf -m \ + --header "Select versions of $selected_package to UNPUBLISH (Tab to mark multiple, Enter to confirm)" \ + --height 50% \ + --layout=reverse) + +if [ -z "$selected_versions" ]; then + echo "No versions selected. Aborting." + exit 0 +fi + +# Step 3: Execution/Dry Run +if [ "$DRY_RUN" = true ]; then + echo -e "\n--- DRY RUN MODE: No changes will be made ---\n" + for version in $selected_versions; do + echo "[DRY-RUN] npm unpublish ${selected_package}@${version}" + done + echo -e "\nDry run finished." +else + # Confirmation for actual unpublishing + echo -e "\nSelected versions of $selected_package for unpublishing:" + for version in $selected_versions; do + echo " - $version" + done + printf "\nAre you sure you want to UNPUBLISH these versions? This action is IRREVERSIBLE! (y/N): " + read -r confirm + + if [[ "$confirm" =~ ^[yY]$ ]]; then + OTP_CODE="" + for version in $selected_versions; do + while true; do + echo "Unpublishing: ${selected_package}@${version}" + + # Build command args + args=("unpublish" "${selected_package}@${version}") + if [ -n "$OTP_CODE" ]; then + args+=("--otp=$OTP_CODE") + fi + + output=$(npm "${args[@]}" 2>&1) + status=$? + + if [ $status -eq 0 ]; then + echo "✅ Successfully unpublished ${selected_package}@${version}" + break + else + # Check if error is EOTP + if echo "$output" | grep -q "EOTP"; then + echo -e "⚠️ This operation requires a One-Time Password (OTP)." + printf "Enter OTP code: " + read -r OTP_CODE + if [ -z "$OTP_CODE" ]; then + echo -e "❌ Cancelled OTP input. Skipping ${selected_package}@${version}.\n" + break + fi + # Loop continues and retries the same version with the new OTP_CODE + else + echo -e "❌ Failed to unpublish ${selected_package}@${version}:\n$output\n" + break + fi + fi + done + done + echo "Unpublish process complete." + else + echo "Operation cancelled." + fi +fi diff --git a/scripts/upload-windows.sh b/scripts/upload-windows.sh new file mode 100644 index 00000000..1ace2820 --- /dev/null +++ b/scripts/upload-windows.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# This script uploads the latest Windows installer to the VM and starts an RDP session. +# Usage: ./scripts/upload-windows.sh + +# --- Configuration --- +VM_HOST="localhost" +VM_USER="Docker" +VM_PASS="admin" +VM_RDP_PORT="3389" +SHARED_FOLDER="/home/armaldio/Documents/vms/shared" + +# --- Build Step --- +echo "🏗️ Building dependencies..." +pnpm turbo build --filter=@pipelab/app + +echo "📦 Creating Windows installer..." +pnpm --filter=@pipelab/app make --platform win32 --arch x64 + +# --- Find the latest installer --- +# Squirrel installer is typically in apps/desktop/out/make/squirrel.windows/x64/ +INSTALLER_DIR="apps/desktop/out/make/squirrel.windows/x64/" +INSTALLER=$(find "$INSTALLER_DIR" -name "*.exe" | head -n 1) + +if [ -z "$INSTALLER" ]; then + echo "❌ Error: No Windows installer found in $INSTALLER_DIR" + echo "Please run 'pnpm --filter @pipelab/app make' first to generate the installer." + exit 1 +fi + +echo "🚀 Found installer: $INSTALLER" + +# --- Copy to Shared Folder --- +if [ ! -d "$SHARED_FOLDER" ]; then + echo "❌ Error: Shared folder not found at $SHARED_FOLDER" + exit 1 +fi + +echo "📤 Copying to shared folder: $SHARED_FOLDER" +cp "$INSTALLER" "$SHARED_FOLDER/" + +if [ $? -eq 0 ]; then + echo "✅ Copy successful!" +else + echo "❌ Copy failed!" + exit 1 +fi diff --git a/src/auto-imports.d.ts b/src/auto-imports.d.ts deleted file mode 100644 index d2c795cf..00000000 --- a/src/auto-imports.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ -// @ts-nocheck -// noinspection JSUnusedGlobalSymbols -// Generated by unplugin-auto-import -export {} -declare global { - const Steps: typeof import('primevue/steps')['Steps'] -} diff --git a/src/components.d.ts b/src/components.d.ts deleted file mode 100644 index a87d0247..00000000 --- a/src/components.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint-disable */ -// @ts-nocheck -// Generated by unplugin-vue-components -// Read more: https://github.com/vuejs/core/pull/3399 -export {} - -/* prettier-ignore */ -declare module 'vue' { - export interface GlobalComponents { - AddNodeButton: typeof import('./src/components/AddNodeButton.vue')['default'] - Boolean: typeof import('./src/components/controls/boolean/boolean.vue')['default'] - Button: typeof import('primevue/button')['default'] - Checkbox: typeof import('./src/components/controls/checkbox/checkbox.vue')['default'] - Dialog: typeof import('primevue/dialog')['default'] - Drawer: typeof import('primevue/drawer')['default'] - EditorNodeAction: typeof import('./src/components/nodes/EditorNodeAction.vue')['default'] - EditorNodeCondition: typeof import('./src/components/nodes/EditorNodeCondition.vue')['default'] - EditorNodeDummy: typeof import('./src/components/nodes/EditorNodeDummy.vue')['default'] - EditorNodeEvent: typeof import('./src/components/nodes/EditorNodeEvent.vue')['default'] - EditorNodeLoop: typeof import('./src/components/nodes/EditorNodeLoop.vue')['default'] - IconField: typeof import('primevue/iconfield')['default'] - Inplace: typeof import('primevue/inplace')['default'] - Input: typeof import('./src/components/controls/input/input.vue')['default'] - InputIcon: typeof import('primevue/inputicon')['default'] - InputText: typeof import('primevue/inputtext')['default'] - Listbox: typeof import('primevue/listbox')['default'] - Panel: typeof import('primevue/panel')['default'] - ParamEditor: typeof import('./src/components/nodes/ParamEditor.vue')['default'] - 'ParamEditor.old': typeof import('./src/components/nodes/ParamEditor.old.vue')['default'] - Path: typeof import('./src/components/controls/path/path.vue')['default'] - PluginIcon: typeof import('./src/components/nodes/PluginIcon.vue')['default'] - RouterLink: typeof import('vue-router')['RouterLink'] - RouterView: typeof import('vue-router')['RouterView'] - ScenarioListItem: typeof import('./src/components/ScenarioListItem.vue')['default'] - ScenarioListItemFile: typeof import('./src/components/ScenarioListItemFile.vue')['default'] - ScenarioListItemRecent: typeof import('./src/components/ScenarioListItemRecent.vue')['default'] - Select: typeof import('./src/components/controls/select/select.vue')['default'] - SelectButton: typeof import('primevue/selectbutton')['default'] - Skeleton: typeof import('primevue/skeleton')['default'] - } -} diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 08af4f4f..00000000 --- a/src/constants.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { platform } from 'process' - -export const name = 'Pipelab' - -export const outFolderName = ( - binName: string, - platform: NodeJS.Platform, - arch: NodeJS.Architecture -) => { - let platformName = '' - let archName = '' - - console.log('platform', platform) - - if (platform === 'linux') { - platformName = 'linux' - } else if (platform === 'win32') { - platformName = 'win32' - } else if (platform === 'darwin') { - platformName = 'darwin' - } else { - throw new Error('Unsupported platform') - } - - if (arch === 'x64') { - archName = 'x64' - } else if (arch === 'arm') { - archName = 'arm' - } else if (arch === 'arm64') { - archName = 'arm64' - } else if (arch === 'ia32') { - archName = 'ia32' - } else { - throw new Error('Unsupported architecture') - } - - return `${binName}-${platformName}-${archName}` -} - -export const getBinName = (name: string) => { - if (platform === 'win32') { - return `${name}.exe` - } - if (platform === 'darwin') { - return `${name}.app/Contents/MacOS/${name}` - } - return name -} - -export const websocketPort = 33753 diff --git a/src/definitions.d.ts b/src/definitions.d.ts deleted file mode 100644 index 5a788447..00000000 --- a/src/definitions.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -declare namespace DesktopApp { - interface Config { - width: number - height: number - fullscreen: boolean - frame: boolean - transparent: boolean - toolbar: boolean - alwaysOnTop: boolean - name: string - appBundleId: string - appCopyright: string - appVersion: string - author: string - description: string - appCategoryType: string - icon: string - enableExtraLogging: boolean - clearServiceWorkerOnBoot: boolean - - enableSteamSupport: boolean - steamGameId: number - - enableDiscordSupport: boolean - discordAppId: string - - ignore: (string | RegExp)[] - openDevtoolsOnStart: boolean - - /** - * User-defined npm packages to install (format: "package[@version]") - */ - customPackages?: string[] - backgroundColor: string - enableDoctor: boolean - serverMode: 'default' | 'customProtocol' - } - - interface Electron extends Config { - enableInProcessGPU: boolean - enableDisableRendererBackgrounding: boolean - customMainCode: string - electronVersion: string - disableAsarPackaging: boolean - forceHighPerformanceGpu: boolean - clearServiceWorkerOnBoot: boolean - } - - interface Tauri extends Config { - tauriVersion: string - } -} diff --git a/src/global.d.ts b/src/global.d.ts deleted file mode 100644 index e4115040..00000000 --- a/src/global.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare global { - interface Window { - __POSTHOG_API_KEY__: string - } -} diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index 4e85f115..00000000 --- a/src/main.ts +++ /dev/null @@ -1,427 +0,0 @@ -import { app, shell, BrowserWindow, dialog, autoUpdater, protocol, screen } from 'electron' -import { join } from 'path' -import { platform } from 'os' -import { electronApp, optimizer, is } from '@electron-toolkit/utils' -import { registerIPCHandlers } from './main/handlers' -import { webSocketServer } from './main/websocket-server' -import { usePlugins } from '@@/plugins' -import { parseArgs, ParseArgsConfig } from 'node:util' -import { readFile, writeFile, mkdir } from 'fs/promises' -import { executeGraphWithHistory } from '@main/utils' -import { SavedFile } from '@@/model' -import { useLogger } from '@@/logger' -import * as Sentry from '@sentry/electron/main' -import { assetsPath } from '@main/paths' -import { usePluginAPI } from '@main/api' -import { setupConfig } from '@main/config' -import { resolve } from 'node:path' -import Squirrel from 'electron-squirrel-startup' - -if (is.dev) { - app.setPath('userData', app.getPath('userData') + '-dev') - console.log('Dev mode: userData path set to', app.getPath('userData')) -} - -const isLinux = platform() === 'linux' -// let tray -let isReadyToShow = false - -const { logger, setMainWindow } = useLogger() - -logger().info('app.isPackaged', app.isPackaged) -logger().info('process.env.TEST', process.env.TEST) -logger().info('process.env.WINEHOMEDIR', process.env.WINEHOMEDIR) -logger().info('isLinux', isLinux) - -const isWine = platform() === 'win32' && 'WINEHOMEDIR' in process.env - -// @ts-expect-error import.meta -const isCI = process.env.CI === 'true' || import.meta.env.CI === 'true' - -if (app.isPackaged && process.env.TEST !== 'true' && !isWine && !isCI) { - Sentry.init({ - dsn: 'https://757630879674735027fa5700162253f7@o45694.ingest.us.sentry.io/4507621723144192', - debug: true - }) -} - -let ext = '.png' -if (platform() === 'linux') { - ext = '.png' -} else if (platform() === 'win32') { - ext = '.ico' -} else if (platform() === 'darwin') { - ext = '.icns' -} - -const imagePath = join('./assets', 'build', `icon${ext}`) -// let isQuiting = false - -if ( - !isLinux && - process.env.TEST !== 'true' && - app.isPackaged && - Squirrel - // require('electron-squirrel-startup') -) { - app.quit() -} - -let api: any -let mainWindow: BrowserWindow | undefined - -function createWindow(): void { - const displays = screen.getAllDisplays() - const externalDisplay = displays.find((display) => { - return display.bounds.x !== 0 || display.bounds.y !== 0 - }) - - const position = - externalDisplay && is.dev - ? { - x: externalDisplay.bounds.x + 50, - y: externalDisplay.bounds.y + 50 - } - : {} - - // Create the browser window. - mainWindow = new BrowserWindow({ - width: 1280, - height: 720, - show: false, - icon: imagePath, - autoHideMenuBar: true, - ...position, - webPreferences: { - preload: join(__dirname, 'preload.js'), - sandbox: false, - devTools: is.dev - } - }) - - setMainWindow(mainWindow) - - api = usePluginAPI(mainWindow) - - if (is.dev) { - mainWindow.webContents.openDevTools() - } - - mainWindow.on('ready-to-show', () => { - isReadyToShow = true - }) - - // TODO: only if minimize to tray enabled - // mainWindow.on('minimize', function (event: Event) { - // event.preventDefault() - // mainWindow.hide() - // }) - - mainWindow.on('close', function () { - app.quit() - }) - - mainWindow.webContents.setWindowOpenHandler((details) => { - shell.openExternal(details.url) - return { action: 'deny' } - }) - - // and load the index.html of the app. - if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { - mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL) - } else { - mainWindow.loadFile(join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)) - } -} - -const { registerBuiltIn } = usePlugins() - -if (is.dev && process.platform === 'win32') { - app.setAsDefaultProtocolClient('pipelab', process.execPath, [resolve(process.argv[1])]) -} else { - app.setAsDefaultProtocolClient('pipelab') -} - -function handleProtocolUrl(url: string) { - if (!url || !url.startsWith('pipelab://')) return - - // Parse the URL - const urlObj = new URL(url) - const path = urlObj.pathname.replace(/^\/+/, '') - - if (path === 'open') { - // Handle pipelab://open - console.log('Opening the app') - // Your code to handle opening specific app view - } else if (path === 'run') { - // Handle pipelab://run?id=xxx - const id = urlObj.searchParams.get('id') - if (id) { - console.log(`Running command with ID: ${id}`) - // Your code to execute something with the ID - } - } -} - -app.whenReady().then(async () => { - protocol.handle('pipelab', async (request) => { - const url = request.url - console.log('handle url', url) - await handleProtocolUrl(url) - }) - - if (!is.dev) { - autoUpdater.setFeedURL({ - url: 'https://github.com/CynToolkit/pipelab/releases/latest/download', - headers: { - 'Cache-Control': 'no-cache' - } - }) - - autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => { - api?.execute('update:set-status', { - status: 'update-downloaded' - }) - logger().info('releaseNotes', releaseNotes) - logger().info('releaseName', releaseName) - logger().info('event', event) - const dialogOpts: Electron.MessageBoxOptions = { - type: 'info', - buttons: ['Restart', 'Later'], - title: 'Application Update', - message: process.platform === 'win32' ? releaseNotes : releaseName, - detail: 'A new version has been downloaded. Restart the application to apply the updates.' - } - - dialog.showMessageBox(dialogOpts).then((returnValue) => { - if (returnValue.response === 0) autoUpdater.quitAndInstall() - }) - }) - - autoUpdater.on('error', (message) => { - api?.execute('update:set-status', { - status: 'error' - }) - logger().info('There was a problem updating the application') - console.log(message) - }) - - autoUpdater.on('update-available', () => { - api?.execute('update:set-status', { - status: 'update-available' - }) - logger().info('Found update') - }) - - autoUpdater.on('update-not-available', () => { - api?.execute('update:set-status', { - status: 'update-not-available' - }) - logger().info('No update available') - }) - - autoUpdater.on('checking-for-update', (info: any) => { - api?.execute('update:set-status', { - status: 'checking-for-update' - }) - logger().info('checking-for-update', info) - }) - logger().info('autoUpdater.getFeedURL()', autoUpdater.getFeedURL()) - } - - logger().info('app ready') - - // Set app user model id for windows - electronApp.setAppUserModelId('com.pipelab') - - // Default open or close DevTools by F12 in development - // and ignore CommandOrControl + R in production. - // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils - app.on('browser-window-created', (_, window) => { - optimizer.watchWindowShortcuts(window) - }) - - const assets = await assetsPath() - const shimsPaths = join(assets, 'shims') - - await mkdir(shimsPaths, { recursive: true }) - - const settingsG = await setupConfig() - - const settings = await settingsG.getConfig() - - console.log('settings', settings) - - registerIPCHandlers() - await registerBuiltIn() - // registerOtherPlugins() - - // Start WebSocket server - try { - await webSocketServer.start() - // Wait for WebSocket server to be ready before creating window - await webSocketServer.waitForReady() - logger().info('WebSocket server is ready, creating window') - } catch (error) { - logger().error('Failed to start WebSocket server:', error) - } - - const config = { - options: { - /** project: path to file .pipelab */ - project: { - type: 'string', - short: 'p' - }, - /** action: run | open */ - action: { - type: 'string', - short: 'a' - }, - /** output: path to output result */ - output: { - type: 'string', - short: 'o' - }, - inspect: { - type: 'boolean' - } - } - } satisfies ParseArgsConfig - - const { values } = parseArgs(config) - - logger().info('values', values) - - createWindow() - - delete values['inspect'] - - // exit if values are passed - if (Object.keys(values).length > 0) { - logger().info('Processing graph...') - - const { action, project, output } = values - - if (action === 'run') { - const rawData = await readFile(project, 'utf8') - const data = JSON.parse(rawData) as SavedFile - - logger().info('data', data) - - const { canvas, variables } = data - const { blocks: nodes } = canvas - - try { - await executeGraphWithHistory({ - graph: nodes, - variables: variables, - projectName: data.name || 'Unnamed Pipeline', - projectPath: project, - mainWindow: mainWindow, - onNodeEnter: (node) => { - logger().info('onNodeEnter', node.uid) - }, - onNodeExit: (node) => { - logger().info('onNodeExit', node.uid) - }, - onLog: (data) => { - if (!isCI) { - logger().info('send', data) - } - console.log('send', data) - }, - outputPath: output - }) - - console.log('got an output', output) - } catch (e) { - console.error('error while executing process', e) - if (output) { - await writeFile(output, JSON.stringify({ error: (e as Error).message }, null, 2), 'utf8') - } - } - } - - process.exit(0) - } - - // const icon = nativeImage.createFromPath(imagePath) - // tray = new Tray(icon) - // const contextMenu = Menu.buildFromTemplate([ - // { - // label: 'Open', - // type: 'normal', - // click: () => { - // if (mainWindow) { - // mainWindow.show() - // } - // } - // }, - // { type: 'separator' }, - // { - // label: 'Exit', - // type: 'normal', - // click: () => { - // // isQuiting = true - // app.quit() - // } - // } - // ]) - - // tray.setContextMenu(contextMenu) - // tray.on('click', () => { - // mainWindow.show() - // }) - - mainWindow.on('ready-to-show', () => { - mainWindow.show() - mainWindow.maximize() - - if (app.isPackaged) { - setTimeout(() => { - autoUpdater.checkForUpdates() - console.log('checkForUpdates') - }, 10000) - } - }) - if (isReadyToShow) { - mainWindow.show() - mainWindow.maximize() - } - - app.on('activate', function () { - // On macOS it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (BrowserWindow.getAllWindows().length === 0) createWindow() - }) -}) - -// Quit when all windows are closed, except on macOS. There, it's common -// for applications and their menu bar to stay active until the user quits -// explicitly with Cmd + Q. -app.on('window-all-closed', async () => { - if (process.platform !== 'darwin') { - // Stop WebSocket server before quitting - try { - await webSocketServer.stop() - } catch (error) { - logger().error('Error stopping WebSocket server:', error) - } - app.quit() - } -}) - -// Handle app before quit to cleanup WebSocket server -app.on('before-quit', async (event) => { - event.preventDefault() - - try { - await webSocketServer.stop() - logger().info('WebSocket server stopped, quitting app') - app.exit(0) - } catch (error) { - logger().error('Error stopping WebSocket server during quit:', error) - app.exit(1) - } -}) diff --git a/src/main/api.ts b/src/main/api.ts deleted file mode 100644 index 4c70bee7..00000000 --- a/src/main/api.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { BrowserWindow } from 'electron' -import { klona } from 'klona' -import { toRaw } from 'vue' - -import type { Tagged } from 'type-fest' -import { ILogObjMeta } from 'tslog' -import { useLogger } from '@@/logger' - -export type UpdateStatus = - | 'update-available' - | 'update-downloaded' - | 'checking-for-update' - | 'update-not-available' - | 'error' - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -type Event = { type: TYPE; data: DATA } -type EndEvent = { - type: 'end' - data: - | { - type: 'success' - result: DATA - } - | { - type: 'error' - ipcError: string - } -} - -export type IpcDefinition = { - 'dialog:alert': [ - // input - { message: string; buttons?: { title: string; value: string }[] }, - EndEvent<{ answer: string }> - ] - 'dialog:prompt': [ - // input - { message: string; buttons?: { title: string; value: string }[] }, - EndEvent<{ answer: string }> - ] - 'log:message': [ - // input - ILogObjMeta, - EndEvent - ] - 'update:set-status': [ - // input - { - status: UpdateStatus - }, - EndEvent - ] -} - -export type RendererChannels = keyof IpcDefinition -export type RendererData = IpcDefinition[KEY][0] -export type RendererEvents = IpcDefinition[KEY][1] -export type RendererEnd = Extract< - IpcDefinition[KEY][1], - { type: 'end' } ->['data'] - -export type RendererMessage = { - // the channel to communicate - requestId: RequestId - data: any -} -export type RequestId = Tagged - -// type Output = End<'fs:openFolder'> - -export type HandleListenerSendFn = ( - events: RendererEvents -) => void - -export type HandleListener = ( - event: Electron.IpcMainInvokeEvent, - data: { value: RendererData; send: HandleListenerSendFn } -) => Promise - -export type ListenerMain = ( - event: Electron.IpcMainEvent, - data: RendererEvents -) => Promise - -export const usePluginAPI = (browserWindow: BrowserWindow) => { - const { logger } = useLogger() - /** - * Send an order - */ - const send = (channel: KEY, args?: RendererData) => - // browserWindow.webContents.send(channel, args) - browserWindow.webContents.send(channel, args) - - const on = ( - channel: KEY | string, - listener: (event: Electron.IpcMainEvent, data: RendererEvents) => void - ) => { - const ipcMain = browserWindow.webContents.ipc.on(channel, listener) - - const cancel = () => ipcMain.removeListener(channel, listener) - - return cancel - } - - /** - * Send an order and wait for it's execution - */ - const execute = async ( - channel: KEY, - data?: RendererData, - listener?: ListenerMain - ) => { - const { nanoid } = await import('nanoid') - const newId = nanoid() as RequestId - // eslint-disable-next-line no-async-promise-executor - return new Promise>(async (resolve) => { - const message: RendererMessage = { - requestId: newId, - data: toRaw(klona(data)) - } - - const cancel = on(newId, async (event, data) => { - // console.log('receiving event', event, data) - if (data.type === 'end') { - cancel() - return resolve(data.data) - } else { - await listener?.(event, data) - } - }) - - // send the message - try { - browserWindow.webContents.send(channel, message) - } catch (e) { - logger().error(e) - logger().error(channel, message) - } - }) - } - - return { - send, - on, - execute - } -} - -export type UseMainAPI = ReturnType diff --git a/src/main/config.ts b/src/main/config.ts deleted file mode 100644 index 8731c8cf..00000000 --- a/src/main/config.ts +++ /dev/null @@ -1,260 +0,0 @@ -import { createMigration, createMigrator, finalVersion, initialVersion } from '@@/libs/migration' -import { createVersionSchema, OmitVersion } from '@@/libs/migration/models/migration' -import { app } from 'electron' -import { join } from 'node:path' -import { union, literal, InferInput, string, boolean, object, number } from 'valibot' -import { ensure } from './utils' -import { readFile, writeFile } from 'node:fs/promises' -import { useLogger } from '@@/logger' -import { tmpdir } from 'node:os' - -export const AppSettingsValidatorV1 = createVersionSchema({ - cacheFolder: string(), - theme: union([literal('light'), literal('dark')]), - version: literal('1.0.0') -}) - -export const AppSettingsValidatorV2 = createVersionSchema({ - cacheFolder: string(), - theme: union([literal('light'), literal('dark')]), - version: literal('2.0.0') -}) - -export const AppSettingsValidatorV3 = createVersionSchema({ - cacheFolder: string(), - theme: union([literal('light'), literal('dark')]), - version: literal('3.0.0'), - clearTemporaryFoldersOnPipelineEnd: boolean() -}) - -export const AppSettingsValidatorV4 = createVersionSchema({ - theme: union([literal('light'), literal('dark')]), - version: literal('4.0.0'), - cacheFolder: string(), - clearTemporaryFoldersOnPipelineEnd: boolean(), - locale: union([ - literal('en-US'), - literal('fr-FR'), - literal('pt-BR'), - literal('zh-CN'), - literal('es-ES'), - literal('de-DE') - ]) -}) - -export const AppSettingsValidatorV5 = createVersionSchema({ - theme: union([literal('light'), literal('dark')]), - version: literal('5.0.0'), - cacheFolder: string(), - clearTemporaryFoldersOnPipelineEnd: boolean(), - locale: union([ - literal('en-US'), - literal('fr-FR'), - literal('pt-BR'), - literal('zh-CN'), - literal('es-ES'), - literal('de-DE') - ]), - tours: object({ - dashboard: object({ - step: number(), - completed: boolean() - }), - editor: object({ - step: number(), - completed: boolean() - }) - }) -}) - -export const AppSettingsValidatorV6 = createVersionSchema({ - theme: union([literal('light'), literal('dark')]), - version: literal('6.0.0'), - cacheFolder: string(), - clearTemporaryFoldersOnPipelineEnd: boolean(), - locale: union([ - literal('en-US'), - literal('fr-FR'), - literal('pt-BR'), - literal('zh-CN'), - literal('es-ES'), - literal('de-DE') - ]), - tours: object({ - dashboard: object({ - step: number(), - completed: boolean() - }), - editor: object({ - step: number(), - completed: boolean() - }) - }), - autosave: boolean() -}) - -export type AppConfigV1 = InferInput -export type AppConfigV2 = InferInput -export type AppConfigV3 = InferInput -export type AppConfigV4 = InferInput -export type AppConfigV5 = InferInput -export type AppConfigV6 = InferInput - -export type AppConfig = AppConfigV6 -export const AppSettingsValidator = AppSettingsValidatorV6 - -const migrator = createMigrator() - -const defaultCacheFolder = join(tmpdir(), 'pipelab') - -export const defaultAppSettings = migrator.createDefault({ - cacheFolder: defaultCacheFolder, - clearTemporaryFoldersOnPipelineEnd: false, - locale: 'en-US', - theme: 'light', - version: '6.0.0', - autosave: true, - tours: { - dashboard: { - step: 0, - completed: false - }, - editor: { - step: 0, - completed: false - } - } -}) - -export const appSettingsMigrator = migrator.createMigrations({ - defaultValue: defaultAppSettings, - migrations: [ - createMigration({ - version: '1.0.0', - up: (state) => state satisfies OmitVersion, - down: initialVersion - }), - createMigration({ - version: '2.0.0', - up: (state) => { - return { - ...state, - clearTemporaryFoldersOnPipelineEnd: false - } satisfies OmitVersion - }, - down: () => { - throw new Error("Can't migrate down from 2.0.0") - } - }), - createMigration({ - version: '3.0.0', - up: (state) => ({ - ...state, - locale: 'en-US' as const // Default locale for existing users - }), - down: (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { locale, ...rest } = state as AppConfigV4 - return rest as unknown as AppConfigV3 - } - }), - createMigration({ - version: '4.0.0', - up: (state) => ({ - ...state, - tours: { - dashboard: { - step: 0, - completed: false - }, - editor: { - step: 0, - completed: false - } - } - }), - down: (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { tours, ...rest } = state as AppConfigV5 - return rest as unknown as AppConfigV4 - } - }), - createMigration({ - version: '5.0.0', - up: (state) => ({ - ...state, - autosave: true - }), - down: (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { autosave, ...rest } = state as AppConfigV6 - return rest as unknown as AppConfigV5 - } - }), - createMigration({ - version: '6.0.0', - up: finalVersion, - down: () => { - throw new Error("Can't migrate down from 6.0.0") - } - }) - ] -}) - -export const getDefaultAppSettingsMigrated = () => { - try { - return appSettingsMigrator.migrate(defaultAppSettings) - } catch (e) { - console.error('Error migrating default app settings', e) - return defaultAppSettings - } -} - -export const setupConfig = async () => { - const userData = app.getPath('userData') - const filesPath = join(userData, 'config', 'settings.json') - await ensure(filesPath, JSON.stringify(appSettingsMigrator.defaultValue)) - - return { - setConfig: async (config: AppConfig) => { - const { logger } = useLogger() - try { - await writeFile(filesPath, JSON.stringify(config)) - return true - } catch (e) { - logger().error('e', e) - return false - } - }, - getConfig: async () => { - const { logger } = useLogger() - - let content = undefined - try { - content = await readFile(filesPath, 'utf8') - } catch (e) { - logger().error('e', e) - } - - logger().info('content', content) - - let json = undefined - try { - json = await appSettingsMigrator.migrate( - content === undefined ? content : JSON.parse(content), - { debug: true } - ) - } catch (e) { - logger().error('e', e) - } - - try { - await writeFile(filesPath, JSON.stringify(json)) - } catch (e) { - logger().error('e', e) - } - - return json - } - } -} diff --git a/src/main/handler-func.ts b/src/main/handler-func.ts deleted file mode 100644 index 5186e6ba..00000000 --- a/src/main/handler-func.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { End } from '@@/apis' -import { - Action, - ActionRunner, - Condition, - ConditionRunner, - InputsDefinition -} from '@@/libs/plugin-core' -import { usePlugins } from '@@/plugins' -import { isRequired } from '@@/validation' -import { mkdir } from 'node:fs/promises' -import { assetsPath, unpackPath } from './paths' -import { useLogger } from '@@/logger' -import { BrowserWindow } from 'electron' -import { usePluginAPI } from './api' -import { BlockCondition } from '@@/model' -import { HandleListenerSendFn } from './handlers' -import { ensureNodeJS, generateTempFolder } from './utils' -import { join } from 'node:path' -import { tmpdir } from 'node:os' -import { setupConfig } from './config' - -const checkParams = (definitionParams: InputsDefinition, elementParams: Record) => { - // get a list of all required params - let expected = Object.keys(definitionParams) - - const found: string[] = [] - // for each param in elementParams - for (const param of Object.keys(elementParams)) { - // if the param is in the expected list - if (expected.includes(param)) { - // add to found - found.push(param) - // remove from expected - expected = expected.filter((x) => x !== param) - } else { - // throw new Error('Unexpected param "' + param + '"') - console.warn('Unexpected param "' + param + '"') - } - } - - for (const param of expected) { - if (isRequired(definitionParams[param])) { - throw new Error('Missing param "' + param + '"') - } - } -} - -export const handleConditionExecute = async ( - nodeId: string, - pluginId: string, - params: BlockCondition['params'] - // { send }: { send: HandleListenerSendFn<'condition:execute'> } -): Promise> => { - const { plugins } = usePlugins() - const { logger } = useLogger() - - const node = plugins.value - .find((plugin) => plugin.id === pluginId) - ?.nodes.find((node) => node.node.id === nodeId) as - | { - node: Condition - runner: ConditionRunner - } - | undefined - - if (!node) { - return { - type: 'error', - ipcError: 'Node not found' - } - } - - const tmp = await generateTempFolder(tmpdir()) - - await mkdir(tmp, { - recursive: true - }) - - try { - checkParams(node.node.params, params) - const resolvedInputs = params // await resolveConditionInputs(params, node.node, steps) - - const result = await node.runner({ - inputs: resolvedInputs, - log: (...args) => { - logger().info(`[${node.node.name}]`, ...args) - }, - meta: { - definition: '' - }, - setMeta: () => { - logger().info('set meta defined here') - }, - cwd: tmp - }) - - return { - type: 'success', - result: { - outputs: {}, - value: result - } - } - } catch (e) { - logger().error('Error in condition execution:', e) - return { - type: 'error', - ipcError: e - } - } -} - -export const handleActionExecute = async ( - nodeId: string, - pluginId: string, - params: Record, - mainWindow: BrowserWindow | undefined, - send: HandleListenerSendFn<'action:execute'>, - abortSignal: AbortSignal -): Promise> => { - const { plugins } = usePlugins() - const { logger } = useLogger() - const settings = await setupConfig() - const config = await settings.getConfig() - - mainWindow?.setProgressBar(1, { - mode: 'indeterminate' - }) - - const node = plugins.value - .find((plugin) => plugin.id === pluginId) - ?.nodes.find((node) => node.node.id === nodeId) as - | { - node: Action - runner: ActionRunner - } - | undefined - - if (!node) { - mainWindow?.setProgressBar(1, { mode: 'normal' }) - return { - type: 'error', - ipcError: 'Node not found' - } - } - - const tmp = await generateTempFolder(config.cacheFolder) - - const _assetsPath = await assetsPath() - const _unpackPath = await unpackPath() - const nodePath = await ensureNodeJS() - const modulesPath = join(_unpackPath, 'node_modules') - const pnpm = join(modulesPath, 'pnpm', 'bin', 'pnpm.cjs') - const outputs: Record = {} - const api = usePluginAPI(mainWindow) - - try { - await mkdir(tmp, { recursive: true }) - checkParams(node.node.params, params) - const resolvedInputs = params // await resolveActionInputs(params, node.node, steps) - logger().info('resolvedInputs', resolvedInputs) - - await node.runner({ - inputs: resolvedInputs, - log: (...args) => { - const decorator = `[${node.node.name}]` - const logArgs = [decorator, ...args] - logger().info(...logArgs) - send({ - type: 'log', - data: { - decorator, - time: Date.now(), - message: args - } - }) - }, - setOutput: (key: string, value: unknown) => { - outputs[key] = value - }, - meta: { - definition: '' - }, - setMeta: () => { - logger().info('set meta defined here') - }, - cwd: tmp, - paths: { - assets: _assetsPath, - unpack: _unpackPath, - cache: config.cacheFolder, - node: nodePath, - pnpm - }, - api, - browserWindow: mainWindow, - abortSignal - }) - - mainWindow?.setProgressBar(1, { mode: 'normal' }) - - return { - type: 'success', - result: { outputs, tmp } - } - } catch (e) { - logger().error('Error in action execution:', e) - mainWindow?.setProgressBar(1, { mode: 'normal' }) - - // If aborted, throw AbortError to distinguish from actual errors - if (abortSignal.aborted) { - const abortError = new Error('Aborted') - abortError.name = 'AbortError' - throw abortError - } - - return { - type: 'error', - ipcError: e - } - } -} diff --git a/src/main/handlers.ts b/src/main/handlers.ts deleted file mode 100644 index 6a411306..00000000 --- a/src/main/handlers.ts +++ /dev/null @@ -1,856 +0,0 @@ -import { Channels, Data, Events, Message } from '@@/apis' -import { ensure, getFinalPlugins, executeGraphWithHistory } from './utils' -import { WebSocket as WSWebSocket } from 'ws' -import { join } from 'node:path' -import { writeFile, readFile } from 'node:fs/promises' -import { presets } from './presets/list' -import { handleActionExecute, handleConditionExecute } from './handler-func' -import { useLogger } from '@@/logger' -import { getDefaultAppSettingsMigrated, setupConfig } from './config' -import { buildHistoryStorage } from './handlers/build-history' -import { SubscriptionRequiredError } from '@@/subscription-errors' -import { WebSocketEvent, WebSocketHandler, WebSocketSendFunction } from '@@/websocket.types' -import { app, BrowserWindow, dialog } from 'electron' - -export type HandleListenerSendFn = WebSocketSendFunction - -export type WsEvent = WebSocketEvent - -export type HandleListener = WebSocketHandler - -const handlers: Record> = {} - -export const useAPI = () => { - const { logger } = useLogger() - - const handle = (channel: KEY, listener: WebSocketHandler) => { - handlers[channel] = listener - - return { - channel, - listener - } - } - - const processWebSocketMessage = (ws: WSWebSocket, channel: string, message: Message) => { - const { data, requestId } = message - - if (handlers[channel]) { - logger().debug('Executing handler for channel:', channel) - const event: WsEvent = { - sender: ws.url || 'websocket-client' - } - - const send: HandleListenerSendFn = (events) => { - logger().debug('sending', events, 'to', requestId) - const response = { - type: 'response', - requestId, - events - } - ws.send(JSON.stringify(response)) - return Promise.resolve() - } - - return handlers[channel](event, { - send, - value: data - }) - } else { - logger().warn('No handler found for channel:', channel) - } - } - - return { - handle, - processWebSocketMessage, - handlers - } -} - -export const registerIPCHandlers = () => { - const { handle } = useAPI() - const { logger } = useLogger() - - logger().info('registering ipc handlers') - - // Helper function to check build history authorization - const checkBuildHistoryAuthorization = async (event: WsEvent): Promise => { - logger().info('AUTH BYPASS: Skipping auth verification for build history access') - - // Always authorize for now - relying on frontend auth checks only - const isAuthorized = true - - if (!isAuthorized) { - throw new SubscriptionRequiredError('build-history') - } - - return true - } - - handle('dialog:showOpenDialog', async (event, { value, send }) => { - const slash = (await import('slash')).default - - // logger().info('event', event) - logger().info('value', value) - logger().info('dialog:showOpenDialog') - - const mainWindow = BrowserWindow.getFocusedWindow() - - if (!mainWindow) { - logger().error('mainWindow not found') - return - } - - const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, value) - - send({ - type: 'end', - data: { - type: 'success', - result: { - filePaths: filePaths.map((f) => slash(f)), - canceled - } - } - }) - }) - - handle('fs:read', async (event, { value, send }) => { - const { logger } = useLogger() - - // logger.info('event', event) - // logger().info('value', value) - // logger().info('fs:read') - - try { - const data = await readFile(value.path, 'utf-8') - - send({ - type: 'end', - data: { - type: 'success', - result: { - content: data - } - } - }) - } catch (e) { - logger().error('e', e) - send({ - type: 'end', - data: { - type: 'error', - ipcError: 'Unable to read file' - } - }) - } - }) - - handle('fs:write', async (event, { value, send }) => { - const { logger } = useLogger() - - await writeFile(value.path, value.content, 'utf-8') - - send({ - type: 'end', - data: { - type: 'success', - result: { - ok: true - } - } - }) - }) - - handle('dialog:showSaveDialog', async (event, { value, send }) => { - const { logger } = useLogger() - - // logger.info('event', event) - logger().info('value', value) - logger().info('dialog:showSaveDialog') - - const mainWindow = BrowserWindow.getFocusedWindow() - - if (!mainWindow) { - logger().error('mainWindow not found') - return - } - - const { canceled, filePath } = await dialog.showSaveDialog(mainWindow, value) - - console.log('canceled', canceled) - console.log('filePath', filePath) - - send({ - type: 'end', - data: { - type: 'success', - result: { - filePath, - canceled - } - } - }) - }) - - handle('nodes:get', async (_, { send }) => { - const finalPlugins = getFinalPlugins() - - // logger.info( - // inspect(finalPlugins, { - // depth: 5 - // }) - // ) - - send({ - type: 'end', - data: { - type: 'success', - result: { - nodes: finalPlugins - } - } - }) - }) - - handle('presets:get', async (_, { send }) => { - const presetData = await presets() - - // logger.info( - // inspect(presetData, { - // depth: 5 - // }) - // ) - - send({ - type: 'end', - data: { - type: 'success', - result: presetData - } - }) - }) - - handle('condition:execute', async (_, { value }) => { - const { nodeId, params, pluginId } = value - - await handleConditionExecute( - nodeId, - pluginId, - params /* , { - send, - } */ - ) - }) - let abortControllerGraph: undefined | AbortController = undefined - - const effectiveActionExecute = async ( - nodeId: string, - pluginId: string, - params: Record, - mainWindow: BrowserWindow | undefined, - send: HandleListenerSendFn<'action:execute'> - ) => { - try { - // Listen to the abort signal and trigger rejection. - - const result = await handleActionExecute( - nodeId, - pluginId, - params, - mainWindow, - send, - abortControllerGraph.signal - ) - - await send({ - data: result, - type: 'end' - }) - } catch (e) { - // Catch any error and propagate it. - console.error('Error during action execution:', e) - await send({ - type: 'end', - data: { - ipcError: e instanceof Error ? e.message : 'Unknown error', - type: 'error' - } - }) - } finally { - console.log('action execution done, either ok or ko') - } - } - - handle('action:execute', async (event, { send, value }) => { - const { nodeId, params, pluginId } = value - - // In WebSocket mode, no BrowserWindow available - const mainWindow = BrowserWindow.getFocusedWindow() - abortControllerGraph = new AbortController() - - const signalPromise = new Promise((resolve, reject) => { - abortControllerGraph.signal.addEventListener('abort', async (ev) => { - console.log('ev', ev) - await send({ - type: 'end', - data: { - ipcError: 'Action aborted', - type: 'error' - } - }) - return reject(new Error('Action interrupted: ' + 'Unknown reason')) - }) - }) - - console.log('race started') - - await Promise.race([ - signalPromise, - effectiveActionExecute(nodeId, pluginId, params, mainWindow, send) - ]) - }) - - handle('constants:get', async (_, { send }) => { - const userData = app.getPath('userData') - - send({ - type: 'end', - data: { - type: 'success', - result: { - result: { - userData - } - } - } - }) - }) - - handle('config:load', async (_, { send, value }) => { - const { config } = value - - const userData = app.getPath('userData') - - const filesPath = join(userData, 'config', config + '.json') - - await ensure(filesPath) - - let content = '{}' - try { - content = await readFile(filesPath, 'utf8') - } catch (e) { - logger().error('e', e) - } - - const json = JSON.parse(content) - - send({ - type: 'end', - data: { - type: 'success', - result: { - result: json - } - } - }) - }) - - handle('settings:load', async (_, { send }) => { - const settingsG = await setupConfig() - const settings = await settingsG.getConfig() - - send({ - type: 'end', - data: { - type: 'success', - result: { - result: settings - } - } - }) - }) - - handle('settings:save', async (_, { send, value }) => { - const settingsG = await setupConfig() - const settings = await settingsG.setConfig(value) - - send({ - type: 'end', - data: { - type: 'success', - result: { - result: settings === true ? 'ok' : 'ko' - } - } - }) - }) - - handle('settings:reset', async (event, { value, send }) => { - const { logger } = useLogger() - logger().info('value', value) - logger().info('settings:reset') - - const settingsG = await setupConfig() - const settings = await settingsG.getConfig() - - const migratedSettings = await getDefaultAppSettingsMigrated() - - await settingsG.setConfig({ - ...settings, - [value.key]: migratedSettings[value.key as keyof typeof migratedSettings] as any - }) - - send({ - type: 'end', - data: { - type: 'success', - result: { - result: 'ok' - } - } - }) - }) - - handle('config:save', async (_, { send, value }) => { - const { data, config } = value - - const userData = app.getPath('userData') - - const filesPath = join(userData, 'config', config + '.json') - - await ensure(filesPath) - - await writeFile(filesPath, data, 'utf8') - - send({ - type: 'end', - data: { - type: 'success', - result: { - result: 'ok' - } - } - }) - }) - - handle('action:cancel', async (_, { send }) => { - abortControllerGraph.abort('Interrupted by user') - send({ - type: 'end', - data: { - type: 'success', - result: { - result: 'ok' - } - } - }) - }) - - // Build History Handlers - handle('build-history:save', async (event, { send, value }) => { - const { logger } = useLogger() - - try { - // Check authorization before allowing save - logger().info('AUTH BYPASS: Processing build-history:save request') - await checkBuildHistoryAuthorization(event) - - await buildHistoryStorage.save(value.entry) - send({ - type: 'end', - data: { - type: 'success', - result: { result: 'ok' } - } - }) - } catch (error) { - logger().error('Failed to save build history entry:', error) - - // Handle subscription errors with user-friendly messages - if (error instanceof SubscriptionRequiredError) { - send({ - type: 'end', - data: { - type: 'error', - ipcError: error.userMessage, - code: error.code - } - }) - return - } - - send({ - type: 'end', - data: { - type: 'error', - ipcError: error instanceof Error ? error.message : 'Failed to save build history entry' - } - }) - } - }) - - handle('build-history:get', async (event, { send, value }) => { - const { logger } = useLogger() - - try { - // Check authorization before allowing access - logger().info('AUTH BYPASS: Processing build-history:get request') - await checkBuildHistoryAuthorization(event) - - const entry = await buildHistoryStorage.get(value.id) - send({ - type: 'end', - data: { - type: 'success', - result: { entry } - } - }) - } catch (error) { - logger().error('Failed to get build history entry:', error) - - // Handle subscription errors with user-friendly messages - if (error instanceof SubscriptionRequiredError) { - send({ - type: 'end', - data: { - type: 'error', - ipcError: error.userMessage, - code: error.code - } - }) - return - } - - send({ - type: 'end', - data: { - type: 'error', - ipcError: error instanceof Error ? error.message : 'Failed to get build history entry' - } - }) - } - }) - - handle('build-history:get-all', async (event, { send, value }) => { - const { logger } = useLogger() - - try { - // Check authorization before allowing access - logger().info('AUTH BYPASS: Processing build-history:get-all request') - await checkBuildHistoryAuthorization(event) - - // Simplified: get all entries, optionally filter by pipeline - const allEntries = await buildHistoryStorage.getAll() - const filteredEntries = value.query?.pipelineId - ? allEntries.filter((entry) => entry.pipelineId === value.query.pipelineId) - : allEntries - - send({ - type: 'end', - data: { - type: 'success', - result: { - entries: filteredEntries, - total: filteredEntries.length - } - } - }) - } catch (error) { - logger().error('Failed to get build history entries:', error) - - // Handle subscription errors with user-friendly messages - if (error instanceof SubscriptionRequiredError) { - send({ - type: 'end', - data: { - type: 'error', - ipcError: error.userMessage, - code: error.code - } - }) - return - } - - send({ - type: 'end', - data: { - type: 'error', - ipcError: error instanceof Error ? error.message : 'Failed to get build history entries' - } - }) - } - }) - - handle('build-history:update', async (event, { send, value }) => { - const { logger } = useLogger() - - try { - // Check authorization before allowing update - await checkBuildHistoryAuthorization(event) - - await buildHistoryStorage.update(value.id, value.updates) - send({ - type: 'end', - data: { - type: 'success', - result: { result: 'ok' } - } - }) - } catch (error) { - logger().error('Failed to update build history entry:', error) - - // Handle subscription errors with user-friendly messages - if (error instanceof SubscriptionRequiredError) { - send({ - type: 'end', - data: { - type: 'error', - ipcError: error.userMessage, - code: error.code - } - }) - return - } - - send({ - type: 'end', - data: { - type: 'error', - ipcError: error instanceof Error ? error.message : 'Failed to update build history entry' - } - }) - } - }) - - handle('build-history:delete', async (event, { send, value }) => { - const { logger } = useLogger() - - try { - // Check authorization before allowing deletion - await checkBuildHistoryAuthorization(event) - - await buildHistoryStorage.delete(value.id) - send({ - type: 'end', - data: { - type: 'success', - result: { result: 'ok' } - } - }) - } catch (error) { - logger().error('Failed to delete build history entry:', error) - - // Handle subscription errors with user-friendly messages - if (error instanceof SubscriptionRequiredError) { - send({ - type: 'end', - data: { - type: 'error', - ipcError: error.userMessage, - code: error.code - } - }) - return - } - - send({ - type: 'end', - data: { - type: 'error', - ipcError: error instanceof Error ? error.message : 'Failed to delete build history entry' - } - }) - } - }) - - handle('build-history:clear', async (event, { send }) => { - const { logger } = useLogger() - - try { - // Check authorization before allowing clear operation - await checkBuildHistoryAuthorization(event) - - await buildHistoryStorage.clear() - send({ - type: 'end', - data: { - type: 'success', - result: { result: 'ok' } - } - }) - } catch (error) { - logger().error('Failed to clear build history:', error) - - // Handle subscription errors with user-friendly messages - if (error instanceof SubscriptionRequiredError) { - send({ - type: 'end', - data: { - type: 'error', - ipcError: error.userMessage, - code: error.code - } - }) - return - } - - send({ - type: 'end', - data: { - type: 'error', - ipcError: error instanceof Error ? error.message : 'Failed to clear build history' - } - }) - } - }) - - handle('build-history:get-storage-info', async (event, { send }) => { - const { logger } = useLogger() - - try { - // Check authorization before allowing access to storage info - await checkBuildHistoryAuthorization(event) - - const info = await buildHistoryStorage.getStorageInfo() - send({ - type: 'end', - data: { - type: 'success', - result: info - } - }) - } catch (error) { - logger().error('Failed to get build history storage info:', error) - - // Handle subscription errors with user-friendly messages - if (error instanceof SubscriptionRequiredError) { - send({ - type: 'end', - data: { - type: 'error', - ipcError: error.userMessage, - code: error.code - } - }) - return - } - - send({ - type: 'end', - data: { - type: 'error', - ipcError: - error instanceof Error ? error.message : 'Failed to get build history storage info' - } - }) - } - }) - - handle('build-history:configure', async (_, { send, value }) => { - const { logger } = useLogger() - - try { - // For now, we'll just log the configuration request - // In a real implementation, you might want to make the storage configurable - logger().info('Build history configuration request:', value.config) - - send({ - type: 'end', - data: { - type: 'success', - result: { result: 'ok' } - } - }) - } catch (error) { - logger().error('Failed to configure build history:', error) - send({ - type: 'end', - data: { - type: 'error', - ipcError: error instanceof Error ? error.message : 'Failed to configure build history' - } - }) - } - }) - - handle('graph:execute', async (event, { send, value }) => { - const { graph, variables, projectName, projectPath, pipelineId } = value - - const mainWindow = BrowserWindow.getFocusedWindow() - abortControllerGraph = new AbortController() - - try { - const { result, buildId } = await executeGraphWithHistory({ - graph, - variables, - projectName, - projectPath, - pipelineId, - mainWindow, - onNodeEnter: (node) => { - // Send UI update for node entering - send({ - type: 'node-enter', - data: { - nodeUid: node.uid, - nodeName: node.name - } - }) - }, - onNodeExit: (node) => { - // Send UI update for node exiting - send({ - type: 'node-exit', - data: { - nodeUid: node.uid, - nodeName: node.name - } - }) - }, - onLog: (data, node) => { - // Send log data to frontend - if (data.type === 'log') { - // Sanitize data for IPC serialization - const sanitizedData = { - message: data.data.message, - timestamp: data.data.time - } - - send({ - type: 'node-log', - data: { - nodeUid: node?.uid || 'unknown', - logData: sanitizedData - } - }) - } - }, - abortSignal: abortControllerGraph.signal - }) - - send({ - type: 'end', - data: { - type: 'success', - result: { - result, - buildId - } - } - }) - } catch (e) { - console.log('abortControllerGraph.signal.aborted', abortControllerGraph.signal.aborted) - const isCanceled = e instanceof Error && e.name === 'AbortError' - send({ - type: 'end', - data: { - type: 'error', - code: isCanceled ? 'canceled' : 'error', - ipcError: e instanceof Error ? e.message : 'Unknown error' - } - }) - } - }) -} diff --git a/src/main/handlers/build-history.ts b/src/main/handlers/build-history.ts deleted file mode 100644 index 441a19cc..00000000 --- a/src/main/handlers/build-history.ts +++ /dev/null @@ -1,258 +0,0 @@ -import { app } from 'electron' -import { join } from 'node:path' -import { writeFile, readFile, unlink, mkdir } from 'node:fs/promises' -import { BuildHistoryEntry, IBuildHistoryStorage } from '@@/build-history' -import { useLogger } from '@@/logger' - -// Simplified storage - one file per pipeline containing array of build entries -const STORAGE_PATH = join(app.getPath('userData'), 'build-history') - -export class BuildHistoryStorage implements IBuildHistoryStorage { - private logger = useLogger() - - constructor() { - // Simple initialization - no complex setup needed - } - - private getPipelinePath(pipelineId: string): string { - // Sanitize the pipelineId to create a valid filename - // Replace invalid filename characters with underscores - const sanitizedId = pipelineId - .replace(/[/\\:*?"<>|]/g, '_') - .replace(/__/g, '_') // Replace multiple underscores with single - .replace(/^_+|_+$/g, '') // Remove leading/trailing underscores - - return join(STORAGE_PATH, `pipeline-${sanitizedId}.json`) - } - - private async ensureStoragePath(): Promise { - try { - await mkdir(STORAGE_PATH, { recursive: true }) - } catch (error) { - this.logger.logger().error('Failed to create storage path:', error) - throw new Error(`Failed to create storage directory: ${error}`) - } - } - - private async loadPipelineHistory(pipelineId: string): Promise { - try { - const pipelinePath = this.getPipelinePath(pipelineId) - const data = await readFile(pipelinePath, 'utf-8') - return JSON.parse(data) - } catch (error) { - // File doesn't exist or is corrupted, return empty array - return [] - } - } - - private async savePipelineHistory( - pipelineId: string, - entries: BuildHistoryEntry[] - ): Promise { - console.log('savePipelineHistory', pipelineId, entries.length) - try { - await this.ensureStoragePath() - const pipelinePath = this.getPipelinePath(pipelineId) - await writeFile(pipelinePath, JSON.stringify(entries, null, 2), 'utf-8') - } catch (error) { - this.logger.logger().error('Failed to save pipeline history:', error) - throw new Error(`Failed to save pipeline history: ${error}`) - } - } - - async save(entry: BuildHistoryEntry): Promise { - try { - const entries = await this.loadPipelineHistory(entry.pipelineId) - const existingIndex = entries.findIndex((e) => e.id === entry.id) - - if (existingIndex >= 0) { - entries[existingIndex] = entry - } else { - entries.push(entry) - } - - await this.savePipelineHistory(entry.pipelineId, entries) - this.logger - .logger() - .info(`Saved build history entry: ${entry.id} for pipeline: ${entry.pipelineId}`) - } catch (error) { - this.logger.logger().error('Failed to save build history entry:', error) - throw new Error(`Failed to save build history entry: ${error}`) - } - } - - async get(id: string): Promise { - try { - // We need to search through all pipeline files to find the entry - // This is simple but not optimized - for production you'd want indexing - const files = await this.getAllPipelineFiles() - - for (const file of files) { - const pipelineId = file.replace('pipeline-', '').replace('.json', '') - const entries = await this.loadPipelineHistory(pipelineId) - - const entry = entries.find((e) => e.id === id) - if (entry) { - return entry - } - } - - return undefined - } catch (error) { - this.logger.logger().error(`Failed to get build history entry ${id}:`, error) - return undefined - } - } - - async getAll(): Promise { - try { - const files = await this.getAllPipelineFiles() - const allEntries: BuildHistoryEntry[] = [] - - for (const file of files) { - const pipelineId = file.replace('pipeline-', '').replace('.json', '') - const entries = await this.loadPipelineHistory(pipelineId) - allEntries.push(...entries) - } - - // Sort by creation time, newest first - return allEntries.sort((a, b) => b.createdAt - a.createdAt) - } catch (error) { - this.logger.logger().error('Failed to get all build history entries:', error) - throw new Error(`Failed to get build history entries: ${error}`) - } - } - - async getByPipeline(pipelineId: string): Promise { - try { - const entries = await this.loadPipelineHistory(pipelineId) - // Sort by creation time, newest first - return entries.sort((a, b) => b.createdAt - a.createdAt) - } catch (error) { - this.logger.logger().error(`Failed to get build history for pipeline ${pipelineId}:`, error) - throw new Error(`Failed to get build history for pipeline: ${error}`) - } - } - - async update(id: string, updates: Partial): Promise { - try { - const files = await this.getAllPipelineFiles() - - for (const file of files) { - const pipelineId = file.replace('pipeline-', '').replace('.json', '') - const entries = await this.loadPipelineHistory(pipelineId) - - const entryIndex = entries.findIndex((e) => e.id === id) - if (entryIndex >= 0) { - entries[entryIndex] = { - ...entries[entryIndex], - ...updates, - updatedAt: Date.now() - } - await this.savePipelineHistory(pipelineId, entries) - return - } - } - - throw new Error(`Build history entry ${id} not found`) - } catch (error) { - this.logger.logger().error(`Failed to update build history entry ${id}:`, error) - throw new Error(`Failed to update build history entry: ${error}`) - } - } - - async delete(id: string): Promise { - try { - const files = await this.getAllPipelineFiles() - - for (const file of files) { - const pipelineId = file.replace('pipeline-', '').replace('.json', '') - const entries = await this.loadPipelineHistory(pipelineId) - - const entryIndex = entries.findIndex((e) => e.id === id) - if (entryIndex >= 0) { - entries.splice(entryIndex, 1) - await this.savePipelineHistory(pipelineId, entries) - this.logger.logger().info(`Deleted build history entry: ${id}`) - return - } - } - - // Entry not found, but don't throw error - this.logger.logger().info(`Build history entry ${id} not found for deletion`) - } catch (error) { - this.logger.logger().error(`Failed to delete build history entry ${id}:`, error) - throw new Error(`Failed to delete build history entry: ${error}`) - } - } - - async clear(): Promise { - try { - await this.ensureStoragePath() - - const files = await this.getAllPipelineFiles() - await Promise.all(files.map((file) => unlink(join(STORAGE_PATH, file)))) - - this.logger.logger().info('Cleared all build history entries') - } catch (error) { - this.logger.logger().error('Failed to clear build history:', error) - throw new Error(`Failed to clear build history: ${error}`) - } - } - - async getStorageInfo(): Promise<{ - totalEntries: number - totalSize: number - oldestEntry?: number - newestEntry?: number - }> { - try { - const allEntries = await this.getAll() - if (allEntries.length === 0) { - return { - totalEntries: 0, - totalSize: 0 - } - } - - // Calculate approximate size - let totalSize = 0 - try { - const files = await this.getAllPipelineFiles() - for (const file of files) { - const filePath = join(STORAGE_PATH, file) - const stats = await import('node:fs/promises').then((fs) => fs.stat(filePath)) - totalSize += stats.size - } - } catch (error) { - // Rough estimate if we can't calculate actual size - totalSize = allEntries.length * 1024 - } - - const sortedEntries = allEntries.sort((a, b) => a.createdAt - b.createdAt) - - return { - totalEntries: allEntries.length, - totalSize, - oldestEntry: sortedEntries[0]?.createdAt, - newestEntry: sortedEntries[sortedEntries.length - 1]?.createdAt - } - } catch (error) { - this.logger.logger().error('Failed to get storage info:', error) - throw new Error(`Failed to get storage info: ${error}`) - } - } - - private async getAllPipelineFiles(): Promise { - try { - await this.ensureStoragePath() - const files = await import('node:fs/promises').then((fs) => fs.readdir(STORAGE_PATH)) - return files.filter((file) => file.startsWith('pipeline-') && file.endsWith('.json')) - } catch (error) { - return [] - } - } -} - -// Export a default instance -export const buildHistoryStorage = new BuildHistoryStorage() diff --git a/src/main/paths.ts b/src/main/paths.ts deleted file mode 100644 index bece5ed9..00000000 --- a/src/main/paths.ts +++ /dev/null @@ -1,29 +0,0 @@ -export const unpackPath = async () => { - const { join } = await import('path') - const { app } = await import('electron') - const _unpackPath = - !process.env.NODE_ENV || process.env.NODE_ENV === 'production' - ? app.getAppPath() // Live Mode - : process.cwd() // Dev Mode - - return join(_unpackPath) -} - -export const assetsPath = async () => { - const { app } = await import('electron') - const { join } = await import('path') - const _assetsPath = - !process.env.NODE_ENV || process.env.NODE_ENV === 'production' - ? join(app.getAppPath(), '..') // Live Mode - : process.cwd() // Dev Mode - return join(_assetsPath, 'assets') -} - -export const dirname = async () => { - const { join } = await import('path') - const _dirname = - !process.env.NODE_ENV || process.env.NODE_ENV === 'production' - ? __dirname // Live Mode - : __dirname // Dev Mode - return join(_dirname) -} diff --git a/src/main/presets/c3toSteam.ts b/src/main/presets/c3toSteam.ts deleted file mode 100644 index 0652a961..00000000 --- a/src/main/presets/c3toSteam.ts +++ /dev/null @@ -1,272 +0,0 @@ -import { PresetFn, SavedFile } from '@@/model' - -export const c3toSteamPreset: PresetFn = async () => { - const startId = 'manual-start' - - const data: SavedFile = { - version: '3.0.0', - name: 'Construct 3 to Steam', - description: 'A basic project to get you started with Construct 3 and Steam', - variables: [], - canvas: { - triggers: [ - { - type: 'event', - origin: { - pluginId: 'system', - nodeId: 'manual' - }, - uid: startId, - params: {} - } - ], - blocks: [ - { - uid: '3oHbOKmCXo6NSjmrn0tHG', - type: 'action', - origin: { - nodeId: 'export-construct-project', - pluginId: 'construct' - }, - params: { - file: { - editor: 'simple', - value: '' - }, - username: { - editor: 'simple', - value: '""' - }, - password: { - editor: 'simple', - value: '""' - }, - version: { - editor: 'simple', - value: '' - }, - headless: { - editor: 'simple', - value: 'true' - }, - timeout: { - editor: 'simple', - value: '120' - }, - customProfile: { - editor: 'simple', - value: '' - } - } - }, - { - uid: '6s1uYWDi2XbRriBpvQSBS', - type: 'action', - origin: { - nodeId: 'unzip-file-node', - pluginId: 'filesystem' - }, - params: { - file: { - editor: 'editor', - value: "steps['3oHbOKmCXo6NSjmrn0tHG']['outputs']['zipFile']" - } - } - }, - { - uid: 'cvxzwBfXPZhH1RbmmxBdG', - type: 'action', - origin: { - nodeId: 'electron:package:v2', - pluginId: 'electron' - }, - params: { - arch: { - editor: 'simple', - value: '' - }, - platform: { - editor: 'simple', - value: '' - }, - 'input-folder': { - editor: 'editor', - value: "steps['6s1uYWDi2XbRriBpvQSBS']['outputs']['output']" - }, - name: { - editor: 'simple', - value: '"Pipelab"' - }, - appBundleId: { - editor: 'simple', - value: '"com.pipelab.app"' - }, - appCopyright: { - editor: 'simple', - value: '"Copyright © 2024 Pipelab"' - }, - appVersion: { - editor: 'simple', - value: '"1.0.0"' - }, - icon: { - editor: 'simple', - value: '' - }, - author: { - editor: 'simple', - value: '"Pipelab"' - }, - description: { - editor: 'simple', - value: '"A sample application"' - }, - appCategoryType: { - editor: 'simple', - value: '"public.app-category.developer-tools"' - }, - width: { - editor: 'simple', - value: 800 - }, - height: { - editor: 'simple', - value: 600 - }, - fullscreen: { - editor: 'simple', - value: 'false' - }, - frame: { - editor: 'simple', - value: 'true' - }, - transparent: { - editor: 'simple', - value: 'false' - }, - toolbar: { - editor: 'simple', - value: 'true' - }, - alwaysOnTop: { - editor: 'simple', - value: 'false' - }, - electronVersion: { - editor: 'simple', - value: '""' - }, - customMainCode: { - editor: 'simple', - value: '' - }, - disableAsarPackaging: { - editor: 'simple', - value: 'true' - }, - enableExtraLogging: { - editor: 'simple', - value: 'false' - }, - clearServiceWorkerOnBoot: { - editor: 'simple', - value: 'false' - }, - enableInProcessGPU: { - editor: 'simple', - value: 'false' - }, - enableDisableRendererBackgrounding: { - editor: 'simple', - value: 'false' - }, - forceHighPerformanceGpu: { - editor: 'simple', - value: 'false' - }, - websocketApi: { - editor: 'simple', - value: '[]' - }, - ignore: { - editor: 'simple', - value: "[\n // use 'src/app/' as starting point\n]" - }, - enableSteamSupport: { - editor: 'simple', - value: 'true' - }, - steamGameId: { - editor: 'simple', - value: '480' - } - } - }, - { - uid: '1pJrNARroFnuY9DfiC56r', - type: 'action', - origin: { - nodeId: 'steam-upload', - pluginId: 'steam' - }, - params: { - sdk: { - editor: 'simple', - value: '' - }, - username: { - editor: 'simple', - value: '' - }, - appId: { - editor: 'simple', - value: '' - }, - depotId: { - editor: 'simple', - value: '' - }, - description: { - editor: 'simple', - value: '' - }, - folder: { - editor: 'editor', - value: "steps['cvxzwBfXPZhH1RbmmxBdG']['outputs']['output']" - }, - enableDRM: { - editor: 'simple', - value: 'false' - }, - binaryToPatch: { - editor: 'simple', - value: '' - } - }, - disabled: false - }, - { - uid: 'gnTsA6oO49ySfetxUf-0K', - type: 'action', - origin: { - nodeId: 'fs:open-in-explorer', - pluginId: 'filesystem' - }, - params: { - path: { - editor: 'editor', - value: "steps['cvxzwBfXPZhH1RbmmxBdG']['outputs']['output']" - } - }, - disabled: false - } - ] - } - } - - return { - data, - hightlight: true - } -} diff --git a/src/main/presets/demo.ts b/src/main/presets/demo.ts deleted file mode 100644 index acad93e3..00000000 --- a/src/main/presets/demo.ts +++ /dev/null @@ -1,123 +0,0 @@ -// @ts-nocheck - -import { PresetFn, SavedFile } from '@@/model' - -export const demoPreset: PresetFn = async () => { - const startId = 'manual-start' - const exportConstructProjectId = 'export-construct-project' - const listFilesNodeId = 'list-files-node' - const logOkId = 'log-ok' - - const data: SavedFile = { - version: '1.0.0', - variables: [], - name: 'demo', - description: 'demo', - canvas: { - blocks: [ - { - type: 'event', - origin: { - pluginId: 'system', - nodeId: 'manual' - }, - uid: startId, - params: {} - }, - { - type: 'action', - origin: { - pluginId: 'construct', - nodeId: 'export-construct-project' - }, - uid: exportConstructProjectId, - params: { - version: '300', - username: 'quentin', - password: 'aaa', - headless: false - } - }, - { - type: 'action', - origin: { - pluginId: 'filesystem', - nodeId: 'list-files-node' - }, - uid: listFilesNodeId, - params: { - folder: '/home/quentin/Téléchargements/sourcegit/', - recursive: true - } - }, - { - type: 'loop', - origin: { - pluginId: 'system', - nodeId: 'for' - }, - - params: { - value: `{{ steps['${listFilesNodeId}']['outputs']['paths'] }}` - }, - children: [ - { - type: 'condition', - origin: { - pluginId: 'filesystem', - nodeId: 'is-file' - }, - uid: 'is-file-condition', - - params: { - path: `{{ steps['${listFilesNodeId}']['outputs']['paths'][context.loopindex] }}` - }, - branchTrue: [ - { - type: 'action', - origin: { - pluginId: 'system', - nodeId: 'log' - }, - params: { - message: `File: {{ steps['${listFilesNodeId}']['outputs']['paths'] }}` - }, - uid: 'log-ok-in-foreach' - } - ], - branchFalse: [ - { - type: 'action', - origin: { - pluginId: 'system', - nodeId: 'log' - }, - params: { - message: `Folder: {{ steps['${listFilesNodeId}']['outputs']['paths'] }}` - }, - uid: 'log-ko-in-foreach' - } - ] - } - ], - uid: 'for-each-file' - }, - { - type: 'action', - origin: { - pluginId: 'system', - nodeId: 'log' - }, - uid: logOkId, - params: { - message: '{{ Filesystem.Join() }}' - } - } - ] - } - } - - return { - data - } -} diff --git a/src/main/presets/if.ts b/src/main/presets/if.ts deleted file mode 100644 index 87ce1715..00000000 --- a/src/main/presets/if.ts +++ /dev/null @@ -1,69 +0,0 @@ -// @ts-nocheck -import { PresetFn, SavedFile } from '@@/model' - -export const ifPreset: PresetFn = async () => { - const branchId = 'branchId' - const logOkId = 'logOkId' - const logKoId = 'logKoId' - const booleanId = 'booleanId' - - const data: SavedFile = { - version: '1.0.0', - name: 'Condition demo', - description: 'Condition demo', - variables: [ - { - type: 'boolean', - id: booleanId, - description: 'The value of the conditon', - name: 'Value', - value: true - } - ], - canvas: { - blocks: [ - { - type: 'condition', - origin: { - pluginId: 'system', - nodeId: 'branch' - }, - uid: branchId, - params: { - condition: '' - }, - branchTrue: [ - { - type: 'action', - origin: { - pluginId: 'system', - nodeId: 'log' - }, - uid: logOkId, - params: { - text: 'OK' - } - } - ], - branchFalse: [ - { - type: 'action', - origin: { - pluginId: 'system', - nodeId: 'log' - }, - uid: logKoId, - params: { - text: 'KO' - } - } - ] - } - ] - } - } - - return { - data - } -} diff --git a/src/main/presets/loop.ts b/src/main/presets/loop.ts deleted file mode 100644 index 28789e34..00000000 --- a/src/main/presets/loop.ts +++ /dev/null @@ -1,65 +0,0 @@ -// @ts-nocheck - -import { PresetFn, SavedFile } from '@@/model' - -export const loopPreset: PresetFn = async () => { - const forId = 'forId' - const arrayId = 'arrayId' - - const logStepId = 'logStepId' - const logExitId = 'logExitId' - - const data: SavedFile = { - version: '1.0.0', - name: 'Loop demo', - description: 'Loop demo', - variables: [ - { - id: arrayId, - description: 'An array', - name: 'Array', - type: 'array', - of: 'string', - value: [] - } - ], - canvas: { - blocks: [ - { - type: 'loop', - origin: { - pluginId: 'system', - nodeId: 'for' - }, - - params: {}, - children: [ - { - type: 'action', - origin: { - pluginId: 'system', - nodeId: 'log' - }, - params: {}, - uid: logStepId - } - ], - uid: forId - }, - { - type: 'action', - origin: { - pluginId: 'system', - nodeId: 'log' - }, - params: {}, - uid: logExitId - } - ] - } - } - - return { - data - } -} diff --git a/src/main/presets/moreToCome.ts b/src/main/presets/moreToCome.ts deleted file mode 100644 index b120c519..00000000 --- a/src/main/presets/moreToCome.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { PresetFn, SavedFile } from '@@/model' - -export const moreToCome: PresetFn = async () => { - const startId = 'manual-start' - - const data: SavedFile = { - version: '3.0.0', - name: 'More to come!', - description: 'Do not hesitate to suggest templates you would see here', - variables: [], - canvas: { - triggers: [ - { - type: 'event', - origin: { - pluginId: 'system', - nodeId: 'manual' - }, - uid: startId, - params: {} - } - ], - blocks: [ - - ] - } - } - - return { - data, - disabled: true, - hightlight: false - } -} diff --git a/src/main/presets/newProject.ts b/src/main/presets/newProject.ts deleted file mode 100644 index 4f1e583a..00000000 --- a/src/main/presets/newProject.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { PresetFn, SavedFile } from '@@/model' - -export const newProjectPreset: PresetFn = async () => { - const startId = 'manual-start' - - const data: SavedFile = { - version: '3.0.0', - name: 'Empty project', - description: 'A default project with no tasks added', - variables: [], - canvas: { - triggers: [ - { - type: 'event', - origin: { - pluginId: 'system', - nodeId: 'manual' - }, - uid: startId, - params: {} - } - ], - blocks: [ - - ] - } - } - - return { - data, - hightlight: true, - } -} diff --git a/src/main/presets/test-c3-offline.ts b/src/main/presets/test-c3-offline.ts deleted file mode 100644 index 5b239732..00000000 --- a/src/main/presets/test-c3-offline.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { PresetFn, SavedFile } from '@@/model' - -export const testC3Offline: PresetFn = async () => { - const packageWithElecton = 'electron-package-node' - const steamUpload = 'steam-upload-node' - - const data: SavedFile = { - version: '3.0.0', - variables: [], - name: 'C3 test without export', - description: 'C3 test without export', - canvas: { - triggers: [ - { - type: 'event', - origin: { - pluginId: 'system', - nodeId: 'manual' - }, - uid: 'manual-start', - params: {} - }, - ], - blocks: [ - { - uid: packageWithElecton, - type: 'action', - origin: { - nodeId: 'package-to-electron', - pluginId: 'electron' - }, - params: { - 'input-folder': { - editor: 'editor', - value: `/home/quentin/Documents/Cyn Assets/app` - }, - arch: undefined, - platform: undefined - } - }, - { - uid: steamUpload, - type: 'action', - origin: { - nodeId: 'steam-upload', - pluginId: 'steam' - }, - params: { - folder: { - editor: 'editor', - value: `{{ steps['${packageWithElecton}']['outputs']['output'] }}`, - }, - appId: { - editor: 'editor', - value: '3047200', - }, - depotId: { - editor: 'editor', - value: '3047201', - }, - sdk: { - editor: 'editor', - value: '/home/quentin/Documents/steamworkssdk/sdk', - }, - username: { - editor: 'editor', - value: 'armaldio', - }, - } - } - ] - } - } - - return { - data - } -} diff --git a/src/main/presets/test-c3-unzip.ts b/src/main/presets/test-c3-unzip.ts deleted file mode 100644 index cad561f0..00000000 --- a/src/main/presets/test-c3-unzip.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { PresetFn, SavedFile } from '@@/model' - -export const testC3Unzip: PresetFn = async () => { - const exportConstructProjectId = 'export-construct-project' - const unzipFileId = 'unzip-file-node' - const packageWithElecton = 'electron-package-node' - const steamUpload = 'steam-upload-node' - - const data: SavedFile = { - version: '3.0.0', - name: 'From Construct to Steam', - description: 'Export from Construct, package with Electron, then upload to Steam', - variables: [], - canvas: { - triggers: [ - { - type: 'event', - origin: { - pluginId: 'system', - nodeId: 'manual' - }, - uid: 'manual-start', - params: {} - } - ], - blocks: [ - { - uid: exportConstructProjectId, - type: 'action', - origin: { - nodeId: 'export-construct-project', - pluginId: 'construct' - }, - params: { - file: { - editor: 'editor', - value: `'/home/armaldio/Téléchargements/test.c3p'` - }, - username: { - editor: 'editor', - value: '"a"' - }, - password: { - editor: 'editor', - value: '"a"' - }, - version: { - editor: 'editor', - value: '"395"' - }, - headless: { - editor: 'editor', - value: false - } - } - }, - { - uid: unzipFileId, - type: 'action', - origin: { - nodeId: 'unzip-file-node', - pluginId: 'filesystem' - }, - params: { - file: { - editor: 'editor', - value: `steps['${exportConstructProjectId}']['outputs']['folder']` - } - } - }, - { - uid: packageWithElecton, - type: 'action', - origin: { - nodeId: 'electron:package', - pluginId: 'electron' - }, - params: { - 'input-folder': { - editor: 'editor', - value: `steps['${unzipFileId}']['outputs']['output']` - }, - arch: undefined, - platform: undefined - } - }, - { - uid: steamUpload, - type: 'action', - origin: { - nodeId: 'steam-upload', - pluginId: 'steam' - }, - params: { - folder: { - editor: 'editor', - value: `steps['${packageWithElecton}']['outputs']['output']` - }, - appId: { - editor: 'editor', - value: "'3047200'" - }, - depotId: { - editor: 'editor', - value: "'3047201'" - }, - sdk: { - editor: 'editor', - value: "'/home/armaldio/Documents/steamworkssdk/sdk'" - }, - username: { - editor: 'editor', - value: "'armaldio'" - } - } - } - ] - } - } - - return { - data - } -} diff --git a/src/main/utils.ts b/src/main/utils.ts deleted file mode 100644 index 0dc03f23..00000000 --- a/src/main/utils.ts +++ /dev/null @@ -1,580 +0,0 @@ -import { usePlugins } from '@@/plugins' -import { downloadFile, Hooks, RendererPluginDefinition } from '../shared/libs/plugin-core' -import { access, chmod, mkdir, mkdtemp, realpath, rm, unlink, writeFile } from 'node:fs/promises' -import { dirname, join } from 'node:path' -import { tmpdir } from 'node:os' -import { app, BrowserWindow } from 'electron' -import * as zlib from 'zlib' // For gunzip (used with tar.gz) -import * as tar from 'tar' // Library for tar extraction -import * as yauzl from 'yauzl' // Library for zip extraction -import { constants, createReadStream, createWriteStream } from 'node:fs' -import { throttle } from 'es-toolkit' -import { processGraph } from '@@/graph' -import { handleActionExecute } from './handler-func' -import { useLogger } from '@@/logger' -import { buildHistoryStorage } from './handlers/build-history' -import type { BuildHistoryEntry } from '@@/build-history' -import type { Variable } from '@pipelab/core-app' - -export const getFinalPlugins = () => { - const { plugins } = usePlugins() - // console.log('plugins.value', plugins.value) - - const finalPlugins: RendererPluginDefinition[] = [] - - for (const plugin of Object.values(plugins.value)) { - const finalNodes: RendererPluginDefinition['nodes'][number][] = [] - // console.log('/*') - // console.log('node', node.definition) - // console.log('node', JSON.stringify(node.definition, undefined, 2)) - // console.log('*/') - - // send without runner - for (const element of plugin.nodes) { - const { node } = element - finalNodes.push({ - node - }) - } - - finalPlugins.push({ - ...plugin, - nodes: finalNodes - }) - } - - return finalPlugins -} - -export const ensure = async (filesPath: string, defaultContent = '{}') => { - // create parent folder - await mkdir(dirname(filesPath), { - recursive: true - }) - - // ensure file exist - try { - await access(filesPath) - } catch { - // File doesn't exist, create it - await writeFile(filesPath, defaultContent) // json - } -} - -export const generateTempFolder = async (base = tmpdir()) => { - await mkdir(base, { - recursive: true - }) - const realPath = await realpath(base) - console.log('join', join(realPath, 'pipelab-')) - const tempFolder = await mkdtemp(join(realPath, 'pipelab-')) - - return tempFolder -} - -/** - * Extracts a .tar.gz archive. - * @param archivePath The full path to the .tar.gz file. - * @param destinationDir The directory to extract contents into. - * @returns A Promise that resolves when extraction is complete. - */ -export async function extractTarGz(archivePath: string, destinationDir: string): Promise { - console.log(`Extracting ${archivePath} to ${destinationDir}...`) - - // Ensure the destination directory exists - await mkdir(destinationDir, { recursive: true }) - - return new Promise((resolve, reject) => { - const readStream = createReadStream(archivePath) // Use sync version for createReadStream - const gunzipStream = zlib.createGunzip() - // Use tar.extract with cwd and strip=1 to extract contents directly into destinationDir - // stripping the top-level directory typically found in node tarballs (e.g., node-vX.Y.Z-...) - const extractStream = tar.extract({ cwd: destinationDir, strip: 1 }) - - readStream.on('error', reject) - gunzipStream.on('error', reject) - extractStream.on('error', reject) - - // tar.extract emits 'close' when extraction is finished - extractStream.on('close', () => { - console.log('Extraction finished.') - resolve() - }) - - readStream.pipe(gunzipStream).pipe(extractStream) - }) -} - -/** - * Extracts a .zip archive. - * @param archivePath The full path to the .zip file. - * @param destinationDir The directory to extract contents into. - * @returns A Promise that resolves when extraction is complete. - */ -export async function extractZip(archivePath: string, destinationDir: string): Promise { - console.log(`Extracting ${archivePath} to ${destinationDir}...`) - - // Ensure the destination directory exists - await mkdir(destinationDir, { recursive: true }) - - return new Promise((resolve, reject) => { - yauzl.open(archivePath, { lazyEntries: true }, (err, zipfile) => { - if (err || !zipfile) { - return reject(err || new Error('Could not open zip file')) - } - - zipfile.on('error', reject) - - zipfile.readEntry() // Start reading entries - - zipfile.on('entry', (entry) => { - // Skip directories unless they end with a slash - // Note: yauzl entries for directories typically end with '/'. - if (/\/$/.test(entry.fileName)) { - mkdir(join(destinationDir, entry.fileName), { recursive: true }) - .then(() => { - zipfile.readEntry() // Read next entry - }) - .catch(reject) - return - } - - // Strip the first path component (e.g., 'node-vX.Y.Z-...') - // Find the index of the first '/' to split the path - const firstSlashIndex = entry.fileName.indexOf('/') - const strippedFileName = - firstSlashIndex === -1 - ? entry.fileName // No slash, use as is (less common for node archives) - : entry.fileName.substring(firstSlashIndex + 1) // Path after the first slash - - const entryPath = join(destinationDir, strippedFileName) - - // If it's a file, extract it - zipfile.openReadStream(entry, (err, readStream) => { - if (err || !readStream) { - return reject( - err || new Error(`Could not open read stream for entry: ${entry.fileName}`) - ) - } - - readStream.on('error', reject) - - // Ensure parent directory exists before writing - mkdir(dirname(entryPath), { recursive: true }) - .then(() => { - const writeStream = createWriteStream(entryPath) // Use sync version for createWriteStream - writeStream.on('error', reject) - writeStream.on('finish', () => { - zipfile.readEntry() // Read next entry after file is written - }) - readStream.pipe(writeStream) - }) - .catch(reject) - }) - }) - - zipfile.on('end', () => { - console.log('Extraction finished.') - resolve() - }) - }) - }) -} - -/** - * Ensures a specific version of Node.js is downloaded and extracted to a user-specific directory. - * Uses the provided downloadFile function and handles platform-specific archives (.zip, .tar.gz). - * - * @param version The desired Node.js version (e.g., '18.17.1'). - * @param downloadOptions Options passed to the downloadFile function (e.g., { onProgress }). - * @param abortSignal An AbortSignal to cancel the download and extraction. - * @returns A Promise that resolves with the absolute path to the Node.js executable. - */ -export const ensureNodeJS = async ( - downloadOptions?: Hooks, - abortSignal?: AbortSignal -): Promise => { - const version = '22.14.0' - const userData = app.getPath('userData') - const baseDestinationDir = join(userData, 'thirdparty', 'node') - // Create a version-specific directory for extraction - const versionedDir = join(baseDestinationDir, `v${version}`) - // Determine the expected path of the node executable *after* extraction - // Standard Node.js archives structure, after stripping the top-level dir: - // tar.gz (Linux/macOS): bin/node - // zip (Windows): node.exe - const nodeBinRelative = process.platform === 'win32' ? 'node.exe' : join('bin', 'node') - const finalNodePath = join(versionedDir, nodeBinRelative) - console.log(`Checking for Node.js ${version} executable at ${finalNodePath}...`) - // 1. Check if the final executable already exists and is accessible - try { - // Use fs.access with fsSync.constants.X_OK to check for existence and execute permission - await access(finalNodePath, constants.X_OK) - console.log(`Node.js ${version} found at ${finalNodePath}. Using existing installation.`) - return finalNodePath // Found it, return the path - } catch (e: any) { - if (e.code !== 'ENOENT' && e.code !== 'EACCES') { - // Re-throw unexpected errors other than not found or permission denied - throw new Error(`Error checking for existing Node.js installation: ${e.message}`) - } - // If ENOENT (not found) or EACCES (permission denied), proceed with download/extraction - console.log( - `Node.js ${version} not found or not executable at ${finalNodePath}. Proceeding with download/extraction.` - ) - } - // 2. If not found, determine download details - const platform = process.platform === 'win32' ? 'win' : process.platform - // Note: process.arch gives 'x64', 'ia32', 'arm', 'arm64'. These match Node.js distribution names. - const arch = process.arch - const fileExtension = platform === 'win' ? 'zip' : 'tar.gz' - const fileName = `node-v${version}-${platform}-${arch}.${fileExtension}` - const url = `https://nodejs.org/dist/v${version}/${fileName}` - // The downloaded archive will live temporarily in the base directory - const archivePath = join(baseDestinationDir, fileName) - // 3. Ensure the base destination directory exists for the archive - await mkdir(baseDestinationDir, { recursive: true }) - // 4. Download the archive using the provided downloadFile function - console.log(`Attempting to download Node.js ${version} for ${platform}-${arch} from ${url}...`) - try { - // Assuming downloadFile is available and matches the signature - await downloadFile(url, archivePath, downloadOptions, abortSignal) - console.log('Node.js archive downloaded successfully.') - } catch (error: any) { - // Attempt to clean up the incomplete file if download failed - try { - await unlink(archivePath) - } catch {} // Ignore cleanup errors - throw new Error(`Failed to download Node.js archive from ${url}: ${error.message}`) - } - // Check if the operation was aborted after download - if (abortSignal?.aborted) { - console.log('Download aborted after completion.') - // Attempt to clean up the downloaded archive - try { - await unlink(archivePath) - } catch {} // Ignore cleanup errors - throw new Error('Download aborted') - } - // 5. Ensure the versioned extraction directory exists (and is clean if needed) - // It's safer to remove the directory first if it exists from a previous failed attempt - try { - await rm(versionedDir, { recursive: true, force: true }) - console.log(`Cleaned up potential previous extraction directory: ${versionedDir}`) - } catch (e: any) { - // Ignore errors if the directory didn't exist or couldn't be removed for benign reasons - if (e.code !== 'ENOENT') { - console.warn(`Failed to clean up ${versionedDir}: ${e.message}`) - } - } - await mkdir(versionedDir, { recursive: true }) - // 6. Extract the archive - try { - if (fileExtension === 'zip') { - await extractZip(archivePath, versionedDir) - } else { - // tar.gz - await extractTarGz(archivePath, versionedDir) - } - console.log('Node.js archive extracted successfully.') - } catch (error: any) { - // Attempt to clean up the failed extraction directory and the downloaded archive - try { - await rm(versionedDir, { recursive: true, force: true }) - } catch {} // Ignore cleanup errors - try { - await unlink(archivePath) - } catch {} // Ignore cleanup errors - throw new Error(`Failed to extract Node.js archive ${archivePath}: ${error.message}`) - } - // Check if the operation was aborted after extraction - if (abortSignal?.aborted) { - console.log('Extraction aborted after completion.') - // Attempt to clean up the extracted directory and the downloaded archive (archive might already be gone) - try { - await rm(versionedDir, { recursive: true, force: true }) - } catch {} // Ignore cleanup errors - try { - await unlink(archivePath) - } catch {} // Ignore cleanup errors - throw new Error('Extraction aborted') - } - // 7. Clean up the downloaded archive file - try { - await unlink(archivePath) - console.log(`Removed downloaded archive: ${archivePath}`) - } catch (e: any) { - console.warn(`Failed to remove downloaded archive ${archivePath}: ${e.message}`) - // Don't fail the whole function because cleanup failed - } - // 8. Set execute permissions on the executable for non-Windows platforms - if (process.platform !== 'win32') { - try { - console.log(`Setting permissions on ${finalNodePath}`) - await chmod(finalNodePath, 0o755) // rwxr-xr-x - console.log('Permissions set successfully.') - } catch (e: any) { - console.warn(`Failed to set executable permissions on ${finalNodePath}: ${e.message}`) - // This might cause issues later, but don't fail the *download/extract* process - } - } - // 9. Final check: Verify the executable exists and is accessible after extraction - try { - await access(finalNodePath, constants.X_OK) // Check existence and executability - console.log(`Node.js ${version} successfully installed and verified at ${finalNodePath}`) - return finalNodePath // Success, return the path - } catch (e: any) { - // This should ideally not happen if extraction was reported as successful and chmod ran - throw new Error( - `Node.js executable not found or not executable after extraction at ${finalNodePath}. Extraction might have completed with errors or the directory structure is unexpected.` - ) - } -} - -export const zipFolder = async (from: string, to: string, log: typeof console.log) => { - const archiver = await import('archiver') - - const { createWriteStream } = await import('node:fs') - - const output = createWriteStream(to) - // const input = createReadStream(from); - - const archive = archiver.default('zip', { - zlib: { level: 9 } // Sets the compression level. - }) - - // eslint-disable-next-line no-async-promise-executor - return new Promise(async (resolve, reject) => { - // listen for all archive data to be written - // 'close' event is fired only when a file descriptor is involved - output.on('close', function () { - log(archive.pointer() + ' total bytes') - log('archiver has been finalized and the output file descriptor has closed.') - return resolve(to) - }) - - // This event is fired when the data source is drained no matter what was the data source. - // It is not part of this library but rather from the NodeJS Stream API. - // @see: https://nodejs.org/api/stream.html#stream_event_end - output.on('end', function () { - log('Data has been drained') - }) - - const trottledLog = throttle((text: string) => { - log(text) - }, 500) - - archive.on('progress', (progress: any) => { - trottledLog(`Progress: ${progress.entries.processed} / ${progress.entries.total} files`) - }) - - // archive.on("entry", (entry) => { - // log("entry", entry); - // }) - - // good practice to catch warnings (ie stat failures and other non-blocking errors) - archive.on('warning', function (err: Error) { - log('warning', err) - }) - - // good practice to catch this error explicitly - archive.on('error', function (err: Error) { - reject(err) - }) - - archive.pipe(output) - - // // Find all files in the source directory - // const files = await glob("**/*", { - // cwd: from, - // nodir: true, - // dot: true, - // }); - - // console.log('files', files) - - // // Add each file to the archive - // for (const file of files) { - // const filePath = resolvePath(from, file); - // const relativePath = relative(from, filePath); - // archive.file(filePath, { name: relativePath }); - // } - - archive.directory(from, false) - - log('from', from) - log('to', to) - archive.finalize() - }) -} - -// @ts-expect-error import.meta -const isCI = process.env.CI === 'true' || import.meta.env.CI === 'true' - -export interface GraphExecutionOptions { - /** The graph nodes to execute */ - graph: any[] - /** Variables for the execution */ - variables: Variable[] - /** Project information */ - projectName?: string - projectPath?: string - /** Main window for action execution */ - mainWindow?: BrowserWindow - /** Logger function for node events */ - onNodeEnter?: (node: any) => void - onNodeExit?: (node: any) => void - /** Log handler function */ - onLog?: (data: any, node?: any) => void - /** Abort signal for cancellation */ - abortSignal?: AbortSignal - /** Optional output file path for CLI usage */ - outputPath?: string - pipelineId?: string -} - -/** - * Unified function for executing processGraph with build history tracking - * Used by both CLI (main.ts) and IPC handler (handlers.ts) implementations - */ -export const executeGraphWithHistory = async (options: GraphExecutionOptions) => { - const { logger } = useLogger() - const { - graph, - variables, - projectName, - projectPath, - mainWindow, - onNodeEnter, - onNodeExit, - onLog, - abortSignal, - outputPath, - pipelineId - } = options - - console.log('options', options) - - // Create build history entry for this pipeline execution - const buildId = `build-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` - const buildEntry: BuildHistoryEntry = { - id: buildId, - pipelineId: pipelineId, - projectName: projectName || 'Unnamed Pipeline', - projectPath: projectPath || 'unknown', - status: 'running', - startTime: Date.now(), - steps: [], - totalSteps: graph.length, - completedSteps: 0, - failedSteps: 0, - cancelledSteps: 0, - logs: [], - createdAt: Date.now(), - updatedAt: Date.now() - } - - // Save initial build history entry - try { - await buildHistoryStorage.save(buildEntry) - logger().info(`Build history entry created: ${buildId}`) - } catch (error) { - logger().error('Failed to save initial build history entry:', error) - } - - try { - const pluginDefinitions = getFinalPlugins() - - const result = await processGraph({ - graph, - definitions: pluginDefinitions, - variables, - steps: {}, - context: {}, - abortSignal, - onNodeEnter: (node) => { - logger().info('onNodeEnter', node.uid) - onNodeEnter?.(node) - }, - onNodeExit: (node) => { - logger().info('onNodeExit', node.uid) - onNodeExit?.(node) - }, - onExecuteItem: (node, params) => { - if (node.type === 'action') { - return handleActionExecute( - node.origin.nodeId, - node.origin.pluginId, - params, - mainWindow, - async (data) => { - if (!isCI) { - logger().info('send', data) - } - onLog?.(data, node) - }, - abortSignal || new AbortController().signal - ) - } else { - throw new Error('Unhandled type ' + node.type) - } - } - }) - - // Update build history entry as completed - buildEntry.status = 'completed' - buildEntry.endTime = Date.now() - buildEntry.duration = buildEntry.endTime - buildEntry.startTime - buildEntry.completedSteps = graph.length - buildEntry.updatedAt = Date.now() - - await buildHistoryStorage.save(buildEntry) - logger().info(`Build history entry updated as completed: ${buildId}`) - - // Handle output file for CLI usage - if (outputPath) { - const fs = await import('fs/promises') - await fs.writeFile(outputPath, JSON.stringify(result, null, 2), 'utf8') - } - - return { result, buildId } - } catch (e) { - buildEntry.endTime = Date.now() - buildEntry.duration = buildEntry.endTime - buildEntry.startTime - buildEntry.updatedAt = Date.now() - - console.log('aaaaa e', e) - - // Check if the error is due to user cancellation (AbortError) - if (e instanceof Error && e.name === 'AbortError') { - // Update build history entry as cancelled - buildEntry.status = 'cancelled' - buildEntry.error = { - message: 'Build canceled by user', - timestamp: Date.now() - } - logger().info(`Build history entry updated as cancelled: ${buildId}`) - } else { - // Update build history entry as failed - buildEntry.status = 'failed' - buildEntry.error = { - message: e instanceof Error ? e.message : 'Unknown error', - timestamp: Date.now() - } - logger().info(`Build history entry updated as failed: ${buildId}`) - } - - await buildHistoryStorage.save(buildEntry) - - // Handle error output file for CLI usage - if (outputPath) { - const fs = await import('fs/promises') - await fs.writeFile( - outputPath, - JSON.stringify({ error: (e as Error).message }, null, 2), - 'utf8' - ) - } - - throw e - } -} diff --git a/src/main/websocket-server.ts b/src/main/websocket-server.ts deleted file mode 100644 index 38249be8..00000000 --- a/src/main/websocket-server.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { WebSocketServer as WSWebSocketServer, WebSocket as WSWebSocket } from 'ws' -import { IncomingMessage } from 'http' -import { useAPI } from './handlers' -import { useLogger } from '@@/logger' -import { - WebSocketServerConfig, - WebSocketServerEvents, - WebSocketConnectionState, - WebSocketError, - WebSocketMessage, - isWebSocketRequestMessage -} from '@@/websocket.types' -import { websocketPort } from 'src/constants' - -export class WebSocketServer { - private wss: WSWebSocketServer | null = null - private server: import('http').Server | null = null - private isReady = false - private readyResolve: (() => void) | null = null - private connectionState: WebSocketConnectionState = 'disconnected' - - async start(port: number = websocketPort): Promise { - const { logger } = useLogger() - - return new Promise((resolve, reject) => { - try { - logger().info('Starting WebSocket server on port', port) - - // Create HTTP server for WebSocket - const http = require('http') - this.server = http.createServer() - - // Create WebSocket server - this.wss = new WSWebSocketServer({ server: this.server }) - - this.wss.on('connection', (ws: WSWebSocket, request: IncomingMessage) => { - logger().info('WebSocket client connected', { url: request.url }) - - ws.on('message', (data: Buffer) => { - try { - const message = JSON.parse(data.toString()) - logger().debug('Received WebSocket message:', message) - this.handleWebSocketMessage(ws, message) - } catch (error) { - logger().error('Failed to parse WebSocket message:', error) - this.sendError(ws, undefined, 'Invalid message format') - } - }) - - ws.on('close', (code: number, reason: Buffer) => { - logger().info('WebSocket client disconnected', { code, reason: reason.toString() }) - }) - - ws.on('error', (error: Error) => { - logger().error('WebSocket error:', error) - }) - }) - - this.server.listen(port, () => { - this.connectionState = 'connected' - logger().info(`WebSocket server listening on port ${port}`) - this.isReady = true - if (this.readyResolve) { - this.readyResolve() - } - resolve() - }) - - this.server.on('error', (error: Error) => { - this.connectionState = 'error' - logger().error('WebSocket server error:', error) - reject(new WebSocketError(`Server error: ${error.message}`)) - }) - } catch (error) { - this.connectionState = 'error' - logger().error('Failed to start WebSocket server:', error) - reject( - new WebSocketError( - `Failed to start server: ${error instanceof Error ? error.message : 'Unknown error'}` - ) - ) - } - }) - } - - private async handleWebSocketMessage(ws: WSWebSocket, message: WebSocketMessage) { - const { logger } = useLogger() - const { processWebSocketMessage } = useAPI() - - try { - if (isWebSocketRequestMessage(message)) { - logger().debug('Processing WebSocket request message:', { - channel: message.channel, - requestId: message.requestId, - hasData: !!message.data - }) - - logger().debug('Routing message to handler:', message.channel) - await processWebSocketMessage(ws, message.channel, message) - logger().debug('Handler processed message successfully') - } else { - logger().warn('Invalid message format received:', { - type: message.type, - requestId: message.requestId, - hasError: 'error' in message - }) - this.sendError( - ws, - message.requestId, - 'Invalid message format: missing channel or requestId' - ) - } - } catch (error) { - logger().error('Error processing WebSocket message:', error) - this.sendError( - ws, - message.requestId, - error instanceof Error ? error.message : 'Unknown error' - ) - } - } - - private sendError( - ws: WSWebSocket, - requestId: string | undefined, - errorMessage: string, - code?: string - ) { - try { - const errorResponse: any = { - type: 'error', - requestId, - error: errorMessage, - ...(code && { code }) - } - ws.send(JSON.stringify(errorResponse)) - } catch (error) { - console.error('Failed to send error response:', error) - } - } - - async stop(): Promise { - const { logger } = useLogger() - - return new Promise((resolve) => { - this.isReady = false - this.connectionState = 'disconnected' - - if (this.wss) { - this.wss.close(() => { - logger().info('WebSocket server closed') - resolve() - }) - } else { - resolve() - } - - if (this.server) { - this.server.close() - } - }) - } - - waitForReady(): Promise { - if (this.isReady) { - return Promise.resolve() - } - - return new Promise((resolve) => { - this.readyResolve = resolve - }) - } - - isServerReady(): boolean { - return this.isReady - } - - getConnectionState(): WebSocketConnectionState { - return this.connectionState - } -} - -// Export singleton instance -export const webSocketServer = new WebSocketServer() diff --git a/src/preload.d.ts b/src/preload.d.ts deleted file mode 100644 index a1536695..00000000 --- a/src/preload.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ElectronAPI } from '@electron-toolkit/preload' - -declare global { - interface Window { - electron: ElectronAPI - api: unknown - } -} diff --git a/src/preload.ts b/src/preload.ts deleted file mode 100644 index d6e7d97e..00000000 --- a/src/preload.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { contextBridge } from 'electron' -import { electronAPI } from '@electron-toolkit/preload' -import { version } from '../package.json' - -// Custom APIs for renderer -const api = {} - -// TODO: unify window and contextBridge - -// Use `contextBridge` APIs to expose Electron APIs to -// renderer only if context isolation is enabled, otherwise -// just add to the DOM global. -if (process.contextIsolated) { - // @ts-expect-error import.meta - const isCI = process.env.CI === 'true' || import.meta.env.CI === 'true' - - try { - contextBridge.exposeInMainWorld('electron', electronAPI) - contextBridge.exposeInMainWorld('api', api) - contextBridge.exposeInMainWorld('version', version) - contextBridge.exposeInMainWorld('isPackaged', process.env.NODE_ENV !== 'development') - contextBridge.exposeInMainWorld('isTest', process.env.TEST === 'true') - contextBridge.exposeInMainWorld('isCI', isCI) - // eslint-disable-next-line no-console - console.log('process.env.NODE_ENV', process.env.NODE_ENV) - // contextBridge.exposeInMainWorld('_dirname', __dirname) - } catch (error) {} -} else { - window.electron = electronAPI - window.api = api - window.version = version - window.isPackaged = process.env.NODE_ENV !== 'development' - window.isTest = process.env.TEST === 'true' - // window.__dirname = __dirname -} diff --git a/src/renderer.ts b/src/renderer.ts deleted file mode 100644 index 714acd00..00000000 --- a/src/renderer.ts +++ /dev/null @@ -1 +0,0 @@ -import './renderer/main' diff --git a/src/renderer/App.vue b/src/renderer/App.vue deleted file mode 100644 index c795210e..00000000 --- a/src/renderer/App.vue +++ /dev/null @@ -1,255 +0,0 @@ - - - - - diff --git a/src/renderer/agent/utils/json.ts b/src/renderer/agent/utils/json.ts deleted file mode 100644 index 5a8ff6d7..00000000 --- a/src/renderer/agent/utils/json.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const safeParse = (str: string): T | undefined => { - try { - return JSON.parse(str); - } catch (e) { - return undefined - } -} \ No newline at end of file diff --git a/src/renderer/components/AddNodeButton.model.ts b/src/renderer/components/AddNodeButton.model.ts deleted file mode 100644 index bcce6836..00000000 --- a/src/renderer/components/AddNodeButton.model.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { PipelabNode, Event, RendererPluginDefinition } from '../../shared/libs/plugin-core' - -export interface AddNodeEvent { - node: PipelabNode - plugin: RendererPluginDefinition - path: string[] - insertAt: number -} - -export interface AddTriggerEvent { - trigger: Event - plugin: RendererPluginDefinition - path: string[] - insertAt: number -} diff --git a/src/renderer/components/AddNodeButton.vue b/src/renderer/components/AddNodeButton.vue deleted file mode 100644 index 58aaa699..00000000 --- a/src/renderer/components/AddNodeButton.vue +++ /dev/null @@ -1,463 +0,0 @@ - - - - - diff --git a/src/renderer/components/BuildDetailsModal.vue b/src/renderer/components/BuildDetailsModal.vue deleted file mode 100644 index 3338c0da..00000000 --- a/src/renderer/components/BuildDetailsModal.vue +++ /dev/null @@ -1,634 +0,0 @@ - - - - - diff --git a/src/renderer/components/BuildHistoryItem.vue b/src/renderer/components/BuildHistoryItem.vue deleted file mode 100644 index a461e315..00000000 --- a/src/renderer/components/BuildHistoryItem.vue +++ /dev/null @@ -1,464 +0,0 @@ - - - - - diff --git a/src/renderer/components/FileInput.vue b/src/renderer/components/FileInput.vue deleted file mode 100644 index 3a57f9db..00000000 --- a/src/renderer/components/FileInput.vue +++ /dev/null @@ -1,83 +0,0 @@ - - - - - diff --git a/src/renderer/components/Layout.vue b/src/renderer/components/Layout.vue deleted file mode 100644 index b03bb937..00000000 --- a/src/renderer/components/Layout.vue +++ /dev/null @@ -1,661 +0,0 @@ - - - - - diff --git a/src/renderer/components/ScenarioListItemFile.vue b/src/renderer/components/ScenarioListItemFile.vue deleted file mode 100644 index 452c01df..00000000 --- a/src/renderer/components/ScenarioListItemFile.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - - - diff --git a/src/renderer/components/Settings.vue b/src/renderer/components/Settings.vue deleted file mode 100644 index 5df85fae..00000000 --- a/src/renderer/components/Settings.vue +++ /dev/null @@ -1,547 +0,0 @@ - - - - - diff --git a/src/renderer/components/nodes/EditorNodeCondition.vue b/src/renderer/components/nodes/EditorNodeCondition.vue deleted file mode 100644 index a4c09443..00000000 --- a/src/renderer/components/nodes/EditorNodeCondition.vue +++ /dev/null @@ -1,255 +0,0 @@ - - - - - diff --git a/src/renderer/components/nodes/EditorNodeLoop.vue b/src/renderer/components/nodes/EditorNodeLoop.vue deleted file mode 100644 index f300e309..00000000 --- a/src/renderer/components/nodes/EditorNodeLoop.vue +++ /dev/null @@ -1,222 +0,0 @@ - - - - - diff --git a/src/renderer/composables/api.ts b/src/renderer/composables/api.ts deleted file mode 100644 index 53f90072..00000000 --- a/src/renderer/composables/api.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Channels, Data, End, Events } from '@@/apis' -import { useLogger } from '@@/logger' -import { useWebSocketAPI } from './websocket-client' -import { WebSocketListener } from '@@/websocket.types' - -// Re-export for backwards compatibility -export type { WebSocketListener } - -export const useAPI = () => { - const { logger } = useLogger() - const { execute: wsExecute, isConnected } = useWebSocketAPI() - - /** - * Send an order and wait for its execution - */ - const execute = async ( - channel: KEY, - data?: Data, - listener?: WebSocketListener - ): Promise> => { - try { - const result = await wsExecute(channel, data, listener) - - return result - } catch (error) { - logger().error('API execution error:', error) - throw error - } - } - - /** - * Send an order (for backwards compatibility) - */ - const send = (channel: KEY, data?: Data) => { - logger().warn('useAPI.send() is deprecated. Use useAPI.execute() instead.') - return execute(channel, data) - } - - /** - * On method (placeholder for backwards compatibility) - */ - const on = ( - channel: KEY | string, - listener: (event: any, data: Events) => void - ) => { - logger().warn('useAPI.on() is not supported in WebSocket mode. Use useAPI.execute() instead.') - // Return a no-op function for backwards compatibility - return () => {} - } - - return { - send, - on, - execute, - isConnected - } -} - -export type UseAPI = ReturnType diff --git a/src/renderer/composables/usePipeline.ts b/src/renderer/composables/usePipeline.ts deleted file mode 100644 index fc5aad26..00000000 --- a/src/renderer/composables/usePipeline.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { EnhancedFile, SavedFileDefault, SavedFileSimple } from '@@/model' -import { AppStore, useAppStore } from '@renderer/store/app' - -export function isSimplePipeline( - pipeline: EnhancedFile -): pipeline is EnhancedFile { - return pipeline.content.type === 'simple' -} - -export function isDefaultPipeline( - pipeline: EnhancedFile -): pipeline is EnhancedFile { - return pipeline.content.type === 'default' -} - -export const usePipeline = () => { - const appStore = useAppStore() - const { getPluginDefinition } = appStore - - const context: Context = { - getPluginDefinition - } - - function createPipeline(pipeline: EnhancedFile) { - if (isSimplePipeline(pipeline)) { - return useSimplePipeline(pipeline, context) - } else if (isDefaultPipeline(pipeline)) { - return useDefaultPipeline(pipeline, context) - } else { - throw new Error('Invalid pipeline type' + pipeline.content.type) - } - } - - return { - createPipeline - } -} - -interface UsePipeline { - getIcons: () => any[] -} - -interface Context { - getPluginDefinition: AppStore['getPluginDefinition'] -} - -export const useSimplePipeline = ( - pipeline: EnhancedFile, - context: Context -): UsePipeline => { - return { - getIcons: () => [] - } -} - -export const useDefaultPipeline = ( - pipeline: EnhancedFile, - context: Context -): UsePipeline => { - const getIcons = () => { - const icons: any[] = [] - if (!pipeline?.content?.canvas?.blocks) return icons - const blocks = pipeline.content.canvas.blocks - for (const node of blocks) { - const def = context.getPluginDefinition(node.origin.pluginId) - if (def && def.icon) { - icons.push({ origin: node.origin, ...def.icon }) - } - } - if (icons.length > 4) { - return icons - .slice(0, 3) - .concat({ type: 'icon', icon: 'mdi-plus', origin: { nodeId: '0', pluginId: '0' } }) - } - return icons - } - - return { - getIcons - } -} diff --git a/src/renderer/composables/usePostHog.ts b/src/renderer/composables/usePostHog.ts deleted file mode 100644 index 8de3cca3..00000000 --- a/src/renderer/composables/usePostHog.ts +++ /dev/null @@ -1,9 +0,0 @@ -import posthog from 'posthog-js' - -export function usePostHog() { - posthog.init(__POSTHOG_API_KEY__, { - api_host: 'https://eu.i.posthog.com' - }) - - return { posthog } -} diff --git a/src/renderer/composables/useTour.ts b/src/renderer/composables/useTour.ts deleted file mode 100644 index d082d503..00000000 --- a/src/renderer/composables/useTour.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { driver, DriveStep } from 'driver.js' -import { useAppSettings } from '@renderer/store/settings' -import { storeToRefs } from 'pinia' - -export function useTour(tourId: 'dashboard' | 'editor') { - const settingsStore = useAppSettings() - const { settings } = storeToRefs(settingsStore) - const { updateSettings } = settingsStore - - const startTour = (steps: DriveStep[], force = false) => { - const d = driver({ - showProgress: true, - steps: steps, - onHighlighted: (element, step, { state }) => { - const tours = { ...settings.value.tours } - tours[tourId] = { - step: state.activeIndex, - completed: state.activeIndex === steps.length - 1 - } - - updateSettings({ - ...settings.value, - tours - }) - } - }) - - const currentStep = settings.value.tours[tourId]?.step ?? 0 - d.drive(force ? 0 : currentStep) - } - - return { - startTour, - isCompleted: () => settings.value.tours[tourId]?.completed ?? false - } -} diff --git a/src/renderer/composables/variables.ts b/src/renderer/composables/variables.ts deleted file mode 100644 index b43e0a2f..00000000 --- a/src/renderer/composables/variables.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Variable } from '@@/libs/core-app' -import { CreateQuickJSFn } from '@renderer/utils/quickjs' - -export const variableToFormattedVariable = async ( - vm: Awaited, - variables: Variable[] -) => { - const result: Record = {} - for (const variable of variables) { - console.log('variable.value', variable.value) - const variableResult = await vm.run(variable.value, { - params: {} - }) - - result[variable.id] = variableResult - // result[variable.id] = variable.value - } - return result -} diff --git a/src/renderer/composables/websocket-client.ts b/src/renderer/composables/websocket-client.ts deleted file mode 100644 index 19d2be2f..00000000 --- a/src/renderer/composables/websocket-client.ts +++ /dev/null @@ -1,369 +0,0 @@ -import { Channels, Data, End, RequestId } from '@@/apis' -import { useLogger } from '@@/logger' -import { klona } from 'klona' -import { nanoid } from 'nanoid' -import { toRaw } from 'vue' -import { - WebSocketSendFunction, - WebSocketClientConfig, - WebSocketConnectionState, - WebSocketError, - WebSocketConnectionError, - WebSocketMessage, - isWebSocketRequestMessage, - isWebSocketResponseMessage, - isWebSocketErrorMessage -} from '@@/websocket.types' -import { websocketPort } from 'src/constants' - -export type WebSocketSendFn = WebSocketSendFunction - -// Message queue item interface -interface QueuedMessage { - channel: Channels - data?: any - resolve: (value: any) => void - reject: (reason: any) => void - requestId: RequestId - listener?: (event: any) => void -} - - -export class WebSocketClient { - private ws: WebSocket | null = null - private listeners: Map void> = new Map() - private reconnectAttempts = 0 - private maxReconnectAttempts = 5 - private reconnectDelay = 1000 - private isConnecting = false - private connectionState: WebSocketConnectionState = 'disconnected' - private stateChangeListeners: Set<(state: WebSocketConnectionState) => void> = new Set() - private messageQueue: QueuedMessage[] = [] - - constructor(private config: WebSocketClientConfig = {}) { - const { - url = `ws://localhost:${websocketPort}`, - maxReconnectAttempts = 5, - reconnectDelay = 1000 - } = config - this.maxReconnectAttempts = maxReconnectAttempts - this.reconnectDelay = reconnectDelay - this.connect(url) - } - - private connect(url?: string) { - if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) { - return - } - - this.isConnecting = true - this.connectionState = 'connecting' - this.notifyStateChange() - - try { - const connectionUrl = url || this.config.url || `ws://localhost:${websocketPort}` - this.ws = new WebSocket(connectionUrl) - - this.ws.onopen = () => { - console.log('WebSocket connected') - this.isConnecting = false - this.reconnectAttempts = 0 - this.connectionState = 'connected' - this.notifyStateChange() - - const { logger } = useLogger() - logger().debug('WebSocket client connected successfully') - - // Flush any queued messages now that connection is ready - this.flushQueue() - } - - this.ws.onmessage = (event) => { - this.handleMessage(event) - } - - this.ws.onclose = (event) => { - console.log('WebSocket disconnected', { code: event.code, reason: event.reason }) - this.isConnecting = false - this.connectionState = 'disconnected' - this.notifyStateChange() - - this.scheduleReconnect() - } - - this.ws.onerror = (error) => { - console.error('WebSocket error:', error) - this.isConnecting = false - this.connectionState = 'error' - this.notifyStateChange() - } - } catch (error) { - console.error('Failed to create WebSocket connection:', error) - this.isConnecting = false - this.connectionState = 'error' - this.notifyStateChange() - this.scheduleReconnect() - } - } - - private notifyStateChange() { - this.stateChangeListeners.forEach((listener) => { - try { - listener(this.connectionState) - } catch (error) { - console.error('Error in state change listener:', error) - } - }) - } - - private scheduleReconnect() { - if (this.reconnectAttempts >= this.maxReconnectAttempts) { - console.error('Max reconnection attempts reached') - this.clearQueue() - return - } - - this.reconnectAttempts++ - const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1) // Exponential backoff - - setTimeout(() => { - console.log( - `Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})` - ) - this.connect() - }, delay) - } - - private handleMessage(event: MessageEvent) { - try { - const message: WebSocketMessage = JSON.parse(event.data) - - if (isWebSocketResponseMessage(message) || isWebSocketErrorMessage(message)) { - if (this.listeners.has(message.requestId)) { - this.listeners.get(message.requestId)!(message) - } - } else if (isWebSocketRequestMessage(message)) { - // Handle incoming request messages if needed - console.log('Received request message:', message) - } - } catch (error) { - console.error('Failed to parse WebSocket message:', error) - } - } - - public send( - channel: KEY, - data?: Data, - listener?: (event: any) => void - ): Promise> { - return new Promise((resolve, reject) => { - const { logger } = useLogger() - - // If connection is not ready, queue the message - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { - logger().debug('WebSocket not ready, queuing message:', { channel, hasData: !!data }) - - const requestId = nanoid() as RequestId - this.messageQueue.push({ - channel, - data: toRaw(klona(data)), - resolve, - reject, - requestId, - listener - }) - - return - } - - // Connection is ready, send immediately - this.sendMessage(channel, data, resolve, reject, listener) - }) - } - - private sendMessage( - channel: KEY, - data: Data | undefined, - resolve: (value: End) => void, - reject: (reason: any) => void, - listener?: (event: any) => void - ): void { - const { logger } = useLogger() - - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { - logger().error('WebSocket send failed: connection not open') - reject(new WebSocketConnectionError('WebSocket is not connected')) - return - } - - const requestId = nanoid() as RequestId - const message: WebSocketMessage = { - channel, - requestId, - data: toRaw(klona(data)) - } - - logger().debug('Sending WebSocket message:', { - channel, - requestId, - hasData: !!data - }) - - - this.listeners.set(requestId, (response: WebSocketMessage) => { - if (isWebSocketErrorMessage(response)) { - // Handle error messages immediately - this.listeners.delete(requestId) - reject(new WebSocketError(response.error, response.code, response.requestId)) - } else if (isWebSocketResponseMessage(response)) { - // Handle the response events - const endEvent = response.events - - if (endEvent.type === 'end') { - // Only resolve and cleanup when we receive the final 'end' message - this.listeners.delete(requestId) - resolve(endEvent.data) - } else { - // Handle intermediate events - call the provided listener if available - if (listener) { - listener(endEvent) - } else { - logger().info('Received intermediate event:', { - requestId, - eventType: endEvent.type, - hasData: !!endEvent.data - }) - } - } - } - }) - - try { - this.ws.send(JSON.stringify(message)) - } catch (error) { - this.listeners.delete(requestId) - reject( - new WebSocketError( - `Failed to send message: ${error instanceof Error ? error.message : 'Unknown error'}` - ) - ) - } - } - - private flushQueue(): void { - const { logger } = useLogger() - - if (this.messageQueue.length === 0) { - return - } - - logger().debug(`Flushing ${this.messageQueue.length} queued messages`) - - // Create a copy of the queue and clear it - const queuedMessages = [...this.messageQueue] - this.messageQueue = [] - - // Send all queued messages - for (const queuedMessage of queuedMessages) { - this.sendMessage( - queuedMessage.channel, - queuedMessage.data, - queuedMessage.resolve, - queuedMessage.reject, - queuedMessage.listener - ) - } - } - - private clearQueue(): void { - const { logger } = useLogger() - - if (this.messageQueue.length === 0) { - return - } - - logger().debug( - `Clearing ${this.messageQueue.length} queued messages due to connection error/disconnect` - ) - - // Reject all queued messages - for (const queuedMessage of this.messageQueue) { - queuedMessage.reject(new WebSocketConnectionError('WebSocket connection lost')) - } - - this.messageQueue = [] - } - - - public isConnected(): boolean { - return this.ws?.readyState === WebSocket.OPEN - } - - public disconnect() { - this.connectionState = 'disconnected' - this.notifyStateChange() - - // Clear any queued messages since we're disconnecting - this.clearQueue() - - if (this.ws) { - this.ws.close() - this.ws = null - } - this.listeners.clear() - this.reconnectAttempts = 0 - } - - public getConnectionState(): WebSocketConnectionState { - return this.connectionState - } - - public onStateChange(callback: (state: WebSocketConnectionState) => void): () => void { - this.stateChangeListeners.add(callback) - return () => { - this.stateChangeListeners.delete(callback) - } - } - - public reconnect(url?: string) { - this.disconnect() - this.connect(url) - } -} - -// Global WebSocket client instance -let wsClient: WebSocketClient | null = null - -export const getWebSocketClient = (): WebSocketClient => { - if (!wsClient) { - wsClient = new WebSocketClient() - } - return wsClient -} - -export const useWebSocketAPI = () => { - const { logger } = useLogger() - const client = getWebSocketClient() - - /** - * Send an order and wait for its execution - */ - const execute = async ( - channel: KEY, - data?: Data, - listener?: (event: any) => void - ): Promise> => { - try { - return await client.send(channel, data, listener) - } catch (error) { - logger().error('WebSocket API error:', error) - throw error - } - } - - return { - execute, - isConnected: client.isConnected(), - disconnect: client.disconnect.bind(client) - } -} diff --git a/src/renderer/composables/websocket-manager.ts b/src/renderer/composables/websocket-manager.ts deleted file mode 100644 index c1bd35d4..00000000 --- a/src/renderer/composables/websocket-manager.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { Channels, Data, End } from '@@/apis' -import { useLogger } from '@@/logger' -import { getWebSocketClient, WebSocketClient } from './websocket-client' -import { - WebSocketManager, - WebSocketConnectionState, - WebSocketClientConfig, - WebSocketError, - WebSocketConnectionError -} from '@@/websocket.types' - -class WebSocketManagerImpl implements WebSocketManager { - private client: WebSocketClient | null = null - private stateChangeListeners: Set<(state: WebSocketConnectionState) => void> = new Set() - private isInitialized = false - - async initialize(config?: WebSocketClientConfig): Promise { - if (this.isInitialized) { - return - } - - const { logger } = useLogger() - - try { - this.client = getWebSocketClient() - - // Set up state change listener - this.client.onStateChange((state) => { - this.stateChangeListeners.forEach((listener) => { - try { - listener(state) - } catch (error) { - logger().error('Error in WebSocket state change listener:', error) - } - }) - }) - - this.isInitialized = true - logger().info('WebSocket manager initialized') - } catch (error) { - logger().error('Failed to initialize WebSocket manager:', error) - throw new WebSocketConnectionError( - `Initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}` - ) - } - } - - async connect(url?: string): Promise { - if (!this.client) { - await this.initialize() - } - - if (!this.client) { - throw new WebSocketConnectionError('WebSocket client not available') - } - - const { logger } = useLogger() - - try { - if (url && this.client.isConnected()) { - this.client.disconnect() - } - - if (url) { - this.client.reconnect(url) - } else { - this.client.reconnect() - } - - logger().info('WebSocket connection initiated', { url }) - } catch (error) { - logger().error('Failed to connect WebSocket:', error) - throw error - } - } - - disconnect(): void { - if (this.client) { - this.client.disconnect() - } - } - - send(channel: KEY, data?: Data): Promise> { - if (!this.client) { - throw new WebSocketConnectionError('WebSocket client not initialized') - } - - if (!this.client.isConnected()) { - throw new WebSocketConnectionError('WebSocket is not connected') - } - - return this.client.send(channel, data) - } - - isConnected(): boolean { - return this.client?.isConnected() ?? false - } - - getConnectionState(): WebSocketConnectionState { - return this.client?.getConnectionState() ?? 'disconnected' - } - - onStateChange(callback: (state: WebSocketConnectionState) => void): () => void { - this.stateChangeListeners.add(callback) - return () => { - this.stateChangeListeners.delete(callback) - } - } - - getClient(): WebSocketClient | null { - return this.client - } - - async ensureConnection(url?: string): Promise { - const { logger } = useLogger() - - logger().debug('Ensuring WebSocket connection...', { - hasClient: !!this.client, - isConnected: this.client?.isConnected() ?? false, - targetUrl: url - }) - - if (!this.client) { - logger().debug('Initializing WebSocket client...') - await this.initialize() - } - - if (!this.client) { - throw new WebSocketConnectionError('WebSocket client not available') - } - - if (!this.client.isConnected()) { - logger().debug('Connecting WebSocket client...') - await this.connect(url) - logger().info('WebSocket connection established successfully') - } else { - logger().debug('WebSocket already connected') - } - } -} - -// Export singleton instance -export const websocketManager = new WebSocketManagerImpl() diff --git a/src/renderer/env.d.ts b/src/renderer/env.d.ts deleted file mode 100644 index aafef950..00000000 --- a/src/renderer/env.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -declare module '*.vue' { - import type { DefineComponent } from 'vue' - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types - const component: DefineComponent<{}, {}, any> - export default component -} diff --git a/src/renderer/i18n.ts b/src/renderer/i18n.ts deleted file mode 100644 index 0d8d979a..00000000 --- a/src/renderer/i18n.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MessageSchema, Locales, en_US, fr_FR, pt_BR, zh_CN, es_ES, de_DE } from '@@/i18n-utils' -import { createI18n } from 'vue-i18n' - -export const i18n = createI18n<[MessageSchema], Locales>({ - legacy: false, - locale: 'en-US', - fallbackLocale: 'en-US', - messages: { - 'en-US': en_US, - 'fr-FR': fr_FR as unknown as MessageSchema, - 'pt-BR': pt_BR as unknown as MessageSchema, - 'zh-CN': zh_CN as unknown as MessageSchema, - 'es-ES': es_ES as unknown as MessageSchema, - 'de-DE': de_DE as unknown as MessageSchema - } -}) diff --git a/src/renderer/main.ts b/src/renderer/main.ts deleted file mode 100644 index 54aa224c..00000000 --- a/src/renderer/main.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { createApp } from 'vue' -import Root from './Root.vue' -import { router } from './router/router' - -import { createPinia } from 'pinia' -import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' -import { createI18n } from 'vue-i18n' - -import PrimeVue from 'primevue/config' -import Lara from '@primevue/themes/lara' -import 'primeicons/primeicons.css' -import 'primeflex/primeflex.css' -import '@mdi/font/css/materialdesignicons.css' -import 'driver.js/dist/driver.css' -import { definePreset } from '@primevue/themes' -import './style/main.scss' -import VueDOMPurifyHTML from 'vue-dompurify-html' - -import { init } from '@sentry/electron/renderer' -import { breadcrumbsIntegration, init as vueInit } from '@sentry/vue' -import ToastService from 'primevue/toastservice' -import ConfirmationService from 'primevue/confirmationservice' -import posthogPlugin from './plugins/posthog' //import the plugin. -import posthog from 'posthog-js' -import { i18n } from './i18n' - -import { websocketManager } from './composables/websocket-manager' -import { useLogger } from '@@/logger' - -if (window.isPackaged && !window.isTest && !window.isCI) { - init( - { - dsn: 'https://757630879674735027fa5700162253f7@o45694.ingest.us.sentry.io/4507621723144192', - debug: true, - integrations: [ - breadcrumbsIntegration({ - console: false - }), - posthog.sentryIntegration({ - organization: 'armaldio', - projectId: 4507621723144192, - severityAllowList: ['error', 'info'] // optional: here is set to handle captureMessage (info) and captureException (error) - }) - ] - }, - vueInit - ) -} - -const pinia = createPinia() -pinia.use(piniaPluginPersistedstate) - -const PipelabPreset = definePreset(Lara, { - semantic: { - transitionDuration: '0.2s', - focusRing: { - width: '1px', - style: 'solid', - color: '{primary.color}', - offset: '2px', - shadow: 'none' - }, - disabledOpacity: '0.6', - iconSize: '1rem', - anchorGutter: '2px', - primary: { - 50: '{zinc.50}', - 100: '{zinc.100}', - 200: '{zinc.200}', - 300: '{zinc.300}', - 400: '{zinc.400}', - 500: '{zinc.500}', - 600: '{zinc.600}', - 700: '{zinc.700}', - 800: '{zinc.800}', - 900: '{zinc.900}', - 950: '{zinc.950}' - }, - colorScheme: { - light: { - primary: { - color: '{zinc.950}', - inverseColor: '#ffffff', - hoverColor: '{zinc.900}', - activeColor: '{zinc.800}' - }, - highlight: { - background: '{zinc.950}', - focusBackground: '{zinc.700}', - color: '#ffffff', - focusColor: '#ffffff' - } - }, - dark: { - primary: { - color: '{zinc.50}', - inverseColor: '{zinc.950}', - hoverColor: '{zinc.100}', - activeColor: '{zinc.200}' - }, - highlight: { - background: 'rgba(250, 250, 250, .16)', - focusBackground: 'rgba(250, 250, 250, .24)', - color: 'rgba(255,255,255,.87)', - focusColor: 'rgba(255,255,255,.87)' - } - } - } - } -}) - -// init({ -// vueInit, -// integrations: [ -// browserTracingIntegration({ router }), -// replayIntegration(), -// ], - -// // Set tracesSampleRate to 1.0 to capture 100% -// // of transactions for performance monitoring. -// // We recommend adjusting this value in production -// tracesSampleRate: 1.0, - -// // Capture Replay for 10% of all sessions, -// // plus for 100% of sessions with an error -// replaysSessionSampleRate: 0.1, -// replaysOnErrorSampleRate: 1.0, -// }); - -const app = createApp(Root) - -app.use(router) -app.use(pinia) -app.use(VueDOMPurifyHTML) -app.use(PrimeVue, { - theme: { - preset: PipelabPreset, - options: { - darkModeSelector: 'light' - } - } -}) -app.use(ToastService) -app.use(ConfirmationService) -if (window.isPackaged && process.env.TEST !== 'true') { - app.use(posthogPlugin) -} -app.use(i18n) - -const { logger } = useLogger() - -// Initialize WebSocket manager in background -websocketManager.initialize().catch((error) => { - logger().warn( - 'WebSocket manager initialization failed, app will continue without WebSocket:', - error - ) -}) -app.mount('#app') -logger().info('App mounted') - -// Ensure WebSocket connection after app is mounted -setTimeout(() => { - websocketManager.ensureConnection() -}, 1000) // Wait 1 second after mount to ensure server is ready diff --git a/src/renderer/models/constants.ts b/src/renderer/models/constants.ts deleted file mode 100644 index c50858c7..00000000 --- a/src/renderer/models/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const PROJECT_EXTENSION = 'plb' diff --git a/src/renderer/models/controls.ts b/src/renderer/models/controls.ts deleted file mode 100644 index 04af640e..00000000 --- a/src/renderer/models/controls.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ControlType } from '@pipelab/plugin-core' -import { match } from 'ts-pattern' - -type PrimitiveConstructor = - | 'string' - | 'number' - | 'boolean' - | 'object' - | 'symbol' - | 'function' - | 'bigint' - -export const controlsToType = (control: ControlType) => { - return match(control) - .returnType() - .with({ type: 'path' }, () => 'string') - .with({ type: 'input', options: { kind: 'number' } }, () => 'number') - .with({ type: 'input', options: { kind: 'text' } }, () => 'string') - .with({ type: 'boolean' }, () => 'boolean') - .with({ type: 'checkbox' }, () => 'boolean') - .with({ type: 'select' }, () => 'string') - .with({ type: 'multi-select' }, () => 'object') - .with({ type: 'json' }, () => 'object') - .with({ type: 'expression' }, () => 'string') - .with({ type: 'array', options: { kind: 'number' } }, () => 'object') - .with({ type: 'array', options: { kind: 'text' } }, () => 'object') - .with({ type: 'electron:configure:v2' }, () => 'object') - .with({ type: 'netlify-site' }, () => 'string') - .with({ type: 'color' }, () => 'string') - .exhaustive() -} - -export const controlsToIcon = (control: ControlType) => { - return match(control) - .returnType() - .with({ type: 'path' }, () => 'mdi-alphabetical-variant') - .with({ type: 'input', options: { kind: 'number' } }, () => 'mdi-numeric') - .with({ type: 'input', options: { kind: 'text' } }, () => 'mdi-alphabetical-variant') - .with({ type: 'boolean' }, () => 'mdi-toggle-switch') - .with({ type: 'checkbox' }, () => 'mdi-toggle-switch') - .with({ type: 'select' }, () => 'mdi-alphabetical-variant') - .with({ type: 'multi-select' }, () => 'mdi-code-brackets') - .with({ type: 'json' }, () => 'mdi-code-braces') - .with({ type: 'expression' }, () => 'mdi-') - .with({ type: 'array', options: { kind: 'number' } }, () => 'mdi-code-brackets') - .with({ type: 'array', options: { kind: 'text' } }, () => 'mdi-code-brackets') - .with({ type: 'electron:configure:v2' }, () => 'mdi-code-braces') - .with({ type: 'netlify-site' }, () => 'mdi-code-braces') - .with({ type: 'color' }, () => 'mdi-palette') - .exhaustive() -} diff --git a/src/renderer/models/error.ts b/src/renderer/models/error.ts deleted file mode 100644 index 7628507c..00000000 --- a/src/renderer/models/error.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ValidationError { - type: 'missing'; - param: string -} diff --git a/src/renderer/pages/editor.vue b/src/renderer/pages/editor.vue deleted file mode 100644 index 11dc85f8..00000000 --- a/src/renderer/pages/editor.vue +++ /dev/null @@ -1,1200 +0,0 @@ - - - - - diff --git a/src/renderer/pages/index.vue b/src/renderer/pages/index.vue deleted file mode 100644 index 59b31ea3..00000000 --- a/src/renderer/pages/index.vue +++ /dev/null @@ -1,1308 +0,0 @@ - - - - - diff --git a/src/renderer/pages/project-settings-editor.vue b/src/renderer/pages/project-settings-editor.vue deleted file mode 100644 index df26c404..00000000 --- a/src/renderer/pages/project-settings-editor.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - - - diff --git a/src/renderer/plugins/posthog.ts b/src/renderer/plugins/posthog.ts deleted file mode 100644 index 9f5d1a4a..00000000 --- a/src/renderer/plugins/posthog.ts +++ /dev/null @@ -1,10 +0,0 @@ -//./plugins/posthog.js -import posthog from 'posthog-js' - -export default { - install(app: any) { - app.config.globalProperties.$posthog = posthog.init(__POSTHOG_API_KEY__, { - api_host: 'https://eu.i.posthog.com' - }) - } -} diff --git a/src/renderer/router/router.ts b/src/renderer/router/router.ts deleted file mode 100644 index b9cf4bcf..00000000 --- a/src/renderer/router/router.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { createRouter, createWebHashHistory, RouterOptions } from 'vue-router' -import { i18n } from '../i18n' - -const { t } = i18n.global - -const routes: RouterOptions['routes'] = [ - { - path: '/', - name: 'Home', - redirect: 'Dashboard' - }, - { - path: '/dashboard', - component: () => import('../pages/index.vue'), - name: 'Dashboard', - meta: { - title: t('headers.dashboard') - } - }, - { - path: '/scenarios', - name: 'Scenarios', - component: () => import('../pages/scenarios.vue'), - meta: { - title: t('headers.scenarios') - }, - children: [] - }, - { - path: '/scenarios/editor/:pipelineId/:projectId', - name: 'Editor', - component: () => import('../pages/editor.vue'), - meta: { - title: t('headers.editor') - } - }, - { - path: '/billing', - name: 'Billing', - component: () => import('../pages/editor.vue'), - meta: { - title: t('headers.billing') - } - }, - { - path: '/team', - name: 'Team', - component: () => import('../pages/team.vue'), - meta: { - title: t('headers.team') - } - }, - { - path: '/simple-editor', - name: 'SimpleEditor', - component: () => import('../pages/simple-editor.vue'), - meta: { - title: 'Simple Editor' - } - } -] - -export const router = createRouter({ - history: createWebHashHistory(), - routes -}) diff --git a/src/renderer/store/app.ts b/src/renderer/store/app.ts deleted file mode 100644 index 4eedeb88..00000000 --- a/src/renderer/store/app.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { defineStore } from 'pinia' -import { createEventHook } from '@vueuse/core' -import { ref } from 'vue' -import { useAPI } from '@renderer/composables/api' -import { RendererPluginDefinition } from '@pipelab/plugin-core' -import { Presets } from '@@/apis' -import { useLogger } from '@@/logger' - -export const useAppStore = defineStore('app', () => { - const { logger } = useLogger() - - /** Presets to load from */ - const presets = ref() - - /** All the plugins definitions */ - const pluginDefinitions = ref>([]) - - const api = useAPI() - - const { on: onPresetsLoaded, trigger: triggerPresetsLoaded } = createEventHook() - - const init = async () => { - // - const nodeGetResult = await api.execute('nodes:get') - - if (nodeGetResult.type === 'error') { - throw new Error(nodeGetResult.ipcError) - } - - const { result } = nodeGetResult - const { nodes: nodeDefs } = result - - pluginDefinitions.value = nodeDefs - - // - const presentResult = await api.execute('presets:get') - if (presentResult.type === 'error') { - throw new Error(presentResult.ipcError) - } - presets.value = presentResult.result - - // - triggerPresetsLoaded() - } - - const getPluginDefinition = (pluginId: string) => { - const result = pluginDefinitions.value.find((nodeDef) => { - if (!pluginId) { - logger().error('Missing origin: node', pluginId) - } - return nodeDef.id === pluginId - }) - return result - } - - const getNodeDefinition = (nodeId: string, pluginId: string) => { - // const getNodeDefinition = (node: T extends Block ? T : never) => { - const plugin = getPluginDefinition(pluginId) - if (plugin) { - return plugin.nodes.find((pluginNode) => pluginNode.node.id === nodeId) - } - return undefined - } - - return { - presets, - onPresetsLoaded, - init, - - pluginDefinitions, - - getPluginDefinition, - getNodeDefinition - } -}) - -export type AppStore = ReturnType diff --git a/src/renderer/store/auth.ts b/src/renderer/store/auth.ts deleted file mode 100644 index 61a6223f..00000000 --- a/src/renderer/store/auth.ts +++ /dev/null @@ -1,439 +0,0 @@ -import { useLogger } from '@@/logger' // Assuming path is correct -import { isSupabaseAvailable, supabase as supabaseFn } from '@@/supabase' // Assuming path is correct -import { AuthChangeEvent, Session, User, UserResponse } from '@supabase/supabase-js' -import { defineStore } from 'pinia' -import { computed, readonly, Ref, ref, shallowRef } from 'vue' -import posthog from 'posthog-js' -import { email } from 'valibot' -import { Subscription } from '@polar-sh/sdk/dist/commonjs/models/components/subscription' -import { createEventHook } from '@vueuse/core' - -// Define a more comprehensive AuthStateType -export type AuthStateType = - | 'INITIALIZING' // App is checking for existing session - | 'SIGNED_IN' - | 'SIGNED_OUT' - | 'ERROR' - | 'AWAITING_VALIDATION' - | 'LOADING' // Authentication action in progress - -export const useAuth = defineStore('auth', () => { - const logger = useLogger() - const user = shallowRef() - const authState = ref('INITIALIZING') as Ref // Start in INITIALIZING state - const isAuthenticating = ref(false) // Track loading state for auth actions - const errorMessage = ref() // For storing error messages to display to the user - const subscriptions = ref([]) // Store user subscriptions - const subscriptionError = ref() // Store subscription loading errors - - const isAuthModalVisible = ref(false) - const authModalTitle = ref() - const authModalSubTitle = ref() - - const onAuthChanged = createEventHook<{ event: AuthChangeEvent; session: Session }>() - const onSubscriptionChanged = createEventHook<{ subscriptions: Subscription[] }>() - - const supabase = isSupabaseAvailable ? supabaseFn() : undefined - - const displayAuthModal = (title?: string, subtitle?: string) => { - isAuthModalVisible.value = true - authModalTitle.value = title - authModalSubTitle.value = subtitle - } - - const hideAuthModal = () => { - isAuthModalVisible.value = false - authModalTitle.value = undefined - authModalSubTitle.value = undefined - } - - const setAuthState = (state: AuthStateType) => { - authState.value = state - logger.logger().debug(`[Auth State] Changed to: ${state}`) - } - - const clearError = () => { - errorMessage.value = null - } - - const fetchSubscription = async () => { - console.log('[Auth] fetchSubscription: Starting, setting isLoadingSubscriptions to true') - isLoadingSubscriptions.value = true - subscriptionError.value = undefined - if (user.value) { - if (user.value.email) { - try { - const result = await supabase.functions.invoke('polar-user-plan') - if (result.error) { - throw new Error(result.error.message || 'Network error') - } - if (!result.data) { - throw new Error('Invalid response: no data') - } - if (!Array.isArray(result.data.subscriptions)) { - throw new Error('Invalid response: subscriptions is not an array') - } - console.log('Subscription result', result) - subscriptions.value = result.data.subscriptions - } catch (error) { - console.error('Failed to fetch subscription:', error) - subscriptionError.value = error instanceof Error ? error.message : 'Unknown error' - subscriptions.value = [] - } - } else { - console.warn('User email is not available, skipping subscription fetch.') - subscriptionError.value = 'User email not available' - subscriptions.value = [] - } - } else { - console.warn('User is anonymous, skipping subscription fetch.') - subscriptionError.value = 'User is anonymous' - subscriptions.value = [] - } - console.log('[Auth] fetchSubscription: Completed, setting isLoadingSubscriptions to false') - isLoadingSubscriptions.value = false - onSubscriptionChanged.trigger({ subscriptions: subscriptions.value }) - } - - supabase?.auth.onAuthStateChange((event, session) => { - // Removed async to make it fully synchronous event handler as we are not initiating async actions inside - logger.logger().debug('[Auth Change] Event:', event) - logger - .logger() - .debug( - '[Auth Change] User ID:', - session?.user?.id, - 'is_anonymous:', - session?.user?.is_anonymous, - 'email:', - session?.user?.email - ) - - switch (event) { - case 'SIGNED_IN': - if (session?.user) { - user.value = session.user - console.log('Session', session) - posthog.identify(session.user.id, { - email: session.user.email, - is_anonymous: session.user.is_anonymous || false - }) - setAuthState('SIGNED_IN') - } - break - case 'INITIAL_SESSION': - logger - .logger() - .debug('[Auth] Initial Session event - Handling session check in init function.') - // No action here. Initial session check and anonymous sign-in is handled in init() now. - if (session?.user) { - logger - .logger() - .debug( - '[Auth Change] User ID:', - session?.user?.id, - 'is_anonymous:', - session?.user?.is_anonymous, - 'email:', - session?.user?.email - ) - console.log('Session', session) - posthog.identify(session.user.id, { - email: session.user.email, - is_anonymous: session.user.is_anonymous || false - }) - user.value = session.user - setAuthState('SIGNED_IN') - } else { - logger - .logger() - .info( - '[Auth] No user found on initial session, anonymous sign-in will be triggered in init().' - ) - // Anonymous sign-in will be handled in the init() function if no user is found after initial check. - } - break - case 'SIGNED_OUT': - logger.logger().info('[Auth] Signed out event.') - user.value = null - posthog.reset() - setAuthState('SIGNED_OUT') - // No signInAnonymously() here. Let the app handle anonymous sign-in separately if needed after sign-out, or rely on initial sign-in on next load. - break - case 'USER_UPDATED': // Or other events you want to handle specifically - if (session?.user) { - user.value = session.user // Refresh user data on update - } - break - case 'TOKEN_REFRESHED': - break - default: - logger.logger().warn('[Auth] Unhandled auth event:', event) - // setAuthState('SIGNED_OUT') // Fallback to signed out for unhandled events - // user.value = null - // No signInAnonymously() here. Similar to SIGNED_OUT, handle anonymous sign-in outside if needed. - break - } - - onAuthChanged.trigger({ event, session }) - }) - - // Explicitly initialize the auth state when the store is created - const init = async () => { - if (!isSupabaseAvailable) { - return - } - - if (authState.value !== 'INITIALIZING') { - logger.logger().warn('[Auth] Init called when not in INITIALIZING state. Ignoring.') - return // Prevent duplicate init calls - } - logger.logger().info('[Auth] Initializing authentication...') - setAuthState('LOADING') // Set loading state during init - try { - const { data, error } = await supabase.auth.getUser() // Use getUser for initial check - if (error) { - logger.logger().error('[Auth] Error fetching user during init:', error) - // Fallback to anonymous sign-in on init error, as initial user fetch failed. - logger - .logger() - .info('[Auth] Falling back to anonymous sign-in due to initial user fetch error.') - } else if (data.user) { - logger - .logger() - .info( - '[Auth] Found existing user during init:', - data.user.id, - 'anonymous:', - data.user.is_anonymous, - 'email:', - data.user.email - ) - console.log('Session', data) - posthog.identify(data.user.id, { - email: data.user.email, - is_anonymous: data.user.is_anonymous || false - }) - user.value = data.user - setAuthState('SIGNED_IN') - await fetchSubscription() - } else { - logger.logger().info('[Auth] No user found during init, signing in anonymously...') - posthog.identify() - } - } catch (e) { - logger.logger().error('[Auth] Unexpected error during init:', e) - setAuthState('ERROR') // Set error state if init fails unexpectedly - errorMessage.value = 'Failed to initialize authentication.' - } finally { - if (authState.value === 'LOADING') { - // Ensure we transition from loading state even if errors occur during init - if ( - authState.value !== 'SIGNED_IN' && - authState.value !== 'ANONYMOUS' && - authState.value !== 'ERROR' - ) { - // If after init, state is still loading and not signed in or anonymous, default to signed out (though should ideally be ANONYMOUS or ERROR after signInAnonymously in error cases). - setAuthState('SIGNED_OUT') // As a last resort fallback, though ideally we should be in ANONYMOUS or ERROR state if initial auth fails and anonymous sign in is attempted in init. - } - } - } - } - - const login = async (email: string, password: string): Promise => { - isAuthenticating.value = true - setAuthState('LOADING') - clearError() - try { - const loginResponse = await supabase.auth.signInWithPassword({ email, password }) - const { data, error } = loginResponse - if (error) { - logger.logger().error('[Auth] Login error:', error) - setAuthState('ERROR') - errorMessage.value = 'Invalid login credentials.' - return loginResponse - } else { - logger.logger().info('[Auth] Logged in user:', data.user.id) - user.value = data.user - setAuthState('SIGNED_IN') - await fetchSubscription() - return loginResponse - } - } finally { - isAuthenticating.value = false - } - } - - const register = async (email: string, password: string): Promise => { - isAuthenticating.value = true - setAuthState('LOADING') - clearError() - try { - const registerResponse = await supabase.auth.signUp({ email, password }) // Use signUp for registration - console.log('registerResponse', registerResponse) - const { data, error } = registerResponse - if (error) { - logger.logger().error('[Auth] Registration error:', error) - setAuthState('ERROR') - errorMessage.value = 'Failed to register. Please try again.' - return registerResponse - } else { - // an email is sent, you must validate it - logger.logger().info('[Auth] Registered new user:', data.user.id) - setAuthState('AWAITING_VALIDATION') - return registerResponse - } - } finally { - isAuthenticating.value = false - } - } - - const logout = async (): Promise => { - isAuthenticating.value = true // Indicate loading during logout if needed - setAuthState('LOADING') // Optionally set authState to loading during logout - clearError() - try { - await supabase.auth.signOut() - logger.logger().info('[Auth] Signed out.') - user.value = null // Already handled in onAuthStateChange('SIGNED_OUT') but good to keep for immediate null user. - setAuthState('SIGNED_OUT') // Ensure state is set to signed out - also handled in onAuthStateChange, but good for clarity - subscriptions.value = [] - } catch (error) { - logger.logger().error('[Auth] Logout error:', error) - setAuthState('ERROR') - errorMessage.value = 'Failed to logout.' - } finally { - isAuthenticating.value = false - } - } - - const resetPassword = async (email: string): Promise<{ error: any }> => { - isAuthenticating.value = true - setAuthState('LOADING') - clearError() - try { - const { error } = await supabase.auth.resetPasswordForEmail(email) - if (error) { - logger.logger().error('[Auth] Reset password error:', error) - setAuthState('ERROR') - errorMessage.value = 'Failed to send reset email.' - return { error } - } else { - logger.logger().info('[Auth] Reset password email sent to:', email) - setAuthState('SIGNED_OUT') // Reset to signed out state - return { error: null } - } - } finally { - isAuthenticating.value = false - } - } - - // Call init immediately when the store is created to check initial auth state - init() - - const isLoggedIn = computed(() => authState.value === 'SIGNED_IN') - - const benefits = { - 'cloud-save': '16955d3e-3e0f-4574-9093-87a32edf237c', - 'build-history': 'b77e9800-8302-4581-8df3-6f1b979acef5', - 'multiple-projects': 'ad00648e-ba6f-461a-87d0-84cabd53e489' - } - - const devOverrides = ref>({}) - - const loadDevOverrides = () => { - if (process.env.NODE_ENV === 'development') { - const stored = localStorage.getItem('dev-benefits-overrides') - if (stored) { - devOverrides.value = JSON.parse(stored) - } - } - } - - const saveDevOverrides = () => { - if (process.env.NODE_ENV === 'development') { - localStorage.setItem('dev-benefits-overrides', JSON.stringify(devOverrides.value)) - } - } - - const setDevOverride = (benefit: string, value: string) => { - devOverrides.value[benefit] = value - saveDevOverrides() - } - - const getActualBenefit = (benefit: keyof typeof benefits) => { - // Check subscriptions for actual status - return subscriptions.value.some((sub) => - sub.product.benefits.map((b) => b.id).includes(benefits[benefit]) - ) - } - - const hasBenefit = (benefit: keyof typeof benefits) => { - // Check dev overrides in development mode - if (process.env.NODE_ENV === 'development') { - const override = devOverrides.value[benefit] - if (override !== undefined) { - switch (override) { - case 'force-on': - return true - case 'force-off': - return false - case 'actual': - default: - // Fall through to actual check - break - } - } - } - - // Default behavior: check subscriptions - const actual = getActualBenefit(benefit) - return actual - } - - // Load overrides on store creation - loadDevOverrides() - - const hasBuildHistoryBenefit = computed(() => hasBenefit('build-history')) - const hasCloudSaveBenefit = computed(() => hasBenefit('cloud-save')) - const hasMultipleProjectsBenefit = computed(() => hasBenefit('multiple-projects')) - - const isLoadingSubscriptions = ref(false) - - return { - user, - authState, - isLoggedIn, - isAuthenticating, - hasLoginProvider: isSupabaseAvailable, - errorMessage, - subscriptions: readonly(subscriptions), - subscriptionError: readonly(subscriptionError), - isLoadingSubscriptions, - hasBenefit, - getActualBenefit, - devOverrides: readonly(devOverrides), - setDevOverride, - - clearError, - init, // Keep init for explicit re-initialization if needed, though generally called once on app start. - login, - register, - logout, - resetPassword, - fetchSubscription, - - displayAuthModal, - hideAuthModal, - isAuthModalVisible, - authModalTitle, - authModalSubTitle, - - hasBuildHistoryBenefit, - hasCloudSaveBenefit, - hasMultipleProjectsBenefit, - - onAuthChanged: onAuthChanged.on, - onSubscriptionChanged: onSubscriptionChanged.on - } -}) diff --git a/src/renderer/store/build-history.ts b/src/renderer/store/build-history.ts deleted file mode 100644 index 4c41b974..00000000 --- a/src/renderer/store/build-history.ts +++ /dev/null @@ -1,369 +0,0 @@ -import { defineStore, storeToRefs } from 'pinia' -import { ref, computed, readonly } from 'vue' -import { useLogger } from '@@/logger' -import { useAuth } from './auth' -import { useAPI } from '@renderer/composables/api' -import type { - BuildHistoryEntry, - BuildHistoryQuery, - BuildHistoryResponse, - SubscriptionError -} from '@@/build-history' -import { isSubscriptionError, SubscriptionRequiredError } from '@@/subscription-errors' - -export const useBuildHistory = defineStore('build-history', () => { - const api = useAPI() - const logger = useLogger() - const authStore = useAuth() - - const {} = authStore - const { hasBuildHistoryBenefit } = storeToRefs(authStore) - - const isRefreshingHistory = ref(false) - - // IPC API functions - const buildHistoryAPI = { - async save(entry: BuildHistoryEntry): Promise { - const result = await api.execute('build-history:save', { - entry - }) - if (result.type === 'error') { - throw new Error(result.ipcError || 'Failed to save build history entry') - } - }, - - async get(id: string): Promise { - const result = await api.execute('build-history:get', { id }) - if (result.type === 'error') { - throw new Error(result.ipcError || 'Failed to get build history entry') - } - return result.result.entry - }, - - async getAll(query?: BuildHistoryQuery): Promise { - const result = await api.execute('build-history:get-all', { - query - }) - console.log('result', result) - if (result.type === 'error') { - throw new Error(result.ipcError || 'Failed to get build history entries') - } - return result.result - }, - - async update(id: string, updates: Partial): Promise { - const result = await api.execute('build-history:update', { - id, - updates - }) - if (result.type === 'error') { - throw new Error(result.ipcError || 'Failed to update build history entry') - } - }, - - async delete(id: string): Promise { - const result = await api.execute('build-history:delete', { id }) - if (result.type === 'error') { - throw new Error(result.ipcError || 'Failed to delete build history entry') - } - }, - - async clear(): Promise { - const result = await api.execute('build-history:clear') - if (result.type === 'error') { - throw new Error(result.ipcError || 'Failed to clear build history') - } - }, - - async getStorageInfo(): Promise<{ - totalEntries: number - totalSize: number - oldestEntry?: number - newestEntry?: number - }> { - const result = await api.execute('build-history:get-storage-info') - if (result.type === 'error') { - throw new Error(result.ipcError || 'Failed to get build history storage info') - } - return result.result - } - } - - // State - const entries = ref([]) - const currentEntry = ref() - const isLoading = ref(false) - const error = ref() - const storageInfo = ref< - | { - totalEntries: number - totalSize: number - oldestEntry?: number - newestEntry?: number - } - | undefined - >() - - // Filtering state - const currentPipelineId = ref() - const currentScenarioId = ref() - - // Computed - const hasEntries = computed(() => entries.value.length > 0) - const totalEntries = computed(() => entries.value.length) - const canUseHistory = computed(() => hasBuildHistoryBenefit.value) - - const setError = (errorMessage: string) => { - error.value = errorMessage - logger.logger().error('[Build History]', errorMessage) - } - - const buildQuery = (): BuildHistoryQuery => ({ - pipelineId: currentPipelineId.value - }) - - // Actions - const loadEntries = async (query?: BuildHistoryQuery): Promise => { - console.trace('query', query) - isLoading.value = true - - // Check authorization before attempting to load - if (!canUseHistory.value) { - isLoading.value = false - return - } - - try { - const response = await buildHistoryAPI.getAll(query) - entries.value = response.entries - storageInfo.value = { - totalEntries: response.total, - totalSize: 0, // This would need to be calculated separately - oldestEntry: - response.total > 0 ? Math.min(...response.entries.map((e) => e.startTime)) : undefined, - newestEntry: - response.total > 0 ? Math.max(...response.entries.map((e) => e.startTime)) : undefined - } - } catch (err) { - const errorMessage = - err instanceof Error ? err.message : 'Failed to load build history entries' - setError(errorMessage) - throw err - } finally { - isLoading.value = false - } - } - - const loadEntry = async (id: string): Promise => { - isLoading.value = true - - // Check authorization before attempting to load - if (!canUseHistory.value) { - isLoading.value = false - return undefined - } - - try { - const entry = await buildHistoryAPI.get(id) - if (entry) { - currentEntry.value = entry - // Update entry in the entries list if it exists - const index = entries.value.findIndex((e) => e.id === id) - if (index >= 0) { - entries.value[index] = entry - } - } - return entry - } catch (err) { - const errorMessage = err instanceof Error ? err.message : 'Failed to load build history entry' - setError(errorMessage) - throw err - } finally { - isLoading.value = false - } - } - - const saveEntry = async (entry: BuildHistoryEntry): Promise => { - isLoading.value = true - - // Check authorization before attempting to save - if (!canUseHistory.value) { - isLoading.value = false - return - } - - try { - await buildHistoryAPI.save(entry) - - // Add or update entry in the local state - const existingIndex = entries.value.findIndex((e) => e.id === entry.id) - if (existingIndex >= 0) { - entries.value[existingIndex] = entry - } else { - entries.value.unshift(entry) - } - - // Update current entry if it's the same - if (currentEntry.value?.id === entry.id) { - currentEntry.value = entry - } - } catch (err) { - const errorMessage = err instanceof Error ? err.message : 'Failed to save build history entry' - setError(errorMessage) - throw err - } finally { - isLoading.value = false - } - } - - const updateEntry = async (id: string, updates: Partial): Promise => { - isLoading.value = true - - // Check authorization before attempting to update - if (!canUseHistory.value) { - isLoading.value = false - return - } - - try { - await buildHistoryAPI.update(id, updates) - - // Update entry in local state - const index = entries.value.findIndex((e) => e.id === id) - if (index >= 0) { - entries.value[index] = { ...entries.value[index], ...updates, updatedAt: Date.now() } - } - - // Update current entry if it's the same - if (currentEntry.value?.id === id) { - currentEntry.value = { ...currentEntry.value, ...updates, updatedAt: Date.now() } - } - } catch (err) { - const errorMessage = - err instanceof Error ? err.message : 'Failed to update build history entry' - setError(errorMessage) - throw err - } finally { - isLoading.value = false - } - } - - const deleteEntry = async (id: string): Promise => { - isLoading.value = true - - // Check authorization before attempting to delete - if (!canUseHistory.value) { - isLoading.value = false - return - } - - try { - await buildHistoryAPI.delete(id) - - // Remove from local state - const index = entries.value.findIndex((e) => e.id === id) - if (index >= 0) { - entries.value.splice(index, 1) - } - - // Clear current entry if it's the same - if (currentEntry.value?.id === id) { - currentEntry.value = undefined - } - } catch (err) { - const errorMessage = - err instanceof Error ? err.message : 'Failed to delete build history entry' - setError(errorMessage) - throw err - } finally { - isLoading.value = false - } - } - - const clearHistory = async (): Promise => { - isLoading.value = true - - // Check authorization before attempting to clear - if (!canUseHistory.value) { - isLoading.value = false - return - } - - try { - await buildHistoryAPI.clear() - entries.value = [] - currentEntry.value = undefined - storageInfo.value = undefined - } catch (err) { - const errorMessage = err instanceof Error ? err.message : 'Failed to clear build history' - setError(errorMessage) - throw err - } finally { - isLoading.value = false - } - } - - const refreshStorageInfo = async (): Promise => { - // Check authorization before attempting to get storage info - if (!canUseHistory.value) { - return - } - - try { - storageInfo.value = await buildHistoryAPI.getStorageInfo() - } catch (err) { - const errorMessage = err instanceof Error ? err.message : 'Failed to refresh storage info' - setError(errorMessage) - } - } - - const setCurrentPipeline = (pipelineId: string | undefined): void => { - currentPipelineId.value = pipelineId - } - - const clearCurrentPipeline = (): void => { - currentPipelineId.value = undefined - } - - const setCurrentScenario = (scenarioId: string | undefined): void => { - currentScenarioId.value = scenarioId - } - - const clearCurrentScenario = (): void => { - currentScenarioId.value = undefined - } - - return { - // State - entries: entries, - currentEntry: readonly(currentEntry), - isLoading: readonly(isLoading), - error: readonly(error), - storageInfo: readonly(storageInfo), - - // Computed - hasEntries, - totalEntries, - canUseHistory, - - // Pipeline filtering - currentPipelineId: readonly(currentPipelineId), - currentScenarioId: readonly(currentScenarioId), - - // Actions - loadEntries, - loadEntry, - saveEntry, - updateEntry, - deleteEntry, - clearHistory, - refreshStorageInfo, - setCurrentPipeline, - clearCurrentPipeline, - setCurrentScenario, - clearCurrentScenario, - - // Query builder - buildQuery - } -}) diff --git a/src/renderer/store/editor.ts b/src/renderer/store/editor.ts deleted file mode 100644 index 9e5f6058..00000000 --- a/src/renderer/store/editor.ts +++ /dev/null @@ -1,765 +0,0 @@ -import { computed, onMounted, ref, shallowRef, watch } from 'vue' -import { - Block, - BlockAction, - BlockCondition, - BlockEvent, - BlockLoop, - SavedFile, - savedFileMigrator, - SavedFileValidator, - Steps -} from '@@/model' -import { - Action, - Condition, - Event, - Loop, - PipelabNode, - RendererNodeDefinition -} from '@pipelab/plugin-core' -import { Variable } from '@pipelab/core-app' -import { defineStore, storeToRefs } from 'pinia' -import get from 'get-value' -import set from 'set-value' -import { nanoid } from 'nanoid' -import { AddNodeEvent, AddTriggerEvent } from '@renderer/components/AddNodeButton.model' -import { useAppStore } from './app' -import { useFiles } from './files' -import { useRouteParams } from '@vueuse/router' -import { ValidationError } from '@renderer/models/error' -import { isRequired } from '@@/validation' -import { useLogger } from '@@/logger' -import { klona } from 'klona' -import { create } from 'mutative' -import { parse, value } from 'valibot' -import { createEventHook, watchDebounced } from '@vueuse/core' -import { makeResolvedParams } from '@renderer/utils/evaluator' -import { createQuickJs } from '@renderer/utils/quickjs' - -export type Context = Record - -// Definitions -export const isActionDefinition = (nodeDefinition: PipelabNode): nodeDefinition is Action => { - return nodeDefinition.type === 'action' -} - -export const isConditionDefinition = (nodeDefinition: PipelabNode): nodeDefinition is Condition => { - return nodeDefinition.type === 'condition' -} - -export const isEventDefinition = (nodeDefinition: PipelabNode): nodeDefinition is Event => { - return nodeDefinition.type === 'event' -} - -export const isLoopDefinition = (nodeDefinition: PipelabNode): nodeDefinition is Loop => { - return nodeDefinition.type === 'loop' -} - -export const isActionBlock = (nodeDefinition: Block): nodeDefinition is BlockAction => { - return nodeDefinition.type === 'action' -} - -// export const isConditionBlock = (nodeDefinition: Block): nodeDefinition is BlockCondition => { -// return nodeDefinition.type === 'condition' -// } - -// export const isCommentBlock = (nodeDefinition: Block): nodeDefinition is BlockComment => { -// return nodeDefinition.type === 'comment' -// } - -// export const isEventBlock = (nodeDefinition: Block): nodeDefinition is BlockEvent => { -// return nodeDefinition.type === 'event' -// } - -// export const isLoopBlock = (nodeDefinition: Block): nodeDefinition is BlockLoop => { -// return nodeDefinition.type === 'loop' -// } - -export type BlockToNode = T['type'] extends 'action' - ? Action - : T['type'] extends 'condition' - ? Condition - : T['type'] extends 'event' - ? Event - : T['type'] extends 'loop' - ? Loop - : never - -export type Status = 'idle' | 'running' | 'error' | 'canceled' | 'done' - -export const useEditor = defineStore('editor', () => { - const appStore = useAppStore() - const { presets, pluginDefinitions } = storeToRefs(appStore) - const { getNodeDefinition, getPluginDefinition } = appStore - - const { logger } = useLogger() - - const filesStore = useFiles() - const { files } = storeToRefs(filesStore) - - const pipelineId = useRouteParams('pipelineId') - const projectId = useRouteParams('projectId') - - const name = ref('') - const description = ref('') - - const isRunning = ref(false) - const setIsRunning = (value: boolean) => { - isRunning.value = value - } - - /** All the nodes on the editor */ - const blocks = ref>([]) - - /** All the trigger nodes on the editor */ - const triggers = ref>([]) - - /** All the variables of the editor */ - const variables = ref>([]) - - /** All the environnement variables supported for the editor */ - const environnements = ref>([]) - - /** All log lines relative to their plugin instance */ - const logLines = ref>({}) - - const nodeStatuses = ref>({}) - - /** The API helper */ - // const api = useAPI() - - const pushLine = (nodeUid: string, data: string) => { - if (!logLines.value[nodeUid]) { - logLines.value[nodeUid] = [] - } - logLines.value[nodeUid].push(data) - } - - const clearLogs = () => { - logLines.value = {} - } - - const currentFilePointer = computed(() => { - return files.value.pipelines.find((x) => x.id === pipelineId.value) - }) - - // const savedFile = computed(() => { - // return { - // version: '2.0.0', - // name: toRaw(name.value), - // description: '', - // canvas: { - // blocks: toRaw(blocks.value), - // triggers: toRaw(triggers.value) - // }, - // variables: toRaw(variables.value) - // } satisfies SavedFile - // }) - - // watchEffect(async () => { - // if (id.value === undefined) { - // return - // } - // await update((state) => { - // state[id.value] = { - // data: savedFile.value, - // } - // }) - // }) - - const stepsDisplay = computed(() => { - const result: Steps = {} - - for (const node of blocks.value) { - const pluginDef = getNodeDefinition(node.origin.nodeId, node.origin.pluginId) - - if (!result[node.uid]) { - result[node.uid] = { - outputs: {} - } - } - - if (pluginDef) { - if (pluginDef.node.type === 'action') { - const outputs = pluginDef.node.outputs - - for (const [key, output] of Object.entries(outputs)) { - /* - - */ - result[node.uid]['outputs'][key] = - `${node.name ?? pluginDef.node.name} → ${output.label}` - } - } - } - } - - return result - }) - - const activeNode = ref() - const setActiveNode = (node: BlockAction | BlockCondition | BlockLoop | undefined) => { - activeNode.value = node - } - - const selectedNodeUid = ref() - const selectedNode = computed(() => { - if (!selectedNodeUid.value) { - return undefined - } - return blocks.value.find((x) => x.uid === selectedNodeUid.value) - }) - const setSelectedNode = (node: BlockAction | BlockCondition | BlockLoop | undefined) => { - selectedNodeUid.value = node?.uid - } - - /** All the plugins's node definitions */ - const nodeDefinitions = computed(() => { - return pluginDefinitions.value - .map((x) => - x.nodes.map((n) => ({ - ...n, - plugin: x.id - })) - ) - .flat(3) satisfies RendererNodeDefinition[] - }) - - const clear = () => { - blocks.value = [] - variables.value = [] - triggers.value = [] - setActiveNode(undefined) - setSelectedNode(undefined) - } - - const errors = computed(() => { - const editorErrors: Record = {} - for (const block of blocks.value) { - const blockErrors = validate(block) - - for (const err of blockErrors) { - if (!editorErrors[block.uid]) { - editorErrors[block.uid] = [] - } - editorErrors[block.uid].push(err) - } - } - - return editorErrors - }) - - const validate = (block: Block | BlockEvent) => { - const errors: ValidationError[] = [] - if (block.type === 'action') { - const definition = getNodeDefinition(block.origin.nodeId, block.origin.pluginId) - if (!definition) { - errors.push({ - type: 'missing', - param: block.origin.nodeId + ':' + block.origin.pluginId - }) - logger().warn(`Missing required node "${block.origin.nodeId}:${block.origin.pluginId}"`) - return errors - } - const requiredParams = Object.entries(definition.node?.params ?? {}) - for (const [key, param] of requiredParams) { - if ( - (isRequired(param) && !(key in block.params)) || - (isRequired(param) && !block.params[key].value) - ) { - logger().warn(`Missing required param "${key}" in node "${block.uid}"`) - errors.push({ - type: 'missing', - param: key - }) - } - } - - // } else if (block.type === 'condition') { - // const definition = getNodeDefinition(block.origin.nodeId, block.origin.pluginId) - // const requiredParams = Object.keys(definition?.params ?? {}) - // for (const requiredParam of requiredParams) { - // if (!(requiredParam in block.params)) { - // console.warn(`Missing required param "${requiredParam}" in node "${block.uid}"`) - // errors.push({ - // type: 'missing', - // param: requiredParam - // }) - // } - // } - } else if (block.type === 'event') { - // - // } else if (block.type === 'loop') { - // const definition = getNodeDefinition(block.origin.nodeId, block.origin.pluginId) - // const requiredParams = Object.keys(definition?.params ?? {}) - // for (const requiredParam of requiredParams) { - // if (!(requiredParam in block.params)) { - // console.warn(`Missing required param "${requiredParam}" in node "${block.uid}"`) - // errors.push({ - // type: 'missing', - // param: requiredParam - // }) - // } - // } - // } else if (block.type === 'comment') { - // // - } - return errors - } - - const loadSavedFile = async (input: Readonly) => { - clear() - - const data = await savedFileMigrator.migrate(input, { - debug: true - }) - - // ensure all params are there - const finalData = create(data, (draft) => { - for (const block of draft.canvas.blocks) { - const definition = getNodeDefinition(block.origin.nodeId, block.origin.pluginId) - if (definition) { - const params = definition.node.params - for (const param of Object.keys(params)) { - if (!(param in block.params)) { - console.log('params[param]', params[param]) - console.warn('adding mising param', param, { - editor: 'simple', - value: params[param].value - }) - block.params[param] = { - editor: 'simple', - value: params[param].value - } - } - } - } - } - }) - - await parse(SavedFileValidator, finalData) - - name.value = finalData.name - description.value = finalData.description - - for (const variable of finalData.variables) { - addVariable(variable) - } - - for (const block of finalData.canvas.blocks) { - blocks.value.push(block) - validate(block) - } - - for (const trigger of finalData.canvas.triggers) { - triggers.value.push(trigger) - validate(trigger) - } - - // // load connections - // for (const connection of data.connections) { - // editor.addConnection({ - // id: connection.uid, - // source: connection.sourceUid, - // sourceOutput: connection.sourcePort, - // target: connection.targetUid, - // targetInput: connection.targetPort - // }) - // } - - // console.log('/ loadSchemaIntoEditor') - } - - /** - * TODO: support nested removals - */ - const removeNode = (nodeId: string) => { - const nodeIndex = blocks.value.findIndex((b) => b.uid === nodeId) - if (nodeIndex > -1) { - blocks.value = [ - ...blocks.value.slice(0, nodeIndex), - ...blocks.value.slice(nodeIndex + 1, undefined) - ] - } - } - - const removeTrigger = (triggerId: string) => { - const triggerIndex = triggers.value.findIndex((b) => b.uid === triggerId) - if (triggerIndex > -1) { - triggers.value = [ - ...triggers.value.slice(0, triggerIndex), - ...triggers.value.slice(triggerIndex + 1, undefined) - ] - } - } - - const setBlockValue = (nodeId: string, value: Block) => { - const nodeIndex = blocks.value.findIndex((b) => b.uid === nodeId) - if (nodeIndex > -1) { - // replace node - blocks.value = [ - ...blocks.value.slice(0, nodeIndex), - value, - ...blocks.value.slice(nodeIndex + 1, undefined) - ] - } - } - - const setTriggerValue = (nodeId: string, value: BlockEvent) => { - const nodeIndex = triggers.value.findIndex((b) => b.uid === nodeId) - if (nodeIndex > -1) { - // replace node - triggers.value = [ - ...triggers.value.slice(0, nodeIndex), - value, - ...triggers.value.slice(nodeIndex + 1, undefined) - ] - } - } - - const swapNodes = (index: number, direction: 'up' | 'down') => { - const newIndex = index + (direction === 'up' ? -1 : 1) - const output = blocks.value.map((element, _index) => - _index === index - ? blocks.value[newIndex] - : _index === newIndex - ? blocks.value[index] - : element - ) - console.log('input', blocks.value) - console.log('output', output) - - blocks.value = output - } - - const cloneNode = (node: Block, newIndex: number) => { - const newNode = klona(node) - newNode.uid = nanoid() - addNodeToBlock(newNode, [], newIndex) - } - - const disableNode = (node: Block) => { - blocks.value = create(klona(blocks.value), (draft) => { - for (let i = 0; i < draft.length; i += 1) { - if (draft[i].uid === node.uid) { - draft[i].disabled = true - } - } - }) - } - - const enableNode = (node: Block) => { - blocks.value = create(klona(blocks.value), (draft) => { - for (let i = 0; i < draft.length; i += 1) { - if (draft[i].uid === node.uid) { - draft[i].disabled = false - } - } - }) - } - - const addNode = (event: AddNodeEvent) => { - const { node: nodeDefinition, path, plugin: pluginDefinition, insertAt } = event - - if (nodeDefinition && pluginDefinition) { - if (isActionDefinition(nodeDefinition)) { - console.log('nodeDefinition', nodeDefinition) - - const createParams: BlockAction['params'] = {} - for (const [key, param] of Object.entries(nodeDefinition.params)) { - // ensure the value is converted to code expression - const val = param.value - - createParams[key] = { - editor: 'simple', - value: val - } - } - - console.log('createParams', createParams) - - const node: BlockAction = { - uid: nanoid(), - type: nodeDefinition.type, - origin: { - nodeId: nodeDefinition.id, - pluginId: pluginDefinition.id - }, - params: createParams - } - addNodeToBlock(node, path, insertAt) - } /* else if (isConditionDefinition(nodeDefinition)) { - const node: BlockCondition = { - uid: nanoid(), - type: nodeDefinition.type, - origin: { - nodeId: nodeDefinition.id, - pluginId: pluginDefinition.id - }, - params: {}, - branchFalse: [], - branchTrue: [] - } - addNodeToBlock(node, path, insertAt) - } else if (isLoopDefinition(nodeDefinition)) { - const node: BlockLoop = { - uid: nanoid(), - type: nodeDefinition.type, - origin: { - nodeId: nodeDefinition.id, - pluginId: pluginDefinition.id - }, - params: {}, - children: [] - } - addNodeToBlock(node, path, insertAt) - } */ else { - logger().error('Unhandled', nodeDefinition) - } - } - } - - const addTrigger = (event: AddTriggerEvent) => { - const { trigger: triggerDefinition, path, plugin: pluginDefinition, insertAt } = event - - if (triggerDefinition && pluginDefinition) { - if (isEventDefinition(triggerDefinition)) { - const node: BlockEvent = { - uid: nanoid(), - type: triggerDefinition.type, - origin: { - nodeId: triggerDefinition.id, - pluginId: pluginDefinition.id - }, - params: {} - } - addTriggerToBlock(node, path, insertAt) - } else { - logger().error('Unhandled', triggerDefinition) - } - } - } - - const addTriggerToBlock = (node: BlockEvent, path: string[], insertAt: number) => { - const value = path.length === 0 ? triggers.value : get(triggers.value, path) - - // const firstPart = value.slice(0, insertAt) - // const secondPart = value.slice(insertAt + 1) - - const newValue = [ - ...value.slice(0, insertAt), - node, - ...value.slice( - insertAt // already has +1 - ) - ] - if (path.length === 0) { - triggers.value = newValue - } else { - set(triggers.value, path, newValue) - } - - return - } - - // const addNodeToBlock = (node: Block, path: string[], insertAt: number) => { - // console.log('node', node) - // console.log('path', path) - // console.log('insertAt', insertAt) - // const value = path.length === 0 ? blocks.value : get(blocks.value, path) - - // const firstPart = value.slice(0, insertAt) - // const secondPart = value.slice(insertAt + 1) - - // const newValue = [ - // ...value.slice(0, insertAt), - // node, - // ...value.slice( - // insertAt // already has +1 - // ) - // ] - // if (path.length === 0) { - // blocks.value = newValue - // } else { - // set(blocks.value, path, newValue) - // } - - // return - // } - - const addNodeToBlock = (node: Block, path: string[], insertAt: number) => { - console.log('node', node) - console.log('path', path) - console.log('insertAt', insertAt) - - const value = blocks.value - - const newValue = [ - ...value.slice(0, insertAt), - node, - ...value.slice( - insertAt // already has +1 - ) - ] - blocks.value = newValue - - return - } - - const addVariable = (variable: Variable) => { - variables.value.push(variable) - } - - const removeVariable = (id: string) => { - const index = variables.value.findIndex((x) => x.id === id) - variables.value = [ - ...variables.value.slice(0, index), - ...variables.value.slice(index + 1, undefined) - ] - } - - const updateVariable = (variable: Variable) => { - variables.value = create(variables.value, (draft) => { - console.log('draft', draft) - for (let i = 0; i < draft.length; i += 1) { - console.log('draft[i]', draft[i]) - if (draft[i].id === variable.id) { - draft[i] = klona(variable) - } - } - return draft - }) - } - - const loadPreset = async (preset: string) => { - if (!presets.value) { - throw new Error('No presets') - } - - if (preset) { - const selectedPreset = presets.value[preset] - if (selectedPreset) { - await loadSavedFile(selectedPreset.data) - } - } - } - - const variablesDisplay = computed(() => { - const result: Record = {} - for (const variable of variables.value) { - result[variable.id] = `
@${variable.name}
` - } - return result - }) - - const vm = shallowRef() - createQuickJs().then((_vm) => { - vm.value = _vm - }) - - const whenModified = createEventHook() - - async function saveParams() { - const newResolvedParams: Record> = {} - - for (const block of blocks.value) { - if (block.type === 'action') { - const resolved = await makeResolvedParams( - { - params: block.params, - steps: stepsDisplay.value, - context: {}, - variables: variablesDisplay.value - }, - (item) => { - return item - }, - vm.value - ) - newResolvedParams[block.uid] = resolved - } - } - - resolvedParams.value = newResolvedParams - whenModified.trigger() - } - - const resolvedParams = ref>>({}) - watch([blocks, stepsDisplay, variablesDisplay], saveParams, { - deep: true - }) - - onMounted(() => { - console.group('onMounted') - saveParams() - console.groupEnd() - }) - - return { - nodes: blocks, - triggers, - variables, - environnements, - nodeDefinitions, - activeNode, - selectedNode, - name, - pipelineId, - projectId, - description, - errors, - - stepsDisplay, - - currentFilePointer, - - pushLine, - clearLogs, - logLines, - - nodeStatuses, - - setActiveNode, - setSelectedNode, - setBlockValue, - setTriggerValue, - removeNode, - removeTrigger, - - clear, - loadSavedFile, - addNode, - addNodeToBlock, - - addTrigger, - addTriggerToBlock, - - addVariable, - updateVariable, - removeVariable, - getPluginDefinition, - getNodeDefinition, - loadPreset, - isRunning, - setIsRunning, - - swapNodes, - cloneNode, - disableNode, - enableNode, - - saveParams, - - vm, - resolvedParams, - steps: stepsDisplay, - - // Hooks - onEditorChanged: whenModified.on - } -}) - -export type UseEditorFn = ReturnType diff --git a/src/renderer/store/files.ts b/src/renderer/store/files.ts deleted file mode 100644 index ba062579..00000000 --- a/src/renderer/store/files.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { SavedFile } from '@@/model' -import { defineStore } from 'pinia' -import { ref } from 'vue' -import { Draft, create } from 'mutative' -import { createConfig } from '@renderer/utils/config' -import { klona } from 'klona' -import { SaveLocationValidator } from '@@/save-location' -import { - object, - string, - optional, - record, - InferInput, - parse, - ValiError, - literal, - array -} from 'valibot' -import { createMigration, createMigrator, finalVersion, initialVersion } from '@@/libs/migration' -import { OmitVersion } from '@@/libs/migration/models/migration' - -export interface File { - data: SavedFile -} - -export const FileRepoValidatorV1 = object({ - version: literal('1.0.0'), - data: optional(record(string(), SaveLocationValidator), {}) -}) - -// --- - -export const FileRepoProjectValidatorV2 = object({ - id: string(), - name: string(), - description: string() -}) - -export const FileRepoValidatorV2 = object({ - version: literal('2.0.0'), - projects: array(FileRepoProjectValidatorV2), - pipelines: optional(array(SaveLocationValidator), []) -}) - -export type FileRepoV1 = InferInput -export type FileRepoV2 = InferInput - -export const FileRepoValidator = FileRepoValidatorV2 -export type FileRepo = InferInput - -export const fileRepoMigrator = createMigrator() -const defaultValue = fileRepoMigrator.createDefault({ - version: '2.0.0', - // a default project with no files - projects: [ - { - id: 'main', - name: 'Default project', - description: 'The initial default project' - } - ], - pipelines: [] -}) -export const fileRepoMigrations = fileRepoMigrator.createMigrations({ - defaultValue, - migrations: [ - createMigration({ - version: '1.0.0', - up: (state) => { - // on V1, there are no projects, just a data record - // we put everything on a main single project - - const pipelines: FileRepoV2['pipelines'] = Object.entries(state.data).map(([id, file]) => { - return { - id, - project: defaultValue.projects[0].id, // all go to the main project - ...file - } - }) - return { - projects: defaultValue.projects, - pipelines: pipelines - } satisfies OmitVersion - }, - down: initialVersion - }), - createMigration({ - version: '2.0.0', - up: finalVersion, - down: () => { - throw new Error('Migration down not implemented') - } - }) - ] -}) - -export const useFile = (name: string) => { - // const file = ref() - - const { load, save } = createConfig>(name) - - return { - save, - load - } -} - -export const useFiles = defineStore('files', () => { - const files = ref(defaultValue) - - const { - load: loadConfig, - save: saveConfig, - backup: backupConfig - } = createConfig('projects') - - const update = async (callback: (state: Draft) => void) => { - files.value = create(files.value, callback) - console.log('files.value', files.value) - await saveConfig(klona(files.value)) - } - - const load = async () => { - const data = await loadConfig() - - if (data.type === 'success') { - // TODO: beter typing for "data.result.result.version" - if (fileRepoMigrations.needMigration(data.result.result.version ?? '0.0.0')) { - console.log('backing up') - backupConfig(data.result.result.version) - } - try { - const filerepo = await fileRepoMigrations.migrate(data.result.result) - files.value = filerepo - } catch (e) { - if (e instanceof ValiError) { - console.log('error', e.issues) - } - console.error('error', e) - files.value = defaultValue - } - } else { - files.value = defaultValue - } - } - - const remove = async (id: string) => { - update((state) => { - state.pipelines = state.pipelines.filter((file) => file.id !== id) - }) - } - - const removeProject = async (id: string) => { - update((state) => { - state.projects = state.projects.filter((project) => project.id !== id) - }) - } - - const transferPipeline = async (pipelineId: string, projectId: string) => { - update((state) => { - const pipeline = state.pipelines.find((p) => p.id === pipelineId) - if (pipeline) { - pipeline.project = projectId - } - }) - } - - const loadFile = (name: string) => { - const { load, save } = createConfig>(name) - return { - load, - save - } - } - - return { - files: files, - // files: readonly(files), - - load, - loadFile, - update, - remove, - removeProject, - transferPipeline - } -}) diff --git a/src/renderer/store/recents.ts b/src/renderer/store/recents.ts deleted file mode 100644 index f44e8c13..00000000 --- a/src/renderer/store/recents.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { SaveLocation } from "@@/save-location"; -import { defineStore } from "pinia"; -import { ref } from "vue"; - -export interface Recent { - id: string - saveLocation: SaveLocation - name: string -} - -export const useRecentsStore = defineStore('recent-files', () => { - const recents = ref>({}); - - const addRecent = (recent: Recent) => { - recents.value[recent.id] = recent - } - - const removeRecent = (recentId: Recent['id']) => { - delete recents.value[recentId] - } - - return { - recents, - - addRecent, - removeRecent, - } -}, { - persist: true, -}) diff --git a/src/renderer/store/settings.ts b/src/renderer/store/settings.ts deleted file mode 100644 index 6efb10ab..00000000 --- a/src/renderer/store/settings.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { defineStore } from 'pinia' -import { useAPI } from '@renderer/composables/api' -import { AppConfig } from '@main/config' -import { readonly, ref } from 'vue' - -export const useAppSettings = defineStore('settings', () => { - const api = useAPI() - const settings = ref() - - const init = async () => { - await load() - } - - const load = async () => { - const result = await api.execute('settings:load') - if (result.type === 'error') { - console.error(result) - } else { - settings.value = result.result.result - } - } - - const updateSettings = async (_settings: AppConfig) => { - settings.value = _settings - const result = await api.execute('settings:save', _settings) - if (result.type === 'error') { - console.error(result) - } - await load() - } - - const reset = async (key: keyof AppConfig) => { - const result = await api.execute('settings:reset', { key }) - if (result.type === 'error') { - console.error(result) - } - await load() - } - - return { init, updateSettings, settings: readonly(settings), reset, load } -}) diff --git a/src/renderer/store/user.ts b/src/renderer/store/user.ts deleted file mode 100644 index 5565e09e..00000000 --- a/src/renderer/store/user.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineStore } from 'pinia' -import { ref } from 'vue' - -export default defineStore('user', () => { - const user = ref() - const benefits = ref() - - return { - user, - benefits - } -}) diff --git a/src/renderer/style/main.scss b/src/renderer/style/main.scss deleted file mode 100644 index 3beaebfe..00000000 --- a/src/renderer/style/main.scss +++ /dev/null @@ -1,113 +0,0 @@ -@use "sass:list"; -.node-icon { - font-size: 40px; -} - -.subtitle .param { - // flex: 1 0 auto; -} - -.editor .subtitle .param { - border: 1px solid #ccc; - background-color: #ddd; - padding: 2px 4px; - margin: 2px 4px; - border-radius: 4px; - cursor: pointer; - display: flex; - flex-direction: row; - gap: 4px; - align-items: baseline; - - &.primary { - color: blue; - } - - &:hover { - border: 1px solid #ddd; - background-color: #eee; - - &.primary { - color: blue; - } - } - - .step { - // border: 1px solid #ccc; - // background-color: #ddd; - // padding: 4px; - // margin: 2px; - border-radius: 4px; - cursor: pointer; - display: flex; - flex-direction: row; - gap: 4px; - color: rgb(0, 99, 8); - } - - .variable { - border: 1px solid rgb(139, 197, 255); - background-color: rgb(173, 214, 255); - color: rgb(26, 140, 255); - padding: 4px; - margin: 2px; - border-radius: 4px; - cursor: pointer; - display: flex; - flex-direction: row; - gap: 4px; - } - - -} - -.editor .step-placeholder { - border: 1px solid #ccc; - background-color: #ddd; - padding: 2px; - margin: 2px; - border-radius: 4px; - cursor: pointer; -} - -.step-missing { - color: red; - font-weight: bold; -} - -.bold { - font-weight: 700; -} - - -.p-button { - font-weight: 500; -} - -$sizes: 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96 !default; -@for $i from 1 through list.length($sizes) { - .fs-#{list.nth($sizes, $i)} { - font-size: #{list.nth($sizes, $i)}px; - } -} - -.rotate { - animation: rotate 2s linear infinite; -} - -@keyframes rotate { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -// .premium { -// &.p-button { -// background-color: #FFD7004D; -// border-color: #FFD7004D; -// color: #ffffff; -// } -// } diff --git a/src/renderer/style/main.ts b/src/renderer/style/main.ts deleted file mode 100644 index 53c8db8a..00000000 --- a/src/renderer/style/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { darken } from 'polished' - -export const primary = "#3B82F6" -export const primaryDarken1 = darken(0.05)(primary) -export const primaryDarken2 = darken(0.1)(primary) diff --git a/src/renderer/utils/config.ts b/src/renderer/utils/config.ts deleted file mode 100644 index ccced11e..00000000 --- a/src/renderer/utils/config.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { useAPI } from '@renderer/composables/api' -import { klona } from 'klona' - -export const loadInternalFile = (name: string) => { - const api = useAPI() - - return api.execute('config:load', { - config: name - }) -} - -export const saveInternalFile = (name: string, data: unknown) => { - const api = useAPI() - - api.execute('config:save', { - config: name, - data: JSON.stringify(klona(data)) - }) -} - -export const loadExternalFile = (path: string) => { - const api = useAPI() - - return api.execute('fs:read', { - path - }) -} - -export const saveExternalFile = (path: string, data: unknown) => { - const api = useAPI() - - api.execute('fs:write', { - path, - content: JSON.stringify(klona(data)) - }) -} - -export const createConfig = (config: string) => { - const api = useAPI() - - const load = async () => { - return api.execute('config:load', { - config - }) as Promise< - | { type: 'error'; ipcError: string; code?: string } - | { type: 'success'; result: { result: T } } - > - // TODO: better typing - } - - const save = async (data: T) => { - await api.execute('config:save', { - config, - data: JSON.stringify(klona(data)) - }) - } - - const backup = async (suffix: string) => { - const data = await load() - if (data.type === 'error') { - throw new Error(data.ipcError) - } - await api.execute('config:save', { - config: `${config}_${suffix}`, - data: JSON.stringify(klona(data.result.result)) - }) - } - - return { - save, - load, - backup - } -} diff --git a/src/renderer/utils/evaluator.ts b/src/renderer/utils/evaluator.ts deleted file mode 100644 index a28adb78..00000000 --- a/src/renderer/utils/evaluator.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { BlockAction, Steps } from '@@/model' -import { createQuickJs, CreateQuickJSFn } from './quickjs' -import { useLogger } from '@@/logger' - -export const makeResolvedParams = async ( - data: { - params: BlockAction['params'] - steps: Steps - variables: Record - context: Record - }, - onItem: (item: any) => string = (item: any) => item, - _vm?: Awaited | undefined -) => { - const { logger } = useLogger() - const vm = _vm ?? (await createQuickJs()) - - const result: Record = {} - - const ctx = 'createContext' in vm ? (vm as any).createContext() : null - - for (const [paramName, param] of Object.entries(data.params)) { - try { - const parameterCodeValue = (param.value ?? '').toString() - - const runParams = { - steps: data.steps, - params: {}, - variables: data.variables - } - - const output = ctx ? ctx.run(parameterCodeValue, runParams) : await vm.run(parameterCodeValue, runParams) - - const outputResult = onItem(output) - - result[paramName] = outputResult - } catch (e) { - logger().error('error', e) - result[paramName] = '' - } - } - - if (ctx) { - ctx.dispose() - } - - return result -} diff --git a/src/renderer/utils/fmt.ts b/src/renderer/utils/fmt.ts deleted file mode 100644 index 1ad09f09..00000000 --- a/src/renderer/utils/fmt.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const fmt = { - param: (value: string, variant?: 'primary' | 'secondary' | undefined, ifEmpty: string = "") => { - return `${value ? value : ifEmpty}` - } -} diff --git a/src/renderer/utils/graph.ts b/src/renderer/utils/graph.ts deleted file mode 100644 index 325a5678..00000000 --- a/src/renderer/utils/graph.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Block } from '@@/model' - -export const walker = async (graph: Array, onNode: (node: Block) => Promise) => { - for (const node of graph) { - /* if (node.type === 'condition') { - await onNode(node) - - await walker(node.branchTrue, onNode) - await walker(node.branchFalse, onNode) - } else */if (node.type === 'action') { - await onNode(node) - } /* else if (node.type === 'loop') { - await onNode(node) - - await walker(node.children, onNode) - } */else if (node.type === 'comment') { - await onNode(node) - } else if (node.type === 'event') { - await onNode(node) - } - } -} diff --git a/src/renderer/utils/quickjs.ts b/src/renderer/utils/quickjs.ts deleted file mode 100644 index 3fa96fef..00000000 --- a/src/renderer/utils/quickjs.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { useLogger } from '@@/logger' -import { isRenderer } from '@@/validation' -import { newQuickJSWASMModuleFromVariant, newVariant, RELEASE_SYNC, QuickJSContext } from 'quickjs-emscripten' -import { Arena } from 'quickjs-emscripten-sync' -import { fmt } from './fmt' - -class EvaluationError extends Error { - constructor( - public name: string, - public description: string - ) { - super(description) - this.name = name - } -} - -export const createQuickJs = async () => { - const { logger } = useLogger() - - let location: string - if (isRenderer()) { - location = (await import('@jitl/quickjs-wasmfile-release-sync/wasm?url')).default - } else { - const { join } = await import('node:path') - const { dirname } = await import('@main/paths') - const _dirname = await dirname() - location = join(_dirname, 'emscripten-module.wasm') - } - - const variant = newVariant(RELEASE_SYNC, { - wasmLocation: location - }) - const quickjs = await newQuickJSWASMModuleFromVariant(variant) - - const createContext = () => { - const vm = quickjs.newContext() - const arena = new Arena(vm, { isMarshalable: true }) - - const run = (code: string, params: Record) => { - const exposed = { - fmt, - ...params - } - arena.expose(exposed) - - const finalCode = `(() => { - return ${code}; - })()` - - try { - return arena.evalCode(finalCode) - } catch (e) { - logger().error('error', e) - logger().error('Final code was', finalCode) - throw new EvaluationError(e.name, e.message) - } - } - - return { - run, - dispose: () => { - try { - arena.dispose() - } catch (e) { - logger().error('Failed to dispose arena', e) - } - try { - vm.dispose() - } catch (e) { - logger().error('Failed to dispose VM', e) - } - } - } - } - - const run = (code: string, params: Record) => { - const ctx = createContext() - try { - return ctx.run(code, params) - } finally { - try { - ctx.dispose() - } catch (e) { - logger().error('Failed to dispose context', e) - } - } - } - - return { - run, - createContext - } -} - -export type CreateQuickJSFn = ReturnType diff --git a/src/shared/apis.ts b/src/shared/apis.ts deleted file mode 100644 index 6d12b3aa..00000000 --- a/src/shared/apis.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { RendererPluginDefinition } from '@pipelab/plugin-core' -import type { Tagged } from 'type-fest' -import { PresetResult, Steps } from './model' -import { AppConfig } from '@main/config' -import { - BuildHistoryEntry, - BuildHistoryQuery, - BuildHistoryResponse, - BuildHistoryConfig, - RetentionPolicy -} from './build-history' - -type Event = - | { type: TYPE; data: DATA } - | { type: 'log'; data: { decorator: string; message: unknown[]; time: number } } -type EndEvent = { - type: 'end' - data: - | { - type: 'success' - result: DATA - } - | { - type: 'error' - ipcError: string - code?: string - } -} - -export type Presets = Record - -export type IpcDefinition = { - 'fs:read': [ - // input - { path: string }, - EndEvent<{ content: string }> - ] - 'fs:remove': [ - // input - { path: string }, - EndEvent - ] - 'fs:write': [ - // input - { - path: string - content: string - }, - EndEvent<{ ok: boolean }> - ] - 'fs:rm': [ - // input - { - path: string - recursive: boolean - force: boolean - }, - EndEvent<{ ok: boolean }> - ] - 'settings:reset': [ - // input - { key: keyof AppConfig }, - EndEvent<{ result: string }> - ] - 'dialog:showOpenDialog': [ - // input - Electron.OpenDialogOptions, - EndEvent<{ canceled: boolean; filePaths: string[] }> - ] - 'dialog:showSaveDialog': [ - // input - Electron.SaveDialogOptions, - EndEvent<{ canceled: boolean; filePath: string | undefined }> - ] - 'nodes:get': [void, EndEvent<{ nodes: RendererPluginDefinition[] }>] - 'presets:get': [void, EndEvent] - 'action:execute': [ - { - pluginId: string - nodeId: string - params: any - steps: Steps - }, - ( - | Event<'progress', unknown> - | Event<'progress', unknown> - | EndEvent<{ outputs: Record; tmp: string }> - ) - ] - 'condition:execute': [ - { - pluginId: string - nodeId: string - params: any - steps: Steps - }, - ( - | Event<'progress', unknown> - | Event<'progress', unknown> - | EndEvent<{ outputs: Record; value: boolean }> - ) - ] - 'constants:get': [void, EndEvent<{ result: { userData: string } }>] - - 'config:load': [{ config: string }, EndEvent<{ result: any }>] - 'config:save': [{ data: string; config: string }, EndEvent<{ result: 'ok' }>] - 'action:cancel': [void, EndEvent<{ result: 'ok' | 'ko' }>] - 'settings:load': [never, EndEvent<{ result: AppConfig }>] - 'settings:save': [AppConfig, EndEvent<{ result: 'ok' | 'ko' }>] - - // Build History APIs - 'build-history:save': [{ entry: BuildHistoryEntry }, EndEvent<{ result: 'ok' | 'ko' }>] - 'build-history:get': [{ id: string }, EndEvent<{ entry?: BuildHistoryEntry }>] - 'build-history:get-all': [{ query?: BuildHistoryQuery }, EndEvent] - 'build-history:update': [ - { id: string; updates: Partial }, - EndEvent<{ result: 'ok' | 'ko' }> - ] - 'build-history:delete': [{ id: string }, EndEvent<{ result: 'ok' | 'ko' }>] - 'build-history:clear': [void, EndEvent<{ result: 'ok' | 'ko' }>] - 'build-history:get-storage-info': [ - void, - EndEvent<{ - totalEntries: number - totalSize: number - oldestEntry?: number - newestEntry?: number - }> - ] - 'build-history:configure': [ - { config: Partial }, - EndEvent<{ result: 'ok' | 'ko' }> - ] - 'graph:execute': [ - { - graph: any[] - variables: any[] - pipelineId?: string - projectId?: string - projectName?: string - projectPath?: string - }, - ( - | { type: 'node-enter'; data: { nodeUid: string; nodeName: string } } - | { type: 'node-exit'; data: { nodeUid: string; nodeName: string } } - | { type: 'node-log'; data: { nodeUid: string; logData: any } } - | EndEvent<{ result: any; buildId: string }> - ) - ] -} - -export type Channels = keyof IpcDefinition -export type Data = IpcDefinition[KEY][0] -export type Events = IpcDefinition[KEY][1] -export type End = Extract['data'] - -export type Message = { - // the channel to communicate - requestId: RequestId - data: any -} -export type RequestId = Tagged - -// type Output = End<'fs:openFolder'> diff --git a/src/shared/build-history.ts b/src/shared/build-history.ts deleted file mode 100644 index a238cc5d..00000000 --- a/src/shared/build-history.ts +++ /dev/null @@ -1,119 +0,0 @@ -// Build History Storage Types and Interfaces - -export interface ExecutionStep { - id: string - name: string - status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' - startTime: number - endTime?: number - duration?: number - logs: LogEntry[] - error?: ExecutionError - output?: Record -} - -export interface ExecutionError { - message: string - stack?: string - code?: string - timestamp: number -} - -export interface LogEntry { - id: string - timestamp: number - level: 'debug' | 'info' | 'warn' | 'error' - message: string - source?: string - data?: Record -} - -export interface BuildHistoryEntry { - id: string - pipelineId: string - projectName: string - projectPath: string - status: 'running' | 'completed' | 'failed' | 'cancelled' - startTime: number - endTime?: number - duration?: number - steps: ExecutionStep[] - totalSteps: number - completedSteps: number - failedSteps: number - cancelledSteps: number - logs: LogEntry[] - error?: ExecutionError - output?: Record - metadata?: Record - userId?: string - createdAt: number - updatedAt: number -} - -// Query interface supporting both pipeline and scenario filtering -export interface BuildHistoryQuery { - pipelineId?: string -} - -export interface BuildHistoryResponse { - entries: BuildHistoryEntry[] - total: number -} - -// Storage interfaces - Simplified for pipeline-specific storage -export interface IBuildHistoryStorage { - save(entry: BuildHistoryEntry): Promise - get(id: string): Promise - getAll(): Promise - getByPipeline(pipelineId: string): Promise - update(id: string, updates: Partial): Promise - delete(id: string): Promise - clear(): Promise - getStorageInfo(): Promise<{ - totalEntries: number - totalSize: number - oldestEntry?: number - newestEntry?: number - }> -} - -// Retention policy configuration -export interface RetentionPolicy { - enabled: boolean - maxEntries: number - maxAge: number // in milliseconds - maxSize: number // in bytes - keepFailedBuilds: boolean - keepSuccessfulBuilds: boolean -} - -// Storage configuration -export interface BuildHistoryConfig { - storagePath: string - indexFileName: string - entryFilePrefix: string - retentionPolicy: RetentionPolicy -} - -// Authorization and subscription types -export interface SubscriptionBenefit { - id: string - name: string - description?: string -} - -export interface SubscriptionError extends Error { - code: 'SUBSCRIPTION_REQUIRED' | 'SUBSCRIPTION_EXPIRED' | 'BENEFIT_NOT_FOUND' | 'UNAUTHORIZED' - benefit?: string - userMessage: string -} - -export interface AuthorizationContext { - userId?: string - hasBenefit: (benefitId: string) => boolean - isPaidUser: boolean -} - -// Authorization check function type -export type AuthorizationCheck = (context: AuthorizationContext) => void diff --git a/src/shared/graph.ts b/src/shared/graph.ts deleted file mode 100644 index 566451c5..00000000 --- a/src/shared/graph.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { makeResolvedParams } from '@renderer/utils/evaluator' -import { Steps } from '@@/model' -import { Variable } from './libs/core-app' -import { RendererPluginDefinition } from './libs/plugin-core' -import { Block } from './model' -import { Context } from '@renderer/store/editor' -import { End } from './apis' -import { useLogger } from './logger' -import { variableToFormattedVariable } from '@renderer/composables/variables' -import { createQuickJs } from '@renderer/utils/quickjs' - -const getPluginDefinition = (pluginId: string, definitions: Array) => { - const result = definitions.find((nodeDef) => { - return nodeDef.id === pluginId - }) - return result -} - -const getNodeDefinition = ( - nodeId: string, - pluginId: string, - definitions: Array -) => { - // const getNodeDefinition = (node: T extends Block ? T : never) => { - const plugin = getPluginDefinition(pluginId, definitions) - if (plugin) { - return plugin.nodes.find((pluginNode) => pluginNode.node.id === nodeId) - } - return undefined -} - -export const processGraph = async (options: { - graph: Array - definitions: Array - // editor user defined variables - variables: Array - // steps outputs - steps: Steps - // context like loopindex - context: Context - onExecuteItem: ( - node: Block, - params: Record, - steps: Steps - ) => Promise | End<'action:execute'>> - onNodeEnter: (node: Block) => void - onNodeExit: (node: Block) => void - abortSignal?: AbortSignal -}) => { - const { logger } = useLogger() - - for (const node of options.graph) { - // Check if operation was aborted - if (options.abortSignal?.aborted) { - const abortError = new Error('Aborted') - abortError.name = 'AbortError' - throw abortError - } - - const rawNode = node - - const pluginDefinition = getPluginDefinition(node.origin.pluginId, options.definitions) - const nodeDefinition = getNodeDefinition( - node.origin.nodeId, - node.origin.pluginId, - options.definitions - ) - - /* if (rawNode.type === 'condition') { - options.onNodeEnter(rawNode) - - const newParams = await makeResolvedParams({ - params: rawNode.params, - variables: options.variables, - steps: options.steps, - context: options.context - }) - - const result = await options.onExecuteItem(node, newParams, options.steps) as End<'condition:execute'> - - if ('result' in result) { - logger().error(result.result) - options.onNodeExit(rawNode) - throw new Error('Condition error') - } else { - const { value, outputs } = result - if (!options.steps[rawNode.uid]) { - options.steps[rawNode.uid] = { - outputs: {} - } - } - options.steps[rawNode.uid].outputs = outputs - - if (value === true) { - await processGraph({ - graph: rawNode.branchTrue, - ...options, - abortSignal: options.abortSignal - }) - } else { - await processGraph({ - graph: rawNode.branchFalse, - ...options, - abortSignal: options.abortSignal - }) - } - } - options.onNodeExit(rawNode) - } else */ if (rawNode.type === 'action') { - if (rawNode.disabled === true) { - console.warn( - `Node ${rawNode.uid} (${rawNode.origin.pluginId}::${rawNode.origin.nodeId}) is disabled` - ) - continue - } - - options.onNodeEnter(rawNode) - - const vm = await createQuickJs() - - const variables = await variableToFormattedVariable(vm, options.variables) - console.log('variables', variables) - - const newParams = await makeResolvedParams( - { - params: rawNode.params, - variables, - steps: options.steps, - context: options.context - }, - undefined, - vm - ) - - const result = (await options.onExecuteItem( - node, - newParams, - options.steps - )) as End<'action:execute'> - - if (result.type === 'error') { - logger().error(result.ipcError) - options.onNodeExit(rawNode) - // Check if it's an AbortError from cancellation - if (result.ipcError && typeof result.ipcError === 'object' && (result.ipcError as Error).name === 'AbortError') { - throw result.ipcError - } - throw new Error(`"${nodeDefinition.node.name}" action error: ${result.ipcError}`) - } - - if (result.type === 'success') { - if (!options.steps[rawNode.uid]) { - options.steps[rawNode.uid] = { - outputs: {} - } - } - options.steps[rawNode.uid].outputs = result.result.outputs - } - options.onNodeExit(rawNode) - } else if (rawNode.type === 'loop') { - options.onNodeEnter(rawNode) - - // const context = {} - - // const arrayToLoopOn = await evaluate(rawNode.params.value, context) - - // element is the value of the element at loopindex - // let loopindex = 0 - // for (const _element of arrayToLoopOn) { - // await processGraph(rawNode.children, definitions, variables, steps, { - // ...context, - // loopindex - // }) - - // loopindex += 1 - // } - - // continue after loop - - // TODO: process loop - // const result = await api.execute('node:execute', { - // nodeId: rawNode.origin.nodeId, - // pluginId: rawNode.origin.pluginId, - // params: rawNode.params - // }) - // console.log('result', result) - options.onNodeExit(rawNode) - } else if (rawNode.type === 'comment') { - // pass - } else if (rawNode.type === 'event') { - options.onNodeEnter(rawNode) - // pass - options.onNodeExit(rawNode) - } else { - logger().error('Unknown node type', rawNode.type) - } - - logger().info('steps', options.steps) - } - return options -} diff --git a/src/shared/i18n-utils.ts b/src/shared/i18n-utils.ts deleted file mode 100644 index 2bff1992..00000000 --- a/src/shared/i18n-utils.ts +++ /dev/null @@ -1,10 +0,0 @@ -import en_US from './i18n/en_US.json' -import fr_FR from './i18n/fr_FR.json' -import pt_BR from './i18n/pt_BR.json' -import zh_CN from './i18n/zh_CN.json' -import es_ES from './i18n/es_ES.json' -import de_DE from './i18n/de_DE.json' - -type MessageSchema = typeof en_US -export type Locales = 'en-US' | 'fr-FR' | 'pt-BR' | 'zh-CN' | 'es-ES' | 'de-DE' -export { MessageSchema, en_US, fr_FR, pt_BR, zh_CN, es_ES, de_DE } diff --git a/src/shared/i18n/de_DE.json b/src/shared/i18n/de_DE.json deleted file mode 100644 index 71969e0d..00000000 --- a/src/shared/i18n/de_DE.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "settings": { - "darkTheme": "Dark theme", - "language": "Language", - "languageOptions": { - "en-US": "English", - "fr-FR": "French", - "pt-BR": "Portuguese", - "zh-CN": "Chinese", - "es-ES": "Spanish", - "de-DE": "German" - }, - "tabs": { - "general": "General", - "storage": "Storage", - "integrations": "Integrations", - "advanced": "Advanced", - "billing": "Billing" - }, - "clearTempFolders": "Automatically clean up temporary files", - "clearTempFoldersDescription": "Wenn aktiviert, werden alle temporären Dateien, die während der Pipeline-Ausführung erstellt wurden, automatisch gelöscht, nachdem die Pipeline abgeschlossen ist. Dies hilft, Speicherplatz auf der Festplatte zu sparen, aber möglicherweise müssen Sie selbst Artefakte kopieren, um sie zu bewahren.", - "pipeline-cache-folder": "Pipeline Cache Folder:", - "enter-or-browse-for-a-folder": "Enter or browse for a folder", - "browse": "Browse", - "manage-where-the-app-stores-temporary-and-cache-files": "Manage where the app stores temporary and cache files.", - "clear-cache": "Clear cache", - "reset-to-default": "Reset to default", - "manage-subscription": "Manage Subscription", - "renewal-date": "Renewal Date", - "start-date": "Start Date:", - "cache-cleared-successfully": "Cache cleared successfully", - "failed-to-clear-cache-error-message": "Failed to clear cache: {0}", - "failed-to-reset-cache-folder-error-message": "Failed to reset cache folder: {0}", - "select-cache-folder": "Select Cache Folder" - }, - "headers": { - "dashboard": "Dashboard", - "scenarios": "Scenarios", - "editor": "Editor", - "billing": "Billing", - "team": "Team" - }, - "base": { - "close": "Schließen", - "save": "Speichern", - "run": "Ausführen", - "cancel": "Abbrechen", - "end": "Ende", - "delete": "Löschen", - "logs": "Protokolle", - "ok": "OK", - "add": "Hinzufügen" - }, - "editor": { - "invalid-file-content": "Invalid file content", - "welcome-back": "Welcome back!", - "please-log-in-to-run-a-scenario": "Please log in to run a scenario", - "execution-done": "Execution done", - "your-project-has-been-executed-successfully": "Your project has been executed successfully", - "execution-failed": "Execution failed", - "project-has-encountered-an-error": "Project has encountered an error:", - "project-saved": "Project saved", - "your-project-has-be-saved-successfully": "Your project has be saved successfully" - }, - "home": { - "invalid-preset": "Invalid preset", - "store-project-on-the-cloud": "Store project on the cloud", - "cloud": "Cloud", - "store-project-locally": "Store project locally", - "local": "Local", - "invalid-number-of-paths-selected": "Invalid number of paths selected", - "pipelab-project": "Pipelab Project", - "choose-a-new-path": "Choose a new path", - "invalid-file-type": "Invalid file type", - "create-project": "Create project", - "duplicate-project": "Duplicate project", - "project-name": "Project Name", - "new-project": "New Project", - "open": "Open", - "your-projects": "Your projects", - "no-projects-yet": "No projects yet" - }, - "scenarios": { - "scenarios": "Scenarios" - } -} \ No newline at end of file diff --git a/src/shared/i18n/en_US.json b/src/shared/i18n/en_US.json deleted file mode 100644 index 15d640cd..00000000 --- a/src/shared/i18n/en_US.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "settings": { - "darkTheme": "Dark theme", - "autosave": "Autosave", - "autosaveDescription": "When enabled, your changes will be automatically saved as you edit your pipelines.", - "language": "Language", - "languageOptions": { - "en-US": "English", - "fr-FR": "French", - "pt-BR": "Portuguese", - "zh-CN": "Chinese", - "es-ES": "Spanish", - "de-DE": "German" - }, - "tabs": { - "general": "General", - "storage": "Storage", - "integrations": "Integrations", - "advanced": "Advanced", - "billing": "Billing" - }, - "clearTempFolders": "Automatically clean up temporary files", - "clearTempFoldersDescription": "When enabled, all temporary files created during pipeline execution will be automatically deleted after the pipeline completes. This helps save disk space but you may need to copy artifacts yourself to preserve them.", - "pipeline-cache-folder": "Pipeline Cache Folder:", - "enter-or-browse-for-a-folder": "Enter or browse for a folder", - "browse": "Browse", - "manage-where-the-app-stores-temporary-and-cache-files": "Manage where the app stores temporary and cache files.", - "clear-cache": "Clear cache", - "reset-to-default": "Reset to default", - "manage-subscription": "Manage Subscription", - "renewal-date": "Renewal Date", - "start-date": "Start Date:", - "cache-cleared-successfully": "Cache cleared successfully", - "failed-to-clear-cache-error-message": "Failed to clear cache: {0}", - "failed-to-reset-cache-folder-error-message": "Failed to reset cache folder: {0}", - "select-cache-folder": "Select Cache Folder", - "restart-dashboard-tour": "Restart Dashboard Tour", - "restart-editor-tour": "Restart Editor Tour", - "tour-reset-success": "Tour has been reset. It will start the next time you visit the page." - }, - "headers": { - "dashboard": "Dashboard", - "scenarios": "Scenarios", - "editor": "Editor", - "billing": "Billing", - "team": "Team" - }, - "navigation": { - "build-history": "Build History" - }, - "base": { - "close": "Close", - "save": "Save", - "run": "Run", - "cancel": "Cancel", - "end": "End", - "delete": "Delete", - "logs": "Logs", - "ok": "OK", - "add": "Add", - "search": "Search..." - }, - "editor": { - "invalid-file-content": "Invalid file content", - "welcome-back": "Welcome back!", - "please-log-in-to-run-a-scenario": "Please log in to run a scenario", - "execution-done": "Execution done", - "your-project-has-been-executed-successfully": "Your project has been executed successfully", - "execution-failed": "Execution failed", - "project-has-encountered-an-error": "Project has encountered an error:", - "project-saved": "Project saved", - "your-project-has-be-saved-successfully": "Your project has be saved successfully", - "view-history": "History", - "add-plugin": "Add plugin", - "display-advanced-nodes": "Display advanced nodes" - }, - "home": { - "invalid-preset": "Invalid preset", - "store-project-on-the-cloud": "Store project on the cloud", - "cloud": "Cloud", - "store-project-locally": "Store project locally", - "local": "Local", - "invalid-number-of-paths-selected": "Invalid number of paths selected", - "pipelab-project": "Pipelab Project", - "choose-a-new-path": "Choose a new path", - "invalid-file-type": "Invalid file type", - "create-project": "Create project", - "duplicate-project": "Duplicate project", - "project-name": "Project Name", - "new-project": "New Project", - "new-pipeline": "New pipeline", - "open": "Open", - "import": "Import", - "pipeline-name": "Pipeline Name", - "your-projects": "Your projects", - "no-projects-yet": "No projects yet", - "no-pipelines-yet": "No pipelines yet", - "delete-project": "Delete project", - "confirm-delete-project": "Are you sure you want to delete this project? This action cannot be undone.", - "cannot-delete-project": "Cannot delete project", - "project-not-empty": "This project contains pipelines. Please delete them first.", - "transfer": "Transfer", - "transfer-successful": "Transfer Successful", - "pipeline-transferred": "Pipeline transferred successfully", - "select-project": "Select Project", - "build-history": "Build History", - "duplicate": "Duplicate", - "rename-project": "Rename Project", - "new-project-name": "New Project Name", - "premium-feature": "This is a premium feature", - "migrate-warning": "This file type will soon be not supported anymore. Please migrate it using the option from the menu", - "simple-pipeline": "Simple pipeline", - "advanced-pipeline": "Advanced pipeline", - "new-simple-project": "New simple project", - "new-advanced-project": "New advanced project", - "store-project-internally": "Store project internally", - "internal": "Internal", - "confirm-migration-message": "Are you sure you want to migrate this pipeline to internal storage? This will create a copy in the internal storage managed by Pipelab.", - "migrate-pipeline": "Migrate Pipeline", - "migration-success": "Pipeline migrated successfully", - "migrate-to-internal": "Migrate to Internal" - }, - "scenarios": { - "scenarios": "Scenarios" - }, - "tour": { - "start-tour": "Start Tour", - "projects-list-title": "Project Navigator", - "projects-list-description": "This sidebar shows all your projects. Selecting a project will display its associated pipelines in the main area.", - "add-project-title": "Create New Project", - "add-project-description": "Projects help you organize your pipelines by topic or client. Click here to start a fresh project.", - "new-pipeline-title": "Build a Pipeline", - "new-pipeline-description": "Ready to automate? Create a new pipeline to start adding logic and blocks.", - "project-actions-title": "Project Management", - "project-actions-description": "Use these buttons to rename or delete the currently selected project.", - "editor-canvas-title": "The Visual Canvas", - "editor-canvas-description": "This is your workspace. Drag and drop blocks here to define your automation flow from top to bottom.", - "editor-save-title": "Save Progress", - "editor-save-description": "Keep your changes safe. We recommend saving frequently, especially after complex logic changes.", - "editor-run-title": "Test your Automation", - "editor-run-description": "Click Run to start the execution. Pipelab will process each block and provide real-time feedback.", - "editor-logs-title": "Execution Logs", - "editor-logs-description": "The logs window shows exactly what's happening during execution. Great for debugging and monitoring progress.", - "editor-close-title": "Exit Editor", - "editor-close-description": "Done for now? Return to the dashboard to manage other projects or pipelines." - } -} diff --git a/src/shared/i18n/es_ES.json b/src/shared/i18n/es_ES.json deleted file mode 100644 index 1e58da79..00000000 --- a/src/shared/i18n/es_ES.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "settings": { - "darkTheme": "Dark theme", - "language": "Language", - "languageOptions": { - "en-US": "English", - "fr-FR": "French", - "pt-BR": "Portuguese", - "zh-CN": "Chinese", - "es-ES": "Spanish", - "de-DE": "German" - }, - "tabs": { - "general": "General", - "storage": "Storage", - "integrations": "Integrations", - "advanced": "Advanced", - "billing": "Billing" - }, - "clearTempFolders": "Automatically clean up temporary files", - "clearTempFoldersDescription": "Cuando está habilitado, todos los archivos temporales creados durante la ejecución del pipeline se eliminarán automáticamente después de que el pipeline se complete. Esto ayuda a ahorrar espacio en el disco, pero puede que necesite copiar los artefactos usted mismo para preservarlos.", - "pipeline-cache-folder": "Pipeline Cache Folder:", - "enter-or-browse-for-a-folder": "Enter or browse for a folder", - "browse": "Browse", - "manage-where-the-app-stores-temporary-and-cache-files": "Manage where the app stores temporary and cache files.", - "clear-cache": "Clear cache", - "reset-to-default": "Reset to default", - "manage-subscription": "Manage Subscription", - "renewal-date": "Renewal Date", - "start-date": "Start Date:", - "cache-cleared-successfully": "Cache cleared successfully", - "failed-to-clear-cache-error-message": "Failed to clear cache: {0}", - "failed-to-reset-cache-folder-error-message": "Failed to reset cache folder: {0}", - "select-cache-folder": "Select Cache Folder" - }, - "headers": { - "dashboard": "Dashboard", - "scenarios": "Scenarios", - "editor": "Editor", - "billing": "Billing", - "team": "Team" - }, - "base": { - "close": "Cerrar", - "save": "Guardar", - "run": "Ejecutar", - "cancel": "Cancelar", - "end": "Fin", - "delete": "Eliminar", - "logs": "Registros", - "ok": "Aceptar", - "add": "Añadir" - }, - "editor": { - "invalid-file-content": "Invalid file content", - "welcome-back": "Welcome back!", - "please-log-in-to-run-a-scenario": "Please log in to run a scenario", - "execution-done": "Execution done", - "your-project-has-been-executed-successfully": "Your project has been executed successfully", - "execution-failed": "Execution failed", - "project-has-encountered-an-error": "Project has encountered an error:", - "project-saved": "Project saved", - "your-project-has-be-saved-successfully": "Your project has be saved successfully" - }, - "home": { - "invalid-preset": "Invalid preset", - "store-project-on-the-cloud": "Store project on the cloud", - "cloud": "Cloud", - "store-project-locally": "Store project locally", - "local": "Local", - "invalid-number-of-paths-selected": "Invalid number of paths selected", - "pipelab-project": "Pipelab Project", - "choose-a-new-path": "Choose a new path", - "invalid-file-type": "Invalid file type", - "create-project": "Create project", - "duplicate-project": "Duplicate project", - "project-name": "Project Name", - "new-project": "New Project", - "open": "Open", - "your-projects": "Your projects", - "no-projects-yet": "No projects yet" - }, - "scenarios": { - "scenarios": "Scenarios" - } -} \ No newline at end of file diff --git a/src/shared/i18n/fr_FR.json b/src/shared/i18n/fr_FR.json deleted file mode 100644 index 9482ff12..00000000 --- a/src/shared/i18n/fr_FR.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "settings": { - "darkTheme": "Thème sombre", - "language": "Langue", - "languageOptions": { - "en-US": "English", - "fr-FR": "Français", - "pt-BR": "Portuguese", - "zh-CN": "Chinese", - "es-ES": "Spanish", - "de-DE": "German" - }, - "tabs": { - "general": "Général", - "storage": "Stockage", - "integrations": "Intégrations", - "advanced": "Avancé", - "billing": "Facturation" - }, - "clearTempFolders": "Nettoyer automatiquement les fichiers temporaires", - "clearTempFoldersDescription": "Lorsque cette option est activée, tous les fichiers temporaires créés lors de l'exécution du pipeline seront automatiquement supprimés une fois le pipeline terminé. Cela permet d'économiser de l'espace disque, mais vous devrez peut-être copier vous-même des artefacts pour les préserver.", - "pipeline-cache-folder": "Pipeline Cache Folder:", - "enter-or-browse-for-a-folder": "Enter or browse for a folder", - "browse": "Browse", - "manage-where-the-app-stores-temporary-and-cache-files": "Manage where the app stores temporary and cache files.", - "clear-cache": "Clear cache", - "reset-to-default": "Reset to default", - "manage-subscription": "Manage Subscription", - "renewal-date": "Renewal Date", - "start-date": "Start Date:", - "cache-cleared-successfully": "Cache cleared successfully", - "failed-to-clear-cache-error-message": "Failed to clear cache: {0}", - "failed-to-reset-cache-folder-error-message": "Failed to reset cache folder: {0}", - "select-cache-folder": "Select Cache Folder" - }, - "headers": { - "dashboard": "Tableau de bord", - "scenarios": "Scénarios", - "editor": "Éditeur", - "billing": "Facturation", - "team": "Équipe" - }, - "base": { - "close": "Fermer", - "save": "Enregistrer", - "run": "Exécuter", - "cancel": "Annuler", - "end": "Fin", - "delete": "Supprimer", - "logs": "Logs", - "ok": "OK", - "add": "Ajouter", - "search": "Rechercher..." - }, - "editor": { - "invalid-file-content": "Contenu du fichier invalide", - "welcome-back": "Bon retour parmi nous !", - "please-log-in-to-run-a-scenario": "Veuillez vous connecter pour exécuter un scénario", - "execution-done": "Exécution terminée", - "your-project-has-been-executed-successfully": "Votre projet a été exécuté avec succès", - "execution-failed": "Échec de l'exécution", - "project-has-encountered-an-error": "Le projet a rencontré une erreur :", - "project-saved": "Projet enregistré", - "your-project-has-be-saved-successfully": "Votre projet a été enregistré avec succès", - "add-plugin": "Ajouter un plugin", - "display-advanced-nodes": "Afficher les nœuds avancés" - }, - "home": { - "invalid-preset": "Préréglage non valide", - "store-project-on-the-cloud": "Enregistrer le projet en ligne", - "cloud": "En ligne", - "store-project-locally": "Enregistrer le projet localement", - "local": "Local", - "invalid-number-of-paths-selected": "Nombre non valide de chemins sélectionnés", - "pipelab-project": "Projet Pipelab", - "choose-a-new-path": "Choisissez un nouveau chemin", - "invalid-file-type": "Type de fichier invalide", - "create-project": "Créer un projet", - "duplicate-project": "Dupliquer le projet", - "project-name": "Nom du projet", - "new-project": "Nouveau projet", - "open": "Ouvrir", - "your-projects": "Vos projets", - "no-projects-yet": "Aucun projet jusqu'à présent" - }, - "scenarios": { - "scenarios": "Scénarios" - } -} \ No newline at end of file diff --git a/src/shared/i18n/pt_BR.json b/src/shared/i18n/pt_BR.json deleted file mode 100644 index 510ac694..00000000 --- a/src/shared/i18n/pt_BR.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "settings": { - "darkTheme": "Tema escuro", - "language": "Idioma", - "languageOptions": { - "en-US": "English", - "fr-FR": "French", - "pt-BR": "Portuguese", - "zh-CN": "Chinese", - "es-ES": "Spanish", - "de-DE": "German" - }, - "tabs": { - "general": "Geral", - "storage": "Armazenagem", - "integrations": "Integrações", - "advanced": "Avançado", - "billing": "Pagamento" - }, - "clearTempFolders": "Automatically clean up temporary files", - "clearTempFoldersDescription": "When enabled, all temporary files created during pipeline execution will be automatically deleted after the pipeline completes. This helps save disk space but you may need to copy artifacts yourself to preserve them.", - "pipeline-cache-folder": "Pipeline Cache Folder:", - "enter-or-browse-for-a-folder": "Enter or browse for a folder", - "browse": "Browse", - "manage-where-the-app-stores-temporary-and-cache-files": "Manage where the app stores temporary and cache files.", - "clear-cache": "Clear cache", - "reset-to-default": "Reset to default", - "manage-subscription": "Manage Subscription", - "renewal-date": "Renewal Date", - "start-date": "Start Date:", - "cache-cleared-successfully": "Cache cleared successfully", - "failed-to-clear-cache-error-message": "Failed to clear cache: {0}", - "failed-to-reset-cache-folder-error-message": "Failed to reset cache folder: {0}", - "select-cache-folder": "Select Cache Folder" - }, - "headers": { - "dashboard": "Dashboard", - "scenarios": "Scenarios", - "editor": "Editor", - "billing": "Billing", - "team": "Team" - }, - "base": { - "close": "Fechar", - "save": "Salvar", - "run": "Executar", - "cancel": "Cancelar", - "end": "Fim", - "delete": "Excluir", - "logs": "Logs", - "ok": "OK", - "add": "Adicionar" - }, - "editor": { - "invalid-file-content": "Invalid file content", - "welcome-back": "Welcome back!", - "please-log-in-to-run-a-scenario": "Please log in to run a scenario", - "execution-done": "Execution done", - "your-project-has-been-executed-successfully": "Your project has been executed successfully", - "execution-failed": "Execution failed", - "project-has-encountered-an-error": "Project has encountered an error:", - "project-saved": "Project saved", - "your-project-has-be-saved-successfully": "Your project has be saved successfully" - }, - "home": { - "invalid-preset": "Invalid preset", - "store-project-on-the-cloud": "Store project on the cloud", - "cloud": "Cloud", - "store-project-locally": "Store project locally", - "local": "Local", - "invalid-number-of-paths-selected": "Invalid number of paths selected", - "pipelab-project": "Pipelab Project", - "choose-a-new-path": "Choose a new path", - "invalid-file-type": "Invalid file type", - "create-project": "Create project", - "duplicate-project": "Duplicate project", - "project-name": "Project Name", - "new-project": "New Project", - "open": "Open", - "your-projects": "Your projects", - "no-projects-yet": "No projects yet" - }, - "scenarios": { - "scenarios": "Scenarios" - } -} \ No newline at end of file diff --git a/src/shared/i18n/zh_CN.json b/src/shared/i18n/zh_CN.json deleted file mode 100644 index b18bea2f..00000000 --- a/src/shared/i18n/zh_CN.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "settings": { - "darkTheme": "Dark theme", - "language": "Language", - "languageOptions": { - "en-US": "English", - "fr-FR": "French", - "pt-BR": "Portuguese", - "zh-CN": "Chinese", - "es-ES": "Spanish", - "de-DE": "German" - }, - "tabs": { - "general": "General", - "storage": "Storage", - "integrations": "Integrations", - "advanced": "Advanced", - "billing": "Billing" - }, - "clearTempFolders": "Automatically clean up temporary files", - "clearTempFoldersDescription": "When enabled, all temporary files created during pipeline execution will be automatically deleted after the pipeline completes. This helps save disk space but you may need to copy artifacts yourself to preserve them.", - "pipeline-cache-folder": "Pipeline Cache Folder:", - "enter-or-browse-for-a-folder": "Enter or browse for a folder", - "browse": "Browse", - "manage-where-the-app-stores-temporary-and-cache-files": "Manage where the app stores temporary and cache files.", - "clear-cache": "Clear cache", - "reset-to-default": "Reset to default", - "manage-subscription": "Manage Subscription", - "renewal-date": "Renewal Date", - "start-date": "Start Date:", - "cache-cleared-successfully": "Cache cleared successfully", - "failed-to-clear-cache-error-message": "Failed to clear cache: {0}", - "failed-to-reset-cache-folder-error-message": "Failed to reset cache folder: {0}", - "select-cache-folder": "Select Cache Folder" - }, - "headers": { - "dashboard": "Dashboard", - "scenarios": "Scenarios", - "editor": "Editor", - "billing": "Billing", - "team": "Team" - }, - "base": { - "close": "关闭", - "save": "保存", - "run": "运行", - "cancel": "取消", - "end": "结束", - "delete": "删除", - "logs": "日志", - "ok": "确定", - "add": "添加" - }, - "editor": { - "invalid-file-content": "Invalid file content", - "welcome-back": "Welcome back!", - "please-log-in-to-run-a-scenario": "Please log in to run a scenario", - "execution-done": "Execution done", - "your-project-has-been-executed-successfully": "Your project has been executed successfully", - "execution-failed": "Execution failed", - "project-has-encountered-an-error": "Project has encountered an error:", - "project-saved": "Project saved", - "your-project-has-be-saved-successfully": "Your project has be saved successfully" - }, - "home": { - "invalid-preset": "Invalid preset", - "store-project-on-the-cloud": "Store project on the cloud", - "cloud": "Cloud", - "store-project-locally": "Store project locally", - "local": "Local", - "invalid-number-of-paths-selected": "Invalid number of paths selected", - "pipelab-project": "Pipelab Project", - "choose-a-new-path": "Choose a new path", - "invalid-file-type": "Invalid file type", - "create-project": "Create project", - "duplicate-project": "Duplicate project", - "project-name": "Project Name", - "new-project": "New Project", - "open": "Open", - "your-projects": "Your projects", - "no-projects-yet": "No projects yet" - }, - "scenarios": { - "scenarios": "Scenarios" - } -} \ No newline at end of file diff --git a/src/shared/libs/.gitkeep b/src/shared/libs/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/shared/libs/core-app/index.ts b/src/shared/libs/core-app/index.ts deleted file mode 100644 index 448e0115..00000000 --- a/src/shared/libs/core-app/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './variables.js' \ No newline at end of file diff --git a/src/shared/libs/core-app/variables.ts b/src/shared/libs/core-app/variables.ts deleted file mode 100644 index 06b7366c..00000000 --- a/src/shared/libs/core-app/variables.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface VariableBase { - value: string - id: string - name: string - description: string -} - -export type Variable = VariableBase - -export const foo = 'aaa' diff --git a/src/shared/libs/migration/index.ts b/src/shared/libs/migration/index.ts deleted file mode 100644 index c5428a27..00000000 --- a/src/shared/libs/migration/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from './models/createMigration'; -export * from './models/createMigrator'; -export type { - MigrationSchema, - Migrator, - MigratorConfig, - MigrationFn, - SemVer, -} from './models/migration'; diff --git a/src/shared/libs/migration/models/createMigration.ts b/src/shared/libs/migration/models/createMigration.ts deleted file mode 100644 index 353a815a..00000000 --- a/src/shared/libs/migration/models/createMigration.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - MigrationFn, - MigrationObjInput, - MigrationClass, - MigrationSchema, - OmitVersion, - SemVer -} from './migration' - -export function createMigration< - Down extends MigrationSchema, - Current extends MigrationSchema, - Up extends MigrationSchema ->(migration: MigrationObjInput): MigrationClass { - return { - version: migration.version, - up: async (state, nextVersion) => { - const newState = (await migration.up(state, nextVersion)) as unknown as Up - newState.version = nextVersion as SemVer - return newState - }, - down: async (state, nextVersion) => { - const newState = (await migration.down(state, nextVersion)) as unknown as Down - newState.version = nextVersion as SemVer - return newState - } - } -} - -export const initialVersion = () => { - throw new Error('Unable to go down on the initial version!') -} - -export const finalVersion = () => { - throw new Error('Unable to go up on the final version!') -} - -// export const finalVersion = (state: T) => { -// return state -// } - -/** - * @deprecated - * @param version - * @param migration - * @returns - */ -export function initial( - version: SemVer, - migration: MigrationFn, OmitVersion> -): MigrationClass { - return createMigration({ - version, - up: migration, - down() { - throw new Error('Unable to go down on the initial version!') - } - }) -} - -export function final( - version: SemVer, - migration: MigrationFn, OmitVersion> -): MigrationClass { - return createMigration({ - version, - up: () => { - throw new Error(`Unable to go up on the final version "${version}"!`) - }, - down: migration - }) -} diff --git a/src/shared/libs/migration/models/createMigrator.ts b/src/shared/libs/migration/models/createMigrator.ts deleted file mode 100644 index 080f0c80..00000000 --- a/src/shared/libs/migration/models/createMigrator.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigratorConfig, Migrator, MigrationSchema } from './migration' - -export const createMigrator = < - InitialState extends MigrationSchema, - FinalState extends MigrationSchema ->() => { - return { - createDefault(defaultState: FinalState): FinalState { - return defaultState - }, - createMigrations( - config: MigratorConfig - ): Migrator { - return new Migrator(config) - } - } -} - -export type MigratorFactory< - InitialState extends MigrationSchema, - FinalState extends MigrationSchema -> = ReturnType> diff --git a/src/shared/libs/migration/models/migration.spec.ts b/src/shared/libs/migration/models/migration.spec.ts deleted file mode 100644 index 29d137d5..00000000 --- a/src/shared/libs/migration/models/migration.spec.ts +++ /dev/null @@ -1,343 +0,0 @@ -import { describe, test, expect, beforeAll, beforeEach, afterEach, vi } from 'vitest' -import { createMigration, final, finalVersion, initial, initialVersion } from './createMigration' -import { createMigrator, MigratorFactory } from './createMigrator' -import { Migrator, MigrationSchema } from './migration' -import { z } from 'zod' - -export const withMigration = (obj: z.AnyZodObject) => - z - .object({ - version: z.string() - }) - .merge(obj) - -interface V1 extends MigrationSchema { - dummyV1: string -} - -interface V2 extends MigrationSchema { - dummyV2: string -} - -interface V3 extends MigrationSchema { - dummyV3: string -} - -interface V4 extends MigrationSchema { - dummy: string -} - -const outputV1: V1 = { - dummyV1: 'aaa', - version: '1.0.0', -}; - -const outputV2: V2 = { - dummyV2: 'aaa', - version: '2.0.0' -} - -const outputV3: V3 = { - dummyV3: 'aaa', - version: '3.0.0' -} - -const outputV4: V4 = { - dummy: 'aaa', - version: '4.0.0' -} - -const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)) - -describe('migrator', () => { - let migratorInstance: MigratorFactory - let migratorMigrations: Migrator - beforeAll(() => { - // migratorInstance = createMigrator({ - // migrations: [ - // initial('1.0.0', (state) => ({ - // dummyV2: state.dummyV1, - // })), - // createMigration({ - // version: '2.0.0', - // up: (state) => ({ - // dummyV3: state.dummyV2, - // }), - // down: (state) => ({ - // dummyV1: state.dummyV2, - // }), - // }), - // createMigration({ - // version: '3.0.0', - // up: (state) => ({ - // dummy: state.dummyV3, - // }), - // down: (state) => ({ - // dummyV2: state.dummyV3, - // }), - // }), - // final('4.0.0', (state) => ({ - // dummyV3: state.dummy, - // })), - // ], - // }); - - migratorInstance = createMigrator() - migratorMigrations = migratorInstance.createMigrations({ - defaultValue: outputV1, - migrations: [ - createMigration({ - version: '1.0.0', - up: (state) => ({ - dummyV2: state.dummyV1 - }), - down: initialVersion - }), - createMigration({ - version: '2.0.0', - up: (state) => ({ - dummyV3: state.dummyV2 - }), - down: (state) => ({ - dummyV1: state.dummyV2 - }) - }), - createMigration({ - version: '3.0.0', - up: (state) => ({ - dummy: state.dummyV3 - }), - down: (state) => ({ - dummyV2: state.dummyV3 - }) - }), - createMigration({ - version: '4.0.0', - up: finalVersion, - down: (state) => ({ - dummyV3: state.dummy - }) - }) - ] - }) - }) - - test('should not need migration', () => { - expect(migratorMigrations.needMigration('4.0.0')).toBe(false) - expect(migratorMigrations.needMigration('5.0.0')).toBe(false) - expect(migratorMigrations.needMigration('4.1.0')).toBe(false) - expect(migratorMigrations.needMigration('4.0.1')).toBe(false) - expect(migratorMigrations.needMigration('5.0.1')).toBe(false) - }) - - test('should need migration', () => { - expect(migratorMigrations.needMigration('0.0.0')).toBe(true) - expect(migratorMigrations.needMigration('0.1.0')).toBe(true) - expect(migratorMigrations.needMigration('0.0.1')).toBe(true) - expect(migratorMigrations.needMigration('1.0.1')).toBe(true) - expect(migratorMigrations.needMigration('2.3.1')).toBe(true) - expect(migratorMigrations.needMigration('3.4.1')).toBe(true) - }) - - test('should migrate', async () => { - const input: V1 = { - dummyV1: 'aaa', - version: '1.0.0' - } - const result = await migratorMigrations.migrate(input) - expect(result).toStrictEqual(outputV4) - }) - - test('should return instance if same target version', async () => { - const input: V4 = { - dummy: 'aaa', - version: '4.0.0' - } - const result = await migratorMigrations.migrate(input) - expect(result).toStrictEqual(outputV4) - }) - - test('should not do anything if migrate up but nothing more', () => { - const input: V4 = { - dummy: 'aaa', - version: '4.0.0' - } - return expect(migratorMigrations.migrate(input)).resolves.toStrictEqual(outputV4) - }) - - test('should downgrade', async () => { - const input: V4 = { - dummy: 'aaa', - version: '4.0.0' - } - const result = await migratorMigrations.migrate(input) - expect(result).toEqual(outputV4) - const resultDown = await migratorMigrations.migrate(result, { - target: '3.0.0' - }) - expect(resultDown).toEqual(outputV3) - const resultDown2 = await migratorMigrations.migrate(resultDown, { - target: '2.0.0' - }) - expect(resultDown2).toEqual(outputV2) - const resultUp = await migratorMigrations.migrate(resultDown2, { - target: '3.0.0' - }) - expect(resultUp).toEqual(outputV3) - }) - - test('should throw if target is not in migrations', async () => { - const input: V4 = { - dummy: 'aaa', - version: '1.2.0' - } - - const badMigratorInstance = createMigrator().createMigrations({ - migrations: [ - initial('1.0.0', (state) => ({ - dummyV2: state.dummyV1 - })), - final('4.0.0', (state) => ({ - dummyV3: state.dummy - })) - ] - }) - - return expect(badMigratorInstance.migrate(input)).rejects.toThrow() - }) - - test('should throw on migration not found', async () => { - const input: V4 = { - dummy: 'aaa', - version: '1.2.0' - } - - const badMigratorInstance = createMigrator().createMigrations({ - migrations: [ - initial('1.0.0', (state) => ({ - dummyV2: state.dummyV1 - })), - final('4.0.0', (state) => ({ - dummyV3: state.dummy - })) - ] - }) - - await expect(badMigratorInstance.migrate(input)).rejects.toThrow() - }) - - test('should migrate an incomplete version (loose)', async () => { - const input: V1 = { - dummyV1: 'aaa', - // @ts-expect-error specific to the test - version: '1' - } - - const migrator = createMigrator().createMigrations({ - migrations: [ - createMigration({ - version: '1.0.0', - up: (state) => ({ - dummyV2: state.dummyV1 - }), - down: initialVersion - }), - createMigration({ - version: '2.0.0', - up: finalVersion, - down: (state) => ({ - dummyV1: state.dummyV2 - }) - }) - ] - }) - - const result = await migrator.migrate(input) - - expect(result).toEqual(expect.objectContaining({ version: '2.0.0' })) - }) - - test('should not migrate an incomplete version when coerce option disabled', async () => { - const input: V1 = { - dummyV1: 'aaa', - // @ts-expect-error specific to the test - version: '1' - } - - const migrator = createMigrator().createMigrations({ - migrations: [ - createMigration({ - version: '1.0.0', - up: (state) => ({ - dummyV2: state.dummyV1 - }), - down: initialVersion - }), - createMigration({ - version: '2.0.0', - up: finalVersion, - down: (state) => ({ - dummyV1: state.dummyV2 - }) - }) - ], - coerce: false - }) - - await expect(migrator.migrate(input)).rejects.toThrow( - 'Current version "1" not found in migrations' - ) - }) -}) - -describe('async', () => { - beforeEach(() => { - vi.useFakeTimers() - }) - afterEach(() => { - vi.restoreAllMocks() - }) - - test('should support async migration', async () => { - const input: V1 = { - dummyV1: 'aaa', - version: '1.0.0' - } - - const migrator = createMigrator().createMigrations({ - migrations: [ - createMigration({ - version: '1.0.0', - up: async (state) => { - await sleep(1000) - return { - dummyV2: state.dummyV1 - } - }, - down: initialVersion - }), - createMigration({ - version: '2.0.0', - up: finalVersion, - down: async (state) => { - await sleep(1000) - return { - dummyV1: state.dummyV2 - } - } - }) - ] - }) - - const promise = migrator.migrate(input) - - vi.advanceTimersByTime(1000) - - const result = await promise - - expect(result).toStrictEqual({ - dummyV2: 'aaa', - version: '2.0.0' - }) - }) -}) diff --git a/src/shared/libs/migration/models/migration.ts b/src/shared/libs/migration/models/migration.ts deleted file mode 100644 index a1db1b00..00000000 --- a/src/shared/libs/migration/models/migration.ts +++ /dev/null @@ -1,157 +0,0 @@ -import * as semver from 'semver' -import { coerce } from 'semver' -import { objectKeys } from '../utils/object-keys' -import { klona } from 'klona' -import { custom, InferOutput, object, ObjectEntries } from 'valibot' - -export type Awaitable = Promise | T - -export type MigrationFn = (state: From, targetVersion: string) => Awaitable - -export type MigrateOptions = { - debug?: boolean - target?: SemVer -} - -const SemverValidator = custom((input) => - typeof input === 'string' ? /^\d+\.\d+\.\d+$/.test(input) : false -) - -export const SemverVersionValidator = SemverValidator -// export const SemverVersionValidator = optional(SemverValidator, '1.0.0') - -export const MigrationSchemaValidator = object({ - version: SemverVersionValidator -}) - -export const createVersionSchema = (schema: OBJECTENTRIES) => - object({ - ...schema - }) - -export type MigrationSchema = InferOutput - -export type OmitVersion = Omit - -export type SemVer = `${number}.${number}.${number}` - -export interface MigrationClass { - version: SemVer - up: MigrationFn - down: MigrationFn -} - -export interface MigrationObjInput { - version: SemVer - up: MigrationFn, OmitVersion> - down: MigrationFn, OmitVersion> -} - -export interface MigratorConfig { - migrations: MigrationClass[] - coerce?: boolean - defaultValue?: FinalState -} - -export class Migrator { - current: SemVer - - migrations: Record> = {} - - coerce: boolean - defaultValue: OutputState - - constructor(config: MigratorConfig) { - config.migrations.forEach((migration) => { - this.migrations[migration.version] = migration - }) - - this.defaultValue = config?.defaultValue ?? ({} as OutputState) - - const versions = this.getVersions() - this.current = versions[versions.length - 1] - this.coerce = config?.coerce ?? true - } - - getVersions() { - const keys = objectKeys(this.migrations) - return semver.sort(keys) - } - - async migrate( - _state: MigrationSchema | undefined, - options?: MigrateOptions - ): Promise { - const state = _state ?? this.defaultValue - const currentVersion = this.tryCoerce(state.version) - const targetVersion = this.tryCoerce(options?.target ?? this.current) - - if (options?.debug) { - console.log('Migrating from', currentVersion, 'to', targetVersion) - } - - let finalState = klona(state) as any // Using any here because we'll be transforming between versions - const versions = this.getVersions() - const currentIndex = versions.indexOf(currentVersion) - const targetIndex = versions.indexOf(targetVersion) - - if (currentIndex === -1) { - throw new Error(`Current version "${currentVersion}" not found in migrations`) - } - if (targetIndex === -1) { - throw new Error(`Target version "${targetVersion}" not found in migrations`) - } - - // If we're already at the target version, return the state - if (currentIndex === targetIndex) { - return finalState as OutputState - } - - // Get the migration path - const isUpgrade = currentIndex < targetIndex - const increment = isUpgrade ? 1 : -1 - const direction = isUpgrade ? 'up' : 'down' - - // Perform migrations - for (let i = currentIndex; isUpgrade ? i < targetIndex : i > targetIndex; i += increment) { - const currentVersion = versions[i] - const nextVersion = versions[i + increment] - - if (options?.debug) { - console.log('\tMigrating to version:', nextVersion) - } - - // For upgrades, use current version's migration - // For downgrades, use previous version's migration - const migrationVersion = currentVersion - const migration = this.migrations[migrationVersion] - - // Remove version before migration - const { version: _, ...stateWithoutVersion } = finalState - - // Perform migration - const migratedState = await migration[direction](stateWithoutVersion, currentVersion) - - // Add new version - finalState = { - ...migratedState, - version: nextVersion - } - - if (options?.debug) { - console.log('\tMigrated state:', finalState) - } - } - - return finalState as OutputState - } - - tryCoerce(version: SemVer): SemVer { - return this.coerce ? ((coerce(version)?.version as SemVer | undefined) ?? version) : version - } - - needMigration(version: SemVer) { - const newVersion = this.tryCoerce(version) - return semver.lt(newVersion, this.current) - } -} diff --git a/src/shared/libs/plugin-construct/assets/script.ts b/src/shared/libs/plugin-construct/assets/script.ts deleted file mode 100644 index 2bf8bb5a..00000000 --- a/src/shared/libs/plugin-construct/assets/script.ts +++ /dev/null @@ -1,297 +0,0 @@ -import { Page } from 'playwright' -import { join } from 'node:path' - -const registerInstallButtonListener = (page: Page, log: typeof console.log) => { - // as soon as it appear, without blocking flow - // accept installing plugins - const installDialog = page.locator('#addonConfirmInstallDialog') - const installBtn = installDialog.locator('.okButton') - installBtn - .waitFor({ - timeout: 0 - }) - .then(async () => { - await installBtn.click() - log('installBtn clicked') - registerInstallButtonListener(page, log) - }) - .catch(async () => { - log('installBtn.click() failed') - }) -} - -const registerSaveLoginExpiredistener = (page: Page, log: typeof console.log) => { - // as soon as it appear, without blocking flow - // accept installing plugins - const installDialog = page.locator('#confirmDialog') - const cancelBtn = installDialog.locator('.cancelConfirmButton') - cancelBtn - .waitFor({ - timeout: 0 - }) - .then(async () => { - await cancelBtn.click() - log('cancelBtn clicked') - registerSaveLoginExpiredistener(page, log) - }) - .catch(async () => { - log('cancelBtn.click() failed') - }) -} - -const registerWebglErrorListener = (page: Page, log: typeof console.log) => { - // as soon as it appear, without blocking flow - // ignore webgl error - const okDialog = page.locator('#okDialog') - const webglErrorButton = okDialog.locator('.okButton') - webglErrorButton - .waitFor({ - timeout: 0 - }) - .then(async () => { - const text = await okDialog.allInnerTexts() - - if (text.join().toLowerCase().includes('webgl')) { - webglErrorButton.click() - log('webglErrorButton clicked') - registerWebglErrorListener(page, log) - } - }) - .catch(async () => { - log('webglErrorButton.click() failed') - }) -} -const registerDeprecatedFeatures = (page: Page, log: typeof console.log) => { - // as soon as it appear, without blocking flow - // ignore deprecated feature - const deprecatedFeaturesDialog = page.locator('#deprecatedFeaturesDialog') - const okButton = deprecatedFeaturesDialog.locator('.okButton') - okButton - .waitFor({ - timeout: 0 - }) - .then(async () => { - await okButton.click() - log('okButton clicked') - registerDeprecatedFeatures(page, log) - }) - .catch(async () => { - log('okButton.click() failed') - }) -} -const registerWelcomeToConstructListener = (page: Page, log: typeof console.log) => { - // as soon as it appear, without blocking flow - // ignore deprecated feature - const welcomeTourDialog = page.locator('#welcomeTourDialog') - const okButton = welcomeTourDialog.locator('.noThanksLink') - okButton - .waitFor({ - timeout: 0 - }) - .then(async () => { - await okButton.click() - log('okButton clicked') - registerDeprecatedFeatures(page, log) - }) - .catch(async () => { - log('okButton.click() failed') - }) -} - -const registerMissingAddonErrorListener = (page: Page, log: typeof console.log) => { - // as soon as it appear, without blocking flow - // ignore missing addon and throw - const okDialog = page.locator('#missingAddonsDialog') - const webglErrorButton = okDialog.locator('.okButton') - webglErrorButton - .waitFor({ - timeout: 0 - }) - .then(async () => { - throw new Error('Missing addon. You should bundle addons with your project') - }) - .catch(async () => { - log('webglErrorButton.click() failed') - }) -} - -export const script = async ( - page: Page, - log: typeof console.log, - filePath: string, - username: string | undefined, - password: string | undefined, - version: string | undefined, - downloadDir: string - // addonsFolder: string | undefined -) => { - let url = 'https://editor.construct.net/' - if (version) { - url += version - } - log('Navigating to URL', url) - // const serviceWorkerPromise = page.waitForEvent("serviceworker"); - await page.goto(url) - log('after navigating') - - // const serviceworker = await serviceWorkerPromise; - registerWelcomeToConstructListener(page, log) - - log('after event') - - // if (addonsFolder) { - // const _files = await readdir(addonsFolder) - // const addonFiles = _files - // .filter((x) => extname(x) === '.c3addon') - // .map((x) => join(addonsFolder, x)) - // console.log('addonFiles', addonFiles) - - // await page.pause() - // await page.getByRole('button', { name: 'Menu' }).click(); - // await page.mouse.move(30, 150) - // await page.mouse.move(150, 100) - // await page.mouse.click(150, 100); - - // const [fileChooserAddons] = await Promise.all([ - // page.waitForEvent('filechooser'), - // await page.getByRole('button', { name: 'Install new addon...' }).click() - // ]) - - // await fileChooserAddons.setFiles(addonFiles) - - // // await page.pause() - // // if (addonFiles.length > 0) { - // // for (let i = 0; i < addonFiles.length - 1; i += 1) { - // // const [fileChooser] = await Promise.all([ - // // page.waitForEvent('filechooser'), - // // page.keyboard.press('ControlOrMeta+O') - // // ]) - - // // await fileChooser.setFiles(addonFiles[i]) - // // log('Set addon files', addonFiles[i]) - - // // await page.pause() - // // } - // // } - // } - - await page.waitForTimeout(2000) - log('after wait') - - if (username && password) { - log('Authenticating') - await page.getByTitle('User account').locator('ui-icon').click() - await page.getByRole('menuitem', { name: 'Log in' }).locator('span').click() - await page.frameLocator('#loginDialog iframe').getByLabel('Username').fill(username) - await page.frameLocator('#loginDialog iframe').getByLabel('Password').fill(password) - - const tokenPromise = page.waitForResponse(/https:\/\/account.*\.construct\.net\/login.json/i) - - await page.frameLocator('#loginDialog iframe').getByRole('button', { name: 'Log in' }).click() - - const response = await tokenPromise - const jsonResponse = await response.json() - - if (jsonResponse.request.status === 'error') { - await page.close() - - throw new Error('Invalid credentials') - } - log('Authenticated') - } - - await page.waitForTimeout(2000) - - const [fileChooser] = await Promise.all([ - page.waitForEvent('filechooser'), - page.keyboard.press('ControlOrMeta+O') - ]) - log('filechooser') - - console.log('filePath', filePath) - await fileChooser.setFiles([filePath]) - log('Set file') - - // await page.getByText("Not now").click({ - // timeout: 1000 - // }); - - const progressDialog = page.locator('#progressDialog') - // - const progessBar = progressDialog.locator('.progressBar') - - log('Waiting for progress dialog') - await progressDialog.waitFor({ - timeout: 0 - }) - log('Got loading progress dialog') - - const progressInterval = setInterval(async () => { - const text = await progessBar.getAttribute('value') - const textAsNumber = parseFloat(text) - const finalText = Number.isNaN(textAsNumber) ? 0 : textAsNumber - log('progress', `${finalText * 100}%`) - }, 500) - - // as soon as it appear, without blocking flow - // ignore asking for update - const notNowBtn = page.getByText('Not now') - notNowBtn - .waitFor({ - timeout: 0 - }) - .then(async () => { - return notNowBtn.click() - }) - .then(() => { - log('notNowBtn clicked') - }) - .catch(async () => { - log('notNowBtn.click() failed') - }) - - registerInstallButtonListener(page, log) - registerWebglErrorListener(page, log) - registerMissingAddonErrorListener(page, log) - registerDeprecatedFeatures(page, log) - registerSaveLoginExpiredistener(page, log) - - log('Waiting for progress dialog to disapear') - await progressDialog.waitFor({ - state: 'detached', - timeout: 0 - }) - log('Got progress dialog to disapear') - clearTimeout(progressInterval) - - await page.getByRole('button', { name: 'Menu' }).click() - await page.getByRole('menuitem', { name: 'Project' }).click() - await page.getByRole('menuitem', { name: 'Export' }).click() - log('"Export" clicked') - await page - .locator('ui-iconviewitem') - .filter({ hasText: 'Web (HTML5)' }) - .locator('ui-icon') - .click() - log('"Web" clicked') - - await page.locator('#exportSelectPlatformDialog').getByRole('button', { name: 'Next' }).click() - - await page.getByLabel('Offline support').uncheck() - log('Disabled offline support') - - await page.locator('#exportStandardOptionsDialog').getByRole('button', { name: 'Next' }).click() - log('"Next" clicked') - const downloadPromise = page.waitForEvent('download') - await page.locator('.downloadExportedProject').click() - const download = await downloadPromise - await page.getByRole('button', { name: 'OK' }).click() - log('"Download" clicked') - - const finalPath = join(downloadDir, download.suggestedFilename()) - await download.saveAs(finalPath) - log('File Downloaded') - - await page.close() - return finalPath -} diff --git a/src/shared/libs/plugin-construct/declarations.d.ts b/src/shared/libs/plugin-construct/declarations.d.ts deleted file mode 100644 index 5ab250f4..00000000 --- a/src/shared/libs/plugin-construct/declarations.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.webp' diff --git a/src/shared/libs/plugin-construct/export-project.ts b/src/shared/libs/plugin-construct/export-project.ts deleted file mode 100644 index f343d0fd..00000000 --- a/src/shared/libs/plugin-construct/export-project.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { - ExtractInputsFromAction, - createAction, - createActionRunner, - createPathParam, - fileExists -} from '@pipelab/plugin-core' -import { exportc3p, sharedParams } from './export-shared.js' -import { throttle } from 'es-toolkit' -import { zipFolder } from '@main/utils.js' - -export const ID = 'export-construct-project-folder' - -export const exportProjectAction = createAction({ - id: ID, - name: 'Export folder', - displayString: "`Export project ${params.version ? `r${params.version}` : ''}`", - meta: {}, - params: { - folder: createPathParam('', { - required: true, - label: 'Folder', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }), - ...sharedParams - }, - outputs: { - folder: { - type: 'path', - deprecated: true, - value: undefined as undefined | string, - label: 'Exported zip' - // schema: schema.string() - }, - parentFolder: { - type: 'path', - deprecated: false, - value: undefined as undefined | string, - label: 'Path to parent folder of exported zip' - // schema: schema.string() - }, - zipFile: { - type: 'path', - deprecated: false, - value: undefined as undefined | string, - label: 'Exported zip' - // schema: schema.string() - } - }, - description: 'Export construct project from folder', - icon: '' -}) - -export const ExportProjectActionRunner = createActionRunner( - async (options) => { - const { join } = await import('node:path') - - const c3pFolderExists = await fileExists(options.inputs.folder) - if (!c3pFolderExists) { - throw new Error('You must specify a valid construct project folder') - } - - const outputPath = join(options.cwd, 'c3_tmp_proj.c3p') - - const to = await zipFolder(options.inputs.folder, outputPath, options.log) - - await exportc3p(to, options) - } -) - -export type Params = ExtractInputsFromAction diff --git a/src/shared/libs/plugin-construct/export-shared.ts b/src/shared/libs/plugin-construct/export-shared.ts deleted file mode 100644 index efec3963..00000000 --- a/src/shared/libs/plugin-construct/export-shared.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { - Action, - ActionRunnerData, - createNumberParam, - createPasswordParam, - createPathParam, - createStringParam, - InputsDefinition, - ParamsToInput, - runWithLiveLogs -} from '@pipelab/plugin-core' -import { script } from './assets/script.js' -import * as v from 'valibot' -import { BrowserContext } from 'playwright' -import { join } from 'node:path' -import { homedir } from 'node:os' - -const platform = process.platform -const { LOCALAPPDATA, XDG_CONFIG_HOME } = process.env - -// @ts-expect-error import.meta -const isCI = process.env.CI === 'true' || import.meta.env.CI === 'true' - -let baseProfile -if (platform === 'win32') { - baseProfile = join(LOCALAPPDATA ?? '', 'Google', 'Chrome', 'User Data') -} else if (platform === 'linux') { - baseProfile = join(XDG_CONFIG_HOME ?? '', 'google-chrome') -} else if (platform === 'darwin') { - baseProfile = join(homedir(), 'Library', 'Application Support', 'Google', 'Chrome') -} - -export const sharedParams = { - username: createStringParam('', { - label: 'Username', - required: false, - description: 'Your Construct username' - }), - password: createPasswordParam('', { - description: - 'Your Construct password. Will only be used locally to automate the export on Construct website via a local browser. Will not be sent to any server.', - required: false, - label: 'Password' - }), - version: createStringParam('', { - description: 'The Construct version you want to use', - label: 'Version', - required: false - }), - headless: { - description: 'Whether to show the browser while export', - required: false, - control: { - type: 'boolean' - }, - value: false, - label: 'Start headless' - }, - timeout: createNumberParam(120, { - description: "The timeout (in seconds) to close the browser if it's stuck", - required: false, - label: 'Timeout' - }), - // customBrowser: { - // description: 'Start your own browser rather than the predefined one', - // control: { - // type: 'path', - // options: { - // properties: ['openFile'] - // } - // }, - // label: 'Custom browser', - // value: '' - // }, - customProfile: createPathParam(undefined, { - required: false, - description: - 'Use your own profile (X:\\Users\\XXX\\AppData\\Local\\Google\\Chrome\\User Data). Usefull if you want to reuse plugins installed in your current browser', - control: { - type: 'path', - options: { - properties: ['openDirectory'], - defaultPath: baseProfile - } - }, - label: 'Custom profile' - }) - // addonsFolder: { - // description: 'Folder containing addons to import in the editor', - // required: false, - // control: { - // type: 'path', - // options: { - // buttonLabel: 'Addons folder', - // properties: ['openDirectory'] - // } - // }, - // value: '', - // label: 'Addons folder' - // } -} satisfies InputsDefinition - -type Inputs = ParamsToInput - -export const exportc3p = async ( - file: string, - { cwd, log, inputs, setOutput, paths, abortSignal }: ActionRunnerData -) => { - let context: BrowserContext | undefined = undefined - - abortSignal.addEventListener('abort', () => { - console.error('aborted') - - context?.close() - }) - const newInputs = inputs as Inputs - - // const { addonsFolder } = newInputs - - const playwright = await import('playwright') - const { join, dirname } = await import('node:path') - const { cp, mkdir } = await import('node:fs/promises') - - const { unpack, node } = paths - const modulesPath = join(unpack, 'node_modules') - - // const playwrightServer = await import("playwright-core/lib/server"); - - const browserName: 'chromium' | 'firefox' | 'webkit' = 'chromium' - - // const a = await playwrightServer.installBrowsersForNpmInstall([ - // browserName, - // ]); - log('Downloading browser') - await runWithLiveLogs( - node, - [join(modulesPath, 'playwright', 'cli.js'), 'install', browserName], - { - env: {}, - cancelSignal: abortSignal - }, - log, - { - onStdout(data) { - log(data) - }, - onStderr(data) { - log(data) - } - } - ) - - const downloadDir = join(cwd, 'playwright') - - log('Browser downloaded to', downloadDir) - - log('Exporting construct project') - - console.log('newInputs', newInputs) - - const browserInstance = playwright[browserName] - - let version = newInputs.version - // if version is full digit, prepend "r", otherwise, use as is - if (version && /^\d+$/.test(version)) { - version = `r${version}` - } - const headless = newInputs.headless - - // if (newInputs.customBrowser && !newInputs.customProfile) { - // throw new Error('You must specify a custom profile when using a custom browser') - // } - - // if (!newInputs.customBrowser && newInputs.customProfile) { - // throw new Error('You must specify a custom browser when using a custom profile') - // } - - // if (newInputs.customBrowser && newInputs.customProfile) { - if (newInputs.customProfile) { - const customProfile = join(cwd, 'playwright-profile') - - await mkdir(customProfile, { - recursive: true - }) - - const indexedDbPathSource = join(newInputs.customProfile, 'Default', 'IndexedDB') - const indexedDbPathDestination = join(customProfile, 'Default', 'IndexedDB') - const pathsToCopy = [ - 'https_editor.construct.net_0.indexeddb.blob', - 'https_editor.construct.net_0.indexeddb.leveldb' - ] - - for (const p of pathsToCopy) { - const from = join(indexedDbPathSource, p) - const to = join(indexedDbPathDestination, p) - await cp(from, to, { - recursive: true - }) - } - - context = await browserInstance.launchPersistentContext(customProfile, { - headless, - locale: 'en-US', - recordVideo: isCI - ? { - dir: join(process.cwd(), 'playwright') - } - : undefined - }) - } else { - const browser = await browserInstance.launch({ - headless - }) - - context = await browser.newContext({ - locale: 'en-US', - recordVideo: isCI - ? { - dir: join(process.cwd(), 'playwright') - } - : undefined - }) - await context.clearPermissions() - } - - const page = await context.newPage() - - page.setDefaultTimeout(newInputs.timeout * 1000) - - // this exact sequn=ence make it work - await page.addInitScript(() => { - // @ts-expect-error dds - delete self.showOpenFilePicker - }) - page.on('filechooser', (worker) => { - console.log('filechooser created: ' + worker.page.name) - }) - // --------------------------------- - - try { - const result = await script( - page, - log, - file, - newInputs.username, - newInputs.password, - version, - downloadDir - // addonsFolder, - ) - - log('Setting output result to ', result) - - setOutput('folder', result) // deprecated - - setOutput('parentFolder', dirname(result)) - setOutput('zipFile', result) - } catch (e) { - log('error, no result, crashed', e) - throw new Error('ConstructExport failed: ' + e.message) - } finally { - // await context.browser().close() - await context.close() - } -} - -export const constructVersionValidator = (options: any) => { - void options - return v.pipe(v.string(), v.regex(/^\d+(-\d+)?$/, 'Invalid version')) -} diff --git a/src/shared/libs/plugin-construct/index.ts b/src/shared/libs/plugin-construct/index.ts deleted file mode 100644 index b373c0ee..00000000 --- a/src/shared/libs/plugin-construct/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { createNodeDefinition } from '@pipelab/plugin-core' -import { exportAction, ExportActionRunner } from './export-c3p.js' -import { exportProjectAction, ExportProjectActionRunner } from './export-project.js' -import icon from './assets/construct.webp' -import { constructVersionValidator } from './export-shared' - -export default createNodeDefinition({ - description: 'Construct', - name: 'Construct', - id: 'construct', - icon: { - type: 'image', - image: icon - }, - nodes: [ - { - node: exportAction, - runner: ExportActionRunner - }, - { - node: exportProjectAction, - runner: ExportProjectActionRunner - } - ], - validators: [ - // { - // id: 'construct-version', - // description: 'Version must be a valid semver', - // validator: constructVersionValidator - // } - ] -}) - -export type { Params as ExportParams } from './export-c3p.js' diff --git a/src/shared/libs/plugin-core/create-plugin.ts b/src/shared/libs/plugin-core/create-plugin.ts deleted file mode 100644 index 81347b2b..00000000 --- a/src/shared/libs/plugin-core/create-plugin.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type Plugin = { - nodes: Record - runtime: () => Promise -} - -export const createPlugin = (plugin: Plugin) => { - return plugin -} \ No newline at end of file diff --git a/src/shared/libs/plugin-core/custom-errors.ts b/src/shared/libs/plugin-core/custom-errors.ts deleted file mode 100644 index 3d663207..00000000 --- a/src/shared/libs/plugin-core/custom-errors.ts +++ /dev/null @@ -1,12 +0,0 @@ - -export class ExternalCommandError extends Error { - code: number; - - constructor(message: string, code: number) { - super(message) - - this.code = code; - - Object.setPrototypeOf(this, ExternalCommandError.prototype) - } -} diff --git a/src/shared/libs/plugin-core/index.ts b/src/shared/libs/plugin-core/index.ts deleted file mode 100644 index 372fc5bf..00000000 --- a/src/shared/libs/plugin-core/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from './pipelab.js' - -export * from './create-plugin.js' - -export * from './utils.js' - -export { z as schema } from 'zod' - -export type NoData = { [index in string]?: unknown } - -export { createColorPicker } from './pipelab.js' \ No newline at end of file diff --git a/src/shared/libs/plugin-core/pipelab.ts b/src/shared/libs/plugin-core/pipelab.ts deleted file mode 100644 index 86278a15..00000000 --- a/src/shared/libs/plugin-core/pipelab.ts +++ /dev/null @@ -1,748 +0,0 @@ -import type { ConditionalPick } from 'type-fest' -import type { BrowserWindow, OpenDialogOptions } from 'electron' -import { UseMainAPI } from '@main/api' -import { BlockAction, BlockCondition, BlockEvent, BlockLoop } from '@@/model' - -export type PathOptions = { - filter?: RegExp - type?: 'file' | 'folder' -} - -// export const definitionToSocket = ( -// definition: InputOutputDefinition, -// side: "input" | "output" -// ) => { -// return match(definition) -// .returnType() -// .with({ kind: "any" }, (def) => { -// return unknown(def); -// }) -// .with({ kind: "array" }, (def) => { -// return array(def); -// }) -// .with({ kind: "boolean" }, (def) => { -// return boolean(def); -// }) -// .with({ kind: "number" }, (def) => { -// return number(def); -// }) -// .with({ kind: "string" }, (def) => { -// return string(def); -// }) -// .with( -// { -// kind: { -// type: "array", -// }, -// }, -// (def) => { -// return array(def); -// } -// ) -// .with({ kind: Pattern.array() }, (def) => { -// // eslint-disable-next-line @typescript-eslint/no-unused-vars -// const map = def.kind.map((x) => -// definitionToSocket( -// { -// ...def, -// kind: x, -// }, -// side -// ) -// ); -// console.warn("Array kinds are not yet supported"); -// return unknown(def); -// }) -// .exhaustive(); -// }; - -export type PropType = - | 'string' - | 'number' - | 'boolean' - | 'array' - | { - type: 'array' - of: PropType - } - | 'any' - | PropType[] - -// export type PropTypeToType = T extends "string" -// ? string -// : T extends "number" -// ? number -// : T extends "any" -// ? any -// : T extends "boolean" -// ? boolean -// : T extends "path" -// ? string -// : T extends "array" -// ? unknown[] -// : T extends "checkbox" -// ? boolean -// // a union of values -// : T extends any[] -// ? PropTypeToType -// // an array of any type -// : T extends { type: "array"; of: any } -// ? Array> -// : never; - -// type a1 = PropTypeToType<"string">; -// type a2 = PropTypeToType<"number">; -// type a3 = PropTypeToType<"any">; -// type a6 = PropTypeToType<["string", "number"]>; -// type a7 = PropTypeToType<{ type: "array"; of: "string" }>; -// type a8 = PropTypeToType<{ -// type: "array"; -// of: [ -// { -// type: "array"; -// of: ["string", "number"]; -// }, -// "boolean", -// ]; -// }>; - -export interface ControlTypeBase { - type: string - // options: { - // value: any; - // onChange: (value: any) => void; - // }; -} - -export interface ControlTypeInput extends ControlTypeBase { - type: 'input' - options: { - kind: 'number' | 'text' - validator?: string - placeholder?: string - password?: boolean - // value: string; - // onChange: (value: any) => void; - } -} - -export interface ControlTypeExpression extends ControlTypeBase { - type: 'expression' - options: { - // kind: "number" | "text"; - // value: string; - // onChange: (value: any) => void; - } -} - -export interface ControlTypeNetlifySite extends ControlTypeBase { - type: 'netlify-site' - options: { - allowCreate?: boolean - placeholder?: string - tokenKey: string - } -} - -export interface PipelabSelectOption { - label: string - value: string -} - -export interface ControlTypeSelect extends ControlTypeBase { - type: 'select' - options: { - options: Array - placeholder: string - } -} - -export interface ControlTypeMultiSelect extends ControlTypeBase { - type: 'multi-select' - options: { - options: Array - placeholder: string - } -} - -export interface ControlTypeBoolean extends ControlTypeBase { - type: 'boolean' - // options?: { - // allowAuto?: boolean - // } -} - -export interface ControlTypeCheckbox extends ControlTypeBase { - type: 'checkbox' - // options: { - // value: boolean; - // onChange: (value: boolean) => void; - // }; -} - -export interface ControlTypePath extends ControlTypeBase { - type: 'path' - options: OpenDialogOptions - label?: string -} - -export interface ControlTypeJSON extends ControlTypeBase { - type: 'json' - // options: { - // value: string; - // onChange: (value: string) => void; - // }; -} - -export interface ControlTypeArray extends ControlTypeBase { - type: 'array' - options: { - kind: 'number' | 'text' - } -} - -export interface ControlTypeColor extends ControlTypeBase { - type: 'color' -} - -export interface ControlTypeElectronConfigureV2 extends ControlTypeBase { - type: 'electron:configure:v2' -} - -export type ControlType = - | ControlTypeInput - | ControlTypeSelect - | ControlTypeMultiSelect - | ControlTypeBoolean - | ControlTypeCheckbox - | ControlTypePath - | ControlTypeJSON - | ControlTypeExpression - | ControlTypeNetlifySite - | ControlTypeArray - | ControlTypeColor - | ControlTypeElectronConfigureV2 - -export type InputDefinition = { - label: string - description?: string - validator?: () => any - required: boolean - // validator?: z.ZodTypeAny - control: T - value: unknown - platforms?: NodeJS.Platform[] - onNodeUpdate?: ( - value: BlockAction | BlockEvent | BlockCondition | BlockLoop, - settings: InputDefinition - ) => void -} - -export type InputsDefinition = Record -export type Meta = Record - -export interface OutputDefinition { - label: string - description?: string - deprecated?: boolean - // validator: z.ZodTypeAny - validator?: (value: any) => any - control?: ControlType - value: unknown -} - -export type OutputsDefinition = Record - -export type InputOutputDefinition = InputDefinition | OutputDefinition - -export type IconType = - | { - type: 'image' - /** - * base64 image - */ - image: string - } - | { - type: 'icon' - icon: string - } -export interface PluginDefinition { - id: string - name: string - icon: IconType - description: string -} - -export type RendererNodeDefinition = { - node: PipelabNode -} - -export interface RendererPluginDefinition extends PluginDefinition { - nodes: Array -} - -export interface MainPluginDefinition extends PluginDefinition { - nodes: ({ - runner: Runner - } & RendererNodeDefinition)[] - validators?: Array<{ - id: string - description: string - validator: (options: any) => any - }> -} - -export const createNodeDefinition = (def: MainPluginDefinition) => { - return def -} - -export type RunnerCallbackFnArgument = { - done: () => void - id: string - log: (...args: Parameters<(typeof console)['log']>) => void -} - -// type friendly version of execute -// export const createRunner = ( -// callback: (data: RunnerCallbackFnArgument) => Promise -// ) => { -// return callback; -// }; - -export type InputsOutputsDefinition = InputsDefinition | OutputsDefinition - -export type GetFlowEntries = ConditionalPick -export type GetDataEntries = ConditionalPick - -export type GetFlowKeys = keyof GetFlowEntries -export type GetDataKeys = keyof GetDataEntries - -export type DataResult = Record - -export type SetOutputActionFn = ( - key: keyof T['outputs'], - value: T['outputs'][typeof key]['value'] -) => void -export type SetOutputLoopFn = ( - key: keyof T['outputs'], - value: T['outputs'][typeof key]['value'] -) => void -export type SetOutputExpressionFn = ( - key: keyof T['outputs'], - value: T['outputs'][typeof key]['value'] -) => void - -export type ParamsToInput = { - [index in keyof PARAMS]: PARAMS[index]['required'] extends true - ? PARAMS[index]['value'] - : PARAMS[index]['value'] | null -} - -export interface BaseNode { - disabled?: boolean | string - advanced?: boolean | string - updateAvailable?: boolean | string -} - -export interface Action extends BaseNode { - id: string - type: 'action' - version?: number - displayString: string - icon: string - name: string - description: string - params: InputsDefinition - meta: Meta - outputs: OutputsDefinition - platforms?: NodeJS.Platform[] - deprecated?: boolean - deprecatedMessage?: string -} - -export type ExtractInputsFromAction = { - [index in keyof ACTION['params']]: ACTION['params'][index]['value'] -} - -export type ExtractInputsFromCondition = { - [index in keyof CONDITION['params']]: CONDITION['params'][index]['value'] -} -export type ExtractInputsFromLoop = { - [index in keyof LOOP['params']]: LOOP['params'][index]['value'] -} -export type ExtractInputsFromEvent = { - [index in keyof EVENT['params']]: EVENT['params'][index]['value'] -} -export type ExtractInputsFromExpression = { - [index in keyof EXPRESSION['params']]: EXPRESSION['params'][index]['value'] -} - -export type ActionRunnerData = { - log: typeof console.log - setOutput: SetOutputActionFn - // inputs: ParamsToInput>, - inputs: ExtractInputsFromAction - setMeta: (callback: (data: ACTION['meta']) => ACTION['meta']) => void - meta: ACTION['meta'] - cwd: string - paths: { - unpack: string - assets: string - cache: string - pnpm: string - node: string - } - api: UseMainAPI - browserWindow: BrowserWindow - abortSignal: AbortSignal -} - -export type ActionRunner = (data: ActionRunnerData) => Promise -export const createActionRunner = (runner: ActionRunner) => runner - -// --- - -export interface Condition extends BaseNode { - id: string - type: 'condition' - version?: number - displayString: string - icon: string - name: string - description: string - params: InputsDefinition - meta?: Meta - platforms?: NodeJS.Platform[] -} -export type ConditionRunner = (data: { - log: typeof console.log - inputs: ExtractInputsFromCondition - setMeta: (callback: (data: CONDITION['meta']) => CONDITION['meta']) => void - meta: CONDITION['meta'] - cwd: string -}) => Promise -export const createConditionRunner = ( - runner: ConditionRunner -) => runner - -// --- - -export interface Loop extends BaseNode { - id: string - type: 'loop' - version?: number - displayString: string - icon: string - name: string - description: string - params: InputsDefinition - meta?: Meta - outputs: OutputsDefinition -} -type LoopRunner = (data: { - log: typeof console.log - setOutput: SetOutputLoopFn - inputs: ExtractInputsFromLoop - setMeta: (callback: (data: LOOP['meta']) => LOOP['meta']) => void - meta: LOOP['meta'] - cwd: string -}) => Promise<'step' | 'exit'> -export const createLoopRunner = (runner: LoopRunner) => runner - -export interface Expression extends BaseNode { - id: string - type: 'expression' - displayString: string - version?: number - icon: string - name: string - description: string - params: InputsDefinition - meta?: Meta - outputs: OutputsDefinition -} -type ExpressionRunner = (data: { - log: typeof console.log - setOutput: SetOutputExpressionFn - inputs: ExtractInputsFromExpression - setMeta: (callback: (data: EXPRESSION['meta']) => EXPRESSION['meta']) => void - meta: EXPRESSION['meta'] - cwd: string -}) => Promise -export const createExpressionRunner = ( - runner: ExpressionRunner -) => runner - -export interface Event extends BaseNode { - id: string - type: 'event' - version?: number - displayString: string - icon: string - name: string - description: string - params: InputsDefinition - meta?: Meta - platforms?: NodeJS.Platform[] -} -type EventRunner = (data: { - log: typeof console.log - inputs: ExtractInputsFromEvent - setMeta: (callback: (data: EVENT['meta']) => EVENT['meta']) => void - meta: EVENT['meta'] - cwd: string -}) => Promise -export const createEventRunner = (runner: EventRunner) => runner - -export type PipelabNode = Event | Condition | Expression | Action | Loop - -export const createDefinition = (definition: T) => { - return definition satisfies T -} - -export const createAction = >(action: T) => { - return { - ...action, - type: 'action' - } satisfies Action -} - -export const createStringParam = ( - value: string, - definition: Omit, 'value' | 'control'> -) => { - return { - ...definition, - control: { - type: 'input', - options: { - kind: 'text' - } - }, - value: `"${value}"` - } satisfies InputDefinition -} -export const createColorPicker = ( - value: string, - definition: Omit, 'value' | 'control'> -) => { - return { - ...definition, - control: { - type: 'color' - }, - value: `"${value}"` - } satisfies InputDefinition -} -export const createPasswordParam = ( - value: string, - definition: Omit, 'value' | 'control'> -) => { - return { - ...definition, - control: { - type: 'input', - options: { - kind: 'text', - password: true - } - }, - value: `"${value}"` - } satisfies InputDefinition -} - -export const createPathParam = ( - value: string | undefined, - definition: Omit, 'value'> -) => { - return { - ...definition, - value: value ? `"${value}"` : value - } satisfies InputDefinition -} -export const createArray = ( - value: string | Array, - definition: Omit, 'value'> -) => { - return { - ...definition, - value: (Array.isArray(value) ? `"${value}"` : value) as unknown as T - } satisfies InputDefinition -} - -export const createNetlifySiteParam = ( - value: string, - tokenKey: string, - definition: Omit, 'value' | 'control'> -) => { - return { - ...definition, - control: { - type: 'netlify-site', - options: { - allowCreate: true, - placeholder: 'Select a site', - tokenKey - } - }, - value: `"${value}"` - } satisfies InputDefinition -} - -export const createNumberParam = ( - value: number, - definition: Omit, 'value' | 'control'> -) => { - return { - ...definition, - control: { - type: 'input', - options: { - kind: 'number' - } - }, - value - } satisfies InputDefinition -} - -export const createBooleanParam = ( - value: boolean, - definition: Omit, 'value' | 'control'> -) => { - return { - ...definition, - control: { - type: 'boolean' - }, - value - } satisfies InputDefinition -} - -export const createRawParam = (value: T, definition: Omit) => { - return { - ...definition, - value - } -} - -export const createExpression = >(expression: T) => { - return { - ...expression, - type: 'expression' - } satisfies Expression -} - -export const createCondition = >(condition: T) => { - return { - ...condition, - type: 'condition' - } satisfies Condition -} - -export const createLoop = >(loop: T) => { - return { - ...loop, - type: 'loop' - } satisfies Loop -} - -export const createEvent = >(event: T) => { - return { - ...event, - type: 'event' - } satisfies Event -} - -export type Runner = ActionRunner | LoopRunner | EventRunner | ConditionRunner - -const a1 = createAction({ - id: 'aaa', - name: 'AAA', - icon: '', - displayString: '', - meta: {}, - description: '', - run: async () => { - // - }, - params: { - aaa: { - value: 'aaa', - control: { - type: 'input', - options: { - kind: 'text' - } - }, - label: 'AAA' - }, - bbb: { - value: 12, - label: 'BBB', - control: { - type: 'input', - options: { - kind: 'number' - } - } - }, - ccc: { - value: ['aaa'], - label: 'CCC', - control: { - type: 'select', - options: { - placeholder: 'aaa', - options: [ - { - label: 'AAA', - value: 'aaa' - } - ] - } - } - }, - ddd: { - value: ['a', 12], - label: 'DDD', - control: { - type: 'select', - options: { - placeholder: 'ddd', - options: [ - { - label: 'AAA', - value: 'aaa' - } - ] - } - } - } - }, - outputs: { - aaa: { - value: 'string', - label: 'AAA', - validator: (value) => value === 'hello' || value == 'bye' - }, - bbb: { - label: 'BBB', - // schema: z.number(), - value: 12 - }, - ccc: { - label: 'CCC', - // schema: z.array(z.string()), - value: [] as string[] - }, - ddd: { - label: 'DDD', - value: undefined as Array | undefined - } - } -}) - -const sleep = (duration: number) => { - return new Promise((resolve) => setTimeout(resolve, duration)) -} diff --git a/src/shared/libs/plugin-core/utils.ts b/src/shared/libs/plugin-core/utils.ts deleted file mode 100644 index c3862226..00000000 --- a/src/shared/libs/plugin-core/utils.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { Options, Subprocess } from 'execa' -import { IPty, type IPtyForkOptions, type IWindowsPtyForkOptions } from '@lydell/node-pty' -import { createWriteStream } from 'fs' -import { pipeline } from 'stream/promises' -import { ExternalCommandError } from './custom-errors' - -export const fileExists = async (path: string): Promise => { - try { - await import('fs/promises').then(({ access }) => access(path)) - return true - } catch { - return false - } -} - -export const runWithLiveLogs = async ( - command: string, - args: string[], - execaOptions: Options, - log: typeof console.log, - hooks?: { - onStdout?: (data: string, subprocess: Subprocess) => void - onStderr?: (data: string, subprocess: Subprocess) => void - onExit?: (code: number) => void - } -): Promise => { - const { execa } = await import('execa') - return new Promise((resolve, reject) => { - console.log('command: ', command, args.join(' ')) - - const subprocess = execa(command, args, { - ...execaOptions, - stdout: 'pipe', - stderr: 'pipe', - stdin: 'pipe' - }) - - subprocess.stdout.on('data', (data: Buffer) => { - hooks?.onStdout?.(data.toString(), subprocess) - }) - - subprocess.stderr?.on('data', (data: Buffer) => { - hooks?.onStderr?.(data.toString(), subprocess) - }) - - subprocess.on('error', (error: Error) => { - console.log('error', error) - return reject(error) - }) - - subprocess.on('close', (code: number) => { - console.log('close', code) - hooks?.onExit?.(code) - - if (code === 0) { - return resolve() - } else { - return reject(new Error(`Command exited with non-zero code: ${code}`)) - } - }) - - subprocess.on('disconnect', () => { - console.log('disconnect') - hooks?.onExit?.(0) - return resolve() - }) - - subprocess.on('exit', (code: number) => { - console.log('exit', code) - hooks?.onExit?.(code) - - if (code === 0) { - return resolve() - } else { - return reject(new Error(`Command exited with non-zero code: ${code}`)) - } - }) - }) -} - - - -export const runWithLiveLogsPTY = async ( - command: string, - args: string[], - ptyOptions: IPtyForkOptions | IWindowsPtyForkOptions, - log: typeof console.log, - hooks?: { - onStdout?: (data: string, subprocess: IPty) => void - onStderr?: (data: string, subprocess: IPty) => void - onExit?: (code: number) => void - onCreated?: (subprocess: IPty) => void - }, - abortSignal?: AbortSignal -): Promise => { - const { spawn } = await import('@lydell/node-pty') - return new Promise((resolve, reject) => { - console.log('command: ', command, args.join(' ')) - - const subprocess = spawn(command, args, ptyOptions) - - hooks.onCreated?.(subprocess) - - subprocess.onData((data) => { - hooks?.onStdout?.(data.toString(), subprocess) - }) - - subprocess.onExit(({ exitCode, signal }) => { - console.log('exit', exitCode) - hooks?.onExit?.(exitCode) - - if (exitCode === 0) { - return resolve() - } else { - return reject(new ExternalCommandError(`Command exited with non-zero exitCode: ${exitCode}`, exitCode)) - } - }) - }) -} - -export interface Hooks { - onProgress?: (data: { progress: number; downloadedSize: number }) => void -} - -/** - * Downloads a file from a given URL to a specified local path with progress tracking. - * - * @param url - The URL of the file to download. - * @param localPath - The local file path to save the downloaded file. - * @returns A promise that resolves when the file is downloaded. - */ -export const downloadFile = async ( - url: string, - localPath: string, - hooks?: Hooks, - abortSignal?: AbortSignal -): Promise => { - // Fetch the resource - const response = await fetch(url, { - signal: abortSignal - }) - - // Check if the fetch was successful - if (!response.ok) { - throw new Error(`Failed to fetch file: ${response.statusText}`) - } - - // Get the total size of the file - const contentLength = response.headers.get('content-length') - if (!contentLength) { - throw new Error('Content-Length header is missing') - } - const totalSize = parseInt(contentLength, 10) - - // Track progress - let downloadedSize = 0 - - // Create a write stream for the file - const fileStream = createWriteStream(localPath) - - // Create a readable stream to monitor progress - const progressStream = new TransformStream({ - transform(chunk, controller) { - downloadedSize += chunk.length - const progress = (downloadedSize / totalSize) * 100 - if (hooks?.onProgress) { - hooks.onProgress({ - progress, - downloadedSize - }) - } - controller.enqueue(chunk) - } - }) - - // Pipe the response through the progress tracker and into the file - const readable = response.body?.pipeThrough(progressStream) - if (!readable) { - throw new Error('Failed to create a readable stream') - } - - await pipeline(readable, fileStream) -} diff --git a/src/shared/libs/plugin-discord/declarations.d.ts b/src/shared/libs/plugin-discord/declarations.d.ts deleted file mode 100644 index 5ab250f4..00000000 --- a/src/shared/libs/plugin-discord/declarations.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.webp' diff --git a/src/shared/libs/plugin-discord/discord.ts b/src/shared/libs/plugin-discord/discord.ts deleted file mode 100644 index 5fc4d7eb..00000000 --- a/src/shared/libs/plugin-discord/discord.ts +++ /dev/null @@ -1,419 +0,0 @@ -import { - ActionRunnerData, - createAction, - createPathParam, - createStringParam, - InputsDefinition, - OutputsDefinition, - runWithLiveLogs -} from '../plugin-core' -import { detectRuntime } from '@@/plugins' -import { app } from 'electron' -import { dirname } from 'node:path' -import { startTunnel } from 'untun' - -export const IDPackage = 'discord:package' -export const IDPreview = 'discord:preview' - -const paramsInputFolder = { - 'input-folder': createPathParam('', { - label: 'Folder to package', - required: true, - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }) -} satisfies InputsDefinition - -// const paramsInputURL = { -// 'input-url': createStringParam('', { -// label: 'URL to preview', -// required: true -// }) -// } satisfies InputsDefinition - -export const configureParams = { - name: createStringParam('Pipelab', { - label: 'Application name', - description: 'The name of the application', - required: true - }) -} satisfies InputsDefinition - -const outputs = { - outputDir: { - label: 'Output folder', - value: '', - description: 'The folder where the packaged application is located' - } -} satisfies OutputsDefinition - -export const createPackageProps = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string, - advanced?: boolean, - deprecated?: boolean, - deprecatedMessage?: string, - disabled?: false, - updateAvailable?: boolean -) => { - return createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - advanced, - deprecated, - deprecatedMessage, - disabled, - updateAvailable, - params: { - ...paramsInputFolder, - ...configureParams - }, - outputs: { - outputDir: outputs.outputDir - } - }) -} - -export const createPreviewProps = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string -) => - createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - params: { - ...paramsInputFolder, - ...configureParams, - customHostname: createStringParam('', { - required: false, - label: 'Custom hostname', - description: 'The hostname to use for the preview' - }) - }, - outputs: { - // ...outputs.outputDir - } - }) - -const createAppServer = async (folder: string) => { - try { - const serve = await import('serve-handler') - const { createServer } = await import('http') - - const server = createServer() - - server.on('request', (req, res) => { - return serve.default(req, res, { - maxAge: 0, - public: folder, - headers: { - 'bypass-tunnel-reminder': 'false' - } - }) - }) - - const listen = async () => { - return new Promise((resolve, reject) => { - server.listen(40400, '127.0.0.1', () => { - return resolve(server) - }) - }) - } - - await listen() - console.log('listening2') - console.log('address', server.address) - const addressRes = server.address() - console.log('addressRes', addressRes) - if (addressRes && typeof addressRes !== 'string') { - return { port: addressRes.port } - } - throw new Error('Unable to bind server: adress is not an object') - } catch (e) { - console.error(e) - throw e - } -} - -const createTunnel = async (port: number, subdomain: string) => { - // const localtunnel = await import('localtunnel') - // console.log('localtunnel', localtunnel) - // const tunnel = await localtunnel.default({ port, subdomain }) - // tunnel.on('close', () => { - // // tunnels are closed - // }) - // console.log('tunnel.url', tunnel.url) - // return tunnel - // const localtunnel = await import('tunnelmole') - // console.log('localtunnel', localtunnel) - // const tunnel = await localtunnel.tunnelmole({ port, domain: subdomain }) - // tunnel.on('close', () => { - // // tunnels are closed - // }) - // console.log('tunnel.url', tunnel) - // return tunnel -} - -export const waitForAbort = (signal: AbortSignal): Promise => { - return new Promise((resolve, reject) => { - if (signal.aborted) { - return resolve() // Already aborted - } - - const onAbort = () => { - signal.removeEventListener('abort', onAbort) - resolve() - } - - signal.addEventListener('abort', onAbort) - }) -} - -export const discord = async ( - action: 'package' | 'preview', - appFolder: string | undefined, - { - cwd, - log, - inputs, - setOutput, - paths, - abortSignal - }: - | ActionRunnerData> - | ActionRunnerData>, - completeConfiguration: DesktopApp.Config -): Promise<{ folder: string; binary: string | undefined } | undefined> => { - const { join, basename, delimiter } = await import('node:path') - const { cp, readFile, writeFile } = await import('node:fs/promises') - const { arch, platform } = await import('os') - const { kebabCase } = await import('change-case') - - console.log('appFolder', appFolder) - - log('Building discord') - - const runtime = await detectRuntime(appFolder) - - const { assets, unpack, cache, node, pnpm } = paths - - const destinationFolder = join(cwd, 'build') - - const templateFolder = join(assets, 'discord', 'templates', 'nitro-app') - - // copy template to destination - await cp(templateFolder, destinationFolder, { - recursive: true, - filter: (src) => { - log('src', src) - // log('dest', dest) - // TODO: support other oses - return ( - basename(src) !== 'node_modules' && - !src.includes('.nitro') && - !src.includes('.output') && - !src.includes('.env') - ) - } - }) - - const placeAppFolder = join(destinationFolder, 'src', 'app') - - // if input is folder, copy folder to destination - if (appFolder) { - // copy app to template - await cp(appFolder, placeAppFolder, { - recursive: true - }) - } - - writeFile( - join(destinationFolder, '.env'), - `DISCORD_CLIENT_ID=1357217738241736724 -DISCORD_CLIENT_SECRET=yJ4vRnzDtKAqg2Le3_Sap2CqHybkTp2U`, - 'utf8' - ) - - const shimsPaths = join(assets, 'shims') - - const userData = app.getPath('userData') - - const pnpmHome = join(userData, 'config', 'pnpm') - - const sanitizedName = kebabCase(completeConfiguration.name) - - // package.json update - // const pkgJSONPath = join(destinationFolder, 'package.json') - // const pkgJSONContent = await readFile(pkgJSONPath, 'utf8') - // const pkgJSON = JSON.parse(pkgJSONContent) - // log('Setting name to', sanitizedName) - // pkgJSON.name = sanitizedName - // log('Setting productName to', completeConfiguration.name) - // pkgJSON.productName = completeConfiguration.name - // await writeFile(pkgJSONPath, JSON.stringify(pkgJSON, null, 2)) - - // discord.conf.json update - // const tauriConfJSONPath = join(destinationFolder, 'src-discord', 'discord.conf.json') - // const tauriConfJSONContent = await readFile(tauriConfJSONPath, 'utf8') - // const tauriConfJSON = JSON.parse(tauriConfJSONContent) - // log('Setting productName to', completeConfiguration.name) - // tauriConfJSON.productName = completeConfiguration.name - // log('Setting version to', completeConfiguration.appVersion) - // tauriConfJSON.version = completeConfiguration.appVersion - // log('Setting identifier to', completeConfiguration.appBundleId) - // tauriConfJSON.identifier = completeConfiguration.appBundleId - // log('Setting build.devUrl to', appFolder) - // tauriConfJSON.build.devUrl = appFolder - // await writeFile(tauriConfJSONPath, JSON.stringify(tauriConfJSON, null, 2)) - - log('Installing packages') - await runWithLiveLogs( - node, - [pnpm, 'install', '--prefer-offline'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PNPM_HOME: pnpmHome - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - - // override discord version - // if (completeConfiguration.electronVersion && completeConfiguration.electronVersion !== '') { - // log(`Installing discord@${completeConfiguration.electronVersion}`) - // await runWithLiveLogs( - // process.execPath, - // [pnpm, 'install', `discord@${completeConfiguration.electronVersion}`, '--prefer-offline'], - // { - // cwd: destinationFolder, - // env: { - // // DEBUG: '*', - // PNPM_HOME: pnpmHome - // }, - // cancelSignal: abortSignal - // }, - // log, - // { - // onStderr(data) { - // log(data) - // }, - // onStdout(data) { - // log(data) - // } - // } - // ) - // } - - try { - if (action === 'preview') { - const port = 14141 - - const modulesPath = join(unpack, 'node_modules') - const nitro = join(modulesPath, 'nitropack', 'dist', 'cli', 'index.mjs') - - // const nitro = await import('nitropack') - - console.log('nitro', nitro) - - await Promise.allSettled([ - runWithLiveLogs( - node, - [pnpm, 'dlx', 'nitropack', 'dev'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome, - PORT: port.toString() - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ), - (async () => { - const tunnel = await startTunnel({ port, acceptCloudflareNotice: true }) - console.log('tunnel', tunnel) - const url = await tunnel.getURL() - console.log('Public URL:', url) - })() - ]) - - // const { port } = await createAppServer(placeAppFolder) - - // const tunnel = await createTunnel(port, inputs['customHostname']) - - // await waitForAbort(abortSignal) - } else { - throw new Error('TODO') - } - - if (action === 'package') { - // const binName = getBinName(completeConfiguration.name) - // log('cargoOutputPath', cargoOutputPath) - // setOutput('output', cargoOutputPath) - // return { - // folder: cargoOutputPath, - // binary: join(cargoOutputPath, binName) - // } - } else if (action === 'preview') { - // continue - } else { - throw new Error('Unsupported action') - // const output = join(destinationFolder, 'out', 'make') - // setOutput('output', output) - // return { - // folder: output, - // binary: undefined - // } - } - } catch (e) { - if (e instanceof Error) { - if (e.name === 'RequestError') { - log('Request error') - } - if (e.name === 'RequestError') { - log('Request error') - } - } - log(e) - return undefined - } -} diff --git a/src/shared/libs/plugin-discord/index.ts b/src/shared/libs/plugin-discord/index.ts deleted file mode 100644 index de52f53c..00000000 --- a/src/shared/libs/plugin-discord/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { previewRunner } from './preview.js' - -import { createNodeDefinition } from '@pipelab/plugin-core' -import icon from './public/discord.webp' -import { createPackageProps, createPreviewProps, IDPreview, IDPackage } from './discord.js' -import { packageV2Runner } from './package.js' - -export default createNodeDefinition({ - description: 'Discord', - name: 'Discord', - id: 'dicord', - icon: { - type: 'image', - image: icon - }, - nodes: [ - { - node: createPackageProps( - IDPackage, - 'Package as Discord Activity', - 'Package your app as a Discord Activity', - '', - "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", - false, - false, - undefined, - false, - false - ), - runner: packageV2Runner - }, - { - node: createPreviewProps( - IDPreview, - 'Preview Discord Acitivity app', - 'Package and preview your app as a Discord Activity', - '', - "`Preview app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`" - ), - runner: previewRunner - } - ] -}) diff --git a/src/shared/libs/plugin-discord/package.ts b/src/shared/libs/plugin-discord/package.ts deleted file mode 100644 index 4301f1dd..00000000 --- a/src/shared/libs/plugin-discord/package.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { createActionRunner } from '@pipelab/plugin-core' -import { createPackageProps, discord } from './discord' -import { merge } from 'ts-deepmerge' -import { defaultTauriConfig } from './utils' -import { basename, join } from 'path' -import { cp } from 'fs/promises' - -export const packageV2Runner = createActionRunner>( - async ({ inputs, cwd, paths, log, setOutput }) => { - const appFolder = inputs['input-folder'] - - const { assets, unpack, cache, node, pnpm } = paths - const destinationFolder = join(cwd) - const templateFolder = join(assets, 'discord', 'templates', 'nitro-app') - - // copy template to destination - await cp(templateFolder, destinationFolder, { - recursive: true, - filter: (src) => { - log('src', src) - // log('dest', dest) - // TODO: support other oses - return basename(src) !== 'node_modules' && !src.includes('.nitro') && !src.includes('dist') - } - }) - const placeAppFolder = join(destinationFolder, 'server', 'public', '.proxy') - if (appFolder) { - // copy app to template - await cp(appFolder, placeAppFolder, { - recursive: true - }) - } - - log('destinationFolder', destinationFolder) - - setOutput('outputDir', destinationFolder) - } -) diff --git a/src/shared/libs/plugin-discord/preview.ts b/src/shared/libs/plugin-discord/preview.ts deleted file mode 100644 index 7fd59a05..00000000 --- a/src/shared/libs/plugin-discord/preview.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createActionRunner } from '@pipelab/plugin-core' -import { createPreviewProps, discord } from './discord' -import { merge } from 'ts-deepmerge' - -export const previewRunner = createActionRunner>( - async (options) => { - const inputFolder = options.inputs['input-folder'] - if (inputFolder === '') { - throw new Error("URL can't be empty") - } - - // if (!options.inputs.configuration) { - // throw new Error('Missing tauri configuration') - // } - - const completeConfiguration = merge({}, { - ...options.inputs - } satisfies any) as any - - console.log('completeConfiguration', completeConfiguration) - - await discord('preview', inputFolder, options, completeConfiguration) - return - } -) diff --git a/src/shared/libs/plugin-discord/utils.ts b/src/shared/libs/plugin-discord/utils.ts deleted file mode 100644 index ed2ed6b5..00000000 --- a/src/shared/libs/plugin-discord/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const defaultTauriConfig = { - alwaysOnTop: false, - appBundleId: 'com.pipelab.app', - appCategoryType: '', - appCopyright: 'Copyright © 2024 Pipelab', - appVersion: '1.0.0', - author: 'Pipelab', - description: 'A simple Electron application', - tauriVersion: '', - enableExtraLogging: false, - clearServiceWorkerOnBoot: false, - frame: true, - fullscreen: false, - icon: '', - height: 600, - name: 'Pipelab', - toolbar: true, - transparent: false, - width: 800, - enableSteamSupport: false, - steamGameId: 480, - enableDiscordSupport: false, - discordAppId: '', - ignore: [] as string[], - backgroundColor: '#FFF', - openDevtoolsOnStart: false, -} satisfies DesktopApp.Tauri diff --git a/src/shared/libs/plugin-electron/configure.ts b/src/shared/libs/plugin-electron/configure.ts deleted file mode 100644 index be71c94c..00000000 --- a/src/shared/libs/plugin-electron/configure.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createAction, createActionRunner } from '@pipelab/plugin-core' -import { configureParams } from './forge' - -export const props = createAction({ - id: 'electron:configure', - description: 'Configure electron', - displayString: "'Configure Electron'", - icon: '', - meta: {}, - name: 'Configure Electron', - advanced: true, - outputs: { - configuration: { - label: 'Configuration', - value: {} as Partial - } - }, - params: configureParams -}) - -export const configureRunner = createActionRunner(async ({ setOutput, inputs }) => { - setOutput('configuration', inputs) -}) diff --git a/src/shared/libs/plugin-electron/declarations.d.ts b/src/shared/libs/plugin-electron/declarations.d.ts deleted file mode 100644 index 5ab250f4..00000000 --- a/src/shared/libs/plugin-electron/declarations.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.webp' diff --git a/src/shared/libs/plugin-electron/forge.ts b/src/shared/libs/plugin-electron/forge.ts deleted file mode 100644 index aa465e86..00000000 --- a/src/shared/libs/plugin-electron/forge.ts +++ /dev/null @@ -1,918 +0,0 @@ -import { getBinName, outFolderName } from 'src/constants' -import { - ActionRunnerData, - createAction, - createArray, - createBooleanParam, - createColorPicker, - createNumberParam, - createPathParam, - createStringParam, - InputsDefinition, - OutputsDefinition, - runWithLiveLogs -} from '../plugin-core' - -import { app } from 'electron' -import { detectRuntime } from '@@/plugins' -import { dirname } from 'node:path' -import * as esbuild from 'esbuild' - -// TODO: https://js.electronforge.io/modules/_electron_forge_core.html - -export const IDMake = 'electron:make' -export const IDPackage = 'electron:package' -export const IDPackageV2 = 'electron:package:v2' -export const IDPackageV3 = 'electron:package:v3' -export const IDPreview = 'electron:preview' - -const paramsInputFolder = { - 'input-folder': createPathParam('', { - label: 'Folder to package', - required: true, - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }) -} satisfies InputsDefinition - -const paramsInputURL = { - 'input-url': createStringParam('', { - label: 'URL to preview', - required: true - }) -} satisfies InputsDefinition - -const params = { - arch: { - value: '' as NodeJS.Architecture | '', // MakeOptions['arch'], - label: 'Architecture', - required: false, - control: { - type: 'select', - options: { - placeholder: 'Architecture', - options: [ - { - label: 'Older PCs (ia32)', - value: 'ia32' - }, - { - label: 'Modern PCs (x64)', - value: 'x64' - }, - { - label: 'Older Mobile/Pi (armv7l)', - value: 'armv7l' - }, - { - label: 'New Mobile/Apple Silicon (arm64)', - value: 'arm64' - }, - { - label: 'Mac Universal (universal)', - value: 'universal' - }, - { - label: 'Special Systems (mips64el)', - value: 'mips64el' - } - ] - } - } - }, - platform: { - value: '' as NodeJS.Platform | '', // MakeOptions['platform'], - label: 'Platform', - required: false, - control: { - type: 'select', - options: { - placeholder: 'Platform', - options: [ - { - label: 'Windows (win32)', - value: 'win32' - }, - { - label: 'macOS (darwin)', - value: 'darwin' - }, - { - label: 'Linux (linux)', - value: 'linux' - } - ] - } - } - }, - configuration: { - label: 'Electron configuration', - value: undefined as Partial | undefined, - required: true, - control: { - type: 'json' - } - } -} satisfies InputsDefinition - -export const configureParams = { - name: createStringParam('Pipelab', { - label: 'Application name', - description: 'The name of the application', - required: true - }), - appBundleId: createStringParam('com.pipelab.app', { - label: 'Application bundle ID', - description: 'The bundle ID of the application', - required: true - }), - appCopyright: createStringParam('Copyright © 2024 Pipelab', { - label: 'Application copyright', - description: 'The copyright of the application', - required: false - }), - appVersion: createStringParam('1.0.0', { - label: 'Application version', - description: 'The version of the application', - required: true - }), - icon: createPathParam('', { - label: 'Application icon', - description: 'The icon of the application. macOS: .icns. Windows: .ico', - required: false, - control: { - type: 'path', - options: { - filters: [ - { name: 'Image', extensions: ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'icns'] } - ] - }, - label: 'Path to an image file' - } - }), - author: createStringParam('Pipelab', { - label: 'Application author', - description: 'The author of the application', - required: true - }), - description: createStringParam('A simple Electron application', { - label: 'Application description', - description: 'The description of the application', - required: false - }), - customPackages: createArray( - `[ - // e.g. "lodash" or "express@4.17.1" -]`, - { - label: 'Custom npm packages', - description: - 'A list of additional npm packages to install (format: "package" or "package@version")', - required: false, - control: { - type: 'array', - options: { - kind: 'text' - } - } - } - ), - - appCategoryType: createStringParam('public.app-category.developer-tools', { - platforms: ['darwin'], - label: 'Application category type', - description: 'The category type of the application', - required: false - }), - - // window - width: createNumberParam(800, { - label: 'Window width', - description: 'The width of the window', - required: false - }), - height: createNumberParam(600, { - label: 'Window height', - description: 'The height of the window', - required: false - }), - fullscreen: { - label: 'Fullscreen', - value: false, - description: 'Whether to start the application in fullscreen mode', - required: false, - control: { - type: 'boolean' - } - }, - frame: { - label: 'Frame', - value: true, - description: 'Whether to show the window frame', - required: false, - control: { - type: 'boolean' - } - }, - transparent: { - label: 'Transparent', - value: false, - description: 'Whether to make the window transparent', - required: false, - control: { - type: 'boolean' - } - }, - toolbar: { - label: 'Toolbar', - value: true, - description: 'Whether to show the toolbar', - required: false, - control: { - type: 'boolean' - } - }, - alwaysOnTop: { - label: 'Always on top', - value: false, - description: 'Whether to always keep the window on top', - required: false, - control: { - type: 'boolean' - } - }, - - backgroundColor: createColorPicker('#ffffff', { - label: 'Background Color', - description: 'The background color of the window', - required: false - }), - - electronVersion: createStringParam('', { - label: 'Electron version', - description: - 'The version of Electron to use. If no version specified, it will use the latest one.', - required: false - }), - customMainCode: createPathParam('', { - required: false, - label: 'Custom main code', - control: { - type: 'path', - options: { - filters: [{ name: 'JavaScript', extensions: ['js'] }] - }, - label: 'Path to a file containing custom main code' - } - }), - disableAsarPackaging: { - required: false, - label: 'Disable ASAR packaging', - value: true, - control: { - type: 'boolean' - }, - description: 'Whether to disable packaging project files in a single binary or not' - }, - enableExtraLogging: { - required: false, - label: 'Enable extra logging', - value: false, - control: { - type: 'boolean' - }, - description: 'Whether to enable extra logging of internal tools while bundling' - }, - clearServiceWorkerOnBoot: { - required: false, - label: 'Clear service worker on boot', - value: false, - control: { - type: 'boolean' - }, - description: 'Whether to clear service worker on boot' - }, - openDevtoolsOnStart: createBooleanParam(false, { - label: 'Open devtools on app start', - required: false, - description: 'Whether to open devtools on app start' - }), - - // Flags - - enableInProcessGPU: { - required: false, - label: 'Enable in-process GPU', - description: - 'When enabled, the GPU process runs inside the main browser process instead of a separate one. This can reduce overhead but may lead to instability or crashes if the GPU process fails.', - value: false, - control: { - type: 'boolean' - } - }, - enableDisableRendererBackgrounding: { - required: false, - description: - 'Enabling this prevents background tabs from being throttled, which can be useful for web apps that need continuous performance.', - label: 'Disable renderer backgrounding', - value: false, - control: { - type: 'boolean' - } - }, - forceHighPerformanceGpu: { - required: false, - description: - 'Enabling this forces the app to always use the high-performance GPU, which can improve rendering but may increase power consumption.', - label: 'Force high performance GPU', - value: false, - control: { - type: 'boolean' - } - }, - - // websocket apis - websocketApi: { - required: false, - label: 'WebSocket APIs to allow (empty = all)', - value: '[]', - control: { - type: 'array', - options: { - kind: 'text' - } - } - }, - ignore: createArray<(string | RegExp)[]>( - `[ - // use 'src/app/' as starting point -]`, - { - required: false, - label: 'Folders to ignore', - description: - 'An array of string or Regex that allow ignoring certain files or folders from being packaged', - control: { - type: 'array', - options: { - kind: 'text' - } - } - } - ), - - // integrations - - enableSteamSupport: { - required: false, - label: 'Enable steam support', - description: 'Whether to enable Steam support', - value: false, - control: { - type: 'boolean' - } - }, - steamGameId: createNumberParam(480, { - required: false, - label: 'Steam game ID', - description: 'The Steam game ID' - }), - enableDiscordSupport: { - required: false, - label: 'Enable Discord support', - description: 'Whether to enable Discord support', - value: false, - control: { - type: 'boolean' - } - }, - discordAppId: createStringParam('', { - required: false, - label: 'Discord application ID', - description: 'The Discord application ID' - }), - enableDoctor: createBooleanParam(true, { - required: false, - label: 'Enable doctor file', - description: - 'Whether to include the doctor.bat file in Windows builds for prerequisite checking and app launching' - }), - serverMode: { - value: '"default"' as 'default' | 'customProtocol', - required: false, - label: 'Server mode', - description: 'The server mode to use', - control: { - type: 'select', - options: { - placeholder: 'Mode', - options: [ - { - value: 'default', - label: 'Default' - }, - { - value: 'customProtocol', - label: 'Custom Protocol' - } - ] - } - } - } -} satisfies InputsDefinition - -const outputs = { - output: { - label: 'Output', - value: '', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - } -} satisfies OutputsDefinition - -// type Inputs = ParamsToInput - -export const createMakeProps = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string -) => - createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - params: { - ...params, - ...paramsInputFolder - }, - outputs - }) - -export const createPackageProps = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string, - advanced?: boolean, - deprecated?: boolean, - deprecatedMessage?: string, - disabled?: false, - updateAvailable?: boolean -) => - createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - advanced, - deprecated, - deprecatedMessage, - disabled, - updateAvailable, - params: { - ...params, - ...paramsInputFolder - }, - outputs: outputs - }) -export const createPackageV2Props = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string, - advanced?: boolean, - deprecated?: boolean, - deprecatedMessage?: string, - disabled?: false, - updateAvailable?: boolean -) => { - const { arch, platform } = params - return createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - advanced, - deprecated, - deprecatedMessage, - disabled, - updateAvailable, - params: { - arch, - platform, - ...paramsInputFolder, - ...configureParams - }, - outputs: outputs - }) -} - -export const createPreviewProps = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string -) => - createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - params: { - ...params, - ...paramsInputURL - }, - outputs: outputs - }) - -export const forge = async ( - action: 'make' | 'package' | 'preview', - appFolder: string | undefined, - { - cwd, - log, - inputs, - setOutput, - paths, - abortSignal - }: ActionRunnerData< - | ReturnType - | ReturnType - | ReturnType - | ReturnType - >, - completeConfiguration: DesktopApp.Electron -): Promise<{ folder: string; binary: string | undefined } | undefined> => { - const { join, basename, delimiter } = await import('node:path') - const { cp, readFile, writeFile, rm } = await import('node:fs/promises') - const { arch, platform } = await import('os') - const { kebabCase } = await import('change-case') - const semver = (await import('semver')).default - - log('Building electron') - - if (action !== 'preview') { - await detectRuntime(appFolder) - } - - const { assets, unpack, node } = paths - - console.log('assets', assets) - - // const { fileURLToPath } = await import('url') - // const __dirname = fileURLToPath(dirname(import.meta.url)) - // const { app } = await import('electron') - - const modulesPath = join(unpack, 'node_modules') - - const pnpm = join(modulesPath, 'pnpm', 'bin', 'pnpm.cjs') - - const destinationFolder = join(cwd, 'build') - - const forge = join( - destinationFolder, - 'node_modules', - '@electron-forge', - 'cli', - 'dist', - 'electron-forge.js' - ) - - const templateFolder = join(assets, 'electron', 'template', 'app') - console.log('templateFolder', templateFolder) - console.log('destinationFolder', destinationFolder) - - // copy template to destination - await cp(templateFolder, destinationFolder, { - recursive: true, - filter: (src) => { - // console.log('src', src) - // console.log('dest', dest) - return basename(src) !== 'node_modules' - } - }) - - console.log('copy done') - - const pkgJSONPath = join(destinationFolder, 'package.json') - const pkgJSONContent = await readFile(pkgJSONPath, 'utf8') - const userData = app.getPath('userData') - const pnpmHome = join(userData, 'config', 'pnpm') - const sanitizedName = kebabCase(completeConfiguration.name) - - const originalIconPath = completeConfiguration.icon - const hasIcon = completeConfiguration.icon !== undefined && completeConfiguration.icon !== '' - const iconFilename = hasIcon ? basename(completeConfiguration.icon) : '' - const newIconPath = hasIcon ? join(destinationFolder, iconFilename) : '' - const relativeIconPath = hasIcon ? join('./', 'build', iconFilename) : '' - const relativeIconPath1 = hasIcon ? join('./', iconFilename) : '' - - log('relativeIconPath', relativeIconPath) - log('relativeIconPath1', relativeIconPath1) - - const hasElectronVersion = - completeConfiguration.electronVersion !== undefined && - completeConfiguration.electronVersion !== '' - const isCJSOnly = - hasElectronVersion && - semver.lt(semver.coerce(completeConfiguration.electronVersion) || '0.0.0', '28.0.0') - - const pkgJSON = JSON.parse(pkgJSONContent) - log('Setting name to', sanitizedName) - pkgJSON.name = sanitizedName - log('Setting productName to', completeConfiguration.name) - pkgJSON.productName = completeConfiguration.name - - completeConfiguration.icon = relativeIconPath1 - - writeFile( - join(destinationFolder, 'config.cjs'), - `module.exports = ${JSON.stringify(completeConfiguration, undefined, 2)}`, - 'utf8' - ) - - if (isCJSOnly) { - log('Setting type to', 'commonjs') - pkgJSON.type = 'commonjs' - } else { - log('Setting type to', 'module') - pkgJSON.type = 'module' - } - - await writeFile(pkgJSONPath, JSON.stringify(pkgJSON, null, 2)) - - log('Installing packages') - await runWithLiveLogs( - node, - [pnpm, 'install', '--prefer-offline'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - - console.log('done install') - - // install user-defined custom packages - if ( - Array.isArray(completeConfiguration.customPackages) && - completeConfiguration.customPackages.length > 0 - ) { - log(`Installing custom packages: ${completeConfiguration.customPackages.join(', ')}`) - await runWithLiveLogs( - node, - [pnpm, 'install', ...completeConfiguration.customPackages, '--prefer-offline'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - } - - // override electron version - if (completeConfiguration.electronVersion && completeConfiguration.electronVersion !== '') { - log(`Installing electron@${completeConfiguration.electronVersion}`) - await runWithLiveLogs( - node, - [pnpm, 'install', `electron@${completeConfiguration.electronVersion}`, '--prefer-offline'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - } - - if (isCJSOnly) { - log(`Installing execa@8`) - await runWithLiveLogs( - node, - [pnpm, 'install', `execa@8`, '--prefer-offline'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - } - - console.log('completeConfiguration.icon', completeConfiguration.icon) - - // copy icon - if (hasIcon) { - await cp(originalIconPath, newIconPath) - } - - // copy custom main code - const destinationFile = join(destinationFolder, 'src', 'custom-main.js') - if (completeConfiguration.customMainCode) { - await cp(completeConfiguration.customMainCode, destinationFile) - } else { - await writeFile(destinationFile, 'console.log("No custom main code provided")', { - signal: abortSignal - }) - } - - if (isCJSOnly) { - /* ESBUILD transpilation */ - const external = [ - 'electron', - '@pipelab/steamworks.js', - 'electron', - 'node:*', - 'http', - 'node:stream' - ] - await esbuild.build({ - entryPoints: [join(destinationFolder, 'src', 'index.js')], - bundle: true, - write: true, - format: 'cjs', - platform: 'node', - external, - outfile: join(destinationFolder, 'dist', 'index.js') - }) - await esbuild.build({ - entryPoints: [join(destinationFolder, 'src', 'preload.js')], - bundle: true, - platform: 'node', - external, - format: 'cjs', - write: true, - outfile: join(destinationFolder, 'dist', 'preload.js') - }) - await esbuild.build({ - entryPoints: [join(destinationFolder, 'src', 'custom-main.js')], - bundle: true, - platform: 'node', - external, - format: 'cjs', - write: true, - outfile: join(destinationFolder, 'dist', 'custom-main.js') - }) - await rm(join(destinationFolder, 'src'), { recursive: true }) - await cp(join(destinationFolder, 'dist'), join(destinationFolder, 'src'), { - recursive: true - }) - await rm(join(destinationFolder, 'dist'), { recursive: true }) - /* ESBUILD transpilation */ - } - - const placeAppFolder = join(destinationFolder, 'src', 'app') - - // if input is folder, copy folder to destination - if (appFolder && action !== 'preview') { - // copy app to template - await cp(appFolder, placeAppFolder, { - recursive: true - }) - } - - const inputPlatform = inputs.platform === '' ? undefined : inputs.platform - const inputArch = inputs.arch === '' ? undefined : inputs.arch - - try { - log('typeof inputs.platform', typeof inputs.platform) - const finalPlatform = inputPlatform ?? platform() ?? '' - log('finalPlatform', finalPlatform) - const finalArch = inputArch ?? arch() ?? '' - - try { - await runWithLiveLogs( - node, - [forge, action, /* '--', */ '--arch', finalArch, '--platform', finalPlatform], - { - cwd: destinationFolder, - env: { - DEBUG: completeConfiguration.enableExtraLogging ? '*' : '', - ELECTRON_NO_ASAR: '1', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}` - // DEBUG: "electron-packager" - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - } catch (e) { - console.error('e', e) - } - - if (action === 'package') { - const outName = outFolderName( - completeConfiguration.name, - finalPlatform as NodeJS.Platform, - finalArch as NodeJS.Architecture - ) - const binName = getBinName(completeConfiguration.name) - - const output = join(destinationFolder, 'out', outName) - setOutput('output', output) - return { - folder: output, - binary: join(output, binName) - } - } else { - const output = join(destinationFolder, 'out', 'make') - setOutput('output', output) - return { - folder: output, - binary: undefined - } - } - } catch (e) { - if (e instanceof Error) { - if (e.name === 'RequestError') { - log('Request error') - } - if (e.name === 'RequestError') { - log('Request error') - } - } - log(e) - return undefined - } -} diff --git a/src/shared/libs/plugin-electron/index.ts b/src/shared/libs/plugin-electron/index.ts deleted file mode 100644 index bb9ee120..00000000 --- a/src/shared/libs/plugin-electron/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { makeRunner } from './make.js' -import { packageRunner } from './package.js' -import { previewRunner } from './preview.js' - -import { createNodeDefinition } from '@pipelab/plugin-core' -import icon from './public/electron.webp' -import { - createMakeProps, - createPackageProps, - createPackageV2Props, - createPreviewProps, - IDMake, - IDPackage, - IDPackageV2, - IDPreview -} from './forge.js' -import { configureRunner, props } from './configure.js' -import { packageV2Runner } from './package-v2.js' - -export default createNodeDefinition({ - description: 'Electron', - name: 'Electron', - id: 'electron', - icon: { - type: 'image', - image: icon - }, - nodes: [ - // make and package - { - node: createMakeProps( - IDMake, - 'Create Installer', - 'Create a distributable installer for your chosen platform', - '', - "`Build package for ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`" - ), - runner: makeRunner - // disabled: platform === 'linux' ? 'Electron is not supported on Linux' : undefined - }, - // package - // v1 - { - node: createPackageProps( - IDPackage, - 'Package app', - 'Gather all necessary files and prepare your app for distribution, creating a platform-specific bundle.', - '', - "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", - true - ), - runner: packageRunner - }, - // v2 - { - node: createPackageV2Props( - IDPackageV2, - 'Package app with configuration', - 'Gather all necessary files and prepare your app for distribution, creating a platform-specific bundle.', - '', - "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", - false, - false, - undefined, - false, - false - ), - runner: packageV2Runner - }, - { - node: createPreviewProps( - IDPreview, - 'Preview app', - 'Package and preview your app from an URL', - '', - "`Preview app from ${fmt.param(params['input-url'], 'primary', 'URL not set')}`" - ), - runner: previewRunner - }, - { - node: props, - runner: configureRunner - } - // { - // node: propsConfigureV2, - // runner: configureV2Runner - // } - // make without package - // { - // node: packageApp, - // runner: packageRunner, - // }, - ] -}) diff --git a/src/shared/libs/plugin-electron/make.ts b/src/shared/libs/plugin-electron/make.ts deleted file mode 100644 index d1571178..00000000 --- a/src/shared/libs/plugin-electron/make.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createActionRunner } from '@pipelab/plugin-core' -import { forge, createMakeProps } from './forge' -import { merge } from 'ts-deepmerge' -import { defaultElectronConfig } from './utils' - -export const makeRunner = createActionRunner>( - async (options) => { - const appFolder = options.inputs['input-folder'] - - if (!options.inputs.configuration) { - throw new Error('Missing electron configuration') - } - - const completeConfiguration = merge( - defaultElectronConfig, - options.inputs.configuration - ) as DesktopApp.Electron - - await forge('make', appFolder, options, completeConfiguration) - } -) diff --git a/src/shared/libs/plugin-electron/package-v2.ts b/src/shared/libs/plugin-electron/package-v2.ts deleted file mode 100644 index 9f03b368..00000000 --- a/src/shared/libs/plugin-electron/package-v2.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { createActionRunner } from '@pipelab/plugin-core' -import { forge } from './forge' -import { createPackageV2Props } from './forge' -import { merge } from 'ts-deepmerge' -import { defaultElectronConfig } from './utils' - -export const packageV2Runner = createActionRunner>( - async (options) => { - const appFolder = options.inputs['input-folder'] - - const completeConfiguration = merge(defaultElectronConfig, { - alwaysOnTop: options.inputs['alwaysOnTop'], - appBundleId: options.inputs['appBundleId'], - appCategoryType: options.inputs['appCategoryType'], - appCopyright: options.inputs['appCopyright'], - appVersion: options.inputs['appVersion'], - author: options.inputs['author'], - customMainCode: options.inputs['customMainCode'], - description: options.inputs['description'], - electronVersion: options.inputs['electronVersion'], - disableAsarPackaging: options.inputs['disableAsarPackaging'], - forceHighPerformanceGpu: options.inputs['forceHighPerformanceGpu'], - enableExtraLogging: options.inputs['enableExtraLogging'], - clearServiceWorkerOnBoot: options.inputs['clearServiceWorkerOnBoot'], - enableDisableRendererBackgrounding: options.inputs['enableDisableRendererBackgrounding'], - enableInProcessGPU: options.inputs['enableInProcessGPU'], - frame: options.inputs['frame'], - fullscreen: options.inputs['fullscreen'], - icon: options.inputs['icon'], - height: options.inputs['height'], - name: options.inputs['name'], - toolbar: options.inputs['toolbar'], - transparent: options.inputs['transparent'], - width: options.inputs['width'], - enableSteamSupport: options.inputs['enableSteamSupport'], - steamGameId: options.inputs['steamGameId'], - ignore: options.inputs['ignore'], - openDevtoolsOnStart: options.inputs['openDevtoolsOnStart'], - enableDiscordSupport: options.inputs['enableDiscordSupport'], - discordAppId: options.inputs['discordAppId'], - customPackages: options.inputs['customPackages'], - backgroundColor: options.inputs['backgroundColor'], - enableDoctor: options.inputs['enableDoctor'], - serverMode: options.inputs['serverMode'] - } satisfies DesktopApp.Electron) as DesktopApp.Electron - - options.log('completeConfiguration', completeConfiguration) - - // @ts-expect-error options is not really compatible - await forge('package', appFolder, options, completeConfiguration) - } -) diff --git a/src/shared/libs/plugin-electron/package.ts b/src/shared/libs/plugin-electron/package.ts deleted file mode 100644 index 90584da2..00000000 --- a/src/shared/libs/plugin-electron/package.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { createActionRunner } from '@pipelab/plugin-core' -import { createPackageProps, forge } from './forge' -import { merge } from 'ts-deepmerge' -import { defaultElectronConfig } from './utils' - -export const packageRunner = createActionRunner>( - async (options) => { - const appFolder = options.inputs['input-folder'] - - if (!options.inputs.configuration) { - throw new Error('Missing electron configuration') - } - - const completeConfiguration = merge( - defaultElectronConfig, - options.inputs.configuration - ) as DesktopApp.Electron - - // @ts-expect-error options is not really compatible - await forge('package', appFolder, options, completeConfiguration) - } -) diff --git a/src/shared/libs/plugin-electron/preview.ts b/src/shared/libs/plugin-electron/preview.ts deleted file mode 100644 index cfebe458..00000000 --- a/src/shared/libs/plugin-electron/preview.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { createActionRunner, runWithLiveLogs } from '@pipelab/plugin-core' -import { createPreviewProps, forge } from './forge' -import { merge } from 'ts-deepmerge' -import { defaultElectronConfig } from './utils' - -export const previewRunner = createActionRunner>( - async (options) => { - const url = options.inputs['input-url'] - if (url === '') { - throw new Error("URL can't be empty") - } - - if (!options.inputs.configuration) { - throw new Error('Missing electron configuration') - } - - const completeConfiguration = merge( - defaultElectronConfig, - options.inputs.configuration - ) as DesktopApp.Electron - - const output = await forge('package', undefined, options, completeConfiguration) - options.log('Opening preview', JSON.stringify(output)) - options.log('Opening url', url) - await runWithLiveLogs( - output.binary, - ['--url', url], - { - cancelSignal: options.abortSignal - }, - options.log - ) - return - } -) diff --git a/src/shared/libs/plugin-filesystem/copy.ts b/src/shared/libs/plugin-filesystem/copy.ts deleted file mode 100644 index f93c7929..00000000 --- a/src/shared/libs/plugin-filesystem/copy.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' - -export const ID = 'fs:copy' - -export const copy = createAction({ - id: ID, - name: 'Copy file/folder', - displayString: - '`Copy ${fmt.param(params.from, "primary", "Source")} to ${fmt.param(params.to, "primary", "Destination")}`', - params: { - from: createPathParam('', { - label: 'From', - required: true, - control: { - type: 'path', - options: { - properties: ['openFile', 'openDirectory'] - } - } - }), - to: createPathParam('', { - label: 'To', - required: true, - control: { - type: 'path', - options: { - properties: ['openFile', 'openDirectory', 'createDirectory', 'promptToCreate'] - } - } - }), - recursive: { - label: 'Recursive', - required: true, - value: true, - control: { - type: 'boolean' - } - }, - overwrite: { - label: 'Overwrite', - required: true, - value: true, - control: { - type: 'boolean' - } - }, - cleanup: { - label: 'Cleanup', - required: true, - description: 'Whether to delete the original file/folder', - value: true, - control: { - type: 'boolean' - } - } - }, - - outputs: { - output: { - label: 'Output', - value: '', - description: 'The copied file/folder' - }, - input: { - label: 'Input', - value: '', - description: 'The original file/folder' - }, - parentDirectory: { - label: 'Parent directory', - value: '', - description: 'The parent directory of the copied file/folder' - } - }, - description: 'Copy a file or a folder from one location to another', - icon: '', - meta: {} -}) - -export const copyRunner = createActionRunner(async ({ log, inputs, setOutput }) => { - const { cp, mkdir, rm, stat } = await import('node:fs/promises') - const { basename, join, dirname } = await import('node:path') - log('') - - const from = inputs.from - let to = inputs.to - - let fromIsAFile = false - try { - const stats = await stat(from) - if (stats.isFile()) { - fromIsAFile = true - } - } catch (e) { - log('Error getting file stats', e) - throw e - } - const fromFileName = fromIsAFile ? basename(from) : '' - - if (!from) { - log('From', from) - throw new Error('Missing source') - } - - if (!to) { - log('To', to) - throw new Error('Missing destination') - } - - // if from is a file, we need to add the file name to the destination - if (fromIsAFile) { - to = join(to, fromFileName) - } - - log('Copying', from, 'to', to, 'recursive', inputs.recursive, 'overwrite', inputs.overwrite) - - if (inputs.cleanup) { - try { - log('Cleaning up', to) - process.noAsar = true - await rm(to, { recursive: true, force: true, maxRetries: 3 }) - if (!fromIsAFile) { - await mkdir(to, { recursive: true }) - } - process.noAsar = false - } catch (e) { - log('Error cleaning up file', e) - throw e - } - } - - try { - process.noAsar = true - await cp(from, to, { - recursive: inputs.recursive && !fromIsAFile, - force: inputs.overwrite - }) - process.noAsar = false - setOutput('output', to) - setOutput('input', from) - setOutput('parentDirectory', dirname(to)) - log('Copied', from, 'to', to) - } catch (e) { - log('Error copying file', e) - throw e - } -}) diff --git a/src/shared/libs/plugin-filesystem/index.ts b/src/shared/libs/plugin-filesystem/index.ts deleted file mode 100644 index 08466120..00000000 --- a/src/shared/libs/plugin-filesystem/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { createNodeDefinition } from '@pipelab/plugin-core' -import { ListFilesAction, ListFilesActionRun } from './list-files.js' -import { isFileCondition, isFileRunner } from './is-file.js' -import { zipRunner, zip } from './zip.js' -import { zipV2Runner, zipV2 } from './zip-v2.js' -import { unzipRunner, unzip } from './unzip.js' -import { copy, copyRunner } from './copy.js' -import { remove, removeRunner } from './remove.js' -import { run, runRunner } from './run.js' -import { openInExplorer, openInExplorerRunner } from './open.js' - -export default createNodeDefinition({ - description: 'Filesystem', - id: 'filesystem', - name: 'Filesystem', - icon: { - type: 'icon', - icon: 'mdi-folder-zip-outline' - }, - nodes: [ - // { - // node: ListFilesAction, - // runner: ListFilesActionRun - // }, - // { - // node: isFileCondition, - // runner: isFileRunner - // }, - { - node: zip, - runner: zipRunner - }, - { - node: zipV2, - runner: zipV2Runner - }, - { - node: unzip, - runner: unzipRunner - }, - { - node: copy, - runner: copyRunner - }, - { - node: remove, - runner: removeRunner - }, - { - node: run, - runner: runRunner - }, - { - node: openInExplorer, - runner: openInExplorerRunner - } - ] -}) diff --git a/src/shared/libs/plugin-filesystem/is-file.ts b/src/shared/libs/plugin-filesystem/is-file.ts deleted file mode 100644 index f3a39421..00000000 --- a/src/shared/libs/plugin-filesystem/is-file.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - createCondition, - createConditionRunner, - } from "@pipelab/plugin-core"; - - export const ID = "is-file"; - - export const isFileCondition = createCondition({ - id: ID, - icon: "", - name: "Is file", - description: "", - displayString: "`If ${params.path} is a file`", - params: { - path: { - value: '', - label: "Path", - control: { - type: 'input', - options: { - kind: 'text' - } - } - }, - }, - }); - - export const isFileRunner = createConditionRunner< - typeof isFileCondition - >(async ({ log, inputs }) => { - const fs = await import('node:fs/promises') - - const path = inputs.path; - - log('path', path) - - const stats = await fs.stat(path) - - return stats.isFile() - }); diff --git a/src/shared/libs/plugin-filesystem/list-files.ts b/src/shared/libs/plugin-filesystem/list-files.ts deleted file mode 100644 index 47f353af..00000000 --- a/src/shared/libs/plugin-filesystem/list-files.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { createAction, createActionRunner } from "@pipelab/plugin-core"; -export const ID = "list-files-node"; - -export const ListFilesAction = createAction({ - id: ID, - name: "List files", - displayString: "`List files \"${params.recursive ? 'recursively' : ''}\" from \"${params.folder}`", - params: { - folder: { - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - }, - value: '', - label: "Folder", - }, - recursive: { - control: { - type: 'boolean', - }, - value: false, - label: "Recursive", - }, - }, - - outputs: { - paths: { - value: [] as Array, - label: "Paths", - }, - }, - description: "List files from a folder", - icon: "", - meta: {}, -}); - - -export const ListFilesActionRun = createActionRunner(async ({ log, inputs, setOutput }) => { - const fs = await import("node:fs/promises"); - const path = await import("node:path"); - - const readdir = fs.readdir; - - log(""); - - log("inputs", inputs); - - const folder = inputs.folder; - const recursive = inputs.recursive; - - log("folder", folder); - - const response = await readdir(folder, { - withFileTypes: true, - recursive, - }); - - log("response", response); - - const files = response; - - log("-- setValue('paths')"); - setOutput( - "paths", - files.map((x) => path.join(x.path, x.name)) - ); -}) diff --git a/src/shared/libs/plugin-filesystem/open.ts b/src/shared/libs/plugin-filesystem/open.ts deleted file mode 100644 index 89191ecf..00000000 --- a/src/shared/libs/plugin-filesystem/open.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' -// import displayString from './displayStringRun.lua?raw' - -export const ID = 'fs:open-in-explorer' - -export const openInExplorer = createAction({ - id: ID, - name: 'Open path in explorer', - displayString: "`Open ${fmt.param(params.path, 'primary', 'No path set')} in explorer`", - params: { - path: createPathParam('', { - required: true, - label: 'Path', - control: { - type: 'path', - options: { - properties: ['openDirectory', 'openFile'] - } - } - }) - }, - - outputs: { - message: { - label: 'Message', - value: '' - } - }, - description: 'Open a file or folder in your explorer', - icon: '', - meta: {} -}) - -export const openInExplorerRunner = createActionRunner( - async ({ log, inputs, setOutput }) => { - const { shell } = await import('electron') - - log(`Opening ${inputs.path}`) - const message = await shell.openPath(inputs.path) - setOutput('message', message) - } -) diff --git a/src/shared/libs/plugin-filesystem/remove.ts b/src/shared/libs/plugin-filesystem/remove.ts deleted file mode 100644 index 4b7ee960..00000000 --- a/src/shared/libs/plugin-filesystem/remove.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' - -export const ID = 'fs:remove' - -export const remove = createAction({ - id: ID, - name: 'Remove file/folder', - displayString: '`Remove ${fmt.param(params.from, "primary")}`', - params: { - from: createPathParam('', { - label: 'Path', - required: true, - control: { - type: 'path', - options: { - properties: ['openFile'] - } - } - }), - recursive: { - label: 'Recursive', - required: true, - value: true, - control: { - type: 'boolean' - } - } - }, - - outputs: {}, - description: 'Remove a file or a folder', - icon: '', - meta: {} -}) - -export const removeRunner = createActionRunner(async ({ log, inputs }) => { - const { rm } = await import('node:fs/promises') - log('') - - const from = inputs.from - - log('Removing', from, inputs.recursive) - - if (!from) { - log('From', from) - throw new Error('Missing source') - } - - try { - process.noAsar = true - await rm(from, { recursive: true, force: true, maxRetries: 3 }) - process.noAsar = false - log('Removed', from) - } catch (e) { - log('Error removeing file', e) - throw e - } -}) diff --git a/src/shared/libs/plugin-filesystem/run.ts b/src/shared/libs/plugin-filesystem/run.ts deleted file mode 100644 index ecb85a32..00000000 --- a/src/shared/libs/plugin-filesystem/run.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - createAction, - createActionRunner, - createPathParam, - createStringParam, - runWithLiveLogs -} from '@pipelab/plugin-core' - -export const ID = 'fs:run' - -export const run = createAction({ - id: ID, - name: 'Invoke file', - displayString: - "`Invoke ${fmt.param(params.command, 'primary')} ${(params.parameters ?? []).map(x => fmt.param(x)).join(' ')}`", - // displayString: displayString, - params: { - command: createStringParam('', { - required: true, - description: 'The command to run', - label: 'Command' - }), - parameters: { - required: true, - description: "The command's parameters", - label: 'Arguments', - value: [], - control: { - type: 'array', - options: { - kind: 'text' - } - } - }, - workingDirectory: createPathParam('', { - required: false, - description: 'The directory to run the command in. Default to current task directory', - label: 'Working directory', - control: { - type: 'path', - options: { - properties: ['createDirectory', 'openDirectory'] - } - } - }), - stopOnError: { - required: false, - description: 'Stop the task if the command fails', - label: 'Stop on error', - value: false, - control: { - type: 'boolean' - } - } - }, - - outputs: { - stdout: { - label: 'Standard output', - description: 'Standard output of the command', - value: '' - }, - stderr: { - label: 'Error output', - value: '' - }, - exitCode: { - label: 'Exit code', - value: 0 - }, - duration: { - label: 'Duration', - value: 0 - } - }, - description: 'Invoke an arbitrary executable', - icon: '', - meta: {} -}) - -export const runRunner = createActionRunner( - async ({ log, inputs, setOutput, abortSignal }) => { - const str = `${inputs.command} ${inputs.parameters.join(' ')}` - - log(`Running ${str}`) - - let stdout: string = '' - let stderr: string = '' - let exitCode: number = 0 - const durationMs: number = 0 - - const wd = inputs.workingDirectory ?? process.cwd() - log(`Working directory: ${wd}`) - - try { - await runWithLiveLogs( - inputs.command, - inputs.parameters, - { - cwd: wd, - cancelSignal: abortSignal - }, - log, - { - onStdout: (data) => { - stdout += data.toString() - log(data.toString()) - }, - onStderr: (data) => { - stderr += data.toString() - log(data.toString()) - }, - onExit(code) { - exitCode = code - } - } - ) - - setOutput('exitCode', exitCode === undefined ? -1 : exitCode) - setOutput('stdout', stdout) - setOutput('stderr', stderr) - setOutput('duration', durationMs) - if ((exitCode > 0 || exitCode === undefined) && inputs.stopOnError === true) { - throw new Error(`Command failed with exit code ${exitCode}`) - } - } catch (error) { - console.log('error', error) - if (inputs.stopOnError === true) { - throw error - } else if (error /* instanceof ExecaError */) { - setOutput('exitCode', error.exitCode === undefined ? -1 : error.exitCode) - setOutput('stdout', error.stdout ?? '') - setOutput('stderr', error.stderr ?? '') - setOutput('duration', error.durationMs ?? 0) - } - } - } -) diff --git a/src/shared/libs/plugin-filesystem/unzip.ts b/src/shared/libs/plugin-filesystem/unzip.ts deleted file mode 100644 index 0ccfb334..00000000 --- a/src/shared/libs/plugin-filesystem/unzip.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' - -export const ID = 'unzip-file-node' - -export const unzip = createAction({ - id: ID, - name: 'Unzip file', - displayString: '`Unzip ${fmt.param(params.file, "primary", "No file specified")}`', - params: { - file: createPathParam('', { - required: true, - control: { - type: 'path', - options: { - properties: ['openFile'] - } - }, - label: 'File' - }) - }, - - outputs: { - output: { - value: '', - label: 'Output' - } - }, - description: 'Unzip a file to a specified folder', - icon: '', - meta: {} -}) - -export const unzipRunner = createActionRunner( - async ({ log, inputs, setOutput, cwd }) => { - const StreamZip = await import('node-stream-zip') - const { join } = await import('node:path') - - console.log('inputs', inputs) - - console.log('inputs.file', inputs.file) - const file = inputs.file - console.log('file', file) - const output = join(cwd) - - console.log('file', file) - console.log('output', output) - - log('Unzip file', inputs.file, 'to', output) - - const zip = new StreamZip.default.async({ file }) - - const bytes = await zip.extract(null, output) - await zip.close() - - console.log('bytes', bytes) - - setOutput('output', output) - } -) diff --git a/src/shared/libs/plugin-filesystem/zip-v2.ts b/src/shared/libs/plugin-filesystem/zip-v2.ts deleted file mode 100644 index c9fe5f47..00000000 --- a/src/shared/libs/plugin-filesystem/zip-v2.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' - -export const ID = 'zip-v2-node' - -export type MaybeArray = T | T[] - -export const getValue = (array: MaybeArray): T => { - if (Array.isArray(array)) { - return array[0] - } else { - return array - } -} - -export const zipV2 = createAction({ - id: ID, - name: 'Zip', - displayString: '`Zip ${fmt.param(params.folder, "primary", "No folder specified")}`', - params: { - folder: createPathParam('', { - required: true, - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - }, - label: 'Folder' - }) - }, - - outputs: { - path: { - value: '', - label: 'Path' - } - }, - description: 'Zip a folder into a .zip file', - icon: '', - meta: {} -}) - -export const zipV2Runner = createActionRunner( - async ({ log, inputs, setOutput, abortSignal, paths }) => { - const { createWriteStream } = await import('node:fs') - const { join } = await import('path') - const { default: archiver } = await import('archiver') - - abortSignal.addEventListener('abort', () => { - throw new Error('Aborted') - }) - - const outputDir = paths.cache - const outputFile = join(outputDir, 'output.zip') - - console.log('outputFile', outputFile) - - const output = createWriteStream(outputFile) - - const archive = archiver('zip', { - zlib: { level: 9 } // Sets the compression level. - }) - - return new Promise((resolve, reject) => { - output.on('close', function () { - console.log(archive.pointer() + ' total bytes') - console.log('archiver has been finalized and the output file descriptor has closed.') - - setOutput('path', outputFile) - resolve() - }) - - output.on('end', function () { - console.log('Data has been drained') - }) - - archive.on('warning', function (err) { - if (err.code === 'ENOENT') { - console.log('Archiver warning: ENOENT') - } else { - reject(err) - } - }) - - archive.on('error', function (err) { - reject(err) - }) - - // archive.on('data', function (data) { - // log('data', data) - // }) - // archive.on('progress', function (data) { - // /* { - // entries: - // { - // total: 5012, - // processed: 5012 - // }, - // fs: - // { - // totalBytes: 318794388, - // processedBytes: 318794388 - // } - // } */ - // // log('progress', data.entries.processed + '/' + data.entries.total) - // }) - archive.on('entry', function (data) { - log('Adding', data.name) - }) - archive.on('finish', function () { - log('finish') - }) - - archive.pipe(output) - - archive.directory(inputs.folder, false) - - archive.finalize() - }) - } -) diff --git a/src/shared/libs/plugin-filesystem/zip.ts b/src/shared/libs/plugin-filesystem/zip.ts deleted file mode 100644 index 991cc1da..00000000 --- a/src/shared/libs/plugin-filesystem/zip.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' - -export const ID = 'zip-node' - -export type MaybeArray = T | T[] - -export const getValue = (array: MaybeArray): T => { - if (Array.isArray(array)) { - return array[0] - } else { - return array - } -} - -export const zip = createAction({ - id: ID, - name: 'Zip', - updateAvailable: true, - displayString: - '`Zip ${fmt.param(params.folder, "primary", "No folder specified")} to ${fmt.param(params.output, "secondary", "No output specified")}`', - params: { - folder: createPathParam('', { - required: true, - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - }, - label: 'Folder' - }), - output: createPathParam('', { - required: true, - control: { - type: 'path', - options: { - properties: ['openFile', 'promptToCreate'], - // must be zip file - filters: [ - { - extensions: ['zip'], - name: 'Zip file' - } - ] - } - }, - label: 'Folder' - }) - }, - - outputs: { - path: { - value: '', - label: 'Path' - } - }, - description: 'Zip a folder into a .zip file', - icon: '', - meta: {} -}) - -export const zipRunner = createActionRunner( - async ({ log, inputs, setOutput, abortSignal }) => { - const { createWriteStream } = await import('node:fs') - const { default: archiver } = await import('archiver') - - abortSignal.addEventListener('abort', () => { - throw new Error('Aborted') - }) - - const output = createWriteStream(inputs.output) - - const archive = archiver('zip', { - zlib: { level: 9 } // Sets the compression level. - }) - - return new Promise((resolve, reject) => { - output.on('close', function () { - console.log(archive.pointer() + ' total bytes') - console.log('archiver has been finalized and the output file descriptor has closed.') - - setOutput('path', inputs.output) - resolve() - }) - - output.on('end', function () { - console.log('Data has been drained') - }) - - archive.on('warning', function (err) { - if (err.code === 'ENOENT') { - console.log('Archiver warning: ENOENT') - } else { - reject(err) - } - }) - - archive.on('error', function (err) { - reject(err) - }) - - // archive.on('data', function (data) { - // log('data', data) - // }) - // archive.on('progress', function (data) { - // /* { - // entries: - // { - // total: 5012, - // processed: 5012 - // }, - // fs: - // { - // totalBytes: 318794388, - // processedBytes: 318794388 - // } - // } */ - // // log('progress', data.entries.processed + '/' + data.entries.total) - // }) - archive.on('entry', function (data) { - log('Adding', data.name) - }) - archive.on('finish', function () { - log('finish') - }) - - archive.pipe(output) - - archive.directory(inputs.folder, false) - - archive.finalize() - }) - } -) diff --git a/src/shared/libs/plugin-itch/export.ts b/src/shared/libs/plugin-itch/export.ts deleted file mode 100644 index 2428548f..00000000 --- a/src/shared/libs/plugin-itch/export.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { extractZip } from '@main/utils' -import { - createAction, - createActionRunner, - createPathParam, - createStringParam, - downloadFile, - runWithLiveLogs -} from '@pipelab/plugin-core' - -export const ID = 'itch-upload' - -export interface ButlerJSONOutputLog { - level: 'info' - message: string - time: number - type: 'log' -} - -export interface ButlerJSONOutputProgress { - bps: number - eta: number - progress: number - time: 1736873335 - type: 'progress' -} - -export type ButlerJSONOutput = ButlerJSONOutputLog | ButlerJSONOutputProgress - -export const uploadToItch = createAction({ - id: ID, - name: 'Upload to Itch.io', - description: '', - icon: '', - displayString: - "`Upload ${fmt.param(params['input-folder'], 'primary', 'No path selected')} to ${fmt.param(params['user'], 'primary', 'No project')}/${fmt.param(params['project'], 'primary', 'No project')}:${fmt.param(params['channel'], 'primary', 'No channel')}`", - meta: {}, - params: { - 'input-folder': createPathParam('', { - required: true, - label: 'Folder to Upload', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }), - user: createStringParam('', { - required: true, - label: 'User' - }), - project: createStringParam('', { - required: true, - label: 'Project' - }), - channel: createStringParam('', { - required: true, - label: 'Channel' - }), - 'api-key': createStringParam('', { - required: true, - label: 'API key' - }) - }, - outputs: {} -}) - -export const uploadToItchRunner = createActionRunner( - async ({ log, inputs, cwd, abortSignal }) => { - const { app } = await import('electron') - const { join, dirname } = await import('node:path') - const { mkdir, access, chmod } = await import('node:fs/promises') - const StreamZip = await import('node-stream-zip') - - const userData = app.getPath('userData') - - const itchMetadataPath = join(userData, 'thirdparty', 'itch') - const butlerTmpZipFile = join(cwd, 'thirdparty', 'itch', 'butler.zip') - - log('butlerTmpZipFile', butlerTmpZipFile) - - // create destination dir - await mkdir(itchMetadataPath, { - recursive: true - }) - - // create tmp dir - await mkdir(dirname(butlerTmpZipFile), { - recursive: true - }) - - const localOs = process.platform - const localArch = process.arch - - let butlerName = '' - if (localOs === 'darwin') { - butlerName += 'darwin' - } else if (localOs === 'linux') { - butlerName += 'linux' - } else if (localOs === 'win32') { - butlerName += 'windows' - } - - butlerName += '-' - - if (localArch === 'x64') { - butlerName += 'amd64' - } else { - throw new Error('Unsupported architecture') - } - - let extension = '' - if (localOs === 'win32') { - extension += '.exe' - } - - const butlerPath = join(itchMetadataPath, `butler${extension}`) - console.log('butlerPath', butlerPath) - - let alreadyExist = true - - try { - await access(butlerPath) - } catch (e) { - alreadyExist = false - } - - const url = `https://broth.itch.zone/butler/${butlerName}/LATEST/archive/default` - console.log('url', url) - - if (alreadyExist === false) { - await downloadFile( - url, - butlerTmpZipFile, - { - onProgress: ({ progress }) => { - log(`Downloading itch.io butler: ${progress.toFixed(2)}%`) - } - }, - abortSignal - ) - // const zip = new StreamZip.default.async({ file: butlerTmpZipFile }) - - // const bytes = await zip.extract(null, dirname(butlerPath)) - // await zip.close() - - await extractZip(butlerTmpZipFile, dirname(butlerPath)) - - // log('bytes', bytes) - } - - await chmod(butlerPath, 0o755) - - log('Uploading to itch') - - await runWithLiveLogs( - butlerPath, - [ - 'push', - inputs['input-folder'], - `${inputs.user}/${inputs.project}:${inputs.channel}`, - '--json' - ], - { - env: { - BUTLER_API_KEY: inputs['api-key'] - }, - cancelSignal: abortSignal - }, - log, - { - onStdout(data, subprocess) { - const jsons = data.trim().split('\n') - for (const jsonData of jsons) { - const json = JSON.parse(jsonData) as ButlerJSONOutput - switch (json.type) { - case 'log': - log(json.message) - break - case 'progress': - log(`${json.progress}% - ETA: ${json.eta}s`) - break - } - } - } - } - ) - - log('Uploaded to itch') - } -) diff --git a/src/shared/libs/plugin-itch/index.ts b/src/shared/libs/plugin-itch/index.ts deleted file mode 100644 index f9a6119e..00000000 --- a/src/shared/libs/plugin-itch/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { uploadToItch, uploadToItchRunner } from './export' - -import { createNodeDefinition } from '@pipelab/plugin-core' -import icon from './assets/itch-icon.webp' - -export default createNodeDefinition({ - description: 'Itch.io', - name: 'Itch.io', - id: 'itch.io', - icon: { - type: 'image', - image: icon - }, - nodes: [ - // make and package - { - node: uploadToItch, - runner: uploadToItchRunner - } - ] -}) diff --git a/src/shared/libs/plugin-minify/code.ts b/src/shared/libs/plugin-minify/code.ts deleted file mode 100644 index 141488d2..00000000 --- a/src/shared/libs/plugin-minify/code.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' - -export const ID = 'minify:code' - -export const minifyCode = createAction({ - id: ID, - name: 'Minify code', - description: '', - icon: '', - displayString: '`Minify code`', - meta: {}, - params: { - 'input-folder': createPathParam('', { - required: true, - label: 'Folder to compress', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }) - }, - outputs: {} -}) - -const getAllJsFiles = async (dir: string): Promise => { - const { readdir } = await import('node:fs/promises') - const { join } = await import('node:path') - - const files = await readdir(dir, { withFileTypes: true }) - return files.flatMap((file) => { - const fullPath = join(dir, file.name) - if (file.isDirectory()) { - return getAllJsFiles(fullPath) - } else if (file.isFile() && fullPath.endsWith('.js')) { - return fullPath - } - return [] - }) -} - -export const minifyCodeRunner = createActionRunner( - async ({ log, inputs, cwd, abortSignal }) => { - const { app } = await import('electron') - const { join, dirname } = await import('node:path') - const { mkdir, access, chmod } = await import('node:fs/promises') - const esbuild = (await import('esbuild')).default - - const jsFiles = await getAllJsFiles(inputs['input-folder']) - - for (const file of jsFiles) { - await esbuild.build({ - entryPoints: [file], // Process one file at a time - outfile: file, // Write directly to the original file - minify: true, // Minify the content - bundle: false, // Don't bundle dependencies - sourcemap: false, // No source maps (optional) - format: 'esm', // Optional: Specify output format - write: true // Ensure the file is overwritten - }) - console.log(`Minified: ${file}`) - } - - log('Minified code') - } -) diff --git a/src/shared/libs/plugin-minify/images.ts b/src/shared/libs/plugin-minify/images.ts deleted file mode 100644 index b830512a..00000000 --- a/src/shared/libs/plugin-minify/images.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { createAction, createActionRunner, createPathParam } from '@pipelab/plugin-core' - -export const ID = 'minify:images' - -export const minifyImages = createAction({ - id: ID, - name: 'Minify images', - description: '', - icon: '', - displayString: '`Minify`', - meta: {}, - params: { - 'input-folder': createPathParam('', { - required: true, - label: 'Folder to Upload', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }) - }, - outputs: {} -}) - -export const minifyImagesRunner = createActionRunner( - async ({ log, inputs, cwd, abortSignal }) => { - const { app } = await import('electron') - const { join, dirname } = await import('node:path') - const { mkdir, access, chmod } = await import('node:fs/promises') - - // TODO: https://github.com/imagemin/imagemin - - log('Minified images') - } -) diff --git a/src/shared/libs/plugin-minify/index.ts b/src/shared/libs/plugin-minify/index.ts deleted file mode 100644 index cb9762c4..00000000 --- a/src/shared/libs/plugin-minify/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { minifyCode, minifyCodeRunner } from './code' -import { minifyImages, minifyImagesRunner } from './images' - -import { createNodeDefinition } from '@pipelab/plugin-core' - -export default createNodeDefinition({ - description: 'Minify and compress code and images', - name: 'Minifyer', - id: 'poki', - icon: { - type: 'icon', - icon: 'mdi-zip-box' - }, - nodes: [ - // make and package - { - node: minifyCode, - runner: minifyCodeRunner - }, - { - node: minifyImages, - runner: minifyImagesRunner - } - ] -}) diff --git a/src/shared/libs/plugin-netlify/build.ts b/src/shared/libs/plugin-netlify/build.ts deleted file mode 100644 index 70bf875d..00000000 --- a/src/shared/libs/plugin-netlify/build.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { ensure, extractZip, zipFolder } from '@main/utils' -import { - createAction, - createActionRunner, - createNetlifySiteParam, - createPathParam, - createStringParam, - downloadFile, - fileExists, - runWithLiveLogs -} from '@pipelab/plugin-core' -import { app, shell } from 'electron' -import { createReadStream } from 'node:fs' -import { cp, mkdir, rm, writeFile } from 'node:fs/promises' -import { delimiter, dirname, join } from 'node:path' - -export const ID = 'netlify-build' - -export const buildNetlifySite = createAction({ - id: ID, - name: 'Build Netlify site', - description: '', - icon: '', - displayString: "`Build ${fmt.param(params['input-folder'], 'primary', 'No path selected')}`", - meta: {}, - params: { - 'input-folder': createPathParam('', { - required: true, - label: 'Path to the folder to upload to netlify', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }), - token: createStringParam('', { - required: true, - label: 'Token' - }) - }, - outputs: {} -}) - -export const buildNetlifySiteRunner = createActionRunner( - async ({ log, inputs, cwd, abortSignal, paths }) => { - log('Building netlify site') - - const { pnpm, node } = paths - - const userData = app.getPath('userData') - const pnpmHome = join(userData, 'config', 'pnpm') - - const buildDir = join(cwd, 'build') - - const inputFolder = inputs['input-folder'] - // ensure input folder have apackage.json - const packageJsonPath = join(inputFolder, 'package.json') - const packageJson = await fileExists(packageJsonPath) - if (!packageJson) { - throw new Error('No package.json found in input folder') - } - - await cp(inputs['input-folder'], buildDir, { - recursive: true - }) - - const netlifyDir = join(buildDir, '.netlify') - const netlifyState = join(netlifyDir, 'state.json') - - await mkdir(netlifyDir, { recursive: true }) - - await writeFile(netlifyState, `{ "siteId": "${inputs.site}" }`, 'utf-8') - - // log('Installing packages') - // await runWithLiveLogs( - // node, - // [pnpm, 'install', '--prefer-offline'], - // { - // cwd: buildDir, - // env: { - // // DEBUG: '*', - // PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - // PNPM_HOME: pnpmHome - // }, - // cancelSignal: abortSignal - // }, - // log, - // { - // onStderr(data) { - // log(data) - // }, - // onStdout(data) { - // log(data) - // } - // } - // ) - - // await runWithLiveLogs( - // node, - // [pnpm, 'build', '--preset', 'netlify'], - // { - // cwd: buildDir, - // env: { - // // DEBUG: '*', - // PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - // PNPM_HOME: pnpmHome - // }, - // cancelSignal: abortSignal - // }, - // log, - // { - // onStderr(data) { - // log(data) - // }, - // onStdout(data) { - // log(data) - // } - // } - // ) - await runWithLiveLogs( - node, - [pnpm, '--package', 'netlify-cli', 'dlx', 'netlify', 'build'], - { - cwd: buildDir, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome, - NETLIFY_AUTH_TOKEN: inputs.token - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - - // const distDir = join(buildDir, 'dist') - - // const distZipPath = join(cwd, 'dist.zip') - // const zip = await zipFolder(distDir, distZipPath, log) - - // console.log('zip', zip) - // console.log('distZipPath', distZipPath) - - // const result = await fetch(`https://api.netlify.com/api/v1/sites/${inputs.site}/deploys`, { - // method: 'POST', - // body: createReadStream(distZipPath), - // headers: { - // 'Content-Type': 'application/zip', - // Authorization: `Bearer ${inputs.token}` - // }, - // duplex: 'half' - // }) - // - // const deploy = await result.json() - - await runWithLiveLogs( - node, - [pnpm, '--package', 'netlify-cli', 'dlx', 'netlify', 'deploy', '--prod'], - { - cwd: buildDir, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome, - NETLIFY_AUTH_TOKEN: inputs.token - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - - // log('Deployed to netlify', deploy) - - log('Uploaded to netlify') - } -) diff --git a/src/shared/libs/plugin-netlify/index.ts b/src/shared/libs/plugin-netlify/index.ts deleted file mode 100644 index 31038507..00000000 --- a/src/shared/libs/plugin-netlify/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { uploadToNetlify, uploadToNetlifyRunner } from './publish' -import { buildNetlifySite, buildNetlifySiteRunner } from './build' - -import { createNodeDefinition } from '@pipelab/plugin-core' -import icon from './assets/netlify-icon.webp' - -export default createNodeDefinition({ - description: 'Netlify', - name: 'Netlify', - id: 'netlify', - icon: { - type: 'image', - image: icon - }, - nodes: [ - // make and package - { - node: buildNetlifySite, - runner: buildNetlifySiteRunner - }, - { - node: uploadToNetlify, - runner: uploadToNetlifyRunner - } - ] -}) diff --git a/src/shared/libs/plugin-nvpatch/index.ts b/src/shared/libs/plugin-nvpatch/index.ts deleted file mode 100644 index d15c5bca..00000000 --- a/src/shared/libs/plugin-nvpatch/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { NVPatch, NVPatchRunner } from './nvpatch' - -import { createNodeDefinition } from '@pipelab/plugin-core' - -export default createNodeDefinition({ - description: 'NVPatch', - name: 'NVPatch', - id: 'nv-patch', - icon: { - type: 'icon', - icon: 'mdi-wrench' - }, - nodes: [ - // make and package - { - node: NVPatch, - runner: NVPatchRunner - } - ] -}) diff --git a/src/shared/libs/plugin-nvpatch/nvpatch.ts b/src/shared/libs/plugin-nvpatch/nvpatch.ts deleted file mode 100644 index 5b132d62..00000000 --- a/src/shared/libs/plugin-nvpatch/nvpatch.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { - createAction, - createActionRunner, - createPathParam, - runWithLiveLogs -} from '@pipelab/plugin-core' - -export const ID = 'nvpatch' - -export const NVPatch = createAction({ - id: ID, - name: 'Patch binary', - description: '', - icon: '', - displayString: "`Patch binary ${fmt.param(params['input'], 'primary')}`", - meta: {}, - params: { - input: createPathParam('', { - required: true, - label: 'File to patch', - control: { - type: 'path', - options: { - properties: ['openFile'] - } - } - }) - }, - outputs: {} -}) - -export const NVPatchRunner = createActionRunner( - async ({ log, inputs, paths, abortSignal, cwd }) => { - const { join, resolve } = await import('node:path') - const { fileExists } = await import('@@/libs/plugin-core') - const { execa } = await import('execa') - const semver = (await import('semver')).default - - const checkDotnetVersion = async (command: string) => { - try { - const { stdout } = await execa(command, ['--version']) - const version = stdout.trim() - log(`.NET version found: ${version}`) - if (semver.lt(semver.coerce(version) || '0.0.0', '8.0.0')) { - throw new Error(`.NET version 8 or higher is required. Found version ${version}.`) - } - } catch (e: unknown) { - if (e instanceof Error && e.message?.includes('.NET version 8 or higher is required')) { - throw e - } - throw new Error( - `.NET runtime not found (command: "${command}"). Please ensure .NET 8 or higher is installed.` - ) - } - } - - // run - - console.log('process.env', process.env) - - // Detect platform and set up platform-specific configuration - const isMacOS = process.platform === 'darwin' - const isWindows = process.platform === 'win32' - - let nvpatchCommand: string - let nvpatchArgs: string[] - - if (isMacOS) { - // macOS: Use arch -x86_64 with dotnet runtime and DLL path - const dotnetRuntime = '/usr/local/share/dotnet/x64/dotnet' - const nvpatchDll = resolve(join(process.env.HOME!, '.dotnet', 'tools', 'nvpatch.dll')) - - log('Trying nvpatch from', nvpatchDll) - - // ensure dotnet runtime is installed - await checkDotnetVersion(dotnetRuntime) - - nvpatchCommand = 'arch' - nvpatchArgs = ['-x86_64', dotnetRuntime, nvpatchDll, '--enable', inputs['input']] - } else { - // Windows: Use direct executable path with HOME instead of USERPROFILE - const nvpatchExe = resolve( - join(process.env.USERPROFILE || process.env.HOME || '', '.dotnet', 'tools', 'nvpatch.exe') - ) - - log('Trying nvpatch from', nvpatchExe) - - nvpatchCommand = nvpatchExe - nvpatchArgs = ['--enable', inputs['input']] - - // ensure the binary exists - if (!(await fileExists(nvpatchExe))) { - throw new Error(`nvpatch.exe not found at ${nvpatchExe}`) - } - - // ensure dotnet runtime is installed - await checkDotnetVersion('dotnet') - } - - await runWithLiveLogs( - nvpatchCommand, - nvpatchArgs, - { - cancelSignal: abortSignal - }, - log - ) - log('nvpatch done') - } -) diff --git a/src/shared/libs/plugin-poki/export.ts b/src/shared/libs/plugin-poki/export.ts deleted file mode 100644 index 646cc213..00000000 --- a/src/shared/libs/plugin-poki/export.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { createAction, createActionRunner, createPathParam, createStringParam, runWithLiveLogs } from '@pipelab/plugin-core' -import { dirname } from 'node:path' - -export const ID = 'poki-upload' - -export const uploadToPoki = createAction({ - id: ID, - name: 'Upload to Poki.io', - description: '', - icon: '', - displayString: - "`Upload ${fmt.param(params['input-folder'], 'primary', 'No path selected')} to ${fmt.param(params['project'], 'primary', 'No project')} poki game (${fmt.param(params['name'], 'primary', 'No version name')})`", - meta: {}, - params: { - 'input-folder': createPathParam('', { - required: true, - label: 'Folder to Upload', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }), - project: createStringParam('', { - required: true, - label: 'Project', - description: 'This is you Poki game id', - }), - name: createStringParam('', { - required: true, - label: 'Version name', - description: 'This is the name of the version', - }), - notes: createStringParam('', { - required: true, - label: 'Version notes', - description: 'These are notes you want to specify with your version', - }) - }, - outputs: {} -}) - -export const uploadToPokiRunner = createActionRunner( - async ({ log, inputs, paths, abortSignal, cwd }) => { - const { join, basename, delimiter } = await import('node:path') - const { writeFile, cp, mkdir } = await import('node:fs/promises') - const { shell } = await import('electron') - - const { unpack } = paths - const modulesPath = join(unpack, 'node_modules') - const poki = join(modulesPath, '@poki', 'cli', 'bin', 'index.js') - - const dist = join(cwd, 'dist') - - await mkdir(dist, { recursive: true }) - await cp(inputs['input-folder'], dist, { - recursive: true - }) - - const pokiJsonPath = join(cwd, 'poki.json') - - // create file at the same place the folder to upload - await writeFile( - pokiJsonPath, - JSON.stringify( - { - game_id: inputs.project, - build_dir: 'dist' - }, - undefined, - 2 - ), - 'utf-8' - ) - - await shell.openPath(cwd) - - // TODO: needs auth - - await runWithLiveLogs( - poki, - ['upload', '--name', inputs.name, '--notes', inputs.notes], - { - cwd, - env: { - // DEBUG: '*', - PATH: `${dirname(poki)}${delimiter}${process.env.PATH}`, - }, - cancelSignal: abortSignal, - }, - log, - { - onStderr(data, subprocess) { - log(data) - }, - onStdout(data, subprocess) { - log(data) - } - } - ) - - /* - { - "game_id": "c7bfd2ba-e23b-486f-9504-a6f196cb44df", - "build_dir": "dist" - } - npx @poki/cli upload --name "$(git rev-parse --short HEAD)" --notes "$(git log -1 --pretty=%B)" - */ - - log('Uploaded to poki') - } -) diff --git a/src/shared/libs/plugin-poki/index.ts b/src/shared/libs/plugin-poki/index.ts deleted file mode 100644 index 4883fdd6..00000000 --- a/src/shared/libs/plugin-poki/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { uploadToPoki, uploadToPokiRunner } from './export' - -import { createNodeDefinition } from '@pipelab/plugin-core' -import icon from './assets/poki-icon.webp' - -export default createNodeDefinition({ - description: 'Poki', - name: 'Poki', - id: 'poki', - icon: { - type: 'image', - image: icon - }, - nodes: [ - // make and package - { - node: uploadToPoki, - runner: uploadToPokiRunner - } - ] -}) diff --git a/src/shared/libs/plugin-steam/declarations.d.ts b/src/shared/libs/plugin-steam/declarations.d.ts deleted file mode 100644 index 5ab250f4..00000000 --- a/src/shared/libs/plugin-steam/declarations.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.webp' diff --git a/src/shared/libs/plugin-steam/index.ts b/src/shared/libs/plugin-steam/index.ts deleted file mode 100644 index c1680f56..00000000 --- a/src/shared/libs/plugin-steam/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { uploadToSteam, uploadToSteamRunner } from './upload-to-steam.js' -import { createNodeDefinition } from '@pipelab/plugin-core' -import icon from './steam.webp' - -export default createNodeDefinition({ - description: 'Steam', - id: 'steam', - name: 'Steam', - icon: { - type: 'image', - image: icon - }, - nodes: [ - { - node: uploadToSteam, - runner: uploadToSteamRunner - } - ] -}) diff --git a/src/shared/libs/plugin-steam/upload-to-steam.ts b/src/shared/libs/plugin-steam/upload-to-steam.ts deleted file mode 100644 index 3f29639f..00000000 --- a/src/shared/libs/plugin-steam/upload-to-steam.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { - createAction, - createActionRunner, - createPathParam, - createStringParam, - fileExists, - runWithLiveLogsPTY -} from '@pipelab/plugin-core' -import { checkSteamAuth, openExternalTerminal } from './utils' -import { ExternalCommandError } from '../plugin-core/custom-errors' - -// https://github.com/ztgasdf/steampkg?tab=readme-ov-file#account-management - -// How to login -// Do it at least once -// sdk/tools/ContentBuilder/builder_linux/steamcmd.sh +login User +quit - -export const ID = 'steam-upload' - -export const uploadToSteam = createAction({ - id: ID, - name: 'Upload to Steam', - description: 'Upload a folder to Steam', - icon: '', - displayString: "`Upload ${fmt.param(params['folder'], 'primary')} to steam`", - meta: {}, - params: { - sdk: createPathParam('', { - required: true, - label: 'Steam Sdk path', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }), - username: createStringParam('', { - required: true, - label: 'Steam username' - }), - appId: createStringParam('', { - required: true, - label: 'App Id' - }), - depotId: createStringParam('', { - required: true, - label: 'Depot Id' - }), - description: createStringParam('', { - required: true, - label: 'Description' - }), - folder: createPathParam('', { - required: true, - label: 'Folder to upload', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }) - // enableDRM: { - // value: false, - // label: 'Enable DRM', - // control: { - // type: 'boolean' - // } - // }, - // binaryToPatch: createPathParam('', { - // label: 'Binary to patch', - // control: { - // type: 'path', - // options: { - // properties: ['openFile'] - // } - // } - // }) - }, - outputs: {} -}) - -export const uploadToSteamRunner = createActionRunner( - async ({ log, inputs, cwd, abortSignal }) => { - const { join, dirname, basename } = await import('path') - const { platform } = await import('os') - const { chmod, mkdir, writeFile, cp } = await import('fs/promises') - - const { folder, appId, sdk, depotId, username, description } = inputs - log(`uploading "${folder}" to steam`) - - const errorMap = { - 6: `No connection to content server. Your depot id (${depotId}) may be invalid` - } - - const isSDKExisting = await fileExists(sdk) - if (!isSDKExisting) { - throw new Error(`You must enter a valid path to the Steam SDK`) - } - - const buildOutput = join(cwd, 'steam', 'output') - const scriptPath = join(cwd, 'steam', 'script.vdf') - - await mkdir(buildOutput, { - recursive: true - }) - - await mkdir(dirname(scriptPath), { - recursive: true - }) - - const script = `"AppBuild" -{ - "AppID" "${appId}" // your AppID - "Desc" "${description}" // internal description for this build - - "ContentRoot" "${folder}" // root content folder, relative to location of this file - "BuildOutput" "${buildOutput}" // build output folder for build logs and build cache files - - "Depots" - { - "${depotId}" // your DepotID - { - "FileMapping" - { - "LocalPath" "*" // all files from contentroot folder - "DepotPath" "." // mapped into the root of the depot - "recursive" "1" // include all subfolders - } - } - } -}` - - console.log('script', script) - - let builderFolder = 'builder' - if (platform() === 'linux') { - builderFolder += '_linux' - } else if (platform() === 'darwin') { - builderFolder += '_osx' - } - - const cmd = 'steamcmd' - let cmdFinal = 'steamcmd' - if (platform() === 'linux') { - cmdFinal += '.sh' - } else if (platform() === 'darwin') { - cmdFinal += '.sh' - } else if (platform() === 'win32') { - cmdFinal += '.exe' - } - - const steamcmdPath = join(sdk, 'tools', 'ContentBuilder', builderFolder, cmdFinal) - - console.log('steamcmdPath', steamcmdPath) - - if (platform() === 'linux' || platform() === 'darwin') { - if (platform() === 'linux') { - log('Adding "execute" permissions to linux binary') - const steamcmdBinaryPath = join( - sdk, - 'tools', - 'ContentBuilder', - builderFolder, - 'linux32', - cmd - ) - await chmod(steamcmdBinaryPath, 0o755) - const steamcmdBinaryErrorReporterPath = join( - sdk, - 'tools', - 'ContentBuilder', - builderFolder, - 'linux32', - 'steamerrorreporter' - ) - await chmod(steamcmdBinaryErrorReporterPath, 0o755) - } - - if (platform() === 'darwin') { - const steamcmdBinaryPath = join(sdk, 'tools', 'ContentBuilder', builderFolder, cmd) - log('Adding "execute" permissions to darwin binary') - await chmod(steamcmdBinaryPath, 0o755) - } - - log('Adding "execute" permissions to binary') - await chmod(steamcmdPath, 0o755) - } - - // check for steam authentication - const isAuthenticated = await checkSteamAuth({ - context: { - log, - abortSignal - }, - scriptPath, - steamcmdPath, - username - }) - - log('isAuthenticated', JSON.stringify(isAuthenticated)) - - if (isAuthenticated.success === false) { - log('Opening terminal with interactive login') - await openExternalTerminal(steamcmdPath, ['+login', username, '+quit'], { - cancelSignal: abortSignal - }) - const isAuthenticatedNow = await checkSteamAuth({ - context: { - log, - abortSignal - }, - scriptPath, - steamcmdPath, - username - }) - if (isAuthenticatedNow.success === false) { - throw new Error('Not authenticated') - } - } - - log('Writing script') - await writeFile(scriptPath, script, { - encoding: 'utf8', - signal: abortSignal - }) - - log('Executing steamcmd') - - // Should be authed here - try { - await runWithLiveLogsPTY( - steamcmdPath, - ['+login', username, '+run_app_build', scriptPath, '+quit'], - {}, - log, - { - onStdout: (data) => { - log('[steamcmd]', data) - }, - onStderr: (data) => { - log('[steamcmd]', data) - } - }, - abortSignal - ) - } catch (e) { - if (e instanceof ExternalCommandError) { - const code = e.code as keyof typeof errorMap - const message = (code in errorMap) ? errorMap[code] : 'SteamCmd error:' + e.code + ' ' + e.message - throw new Error(message) - } else if (e instanceof Error) { - console.error(e) - throw new Error('Error:' + e.message) - } else { - throw new Error('unknwon error') - } - } - - log('Done uploading') - } -) diff --git a/src/shared/libs/plugin-system/alert.ts b/src/shared/libs/plugin-system/alert.ts deleted file mode 100644 index c0d8710e..00000000 --- a/src/shared/libs/plugin-system/alert.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { createAction, createActionRunner, createStringParam } from '@pipelab/plugin-core' - -export const ID = 'system:alert' - -export type Data = { - text: string -} - -export const alertAction = createAction({ - id: ID, - name: 'Alert', - description: 'Alert a message', - icon: '', - displayString: "`Alert ${fmt.param(params.message ?? 'No message')}`", - meta: {}, - params: { - message: createStringParam('', { - required: true, - label: 'Message', - }) - }, - - outputs: { - answer: { - label: 'Answer', - value: '' - } - } -}) - -export const alertActionRunner = createActionRunner( - async ({ log, inputs, api, setOutput, browserWindow }) => { - browserWindow.flashFrame(true) - // 'cancel' | 'ok' - const _answer = await api.execute('dialog:alert', { - message: inputs.message - }) - - if ('content' in _answer) { - setOutput('answer', _answer.content.toString()) - } else { - log('error') - } - } -) diff --git a/src/shared/libs/plugin-system/branch.ts b/src/shared/libs/plugin-system/branch.ts deleted file mode 100644 index 21af4b6d..00000000 --- a/src/shared/libs/plugin-system/branch.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { createCondition, createConditionRunner } from '@pipelab/plugin-core' - -export const ID = 'branch' - -export const branchCondition = createCondition({ - id: ID, - icon: '', - name: 'Branch', - description: '', - displayString: 'If {{ params.valueA }} {{ params.operator }} {{ params.valueB }}', - params: { - valueA: { - value: '', - label: 'First value', - control: { - type: 'input', - options: { - kind: 'text' - } - } - }, - operator: { - value: '', - label: 'Comparison', - control: { - type: 'select', - options: { - placeholder: 'Comparison', - options: [ - { - label: '=', - value: '=' - } - ] - } - } - }, - valueB: { - value: '', - label: 'Second value', - control: { - type: 'input', - options: { - kind: 'text' - } - } - } - } -}) - -export const branchConditionRunner = createConditionRunner( - async ({ log, inputs }) => { - const firstValue = inputs.valueA - const secondValue = inputs.valueB - const operator = inputs.operator as '=' | '!=' | '<' | '<=' | '>' | '>=' - - let result - switch (operator) { - case '!=': - result = firstValue != secondValue - break - - case '<': - result = firstValue < secondValue - break - - case '<=': - result = firstValue <= secondValue - break - - case '=': - result = firstValue === secondValue - break - - case '>': - result = firstValue > secondValue - break - - case '>=': - result = firstValue >= secondValue - break - - default: - throw new Error('Unhandled case') - } - - return result - } -) diff --git a/src/shared/libs/plugin-system/for.ts b/src/shared/libs/plugin-system/for.ts deleted file mode 100644 index 0e31e99a..00000000 --- a/src/shared/libs/plugin-system/for.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Meta, createLoop, createLoopRunner } from "@pipelab/plugin-core"; - -export const ID = "for"; - -export const forLoop = createLoop({ - id: ID, - name: "For", - icon: '', - description: 'A loop', - outputs: { - item: { - value: undefined as any, - label: "Item", - }, - }, - params: { - value: { - value: [] as Array, - label: 'Value', - control: { - type: 'expression', - options: {} - } - } - }, - meta: { - loopindex: 0 - }, - displayString: 'Loop for every element of {{params.value}}', -}); - -export const ForLoopRunner = createLoopRunner(async ({ log, meta, setMeta, inputs }) => { - const index = meta?.loopindex - const value = inputs.value - - log('index', index) - - setMeta((meta) => { - return { - ...meta, - loopindex: index + 1 - } - }) - - return value.length < index ? 'step' : 'exit'; -}) diff --git a/src/shared/libs/plugin-system/index.ts b/src/shared/libs/plugin-system/index.ts deleted file mode 100644 index e35381b6..00000000 --- a/src/shared/libs/plugin-system/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { createNodeDefinition } from '@pipelab/plugin-core' -import { logAction, logActionRunner } from './log.js' -// import { branchCondition, branchConditionRunner } from './branch.js' -// import { forLoop, ForLoopRunner } from './for.js' -import { manualEvent, manualEvaluator } from './manual.js' -import { alertAction, alertActionRunner } from './alert.js' -import { promptAction, promptActionRunner } from './prompt.js' -import { sleepAction, sleepActionRunner } from './sleep.js' - -export default createNodeDefinition({ - id: 'system', - description: 'System', - name: 'System', - icon: { - type: 'icon', - icon: 'mdi-cog-outline' - }, - nodes: [ - { - node: logAction, - runner: logActionRunner - }, - // { - // node: branchCondition, - // runner: branchConditionRunner, - // }, - // { - // node: forLoop, - // runner: ForLoopRunner - // }, - { - node: manualEvent, - runner: manualEvaluator - }, - { - node: alertAction, - runner: alertActionRunner - }, - { - node: promptAction, - runner: promptActionRunner - }, - { - node: sleepAction, - runner: sleepActionRunner - } - ] -}) diff --git a/src/shared/libs/plugin-system/join.ts b/src/shared/libs/plugin-system/join.ts deleted file mode 100644 index 4ae86ed6..00000000 --- a/src/shared/libs/plugin-system/join.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - createExpression, - createExpressionRunner, -} from "@pipelab/plugin-core"; - -export const ID = "join"; - -export type Data = { - value: string; -}; - -const DEFAULT_SEPARATOR = ", "; - -export const join = createExpression({ - id: ID, - name: "Join", - description: 'Join values', - displayString: 'Join {{ params.value }}', - icon: '', - meta: {}, - params: { - input: { - label: 'Input', - value: [], - control: { - type: 'input', - options: { - kind: 'text' - } - } - }, - separator: { - label: 'Separator', - value: DEFAULT_SEPARATOR, - control: { - type: 'input', - options: { - kind: 'text' - } - } - }, - }, - - outputs: { - value: { - label: 'Value', - value: '' - }, - }, -}); - -export const evaluator = createExpressionRunner(async ({ inputs }) => { - const inputArr = inputs?.input; - const separatorArr = inputs?.separator; - - const input = inputArr ? inputArr[0] : []; - const separator = separatorArr?.[0] ?? DEFAULT_SEPARATOR; - - const result = input.join(separator) - return result - } -); \ No newline at end of file diff --git a/src/shared/libs/plugin-system/log.ts b/src/shared/libs/plugin-system/log.ts deleted file mode 100644 index 950834da..00000000 --- a/src/shared/libs/plugin-system/log.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { createAction, createActionRunner, createStringParam } from '@pipelab/plugin-core' - -export const ID = 'log' - -export type Data = { - text: string -} - -export const logAction = createAction({ - id: ID, - name: 'Log', - description: 'Log a message', - icon: '', - displayString: '`Log "${fmt.param(params.message)}"`', - meta: {}, - params: { - message: createStringParam('', { - required: true, - label: 'Message' - }) - }, - - outputs: {} -}) - -export const logActionRunner = createActionRunner(async ({ log, inputs }) => { - log(`${inputs.message ?? ''}`) -}) diff --git a/src/shared/libs/plugin-system/prompt.ts b/src/shared/libs/plugin-system/prompt.ts deleted file mode 100644 index f182731e..00000000 --- a/src/shared/libs/plugin-system/prompt.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { createAction, createActionRunner, createStringParam } from '@pipelab/plugin-core' - -export const ID = 'system:prompt' - -export type Data = { - text: string -} - -export const promptAction = createAction({ - id: ID, - name: 'Prompt', - description: 'Prompt a message', - icon: '', - displayString: "`Prompt ${fmt.param(params.message ?? 'No message')}`", - meta: {}, - params: { - message: createStringParam('', { - required: true, - label: 'Message', - }) - }, - - outputs: { - answer: { - label: 'Answer', - value: '' - } - } -}) - -export const promptActionRunner = createActionRunner( - async ({ log, inputs, api, setOutput, browserWindow }) => { - browserWindow.flashFrame(true) - // 'cancel' | 'ok' - const _answer = await api.execute('dialog:prompt', { - message: inputs.message - }) - - log('_answer', _answer) - - if (_answer.type === 'success') { - setOutput('answer', _answer.result.answer) - } else { - throw new Error(_answer.ipcError) - } - } -) diff --git a/src/shared/libs/plugin-system/sleep.ts b/src/shared/libs/plugin-system/sleep.ts deleted file mode 100644 index 3539d698..00000000 --- a/src/shared/libs/plugin-system/sleep.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { createAction, createActionRunner, createNumberParam } from '@pipelab/plugin-core' - -export const ID = 'system:sleep' - -export const sleepAction = createAction({ - id: ID, - name: 'Wait', - description: 'Wait for a given time (in milliseconds)', - icon: '', - displayString: '`Wait for ${fmt.param(params.duration)}ms`', - meta: {}, - params: { - duration: createNumberParam(2000, { - required: true, - label: 'Duration', - }) - }, - - outputs: {} -}) - -const sleep = (duration: number) => new Promise((resolve) => setTimeout(resolve, duration)) - -export const sleepActionRunner = createActionRunner(async ({ inputs }) => { - await sleep(inputs.duration) -}) diff --git a/src/shared/libs/plugin-tauri/configure.ts b/src/shared/libs/plugin-tauri/configure.ts deleted file mode 100644 index 32b24bb3..00000000 --- a/src/shared/libs/plugin-tauri/configure.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createAction, createActionRunner } from '@pipelab/plugin-core' -import { configureParams } from './tauri' - -export const props = createAction({ - id: 'tauri:configure', - description: 'Configure tauri', - displayString: "'Configure Tauri'", - icon: '', - meta: {}, - name: 'Configure Tauri', - advanced: true, - outputs: { - configuration: { - label: 'Configuration', - value: {} as Partial - } - }, - params: configureParams -}) - -export const configureRunner = createActionRunner(async ({ setOutput, inputs }) => { - setOutput('configuration', inputs) -}) diff --git a/src/shared/libs/plugin-tauri/declarations.d.ts b/src/shared/libs/plugin-tauri/declarations.d.ts deleted file mode 100644 index 5ab250f4..00000000 --- a/src/shared/libs/plugin-tauri/declarations.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.webp' diff --git a/src/shared/libs/plugin-tauri/index.ts b/src/shared/libs/plugin-tauri/index.ts deleted file mode 100644 index d71933c6..00000000 --- a/src/shared/libs/plugin-tauri/index.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { makeRunner } from './make.js' -import { previewRunner } from './preview.js' - -import { createNodeDefinition } from '@pipelab/plugin-core' -import icon from './public/tauri.webp' -import { - createMakeProps, - createPackageV2Props, - createPreviewProps, - IDMake, - IDPackageV2, - IDPreview -} from './tauri.js' -import { configureRunner, props } from './configure.js' -import { packageV2Runner } from './package.js' - -export default createNodeDefinition({ - description: 'Tauri', - name: 'Tauri', - id: 'tauri', - icon: { - type: 'image', - image: icon - }, - nodes: [ - // make and package - { - node: createMakeProps( - IDMake, - 'Create Installer', - 'Create a distributable installer for your chosen platform', - '', - "`Build package for ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`" - ), - runner: makeRunner - // disabled: platform === 'linux' ? 'Tauri is not supported on Linux' : undefined - }, - { - node: createPackageV2Props( - IDPackageV2, - 'Package app with configuration', - 'Gather all necessary files and prepare your app for distribution, creating a platform-specific bundle.', - '', - "`Package app from ${fmt.param(params['input-folder'], 'primary', 'Input folder not set')}`", - false, - false, - undefined, - false, - false - ), - runner: packageV2Runner, - }, - { - node: createPreviewProps( - IDPreview, - 'Preview app', - 'Package and preview your app from an URL', - '', - "`Preview app from ${fmt.param(params['input-url'], 'primary', 'Input folder not set')}`", - ), - runner: previewRunner - }, - { - node: props, - runner: configureRunner, - } - ] -}) diff --git a/src/shared/libs/plugin-tauri/make.ts b/src/shared/libs/plugin-tauri/make.ts deleted file mode 100644 index 83c0a8eb..00000000 --- a/src/shared/libs/plugin-tauri/make.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createActionRunner } from '@pipelab/plugin-core' -import { createMakeProps, tauri } from './tauri' -import { merge } from 'ts-deepmerge' -import { defaultTauriConfig } from './utils' - -export const makeRunner = createActionRunner>( - async (options) => { - const appFolder = options.inputs['input-folder'] - - if (!options.inputs.configuration) { - throw new Error('Missing tauri configuration') - } - - const completeConfiguration = merge( - defaultTauriConfig, - options.inputs.configuration - ) as DesktopApp.Tauri - - await tauri('make', appFolder, options, completeConfiguration) - } -) diff --git a/src/shared/libs/plugin-tauri/package.ts b/src/shared/libs/plugin-tauri/package.ts deleted file mode 100644 index 748012cb..00000000 --- a/src/shared/libs/plugin-tauri/package.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { createActionRunner } from '@pipelab/plugin-core' -import { createPackageV2Props, tauri } from './tauri' -import { merge } from 'ts-deepmerge' -import { defaultTauriConfig } from './utils' - -export const packageV2Runner = createActionRunner>( - async (options) => { - const appFolder = options.inputs['input-folder'] - - const completeConfiguration = merge(defaultTauriConfig, { - alwaysOnTop: options.inputs['alwaysOnTop'], - appBundleId: options.inputs['appBundleId'], - appCategoryType: options.inputs['appCategoryType'], - appCopyright: options.inputs['appCopyright'], - appVersion: options.inputs['appVersion'], - author: options.inputs['author'], - description: options.inputs['description'], - tauriVersion: options.inputs['tauriVersion'], - enableExtraLogging: options.inputs['enableExtraLogging'], - clearServiceWorkerOnBoot: options.inputs['clearServiceWorkerOnBoot'], - frame: options.inputs['frame'], - fullscreen: options.inputs['fullscreen'], - icon: options.inputs['icon'], - height: options.inputs['height'], - name: options.inputs['name'], - toolbar: options.inputs['toolbar'], - transparent: options.inputs['transparent'], - width: options.inputs['width'], - enableSteamSupport: options.inputs['enableSteamSupport'], - steamGameId: options.inputs['steamGameId'], - ignore: options.inputs['ignore'], - openDevtoolsOnStart: options.inputs['openDevtoolsOnStart'], - enableDiscordSupport: options.inputs['enableDiscordSupport'], - discordAppId: options.inputs['discordAppId'], - customPackages: options.inputs['customPackages'], - backgroundColor: options.inputs['backgroundColor'] - } satisfies DesktopApp.Tauri) as DesktopApp.Tauri - - console.log('completeConfiguration', completeConfiguration) - - await tauri('package', appFolder, options, completeConfiguration) - } -) diff --git a/src/shared/libs/plugin-tauri/preview.ts b/src/shared/libs/plugin-tauri/preview.ts deleted file mode 100644 index ddeb48b3..00000000 --- a/src/shared/libs/plugin-tauri/preview.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { createActionRunner, runWithLiveLogs } from '@pipelab/plugin-core' -import { createPreviewProps, tauri } from './tauri' -import { merge } from 'ts-deepmerge' -import { defaultTauriConfig } from './utils' - -export const previewRunner = createActionRunner>( - async (options) => { - const url = options.inputs['input-url'] - if (url === '') { - throw new Error("URL can't be empty") - } - - if (!options.inputs.configuration) { - throw new Error('Missing tauri configuration') - } - - const completeConfiguration = merge(defaultTauriConfig, { - alwaysOnTop: options.inputs.configuration['alwaysOnTop'], - appBundleId: options.inputs.configuration['appBundleId'], - appCategoryType: options.inputs.configuration['appCategoryType'], - appCopyright: options.inputs.configuration['appCopyright'], - appVersion: options.inputs.configuration['appVersion'], - author: options.inputs.configuration['author'], - description: options.inputs.configuration['description'], - tauriVersion: options.inputs.configuration['tauriVersion'], - enableExtraLogging: options.inputs.configuration['enableExtraLogging'], - clearServiceWorkerOnBoot: options.inputs.configuration['clearServiceWorkerOnBoot'], - frame: options.inputs.configuration['frame'], - fullscreen: options.inputs.configuration['fullscreen'], - icon: options.inputs.configuration['icon'], - height: options.inputs.configuration['height'], - name: options.inputs.configuration['name'], - toolbar: options.inputs.configuration['toolbar'], - transparent: options.inputs.configuration['transparent'], - width: options.inputs.configuration['width'], - enableSteamSupport: options.inputs.configuration['enableSteamSupport'], - steamGameId: options.inputs.configuration['steamGameId'], - ignore: options.inputs.configuration['ignore'], - openDevtoolsOnStart: options.inputs.configuration['openDevtoolsOnStart'], - enableDiscordSupport: options.inputs.configuration['enableDiscordSupport'], - discordAppId: options.inputs.configuration['discordAppId'], - customPackages: options.inputs.configuration['customPackages'], - backgroundColor: options.inputs.configuration['backgroundColor'] - } satisfies DesktopApp.Tauri) as DesktopApp.Tauri - - console.log('completeConfiguration', completeConfiguration) - - await tauri('preview', url, options, completeConfiguration) - return - } -) diff --git a/src/shared/libs/plugin-tauri/tauri.ts b/src/shared/libs/plugin-tauri/tauri.ts deleted file mode 100644 index b035b5a2..00000000 --- a/src/shared/libs/plugin-tauri/tauri.ts +++ /dev/null @@ -1,864 +0,0 @@ -import { getBinName } from 'src/constants' -import { - ActionRunnerData, - createAction, - createArray, - createBooleanParam, - createNumberParam, - createPathParam, - createStringParam, - InputsDefinition, - OutputsDefinition, - runWithLiveLogs -} from '../plugin-core' -import { detectRuntime } from '@@/plugins' -import { app } from 'electron' -import { dirname, join } from 'node:path' -import { existsSync } from 'node:fs' - -/** - * Searches for common cargo paths and resolves to a valid cargo executable path - * @returns The path to the cargo executable - * @throws Error if cargo cannot be found - */ -async function resolveCargoPath(): Promise { - const { platform } = await import('os') - const { execa } = await import('execa') - const cargoBinName = platform() === 'win32' ? 'cargo.exe' : 'cargo' - - // Common cargo paths by platform - const commonPaths: string[] = [] - const currentPlatform = platform() - - // Helper function to add paths if they exist - const addIfExists = (path: string) => { - if (existsSync(path)) { - commonPaths.push(path) - } - } - - const rustupHome = process.env.RUSTUP_HOME || join(app.getPath('home'), '.rustup') - const cargoHome = process.env.CARGO_HOME || join(app.getPath('home'), '.cargo') - - if (currentPlatform === 'win32') { - // Windows paths - addIfExists( - join(rustupHome, 'toolchains', 'stable-x86_64-pc-windows-msvc', 'bin', cargoBinName) - ) - addIfExists( - join(rustupHome, 'toolchains', 'nightly-x86_64-pc-windows-msvc', 'bin', cargoBinName) - ) - addIfExists(join(cargoHome, 'bin', cargoBinName)) - } else if (currentPlatform === 'linux') { - // Linux paths - addIfExists( - join(rustupHome, 'toolchains', 'stable-x86_64-unknown-linux-gnu', 'bin', cargoBinName) - ) - addIfExists( - join(rustupHome, 'toolchains', 'nightly-x86_64-unknown-linux-gnu', 'bin', cargoBinName) - ) - addIfExists(join(cargoHome, 'bin', cargoBinName)) - addIfExists('/usr/bin/cargo') - addIfExists('/usr/local/bin/cargo') - } else if (currentPlatform === 'darwin') { - // macOS paths - addIfExists(join(rustupHome, 'toolchains', 'stable-x86_64-apple-darwin', 'bin', cargoBinName)) - addIfExists(join(rustupHome, 'toolchains', 'nightly-x86_64-apple-darwin', 'bin', cargoBinName)) - addIfExists(join(cargoHome, 'bin', cargoBinName)) - addIfExists('/usr/local/bin/cargo') - addIfExists('/opt/homebrew/bin/cargo') - } - - // Return first existing path found - if (commonPaths.length > 0) { - return commonPaths[0] - } - - // Fallback: try to find cargo using system tools on Unix systems - if (currentPlatform !== 'win32') { - try { - const whichResult = await execa('which', ['cargo']) - const cargoPath = whichResult.stdout.trim() - if (cargoPath && existsSync(cargoPath)) { - return cargoPath - } - } catch { - // Ignore errors from which command - } - } - - throw new Error('Cargo not found. Please install it first') -} - -// TODO: https://js.electronforge.io/modules/_electron_forge_core.html - -export const IDMake = 'tauri:make' -export const IDPackageV2 = 'tauri:package:v2' -export const IDPreview = 'tauri:preview' - -const paramsInputFolder = { - 'input-folder': createPathParam('', { - label: 'Folder to package', - required: true, - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }) -} satisfies InputsDefinition - -const paramsInputURL = { - 'input-url': createStringParam('', { - label: 'URL to preview', - required: true - }) -} satisfies InputsDefinition - -const params = { - arch: { - value: '' as NodeJS.Architecture | '', // MakeOptions['arch'], - label: 'Architecture', - required: false, - control: { - type: 'select', - options: { - placeholder: 'Architecture', - options: [ - { - label: 'Older PCs (ia32)', - value: 'ia32' - }, - { - label: 'Modern PCs (x64)', - value: 'x64' - }, - { - label: 'Older Mobile/Pi (armv7l)', - value: 'armv7l' - }, - { - label: 'New Mobile/Apple Silicon (arm64)', - value: 'arm64' - }, - { - label: 'Mac Universal (universal)', - value: 'universal' - }, - { - label: 'Special Systems (mips64el)', - value: 'mips64el' - } - ] - } - } - }, - platform: { - value: '' as NodeJS.Platform | '', // MakeOptions['platform'], - label: 'Platform', - required: false, - control: { - type: 'select', - options: { - placeholder: 'Platform', - options: [ - { - label: 'Windows (win32)', - value: 'win32' - }, - { - label: 'macOS (darwin)', - value: 'darwin' - }, - { - label: 'Linux (linux)', - value: 'linux' - }, - { - label: 'Android', - value: 'android' - }, - { - label: 'iOS', - value: 'ios' - } - ] - } - } - }, - configuration: { - label: 'Tauri configuration', - value: undefined as Partial | undefined, - required: true, - control: { - type: 'json' - } - } -} satisfies InputsDefinition - -export const configureParams = { - name: createStringParam('Pipelab', { - label: 'Application name', - description: 'The name of the application', - required: true - }), - appBundleId: createStringParam('com.pipelab.app', { - label: 'Application bundle ID', - description: 'The bundle ID of the application', - required: true - }), - appCopyright: createStringParam('Copyright © 2024 Pipelab', { - label: 'Application copyright', - description: 'The copyright of the application', - required: false - }), - appVersion: createStringParam('1.0.0', { - label: 'Application version', - description: 'The version of the application', - required: true - }), - icon: createPathParam('', { - label: 'Application icon', - description: 'The icon of the application. macOS: .icns. Windows: .ico', - required: false, - control: { - type: 'path', - options: { - filters: [ - { name: 'Image', extensions: ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'icns'] } - ] - }, - label: 'Path to an image file' - } - }), - author: createStringParam('Pipelab', { - label: 'Application author', - description: 'The author of the application', - required: true - }), - description: createStringParam('A simple Electron application', { - label: 'Application description', - description: 'The description of the application', - required: false - }), - - appCategoryType: createStringParam('public.app-category.developer-tools', { - platforms: ['darwin'], - label: 'Application category type', - description: 'The category type of the application', - required: false - }), - - // window - width: createNumberParam(800, { - label: 'Window width', - description: 'The width of the window', - required: false - }), - height: createNumberParam(600, { - label: 'Window height', - description: 'The height of the window', - required: false - }), - fullscreen: { - label: 'Fullscreen', - value: false, - description: 'Whether to start the application in fullscreen mode', - required: false, - control: { - type: 'boolean' - } - }, - frame: { - label: 'Frame', - value: true, - description: 'Whether to show the window frame', - required: false, - control: { - type: 'boolean' - } - }, - transparent: { - label: 'Transparent', - value: false, - description: 'Whether to make the window transparent', - required: false, - control: { - type: 'boolean' - } - }, - toolbar: { - label: 'Toolbar', - value: true, - description: 'Whether to show the toolbar', - required: false, - control: { - type: 'boolean' - } - }, - alwaysOnTop: { - label: 'Always on top', - value: false, - description: 'Whether to always keep the window on top', - required: false, - control: { - type: 'boolean' - } - }, - - tauriVersion: createStringParam('', { - label: 'Tauri version', - description: - 'The version of Tauri to use. If no version specified, it will use the latest one.', - required: false - }), - enableExtraLogging: { - required: false, - label: 'Enable extra logging', - value: false, - control: { - type: 'boolean' - }, - description: 'Whether to enable extra logging of internal tools while bundling' - }, - openDevtoolsOnStart: createBooleanParam(false, { - label: 'Open devtools on app start', - required: false, - description: 'Whether to open devtools on app start' - }), - - // websocket apis - websocketApi: { - required: false, - label: 'WebSocket APIs to allow (empty = all)', - value: '[]', - control: { - type: 'array', - options: { - kind: 'text' - } - } - }, - ignore: createArray<(string | RegExp)[]>( - `[ - // use 'src/app/' as starting point -]`, - { - required: false, - label: 'Folders to ignore', - description: - 'An array of string or Regex that allow ignoring certain files or folders from being packaged', - control: { - type: 'array', - options: { - kind: 'text' - } - } - } - ), - - // integrations - - enableSteamSupport: { - required: false, - label: 'Enable steam support', - description: 'Whether to enable Steam support', - value: false, - control: { - type: 'boolean' - } - }, - steamGameId: createNumberParam(480, { - required: false, - label: 'Steam game ID', - description: 'The Steam game ID' - }), - enableDiscordSupport: { - required: false, - label: 'Enable Discord support', - description: 'Whether to enable Discord support', - value: false, - control: { - type: 'boolean' - } - }, - discordAppId: createStringParam('', { - required: false, - label: 'Discord application ID', - description: 'The Discord application ID' - }) -} satisfies InputsDefinition - -const outputs = { - output: { - label: 'Output', - value: '', - control: { - type: 'path', - options: { - properties: ['openDirectory'] - } - } - }, - binary: { - label: 'Binary', - value: '', - control: { - type: 'path', - options: { - properties: ['openFile'] - } - } - } -} satisfies OutputsDefinition - -// type Inputs = ParamsToInput - -export const createMakeProps = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string -) => - createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - params: { - ...params, - ...paramsInputFolder - }, - outputs - }) - -export const createPackageV2Props = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string, - advanced?: boolean, - deprecated?: boolean, - deprecatedMessage?: string, - disabled?: false, - updateAvailable?: boolean -) => { - const { arch, platform } = params - return createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - advanced, - deprecated, - deprecatedMessage, - disabled, - updateAvailable, - params: { - arch, - platform, - ...paramsInputFolder, - ...configureParams - }, - outputs: outputs - }) -} - -export const createPreviewProps = ( - id: string, - name: string, - description: string, - icon: string, - displayString: string -) => - createAction({ - id, - name, - description, - icon, - displayString, - meta: {}, - params: { - ...params, - ...paramsInputURL - }, - outputs: outputs - }) - -export const tauri = async ( - action: 'make' | 'package' | 'preview', - appFolder: string | undefined, - { - cwd, - log, - inputs, - setOutput, - paths, - abortSignal - }: ActionRunnerData>, - completeConfiguration: DesktopApp.Config -): Promise<{ folder: string; binary: string | undefined } | undefined> => { - const { join, basename, delimiter } = await import('node:path') - const { cp, readFile, writeFile } = await import('node:fs/promises') - const { arch, platform } = await import('os') - const { kebabCase } = await import('change-case') - const { parseTOML, stringifyTOML } = await import('confbox') - - console.log('appFolder', appFolder) - - log('Building tauri') - - if (action !== 'preview') { - await detectRuntime(appFolder) - } - - const { assets, unpack, cache, node, pnpm } = paths - - const destinationFolder = join(cwd, 'build') - - const templateFolder = join(assets, 'tauri', 'template', 'app') - - // copy template to destination - await cp(templateFolder, destinationFolder, { - recursive: true, - filter: (src) => { - // log('src', src) - // log('dest', dest) - // TODO: support other oses - return ( - basename(src) !== 'node_modules' && - !src.includes('src-tauri\\target') && - !src.includes('src-tauri\\gen') - ) - } - }) - - const placeAppFolder = join(destinationFolder, 'src', 'app') - - // if input is folder, copy folder to destination - if (appFolder && action !== 'preview') { - // copy app to template - await cp(appFolder, placeAppFolder, { - recursive: true - }) - } - - writeFile( - join(destinationFolder, 'config.cjs'), - `module.exports = ${JSON.stringify(completeConfiguration, undefined, 2)}`, - 'utf8' - ) - - const shimsPaths = join(assets, 'shims') - - const userData = app.getPath('userData') - - const pnpmHome = join(userData, 'config', 'pnpm') - - const sanitizedName = kebabCase(completeConfiguration.name) - - // package.json update - log('Package.json update') - const pkgJSONPath = join(destinationFolder, 'package.json') - const pkgJSONContent = await readFile(pkgJSONPath, 'utf8') - const pkgJSON = JSON.parse(pkgJSONContent) - log('Setting name to', sanitizedName) - pkgJSON.name = sanitizedName - log('Setting productName to', completeConfiguration.name) - pkgJSON.productName = completeConfiguration.name - await writeFile(pkgJSONPath, JSON.stringify(pkgJSON, null, 2)) - - // Cargo.toml update - log('Cargo.toml update') - const cargoTomlPath = join(destinationFolder, 'src-tauri', 'Cargo.toml') - const cargoTomlContent = await readFile(cargoTomlPath, 'utf8') - const cargoToml = parseTOML(cargoTomlContent) as { name: string; version: string } - log('Setting name to', sanitizedName) - console.log('cargoToml', cargoToml) - cargoToml.name = sanitizedName - log('Setting version to', completeConfiguration.appVersion) - cargoToml.version = completeConfiguration.appVersion - console.log('cargoToml', stringifyTOML(cargoToml)) - await writeFile(cargoTomlPath, stringifyTOML(cargoToml)) - - // tauri.conf.json update - log('Tauri.conf.json update') - const tauriConfJSONPath = join(destinationFolder, 'src-tauri', 'tauri.conf.json') - const tauriConfJSONContent = await readFile(tauriConfJSONPath, 'utf8') - const tauriConfJSON = JSON.parse(tauriConfJSONContent) - log('Setting productName to', completeConfiguration.name) - tauriConfJSON.productName = completeConfiguration.name - log('Setting version to', completeConfiguration.appVersion) - tauriConfJSON.version = completeConfiguration.appVersion - log('Setting identifier to', completeConfiguration.appBundleId) - tauriConfJSON.identifier = completeConfiguration.appBundleId - if (action === 'preview') { - log('Setting build.devUrl to', appFolder) - tauriConfJSON.build.devUrl = appFolder - await writeFile(tauriConfJSONPath, JSON.stringify(tauriConfJSON, null, 2)) - } - /* else { - log('Setting build.frontendDist to', appFolder) - tauriConfJSON.build.frontendDist = appFolder - await writeFile(tauriConfJSONPath, JSON.stringify(tauriConfJSON, null, 2)) - } */ - - log('Installing packages') - await runWithLiveLogs( - node, - [pnpm, 'install', '--prefer-offline'], - { - cwd: destinationFolder, - env: { - // DEBUG: '*', - PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - PNPM_HOME: pnpmHome - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - - // override tauri version - // if (completeConfiguration.electronVersion && completeConfiguration.electronVersion !== '') { - // log(`Installing tauri@${completeConfiguration.electronVersion}`) - // await runWithLiveLogs( - // process.execPath, - // [pnpm, 'install', `tauri@${completeConfiguration.electronVersion}`, '--prefer-offline'], - // { - // cwd: destinationFolder, - // env: { - // // DEBUG: '*', - // PATH: `${dirname(node)}${delimiter}${process.env.PATH}`, - // PNPM_HOME: pnpmHome - // }, - // cancelSignal: abortSignal - // }, - // log, - // { - // onStderr(data) { - // log(data) - // }, - // onStdout(data) { - // log(data) - // } - // } - // ) - // } - - const inputPlatform = inputs.platform === '' ? undefined : inputs.platform - const inputArch = inputs.arch === '' ? undefined : inputs.arch - - try { - log('typeof inputs.platform', typeof inputs.platform) - const finalPlatform: NodeJS.Platform = inputPlatform ?? platform() - log('finalPlatform', finalPlatform) - const finalArch: NodeJS.Architecture = inputArch ?? (arch() as NodeJS.Architecture) - log('finalArch', finalArch) - - let tauriPlatform = '' - if (finalPlatform === 'win32') { - tauriPlatform = 'pc-windows-msvc' - } else if (finalPlatform === 'linux') { - tauriPlatform = 'unknown-linux-gnu' - } else { - throw new Error('Unsupported platform') - } - - let tauriArch = '' - if (finalArch === 'x64') { - tauriArch = 'x86_64' - } else { - throw new Error('Unsupported arch') - } - - const target = `${tauriArch}-${tauriPlatform}` - - // Resolve cargo path using the new function - const cargo = await resolveCargoPath() - const cargoBinDir = dirname(cargo) - - log('cargoBinDir', cargoBinDir) - console.log('cargo', cargo) - - log('destinationFolder', destinationFolder) - - const cargoTargetDir = join(cache, 'cargo', 'target', completeConfiguration.appBundleId) - const cargoOutputPath = join(cargoTargetDir, target, 'release') - - log('cargoTargetDir', cargoTargetDir) - log('cargoOutputPath', cargoOutputPath) - - log('Starting compiling') - - // by default add the tauri cli - await runWithLiveLogs( - cargo, - ['install', 'tauri-cli', '--version', '^2.0.0', '--locked'], - { - cwd: join(destinationFolder, 'src-tauri'), - env: { - DEBUG: completeConfiguration.enableExtraLogging ? '*' : '', - ELECTRON_NO_ASAR: '1', - CARGO_TARGET_DIR: cargoTargetDir, - PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}` - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - // on ci, do not log - if (!process.env.CI) { - log(data) - } - }, - onStdout(data) { - // on ci, do not log - if (!process.env.CI) { - log(data) - } - } - } - ) - - // if preview, run tauri dev - if (action === 'preview') { - await runWithLiveLogs( - cargo, - ['tauri', 'dev', '--target', target], - { - cwd: join(destinationFolder, 'src-tauri'), - env: { - DEBUG: completeConfiguration.enableExtraLogging ? '*' : '', - ELECTRON_NO_ASAR: '1', - CARGO_TARGET_DIR: cargoTargetDir, - PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}` - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - } else { - // otherwise build, but don't bundle - await runWithLiveLogs( - cargo, - ['tauri', 'build', '--target', target, '--no-bundle'], - { - cwd: join(destinationFolder, 'src-tauri'), - env: { - DEBUG: completeConfiguration.enableExtraLogging ? '*' : '', - ELECTRON_NO_ASAR: '1', - CARGO_TARGET_DIR: cargoTargetDir, - PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}` - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - // on ci, do not log - if (!process.env.CI) { - log(data) - } - }, - onStdout(data) { - // on ci, do not log - if (!process.env.CI) { - log(data) - } - } - } - ) - - // if make, bundle - if (action === 'make') { - await runWithLiveLogs( - cargo, - // TODO: https://v2.tauri.app/fr/distribute/#bundling - ['tauri', 'bundle', '--', '--bundles', 'appimage'], - { - cwd: join(destinationFolder, 'src-tauri'), - env: { - DEBUG: completeConfiguration.enableExtraLogging ? '*' : '', - ELECTRON_NO_ASAR: '1', - CARGO_TARGET_DIR: cargoTargetDir, - PATH: `${cargoBinDir}${delimiter}${dirname(node)}${delimiter}${process.env.PATH}` - }, - cancelSignal: abortSignal - }, - log, - { - onStderr(data) { - log(data) - }, - onStdout(data) { - log(data) - } - } - ) - } - } - - if (action === 'package') { - const binName = getBinName(sanitizedName) - - log('cargoOutputPath', cargoOutputPath) - - setOutput('output', cargoOutputPath) - setOutput('binary', join(cargoOutputPath, binName)) - return { - folder: cargoOutputPath, - binary: join(cargoOutputPath, binName) - } - } else if (action === 'make') { - // TODO: - throw new Error('Unsupported action') - } else if (action === 'preview') { - // continue - } else { - throw new Error('Unsupported action') - // const output = join(destinationFolder, 'out', 'make') - // setOutput('output', output) - // return { - // folder: output, - // binary: undefined - // } - } - } catch (e) { - if (e instanceof Error) { - if (e.name === 'RequestError') { - log('Request error') - } - if (e.name === 'RequestError') { - log('Request error') - } - throw e - } - log(e) - return undefined - } -} diff --git a/src/shared/libs/plugin-tauri/utils.ts b/src/shared/libs/plugin-tauri/utils.ts deleted file mode 100644 index ed2ed6b5..00000000 --- a/src/shared/libs/plugin-tauri/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const defaultTauriConfig = { - alwaysOnTop: false, - appBundleId: 'com.pipelab.app', - appCategoryType: '', - appCopyright: 'Copyright © 2024 Pipelab', - appVersion: '1.0.0', - author: 'Pipelab', - description: 'A simple Electron application', - tauriVersion: '', - enableExtraLogging: false, - clearServiceWorkerOnBoot: false, - frame: true, - fullscreen: false, - icon: '', - height: 600, - name: 'Pipelab', - toolbar: true, - transparent: false, - width: 800, - enableSteamSupport: false, - steamGameId: 480, - enableDiscordSupport: false, - discordAppId: '', - ignore: [] as string[], - backgroundColor: '#FFF', - openDevtoolsOnStart: false, -} satisfies DesktopApp.Tauri diff --git a/src/shared/logger.ts b/src/shared/logger.ts deleted file mode 100644 index b9c00633..00000000 --- a/src/shared/logger.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Logger } from 'tslog' -import { isRenderer } from './validation' -import { usePluginAPI } from '@main/api' -import { BrowserWindow } from 'electron' - -const createDefaultLogger = () => - new Logger({ - minLevel: 3, // INFO - hideLogPositionForProduction: false - }) - -let _logger = createDefaultLogger() -// let _mainWindow: BrowserWindow | undefined = undefined - -export const useLogger = () => { - const setMainWindow = (mainWindow: BrowserWindow) => { - // _mainWindow = mainWindow - _logger = createDefaultLogger() - - // in main, send logs to renderer - if (!isRenderer()) { - _logger.attachTransport((logObj) => { - const api = usePluginAPI(mainWindow) - api.execute('log:message', logObj) - }) - } - } - - return { - logger: () => _logger, - setMainWindow - } -} diff --git a/src/shared/model.test.ts b/src/shared/model.test.ts deleted file mode 100644 index 55893d6d..00000000 --- a/src/shared/model.test.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { savedFileMigrator, SavedFileV1, SavedFileV2, SavedFileV3 } from './model' - -describe('model', () => { - it('should migrate 1.0.0 to 2.0.0', async () => { - const v1: SavedFileV1 = { - version: '1.0.0', - canvas: { - blocks: [ - { - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - foo: 'bar' - }, - nodata: undefined - }, - type: 'action', - uid: 'aaa', - disabled: false - }, - { - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - foo: 'bar' - } - }, - type: 'event', - uid: 'aaa' - } - ] - }, - description: 'aaa', - name: 'aaa', - variables: [ - { - description: 'aaa', - id: 'aaa', - name: 'aaa', - value: 'aaa' - } - ] - } - - const v2 = await savedFileMigrator.migrate(v1, { - debug: true, - target: '2.0.0' - }) - - expect(v2).toStrictEqual({ - canvas: { - blocks: [ - { - disabled: false, - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - foo: 'bar' - }, - nodata: undefined - }, - type: 'action', - uid: 'aaa' - } - ], - triggers: [ - { - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - foo: 'bar' - } - }, - type: 'event', - uid: 'aaa' - } - ] - }, - description: 'aaa', - name: 'aaa', - variables: [ - { - description: 'aaa', - id: 'aaa', - name: 'aaa', - value: 'aaa' - } - ], - version: '2.0.0' - } satisfies SavedFileV2) - }) - - it('should migrate 2.0.0 to 3.0.0', async () => { - const v2: SavedFileV2 = { - canvas: { - blocks: [ - { - disabled: false, - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - foo: 'bar' - }, - nodata: undefined - }, - type: 'action', - uid: 'aaa' - } - ], - triggers: [ - { - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - foo: 'bar' - } - }, - type: 'event', - uid: 'aaa' - } - ] - }, - description: 'aaa', - name: 'aaa', - variables: [ - { - description: 'aaa', - id: 'aaa', - name: 'aaa', - value: 'aaa' - } - ], - version: '2.0.0' - } - - const v3 = await savedFileMigrator.migrate(v2, { - debug: true, - target: '3.0.0' - }) - - expect(v3).toStrictEqual({ - canvas: { - blocks: [ - { - disabled: false, - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - editor: 'editor', - value: { - foo: 'bar' - } - }, - nodata: { - editor: 'editor', - value: undefined - } - }, - type: 'action', - uid: 'aaa' - } - ], - triggers: [ - { - origin: { - nodeId: 'aaa', - pluginId: 'aaa' - }, - params: { - aaa: { - foo: 'bar' - } - }, - type: 'event', - uid: 'aaa' - } - ] - }, - description: 'aaa', - name: 'aaa', - variables: [ - { - description: 'aaa', - id: 'aaa', - name: 'aaa', - value: 'aaa' - } - ], - version: '3.0.0' - } satisfies SavedFileV3) - }) -}) diff --git a/src/shared/model.ts b/src/shared/model.ts deleted file mode 100644 index 6de49da4..00000000 --- a/src/shared/model.ts +++ /dev/null @@ -1,346 +0,0 @@ -import { Variable } from '@pipelab/core-app' -import { WithId } from './utils' -import { SaveLocation } from './save-location' -import type { Simplify } from 'type-fest' -import { createMigration, createMigrator, finalVersion, initialVersion } from './libs/migration' -import { - any, - array, - boolean, - custom, - description, - GenericSchema, - InferOutput, - lazy, - literal, - object, - optional, - pipe, - record, - string, - union, - unknown, - variant -} from 'valibot' -import type { OmitVersion } from './libs/migration/models/migration' - -export type NodeId = string - -export type Position = { - x: number - y: number -} - -export const OriginValidator = object({ - pluginId: string(), - nodeId: string() -}) - -export type Origin = InferOutput - -const BlockActionValidatorV1 = object({ - type: literal('action'), - uid: string(), - disabled: optional(boolean()), - params: record(string(), any()), - origin: OriginValidator -}) - -export const EditorParamValidatorV3 = union([literal('simple'), literal('editor')]) -export type EditorParam = InferOutput -const BlockActionValidatorV3 = object({ - type: literal('action'), - uid: string(), - name: pipe(optional(string()), description('A custom name provided by the user')), - disabled: optional(boolean()), - params: record( - string(), - object({ - editor: EditorParamValidatorV3, - value: unknown() - }) - ), - origin: OriginValidator -}) - -export type Condition = { - type: 'condition' - uid: string - origin: Origin - params: Record - branchTrue: Array - branchFalse: Array -} - -const BlockConditionValidator: GenericSchema = object({ - type: literal('condition'), - uid: string(), - origin: OriginValidator, - params: record(string(), any()), - branchTrue: lazy(() => array(BlockValidator)), - branchFalse: lazy(() => array(BlockValidator)) -}) - -export type Loop = { - type: 'loop' - uid: string - origin: Origin - params: Record - children: Array -} -const BlockLoopValidator: GenericSchema = object({ - type: literal('loop'), - uid: string(), - origin: OriginValidator, - params: record(string(), any()), - children: lazy(() => array(BlockValidator)) -}) - -const BlockEventValidator = object({ - type: literal('event'), - uid: string(), - origin: OriginValidator, - params: record(string(), any()) -}) - -const BlockCommentValidator = object({ - type: literal('comment'), - uid: string(), - origin: OriginValidator, - comment: string() -}) - -const BlockValidatorV1 = variant('type', [ - BlockActionValidatorV1, - // BlockConditionValidator, - BlockEventValidator - // BlockLoopValidator, - // BlockCommentValidator -]) - -const BlockValidatorV2 = variant('type', [ - BlockActionValidatorV1 - // BlockConditionValidator, - // BlockEventValidator, - // BlockLoopValidator, - // BlockCommentValidator -]) - -const BlockValidatorV3 = variant('type', [ - BlockActionValidatorV3 - // BlockConditionValidator, - // BlockEventValidator, - // BlockLoopValidator, - // BlockCommentValidator -]) - -const BlockValidator = BlockValidatorV3 - -export type BlockAction = Simplify> -export type BlockCondition = InferOutput -export type BlockLoop = InferOutput -export type BlockEvent = InferOutput -export type BlockComment = InferOutput - -export type Block = InferOutput - -const CanvasValidatorV1 = object({ - blocks: array(BlockValidatorV1) -}) - -const CanvasValidatorV2 = object({ - blocks: array(BlockValidatorV2), - triggers: array(BlockEventValidator) -}) - -const CanvasValidatorV3 = object({ - blocks: array(BlockValidatorV3), - triggers: array(BlockEventValidator) -}) - -const VariableValidatorV1 = custom(() => true) - -export const SavedFileValidatorV1 = object({ - version: literal('1.0.0'), - name: string(), - description: string(), - canvas: CanvasValidatorV1, - variables: array(VariableValidatorV1) -}) - -export const SavedFileValidatorV2 = object({ - version: literal('2.0.0'), - name: string(), - description: string(), - canvas: CanvasValidatorV2, - variables: array(VariableValidatorV1) -}) - -export const SavedFileValidatorV3 = object({ - version: literal('3.0.0'), - name: string(), - description: string(), - canvas: CanvasValidatorV3, - variables: array(VariableValidatorV1) -}) - -export const SavedFileDefaultValidator = object({ - version: literal('4.0.0'), - type: literal('default'), - name: string(), - description: string(), - canvas: CanvasValidatorV3, - variables: array(VariableValidatorV1) -}) - -export const SavedFileSimpleValidator = object({ - version: literal('4.0.0'), - type: literal('simple'), - name: string(), - description: string(), - source: object({ - type: union([literal('c3-html'), literal('c3-nwjs'), literal('godot'), literal('html')]), - path: string() - }), - packaging: object({ - enabled: boolean() - }), - publishing: object({ - steam: object({ enabled: boolean(), appId: optional(string()) }), - itch: object({ enabled: boolean(), project: optional(string()) }), - poki: object({ enabled: boolean(), gameId: optional(string()) }) - }) -}) - -export type SavedFileDefault = InferOutput -export type SavedFileSimple = InferOutput -export const SavedFileValidatorV4 = union([SavedFileDefaultValidator, SavedFileSimpleValidator]) - -export type SavedFileV1 = InferOutput -export type SavedFileV2 = InferOutput -export type SavedFileV3 = InferOutput -export type SavedFileV4 = InferOutput -export type SavedFile = SavedFileV4 -export const SavedFileValidator = SavedFileValidatorV4 - -const savedFileMigratorr = createMigrator() -const defaultValue = savedFileMigratorr.createDefault({ - canvas: { - triggers: [], - blocks: [] - }, - description: '', - name: '', - variables: [], - type: 'default', - version: '4.0.0' -}) - -export const savedFileMigrator = savedFileMigratorr.createMigrations({ - defaultValue, - migrations: [ - createMigration({ - version: '1.0.0', - up: (state) => { - const blocks = state.canvas.blocks - - const triggers: Array = [] - const newBlocks: Array = [] - - for (const block of blocks) { - if (block.type === 'event') { - // add to triggers - triggers.push(block) - } else { - // restore in blocks because it's not a trigger - newBlocks.push(block) - } - } - - return { - canvas: { - blocks: newBlocks, - triggers: triggers - }, - description: state.description, - name: state.name, - variables: state.variables - } satisfies OmitVersion - }, - down: initialVersion - }), - createMigration({ - version: '2.0.0', - up: (state) => { - const { canvas, ...rest } = state - const { blocks, triggers } = canvas - - const newBlocks: SavedFileV2['canvas']['blocks'] = [] - - for (const block of blocks) { - const newParams: SavedFileV2['canvas']['blocks'][number]['params'] = {} - - for (const data of Object.entries(block.params)) { - if (data === undefined) { - throw new Error("Can't migrate block with undefined params") - } else { - const [key, value] = data - newParams[key] = { - editor: 'editor', - value - } - } - } - - newBlocks.push({ - ...block, - params: newParams - }) - } - - return { - ...rest, - canvas: { - triggers, - blocks: newBlocks - } - } satisfies OmitVersion - }, - down: () => { - throw new Error('Migration down not implemented') - } - }), - createMigration({ - version: '3.0.0', - up: (state) => { - return { - ...state, - type: 'default' - } satisfies OmitVersion - }, - down: () => { - throw new Error('Migration down not implemented') - } - }), - createMigration({ - version: '4.0.0', - up: finalVersion, - down: () => { - throw new Error('Migration down not implemented') - } - }) - ] -}) - -export type Preset = SavedFile -export type PresetResult = { data: SavedFile; hightlight?: boolean; disabled?: boolean } -export type PresetFn = () => Promise - -export type Steps = Record< - string, - { - outputs: Record - } -> - -export type EnhancedFile = WithId & { content: T } diff --git a/src/shared/plugins.ts b/src/shared/plugins.ts deleted file mode 100644 index cb932894..00000000 --- a/src/shared/plugins.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { shallowRef } from 'vue' -import { createNodeDefinition } from '../shared/libs/plugin-core' -import { is } from '@electron-toolkit/utils' - -const builtInPlugins = async () => { - const base = [ - (await import('./libs/plugin-construct')).default, - (await import('./libs/plugin-filesystem')).default, - (await import('./libs/plugin-system')).default, - (await import('./libs/plugin-steam')).default, - (await import('./libs/plugin-itch')).default, - (await import('./libs/plugin-electron')).default, - (await import('./libs/plugin-discord')).default, - (await import('./libs/plugin-poki')).default, - (await import('./libs/plugin-nvpatch')).default, - (await import('./libs/plugin-tauri')).default - ] - - if (is.dev) { - base.push((await import('./libs/plugin-netlify')).default) - } - - return (await Promise.all([...base])).flat() -} - -type Plugin = ReturnType - -const plugins = shallowRef([]) - -export const usePlugins = () => { - const load = () => {} - - const registerBuiltIn = async () => { - const builtIns = (await builtInPlugins()) as Plugin[] - plugins.value.push(...builtIns) - } - - return { - load, - registerBuiltIn, - plugins - } -} - -export type OutputRuntimes = 'construct' | 'godot' - -export const detectRuntime = async ( - appFolder: string | undefined -): Promise => { - const { fileExists } = await import('@@/libs/plugin-core') - const { join } = await import('node:path') - - let detectedRuntime: OutputRuntimes | undefined = undefined - if (appFolder) { - const indexExist = await fileExists(join(appFolder, 'index.html')) - const swExist = await fileExists(join(appFolder, 'sw.js')) - const offlineJSON = await fileExists(join(appFolder, 'offline.json')) - const dataJSON = await fileExists(join(appFolder, 'data.json')) - const scriptsFolder = await fileExists(join(appFolder, 'scripts')) - const workermainJs = await fileExists(join(appFolder, 'workermain.js')) - - if (!indexExist) { - throw new Error('The input folder does not contain an index.html file') - } - - if (swExist || dataJSON || workermainJs || scriptsFolder) { - detectedRuntime = 'construct' - } - - console.log('Detected runtime', detectedRuntime) - - if (detectedRuntime === 'construct' && offlineJSON && swExist) { - throw new Error( - 'Construct runtime detected, please disable offline capabilties when using HTML5 export. Offline is already supported by default.' - ) - } - } - return detectedRuntime -} diff --git a/src/shared/subscription-errors.ts b/src/shared/subscription-errors.ts deleted file mode 100644 index 5d7a025a..00000000 --- a/src/shared/subscription-errors.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { SubscriptionError } from './build-history' - -export class SubscriptionRequiredError extends Error implements SubscriptionError { - public readonly code = 'SUBSCRIPTION_REQUIRED' as const - public benefit: string - public userMessage: string - - constructor(benefit?: string) { - super(`Subscription required${benefit ? ` for benefit: ${benefit}` : ''}`) - this.name = 'SubscriptionRequiredError' - this.benefit = benefit || 'build-history' - this.userMessage = `Build history is a premium feature. Please upgrade your subscription to access this feature.` - } -} - -export class SubscriptionExpiredError extends Error implements SubscriptionError { - public readonly code = 'SUBSCRIPTION_EXPIRED' as const - public benefit: string - public userMessage: string - - constructor(benefit?: string) { - super(`Subscription expired${benefit ? ` for benefit: ${benefit}` : ''}`) - this.name = 'SubscriptionExpiredError' - this.benefit = benefit || 'build-history' - this.userMessage = `Your subscription has expired. Please renew your subscription to continue using build history.` - } -} - -export class BenefitNotFoundError extends Error implements SubscriptionError { - public readonly code = 'BENEFIT_NOT_FOUND' as const - public benefit: string - public userMessage: string - - constructor(benefit: string) { - super(`Benefit not found: ${benefit}`) - this.name = 'BenefitNotFoundError' - this.benefit = benefit - this.userMessage = `The requested feature (${benefit}) is not available in your current subscription.` - } -} - -export class UnauthorizedError extends Error implements SubscriptionError { - public readonly code = 'UNAUTHORIZED' as const - public benefit?: string - public userMessage: string - - constructor(message?: string, benefit?: string) { - super(message || 'Unauthorized access') - this.name = 'UnauthorizedError' - this.benefit = benefit - this.userMessage = message || 'You do not have permission to access this feature.' - } -} - -export function createSubscriptionError( - code: SubscriptionError['code'], - benefit?: string, - customMessage?: string -): SubscriptionError { - switch (code) { - case 'SUBSCRIPTION_REQUIRED': - return new SubscriptionRequiredError(benefit) - case 'SUBSCRIPTION_EXPIRED': - return new SubscriptionExpiredError(benefit) - case 'BENEFIT_NOT_FOUND': - if (!benefit) throw new Error('Benefit is required for BENEFIT_NOT_FOUND error') - return new BenefitNotFoundError(benefit) - case 'UNAUTHORIZED': - return new UnauthorizedError(customMessage, benefit) - default: - throw new Error(`Unknown subscription error code: ${code}`) - } -} - -export function isSubscriptionError(error: unknown): error is SubscriptionError { - return error instanceof Error && 'code' in error && 'userMessage' in error -} - -export function getSubscriptionErrorMessage(error: unknown): string { - if (isSubscriptionError(error)) { - return error.userMessage - } - if (error instanceof Error) { - return error.message - } - return 'An unknown error occurred' -} diff --git a/src/shared/supabase.ts b/src/shared/supabase.ts deleted file mode 100644 index f16e6b57..00000000 --- a/src/shared/supabase.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { createClient } from '@supabase/supabase-js' -import { Database } from './database.types' - -let _isSupabaseAvailable = true -// ensure supabase env variables are available at build time -if (!__SUPABASE_URL__ || !__SUPABASE_ANON_KEY__) { - console.warn('Supabase environment variables are not configured.') - _isSupabaseAvailable = false -} - -export const supabase = () => createClient(__SUPABASE_URL__, __SUPABASE_ANON_KEY__) -export const isSupabaseAvailable = _isSupabaseAvailable diff --git a/src/shared/types.ts b/src/shared/types.ts deleted file mode 100644 index 1078ac91..00000000 --- a/src/shared/types.ts +++ /dev/null @@ -1 +0,0 @@ -export type NodeId = string // keyof typeof nodes diff --git a/src/shared/utils.ts b/src/shared/utils.ts deleted file mode 100644 index 2ceb4e7b..00000000 --- a/src/shared/utils.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const foo = 'bar' - -export type WithId = T extends (string | number) ? never : T & { id: string } diff --git a/src/shared/validation.ts b/src/shared/validation.ts deleted file mode 100644 index 510beedc..00000000 --- a/src/shared/validation.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { InputDefinition } from "@pipelab/plugin-core" - -export const isRequired = (param: InputDefinition) => { - return param.required === true -} - -export const isRenderer = () => { - // running in a web browser - if (typeof process === 'undefined') return true - - // node-integration is disabled - if (!process) return true - - // @ts-expect-error - return process.browser === true || process.title === 'browser' -}; diff --git a/supabase/functions/c3-export/index.ts b/supabase/functions/c3-export/index.ts new file mode 100644 index 00000000..4d432812 --- /dev/null +++ b/supabase/functions/c3-export/index.ts @@ -0,0 +1,129 @@ +import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; +import JSZip from "https://esm.sh/jszip@3.10.1"; + +const corsHeaders = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type", +}; + +serve(async (req) => { + if (req.method === "OPTIONS") { + return new Response("ok", { headers: corsHeaders }); + } + + try { + const formData = await req.formData(); + const file = formData.get("file") as File; + const name = (formData.get("name") as string) || "Construct3Game"; + const version = (formData.get("version") as string) || "1.0.0"; + const platform = (formData.get("platform") as string) || "win32"; + + if (!file) { + throw new Error("No file uploaded"); + } + + // 1. Download base Electron zip for the selected platform + let electronUrl = ""; + if (platform === "win32") { + electronUrl = "https://github.com/electron/electron/releases/download/v30.0.0/electron-v30.0.0-win32-x64.zip"; + } else if (platform === "linux") { + electronUrl = "https://github.com/electron/electron/releases/download/v30.0.0/electron-v30.0.0-linux-x64.zip"; + } else { + throw new Error("Unsupported platform"); + } + + const electronRes = await fetch(electronUrl); + if (!electronRes.ok) { + throw new Error(`Failed to download base Electron zip: ${electronRes.statusText}`); + } + const electronBytes = await electronRes.arrayBuffer(); + + // 2. Load both zip files + const electronZip = await JSZip.loadAsync(electronBytes); + const c3ZipBytes = await file.arrayBuffer(); + const c3Zip = await JSZip.loadAsync(c3ZipBytes); + + // 3. Inject C3 files into resources/app/ + const packageJson = JSON.stringify({ + name: name.toLowerCase().replace(/[^a-z0-9-]/g, "-"), + version: version, + main: "main.js", + }, null, 2); + + const mainJs = ` +const { app, BrowserWindow } = require('electron'); +const path = require('path'); + +function createWindow() { + const win = new BrowserWindow({ + width: 1280, + height: 720, + useContentSize: true, + webPreferences: { + nodeIntegration: false, + contextIsolation: true + } + }); + + win.loadFile(path.join(__dirname, 'index.html')); + win.setMenuBarVisibility(false); +} + +app.whenReady().then(createWindow); + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit(); + } +}); +`; + + // Write package.json and main.js to resources/app/ + electronZip.file("resources/app/package.json", packageJson); + electronZip.file("resources/app/main.js", mainJs); + + // Copy all files from the Construct 3 export zip to resources/app/ + for (const [relativePath, zipEntry] of Object.entries(c3Zip.files)) { + if (!zipEntry.dir) { + const content = await zipEntry.async("uint8array"); + electronZip.file(`resources/app/${relativePath}`, content); + } + } + + // 4. Rename electron.exe (Windows) or electron (Linux) + if (platform === "win32") { + const electronExe = electronZip.file("electron.exe"); + if (electronExe) { + const content = await electronExe.async("uint8array"); + electronZip.file(`${name}.exe`, content); + electronZip.remove("electron.exe"); + } + } else if (platform === "linux") { + const electronBin = electronZip.file("electron"); + if (electronBin) { + const content = await electronBin.async("uint8array"); + electronZip.file(`${name}`, content); + electronZip.remove("electron"); + } + } + + // 5. Generate the output zip file + const outputBytes = await electronZip.generateAsync({ type: "uint8array", compression: "DEFLATE" }); + + return new Response(outputBytes, { + headers: { + ...corsHeaders, + "Content-Type": "application/zip", + "Content-Disposition": `attachment; filename="${name}-electron.zip"`, + }, + }); + } catch (error) { + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + headers: { + ...corsHeaders, + "Content-Type": "application/json", + }, + }); + } +}); diff --git a/supabase/functions/cloud-run/index.ts b/supabase/functions/cloud-run/index.ts new file mode 100644 index 00000000..2d084ae8 --- /dev/null +++ b/supabase/functions/cloud-run/index.ts @@ -0,0 +1,78 @@ +import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; +import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; +import { AzureProvider } from "npm:@pipelab/cloud-azure"; + +const corsHeaders = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type", +}; + +serve(async (req) => { + if (req.method === "OPTIONS") { + return new Response("ok", { headers: corsHeaders }); + } + + try { + const supabaseClient = createClient( + Deno.env.get("SUPABASE_URL") ?? "", + Deno.env.get("SUPABASE_ANON_KEY") ?? "", + { global: { headers: { Authorization: req.headers.get("Authorization")! } } }, + ); + + const { + data: { user }, + } = await supabaseClient.auth.getUser(); + if (!user) throw new Error("Unauthorized"); + + const { pipeline, options } = await req.json(); + + // Azure Configuration from environment variables (managed by developer) + const azureProvider = new AzureProvider({ + subscriptionId: Deno.env.get("AZURE_SUBSCRIPTION_ID")!, + resourceGroup: Deno.env.get("AZURE_RESOURCE_GROUP")!, + location: Deno.env.get("AZURE_LOCATION")!, + storageAccountName: Deno.env.get("AZURE_STORAGE_ACCOUNT_NAME")!, + storageAccountKey: Deno.env.get("AZURE_STORAGE_ACCOUNT_KEY")!, + fileShareName: Deno.env.get("AZURE_FILE_SHARE_NAME")!, + image: Deno.env.get("PIPELAB_CLI_IMAGE")!, + }); + + // 1. Create run record in DB + const { data: run, error: runError } = await supabaseClient + .from("cloud_runs") + .insert({ + user_id: user.id, + provider_id: azureProvider.id, + status: "initializing", + }) + .select() + .single(); + + if (runError) throw runError; + + // 2. Start ACI + const cloudRun = await azureProvider.run(pipeline, { + ...options, + cloudRunId: run.id, + }); + + // 3. Update status + await supabaseClient + .from("cloud_runs") + .update({ status: "running", provider_run_id: cloudRun.id }) + .eq("id", run.id); + + // 4. Start log polling worker (background) + // In a real Edge Function, we might trigger another function or a queue + // For now, we'll return the run info + + return new Response(JSON.stringify({ runId: run.id }), { + headers: { ...corsHeaders, "Content-Type": "application/json" }, + }); + } catch (error) { + return new Response(JSON.stringify({ error: error.message }), { + status: 400, + headers: { ...corsHeaders, "Content-Type": "application/json" }, + }); + } +}); diff --git a/tests/e2e/tests/basic.spec.ts b/tests/e2e/tests/basic.spec.ts deleted file mode 100644 index ad60bb7c..00000000 --- a/tests/e2e/tests/basic.spec.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { it, expect, describe, vi } from 'vitest' -import { execa } from 'execa' -import { dirname, join } from 'path' -import { tmpdir } from 'os' -import { nanoid } from 'nanoid' -import { mkdir, readFile, writeFile } from 'fs/promises' -import { getBinName, name, outFolderName } from '../../../src/constants' -import { platform, arch } from 'process' - -const tmpLogFile = join(tmpdir(), nanoid() + 'pipelab-app-test.log.json') -const root = process.cwd() - -const binFolder = outFolderName('Pipelab', platform, arch) -const binName = getBinName(name) - -const bin = join(root, 'out', binFolder, binName) -// const bin = '/home/quentin/Projects/pipelab-monorepo/out/@pipelab-app-win32-x64/@pipelab-app.exe' -console.log('bin', bin) - -const fixtures = join(root, 'tests/e2e/fixtures') - -console.log('fixtures', fixtures) -console.log('tmpLogFile', tmpLogFile) - -describe('basic', () => { - it( - 'package folder to electron', - { - timeout: 60_000 - }, - async () => { - const jsonProject = join(fixtures, 'folder-to-electron.json') - console.log('jsonProject', jsonProject) - - try { - const { exitCode, stdout, stderr } = await execa( - bin, - ['--', '--project', jsonProject, '--action', 'run', '--output', tmpLogFile], - { - stdout: ['pipe', 'inherit'], - stderr: ['pipe', 'inherit'], - env: {} - } - ) - - const result = JSON.parse(await readFile(tmpLogFile, 'utf8')) - - console.log('result', result) - - expect(exitCode).toBe(0) - expect(result.steps).toBeDefined() - expect(result.steps).toEqual({ - 'electron-package-node': { - outputs: { - output: expect.any(String) - } - } - }) - - const output = result.steps['electron-package-node'].outputs.output - const outputRun = await execa(join(output, binName), []) - - expect(outputRun.exitCode).toBe(0) - } catch (e) { - console.log('e', e) - throw e - } - } - ) - - it( - 'package folder to tauri', - { - timeout: 240_000 - }, - async () => { - const jsonProject = join(fixtures, 'folder-to-tauri.json') - console.log('jsonProject', jsonProject) - - try { - const { exitCode, stdout, stderr } = await execa( - bin, - ['--', '--project', jsonProject, '--action', 'run', '--output', tmpLogFile], - { - stdout: ['pipe', 'inherit'], - stderr: ['pipe', 'inherit'], - env: {} - } - ) - - const result = JSON.parse(await readFile(tmpLogFile, 'utf8')) - - console.log('result', result) - - const binary = result.steps['tauri-package-node']?.outputs?.binary - - console.log('binary', binary) - - expect(exitCode).toBe(0) - expect(binary).toBeDefined() - expect(result.steps).toBeDefined() - expect(result.steps).toEqual({ - 'tauri-package-node': { - outputs: { - output: expect.any(String), - binary: expect.any(String) - } - } - }) - - const outputRun = await execa(binary, []) - - expect(outputRun.exitCode).toBe(0) - } catch (e) { - console.log('e', e) - throw e - } - } - ) - - it( - 'export c3', - { - timeout: 60_000 - }, - async () => { - // const { testC3Unzip } = await import('../../../src/main/presets/test-c3-unzip') - - // const project = await testC3Unzip() - - // console.log('project', project) - // // const jsonProject = join(fixtures, 'c3-export.json') - // const jsonProjectData = JSON.stringify(project.data) - // console.log('jsonProjectData', jsonProjectData) - - // const jsonProject = join(tmpdir(), nanoid(), 'c3-export.json') - - // await mkdir(dirname(jsonProject), { - // recursive: true, - // }) - - // console.log('jsonProject', jsonProject) - - // await writeFile(jsonProject, jsonProjectData) - - const jsonProject = join(fixtures, 'c3-export.json') - - try { - const { exitCode, stdout, stderr } = await execa( - bin, - ['--', '--project', jsonProject, '--action', 'run', '--output', tmpLogFile], - { - stdout: ['pipe', 'inherit'], - stderr: ['pipe', 'inherit'], - env: {} - } - ) - - const result = JSON.parse(await readFile(tmpLogFile, 'utf8')) - - expect(exitCode).toBe(0) - expect(result.steps).toBeDefined() - expect(result.steps).toEqual({ - 'export-construct-project': { - outputs: { - folder: expect.any(String), - parentFolder: expect.any(String), - zipFile: expect.any(String) - } - } - }) - } catch (e) { - console.log('e', e) - throw e - } - } - ) -}) diff --git a/tests/e2e/vitest.config.mts b/tests/e2e/vitest.config.mts deleted file mode 100644 index e01e2cc4..00000000 --- a/tests/e2e/vitest.config.mts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - root: 'tests/e2e', - environment: 'node', - reporters: process.env.GITHUB_ACTIONS - ? ['hanging-process', 'github-actions', 'default'] - : ['hanging-process', 'default'] - } -}) diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 00000000..2c1c73c6 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "resolveJsonModule": true + } +} diff --git a/tsconfig.json b/tsconfig.json index 13bf8b0c..127c5b6f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,36 +1,26 @@ { - "compilerOptions": { - "target": "ESNext", - "module": "commonjs", - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "noImplicitAny": true, - "baseUrl": ".", - "outDir": "dist", - "moduleResolution": "node", - "inlineSourceMap": true, - "resolveJsonModule": true, - "paths": { - "@@/*": [ - "./src/shared/*" - ], - "@main/*": [ - "./src/main/*" - ], - "@renderer/*": [ - "./src/renderer/*" - ], - "@pipelab/*": [ - "./src/shared/libs/*" - ], - } - }, - "exclude": [ - "node_modules", - "./assets/tauri/template/app/src-tauri", - "dist", - "out", - "./assets" + "files": [], + "references": [ + { "path": "./packages/constants" }, + { "path": "./packages/migration" }, + { "path": "./packages/shared" }, + { "path": "./packages/core-node" }, + { "path": "./packages/test-utils" }, + { "path": "./apps/ui" }, + { "path": "./apps/cli" }, + { "path": "./apps/desktop" }, + { "path": "./plugins/plugin-construct" }, + { "path": "./plugins/plugin-core" }, + { "path": "./plugins/plugin-discord" }, + { "path": "./plugins/plugin-electron" }, + { "path": "./plugins/plugin-filesystem" }, + { "path": "./plugins/plugin-itch" }, + { "path": "./plugins/plugin-minify" }, + { "path": "./plugins/plugin-netlify" }, + { "path": "./plugins/plugin-nvpatch" }, + { "path": "./plugins/plugin-poki" }, + { "path": "./plugins/plugin-steam" }, + { "path": "./plugins/plugin-system" }, + { "path": "./plugins/plugin-tauri" } ] -} \ No newline at end of file +} diff --git a/turbo.json b/turbo.json new file mode 100644 index 00000000..fcf578c7 --- /dev/null +++ b/turbo.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**", ".vite/**", "out/**"] + }, + "@pipelab/cli#build": { + "dependsOn": ["^build"] + }, + "package": { + "dependsOn": ["build"], + "outputs": ["out/**", "bin/**"] + }, + "make": { + "dependsOn": ["build"], + "outputs": ["out/**"] + }, + "publish": { + "dependsOn": ["build"], + "outputs": ["out/**"] + }, + "test": { + "outputs": [] + }, + "lint": { + "outputs": [] + }, + "typecheck": { + // dependsOn is required so dependencies build declarations via tsc -b before apps typecheck + "dependsOn": ["^typecheck"], + "outputs": ["dist/**/*.d.ts", "dist/**/*.d.ts.map", "dist/tsconfig.tsbuildinfo"] + }, + "format": { + "outputs": [] + }, + "dev": { + "cache": false, + "persistent": true + } + }, + "globalEnv": ["SUPABASE_URL", "SUPABASE_ANON_KEY", "SUPABASE_PROJECT_ID", "POSTHOG_API_KEY"], + "globalPassThroughEnv": [ + "DEBUG", + "APPLE_TEAM_ID", + "APPLE_ID", + "APPLE_ID_PASSWORD", + "APPLE_CODESIGN_IDENTITY", + "TARGET_ARCH", + "FORCE_UPDATE_CHECK", + "PIPELAB_OVERRIDE_RELEASE", + "PRERELEASE", + "APP_UPDATE_URL" + ] +} diff --git a/vite.base.config.mts b/vite.base.config.mts deleted file mode 100644 index 13845f09..00000000 --- a/vite.base.config.mts +++ /dev/null @@ -1,100 +0,0 @@ -import { builtinModules } from 'node:module' -import type { AddressInfo } from 'node:net' -import { loadEnv, type ConfigEnv, type Plugin, type UserConfig } from 'vite' -import pkg from './package.json' - -export const builtins = ['electron', ...builtinModules.map((m) => [m, `node:${m}`]).flat()] - -export const external = [ - ...builtins, - ...Object.keys('dependencies' in pkg ? (pkg.dependencies as Record) : {}) -] - -export function getBuildConfig(env: ConfigEnv<'build'>): UserConfig { - const { root, mode, command } = env - - return { - root, - mode, - build: { - // Prevent multiple builds from interfering with each other. - emptyOutDir: false, - // 🚧 Multiple builds may conflict. - outDir: '.vite/build', - watch: command === 'serve' ? {} : null, - minify: command === 'build' - }, - clearScreen: false - } -} - -export function getDefineKeys(names: string[]) { - const define: { [name: string]: VitePluginRuntimeKeys } = {} - - return names.reduce((acc, name) => { - const NAME = name.toUpperCase() - const keys: VitePluginRuntimeKeys = { - VITE_DEV_SERVER_URL: `${NAME}_VITE_DEV_SERVER_URL`, - VITE_NAME: `${NAME}_VITE_NAME` - } - - return { ...acc, [name]: keys } - }, define) -} - -export function getBuildDefine(env: ConfigEnv<'build'>) { - const { command, forgeConfig } = env - const names = forgeConfig.renderer.filter(({ name }) => name != null).map(({ name }) => name!) - const defineKeys = getDefineKeys(names) - const define = Object.entries(defineKeys).reduce( - (acc, [name, keys]) => { - const { VITE_DEV_SERVER_URL, VITE_NAME } = keys - const def = { - [VITE_DEV_SERVER_URL]: - command === 'serve' ? JSON.stringify(process.env[VITE_DEV_SERVER_URL]) : undefined, - [VITE_NAME]: JSON.stringify(name) - } - return { ...acc, ...def } - }, - {} as Record - ) - - return define -} - -export function pluginExposeRenderer(name: string): Plugin { - const { VITE_DEV_SERVER_URL } = getDefineKeys([name])[name] - - return { - name: '@electron-forge/plugin-vite:expose-renderer', - configureServer(server) { - process.viteDevServers ??= {} - // Expose server for preload scripts hot reload. - process.viteDevServers[name] = server - - server.httpServer?.once('listening', () => { - const addressInfo = server.httpServer!.address() as AddressInfo - // Expose env constant for main process use. - process.env[VITE_DEV_SERVER_URL] = `http://localhost:${addressInfo?.port}` - }) - } - } -} - -export function pluginHotRestart(command: 'reload' | 'restart'): Plugin { - return { - name: '@electron-forge/plugin-vite:hot-restart', - closeBundle() { - if (command === 'reload') { - for (const server of Object.values(process.viteDevServers)) { - // Preload scripts hot reload. - server.ws.send({ type: 'full-reload' }) - } - } else { - // Main process hot restart. - // https://github.com/electron/forge/blob/v7.2.0/packages/api/core/src/api/start.ts#L216-L223 - process.stdin.emit('data', 'rs') - } - } - } -} diff --git a/vite.main.config.mts b/vite.main.config.mts deleted file mode 100644 index 1b62bdd4..00000000 --- a/vite.main.config.mts +++ /dev/null @@ -1,67 +0,0 @@ -import type { ConfigEnv, UserConfig } from 'vite' -import { defineConfig, loadEnv, mergeConfig } from 'vite' -import { getBuildConfig, getBuildDefine, external, pluginHotRestart } from './vite.base.config.mjs' -import tsconfigPaths from 'vite-tsconfig-paths' -import { viteStaticCopy } from 'vite-plugin-static-copy' -import { sentryVitePlugin } from '@sentry/vite-plugin' - -// https://vitejs.dev/config -export default defineConfig((env) => { - const forgeEnv = env as ConfigEnv<'build'> - const { forgeConfigSelf } = forgeEnv - const define = getBuildDefine(forgeEnv) - const environment = loadEnv(env.mode, process.cwd(), '') - - const plugins = [ - pluginHotRestart('restart'), - tsconfigPaths({ - projects: ['./tsconfig.json'] - }), - viteStaticCopy({ - targets: [ - { - src: 'node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.wasm', - dest: '.' - } - ] - }) - ] - - // check if we are in a tag - const tag = process.env.GITHUB_REF?.includes('refs/tags/') - console.log('tag', tag) - if (tag) { - plugins.push( - sentryVitePlugin({ - org: 'armaldio', - project: 'cyn', - authToken: environment.SENTRY_AUTH_TOKEN - }) - ) - } - - const config: UserConfig = { - build: { - sourcemap: true, - lib: { - entry: forgeConfigSelf.entry!, - fileName: () => '[name].js', - formats: ['cjs'] - }, - rollupOptions: { - external - } - }, - plugins, - define: { - ...define, - __POSTHOG_API_KEY__: JSON.stringify(environment.POSTHOG_API_KEY) - }, - resolve: { - // Load the Node.js entry. - mainFields: ['module', 'jsnext:main', 'jsnext'] - } - } - - return mergeConfig(getBuildConfig(forgeEnv), config) -}) diff --git a/vite.preload.config.mts b/vite.preload.config.mts deleted file mode 100644 index 44b1b8c0..00000000 --- a/vite.preload.config.mts +++ /dev/null @@ -1,29 +0,0 @@ -import type { ConfigEnv, UserConfig } from 'vite'; -import { defineConfig, mergeConfig } from 'vite'; -import { getBuildConfig, external, pluginHotRestart } from './vite.base.config.mjs'; - -// https://vitejs.dev/config -export default defineConfig((env) => { - const forgeEnv = env as ConfigEnv<'build'>; - const { forgeConfigSelf } = forgeEnv; - const config: UserConfig = { - build: { - rollupOptions: { - external, - // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`. - input: forgeConfigSelf.entry!, - output: { - format: 'cjs', - // It should not be split chunks. - inlineDynamicImports: true, - entryFileNames: '[name].js', - chunkFileNames: '[name].js', - assetFileNames: '[name].[ext]', - }, - }, - }, - plugins: [pluginHotRestart('reload')], - }; - - return mergeConfig(getBuildConfig(forgeEnv), config); -}); diff --git a/vite.renderer.config.mts b/vite.renderer.config.mts deleted file mode 100644 index 1feb8c65..00000000 --- a/vite.renderer.config.mts +++ /dev/null @@ -1,66 +0,0 @@ -import type { ConfigEnv, UserConfig } from 'vite' -import { defineConfig, loadEnv } from 'vite' -import { pluginExposeRenderer } from './vite.base.config.mjs' -import tsconfigPaths from 'vite-tsconfig-paths' -import vue from '@vitejs/plugin-vue' -import Components from 'unplugin-vue-components/vite' -import { PrimeVueResolver } from '@primevue/auto-import-resolver' -import vitePluginVueDevtool from 'vite-plugin-vue-devtools' -import { sentryVitePlugin } from '@sentry/vite-plugin' - -// https://vitejs.dev/config -export default defineConfig((env) => { - const forgeEnv = env as ConfigEnv<'renderer'> - const { root, mode, forgeConfigSelf } = forgeEnv - const name = forgeConfigSelf.name ?? '' - - const environment = loadEnv(env.mode, process.cwd(), '') - - const plugins = [ - pluginExposeRenderer(name), - tsconfigPaths({ - projects: ['./tsconfig.json'] - }), - vue(), - Components({ - resolvers: [PrimeVueResolver()] - }), - vitePluginVueDevtool() - // nodePolyfills(), - ] - - const tag = process.env.GITHUB_REF?.includes('refs/tags/') - if (tag) { - plugins.push( - sentryVitePlugin({ - org: 'armaldio', - project: 'cyn', - authToken: environment.SENTRY_AUTH_TOKEN - }) - ) - } - - return { - root, - mode, - base: './', - define: { - __SUPABASE_URL__: JSON.stringify(environment.SUPABASE_URL), - __SUPABASE_ANON_KEY__: JSON.stringify(environment.SUPABASE_ANON_KEY), - __SUPABASE_PROJECT_ID__: JSON.stringify(environment.SUPABASE_PROJECT_ID), - __POSTHOG_API_KEY__: JSON.stringify(environment.POSTHOG_API_KEY) - }, - build: { - outDir: `.vite/renderer/${name}`, - sourcemap: true - }, - optimizeDeps: { - include: ['@codemirror/state', '@codemirror/view'] - }, - plugins, - resolve: { - preserveSymlinks: true - }, - clearScreen: false - } as UserConfig -}) diff --git a/vitest.config.mts b/vitest.config.mts deleted file mode 100644 index 0372722b..00000000 --- a/vitest.config.mts +++ /dev/null @@ -1,22 +0,0 @@ -import { configDefaults, defineConfig, mergeConfig } from 'vitest/config' -import renderer from './vite.renderer.config.mjs' - -export default defineConfig((configEnv) => { - const baseConfig = renderer({ - ...configEnv, - // @ts-expect-error forgeConfigSelf - forgeConfigSelf: { - name: 'Tests' - } - }) - - return mergeConfig( - baseConfig, - defineConfig({ - // plugins: [tsconfigPaths()], - test: { - exclude: [...configDefaults.exclude, 'tests/e2e/**/*.spec.ts'] - } - }) - ) -}) diff --git a/website b/website deleted file mode 160000 index e4b4f61b..00000000 --- a/website +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e4b4f61bc59b0c79e43cfd027c59596bf7ee7298

Please open the UI through its own dev server (usually http://localhost:5173).