This commit is contained in:
13
better-auth_migrations/2026-04-06T06-34-22.284Z.sql
Normal file
13
better-auth_migrations/2026-04-06T06-34-22.284Z.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
create table "user" ("id" text not null primary key, "name" text not null, "email" text not null unique, "emailVerified" boolean not null, "image" text, "createdAt" timestamptz default CURRENT_TIMESTAMP not null, "updatedAt" timestamptz default CURRENT_TIMESTAMP not null);
|
||||
|
||||
create table "session" ("id" text not null primary key, "expiresAt" timestamptz not null, "token" text not null unique, "createdAt" timestamptz default CURRENT_TIMESTAMP not null, "updatedAt" timestamptz not null, "ipAddress" text, "userAgent" text, "userId" text not null references "user" ("id") on delete cascade);
|
||||
|
||||
create table "account" ("id" text not null primary key, "accountId" text not null, "providerId" text not null, "userId" text not null references "user" ("id") on delete cascade, "accessToken" text, "refreshToken" text, "idToken" text, "accessTokenExpiresAt" timestamptz, "refreshTokenExpiresAt" timestamptz, "scope" text, "password" text, "createdAt" timestamptz default CURRENT_TIMESTAMP not null, "updatedAt" timestamptz not null);
|
||||
|
||||
create table "verification" ("id" text not null primary key, "identifier" text not null, "value" text not null, "expiresAt" timestamptz not null, "createdAt" timestamptz default CURRENT_TIMESTAMP not null, "updatedAt" timestamptz default CURRENT_TIMESTAMP not null);
|
||||
|
||||
create index "session_userId_idx" on "session" ("userId");
|
||||
|
||||
create index "account_userId_idx" on "account" ("userId");
|
||||
|
||||
create index "verification_identifier_idx" on "verification" ("identifier");
|
||||
83
bun.lock
83
bun.lock
@@ -9,11 +9,16 @@
|
||||
"@grpc/grpc-js": "^1.14.3",
|
||||
"@grpc/proto-loader": "^0.8.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"better-auth": "^1.5.6",
|
||||
"jose": "^6.1.3",
|
||||
"nodemailer": "^8.0.5",
|
||||
"pg": "^8.20.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/bun": "latest",
|
||||
"@types/nodemailer": "^8.0.0",
|
||||
"@types/pg": "^8.20.0",
|
||||
"prettier": "3.8.1",
|
||||
"ts-proto": "^2.11.4",
|
||||
},
|
||||
@@ -103,6 +108,24 @@
|
||||
|
||||
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="],
|
||||
|
||||
"@better-auth/core": ["@better-auth/core@1.5.6", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.39.0", "@standard-schema/spec": "^1.1.0", "zod": "^4.3.6" }, "peerDependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@cloudflare/workers-types": ">=4", "@opentelemetry/api": "^1.9.0", "better-call": "1.3.2", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" }, "optionalPeers": ["@cloudflare/workers-types"] }, "sha512-Ez9DZdIMFyxHremmoLz1emFPGNQomDC1jqqBPnZ6Ci+6TiGN3R9w/Y03cJn6I8r1ycKgOzeVMZtJ/erOZ27Gsw=="],
|
||||
|
||||
"@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.5.6", "", { "peerDependencies": { "@better-auth/core": "1.5.6", "@better-auth/utils": "^0.3.0", "drizzle-orm": ">=0.41.0" }, "optionalPeers": ["drizzle-orm"] }, "sha512-VfFFmaoFw3ug12SiSuIwzrMoHyIVmkMGWm9gZ4sXdYYVX4HboCL4m3fjzOhppcmK5OGatRuU+N1UX6wxCITcXw=="],
|
||||
|
||||
"@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.5.6", "", { "peerDependencies": { "@better-auth/core": "1.5.6", "@better-auth/utils": "^0.3.0", "kysely": "^0.27.0 || ^0.28.0" }, "optionalPeers": ["kysely"] }, "sha512-Fnf+h8WVKtw6lEOmVmiVVzDf3shJtM60AYf9XTnbdCeUd6MxN/KnaJZpkgtYnRs7a+nwtkVB+fg4lGETebGFXQ=="],
|
||||
|
||||
"@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.5.6", "", { "peerDependencies": { "@better-auth/core": "1.5.6", "@better-auth/utils": "^0.3.0" } }, "sha512-rS7ZsrIl5uvloUgNN0u9LOZJMMXnsZXVdUZ3MrTBKWM2KpoJjzPr9yN3Szyma5+0V7SltnzSGHPkYj2bEzzmlA=="],
|
||||
|
||||
"@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.5.6", "", { "peerDependencies": { "@better-auth/core": "1.5.6", "@better-auth/utils": "^0.3.0", "mongodb": "^6.0.0 || ^7.0.0" }, "optionalPeers": ["mongodb"] }, "sha512-6+M3MS2mor8fTUV3EI1FBLP0cs6QfbN+Ovx9+XxR/GdfKIBoNFzmPEPRbdGt+ft6PvrITsUm+T70+kkHgVSP6w=="],
|
||||
|
||||
"@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.5.6", "", { "peerDependencies": { "@better-auth/core": "1.5.6", "@better-auth/utils": "^0.3.0", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@prisma/client", "prisma"] }, "sha512-UxY9vQJs1Tt+O+T2YQnseDMlWmUSQvFZSBb5YiFRg7zcm+TEzujh4iX2/csA0YiZptLheovIuVWTP9nriewEBA=="],
|
||||
|
||||
"@better-auth/telemetry": ["@better-auth/telemetry@1.5.6", "", { "dependencies": { "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21" }, "peerDependencies": { "@better-auth/core": "1.5.6" } }, "sha512-yXC7NSxnIFlxDkGdpD7KA+J9nqIQAPCJKe77GoaC5bWoe/DALo1MYorZfTgOafS7wrslNtsPT4feV/LJi1ubqQ=="],
|
||||
|
||||
"@better-auth/utils": ["@better-auth/utils@0.3.1", "", {}, "sha512-+CGp4UmZSUrHHnpHhLPYu6cV+wSUSvVbZbNykxhUDocpVNTo9uFFxw/NqJlh1iC4wQ9HKKWGCKuZ5wUgS0v6Kg=="],
|
||||
|
||||
"@better-fetch/fetch": ["@better-fetch/fetch@1.1.21", "", {}, "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A=="],
|
||||
|
||||
"@bufbuild/protobuf": ["@bufbuild/protobuf@2.11.0", "", {}, "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ=="],
|
||||
|
||||
"@grpc/grpc-js": ["@grpc/grpc-js@1.14.3", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA=="],
|
||||
@@ -111,6 +134,14 @@
|
||||
|
||||
"@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="],
|
||||
|
||||
"@noble/ciphers": ["@noble/ciphers@2.1.1", "", {}, "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw=="],
|
||||
|
||||
"@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
|
||||
|
||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
||||
|
||||
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
||||
|
||||
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
||||
@@ -233,18 +264,28 @@
|
||||
|
||||
"@smithy/uuid": ["@smithy/uuid@1.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g=="],
|
||||
|
||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||
|
||||
"@types/bcrypt": ["@types/bcrypt@6.0.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
|
||||
|
||||
"@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="],
|
||||
|
||||
"@types/nodemailer": ["@types/nodemailer@8.0.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA=="],
|
||||
|
||||
"@types/pg": ["@types/pg@8.20.0", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"bcrypt": ["bcrypt@6.0.0", "", { "dependencies": { "node-addon-api": "^8.3.0", "node-gyp-build": "^4.8.4" } }, "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg=="],
|
||||
|
||||
"better-auth": ["better-auth@1.5.6", "", { "dependencies": { "@better-auth/core": "1.5.6", "@better-auth/drizzle-adapter": "1.5.6", "@better-auth/kysely-adapter": "1.5.6", "@better-auth/memory-adapter": "1.5.6", "@better-auth/mongo-adapter": "1.5.6", "@better-auth/prisma-adapter": "1.5.6", "@better-auth/telemetry": "1.5.6", "@better-auth/utils": "0.3.1", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", "better-call": "1.3.2", "defu": "^6.1.4", "jose": "^6.1.3", "kysely": "^0.28.12", "nanostores": "^1.1.1", "zod": "^4.3.6" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", "drizzle-orm": ">=0.41.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-QSpJTqaT1XVfWRQe/fm3PgeuwOIlz1nWX/Dx7nsHStJ382bLzmDbQk2u7IT0IJ6wS5SRxfqEE1Ev9TXontgyAQ=="],
|
||||
|
||||
"better-call": ["better-call@1.3.2", "", { "dependencies": { "@better-auth/utils": "^0.3.1", "@better-fetch/fetch": "^1.1.21", "rou3": "^0.7.12", "set-cookie-parser": "^3.0.1" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-4cZIfrerDsNTn3cm+MhLbUePN0gdwkhSXEuG7r/zuQ8c/H7iU0/jSK5TD3FW7U0MgKHce/8jGpPYNO4Ve+4NBw=="],
|
||||
|
||||
"bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
|
||||
@@ -257,6 +298,8 @@
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"defu": ["defu@6.1.6", "", {}, "sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug=="],
|
||||
|
||||
"detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
|
||||
|
||||
"dprint-node": ["dprint-node@1.0.8", "", { "dependencies": { "detect-libc": "^1.0.3" } }, "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg=="],
|
||||
@@ -275,22 +318,58 @@
|
||||
|
||||
"jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
|
||||
|
||||
"kysely": ["kysely@0.28.15", "", {}, "sha512-r2clcf7HLWvDXaVUEvQymXJY4i3bSOIV3xsL/Upy3ZfSv5HeKsk9tsqbBptLvth5qHEIhxeHTA2jNLyQABkLBA=="],
|
||||
|
||||
"lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
|
||||
|
||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||
|
||||
"nanostores": ["nanostores@1.2.0", "", {}, "sha512-F0wCzbsH80G7XXo0Jd9/AVQC7ouWY6idUCTnMwW5t/Rv9W8qmO6endavDwg7TNp5GbugwSukFMVZqzPSrSMndg=="],
|
||||
|
||||
"node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="],
|
||||
|
||||
"node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="],
|
||||
|
||||
"nodemailer": ["nodemailer@8.0.5", "", {}, "sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w=="],
|
||||
|
||||
"path-expression-matcher": ["path-expression-matcher@1.1.3", "", {}, "sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ=="],
|
||||
|
||||
"pg": ["pg@8.20.0", "", { "dependencies": { "pg-connection-string": "^2.12.0", "pg-pool": "^3.13.0", "pg-protocol": "^1.13.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA=="],
|
||||
|
||||
"pg-cloudflare": ["pg-cloudflare@1.3.0", "", {}, "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ=="],
|
||||
|
||||
"pg-connection-string": ["pg-connection-string@2.12.0", "", {}, "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ=="],
|
||||
|
||||
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
|
||||
|
||||
"pg-pool": ["pg-pool@3.13.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA=="],
|
||||
|
||||
"pg-protocol": ["pg-protocol@1.13.0", "", {}, "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w=="],
|
||||
|
||||
"pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
|
||||
|
||||
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
|
||||
|
||||
"postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
|
||||
|
||||
"postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="],
|
||||
|
||||
"postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
|
||||
|
||||
"postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
|
||||
|
||||
"prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
|
||||
|
||||
"protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
|
||||
|
||||
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
||||
|
||||
"rou3": ["rou3@0.7.12", "", {}, "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg=="],
|
||||
|
||||
"set-cookie-parser": ["set-cookie-parser@3.1.0", "", {}, "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw=="],
|
||||
|
||||
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
|
||||
|
||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
@@ -311,12 +390,16 @@
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
|
||||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||
|
||||
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
|
||||
"@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
"@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/bun": "latest",
|
||||
"@types/nodemailer": "^8.0.0",
|
||||
"@types/pg": "^8.20.0",
|
||||
"prettier": "3.8.1",
|
||||
"ts-proto": "^2.11.4"
|
||||
},
|
||||
@@ -21,6 +23,9 @@
|
||||
"@grpc/grpc-js": "^1.14.3",
|
||||
"@grpc/proto-loader": "^0.8.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"jose": "^6.1.3"
|
||||
"better-auth": "^1.5.6",
|
||||
"jose": "^6.1.3",
|
||||
"nodemailer": "^8.0.5",
|
||||
"pg": "^8.20.0"
|
||||
}
|
||||
}
|
||||
|
||||
73
src/auth.ts
Normal file
73
src/auth.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { betterAuth } from 'better-auth'
|
||||
import { magicLink, emailOTP } from 'better-auth/plugins'
|
||||
import { Pool } from 'pg'
|
||||
import { emailSender } from './email'
|
||||
|
||||
export const auth = betterAuth({
|
||||
plugins: [
|
||||
emailOTP({
|
||||
async sendVerificationOTP({ email, otp, type }) {
|
||||
if (type === "sign-in") {
|
||||
void emailSender.sendEmail({
|
||||
to: email,
|
||||
subject: 'otp code',
|
||||
text: `sign-in otp code: ${otp}`,
|
||||
})
|
||||
} else if (type === "email-verification") {
|
||||
void emailSender.sendEmail({
|
||||
to: email,
|
||||
subject: 'otp code',
|
||||
text: `email-verification otp code: ${otp}`,
|
||||
})
|
||||
} else {
|
||||
console.log('sign-in', email, otp)
|
||||
// Send the OTP for password reset
|
||||
}
|
||||
},
|
||||
}),
|
||||
magicLink({
|
||||
sendMagicLink: async ({ email, token, url, metadata }, ctx) => {
|
||||
console.log(email,token,url, metadata)
|
||||
// send email to user
|
||||
}
|
||||
})
|
||||
],
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
autoSignIn: false,
|
||||
requireEmailVerification: true,
|
||||
onExistingUserSignUp: async ({ user }, request) => {
|
||||
void emailSender.sendEmail({
|
||||
to: user.email,
|
||||
subject: 'Sign-up attempt with your email',
|
||||
text: 'Someone tried to create an account using your email address. If this was you, try signing in instead. If not, you can safely ignore this email.',
|
||||
})
|
||||
},
|
||||
sendResetPassword: async ({ user, url, token }, request) => {
|
||||
void emailSender.sendEmail({
|
||||
to: user.email,
|
||||
subject: 'Reset your password',
|
||||
text: `Click the link to reset your password: ${url}`,
|
||||
})
|
||||
},
|
||||
onPasswordReset: async ({ user }, request) => {
|
||||
// your logic here
|
||||
console.log(`Password for user ${user.email} has been reset.`)
|
||||
},
|
||||
},
|
||||
emailVerification: {
|
||||
sendVerificationEmail: async ({ user, url }) => {
|
||||
void emailSender.sendEmail({
|
||||
to: user.email,
|
||||
subject: 'Verify your email address',
|
||||
text: `Click the link to verify your email: ${url}`,
|
||||
})
|
||||
},
|
||||
sendOnSignIn: true,
|
||||
},
|
||||
// trustedOrigins: ['http://localhost:3000'],
|
||||
advanced: { disableOriginCheck: true, disableCSRFCheck: true },
|
||||
database: new Pool({
|
||||
connectionString: 'postgres://postgres:postgres@192.168.1.11:5432/users',
|
||||
}),
|
||||
})
|
||||
29
src/email.ts
Normal file
29
src/email.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import nodemailer, { type SendMailOptions } from 'nodemailer'
|
||||
|
||||
class EmailSender {
|
||||
transporter: nodemailer.Transporter
|
||||
|
||||
constructor() {
|
||||
this.transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
auth: {
|
||||
user: process.env.GOOGLE_APP_USER,
|
||||
pass: process.env.GOOGLE_APP_PASSWORD,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async sendEmail(params: SendMailOptions) {
|
||||
try {
|
||||
const verify = await this.transporter.verify()
|
||||
console.log(verify)
|
||||
|
||||
const send = await this.transporter.sendMail(params)
|
||||
console.log(send)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const emailSender = new EmailSender()
|
||||
@@ -1,292 +0,0 @@
|
||||
import path from 'path'
|
||||
import protoLoader from '@grpc/proto-loader'
|
||||
import grpc from '@grpc/grpc-js'
|
||||
|
||||
// req dto
|
||||
interface CreateUserDto {
|
||||
email: string
|
||||
name?: string
|
||||
}
|
||||
|
||||
interface UpdateUserDto {
|
||||
id: number
|
||||
token?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
interface GetUserByTokenDto {
|
||||
token: string
|
||||
}
|
||||
|
||||
interface GetUserByEmailDto {
|
||||
email: string
|
||||
}
|
||||
|
||||
interface GetUserByIDDto {
|
||||
id: number
|
||||
}
|
||||
|
||||
interface ListUserDto {
|
||||
page?: number
|
||||
user_ids?: number[]
|
||||
}
|
||||
|
||||
interface CreateChatDto {
|
||||
name?: string
|
||||
users: { user_id: number; is_admin?: boolean }[]
|
||||
}
|
||||
|
||||
interface UpdateChatDto {
|
||||
id: number
|
||||
users: { user_id: number; is_admin?: boolean }[]
|
||||
}
|
||||
|
||||
interface GetChatDto {
|
||||
id: string
|
||||
}
|
||||
|
||||
interface ListChatDto {
|
||||
page: number
|
||||
user_id: number
|
||||
}
|
||||
|
||||
interface CreateMessageDto {
|
||||
chat_id: string
|
||||
user_id: number
|
||||
text?: string
|
||||
image?: string
|
||||
video?: string
|
||||
file?: string
|
||||
}
|
||||
interface UpdateMessageDto {
|
||||
id: number
|
||||
chat_id: string
|
||||
text?: string
|
||||
image?: string
|
||||
video?: string
|
||||
file?: string
|
||||
}
|
||||
interface GetMessageDto {
|
||||
id: number
|
||||
}
|
||||
interface ListMessageDto {
|
||||
page: number
|
||||
chat_id: string
|
||||
user_id: number
|
||||
}
|
||||
|
||||
interface VersionDto {}
|
||||
|
||||
export interface User {
|
||||
id: number
|
||||
email: string
|
||||
token?: string
|
||||
description?: string
|
||||
is_admin?: boolean
|
||||
}
|
||||
|
||||
export interface Chat {
|
||||
id: string
|
||||
type_id: number
|
||||
name: string
|
||||
users: { user_id: number; is_admin?: boolean }[]
|
||||
}
|
||||
|
||||
interface Message {
|
||||
id: number
|
||||
user_id: number
|
||||
text?: string
|
||||
image?: string
|
||||
video?: string
|
||||
file?: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
interface Version {
|
||||
id: number
|
||||
version: string
|
||||
}
|
||||
|
||||
interface Callback<T> {
|
||||
(error: Error, res: { data: T }): void
|
||||
}
|
||||
|
||||
interface Services {
|
||||
createUser: (data: CreateUserDto, cb: Callback<User>) => void
|
||||
updateUser: (data: UpdateUserDto, cb: Callback<User>) => void
|
||||
getUserByToken: (data: GetUserByTokenDto, cb: Callback<User>) => void
|
||||
getUserByEmail: (data: GetUserByEmailDto, cb: Callback<User>) => void
|
||||
getUser: (data: GetUserByIDDto, cb: Callback<User>) => void
|
||||
listUser: (data: ListUserDto, cb: Callback<User[]>) => void
|
||||
createChat: (data: CreateChatDto, cb: Callback<Chat>) => void
|
||||
updateChat: (data: UpdateChatDto, cb: Callback<Chat>) => void
|
||||
getChat: (data: GetChatDto, cb: Callback<Chat>) => void
|
||||
listChat: (data: ListChatDto, cb: Callback<Chat[]>) => void
|
||||
createMessage: (data: CreateMessageDto, cb: Callback<Message>) => void
|
||||
updateMessage: (data: UpdateMessageDto, cb: Callback<Message>) => void
|
||||
getMessage: (data: GetMessageDto, cb: Callback<Message>) => void
|
||||
listMessage: (data: ListMessageDto, cb: Callback<Message[]>) => void
|
||||
getVersion: (data: VersionDto, cb: Callback<Version>) => void
|
||||
}
|
||||
|
||||
class GrpcClient {
|
||||
private messageClient: Services
|
||||
|
||||
constructor() {
|
||||
console.log('Grpc Client init')
|
||||
const PROTO_PATH = path.resolve('./proto/message.proto')
|
||||
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
})
|
||||
|
||||
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition)
|
||||
const messageProto = protoDescriptor.message as any
|
||||
this.messageClient = new messageProto.MessageService('localhost:8070', grpc.credentials.createInsecure())
|
||||
}
|
||||
|
||||
// User
|
||||
createUser(dto: CreateUserDto): Promise<{ data: User }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.createUser(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
updateUser(dto: UpdateUserDto): Promise<{ data: User }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.updateUser(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getUserByToken(dto: GetUserByTokenDto): Promise<{ data: User }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.getUserByToken(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getUserByEmail(dto: GetUserByEmailDto): Promise<{ data: User }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.getUserByEmail(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getUser(dto: GetUserByIDDto): Promise<{ data: User }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.getUser(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
listUser(dto: ListUserDto): Promise<{ data: User[] }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.listUser(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Chat
|
||||
createChat(dto: CreateChatDto): Promise<{ data: Chat }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.createChat(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
updateChat(dto: UpdateChatDto): Promise<{ data: Chat }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.updateChat(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getChat(dto: GetChatDto): Promise<{ data: Chat }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.getChat(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
listChat(dto: ListChatDto): Promise<{ data: Chat[] }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.listChat(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// message
|
||||
createMessage(dto: CreateMessageDto): Promise<{ data: Message }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.createMessage(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
updateMessage(dto: UpdateMessageDto): Promise<{ data: Message }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.updateMessage(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getMessage(dto: GetMessageDto): Promise<{ data: Message }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.getMessage(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
listMessage(dto: ListMessageDto): Promise<{ data: Message[] }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.listMessage(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// version
|
||||
getVersion(dto: VersionDto): Promise<{ data: Version }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.messageClient.getVersion(dto, (error, data) => {
|
||||
if (error) reject(error?.message)
|
||||
else resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const grpcClient = new GrpcClient()
|
||||
@@ -1,15 +1,15 @@
|
||||
import { HttpStatusCodes } from './constants.ts'
|
||||
import { errors } from 'jose'
|
||||
import type { LoginDto, WebSocketCtx, WebSocketData } from './types/types.ts'
|
||||
import type { LoginDto, WebSocketCtx } from './types.ts'
|
||||
import { createAccessToken, verifyAccessToken } from './utils/jwt.ts'
|
||||
import { config } from './config.ts'
|
||||
import { messageService } from './grpc/message.ts'
|
||||
import { storage } from './storage'
|
||||
import { randomUUIDv7 } from 'bun'
|
||||
import { auth } from './auth.ts'
|
||||
|
||||
export const handlers = {
|
||||
async getVersion(req: Request) {
|
||||
console.log('test')
|
||||
try {
|
||||
const res = await messageService.getVersion()
|
||||
console.log(res)
|
||||
@@ -53,23 +53,32 @@ export const handlers = {
|
||||
return Response.json({ message: 'Invalid image' }, { status: HttpStatusCodes.BAD_REQUEST })
|
||||
}
|
||||
const uuid = randomUUIDv7()
|
||||
await storage.upload(file,`${uuid}.${file.type.split('/')[1]}`)
|
||||
await storage.upload(file, `${uuid}.${file.type.split('/')[1]}`)
|
||||
},
|
||||
async getAvatar(req: Request) {
|
||||
const url = storage.presign('avatar.jpg')
|
||||
|
||||
return Response.json({ url })
|
||||
}
|
||||
}
|
||||
},
|
||||
async upgrade(req: Request, server: Bun.Server<WebSocketCtx>) {
|
||||
const payload = await checkRequest(req)
|
||||
|
||||
export async function upgrade(req: Request, server: Bun.Server<WebSocketCtx>) {
|
||||
const payload = await checkRequest(req)
|
||||
if (!payload) return new Response('Invalid token', { status: HttpStatusCodes.NOT_FOUND })
|
||||
const session = await auth.api.getSession({
|
||||
headers: req.headers,
|
||||
})
|
||||
console.log(session)
|
||||
if (!session) {
|
||||
return Response.json({ message: 'unauthorised' }, { status: HttpStatusCodes.UNAUTHORIZED })
|
||||
}
|
||||
|
||||
const success = server.upgrade(req, { data: { userId: +payload.sub, email: payload.email } })
|
||||
if (success) return undefined
|
||||
console.log(payload)
|
||||
if (!payload) return new Response('Invalid token', { status: HttpStatusCodes.NOT_FOUND })
|
||||
|
||||
return new Response('Upgrade failed', { status: HttpStatusCodes.BAD_REQUEST })
|
||||
const success = server.upgrade(req, { data: { userId: +payload.sub, email: payload.email } })
|
||||
if (success) return undefined
|
||||
|
||||
return new Response('Upgrade failed', { status: HttpStatusCodes.BAD_REQUEST })
|
||||
},
|
||||
}
|
||||
|
||||
async function checkRequest(req: Request) {
|
||||
|
||||
64
src/index.ts
64
src/index.ts
@@ -1,26 +1,31 @@
|
||||
import { HttpStatusCodes } from './constants.ts'
|
||||
import type { WebSocketCtx, WebSocketData } from './types/types.ts'
|
||||
|
||||
import { handlers, upgrade } from './handles.ts'
|
||||
import type { WebSocketCtx, WebSocketData } from './types.ts'
|
||||
import { handlers } from './handles.ts'
|
||||
import { messageService } from './grpc/message.ts'
|
||||
import { auth } from './auth.ts'
|
||||
|
||||
const PORT = 3000
|
||||
async function authCheck(req: Request, fn: (request: Request) => Promise<Response>) {
|
||||
const session = await auth.api.getSession({
|
||||
headers: req.headers,
|
||||
})
|
||||
if (!session) {
|
||||
return Response.json({ message: 'unauthorised' }, { status: HttpStatusCodes.UNAUTHORIZED })
|
||||
}
|
||||
|
||||
return fn(req)
|
||||
}
|
||||
|
||||
const server = Bun.serve({
|
||||
port: PORT,
|
||||
|
||||
port: 3000,
|
||||
routes: {
|
||||
'/api/auth/*': auth.handler,
|
||||
'/api/version': handlers.getVersion,
|
||||
},
|
||||
async fetch(req, server) {
|
||||
const url = new URL(req.url)
|
||||
const pathname = url.pathname
|
||||
const method = req.method
|
||||
if (url.pathname === '/ws') return handlers.upgrade(req, server)
|
||||
|
||||
if (pathname === '/api/version' && method === 'GET') return handlers.getVersion(req)
|
||||
if (pathname === '/api/avatar' && method === 'POST') return handlers.setAvatar(req)
|
||||
if (pathname === '/api/avatar' && method === 'GET') return handlers.getAvatar(req)
|
||||
if (pathname === '/api/login' && method === 'POST') return handlers.login(req)
|
||||
if (pathname === '/ws') return upgrade(req, server)
|
||||
|
||||
return new Response('Not found', { status: HttpStatusCodes.NOT_FOUND })
|
||||
return Response.json({ message: 'unknown url' }, { status: HttpStatusCodes.NOT_FOUND })
|
||||
},
|
||||
websocket: {
|
||||
data: {} as WebSocketCtx,
|
||||
@@ -30,13 +35,14 @@ const server = Bun.serve({
|
||||
console.log('ipAddr', ipAddr)
|
||||
|
||||
const user = ws.data
|
||||
console.log(user)
|
||||
|
||||
const userResponse = await messageService.getUser({ id: user.userId })
|
||||
ws.send(JSON.stringify({ type: 'USER', ...userResponse }))
|
||||
|
||||
const chatResponse = await messageService.listChat({ page: 0, userId: user.userId })
|
||||
chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
||||
ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
||||
// const userResponse = await messageService.getUser({ id: user.userId })
|
||||
// ws.send(JSON.stringify({ type: 'USER', ...userResponse }))
|
||||
//
|
||||
// const chatResponse = await messageService.listChat({ page: 0, userId: user.userId })
|
||||
// chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
||||
// ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
ws.close(1011, 'error')
|
||||
@@ -52,12 +58,17 @@ const server = Bun.serve({
|
||||
async message(ws, message) {
|
||||
console.log('Websocket message', message)
|
||||
|
||||
// const str = 'Hello World'
|
||||
// const encoder = new TextEncoder()
|
||||
// const arrayBuffer = encoder.encode(str).buffer
|
||||
// console.log({ arrayBuffer })
|
||||
|
||||
try {
|
||||
if (typeof message === 'string') {
|
||||
const webSocketData = JSON.parse(message) as WebSocketData
|
||||
if (!webSocketData) return
|
||||
|
||||
if(webSocketData.type === 'GET_CHATS') {
|
||||
if (webSocketData.type === 'GET_CHATS') {
|
||||
const chatResponse = await messageService.listChat({ page: 0, userId: ws.data.userId })
|
||||
chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
||||
ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
||||
@@ -65,15 +76,12 @@ const server = Bun.serve({
|
||||
|
||||
if (webSocketData.type === 'CREATE_CHAT') {
|
||||
const chat = await messageService.createChat({
|
||||
users: [
|
||||
{ userId: webSocketData.data.userId },
|
||||
{ userId: ws.data.userId }
|
||||
] })
|
||||
users: [{ userId: webSocketData.data.userId }, { userId: ws.data.userId }],
|
||||
})
|
||||
if (chat?.data) {
|
||||
ws.subscribe(chat.data.id)
|
||||
ws.send(JSON.stringify({ type: 'CHATS', ...chat }))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (webSocketData.type === 'CREATE_MESSAGE') {
|
||||
@@ -126,5 +134,5 @@ const server = Bun.serve({
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
console.log(Bun.version)
|
||||
console.log(`Listening on ${server.hostname}:${server.port}`)
|
||||
|
||||
11
src/sqlite/index.ts
Normal file
11
src/sqlite/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Database, constants } from 'bun:sqlite'
|
||||
|
||||
const db = new Database('db.sqlite', {create: true, strict: true})
|
||||
db.run('PRAGMA journal_mode = WAL;')
|
||||
|
||||
db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0)
|
||||
// Checkpoint and truncate the WAL file
|
||||
db.run('PRAGMA wal_checkpoint(TRUNCATE);')
|
||||
db.close()
|
||||
|
||||
const query = db.query(`select "Hello world" as message`)
|
||||
Reference in New Issue
Block a user