From 5705d621331e7cd047dc706bdecd56b9e14d693a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2026 22:06:28 +0000 Subject: [PATCH 1/5] chore(deps-dev): bump ultracite from 7.11.1 to 8.0.1 Bumps [ultracite](https://github.com/haydenbleasel/ultracite) from 7.11.1 to 8.0.1. - [Release notes](https://github.com/haydenbleasel/ultracite/releases) - [Commits](https://github.com/haydenbleasel/ultracite/compare/ultracite@7.11.1...ultracite@8.0.1) --- updated-dependencies: - dependency-name: ultracite dependency-version: 8.0.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- bun.lock | 28 ++++++++++++++++------------ package.json | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/bun.lock b/bun.lock index 0f05df3..fe42c68 100644 --- a/bun.lock +++ b/bun.lock @@ -20,7 +20,7 @@ "publint": "0.3.25", "turbo": "^2.11.8", "typescript": "^7", - "ultracite": "7.11.1", + "ultracite": "8.0.1", }, }, "apps/web": { @@ -1025,7 +1025,7 @@ "emojilib": ["emojilib@2.4.0", "", {}, "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw=="], - "empathic": ["empathic@2.0.1", "", {}, "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q=="], + "empathic": ["empathic@2.1.0", "", {}, "sha512-AnfC1ATldl49/cvZdLPDjBfrRNwbDO05aibiOtzQu3qtlbJtomNLhF30HEtn/7iBz50dlMECqATo3fG0LrdEgw=="], "enhanced-resolve": ["enhanced-resolve@5.24.5", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A=="], @@ -1411,7 +1411,7 @@ "magic-string": ["magic-string@1.4.3", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.6.0" } }, "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ=="], - "magicast": ["magicast@0.5.4", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w=="], + "magicast": ["magicast@0.5.5", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA=="], "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], @@ -1625,7 +1625,7 @@ "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], @@ -1819,7 +1819,7 @@ "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], - "string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="], + "string-width": ["string-width@8.3.0", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ=="], "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], @@ -1905,7 +1905,7 @@ "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], - "ultracite": ["ultracite@7.11.1", "", { "dependencies": { "@clack/prompts": "^1.7.0", "cli-truncate": "^6.1.1", "commander": "^15.0.0", "deepmerge": "^4.3.1", "empathic": "^2.0.1", "execa": "^10.0.1", "fast-glob": "^3.3.3", "find-workspaces": "^0.3.1", "jsonc-parser": "^3.3.1", "log-update": "^8.0.0", "magicast": "^0.5.4", "nypm": "^0.6.9", "resolve.exports": "^2.0.3", "semver": "^7.8.5", "string-width": "^8.2.2", "yaml": "^2.9.0", "zod": "^4.5.4" }, "peerDependencies": { "@biomejs/biome": "^2.5.0", "eslint": "^10.0.0", "oxfmt": ">=0.40.0", "oxlint": "^1.79.0", "prettier": "^3.0.0", "stylelint": "^17.0.0" }, "optionalPeers": ["@biomejs/biome", "eslint", "oxfmt", "oxlint", "prettier", "stylelint"], "bin": { "ultracite": "dist/index.js" } }, "sha512-NHqXD/fpNpLyAWCU3AOfRppVvXtxVk0D+oWrEOUXOveAiQCoyCnx+vL34Fa/rnFPY2piYfdqNhghp/J04uQ6JQ=="], + "ultracite": ["ultracite@8.0.1", "", { "dependencies": { "@clack/prompts": "^1.8.1", "cli-truncate": "^6.1.1", "commander": "^15.0.0", "deepmerge": "^4.3.1", "empathic": "^2.1.0", "execa": "^10.0.1", "fast-glob": "^3.3.3", "find-workspaces": "^0.3.1", "jsonc-parser": "^3.3.1", "log-update": "^8.0.0", "magicast": "^0.5.5", "npm-run-path": "^6.0.0", "nypm": "^0.6.10", "resolve.exports": "^2.0.3", "semver": "^7.8.5", "string-width": "^8.3.0", "which-command": "^0.1.0", "yaml": "^2.9.1", "zod": "^4.6.5" }, "peerDependencies": { "@biomejs/biome": "^2.5.0", "eslint": "^10.9.0", "oxfmt": ">=0.71.0 <1", "oxlint": "^1.86.0", "prettier": "^3.5.3", "stylelint": "^17.0.0" }, "optionalPeers": ["@biomejs/biome", "eslint", "oxfmt", "oxlint", "prettier", "stylelint"], "bin": { "ultracite": "dist/index.js" } }, "sha512-4XtB3My7o/O8uveSBPjMO6aPwkO7LEGDf2RCuR4jMVSJ4JByLNIb8+xpCR5M+HssgPrl0aSTQ/40od80ItmiqQ=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], @@ -2043,12 +2043,16 @@ "cli-table3/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "cli-truncate/string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="], + "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "eslint/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "eslint/espree": ["espree@11.2.0", "", { "dependencies": { "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^5.0.1" } }, "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw=="], @@ -2077,7 +2081,7 @@ "fumadocs-ui/cn": ["cn@0.4.0", "", { "bin": { "cn": "bin/cn.mjs" } }, "sha512-qOAeUhPwPzBxx6jaeQdo646XIKliKHc2j1ZF7Ngb1o0pJZKH5gq8FkA0aVdUdPFUDXNXyUCXpCtoJISo6dhizg=="], - "magicast/source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "log-update/string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="], "marked-terminal/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], @@ -2091,8 +2095,6 @@ "node-exports-info/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], - "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], @@ -2109,14 +2111,14 @@ "tsdown/cac": ["cac@7.1.0", "", {}, "sha512-LMDU/U2yA4IPIY8KT0NsNPWEYZvAMkbgyspxJ6btJaYV+WMDOHAZCmB0lsTObiHaRS1V/ztKAl7+TSkTqXyeoA=="], - "tsdown/empathic": ["empathic@2.1.0", "", {}, "sha512-AnfC1ATldl49/cvZdLPDjBfrRNwbDO05aibiOtzQu3qtlbJtomNLhF30HEtn/7iBz50dlMECqATo3fG0LrdEgw=="], + "ultracite/@clack/prompts": ["@clack/prompts@1.8.1", "", { "dependencies": { "@clack/core": "1.5.1", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ=="], "ultracite/commander": ["commander@15.0.0", "", {}, "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg=="], - "ultracite/yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "wrap-ansi/string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="], + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "yuku-analyzer/yuku-ast": ["yuku-ast@0.17.0", "", { "dependencies": { "@yuku-toolchain/types": "^0.17.0" } }, "sha512-htIzp3bLNdBtOSh8L8pJ7nkTft2kw/C3ghTToSg3FKtzi0YGkvAdEUUza9c744tnbeXtKUMEupFOYHuVNXn1yQ=="], @@ -2169,6 +2171,8 @@ "next/postcss/source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "ultracite/@clack/prompts/@clack/core": ["@clack/core@1.5.1", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ=="], + "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], diff --git a/package.json b/package.json index 1b9dd9f..4597f83 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "publint": "0.3.25", "turbo": "^2.11.8", "typescript": "^7", - "ultracite": "7.11.1" + "ultracite": "8.0.1" }, "devEngines": { "packageManager": { From f9c151586fe95af51775016fbdd8a58490649fcc Mon Sep 17 00:00:00 2001 From: PunGrumpy <108584943+PunGrumpy@users.noreply.github.com> Date: Fri, 23 Oct 2026 09:27:36 +0700 Subject: [PATCH 2/5] chore(lint): allow bare early returns in effects ultracite 8 turns on sonarjs/no-inconsistent-returns, which conflicts with unicorn/no-useless-undefined for React effects that bail out early and otherwise return a cleanup. Keep the unicorn rule and turn the sonarjs one off. --- oxlint.config.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/oxlint.config.ts b/oxlint.config.ts index a9f449a..9c403d4 100644 --- a/oxlint.config.ts +++ b/oxlint.config.ts @@ -12,5 +12,11 @@ export default defineConfig({ extends: [core, react, next, nextJsPlugins, antiSlop, jsPlugins], ignorePatterns: core.ignorePatterns, jsPlugins: jsPlugins.jsPlugins, + rules: { + // React effects bail out early with a bare `return;` and otherwise return + // a cleanup. unicorn/no-useless-undefined forbids the explicit + // `return undefined;` that this rule would need instead. + "sonarjs/no-inconsistent-returns": "off", + }, settings: jsPluginSettings, }); From a489f502f319d33957417e415e6dfae74ca7e636 Mon Sep 17 00:00:00 2001 From: PunGrumpy <108584943+PunGrumpy@users.noreply.github.com> Date: Fri, 23 Oct 2026 09:27:51 +0700 Subject: [PATCH 3/5] refactor(filter): use \w in the redis field pattern ultracite 8 turns on sonarjs/concise-regex. [A-Za-z0-9_] and \w match the same characters here (no i flag). --- packages/vecstore-sdk/src/filter/redis.ts | 43 ++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/vecstore-sdk/src/filter/redis.ts b/packages/vecstore-sdk/src/filter/redis.ts index cc2d4d3..11cd583 100644 --- a/packages/vecstore-sdk/src/filter/redis.ts +++ b/packages/vecstore-sdk/src/filter/redis.ts @@ -29,7 +29,7 @@ export interface RedisFilterProblem { export type RedisFilterResult = Result; -export const REDIS_FIELD_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/u; +export const REDIS_FIELD_PATTERN = /^[A-Za-z_]\w*$/u; export const REDIS_RESERVED_FIELDS: ReadonlySet = new Set([ "namespace", @@ -117,10 +117,13 @@ const typeOfField = ( if (REDIS_RESERVED_FIELDS.has(field)) { return err(reservedField(field)); } + if (!REDIS_FIELD_PATTERN.test(field)) { return err(malformedField(field)); } + const type = types.get(field); + return type === undefined ? err(unknownField(field)) : ok(type); }; @@ -128,6 +131,7 @@ const tagValue = (field: string, value: Scalar): RedisFilterResult => { if (isNumber(value)) { return err(tagHoldsNoNumber(field)); } + return ok(isString(value) ? value : String(value)); }; @@ -135,6 +139,7 @@ const numericValue = (field: string, value: Scalar): RedisFilterResult => { if (!isNumber(value)) { return err(numericHoldsOnlyNumbers(field)); } + return Number.isFinite(value) ? ok(String(value)) : err(finiteNumbersOnly(field, value)); @@ -150,9 +155,12 @@ const equality = ( ): RedisFilterResult => { if (type === "numeric") { const number = numericValue(field, value); + return number.ok ? ok(numericMatch(field, number.value)) : number; } + const tag = tagValue(field, value); + return tag.ok ? ok(redisTagClause(field, tag.value)) : tag; }; @@ -164,11 +172,15 @@ const comparison = ( if (type === "tag") { return err(rangeNeedsNumeric(field)); } + const number = numericValue(field, filter.value); + if (!number.ok) { return number; } + const [start, end] = RANGE_BOUNDS[filter.kind](number.value); + return ok(`@${field}:[${start} ${end}]`); }; @@ -177,13 +189,17 @@ const tagMembership = ( values: NonEmpty ): RedisFilterResult => { const tags: string[] = []; + for (const value of values) { const tag = tagValue(field, value); + if (!tag.ok) { return tag; } + tags.push(escapeRedisTag(tag.value)); } + return ok(`@${field}:{${tags.join(" | ")}}`); }; @@ -192,13 +208,17 @@ const numericMembership = ( values: NonEmpty ): RedisFilterResult => { const matches: string[] = []; + for (const value of values) { const number = numericValue(field, value); + if (!number.ok) { return number; } + matches.push(numericMatch(field, number.value)); } + return ok(`(${matches.join(" | ")})`); }; @@ -213,12 +233,14 @@ const leafClause = ( case "ne": { return equality(filter.field, type, filter.value); } + case "in": case "nin": { return type === "tag" ? tagMembership(filter.field, filter.values) : numericMembership(filter.field, filter.values); } + default: { return comparison(filter.field, type, filter); } @@ -236,13 +258,17 @@ const compileLeaf = ( negated: boolean ): RedisFilterResult => { const type = typeOfField(filter.field, types); + if (!type.ok) { return type; } + const clause = leafClause(filter, type.value); + if (!clause.ok) { return clause; } + return ok( isNegatedLeaf(filter) === negated ? clause.value : negate(clause.value) ); @@ -260,14 +286,19 @@ const compileGroup = ( compile: CompileNode ): RedisFilterResult => { const clauses: string[] = []; + for (const child of filter.filters) { const compiled = compile(child, types, false); + if (!compiled.ok) { return compiled; } + clauses.push(compiled.value); } + const separator = filter.kind === "and" ? " " : " | "; + return ok(`(${clauses.join(separator)})`); }; @@ -277,10 +308,13 @@ const compileExists = ( negated: boolean ): RedisFilterResult => { const type = typeOfField(field, types); + if (!type.ok) { return type; } + const clause = `ismissing(@${field})`; + return ok(negated ? clause : `-${clause}`); }; @@ -296,22 +330,29 @@ const compileNode: CompileNode = (filter, types, negated) => { case "nin": { return compileLeaf(filter, types, negated); } + case "exists": { return compileExists(filter.field, types, negated); } + case "and": case "or": { const group = compileGroup(filter, types, compileNode); + if (!group.ok) { return group; } + return ok(negated ? negate(group.value) : group.value); } + case "not": { return compileNode(filter.filter, types, !negated); } + default: { const exhaustive: never = filter; + return exhaustive; } } From 94e1f36b1dfa3b70d8b9ac876df7949121c27f14 Mon Sep 17 00:00:00 2001 From: PunGrumpy <108584943+PunGrumpy@users.noreply.github.com> Date: Fri, 23 Oct 2026 09:28:00 +0700 Subject: [PATCH 4/5] style: apply ultracite 8 formatting Insert the blank lines anti-slop/require-readable-spacing now asks for before statements, and let the fixer inline a one-use helper in setupLive. --- apps/web/app/changelog/rss.xml/route.ts | 2 + apps/web/app/layout.tsx | 1 + apps/web/app/llms.txt/route.ts | 1 + apps/web/app/og/docs/[...slug]/route.ts | 2 + apps/web/components/brand-menu.tsx | 29 ++++++ apps/web/components/docs/sidebar-items.tsx | 3 + apps/web/components/landing/copy-command.tsx | 1 + apps/web/components/landing/demo.tsx | 2 + apps/web/components/landing/hero-demo.tsx | 6 ++ apps/web/components/landing/store/canvas.tsx | 32 +++++++ apps/web/components/landing/store/mesh.ts | 24 +++++ apps/web/components/landing/store/query.ts | 4 + apps/web/components/landing/store/stack.tsx | 4 + apps/web/components/provider-icon.tsx | 6 ++ apps/web/components/search-dialog.tsx | 1 + apps/web/lib/get-llm-text.ts | 1 + .../vecstore-sdk/scripts/check-exports.ts | 5 ++ packages/vecstore-sdk/src/errors.ts | 2 + packages/vecstore-sdk/src/filter/pgvector.ts | 18 ++++ packages/vecstore-sdk/src/filter/pinecone.ts | 16 ++++ packages/vecstore-sdk/src/filter/qdrant.ts | 18 ++++ packages/vecstore-sdk/src/filter/upstash.ts | 22 +++++ packages/vecstore-sdk/src/filter/vectorize.ts | 29 ++++++ packages/vecstore-sdk/src/index.ts | 5 ++ .../vecstore-sdk/src/internal/collections.ts | 16 ++++ .../src/internal/delete-selector.ts | 3 + packages/vecstore-sdk/src/internal/filter.ts | 14 +++ .../vecstore-sdk/src/internal/metadata.ts | 1 + packages/vecstore-sdk/src/internal/network.ts | 1 + .../vecstore-sdk/src/internal/postgres.ts | 15 ++++ .../src/internal/query-options.ts | 1 + packages/vecstore-sdk/src/internal/uuid.ts | 2 + packages/vecstore-sdk/src/pgvector/index.ts | 55 ++++++++++++ packages/vecstore-sdk/src/pinecone/index.ts | 24 +++++ packages/vecstore-sdk/src/qdrant/index.ts | 44 +++++++++ packages/vecstore-sdk/src/redis/index.ts | 89 +++++++++++++++++++ packages/vecstore-sdk/src/supabase/index.ts | 19 ++++ packages/vecstore-sdk/src/upstash/index.ts | 73 +++++++++++++++ packages/vecstore-sdk/src/vectorize/index.ts | 48 ++++++++++ .../test/adapters/pgvector.test.ts | 30 +++++++ .../test/adapters/pinecone.test.ts | 33 +++++++ .../vecstore-sdk/test/adapters/qdrant.test.ts | 42 +++++++++ .../vecstore-sdk/test/adapters/redis.test.ts | 49 ++++++++++ .../test/adapters/supabase.test.ts | 38 ++++++++ .../test/adapters/upstash.test.ts | 69 ++++++++++++++ .../test/adapters/vectorize.test.ts | 50 +++++++++++ .../vecstore-sdk/test/filter/pgvector.test.ts | 1 + .../vecstore-sdk/test/filter/qdrant.test.ts | 2 + .../vecstore-sdk/test/filter/redis.test.ts | 2 + .../vecstore-sdk/test/filter/upstash.test.ts | 1 + .../test/filter/vectorize.test.ts | 2 + packages/vecstore-sdk/test/internal.test.ts | 11 +++ .../vecstore-sdk/test/live/conformance.ts | 25 +++++- .../test/live/pgvector-live.test.ts | 1 + .../vecstore-sdk/test/live/redis-live.test.ts | 5 ++ .../test/live/supabase-live.test.ts | 1 + .../test/live/vectorize-live.test.ts | 1 + .../test/postgres/filter-differential.test.ts | 6 ++ packages/vecstore-sdk/test/postgres/pglite.ts | 2 + .../test/postgres/pgvector.test.ts | 21 +++++ .../test/postgres/supabase.test.ts | 32 +++++++ scripts/glyph-path.ts | 4 + scripts/render-hero.ts | 11 +++ scripts/render-logo.ts | 14 +++ scripts/render-provider-marks.ts | 14 +++ scripts/render-web-icons.ts | 21 +++++ 66 files changed, 1124 insertions(+), 3 deletions(-) diff --git a/apps/web/app/changelog/rss.xml/route.ts b/apps/web/app/changelog/rss.xml/route.ts index 240f3e6..0fc6400 100644 --- a/apps/web/app/changelog/rss.xml/route.ts +++ b/apps/web/app/changelog/rss.xml/route.ts @@ -12,6 +12,7 @@ const escapeXml = (value: string): string => const handler = () => { const entries = getChangelogEntries(); + const items = entries .map( (entry) => ` @@ -23,6 +24,7 @@ const handler = () => { ` ) .join("\n"); + const lastBuildDate = entries[0]?.data.date.toUTCString() ?? ""; const feed = ` diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index a08b6a2..f104fb2 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -8,6 +8,7 @@ import { fonts } from "@/lib/fonts"; import { url } from "@/lib/url"; const siteName = "VecStore SDK"; + const siteDescription = "A unified vector store SDK for TypeScript. One filter language across Qdrant, pgvector, Pinecone, Supabase, Upstash Vector, Cloudflare Vectorize, and Redis, so you can switch providers without rewriting queries."; diff --git a/apps/web/app/llms.txt/route.ts b/apps/web/app/llms.txt/route.ts index 9cdf0fc..3e37531 100644 --- a/apps/web/app/llms.txt/route.ts +++ b/apps/web/app/llms.txt/route.ts @@ -5,6 +5,7 @@ export const revalidate = false; const handler = async () => { const pages = await Promise.all(source.getPages().map(getLLMText)); + return new Response(pages.join("\n\n"), { headers: { "Content-Type": "text/plain" }, }); diff --git a/apps/web/app/og/docs/[...slug]/route.ts b/apps/web/app/og/docs/[...slug]/route.ts index a97ece4..55bfc61 100644 --- a/apps/web/app/og/docs/[...slug]/route.ts +++ b/apps/web/app/og/docs/[...slug]/route.ts @@ -13,10 +13,12 @@ const backgrounds = path.join(process.cwd(), "app", "og", "docs", "[...slug]"); const readBackground = (slugs: readonly string[]) => { const [group, name] = slugs; + const provider = group === "providers" && providerIds.some((id) => id === name) ? name : undefined; + const file = provider ? `background-${provider}.png` : "background.png"; return readFile(path.join(backgrounds, file)); diff --git a/apps/web/components/brand-menu.tsx b/apps/web/components/brand-menu.tsx index 528c3f3..c6530fe 100644 --- a/apps/web/components/brand-menu.tsx +++ b/apps/web/components/brand-menu.tsx @@ -15,15 +15,19 @@ const MENU_GAP = 8; const serialize = (svg: SVGSVGElement): string => { const clone = svg.cloneNode(true); + if (!(clone instanceof SVGSVGElement)) { return ""; } + const ink = document.documentElement.classList.contains("dark") ? "#ededed" : "#171717"; + clone.removeAttribute("class"); clone.removeAttribute("aria-hidden"); clone.setAttribute("xmlns", "http://www.w3.org/2000/svg"); + return new XMLSerializer() .serializeToString(clone) .replaceAll("currentColor", ink); @@ -44,7 +48,9 @@ const CopyTile = ({ if (status === "idle") { return; } + const timer = window.setTimeout(() => setStatus("idle"), COPIED_MS); + return () => window.clearTimeout(timer); }, [status]); @@ -53,9 +59,11 @@ const CopyTile = ({ className="text-gray-1000 hover:bg-gray-alpha-100 flex min-w-0 flex-col gap-2 rounded-md p-2 text-left text-[14px] transition-colors" onClick={async (event) => { event.stopPropagation(); + if (!svgRef.current) { return; } + try { await navigator.clipboard.writeText(serialize(svgRef.current)); setStatus("copied"); @@ -98,18 +106,23 @@ export const BrandMenu = ({ children }: { readonly children: ReactNode }) => { useEffect(() => { const anchor = anchorRef.current?.closest("a") ?? anchorRef.current; + if (!anchor) { return; } + anchor.setAttribute("aria-haspopup", "menu"); anchor.setAttribute("aria-controls", menuId); + const handle = (event: Event) => { event.preventDefault(); const rect = anchor.getBoundingClientRect(); setPosition({ left: rect.left, top: rect.bottom + MENU_GAP }); setOpen(true); }; + anchor.addEventListener("contextmenu", handle); + return () => anchor.removeEventListener("contextmenu", handle); }, [menuId]); @@ -122,11 +135,14 @@ export const BrandMenu = ({ children }: { readonly children: ReactNode }) => { if (!open) { return; } + menuRef.current?.querySelector("[role=menuitem]")?.focus(); + const close = (event: Event) => { if (event instanceof KeyboardEvent && event.key !== "Escape") { return; } + if ( event instanceof PointerEvent && event.target instanceof Node && @@ -134,11 +150,14 @@ export const BrandMenu = ({ children }: { readonly children: ReactNode }) => { ) { return; } + setOpen(false); (anchorRef.current?.closest("a") ?? anchorRef.current)?.focus(); }; + document.addEventListener("keydown", close); document.addEventListener("pointerdown", close); + return () => { document.removeEventListener("keydown", close); document.removeEventListener("pointerdown", close); @@ -148,34 +167,44 @@ export const BrandMenu = ({ children }: { readonly children: ReactNode }) => { const moveFocus = (event: KeyboardEvent) => { if (event.key === "Tab") { setOpen(false); + return; } + const items = [ ...(menuRef.current?.querySelectorAll("[role=menuitem]") ?? []), ]; + const active = document.activeElement; const index = active instanceof HTMLElement ? items.indexOf(active) : -1; + const resolveTarget = (): HTMLElement | undefined => { switch (event.key) { case "ArrowDown": { return items.at((index + 1) % items.length); } + case "ArrowUp": { return items.at((index - 1 + items.length) % items.length); } + case "End": { return items.at(-1); } + case "Home": { return items[0]; } + default: { return undefined; } } }; + const target = resolveTarget(); + if (target) { event.preventDefault(); target.focus(); diff --git a/apps/web/components/docs/sidebar-items.tsx b/apps/web/components/docs/sidebar-items.tsx index a46869c..dcee151 100644 --- a/apps/web/components/docs/sidebar-items.tsx +++ b/apps/web/components/docs/sidebar-items.tsx @@ -24,16 +24,19 @@ const containsPath = ( if (node.type === "page") { return node.url === pathname; } + if (node.type === "folder") { return ( node.index?.url === pathname || containsPath(node.children, pathname) ); } + return false; }); export const Item = ({ item }: { readonly item: PageTreeItem }) => { const pathname = usePathname(); + return ( navigator.clipboard.writeText(command) ); + const Icon = copied ? CheckIcon : CopyIcon; return ( diff --git a/apps/web/components/landing/demo.tsx b/apps/web/components/landing/demo.tsx index 44b5195..55b94e0 100644 --- a/apps/web/components/landing/demo.tsx +++ b/apps/web/components/landing/demo.tsx @@ -47,6 +47,7 @@ export const Demo = async () => { await renderCode(provider.snippet(example.filterCode)), ]) ); + return { code: Object.fromEntries(entries), expression: example.expression, @@ -56,6 +57,7 @@ export const Demo = async () => { }; }) ); + const providers = demoProviders.map(({ id, label }) => ({ id, label })); return ; diff --git a/apps/web/components/landing/hero-demo.tsx b/apps/web/components/landing/hero-demo.tsx index e6c6ca1..fd1628f 100644 --- a/apps/web/components/landing/hero-demo.tsx +++ b/apps/web/components/landing/hero-demo.tsx @@ -52,15 +52,19 @@ export const HeroDemo = ({ providers, examples }: HeroDemoProps) => { useLayoutEffect(() => { const measure = () => { const tab = tabRefs.current[exampleIndex]; + if (tab) { setIndicator({ left: tab.offsetLeft, width: tab.offsetWidth }); } }; + measure(); const observer = new ResizeObserver(measure); + if (listRef.current) { observer.observe(listRef.current); } + return () => observer.disconnect(); }, [exampleIndex]); const example = examples[exampleIndex] ?? examples[0]; @@ -77,6 +81,7 @@ export const HeroDemo = ({ providers, examples }: HeroDemoProps) => { const selectProvider = (id: string) => { const index = providers.findIndex((item) => item.id === id); + if (index !== -1) { setProviderIndex(index); } @@ -103,6 +108,7 @@ export const HeroDemo = ({ providers, examples }: HeroDemoProps) => { /> {examples.map((item, index) => { const active = index === exampleIndex; + return (