🐜 fix: Fix an issue where ts-server is taking forever to load (#272)

## Description
<!-- Briefly describe the purpose and scope of your changes -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Centralized and standardized error response schemas for APIs.
- Utility functions for result formatting and enhanced validation error
handling.
  - New utility modules for authentication and OAuth provider handling.
  - Added Discord OAuth user data fetching with email verification.

- **Bug Fixes**
- Improved error safety in cloud task creation by preventing potential
runtime errors.

- **Refactor**
- Major simplification and reorganization of API routes and
authentication logic.
  - Migration from valibot to zod for schema validation.
  - Streamlined import paths and consolidated utility exports.
- Simplified TypeScript and .gitignore configuration for easier
maintenance.
  - Disabled machine authentication provider and related logic.

- **Chores**
- Removal of unused or deprecated API endpoints, database migration, and
permissions deployment code.
- Updated package dependencies and scripts for improved reliability and
performance.
  - Enhanced documentation and updated project metadata.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Wanjohi
2025-05-06 05:22:26 +03:00
committed by GitHub
parent 47e61599bb
commit a0dc353561
43 changed files with 502 additions and 1391 deletions

View File

@@ -71,7 +71,7 @@
"typescript": "5.4.5",
"undici": "*",
"valibot": "^0.42.1",
"vite": "6.0.14",
"vite": "6.0.15",
"vite-tsconfig-paths": "^4.2.1",
"wrangler": "^3.0.0",
},
@@ -104,7 +104,7 @@
"zod-openapi": "^4.2.2",
},
},
"packages/functions": {
"packages/fn": {
"name": "@nestri/functions",
"dependencies": {
"@actor-core/bun": "^0.7.9",
@@ -127,6 +127,22 @@
"typescript": "^5.0.0",
},
},
"packages/functions": {
"name": "functions",
"dependencies": {
"@actor-core/bun": "^0.8.0",
"@nestri-core": "workspace:",
"actor-core": "^0.8.0",
"hono": "^4.7.8",
"hono-openapi": "^0.4.8",
},
"devDependencies": {
"@types/bun": "latest",
},
"peerDependencies": {
"typescript": "^5",
},
},
"packages/input": {
"name": "@nestri/input",
"version": "0.0.0",
@@ -245,7 +261,7 @@
"@macaron-css/vite": "1.5.1",
"@types/bun": "latest",
"@types/qrcode": "^1.5.5",
"vite": "6.0.14",
"vite": "6.0.15",
"vite-plugin-solid": "^2.11.2",
},
"peerDependencies": {
@@ -774,9 +790,11 @@
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.7", "", { "dependencies": { "@emnapi/core": "^1.3.1", "@emnapi/runtime": "^1.3.1", "@tybys/wasm-util": "^0.9.0" } }, "sha512-5yximcFK5FNompXfJFoWanu5l8v1hNGqNHh9du1xETp9HWk/B/PzvchX55WYOPaIeNglG8++68AAiauBAtbnzw=="],
"@nestri-core": ["functions@workspace:packages/functions"],
"@nestri/core": ["@nestri/core@workspace:packages/core"],
"@nestri/functions": ["@nestri/functions@workspace:packages/functions"],
"@nestri/functions": ["@nestri/functions@workspace:packages/fn"],
"@nestri/input": ["@nestri/input@workspace:packages/input"],
@@ -1394,7 +1412,7 @@
"@types/babel__traverse": ["@types/babel__traverse@7.20.6", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg=="],
"@types/bun": ["@types/bun@1.2.9", "", { "dependencies": { "bun-types": "1.2.9" } }, "sha512-epShhLGQYc4Bv/aceHbmBhOz1XgUnuTZgcxjxk+WXwNyDXavv5QHD1QEFV0FwbTSQtNq6g4ZcV6y0vZakTjswg=="],
"@types/bun": ["@types/bun@1.2.12", "", { "dependencies": { "bun-types": "1.2.12" } }, "sha512-lY/GQTXDGsolT/TiH72p1tuyUORuRrdV7VwOTOjDOt8uTBJQOJc5zz3ufwwDl0VBaoxotSk4LdP0hhjLJ6ypIQ=="],
"@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="],
@@ -1472,21 +1490,21 @@
"@types/ws": ["@types/ws@8.18.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.29.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.29.1", "@typescript-eslint/type-utils": "8.29.1", "@typescript-eslint/utils": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.32.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/type-utils": "8.32.0", "@typescript-eslint/utils": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.29.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.29.1", "@typescript-eslint/types": "8.29.1", "@typescript-eslint/typescript-estree": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.32.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.29.1", "", { "dependencies": { "@typescript-eslint/types": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1" } }, "sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0" } }, "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.29.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.29.1", "@typescript-eslint/utils": "8.29.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.32.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.32.0", "@typescript-eslint/utils": "8.32.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.29.1", "", {}, "sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.32.0", "", {}, "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.29.1", "", { "dependencies": { "@typescript-eslint/types": "8.29.1", "@typescript-eslint/visitor-keys": "8.29.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.29.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.29.1", "@typescript-eslint/types": "8.29.1", "@typescript-eslint/typescript-estree": "8.29.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.32.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.29.1", "", { "dependencies": { "@typescript-eslint/types": "8.29.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w=="],
"@typescript/lib-dom": ["@types/web@0.0.115", "", {}, "sha512-IBtUgtxnITC7WTCg4tv6kCnSP0T+fM+3PzQPIzLzJY1DDlhBFKM/9+uMURw14YweWPDiFNIZ94Gc1bJtwow97g=="],
@@ -2352,6 +2370,8 @@
"function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="],
"functions": ["functions@workspace:packages/functions"],
"functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
"fuse.js": ["fuse.js@6.6.2", "", {}, "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA=="],
@@ -2464,7 +2484,7 @@
"help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="],
"hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"hono": ["hono@4.7.8", "", {}, "sha512-PCibtFdxa7/Ldud9yddl1G81GjYaeMYYTq4ywSaNsYbB1Lug4mwtOMJf2WXykL0pntYwmpRJeOI3NmoDgD+Jxw=="],
"hono-openapi": ["hono-openapi@0.3.1", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "optionalDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.6", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "2.0.0-rc.25", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" } }, "sha512-8j02qmkE3BJkr+s/tqiauiHy+/OMmM/bvf33G9CZpBRdyM95aVL3fgRj4tNsRdkL+e/rM5+EClozD3jxnwr4eA=="],
@@ -3864,7 +3884,7 @@
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
"ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
@@ -4016,7 +4036,7 @@
"vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
"vite": ["vite@6.0.14", "", { "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.4.49", "rollup": "^4.23.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "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" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-RPfVU0Z3aFfl5BQG8xgIvuN8PofO6np7PBnurYSwx9hfcK6mjuTC5XQxA65L+pxmVbmT3Swqp9CYqc5VshQIfQ=="],
"vite": ["vite@6.0.15", "", { "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.4.49", "rollup": "^4.23.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "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" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-uC/aEgK2B7Ryaznyfj6h1PMUe4G7/6cKG97idqJFcgasmaoIRoemtlDQbsTTb6y5n3ly2L3kTgMR3sso9ASz0g=="],
"vite-dev-rpc": ["vite-dev-rpc@1.0.7", "", { "dependencies": { "birpc": "^2.0.19", "vite-hot-client": "^2.0.4" }, "peerDependencies": { "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1" } }, "sha512-FxSTEofDbUi2XXujCA+hdzCDkXFG1PXktMjSk1efq9Qb5lOYaaM9zNSvKvPPF7645Bak79kSp1PTooMW2wktcA=="],
@@ -4150,8 +4170,12 @@
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"@actor-core/file-system/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"@actor-core/memory/@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="],
"@actor-core/memory/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
"@antfu/install-pkg/package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="],
@@ -4528,6 +4552,12 @@
"@modelcontextprotocol/sdk/eventsource": ["eventsource@3.0.5", "", { "dependencies": { "eventsource-parser": "^3.0.0" } }, "sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw=="],
"@nestri-core/@actor-core/bun": ["@actor-core/bun@0.8.0", "", { "dependencies": { "dedent": "^1.5.3", "zod": "^3.24.2" }, "peerDependencies": { "@actor-core/file-system": "*", "@actor-core/memory": "*", "actor-core": "*" } }, "sha512-p4HfeCwvPgSOtMqDFIJsZlqsKhLlUqh+TnlvJVG/PQWDlHRCTh168z5v0TDJAbn7t12SjRpzozz8LbeaBw+haw=="],
"@nestri-core/actor-core": ["actor-core@0.8.0", "", { "dependencies": { "cbor-x": "^1.6.0", "hono": "^4.7.0", "invariant": "^2.2.4", "on-change": "^5.0.1", "p-retry": "^6.2.1", "zod": "^3.24.1" }, "peerDependencies": { "eventsource": "^3.0.5", "ws": "^8.0.0" }, "optionalPeers": ["eventsource", "ws"], "bin": "./dist/cli/mod.cjs" }, "sha512-I1Ab0qr2TA3O2CF8Yi8+xSAtiDE5RBKX4O9scc88baE+wFcVEhtSwo1J6e5B8n4mwkjX/xOeKnea3gD/3jvmCw=="],
"@nestri-core/hono-openapi": ["hono-openapi@0.4.8", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "peerDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.0 || ^0.3.0", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "^2.0.0", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" }, "optionalPeers": ["@hono/arktype-validator", "@hono/effect-validator", "@hono/typebox-validator", "@hono/valibot-validator", "@hono/zod-validator", "@sinclair/typebox", "@valibot/to-json-schema", "arktype", "effect", "hono", "valibot", "zod", "zod-openapi"] }, "sha512-LYr5xdtD49M7hEAduV1PftOMzuT8ZNvkyWfh1DThkLsIr4RkvDb12UxgIiFbwrJB6FLtFXLoOZL9x4IeDk2+VA=="],
"@nestri/functions/@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250303.0", "", {}, "sha512-O7F7nRT4bbmwHf3gkRBLfJ7R6vHIJ/oZzWdby6obOiw2yavUfp/AIwS7aO2POu5Cv8+h3TXS3oHs3kKCZLraUA=="],
"@nestri/sdk/@types/node": ["@types/node@18.19.80", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ=="],
@@ -4798,7 +4828,7 @@
"@tufjs/models/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@types/bun/bun-types": ["bun-types@1.2.9", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-dk/kOEfQbajENN/D6FyiSgOKEuUi9PWfqKQJEgwKrCMWbjS/S6tEXp178mWvWAcUSYm9ArDlWHZKO3T/4cLXiw=="],
"@types/bun/bun-types": ["bun-types@1.2.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-tvWMx5vPqbRXgE8WUZI94iS1xAYs8bkqESR9cxBB1Wi+urvfTrF1uzuDgBHFAdO0+d2lmsbG3HmeKMvUyj6pWA=="],
"@types/cacheable-request/@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="],
@@ -4816,6 +4846,8 @@
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
"@vanilla-extract/integration/vite": ["vite@5.4.12", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-KwUaKB27TvWwDJr1GjjWthLMATbGEbeWYZIbGZ5qFIsgPP3vWzLu4cVooqhm5/Z2SPDUMjyPVjTztm5tYKwQxA=="],
@@ -4870,6 +4902,8 @@
"accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
"actor-core/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"aws-crt/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
@@ -4982,6 +5016,12 @@
"foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"functions/@actor-core/bun": ["@actor-core/bun@0.8.0", "", { "dependencies": { "dedent": "^1.5.3", "zod": "^3.24.2" }, "peerDependencies": { "@actor-core/file-system": "*", "@actor-core/memory": "*", "actor-core": "*" } }, "sha512-p4HfeCwvPgSOtMqDFIJsZlqsKhLlUqh+TnlvJVG/PQWDlHRCTh168z5v0TDJAbn7t12SjRpzozz8LbeaBw+haw=="],
"functions/actor-core": ["actor-core@0.8.0", "", { "dependencies": { "cbor-x": "^1.6.0", "hono": "^4.7.0", "invariant": "^2.2.4", "on-change": "^5.0.1", "p-retry": "^6.2.1", "zod": "^3.24.1" }, "peerDependencies": { "eventsource": "^3.0.5", "ws": "^8.0.0" }, "optionalPeers": ["eventsource", "ws"], "bin": "./dist/cli/mod.cjs" }, "sha512-I1Ab0qr2TA3O2CF8Yi8+xSAtiDE5RBKX4O9scc88baE+wFcVEhtSwo1J6e5B8n4mwkjX/xOeKnea3gD/3jvmCw=="],
"functions/hono-openapi": ["hono-openapi@0.4.8", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "peerDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.0 || ^0.3.0", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "^2.0.0", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" }, "optionalPeers": ["@hono/arktype-validator", "@hono/effect-validator", "@hono/typebox-validator", "@hono/valibot-validator", "@hono/zod-validator", "@sinclair/typebox", "@valibot/to-json-schema", "arktype", "effect", "hono", "valibot", "zod", "zod-openapi"] }, "sha512-LYr5xdtD49M7hEAduV1PftOMzuT8ZNvkyWfh1DThkLsIr4RkvDb12UxgIiFbwrJB6FLtFXLoOZL9x4IeDk2+VA=="],
"gel/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
"get-source/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
@@ -5004,6 +5044,8 @@
"hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="],
"hono-openapi/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"http-assert/http-errors": ["http-errors@1.8.1", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.1" } }, "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="],
"ignore-walk/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
@@ -5120,6 +5162,8 @@
"nypm/consola": ["consola@3.4.0", "", {}, "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA=="],
"opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="],
"openid-client/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
@@ -5812,6 +5856,8 @@
"@nuxt/eslint-config/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.26.0", "", { "dependencies": { "@typescript-eslint/types": "8.26.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg=="],
"@nuxt/eslint-config/@typescript-eslint/eslint-plugin/ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
"@nuxt/eslint-config/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.26.0", "", { "dependencies": { "@typescript-eslint/types": "8.26.0", "@typescript-eslint/visitor-keys": "8.26.0" } }, "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA=="],
"@nuxt/eslint-config/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.26.0", "", {}, "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA=="],
@@ -6796,6 +6842,8 @@
"@nuxt/eslint-config/@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@nuxt/eslint-config/@typescript-eslint/parser/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
"@nuxt/eslint-config/@typescript-eslint/parser/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
"@nuxt/eslint-config/local-pkg/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
@@ -6808,6 +6856,8 @@
"@nuxt/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@nuxt/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
"@nuxt/icon/@nuxt/devtools-kit/@nuxt/schema/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"@nuxt/icon/@nuxt/devtools-kit/execa/human-signals": ["human-signals@4.3.1", "", {}, "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ=="],
@@ -6836,6 +6886,8 @@
"@stylistic/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@stylistic/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
"@types/bun/bun-types/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
"@vanilla-extract/integration/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
@@ -7002,12 +7054,16 @@
"eslint-plugin-import-x/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.26.0", "", { "dependencies": { "@typescript-eslint/types": "8.26.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg=="],
"eslint-plugin-import-x/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
"eslint-plugin-qwik/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.28.0", "", { "dependencies": { "@typescript-eslint/types": "8.28.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-hbn8SZ8w4u2pRwgQ1GlUrPKE+t2XvcCW5tTRF7j6SMYIuYG37XuzIW44JCZPa36evi0Oy2SnM664BlIaAuQcvg=="],
"eslint-plugin-qwik/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.28.0", "", { "dependencies": { "@typescript-eslint/types": "8.28.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-hbn8SZ8w4u2pRwgQ1GlUrPKE+t2XvcCW5tTRF7j6SMYIuYG37XuzIW44JCZPa36evi0Oy2SnM664BlIaAuQcvg=="],
"eslint-plugin-qwik/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"eslint-plugin-qwik/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
"pkg-dir/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
"read-pkg-up/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],

View File

@@ -9,7 +9,7 @@ export const auth = new sst.aws.Service("Auth", {
cluster,
cpu: $app.stage === "production" ? "1 vCPU" : undefined,
memory: $app.stage === "production" ? "2 GB" : undefined,
command: ["bun", "run", "./src/auth.ts"],
command: ["bun", "run", "./src/auth/index.ts"],
link: [
bus,
postgres,

View File

@@ -49,20 +49,20 @@ new sst.x.DevCommand("Studio", {
},
});
const migrator = new sst.aws.Function("DatabaseMigrator", {
handler: "packages/functions/src/migrator.handler",
link: [postgres],
copyFiles: [
{
from: "packages/core/migrations",
to: "./migrations",
},
],
});
// const migrator = new sst.aws.Function("DatabaseMigrator", {
// handler: "packages/functions/src/migrator.handler",
// link: [postgres],
// copyFiles: [
// {
// from: "packages/core/migrations",
// to: "./migrations",
// },
// ],
// });
if (!$dev) {
new aws.lambda.Invocation("DatabaseMigratorInvocation", {
input: Date.now().toString(),
functionName: migrator.name,
});
}
// if (!$dev) {
// new aws.lambda.Invocation("DatabaseMigratorInvocation", {
// input: Date.now().toString(),
// functionName: migrator.name,
// });
// }

View File

@@ -84,44 +84,44 @@ const replicationManager = !$dev
}) : undefined;
// Permissions deployment
const permissions = new sst.aws.Function(
"ZeroPermissions",
{
vpc,
link: [postgres],
handler: "packages/functions/src/zero.handler",
// environment: { ["ZERO_UPSTREAM_DB"]: connectionString },
copyFiles: [{
from: "packages/zero/.permissions.sql",
to: "./.permissions.sql"
}],
}
);
// const permissions = new sst.aws.Function(
// "ZeroPermissions",
// {
// vpc,
// link: [postgres],
// handler: "packages/functions/src/zero.handler",
// // environment: { ["ZERO_UPSTREAM_DB"]: connectionString },
// copyFiles: [{
// from: "packages/zero/.permissions.sql",
// to: "./.permissions.sql"
// }],
// }
// );
if (replicationManager) {
new aws.lambda.Invocation(
"ZeroPermissionsInvocation",
{
input: Date.now().toString(),
functionName: permissions.name,
},
{ dependsOn: replicationManager }
);
// new command.local.Command(
// "ZeroPermission",
// {
// dir: process.cwd() + "/packages/zero",
// environment: {
// ZERO_UPSTREAM_DB: connectionString,
// },
// create: "bun run zero-deploy-permissions",
// triggers: [Date.now()],
// },
// {
// dependsOn: [replicationManager],
// },
// );
}
// if (replicationManager) {
// new aws.lambda.Invocation(
// "ZeroPermissionsInvocation",
// {
// input: Date.now().toString(),
// functionName: permissions.name,
// },
// { dependsOn: replicationManager }
// );
// // new command.local.Command(
// // "ZeroPermission",
// // {
// // dir: process.cwd() + "/packages/zero",
// // environment: {
// // ZERO_UPSTREAM_DB: connectionString,
// // },
// // create: "bun run zero-deploy-permissions",
// // triggers: [Date.now()],
// // },
// // {
// // dependsOn: [replicationManager],
// // },
// // );
// }
export const zero = new sst.aws.Service("Zero", {
cluster,

View File

@@ -1,175 +1,34 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# dependencies (bun install)
node_modules
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Caches
.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
# output
out
dist
*.tgz
# code coverage
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# caches
.eslintcache
.cache
*.tsbuildinfo
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store
.DS_Store

View File

@@ -1,4 +1,4 @@
# auth
# @nestri/functions
To install dependencies:
@@ -12,4 +12,4 @@ To run:
bun run index.ts
```
This project was created using `bun init` in bun v1.1.34. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
This project was created using `bun init` in bun v1.2.11. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.

View File

@@ -1,31 +1,23 @@
{
"name": "@nestri/functions",
"module": "index.ts",
"type": "module",
"exports": {
"./*": "./src/*.ts"
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"scripts": {
"dev:auth": "bun run --watch ./src/auth.ts",
"dev:auth": "bun run --watch ./src/auth/index.ts",
"dev:api": "bun run --watch ./src/api/index.ts"
},
"devDependencies": {
"@aws-sdk/client-ecs": "^3.738.0",
"@aws-sdk/client-sqs": "^3.734.0",
"@cloudflare/workers-types": "^4.20241224.0",
"@nestri/core": "*",
"@types/bun": "latest",
"valibot": "^1.0.0-beta.9"
},
"peerDependencies": {
"typescript": "^5.0.0"
"typescript": "^5"
},
"dependencies": {
"@actor-core/bun": "^0.7.9",
"@openauthjs/openauth": "*",
"actor-core": "^0.7.9",
"hono": "^4.6.15",
"hono-openapi": "^0.3.1",
"partysocket": "1.0.3",
"postgres": "^3.4.5"
"@actor-core/bun": "^0.8.0",
"@nestri/core":"workspace:",
"actor-core": "^0.8.0",
"hono": "^4.7.8",
"hono-openapi": "^0.4.8"
}
}
}

View File

@@ -1,12 +1,12 @@
import { z } from "zod";
import { Hono } from "hono";
import { notPublic } from "./auth";
import { notPublic } from "./utils/auth";
import { describeRoute } from "hono-openapi";
import { User } from "@nestri/core/user/index";
import { Team } from "@nestri/core/team/index";
import { assertActor } from "@nestri/core/actor";
import { Examples } from "@nestri/core/examples";
import { ErrorResponses, Result } from "./common";
import { ErrorResponses, Result } from "./utils";
import { ErrorCodes, VisibleError } from "@nestri/core/error";
export namespace AccountApi {

View File

@@ -1,246 +0,0 @@
import { z, ZodSchema } from "zod";
import {type Hook } from "./types/hook";
import { ErrorCodes, ErrorResponse } from "@nestri/core/error";
import type { MiddlewareHandler, ValidationTargets } from "hono";
import { resolver, validator as zodValidator } from "hono-openapi/zod";
export function Result<T extends z.ZodTypeAny>(schema: T) {
return resolver(
z.object({
data: schema,
}),
);
}
/**
* Custom validator wrapper around hono-openapi/zod validator that formats errors
* according to our standard API error format
*/
export const validator = <
T extends ZodSchema,
Target extends keyof ValidationTargets
>(
target: Target,
schema: T
): MiddlewareHandler<
any,
string,
{
in: {
[K in Target]: z.input<T>;
};
out: {
[K in Target]: z.output<T>;
};
}
> => {
// Create a custom error handler that formats errors according to our standards
// const standardErrorHandler: Parameters<typeof zodValidator>[2] = (
const standardErrorHandler: Hook<z.infer<T>, any, any, Target> = (
result,
c,
) => {
if (!result.success) {
// Get the validation issues
const issues = result.error.issues || result.error.errors || [];
if (issues.length === 0) {
// If there are no issues, return a generic error
return c.json(
{
type: "validation",
code: ErrorCodes.Validation.INVALID_PARAMETER,
message: "Invalid request data",
},
400,
);
}
// Get the first error for the main response
const firstIssue = issues[0]!;
const fieldPath = firstIssue.path
? Array.isArray(firstIssue.path)
? firstIssue.path.join(".")
: firstIssue.path
: undefined;
// Map Zod error codes to our standard error codes
let errorCode = ErrorCodes.Validation.INVALID_PARAMETER;
if (
firstIssue.code === "invalid_type" &&
firstIssue.received === "undefined"
) {
errorCode = ErrorCodes.Validation.MISSING_REQUIRED_FIELD;
} else if (
["invalid_string", "invalid_date", "invalid_regex"].includes(
firstIssue.code,
)
) {
errorCode = ErrorCodes.Validation.INVALID_FORMAT;
}
// Create our standardized error response
const response = {
type: "validation",
code: errorCode,
message: firstIssue.message,
param: fieldPath,
details: undefined as any,
};
// Add details if we have multiple issues
if (issues.length > 0) {
response.details = {
issues: issues.map((issue) => ({
path: issue.path
? Array.isArray(issue.path)
? issue.path.join(".")
: issue.path
: undefined,
code: issue.code,
message: issue.message,
// @ts-expect-error
expected: issue.expected,
// @ts-expect-error
received: issue.received,
})),
};
}
console.log("Validation error in validator:", response);
return c.json(response, 400);
}
};
// Use the original validator with our custom error handler
return zodValidator(target, schema, standardErrorHandler);
};
/**
* Standard error responses for OpenAPI documentation
*/
export const ErrorResponses = {
400: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Validation error",
example: {
type: "validation",
code: "invalid_parameter",
message: "The request was invalid",
param: "email",
},
}),
),
},
},
description:
"Bad Request - The request could not be understood or was missing required parameters.",
},
401: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Authentication error",
example: {
type: "authentication",
code: "unauthorized",
message: "Authentication required",
},
}),
),
},
},
description:
"Unauthorized - Authentication is required and has failed or has not been provided.",
},
403: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Permission error",
example: {
type: "forbidden",
code: "permission_denied",
message: "You do not have permission to access this resource",
},
}),
),
},
},
description:
"Forbidden - You do not have permission to access this resource.",
},
404: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Not found error",
example: {
type: "not_found",
code: "resource_not_found",
message: "The requested resource could not be found",
},
}),
),
},
},
description: "Not Found - The requested resource does not exist.",
},
409: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Conflict Error",
example: {
type: "already_exists",
code: "resource_already_exists",
message: "The resource could not be created because it already exists",
},
}),
),
},
},
description: "Conflict - The resource could not be created because it already exists.",
},
429: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Rate limit error",
example: {
type: "rate_limit",
code: "too_many_requests",
message: "Rate limit exceeded",
},
}),
),
},
},
description:
"Too Many Requests - You have made too many requests in a short period of time.",
},
500: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Server error",
example: {
type: "internal",
code: "internal_error",
message: "Internal server error",
},
}),
),
},
},
description: "Internal Server Error - Something went wrong on our end.",
},
};

View File

@@ -1,15 +1,11 @@
import "zod-openapi/extend";
import { Hono } from "hono";
import { auth } from "./auth";
import { cors } from "hono/cors";
import { TeamApi } from "./team";
import { PolarApi } from "./polar";
import { logger } from "hono/logger";
import { Realtime } from "./realtime";
import { auth } from "./utils/auth";
import { AccountApi } from "./account";
import { MachineApi } from "./machine";
import { openAPISpecs } from "hono-openapi";
import { patchLogger } from "../log-polyfill";
import { patchLogger } from "../utils/patch-logger";
import { HTTPException } from "hono/http-exception";
import { ErrorCodes, VisibleError } from "@nestri/core/error";
@@ -26,10 +22,7 @@ app
const routes = app
.get("/", (c) => c.text("Hello World!"))
.route("/realtime", Realtime.route)
.route("/team", TeamApi.route)
.route("/polar", PolarApi.route)
.route("/account", AccountApi.route)
.route("/machine", MachineApi.route)
.onError((error, c) => {
if (error instanceof VisibleError) {
console.error("api error:", error);

View File

@@ -1,292 +0,0 @@
import { z } from "zod"
import { Hono } from "hono";
import { notPublic } from "./auth";
import { describeRoute } from "hono-openapi";
import { validator } from "hono-openapi/zod";
import { Examples } from "@nestri/core/examples";
import { assertActor } from "@nestri/core/actor";
import { ErrorResponses, Result } from "./common";
import { Machine } from "@nestri/core/machine/index";
import { Realtime } from "@nestri/core/realtime/index";
import { ErrorCodes, VisibleError } from "@nestri/core/error";
import { CreateMessageSchema, StartMessageSchema, StopMessageSchema } from "./messages.ts";
export namespace MachineApi {
export const route = new Hono()
.use(notPublic)
.get("/",
describeRoute({
tags: ["Machine"],
summary: "Get all BYOG machines",
description: "All the BYOG machines owned by this user",
responses: {
200: {
content: {
"application/json": {
schema: Result(
Machine.Info.array().openapi({
description: "All the user's BYOG machines",
example: [Examples.Machine],
}),
),
},
},
description: "Successfully retrieved all the user's machines",
},
404: ErrorResponses[404],
429: ErrorResponses[429]
}
}),
async (c) => {
const user = assertActor("user");
const machineInfo = await Machine.fromUserID(user.properties.userID);
if (!machineInfo)
throw new VisibleError(
"not_found",
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
"No machines not found",
);
return c.json({ data: machineInfo, }, 200);
})
.get("/hosted",
describeRoute({
tags: ["Machine"],
summary: "Get all cloud machines",
description: "All the machines that are connected to Nestri",
responses: {
200: {
content: {
"application/json": {
schema: Result(
Machine.Info.array().openapi({
description: "All the machines connected to Nestri",
example: [{ ...Examples.Machine, userID: null }],
}),
),
},
},
description: "Successfully retrieved all the hosted machines",
},
404: ErrorResponses[404],
429: ErrorResponses[429]
}
}),
async (c) => {
const machineInfo = await Machine.list();
if (!machineInfo)
throw new VisibleError(
"not_found",
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
"No machines not found",
);
return c.json({ data: machineInfo, }, 200);
})
.post("/",
describeRoute({
tags: ["Machine"],
summary: "Send messages to the machine",
description: "Send messages directly to the machine",
responses: {
200: {
content: {
"application/json": {
schema: Result(
z.literal("ok")
),
},
},
description: "Successfully sent the message to Maitred"
},
}
}),
validator(
"json",
z.any()
),
async (c) => {
const actor = assertActor("machine");
console.log("actor.id", actor.properties.machineID)
await Realtime.publish(c.req.valid("json"))
return c.json({
data: "ok"
}, 200);
},
)
.post("/:machineID/create",
describeRoute({
tags: ["Machine"],
summary: "Request to create a container for a specific machine",
description: "Publishes a message to create a container via MQTT for the given machine ID",
responses: {
200: {
content: {
"application/json": {
schema: Result(
z.object({
message: z.literal("create request sent"),
})
),
},
},
description: "Create request successfully sent to MQTT",
},
400: {
content: {
"application/json": {
schema: Result(
z.object({ error: z.string() })
),
},
},
description: "Failed to publish create request",
},
},
}),
validator("json", CreateMessageSchema.shape.payload.optional()), // No payload required for create
async (c) => {
const actor = assertActor("machine");
const body = c.req.valid("json");
const message = {
type: "create" as const,
payload: body || {}, // Empty payload if none provided
};
try {
await Realtime.publish(message, "create");
console.log("Published create request to");
} catch (error) {
console.error("Failed to publish to MQTT:", error);
return c.json({ error: "Failed to send create request" }, 400);
}
return c.json({
data: {
message: "create request sent",
},
}, 200);
}
)
.post("/:machineID/start",
describeRoute({
tags: ["Machine"],
summary: "Request to start a container for a specific machine",
description: "Publishes a message to start a container via MQTT for the given machine ID",
responses: {
200: {
content: {
"application/json": {
schema: Result(
z.object({
message: z.literal("start request sent"),
})
),
},
},
description: "Start request successfully sent to MQTT",
},
400: {
content: {
"application/json": {
schema: Result(
z.object({ error: z.string() })
),
},
},
description: "Failed to publish start request",
},
},
}),
validator("json", StartMessageSchema.shape.payload), // Use the payload schema
async (c) => {
const actor = assertActor("machine");
const body = c.req.valid("json");
const message = {
type: "start" as const,
payload: {
container_id: body.container_id,
},
};
try {
await Realtime.publish(message, "start");
console.log("Published start request");
} catch (error) {
console.error("Failed to publish to MQTT:", error);
return c.json({ error: "Failed to send start request" }, 400);
}
return c.json({
data: {
message: "start request sent",
},
}, 200);
}
)
.post("/:machineID/stop",
describeRoute({
tags: ["Machine"],
summary: "Request to stop a container for a specific machine",
description: "Publishes a message to stop a container via MQTT for the given machine ID",
responses: {
200: {
content: {
"application/json": {
schema: Result(
z.object({
message: z.literal("stop request sent"),
})
),
},
},
description: "Stop request successfully sent to MQTT",
},
400: {
content: {
"application/json": {
schema: Result(
z.object({ error: z.string() })
),
},
},
description: "Failed to publish start request",
},
},
}),
validator("json", StopMessageSchema.shape.payload), // Use the payload schema
async (c) => {
const actor = assertActor("machine");
const body = c.req.valid("json");
const message = {
type: "stop" as const,
payload: {
container_id: body.container_id,
},
};
try {
await Realtime.publish(message, "stop");
console.log("Published stop request");
} catch (error) {
console.error("Failed to publish to MQTT:", error);
return c.json({ error: "Failed to send stop request" }, 400);
}
return c.json({
data: {
message: "stop request sent",
},
}, 200);
}
)
}

View File

@@ -1,54 +0,0 @@
import { z } from "zod"
// Base message interface
export interface BaseMessage {
type: string; // e.g., "start", "stop", "status"
payload: Record<string, any>; // Generic payload, refined by specific types
}
// Specific message types
export interface StartMessage extends BaseMessage {
type: "start";
payload: {
container_id: string;
[key: string]: any; // Allow additional fields for future expansion
};
}
// Example future message type
export interface StopMessage extends BaseMessage {
type: "stop";
payload: {
container_id: string;
[key: string]: any;
};
}
// Union type for all possible messages (expandable)
export type MachineMessage = StartMessage | StopMessage; // Add more types as needed
// Zod schema for validation
export const BaseMessageSchema = z.object({
type: z.string(),
payload: z.record(z.any()),
});
export const CreateMessageSchema = BaseMessageSchema.extend({
type: z.literal("create"),
});
export const StartMessageSchema = BaseMessageSchema.extend({
type: z.literal("start"),
payload: z.object({
container_id: z.string(),
}).passthrough(),
});
export const StopMessageSchema = BaseMessageSchema.extend({
type: z.literal("stop"),
payload: z.object({
container_id: z.string(),
}).passthrough(),
});
export const MachineMessageSchema = z.union([StartMessageSchema, StopMessageSchema]);

View File

@@ -1,174 +0,0 @@
import { z } from "zod";
import { Hono } from "hono";
import { Resource } from "sst";
import { notPublic } from "./auth";
import { describeRoute } from "hono-openapi";
import { User } from "@nestri/core/user/index";
import { assertActor } from "@nestri/core/actor";
import { Polar } from "@nestri/core/polar/index";
import { Examples } from "@nestri/core/examples";
import { ErrorResponses, Result, validator } from "./common";
import { ErrorCodes, VisibleError } from "@nestri/core/error";
import { PlanType } from "@nestri/core/subscription/subscription.sql";
import { WebhookVerificationError, validateEvent } from "@polar-sh/sdk/webhooks";
export namespace PolarApi {
export const route = new Hono()
.use(notPublic)
.get("/",
describeRoute({
tags: ["Polar"],
summary: "Create a Polar.sh customer portal",
description: "Creates Polar.sh's customer portal url where the user can manage their payments",
responses: {
200: {
content: {
"application/json": {
schema: Result(
z.object({
portalUrl: z.string()
}).openapi({
description: "The customer portal url",
example: { portalUrl: "https://polar.sh/portal/39393jdie09292" }
})
),
},
},
description: "customer portal url"
},
400: ErrorResponses[400],
404: ErrorResponses[404],
429: ErrorResponses[429],
}
}),
async (c) => {
const actor = assertActor("user");
const user = await User.fromID(actor.properties.userID);
if (!user)
throw new VisibleError(
"not_found",
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
"User not found",
);
if (!user.polarCustomerID)
throw new VisibleError(
"not_found",
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
"User does not contain Polar customer ID"
)
const portalUrl = await Polar.createPortal(user.polarCustomerID)
return c.json({
data: {
portalUrl
}
})
}
)
.post("/checkout",
describeRoute({
tags: ["Polar"],
summary: "Create a checkout url",
description: "Creates a Polar.sh's checkout url for the user to pay a subscription for this team",
responses: {
200: {
content: {
"application/json": {
schema: Result(
z.object({
checkoutUrl: z.string()
}).openapi({
description: "The checkout url",
example: { checkoutUrl: "https://polar.sh/portal/39393jdie09292" }
})
),
},
},
description: "checkout url"
},
400: ErrorResponses[400],
404: ErrorResponses[404],
429: ErrorResponses[429],
}
}),
validator(
"json",
z
.object({
planType: z.enum(PlanType),
successUrl: z.string().url("Success url must be a valid url")
})
.openapi({
description: "Details of the team to create",
example: {
planType: Examples.Subscription.planType,
successUrl: "https://your-url.io/thanks"
},
})
),
async (c) => {
const body = c.req.valid("json");
const actor = assertActor("user");
const user = await User.fromID(actor.properties.userID);
if (!user)
throw new VisibleError(
"not_found",
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
"User not found",
);
if (!user.polarCustomerID)
throw new VisibleError(
"not_found",
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
"User does not contain Polar customer ID"
)
const checkoutUrl = await Polar.createCheckout({ customerID: user.polarCustomerID, planType: body.planType, successUrl: body.successUrl })
return c.json({
data: {
checkoutUrl,
}
})
}
)
.post("/webhook",
async (c) => {
const requestBody = await c.req.text();
const webhookSecret = Resource.PolarWebhookSecret.value
const webhookHeaders = {
"webhook-id": c.req.header("webhook-id") ?? "",
"webhook-timestamp": c.req.header("webhook-timestamp") ?? "",
"webhook-signature": c.req.header("webhook-signature") ?? "",
};
let webhookPayload: ReturnType<typeof validateEvent>;
try {
webhookPayload = validateEvent(
requestBody,
webhookHeaders,
webhookSecret,
);
} catch (error) {
if (error instanceof WebhookVerificationError) {
return c.json({ received: false }, { status: 403 });
}
throw error;
}
await Polar.handleWebhook(webhookPayload)
return c.json({ received: true });
}
)
}

View File

@@ -1,46 +0,0 @@
import { Hono } from "hono";
import { notPublic } from "./auth";
import { describeRoute } from "hono-openapi";
import { Examples } from "@nestri/core/examples";
import { assertActor } from "@nestri/core/actor";
import { ErrorResponses, Result } from "./common";
import { Subscription } from "@nestri/core/subscription/index";
export namespace SubscriptionApi {
export const route = new Hono()
.use(notPublic)
.get("/",
describeRoute({
tags: ["Subscription"],
summary: "Get user subscriptions",
description: "Get all user subscriptions",
responses: {
200: {
content: {
"application/json": {
schema: Result(
Subscription.Info.array().openapi({
description: "All the subscriptions this user has",
example: [Examples.Subscription]
})
),
},
},
description: "All user subscriptions"
},
400: ErrorResponses[400],
404: ErrorResponses[404],
429: ErrorResponses[429],
}
}),
async (c) => {
const actor = assertActor("user")
const subscriptions = await Subscription.fromUserID(actor.properties.userID)
return c.json({
data: subscriptions
})
}
)
}

View File

@@ -1,124 +0,0 @@
import { z } from "zod";
import { Hono } from "hono";
import { notPublic } from "./auth";
import { describeRoute } from "hono-openapi";
import { User } from "@nestri/core/user/index";
import { Team } from "@nestri/core/team/index";
import { Examples } from "@nestri/core/examples";
import { Polar } from "@nestri/core/polar/index";
import { Member } from "@nestri/core/member/index";
import { assertActor, withActor } from "@nestri/core/actor";
import { ErrorResponses, Result, validator } from "./common";
import { Subscription } from "@nestri/core/subscription/index";
import { PlanType } from "@nestri/core/subscription/subscription.sql";
export namespace TeamApi {
export const route = new Hono()
.use(notPublic)
.get("/",
describeRoute({
tags: ["Team"],
summary: "List teams",
description: "List the teams associated with the current user",
responses: {
200: {
content: {
"application/json": {
schema: Result(
Team.Info.array().openapi({
description: "List of teams",
example: [Examples.Team]
})
),
},
},
description: "List of teams"
},
}
}),
async (c) => {
return c.json({
data: await User.teams()
}, 200);
},
)
.post("/",
describeRoute({
tags: ["Team"],
summary: "Create a team",
description: "Create a team for the current user",
responses: {
200: {
content: {
"application/json": {
schema: Result(
z.object({
checkoutUrl: z.string().openapi({
description: "The checkout url to confirm subscription for this team",
example: "https://polar.sh/checkout/2903038439320298377"
})
})
)
}
},
description: "Team created succesfully"
},
400: ErrorResponses[400],
409: ErrorResponses[409],
429: ErrorResponses[429],
500: ErrorResponses[500],
}
}),
validator(
"json",
Team.create.schema
.pick({ slug: true, name: true })
.extend({ planType: z.enum(PlanType), successUrl: z.string().url("Success url must be a valid url") })
.openapi({
description: "Details of the team to create",
example: {
slug: Examples.Team.slug,
name: Examples.Team.name,
planType: Examples.Subscription.planType,
successUrl: "https://your-url.io/thanks"
},
})
),
async (c) => {
const body = c.req.valid("json")
const actor = assertActor("user");
const teamID = await Team.create({ name: body.name, slug: body.slug });
await withActor(
{
type: "system",
properties: {
teamID,
},
},
async () => {
await Member.create({
first: true,
email: actor.properties.email,
});
await Subscription.create({
planType: body.planType,
userID: actor.properties.userID,
// FIXME: Make this make sense
tokens: body.planType === "free" ? 100 : body.planType === "pro" ? 1000 : body.planType === "family" ? 10000 : 0,
});
}
);
const checkoutUrl = await Polar.createCheckout({ planType: body.planType, successUrl: body.successUrl, teamID })
return c.json({
data: {
checkoutUrl,
}
})
}
)
}

View File

@@ -1,13 +1,13 @@
import { Resource } from "sst";
import { subjects } from "../subjects";
import { subjects } from "../../subjects";
import { type MiddlewareHandler } from "hono";
import { useActor, withActor } from "@nestri/core/actor";
import { createClient } from "@openauthjs/openauth/client";
import { ErrorCodes, VisibleError } from "@nestri/core/error";
const client = createClient({
issuer: Resource.Auth.url,
clientID: "api",
issuer: Resource.Auth.url,
});
export const notPublic: MiddlewareHandler = async (c, next) => {

View File

@@ -0,0 +1,129 @@
import { resolver } from "hono-openapi/zod";
import { ErrorResponse } from "@nestri/core/error";
export const ErrorResponses = {
400: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Validation error",
example: {
type: "validation",
code: "invalid_parameter",
message: "The request was invalid",
param: "email",
},
}),
),
},
},
description:
"Bad Request - The request could not be understood or was missing required parameters.",
},
401: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Authentication error",
example: {
type: "authentication",
code: "unauthorized",
message: "Authentication required",
},
}),
),
},
},
description:
"Unauthorized - Authentication is required and has failed or has not been provided.",
},
403: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Permission error",
example: {
type: "forbidden",
code: "permission_denied",
message: "You do not have permission to access this resource",
},
}),
),
},
},
description:
"Forbidden - You do not have permission to access this resource.",
},
404: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Not found error",
example: {
type: "not_found",
code: "resource_not_found",
message: "The requested resource could not be found",
},
}),
),
},
},
description: "Not Found - The requested resource does not exist.",
},
409: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Conflict Error",
example: {
type: "already_exists",
code: "resource_already_exists",
message: "The resource could not be created because it already exists",
},
}),
),
},
},
description: "Conflict - The resource could not be created because it already exists.",
},
429: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Rate limit error",
example: {
type: "rate_limit",
code: "too_many_requests",
message: "Rate limit exceeded",
},
}),
),
},
},
description:
"Too Many Requests - You have made too many requests in a short period of time.",
},
500: {
content: {
"application/json": {
schema: resolver(
ErrorResponse.openapi({
description: "Server error",
example: {
type: "internal",
code: "internal_error",
message: "Internal server error",
},
}),
),
},
},
description: "Internal Server Error - Something went wrong on our end.",
},
};

View File

@@ -17,4 +17,4 @@ declare const zValidator: <T extends ZodSchema<any, z.ZodTypeDef, any>, Target e
out: { [K_2 in Target]: Out; };
}, V extends I = I>(target: Target, schema: T, hook?: Hook<z.TypeOf<T>, E, P, Target, {}> | undefined) => MiddlewareHandler<E, P, V>;
export { type Hook, zValidator };
export { type Hook, zValidator };

View File

@@ -0,0 +1,3 @@
export * from "./validator";
export * from "./result";
export * from "./error";

View File

@@ -0,0 +1,6 @@
import { z } from "zod";
import { resolver } from "hono-openapi/zod";
export function Result<T extends z.ZodTypeAny>(schema: T) {
return resolver(z.object({ data: schema }));
}

View File

@@ -0,0 +1,77 @@
import type { Hook } from "./hook";
import { z, ZodSchema } from "zod";
import { ErrorCodes } from "@nestri/core/error";
import { validator as zodValidator } from "hono-openapi/zod";
import type { MiddlewareHandler, ValidationTargets } from "hono";
type ZodIssueExtended = z.ZodIssue & {
expected?: unknown;
received?: unknown;
}
/**
* Custom validator wrapper around hono-openapi/zod validator that formats errors
*/
export const validator = <
T extends ZodSchema,
Target extends keyof ValidationTargets
>(
target: Target,
schema: T
): MiddlewareHandler<
Record<string, unknown>,
string,
{
in: {
[K in Target]: z.input<T>;
};
out: {
[K in Target]: z.output<T>;
};
}
> => {
const standardErrorHandler: Hook<z.infer<T>, any, any, Target> = (
result,
c,
) => {
if (!result.success) {
const issues = result.error.issues || result.error.errors || [];
const firstIssue = issues[0];
const fieldPath = Array.isArray(firstIssue?.path)
? firstIssue.path.join(".")
: firstIssue?.path;
let errorCode = ErrorCodes.Validation.INVALID_PARAMETER;
if (firstIssue?.code === "invalid_type" && firstIssue?.received === "undefined") {
errorCode = ErrorCodes.Validation.MISSING_REQUIRED_FIELD;
} else if (
["invalid_string", "invalid_date", "invalid_regex"].includes(firstIssue?.code as string)
) {
errorCode = ErrorCodes.Validation.INVALID_FORMAT;
}
const response = {
type: "validation",
code: errorCode,
message: firstIssue?.message,
param: fieldPath,
details: issues.length > 1
? {
issues: issues.map((issue: ZodIssueExtended) => ({
path: Array.isArray(issue.path) ? issue.path.join(".") : issue.path,
code: issue.code,
message: issue.message,
expected: issue.expected,
received: issue.received,
})),
}
: undefined,
};
console.log("Validation error in validator:", response);
return c.json(response, 400);
}
};
return zodValidator(target, schema, standardErrorHandler);
};

View File

@@ -1,4 +1,4 @@
import { Oauth2Adapter, type Oauth2WrappedConfig } from "./oauth2"
import { Oauth2Adapter, type Oauth2WrappedConfig } from "../ui/oauth2"
export function DiscordAdapter(config: Oauth2WrappedConfig) {
return Oauth2Adapter({

View File

@@ -1,4 +1,4 @@
import { Oauth2Adapter, type Oauth2WrappedConfig } from "./oauth2"
import { Oauth2Adapter, type Oauth2WrappedConfig } from "../ui/oauth2"
export function GithubAdapter(config: Oauth2WrappedConfig) {
return Oauth2Adapter({

View File

@@ -0,0 +1,3 @@
export * from "./discord"
export * from "./github"
export * from "./password"

View File

@@ -1,19 +1,16 @@
import { Resource } from "sst"
import { Select } from "./ui/select";
import { subjects } from "./subjects"
import { logger } from "hono/logger";
import { PasswordUI } from "./ui/password"
import { patchLogger } from "./log-polyfill";
import { subjects } from "../subjects"
import { Select, PasswordUI } from "./ui";
import { issuer } from "@openauthjs/openauth";
import { User } from "@nestri/core/user/index"
import { Email } from "@nestri/core/email/index";
// import { Email } from "@nestri/core/email/index";
// import { Machine } from "@nestri/core/machine/index"
import { patchLogger } from "../utils/patch-logger";
import { handleDiscord, handleGithub } from "./utils";
import { GithubAdapter } from "./ui/adapters/github";
import { Machine } from "@nestri/core/machine/index"
import { DiscordAdapter } from "./ui/adapters/discord";
import { PasswordAdapter } from "./ui/adapters/password";
import { type Provider } from "@openauthjs/openauth/provider/provider"
import { MemoryStorage } from "@openauthjs/openauth/storage/memory";
// import { type Provider } from "@openauthjs/openauth/provider/provider"
import { DiscordAdapter, PasswordAdapter, GithubAdapter } from "./adapters";
type OauthUser = {
primary: {
@@ -80,25 +77,25 @@ const app = issuer({
},
}),
),
machine: {
type: "machine",
async client(input) {
// FIXME: Do we really need this?
// if (input.clientSecret !== Resource.AuthFingerprintKey.value) {
// throw new Error("Invalid authorization token");
// }
// machine: {
// type: "machine",
// async client(input) {
// // FIXME: Do we really need this?
// // if (input.clientSecret !== Resource.AuthFingerprintKey.value) {
// // throw new Error("Invalid authorization token");
// // }
const fingerprint = input.params.fingerprint;
if (!fingerprint) {
throw new Error("Hostname is required");
}
// const fingerprint = input.params.fingerprint;
// if (!fingerprint) {
// throw new Error("Hostname is required");
// }
return {
fingerprint,
};
},
init() { }
} as Provider<{ fingerprint: string; }>,
// return {
// fingerprint,
// };
// },
// init() { }
// } as Provider<{ fingerprint: string; }>,
},
allow: async (input) => {
const url = new URL(input.redirectURI);
@@ -108,39 +105,40 @@ const app = issuer({
return false;
},
success: async (ctx, value, req) => {
if (value.provider === "machine") {
const countryCode = req.headers.get('CloudFront-Viewer-Country') || 'Unknown'
const country = req.headers.get('CloudFront-Viewer-Country-Name') || 'Unknown'
const latitude = Number(req.headers.get('CloudFront-Viewer-Latitude')) || 0
const longitude = Number(req.headers.get('CloudFront-Viewer-Longitude')) || 0
const timezone = req.headers.get('CloudFront-Viewer-Time-Zone') || 'Unknown'
const fingerprint = value.fingerprint
// I dunno what i broke... will check later
// if (value.provider === "machine") {
// const countryCode = req.headers.get('CloudFront-Viewer-Country') || 'Unknown'
// const country = req.headers.get('CloudFront-Viewer-Country-Name') || 'Unknown'
// const latitude = Number(req.headers.get('CloudFront-Viewer-Latitude')) || 0
// const longitude = Number(req.headers.get('CloudFront-Viewer-Longitude')) || 0
// const timezone = req.headers.get('CloudFront-Viewer-Time-Zone') || 'Unknown'
// const fingerprint = value.fingerprint
const existing = await Machine.fromFingerprint(fingerprint)
if (!existing) {
const machineID = await Machine.create({
countryCode,
country,
fingerprint,
timezone,
location: {
latitude,
longitude
},
//FIXME: Make this better
// userID: null
})
return ctx.subject("machine", {
machineID,
fingerprint
});
}
// const existing = await Machine.fromFingerprint(fingerprint)
// if (!existing) {
// const machineID = await Machine.create({
// countryCode,
// country,
// fingerprint,
// timezone,
// location: {
// latitude,
// longitude
// },
// //FIXME: Make this better
// // userID: null
// })
// return ctx.subject("machine", {
// machineID,
// fingerprint
// });
// }
return ctx.subject("machine", {
machineID: existing.id,
fingerprint
});
}
// return ctx.subject("machine", {
// machineID: existing.id,
// fingerprint
// });
// }
// TODO: This works, so use this while registering the task
// console.log("country_code", req.headers.get('CloudFront-Viewer-Country'))

View File

@@ -0,0 +1,2 @@
export * from "./password"
export * from "./select"

View File

@@ -1,5 +1,6 @@
/** @jsxImportSource hono/jsx */
import { Layout } from "../base"
import fetch from "node-fetch"
import { Layout } from "./base"
import { OauthError } from "@openauthjs/openauth/error"
import { getRelativeUrl } from "@openauthjs/openauth/util"
import { type Provider } from "@openauthjs/openauth/provider/provider"

View File

@@ -4,7 +4,7 @@ import {
type PasswordConfig,
type PasswordLoginError,
type PasswordRegisterError,
} from "./adapters/password"
} from "../adapters"
// import { Layout } from "@openauthjs/openauth/ui/base"
import { Layout } from "./base"
import "@openauthjs/openauth/ui/form"

View File

@@ -0,0 +1,38 @@
import fetch from "node-fetch"
export const handleDiscord = async (accessKey: string) => {
try {
const response = await fetch("https://discord.com/api/v10/users/@me", {
headers: {
Authorization: `Bearer ${accessKey}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error(`Discord API error: ${response.status}`);
}
const user = await response.json();
// console.log("raw user", user)
if (!user.verified) {
throw new Error("Email not verified");
}
return {
primary: {
email: user.email,
verified: user.verified,
primary: true
},
avatar: user.avatar
? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`
: null,
username: user.global_name ?? user.username
};
} catch (error) {
console.error('Discord OAuth error:', error);
throw error;
}
}

View File

@@ -1,3 +1,5 @@
import fetch from "node-fetch";
export const handleGithub = async (accessKey: string) => {
console.log("acceskey", accessKey)
@@ -37,41 +39,4 @@ export const handleGithub = async (accessKey: string) => {
console.error('GitHub OAuth error:', error);
throw error;
}
}
export const handleDiscord = async (accessKey: string) => {
try {
const response = await fetch("https://discord.com/api/v10/users/@me", {
headers: {
Authorization: `Bearer ${accessKey}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error(`Discord API error: ${response.status}`);
}
const user = await response.json();
// console.log("raw user", user)
if (!user.verified) {
throw new Error("Email not verified");
}
return {
primary: {
email: user.email,
verified: user.verified,
primary: true
},
avatar: user.avatar
? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`
: null,
username: user.global_name ?? user.username
};
} catch (error) {
console.error('Discord OAuth error:', error);
throw error;
}
}

View File

@@ -0,0 +1,2 @@
export * from "./discord"
export * from "./github"

View File

@@ -1,8 +0,0 @@
import { db } from "@nestri/core/drizzle/index";
import { migrate } from "drizzle-orm/postgres-js/migrator";
export const handler = async (event: any) => {
await migrate(db, {
migrationsFolder: "./migrations",
});
};

View File

@@ -1,38 +0,0 @@
import { Resource } from "sst";
import { subjects } from "../subjects";
import { realtime } from "sst/aws/realtime";
import { createClient } from "@openauthjs/openauth/client";
export const handler = realtime.authorizer(async (token) => {
//TODO: Use the following criteria for a topic - team-slug/container-id (container ids are not unique globally)
//TODO: Allow the authorizer to subscriber/publisher to listen on - team-slug topics only (as the container will listen on the team-slug/container-id topic to be specific)
// Return the topics to subscribe and publish
const client = createClient({
clientID: "api",
issuer: Resource.Auth.url
});
const result = await client.verify(subjects, token);
if (result.err) {
console.log("error", result.err)
return {
subscribe: [],
publish: [],
};
}
if (result.subject.type != "user") {
return {
subscribe: [],
publish: [],
};
}
return {
//It can publish and listen to other instances under this team
subscribe: [`${Resource.App.name}/${Resource.App.stage}/*`],
publish: [`${Resource.App.name}/${Resource.App.stage}/*`],
};
});

View File

@@ -40,9 +40,9 @@ export const handler = async (event: any) => {
// Extract task details
const task = runResponse.tasks[0];
const taskArn = task.taskArn!;
const taskArn = task?.taskArn!;
const taskId = taskArn.split('/').pop()!; // Extract task ID from ARN
const taskStatus = task.lastStatus!;
const taskStatus = task?.lastStatus!;
return {
statusCode: 200,

View File

@@ -1,13 +1,13 @@
import * as v from "valibot"
import { z } from "zod"
import { createSubjects } from "@openauthjs/openauth/subject"
export const subjects = createSubjects({
user: v.object({
email: v.string(),
userID: v.string(),
}),
machine: v.object({
fingerprint: v.string(),
machineID: v.string(),
})
user: z.object({
email: z.string(),
userID: z.string(),
}),
machine: z.object({
fingerprint: z.string(),
machineID: z.string(),
})
})

View File

@@ -1,4 +0,0 @@
export enum Subscription {
Pro = "Pro",
Free = "Free"
}

View File

@@ -1,10 +0,0 @@
import fs from "node:fs";
// import postgres from "postgres";
import { db, sql } from "@nestri/core/drizzle/index";
export async function handler() {
// const sql = postgres(process.env.ZERO_UPSTREAM_DB!);
const perms = fs.readFileSync(".permissions.sql", "utf8");
// await sql.unsafe(perms);
await db.execute(sql.raw(perms))
}

View File

@@ -1,27 +1,10 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
// Enable latest features
"lib": [
"ESNext",
"DOM"
],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"module": "esnext",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
"noUncheckedIndexedAccess": true
}
}
}