From 21a1eba53b167831ab52416a7007a3fc4537d4e6 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Fri, 28 Nov 2025 07:31:57 +0800 Subject: [PATCH 01/13] update to latest vitest (#447) --- .vscode/extensions.json | 2 +- .vscode/settings.json | 4 +- package.json | 3 +- pnpm-lock.yaml | 335 ++++++++++++---------------------------- 4 files changed, 107 insertions(+), 237 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c8dffa941..551612d21 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,5 +3,5 @@ // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp // List of extensions which should be recommended for users of this workspace. - "recommendations": ["langium.langium-vscode", "kingwl.vscode-vitest-runner"] + "recommendations": ["langium.langium-vscode", "vitest.explorer"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 0967ef424..6c4c331ee 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1 +1,3 @@ -{} +{ + "vitest.maximumConfigs": 20 +} diff --git a/package.json b/package.json index 45ad32521..1aa1ebedd 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "3.0.0-beta.26", "description": "ZenStack", "packageManager": "pnpm@10.23.0", + "type": "module", "scripts": { "build": "turbo run build", "watch": "turbo run watch build", @@ -31,7 +32,7 @@ "turbo": "^2.5.4", "typescript": "catalog:", "typescript-eslint": "^8.34.1", - "vitest": "^3.2.4", + "vitest": "^4.0.14", "yaml": "^2.8.0" }, "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e1199a79..35ce119e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,8 +114,8 @@ importers: specifier: ^8.34.1 version: 8.34.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3) vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) + specifier: ^4.0.14 + version: 4.0.14(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) yaml: specifier: ^2.8.0 version: 2.8.0 @@ -3210,34 +3210,34 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vue: ^3.2.25 - '@vitest/expect@3.2.4': - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@4.0.14': + resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + '@vitest/mocker@4.0.14': + resolution: {integrity: sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@3.2.4': - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/pretty-format@4.0.14': + resolution: {integrity: sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==} - '@vitest/runner@3.2.4': - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + '@vitest/runner@4.0.14': + resolution: {integrity: sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==} - '@vitest/snapshot@3.2.4': - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + '@vitest/snapshot@4.0.14': + resolution: {integrity: sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==} - '@vitest/spy@3.2.4': - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@4.0.14': + resolution: {integrity: sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==} - '@vitest/utils@3.2.4': - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@4.0.14': + resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==} '@volar/language-core@2.4.23': resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==} @@ -3464,10 +3464,6 @@ packages: resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} engines: {node: '>=12.0.0'} - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - ast-kit@2.1.3: resolution: {integrity: sha512-TH+b3Lv6pUjy/Nu0m6A2JULtdzLpmqF9x1Dhj00ZoEiML8qvVA9j1flkzTKNYgdEhWrjDwtWNpyyCUbfQe514g==} engines: {node: '>=20.19.0'} @@ -3686,9 +3682,9 @@ packages: caniuse-lite@1.0.30001751: resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} - chai@5.2.0: - resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} - engines: {node: '>=12'} + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + engines: {node: '>=18'} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -3698,10 +3694,6 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} - chevrotain-allstar@0.3.1: resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} peerDependencies: @@ -4019,10 +4011,6 @@ packages: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -4430,8 +4418,8 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - expect-type@1.2.1: - resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} express@5.1.0: @@ -5342,9 +5330,6 @@ packages: engines: {node: '>= 8.x', npm: '>= 5.x'} hasBin: true - loupe@3.1.4: - resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -5705,6 +5690,9 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + ofetch@1.5.0: resolution: {integrity: sha512-A7llJ7eZyziA5xq9//3ZurA8OhFqtS99K5/V1sLBJ5j137CM/OAjlbA/TEJXBuOWwOfLqih+oH5U3ran4za1FQ==} @@ -5852,10 +5840,6 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.0: - resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} - engines: {node: '>= 14.16'} - perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} @@ -6663,9 +6647,6 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -6741,9 +6722,6 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} - strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} @@ -6881,16 +6859,8 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - - tinyspy@4.0.3: - resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} tldts-core@7.0.17: @@ -7333,46 +7303,6 @@ packages: vite: ^6.0.0 || ^7.0.0 vue: ^3.5.0 - vite@6.3.5: - resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - vite@7.1.12: resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7421,26 +7351,32 @@ packages: vite: optional: true - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vitest@4.0.14: + resolution: {integrity: sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.14 + '@vitest/browser-preview': 4.0.14 + '@vitest/browser-webdriverio': 4.0.14 + '@vitest/ui': 4.0.14 happy-dom: '*' jsdom: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@types/debug': + '@opentelemetry/api': optional: true '@types/node': optional: true - '@vitest/browser': + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': optional: true '@vitest/ui': optional: true @@ -9157,10 +9093,10 @@ snapshots: '@rollup/pluginutils': 5.3.0(rollup@4.52.5) commondir: 1.0.1 estree-walker: 2.0.2 - fdir: 6.4.6(picomatch@4.0.2) + fdir: 6.5.0(picomatch@4.0.3) is-reference: 1.2.1 magic-string: 0.30.21 - picomatch: 4.0.2 + picomatch: 4.0.3 optionalDependencies: rollup: 4.52.5 @@ -9207,7 +9143,7 @@ snapshots: dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 4.0.3 optionalDependencies: rollup: 4.52.5 @@ -9992,7 +9928,7 @@ snapshots: glob: 10.4.5 graceful-fs: 4.2.11 node-gyp-build: 4.8.4 - picomatch: 4.0.2 + picomatch: 4.0.3 resolve-from: 5.0.0 transitivePeerDependencies: - encoding @@ -10017,47 +9953,44 @@ snapshots: vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1) vue: 3.5.22(typescript@5.9.3) - '@vitest/expect@3.2.4': + '@vitest/expect@4.0.14': dependencies: + '@standard-schema/spec': 1.0.0 '@types/chai': 5.2.2 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.2.0 - tinyrainbow: 2.0.0 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 + chai: 6.2.1 + tinyrainbow: 3.0.3 - '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0))': + '@vitest/mocker@4.0.14(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0))': dependencies: - '@vitest/spy': 3.2.4 + '@vitest/spy': 4.0.14 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.21 optionalDependencies: - vite: 6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) + vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) - '@vitest/pretty-format@3.2.4': + '@vitest/pretty-format@4.0.14': dependencies: - tinyrainbow: 2.0.0 + tinyrainbow: 3.0.3 - '@vitest/runner@3.2.4': + '@vitest/runner@4.0.14': dependencies: - '@vitest/utils': 3.2.4 + '@vitest/utils': 4.0.14 pathe: 2.0.3 - strip-literal: 3.0.0 - '@vitest/snapshot@3.2.4': + '@vitest/snapshot@4.0.14': dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.17 + '@vitest/pretty-format': 4.0.14 + magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@3.2.4': - dependencies: - tinyspy: 4.0.3 + '@vitest/spy@4.0.14': {} - '@vitest/utils@3.2.4': + '@vitest/utils@4.0.14': dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.1.4 - tinyrainbow: 2.0.0 + '@vitest/pretty-format': 4.0.14 + tinyrainbow: 3.0.3 '@volar/language-core@2.4.23': dependencies: @@ -10376,8 +10309,6 @@ snapshots: pvutils: 1.1.5 tslib: 2.8.1 - assertion-error@2.0.1: {} - ast-kit@2.1.3: dependencies: '@babel/parser': 7.28.5 @@ -10627,13 +10558,7 @@ snapshots: caniuse-lite@1.0.30001751: {} - chai@5.2.0: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.1.4 - pathval: 2.0.0 + chai@6.2.1: {} chalk@4.1.2: dependencies: @@ -10642,8 +10567,6 @@ snapshots: chalk@5.3.0: {} - check-error@2.1.1: {} - chevrotain-allstar@0.3.1(chevrotain@11.0.3): dependencies: chevrotain: 11.0.3 @@ -10929,8 +10852,6 @@ snapshots: dependencies: mimic-response: 3.1.0 - deep-eql@5.0.2: {} - deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -11254,7 +11175,7 @@ snapshots: eslint: 9.29.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.29.0(jiti@2.6.1)) @@ -11287,7 +11208,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -11302,7 +11223,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -11509,7 +11430,7 @@ snapshots: expand-template@2.0.3: {} - expect-type@1.2.1: {} + expect-type@1.2.2: {} express@5.1.0: dependencies: @@ -12494,8 +12415,6 @@ snapshots: dependencies: commander: 9.5.0 - loupe@3.1.4: {} - lru-cache@10.4.3: {} lru-cache@11.1.0: {} @@ -13016,6 +12935,8 @@ snapshots: obuf@1.1.2: {} + obug@2.1.1: {} + ofetch@1.5.0: dependencies: destr: 2.0.5 @@ -13211,8 +13132,6 @@ snapshots: pathe@2.0.3: {} - pathval@2.0.0: {} - perfect-debounce@1.0.0: {} perfect-debounce@2.0.0: {} @@ -13746,7 +13665,7 @@ snapshots: rollup-plugin-visualizer@6.0.5(rollup@4.52.5): dependencies: open: 8.4.2 - picomatch: 4.0.2 + picomatch: 4.0.3 source-map: 0.7.6 yargs: 17.7.2 optionalDependencies: @@ -14076,8 +13995,6 @@ snapshots: std-env@3.10.0: {} - std-env@3.9.0: {} - stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -14182,10 +14099,6 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@3.0.0: - dependencies: - js-tokens: 9.0.1 - strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 @@ -14365,11 +14278,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinypool@1.1.1: {} - - tinyrainbow@2.0.0: {} - - tinyspy@4.0.3: {} + tinyrainbow@3.0.3: {} tldts-core@7.0.17: optional: true @@ -14776,34 +14685,13 @@ snapshots: dependencies: vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1) - vite-node@3.2.4(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0): - dependencies: - cac: 6.7.14 - debug: 4.4.1 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - vite-node@3.2.4(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1) + vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -14861,14 +14749,14 @@ snapshots: vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1) vue: 3.5.22(typescript@5.9.3) - vite@6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0): + vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0): dependencies: - esbuild: 0.25.5 - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 + esbuild: 0.25.11 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.44.0 - tinyglobby: 0.2.14 + rollup: 4.52.5 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 20.19.24 fsevents: 2.3.3 @@ -14878,30 +14766,13 @@ snapshots: tsx: 4.20.3 yaml: 2.8.0 - vite@6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1): - dependencies: - esbuild: 0.25.5 - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 - postcss: 8.5.6 - rollup: 4.44.0 - tinyglobby: 0.2.14 - optionalDependencies: - '@types/node': 20.19.24 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - terser: 5.44.0 - tsx: 4.20.3 - yaml: 2.8.1 - vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1): dependencies: esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.44.0 + rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 20.19.24 @@ -14916,30 +14787,27 @@ snapshots: optionalDependencies: vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1) - vitest@3.2.4(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0): + vitest@4.0.14(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0): dependencies: - '@types/chai': 5.2.2 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.2.0 - debug: 4.4.1 - expect-type: 1.2.1 - magic-string: 0.30.17 + '@vitest/expect': 4.0.14 + '@vitest/mocker': 4.0.14(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0)) + '@vitest/pretty-format': 4.0.14 + '@vitest/runner': 4.0.14 + '@vitest/snapshot': 4.0.14 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 + obug: 2.1.1 pathe: 2.0.3 - picomatch: 4.0.2 - std-env: 3.9.0 + picomatch: 4.0.3 + std-env: 3.10.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) - vite-node: 3.2.4(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.19.24 @@ -14954,7 +14822,6 @@ snapshots: - sass-embedded - stylus - sugarss - - supports-color - terser - tsx - yaml From a9ff7e46cec8f108f106a396487ade3cd33d9020 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Fri, 28 Nov 2025 09:19:38 +0800 Subject: [PATCH 02/13] chore: bump vscode version (#448) --- packages/ide/vscode/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ide/vscode/package.json b/packages/ide/vscode/package.json index c6d12348e..bfaf079c9 100644 --- a/packages/ide/vscode/package.json +++ b/packages/ide/vscode/package.json @@ -1,7 +1,7 @@ { "name": "zenstack-v3", "publisher": "zenstack", - "version": "3.0.13", + "version": "3.0.14", "displayName": "ZenStack V3 Language Tools", "description": "VSCode extension for ZenStack (v3) ZModel language", "private": true, From 97a03d414fc4d9a9dcbe3fd8ce3d753263a3cc2d Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Sat, 29 Nov 2025 06:48:08 +0800 Subject: [PATCH 03/13] fix(orm): correcting timezone for Date returned in nested queries (#450) * fix(orm): correcting timezone for Date returned in nested queries * Update packages/orm/src/client/crud/dialects/postgresql.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/orm/src/client/crud/dialects/postgresql.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/orm/src/client/crud/dialects/postgresql.ts b/packages/orm/src/client/crud/dialects/postgresql.ts index 660356dd8..50a9eb606 100644 --- a/packages/orm/src/client/crud/dialects/postgresql.ts +++ b/packages/orm/src/client/crud/dialects/postgresql.ts @@ -106,7 +106,10 @@ export class PostgresCrudDialect extends BaseCrudDiale private transformOutputDate(value: unknown) { if (typeof value === 'string') { - return new Date(value); + // PostgreSQL's jsonb_build_object serializes timestamptz as ISO 8601 strings + // in UTC but without the 'Z' suffix (e.g., "2023-01-01T12:00:00.123456"). + // We add 'Z' to explicitly mark them as UTC for correct Date object creation. + return new Date(value.endsWith('Z') ? value : `${value}Z`); } else if (value instanceof Date && this.options.fixPostgresTimezone !== false) { // SPECIAL NOTES: // node-pg has a terrible quirk that it returns the date value in local timezone From ba08669231a83a601df3a7802127dc2827794bdf Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Sun, 30 Nov 2025 08:38:06 +0800 Subject: [PATCH 04/13] chore(zmodel): add warning for removing "generator" block (#451) --- packages/language/src/validator.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/language/src/validator.ts b/packages/language/src/validator.ts index efbc37944..dcbf549f0 100644 --- a/packages/language/src/validator.ts +++ b/packages/language/src/validator.ts @@ -6,6 +6,7 @@ import type { Enum, Expression, FunctionDecl, + GeneratorDecl, InvocationExpr, Model, TypeDef, @@ -31,6 +32,7 @@ export function registerValidationChecks(services: ZModelServices) { const checks: ValidationChecks = { Model: validator.checkModel, DataSource: validator.checkDataSource, + GeneratorDecl: validator.checkGenerator, DataModel: validator.checkDataModel, TypeDef: validator.checkTypeDef, Enum: validator.checkEnum, @@ -56,6 +58,10 @@ export class ZModelValidator { new DataSourceValidator().validate(node, accept); } + checkGenerator(node: GeneratorDecl, accept: ValidationAcceptor): void { + accept('warning', '"generator" is not used by ZenStack and should be removed.', { node }); + } + checkDataModel(node: DataModel, accept: ValidationAcceptor): void { new DataModelValidator().validate(node, accept); } From c0092460f04ecda0f36bee8be931a194b249a06e Mon Sep 17 00:00:00 2001 From: Mike Willbanks Date: Sun, 30 Nov 2025 17:36:37 -0600 Subject: [PATCH 05/13] fix: elysia should utilize ctx.query vs. request.searchParams (#452) * The standard way to access request query parameters is through ctx.query, not request.searchParams. * request.searchParams can be utilized but generally elysia utilizes ctx.query, unfortunately, they are not synchronized but ctx.query is generally where you would derive additional fields vs. request.searchParams. --- packages/server/src/adapter/elysia/handler.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/server/src/adapter/elysia/handler.ts b/packages/server/src/adapter/elysia/handler.ts index 330465d22..5104e50c4 100644 --- a/packages/server/src/adapter/elysia/handler.ts +++ b/packages/server/src/adapter/elysia/handler.ts @@ -25,7 +25,7 @@ export interface ElysiaOptions extends CommonAdapterOp export function createElysiaHandler(options: ElysiaOptions) { return async (app: Elysia) => { app.all('/*', async (ctx: ElysiaContext) => { - const { request, body, set } = ctx; + const { query, body, set, request } = ctx; const client = await options.getClient(ctx); if (!client) { set.status = 500; @@ -35,7 +35,6 @@ export function createElysiaHandler(options: ElysiaOpt } const url = new URL(request.url); - const query = Object.fromEntries(url.searchParams); let path = url.pathname; if (options.basePath && path.startsWith(options.basePath)) { From 3406956fb73104f5b15beefa9b923ef10351fd03 Mon Sep 17 00:00:00 2001 From: Eugen Istoc Date: Sun, 30 Nov 2025 19:19:55 -0500 Subject: [PATCH 06/13] fix(server): app aliases are not allowed in server runtime (#453) * fix(server): nuxt handler should import `setResponseStatus` from `h3` * chore(server): import H3Event as a type --- packages/server/src/adapter/nuxt/handler.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/server/src/adapter/nuxt/handler.ts b/packages/server/src/adapter/nuxt/handler.ts index c1c2efcd7..9f17b0e54 100644 --- a/packages/server/src/adapter/nuxt/handler.ts +++ b/packages/server/src/adapter/nuxt/handler.ts @@ -1,7 +1,14 @@ import type { ClientContract } from '@zenstackhq/orm'; import type { SchemaDef } from '@zenstackhq/orm/schema'; -import { H3Event, defineEventHandler, getQuery, getRouterParams, readBody, type EventHandlerRequest } from 'h3'; -import { setResponseStatus } from 'nuxt/app'; +import { + defineEventHandler, + getQuery, + getRouterParams, + readBody, + setResponseStatus, + type H3Event, + type EventHandlerRequest, +} from 'h3'; import { logInternalError, type CommonAdapterOptions } from '../common'; /** From 108a9996f27b130cdab2bb308460d5f8547233ec Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Mon, 1 Dec 2025 14:57:19 +0800 Subject: [PATCH 07/13] fix: isomorphic __dirname in CI (#454) --- scripts/bump-version.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/bump-version.ts b/scripts/bump-version.ts index 53057d4a5..5fdda3fd1 100644 --- a/scripts/bump-version.ts +++ b/scripts/bump-version.ts @@ -2,9 +2,12 @@ import * as fs from 'node:fs'; import { glob } from 'glob'; import * as path from 'node:path'; import * as yaml from 'yaml'; +import { fileURLToPath } from 'node:url'; const excludes = ['packages/ide/vscode/package.json']; +const _dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); + function getWorkspacePackageJsonFiles(workspaceFile: string): string[] { const workspaceYaml = fs.readFileSync(workspaceFile, 'utf8'); const workspace = yaml.parse(workspaceYaml) as { packages?: string[] }; @@ -23,7 +26,7 @@ function getWorkspacePackageJsonFiles(workspaceFile: string): string[] { } // include root package.json - files.add(path.resolve(__dirname, '../package.json')); + files.add(path.resolve(_dirname, '../package.json')); const result = Array.from(files).filter((f) => !excludes.some((e) => f.endsWith(e))); return result; @@ -39,11 +42,11 @@ function incrementVersion(version: string): string { } // find all package.json files in the workspace -const workspaceFile = path.resolve(__dirname, '../pnpm-workspace.yaml'); +const workspaceFile = path.resolve(_dirname, '../pnpm-workspace.yaml'); const packageFiles = getWorkspacePackageJsonFiles(workspaceFile); // get version from root package.json -const rootPackageJson = path.resolve(__dirname, '../package.json'); +const rootPackageJson = path.resolve(_dirname, '../package.json'); const rootPkg = JSON.parse(fs.readFileSync(rootPackageJson, 'utf8')) as { version?: string }; if (!rootPkg.version) throw new Error('No "version" key found in package.json'); const rootVersion = rootPkg.version; From 09dabd8387861dff1d5b8f94a7b494782c089ecf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 15:08:01 +0800 Subject: [PATCH 08/13] chore: bump version 3.0.0-beta.27 (#455) Co-authored-by: ymc9 <104139426+ymc9@users.noreply.github.com> --- package.json | 2 +- packages/auth-adapters/better-auth/package.json | 2 +- packages/cli/package.json | 2 +- packages/clients/tanstack-query/package.json | 2 +- packages/common-helpers/package.json | 2 +- packages/config/eslint-config/package.json | 2 +- packages/config/typescript-config/package.json | 2 +- packages/config/vitest-config/package.json | 2 +- packages/create-zenstack/package.json | 2 +- packages/language/package.json | 2 +- packages/orm/package.json | 2 +- packages/plugins/policy/package.json | 2 +- packages/schema/package.json | 2 +- packages/sdk/package.json | 2 +- packages/server/package.json | 2 +- packages/testtools/package.json | 2 +- packages/zod/package.json | 2 +- samples/next.js/package.json | 2 +- samples/orm/package.json | 2 +- tests/e2e/package.json | 2 +- tests/regression/package.json | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 1aa1ebedd..2418e326e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-v3", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack", "packageManager": "pnpm@10.23.0", "type": "module", diff --git a/packages/auth-adapters/better-auth/package.json b/packages/auth-adapters/better-auth/package.json index 91b1878ef..115219a24 100644 --- a/packages/auth-adapters/better-auth/package.json +++ b/packages/auth-adapters/better-auth/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/better-auth", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack Better Auth Adapter. This adapter is modified from better-auth's Prisma adapter.", "type": "module", "scripts": { diff --git a/packages/cli/package.json b/packages/cli/package.json index 533a91cc2..3f6ce268c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -3,7 +3,7 @@ "publisher": "zenstack", "displayName": "ZenStack CLI", "description": "FullStack database toolkit with built-in access control and automatic API generation.", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "type": "module", "author": { "name": "ZenStack Team" diff --git a/packages/clients/tanstack-query/package.json b/packages/clients/tanstack-query/package.json index e00100f03..6e14662dc 100644 --- a/packages/clients/tanstack-query/package.json +++ b/packages/clients/tanstack-query/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/tanstack-query", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "TanStack Query Client for consuming ZenStack v3's CRUD service", "main": "index.js", "type": "module", diff --git a/packages/common-helpers/package.json b/packages/common-helpers/package.json index 3020e8dcf..1654b58d4 100644 --- a/packages/common-helpers/package.json +++ b/packages/common-helpers/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/common-helpers", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack Common Helpers", "type": "module", "scripts": { diff --git a/packages/config/eslint-config/package.json b/packages/config/eslint-config/package.json index f95ca2fd5..6a6c3bf43 100644 --- a/packages/config/eslint-config/package.json +++ b/packages/config/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/eslint-config", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "type": "module", "private": true, "license": "MIT" diff --git a/packages/config/typescript-config/package.json b/packages/config/typescript-config/package.json index 5e4aa3bdf..3cc4bfe1a 100644 --- a/packages/config/typescript-config/package.json +++ b/packages/config/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/typescript-config", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "private": true, "license": "MIT" } diff --git a/packages/config/vitest-config/package.json b/packages/config/vitest-config/package.json index 9e3f0c478..f34377268 100644 --- a/packages/config/vitest-config/package.json +++ b/packages/config/vitest-config/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/vitest-config", "type": "module", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "private": true, "license": "MIT", "exports": { diff --git a/packages/create-zenstack/package.json b/packages/create-zenstack/package.json index a17ebb751..216a99c3b 100644 --- a/packages/create-zenstack/package.json +++ b/packages/create-zenstack/package.json @@ -1,6 +1,6 @@ { "name": "create-zenstack", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "Create a new ZenStack project", "type": "module", "scripts": { diff --git a/packages/language/package.json b/packages/language/package.json index 574386360..e5a45c95f 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/language", "description": "ZenStack ZModel language specification", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "license": "MIT", "author": "ZenStack Team", "files": [ diff --git a/packages/orm/package.json b/packages/orm/package.json index 40250acde..0312e8abe 100644 --- a/packages/orm/package.json +++ b/packages/orm/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/orm", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack ORM", "type": "module", "scripts": { diff --git a/packages/plugins/policy/package.json b/packages/plugins/policy/package.json index 16d7952aa..66348a854 100644 --- a/packages/plugins/policy/package.json +++ b/packages/plugins/policy/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/plugin-policy", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack Policy Plugin", "type": "module", "scripts": { diff --git a/packages/schema/package.json b/packages/schema/package.json index 104377100..dabb3d566 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/schema", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack Runtime Schema", "type": "module", "scripts": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 19f49a234..5ff02b7db 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack SDK", "type": "module", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 8ba75d412..435584429 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack automatic CRUD API handlers and server adapters", "type": "module", "scripts": { diff --git a/packages/testtools/package.json b/packages/testtools/package.json index bbae04306..453852c10 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "ZenStack Test Tools", "type": "module", "scripts": { diff --git a/packages/zod/package.json b/packages/zod/package.json index 0466d07d0..03b734a0e 100644 --- a/packages/zod/package.json +++ b/packages/zod/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/zod", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "", "type": "module", "main": "index.js", diff --git a/samples/next.js/package.json b/samples/next.js/package.json index 67db4521d..a1f7b3791 100644 --- a/samples/next.js/package.json +++ b/samples/next.js/package.json @@ -1,6 +1,6 @@ { "name": "next.js", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "private": true, "scripts": { "generate": "zen generate --lite", diff --git a/samples/orm/package.json b/samples/orm/package.json index 8a4663f41..11a29f8a7 100644 --- a/samples/orm/package.json +++ b/samples/orm/package.json @@ -1,6 +1,6 @@ { "name": "sample-blog", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "description": "", "main": "index.js", "private": true, diff --git a/tests/e2e/package.json b/tests/e2e/package.json index f023e5071..38625d7c0 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -1,6 +1,6 @@ { "name": "e2e", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "private": true, "type": "module", "scripts": { diff --git a/tests/regression/package.json b/tests/regression/package.json index af00968ab..f4a4c8ff2 100644 --- a/tests/regression/package.json +++ b/tests/regression/package.json @@ -1,6 +1,6 @@ { "name": "regression", - "version": "3.0.0-beta.26", + "version": "3.0.0-beta.27", "private": true, "type": "module", "scripts": { From 61719d5d487b993ebb0de9932f64583ff4268e54 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Mon, 1 Dec 2025 20:54:26 +0800 Subject: [PATCH 09/13] chore(cli): suppress prisma update message (#456) * chore(cli): suppress prisma update message * update --- packages/cli/src/utils/exec-utils.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/utils/exec-utils.ts b/packages/cli/src/utils/exec-utils.ts index 0e4ad3edf..03629f628 100644 --- a/packages/cli/src/utils/exec-utils.ts +++ b/packages/cli/src/utils/exec-utils.ts @@ -43,11 +43,19 @@ export function execPrisma(args: string, options?: Omit // ignore and fallback } + const _options = { + ...options, + env: { + ...options?.env, + PRISMA_HIDE_UPDATE_MESSAGE: '1', + }, + }; + if (!prismaPath) { // fallback to npx/bunx execute - execPackage(`prisma ${args}`, options); + execPackage(`prisma ${args}`, _options); return; } - execSync(`node ${prismaPath} ${args}`, options); + execSync(`node ${prismaPath} ${args}`, _options); } From 3c22e342ab8fefde15ec172bb15d01ae0e4b9db7 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Tue, 2 Dec 2025 06:42:29 +0800 Subject: [PATCH 10/13] test(bun): basic e2e tests (#457) * test(bun): basic e2e tests * update CI * update * update * update --- .github/workflows/build-test.yml | 5 + package.json | 2 +- packages/testtools/src/client.ts | 9 +- pnpm-lock.yaml | 96 +++++++++--- pnpm-workspace.yaml | 39 ++--- tests/bun/e2e.test.ts | 113 +++++++++++++++ tests/bun/package.json | 27 ++++ tests/bun/schemas/input.ts | 50 +++++++ tests/bun/schemas/models.ts | 14 ++ tests/bun/schemas/schema.ts | 177 +++++++++++++++++++++++ tests/bun/schemas/schema.zmodel | 46 ++++++ tests/bun/scripts/generate.ts | 20 +++ tests/bun/tsconfig.json | 8 + tests/e2e/package.json | 1 - tests/regression/package.json | 3 +- tests/regression/test/issue-204/input.ts | 4 +- tests/regression/test/issue-422/input.ts | 8 +- tests/regression/tsconfig.json | 2 +- turbo.json | 6 +- 19 files changed, 574 insertions(+), 56 deletions(-) create mode 100644 tests/bun/e2e.test.ts create mode 100644 tests/bun/package.json create mode 100644 tests/bun/schemas/input.ts create mode 100644 tests/bun/schemas/models.ts create mode 100644 tests/bun/schemas/schema.ts create mode 100644 tests/bun/schemas/schema.zmodel create mode 100644 tests/bun/scripts/generate.ts create mode 100644 tests/bun/tsconfig.json diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index f9f1eb9a2..ab0662d47 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -51,6 +51,11 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'pnpm' + - name: Use Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - name: Get pnpm store directory id: pnpm-cache shell: bash diff --git a/package.json b/package.json index 2418e326e..8be97821e 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "build": "turbo run build", "watch": "turbo run watch build", "lint": "turbo run lint", - "test": "vitest run", + "test": "turbo run test", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "pr": "gh pr create --fill-first --base dev", "merge-main": "gh pr create --title \"merge dev to main\" --body \"\" --base main --head dev", diff --git a/packages/testtools/src/client.ts b/packages/testtools/src/client.ts index c756f126b..1defaeaff 100644 --- a/packages/testtools/src/client.ts +++ b/packages/testtools/src/client.ts @@ -25,13 +25,15 @@ export function getTestDbProvider() { return val as 'sqlite' | 'postgresql'; } -const TEST_PG_CONFIG = { +export const TEST_PG_CONFIG = { host: process.env['TEST_PG_HOST'] ?? 'localhost', port: process.env['TEST_PG_PORT'] ? parseInt(process.env['TEST_PG_PORT']) : 5432, user: process.env['TEST_PG_USER'] ?? 'postgres', password: process.env['TEST_PG_PASSWORD'] ?? 'postgres', }; +export const TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`; + type ExtraTestClientOptions = { /** * Database provider @@ -104,10 +106,7 @@ export async function createTestClient( let _schema: SchemaDef; const provider = options?.provider ?? getTestDbProvider() ?? 'sqlite'; const dbName = options?.dbName ?? getTestDbName(provider); - const dbUrl = - provider === 'sqlite' - ? `file:${dbName}` - : `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}/${dbName}`; + const dbUrl = provider === 'sqlite' ? `file:${dbName}` : `${TEST_PG_URL}/${dbName}`; let model: Model | undefined; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 35ce119e7..c5365a5d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -804,6 +804,43 @@ importers: specifier: 'catalog:' version: 6.19.0(magicast@0.3.5)(typescript@5.9.3) + tests/bun: + dependencies: + '@zenstackhq/cli': + specifier: workspace:* + version: link:../../packages/cli + '@zenstackhq/common-helpers': + specifier: workspace:* + version: link:../../packages/common-helpers + '@zenstackhq/orm': + specifier: workspace:* + version: link:../../packages/orm + '@zenstackhq/plugin-policy': + specifier: workspace:* + version: link:../../packages/plugins/policy + '@zenstackhq/testtools': + specifier: workspace:* + version: link:../../packages/testtools + kysely: + specifier: 'catalog:' + version: 0.28.8 + kysely-bun-sqlite: + specifier: ^0.4.0 + version: 0.4.0(kysely@0.28.8) + pg: + specifier: 'catalog:' + version: 8.16.3 + devDependencies: + '@types/pg': + specifier: ^8.15.6 + version: 8.15.6 + '@zenstackhq/typescript-config': + specifier: workspace:* + version: link:../../packages/config/typescript-config + bun-types: + specifier: ^1.3.3 + version: 1.3.3 + tests/e2e: dependencies: '@paralleldrive/cuid2': @@ -846,9 +883,6 @@ importers: specifier: ^11.0.5 version: 11.0.5 devDependencies: - '@types/uuid': - specifier: ^11.0.0 - version: 11.0.0 '@zenstackhq/typescript-config': specifier: workspace:* version: link:../../packages/config/typescript-config @@ -865,6 +899,9 @@ importers: specifier: 'catalog:' version: 10.6.0 devDependencies: + '@types/node': + specifier: 'catalog:' + version: 20.19.24 '@zenstackhq/cli': specifier: workspace:* version: link:../../packages/cli @@ -2916,6 +2953,9 @@ packages: '@types/pg@8.11.11': resolution: {integrity: sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==} + '@types/pg@8.15.6': + resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} + '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} @@ -2963,10 +3003,6 @@ packages: '@types/toposort@2.0.7': resolution: {integrity: sha512-sQNk65vbC36+UixCkcky+dCr7MlflHcVILg1FVGqlUntsLFv9xd9ToWIVko/gTuin+cVe16t+2YubEFkhnSuPQ==} - '@types/uuid@11.0.0': - resolution: {integrity: sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA==} - deprecated: This is a stub types definition. uuid provides its own type definitions, so you do not need this installed. - '@types/vscode@1.101.0': resolution: {integrity: sha512-ZWf0IWa+NGegdW3iU42AcDTFHWW7fApLdkdnBqwYEtHVIBGbTu0ZNQKP/kX3Ds/uMJXIMQNAojHR4vexCEEz5Q==} @@ -3626,6 +3662,9 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + bun-types@1.3.3: + resolution: {integrity: sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ==} + bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} @@ -5160,6 +5199,12 @@ packages: knitwork@1.2.0: resolution: {integrity: sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==} + kysely-bun-sqlite@0.4.0: + resolution: {integrity: sha512-2EkQE5sT4ewiw7IWfJsAkpxJ/QPVKXKO5sRYI/xjjJIJlECuOdtG+ssYM0twZJySrdrmuildNPFYVreyu1EdZg==} + engines: {bun: '>=1.1.31'} + peerDependencies: + kysely: ^0.28.2 + kysely@0.28.8: resolution: {integrity: sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA==} engines: {node: '>=20.0.0'} @@ -9551,7 +9596,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.24 '@types/cookie@0.6.0': {} @@ -9565,7 +9610,7 @@ snapshots: '@types/express-serve-static-core@5.1.0': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.24 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 '@types/send': 1.2.0 @@ -9604,6 +9649,12 @@ snapshots: pg-protocol: 1.10.3 pg-types: 4.0.2 + '@types/pg@8.15.6': + dependencies: + '@types/node': 20.19.24 + pg-protocol: 1.10.3 + pg-types: 2.2.0 + '@types/pluralize@0.0.33': {} '@types/qs@6.14.0': {} @@ -9625,16 +9676,16 @@ snapshots: '@types/send@0.17.5': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.17.24 + '@types/node': 20.19.24 '@types/send@1.2.0': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.24 '@types/serve-static@1.15.9': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 20.17.24 + '@types/node': 20.19.24 '@types/send': 0.17.5 '@types/sql.js@1.4.9': @@ -9646,7 +9697,7 @@ snapshots: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 20.17.24 + '@types/node': 20.19.24 form-data: 4.0.4 '@types/supertest@6.0.3': @@ -9658,10 +9709,6 @@ snapshots: '@types/toposort@2.0.7': {} - '@types/uuid@11.0.0': - dependencies: - uuid: 11.0.5 - '@types/vscode@1.101.0': {} '@types/whatwg-mimetype@3.0.2': {} @@ -10466,6 +10513,10 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + bun-types@1.3.3: + dependencies: + '@types/node': 20.19.24 + bundle-name@4.1.0: dependencies: run-applescript: 7.1.0 @@ -11175,7 +11226,7 @@ snapshots: eslint: 9.29.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.29.0(jiti@2.6.1)) @@ -11208,7 +11259,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -11223,7 +11274,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -12247,6 +12298,11 @@ snapshots: knitwork@1.2.0: {} + kysely-bun-sqlite@0.4.0(kysely@0.28.8): + dependencies: + bun-types: 1.3.3 + kysely: 0.28.8 + kysely@0.28.8: {} langium-cli@3.5.0: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e5cc89972..b165d0c3f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,28 +2,29 @@ packages: - packages/** - samples/** - tests/** + catalog: + '@tanstack/react-query': 5.90.6 + '@types/better-sqlite3': ^7.6.13 + '@types/node': ^20.19.0 + '@types/react': 19.2.0 + '@types/react-dom': 19.2.0 + '@types/tmp': ^0.2.6 + better-sqlite3: ^12.2.0 + decimal.js: ^10.4.3 kysely: ~0.28.8 - zod: ^4.0.0 - prisma: ^6.19.0 langium: 3.5.0 langium-cli: 3.5.0 - ts-pattern: ^5.7.1 - typescript: ^5.9.3 - '@types/node': ^20.19.0 - tmp: ^0.2.3 - '@types/tmp': ^0.2.6 - 'zod-validation-error': ^4.0.1 - 'better-sqlite3': ^12.2.0 - '@types/better-sqlite3': ^7.6.13 - 'pg': ^8.13.1 - 'sql.js': ^1.13.0 - 'decimal.js': '^10.4.3' + next: 16.0.1 + pg: ^8.13.1 + prisma: ^6.19.0 react: 19.2.0 - '@types/react': 19.2.0 react-dom: 19.2.0 - '@types/react-dom': 19.2.0 - '@tanstack/react-query': 5.90.6 - 'next': 16.0.1 - 'vue': 3.5.22 - 'svelte': 5.43.3 + sql.js: ^1.13.0 + svelte: 5.43.3 + tmp: ^0.2.3 + ts-pattern: ^5.7.1 + typescript: ^5.9.3 + vue: 3.5.22 + zod: ^4.0.0 + zod-validation-error: ^4.0.1 diff --git a/tests/bun/e2e.test.ts b/tests/bun/e2e.test.ts new file mode 100644 index 000000000..bfc60494b --- /dev/null +++ b/tests/bun/e2e.test.ts @@ -0,0 +1,113 @@ +import { clone } from '@zenstackhq/common-helpers'; +import { ZenStackClient } from '@zenstackhq/orm'; +import { PostgresDialect } from '@zenstackhq/orm/dialects/postgres'; +import { PolicyPlugin } from '@zenstackhq/plugin-policy'; +import { TEST_PG_URL } from '@zenstackhq/testtools'; +import { Database } from 'bun:sqlite'; +import { describe, expect, it } from 'bun:test'; +import type { Dialect } from 'kysely'; +import { BunSqliteDialect } from 'kysely-bun-sqlite'; +import { Client, Pool } from 'pg'; +import { schema } from './schemas/schema'; + +describe('Bun e2e tests', () => { + const provider = (process.env['TEST_DB_PROVIDER'] ?? 'sqlite') as 'sqlite' | 'postgresql'; + + it('works with simple CRUD', async () => { + const db = await createClient(provider, 'bun-e2e-crud'); + + const user = await db.user.create({ + data: { + id: '1', + email: 'u1@example.com', + name: 'Test User', + }, + }); + expect(user).toMatchObject({ + id: '1', + email: 'u1@example.com', + name: 'Test User', + }); + + let found = await db.user.findUnique({ + where: { id: '1' }, + }); + expect(found).toMatchObject(user); + + await db.user.update({ where: { id: '1' }, data: { name: 'Updated Name' } }); + found = await db.user.findFirst(); + expect(found).toMatchObject({ name: 'Updated Name' }); + + await db.user.delete({ where: { id: '1' } }); + const count = await db.user.count(); + expect(count).toBe(0); + }); + + it('enforces policies', async () => { + const db = await createClient(provider, 'bun-e2e-policies'); + const authDb = db.$use(new PolicyPlugin()); + + // create a user + await db.user.create({ + data: { + id: '1', + email: 'u1@example.com', + name: 'Test User', + posts: { + create: [ + { + id: 'p1', + title: 'First Post', + content: 'Hello World', + published: true, + }, + { + id: 'p2', + title: 'Second Post', + content: 'Draft Post', + published: false, + }, + ], + }, + }, + }); + + const anonCount = await authDb.post.count(); + expect(anonCount).toBe(0); + + const user1DbCount = await authDb.$setAuth({ id: '1' }).post.count(); + expect(user1DbCount).toBe(2); + + const user2DbCount = await authDb.$setAuth({ id: '2' }).post.count(); + expect(user2DbCount).toBe(1); + }); +}); + +async function createClient(provider: 'sqlite' | 'postgresql', dbName: string) { + const _schema = clone(schema); + let dialect: Dialect; + if (provider === 'sqlite') { + (_schema as any).provider.type = 'sqlite'; + dialect = new BunSqliteDialect({ + database: new Database(':memory:'), + }); + } else { + (_schema as any).provider.type = 'postgresql'; + const pgClient = new Client({ + connectionString: TEST_PG_URL, + }); + await pgClient.connect(); + await pgClient.query(`DROP DATABASE IF EXISTS "${dbName}"`); + await pgClient.query(`CREATE DATABASE "${dbName}"`); + await pgClient.end(); + dialect = new PostgresDialect({ + pool: new Pool({ + connectionString: `${TEST_PG_URL}/${dbName}`, + }), + }); + } + + const db = new ZenStackClient(_schema, { dialect }); + await db.$pushSchema(); + return db; +} diff --git a/tests/bun/package.json b/tests/bun/package.json new file mode 100644 index 000000000..a5a29b3d5 --- /dev/null +++ b/tests/bun/package.json @@ -0,0 +1,27 @@ +{ + "name": "bun-e2e", + "version": "3.0.0-beta.27", + "private": true, + "type": "module", + "scripts": { + "build": "pnpm test:generate && pnpm test:typecheck", + "test:generate": "tsx scripts/generate.ts", + "test:typecheck": "tsc --noEmit", + "test": "bun test" + }, + "dependencies": { + "@zenstackhq/cli": "workspace:*", + "@zenstackhq/orm": "workspace:*", + "@zenstackhq/plugin-policy": "workspace:*", + "@zenstackhq/common-helpers": "workspace:*", + "@zenstackhq/testtools": "workspace:*", + "kysely-bun-sqlite": "^0.4.0", + "pg": "catalog:", + "kysely": "catalog:" + }, + "devDependencies": { + "@types/pg": "^8.15.6", + "@zenstackhq/typescript-config": "workspace:*", + "bun-types": "^1.3.3" + } +} diff --git a/tests/bun/schemas/input.ts b/tests/bun/schemas/input.ts new file mode 100644 index 000000000..fb7763147 --- /dev/null +++ b/tests/bun/schemas/input.ts @@ -0,0 +1,50 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaType as $Schema } from "./schema"; +import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput, ClientOptions as $ClientOptions } from "@zenstackhq/orm"; +import type { SimplifiedModelResult as $SimplifiedModelResult, SelectIncludeOmit as $SelectIncludeOmit } from "@zenstackhq/orm"; +export type UserFindManyArgs = $FindManyArgs<$Schema, "User">; +export type UserFindUniqueArgs = $FindUniqueArgs<$Schema, "User">; +export type UserFindFirstArgs = $FindFirstArgs<$Schema, "User">; +export type UserCreateArgs = $CreateArgs<$Schema, "User">; +export type UserCreateManyArgs = $CreateManyArgs<$Schema, "User">; +export type UserCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "User">; +export type UserUpdateArgs = $UpdateArgs<$Schema, "User">; +export type UserUpdateManyArgs = $UpdateManyArgs<$Schema, "User">; +export type UserUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "User">; +export type UserUpsertArgs = $UpsertArgs<$Schema, "User">; +export type UserDeleteArgs = $DeleteArgs<$Schema, "User">; +export type UserDeleteManyArgs = $DeleteManyArgs<$Schema, "User">; +export type UserCountArgs = $CountArgs<$Schema, "User">; +export type UserAggregateArgs = $AggregateArgs<$Schema, "User">; +export type UserGroupByArgs = $GroupByArgs<$Schema, "User">; +export type UserWhereInput = $WhereInput<$Schema, "User">; +export type UserSelect = $SelectInput<$Schema, "User">; +export type UserInclude = $IncludeInput<$Schema, "User">; +export type UserOmit = $OmitInput<$Schema, "User">; +export type UserGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "User", Options, Args>; +export type PostFindManyArgs = $FindManyArgs<$Schema, "Post">; +export type PostFindUniqueArgs = $FindUniqueArgs<$Schema, "Post">; +export type PostFindFirstArgs = $FindFirstArgs<$Schema, "Post">; +export type PostCreateArgs = $CreateArgs<$Schema, "Post">; +export type PostCreateManyArgs = $CreateManyArgs<$Schema, "Post">; +export type PostCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Post">; +export type PostUpdateArgs = $UpdateArgs<$Schema, "Post">; +export type PostUpdateManyArgs = $UpdateManyArgs<$Schema, "Post">; +export type PostUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "Post">; +export type PostUpsertArgs = $UpsertArgs<$Schema, "Post">; +export type PostDeleteArgs = $DeleteArgs<$Schema, "Post">; +export type PostDeleteManyArgs = $DeleteManyArgs<$Schema, "Post">; +export type PostCountArgs = $CountArgs<$Schema, "Post">; +export type PostAggregateArgs = $AggregateArgs<$Schema, "Post">; +export type PostGroupByArgs = $GroupByArgs<$Schema, "Post">; +export type PostWhereInput = $WhereInput<$Schema, "Post">; +export type PostSelect = $SelectInput<$Schema, "Post">; +export type PostInclude = $IncludeInput<$Schema, "Post">; +export type PostOmit = $OmitInput<$Schema, "Post">; +export type PostGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "Post", Options, Args>; diff --git a/tests/bun/schemas/models.ts b/tests/bun/schemas/models.ts new file mode 100644 index 000000000..b91301c96 --- /dev/null +++ b/tests/bun/schemas/models.ts @@ -0,0 +1,14 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { schema as $schema, type SchemaType as $Schema } from "./schema"; +import { type ModelResult as $ModelResult, type TypeDefResult as $TypeDefResult } from "@zenstackhq/orm"; +export type User = $ModelResult<$Schema, "User">; +export type Post = $ModelResult<$Schema, "Post">; +export type CommonFields = $TypeDefResult<$Schema, "CommonFields">; +export const Role = $schema.enums.Role.values; +export type Role = (typeof Role)[keyof typeof Role]; diff --git a/tests/bun/schemas/schema.ts b/tests/bun/schemas/schema.ts new file mode 100644 index 000000000..627922bc9 --- /dev/null +++ b/tests/bun/schemas/schema.ts @@ -0,0 +1,177 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaDef, ExpressionUtils } from "@zenstackhq/orm/schema"; +const _schema = { + provider: { + type: "sqlite" + }, + models: { + User: { + name: "User", + fields: { + id: { + name: "id", + type: "String", + id: true, + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], + default: ExpressionUtils.call("cuid") + }, + createdAt: { + name: "createdAt", + type: "DateTime", + attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.call("now") }] }], + default: ExpressionUtils.call("now") + }, + updatedAt: { + name: "updatedAt", + type: "DateTime", + updatedAt: true, + attributes: [{ name: "@updatedAt" }] + }, + email: { + name: "email", + type: "String", + unique: true, + attributes: [{ name: "@unique" }] + }, + name: { + name: "name", + type: "String", + optional: true + }, + role: { + name: "role", + type: "Role", + attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.literal("USER") }] }], + default: "USER" + }, + posts: { + name: "posts", + type: "Post", + array: true, + relation: { opposite: "author" } + }, + meta: { + name: "meta", + type: "Json", + optional: true + } + }, + attributes: [ + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]), "==", ExpressionUtils.field("id")) }] }, + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("read") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.call("auth"), "!=", ExpressionUtils._null()) }] } + ], + idFields: ["id"], + uniqueFields: { + id: { type: "String" }, + email: { type: "String" } + } + }, + Post: { + name: "Post", + fields: { + id: { + name: "id", + type: "String", + id: true, + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], + default: ExpressionUtils.call("cuid") + }, + createdAt: { + name: "createdAt", + type: "DateTime", + attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.call("now") }] }], + default: ExpressionUtils.call("now") + }, + updatedAt: { + name: "updatedAt", + type: "DateTime", + updatedAt: true, + attributes: [{ name: "@updatedAt" }] + }, + title: { + name: "title", + type: "String" + }, + content: { + name: "content", + type: "String", + optional: true + }, + published: { + name: "published", + type: "Boolean", + attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.literal(false) }] }], + default: false + }, + author: { + name: "author", + type: "User", + attributes: [{ name: "@relation", args: [{ name: "fields", value: ExpressionUtils.array([ExpressionUtils.field("authorId")]) }, { name: "references", value: ExpressionUtils.array([ExpressionUtils.field("id")]) }, { name: "onUpdate", value: ExpressionUtils.literal("Cascade") }, { name: "onDelete", value: ExpressionUtils.literal("Cascade") }] }], + relation: { opposite: "posts", fields: ["authorId"], references: ["id"], onUpdate: "Cascade", onDelete: "Cascade" } + }, + authorId: { + name: "authorId", + type: "String", + foreignKeyFor: [ + "author" + ] + } + }, + attributes: [ + { name: "@@deny", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.call("auth"), "==", ExpressionUtils._null()) }] }, + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]), "==", ExpressionUtils.field("authorId")) }] }, + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("read") }, { name: "condition", value: ExpressionUtils.field("published") }] } + ], + idFields: ["id"], + uniqueFields: { + id: { type: "String" } + } + } + }, + typeDefs: { + CommonFields: { + name: "CommonFields", + fields: { + id: { + name: "id", + type: "String", + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], + default: ExpressionUtils.call("cuid") + }, + createdAt: { + name: "createdAt", + type: "DateTime", + attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.call("now") }] }], + default: ExpressionUtils.call("now") + }, + updatedAt: { + name: "updatedAt", + type: "DateTime", + updatedAt: true, + attributes: [{ name: "@updatedAt" }] + } + } + } + }, + enums: { + Role: { + values: { + ADMIN: "ADMIN", + USER: "USER" + } + } + }, + authType: "User", + plugins: {} +} as const satisfies SchemaDef; +type Schema = typeof _schema & { + __brand?: "schema"; +}; +export const schema: Schema = _schema; +export type SchemaType = Schema; diff --git a/tests/bun/schemas/schema.zmodel b/tests/bun/schemas/schema.zmodel new file mode 100644 index 000000000..05f14bf4f --- /dev/null +++ b/tests/bun/schemas/schema.zmodel @@ -0,0 +1,46 @@ +datasource db { + provider = "sqlite" + url = "file:./dev.db" +} + +plugin policy { + provider = "../../../packages/plugins/policy" +} + +enum Role { + ADMIN + USER +} + +type CommonFields { + id String @id @default(cuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model User with CommonFields { + email String @unique + name String? + password String @ignore + role Role @default(USER) + posts Post[] + meta Json? + + // Access policies + @@allow('all', auth().id == id) + @@allow('read', auth() != null) +} + +model Post with CommonFields { + title String + content String? + published Boolean @default(false) + author User @relation(fields: [authorId], references: [id], onUpdate: Cascade, onDelete: Cascade) + authorId String + + // Access policies + @@deny('all', auth() == null) + @@allow('all', auth().id == authorId) + @@allow('read', published) +} + diff --git a/tests/bun/scripts/generate.ts b/tests/bun/scripts/generate.ts new file mode 100644 index 000000000..09a2ac233 --- /dev/null +++ b/tests/bun/scripts/generate.ts @@ -0,0 +1,20 @@ +import { glob } from 'glob'; +import { execSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const dir = path.dirname(fileURLToPath(import.meta.url)); + +async function main() { + const zmodelFiles = [...glob.sync(path.resolve(dir, '../schemas/*.zmodel'))]; + for (const file of zmodelFiles) { + console.log(`Generating TS schema for: ${file}`); + await generate(file); + } +} + +async function generate(schemaPath: string) { + execSync('bunx --bun zen generate', { cwd: path.dirname(schemaPath) }); +} + +main(); diff --git a/tests/bun/tsconfig.json b/tests/bun/tsconfig.json new file mode 100644 index 000000000..37dbe4e27 --- /dev/null +++ b/tests/bun/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@zenstackhq/typescript-config/base.json", + "compilerOptions": { + "noEmit": true, + "noImplicitAny": false, + "types": ["bun-types"] + } +} diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 38625d7c0..2160f3f78 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -27,7 +27,6 @@ "uuid": "^11.0.5" }, "devDependencies": { - "@types/uuid": "^11.0.0", "@zenstackhq/cli": "workspace:*", "@zenstackhq/typescript-config": "workspace:*", "@zenstackhq/vitest-config": "workspace:*" diff --git a/tests/regression/package.json b/tests/regression/package.json index f4a4c8ff2..b1de33819 100644 --- a/tests/regression/package.json +++ b/tests/regression/package.json @@ -17,6 +17,7 @@ "@zenstackhq/orm": "workspace:*", "@zenstackhq/sdk": "workspace:*", "@zenstackhq/typescript-config": "workspace:*", - "@zenstackhq/vitest-config": "workspace:*" + "@zenstackhq/vitest-config": "workspace:*", + "@types/node": "catalog:" } } diff --git a/tests/regression/test/issue-204/input.ts b/tests/regression/test/issue-204/input.ts index d39dc0e50..9564b7f27 100644 --- a/tests/regression/test/issue-204/input.ts +++ b/tests/regression/test/issue-204/input.ts @@ -6,7 +6,7 @@ /* eslint-disable */ import { type SchemaType as $Schema } from "./schema"; -import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput } from "@zenstackhq/orm"; +import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput, ClientOptions as $ClientOptions } from "@zenstackhq/orm"; import type { SimplifiedModelResult as $SimplifiedModelResult, SelectIncludeOmit as $SelectIncludeOmit } from "@zenstackhq/orm"; export type FooFindManyArgs = $FindManyArgs<$Schema, "Foo">; export type FooFindUniqueArgs = $FindUniqueArgs<$Schema, "Foo">; @@ -27,4 +27,4 @@ export type FooWhereInput = $WhereInput<$Schema, "Foo">; export type FooSelect = $SelectInput<$Schema, "Foo">; export type FooInclude = $IncludeInput<$Schema, "Foo">; export type FooOmit = $OmitInput<$Schema, "Foo">; -export type FooGetPayload> = $SimplifiedModelResult<$Schema, "Foo", Args>; +export type FooGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "Foo", Options, Args>; diff --git a/tests/regression/test/issue-422/input.ts b/tests/regression/test/issue-422/input.ts index 73b7ed9af..a931f0681 100644 --- a/tests/regression/test/issue-422/input.ts +++ b/tests/regression/test/issue-422/input.ts @@ -6,7 +6,7 @@ /* eslint-disable */ import { type SchemaType as $Schema } from "./schema"; -import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput } from "@zenstackhq/orm"; +import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput, ClientOptions as $ClientOptions } from "@zenstackhq/orm"; import type { SimplifiedModelResult as $SimplifiedModelResult, SelectIncludeOmit as $SelectIncludeOmit } from "@zenstackhq/orm"; export type SessionFindManyArgs = $FindManyArgs<$Schema, "Session">; export type SessionFindUniqueArgs = $FindUniqueArgs<$Schema, "Session">; @@ -27,7 +27,7 @@ export type SessionWhereInput = $WhereInput<$Schema, "Session">; export type SessionSelect = $SelectInput<$Schema, "Session">; export type SessionInclude = $IncludeInput<$Schema, "Session">; export type SessionOmit = $OmitInput<$Schema, "Session">; -export type SessionGetPayload> = $SimplifiedModelResult<$Schema, "Session", Args>; +export type SessionGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "Session", Options, Args>; export type UserFindManyArgs = $FindManyArgs<$Schema, "User">; export type UserFindUniqueArgs = $FindUniqueArgs<$Schema, "User">; export type UserFindFirstArgs = $FindFirstArgs<$Schema, "User">; @@ -47,7 +47,7 @@ export type UserWhereInput = $WhereInput<$Schema, "User">; export type UserSelect = $SelectInput<$Schema, "User">; export type UserInclude = $IncludeInput<$Schema, "User">; export type UserOmit = $OmitInput<$Schema, "User">; -export type UserGetPayload> = $SimplifiedModelResult<$Schema, "User", Args>; +export type UserGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "User", Options, Args>; export type ProfileFindManyArgs = $FindManyArgs<$Schema, "Profile">; export type ProfileFindUniqueArgs = $FindUniqueArgs<$Schema, "Profile">; export type ProfileFindFirstArgs = $FindFirstArgs<$Schema, "Profile">; @@ -67,4 +67,4 @@ export type ProfileWhereInput = $WhereInput<$Schema, "Profile">; export type ProfileSelect = $SelectInput<$Schema, "Profile">; export type ProfileInclude = $IncludeInput<$Schema, "Profile">; export type ProfileOmit = $OmitInput<$Schema, "Profile">; -export type ProfileGetPayload> = $SimplifiedModelResult<$Schema, "Profile", Args>; +export type ProfileGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "Profile", Options, Args>; diff --git a/tests/regression/tsconfig.json b/tests/regression/tsconfig.json index e0b83aa88..1dd80744b 100644 --- a/tests/regression/tsconfig.json +++ b/tests/regression/tsconfig.json @@ -2,7 +2,7 @@ "extends": "@zenstackhq/typescript-config/base.json", "compilerOptions": { "noEmit": true, - "types": ["@zenstackhq/testtools/types"] + "types": ["@zenstackhq/testtools/types", "node"] }, "include": ["src/**/*.ts", "test/**/*.ts"] } diff --git a/turbo.json b/turbo.json index ab312f312..c66313588 100644 --- a/turbo.json +++ b/turbo.json @@ -15,7 +15,9 @@ "dependsOn": ["^lint"] }, "test": { - "dependsOn": ["build"] + "dependsOn": ["build"], + "cache": false } - } + }, + "globalPassThroughEnv": ["TEST_DB_PROVIDER"] } From d894f4bc2b4029f8e9134499dbb877ab9191ada2 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Tue, 2 Dec 2025 09:51:54 +0800 Subject: [PATCH 11/13] test: add edge-runtime e2e (#458) * test: add edge-runtime e2e * update * add cleanup * update * simplify typing --- pnpm-lock.yaml | 127 ++++++++++++------ .../bun/bun-e2e.test.ts} | 14 +- tests/{ => runtimes}/bun/package.json | 0 tests/{ => runtimes}/bun/schemas/input.ts | 0 tests/{ => runtimes}/bun/schemas/models.ts | 7 +- tests/{ => runtimes}/bun/schemas/schema.ts | 73 ---------- .../{ => runtimes}/bun/schemas/schema.zmodel | 29 +--- tests/{ => runtimes}/bun/scripts/generate.ts | 0 tests/{ => runtimes}/bun/tsconfig.json | 0 tests/runtimes/edge-runtime/.DS_Store | Bin 0 -> 6148 bytes .../edge-runtime/edge-runtime-e2e.test.ts | 101 ++++++++++++++ tests/runtimes/edge-runtime/package.json | 26 ++++ tests/runtimes/edge-runtime/schemas/input.ts | 50 +++++++ tests/runtimes/edge-runtime/schemas/models.ts | 11 ++ tests/runtimes/edge-runtime/schemas/schema.ts | 104 ++++++++++++++ .../edge-runtime/schemas/schema.zmodel | 31 +++++ .../runtimes/edge-runtime/scripts/generate.ts | 20 +++ tests/runtimes/edge-runtime/tsconfig.json | 6 + tests/runtimes/edge-runtime/vitest.config.ts | 11 ++ vitest.config.ts | 2 +- 20 files changed, 467 insertions(+), 145 deletions(-) rename tests/{bun/e2e.test.ts => runtimes/bun/bun-e2e.test.ts} (92%) rename tests/{ => runtimes}/bun/package.json (100%) rename tests/{ => runtimes}/bun/schemas/input.ts (100%) rename tests/{ => runtimes}/bun/schemas/models.ts (59%) rename tests/{ => runtimes}/bun/schemas/schema.ts (64%) rename tests/{ => runtimes}/bun/schemas/schema.zmodel (54%) rename tests/{ => runtimes}/bun/scripts/generate.ts (100%) rename tests/{ => runtimes}/bun/tsconfig.json (100%) create mode 100644 tests/runtimes/edge-runtime/.DS_Store create mode 100644 tests/runtimes/edge-runtime/edge-runtime-e2e.test.ts create mode 100644 tests/runtimes/edge-runtime/package.json create mode 100644 tests/runtimes/edge-runtime/schemas/input.ts create mode 100644 tests/runtimes/edge-runtime/schemas/models.ts create mode 100644 tests/runtimes/edge-runtime/schemas/schema.ts create mode 100644 tests/runtimes/edge-runtime/schemas/schema.zmodel create mode 100644 tests/runtimes/edge-runtime/scripts/generate.ts create mode 100644 tests/runtimes/edge-runtime/tsconfig.json create mode 100644 tests/runtimes/edge-runtime/vitest.config.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5365a5d6..b780f2f7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,7 +115,7 @@ importers: version: 8.34.1(eslint@9.29.0(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^4.0.14 - version: 4.0.14(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) + version: 4.0.14(@edge-runtime/vm@5.0.0)(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) yaml: specifier: ^2.8.0 version: 2.8.0 @@ -804,43 +804,6 @@ importers: specifier: 'catalog:' version: 6.19.0(magicast@0.3.5)(typescript@5.9.3) - tests/bun: - dependencies: - '@zenstackhq/cli': - specifier: workspace:* - version: link:../../packages/cli - '@zenstackhq/common-helpers': - specifier: workspace:* - version: link:../../packages/common-helpers - '@zenstackhq/orm': - specifier: workspace:* - version: link:../../packages/orm - '@zenstackhq/plugin-policy': - specifier: workspace:* - version: link:../../packages/plugins/policy - '@zenstackhq/testtools': - specifier: workspace:* - version: link:../../packages/testtools - kysely: - specifier: 'catalog:' - version: 0.28.8 - kysely-bun-sqlite: - specifier: ^0.4.0 - version: 0.4.0(kysely@0.28.8) - pg: - specifier: 'catalog:' - version: 8.16.3 - devDependencies: - '@types/pg': - specifier: ^8.15.6 - version: 8.15.6 - '@zenstackhq/typescript-config': - specifier: workspace:* - version: link:../../packages/config/typescript-config - bun-types: - specifier: ^1.3.3 - version: 1.3.3 - tests/e2e: dependencies: '@paralleldrive/cuid2': @@ -921,6 +884,77 @@ importers: specifier: workspace:* version: link:../../packages/config/vitest-config + tests/runtimes/bun: + dependencies: + '@zenstackhq/cli': + specifier: workspace:* + version: link:../../../packages/cli + '@zenstackhq/common-helpers': + specifier: workspace:* + version: link:../../../packages/common-helpers + '@zenstackhq/orm': + specifier: workspace:* + version: link:../../../packages/orm + '@zenstackhq/plugin-policy': + specifier: workspace:* + version: link:../../../packages/plugins/policy + '@zenstackhq/testtools': + specifier: workspace:* + version: link:../../../packages/testtools + kysely: + specifier: 'catalog:' + version: 0.28.8 + kysely-bun-sqlite: + specifier: ^0.4.0 + version: 0.4.0(kysely@0.28.8) + pg: + specifier: 'catalog:' + version: 8.16.3 + devDependencies: + '@types/pg': + specifier: ^8.15.6 + version: 8.15.6 + '@zenstackhq/typescript-config': + specifier: workspace:* + version: link:../../../packages/config/typescript-config + bun-types: + specifier: ^1.3.3 + version: 1.3.3 + + tests/runtimes/edge-runtime: + dependencies: + '@edge-runtime/vm': + specifier: ^5.0.0 + version: 5.0.0 + '@zenstackhq/cli': + specifier: workspace:* + version: link:../../../packages/cli + '@zenstackhq/common-helpers': + specifier: workspace:* + version: link:../../../packages/common-helpers + '@zenstackhq/orm': + specifier: workspace:* + version: link:../../../packages/orm + '@zenstackhq/plugin-policy': + specifier: workspace:* + version: link:../../../packages/plugins/policy + '@zenstackhq/testtools': + specifier: workspace:* + version: link:../../../packages/testtools + pg: + specifier: 'catalog:' + version: 8.16.3 + devDependencies: + '@types/pg': + specifier: ^8.15.6 + version: 8.15.6 + '@zenstackhq/typescript-config': + specifier: workspace:* + version: link:../../../packages/config/typescript-config + '@zenstackhq/vitest-config': + specifier: workspace:* + version: link:../../../packages/config/vitest-config + packages: '@acemir/cssom@0.9.23': @@ -1139,6 +1173,14 @@ packages: '@dxup/unimport@0.1.0': resolution: {integrity: sha512-6Q/Po8qGmlrShdG/R9+rpIhme9N/PGJumpvmwr1UAxGpt9DfOCt9kF8+yJkxhtPdJFL37KgUILZBRAkSU8cJZg==} + '@edge-runtime/primitives@6.0.0': + resolution: {integrity: sha512-FqoxaBT+prPBHBwE1WXS1ocnu/VLTQyZ6NMUBAdbP7N2hsFTTxMC/jMu2D/8GAlMQfxeuppcPuCUk/HO3fpIvA==} + engines: {node: '>=18'} + + '@edge-runtime/vm@5.0.0': + resolution: {integrity: sha512-NKBGBSIKUG584qrS1tyxVpX/AKJKQw5HgjYEnPLC0QsTw79JrGn+qUr8CXFb955Iy7GUdiiUv1rJ6JBGvaKb6w==} + engines: {node: '>=18'} + '@emnapi/core@1.6.0': resolution: {integrity: sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg==} @@ -7946,6 +7988,12 @@ snapshots: '@dxup/unimport@0.1.0': {} + '@edge-runtime/primitives@6.0.0': {} + + '@edge-runtime/vm@5.0.0': + dependencies: + '@edge-runtime/primitives': 6.0.0 + '@emnapi/core@1.6.0': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -14843,7 +14891,7 @@ snapshots: optionalDependencies: vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1) - vitest@4.0.14(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0): + vitest@4.0.14(@edge-runtime/vm@5.0.0)(@types/node@20.19.24)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0): dependencies: '@vitest/expect': 4.0.14 '@vitest/mocker': 4.0.14(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0)) @@ -14866,6 +14914,7 @@ snapshots: vite: 7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: + '@edge-runtime/vm': 5.0.0 '@types/node': 20.19.24 happy-dom: 20.0.10 jsdom: 27.1.0 diff --git a/tests/bun/e2e.test.ts b/tests/runtimes/bun/bun-e2e.test.ts similarity index 92% rename from tests/bun/e2e.test.ts rename to tests/runtimes/bun/bun-e2e.test.ts index bfc60494b..901daaddc 100644 --- a/tests/bun/e2e.test.ts +++ b/tests/runtimes/bun/bun-e2e.test.ts @@ -4,7 +4,7 @@ import { PostgresDialect } from '@zenstackhq/orm/dialects/postgres'; import { PolicyPlugin } from '@zenstackhq/plugin-policy'; import { TEST_PG_URL } from '@zenstackhq/testtools'; import { Database } from 'bun:sqlite'; -import { describe, expect, it } from 'bun:test'; +import { afterEach, describe, expect, it } from 'bun:test'; import type { Dialect } from 'kysely'; import { BunSqliteDialect } from 'kysely-bun-sqlite'; import { Client, Pool } from 'pg'; @@ -13,8 +13,14 @@ import { schema } from './schemas/schema'; describe('Bun e2e tests', () => { const provider = (process.env['TEST_DB_PROVIDER'] ?? 'sqlite') as 'sqlite' | 'postgresql'; + let _db: any; + + afterEach(async () => { + await _db?.$disconnect(); + }); + it('works with simple CRUD', async () => { - const db = await createClient(provider, 'bun-e2e-crud'); + const db = (_db = await createClient(provider, 'bun-e2e-crud')); const user = await db.user.create({ data: { @@ -44,7 +50,7 @@ describe('Bun e2e tests', () => { }); it('enforces policies', async () => { - const db = await createClient(provider, 'bun-e2e-policies'); + const db = (_db = await createClient(provider, 'bun-e2e-policies')); const authDb = db.$use(new PolicyPlugin()); // create a user @@ -58,13 +64,11 @@ describe('Bun e2e tests', () => { { id: 'p1', title: 'First Post', - content: 'Hello World', published: true, }, { id: 'p2', title: 'Second Post', - content: 'Draft Post', published: false, }, ], diff --git a/tests/bun/package.json b/tests/runtimes/bun/package.json similarity index 100% rename from tests/bun/package.json rename to tests/runtimes/bun/package.json diff --git a/tests/bun/schemas/input.ts b/tests/runtimes/bun/schemas/input.ts similarity index 100% rename from tests/bun/schemas/input.ts rename to tests/runtimes/bun/schemas/input.ts diff --git a/tests/bun/schemas/models.ts b/tests/runtimes/bun/schemas/models.ts similarity index 59% rename from tests/bun/schemas/models.ts rename to tests/runtimes/bun/schemas/models.ts index b91301c96..72654e587 100644 --- a/tests/bun/schemas/models.ts +++ b/tests/runtimes/bun/schemas/models.ts @@ -5,10 +5,7 @@ /* eslint-disable */ -import { schema as $schema, type SchemaType as $Schema } from "./schema"; -import { type ModelResult as $ModelResult, type TypeDefResult as $TypeDefResult } from "@zenstackhq/orm"; +import { type SchemaType as $Schema } from "./schema"; +import { type ModelResult as $ModelResult } from "@zenstackhq/orm"; export type User = $ModelResult<$Schema, "User">; export type Post = $ModelResult<$Schema, "Post">; -export type CommonFields = $TypeDefResult<$Schema, "CommonFields">; -export const Role = $schema.enums.Role.values; -export type Role = (typeof Role)[keyof typeof Role]; diff --git a/tests/bun/schemas/schema.ts b/tests/runtimes/bun/schemas/schema.ts similarity index 64% rename from tests/bun/schemas/schema.ts rename to tests/runtimes/bun/schemas/schema.ts index 627922bc9..b7d3bfcdb 100644 --- a/tests/bun/schemas/schema.ts +++ b/tests/runtimes/bun/schemas/schema.ts @@ -21,18 +21,6 @@ const _schema = { attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], default: ExpressionUtils.call("cuid") }, - createdAt: { - name: "createdAt", - type: "DateTime", - attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.call("now") }] }], - default: ExpressionUtils.call("now") - }, - updatedAt: { - name: "updatedAt", - type: "DateTime", - updatedAt: true, - attributes: [{ name: "@updatedAt" }] - }, email: { name: "email", type: "String", @@ -44,22 +32,11 @@ const _schema = { type: "String", optional: true }, - role: { - name: "role", - type: "Role", - attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.literal("USER") }] }], - default: "USER" - }, posts: { name: "posts", type: "Post", array: true, relation: { opposite: "author" } - }, - meta: { - name: "meta", - type: "Json", - optional: true } }, attributes: [ @@ -82,27 +59,10 @@ const _schema = { attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], default: ExpressionUtils.call("cuid") }, - createdAt: { - name: "createdAt", - type: "DateTime", - attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.call("now") }] }], - default: ExpressionUtils.call("now") - }, - updatedAt: { - name: "updatedAt", - type: "DateTime", - updatedAt: true, - attributes: [{ name: "@updatedAt" }] - }, title: { name: "title", type: "String" }, - content: { - name: "content", - type: "String", - optional: true - }, published: { name: "published", type: "Boolean", @@ -134,39 +94,6 @@ const _schema = { } } }, - typeDefs: { - CommonFields: { - name: "CommonFields", - fields: { - id: { - name: "id", - type: "String", - attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], - default: ExpressionUtils.call("cuid") - }, - createdAt: { - name: "createdAt", - type: "DateTime", - attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.call("now") }] }], - default: ExpressionUtils.call("now") - }, - updatedAt: { - name: "updatedAt", - type: "DateTime", - updatedAt: true, - attributes: [{ name: "@updatedAt" }] - } - } - } - }, - enums: { - Role: { - values: { - ADMIN: "ADMIN", - USER: "USER" - } - } - }, authType: "User", plugins: {} } as const satisfies SchemaDef; diff --git a/tests/bun/schemas/schema.zmodel b/tests/runtimes/bun/schemas/schema.zmodel similarity index 54% rename from tests/bun/schemas/schema.zmodel rename to tests/runtimes/bun/schemas/schema.zmodel index 05f14bf4f..ee491c084 100644 --- a/tests/bun/schemas/schema.zmodel +++ b/tests/runtimes/bun/schemas/schema.zmodel @@ -1,39 +1,25 @@ datasource db { provider = "sqlite" - url = "file:./dev.db" } plugin policy { provider = "../../../packages/plugins/policy" } -enum Role { - ADMIN - USER -} - -type CommonFields { - id String @id @default(cuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} - -model User with CommonFields { - email String @unique - name String? - password String @ignore - role Role @default(USER) - posts Post[] - meta Json? +model User { + id String @id @default(cuid()) + email String @unique + name String? + posts Post[] // Access policies @@allow('all', auth().id == id) @@allow('read', auth() != null) } -model Post with CommonFields { +model Post { + id String @id @default(cuid()) title String - content String? published Boolean @default(false) author User @relation(fields: [authorId], references: [id], onUpdate: Cascade, onDelete: Cascade) authorId String @@ -43,4 +29,3 @@ model Post with CommonFields { @@allow('all', auth().id == authorId) @@allow('read', published) } - diff --git a/tests/bun/scripts/generate.ts b/tests/runtimes/bun/scripts/generate.ts similarity index 100% rename from tests/bun/scripts/generate.ts rename to tests/runtimes/bun/scripts/generate.ts diff --git a/tests/bun/tsconfig.json b/tests/runtimes/bun/tsconfig.json similarity index 100% rename from tests/bun/tsconfig.json rename to tests/runtimes/bun/tsconfig.json diff --git a/tests/runtimes/edge-runtime/.DS_Store b/tests/runtimes/edge-runtime/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d6f7ebb287bc2874ccc379f773b65350b317b6e5 GIT binary patch literal 6148 zcmeHK%}T>S5Z>*NO({YT3Oz1(E!dP&5HBIt7cim+m718K!I&*gY7V84v%Zi|;`2DO zyMY#qM-e*%yWi~m>}Ed5{xHV4y9jN@x{NUk8X`w!i=cU{t7d``xtb#iifk4nGT1WB z-!$R3H(Ac+%x4d5{rf+HSrTXYVDQOn^+t2AWwor1b>}_F!pr@9k-7f-21l1tCPAh9 z!Brd;)9%5UOmja@qq$0m!w5oduj4e7g)0|nn5kS(JFK?Vo_2f7r9B$<#n`r2eX%?l z4*Fs=9<5ew>+tCK^kVv)yrl9?6Ul*bCHn>|cn4*zqE~O8CNg~lYn4$&5)uQ%05L!e z>?Q-|Jg_>uSw2-w3=ji9Fo64mfQIN8EH$dF13J7uqrZWO0y@4W5QRaQru?7+j}=U6?q>V5w23Gp<&KdCbby { + let _db: any; + + afterEach(async () => { + await _db?.$disconnect(); + }); + + it('works with simple CRUD', async () => { + const db = (_db = await createClient('edge-runtime-e2e-crud')); + + const user = await db.user.create({ + data: { + id: '1', + email: 'u1@example.com', + name: 'Test User', + }, + }); + expect(user).toMatchObject({ + id: '1', + email: 'u1@example.com', + name: 'Test User', + }); + + let found = await db.user.findUnique({ + where: { id: '1' }, + }); + expect(found).toMatchObject(user); + + await db.user.update({ where: { id: '1' }, data: { name: 'Updated Name' } }); + found = await db.user.findFirst(); + expect(found).toMatchObject({ name: 'Updated Name' }); + + await db.user.delete({ where: { id: '1' } }); + const count = await db.user.count(); + expect(count).toBe(0); + }); + + it('enforces policies', async () => { + const db = (_db = await createClient('edge-runtime-e2e-policies')); + const authDb = db.$use(new PolicyPlugin()); + + // create a user + await db.user.create({ + data: { + id: '1', + email: 'u1@example.com', + name: 'Test User', + posts: { + create: [ + { + id: 'p1', + title: 'First Post', + published: true, + }, + { + id: 'p2', + title: 'Second Post', + published: false, + }, + ], + }, + }, + }); + + const anonCount = await authDb.post.count(); + expect(anonCount).toBe(0); + + const user1DbCount = await authDb.$setAuth({ id: '1' }).post.count(); + expect(user1DbCount).toBe(2); + + const user2DbCount = await authDb.$setAuth({ id: '2' }).post.count(); + expect(user2DbCount).toBe(1); + }); +}); + +async function createClient(dbName: string) { + const pgClient = new Client({ + connectionString: TEST_PG_URL, + }); + await pgClient.connect(); + await pgClient.query(`DROP DATABASE IF EXISTS "${dbName}"`); + await pgClient.query(`CREATE DATABASE "${dbName}"`); + await pgClient.end(); + const dialect = new PostgresDialect({ + pool: new Pool({ + connectionString: `${TEST_PG_URL}/${dbName}`, + }), + }); + + const db = new ZenStackClient(schema, { dialect }); + await db.$pushSchema(); + return db; +} diff --git a/tests/runtimes/edge-runtime/package.json b/tests/runtimes/edge-runtime/package.json new file mode 100644 index 000000000..324a21ca5 --- /dev/null +++ b/tests/runtimes/edge-runtime/package.json @@ -0,0 +1,26 @@ +{ + "name": "edge-runtime-e2e", + "version": "3.0.0-beta.27", + "private": true, + "type": "module", + "scripts": { + "build": "pnpm test:generate && pnpm test:typecheck", + "test:generate": "tsx scripts/generate.ts", + "test:typecheck": "tsc --noEmit", + "test": "vitest run" + }, + "dependencies": { + "@edge-runtime/vm": "^5.0.0", + "@zenstackhq/cli": "workspace:*", + "@zenstackhq/common-helpers": "workspace:*", + "@zenstackhq/orm": "workspace:*", + "@zenstackhq/plugin-policy": "workspace:*", + "@zenstackhq/testtools": "workspace:*", + "pg": "catalog:" + }, + "devDependencies": { + "@types/pg": "^8.15.6", + "@zenstackhq/typescript-config": "workspace:*", + "@zenstackhq/vitest-config": "workspace:*" + } +} diff --git a/tests/runtimes/edge-runtime/schemas/input.ts b/tests/runtimes/edge-runtime/schemas/input.ts new file mode 100644 index 000000000..fb7763147 --- /dev/null +++ b/tests/runtimes/edge-runtime/schemas/input.ts @@ -0,0 +1,50 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaType as $Schema } from "./schema"; +import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput, ClientOptions as $ClientOptions } from "@zenstackhq/orm"; +import type { SimplifiedModelResult as $SimplifiedModelResult, SelectIncludeOmit as $SelectIncludeOmit } from "@zenstackhq/orm"; +export type UserFindManyArgs = $FindManyArgs<$Schema, "User">; +export type UserFindUniqueArgs = $FindUniqueArgs<$Schema, "User">; +export type UserFindFirstArgs = $FindFirstArgs<$Schema, "User">; +export type UserCreateArgs = $CreateArgs<$Schema, "User">; +export type UserCreateManyArgs = $CreateManyArgs<$Schema, "User">; +export type UserCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "User">; +export type UserUpdateArgs = $UpdateArgs<$Schema, "User">; +export type UserUpdateManyArgs = $UpdateManyArgs<$Schema, "User">; +export type UserUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "User">; +export type UserUpsertArgs = $UpsertArgs<$Schema, "User">; +export type UserDeleteArgs = $DeleteArgs<$Schema, "User">; +export type UserDeleteManyArgs = $DeleteManyArgs<$Schema, "User">; +export type UserCountArgs = $CountArgs<$Schema, "User">; +export type UserAggregateArgs = $AggregateArgs<$Schema, "User">; +export type UserGroupByArgs = $GroupByArgs<$Schema, "User">; +export type UserWhereInput = $WhereInput<$Schema, "User">; +export type UserSelect = $SelectInput<$Schema, "User">; +export type UserInclude = $IncludeInput<$Schema, "User">; +export type UserOmit = $OmitInput<$Schema, "User">; +export type UserGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "User", Options, Args>; +export type PostFindManyArgs = $FindManyArgs<$Schema, "Post">; +export type PostFindUniqueArgs = $FindUniqueArgs<$Schema, "Post">; +export type PostFindFirstArgs = $FindFirstArgs<$Schema, "Post">; +export type PostCreateArgs = $CreateArgs<$Schema, "Post">; +export type PostCreateManyArgs = $CreateManyArgs<$Schema, "Post">; +export type PostCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Post">; +export type PostUpdateArgs = $UpdateArgs<$Schema, "Post">; +export type PostUpdateManyArgs = $UpdateManyArgs<$Schema, "Post">; +export type PostUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "Post">; +export type PostUpsertArgs = $UpsertArgs<$Schema, "Post">; +export type PostDeleteArgs = $DeleteArgs<$Schema, "Post">; +export type PostDeleteManyArgs = $DeleteManyArgs<$Schema, "Post">; +export type PostCountArgs = $CountArgs<$Schema, "Post">; +export type PostAggregateArgs = $AggregateArgs<$Schema, "Post">; +export type PostGroupByArgs = $GroupByArgs<$Schema, "Post">; +export type PostWhereInput = $WhereInput<$Schema, "Post">; +export type PostSelect = $SelectInput<$Schema, "Post">; +export type PostInclude = $IncludeInput<$Schema, "Post">; +export type PostOmit = $OmitInput<$Schema, "Post">; +export type PostGetPayload, Options extends $ClientOptions<$Schema> = $ClientOptions<$Schema>> = $SimplifiedModelResult<$Schema, "Post", Options, Args>; diff --git a/tests/runtimes/edge-runtime/schemas/models.ts b/tests/runtimes/edge-runtime/schemas/models.ts new file mode 100644 index 000000000..72654e587 --- /dev/null +++ b/tests/runtimes/edge-runtime/schemas/models.ts @@ -0,0 +1,11 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaType as $Schema } from "./schema"; +import { type ModelResult as $ModelResult } from "@zenstackhq/orm"; +export type User = $ModelResult<$Schema, "User">; +export type Post = $ModelResult<$Schema, "Post">; diff --git a/tests/runtimes/edge-runtime/schemas/schema.ts b/tests/runtimes/edge-runtime/schemas/schema.ts new file mode 100644 index 000000000..7f4436f87 --- /dev/null +++ b/tests/runtimes/edge-runtime/schemas/schema.ts @@ -0,0 +1,104 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaDef, ExpressionUtils } from "@zenstackhq/orm/schema"; +const _schema = { + provider: { + type: "postgresql" + }, + models: { + User: { + name: "User", + fields: { + id: { + name: "id", + type: "String", + id: true, + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], + default: ExpressionUtils.call("cuid") + }, + email: { + name: "email", + type: "String", + unique: true, + attributes: [{ name: "@unique" }] + }, + name: { + name: "name", + type: "String", + optional: true + }, + posts: { + name: "posts", + type: "Post", + array: true, + relation: { opposite: "author" } + } + }, + attributes: [ + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]), "==", ExpressionUtils.field("id")) }] }, + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("read") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.call("auth"), "!=", ExpressionUtils._null()) }] } + ], + idFields: ["id"], + uniqueFields: { + id: { type: "String" }, + email: { type: "String" } + } + }, + Post: { + name: "Post", + fields: { + id: { + name: "id", + type: "String", + id: true, + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("cuid") }] }], + default: ExpressionUtils.call("cuid") + }, + title: { + name: "title", + type: "String" + }, + published: { + name: "published", + type: "Boolean", + attributes: [{ name: "@default", args: [{ name: "value", value: ExpressionUtils.literal(false) }] }], + default: false + }, + author: { + name: "author", + type: "User", + attributes: [{ name: "@relation", args: [{ name: "fields", value: ExpressionUtils.array([ExpressionUtils.field("authorId")]) }, { name: "references", value: ExpressionUtils.array([ExpressionUtils.field("id")]) }, { name: "onUpdate", value: ExpressionUtils.literal("Cascade") }, { name: "onDelete", value: ExpressionUtils.literal("Cascade") }] }], + relation: { opposite: "posts", fields: ["authorId"], references: ["id"], onUpdate: "Cascade", onDelete: "Cascade" } + }, + authorId: { + name: "authorId", + type: "String", + foreignKeyFor: [ + "author" + ] + } + }, + attributes: [ + { name: "@@deny", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.call("auth"), "==", ExpressionUtils._null()) }] }, + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]), "==", ExpressionUtils.field("authorId")) }] }, + { name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("read") }, { name: "condition", value: ExpressionUtils.field("published") }] } + ], + idFields: ["id"], + uniqueFields: { + id: { type: "String" } + } + } + }, + authType: "User", + plugins: {} +} as const satisfies SchemaDef; +type Schema = typeof _schema & { + __brand?: "schema"; +}; +export const schema: Schema = _schema; +export type SchemaType = Schema; diff --git a/tests/runtimes/edge-runtime/schemas/schema.zmodel b/tests/runtimes/edge-runtime/schemas/schema.zmodel new file mode 100644 index 000000000..7872ce263 --- /dev/null +++ b/tests/runtimes/edge-runtime/schemas/schema.zmodel @@ -0,0 +1,31 @@ +datasource db { + provider = "postgresql" +} + +plugin policy { + provider = "../../../packages/plugins/policy" +} + +model User { + id String @id @default(cuid()) + email String @unique + name String? + posts Post[] + + // Access policies + @@allow('all', auth().id == id) + @@allow('read', auth() != null) +} + +model Post { + id String @id @default(cuid()) + title String + published Boolean @default(false) + author User @relation(fields: [authorId], references: [id], onUpdate: Cascade, onDelete: Cascade) + authorId String + + // Access policies + @@deny('all', auth() == null) + @@allow('all', auth().id == authorId) + @@allow('read', published) +} diff --git a/tests/runtimes/edge-runtime/scripts/generate.ts b/tests/runtimes/edge-runtime/scripts/generate.ts new file mode 100644 index 000000000..cd68f93b5 --- /dev/null +++ b/tests/runtimes/edge-runtime/scripts/generate.ts @@ -0,0 +1,20 @@ +import { glob } from 'glob'; +import { execSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const dir = path.dirname(fileURLToPath(import.meta.url)); + +async function main() { + const zmodelFiles = [...glob.sync(path.resolve(dir, '../schemas/*.zmodel'))]; + for (const file of zmodelFiles) { + console.log(`Generating TS schema for: ${file}`); + await generate(file); + } +} + +async function generate(schemaPath: string) { + execSync('npx zen generate', { cwd: path.dirname(schemaPath) }); +} + +main(); diff --git a/tests/runtimes/edge-runtime/tsconfig.json b/tests/runtimes/edge-runtime/tsconfig.json new file mode 100644 index 000000000..b17ade81e --- /dev/null +++ b/tests/runtimes/edge-runtime/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@zenstackhq/typescript-config/base.json", + "compilerOptions": { + "noEmit": true + } +} diff --git a/tests/runtimes/edge-runtime/vitest.config.ts b/tests/runtimes/edge-runtime/vitest.config.ts new file mode 100644 index 000000000..e9e63f31a --- /dev/null +++ b/tests/runtimes/edge-runtime/vitest.config.ts @@ -0,0 +1,11 @@ +import base from '@zenstackhq/vitest-config/base'; +import { defineConfig, mergeConfig } from 'vitest/config'; + +export default mergeConfig( + base, + defineConfig({ + test: { + environment: 'edge-runtime', + }, + }), +); diff --git a/vitest.config.ts b/vitest.config.ts index f7268cb1f..e4c2666aa 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,6 +2,6 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { - projects: ['packages/*', 'tests/*'], + projects: ['packages/**', 'tests/**'], }, }); From 0492085c71f02874f97f27edac0454749dd9ff1e Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Tue, 2 Dec 2025 10:27:11 +0800 Subject: [PATCH 12/13] test(zmodel): more validation tests (#459) --- .../test/attribute-application.test.ts | 25 +++++++ .../language/test/this-resolution.test.ts | 71 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 packages/language/test/this-resolution.test.ts diff --git a/packages/language/test/attribute-application.test.ts b/packages/language/test/attribute-application.test.ts index 71d39323e..ce17ce499 100644 --- a/packages/language/test/attribute-application.test.ts +++ b/packages/language/test/attribute-application.test.ts @@ -20,4 +20,29 @@ describe('Attribute application validation tests', () => { `"before()" is only allowed in "post-update" policy rules`, ); }); + + it('requires relation and fk to have consistent optionality', async () => { + await loadSchemaWithError( + ` + datasource db { + provider = 'sqlite' + url = 'file:./dev.db' + } + + model Foo { + id Int @id @default(autoincrement()) + bar Bar @relation(fields: [barId], references: [id]) + barId Int? + @@allow('all', true) + } + + model Bar { + id Int @id @default(autoincrement()) + foos Foo[] + @@allow('all', true) + } + `, + /relation "bar" is not optional/, + ); + }); }); diff --git a/packages/language/test/this-resolution.test.ts b/packages/language/test/this-resolution.test.ts new file mode 100644 index 000000000..a9caa5a32 --- /dev/null +++ b/packages/language/test/this-resolution.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, it } from 'vitest'; +import { loadSchema, loadSchemaWithError } from './utils'; + +describe('This keyword resolution tests', () => { + it('always resolves to the containing model', async () => { + await loadSchemaWithError( + ` + datasource db { + provider = 'sqlite' + url = 'file:./dev.db' + } + + model A { + id Int @id @default(autoincrement()) + av Int + b B[] + + @@allow('read', b?[c?[cv == this.cv]]) + } + + model B { + id Int @id @default(autoincrement()) + bv Int + aId Int + a A @relation(fields: [aId], references: [id]) + c C[] + } + + model C { + id Int @id @default(autoincrement()) + cv Int + bId Int + b B @relation(fields: [bId], references: [id]) + } + `, + /MemberAccessTarget named 'cv'/, + ); + + await expect( + loadSchema(` + datasource db { + provider = 'sqlite' + url = 'file:./dev.db' + } + + model A { + id Int @id @default(autoincrement()) + av Int + b B[] + + @@allow('read', b?[c?[cv == this.av]]) + } + + model B { + id Int @id @default(autoincrement()) + bv Int + aId Int + a A @relation(fields: [aId], references: [id]) + c C[] + } + + model C { + id Int @id @default(autoincrement()) + cv Int + bId Int + b B @relation(fields: [bId], references: [id]) + } + `), + ).resolves.toBeTruthy(); + }); +}); From 6330c3bd3d27171f1f1db0aab8bdaa5f4ed9a004 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Tue, 2 Dec 2025 11:38:01 +0800 Subject: [PATCH 13/13] fix(orm): more robust timezone adjustment for postgres (#461) * fix(orm): more robust timezone adjustment for postgres * update --- .../orm/src/client/crud/dialects/postgresql.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/orm/src/client/crud/dialects/postgresql.ts b/packages/orm/src/client/crud/dialects/postgresql.ts index 50a9eb606..aa4cedd02 100644 --- a/packages/orm/src/client/crud/dialects/postgresql.ts +++ b/packages/orm/src/client/crud/dialects/postgresql.ts @@ -9,6 +9,7 @@ import { type SelectQueryBuilder, } from 'kysely'; import { match } from 'ts-pattern'; +import z from 'zod'; import type { BuiltinType, FieldDef, GetModels, SchemaDef } from '../../../schema'; import { DELEGATE_JOINED_FIELD_PREFIX } from '../../constants'; import type { FindArgs } from '../../crud-types'; @@ -26,6 +27,8 @@ import { import { BaseCrudDialect } from './base-dialect'; export class PostgresCrudDialect extends BaseCrudDialect { + private isoDateSchema = z.iso.datetime({ local: true, offset: true }); + constructor(schema: Schema, options: ClientOptions) { super(schema, options); } @@ -106,10 +109,16 @@ export class PostgresCrudDialect extends BaseCrudDiale private transformOutputDate(value: unknown) { if (typeof value === 'string') { - // PostgreSQL's jsonb_build_object serializes timestamptz as ISO 8601 strings - // in UTC but without the 'Z' suffix (e.g., "2023-01-01T12:00:00.123456"). - // We add 'Z' to explicitly mark them as UTC for correct Date object creation. - return new Date(value.endsWith('Z') ? value : `${value}Z`); + // PostgreSQL's jsonb_build_object serializes timestamp as ISO 8601 strings + // without timezone, (e.g., "2023-01-01T12:00:00.123456"). Since Date is always + // stored as UTC `timestamp` type, we add 'Z' to explicitly mark them as UTC for + // correct Date object creation. + if (this.isoDateSchema.safeParse(value).success) { + const hasOffset = value.endsWith('Z') || /[+-]\d{2}:\d{2}$/.test(value); + return new Date(hasOffset ? value : `${value}Z`); + } else { + return value; + } } else if (value instanceof Date && this.options.fixPostgresTimezone !== false) { // SPECIAL NOTES: // node-pg has a terrible quirk that it returns the date value in local timezone