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/grpc-js": "^1.14.3",
|
||||||
"@grpc/proto-loader": "^0.8.0",
|
"@grpc/proto-loader": "^0.8.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
|
"better-auth": "^1.5.6",
|
||||||
"jose": "^6.1.3",
|
"jose": "^6.1.3",
|
||||||
|
"nodemailer": "^8.0.5",
|
||||||
|
"pg": "^8.20.0",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcrypt": "^6.0.0",
|
"@types/bcrypt": "^6.0.0",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
|
"@types/nodemailer": "^8.0.0",
|
||||||
|
"@types/pg": "^8.20.0",
|
||||||
"prettier": "3.8.1",
|
"prettier": "3.8.1",
|
||||||
"ts-proto": "^2.11.4",
|
"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=="],
|
"@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=="],
|
"@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=="],
|
"@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=="],
|
"@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/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
||||||
|
|
||||||
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
"@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=="],
|
"@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/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/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/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-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=="],
|
"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=="],
|
"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=="],
|
"bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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-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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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=="],
|
"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": ["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=="],
|
"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/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=="],
|
"@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": {
|
"devDependencies": {
|
||||||
"@types/bcrypt": "^6.0.0",
|
"@types/bcrypt": "^6.0.0",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
|
"@types/nodemailer": "^8.0.0",
|
||||||
|
"@types/pg": "^8.20.0",
|
||||||
"prettier": "3.8.1",
|
"prettier": "3.8.1",
|
||||||
"ts-proto": "^2.11.4"
|
"ts-proto": "^2.11.4"
|
||||||
},
|
},
|
||||||
@@ -21,6 +23,9 @@
|
|||||||
"@grpc/grpc-js": "^1.14.3",
|
"@grpc/grpc-js": "^1.14.3",
|
||||||
"@grpc/proto-loader": "^0.8.0",
|
"@grpc/proto-loader": "^0.8.0",
|
||||||
"bcrypt": "^6.0.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 { HttpStatusCodes } from './constants.ts'
|
||||||
import { errors } from 'jose'
|
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 { createAccessToken, verifyAccessToken } from './utils/jwt.ts'
|
||||||
import { config } from './config.ts'
|
import { config } from './config.ts'
|
||||||
import { messageService } from './grpc/message.ts'
|
import { messageService } from './grpc/message.ts'
|
||||||
import { storage } from './storage'
|
import { storage } from './storage'
|
||||||
import { randomUUIDv7 } from 'bun'
|
import { randomUUIDv7 } from 'bun'
|
||||||
|
import { auth } from './auth.ts'
|
||||||
|
|
||||||
export const handlers = {
|
export const handlers = {
|
||||||
async getVersion(req: Request) {
|
async getVersion(req: Request) {
|
||||||
console.log('test')
|
|
||||||
try {
|
try {
|
||||||
const res = await messageService.getVersion()
|
const res = await messageService.getVersion()
|
||||||
console.log(res)
|
console.log(res)
|
||||||
@@ -59,17 +59,26 @@ export const handlers = {
|
|||||||
const url = storage.presign('avatar.jpg')
|
const url = storage.presign('avatar.jpg')
|
||||||
|
|
||||||
return Response.json({ url })
|
return Response.json({ url })
|
||||||
}
|
},
|
||||||
|
async upgrade(req: Request, server: Bun.Server<WebSocketCtx>) {
|
||||||
|
const payload = await checkRequest(req)
|
||||||
|
|
||||||
|
const session = await auth.api.getSession({
|
||||||
|
headers: req.headers,
|
||||||
|
})
|
||||||
|
console.log(session)
|
||||||
|
if (!session) {
|
||||||
|
return Response.json({ message: 'unauthorised' }, { status: HttpStatusCodes.UNAUTHORIZED })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function upgrade(req: Request, server: Bun.Server<WebSocketCtx>) {
|
console.log(payload)
|
||||||
const payload = await checkRequest(req)
|
|
||||||
if (!payload) return new Response('Invalid token', { status: HttpStatusCodes.NOT_FOUND })
|
if (!payload) return new Response('Invalid token', { status: HttpStatusCodes.NOT_FOUND })
|
||||||
|
|
||||||
const success = server.upgrade(req, { data: { userId: +payload.sub, email: payload.email } })
|
const success = server.upgrade(req, { data: { userId: +payload.sub, email: payload.email } })
|
||||||
if (success) return undefined
|
if (success) return undefined
|
||||||
|
|
||||||
return new Response('Upgrade failed', { status: HttpStatusCodes.BAD_REQUEST })
|
return new Response('Upgrade failed', { status: HttpStatusCodes.BAD_REQUEST })
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkRequest(req: Request) {
|
async function checkRequest(req: Request) {
|
||||||
|
|||||||
62
src/index.ts
62
src/index.ts
@@ -1,26 +1,31 @@
|
|||||||
import { HttpStatusCodes } from './constants.ts'
|
import { HttpStatusCodes } from './constants.ts'
|
||||||
import type { WebSocketCtx, WebSocketData } from './types/types.ts'
|
import type { WebSocketCtx, WebSocketData } from './types.ts'
|
||||||
|
import { handlers } from './handles.ts'
|
||||||
import { handlers, upgrade } from './handles.ts'
|
|
||||||
import { messageService } from './grpc/message.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({
|
const server = Bun.serve({
|
||||||
port: PORT,
|
port: 3000,
|
||||||
|
routes: {
|
||||||
|
'/api/auth/*': auth.handler,
|
||||||
|
'/api/version': handlers.getVersion,
|
||||||
|
},
|
||||||
async fetch(req, server) {
|
async fetch(req, server) {
|
||||||
const url = new URL(req.url)
|
const url = new URL(req.url)
|
||||||
const pathname = url.pathname
|
if (url.pathname === '/ws') return handlers.upgrade(req, server)
|
||||||
const method = req.method
|
|
||||||
|
|
||||||
if (pathname === '/api/version' && method === 'GET') return handlers.getVersion(req)
|
return Response.json({ message: 'unknown url' }, { status: HttpStatusCodes.NOT_FOUND })
|
||||||
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 })
|
|
||||||
},
|
},
|
||||||
websocket: {
|
websocket: {
|
||||||
data: {} as WebSocketCtx,
|
data: {} as WebSocketCtx,
|
||||||
@@ -30,13 +35,14 @@ const server = Bun.serve({
|
|||||||
console.log('ipAddr', ipAddr)
|
console.log('ipAddr', ipAddr)
|
||||||
|
|
||||||
const user = ws.data
|
const user = ws.data
|
||||||
|
console.log(user)
|
||||||
|
|
||||||
const userResponse = await messageService.getUser({ id: user.userId })
|
// const userResponse = await messageService.getUser({ id: user.userId })
|
||||||
ws.send(JSON.stringify({ type: 'USER', ...userResponse }))
|
// ws.send(JSON.stringify({ type: 'USER', ...userResponse }))
|
||||||
|
//
|
||||||
const chatResponse = await messageService.listChat({ page: 0, userId: user.userId })
|
// const chatResponse = await messageService.listChat({ page: 0, userId: user.userId })
|
||||||
chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
// chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
||||||
ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
// ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
ws.close(1011, 'error')
|
ws.close(1011, 'error')
|
||||||
@@ -52,6 +58,11 @@ const server = Bun.serve({
|
|||||||
async message(ws, message) {
|
async message(ws, message) {
|
||||||
console.log('Websocket message', message)
|
console.log('Websocket message', message)
|
||||||
|
|
||||||
|
// const str = 'Hello World'
|
||||||
|
// const encoder = new TextEncoder()
|
||||||
|
// const arrayBuffer = encoder.encode(str).buffer
|
||||||
|
// console.log({ arrayBuffer })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof message === 'string') {
|
if (typeof message === 'string') {
|
||||||
const webSocketData = JSON.parse(message) as WebSocketData
|
const webSocketData = JSON.parse(message) as WebSocketData
|
||||||
@@ -65,15 +76,12 @@ const server = Bun.serve({
|
|||||||
|
|
||||||
if (webSocketData.type === 'CREATE_CHAT') {
|
if (webSocketData.type === 'CREATE_CHAT') {
|
||||||
const chat = await messageService.createChat({
|
const chat = await messageService.createChat({
|
||||||
users: [
|
users: [{ userId: webSocketData.data.userId }, { userId: ws.data.userId }],
|
||||||
{ userId: webSocketData.data.userId },
|
})
|
||||||
{ userId: ws.data.userId }
|
|
||||||
] })
|
|
||||||
if (chat?.data) {
|
if (chat?.data) {
|
||||||
ws.subscribe(chat.data.id)
|
ws.subscribe(chat.data.id)
|
||||||
ws.send(JSON.stringify({ type: 'CHATS', ...chat }))
|
ws.send(JSON.stringify({ type: 'CHATS', ...chat }))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webSocketData.type === 'CREATE_MESSAGE') {
|
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}`)
|
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