diff --git a/bun.lock b/bun.lock index 6722c26..596d7c9 100644 --- a/bun.lock +++ b/bun.lock @@ -1,54 +1,55 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "wirebox", "devDependencies": { - "@biomejs/biome": "^2.3.5", - "@types/bun": "^1.3.2", - "tsdown": "^0.16.4", - "typedoc": "^0.28.14", + "@biomejs/biome": "^2.3.14", + "@types/bun": "^1.3.8", + "tsdown": "^0.20.3", + "typedoc": "^0.28.16", "typedoc-github-theme": "^0.3.1", "typescript": "^5.9.3", }, }, }, "packages": { - "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], + "@babel/generator": ["@babel/generator@8.0.0-rc.1", "", { "dependencies": { "@babel/parser": "^8.0.0-rc.1", "@babel/types": "^8.0.0-rc.1", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" } }, "sha512-3ypWOOiC4AYHKr8vYRVtWtWmyvcoItHtVqF8paFax+ydpmUdPsJpLBkBBs5ItmhdrwC3a0ZSqqFAdzls4ODP3w=="], - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.1", "", {}, "sha512-vi/pfmbrOtQmqgfboaBhaCU50G7mcySVu69VU8z+lYoPPB6WzI9VgV7WQfL908M4oeSH5fDkmoupIqoE0SdApw=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.0-rc.1", "", {}, "sha512-I4YnARytXC2RzkLNVnf5qFNFMzp679qZpmtw/V3Jt2uGnWiIxyJtaukjG7R8pSx8nG2NamICpGfljQsogj+FbQ=="], - "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + "@babel/parser": ["@babel/parser@8.0.0-rc.1", "", { "dependencies": { "@babel/types": "^8.0.0-rc.1" }, "bin": "./bin/babel-parser.js" }, "sha512-6HyyU5l1yK/7h9Ki52i5h6mDAx4qJdiLQO4FdCyJNoB/gy3T3GGJdhQzzbZgvgZCugYBvwtQiWRt94QKedHnkA=="], - "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + "@babel/types": ["@babel/types@8.0.0-rc.1", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.1", "@babel/helper-validator-identifier": "^8.0.0-rc.1" } }, "sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ=="], - "@biomejs/biome": ["@biomejs/biome@2.3.5", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.5", "@biomejs/cli-darwin-x64": "2.3.5", "@biomejs/cli-linux-arm64": "2.3.5", "@biomejs/cli-linux-arm64-musl": "2.3.5", "@biomejs/cli-linux-x64": "2.3.5", "@biomejs/cli-linux-x64-musl": "2.3.5", "@biomejs/cli-win32-arm64": "2.3.5", "@biomejs/cli-win32-x64": "2.3.5" }, "bin": { "biome": "bin/biome" } }, "sha512-HvLhNlIlBIbAV77VysRIBEwp55oM/QAjQEin74QQX9Xb259/XP/D5AGGnZMOyF1el4zcvlNYYR3AyTMUV3ILhg=="], + "@biomejs/biome": ["@biomejs/biome@2.3.14", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.14", "@biomejs/cli-darwin-x64": "2.3.14", "@biomejs/cli-linux-arm64": "2.3.14", "@biomejs/cli-linux-arm64-musl": "2.3.14", "@biomejs/cli-linux-x64": "2.3.14", "@biomejs/cli-linux-x64-musl": "2.3.14", "@biomejs/cli-win32-arm64": "2.3.14", "@biomejs/cli-win32-x64": "2.3.14" }, "bin": { "biome": "bin/biome" } }, "sha512-QMT6QviX0WqXJCaiqVMiBUCr5WRQ1iFSjvOLoTk6auKukJMvnMzWucXpwZB0e8F00/1/BsS9DzcKgWH+CLqVuA=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fLdTur8cJU33HxHUUsii3GLx/TR0BsfQx8FkeqIiW33cGMtUD56fAtrh+2Fx1uhiCsVZlFh6iLKUU3pniZREQw=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UJGPpvWJMkLxSRtpCAKfKh41Q4JJXisvxZL8ChN1eNW3m/WlPFJ6EFDCE7YfUb4XS8ZFi3C1dFpxUJ0Ety5n+A=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-qpT8XDqeUlzrOW8zb4k3tjhT7rmvVRumhi2657I2aGcY4B+Ft5fNwDdZGACzn8zj7/K1fdWjgwYE3i2mSZ+vOA=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-PNkLNQG6RLo8lG7QoWe/hhnMxJIt1tEimoXpGQjwS/dkdNiKBLPv4RpeQl8o3s1OKI3ZOR5XPiYtmbGGHAOnLA=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-u/pybjTBPGBHB66ku4pK1gj+Dxgx7/+Z0jAriZISPX1ocTO8aHh8x8e7Kb1rB4Ms0nA/SzjtNOVJ4exVavQBCw=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-KT67FKfzIw6DNnUNdYlBg+eU24Go3n75GWK6NwU4+yJmDYFe9i/MjiI+U/iEzKvo0g7G7MZqoyrhIYuND2w8QQ=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-eGUG7+hcLgGnMNl1KHVZUYxahYAhC462jF/wQolqu4qso2MSk32Q+QrpN7eN4jAHAg7FUMIo897muIhK4hXhqg=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-LInRbXhYujtL3sH2TMCH/UBwJZsoGwfQjBrMfl84CD4hL/41C/EU5mldqf1yoFpsI0iPWuU83U+nB2TUUypWeg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.5", "", { "os": "linux", "cpu": "x64" }, "sha512-XrIVi9YAW6ye0CGQ+yax0gLfx+BFOtKaNX74n+xHWla6Cl6huUmcKNO7HPx7BiKnJUzrxXY1qYlm7xMvi08X4g=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-ZsZzQsl9U+wxFrGGS4f6UxREUlgHwmEfu1IrXlgNFrNnd5Th6lIJr8KmSzu/+meSa9f4rzFrbEW9LBBA6ScoMA=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.5", "", { "os": "linux", "cpu": "x64" }, "sha512-awVuycTPpVTH/+WDVnEEYSf6nbCBHf/4wB3lquwT7puhNg8R4XvonWNZzUsfHZrCkjkLhFH/vCZK5jHatD9FEg=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-KQU7EkbBBuHPW3/rAcoiVmhlPtDSGOGRPv9js7qJVpYTzjQmVR+C9Rfcz+ti8YCH+zT1J52tuBybtP4IodjxZQ=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-DlBiMlBZZ9eIq4H7RimDSGsYcOtfOIfZOaI5CqsWiSlbTfqbPVfWtCf92wNzx8GNMbu1s7/g3ZZESr6+GwM/SA=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-+IKYkj/pUBbnRf1G1+RlyA3LWiDgra1xpS7H2g4BuOzzRbRB+hmlw0yFsLprHhbbt7jUzbzAbAjK/Pn0FDnh1A=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.5", "", { "os": "win32", "cpu": "x64" }, "sha512-nUmR8gb6yvrKhtRgzwo/gDimPwnO5a4sCydf8ZS2kHIJhEmSmk+STsusr1LHTuM//wXppBawvSQi2xFXJCdgKQ=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.14", "", { "os": "win32", "cpu": "x64" }, "sha512-oizCjdyQ3WJEswpb3Chdngeat56rIdSYK12JI3iI11Mt5T5EXcZ7WLuowzEaFPNJ3zmOQFliMN8QY1Pi+qsfdQ=="], - "@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="], + "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], - "@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="], + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "@gerrit0/mini-shiki": ["@gerrit0/mini-shiki@3.14.0", "", { "dependencies": { "@shikijs/engine-oniguruma": "^3.14.0", "@shikijs/langs": "^3.14.0", "@shikijs/themes": "^3.14.0", "@shikijs/types": "^3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-c5X8fwPLOtUS8TVdqhynz9iV0GlOtFUT1ppXYzUUlEXe4kbZ/mvMT8wXoT8kCwUka+zsiloq7sD3pZ3+QVTuNQ=="], + "@gerrit0/mini-shiki": ["@gerrit0/mini-shiki@3.22.0", "", { "dependencies": { "@shikijs/engine-oniguruma": "^3.22.0", "@shikijs/langs": "^3.22.0", "@shikijs/themes": "^3.22.0", "@shikijs/types": "^3.22.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-jMpciqEVUBKE1QwU64S4saNMzpsSza6diNCk4MWAeCxO2+LFi2FIFmL2S0VDLzEJCxuvCbU783xi8Hp/gkM5CQ=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -58,63 +59,61 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - "@oxc-project/runtime": ["@oxc-project/runtime@0.97.0", "", {}, "sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w=="], + "@oxc-project/types": ["@oxc-project/types@0.112.0", "", {}, "sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ=="], - "@oxc-project/types": ["@oxc-project/types@0.97.0", "", {}, "sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ=="], + "@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="], - "@quansync/fs": ["@quansync/fs@0.1.5", "", { "dependencies": { "quansync": "^0.2.11" } }, "sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.3", "", { "os": "android", "cpu": "arm64" }, "sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-beta.50", "", { "os": "android", "cpu": "arm64" }, "sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-beta.50", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+JRqKJhoFlt5r9q+DecAGPLZ5PxeLva+wCMtAuoFMWPoZzgcYrr599KQ+Ix0jwll4B4HGP43avu9My8KtSOR+w=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-beta.50", "", { "os": "darwin", "cpu": "x64" }, "sha512-fFXDjXnuX7/gQZQm/1FoivVtRcyAzdjSik7Eo+9iwPQ9EgtA5/nB2+jmbzaKtMGG3q+BnZbdKHCtOacmNrkIDA=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-beta.50", "", { "os": "freebsd", "cpu": "x64" }, "sha512-F1b6vARy49tjmT/hbloplzgJS7GIvwWZqt+tAHEstCh0JIh9sa8FAMVqEmYxDviqKBaAI8iVvUREm/Kh/PD26Q=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm" }, "sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.50", "", { "os": "linux", "cpu": "arm" }, "sha512-U6cR76N8T8M6lHj7EZrQ3xunLPxSvYYxA8vJsBKZiFZkT8YV4kjgCO3KwMJL0NOjQCPGKyiXO07U+KmJzdPGRw=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-beta.50", "", { "os": "linux", "cpu": "arm64" }, "sha512-ONgyjofCrrE3bnh5GZb8EINSFyR/hmwTzZ7oVuyUB170lboza1VMCnb8jgE6MsyyRgHYmN8Lb59i3NKGrxrYjw=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-beta.50", "", { "os": "linux", "cpu": "arm64" }, "sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-beta.50", "", { "os": "linux", "cpu": "x64" }, "sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-beta.50", "", { "os": "linux", "cpu": "x64" }, "sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.3", "", { "os": "none", "cpu": "arm64" }, "sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-beta.50", "", { "os": "none", "cpu": "arm64" }, "sha512-eZUssog7qljrrRU9Mi0eqYEPm3Ch0UwB+qlWPMKSUXHNqhm3TvDZarJQdTevGEfu3EHAXJvBIe0YFYr0TPVaMA=="], + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g=="], - "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-beta.50", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-nmCN0nIdeUnmgeDXiQ+2HU6FT162o+rxnF7WMkBm4M5Ds8qTU7Dzv2Wrf22bo4ftnlrb2hKK6FSwAJSAe2FWLg=="], + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-beta.50", "", { "os": "win32", "cpu": "arm64" }, "sha512-7kcNLi7Ua59JTTLvbe1dYb028QEPaJPJQHqkmSZ5q3tJueUeb6yjRtx8mw4uIqgWZcnQHAR3PrLN4XRJxvgIkA=="], + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "x64" }, "sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A=="], - "@rolldown/binding-win32-ia32-msvc": ["@rolldown/binding-win32-ia32-msvc@1.0.0-beta.50", "", { "os": "win32", "cpu": "ia32" }, "sha512-lL70VTNvSCdSZkDPPVMwWn/M2yQiYvSoXw9hTLgdIWdUfC3g72UaruezusR6ceRuwHCY1Ayu2LtKqXkBO5LIwg=="], + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-beta.50", "", { "os": "win32", "cpu": "x64" }, "sha512-4qU4x5DXWB4JPjyTne/wBNPqkbQU8J45bl21geERBKtEittleonioACBL1R0PsBu0Aq21SwMK5a9zdBkWSlQtQ=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.22.0", "", { "dependencies": { "@shikijs/types": "3.22.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA=="], - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.50", "", {}, "sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA=="], + "@shikijs/langs": ["@shikijs/langs@3.22.0", "", { "dependencies": { "@shikijs/types": "3.22.0" } }, "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA=="], - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="], + "@shikijs/themes": ["@shikijs/themes@3.22.0", "", { "dependencies": { "@shikijs/types": "3.22.0" } }, "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g=="], - "@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="], - - "@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="], - - "@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], + "@shikijs/types": ["@shikijs/types@3.22.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg=="], "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@types/bun": ["@types/bun@1.3.2", "", { "dependencies": { "bun-types": "1.3.2" } }, "sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg=="], + "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], - "@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="], + "@types/jsesc": ["@types/jsesc@2.5.1", "", {}, "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw=="], - "@types/react": ["@types/react@19.1.11", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ=="], + "@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="], "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], @@ -122,23 +121,19 @@ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - "ast-kit": ["ast-kit@2.2.0", "", { "dependencies": { "@babel/parser": "^7.28.5", "pathe": "^2.0.3" } }, "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw=="], + "ast-kit": ["ast-kit@3.0.0-beta.1", "", { "dependencies": { "@babel/parser": "^8.0.0-beta.4", "estree-walker": "^3.0.3", "pathe": "^2.0.3" } }, "sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "birpc": ["birpc@2.8.0", "", {}, "sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw=="], + "birpc": ["birpc@4.0.0", "", {}, "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw=="], "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="], + "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], - "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - - "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], - - "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], "dts-resolver": ["dts-resolver@2.1.3", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw=="], @@ -146,11 +141,15 @@ "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], + "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], + + "hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="], - "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], + "import-without-cache": ["import-without-cache@0.2.5", "", {}, "sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], @@ -158,15 +157,13 @@ "lunr": ["lunr@2.3.9", "", {}, "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="], - "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "obug": ["obug@1.0.0", "", { "peerDependencies": { "ms": "^2.0.0" }, "optionalPeers": ["ms"] }, "sha512-WKcS43Yl6YPJekid7KiRdT6CHMSmYWVfJiSFbTaGxWQlC+cEBPxHa9jR1uS2cMiQmXd8Hsa2ipAKErQ/GLhSpg=="], + "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -174,15 +171,13 @@ "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], - "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], - - "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], - "rolldown": ["rolldown@1.0.0-beta.50", "", { "dependencies": { "@oxc-project/types": "=0.97.0", "@rolldown/pluginutils": "1.0.0-beta.50" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-beta.50", "@rolldown/binding-darwin-arm64": "1.0.0-beta.50", "@rolldown/binding-darwin-x64": "1.0.0-beta.50", "@rolldown/binding-freebsd-x64": "1.0.0-beta.50", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.50", "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.50", "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.50", "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.50", "@rolldown/binding-linux-x64-musl": "1.0.0-beta.50", "@rolldown/binding-openharmony-arm64": "1.0.0-beta.50", "@rolldown/binding-wasm32-wasi": "1.0.0-beta.50", "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.50", "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.50", "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.50" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-JFULvCNl/anKn99eKjOSEubi0lLmNqQDAjyEMME2T4CwezUDL0i6t1O9xZsu2OMehPnV2caNefWpGF+8TnzB6A=="], + "rolldown": ["rolldown@1.0.0-rc.3", "", { "dependencies": { "@oxc-project/types": "=0.112.0", "@rolldown/pluginutils": "1.0.0-rc.3" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-x64": "1.0.0-rc.3", "@rolldown/binding-freebsd-x64": "1.0.0-rc.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.3", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.3", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.3", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.3", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.3", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.3" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw=="], - "rolldown-plugin-dts": ["rolldown-plugin-dts@0.17.7", "", { "dependencies": { "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "ast-kit": "^2.2.0", "birpc": "^2.8.0", "dts-resolver": "^2.1.3", "get-tsconfig": "^4.13.0", "magic-string": "^0.30.21", "obug": "^1.0.0" }, "peerDependencies": { "@ts-macro/tsc": "^0.3.6", "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-beta.44", "typescript": "^5.0.0", "vue-tsc": "~3.1.0" }, "optionalPeers": ["@ts-macro/tsc", "@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-ZGgXMhzCItmznNzbJlTcC/KdM6bIwcZoYUykJ2q14HOGvnMhnl2RXU+XrIrdjA2Hyzq3nWqDH7qWaM5a4uCVnw=="], + "rolldown-plugin-dts": ["rolldown-plugin-dts@0.22.1", "", { "dependencies": { "@babel/generator": "8.0.0-rc.1", "@babel/helper-validator-identifier": "8.0.0-rc.1", "@babel/parser": "8.0.0-rc.1", "@babel/types": "8.0.0-rc.1", "ast-kit": "^3.0.0-beta.1", "birpc": "^4.0.0", "dts-resolver": "^2.1.3", "get-tsconfig": "^4.13.1", "obug": "^2.1.1" }, "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", "vue-tsc": "~3.2.0" }, "optionalPeers": ["@ts-macro/tsc", "@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-5E0AiM5RSQhU6cjtkDFWH6laW4IrMu0j1Mo8x04Xo1ALHmaRMs9/7zej7P3RrryVHW/DdZAp85MA7Be55p0iUw=="], "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], @@ -192,11 +187,11 @@ "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], - "tsdown": ["tsdown@0.16.4", "", { "dependencies": { "ansis": "^4.2.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "diff": "^8.0.2", "empathic": "^2.0.0", "hookable": "^5.5.3", "obug": "^1.0.0", "rolldown": "1.0.0-beta.50", "rolldown-plugin-dts": "^0.17.7", "semver": "^7.7.3", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tree-kill": "^1.2.2", "unconfig-core": "^7.4.1", "unrun": "^0.2.9" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@vitejs/devtools": "^0.0.0-alpha.17", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "@vitejs/devtools", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-tdhy+EQpZSVrVkDRnjKEKVfh1git2HrliGp3SylRNg7kk+lOx3SvT7NLakKX5grPAg8WrZrXWLPUrCegWupqgg=="], + "tsdown": ["tsdown@0.20.3", "", { "dependencies": { "ansis": "^4.2.0", "cac": "^6.7.14", "defu": "^6.1.4", "empathic": "^2.0.0", "hookable": "^6.0.1", "import-without-cache": "^0.2.5", "obug": "^2.1.1", "picomatch": "^4.0.3", "rolldown": "1.0.0-rc.3", "rolldown-plugin-dts": "^0.22.1", "semver": "^7.7.3", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tree-kill": "^1.2.2", "unconfig-core": "^7.4.2", "unrun": "^0.2.27" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@vitejs/devtools": "*", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "@vitejs/devtools", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-qWOUXSbe4jN8JZEgrkc/uhJpC8VN2QpNu3eZkBWwNuTEjc/Ik1kcc54ycfcQ5QPRHeu9OQXaLfCI3o7pEJgB2w=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "typedoc": ["typedoc@0.28.14", "", { "dependencies": { "@gerrit0/mini-shiki": "^3.12.0", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", "yaml": "^2.8.1" }, "peerDependencies": { "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" }, "bin": { "typedoc": "bin/typedoc" } }, "sha512-ftJYPvpVfQvFzpkoSfHLkJybdA/geDJ8BGQt/ZnkkhnBYoYW6lBgPQXu6vqLxO4X75dA55hX8Af847H5KXlEFA=="], + "typedoc": ["typedoc@0.28.16", "", { "dependencies": { "@gerrit0/mini-shiki": "^3.17.0", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", "yaml": "^2.8.1" }, "peerDependencies": { "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" }, "bin": { "typedoc": "bin/typedoc" } }, "sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog=="], "typedoc-github-theme": ["typedoc-github-theme@0.3.1", "", { "peerDependencies": { "typedoc": "~0.28.0" } }, "sha512-j6PmkAGmf/MGCzYjQcUH6jS9djPsNl/IoTXooxC+MoeMkBhbmPyKJlpR6Lw12BLoe2OYpYA2J1KMktUJXp/8Sw=="], @@ -204,12 +199,16 @@ "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], - "unconfig-core": ["unconfig-core@7.4.1", "", { "dependencies": { "@quansync/fs": "^0.1.5", "quansync": "^0.2.11" } }, "sha512-Bp/bPZjV2Vl/fofoA2OYLSnw1Z0MOhCX7zHnVCYrazpfZvseBbGhwcNQMxsg185Mqh7VZQqK3C8hFG/Dyng+yA=="], + "unconfig-core": ["unconfig-core@7.4.2", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg=="], "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], - "unrun": ["unrun@0.2.10", "", { "dependencies": { "@oxc-project/runtime": "^0.97.0", "rolldown": "1.0.0-beta.50" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-IcQCpGp3oawzr2ANNmMCh2XNssrDueQvoOfC/ranG4Enq0vVCCLfen+sJTaLYKR22vxZttF2KvvaubgbUadTqA=="], + "unrun": ["unrun@0.2.27", "", { "dependencies": { "rolldown": "1.0.0-rc.3" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw=="], "yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + + "ast-kit/@babel/parser": ["@babel/parser@8.0.0-beta.4", "", { "dependencies": { "@babel/types": "^8.0.0-beta.4" }, "bin": "./bin/babel-parser.js" }, "sha512-fBcUqUN3eenLyg25QFkOwY1lmV6L0RdG92g6gxyS2CVCY8kHdibkQz1+zV3bLzxcvNnfHoi3i9n5Dci+g93acg=="], + + "ast-kit/@babel/parser/@babel/types": ["@babel/types@8.0.0-beta.4", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-beta.4", "@babel/helper-validator-identifier": "^8.0.0-beta.4" } }, "sha512-xjk2xqYp25ePzAs0I08hN2lrbUDDQFfCjwq6MIEa8HwHa0WK8NfNtdvtXod8Ku2CbE1iui7qwWojGvjQiyrQeA=="], } } diff --git a/package.json b/package.json index fd9a76d..f10515f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wirebox", - "version": "1.0.0-alpha.2", + "version": "0.6.0", "type": "module", "module": "./src/index.js", "description": "A simple but flexible dependency injection library.", @@ -33,10 +33,10 @@ "./package.json": "./package.json" }, "devDependencies": { - "@biomejs/biome": "^2.3.5", - "@types/bun": "^1.3.2", - "tsdown": "^0.16.4", - "typedoc": "^0.28.14", + "@biomejs/biome": "^2.3.14", + "@types/bun": "^1.3.8", + "tsdown": "^0.20.3", + "typedoc": "^0.28.16", "typedoc-github-theme": "^0.3.1", "typescript": "^5.9.3" } diff --git a/src/circuit.ts b/src/circuit.ts index c5dad86..8066048 100644 --- a/src/circuit.ts +++ b/src/circuit.ts @@ -3,7 +3,7 @@ import { AlreadyInitializedError, AsyncDependencyError, InvalidProvidableError, - NoCircuitLinkError, + NoCircuitContextError, UnwiredError, } from "./errors.ts"; import { @@ -13,7 +13,7 @@ import { } from "./provider/provider.ts"; import type { Class, Context, ResolvedInstance, Wrapped } from "./types.ts"; -let currentCircuit: Circuit | null = null; +let currentContext: Context | null = null; /** * A circuit is a container which is responsible for managing the instances by holding and initializing them. @@ -66,8 +66,8 @@ export class Circuit { // get the class definition const definition = WireDefinition.from(target); - // if the target not resolved yet and no meta is available, throw an error - if (!definition) throw new UnwiredError(target); + // if the target not resolved yet and no valid definition is available, throw an error + if (!definition || !definition.isValid()) throw new UnwiredError(target); // if the class is a singleton, forward the tap to the singleton circuit if (definition.singleton && definition.singleton !== this) @@ -77,8 +77,12 @@ export class Circuit { if (this.#asyncInitializers.has(target)) throw new AsyncDependencyError(target, true); - // if target is async and not initialized, throw an error - if (definition.async) throw new AsyncDependencyError(target, false); + // if target has an async preconstruct, throw an error + if (definition.preconstructAsync) + throw new AsyncDependencyError(target, false); + + // if target has setup, throw an error + if (definition.setup) throw new AsyncDependencyError(target, false); // resolve the inputs const inputs = this.#resolveDependencies( @@ -87,25 +91,19 @@ export class Circuit { ); // initialize the class either with the preconstruct if available or with the constructor - const instance = this.#runWithCircuit(() => - definition.preconstruct - ? definition.preconstruct(inputs, context) - : Reflect.construct(target, inputs), + const instance = this.#runWithContext( + () => + definition.preconstruct + ? definition.preconstruct(inputs, context) + : Reflect.construct(target, inputs), + context, ); - // check if the class is async - if (instance instanceof Promise) { - // handle the promise and save it to prevent multiple async initializations - this.#handlePromise(target, instance); - - throw new AsyncDependencyError(target, true); - } else { - // save the instance to prevent multiple initializations - this.#instances.set(target, instance); + // save the instance to prevent multiple initializations + this.#instances.set(target, instance); - // resolve and return the instance - return instance; - } + // resolve and return the instance + return instance; } #resolveAsync(target: Class, context: Context): Promise { @@ -124,29 +122,54 @@ export class Circuit { // get the class definition const definition = WireDefinition.from(target); - // if the target not resolved yet and no definition is available, throw an error - if (!definition) throw new UnwiredError(target); + // if the target not resolved yet and no valid definition is available, throw an error + if (!definition || !definition.isValid()) throw new UnwiredError(target); // if the class is a singleton, forward the tap to the singleton circuit if (definition.singleton && definition.singleton !== this) return definition.singleton.#resolveAsync(target, context); // resolve the inputs and initialize the class, with either the initializer or the constructor - const initializer = this.resolveDependenciesAsync( + const initializer = this.#resolveDependenciesAsync( definition.dependencies?.() ?? [], definition.preloads?.() ?? [], context, - ).then((inputs) => - this.#runWithCircuit(() => - definition.preconstruct - ? definition.preconstruct(inputs, context) - : Reflect.construct(target, inputs), - ), - ); + ).then(async (inputs) => { + const instancePromise = this.#runWithContext( + () => + // use preconstructAsync if available + definition.preconstructAsync + ? definition.preconstructAsync(inputs, context) + : // then use preconstruct if available + definition.preconstruct + ? definition.preconstruct(inputs, context) + : // otherwise use the constructor + Reflect.construct(target, inputs), + context, + ); + + const instance = await instancePromise; + + // if there is no setup, return the instance directly + if (!definition.setup) return instance; + + // run the setup + let setupPromise = definition.setup.bind(instance)(); + + // if the setup result is a function, call it to get the actual promise + if (typeof setupPromise === "function") { + setupPromise = setupPromise.bind(instance)(); + } + + // wait for the setup to finish + await setupPromise; + + return instance; + }); // handle the promise and save it to prevent multiple async initializations // and return the promise - return this.#handlePromise(target, initializer); + return this.#handlePromise(target, initializer, context); } /** @@ -242,8 +265,11 @@ export class Circuit { // if no definition is available, return false if (!definition) return false; - // if target has async initializer, return true - if (definition.async) return true; + // if target has async preconstruct, return true + if (definition.preconstructAsync) return true; + + // if target has setup, return true + if (definition.setup) return true; const ctx = this.#createContext(target); @@ -261,20 +287,21 @@ export class Circuit { return providerInfo.async ?? false; } - #runWithCircuit(fn: () => T): T { - const previousCircuit = currentCircuit; + #runWithContext(fn: () => T, context: Context): T { + const previousContext = currentContext; try { - currentCircuit = this; + currentContext = context; return fn(); } finally { - currentCircuit = previousCircuit; + currentContext = previousContext; } } #handlePromise( target: Class, initializer: Promise, + context: Context, ): Promise { const wrapped = initializer .then((result) => { @@ -283,7 +310,7 @@ export class Circuit { const instance = typeof result === "function" - ? this.#runWithCircuit(() => result()) + ? this.#runWithContext(() => result(), context) : result; this.#instances.set(target, instance); @@ -308,7 +335,7 @@ export class Circuit { }); } - async resolveDependenciesAsync( + async #resolveDependenciesAsync( dependencies: readonly Class[], preloads: readonly Class[], context: Context, @@ -401,11 +428,25 @@ export const tapAsync = ( return circuit.tapAsync(target); }; +/** + * @category Core + */ +export const getContext = (): Context => { + const context = currentContext; + if (!context) throw new NoCircuitContextError(); + return context; +}; + +/** + * @category Core + */ +export const getCircuit = (): Circuit => { + return getContext().circuit; +}; + /** * @category Core */ export const link = (target: T): ResolvedInstance => { - const circuit = currentCircuit; - if (!circuit) throw new NoCircuitLinkError(target); - return circuit.tap(target); + return getCircuit().tap(target); }; diff --git a/src/definition/decorators.ts b/src/definition/decorators.ts index 6b73804..89b7294 100644 --- a/src/definition/decorators.ts +++ b/src/definition/decorators.ts @@ -1,5 +1,5 @@ import { Circuit } from "../circuit.ts"; -import type { Class, Context, ResolvedInstances } from "../types.ts"; +import type { Class, Context, ResolvedInstances, Setupable } from "../types.ts"; import { WireDefinition } from "./definition.ts"; /** @@ -24,15 +24,16 @@ export const isWired = (target: Class): boolean => { export const singleton = (circuit?: Circuit) => (target: T, _context: ClassDecoratorContext) => { - WireDefinition.from(target, true).singleton = - circuit || Circuit.getDefault(); + setSingleton(target, circuit); }; /** * @category Definition Setter */ export const setSingleton = (target: T, circuit?: Circuit) => { - WireDefinition.from(target, true).singleton = circuit || Circuit.getDefault(); + WireDefinition.set(target, { + singleton: circuit || Circuit.getDefault(), + }); }; // requires @@ -45,10 +46,10 @@ export const requires = TTarget extends Class>, const TDeps extends readonly Class[], >( - deps: () => TDeps, + dependencies: () => TDeps, ) => (target: TTarget, _context: ClassDecoratorContext) => { - WireDefinition.from(target, true).dependencies = deps; + setRequires(target, dependencies); }; /** @@ -59,9 +60,11 @@ export const setRequires = < const TDeps extends readonly Class[], >( target: TTarget, - deps: () => TDeps, + dependencies: () => TDeps, ) => { - WireDefinition.from(target, true).dependencies = deps; + WireDefinition.set(target, { + dependencies, + }); }; // standalone @@ -72,14 +75,16 @@ export const setRequires = < export const standalone = >() => (target: T, _context: ClassDecoratorContext) => { - WireDefinition.from(target, true).dependencies = () => []; + setStandalone(target); }; /** * @category Definition Setter */ export const setStandalone = >(target: T) => { - WireDefinition.from(target, true).dependencies = () => []; + WireDefinition.set(target, { + dependencies: () => [], + }); }; // preconstruct @@ -96,11 +101,7 @@ export const preconstruct = dependencies?: () => TDeps, ) => (target: T, _context: ClassDecoratorContext) => { - const definition = WireDefinition.from(target, true); - - definition.async = false; - definition.preconstruct = preconstruct as WireDefinition["preconstruct"]; - definition.dependencies = dependencies; + setPreconstruct(target, preconstruct, dependencies); }; /** @@ -117,11 +118,10 @@ export const setPreconstruct = < ) => InstanceType, dependencies?: () => TDeps, ) => { - const definition = WireDefinition.from(target, true); - - definition.async = false; - definition.preconstruct = preconstruct as WireDefinition["preconstruct"]; - definition.dependencies = dependencies; + WireDefinition.set(target, { + dependencies: dependencies ?? (() => []), + preconstruct: preconstruct as WireDefinition["preconstruct"], + }); }; // preconstruct async @@ -131,18 +131,14 @@ export const setPreconstruct = < */ export const preconstructAsync = ( - preconstruct: ( + preconstructAsync: ( dependencies: ResolvedInstances, context: Context, ) => Promise<() => InstanceType>, dependencies?: () => TDeps, ) => (target: T, _context: ClassDecoratorContext) => { - const definition = WireDefinition.from(target, true); - - definition.async = true; - definition.preconstruct = preconstruct as WireDefinition["preconstruct"]; - definition.dependencies = dependencies; + setPreconstructAsync(target, preconstructAsync, dependencies); }; /** @@ -153,17 +149,49 @@ export const setPreconstructAsync = < const TDeps extends readonly Class[] = readonly [], >( target: T, - preconstruct: ( + preconstructAsync: ( dependencies: ResolvedInstances, context: Context, ) => Promise<() => InstanceType>, dependencies?: () => TDeps, ) => { - const definition = WireDefinition.from(target, true); + WireDefinition.set(target, { + dependencies: dependencies ?? (() => []), + preconstructAsync: preconstructAsync as WireDefinition["preconstructAsync"], + }); +}; + +// setup + +/** + * @category Definition Decorator + */ +export const setup = + , TSetup extends Setupable>(setup: TSetup) => + (target: T, _context: ClassDecoratorContext) => { + setSetup(target, setup); + }; + +/** + * @category Definition Setter + */ +export const setSetup = < + T extends Class, + TSetup extends Setupable, +>( + target: T, + setup: TSetup, +) => { + let setupFn: WireDefinition["setup"] | PropertyKey = setup; + + if ( + typeof setupFn === "string" || + typeof setupFn === "symbol" || + typeof setupFn === "number" + ) + setupFn = target.prototype[setupFn]; - definition.async = true; - definition.preconstruct = preconstruct as WireDefinition["preconstruct"]; - definition.dependencies = dependencies; + WireDefinition.set(target, { setup: setupFn as WireDefinition["setup"] }); }; // preloads @@ -174,7 +202,7 @@ export const setPreconstructAsync = < export const preloads = (preloads: () => readonly Class[]) => (target: T, _context: ClassDecoratorContext) => { - WireDefinition.from(target, true).preloads = preloads; + setPreloads(target, preloads); }; /** @@ -184,5 +212,5 @@ export const setPreloads = ( target: T, preloads: () => readonly Class[], ) => { - WireDefinition.from(target, true).preloads = preloads; + WireDefinition.set(target, { preloads }); }; diff --git a/src/definition/definition.ts b/src/definition/definition.ts index daf2a42..4e26348 100644 --- a/src/definition/definition.ts +++ b/src/definition/definition.ts @@ -17,15 +17,28 @@ export class WireDefinition { this.target = target; } - // biome-ignore lint/complexity/useLiteralKeys: formatter cannot handle this - ["async"]: boolean = false; singleton?: Circuit; dependencies?: () => readonly Class[]; preloads?: () => readonly Class[]; + preconstructAsync?: ( + dependencies: readonly unknown[], + context: Context, + ) => Promise<() => unknown>; preconstruct?: ( dependencies: readonly unknown[], context: Context, - ) => unknown | Promise<() => unknown>; + ) => unknown; + setup?: (() => void | Promise) | (() => () => void | Promise); + + isValid(): boolean { + // cannot have both preconstruct and preconstructAsync + if (this.preconstruct && this.preconstructAsync) return false; + + // dependencies must be defined + if (!this.dependencies) return false; + + return true; + } remove(): boolean { return REGISTRY.delete(this.target); @@ -55,8 +68,10 @@ export class WireDefinition { if (options.dependencies) definition.dependencies = options.dependencies; if (options.preloads) definition.preloads = options.preloads; + if (options.preconstructAsync) + definition.preconstructAsync = options.preconstructAsync; if (options.preconstruct) definition.preconstruct = options.preconstruct; - if (options.async) definition.async = options.async; + if (options.setup) definition.setup = options.setup; if (options.singleton) definition.singleton = options.singleton; return definition; diff --git a/src/errors.ts b/src/errors.ts index 95a98a7..5319f9d 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -62,21 +62,15 @@ export class AsyncDependencyError extends WireboxError { } /** - * Thrown when the {@link link} function is called outside of a wired contructor. + * Thrown when the circuit context is not available. * * @category Error */ -export class NoCircuitLinkError extends WireboxError { - readonly target: Class; - - /** - * @param target The target class. - */ - constructor(target: Class) { +export class NoCircuitContextError extends WireboxError { + constructor() { super( - `Class(${target.name}) cannot be instantiated because the Circuit cannot be determined. Make sure you are calling "link" inside a sync constructor of a wired class.`, + `Circuit context is not available. Make sure you are calling "getCircuit"/"getContext" inside a wired class constructor`, ); - this.target = target; } } diff --git a/src/index.ts b/src/index.ts index 4c574f7..1eab5e8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,11 @@ -export { Circuit, link, tap, tapAsync } from "./circuit.ts"; +export { + Circuit, + getCircuit, + getContext, + link, + tap, + tapAsync, +} from "./circuit.ts"; export { isWired, preconstruct, @@ -9,8 +16,10 @@ export { setPreconstructAsync, setPreloads, setRequires, + setSetup, setSingleton, setStandalone, + setup, singleton, standalone, unwire, @@ -20,7 +29,7 @@ export { AlreadyInitializedError, AsyncDependencyError, InvalidProvidableError, - NoCircuitLinkError, + NoCircuitContextError, UnwiredError, WireboxError, } from "./errors.ts"; @@ -47,5 +56,11 @@ export type { ResolvedInstances, } from "./types.ts"; export { combine, type ResolvedCombine } from "./utilities/combine.ts"; +export { + conditional, + conditionalAsync, + setConditional, + setConditionalAsync, +} from "./utilities/conditional.ts"; export { lazy } from "./utilities/lazy.ts"; export { withCircuit } from "./utilities/with-circuit.ts"; diff --git a/src/provider/common.ts b/src/provider/common.ts index 4139d42..622a62d 100644 --- a/src/provider/common.ts +++ b/src/provider/common.ts @@ -1,4 +1,5 @@ -import { setPreconstruct, setStandalone } from "../definition/decorators.ts"; +import { getContext } from "../circuit.ts"; +import { setStandalone } from "../definition/decorators.ts"; import type { Context } from "../types.ts"; import { type Providable, type ProvidableClass, provide } from "./provider.ts"; @@ -26,8 +27,8 @@ export const createProvider = ( class Provider implements Providable { private _value: T; - constructor(ctx: Context) { - this._value = getValue(ctx); + constructor() { + this._value = getValue(getContext()); } [provide] = { @@ -35,7 +36,7 @@ export const createProvider = ( }; } - setPreconstruct(Provider, (_, ctx) => new Provider(ctx)); + setStandalone(Provider); return Provider; }; @@ -49,8 +50,8 @@ export const createAsyncProvider = ( class AsyncProvider implements Providable { private _value: Promise; - constructor(ctx: Context) { - this._value = getValue(ctx); + constructor() { + this._value = getValue(getContext()); } [provide] = { @@ -59,7 +60,7 @@ export const createAsyncProvider = ( }; } - setPreconstruct(AsyncProvider, (_, ctx) => new AsyncProvider(ctx)); + setStandalone(AsyncProvider); return AsyncProvider; }; diff --git a/src/provider/provider.ts b/src/provider/provider.ts index 08f17c1..30c4b8b 100644 --- a/src/provider/provider.ts +++ b/src/provider/provider.ts @@ -39,11 +39,8 @@ export type ProviderInfo = * @param T The class to infer the value type from. * @category Provider */ -export type ProvidedValue = T extends ProvidableClass< - infer TValue -> - ? TValue - : never; +export type ProvidedValue = + T extends ProvidableClass ? TValue : never; /** * A class which provides a value and conforms to {@link Providable}. diff --git a/src/types.ts b/src/types.ts index 2795cac..811fcc5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,6 +13,33 @@ export type Class< TInstance = any, > = abstract new (...args: TArgs) => TInstance; +/** + * Extracts properties from a type `T` whose types match `V` exactly. + * + * @param T The source type. + * @param V The value type to extract. + * @category Utility Type + */ +export type ExtractProperties = { + [K in keyof T as T[K] extends V ? (V extends T[K] ? K : never) : never]: T[K]; +}; + +/** + * A type representing a setup function for a class. + * + * This can be: + * - A function that returns a void promise and is bound to the instance. + * - A function that returns another function which is bound to the instance and returns a void promise. + * - A key of a method on the instance that returns a void promise. + */ +export type Setupable = + | ((this: InstanceType) => void | Promise) + | (() => (this: InstanceType) => void | Promise) + | keyof ExtractProperties< + InstanceType, + (() => Promise) | (() => void) + >; + /** * A wrapped value which holds the actual value in the `value` property. * diff --git a/src/utilities/conditional.ts b/src/utilities/conditional.ts new file mode 100644 index 0000000..fd87f71 --- /dev/null +++ b/src/utilities/conditional.ts @@ -0,0 +1,88 @@ +import { + setPreconstruct, + setPreconstructAsync, +} from "../definition/decorators.ts"; +import type { Class, Context, ResolvedInstances } from "../types.ts"; + +/** + * @category Utility: Conditional + */ +export const conditional = + ( + resolve: ( + dependencies: ResolvedInstances, + context: Context, + ) => NoInfer, + dependencies?: () => TDeps, + ) => + (target: T, _context: ClassDecoratorContext) => { + setConditional(target, resolve, dependencies); + }; + +/** + * @category Utility: Conditional + */ +export const setConditional = < + T extends Class, + const TDeps extends readonly Class[] = readonly [], +>( + target: T, + resolve: ( + dependencies: ResolvedInstances, + context: Context, + ) => NoInfer, + dependencies?: () => TDeps, +) => { + setPreconstruct( + target, + (dependencies, context) => { + const target = resolve(dependencies, context); + const instance = context.circuit.tap(target); + + return instance as InstanceType; + }, + dependencies, + ); +}; + +/** + * @category Utility: Conditional + */ +export const conditionalAsync = + ( + resolveAsync: ( + dependencies: ResolvedInstances, + context: Context, + ) => Promise>, + dependencies?: () => TDeps, + ) => + (target: T, _context: ClassDecoratorContext) => { + setConditionalAsync(target, resolveAsync, dependencies); + }; + +/** + * @category Utility: Conditional + */ +export const setConditionalAsync = < + T extends Class, + const TDeps extends readonly Class[] = readonly [], +>( + target: T, + resolveAsync: ( + dependencies: ResolvedInstances, + context: Context, + ) => Promise>, + dependencies?: () => TDeps, +) => { + setPreconstructAsync( + target, + async (dependencies, context) => { + const target = await resolveAsync(dependencies, context); + const instance = await context.circuit.tapAsync(target); + + return () => instance as InstanceType; + }, + + dependencies, + ); +}; diff --git a/test/preconstruct.test.ts b/test/decorators/preconstruct.test.ts similarity index 95% rename from test/preconstruct.test.ts rename to test/decorators/preconstruct.test.ts index 5682ff5..61b2229 100644 --- a/test/preconstruct.test.ts +++ b/test/decorators/preconstruct.test.ts @@ -1,12 +1,5 @@ -import { beforeAll, describe, expect, mock, test } from "bun:test"; -import { - Circuit, - type Context, - setPreconstruct, - setStandalone, - tap, - WireDefinition, -} from "wirebox"; +import { describe, expect, mock, test } from "bun:test"; +import { Circuit, setPreconstruct, setStandalone, tap } from "wirebox"; describe("Preconstruct", () => { test("basic preconstruct", () => { diff --git a/test/requires.test.ts b/test/decorators/requires.test.ts similarity index 100% rename from test/requires.test.ts rename to test/decorators/requires.test.ts diff --git a/test/decorators/setup.test.ts b/test/decorators/setup.test.ts new file mode 100644 index 0000000..67a7a2f --- /dev/null +++ b/test/decorators/setup.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, mock, test } from "bun:test"; +import { Circuit, setSetup, setStandalone, tap, tapAsync } from "wirebox"; + +describe("Setup", () => { + test("basic setup", async () => { + class MySetupClass { + name = "Setup"; + } + + const setupFn = mock(function (this: MySetupClass) { + expect(this).toBeInstanceOf(MySetupClass); + }); + + setStandalone(MySetupClass); + setSetup(MySetupClass, setupFn); + + const instance1 = await tapAsync(MySetupClass); + expect(instance1).toBeInstanceOf(MySetupClass); + expect(instance1.name).toBe("Setup"); + expect(setupFn).toHaveBeenCalledTimes(1); + + const instance2 = tap(MySetupClass); + expect(instance2).toBeInstanceOf(MySetupClass); + expect(instance2).toBe(instance1); + expect(instance2.name).toBe("Setup"); + expect(setupFn).toHaveBeenCalledTimes(1); + + const otherCircuit = new Circuit(); + const instance3 = await otherCircuit.tapAsync(MySetupClass); + expect(instance3).toBeInstanceOf(MySetupClass); + expect(instance3).not.toBe(instance1); + expect(instance3.name).toBe("Setup"); + expect(setupFn).toHaveBeenCalledTimes(2); + }); + + test("async accessor setup", async () => { + class MyAsyncSetupClass { + initialized = false; + + async inlineSetup() { + expect(this).toBeInstanceOf(MyAsyncSetupClass); + await new Promise((resolve) => setTimeout(resolve, 10)); + this.initialized = true; + } + } + + setStandalone(MyAsyncSetupClass); + setSetup(MyAsyncSetupClass, () => MyAsyncSetupClass.prototype.inlineSetup); + + const instance1 = await tapAsync(MyAsyncSetupClass); + expect(instance1).toBeInstanceOf(MyAsyncSetupClass); + expect(instance1.initialized).toBe(true); + + const instance2 = tap(MyAsyncSetupClass); + expect(instance2).toBe(instance1); + expect(instance2.initialized).toBe(true); + }); + + test("async inline setup", async () => { + class MyAsyncSetupClass { + initialized = false; + } + + setStandalone(MyAsyncSetupClass); + setSetup(MyAsyncSetupClass, async function () { + expect(this).toBeInstanceOf(MyAsyncSetupClass); + await new Promise((resolve) => setTimeout(resolve, 10)); + this.initialized = true; + }); + + const instance1 = await tapAsync(MyAsyncSetupClass); + expect(instance1).toBeInstanceOf(MyAsyncSetupClass); + expect(instance1.initialized).toBe(true); + + const instance2 = tap(MyAsyncSetupClass); + expect(instance2).toBe(instance1); + expect(instance2.initialized).toBe(true); + }); + + test("async method name setup", async () => { + class MyAsyncSetupClass { + initialized = false; + + async inlineSetup() { + expect(this).toBeInstanceOf(MyAsyncSetupClass); + await new Promise((resolve) => setTimeout(resolve, 10)); + this.initialized = true; + } + } + + setStandalone(MyAsyncSetupClass); + setSetup(MyAsyncSetupClass, "inlineSetup"); + + const instance1 = await tapAsync(MyAsyncSetupClass); + expect(instance1).toBeInstanceOf(MyAsyncSetupClass); + expect(instance1.initialized).toBe(true); + + const instance2 = tap(MyAsyncSetupClass); + expect(instance2).toBe(instance1); + expect(instance2.initialized).toBe(true); + }); +}); diff --git a/test/standalone.test.ts b/test/decorators/standalone.test.ts similarity index 100% rename from test/standalone.test.ts rename to test/decorators/standalone.test.ts diff --git a/test/definition.test.ts b/test/definition.test.ts index d998c80..2eac591 100644 --- a/test/definition.test.ts +++ b/test/definition.test.ts @@ -1,9 +1,9 @@ -import { beforeAll, describe, expect, test } from "bun:test"; +import { beforeEach, describe, expect, test } from "bun:test"; import { WireDefinition } from "wirebox"; class ToBeDecorated {} -beforeAll(() => { +beforeEach(() => { WireDefinition.from(ToBeDecorated)?.remove(); }); diff --git a/test/provider.test.ts b/test/provider.test.ts new file mode 100644 index 0000000..c41656e --- /dev/null +++ b/test/provider.test.ts @@ -0,0 +1,180 @@ +import { describe, expect, test } from "bun:test"; +import { + BasicValueProvider, + Circuit, + createAsyncDynamicProvider, + createAsyncProvider, + createAsyncStaticProvider, + createDynamicProvider, + createProvider, + createStaticProvider, + type Providable, + provide, + setStandalone, +} from "wirebox"; + +describe("Provider", () => { + test("raw sync providable", () => { + class Provider implements Providable { + [provide] = { + getValue: () => "provided-value", + }; + } + + setStandalone(Provider); + + const circuit = new Circuit(); + const instance = circuit.tap(Provider); + expect(instance).not.toBeInstanceOf(Provider); + expect(instance).toBe("provided-value"); + }); + + test("raw async providable", async () => { + class AsyncProvider implements Providable { + [provide] = { + async: true as const, + getValue: async () => { + await new Promise((resolve) => setTimeout(resolve, 10)); + return 42; + }, + }; + } + + setStandalone(AsyncProvider); + + const circuit = new Circuit(); + const instance = await circuit.tapAsync(AsyncProvider); + expect(instance).not.toBeInstanceOf(AsyncProvider); + expect(instance).toBe(42); + }); + + test("BasicValueProvider", () => { + class Provider extends BasicValueProvider { + constructor() { + super(123); + } + } + + setStandalone(Provider); + + const circuit = new Circuit(); + const instance = circuit.tap(Provider); + expect(instance).not.toBeInstanceOf(Provider); + expect(instance).not.toBeInstanceOf(BasicValueProvider); + expect(instance).toBe(123); + }); + + test("createProvider", () => { + const Provider = createProvider(() => new Date()); + + const circuit1 = new Circuit(); + const instance10 = circuit1.tap(Provider); + expect(instance10).not.toBeInstanceOf(Provider); + expect(instance10).toBeInstanceOf(Date); + + const instance11 = circuit1.tap(Provider); + expect(instance11).toBe(instance10); + + const circuit2 = new Circuit(); + const instance20 = circuit2.tap(Provider); + expect(instance20).toBeInstanceOf(Date); + expect(instance20).not.toBe(instance10); + }); + + test("createAsyncProvider", async () => { + const Provider = createAsyncProvider(async () => + Bun.sleep(10).then(() => new Date()), + ); + + const circuit1 = new Circuit(); + const instance10 = await circuit1.tapAsync(Provider); + expect(instance10).not.toBeInstanceOf(Provider); + expect(instance10).toBeInstanceOf(Date); + + const instance11 = await circuit1.tapAsync(Provider); + expect(instance11).toBe(instance10); + + const circuit2 = new Circuit(); + const instance20 = await circuit2.tapAsync(Provider); + expect(instance20).toBeInstanceOf(Date); + expect(instance20).not.toBe(instance10); + }); + + test("createDynamicProvider", () => { + const Provider = createDynamicProvider(() => new Date()); + + const circuit1 = new Circuit(); + const instance10 = circuit1.tap(Provider); + expect(instance10).not.toBeInstanceOf(Provider); + expect(instance10).toBeInstanceOf(Date); + + const instance11 = circuit1.tap(Provider); + expect(instance11).toBeInstanceOf(Date); + expect(instance11).not.toBe(instance10); + + const circuit2 = new Circuit(); + const instance20 = circuit2.tap(Provider); + expect(instance20).toBeInstanceOf(Date); + expect(instance20).not.toBe(instance10); + }); + + test("createAsyncDynamicProvider", async () => { + const Provider = createAsyncDynamicProvider(async () => + Bun.sleep(10).then(() => new Date()), + ); + + const circuit1 = new Circuit(); + const instance10 = await circuit1.tapAsync(Provider); + expect(instance10).not.toBeInstanceOf(Provider); + expect(instance10).toBeInstanceOf(Date); + + const instance11 = await circuit1.tapAsync(Provider); + expect(instance11).toBeInstanceOf(Date); + expect(instance11).not.toBe(instance10); + + const circuit2 = new Circuit(); + const instance20 = await circuit2.tapAsync(Provider); + expect(instance20).toBeInstanceOf(Date); + expect(instance20).not.toBe(instance10); + }); + + test("createStaticProvider", () => { + const Provider = createStaticProvider(new Date()); + + const circuit1 = new Circuit(); + const instance10 = circuit1.tap(Provider); + expect(instance10).not.toBeInstanceOf(Provider); + expect(instance10).toBeInstanceOf(Date); + + const instance11 = circuit1.tap(Provider); + expect(instance11).toBeInstanceOf(Date); + expect(instance11).toBe(instance10); + + const circuit2 = new Circuit(); + const instance20 = circuit2.tap(Provider); + expect(instance20).toBeInstanceOf(Date); + expect(instance20).toBe(instance10); + expect(instance20).toBe(instance11); + }); + + test("createAsyncStaticProvider", async () => { + const Provider = createAsyncStaticProvider( + Bun.sleep(10).then(() => new Date()), + ); + + const circuit1 = new Circuit(); + const instance10 = await circuit1.tapAsync(Provider); + expect(instance10).not.toBeInstanceOf(Provider); + expect(instance10).toBeInstanceOf(Date); + + const instance11 = await circuit1.tapAsync(Provider); + expect(instance11).toBeInstanceOf(Date); + expect(instance11).toBe(instance10); + + const circuit2 = new Circuit(); + const instance20 = await circuit2.tapAsync(Provider); + expect(instance20).toBeInstanceOf(Date); + expect(instance20).toBe(instance10); + expect(instance20).toBe(instance11); + }); +}); diff --git a/test/utilities/conditional.test.ts b/test/utilities/conditional.test.ts new file mode 100644 index 0000000..13c7eaf --- /dev/null +++ b/test/utilities/conditional.test.ts @@ -0,0 +1,110 @@ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { + Circuit, + setConditional, + setConditionalAsync, + setStandalone, + unwire, +} from "wirebox"; + +abstract class PubSub { + abstract type: string; + abstract publish(message: string): void; + abstract subscribe(callback: (message: string) => void): void; +} + +class InMemoryPubSub extends PubSub { + type = "in-memory"; + + publish(_message: string): void { + // In-memory publish logic + } + + subscribe(_callback: (message: string) => void): void { + // In-memory subscribe logic + } +} + +class RedisPubSub extends PubSub { + type = "redis"; + + publish(_message: string): void { + // Redis publish logic + } + + subscribe(_callback: (message: string) => void): void { + // Redis subscribe logic + } +} + +afterEach(() => { + expect(unwire(PubSub)).toBe(true); + expect(unwire(InMemoryPubSub)).toBe(true); + expect(unwire(RedisPubSub)).toBe(true); +}); + +describe("Conditional", () => { + test("conditional sync", () => { + const circuit = new Circuit(); + let isInMemory = true; + + setConditional(PubSub, () => (isInMemory ? InMemoryPubSub : RedisPubSub)); + setStandalone(InMemoryPubSub); + setStandalone(RedisPubSub); + + expect(isInMemory).toBe(true); + + const instance1 = circuit.tap(PubSub); + expect(instance1).toBeInstanceOf(InMemoryPubSub); + expect(instance1.type).toBe("in-memory"); + + // Clear instance + circuit.uninstall(PubSub); + expect(circuit.get(PubSub)).toBeUndefined(); + + isInMemory = false; + expect(isInMemory).toBe(false); + + const instance2 = circuit.tap(PubSub); + expect(instance2).toBeInstanceOf(RedisPubSub); + expect(instance2.type).toBe("redis"); + expect(instance2).not.toBe(instance1); + }); + + test("conditional async", async () => { + const circuit = new Circuit(); + let isInMemory = true; + + const getIsInMemory = async () => + new Promise((resolve) => + setTimeout(() => resolve(isInMemory), 10), + ); + + setConditionalAsync(PubSub, async () => + (await getIsInMemory()) ? InMemoryPubSub : RedisPubSub, + ); + setStandalone(InMemoryPubSub); + setStandalone(RedisPubSub); + + expect(isInMemory).toBe(true); + expect(await getIsInMemory()).toBe(true); + + expect(() => circuit.tap(PubSub)).toThrowError(); + const instance1 = await circuit.tapAsync(PubSub); + expect(instance1).toBeInstanceOf(InMemoryPubSub); + expect(instance1.type).toBe("in-memory"); + + // Clear instance + circuit.uninstall(PubSub); + expect(circuit.get(PubSub)).toBeUndefined(); + + isInMemory = false; + expect(isInMemory).toBe(false); + expect(await getIsInMemory()).toBe(false); + + const instance2 = await circuit.tapAsync(PubSub); + expect(instance2).toBeInstanceOf(RedisPubSub); + expect(instance2.type).toBe("redis"); + expect(instance2).not.toBe(instance1); + }); +});