diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60a55f9a6d..41a89a397b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -292,7 +292,7 @@ importers: version: 0.0.260331072558 '@rivet-dev/agent-os-pi': specifier: ^0.1.1 - version: 0.1.1(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76) + version: 0.1.1(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6) rivetkit: specifier: workspace:* version: link:../../rivetkit-typescript/packages/rivetkit @@ -3342,7 +3342,7 @@ importers: version: 5.2.2(react-hook-form@7.62.0(react@19.1.0)) '@ladle/react': specifier: ^5.1.1 - version: 5.1.1(@swc/helpers@0.5.17)(@types/node@20.19.13)(@types/react@19.2.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + version: 5.1.1(@swc/helpers@0.5.17)(@types/node@20.19.13)(@types/react@19.2.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) '@marsidev/react-turnstile': specifier: ^1.5.0 version: 1.5.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -3585,7 +3585,7 @@ importers: version: 2.4.3 better-auth: specifier: ^1.5.6 - version: 1.5.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(next@16.1.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 1.5.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(next@16.1.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) canvas-confetti: specifier: ^1.9.3 version: 1.9.3 @@ -3705,7 +3705,7 @@ importers: version: 5.2.0(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.13)(typescript@5.9.3))(typescript@5.9.3) unplugin-macros: specifier: ^0.18.3 - version: 0.18.3(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + version: 0.18.3(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) usehooks-ts: specifier: ^3.1.1 version: 3.1.1(react@19.1.0) @@ -3724,7 +3724,7 @@ importers: devDependencies: vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) frontend/packages/components: dependencies: @@ -4269,6 +4269,9 @@ importers: '@rivetkit/engine-envoy-protocol': specifier: workspace:* version: link:../../../engine/sdks/typescript/envoy-protocol + '@rivetkit/on-change': + specifier: 6.0.1 + version: 6.0.1 '@rivetkit/rivetkit-napi': specifier: workspace:* version: link:../rivetkit-napi @@ -4353,7 +4356,7 @@ importers: version: 5.9.3 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.10)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.1.4(typescript@5.9.3)(vite@5.4.21(@types/node@22.19.10)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)) vitest: specifier: ^3.1.1 version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.10)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@22.19.10)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0) @@ -7552,20 +7555,24 @@ packages: '@mariozechner/pi-agent-core@0.60.0': resolution: {integrity: sha512-1zQcfFp8r0iwZCxCBQ9/ccFJoagns68cndLPTJJXl1ZqkYirzSld1zBOPxLAgeAKWIz3OX8dB2WQwTJFhmEojQ==} engines: {node: '>=20.0.0'} + deprecated: please use @earendil-works/pi-agent-core instead going forward '@mariozechner/pi-ai@0.60.0': resolution: {integrity: sha512-OiMuXQturnEDPmA+ho7eLe4G8plO2z21yjNMs9niQREauoblWOz7Glv58I66KPzczLED4aZTlQLTRdU6t1rz8A==} engines: {node: '>=20.0.0'} + deprecated: please use @earendil-works/pi-ai instead going forward hasBin: true '@mariozechner/pi-coding-agent@0.60.0': resolution: {integrity: sha512-IOv7cTU4nbznFNUE5ofi13k2dmSG39coBoGWIBQTVw3iVyl0HxuHbg0NiTx3ktrPIDNtkii+y7tWXzWqwoo4lw==} engines: {node: '>=20.6.0'} + deprecated: please use @earendil-works/pi-coding-agent instead going forward hasBin: true '@mariozechner/pi-tui@0.60.0': resolution: {integrity: sha512-ZAK5gxYhGmfJqMjfWcRBjB8glITltDbTrYJXvcDtfengbKTZN0p39p5uO5pvUB8/PiAWKTRS06yaNMhf/LG26g==} engines: {node: '>=20.0.0'} + deprecated: please use @earendil-works/pi-tui instead going forward '@marsidev/react-turnstile@1.5.0': resolution: {integrity: sha512-Ph6mcj8u9WBDsBO7s9jKPsyRDz1sBPBJwrk+Ngx09vFInvKsQ6U6kW5amEcGq4dHOreB6DgFrOJk7/fy318YlQ==} @@ -8913,6 +8920,10 @@ packages: resolution: {integrity: sha512-3qndQUQXLdwafMEqfhz24hUtDPcsf1Bu3q52Kb8MqeH8JUh3h6R4HYW3ZJXiQsLcyYyFM68PuIwlLRlg1xDEpg==} engines: {node: ^14.18.0 || >=16.0.0} + '@rivetkit/on-change@6.0.1': + resolution: {integrity: sha512-QBN/KRBXLJdCgN4gBTL3XAc/zKm58atSnieXWMOyFSPmo6F1/yIVV/LTRdvAktfCttrGx7W6c32i/lwqCHWnsQ==} + engines: {node: '>=20'} + '@rivetkit/sql-loader@2.2.1': resolution: {integrity: sha512-qqykzDGak06VY58o8qh8TH7CL77vIp2FHUJB2ZT78LJ+muRrXiwj/QHeVn9ykWePqCYCD9XP0L6Qd2fmERdXqQ==} @@ -10450,6 +10461,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@urql/core@5.2.0': resolution: {integrity: sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==} @@ -18358,14 +18370,14 @@ snapshots: '@adobe/css-tools@4.3.3': optional: true - '@agentclientprotocol/sdk@0.16.1(zod@3.25.76)': - dependencies: - zod: 3.25.76 - '@agentclientprotocol/sdk@0.16.1(zod@4.1.13)': dependencies: zod: 4.1.13 + '@agentclientprotocol/sdk@0.16.1(zod@4.3.6)': + dependencies: + zod: 4.3.6 + '@ai-sdk/anthropic@1.2.12(zod@4.1.13)': dependencies: '@ai-sdk/provider': 1.1.3 @@ -18527,17 +18539,17 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.2 - '@anthropic-ai/sdk@0.73.0(zod@3.25.76)': + '@anthropic-ai/sdk@0.73.0(zod@4.1.13)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: - zod: 3.25.76 + zod: 4.1.13 - '@anthropic-ai/sdk@0.73.0(zod@4.1.13)': + '@anthropic-ai/sdk@0.73.0(zod@4.3.6)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: - zod: 4.1.13 + zod: 4.3.6 '@asteasolutions/zod-to-openapi@8.2.0(zod@4.1.13)': dependencies: @@ -20817,27 +20829,27 @@ snapshots: '@fortawesome/fontawesome-svg-core': 7.1.0 react: 19.1.0 - '@google/genai@1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))': + '@google/genai@1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))': dependencies: google-auth-library: 10.6.2 p-retry: 4.6.2 protobufjs: 7.5.4 ws: 8.19.0 optionalDependencies: - '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.9)(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.9)(zod@4.1.13) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@google/genai@1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))': + '@google/genai@1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))': dependencies: google-auth-library: 10.6.2 p-retry: 4.6.2 protobufjs: 7.5.4 ws: 8.19.0 optionalDependencies: - '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.9)(zod@4.1.13) + '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.9)(zod@4.3.6) transitivePeerDependencies: - bufferutil - supports-color @@ -21329,7 +21341,7 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@ladle/react@5.1.1(@swc/helpers@0.5.17)(@types/node@20.19.13)(@types/react@19.2.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)': + '@ladle/react@5.1.1(@swc/helpers@0.5.17)(@types/node@20.19.13)(@types/react@19.2.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)': dependencies: '@babel/code-frame': 7.29.0 '@babel/core': 7.29.0 @@ -21341,8 +21353,8 @@ snapshots: '@ladle/react-context': 1.0.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mdx-js/mdx': 3.1.1 '@mdx-js/react': 3.1.1(@types/react@19.2.13)(react@19.1.0) - '@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@vitejs/plugin-react-swc': 3.11.0(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-react-swc': 3.11.0(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) axe-core: 4.11.1 boxen: 8.0.1 chokidar: 4.0.3 @@ -21369,8 +21381,8 @@ snapshots: remark-gfm: 4.0.1 source-map: 0.7.6 vfile: 6.0.3 - vite: 6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + vite: 6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@swc/helpers' - '@types/node' @@ -21482,9 +21494,9 @@ snapshots: std-env: 3.10.0 yoctocolors: 2.1.2 - '@mariozechner/pi-agent-core@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76)': + '@mariozechner/pi-agent-core@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13)': dependencies: - '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76) + '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -21494,9 +21506,9 @@ snapshots: - ws - zod - '@mariozechner/pi-agent-core@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13)': + '@mariozechner/pi-agent-core@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6)': dependencies: - '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) + '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -21506,21 +21518,21 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76)': + '@mariozechner/pi-ai@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13)': dependencies: - '@anthropic-ai/sdk': 0.73.0(zod@3.25.76) + '@anthropic-ai/sdk': 0.73.0(zod@4.1.13) '@aws-sdk/client-bedrock-runtime': 3.1024.0 - '@google/genai': 1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76)) + '@google/genai': 1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13)) '@mistralai/mistralai': 1.14.1 '@sinclair/typebox': 0.34.41 ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) chalk: 5.6.2 - openai: 6.26.0(ws@8.19.0)(zod@3.25.76) + openai: 6.26.0(ws@8.19.0)(zod@4.1.13) partial-json: 0.1.7 proxy-agent: 6.5.0 undici: 7.24.7 - zod-to-json-schema: 3.25.1(zod@3.25.76) + zod-to-json-schema: 3.25.1(zod@4.1.13) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -21530,21 +21542,21 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13)': + '@mariozechner/pi-ai@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6)': dependencies: - '@anthropic-ai/sdk': 0.73.0(zod@4.1.13) + '@anthropic-ai/sdk': 0.73.0(zod@4.3.6) '@aws-sdk/client-bedrock-runtime': 3.1024.0 - '@google/genai': 1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13)) + '@google/genai': 1.48.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6)) '@mistralai/mistralai': 1.14.1 '@sinclair/typebox': 0.34.41 ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) chalk: 5.6.2 - openai: 6.26.0(ws@8.19.0)(zod@4.1.13) + openai: 6.26.0(zod@4.3.6) partial-json: 0.1.7 proxy-agent: 6.5.0 undici: 7.24.7 - zod-to-json-schema: 3.25.1(zod@4.1.13) + zod-to-json-schema: 3.25.1(zod@4.3.6) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -21554,11 +21566,11 @@ snapshots: - ws - zod - '@mariozechner/pi-coding-agent@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76)': + '@mariozechner/pi-coding-agent@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13)': dependencies: '@mariozechner/jiti': 2.6.5 - '@mariozechner/pi-agent-core': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76) - '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76) + '@mariozechner/pi-agent-core': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) + '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) '@mariozechner/pi-tui': 0.60.0 '@silvia-odwyer/photon-node': 0.3.4 chalk: 5.6.2 @@ -21586,11 +21598,11 @@ snapshots: - ws - zod - '@mariozechner/pi-coding-agent@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13)': + '@mariozechner/pi-coding-agent@0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6)': dependencies: '@mariozechner/jiti': 2.6.5 - '@mariozechner/pi-agent-core': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) - '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) + '@mariozechner/pi-agent-core': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6) + '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6) '@mariozechner/pi-tui': 0.60.0 '@silvia-odwyer/photon-node': 0.3.4 chalk: 5.6.2 @@ -21973,6 +21985,29 @@ snapshots: - supports-color optional: true + '@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.13(hono@4.11.9) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 7.5.1(express@5.2.1) + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.1(zod@4.3.6) + transitivePeerDependencies: + - hono + - supports-color + optional: true + '@monaco-editor/loader@1.7.0': dependencies: state-local: 1.0.7 @@ -23348,11 +23383,11 @@ snapshots: '@rivet-dev/agent-os-gzip@0.0.260331072558': {} - '@rivet-dev/agent-os-pi@0.1.1(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76)': + '@rivet-dev/agent-os-pi@0.1.1(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(pyodide@0.28.3)(ws@8.19.0)(zod@4.1.13)': dependencies: - '@agentclientprotocol/sdk': 0.16.1(zod@3.25.76) - '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76) - '@mariozechner/pi-coding-agent': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@3.25.76))(ws@8.19.0)(zod@3.25.76) + '@agentclientprotocol/sdk': 0.16.1(zod@4.1.13) + '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) + '@mariozechner/pi-coding-agent': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) '@rivet-dev/agent-os-core': 0.1.1(pyodide@0.28.3) transitivePeerDependencies: - '@modelcontextprotocol/sdk' @@ -23364,11 +23399,11 @@ snapshots: - ws - zod - '@rivet-dev/agent-os-pi@0.1.1(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(pyodide@0.28.3)(ws@8.19.0)(zod@4.1.13)': + '@rivet-dev/agent-os-pi@0.1.1(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6)': dependencies: - '@agentclientprotocol/sdk': 0.16.1(zod@4.1.13) - '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) - '@mariozechner/pi-coding-agent': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.1.13))(ws@8.19.0)(zod@4.1.13) + '@agentclientprotocol/sdk': 0.16.1(zod@4.3.6) + '@mariozechner/pi-ai': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6) + '@mariozechner/pi-coding-agent': 0.60.0(@modelcontextprotocol/sdk@1.25.3(hono@4.11.9)(zod@4.3.6))(zod@4.3.6) '@rivet-dev/agent-os-core': 0.1.1(pyodide@0.28.3) transitivePeerDependencies: - '@modelcontextprotocol/sdk' @@ -23420,6 +23455,8 @@ snapshots: '@rivetkit/bare-ts@0.6.2': {} + '@rivetkit/on-change@6.0.1': {} + '@rivetkit/sql-loader@2.2.1': {} '@rolldown/pluginutils@1.0.0-beta.27': {} @@ -25430,11 +25467,11 @@ snapshots: d3-time-format: 4.1.0 internmap: 2.0.3 - '@vitejs/plugin-react-swc@3.11.0(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-react-swc@3.11.0(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.27 '@swc/core': 1.15.11(@swc/helpers@0.5.17) - vite: 6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@swc/helpers' @@ -25474,7 +25511,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -25482,7 +25519,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -25576,14 +25613,14 @@ snapshots: msw: 2.12.10(@types/node@22.19.15)(typescript@5.9.3) vite: 5.4.21(@types/node@22.19.15)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0) - '@vitest/mocker@4.0.18(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.10(@types/node@20.19.13)(typescript@5.9.3) - vite: 6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@2.1.9': dependencies: @@ -26404,7 +26441,7 @@ snapshots: bcryptjs@2.4.3: {} - better-auth@1.5.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(next@16.1.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + better-auth@1.5.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(next@16.1.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) '@better-auth/drizzle-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0)) @@ -26431,7 +26468,7 @@ snapshots: pg: 8.17.2 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@cloudflare/workers-types' - '@opentelemetry/api' @@ -31341,16 +31378,15 @@ snapshots: transitivePeerDependencies: - encoding - openai@6.26.0(ws@8.19.0)(zod@3.25.76): - optionalDependencies: - ws: 8.19.0 - zod: 3.25.76 - openai@6.26.0(ws@8.19.0)(zod@4.1.13): optionalDependencies: ws: 8.19.0 zod: 4.1.13 + openai@6.26.0(zod@4.3.6): + optionalDependencies: + zod: 4.3.6 + openapi-types@12.1.3: {} openapi3-ts@4.5.0: @@ -34027,13 +34063,13 @@ snapshots: unpipe@1.0.0: {} - unplugin-macros@0.18.3(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + unplugin-macros@0.18.3(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: ast-kit: 2.2.0 magic-string-ast: 1.0.3 unplugin: 2.3.10 - vite: 7.3.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - vite-node: 5.2.0(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite-node: 5.2.0(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -34320,13 +34356,13 @@ snapshots: - supports-color - terser - vite-node@5.2.0(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + vite-node@5.2.0(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: cac: 6.7.14 es-module-lexer: 1.7.0 obug: 2.0.0(ms@2.1.3) pathe: 2.0.3 - vite: 7.3.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -34399,24 +34435,24 @@ snapshots: - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@5.4.21(@types/node@22.19.10)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: 6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 5.4.21(@types/node@22.19.10)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0) transitivePeerDependencies: - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.10)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: 7.3.1(@types/node@22.19.10)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - typescript @@ -34463,7 +34499,7 @@ snapshots: stylus: 0.62.0 terser: 5.46.0 - vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -34474,7 +34510,7 @@ snapshots: optionalDependencies: '@types/node': 20.19.13 fsevents: 2.3.3 - jiti: 1.21.7 + jiti: 2.6.1 less: 4.4.1 lightningcss: 1.32.0 sass: 1.93.2 @@ -34523,7 +34559,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vite@7.3.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + vite@7.3.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -34534,26 +34570,6 @@ snapshots: optionalDependencies: '@types/node': 20.19.13 fsevents: 2.3.3 - jiti: 1.21.7 - less: 4.4.1 - lightningcss: 1.32.0 - sass: 1.93.2 - stylus: 0.62.0 - terser: 5.46.0 - tsx: 4.21.0 - yaml: 2.8.2 - - vite@7.3.1(@types/node@22.19.10)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.19.10 - fsevents: 2.3.3 jiti: 2.6.1 less: 4.4.1 lightningcss: 1.32.0 @@ -34562,7 +34578,6 @@ snapshots: terser: 5.46.0 tsx: 4.21.0 yaml: 2.8.2 - optional: true vite@7.3.1(@types/node@25.0.7)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: @@ -34808,10 +34823,10 @@ snapshots: - supports-color - terser - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(vite@6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.0.18(msw@2.12.10(@types/node@20.19.13)(typescript@5.9.3))(vite@6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -34828,7 +34843,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 6.4.1(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@20.19.13)(jiti@2.6.1)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 diff --git a/rivetkit-typescript/packages/rivetkit/package.json b/rivetkit-typescript/packages/rivetkit/package.json index 05a18ee3cb..e72854aeb1 100644 --- a/rivetkit-typescript/packages/rivetkit/package.json +++ b/rivetkit-typescript/packages/rivetkit/package.json @@ -168,13 +168,14 @@ "actor-config-schema-gen": "tsx scripts/actor-config-schema-gen.ts" }, "dependencies": { - "@rivet-dev/agent-os-core": "^0.1.1", "@hono/node-server": "^1.18.2", "@hono/node-ws": "^1.1.1", "@hono/zod-openapi": "^1.1.5", + "@rivet-dev/agent-os-core": "^0.1.1", "@rivetkit/bare-ts": "^0.6.2", "@rivetkit/engine-cli": "workspace:*", "@rivetkit/engine-envoy-protocol": "workspace:*", + "@rivetkit/on-change": "6.0.1", "@rivetkit/rivetkit-napi": "workspace:*", "@rivetkit/rivetkit-wasm": "workspace:*", "@rivetkit/traces": "workspace:*", @@ -192,10 +193,10 @@ "zod": "^4.1.0" }, "devDependencies": { + "@biomejs/biome": "^2.3", "@copilotkit/llmock": "^1.6.0", "@rivet-dev/agent-os-common": "*", "@rivet-dev/agent-os-pi": "^0.1.1", - "@biomejs/biome": "^2.3", "@standard-schema/spec": "^1.0.0", "@types/invariant": "^2", "@types/node": "^22.13.1", diff --git a/rivetkit-typescript/packages/rivetkit/src/client/actor-conn.ts b/rivetkit-typescript/packages/rivetkit/src/client/actor-conn.ts index ff3454b7ed..1a2df13c49 100644 --- a/rivetkit-typescript/packages/rivetkit/src/client/actor-conn.ts +++ b/rivetkit-typescript/packages/rivetkit/src/client/actor-conn.ts @@ -22,6 +22,7 @@ import { import { assertUnreachable, stringifyError } from "@/common/utils"; import type { UniversalWebSocket } from "@/common/websocket-interface"; import type { EngineControlClient } from "@/engine-client/driver"; +import type { CborSerializable } from "@/common/encoding"; import { decodeCborCompat, deserializeWithEncoding, @@ -1269,7 +1270,7 @@ export class ActorConnRaw { name: msg.body.val.name, args: bufferToArrayBuffer( encodeCborCompat( - msg.body.val.args, + msg.body.val.args as CborSerializable, ), ), }, diff --git a/rivetkit-typescript/packages/rivetkit/src/client/actor-handle.ts b/rivetkit-typescript/packages/rivetkit/src/client/actor-handle.ts index e6c17a60c5..16377379ad 100644 --- a/rivetkit-typescript/packages/rivetkit/src/client/actor-handle.ts +++ b/rivetkit-typescript/packages/rivetkit/src/client/actor-handle.ts @@ -23,6 +23,7 @@ import { } from "@/common/client-protocol-zod"; import { deconstructError } from "@/common/utils"; import type { EngineControlClient } from "@/engine-client/driver"; +import type { CborSerializable } from "@/common/encoding"; import { decodeCborCompat, deserializeWithEncoding, encodeCborCompat } from "@/serde"; import { bufferToArrayBuffer } from "@/utils"; import type { @@ -332,7 +333,7 @@ export class ActorHandleRaw { args, }), requestToBare: (args): protocol.HttpActionRequest => ({ - args: bufferToArrayBuffer(encodeCborCompat(args)), + args: bufferToArrayBuffer(encodeCborCompat(args as CborSerializable)), }), responseFromJson: (json): Response => json.output as Response, responseFromBare: (bare): Response => diff --git a/rivetkit-typescript/packages/rivetkit/src/client/queue.ts b/rivetkit-typescript/packages/rivetkit/src/client/queue.ts index b1b3f4259d..c1acbed540 100644 --- a/rivetkit-typescript/packages/rivetkit/src/client/queue.ts +++ b/rivetkit-typescript/packages/rivetkit/src/client/queue.ts @@ -12,6 +12,7 @@ import { type HttpQueueSendResponse as HttpQueueSendResponseJson, HttpQueueSendResponseSchema, } from "@/common/client-protocol-zod"; +import type { CborSerializable } from "@/common/encoding"; import { decodeCborCompat, encodeCborCompat } from "@/serde"; import { bufferToArrayBuffer } from "@/utils"; import { sendHttpRequest } from "./utils"; @@ -111,7 +112,7 @@ export function createQueueSender( }), requestToBare: (value): protocol.HttpQueueSendRequest => ({ name: value.name ?? name, - body: bufferToArrayBuffer(encodeCborCompat(value.body)), + body: bufferToArrayBuffer(encodeCborCompat(value.body as CborSerializable)), wait: value.wait ?? false, timeout: value.timeout !== undefined ? BigInt(value.timeout) : null, diff --git a/rivetkit-typescript/packages/rivetkit/src/common/encoding.ts b/rivetkit-typescript/packages/rivetkit/src/common/encoding.ts index 02ab40c951..e1f23ec49d 100644 --- a/rivetkit-typescript/packages/rivetkit/src/common/encoding.ts +++ b/rivetkit-typescript/packages/rivetkit/src/common/encoding.ts @@ -13,6 +13,168 @@ const JSON_COMPAT_BIGINT = "$BigInt"; const JSON_COMPAT_ARRAY_BUFFER = "$ArrayBuffer"; const JSON_COMPAT_UINT8_ARRAY = "$Uint8Array"; const JSON_COMPAT_UNDEFINED = "$Undefined"; +const JSON_COMPAT_SET = "$Set"; + +/** + * Recursive type representing all values that can be serialized via CBOR + * (cbor-x). Matches the supported CBOR tag set: primitives, BigInt (tags 2/3), + * Date (tags 0/1), Error (tag 27), TypedArrays (tags 64-82), ArrayBuffer, + * Map (tag 259), Set (custom $Set encoding), arrays, and plain objects. + */ +export type CborSerializable = + | string + | number + | boolean + | null + | undefined + | bigint + | Date + | Error + | ArrayBuffer + | Uint8Array + | Uint8ClampedArray + | Uint16Array + | Uint32Array + | BigUint64Array + | Int8Array + | Int16Array + | Int32Array + | BigInt64Array + | Float32Array + | Float64Array + | CborSerializable[] + | Map + | Set + | { [key: string]: CborSerializable }; + +function isTypedArray(value: unknown): boolean { + return ( + value instanceof Uint8ClampedArray || + value instanceof Uint16Array || + value instanceof Uint32Array || + value instanceof BigUint64Array || + value instanceof Int8Array || + value instanceof Int16Array || + value instanceof Int32Array || + value instanceof BigInt64Array || + value instanceof Float32Array || + value instanceof Float64Array + ); +} + +/** + * Recursively validates that a value is CBOR serializable. Throws TypeError + * with a descriptive message for non-serializable values. + */ +export function assertCborSerializable( + value: unknown, + path = "", +): asserts value is CborSerializable { + if ( + value === null || + value === undefined || + typeof value === "string" || + typeof value === "number" || + typeof value === "boolean" || + typeof value === "bigint" + ) { + return; + } + + if (typeof value === "function") { + throw new TypeError( + `Value at ${path || "root"} is a function and is not CBOR serializable`, + ); + } + + if (typeof value === "symbol") { + throw new TypeError( + `Value at ${path || "root"} is a symbol and is not CBOR serializable`, + ); + } + + if ( + value instanceof Date || + value instanceof Error || + value instanceof ArrayBuffer || + value instanceof Uint8Array || + isTypedArray(value) + ) { + return; + } + + if (value instanceof RegExp) { + throw new TypeError( + `Value at ${path || "root"} is a RegExp and is not CBOR serializable`, + ); + } + + if (value instanceof WeakMap) { + throw new TypeError( + `Value at ${path || "root"} is a WeakMap and is not CBOR serializable`, + ); + } + + if (value instanceof WeakSet) { + throw new TypeError( + `Value at ${path || "root"} is a WeakSet and is not CBOR serializable`, + ); + } + + if (value instanceof WeakRef) { + throw new TypeError( + `Value at ${path || "root"} is a WeakRef and is not CBOR serializable`, + ); + } + + if (value instanceof Promise) { + throw new TypeError( + `Value at ${path || "root"} is a Promise and is not CBOR serializable`, + ); + } + + if (value instanceof Map) { + for (const [k, v] of value.entries()) { + assertCborSerializable(k, `${path || "root"}.key(${String(k)})`); + assertCborSerializable(v, `${path || "root"}.value(${String(k)})`); + } + return; + } + + if (value instanceof Set) { + let index = 0; + for (const item of value.values()) { + assertCborSerializable(item, `${path || "root"}.set[${index}]`); + index++; + } + return; + } + + if (Array.isArray(value)) { + for (let i = 0; i < value.length; i++) { + assertCborSerializable(value[i], `${path || "root"}[${i}]`); + } + return; + } + + if (isPlainObject(value)) { + for (const key in value) { + assertCborSerializable( + value[key as keyof typeof value], + path ? `${path}.${key}` : key, + ); + } + return; + } + + const typeName = + typeof value === "object" && value !== null + ? value.constructor?.name ?? typeof value + : typeof value; + throw new TypeError( + `Value at ${path || "root"} of type "${typeName}" is not CBOR serializable`, + ); +} export const EncodingSchema = z.enum(["json", "cbor", "bare"]); @@ -112,38 +274,95 @@ function isPlainObject(value: unknown): value is Record { return proto === Object.prototype || proto === null; } -export function encodeJsonCompatValue(input: any): any { +export function encodeJsonCompatValue(input: CborSerializable): unknown { + // Primitives + if (input === null) { + return input; + } if (input === undefined) { return [JSON_COMPAT_UNDEFINED, 0]; } + if ( + typeof input === "string" || + typeof input === "number" || + typeof input === "boolean" + ) { + return input; + } if (typeof input === "bigint") { return [JSON_COMPAT_BIGINT, input.toString()]; } + + // Binary types with custom encoding if (input instanceof ArrayBuffer) { return [JSON_COMPAT_ARRAY_BUFFER, base64EncodeArrayBuffer(input)]; } if (input instanceof Uint8Array) { return [JSON_COMPAT_UINT8_ARRAY, base64EncodeUint8Array(input)]; } + + // TypedArrays pass through for cbor-x native handling + if (isTypedArray(input)) { + return input; + } + + // Date and Error pass through for cbor-x native handling + if (input instanceof Date || input instanceof Error) { + return input; + } + + // Set uses custom tag encoding + if (input instanceof Set) { + const encoded = [...input.values()].map((v) => + encodeJsonCompatValue(v as CborSerializable), + ); + return [JSON_COMPAT_SET, encoded]; + } + + // Map recurses into keys and values + if (input instanceof Map) { + const encoded = new Map(); + for (const [k, v] of input.entries()) { + encoded.set( + encodeJsonCompatValue(k as CborSerializable), + encodeJsonCompatValue(v as CborSerializable), + ); + } + return encoded; + } + + // Arrays if (Array.isArray(input)) { - const encoded = input.map((value) => encodeJsonCompatValue(value)); + const encoded = input.map((value) => + encodeJsonCompatValue(value as CborSerializable), + ); if ( encoded.length === 2 && typeof encoded[0] === "string" && - encoded[0].startsWith("$") + (encoded[0] as string).startsWith("$") ) { return ["$" + encoded[0], encoded[1]]; } return encoded; } + + // Plain objects if (isPlainObject(input)) { const encoded: Record = {}; for (const [key, value] of Object.entries(input)) { - encoded[key] = encodeJsonCompatValue(value); + encoded[key] = encodeJsonCompatValue(value as CborSerializable); } return encoded; } - return input; + + // Not serializable + const typeName = + typeof input === "object" && input !== null + ? (input as object).constructor?.name ?? typeof input + : typeof input; + throw new TypeError( + `Value of type "${typeName}" is not CBOR serializable`, + ); } export interface JsonCompatReviveOptions { @@ -182,6 +401,12 @@ export function reviveJsonCompatValue( if (input[0] === JSON_COMPAT_UNDEFINED) { return undefined; } + if (input[0] === JSON_COMPAT_SET) { + const items = (input[1] as unknown[]).map((v) => + reviveJsonCompatValue(v, options), + ); + return new Set(items); + } if (input[0].startsWith("$$")) { return [ input[0].substring(1), diff --git a/rivetkit-typescript/packages/rivetkit/src/common/router.ts b/rivetkit-typescript/packages/rivetkit/src/common/router.ts index 86977220e1..1dfac4a342 100644 --- a/rivetkit-typescript/packages/rivetkit/src/common/router.ts +++ b/rivetkit-typescript/packages/rivetkit/src/common/router.ts @@ -6,7 +6,7 @@ import { HEADER_ACTOR_ID, HEADER_ACTOR_KEY, } from "@/common/actor-router-consts"; -import type { Encoding } from "@/common/encoding"; +import type { CborSerializable, Encoding } from "@/common/encoding"; import { getRequestEncoding, getRequestExposeInternalError, @@ -111,7 +111,7 @@ export function handleRouteError(error: unknown, c: HonoContext) { code: value.code, message: value.message, metadata: value.metadata - ? bufferToArrayBuffer(encodeCborCompat(value.metadata)) + ? bufferToArrayBuffer(encodeCborCompat(value.metadata as CborSerializable)) : null, actor: value.actor ? { diff --git a/rivetkit-typescript/packages/rivetkit/src/common/utils.ts b/rivetkit-typescript/packages/rivetkit/src/common/utils.ts index 0ebac43829..1fbc01c8eb 100644 --- a/rivetkit-typescript/packages/rivetkit/src/common/utils.ts +++ b/rivetkit-typescript/packages/rivetkit/src/common/utils.ts @@ -36,154 +36,6 @@ export function safeStringify(obj: unknown, maxSize: number) { return JSON.stringify(obj, replacer); } -// TODO: Instead of doing this, use a temp var for state and attempt to write -// it. Roll back state if fails to serialize. - -/** - * Check if a value is CBOR serializable. - * Optionally pass an onInvalid callback to receive the path to invalid values. - * - * For a complete list of supported CBOR tags, see: - * https://github.com/kriszyp/cbor-x/blob/cc1cf9df8ba72288c7842af1dd374d73e34cdbc1/README.md#list-of-supported-tags-for-decoding - */ -export function isCborSerializable( - value: unknown, - onInvalid?: (path: string) => void, - currentPath = "", -): boolean { - // Handle primitive types directly - if (value === null || value === undefined) { - return true; - } - - if (typeof value === "number") { - if (!Number.isFinite(value)) { - onInvalid?.(currentPath); - return false; - } - return true; - } - - if (typeof value === "boolean" || typeof value === "string") { - return true; - } - - // Handle BigInt (CBOR tags 2 and 3) - if (typeof value === "bigint") { - return true; - } - - // Handle Date objects (CBOR tags 0 and 1) - if (value instanceof Date) { - return true; - } - - // Handle typed arrays (CBOR tags 64-82) - if ( - value instanceof Uint8Array || - value instanceof Uint8ClampedArray || - value instanceof Uint16Array || - value instanceof Uint32Array || - value instanceof BigUint64Array || - value instanceof Int8Array || - value instanceof Int16Array || - value instanceof Int32Array || - value instanceof BigInt64Array || - value instanceof Float32Array || - value instanceof Float64Array - ) { - return true; - } - - // Handle Map (CBOR tag 259) - if (value instanceof Map) { - for (const [key, val] of value.entries()) { - const keyPath = currentPath - ? `${currentPath}.key(${String(key)})` - : `key(${String(key)})`; - const valPath = currentPath - ? `${currentPath}.value(${String(key)})` - : `value(${String(key)})`; - if ( - !isCborSerializable(key, onInvalid, keyPath) || - !isCborSerializable(val, onInvalid, valPath) - ) { - return false; - } - } - return true; - } - - // Handle Set (CBOR tag 258) - if (value instanceof Set) { - let index = 0; - for (const item of value.values()) { - const itemPath = currentPath - ? `${currentPath}.set[${index}]` - : `set[${index}]`; - if (!isCborSerializable(item, onInvalid, itemPath)) { - return false; - } - index++; - } - return true; - } - - // Handle RegExp (CBOR tag 27) - if (value instanceof RegExp) { - return true; - } - - // Handle Error objects (CBOR tag 27) - if (value instanceof Error) { - return true; - } - - // Handle arrays - if (Array.isArray(value)) { - for (let i = 0; i < value.length; i++) { - const itemPath = currentPath ? `${currentPath}[${i}]` : `[${i}]`; - if (!isCborSerializable(value[i], onInvalid, itemPath)) { - return false; - } - } - return true; - } - - // Handle plain objects and records (CBOR tags 105, 51, 57344-57599) - if (typeof value === "object") { - // Allow plain objects and objects with prototypes (for records and named objects) - const proto = Object.getPrototypeOf(value); - if (proto !== null && proto !== Object.prototype) { - // Check if it's a known serializable object type - const protoConstructor = value.constructor; - if (protoConstructor && typeof protoConstructor.name === "string") { - // Allow objects with named constructors (records, named objects) - // This includes user-defined classes and built-in objects - // that CBOR can serialize with tag 27 or record tags - } - } - - // Check all properties recursively - for (const key in value) { - const propPath = currentPath ? `${currentPath}.${key}` : key; - if ( - !isCborSerializable( - value[key as keyof typeof value], - onInvalid, - propPath, - ) - ) { - return false; - } - } - return true; - } - - // Not serializable - onInvalid?.(currentPath); - return false; -} export interface DeconstructedError { __type: "ActorError"; diff --git a/rivetkit-typescript/packages/rivetkit/src/engine-client/actor-websocket-client.ts b/rivetkit-typescript/packages/rivetkit/src/engine-client/actor-websocket-client.ts index 34e694de2c..62ec139fb9 100644 --- a/rivetkit-typescript/packages/rivetkit/src/engine-client/actor-websocket-client.ts +++ b/rivetkit-typescript/packages/rivetkit/src/engine-client/actor-websocket-client.ts @@ -16,6 +16,7 @@ import { importWebSocket } from "@/common/websocket"; import { setRemoteHibernatableWebSocketAckTestHooks } from "@/common/websocket-test-hooks"; import type { ActorGatewayQuery, CrashPolicy } from "@/client/query"; import type { Encoding, UniversalWebSocket } from "@/mod"; +import type { CborSerializable } from "@/common/encoding"; import { encodeCborCompat, uint8ArrayToBase64 } from "@/serde"; import { combineUrlPath } from "@/utils"; import { shouldSkipReadyWait, type GatewayRequestOptions } from "./driver"; @@ -302,7 +303,7 @@ function pushInputQueryParam( return; } - const encodedInput = encodeCborCompat(input); + const encodedInput = encodeCborCompat(input as CborSerializable); if (encodedInput.byteLength > maxInputSize) { throw new Error( `Actor query input exceeds maxInputSize (${encodedInput.byteLength} > ${maxInputSize} bytes). Increase client maxInputSize to allow larger query payloads.`, diff --git a/rivetkit-typescript/packages/rivetkit/src/engine-client/mod.ts b/rivetkit-typescript/packages/rivetkit/src/engine-client/mod.ts index 3ac79c195b..8e91ef7111 100644 --- a/rivetkit-typescript/packages/rivetkit/src/engine-client/mod.ts +++ b/rivetkit-typescript/packages/rivetkit/src/engine-client/mod.ts @@ -23,6 +23,7 @@ import type { RuntimeDisplayInformation, } from "@/engine-client/driver"; import type { Encoding, UniversalWebSocket } from "@/mod"; +import type { CborSerializable } from "@/common/encoding"; import { encodeCborCompat, uint8ArrayToBase64 } from "@/serde"; import { combineUrlPath, type GetUpgradeWebSocket } from "@/utils"; import { getNextPhase } from "@/utils/env-vars"; @@ -181,7 +182,7 @@ export class RemoteEngineControlClient implements EngineControlClient { key: serializeActorKey(key), runner_name_selector: this.#config.poolName, input: actorInput - ? uint8ArrayToBase64(encodeCborCompat(actorInput)) + ? uint8ArrayToBase64(encodeCborCompat(actorInput as CborSerializable)) : undefined, crash_policy: crashPolicy ?? "sleep", }); @@ -215,7 +216,7 @@ export class RemoteEngineControlClient implements EngineControlClient { runner_name_selector: this.#config.poolName, key: serializeActorKey(key), input: input - ? uint8ArrayToBase64(encodeCborCompat(input)) + ? uint8ArrayToBase64(encodeCborCompat(input as CborSerializable)) : undefined, crash_policy: crashPolicy ?? "sleep", }); diff --git a/rivetkit-typescript/packages/rivetkit/src/registry/native.ts b/rivetkit-typescript/packages/rivetkit/src/registry/native.ts index 7c0be17e11..7c22f65520 100644 --- a/rivetkit-typescript/packages/rivetkit/src/registry/native.ts +++ b/rivetkit-typescript/packages/rivetkit/src/registry/native.ts @@ -33,6 +33,10 @@ import { HEADER_CONN_PARAMS } from "@/common/actor-router-consts"; import type { AnyDatabaseProvider } from "@/common/database/config"; import { wrapJsNativeDatabase } from "@/common/database/native-database"; import { decodeWorkflowHistoryTransport } from "@/common/inspector-transport"; +import { + assertCborSerializable, + type CborSerializable, +} from "@/common/encoding"; import { deconstructError, stringifyError } from "@/common/utils"; import type { RivetCloseEvent, @@ -54,6 +58,7 @@ import { } from "@/serde"; import { getEnvUniversal, VERSION } from "@/utils"; import { logger } from "./log"; +import { createWriteThroughProxy } from "./write-through-proxy"; import { loadNapiRuntime } from "./napi-runtime"; import { type NativeValidationConfig, @@ -592,7 +597,7 @@ function decodeValue(value?: RuntimeBytes | null): T { } function encodeValue(value: unknown): RuntimeBytes { - return encodeCborCompat(value); + return encodeCborCompat(value as CborSerializable); } function unwrapTsfnPayload(error: unknown, payload: T): T { @@ -1067,54 +1072,6 @@ function decodeArgs(value?: RuntimeBytes | null): unknown[] { : [decoded]; } -function createWriteThroughProxy( - value: T, - commit: (next: T) => void, - beforeChange?: () => void, -): T { - if (!value || typeof value !== "object") { - return value; - } - - const proxies = new WeakMap(); - const wrap = (target: object): object => { - const cached = proxies.get(target); - if (cached) { - return cached; - } - - const proxy = new Proxy(target, { - get(innerTarget, property, receiver) { - const result = Reflect.get(innerTarget, property, receiver); - return result && typeof result === "object" - ? wrap(result as object) - : result; - }, - set(innerTarget, property, nextValue, receiver) { - beforeChange?.(); - const updated = Reflect.set( - innerTarget, - property, - nextValue, - receiver, - ); - commit(value); - return updated; - }, - deleteProperty(innerTarget, property) { - beforeChange?.(); - const updated = Reflect.deleteProperty(innerTarget, property); - commit(value); - return updated; - }, - }); - - proxies.set(target, proxy); - return proxy; - }; - - return wrap(value as object) as T; -} function buildRequest(init: { method: string; @@ -1209,10 +1166,13 @@ class NativeConnAdapter { const nextState = this.#readState(); return createWriteThroughProxy(nextState, (nextValue) => { this.#writeState(nextValue, { writeNative: true }); + }, (newValue) => { + assertCborSerializable(newValue); }); } set state(value: unknown) { + assertCborSerializable(value); this.#writeState(value, { writeNative: true }); } @@ -2505,8 +2465,9 @@ export class ActorContextHandleAdapter { (nextValue) => { this.#writeState(nextValue, { scheduleSave: true }); }, - () => { + (newValue) => { this.#assertCanMutateState(); + assertCborSerializable(newValue); }, ); } @@ -2516,6 +2477,7 @@ export class ActorContextHandleAdapter { throw stateNotEnabledError(); } this.#assertCanMutateState(); + assertCborSerializable(value); this.#writeState(value, { scheduleSave: true }); } diff --git a/rivetkit-typescript/packages/rivetkit/src/registry/write-through-proxy.ts b/rivetkit-typescript/packages/rivetkit/src/registry/write-through-proxy.ts new file mode 100644 index 0000000000..b0dd032264 --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/src/registry/write-through-proxy.ts @@ -0,0 +1,37 @@ +import onChange from "@rivetkit/on-change"; + +/** + * Creates a proxy that tracks deep mutations on an object and calls `commit` + * after every change. Uses `@rivetkit/on-change` internally, which correctly + * detects mutations via methods on Map, Set, Date, TypedArrays, and arrays. + * + * If the value is not an object (primitive, null, undefined), it is returned + * as-is since primitives cannot be proxied or mutated. + * + * @param value - The root value to watch. + * @param commit - Called after every detected mutation with the root object. + * @param beforeChange - Called before every mutation with the new value being + * assigned. Throw to reject the change. + */ +export function createWriteThroughProxy( + value: T, + commit: (next: T) => void, + beforeChange?: (newValue: unknown) => void, +): T { + if (!value || typeof value !== "object") { + return value; + } + + return onChange( + value as T & Record, + () => { + commit(value); + }, + { + onValidate(_path: string, newValue: unknown) { + beforeChange?.(newValue); + return true; + }, + }, + ) as T; +} diff --git a/rivetkit-typescript/packages/rivetkit/src/serde.ts b/rivetkit-typescript/packages/rivetkit/src/serde.ts index 087e490ab2..e4db7f1086 100644 --- a/rivetkit-typescript/packages/rivetkit/src/serde.ts +++ b/rivetkit-typescript/packages/rivetkit/src/serde.ts @@ -3,7 +3,7 @@ import invariant from "invariant"; import type { VersionedDataHandler } from "vbare"; import type { z } from "zod/v4"; import { assertUnreachable } from "@/common/utils"; -import type { Encoding } from "@/common/encoding"; +import type { CborSerializable, Encoding } from "@/common/encoding"; import { encodeJsonCompatValue, jsonParseCompat, @@ -46,7 +46,7 @@ export function contentTypeForEncoding(encoding: Encoding): string { } } -export function encodeCborCompat(value: unknown): Uint8Array { +export function encodeCborCompat(value: CborSerializable): Uint8Array { return cbor.encode(encodeJsonCompatValue(value)); } diff --git a/rivetkit-typescript/packages/rivetkit/src/workflow/inspector.ts b/rivetkit-typescript/packages/rivetkit/src/workflow/inspector.ts index 0110ee1ffb..282a78b3b2 100644 --- a/rivetkit-typescript/packages/rivetkit/src/workflow/inspector.ts +++ b/rivetkit-typescript/packages/rivetkit/src/workflow/inspector.ts @@ -13,6 +13,7 @@ import type { import { encodeWorkflowHistoryTransport } from "@/common/inspector-transport"; import type * as inspectorSchema from "@/common/bare/generated/inspector/v4"; import * as transport from "@/common/bare/transport/v1"; +import type { CborSerializable } from "@/common/encoding"; import { encodeCborCompat } from "@/serde"; import { assertUnreachable, bufferToArrayBuffer } from "@/utils"; @@ -91,7 +92,7 @@ export function createWorkflowInspectorAdapter(): { } function encodeCbor(value: unknown): ArrayBuffer { - return bufferToArrayBuffer(encodeCborCompat(value)); + return bufferToArrayBuffer(encodeCborCompat(value as CborSerializable)); } function encodeOptionalCbor(value: unknown): ArrayBuffer | null { diff --git a/rivetkit-typescript/packages/rivetkit/tests/write-through-proxy.test.ts b/rivetkit-typescript/packages/rivetkit/tests/write-through-proxy.test.ts new file mode 100644 index 0000000000..b3a04dccdf --- /dev/null +++ b/rivetkit-typescript/packages/rivetkit/tests/write-through-proxy.test.ts @@ -0,0 +1,260 @@ +import { describe, expect, test, vi } from "vitest"; +import { createWriteThroughProxy } from "@/registry/write-through-proxy"; +import { + assertCborSerializable, + encodeJsonCompatValue, + reviveJsonCompatValue, +} from "@/common/encoding"; +import { decodeCborCompat, encodeCborCompat } from "@/serde"; + +describe("createWriteThroughProxy", () => { + test("tracks mutations on a record containing all supported types", () => { + const commit = vi.fn(); + + const state = createWriteThroughProxy( + { + str: "hello", + num: 42, + bool: true, + nil: null as null, + undef: undefined as undefined, + big: 99n, + date: new Date("2025-01-01"), + err: new Error("test"), + buf: new ArrayBuffer(8), + u8: new Uint8Array([1, 2, 3]), + u8c: new Uint8ClampedArray([4, 5]), + u16: new Uint16Array([6]), + u32: new Uint32Array([7]), + bu64: new BigUint64Array([8n]), + i8: new Int8Array([-1]), + i16: new Int16Array([-2]), + i32: new Int32Array([-3]), + bi64: new BigInt64Array([-4n]), + f32: new Float32Array([1.5]), + f64: new Float64Array([2.5]), + arr: [1, "two", 3n], + map: new Map([["a", 1]]), + set: new Set([10, 20, 30]), + nested: { inner: { deep: true } }, + }, + commit, + ); + + // Property set on root + commit.mockClear(); + state.str = "world"; + expect(commit).toHaveBeenCalledTimes(1); + expect(state.str).toBe("world"); + + // Nested property set + commit.mockClear(); + state.nested.inner.deep = false; + expect(commit).toHaveBeenCalledTimes(1); + expect(state.nested.inner.deep).toBe(false); + + // Array mutation via push + commit.mockClear(); + state.arr.push("four"); + expect(commit).toHaveBeenCalled(); + expect(state.arr).toContain("four"); + + // Map.set + commit.mockClear(); + state.map.set("b", 2); + expect(commit).toHaveBeenCalled(); + expect(state.map.get("b")).toBe(2); + + // Map.delete + commit.mockClear(); + state.map.delete("a"); + expect(commit).toHaveBeenCalled(); + expect(state.map.has("a")).toBe(false); + + // Set.add + commit.mockClear(); + state.set.add(40); + expect(commit).toHaveBeenCalled(); + expect(state.set.has(40)).toBe(true); + + // Set.delete + commit.mockClear(); + state.set.delete(10); + expect(commit).toHaveBeenCalled(); + expect(state.set.has(10)).toBe(false); + + // Date mutation + commit.mockClear(); + state.date.setFullYear(2030); + expect(commit).toHaveBeenCalled(); + expect(state.date.getFullYear()).toBe(2030); + + // TypedArray index set + commit.mockClear(); + state.u8[0] = 99; + expect(commit).toHaveBeenCalled(); + expect(state.u8[0]).toBe(99); + + // Delete property + commit.mockClear(); + delete (state as Record).bool; + expect(commit).toHaveBeenCalledTimes(1); + }); + + test("returns primitives as-is without proxying", () => { + const commit = vi.fn(); + expect(createWriteThroughProxy(42, commit)).toBe(42); + expect(createWriteThroughProxy("hi", commit)).toBe("hi"); + expect(createWriteThroughProxy(null, commit)).toBe(null); + expect(createWriteThroughProxy(undefined, commit)).toBe(undefined); + }); + + test("beforeChange receives the new value on property set", () => { + const commit = vi.fn(); + const beforeChange = vi.fn(); + + const state = createWriteThroughProxy( + { x: 1 }, + commit, + beforeChange, + ); + + state.x = 99; + expect(beforeChange).toHaveBeenCalled(); + }); + + test("beforeChange throwing prevents the mutation", () => { + const commit = vi.fn(); + const state = createWriteThroughProxy( + { x: 1 }, + commit, + () => { + throw new TypeError("rejected"); + }, + ); + + expect(() => { + state.x = 99; + }).toThrow("rejected"); + expect(commit).not.toHaveBeenCalled(); + expect(state.x).toBe(1); + }); +}); + +describe("assertCborSerializable", () => { + test("accepts all supported types without throwing", () => { + expect(() => + assertCborSerializable({ + str: "hello", + num: 42, + bool: true, + nil: null, + undef: undefined, + big: 99n, + date: new Date(), + err: new Error("test"), + buf: new ArrayBuffer(8), + u8: new Uint8Array([1]), + u8c: new Uint8ClampedArray([1]), + u16: new Uint16Array([1]), + u32: new Uint32Array([1]), + bu64: new BigUint64Array([1n]), + i8: new Int8Array([1]), + i16: new Int16Array([1]), + i32: new Int32Array([1]), + bi64: new BigInt64Array([1n]), + f32: new Float32Array([1]), + f64: new Float64Array([1]), + arr: [1, "two", 3n, [true]], + map: new Map([["k", "v"]]), + set: new Set([1, 2]), + nested: { deep: { value: 42 } }, + }), + ).not.toThrow(); + }); + + test("rejects a function", () => { + expect(() => assertCborSerializable(() => {})).toThrow(TypeError); + }); + + test("rejects a nested function", () => { + expect(() => + assertCborSerializable({ foo: () => {} }), + ).toThrow(TypeError); + }); + + test("rejects a symbol", () => { + expect(() => assertCborSerializable(Symbol("x"))).toThrow(TypeError); + }); + + test("rejects a RegExp", () => { + expect(() => assertCborSerializable(/abc/)).toThrow(TypeError); + }); + + test("rejects a WeakMap", () => { + expect(() => assertCborSerializable(new WeakMap())).toThrow(TypeError); + }); + + test("rejects a WeakSet", () => { + expect(() => assertCborSerializable(new WeakSet())).toThrow(TypeError); + }); + + test("rejects a Promise", () => { + expect(() => + assertCborSerializable(Promise.resolve()), + ).toThrow(TypeError); + }); + + test("rejects a function inside a Map value", () => { + expect(() => + assertCborSerializable(new Map([["k", () => {}]])), + ).toThrow(TypeError); + }); + + test("rejects a function inside a Set", () => { + expect(() => + assertCborSerializable(new Set([() => {}])), + ).toThrow(TypeError); + }); + + test("rejects a function inside an array", () => { + expect(() => assertCborSerializable([1, () => {}])).toThrow(TypeError); + }); +}); + +describe("Set encoding round-trip", () => { + test("encodeJsonCompatValue encodes Set as $Set tag", () => { + const encoded = encodeJsonCompatValue(new Set([1, 2, 3])); + expect(Array.isArray(encoded)).toBe(true); + expect(encoded[0]).toBe("$Set"); + expect(encoded[1]).toEqual([1, 2, 3]); + }); + + test("reviveJsonCompatValue revives $Set tag to Set", () => { + const revived = reviveJsonCompatValue(["$Set", [1, 2, 3]]); + expect(revived).toBeInstanceOf(Set); + expect(revived).toEqual(new Set([1, 2, 3])); + }); + + test("full CBOR round-trip preserves Sets", () => { + const original = { items: new Set([1, "two", 3n]) }; + const encoded = encodeCborCompat(original); + const decoded = decodeCborCompat(encoded); + expect(decoded.items).toBeInstanceOf(Set); + expect(decoded.items.has(1)).toBe(true); + expect(decoded.items.has("two")).toBe(true); + expect(decoded.items.has(3n)).toBe(true); + }); +}); + +describe("encodeJsonCompatValue validation", () => { + test("throws TypeError for a function value", () => { + const fn = (() => {}) as never; + expect(() => encodeJsonCompatValue(fn)).toThrow(TypeError); + }); + + test("throws TypeError for a nested function", () => { + const obj = { foo: () => {} } as never; + expect(() => encodeJsonCompatValue(obj)).toThrow(TypeError); + }); +});