init with db
This commit is contained in:
parent
fe9949c70d
commit
7aee25cb33
26 changed files with 799 additions and 244 deletions
1
.env.example
Normal file
1
.env.example
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
DATABASE_URL=
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -25,6 +25,7 @@ yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
|
|
|
||||||
51
auth-schema.ts
Normal file
51
auth-schema.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
export const user = pgTable("user", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
email: text("email").notNull().unique(),
|
||||||
|
emailVerified: boolean("email_verified").notNull(),
|
||||||
|
image: text("image"),
|
||||||
|
createdAt: timestamp("created_at").notNull(),
|
||||||
|
updatedAt: timestamp("updated_at").notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const session = pgTable("session", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
expiresAt: timestamp("expires_at").notNull(),
|
||||||
|
token: text("token").notNull().unique(),
|
||||||
|
createdAt: timestamp("created_at").notNull(),
|
||||||
|
updatedAt: timestamp("updated_at").notNull(),
|
||||||
|
ipAddress: text("ip_address"),
|
||||||
|
userAgent: text("user_agent"),
|
||||||
|
userId: text("user_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const account = pgTable("account", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
accountId: text("account_id").notNull(),
|
||||||
|
providerId: text("provider_id").notNull(),
|
||||||
|
userId: text("user_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id),
|
||||||
|
accessToken: text("access_token"),
|
||||||
|
refreshToken: text("refresh_token"),
|
||||||
|
idToken: text("id_token"),
|
||||||
|
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
||||||
|
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
||||||
|
scope: text("scope"),
|
||||||
|
password: text("password"),
|
||||||
|
createdAt: timestamp("created_at").notNull(),
|
||||||
|
updatedAt: timestamp("updated_at").notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const verification = pgTable("verification", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
identifier: text("identifier").notNull(),
|
||||||
|
value: text("value").notNull(),
|
||||||
|
expiresAt: timestamp("expires_at").notNull(),
|
||||||
|
createdAt: timestamp("created_at"),
|
||||||
|
updatedAt: timestamp("updated_at"),
|
||||||
|
});
|
||||||
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
|
@ -43,6 +43,22 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- api-network
|
- api-network
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:latest
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: myusername
|
||||||
|
POSTGRES_PASSWORD: mypassword
|
||||||
|
POSTGRES_DB: mydatabase
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- api-network
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
api-network:
|
api-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
|
|
||||||
11
drizzle.config.ts
Normal file
11
drizzle.config.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import "dotenv/config";
|
||||||
|
import { defineConfig } from "drizzle-kit";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
out: "./drizzle",
|
||||||
|
schema: "./src/db/schema.ts",
|
||||||
|
dialect: "postgresql",
|
||||||
|
dbCredentials: {
|
||||||
|
url: process.env.DATABASE_URL!,
|
||||||
|
},
|
||||||
|
});
|
||||||
50
drizzle/0000_elite_ben_parker.sql
Normal file
50
drizzle/0000_elite_ben_parker.sql
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
CREATE TABLE "account" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"account_id" text NOT NULL,
|
||||||
|
"provider_id" text NOT NULL,
|
||||||
|
"user_id" text NOT NULL,
|
||||||
|
"access_token" text,
|
||||||
|
"refresh_token" text,
|
||||||
|
"id_token" text,
|
||||||
|
"access_token_expires_at" timestamp,
|
||||||
|
"refresh_token_expires_at" timestamp,
|
||||||
|
"scope" text,
|
||||||
|
"password" text,
|
||||||
|
"created_at" timestamp NOT NULL,
|
||||||
|
"updated_at" timestamp NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "session" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"expires_at" timestamp NOT NULL,
|
||||||
|
"token" text NOT NULL,
|
||||||
|
"created_at" timestamp NOT NULL,
|
||||||
|
"updated_at" timestamp NOT NULL,
|
||||||
|
"ip_address" text,
|
||||||
|
"user_agent" text,
|
||||||
|
"user_id" text NOT NULL,
|
||||||
|
CONSTRAINT "session_token_unique" UNIQUE("token")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "user" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"email" text NOT NULL,
|
||||||
|
"email_verified" boolean NOT NULL,
|
||||||
|
"image" text,
|
||||||
|
"created_at" timestamp NOT NULL,
|
||||||
|
"updated_at" timestamp NOT NULL,
|
||||||
|
CONSTRAINT "user_email_unique" UNIQUE("email")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "verification" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"identifier" text NOT NULL,
|
||||||
|
"value" text NOT NULL,
|
||||||
|
"expires_at" timestamp NOT NULL,
|
||||||
|
"created_at" timestamp,
|
||||||
|
"updated_at" timestamp
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;
|
||||||
319
drizzle/meta/0000_snapshot.json
Normal file
319
drizzle/meta/0000_snapshot.json
Normal file
|
|
@ -0,0 +1,319 @@
|
||||||
|
{
|
||||||
|
"id": "f4717319-16e8-43a1-8b25-12a12964c98f",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.account": {
|
||||||
|
"name": "account",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
"name": "account_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"provider_id": {
|
||||||
|
"name": "provider_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"access_token": {
|
||||||
|
"name": "access_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"refresh_token": {
|
||||||
|
"name": "refresh_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"id_token": {
|
||||||
|
"name": "id_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"access_token_expires_at": {
|
||||||
|
"name": "access_token_expires_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"refresh_token_expires_at": {
|
||||||
|
"name": "refresh_token_expires_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"name": "scope",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"name": "password",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"account_user_id_user_id_fk": {
|
||||||
|
"name": "account_user_id_user_id_fk",
|
||||||
|
"tableFrom": "account",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.session": {
|
||||||
|
"name": "session",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"name": "token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"ip_address": {
|
||||||
|
"name": "ip_address",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_agent": {
|
||||||
|
"name": "user_agent",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"session_user_id_user_id_fk": {
|
||||||
|
"name": "session_user_id_user_id_fk",
|
||||||
|
"tableFrom": "session",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"session_token_unique": {
|
||||||
|
"name": "session_token_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"token"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email_verified": {
|
||||||
|
"name": "email_verified",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"name": "image",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_email_unique": {
|
||||||
|
"name": "user_email_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"email"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.verification": {
|
||||||
|
"name": "verification",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"identifier": {
|
||||||
|
"name": "identifier",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
drizzle/meta/_journal.json
Normal file
13
drizzle/meta/_journal.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1736255248333,
|
||||||
|
"tag": "0000_elite_ben_parker",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
25
package.json
25
package.json
|
|
@ -4,16 +4,37 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"dev": "bun run --watch src/index.ts",
|
"dev": "bun run --watch src/index.ts",
|
||||||
|
"email": "email dev --dir src/emails",
|
||||||
"build": "bun build --compile --minify-whitespace --minify-syntax --target bun --outfile server ./src/index.ts"
|
"build": "bun build --compile --minify-whitespace --minify-syntax --target bun --outfile server ./src/index.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elysiajs/opentelemetry": "^1.2.0",
|
"@elysiajs/opentelemetry": "^1.2.0",
|
||||||
"@elysiajs/server-timing": "^1.2.0",
|
"@elysiajs/server-timing": "^1.2.0",
|
||||||
"@elysiajs/swagger": "^1.2.0",
|
"@elysiajs/swagger": "^1.2.0",
|
||||||
"elysia": "latest"
|
"@paralleldrive/cuid2": "^2.2.2",
|
||||||
|
"@react-email/components": "^0.0.31",
|
||||||
|
"better-auth": "^1.1.10",
|
||||||
|
"dotenv": "^16.4.7",
|
||||||
|
"drizzle-orm": "^0.38.3",
|
||||||
|
"drizzle-typebox": "^0.2.1",
|
||||||
|
"elysia": "latest",
|
||||||
|
"nodemailer": "^6.9.16",
|
||||||
|
"pg": "^8.13.1",
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"react-dom": "^19.0.0"
|
||||||
|
},
|
||||||
|
"override": {
|
||||||
|
"@sinclair/typebox": "0.34.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bun-types": "latest"
|
"@types/nodemailer": "^6.4.17",
|
||||||
|
"@types/pg": "^8.11.10",
|
||||||
|
"@types/react": "^19.0.3",
|
||||||
|
"@types/react-dom": "^19.0.2",
|
||||||
|
"bun-types": "latest",
|
||||||
|
"drizzle-kit": "^0.30.1",
|
||||||
|
"react-email": "^3.0.4",
|
||||||
|
"tsx": "^4.19.2"
|
||||||
},
|
},
|
||||||
"module": "src/index.js"
|
"module": "src/index.js"
|
||||||
}
|
}
|
||||||
25
src/api/note/note.controller.ts
Normal file
25
src/api/note/note.controller.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Memo } from "./note.model";
|
||||||
|
|
||||||
|
export class Note {
|
||||||
|
constructor(
|
||||||
|
public data: Memo[] = [
|
||||||
|
{
|
||||||
|
data: "Moonhalo",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
) {}
|
||||||
|
|
||||||
|
add(note: Memo) {
|
||||||
|
this.data.push(note);
|
||||||
|
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(index: number) {
|
||||||
|
return this.data.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(index: number, note: Partial<Memo>) {
|
||||||
|
return (this.data[index] = { ...this.data[index], ...note });
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/api/note/note.model.ts
Normal file
7
src/api/note/note.model.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { t } from "elysia";
|
||||||
|
|
||||||
|
export const memoSchema = t.Object({
|
||||||
|
data: t.String(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Memo = typeof memoSchema.static;
|
||||||
44
src/api/note/note.route.ts
Normal file
44
src/api/note/note.route.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { Elysia, t } from "elysia";
|
||||||
|
import { Note } from "./note.controller";
|
||||||
|
import { memoSchema } from "./note.model";
|
||||||
|
|
||||||
|
export const note = new Elysia({ prefix: "/note" })
|
||||||
|
.decorate("note", new Note())
|
||||||
|
.model({
|
||||||
|
memo: t.Omit(memoSchema, ["author"]),
|
||||||
|
})
|
||||||
|
.get("/", ({ note }) => note.data)
|
||||||
|
.put("/", ({ note, body: { data } }) => note.add({ data }), {
|
||||||
|
body: "memo",
|
||||||
|
})
|
||||||
|
.get(
|
||||||
|
"/:index",
|
||||||
|
({ note, params: { index }, error }) => {
|
||||||
|
return note.data[index] ?? error(404, "Not Found :(");
|
||||||
|
},
|
||||||
|
{
|
||||||
|
params: t.Object({
|
||||||
|
index: t.Number(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.guard({
|
||||||
|
params: t.Object({
|
||||||
|
index: t.Number(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.delete("/:index", ({ note, params: { index }, error }) => {
|
||||||
|
if (index in note.data) return note.remove(index);
|
||||||
|
|
||||||
|
return error(422);
|
||||||
|
})
|
||||||
|
.patch(
|
||||||
|
"/:index",
|
||||||
|
({ note, params: { index }, body: { data }, error }) => {
|
||||||
|
if (index in note.data) return note.update(index, { data });
|
||||||
|
return error(422);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: "memo",
|
||||||
|
}
|
||||||
|
);
|
||||||
36
src/api/otp/otp.route.ts
Normal file
36
src/api/otp/otp.route.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { Elysia, t } from "elysia";
|
||||||
|
import { renderToStaticMarkup } from "react-dom/server";
|
||||||
|
import nodemailer from "nodemailer";
|
||||||
|
import OTPEmail from "../../emails/otp";
|
||||||
|
import { createElement } from "react";
|
||||||
|
|
||||||
|
const transporter = nodemailer.createTransport({
|
||||||
|
host: "smtp.gehenna.sh",
|
||||||
|
port: 465,
|
||||||
|
auth: {
|
||||||
|
user: "makoto",
|
||||||
|
pass: "12345678",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const otp = new Elysia({ prefix: "/otp" }).get(
|
||||||
|
"/",
|
||||||
|
async ({ body }) => {
|
||||||
|
// Random between 100,000 and 999,999
|
||||||
|
const otp = ~~(Math.random() * (900_000 - 1)) + 100_000;
|
||||||
|
|
||||||
|
const html = renderToStaticMarkup(createElement(OTPEmail, { otp }));
|
||||||
|
|
||||||
|
await transporter.sendMail({
|
||||||
|
from: "ibuki@gehenna.sh",
|
||||||
|
to: body,
|
||||||
|
subject: "Verify your email address",
|
||||||
|
html,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: t.String({ format: "email" }),
|
||||||
|
}
|
||||||
|
);
|
||||||
23
src/api/user/user.model.ts
Normal file
23
src/api/user/user.model.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { pgTable, varchar, timestamp } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
import { createId } from "@paralleldrive/cuid2";
|
||||||
|
import { createInsertSchema } from "drizzle-typebox";
|
||||||
|
import { t } from "elysia";
|
||||||
|
|
||||||
|
export const user = pgTable("user", {
|
||||||
|
id: varchar("id")
|
||||||
|
.$defaultFn(() => createId())
|
||||||
|
.primaryKey(),
|
||||||
|
username: varchar("username").notNull().unique(),
|
||||||
|
password: varchar("password").notNull(),
|
||||||
|
email: varchar("email").notNull().unique(),
|
||||||
|
salt: varchar("salt", { length: 64 }).notNull(),
|
||||||
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const _createUser = createInsertSchema(user, {
|
||||||
|
email: t.String({ format: "email" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
// ✅ This works, by referencing the type from `drizzle-typebox`
|
||||||
|
export const createUserType = t.Omit(_createUser, ["id", "salt", "createdAt"]);
|
||||||
4
src/db/index.ts
Normal file
4
src/db/index.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
import "dotenv/config";
|
||||||
|
import { drizzle } from "drizzle-orm/node-postgres";
|
||||||
|
|
||||||
|
const db = drizzle(process.env.DATABASE_URL!);
|
||||||
7
src/db/model.ts
Normal file
7
src/db/model.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { createUserType } from "../api/user/user.model";
|
||||||
|
|
||||||
|
export const db = {
|
||||||
|
insert: {
|
||||||
|
user: createUserType,
|
||||||
|
},
|
||||||
|
};
|
||||||
51
src/db/schema.ts
Normal file
51
src/db/schema.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
export const user = pgTable("user", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
email: text("email").notNull().unique(),
|
||||||
|
emailVerified: boolean("email_verified").notNull(),
|
||||||
|
image: text("image"),
|
||||||
|
createdAt: timestamp("created_at").notNull(),
|
||||||
|
updatedAt: timestamp("updated_at").notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const session = pgTable("session", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
expiresAt: timestamp("expires_at").notNull(),
|
||||||
|
token: text("token").notNull().unique(),
|
||||||
|
createdAt: timestamp("created_at").notNull(),
|
||||||
|
updatedAt: timestamp("updated_at").notNull(),
|
||||||
|
ipAddress: text("ip_address"),
|
||||||
|
userAgent: text("user_agent"),
|
||||||
|
userId: text("user_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const account = pgTable("account", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
accountId: text("account_id").notNull(),
|
||||||
|
providerId: text("provider_id").notNull(),
|
||||||
|
userId: text("user_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id),
|
||||||
|
accessToken: text("access_token"),
|
||||||
|
refreshToken: text("refresh_token"),
|
||||||
|
idToken: text("id_token"),
|
||||||
|
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
||||||
|
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
||||||
|
scope: text("scope"),
|
||||||
|
password: text("password"),
|
||||||
|
createdAt: timestamp("created_at").notNull(),
|
||||||
|
updatedAt: timestamp("updated_at").notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const verification = pgTable("verification", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
identifier: text("identifier").notNull(),
|
||||||
|
value: text("value").notNull(),
|
||||||
|
expiresAt: timestamp("expires_at").notNull(),
|
||||||
|
createdAt: timestamp("created_at"),
|
||||||
|
updatedAt: timestamp("updated_at"),
|
||||||
|
});
|
||||||
30
src/emails/otp.tsx
Normal file
30
src/emails/otp.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
import { Tailwind, Section, Text } from '@react-email/components'
|
||||||
|
|
||||||
|
export default function OTPEmail({ otp }: { otp: number }) {
|
||||||
|
return (
|
||||||
|
<Tailwind>
|
||||||
|
<Section className="flex justify-center items-center w-full min-h-screen font-sans">
|
||||||
|
<Section className="flex flex-col items-center w-76 rounded-2xl px-6 py-1 bg-gray-50">
|
||||||
|
<Text className="text-xs font-medium text-violet-500">
|
||||||
|
Verify your Email Address
|
||||||
|
</Text>
|
||||||
|
<Text className="text-gray-500 my-0">
|
||||||
|
Use the following code to verify your email address
|
||||||
|
</Text>
|
||||||
|
<Text className="text-5xl font-bold pt-2">{otp}</Text>
|
||||||
|
<Text className="text-gray-400 font-light text-xs pb-4">
|
||||||
|
This code is valid for 10 minutes
|
||||||
|
</Text>
|
||||||
|
<Text className="text-gray-600 text-xs">
|
||||||
|
Thank you joining us
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
</Section>
|
||||||
|
</Tailwind>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
OTPEmail.PreviewProps = {
|
||||||
|
otp: 123456
|
||||||
|
}
|
||||||
12
src/index.ts
12
src/index.ts
|
|
@ -3,8 +3,9 @@ import { swagger } from "@elysiajs/swagger";
|
||||||
import { opentelemetry } from "@elysiajs/opentelemetry";
|
import { opentelemetry } from "@elysiajs/opentelemetry";
|
||||||
import { serverTiming } from "@elysiajs/server-timing";
|
import { serverTiming } from "@elysiajs/server-timing";
|
||||||
|
|
||||||
import { note } from "./routes/note";
|
import { note } from "./api/note/note.route";
|
||||||
import { user } from "./routes/user";
|
import { betterAuthView } from "./lib/auth/auth-view";
|
||||||
|
import { userMiddleware, userInfo } from "./middlewares/auth-middleware";
|
||||||
|
|
||||||
const app = new Elysia()
|
const app = new Elysia()
|
||||||
.use(opentelemetry())
|
.use(opentelemetry())
|
||||||
|
|
@ -14,6 +15,9 @@ const app = new Elysia()
|
||||||
if (code === "NOT_FOUND") return "Not Found :(";
|
if (code === "NOT_FOUND") return "Not Found :(";
|
||||||
console.error(error);
|
console.error(error);
|
||||||
})
|
})
|
||||||
.use(user)
|
|
||||||
.use(note)
|
.use(note)
|
||||||
.listen(3000);
|
.derive(({ request }) => userMiddleware(request))
|
||||||
|
.all("/api/auth/*", betterAuthView)
|
||||||
|
.get("/user", ({ user, session }) => userInfo(user, session));
|
||||||
|
|
||||||
|
app.listen(3000);
|
||||||
|
|
|
||||||
12
src/lib/auth/auth-view.ts
Normal file
12
src/lib/auth/auth-view.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Context, Elysia } from "elysia";
|
||||||
|
import { auth } from "./auth";
|
||||||
|
|
||||||
|
export const betterAuthView = (context: Context) => {
|
||||||
|
const BETTER_AUTH_ACCEPT_METHODS = ["POST", "GET"];
|
||||||
|
// validate request method
|
||||||
|
if (BETTER_AUTH_ACCEPT_METHODS.includes(context.request.method)) {
|
||||||
|
return auth.handler(context.request);
|
||||||
|
} else {
|
||||||
|
context.error(405);
|
||||||
|
}
|
||||||
|
};
|
||||||
26
src/lib/auth/auth.ts
Normal file
26
src/lib/auth/auth.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { betterAuth } from "better-auth";
|
||||||
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||||
|
import { db } from "../../db/model";
|
||||||
|
export const auth = betterAuth({
|
||||||
|
database: drizzleAdapter(db, {
|
||||||
|
// We're using Drizzle as our database
|
||||||
|
provider: "pg",
|
||||||
|
}),
|
||||||
|
emailAndPassword: {
|
||||||
|
enabled: true, // If you want to use email and password auth
|
||||||
|
},
|
||||||
|
socialProviders: {
|
||||||
|
/*
|
||||||
|
* We're using Google and Github as our social provider,
|
||||||
|
* make sure you have set your environment variables
|
||||||
|
*/
|
||||||
|
// github: {
|
||||||
|
// clientId: process.env.GITHUB_CLIENT_ID!,
|
||||||
|
// clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
||||||
|
// },
|
||||||
|
// google: {
|
||||||
|
// clientId: process.env.GOOGLE_CLIENT_ID!,
|
||||||
|
// clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
});
|
||||||
29
src/middlewares/auth-middleware.ts
Normal file
29
src/middlewares/auth-middleware.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Session, User } from "better-auth/types";
|
||||||
|
import { auth } from "../lib/auth/auth";
|
||||||
|
|
||||||
|
// user middleware (compute user and session and pass to routes)
|
||||||
|
export const userMiddleware = async (request: Request) => {
|
||||||
|
const session = await auth.api.getSession({ headers: request.headers });
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return {
|
||||||
|
user: null,
|
||||||
|
session: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
user: session.user,
|
||||||
|
session: session.session,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// user info view
|
||||||
|
// type User can be export from `typeof auth.$Infer.Session.user`
|
||||||
|
// type Session can be export from `typeof auth.$Infer.Session.session`
|
||||||
|
export const userInfo = (user: User | null, session: Session | null) => {
|
||||||
|
return {
|
||||||
|
user: user,
|
||||||
|
session: session,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
import { Elysia, t } from "elysia";
|
|
||||||
import { getUserId, userService } from "./user";
|
|
||||||
|
|
||||||
const memo = t.Object({
|
|
||||||
data: t.String(),
|
|
||||||
author: t.String(),
|
|
||||||
});
|
|
||||||
|
|
||||||
type Memo = typeof memo.static;
|
|
||||||
|
|
||||||
class Note {
|
|
||||||
constructor(
|
|
||||||
public data: Memo[] = [
|
|
||||||
{
|
|
||||||
data: "Moonhalo",
|
|
||||||
author: "saltyaom",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
) {}
|
|
||||||
|
|
||||||
add(note: Memo) {
|
|
||||||
this.data.push(note);
|
|
||||||
|
|
||||||
return this.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(index: number) {
|
|
||||||
return this.data.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(index: number, note: Partial<Memo>) {
|
|
||||||
return (this.data[index] = { ...this.data[index], ...note });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const note = new Elysia({ prefix: "/note" })
|
|
||||||
.use(userService)
|
|
||||||
.decorate("note", new Note())
|
|
||||||
.model({
|
|
||||||
memo: t.Omit(memo, ["author"]),
|
|
||||||
})
|
|
||||||
.onTransform(function log({ body, params, path, request: { method } }) {
|
|
||||||
console.log(`${method} ${path}`, {
|
|
||||||
body,
|
|
||||||
params,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.get("/", ({ note }) => note.data)
|
|
||||||
.use(getUserId)
|
|
||||||
.put(
|
|
||||||
"/",
|
|
||||||
({ note, body: { data }, username }) =>
|
|
||||||
note.add({ data, author: username }),
|
|
||||||
{
|
|
||||||
body: "memo",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.get(
|
|
||||||
"/:index",
|
|
||||||
({ note, params: { index }, error }) => {
|
|
||||||
return note.data[index] ?? error(404, "Not Found :(");
|
|
||||||
},
|
|
||||||
{
|
|
||||||
params: t.Object({
|
|
||||||
index: t.Number(),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.guard({
|
|
||||||
params: t.Object({
|
|
||||||
index: t.Number(),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.delete("/:index", ({ note, params: { index }, error }) => {
|
|
||||||
if (index in note.data) return note.remove(index);
|
|
||||||
|
|
||||||
return error(422);
|
|
||||||
})
|
|
||||||
.patch(
|
|
||||||
"/:index",
|
|
||||||
({ note, params: { index }, body: { data }, error, username }) => {
|
|
||||||
if (index in note.data)
|
|
||||||
return note.update(index, { data, author: username });
|
|
||||||
|
|
||||||
return error(422);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
isSignIn: true,
|
|
||||||
body: "memo",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
import { Elysia, t } from "elysia";
|
|
||||||
|
|
||||||
export const userService = new Elysia({ name: "user/service" })
|
|
||||||
.state({
|
|
||||||
user: {} as Record<string, string>,
|
|
||||||
session: {} as Record<number, string>,
|
|
||||||
})
|
|
||||||
.model({
|
|
||||||
signIn: t.Object({
|
|
||||||
username: t.String({ minLength: 1 }),
|
|
||||||
password: t.String({ minLength: 8 }),
|
|
||||||
}),
|
|
||||||
session: t.Cookie(
|
|
||||||
{
|
|
||||||
token: t.Number(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
secrets: "seia",
|
|
||||||
}
|
|
||||||
),
|
|
||||||
optionalSession: t.Optional(t.Ref("session")),
|
|
||||||
})
|
|
||||||
.macro({
|
|
||||||
isSignIn(enabled: boolean) {
|
|
||||||
if (!enabled) return;
|
|
||||||
|
|
||||||
return {
|
|
||||||
beforeHandle({ error, cookie: { token }, store: { session } }) {
|
|
||||||
if (!token.value)
|
|
||||||
return error(401, {
|
|
||||||
success: false,
|
|
||||||
message: "Unauthorized",
|
|
||||||
});
|
|
||||||
|
|
||||||
const username = session[token.value as unknown as number];
|
|
||||||
|
|
||||||
if (!username)
|
|
||||||
return error(401, {
|
|
||||||
success: false,
|
|
||||||
message: "Unauthorized",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getUserId = new Elysia()
|
|
||||||
.use(userService)
|
|
||||||
.guard({
|
|
||||||
isSignIn: true,
|
|
||||||
cookie: "session",
|
|
||||||
})
|
|
||||||
.resolve(({ store: { session }, cookie: { token } }) => ({
|
|
||||||
username: session[token.value],
|
|
||||||
}))
|
|
||||||
.as("plugin");
|
|
||||||
|
|
||||||
export const user = new Elysia({ prefix: "/user" })
|
|
||||||
.use(userService)
|
|
||||||
.put(
|
|
||||||
"/sign-up",
|
|
||||||
async ({ body: { username, password }, store, error }) => {
|
|
||||||
if (store.user[username])
|
|
||||||
return error(400, {
|
|
||||||
success: false,
|
|
||||||
message: "User already exists",
|
|
||||||
});
|
|
||||||
|
|
||||||
store.user[username] = await Bun.password.hash(password);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: "User created",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
body: "signIn",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.post(
|
|
||||||
"/sign-in",
|
|
||||||
async ({
|
|
||||||
store: { user, session },
|
|
||||||
error,
|
|
||||||
body: { username, password },
|
|
||||||
cookie: { token },
|
|
||||||
}) => {
|
|
||||||
if (
|
|
||||||
!user[username] ||
|
|
||||||
!(await Bun.password.verify(password, user[username]))
|
|
||||||
)
|
|
||||||
return error(400, {
|
|
||||||
success: false,
|
|
||||||
message: "Invalid username or password",
|
|
||||||
});
|
|
||||||
|
|
||||||
const key = crypto.getRandomValues(new Uint32Array(1))[0];
|
|
||||||
session[key] = username;
|
|
||||||
token.value = key;
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: `Signed in as ${username}`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
body: "signIn",
|
|
||||||
cookie: "optionalSession",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.get(
|
|
||||||
"/sign-out",
|
|
||||||
({ cookie: { token } }) => {
|
|
||||||
token.remove();
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: "Signed out",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cookie: "optionalSession",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.use(getUserId)
|
|
||||||
.get("/profile", ({ username }) => ({
|
|
||||||
success: true,
|
|
||||||
username,
|
|
||||||
}));
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||||
|
|
||||||
/* Projects */
|
/* Projects */
|
||||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||||
|
|
@ -9,11 +8,10 @@
|
||||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
/* Language and Environment */
|
/* Language and Environment */
|
||||||
"target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
"target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
"jsx": "react", /* Specify what JSX code is generated. */
|
||||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||||
|
|
@ -23,7 +21,6 @@
|
||||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
|
||||||
/* Modules */
|
/* Modules */
|
||||||
"module": "ES2022", /* Specify what module code is generated. */
|
"module": "ES2022", /* Specify what module code is generated. */
|
||||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||||
|
|
@ -32,17 +29,17 @@
|
||||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||||
"types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */
|
"types": [
|
||||||
|
"bun-types"
|
||||||
|
], /* Specify type package names to be included without being referenced in a source file. */
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||||
|
|
||||||
/* JavaScript Support */
|
/* JavaScript Support */
|
||||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||||
|
|
||||||
/* Emit */
|
/* Emit */
|
||||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||||
|
|
@ -67,14 +64,12 @@
|
||||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||||
|
|
||||||
/* Interop Constraints */
|
/* Interop Constraints */
|
||||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||||
|
|
||||||
/* Type Checking */
|
/* Type Checking */
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||||
|
|
@ -95,7 +90,6 @@
|
||||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||||
|
|
||||||
/* Completeness */
|
/* Completeness */
|
||||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue