From a0dc35356100f3a8b7e031a2f9b772f8e1f819b5 Mon Sep 17 00:00:00 2001 From: Wanjohi <71614375+wanjohiryan@users.noreply.github.com> Date: Tue, 6 May 2025 05:22:26 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9C=20fix:=20Fix=20an=20issue=20where?= =?UTF-8?q?=20ts-server=20is=20taking=20forever=20to=20load=20(#272)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description ## 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. --- bun.lock | 90 +++++- infra/auth.ts | 2 +- infra/postgres.ts | 32 +- infra/zero.ts | 74 ++--- packages/functions/.gitignore | 173 +---------- packages/functions/README.md | 4 +- packages/functions/package.json | 32 +- packages/functions/src/api/account.ts | 4 +- packages/functions/src/api/common.ts | 246 --------------- packages/functions/src/api/index.ts | 11 +- packages/functions/src/api/machine.ts | 292 ------------------ packages/functions/src/api/messages.ts | 54 ---- packages/functions/src/api/polar.ts | 174 ----------- packages/functions/src/api/subscription.ts | 46 --- packages/functions/src/api/team.ts | 124 -------- .../functions/src/api/{ => utils}/auth.ts | 4 +- packages/functions/src/api/utils/error.ts | 129 ++++++++ .../src/api/{types => utils}/hook.ts | 2 +- packages/functions/src/api/utils/index.ts | 3 + packages/functions/src/api/utils/result.ts | 6 + packages/functions/src/api/utils/validator.ts | 77 +++++ .../src/{ui => auth}/adapters/discord.ts | 2 +- .../src/{ui => auth}/adapters/github.ts | 2 +- packages/functions/src/auth/adapters/index.ts | 3 + .../src/{ui => auth}/adapters/password.ts | 0 .../functions/src/{auth.ts => auth/index.ts} | 114 ++++--- packages/functions/src/{ => auth}/ui/base.tsx | 0 packages/functions/src/{ => auth}/ui/css.ts | 0 packages/functions/src/auth/ui/index.ts | 2 + .../src/{ui/adapters => auth/ui}/oauth2.tsx | 3 +- .../functions/src/{ => auth}/ui/password.tsx | 2 +- .../functions/src/{ => auth}/ui/select.tsx | 0 packages/functions/src/auth/utils/discord.ts | 38 +++ .../src/{utils.ts => auth/utils/github.ts} | 39 +-- packages/functions/src/auth/utils/index.ts | 2 + packages/functions/src/migrator.ts | 8 - packages/functions/src/party/authorizer.ts | 38 --- packages/functions/src/realtime/create.ts | 4 +- packages/functions/src/subjects.ts | 18 +- packages/functions/src/type.ts | 4 - .../patch-logger.ts} | 0 packages/functions/src/zero.ts | 10 - packages/functions/tsconfig.json | 25 +- 43 files changed, 502 insertions(+), 1391 deletions(-) delete mode 100644 packages/functions/src/api/common.ts delete mode 100644 packages/functions/src/api/machine.ts delete mode 100644 packages/functions/src/api/messages.ts delete mode 100644 packages/functions/src/api/polar.ts delete mode 100644 packages/functions/src/api/subscription.ts delete mode 100644 packages/functions/src/api/team.ts rename packages/functions/src/api/{ => utils}/auth.ts (97%) create mode 100644 packages/functions/src/api/utils/error.ts rename packages/functions/src/api/{types => utils}/hook.ts (97%) create mode 100644 packages/functions/src/api/utils/index.ts create mode 100644 packages/functions/src/api/utils/result.ts create mode 100644 packages/functions/src/api/utils/validator.ts rename packages/functions/src/{ui => auth}/adapters/discord.ts (79%) rename packages/functions/src/{ui => auth}/adapters/github.ts (79%) create mode 100644 packages/functions/src/auth/adapters/index.ts rename packages/functions/src/{ui => auth}/adapters/password.ts (100%) rename packages/functions/src/{auth.ts => auth/index.ts} (68%) rename packages/functions/src/{ => auth}/ui/base.tsx (100%) rename packages/functions/src/{ => auth}/ui/css.ts (100%) create mode 100644 packages/functions/src/auth/ui/index.ts rename packages/functions/src/{ui/adapters => auth/ui}/oauth2.tsx (98%) rename packages/functions/src/{ => auth}/ui/password.tsx (99%) rename packages/functions/src/{ => auth}/ui/select.tsx (100%) create mode 100644 packages/functions/src/auth/utils/discord.ts rename packages/functions/src/{utils.ts => auth/utils/github.ts} (54%) create mode 100644 packages/functions/src/auth/utils/index.ts delete mode 100644 packages/functions/src/migrator.ts delete mode 100644 packages/functions/src/party/authorizer.ts delete mode 100644 packages/functions/src/type.ts rename packages/functions/src/{log-polyfill.ts => utils/patch-logger.ts} (100%) delete mode 100644 packages/functions/src/zero.ts diff --git a/bun.lock b/bun.lock index 6c69ffbd..712e67fd 100644 --- a/bun.lock +++ b/bun.lock @@ -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=="], diff --git a/infra/auth.ts b/infra/auth.ts index 4054d980..085ebc12 100644 --- a/infra/auth.ts +++ b/infra/auth.ts @@ -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, diff --git a/infra/postgres.ts b/infra/postgres.ts index 2c129478..0edbebb4 100644 --- a/infra/postgres.ts +++ b/infra/postgres.ts @@ -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, +// }); +// } diff --git a/infra/zero.ts b/infra/zero.ts index 80012713..654fefa2 100644 --- a/infra/zero.ts +++ b/infra/zero.ts @@ -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, diff --git a/packages/functions/.gitignore b/packages/functions/.gitignore index ce007acb..a14702c4 100644 --- a/packages/functions/.gitignore +++ b/packages/functions/.gitignore @@ -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 \ No newline at end of file +.DS_Store diff --git a/packages/functions/README.md b/packages/functions/README.md index ed5db4f0..10c5b5e1 100644 --- a/packages/functions/README.md +++ b/packages/functions/README.md @@ -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. diff --git a/packages/functions/package.json b/packages/functions/package.json index 85242da0..66222fe3 100644 --- a/packages/functions/package.json +++ b/packages/functions/package.json @@ -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" } -} \ No newline at end of file +} diff --git a/packages/functions/src/api/account.ts b/packages/functions/src/api/account.ts index 22691c44..5fafa8ea 100644 --- a/packages/functions/src/api/account.ts +++ b/packages/functions/src/api/account.ts @@ -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 { diff --git a/packages/functions/src/api/common.ts b/packages/functions/src/api/common.ts deleted file mode 100644 index 35cde6d9..00000000 --- a/packages/functions/src/api/common.ts +++ /dev/null @@ -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(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; - }; - out: { - [K in Target]: z.output; - }; - } -> => { - // Create a custom error handler that formats errors according to our standards - // const standardErrorHandler: Parameters[2] = ( - const standardErrorHandler: Hook, 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.", - }, -}; \ No newline at end of file diff --git a/packages/functions/src/api/index.ts b/packages/functions/src/api/index.ts index 3ec536d5..7756c781 100644 --- a/packages/functions/src/api/index.ts +++ b/packages/functions/src/api/index.ts @@ -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); diff --git a/packages/functions/src/api/machine.ts b/packages/functions/src/api/machine.ts deleted file mode 100644 index 1fa2b799..00000000 --- a/packages/functions/src/api/machine.ts +++ /dev/null @@ -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); - } - ) -} \ No newline at end of file diff --git a/packages/functions/src/api/messages.ts b/packages/functions/src/api/messages.ts deleted file mode 100644 index 992cd9a9..00000000 --- a/packages/functions/src/api/messages.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { z } from "zod" - -// Base message interface -export interface BaseMessage { - type: string; // e.g., "start", "stop", "status" - payload: Record; // 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]); \ No newline at end of file diff --git a/packages/functions/src/api/polar.ts b/packages/functions/src/api/polar.ts deleted file mode 100644 index 0c1a5706..00000000 --- a/packages/functions/src/api/polar.ts +++ /dev/null @@ -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; - 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 }); - } - ) -} \ No newline at end of file diff --git a/packages/functions/src/api/subscription.ts b/packages/functions/src/api/subscription.ts deleted file mode 100644 index d6614c58..00000000 --- a/packages/functions/src/api/subscription.ts +++ /dev/null @@ -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 - }) - } - ) -} \ No newline at end of file diff --git a/packages/functions/src/api/team.ts b/packages/functions/src/api/team.ts deleted file mode 100644 index da10ece9..00000000 --- a/packages/functions/src/api/team.ts +++ /dev/null @@ -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, - } - }) - } - ) -} \ No newline at end of file diff --git a/packages/functions/src/api/auth.ts b/packages/functions/src/api/utils/auth.ts similarity index 97% rename from packages/functions/src/api/auth.ts rename to packages/functions/src/api/utils/auth.ts index 1fa21177..5d0ac6ea 100644 --- a/packages/functions/src/api/auth.ts +++ b/packages/functions/src/api/utils/auth.ts @@ -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) => { diff --git a/packages/functions/src/api/utils/error.ts b/packages/functions/src/api/utils/error.ts new file mode 100644 index 00000000..e255808f --- /dev/null +++ b/packages/functions/src/api/utils/error.ts @@ -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.", + }, + }; \ No newline at end of file diff --git a/packages/functions/src/api/types/hook.ts b/packages/functions/src/api/utils/hook.ts similarity index 97% rename from packages/functions/src/api/types/hook.ts rename to packages/functions/src/api/utils/hook.ts index 53238f8d..7a58fbc1 100644 --- a/packages/functions/src/api/types/hook.ts +++ b/packages/functions/src/api/utils/hook.ts @@ -17,4 +17,4 @@ declare const zValidator: , Target e out: { [K_2 in Target]: Out; }; }, V extends I = I>(target: Target, schema: T, hook?: Hook, E, P, Target, {}> | undefined) => MiddlewareHandler; -export { type Hook, zValidator }; +export { type Hook, zValidator }; \ No newline at end of file diff --git a/packages/functions/src/api/utils/index.ts b/packages/functions/src/api/utils/index.ts new file mode 100644 index 00000000..40ff5bde --- /dev/null +++ b/packages/functions/src/api/utils/index.ts @@ -0,0 +1,3 @@ +export * from "./validator"; +export * from "./result"; +export * from "./error"; \ No newline at end of file diff --git a/packages/functions/src/api/utils/result.ts b/packages/functions/src/api/utils/result.ts new file mode 100644 index 00000000..248e9aa9 --- /dev/null +++ b/packages/functions/src/api/utils/result.ts @@ -0,0 +1,6 @@ +import { z } from "zod"; +import { resolver } from "hono-openapi/zod"; + +export function Result(schema: T) { + return resolver(z.object({ data: schema })); +} diff --git a/packages/functions/src/api/utils/validator.ts b/packages/functions/src/api/utils/validator.ts new file mode 100644 index 00000000..f5da2f6e --- /dev/null +++ b/packages/functions/src/api/utils/validator.ts @@ -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, + { + in: { + [K in Target]: z.input; + }; + out: { + [K in Target]: z.output; + }; + } +> => { + const standardErrorHandler: Hook, 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); +}; diff --git a/packages/functions/src/ui/adapters/discord.ts b/packages/functions/src/auth/adapters/discord.ts similarity index 79% rename from packages/functions/src/ui/adapters/discord.ts rename to packages/functions/src/auth/adapters/discord.ts index 7eef9e27..cadc3369 100644 --- a/packages/functions/src/ui/adapters/discord.ts +++ b/packages/functions/src/auth/adapters/discord.ts @@ -1,4 +1,4 @@ -import { Oauth2Adapter, type Oauth2WrappedConfig } from "./oauth2" +import { Oauth2Adapter, type Oauth2WrappedConfig } from "../ui/oauth2" export function DiscordAdapter(config: Oauth2WrappedConfig) { return Oauth2Adapter({ diff --git a/packages/functions/src/ui/adapters/github.ts b/packages/functions/src/auth/adapters/github.ts similarity index 79% rename from packages/functions/src/ui/adapters/github.ts rename to packages/functions/src/auth/adapters/github.ts index 7a53faf0..b5d70d54 100644 --- a/packages/functions/src/ui/adapters/github.ts +++ b/packages/functions/src/auth/adapters/github.ts @@ -1,4 +1,4 @@ -import { Oauth2Adapter, type Oauth2WrappedConfig } from "./oauth2" +import { Oauth2Adapter, type Oauth2WrappedConfig } from "../ui/oauth2" export function GithubAdapter(config: Oauth2WrappedConfig) { return Oauth2Adapter({ diff --git a/packages/functions/src/auth/adapters/index.ts b/packages/functions/src/auth/adapters/index.ts new file mode 100644 index 00000000..3e5e1c54 --- /dev/null +++ b/packages/functions/src/auth/adapters/index.ts @@ -0,0 +1,3 @@ +export * from "./discord" +export * from "./github" +export * from "./password" \ No newline at end of file diff --git a/packages/functions/src/ui/adapters/password.ts b/packages/functions/src/auth/adapters/password.ts similarity index 100% rename from packages/functions/src/ui/adapters/password.ts rename to packages/functions/src/auth/adapters/password.ts diff --git a/packages/functions/src/auth.ts b/packages/functions/src/auth/index.ts similarity index 68% rename from packages/functions/src/auth.ts rename to packages/functions/src/auth/index.ts index 1c45e5ef..242c25b2 100644 --- a/packages/functions/src/auth.ts +++ b/packages/functions/src/auth/index.ts @@ -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')) diff --git a/packages/functions/src/ui/base.tsx b/packages/functions/src/auth/ui/base.tsx similarity index 100% rename from packages/functions/src/ui/base.tsx rename to packages/functions/src/auth/ui/base.tsx diff --git a/packages/functions/src/ui/css.ts b/packages/functions/src/auth/ui/css.ts similarity index 100% rename from packages/functions/src/ui/css.ts rename to packages/functions/src/auth/ui/css.ts diff --git a/packages/functions/src/auth/ui/index.ts b/packages/functions/src/auth/ui/index.ts new file mode 100644 index 00000000..e5919fb6 --- /dev/null +++ b/packages/functions/src/auth/ui/index.ts @@ -0,0 +1,2 @@ +export * from "./password" +export * from "./select" \ No newline at end of file diff --git a/packages/functions/src/ui/adapters/oauth2.tsx b/packages/functions/src/auth/ui/oauth2.tsx similarity index 98% rename from packages/functions/src/ui/adapters/oauth2.tsx rename to packages/functions/src/auth/ui/oauth2.tsx index 5331d2d5..b344057b 100644 --- a/packages/functions/src/ui/adapters/oauth2.tsx +++ b/packages/functions/src/auth/ui/oauth2.tsx @@ -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" diff --git a/packages/functions/src/ui/password.tsx b/packages/functions/src/auth/ui/password.tsx similarity index 99% rename from packages/functions/src/ui/password.tsx rename to packages/functions/src/auth/ui/password.tsx index c84d6036..a4e5ee18 100644 --- a/packages/functions/src/ui/password.tsx +++ b/packages/functions/src/auth/ui/password.tsx @@ -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" diff --git a/packages/functions/src/ui/select.tsx b/packages/functions/src/auth/ui/select.tsx similarity index 100% rename from packages/functions/src/ui/select.tsx rename to packages/functions/src/auth/ui/select.tsx diff --git a/packages/functions/src/auth/utils/discord.ts b/packages/functions/src/auth/utils/discord.ts new file mode 100644 index 00000000..25f7daa4 --- /dev/null +++ b/packages/functions/src/auth/utils/discord.ts @@ -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; + } + +} \ No newline at end of file diff --git a/packages/functions/src/utils.ts b/packages/functions/src/auth/utils/github.ts similarity index 54% rename from packages/functions/src/utils.ts rename to packages/functions/src/auth/utils/github.ts index dce82db7..af689bd7 100644 --- a/packages/functions/src/utils.ts +++ b/packages/functions/src/auth/utils/github.ts @@ -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; - } - } \ No newline at end of file diff --git a/packages/functions/src/auth/utils/index.ts b/packages/functions/src/auth/utils/index.ts new file mode 100644 index 00000000..1544575a --- /dev/null +++ b/packages/functions/src/auth/utils/index.ts @@ -0,0 +1,2 @@ +export * from "./discord" +export * from "./github" \ No newline at end of file diff --git a/packages/functions/src/migrator.ts b/packages/functions/src/migrator.ts deleted file mode 100644 index f6fb8259..00000000 --- a/packages/functions/src/migrator.ts +++ /dev/null @@ -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", - }); -}; \ No newline at end of file diff --git a/packages/functions/src/party/authorizer.ts b/packages/functions/src/party/authorizer.ts deleted file mode 100644 index d7b3c978..00000000 --- a/packages/functions/src/party/authorizer.ts +++ /dev/null @@ -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}/*`], - }; -}); \ No newline at end of file diff --git a/packages/functions/src/realtime/create.ts b/packages/functions/src/realtime/create.ts index 754fd7ce..8c6f23fa 100644 --- a/packages/functions/src/realtime/create.ts +++ b/packages/functions/src/realtime/create.ts @@ -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, diff --git a/packages/functions/src/subjects.ts b/packages/functions/src/subjects.ts index 4c6e9c88..040e61eb 100644 --- a/packages/functions/src/subjects.ts +++ b/packages/functions/src/subjects.ts @@ -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(), + }) }) \ No newline at end of file diff --git a/packages/functions/src/type.ts b/packages/functions/src/type.ts deleted file mode 100644 index 2957c7ee..00000000 --- a/packages/functions/src/type.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum Subscription { - Pro = "Pro", - Free = "Free" -} \ No newline at end of file diff --git a/packages/functions/src/log-polyfill.ts b/packages/functions/src/utils/patch-logger.ts similarity index 100% rename from packages/functions/src/log-polyfill.ts rename to packages/functions/src/utils/patch-logger.ts diff --git a/packages/functions/src/zero.ts b/packages/functions/src/zero.ts deleted file mode 100644 index efe320f9..00000000 --- a/packages/functions/src/zero.ts +++ /dev/null @@ -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)) -} \ No newline at end of file diff --git a/packages/functions/tsconfig.json b/packages/functions/tsconfig.json index e5a2d1f5..c829fea7 100644 --- a/packages/functions/tsconfig.json +++ b/packages/functions/tsconfig.json @@ -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 } -} \ No newline at end of file +}