├── .gitignore ├── CMD.md ├── README.md ├── api-json.json ├── drizzle.config.json ├── img ├── data-flow.png ├── diagram.png └── neon.svg ├── migrations ├── 0000_remarkable_katie_power.sql ├── 0001_mute_true_believers.sql ├── 0002_common_tyger_tiger.sql ├── 0003_secret_forge.sql └── meta │ ├── 0000_snapshot.json │ ├── 0001_snapshot.json │ ├── 0002_snapshot.json │ ├── 0003_snapshot.json │ └── _journal.json ├── package.json ├── pnpm-lock.yaml ├── src ├── config │ ├── env.ts │ └── permissions.ts ├── db │ ├── index.ts │ └── schema.ts ├── main.ts ├── modules │ ├── applications │ │ ├── applications.controllers.ts │ │ ├── applications.routes.ts │ │ ├── applications.schemas.ts │ │ └── applications.services.ts │ ├── roles │ │ ├── role.controllers.ts │ │ ├── role.routes.ts │ │ ├── role.schemas.ts │ │ └── roles.services.ts │ └── users │ │ ├── users.controllers.ts │ │ ├── users.routes.ts │ │ ├── users.schemas.ts │ │ └── users.services.ts └── utils │ ├── logger.ts │ └── server.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env -------------------------------------------------------------------------------- /CMD.md: -------------------------------------------------------------------------------- 1 | ## Install dependencies 2 | 3 | ```bash 4 | pnpm add argon2 drizzle-orm pg pino pino-pretty zennv zod jsonwebtoken fastify-zod fastify-guard fastify 5 | ``` 6 | 7 | ## Install dev dependencies 8 | ```bash 9 | pnpm add zod-to-json-schema @types/jsonwebtoken typescript tsx drizzle-kit @types/pg -D 10 | ``` 11 | ## Initialize TypeScript 12 | ```bash 13 | npx tsc --init 14 | ``` 15 | 16 | ## Run migrations 17 | ```bash 18 | pnpm run migrate 19 | ``` 20 | 21 | ## Run the application 22 | ```bash 23 | pnpm run dev 24 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multi Tenant Role Based Access Control (RBAC) Authentication API 2 | 3 | ## Sponsor 4 | 5 | 6 | Thank you to [Neon](https://bit.ly/tomdoestech) for sponsoring this video! 7 | 8 | ## Features 9 | * Create an application 10 | * Register a user for an application 11 | * Login 12 | * Create a role 13 | * Assign a role to a user 14 | 15 | * Check user permissions with a guard 16 | 17 | ## What are we using? 18 | * [Drizzle ORM](https://github.com/drizzle-team/drizzle-orm) 19 | * [Fastify](https://www.fastify.io/) 20 | * [PostgreSQL](https://www.postgresql.org/) 21 | * [TypeScript](https://www.typescriptlang.org/) 22 | 23 | ## What you'll need 24 | * Editor - [VS Code](https://code.visualstudio.com/download) 25 | * Node.js - [Download](https://nodejs.org/en/download/) 26 | * A database - [PostgreSQL by Neon](https://bit.ly/tomdoestech) 27 | * A REST client - [Thunder Client](https://marketplace.visualstudio.com/items?itemName=rangav.vscode-thunder-client) 28 | 29 | ## What you will learn 30 | * How to create a multi tenant application 31 | * How to create a role based access control system 32 | * Some basic relational database concepts 33 | * A nice and neat file structure for backend services 34 | * TypeScript 35 | * Fastify 36 | * RESTful API design 37 | * How to use Drizzle ORM 38 | 39 | ## Data structure 40 | 41 | 42 | ## Data flow 43 | 44 | 45 | ## Video structure 46 | 1. Setup the initial application 47 | 2. Create a database with Neon 48 | 3. Create database schemas 49 | 4. Run migrations 50 | 5. Register an application 51 | 6. Register a user 52 | 7. Login 53 | 8. Create a role 54 | 9. Assign a role to a user 55 | 10. Check user permissions with a guard 56 | 57 | ## Helpful files 58 | * CMD - Commands used in the video 59 | * api.json - Thunder Client collection 60 | 61 | ## Tips 62 | * Infer the applicationId from the JWT where possible 63 | * Include the applicationId in queries 64 | -------------------------------------------------------------------------------- /api-json.json: -------------------------------------------------------------------------------- 1 | { 2 | "client": "Thunder Client", 3 | "collectionName": "User API", 4 | "dateExported": "2023-05-17T08:03:32.677Z", 5 | "version": "1.1", 6 | "folders": [], 7 | "requests": [ 8 | { 9 | "_id": "5f4eb36c-c5fe-4bd7-9e68-76c25486d4fb", 10 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 11 | "containerId": "", 12 | "name": "Create application", 13 | "url": "{{host}}/api/applications", 14 | "method": "POST", 15 | "sortNum": 5000, 16 | "created": "2023-04-29T21:56:06.725Z", 17 | "modified": "2023-05-03T10:47:42.539Z", 18 | "headers": [], 19 | "params": [], 20 | "body": { 21 | "type": "json", 22 | "raw": "{\n \"name\":\"App three\",\n \"description\":\"hello\"\n}", 23 | "form": [] 24 | }, 25 | "tests": [] 26 | }, 27 | { 28 | "_id": "a1834b3a-fea5-4117-961b-c4ae62c839b6", 29 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 30 | "containerId": "", 31 | "name": "Get applications", 32 | "url": "http://0.0.0.0:3000/api/applications", 33 | "method": "GET", 34 | "sortNum": 10000, 35 | "created": "2023-04-29T21:55:41.812Z", 36 | "modified": "2023-04-29T22:06:13.213Z", 37 | "headers": [], 38 | "params": [], 39 | "body": { 40 | "type": "formdata", 41 | "raw": "", 42 | "form": [], 43 | "files": [ 44 | { 45 | "name": "", 46 | "value": "/home/tom/projects/media-api/test/mailchimp-6kajEqr84iY-unsplash.jpg" 47 | } 48 | ] 49 | }, 50 | "tests": [] 51 | }, 52 | { 53 | "_id": "ad7da438-77ec-42c0-996b-c376e70fe555", 54 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 55 | "containerId": "", 56 | "name": "Get me", 57 | "url": "http://0.0.0.0:3000/api/users/me", 58 | "method": "GET", 59 | "sortNum": 15000, 60 | "created": "2023-05-05T08:43:58.471Z", 61 | "modified": "2023-05-05T08:44:48.938Z", 62 | "headers": [ 63 | { 64 | "name": "Authorization", 65 | "value": "{{authorization}}" 66 | } 67 | ], 68 | "params": [], 69 | "body": { 70 | "type": "formdata", 71 | "raw": "", 72 | "form": [], 73 | "files": [ 74 | { 75 | "name": "", 76 | "value": "/home/tom/projects/media-api/test/mailchimp-6kajEqr84iY-unsplash.jpg" 77 | } 78 | ] 79 | }, 80 | "tests": [] 81 | }, 82 | { 83 | "_id": "35e68843-0c17-45db-a2af-e109b688cfd5", 84 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 85 | "containerId": "", 86 | "name": "Create user 1", 87 | "url": "{{host}}/api/users", 88 | "method": "POST", 89 | "sortNum": 20000, 90 | "created": "2023-04-29T21:55:53.376Z", 91 | "modified": "2023-05-03T10:42:08.788Z", 92 | "headers": [], 93 | "params": [], 94 | "body": { 95 | "type": "json", 96 | "raw": "{\n \"email\": \"{{email}}\",\n \"name\": \"Jane Doe\",\n \"password\": \"{{password}}\",\n \"applicationId\": \"{{applicationId}}\",\n \"initialUser\": true\n}", 97 | "form": [] 98 | }, 99 | "tests": [] 100 | }, 101 | { 102 | "_id": "04983f5e-8ac4-4666-8a3e-937e45d3e644", 103 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 104 | "containerId": "", 105 | "name": "Create user 2", 106 | "url": "{{host}}/api/users", 107 | "method": "POST", 108 | "sortNum": 30000, 109 | "created": "2023-05-05T08:41:15.855Z", 110 | "modified": "2023-05-05T08:47:29.408Z", 111 | "headers": [], 112 | "params": [], 113 | "body": { 114 | "type": "json", 115 | "raw": "{\n \"email\": \"{{email2}}\",\n \"name\": \"Second User\",\n \"password\": \"{{password}}\",\n \"applicationId\": \"{{applicationId}}\"\n}", 116 | "form": [] 117 | }, 118 | "tests": [] 119 | }, 120 | { 121 | "_id": "724af579-846c-4ca1-b657-ee15b8983e31", 122 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 123 | "containerId": "", 124 | "name": "Login", 125 | "url": "{{host}}/api/users/login", 126 | "method": "POST", 127 | "sortNum": 35000, 128 | "created": "2023-05-02T07:59:27.052Z", 129 | "modified": "2023-05-14T08:27:40.373Z", 130 | "headers": [], 131 | "params": [], 132 | "body": { 133 | "type": "json", 134 | "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\",\n \"applicationId\": \"{{applicationId}}\"\n}", 135 | "form": [] 136 | }, 137 | "tests": [] 138 | }, 139 | { 140 | "_id": "5681c22b-e87b-4391-94c6-057567dbeef5", 141 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 142 | "containerId": "", 143 | "name": "Create role", 144 | "url": "{{host}}/api/roles", 145 | "method": "POST", 146 | "sortNum": 40000, 147 | "created": "2023-04-29T21:56:11.563Z", 148 | "modified": "2023-05-03T10:52:53.455Z", 149 | "headers": [ 150 | { 151 | "name": "Authorization", 152 | "value": "{{authorization}}" 153 | } 154 | ], 155 | "params": [], 156 | "body": { 157 | "type": "json", 158 | "raw": "{\n \"applicationId\": \"{{applicationId}}\",\n \"permissions\": [\n \"role:read\",\n \"role:write\"\n ],\n \"name\": \"Some role\"\n}", 159 | "form": [] 160 | }, 161 | "tests": [] 162 | }, 163 | { 164 | "_id": "f44270d5-013b-4a4c-8d0b-bba15e0414d9", 165 | "colId": "ef71f144-c718-4fd5-874e-e9c14db58c6c", 166 | "containerId": "", 167 | "name": "Assign role to user", 168 | "url": "http://0.0.0.0:3000/api/users/roles", 169 | "method": "POST", 170 | "sortNum": 55000, 171 | "created": "2023-05-03T08:55:00.372Z", 172 | "modified": "2023-05-14T08:27:37.591Z", 173 | "headers": [], 174 | "params": [], 175 | "body": { 176 | "type": "json", 177 | "raw": "{\n \"applicationId\": \"{{applicationId}}\",\n \"userId\": \"{{userId}}\",\n \"roleId\": \"5ebe38d0-ed08-4f90-924e-6684ca9eb0b3\"\n}", 178 | "form": [] 179 | }, 180 | "tests": [] 181 | } 182 | ] 183 | } 184 | -------------------------------------------------------------------------------- /drizzle.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "out": "./migrations", 3 | "schema": "./src/db/schema.ts", 4 | "breakpoints": false 5 | } -------------------------------------------------------------------------------- /img/data-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomDoesTech/user-api/46d37be1204e94fb74c9bd947f4477a6963a85d8/img/data-flow.png -------------------------------------------------------------------------------- /img/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomDoesTech/user-api/46d37be1204e94fb74c9bd947f4477a6963a85d8/img/diagram.png -------------------------------------------------------------------------------- /img/neon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /migrations/0000_remarkable_katie_power.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS "applications" ( 2 | "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, 3 | "name" varchar(256) NOT NULL, 4 | "created_at" timestamp DEFAULT now() NOT NULL, 5 | "updated_at" timestamp DEFAULT now() NOT NULL 6 | ); 7 | -------------------------------------------------------------------------------- /migrations/0001_mute_true_believers.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS "users" ( 2 | "id" uuid DEFAULT gen_random_uuid() NOT NULL, 3 | "email" varchar(256) NOT NULL, 4 | "name" varchar(256) NOT NULL, 5 | "applicationId" uuid, 6 | "password" varchar(256) NOT NULL, 7 | "created_at" timestamp DEFAULT now() NOT NULL, 8 | "updated_at" timestamp DEFAULT now() NOT NULL 9 | ); 10 | --> statement-breakpoint 11 | ALTER TABLE "users" ADD CONSTRAINT "users_email_applicationId" PRIMARY KEY("email","applicationId"); 12 | 13 | DO $$ BEGIN 14 | ALTER TABLE "users" ADD CONSTRAINT "users_applicationId_applications_id_fk" FOREIGN KEY ("applicationId") REFERENCES "applications"("id") ON DELETE no action ON UPDATE no action; 15 | EXCEPTION 16 | WHEN duplicate_object THEN null; 17 | END $$; 18 | 19 | CREATE UNIQUE INDEX IF NOT EXISTS "users_id_index" ON "users" ("id"); -------------------------------------------------------------------------------- /migrations/0002_common_tyger_tiger.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS "roles" ( 2 | "id" uuid DEFAULT gen_random_uuid() NOT NULL, 3 | "name" varchar(256) NOT NULL, 4 | "applicationId" uuid, 5 | "permissions" text[], 6 | "created_at" timestamp DEFAULT now() NOT NULL, 7 | "updated_at" timestamp DEFAULT now() NOT NULL 8 | ); 9 | --> statement-breakpoint 10 | ALTER TABLE "roles" ADD CONSTRAINT "roles_name_applicationId" PRIMARY KEY("name","applicationId"); 11 | 12 | DO $$ BEGIN 13 | ALTER TABLE "roles" ADD CONSTRAINT "roles_applicationId_applications_id_fk" FOREIGN KEY ("applicationId") REFERENCES "applications"("id") ON DELETE no action ON UPDATE no action; 14 | EXCEPTION 15 | WHEN duplicate_object THEN null; 16 | END $$; 17 | 18 | CREATE UNIQUE INDEX IF NOT EXISTS "roles_id_index" ON "roles" ("id"); -------------------------------------------------------------------------------- /migrations/0003_secret_forge.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS "usersToRoles" ( 2 | "applicationId" uuid NOT NULL, 3 | "roledId" uuid NOT NULL, 4 | "userId" uuid NOT NULL 5 | ); 6 | --> statement-breakpoint 7 | ALTER TABLE "usersToRoles" ADD CONSTRAINT "usersToRoles_applicationId_roledId_userId" PRIMARY KEY("applicationId","roledId","userId"); 8 | 9 | DO $$ BEGIN 10 | ALTER TABLE "usersToRoles" ADD CONSTRAINT "usersToRoles_applicationId_applications_id_fk" FOREIGN KEY ("applicationId") REFERENCES "applications"("id") ON DELETE no action ON UPDATE no action; 11 | EXCEPTION 12 | WHEN duplicate_object THEN null; 13 | END $$; 14 | 15 | DO $$ BEGIN 16 | ALTER TABLE "usersToRoles" ADD CONSTRAINT "usersToRoles_roledId_roles_id_fk" FOREIGN KEY ("roledId") REFERENCES "roles"("id") ON DELETE no action ON UPDATE no action; 17 | EXCEPTION 18 | WHEN duplicate_object THEN null; 19 | END $$; 20 | 21 | DO $$ BEGIN 22 | ALTER TABLE "usersToRoles" ADD CONSTRAINT "usersToRoles_userId_users_id_fk" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action; 23 | EXCEPTION 24 | WHEN duplicate_object THEN null; 25 | END $$; 26 | -------------------------------------------------------------------------------- /migrations/meta/0000_snapshot.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "dialect": "pg", 4 | "id": "c4595e94-56a5-4f18-ad77-4c7f5b2e29b4", 5 | "prevId": "00000000-0000-0000-0000-000000000000", 6 | "tables": { 7 | "applications": { 8 | "name": "applications", 9 | "schema": "", 10 | "columns": { 11 | "id": { 12 | "name": "id", 13 | "type": "uuid", 14 | "primaryKey": true, 15 | "notNull": true, 16 | "default": "gen_random_uuid()" 17 | }, 18 | "name": { 19 | "name": "name", 20 | "type": "varchar(256)", 21 | "primaryKey": false, 22 | "notNull": true 23 | }, 24 | "created_at": { 25 | "name": "created_at", 26 | "type": "timestamp", 27 | "primaryKey": false, 28 | "notNull": true, 29 | "default": "now()" 30 | }, 31 | "updated_at": { 32 | "name": "updated_at", 33 | "type": "timestamp", 34 | "primaryKey": false, 35 | "notNull": true, 36 | "default": "now()" 37 | } 38 | }, 39 | "indexes": {}, 40 | "foreignKeys": {}, 41 | "compositePrimaryKeys": {} 42 | } 43 | }, 44 | "enums": {}, 45 | "schemas": {}, 46 | "_meta": { 47 | "schemas": {}, 48 | "tables": {}, 49 | "columns": {} 50 | } 51 | } -------------------------------------------------------------------------------- /migrations/meta/0001_snapshot.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "dialect": "pg", 4 | "id": "5054de4c-7142-47fe-81ab-c29b378c18ca", 5 | "prevId": "c4595e94-56a5-4f18-ad77-4c7f5b2e29b4", 6 | "tables": { 7 | "applications": { 8 | "name": "applications", 9 | "schema": "", 10 | "columns": { 11 | "id": { 12 | "name": "id", 13 | "type": "uuid", 14 | "primaryKey": true, 15 | "notNull": true, 16 | "default": "gen_random_uuid()" 17 | }, 18 | "name": { 19 | "name": "name", 20 | "type": "varchar(256)", 21 | "primaryKey": false, 22 | "notNull": true 23 | }, 24 | "created_at": { 25 | "name": "created_at", 26 | "type": "timestamp", 27 | "primaryKey": false, 28 | "notNull": true, 29 | "default": "now()" 30 | }, 31 | "updated_at": { 32 | "name": "updated_at", 33 | "type": "timestamp", 34 | "primaryKey": false, 35 | "notNull": true, 36 | "default": "now()" 37 | } 38 | }, 39 | "indexes": {}, 40 | "foreignKeys": {}, 41 | "compositePrimaryKeys": {} 42 | }, 43 | "users": { 44 | "name": "users", 45 | "schema": "", 46 | "columns": { 47 | "id": { 48 | "name": "id", 49 | "type": "uuid", 50 | "primaryKey": false, 51 | "notNull": true, 52 | "default": "gen_random_uuid()" 53 | }, 54 | "email": { 55 | "name": "email", 56 | "type": "varchar(256)", 57 | "primaryKey": false, 58 | "notNull": true 59 | }, 60 | "name": { 61 | "name": "name", 62 | "type": "varchar(256)", 63 | "primaryKey": false, 64 | "notNull": true 65 | }, 66 | "applicationId": { 67 | "name": "applicationId", 68 | "type": "uuid", 69 | "primaryKey": false, 70 | "notNull": false 71 | }, 72 | "password": { 73 | "name": "password", 74 | "type": "varchar(256)", 75 | "primaryKey": false, 76 | "notNull": true 77 | }, 78 | "created_at": { 79 | "name": "created_at", 80 | "type": "timestamp", 81 | "primaryKey": false, 82 | "notNull": true, 83 | "default": "now()" 84 | }, 85 | "updated_at": { 86 | "name": "updated_at", 87 | "type": "timestamp", 88 | "primaryKey": false, 89 | "notNull": true, 90 | "default": "now()" 91 | } 92 | }, 93 | "indexes": { 94 | "users_id_index": { 95 | "name": "users_id_index", 96 | "columns": [ 97 | "id" 98 | ], 99 | "isUnique": true 100 | } 101 | }, 102 | "foreignKeys": { 103 | "users_applicationId_applications_id_fk": { 104 | "name": "users_applicationId_applications_id_fk", 105 | "tableFrom": "users", 106 | "tableTo": "applications", 107 | "columnsFrom": [ 108 | "applicationId" 109 | ], 110 | "columnsTo": [ 111 | "id" 112 | ], 113 | "onDelete": "no action", 114 | "onUpdate": "no action" 115 | } 116 | }, 117 | "compositePrimaryKeys": { 118 | "users_email_applicationId": { 119 | "name": "users_email_applicationId", 120 | "columns": [ 121 | "email", 122 | "applicationId" 123 | ] 124 | } 125 | } 126 | } 127 | }, 128 | "enums": {}, 129 | "schemas": {}, 130 | "_meta": { 131 | "schemas": {}, 132 | "tables": {}, 133 | "columns": {} 134 | } 135 | } -------------------------------------------------------------------------------- /migrations/meta/0002_snapshot.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "dialect": "pg", 4 | "id": "76e5b141-f614-4188-a33b-368f74e8b2fe", 5 | "prevId": "5054de4c-7142-47fe-81ab-c29b378c18ca", 6 | "tables": { 7 | "applications": { 8 | "name": "applications", 9 | "schema": "", 10 | "columns": { 11 | "id": { 12 | "name": "id", 13 | "type": "uuid", 14 | "primaryKey": true, 15 | "notNull": true, 16 | "default": "gen_random_uuid()" 17 | }, 18 | "name": { 19 | "name": "name", 20 | "type": "varchar(256)", 21 | "primaryKey": false, 22 | "notNull": true 23 | }, 24 | "created_at": { 25 | "name": "created_at", 26 | "type": "timestamp", 27 | "primaryKey": false, 28 | "notNull": true, 29 | "default": "now()" 30 | }, 31 | "updated_at": { 32 | "name": "updated_at", 33 | "type": "timestamp", 34 | "primaryKey": false, 35 | "notNull": true, 36 | "default": "now()" 37 | } 38 | }, 39 | "indexes": {}, 40 | "foreignKeys": {}, 41 | "compositePrimaryKeys": {} 42 | }, 43 | "roles": { 44 | "name": "roles", 45 | "schema": "", 46 | "columns": { 47 | "id": { 48 | "name": "id", 49 | "type": "uuid", 50 | "primaryKey": false, 51 | "notNull": true, 52 | "default": "gen_random_uuid()" 53 | }, 54 | "name": { 55 | "name": "name", 56 | "type": "varchar(256)", 57 | "primaryKey": false, 58 | "notNull": true 59 | }, 60 | "applicationId": { 61 | "name": "applicationId", 62 | "type": "uuid", 63 | "primaryKey": false, 64 | "notNull": false 65 | }, 66 | "permissions": { 67 | "name": "permissions", 68 | "type": "text[]", 69 | "primaryKey": false, 70 | "notNull": false 71 | }, 72 | "created_at": { 73 | "name": "created_at", 74 | "type": "timestamp", 75 | "primaryKey": false, 76 | "notNull": true, 77 | "default": "now()" 78 | }, 79 | "updated_at": { 80 | "name": "updated_at", 81 | "type": "timestamp", 82 | "primaryKey": false, 83 | "notNull": true, 84 | "default": "now()" 85 | } 86 | }, 87 | "indexes": { 88 | "roles_id_index": { 89 | "name": "roles_id_index", 90 | "columns": [ 91 | "id" 92 | ], 93 | "isUnique": true 94 | } 95 | }, 96 | "foreignKeys": { 97 | "roles_applicationId_applications_id_fk": { 98 | "name": "roles_applicationId_applications_id_fk", 99 | "tableFrom": "roles", 100 | "tableTo": "applications", 101 | "columnsFrom": [ 102 | "applicationId" 103 | ], 104 | "columnsTo": [ 105 | "id" 106 | ], 107 | "onDelete": "no action", 108 | "onUpdate": "no action" 109 | } 110 | }, 111 | "compositePrimaryKeys": { 112 | "roles_name_applicationId": { 113 | "name": "roles_name_applicationId", 114 | "columns": [ 115 | "name", 116 | "applicationId" 117 | ] 118 | } 119 | } 120 | }, 121 | "users": { 122 | "name": "users", 123 | "schema": "", 124 | "columns": { 125 | "id": { 126 | "name": "id", 127 | "type": "uuid", 128 | "primaryKey": false, 129 | "notNull": true, 130 | "default": "gen_random_uuid()" 131 | }, 132 | "email": { 133 | "name": "email", 134 | "type": "varchar(256)", 135 | "primaryKey": false, 136 | "notNull": true 137 | }, 138 | "name": { 139 | "name": "name", 140 | "type": "varchar(256)", 141 | "primaryKey": false, 142 | "notNull": true 143 | }, 144 | "applicationId": { 145 | "name": "applicationId", 146 | "type": "uuid", 147 | "primaryKey": false, 148 | "notNull": false 149 | }, 150 | "password": { 151 | "name": "password", 152 | "type": "varchar(256)", 153 | "primaryKey": false, 154 | "notNull": true 155 | }, 156 | "created_at": { 157 | "name": "created_at", 158 | "type": "timestamp", 159 | "primaryKey": false, 160 | "notNull": true, 161 | "default": "now()" 162 | }, 163 | "updated_at": { 164 | "name": "updated_at", 165 | "type": "timestamp", 166 | "primaryKey": false, 167 | "notNull": true, 168 | "default": "now()" 169 | } 170 | }, 171 | "indexes": { 172 | "users_id_index": { 173 | "name": "users_id_index", 174 | "columns": [ 175 | "id" 176 | ], 177 | "isUnique": true 178 | } 179 | }, 180 | "foreignKeys": { 181 | "users_applicationId_applications_id_fk": { 182 | "name": "users_applicationId_applications_id_fk", 183 | "tableFrom": "users", 184 | "tableTo": "applications", 185 | "columnsFrom": [ 186 | "applicationId" 187 | ], 188 | "columnsTo": [ 189 | "id" 190 | ], 191 | "onDelete": "no action", 192 | "onUpdate": "no action" 193 | } 194 | }, 195 | "compositePrimaryKeys": { 196 | "users_email_applicationId": { 197 | "name": "users_email_applicationId", 198 | "columns": [ 199 | "email", 200 | "applicationId" 201 | ] 202 | } 203 | } 204 | } 205 | }, 206 | "enums": {}, 207 | "schemas": {}, 208 | "_meta": { 209 | "schemas": {}, 210 | "tables": {}, 211 | "columns": {} 212 | } 213 | } -------------------------------------------------------------------------------- /migrations/meta/0003_snapshot.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "dialect": "pg", 4 | "id": "3919a618-0315-4ce5-81f1-df247d2d5099", 5 | "prevId": "76e5b141-f614-4188-a33b-368f74e8b2fe", 6 | "tables": { 7 | "applications": { 8 | "name": "applications", 9 | "schema": "", 10 | "columns": { 11 | "id": { 12 | "name": "id", 13 | "type": "uuid", 14 | "primaryKey": true, 15 | "notNull": true, 16 | "default": "gen_random_uuid()" 17 | }, 18 | "name": { 19 | "name": "name", 20 | "type": "varchar(256)", 21 | "primaryKey": false, 22 | "notNull": true 23 | }, 24 | "created_at": { 25 | "name": "created_at", 26 | "type": "timestamp", 27 | "primaryKey": false, 28 | "notNull": true, 29 | "default": "now()" 30 | }, 31 | "updated_at": { 32 | "name": "updated_at", 33 | "type": "timestamp", 34 | "primaryKey": false, 35 | "notNull": true, 36 | "default": "now()" 37 | } 38 | }, 39 | "indexes": {}, 40 | "foreignKeys": {}, 41 | "compositePrimaryKeys": {} 42 | }, 43 | "roles": { 44 | "name": "roles", 45 | "schema": "", 46 | "columns": { 47 | "id": { 48 | "name": "id", 49 | "type": "uuid", 50 | "primaryKey": false, 51 | "notNull": true, 52 | "default": "gen_random_uuid()" 53 | }, 54 | "name": { 55 | "name": "name", 56 | "type": "varchar(256)", 57 | "primaryKey": false, 58 | "notNull": true 59 | }, 60 | "applicationId": { 61 | "name": "applicationId", 62 | "type": "uuid", 63 | "primaryKey": false, 64 | "notNull": false 65 | }, 66 | "permissions": { 67 | "name": "permissions", 68 | "type": "text[]", 69 | "primaryKey": false, 70 | "notNull": false 71 | }, 72 | "created_at": { 73 | "name": "created_at", 74 | "type": "timestamp", 75 | "primaryKey": false, 76 | "notNull": true, 77 | "default": "now()" 78 | }, 79 | "updated_at": { 80 | "name": "updated_at", 81 | "type": "timestamp", 82 | "primaryKey": false, 83 | "notNull": true, 84 | "default": "now()" 85 | } 86 | }, 87 | "indexes": { 88 | "roles_id_index": { 89 | "name": "roles_id_index", 90 | "columns": [ 91 | "id" 92 | ], 93 | "isUnique": true 94 | } 95 | }, 96 | "foreignKeys": { 97 | "roles_applicationId_applications_id_fk": { 98 | "name": "roles_applicationId_applications_id_fk", 99 | "tableFrom": "roles", 100 | "tableTo": "applications", 101 | "columnsFrom": [ 102 | "applicationId" 103 | ], 104 | "columnsTo": [ 105 | "id" 106 | ], 107 | "onDelete": "no action", 108 | "onUpdate": "no action" 109 | } 110 | }, 111 | "compositePrimaryKeys": { 112 | "roles_name_applicationId": { 113 | "name": "roles_name_applicationId", 114 | "columns": [ 115 | "name", 116 | "applicationId" 117 | ] 118 | } 119 | } 120 | }, 121 | "users": { 122 | "name": "users", 123 | "schema": "", 124 | "columns": { 125 | "id": { 126 | "name": "id", 127 | "type": "uuid", 128 | "primaryKey": false, 129 | "notNull": true, 130 | "default": "gen_random_uuid()" 131 | }, 132 | "email": { 133 | "name": "email", 134 | "type": "varchar(256)", 135 | "primaryKey": false, 136 | "notNull": true 137 | }, 138 | "name": { 139 | "name": "name", 140 | "type": "varchar(256)", 141 | "primaryKey": false, 142 | "notNull": true 143 | }, 144 | "applicationId": { 145 | "name": "applicationId", 146 | "type": "uuid", 147 | "primaryKey": false, 148 | "notNull": false 149 | }, 150 | "password": { 151 | "name": "password", 152 | "type": "varchar(256)", 153 | "primaryKey": false, 154 | "notNull": true 155 | }, 156 | "created_at": { 157 | "name": "created_at", 158 | "type": "timestamp", 159 | "primaryKey": false, 160 | "notNull": true, 161 | "default": "now()" 162 | }, 163 | "updated_at": { 164 | "name": "updated_at", 165 | "type": "timestamp", 166 | "primaryKey": false, 167 | "notNull": true, 168 | "default": "now()" 169 | } 170 | }, 171 | "indexes": { 172 | "users_id_index": { 173 | "name": "users_id_index", 174 | "columns": [ 175 | "id" 176 | ], 177 | "isUnique": true 178 | } 179 | }, 180 | "foreignKeys": { 181 | "users_applicationId_applications_id_fk": { 182 | "name": "users_applicationId_applications_id_fk", 183 | "tableFrom": "users", 184 | "tableTo": "applications", 185 | "columnsFrom": [ 186 | "applicationId" 187 | ], 188 | "columnsTo": [ 189 | "id" 190 | ], 191 | "onDelete": "no action", 192 | "onUpdate": "no action" 193 | } 194 | }, 195 | "compositePrimaryKeys": { 196 | "users_email_applicationId": { 197 | "name": "users_email_applicationId", 198 | "columns": [ 199 | "email", 200 | "applicationId" 201 | ] 202 | } 203 | } 204 | }, 205 | "usersToRoles": { 206 | "name": "usersToRoles", 207 | "schema": "", 208 | "columns": { 209 | "applicationId": { 210 | "name": "applicationId", 211 | "type": "uuid", 212 | "primaryKey": false, 213 | "notNull": true 214 | }, 215 | "roledId": { 216 | "name": "roledId", 217 | "type": "uuid", 218 | "primaryKey": false, 219 | "notNull": true 220 | }, 221 | "userId": { 222 | "name": "userId", 223 | "type": "uuid", 224 | "primaryKey": false, 225 | "notNull": true 226 | } 227 | }, 228 | "indexes": {}, 229 | "foreignKeys": { 230 | "usersToRoles_applicationId_applications_id_fk": { 231 | "name": "usersToRoles_applicationId_applications_id_fk", 232 | "tableFrom": "usersToRoles", 233 | "tableTo": "applications", 234 | "columnsFrom": [ 235 | "applicationId" 236 | ], 237 | "columnsTo": [ 238 | "id" 239 | ], 240 | "onDelete": "no action", 241 | "onUpdate": "no action" 242 | }, 243 | "usersToRoles_roledId_roles_id_fk": { 244 | "name": "usersToRoles_roledId_roles_id_fk", 245 | "tableFrom": "usersToRoles", 246 | "tableTo": "roles", 247 | "columnsFrom": [ 248 | "roledId" 249 | ], 250 | "columnsTo": [ 251 | "id" 252 | ], 253 | "onDelete": "no action", 254 | "onUpdate": "no action" 255 | }, 256 | "usersToRoles_userId_users_id_fk": { 257 | "name": "usersToRoles_userId_users_id_fk", 258 | "tableFrom": "usersToRoles", 259 | "tableTo": "users", 260 | "columnsFrom": [ 261 | "userId" 262 | ], 263 | "columnsTo": [ 264 | "id" 265 | ], 266 | "onDelete": "no action", 267 | "onUpdate": "no action" 268 | } 269 | }, 270 | "compositePrimaryKeys": { 271 | "usersToRoles_applicationId_roledId_userId": { 272 | "name": "usersToRoles_applicationId_roledId_userId", 273 | "columns": [ 274 | "applicationId", 275 | "roledId", 276 | "userId" 277 | ] 278 | } 279 | } 280 | } 281 | }, 282 | "enums": {}, 283 | "schemas": {}, 284 | "_meta": { 285 | "schemas": {}, 286 | "tables": {}, 287 | "columns": {} 288 | } 289 | } -------------------------------------------------------------------------------- /migrations/meta/_journal.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "dialect": "pg", 4 | "entries": [ 5 | { 6 | "idx": 0, 7 | "version": "5", 8 | "when": 1684312706166, 9 | "tag": "0000_remarkable_katie_power", 10 | "breakpoints": false 11 | }, 12 | { 13 | "idx": 1, 14 | "version": "5", 15 | "when": 1684313093833, 16 | "tag": "0001_mute_true_believers", 17 | "breakpoints": false 18 | }, 19 | { 20 | "idx": 2, 21 | "version": "5", 22 | "when": 1684313333317, 23 | "tag": "0002_common_tyger_tiger", 24 | "breakpoints": false 25 | }, 26 | { 27 | "idx": 3, 28 | "version": "5", 29 | "when": 1684313670786, 30 | "tag": "0003_secret_forge", 31 | "breakpoints": false 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "tsx watch src/main.ts", 4 | "migrate": "drizzle-kit generate:pg" 5 | }, 6 | "dependencies": { 7 | "argon2": "^0.30.3", 8 | "drizzle-orm": "^0.25.4", 9 | "fastify": "^4.17.0", 10 | "fastify-guard": "^2.0.0", 11 | "fastify-zod": "^1.3.2", 12 | "jsonwebtoken": "^9.0.0", 13 | "pg": "^8.11.0", 14 | "pino": "^8.14.1", 15 | "pino-pretty": "^10.0.0", 16 | "zennv": "^0.1.1", 17 | "zod": "^3.21.4" 18 | }, 19 | "devDependencies": { 20 | "@types/jsonwebtoken": "^9.0.2", 21 | "@types/pg": "^8.6.6", 22 | "drizzle-kit": "^0.17.6", 23 | "tsx": "^3.12.7", 24 | "typescript": "^5.0.4", 25 | "zod-to-json-schema": "^3.21.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | '@types/jsonwebtoken': ^9.0.2 5 | '@types/pg': ^8.6.6 6 | argon2: ^0.30.3 7 | drizzle-kit: ^0.17.6 8 | drizzle-orm: ^0.25.4 9 | fastify: ^4.17.0 10 | fastify-guard: ^2.0.0 11 | fastify-zod: ^1.3.2 12 | jsonwebtoken: ^9.0.0 13 | pg: ^8.11.0 14 | pino: ^8.14.1 15 | pino-pretty: ^10.0.0 16 | tsx: ^3.12.7 17 | typescript: ^5.0.4 18 | zennv: ^0.1.1 19 | zod: ^3.21.4 20 | zod-to-json-schema: ^3.21.1 21 | 22 | dependencies: 23 | argon2: 0.30.3 24 | drizzle-orm: 0.25.4_@types+pg@8.6.6+pg@8.11.0 25 | fastify: 4.17.0 26 | fastify-guard: 2.0.0 27 | fastify-zod: 1.3.2_fastify@4.17.0 28 | jsonwebtoken: 9.0.0 29 | pg: 8.11.0 30 | pino: 8.14.1 31 | pino-pretty: 10.0.0 32 | zennv: 0.1.1 33 | zod: 3.21.4 34 | 35 | devDependencies: 36 | '@types/jsonwebtoken': 9.0.2 37 | '@types/pg': 8.6.6 38 | drizzle-kit: 0.17.6 39 | tsx: 3.12.7 40 | typescript: 5.0.4 41 | zod-to-json-schema: 3.21.1_zod@3.21.4 42 | 43 | packages: 44 | 45 | /@esbuild-kit/cjs-loader/2.4.2: 46 | resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==} 47 | dependencies: 48 | '@esbuild-kit/core-utils': 3.1.0 49 | get-tsconfig: 4.5.0 50 | dev: true 51 | 52 | /@esbuild-kit/core-utils/3.1.0: 53 | resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} 54 | dependencies: 55 | esbuild: 0.17.19 56 | source-map-support: 0.5.21 57 | dev: true 58 | 59 | /@esbuild-kit/esm-loader/2.5.5: 60 | resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} 61 | dependencies: 62 | '@esbuild-kit/core-utils': 3.1.0 63 | get-tsconfig: 4.5.0 64 | dev: true 65 | 66 | /@esbuild/android-arm/0.15.18: 67 | resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} 68 | engines: {node: '>=12'} 69 | cpu: [arm] 70 | os: [android] 71 | requiresBuild: true 72 | dev: true 73 | optional: true 74 | 75 | /@esbuild/android-arm/0.17.19: 76 | resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} 77 | engines: {node: '>=12'} 78 | cpu: [arm] 79 | os: [android] 80 | requiresBuild: true 81 | dev: true 82 | optional: true 83 | 84 | /@esbuild/android-arm64/0.17.19: 85 | resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} 86 | engines: {node: '>=12'} 87 | cpu: [arm64] 88 | os: [android] 89 | requiresBuild: true 90 | dev: true 91 | optional: true 92 | 93 | /@esbuild/android-x64/0.17.19: 94 | resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} 95 | engines: {node: '>=12'} 96 | cpu: [x64] 97 | os: [android] 98 | requiresBuild: true 99 | dev: true 100 | optional: true 101 | 102 | /@esbuild/darwin-arm64/0.17.19: 103 | resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} 104 | engines: {node: '>=12'} 105 | cpu: [arm64] 106 | os: [darwin] 107 | requiresBuild: true 108 | dev: true 109 | optional: true 110 | 111 | /@esbuild/darwin-x64/0.17.19: 112 | resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} 113 | engines: {node: '>=12'} 114 | cpu: [x64] 115 | os: [darwin] 116 | requiresBuild: true 117 | dev: true 118 | optional: true 119 | 120 | /@esbuild/freebsd-arm64/0.17.19: 121 | resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} 122 | engines: {node: '>=12'} 123 | cpu: [arm64] 124 | os: [freebsd] 125 | requiresBuild: true 126 | dev: true 127 | optional: true 128 | 129 | /@esbuild/freebsd-x64/0.17.19: 130 | resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} 131 | engines: {node: '>=12'} 132 | cpu: [x64] 133 | os: [freebsd] 134 | requiresBuild: true 135 | dev: true 136 | optional: true 137 | 138 | /@esbuild/linux-arm/0.17.19: 139 | resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} 140 | engines: {node: '>=12'} 141 | cpu: [arm] 142 | os: [linux] 143 | requiresBuild: true 144 | dev: true 145 | optional: true 146 | 147 | /@esbuild/linux-arm64/0.17.19: 148 | resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} 149 | engines: {node: '>=12'} 150 | cpu: [arm64] 151 | os: [linux] 152 | requiresBuild: true 153 | dev: true 154 | optional: true 155 | 156 | /@esbuild/linux-ia32/0.17.19: 157 | resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} 158 | engines: {node: '>=12'} 159 | cpu: [ia32] 160 | os: [linux] 161 | requiresBuild: true 162 | dev: true 163 | optional: true 164 | 165 | /@esbuild/linux-loong64/0.15.18: 166 | resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} 167 | engines: {node: '>=12'} 168 | cpu: [loong64] 169 | os: [linux] 170 | requiresBuild: true 171 | dev: true 172 | optional: true 173 | 174 | /@esbuild/linux-loong64/0.17.19: 175 | resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} 176 | engines: {node: '>=12'} 177 | cpu: [loong64] 178 | os: [linux] 179 | requiresBuild: true 180 | dev: true 181 | optional: true 182 | 183 | /@esbuild/linux-mips64el/0.17.19: 184 | resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} 185 | engines: {node: '>=12'} 186 | cpu: [mips64el] 187 | os: [linux] 188 | requiresBuild: true 189 | dev: true 190 | optional: true 191 | 192 | /@esbuild/linux-ppc64/0.17.19: 193 | resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} 194 | engines: {node: '>=12'} 195 | cpu: [ppc64] 196 | os: [linux] 197 | requiresBuild: true 198 | dev: true 199 | optional: true 200 | 201 | /@esbuild/linux-riscv64/0.17.19: 202 | resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} 203 | engines: {node: '>=12'} 204 | cpu: [riscv64] 205 | os: [linux] 206 | requiresBuild: true 207 | dev: true 208 | optional: true 209 | 210 | /@esbuild/linux-s390x/0.17.19: 211 | resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} 212 | engines: {node: '>=12'} 213 | cpu: [s390x] 214 | os: [linux] 215 | requiresBuild: true 216 | dev: true 217 | optional: true 218 | 219 | /@esbuild/linux-x64/0.17.19: 220 | resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} 221 | engines: {node: '>=12'} 222 | cpu: [x64] 223 | os: [linux] 224 | requiresBuild: true 225 | dev: true 226 | optional: true 227 | 228 | /@esbuild/netbsd-x64/0.17.19: 229 | resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} 230 | engines: {node: '>=12'} 231 | cpu: [x64] 232 | os: [netbsd] 233 | requiresBuild: true 234 | dev: true 235 | optional: true 236 | 237 | /@esbuild/openbsd-x64/0.17.19: 238 | resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} 239 | engines: {node: '>=12'} 240 | cpu: [x64] 241 | os: [openbsd] 242 | requiresBuild: true 243 | dev: true 244 | optional: true 245 | 246 | /@esbuild/sunos-x64/0.17.19: 247 | resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} 248 | engines: {node: '>=12'} 249 | cpu: [x64] 250 | os: [sunos] 251 | requiresBuild: true 252 | dev: true 253 | optional: true 254 | 255 | /@esbuild/win32-arm64/0.17.19: 256 | resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} 257 | engines: {node: '>=12'} 258 | cpu: [arm64] 259 | os: [win32] 260 | requiresBuild: true 261 | dev: true 262 | optional: true 263 | 264 | /@esbuild/win32-ia32/0.17.19: 265 | resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} 266 | engines: {node: '>=12'} 267 | cpu: [ia32] 268 | os: [win32] 269 | requiresBuild: true 270 | dev: true 271 | optional: true 272 | 273 | /@esbuild/win32-x64/0.17.19: 274 | resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} 275 | engines: {node: '>=12'} 276 | cpu: [x64] 277 | os: [win32] 278 | requiresBuild: true 279 | dev: true 280 | optional: true 281 | 282 | /@fastify/accept-negotiator/1.1.0: 283 | resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==} 284 | engines: {node: '>=14'} 285 | dev: false 286 | 287 | /@fastify/ajv-compiler/3.5.0: 288 | resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} 289 | dependencies: 290 | ajv: 8.12.0 291 | ajv-formats: 2.1.1 292 | fast-uri: 2.2.0 293 | dev: false 294 | 295 | /@fastify/deepmerge/1.3.0: 296 | resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==} 297 | dev: false 298 | 299 | /@fastify/error/3.2.0: 300 | resolution: {integrity: sha512-KAfcLa+CnknwVi5fWogrLXgidLic+GXnLjijXdpl8pvkvbXU5BGa37iZO9FGvsh9ZL4y+oFi5cbHBm5UOG+dmQ==} 301 | dev: false 302 | 303 | /@fastify/fast-json-stringify-compiler/4.3.0: 304 | resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} 305 | dependencies: 306 | fast-json-stringify: 5.7.0 307 | dev: false 308 | 309 | /@fastify/send/2.1.0: 310 | resolution: {integrity: sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==} 311 | dependencies: 312 | '@lukeed/ms': 2.0.1 313 | escape-html: 1.0.3 314 | fast-decode-uri-component: 1.0.1 315 | http-errors: 2.0.0 316 | mime: 3.0.0 317 | dev: false 318 | 319 | /@fastify/static/6.10.1: 320 | resolution: {integrity: sha512-DNnG+5QenQcTQw37qk0/191STThnN6SbU+2XMpWtpYR3gQUfUvMax14jTT/jqNINNbCkQJaKMnPtpFPKo4/68g==} 321 | dependencies: 322 | '@fastify/accept-negotiator': 1.1.0 323 | '@fastify/send': 2.1.0 324 | content-disposition: 0.5.4 325 | fastify-plugin: 4.5.0 326 | glob: 8.1.0 327 | p-limit: 3.1.0 328 | readable-stream: 4.4.0 329 | dev: false 330 | 331 | /@fastify/swagger-ui/1.8.1: 332 | resolution: {integrity: sha512-XMfLGZMXi5dl0Gy6R6tlistA4d0XlJJweUfQkPNVeeBq2hO03DmvtM5yrp8adF392Xoi+6rlGHFaneL9EQdsoA==} 333 | dependencies: 334 | '@fastify/static': 6.10.1 335 | fastify-plugin: 4.5.0 336 | openapi-types: 12.1.0 337 | rfdc: 1.3.0 338 | yaml: 2.2.2 339 | dev: false 340 | 341 | /@fastify/swagger/8.4.0: 342 | resolution: {integrity: sha512-bgTXEIW8HPfBH9ENER410aI81I2iSoHsHkVs8JJU3gzdVoq+ZVZvnwNYYSXB83K6xdTXMKTEiv8GKAimte49lw==} 343 | dependencies: 344 | fastify-plugin: 4.5.0 345 | json-schema-resolver: 2.0.0 346 | openapi-types: 12.1.0 347 | rfdc: 1.3.0 348 | yaml: 2.2.2 349 | transitivePeerDependencies: 350 | - supports-color 351 | dev: false 352 | 353 | /@lukeed/ms/2.0.1: 354 | resolution: {integrity: sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==} 355 | engines: {node: '>=8'} 356 | dev: false 357 | 358 | /@mapbox/node-pre-gyp/1.0.10: 359 | resolution: {integrity: sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==} 360 | hasBin: true 361 | dependencies: 362 | detect-libc: 2.0.1 363 | https-proxy-agent: 5.0.1 364 | make-dir: 3.1.0 365 | node-fetch: 2.6.11 366 | nopt: 5.0.0 367 | npmlog: 5.0.1 368 | rimraf: 3.0.2 369 | semver: 7.5.1 370 | tar: 6.1.15 371 | transitivePeerDependencies: 372 | - encoding 373 | - supports-color 374 | dev: false 375 | 376 | /@phc/format/1.0.0: 377 | resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} 378 | engines: {node: '>=10'} 379 | dev: false 380 | 381 | /@types/js-yaml/4.0.5: 382 | resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==} 383 | dev: false 384 | 385 | /@types/jsonwebtoken/9.0.2: 386 | resolution: {integrity: sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==} 387 | dependencies: 388 | '@types/node': 20.1.7 389 | dev: true 390 | 391 | /@types/node/20.1.7: 392 | resolution: {integrity: sha512-WCuw/o4GSwDGMoonES8rcvwsig77dGCMbZDrZr2x4ZZiNW4P/gcoZXe/0twgtobcTkmg9TuKflxYL/DuwDyJzg==} 393 | 394 | /@types/pg/8.6.6: 395 | resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} 396 | dependencies: 397 | '@types/node': 20.1.7 398 | pg-protocol: 1.6.0 399 | pg-types: 2.2.0 400 | 401 | /abbrev/1.1.1: 402 | resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} 403 | dev: false 404 | 405 | /abort-controller/3.0.0: 406 | resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} 407 | engines: {node: '>=6.5'} 408 | dependencies: 409 | event-target-shim: 5.0.1 410 | dev: false 411 | 412 | /abstract-logging/2.0.1: 413 | resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} 414 | dev: false 415 | 416 | /agent-base/6.0.2: 417 | resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} 418 | engines: {node: '>= 6.0.0'} 419 | dependencies: 420 | debug: 4.3.4 421 | transitivePeerDependencies: 422 | - supports-color 423 | dev: false 424 | 425 | /ajv-formats/2.1.1: 426 | resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} 427 | peerDependenciesMeta: 428 | ajv: 429 | optional: true 430 | dependencies: 431 | ajv: 8.12.0 432 | dev: false 433 | 434 | /ajv/8.12.0: 435 | resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} 436 | dependencies: 437 | fast-deep-equal: 3.1.3 438 | json-schema-traverse: 1.0.0 439 | require-from-string: 2.0.2 440 | uri-js: 4.4.1 441 | dev: false 442 | 443 | /ansi-regex/5.0.1: 444 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 445 | engines: {node: '>=8'} 446 | dev: false 447 | 448 | /aproba/2.0.0: 449 | resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} 450 | dev: false 451 | 452 | /archy/1.0.0: 453 | resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} 454 | dev: false 455 | 456 | /are-we-there-yet/2.0.0: 457 | resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} 458 | engines: {node: '>=10'} 459 | dependencies: 460 | delegates: 1.0.0 461 | readable-stream: 3.6.2 462 | dev: false 463 | 464 | /argon2/0.30.3: 465 | resolution: {integrity: sha512-DoH/kv8c9127ueJSBxAVJXinW9+EuPA3EMUxoV2sAY1qDE5H9BjTyVF/aD2XyHqbqUWabgBkIfcP3ZZuGhbJdg==} 466 | engines: {node: '>=14.0.0'} 467 | requiresBuild: true 468 | dependencies: 469 | '@mapbox/node-pre-gyp': 1.0.10 470 | '@phc/format': 1.0.0 471 | node-addon-api: 5.1.0 472 | transitivePeerDependencies: 473 | - encoding 474 | - supports-color 475 | dev: false 476 | 477 | /argparse/2.0.1: 478 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 479 | dev: false 480 | 481 | /atomic-sleep/1.0.0: 482 | resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} 483 | engines: {node: '>=8.0.0'} 484 | dev: false 485 | 486 | /avvio/8.2.1: 487 | resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==} 488 | dependencies: 489 | archy: 1.0.0 490 | debug: 4.3.4 491 | fastq: 1.15.0 492 | transitivePeerDependencies: 493 | - supports-color 494 | dev: false 495 | 496 | /balanced-match/1.0.2: 497 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 498 | 499 | /base64-js/1.5.1: 500 | resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} 501 | dev: false 502 | 503 | /brace-expansion/1.1.11: 504 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 505 | dependencies: 506 | balanced-match: 1.0.2 507 | concat-map: 0.0.1 508 | dev: false 509 | 510 | /brace-expansion/2.0.1: 511 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 512 | dependencies: 513 | balanced-match: 1.0.2 514 | 515 | /buffer-equal-constant-time/1.0.1: 516 | resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} 517 | dev: false 518 | 519 | /buffer-from/1.1.2: 520 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 521 | dev: true 522 | 523 | /buffer-writer/2.0.0: 524 | resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} 525 | engines: {node: '>=4'} 526 | dev: false 527 | 528 | /buffer/6.0.3: 529 | resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} 530 | dependencies: 531 | base64-js: 1.5.1 532 | ieee754: 1.2.1 533 | dev: false 534 | 535 | /camel-case/4.1.2: 536 | resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} 537 | dependencies: 538 | pascal-case: 3.1.2 539 | tslib: 2.5.0 540 | dev: false 541 | 542 | /camelcase/7.0.1: 543 | resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} 544 | engines: {node: '>=14.16'} 545 | dev: true 546 | 547 | /capital-case/1.0.4: 548 | resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} 549 | dependencies: 550 | no-case: 3.0.4 551 | tslib: 2.5.0 552 | upper-case-first: 2.0.2 553 | dev: false 554 | 555 | /chalk/5.2.0: 556 | resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} 557 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 558 | dev: true 559 | 560 | /change-case/4.1.2: 561 | resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} 562 | dependencies: 563 | camel-case: 4.1.2 564 | capital-case: 1.0.4 565 | constant-case: 3.0.4 566 | dot-case: 3.0.4 567 | header-case: 2.0.4 568 | no-case: 3.0.4 569 | param-case: 3.0.4 570 | pascal-case: 3.1.2 571 | path-case: 3.0.4 572 | sentence-case: 3.0.4 573 | snake-case: 3.0.4 574 | tslib: 2.5.0 575 | dev: false 576 | 577 | /chownr/2.0.0: 578 | resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} 579 | engines: {node: '>=10'} 580 | dev: false 581 | 582 | /cli-color/2.0.3: 583 | resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==} 584 | engines: {node: '>=0.10'} 585 | dependencies: 586 | d: 1.0.1 587 | es5-ext: 0.10.62 588 | es6-iterator: 2.0.3 589 | memoizee: 0.4.15 590 | timers-ext: 0.1.7 591 | dev: true 592 | 593 | /color-support/1.1.3: 594 | resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} 595 | hasBin: true 596 | dev: false 597 | 598 | /colorette/2.0.20: 599 | resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} 600 | dev: false 601 | 602 | /commander/9.5.0: 603 | resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} 604 | engines: {node: ^12.20.0 || >=14} 605 | dev: true 606 | 607 | /concat-map/0.0.1: 608 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 609 | dev: false 610 | 611 | /console-control-strings/1.1.0: 612 | resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} 613 | dev: false 614 | 615 | /constant-case/3.0.4: 616 | resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} 617 | dependencies: 618 | no-case: 3.0.4 619 | tslib: 2.5.0 620 | upper-case: 2.0.2 621 | dev: false 622 | 623 | /content-disposition/0.5.4: 624 | resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} 625 | engines: {node: '>= 0.6'} 626 | dependencies: 627 | safe-buffer: 5.2.1 628 | dev: false 629 | 630 | /cookie/0.5.0: 631 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} 632 | engines: {node: '>= 0.6'} 633 | dev: false 634 | 635 | /d/1.0.1: 636 | resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} 637 | dependencies: 638 | es5-ext: 0.10.62 639 | type: 1.2.0 640 | dev: true 641 | 642 | /dateformat/4.6.3: 643 | resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} 644 | dev: false 645 | 646 | /debug/4.3.4: 647 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 648 | engines: {node: '>=6.0'} 649 | peerDependencies: 650 | supports-color: '*' 651 | peerDependenciesMeta: 652 | supports-color: 653 | optional: true 654 | dependencies: 655 | ms: 2.1.2 656 | 657 | /delegates/1.0.0: 658 | resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} 659 | dev: false 660 | 661 | /depd/2.0.0: 662 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} 663 | engines: {node: '>= 0.8'} 664 | dev: false 665 | 666 | /detect-libc/2.0.1: 667 | resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} 668 | engines: {node: '>=8'} 669 | dev: false 670 | 671 | /difflib/0.2.4: 672 | resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} 673 | dependencies: 674 | heap: 0.2.7 675 | dev: true 676 | 677 | /dot-case/3.0.4: 678 | resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} 679 | dependencies: 680 | no-case: 3.0.4 681 | tslib: 2.5.0 682 | dev: false 683 | 684 | /dotenv/16.0.3: 685 | resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} 686 | engines: {node: '>=12'} 687 | dev: false 688 | 689 | /dreamopt/0.8.0: 690 | resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} 691 | engines: {node: '>=0.4.0'} 692 | dependencies: 693 | wordwrap: 1.0.0 694 | dev: true 695 | 696 | /drizzle-kit/0.17.6: 697 | resolution: {integrity: sha512-diNslu/ItzLv+++7l2noevXaCOrsfDXv+ZxMJWOy061Gs1BeEhP0t+mBKqeOPy8LsEo0aitNKOe+gPltEScmWQ==} 698 | hasBin: true 699 | dependencies: 700 | camelcase: 7.0.1 701 | chalk: 5.2.0 702 | commander: 9.5.0 703 | esbuild: 0.15.18 704 | esbuild-register: 3.4.2_esbuild@0.15.18 705 | glob: 8.1.0 706 | hanji: 0.0.5 707 | json-diff: 0.9.0 708 | zod: 3.21.4 709 | transitivePeerDependencies: 710 | - supports-color 711 | dev: true 712 | 713 | /drizzle-orm/0.25.4_@types+pg@8.6.6+pg@8.11.0: 714 | resolution: {integrity: sha512-vURs2SqDh5pk81WWE4hR8gFKDTRmCK4FbaUGsZoljKnjKvMrjlA5xFPGiCih4/1XKqnOgSuh+I6T9KGBjYcPAA==} 715 | peerDependencies: 716 | '@aws-sdk/client-rds-data': '>=3' 717 | '@cloudflare/workers-types': '>=3' 718 | '@libsql/client': '*' 719 | '@neondatabase/serverless': '>=0.1' 720 | '@planetscale/database': '>=1' 721 | '@types/better-sqlite3': '*' 722 | '@types/pg': '*' 723 | '@types/sql.js': '*' 724 | '@vercel/postgres': '*' 725 | better-sqlite3: '>=7' 726 | bun-types: '*' 727 | knex: '*' 728 | kysely: '*' 729 | mysql2: '>=2' 730 | pg: '>=8' 731 | postgres: '>=3' 732 | sql.js: '>=1' 733 | sqlite3: '>=5' 734 | peerDependenciesMeta: 735 | '@aws-sdk/client-rds-data': 736 | optional: true 737 | '@cloudflare/workers-types': 738 | optional: true 739 | '@libsql/client': 740 | optional: true 741 | '@neondatabase/serverless': 742 | optional: true 743 | '@planetscale/database': 744 | optional: true 745 | '@types/better-sqlite3': 746 | optional: true 747 | '@types/pg': 748 | optional: true 749 | '@types/sql.js': 750 | optional: true 751 | '@vercel/postgres': 752 | optional: true 753 | better-sqlite3: 754 | optional: true 755 | bun-types: 756 | optional: true 757 | knex: 758 | optional: true 759 | kysely: 760 | optional: true 761 | mysql2: 762 | optional: true 763 | pg: 764 | optional: true 765 | postgres: 766 | optional: true 767 | sql.js: 768 | optional: true 769 | sqlite3: 770 | optional: true 771 | dependencies: 772 | '@types/pg': 8.6.6 773 | pg: 8.11.0 774 | dev: false 775 | 776 | /ecdsa-sig-formatter/1.0.11: 777 | resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} 778 | dependencies: 779 | safe-buffer: 5.2.1 780 | dev: false 781 | 782 | /emoji-regex/8.0.0: 783 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 784 | dev: false 785 | 786 | /end-of-stream/1.4.4: 787 | resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 788 | dependencies: 789 | once: 1.4.0 790 | dev: false 791 | 792 | /es5-ext/0.10.62: 793 | resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} 794 | engines: {node: '>=0.10'} 795 | requiresBuild: true 796 | dependencies: 797 | es6-iterator: 2.0.3 798 | es6-symbol: 3.1.3 799 | next-tick: 1.1.0 800 | dev: true 801 | 802 | /es6-iterator/2.0.3: 803 | resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} 804 | dependencies: 805 | d: 1.0.1 806 | es5-ext: 0.10.62 807 | es6-symbol: 3.1.3 808 | dev: true 809 | 810 | /es6-symbol/3.1.3: 811 | resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} 812 | dependencies: 813 | d: 1.0.1 814 | ext: 1.7.0 815 | dev: true 816 | 817 | /es6-weak-map/2.0.3: 818 | resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} 819 | dependencies: 820 | d: 1.0.1 821 | es5-ext: 0.10.62 822 | es6-iterator: 2.0.3 823 | es6-symbol: 3.1.3 824 | dev: true 825 | 826 | /esbuild-android-64/0.15.18: 827 | resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==} 828 | engines: {node: '>=12'} 829 | cpu: [x64] 830 | os: [android] 831 | requiresBuild: true 832 | dev: true 833 | optional: true 834 | 835 | /esbuild-android-arm64/0.15.18: 836 | resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==} 837 | engines: {node: '>=12'} 838 | cpu: [arm64] 839 | os: [android] 840 | requiresBuild: true 841 | dev: true 842 | optional: true 843 | 844 | /esbuild-darwin-64/0.15.18: 845 | resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==} 846 | engines: {node: '>=12'} 847 | cpu: [x64] 848 | os: [darwin] 849 | requiresBuild: true 850 | dev: true 851 | optional: true 852 | 853 | /esbuild-darwin-arm64/0.15.18: 854 | resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==} 855 | engines: {node: '>=12'} 856 | cpu: [arm64] 857 | os: [darwin] 858 | requiresBuild: true 859 | dev: true 860 | optional: true 861 | 862 | /esbuild-freebsd-64/0.15.18: 863 | resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==} 864 | engines: {node: '>=12'} 865 | cpu: [x64] 866 | os: [freebsd] 867 | requiresBuild: true 868 | dev: true 869 | optional: true 870 | 871 | /esbuild-freebsd-arm64/0.15.18: 872 | resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==} 873 | engines: {node: '>=12'} 874 | cpu: [arm64] 875 | os: [freebsd] 876 | requiresBuild: true 877 | dev: true 878 | optional: true 879 | 880 | /esbuild-linux-32/0.15.18: 881 | resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==} 882 | engines: {node: '>=12'} 883 | cpu: [ia32] 884 | os: [linux] 885 | requiresBuild: true 886 | dev: true 887 | optional: true 888 | 889 | /esbuild-linux-64/0.15.18: 890 | resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==} 891 | engines: {node: '>=12'} 892 | cpu: [x64] 893 | os: [linux] 894 | requiresBuild: true 895 | dev: true 896 | optional: true 897 | 898 | /esbuild-linux-arm/0.15.18: 899 | resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==} 900 | engines: {node: '>=12'} 901 | cpu: [arm] 902 | os: [linux] 903 | requiresBuild: true 904 | dev: true 905 | optional: true 906 | 907 | /esbuild-linux-arm64/0.15.18: 908 | resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==} 909 | engines: {node: '>=12'} 910 | cpu: [arm64] 911 | os: [linux] 912 | requiresBuild: true 913 | dev: true 914 | optional: true 915 | 916 | /esbuild-linux-mips64le/0.15.18: 917 | resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==} 918 | engines: {node: '>=12'} 919 | cpu: [mips64el] 920 | os: [linux] 921 | requiresBuild: true 922 | dev: true 923 | optional: true 924 | 925 | /esbuild-linux-ppc64le/0.15.18: 926 | resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==} 927 | engines: {node: '>=12'} 928 | cpu: [ppc64] 929 | os: [linux] 930 | requiresBuild: true 931 | dev: true 932 | optional: true 933 | 934 | /esbuild-linux-riscv64/0.15.18: 935 | resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==} 936 | engines: {node: '>=12'} 937 | cpu: [riscv64] 938 | os: [linux] 939 | requiresBuild: true 940 | dev: true 941 | optional: true 942 | 943 | /esbuild-linux-s390x/0.15.18: 944 | resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==} 945 | engines: {node: '>=12'} 946 | cpu: [s390x] 947 | os: [linux] 948 | requiresBuild: true 949 | dev: true 950 | optional: true 951 | 952 | /esbuild-netbsd-64/0.15.18: 953 | resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==} 954 | engines: {node: '>=12'} 955 | cpu: [x64] 956 | os: [netbsd] 957 | requiresBuild: true 958 | dev: true 959 | optional: true 960 | 961 | /esbuild-openbsd-64/0.15.18: 962 | resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==} 963 | engines: {node: '>=12'} 964 | cpu: [x64] 965 | os: [openbsd] 966 | requiresBuild: true 967 | dev: true 968 | optional: true 969 | 970 | /esbuild-register/3.4.2_esbuild@0.15.18: 971 | resolution: {integrity: sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==} 972 | peerDependencies: 973 | esbuild: '>=0.12 <1' 974 | dependencies: 975 | debug: 4.3.4 976 | esbuild: 0.15.18 977 | transitivePeerDependencies: 978 | - supports-color 979 | dev: true 980 | 981 | /esbuild-sunos-64/0.15.18: 982 | resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==} 983 | engines: {node: '>=12'} 984 | cpu: [x64] 985 | os: [sunos] 986 | requiresBuild: true 987 | dev: true 988 | optional: true 989 | 990 | /esbuild-windows-32/0.15.18: 991 | resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==} 992 | engines: {node: '>=12'} 993 | cpu: [ia32] 994 | os: [win32] 995 | requiresBuild: true 996 | dev: true 997 | optional: true 998 | 999 | /esbuild-windows-64/0.15.18: 1000 | resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==} 1001 | engines: {node: '>=12'} 1002 | cpu: [x64] 1003 | os: [win32] 1004 | requiresBuild: true 1005 | dev: true 1006 | optional: true 1007 | 1008 | /esbuild-windows-arm64/0.15.18: 1009 | resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==} 1010 | engines: {node: '>=12'} 1011 | cpu: [arm64] 1012 | os: [win32] 1013 | requiresBuild: true 1014 | dev: true 1015 | optional: true 1016 | 1017 | /esbuild/0.15.18: 1018 | resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==} 1019 | engines: {node: '>=12'} 1020 | hasBin: true 1021 | requiresBuild: true 1022 | optionalDependencies: 1023 | '@esbuild/android-arm': 0.15.18 1024 | '@esbuild/linux-loong64': 0.15.18 1025 | esbuild-android-64: 0.15.18 1026 | esbuild-android-arm64: 0.15.18 1027 | esbuild-darwin-64: 0.15.18 1028 | esbuild-darwin-arm64: 0.15.18 1029 | esbuild-freebsd-64: 0.15.18 1030 | esbuild-freebsd-arm64: 0.15.18 1031 | esbuild-linux-32: 0.15.18 1032 | esbuild-linux-64: 0.15.18 1033 | esbuild-linux-arm: 0.15.18 1034 | esbuild-linux-arm64: 0.15.18 1035 | esbuild-linux-mips64le: 0.15.18 1036 | esbuild-linux-ppc64le: 0.15.18 1037 | esbuild-linux-riscv64: 0.15.18 1038 | esbuild-linux-s390x: 0.15.18 1039 | esbuild-netbsd-64: 0.15.18 1040 | esbuild-openbsd-64: 0.15.18 1041 | esbuild-sunos-64: 0.15.18 1042 | esbuild-windows-32: 0.15.18 1043 | esbuild-windows-64: 0.15.18 1044 | esbuild-windows-arm64: 0.15.18 1045 | dev: true 1046 | 1047 | /esbuild/0.17.19: 1048 | resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} 1049 | engines: {node: '>=12'} 1050 | hasBin: true 1051 | requiresBuild: true 1052 | optionalDependencies: 1053 | '@esbuild/android-arm': 0.17.19 1054 | '@esbuild/android-arm64': 0.17.19 1055 | '@esbuild/android-x64': 0.17.19 1056 | '@esbuild/darwin-arm64': 0.17.19 1057 | '@esbuild/darwin-x64': 0.17.19 1058 | '@esbuild/freebsd-arm64': 0.17.19 1059 | '@esbuild/freebsd-x64': 0.17.19 1060 | '@esbuild/linux-arm': 0.17.19 1061 | '@esbuild/linux-arm64': 0.17.19 1062 | '@esbuild/linux-ia32': 0.17.19 1063 | '@esbuild/linux-loong64': 0.17.19 1064 | '@esbuild/linux-mips64el': 0.17.19 1065 | '@esbuild/linux-ppc64': 0.17.19 1066 | '@esbuild/linux-riscv64': 0.17.19 1067 | '@esbuild/linux-s390x': 0.17.19 1068 | '@esbuild/linux-x64': 0.17.19 1069 | '@esbuild/netbsd-x64': 0.17.19 1070 | '@esbuild/openbsd-x64': 0.17.19 1071 | '@esbuild/sunos-x64': 0.17.19 1072 | '@esbuild/win32-arm64': 0.17.19 1073 | '@esbuild/win32-ia32': 0.17.19 1074 | '@esbuild/win32-x64': 0.17.19 1075 | dev: true 1076 | 1077 | /escape-html/1.0.3: 1078 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} 1079 | dev: false 1080 | 1081 | /event-emitter/0.3.5: 1082 | resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} 1083 | dependencies: 1084 | d: 1.0.1 1085 | es5-ext: 0.10.62 1086 | dev: true 1087 | 1088 | /event-target-shim/5.0.1: 1089 | resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} 1090 | engines: {node: '>=6'} 1091 | dev: false 1092 | 1093 | /events/3.3.0: 1094 | resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} 1095 | engines: {node: '>=0.8.x'} 1096 | dev: false 1097 | 1098 | /ext/1.7.0: 1099 | resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} 1100 | dependencies: 1101 | type: 2.7.2 1102 | dev: true 1103 | 1104 | /fast-content-type-parse/1.0.0: 1105 | resolution: {integrity: sha512-Xbc4XcysUXcsP5aHUU7Nq3OwvHq97C+WnbkeIefpeYLX+ryzFJlU6OStFJhs6Ol0LkUGpcK+wL0JwfM+FCU5IA==} 1106 | dev: false 1107 | 1108 | /fast-copy/3.0.1: 1109 | resolution: {integrity: sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA==} 1110 | dev: false 1111 | 1112 | /fast-decode-uri-component/1.0.1: 1113 | resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} 1114 | dev: false 1115 | 1116 | /fast-deep-equal/3.1.3: 1117 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1118 | dev: false 1119 | 1120 | /fast-json-stringify/5.7.0: 1121 | resolution: {integrity: sha512-sBVPTgnAZseLu1Qgj6lUbQ0HfjFhZWXAmpZ5AaSGkyLh5gAXBga/uPJjQPHpDFjC9adWIpdOcCLSDTgrZ7snoQ==} 1122 | dependencies: 1123 | '@fastify/deepmerge': 1.3.0 1124 | ajv: 8.12.0 1125 | ajv-formats: 2.1.1 1126 | fast-deep-equal: 3.1.3 1127 | fast-uri: 2.2.0 1128 | rfdc: 1.3.0 1129 | dev: false 1130 | 1131 | /fast-querystring/1.1.1: 1132 | resolution: {integrity: sha512-qR2r+e3HvhEFmpdHMv//U8FnFlnYjaC6QKDuaXALDkw2kvHO8WDjxH+f/rHGR4Me4pnk8p9JAkRNTjYHAKRn2Q==} 1133 | dependencies: 1134 | fast-decode-uri-component: 1.0.1 1135 | dev: false 1136 | 1137 | /fast-redact/3.2.0: 1138 | resolution: {integrity: sha512-zaTadChr+NekyzallAMXATXLOR8MNx3zqpZ0MUF2aGf4EathnG0f32VLODNlY8IuGY3HoRO2L6/6fSzNsLaHIw==} 1139 | engines: {node: '>=6'} 1140 | dev: false 1141 | 1142 | /fast-safe-stringify/2.1.1: 1143 | resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} 1144 | dev: false 1145 | 1146 | /fast-uri/2.2.0: 1147 | resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==} 1148 | dev: false 1149 | 1150 | /fastify-guard/2.0.0: 1151 | resolution: {integrity: sha512-1NGzfCcjnD2oEs0cWJQKpldlzUQvVWbcIqjYL2Zsj5URENcn95shqLyZHHIAkrYs8R/yTevnRKFT2/etTiQE+g==} 1152 | engines: {node: '>=14.0.0'} 1153 | dependencies: 1154 | fastify-plugin: 3.0.1 1155 | http-errors: 2.0.0 1156 | lodash.get: 4.4.2 1157 | dev: false 1158 | 1159 | /fastify-plugin/3.0.1: 1160 | resolution: {integrity: sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==} 1161 | dev: false 1162 | 1163 | /fastify-plugin/4.5.0: 1164 | resolution: {integrity: sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg==} 1165 | dev: false 1166 | 1167 | /fastify-zod/1.3.2_fastify@4.17.0: 1168 | resolution: {integrity: sha512-Gwug3n9/F8kmT9+eUVrnQfqsXkhEf6QGQpyKWMhs1Wg3m2mhomBOHUrikSMyh2LpAVRxUYg6Hk/M3IkEuOnDZw==} 1169 | peerDependencies: 1170 | fastify: ^4.15.0 1171 | dependencies: 1172 | '@fastify/swagger': 8.4.0 1173 | '@fastify/swagger-ui': 1.8.1 1174 | '@types/js-yaml': 4.0.5 1175 | change-case: 4.1.2 1176 | fast-deep-equal: 3.1.3 1177 | fastify: 4.17.0 1178 | js-yaml: 4.1.0 1179 | tslib: 2.5.0 1180 | zod: 3.21.4 1181 | zod-to-json-schema: 3.21.1_zod@3.21.4 1182 | transitivePeerDependencies: 1183 | - supports-color 1184 | dev: false 1185 | 1186 | /fastify/4.17.0: 1187 | resolution: {integrity: sha512-tzuY1tgWJo2Y6qEKwmLhFvACUmr68Io2pqP/sDKU71KRM6A6R3DrCDqLGqANbeLZcKUfdfY58ut35CGqemcTgg==} 1188 | dependencies: 1189 | '@fastify/ajv-compiler': 3.5.0 1190 | '@fastify/error': 3.2.0 1191 | '@fastify/fast-json-stringify-compiler': 4.3.0 1192 | abstract-logging: 2.0.1 1193 | avvio: 8.2.1 1194 | fast-content-type-parse: 1.0.0 1195 | fast-json-stringify: 5.7.0 1196 | find-my-way: 7.6.2 1197 | light-my-request: 5.9.1 1198 | pino: 8.14.1 1199 | process-warning: 2.2.0 1200 | proxy-addr: 2.0.7 1201 | rfdc: 1.3.0 1202 | secure-json-parse: 2.7.0 1203 | semver: 7.5.1 1204 | tiny-lru: 11.0.1 1205 | transitivePeerDependencies: 1206 | - supports-color 1207 | dev: false 1208 | 1209 | /fastq/1.15.0: 1210 | resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} 1211 | dependencies: 1212 | reusify: 1.0.4 1213 | dev: false 1214 | 1215 | /find-my-way/7.6.2: 1216 | resolution: {integrity: sha512-0OjHn1b1nCX3eVbm9ByeEHiscPYiHLfhei1wOUU9qffQkk98wE0Lo8VrVYfSGMgnSnDh86DxedduAnBf4nwUEw==} 1217 | engines: {node: '>=14'} 1218 | dependencies: 1219 | fast-deep-equal: 3.1.3 1220 | fast-querystring: 1.1.1 1221 | safe-regex2: 2.0.0 1222 | dev: false 1223 | 1224 | /forwarded/0.2.0: 1225 | resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} 1226 | engines: {node: '>= 0.6'} 1227 | dev: false 1228 | 1229 | /fs-minipass/2.1.0: 1230 | resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} 1231 | engines: {node: '>= 8'} 1232 | dependencies: 1233 | minipass: 3.3.6 1234 | dev: false 1235 | 1236 | /fs.realpath/1.0.0: 1237 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1238 | 1239 | /fsevents/2.3.2: 1240 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 1241 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1242 | os: [darwin] 1243 | requiresBuild: true 1244 | dev: true 1245 | optional: true 1246 | 1247 | /gauge/3.0.2: 1248 | resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} 1249 | engines: {node: '>=10'} 1250 | dependencies: 1251 | aproba: 2.0.0 1252 | color-support: 1.1.3 1253 | console-control-strings: 1.1.0 1254 | has-unicode: 2.0.1 1255 | object-assign: 4.1.1 1256 | signal-exit: 3.0.7 1257 | string-width: 4.2.3 1258 | strip-ansi: 6.0.1 1259 | wide-align: 1.1.5 1260 | dev: false 1261 | 1262 | /get-tsconfig/4.5.0: 1263 | resolution: {integrity: sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==} 1264 | dev: true 1265 | 1266 | /glob/7.2.3: 1267 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1268 | dependencies: 1269 | fs.realpath: 1.0.0 1270 | inflight: 1.0.6 1271 | inherits: 2.0.4 1272 | minimatch: 3.1.2 1273 | once: 1.4.0 1274 | path-is-absolute: 1.0.1 1275 | dev: false 1276 | 1277 | /glob/8.1.0: 1278 | resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} 1279 | engines: {node: '>=12'} 1280 | dependencies: 1281 | fs.realpath: 1.0.0 1282 | inflight: 1.0.6 1283 | inherits: 2.0.4 1284 | minimatch: 5.1.6 1285 | once: 1.4.0 1286 | 1287 | /hanji/0.0.5: 1288 | resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==} 1289 | dependencies: 1290 | lodash.throttle: 4.1.1 1291 | sisteransi: 1.0.5 1292 | dev: true 1293 | 1294 | /has-unicode/2.0.1: 1295 | resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} 1296 | dev: false 1297 | 1298 | /header-case/2.0.4: 1299 | resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} 1300 | dependencies: 1301 | capital-case: 1.0.4 1302 | tslib: 2.5.0 1303 | dev: false 1304 | 1305 | /heap/0.2.7: 1306 | resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} 1307 | dev: true 1308 | 1309 | /help-me/4.2.0: 1310 | resolution: {integrity: sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA==} 1311 | dependencies: 1312 | glob: 8.1.0 1313 | readable-stream: 3.6.2 1314 | dev: false 1315 | 1316 | /http-errors/2.0.0: 1317 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 1318 | engines: {node: '>= 0.8'} 1319 | dependencies: 1320 | depd: 2.0.0 1321 | inherits: 2.0.4 1322 | setprototypeof: 1.2.0 1323 | statuses: 2.0.1 1324 | toidentifier: 1.0.1 1325 | dev: false 1326 | 1327 | /https-proxy-agent/5.0.1: 1328 | resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} 1329 | engines: {node: '>= 6'} 1330 | dependencies: 1331 | agent-base: 6.0.2 1332 | debug: 4.3.4 1333 | transitivePeerDependencies: 1334 | - supports-color 1335 | dev: false 1336 | 1337 | /ieee754/1.2.1: 1338 | resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} 1339 | dev: false 1340 | 1341 | /inflight/1.0.6: 1342 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1343 | dependencies: 1344 | once: 1.4.0 1345 | wrappy: 1.0.2 1346 | 1347 | /inherits/2.0.4: 1348 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1349 | 1350 | /ipaddr.js/1.9.1: 1351 | resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} 1352 | engines: {node: '>= 0.10'} 1353 | dev: false 1354 | 1355 | /is-fullwidth-code-point/3.0.0: 1356 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1357 | engines: {node: '>=8'} 1358 | dev: false 1359 | 1360 | /is-promise/2.2.2: 1361 | resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} 1362 | dev: true 1363 | 1364 | /joycon/3.1.1: 1365 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 1366 | engines: {node: '>=10'} 1367 | dev: false 1368 | 1369 | /js-yaml/4.1.0: 1370 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1371 | hasBin: true 1372 | dependencies: 1373 | argparse: 2.0.1 1374 | dev: false 1375 | 1376 | /json-diff/0.9.0: 1377 | resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==} 1378 | hasBin: true 1379 | dependencies: 1380 | cli-color: 2.0.3 1381 | difflib: 0.2.4 1382 | dreamopt: 0.8.0 1383 | dev: true 1384 | 1385 | /json-schema-resolver/2.0.0: 1386 | resolution: {integrity: sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg==} 1387 | engines: {node: '>=10'} 1388 | dependencies: 1389 | debug: 4.3.4 1390 | rfdc: 1.3.0 1391 | uri-js: 4.4.1 1392 | transitivePeerDependencies: 1393 | - supports-color 1394 | dev: false 1395 | 1396 | /json-schema-traverse/1.0.0: 1397 | resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 1398 | dev: false 1399 | 1400 | /jsonwebtoken/9.0.0: 1401 | resolution: {integrity: sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==} 1402 | engines: {node: '>=12', npm: '>=6'} 1403 | dependencies: 1404 | jws: 3.2.2 1405 | lodash: 4.17.21 1406 | ms: 2.1.3 1407 | semver: 7.5.1 1408 | dev: false 1409 | 1410 | /jwa/1.4.1: 1411 | resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} 1412 | dependencies: 1413 | buffer-equal-constant-time: 1.0.1 1414 | ecdsa-sig-formatter: 1.0.11 1415 | safe-buffer: 5.2.1 1416 | dev: false 1417 | 1418 | /jws/3.2.2: 1419 | resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} 1420 | dependencies: 1421 | jwa: 1.4.1 1422 | safe-buffer: 5.2.1 1423 | dev: false 1424 | 1425 | /light-my-request/5.9.1: 1426 | resolution: {integrity: sha512-UT7pUk8jNCR1wR7w3iWfIjx32DiB2f3hFdQSOwy3/EPQ3n3VocyipUxcyRZR0ahoev+fky69uA+GejPa9KuHKg==} 1427 | dependencies: 1428 | cookie: 0.5.0 1429 | process-warning: 2.2.0 1430 | set-cookie-parser: 2.6.0 1431 | dev: false 1432 | 1433 | /lodash.get/4.4.2: 1434 | resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} 1435 | dev: false 1436 | 1437 | /lodash.throttle/4.1.1: 1438 | resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} 1439 | dev: true 1440 | 1441 | /lodash/4.17.21: 1442 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 1443 | dev: false 1444 | 1445 | /lower-case/2.0.2: 1446 | resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} 1447 | dependencies: 1448 | tslib: 2.5.0 1449 | dev: false 1450 | 1451 | /lru-cache/6.0.0: 1452 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1453 | engines: {node: '>=10'} 1454 | dependencies: 1455 | yallist: 4.0.0 1456 | dev: false 1457 | 1458 | /lru-queue/0.1.0: 1459 | resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} 1460 | dependencies: 1461 | es5-ext: 0.10.62 1462 | dev: true 1463 | 1464 | /make-dir/3.1.0: 1465 | resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} 1466 | engines: {node: '>=8'} 1467 | dependencies: 1468 | semver: 6.3.0 1469 | dev: false 1470 | 1471 | /memoizee/0.4.15: 1472 | resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} 1473 | dependencies: 1474 | d: 1.0.1 1475 | es5-ext: 0.10.62 1476 | es6-weak-map: 2.0.3 1477 | event-emitter: 0.3.5 1478 | is-promise: 2.2.2 1479 | lru-queue: 0.1.0 1480 | next-tick: 1.1.0 1481 | timers-ext: 0.1.7 1482 | dev: true 1483 | 1484 | /mime/3.0.0: 1485 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 1486 | engines: {node: '>=10.0.0'} 1487 | hasBin: true 1488 | dev: false 1489 | 1490 | /minimatch/3.1.2: 1491 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1492 | dependencies: 1493 | brace-expansion: 1.1.11 1494 | dev: false 1495 | 1496 | /minimatch/5.1.6: 1497 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} 1498 | engines: {node: '>=10'} 1499 | dependencies: 1500 | brace-expansion: 2.0.1 1501 | 1502 | /minimist/1.2.8: 1503 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1504 | dev: false 1505 | 1506 | /minipass/3.3.6: 1507 | resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} 1508 | engines: {node: '>=8'} 1509 | dependencies: 1510 | yallist: 4.0.0 1511 | dev: false 1512 | 1513 | /minipass/5.0.0: 1514 | resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} 1515 | engines: {node: '>=8'} 1516 | dev: false 1517 | 1518 | /minizlib/2.1.2: 1519 | resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} 1520 | engines: {node: '>= 8'} 1521 | dependencies: 1522 | minipass: 3.3.6 1523 | yallist: 4.0.0 1524 | dev: false 1525 | 1526 | /mkdirp/1.0.4: 1527 | resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} 1528 | engines: {node: '>=10'} 1529 | hasBin: true 1530 | dev: false 1531 | 1532 | /ms/2.1.2: 1533 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1534 | 1535 | /ms/2.1.3: 1536 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1537 | dev: false 1538 | 1539 | /next-tick/1.1.0: 1540 | resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} 1541 | dev: true 1542 | 1543 | /no-case/3.0.4: 1544 | resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} 1545 | dependencies: 1546 | lower-case: 2.0.2 1547 | tslib: 2.5.0 1548 | dev: false 1549 | 1550 | /node-addon-api/5.1.0: 1551 | resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} 1552 | dev: false 1553 | 1554 | /node-fetch/2.6.11: 1555 | resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==} 1556 | engines: {node: 4.x || >=6.0.0} 1557 | peerDependencies: 1558 | encoding: ^0.1.0 1559 | peerDependenciesMeta: 1560 | encoding: 1561 | optional: true 1562 | dependencies: 1563 | whatwg-url: 5.0.0 1564 | dev: false 1565 | 1566 | /nopt/5.0.0: 1567 | resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} 1568 | engines: {node: '>=6'} 1569 | hasBin: true 1570 | dependencies: 1571 | abbrev: 1.1.1 1572 | dev: false 1573 | 1574 | /npmlog/5.0.1: 1575 | resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} 1576 | dependencies: 1577 | are-we-there-yet: 2.0.0 1578 | console-control-strings: 1.1.0 1579 | gauge: 3.0.2 1580 | set-blocking: 2.0.0 1581 | dev: false 1582 | 1583 | /object-assign/4.1.1: 1584 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1585 | engines: {node: '>=0.10.0'} 1586 | dev: false 1587 | 1588 | /on-exit-leak-free/2.1.0: 1589 | resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==} 1590 | dev: false 1591 | 1592 | /once/1.4.0: 1593 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1594 | dependencies: 1595 | wrappy: 1.0.2 1596 | 1597 | /openapi-types/12.1.0: 1598 | resolution: {integrity: sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==} 1599 | dev: false 1600 | 1601 | /p-limit/3.1.0: 1602 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1603 | engines: {node: '>=10'} 1604 | dependencies: 1605 | yocto-queue: 0.1.0 1606 | dev: false 1607 | 1608 | /packet-reader/1.0.0: 1609 | resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} 1610 | dev: false 1611 | 1612 | /param-case/3.0.4: 1613 | resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} 1614 | dependencies: 1615 | dot-case: 3.0.4 1616 | tslib: 2.5.0 1617 | dev: false 1618 | 1619 | /pascal-case/3.1.2: 1620 | resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} 1621 | dependencies: 1622 | no-case: 3.0.4 1623 | tslib: 2.5.0 1624 | dev: false 1625 | 1626 | /path-case/3.0.4: 1627 | resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} 1628 | dependencies: 1629 | dot-case: 3.0.4 1630 | tslib: 2.5.0 1631 | dev: false 1632 | 1633 | /path-is-absolute/1.0.1: 1634 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1635 | engines: {node: '>=0.10.0'} 1636 | dev: false 1637 | 1638 | /pg-cloudflare/1.1.0: 1639 | resolution: {integrity: sha512-tGM8/s6frwuAIyRcJ6nWcIvd3+3NmUKIs6OjviIm1HPPFEt5MzQDOTBQyhPWg/m0kCl95M6gA1JaIXtS8KovOA==} 1640 | requiresBuild: true 1641 | dev: false 1642 | optional: true 1643 | 1644 | /pg-connection-string/2.6.0: 1645 | resolution: {integrity: sha512-x14ibktcwlHKoHxx9X3uTVW9zIGR41ZB6QNhHb21OPNdCCO3NaRnpJuwKIQSR4u+Yqjx4HCvy7Hh7VSy1U4dGg==} 1646 | dev: false 1647 | 1648 | /pg-int8/1.0.1: 1649 | resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} 1650 | engines: {node: '>=4.0.0'} 1651 | 1652 | /pg-pool/3.6.0_pg@8.11.0: 1653 | resolution: {integrity: sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==} 1654 | peerDependencies: 1655 | pg: '>=8.0' 1656 | dependencies: 1657 | pg: 8.11.0 1658 | dev: false 1659 | 1660 | /pg-protocol/1.6.0: 1661 | resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} 1662 | 1663 | /pg-types/2.2.0: 1664 | resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} 1665 | engines: {node: '>=4'} 1666 | dependencies: 1667 | pg-int8: 1.0.1 1668 | postgres-array: 2.0.0 1669 | postgres-bytea: 1.0.0 1670 | postgres-date: 1.0.7 1671 | postgres-interval: 1.2.0 1672 | 1673 | /pg/8.11.0: 1674 | resolution: {integrity: sha512-meLUVPn2TWgJyLmy7el3fQQVwft4gU5NGyvV0XbD41iU9Jbg8lCH4zexhIkihDzVHJStlt6r088G6/fWeNjhXA==} 1675 | engines: {node: '>= 8.0.0'} 1676 | peerDependencies: 1677 | pg-native: '>=3.0.1' 1678 | peerDependenciesMeta: 1679 | pg-native: 1680 | optional: true 1681 | dependencies: 1682 | buffer-writer: 2.0.0 1683 | packet-reader: 1.0.0 1684 | pg-connection-string: 2.6.0 1685 | pg-pool: 3.6.0_pg@8.11.0 1686 | pg-protocol: 1.6.0 1687 | pg-types: 2.2.0 1688 | pgpass: 1.0.5 1689 | optionalDependencies: 1690 | pg-cloudflare: 1.1.0 1691 | dev: false 1692 | 1693 | /pgpass/1.0.5: 1694 | resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} 1695 | dependencies: 1696 | split2: 4.2.0 1697 | dev: false 1698 | 1699 | /pino-abstract-transport/1.0.0: 1700 | resolution: {integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==} 1701 | dependencies: 1702 | readable-stream: 4.4.0 1703 | split2: 4.2.0 1704 | dev: false 1705 | 1706 | /pino-pretty/10.0.0: 1707 | resolution: {integrity: sha512-zKFjYXBzLaLTEAN1ayKpHXtL5UeRQC7R3lvhKe7fWs7hIVEjKGG/qIXwQt9HmeUp71ogUd/YcW+LmMwRp4KT6Q==} 1708 | hasBin: true 1709 | dependencies: 1710 | colorette: 2.0.20 1711 | dateformat: 4.6.3 1712 | fast-copy: 3.0.1 1713 | fast-safe-stringify: 2.1.1 1714 | help-me: 4.2.0 1715 | joycon: 3.1.1 1716 | minimist: 1.2.8 1717 | on-exit-leak-free: 2.1.0 1718 | pino-abstract-transport: 1.0.0 1719 | pump: 3.0.0 1720 | readable-stream: 4.4.0 1721 | secure-json-parse: 2.7.0 1722 | sonic-boom: 3.3.0 1723 | strip-json-comments: 3.1.1 1724 | dev: false 1725 | 1726 | /pino-std-serializers/6.2.1: 1727 | resolution: {integrity: sha512-wHuWB+CvSVb2XqXM0W/WOYUkVSPbiJb9S5fNB7TBhd8s892Xq910bRxwHtC4l71hgztObTjXL6ZheZXFjhDrDQ==} 1728 | dev: false 1729 | 1730 | /pino/8.14.1: 1731 | resolution: {integrity: sha512-8LYNv7BKWXSfS+k6oEc6occy5La+q2sPwU3q2ljTX5AZk7v+5kND2o5W794FyRaqha6DJajmkNRsWtPpFyMUdw==} 1732 | hasBin: true 1733 | dependencies: 1734 | atomic-sleep: 1.0.0 1735 | fast-redact: 3.2.0 1736 | on-exit-leak-free: 2.1.0 1737 | pino-abstract-transport: 1.0.0 1738 | pino-std-serializers: 6.2.1 1739 | process-warning: 2.2.0 1740 | quick-format-unescaped: 4.0.4 1741 | real-require: 0.2.0 1742 | safe-stable-stringify: 2.4.3 1743 | sonic-boom: 3.3.0 1744 | thread-stream: 2.3.0 1745 | dev: false 1746 | 1747 | /postgres-array/2.0.0: 1748 | resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} 1749 | engines: {node: '>=4'} 1750 | 1751 | /postgres-bytea/1.0.0: 1752 | resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} 1753 | engines: {node: '>=0.10.0'} 1754 | 1755 | /postgres-date/1.0.7: 1756 | resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} 1757 | engines: {node: '>=0.10.0'} 1758 | 1759 | /postgres-interval/1.2.0: 1760 | resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} 1761 | engines: {node: '>=0.10.0'} 1762 | dependencies: 1763 | xtend: 4.0.2 1764 | 1765 | /process-warning/2.2.0: 1766 | resolution: {integrity: sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==} 1767 | dev: false 1768 | 1769 | /process/0.11.10: 1770 | resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} 1771 | engines: {node: '>= 0.6.0'} 1772 | dev: false 1773 | 1774 | /proxy-addr/2.0.7: 1775 | resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} 1776 | engines: {node: '>= 0.10'} 1777 | dependencies: 1778 | forwarded: 0.2.0 1779 | ipaddr.js: 1.9.1 1780 | dev: false 1781 | 1782 | /pump/3.0.0: 1783 | resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} 1784 | dependencies: 1785 | end-of-stream: 1.4.4 1786 | once: 1.4.0 1787 | dev: false 1788 | 1789 | /punycode/2.3.0: 1790 | resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} 1791 | engines: {node: '>=6'} 1792 | dev: false 1793 | 1794 | /quick-format-unescaped/4.0.4: 1795 | resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} 1796 | dev: false 1797 | 1798 | /readable-stream/3.6.2: 1799 | resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} 1800 | engines: {node: '>= 6'} 1801 | dependencies: 1802 | inherits: 2.0.4 1803 | string_decoder: 1.3.0 1804 | util-deprecate: 1.0.2 1805 | dev: false 1806 | 1807 | /readable-stream/4.4.0: 1808 | resolution: {integrity: sha512-kDMOq0qLtxV9f/SQv522h8cxZBqNZXuXNyjyezmfAAuribMyVXziljpQ/uQhfE1XLg2/TLTW2DsnoE4VAi/krg==} 1809 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1810 | dependencies: 1811 | abort-controller: 3.0.0 1812 | buffer: 6.0.3 1813 | events: 3.3.0 1814 | process: 0.11.10 1815 | dev: false 1816 | 1817 | /real-require/0.2.0: 1818 | resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} 1819 | engines: {node: '>= 12.13.0'} 1820 | dev: false 1821 | 1822 | /require-from-string/2.0.2: 1823 | resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 1824 | engines: {node: '>=0.10.0'} 1825 | dev: false 1826 | 1827 | /ret/0.2.2: 1828 | resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} 1829 | engines: {node: '>=4'} 1830 | dev: false 1831 | 1832 | /reusify/1.0.4: 1833 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1834 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1835 | dev: false 1836 | 1837 | /rfdc/1.3.0: 1838 | resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} 1839 | dev: false 1840 | 1841 | /rimraf/3.0.2: 1842 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1843 | hasBin: true 1844 | dependencies: 1845 | glob: 7.2.3 1846 | dev: false 1847 | 1848 | /safe-buffer/5.2.1: 1849 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 1850 | dev: false 1851 | 1852 | /safe-regex2/2.0.0: 1853 | resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} 1854 | dependencies: 1855 | ret: 0.2.2 1856 | dev: false 1857 | 1858 | /safe-stable-stringify/2.4.3: 1859 | resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} 1860 | engines: {node: '>=10'} 1861 | dev: false 1862 | 1863 | /secure-json-parse/2.7.0: 1864 | resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} 1865 | dev: false 1866 | 1867 | /semver/6.3.0: 1868 | resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} 1869 | hasBin: true 1870 | dev: false 1871 | 1872 | /semver/7.5.1: 1873 | resolution: {integrity: sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==} 1874 | engines: {node: '>=10'} 1875 | hasBin: true 1876 | dependencies: 1877 | lru-cache: 6.0.0 1878 | dev: false 1879 | 1880 | /sentence-case/3.0.4: 1881 | resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} 1882 | dependencies: 1883 | no-case: 3.0.4 1884 | tslib: 2.5.0 1885 | upper-case-first: 2.0.2 1886 | dev: false 1887 | 1888 | /set-blocking/2.0.0: 1889 | resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} 1890 | dev: false 1891 | 1892 | /set-cookie-parser/2.6.0: 1893 | resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} 1894 | dev: false 1895 | 1896 | /setprototypeof/1.2.0: 1897 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} 1898 | dev: false 1899 | 1900 | /signal-exit/3.0.7: 1901 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1902 | dev: false 1903 | 1904 | /sisteransi/1.0.5: 1905 | resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} 1906 | dev: true 1907 | 1908 | /snake-case/3.0.4: 1909 | resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} 1910 | dependencies: 1911 | dot-case: 3.0.4 1912 | tslib: 2.5.0 1913 | dev: false 1914 | 1915 | /sonic-boom/3.3.0: 1916 | resolution: {integrity: sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==} 1917 | dependencies: 1918 | atomic-sleep: 1.0.0 1919 | dev: false 1920 | 1921 | /source-map-support/0.5.21: 1922 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 1923 | dependencies: 1924 | buffer-from: 1.1.2 1925 | source-map: 0.6.1 1926 | dev: true 1927 | 1928 | /source-map/0.6.1: 1929 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1930 | engines: {node: '>=0.10.0'} 1931 | dev: true 1932 | 1933 | /split2/4.2.0: 1934 | resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} 1935 | engines: {node: '>= 10.x'} 1936 | dev: false 1937 | 1938 | /statuses/2.0.1: 1939 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} 1940 | engines: {node: '>= 0.8'} 1941 | dev: false 1942 | 1943 | /string-width/4.2.3: 1944 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1945 | engines: {node: '>=8'} 1946 | dependencies: 1947 | emoji-regex: 8.0.0 1948 | is-fullwidth-code-point: 3.0.0 1949 | strip-ansi: 6.0.1 1950 | dev: false 1951 | 1952 | /string_decoder/1.3.0: 1953 | resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 1954 | dependencies: 1955 | safe-buffer: 5.2.1 1956 | dev: false 1957 | 1958 | /strip-ansi/6.0.1: 1959 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1960 | engines: {node: '>=8'} 1961 | dependencies: 1962 | ansi-regex: 5.0.1 1963 | dev: false 1964 | 1965 | /strip-json-comments/3.1.1: 1966 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1967 | engines: {node: '>=8'} 1968 | dev: false 1969 | 1970 | /tar/6.1.15: 1971 | resolution: {integrity: sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==} 1972 | engines: {node: '>=10'} 1973 | dependencies: 1974 | chownr: 2.0.0 1975 | fs-minipass: 2.1.0 1976 | minipass: 5.0.0 1977 | minizlib: 2.1.2 1978 | mkdirp: 1.0.4 1979 | yallist: 4.0.0 1980 | dev: false 1981 | 1982 | /thread-stream/2.3.0: 1983 | resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==} 1984 | dependencies: 1985 | real-require: 0.2.0 1986 | dev: false 1987 | 1988 | /timers-ext/0.1.7: 1989 | resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==} 1990 | dependencies: 1991 | es5-ext: 0.10.62 1992 | next-tick: 1.1.0 1993 | dev: true 1994 | 1995 | /tiny-lru/11.0.1: 1996 | resolution: {integrity: sha512-iNgFugVuQgBKrqeO/mpiTTgmBsTP0WL6yeuLfLs/Ctf0pI/ixGqIRm8sDCwMcXGe9WWvt2sGXI5mNqZbValmJg==} 1997 | engines: {node: '>=12'} 1998 | dev: false 1999 | 2000 | /toidentifier/1.0.1: 2001 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} 2002 | engines: {node: '>=0.6'} 2003 | dev: false 2004 | 2005 | /tr46/0.0.3: 2006 | resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 2007 | dev: false 2008 | 2009 | /tslib/2.5.0: 2010 | resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} 2011 | dev: false 2012 | 2013 | /tsx/3.12.7: 2014 | resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==} 2015 | hasBin: true 2016 | dependencies: 2017 | '@esbuild-kit/cjs-loader': 2.4.2 2018 | '@esbuild-kit/core-utils': 3.1.0 2019 | '@esbuild-kit/esm-loader': 2.5.5 2020 | optionalDependencies: 2021 | fsevents: 2.3.2 2022 | dev: true 2023 | 2024 | /type/1.2.0: 2025 | resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} 2026 | dev: true 2027 | 2028 | /type/2.7.2: 2029 | resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} 2030 | dev: true 2031 | 2032 | /typescript/5.0.4: 2033 | resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} 2034 | engines: {node: '>=12.20'} 2035 | hasBin: true 2036 | dev: true 2037 | 2038 | /upper-case-first/2.0.2: 2039 | resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} 2040 | dependencies: 2041 | tslib: 2.5.0 2042 | dev: false 2043 | 2044 | /upper-case/2.0.2: 2045 | resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} 2046 | dependencies: 2047 | tslib: 2.5.0 2048 | dev: false 2049 | 2050 | /uri-js/4.4.1: 2051 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 2052 | dependencies: 2053 | punycode: 2.3.0 2054 | dev: false 2055 | 2056 | /util-deprecate/1.0.2: 2057 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 2058 | dev: false 2059 | 2060 | /webidl-conversions/3.0.1: 2061 | resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} 2062 | dev: false 2063 | 2064 | /whatwg-url/5.0.0: 2065 | resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} 2066 | dependencies: 2067 | tr46: 0.0.3 2068 | webidl-conversions: 3.0.1 2069 | dev: false 2070 | 2071 | /wide-align/1.1.5: 2072 | resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} 2073 | dependencies: 2074 | string-width: 4.2.3 2075 | dev: false 2076 | 2077 | /wordwrap/1.0.0: 2078 | resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} 2079 | dev: true 2080 | 2081 | /wrappy/1.0.2: 2082 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 2083 | 2084 | /xtend/4.0.2: 2085 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} 2086 | engines: {node: '>=0.4'} 2087 | 2088 | /yallist/4.0.0: 2089 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 2090 | dev: false 2091 | 2092 | /yaml/2.2.2: 2093 | resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==} 2094 | engines: {node: '>= 14'} 2095 | dev: false 2096 | 2097 | /yocto-queue/0.1.0: 2098 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 2099 | engines: {node: '>=10'} 2100 | dev: false 2101 | 2102 | /zennv/0.1.1: 2103 | resolution: {integrity: sha512-yAszZBjMYY97kuQ7pVQm5FLz/amtOpzyyhaF7+CwdJZ3Kz9f60pLy2LRqygdcWcV3LcxsUcngfWXxk5ZO98XRQ==} 2104 | engines: {node: '>=10'} 2105 | dependencies: 2106 | dotenv: 16.0.3 2107 | zod: 3.21.4 2108 | dev: false 2109 | 2110 | /zod-to-json-schema/3.21.1_zod@3.21.4: 2111 | resolution: {integrity: sha512-y5g0MPxDq+YG/T+cHGPYH4PcBpyCqwK6wxeJ76MR563y0gk/14HKfebq8xHiItY7lkc9GDFygCnkvNDTvAhYAg==} 2112 | peerDependencies: 2113 | zod: ^3.21.4 2114 | dependencies: 2115 | zod: 3.21.4 2116 | 2117 | /zod/3.21.4: 2118 | resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} 2119 | -------------------------------------------------------------------------------- /src/config/env.ts: -------------------------------------------------------------------------------- 1 | import zennv from "zennv"; 2 | import { z } from "zod"; 3 | 4 | export const env = zennv({ 5 | dotenv: true, 6 | schema: z.object({ 7 | PORT: z.number().default(3000), 8 | HOST: z.string().default("0.0.0.0"), 9 | DATABASE_CONNECTION: z.string(), 10 | }), 11 | }); 12 | -------------------------------------------------------------------------------- /src/config/permissions.ts: -------------------------------------------------------------------------------- 1 | export const ALL_PERMISSIONS = [ 2 | // users 3 | "users:roles:write", // Allowed to add a role to a user 4 | "users:roles:delete", // Allowed to remove a role from a user 5 | 6 | // roles 7 | "roles:write", 8 | 9 | // posts 10 | "posts:write", 11 | "posts:read", 12 | "post:delete", 13 | "post:edit-own", 14 | ] as const; 15 | 16 | export const PERMISSIONS = ALL_PERMISSIONS.reduce((acc, permission) => { 17 | acc[permission] = permission; 18 | 19 | return acc; 20 | }, {} as Record<(typeof ALL_PERMISSIONS)[number], (typeof ALL_PERMISSIONS)[number]>); 21 | 22 | export const USER_ROLE_PERMISSIONS = [ 23 | PERMISSIONS["posts:write"], 24 | PERMISSIONS["posts:read"], 25 | ]; 26 | 27 | export const SYSTEM_ROLES = { 28 | SUPER_ADMIN: "SUPER_ADMIN", 29 | APPLICATION_USER: "APPLICATION_USER", 30 | }; 31 | -------------------------------------------------------------------------------- /src/db/index.ts: -------------------------------------------------------------------------------- 1 | import { Pool } from "pg"; 2 | import { drizzle } from "drizzle-orm/node-postgres"; 3 | import { env } from "../config/env"; 4 | 5 | const pool = new Pool({ 6 | connectionString: env.DATABASE_CONNECTION, 7 | ssl: true, 8 | }); 9 | 10 | export const db = drizzle(pool); 11 | -------------------------------------------------------------------------------- /src/db/schema.ts: -------------------------------------------------------------------------------- 1 | import { 2 | pgTable, 3 | primaryKey, 4 | text, 5 | timestamp, 6 | uniqueIndex, 7 | uuid, 8 | varchar, 9 | } from "drizzle-orm/pg-core"; 10 | 11 | export const applications = pgTable("applications", { 12 | id: uuid("id").primaryKey().defaultRandom(), 13 | name: varchar("name", { length: 256 }).notNull(), 14 | createdAt: timestamp("created_at").defaultNow().notNull(), 15 | updatedAt: timestamp("updated_at").defaultNow().notNull(), 16 | }); 17 | 18 | export const users = pgTable( 19 | "users", 20 | { 21 | id: uuid("id").defaultRandom().notNull(), 22 | email: varchar("email", { length: 256 }).notNull(), 23 | name: varchar("name", { length: 256 }).notNull(), 24 | applicationId: uuid("applicationId").references(() => applications.id), 25 | password: varchar("password", { length: 256 }).notNull(), 26 | createdAt: timestamp("created_at").defaultNow().notNull(), 27 | updatedAt: timestamp("updated_at").defaultNow().notNull(), 28 | }, 29 | (users) => { 30 | return { 31 | cpk: primaryKey(users.email, users.applicationId), 32 | idIndex: uniqueIndex("users_id_index").on(users.id), 33 | }; 34 | } 35 | ); 36 | 37 | export const roles = pgTable( 38 | "roles", 39 | { 40 | id: uuid("id").defaultRandom().notNull(), 41 | name: varchar("name", { length: 256 }).notNull(), 42 | applicationId: uuid("applicationId").references(() => applications.id), 43 | permissions: text("permissions").array().$type>(), 44 | createdAt: timestamp("created_at").defaultNow().notNull(), 45 | updatedAt: timestamp("updated_at").defaultNow().notNull(), 46 | }, 47 | (roles) => { 48 | return { 49 | cpk: primaryKey(roles.name, roles.applicationId), 50 | idIndex: uniqueIndex("roles_id_index").on(roles.id), 51 | }; 52 | } 53 | ); 54 | 55 | export const usersToRoles = pgTable( 56 | "usersToRoles", 57 | { 58 | applicationId: uuid("applicationId") 59 | .references(() => applications.id) 60 | .notNull(), 61 | 62 | roleId: uuid("roledId") 63 | .references(() => roles.id) 64 | .notNull(), 65 | 66 | userId: uuid("userId") 67 | .references(() => users.id) 68 | .notNull(), 69 | }, 70 | (usersToRoles) => { 71 | return { 72 | cpk: primaryKey( 73 | usersToRoles.applicationId, 74 | usersToRoles.roleId, 75 | usersToRoles.userId 76 | ), 77 | }; 78 | } 79 | ); 80 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { migrate } from "drizzle-orm/node-postgres/migrator"; 2 | import { env } from "./config/env"; 3 | import { logger } from "./utils/logger"; 4 | import { buildServer } from "./utils/server"; 5 | import { db } from "./db"; 6 | 7 | async function gracefulShutdown({ 8 | app, 9 | }: { 10 | app: Awaited>; 11 | }) { 12 | await app.close(); 13 | } 14 | 15 | async function main() { 16 | const app = await buildServer(); 17 | 18 | await app.listen({ 19 | port: env.PORT, 20 | host: env.HOST, 21 | }); 22 | 23 | await migrate(db, { 24 | migrationsFolder: "./migrations", 25 | }); 26 | 27 | const signals = ["SIGINT", "SIGTERM"]; 28 | 29 | logger.debug(env, "using env"); 30 | 31 | for (const signal of signals) { 32 | process.on(signal, () => { 33 | gracefulShutdown({ 34 | app, 35 | }); 36 | }); 37 | } 38 | } 39 | 40 | main(); 41 | -------------------------------------------------------------------------------- /src/modules/applications/applications.controllers.ts: -------------------------------------------------------------------------------- 1 | import { FastifyReply, FastifyRequest } from "fastify"; 2 | import { CreateApplicationBody } from "./applications.schemas"; 3 | import { createApplication, getApplications } from "./applications.services"; 4 | import { createRole } from "../roles/roles.services"; 5 | import { 6 | ALL_PERMISSIONS, 7 | SYSTEM_ROLES, 8 | USER_ROLE_PERMISSIONS, 9 | } from "../../config/permissions"; 10 | 11 | export async function createApplicationHandler( 12 | request: FastifyRequest<{ 13 | Body: CreateApplicationBody; 14 | }>, 15 | reply: FastifyReply 16 | ) { 17 | const { name } = request.body; 18 | 19 | const application = await createApplication({ 20 | name, 21 | }); 22 | 23 | const superAdminRolePromise = createRole({ 24 | applicationId: application.id, 25 | name: SYSTEM_ROLES.SUPER_ADMIN, 26 | permissions: ALL_PERMISSIONS as unknown as Array, 27 | }); 28 | 29 | const applicationUserRolePromise = createRole({ 30 | applicationId: application.id, 31 | name: SYSTEM_ROLES.APPLICATION_USER, 32 | permissions: USER_ROLE_PERMISSIONS, 33 | }); 34 | 35 | const [superAdminRole, applicationUserRole] = await Promise.allSettled([ 36 | superAdminRolePromise, 37 | applicationUserRolePromise, 38 | ]); 39 | 40 | if (superAdminRole.status === "rejected") { 41 | throw new Error("Error creating super admin role"); 42 | } 43 | 44 | if (applicationUserRole.status === "rejected") { 45 | throw new Error("Error creating application user role"); 46 | } 47 | 48 | return { 49 | application, 50 | superAdminRole: superAdminRole.value, 51 | applicationUserRole: applicationUserRole.value, 52 | }; 53 | } 54 | 55 | export async function getApplicationshandler() { 56 | return getApplications(); 57 | } 58 | -------------------------------------------------------------------------------- /src/modules/applications/applications.routes.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from "fastify"; 2 | import { 3 | createApplicationHandler, 4 | getApplicationshandler, 5 | } from "./applications.controllers"; 6 | import { createApplicationJsonSchema } from "./applications.schemas"; 7 | 8 | export async function applicationRoutes(app: FastifyInstance) { 9 | app.post( 10 | "/", 11 | { 12 | schema: createApplicationJsonSchema, 13 | }, 14 | createApplicationHandler 15 | ); 16 | 17 | app.get("/", getApplicationshandler); 18 | } 19 | -------------------------------------------------------------------------------- /src/modules/applications/applications.schemas.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import zodToJsonSchema from "zod-to-json-schema"; 3 | 4 | const createApplicationBodySchema = z.object({ 5 | name: z.string({ 6 | required_error: "Name is required", 7 | }), 8 | }); 9 | 10 | export type CreateApplicationBody = z.infer; 11 | 12 | export const createApplicationJsonSchema = { 13 | body: zodToJsonSchema( 14 | createApplicationBodySchema, 15 | "createApplicationBodySchema" 16 | ), 17 | }; 18 | -------------------------------------------------------------------------------- /src/modules/applications/applications.services.ts: -------------------------------------------------------------------------------- 1 | import { InferModel } from "drizzle-orm"; 2 | import { db } from "../../db"; 3 | import { applications } from "../../db/schema"; 4 | 5 | export async function createApplication( 6 | data: InferModel 7 | ) { 8 | const result = await db.insert(applications).values(data).returning(); 9 | 10 | return result[0]; 11 | } 12 | 13 | export async function getApplications() { 14 | // SELECT * FROM applications; 15 | // SELECT id, name, createdAt from applications; 16 | const result = await db 17 | .select({ 18 | id: applications.id, 19 | name: applications.name, 20 | createdAt: applications.createdAt, 21 | }) 22 | .from(applications); 23 | 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /src/modules/roles/role.controllers.ts: -------------------------------------------------------------------------------- 1 | import { FastifyReply, FastifyRequest } from "fastify"; 2 | import { CreateRoleBody } from "./role.schemas"; 3 | import { createRole } from "./roles.services"; 4 | 5 | export async function createRoleHandler( 6 | request: FastifyRequest<{ 7 | Body: CreateRoleBody; 8 | }>, 9 | reply: FastifyReply 10 | ) { 11 | const user = request.user; 12 | const applicationId = user.applicationId; 13 | const { name, permissions } = request.body; 14 | 15 | const role = await createRole({ 16 | name, 17 | permissions, 18 | applicationId, 19 | }); 20 | 21 | return role; 22 | } 23 | -------------------------------------------------------------------------------- /src/modules/roles/role.routes.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from "fastify"; 2 | import { CreateRoleBody, createRoleJsonSchema } from "./role.schemas"; 3 | import { createRoleHandler } from "./role.controllers"; 4 | import { PERMISSIONS } from "../../config/permissions"; 5 | 6 | export async function roleRoutes(app: FastifyInstance) { 7 | app.post<{ 8 | Body: CreateRoleBody; 9 | }>( 10 | "/", 11 | { 12 | schema: createRoleJsonSchema, 13 | preHandler: [app.guard.scope([PERMISSIONS["roles:write"]])], 14 | }, 15 | createRoleHandler 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/modules/roles/role.schemas.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { ALL_PERMISSIONS } from "../../config/permissions"; 3 | import zodToJsonSchema from "zod-to-json-schema"; 4 | 5 | const createRoleBodySchema = z.object({ 6 | name: z.string(), 7 | permissions: z.array(z.enum(ALL_PERMISSIONS)), 8 | // applicationId: z.string().uuid(), 9 | }); 10 | 11 | export type CreateRoleBody = z.infer; 12 | 13 | export const createRoleJsonSchema = { 14 | body: zodToJsonSchema(createRoleBodySchema, "createRoleBodySchema"), 15 | }; 16 | -------------------------------------------------------------------------------- /src/modules/roles/roles.services.ts: -------------------------------------------------------------------------------- 1 | import { InferModel, and, eq } from "drizzle-orm"; 2 | import { db } from "../../db"; 3 | import { roles } from "../../db/schema"; 4 | 5 | export async function createRole(data: InferModel) { 6 | const result = await db.insert(roles).values(data).returning(); 7 | 8 | return result[0]; 9 | } 10 | 11 | export async function getRoleByName({ 12 | name, 13 | applicationId, 14 | }: { 15 | name: string; 16 | applicationId: string; 17 | }) { 18 | const result = await db 19 | // SELECT * 20 | .select() 21 | // FROM roles 22 | .from(roles) 23 | // WHERE name = ? AND applicationId ? 24 | .where(and(eq(roles.name, name), eq(roles.applicationId, applicationId))) 25 | .limit(1); 26 | 27 | return result[0]; 28 | } 29 | -------------------------------------------------------------------------------- /src/modules/users/users.controllers.ts: -------------------------------------------------------------------------------- 1 | import { FastifyReply, FastifyRequest } from "fastify"; 2 | import { 3 | AssignRoleToUserBody, 4 | CreateUserBody, 5 | LoginBody, 6 | } from "./users.schemas"; 7 | import { SYSTEM_ROLES } from "../../config/permissions"; 8 | import { getRoleByName } from "../roles/roles.services"; 9 | import { 10 | assignRoleTouser, 11 | createUser, 12 | getUserByEmail, 13 | getUsersByApplication, 14 | } from "./users.services"; 15 | import jwt from "jsonwebtoken"; 16 | import { P } from "pino"; 17 | import { logger } from "../../utils/logger"; 18 | 19 | export async function createUserHandler( 20 | request: FastifyRequest<{ 21 | Body: CreateUserBody; 22 | }>, 23 | reply: FastifyReply 24 | ) { 25 | const { initialUser, ...data } = request.body; 26 | 27 | const roleName = initialUser 28 | ? SYSTEM_ROLES.SUPER_ADMIN 29 | : SYSTEM_ROLES.APPLICATION_USER; 30 | 31 | if (roleName === SYSTEM_ROLES.SUPER_ADMIN) { 32 | const appUsers = await getUsersByApplication(data.applicationId); 33 | 34 | if (appUsers.length > 0) { 35 | return reply.code(400).send({ 36 | message: "Application already has super admin user", 37 | extensions: { 38 | code: "APPLICATION_ALRADY_SUPER_USER", 39 | applicationId: data.applicationId, 40 | }, 41 | }); 42 | } 43 | } 44 | 45 | const role = await getRoleByName({ 46 | name: roleName, 47 | applicationId: data.applicationId, 48 | }); 49 | 50 | if (!role) { 51 | return reply.code(404).send({ 52 | message: "Role not found", 53 | }); 54 | } 55 | 56 | try { 57 | const user = await createUser(data); 58 | 59 | // assign a role to the user 60 | 61 | await assignRoleTouser({ 62 | userId: user.id, 63 | roleId: role.id, 64 | applicationId: data.applicationId, 65 | }); 66 | 67 | return user; 68 | } catch (e) {} 69 | } 70 | 71 | export async function loginHandler( 72 | request: FastifyRequest<{ 73 | Body: LoginBody; 74 | }>, 75 | reply: FastifyReply 76 | ) { 77 | const { applicationId, email, password } = request.body; 78 | 79 | const user = await getUserByEmail({ 80 | applicationId, 81 | email, 82 | }); 83 | 84 | if (!user) { 85 | return reply.code(400).send({ 86 | message: "Invalid email or password", 87 | }); 88 | } 89 | 90 | const token = jwt.sign( 91 | { 92 | id: user.id, 93 | email, 94 | applicationId, 95 | scopes: user.permissions, 96 | }, 97 | "secret" 98 | ); // change this secret or signing method, or get fired 99 | 100 | return { token }; 101 | } 102 | 103 | export async function assignRoleTouserHandler( 104 | request: FastifyRequest<{ 105 | Body: AssignRoleToUserBody; 106 | }>, 107 | reply: FastifyReply 108 | ) { 109 | const applicationId = request.user.applicationId; 110 | const { userId, roleId } = request.body; 111 | 112 | try { 113 | const result = await assignRoleTouser({ 114 | userId, 115 | applicationId, 116 | roleId, 117 | }); 118 | 119 | return result; 120 | } catch (e) { 121 | logger.error(e, `error assigning role to user`); 122 | return reply.code(400).send({ 123 | message: "could not assign role to user", 124 | }); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/modules/users/users.routes.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from "fastify"; 2 | import { 3 | assignRoleTouserHandler, 4 | createUserHandler, 5 | loginHandler, 6 | } from "./users.controllers"; 7 | import { 8 | AssignRoleToUserBody, 9 | assignRoleTouserJsonSchema, 10 | createUserJsonSchema, 11 | loginJsonSchema, 12 | } from "./users.schemas"; 13 | import { PERMISSIONS } from "../../config/permissions"; 14 | 15 | export async function usersRoutes(app: FastifyInstance) { 16 | app.post( 17 | "/", 18 | { 19 | schema: createUserJsonSchema, 20 | }, 21 | createUserHandler 22 | ); 23 | 24 | app.post( 25 | "/login", 26 | { 27 | schema: loginJsonSchema, 28 | }, 29 | loginHandler 30 | ); 31 | 32 | app.post<{ 33 | Body: AssignRoleToUserBody; 34 | }>( 35 | "/roles", 36 | { 37 | schema: assignRoleTouserJsonSchema, 38 | preHandler: [app.guard.scope(PERMISSIONS["users:roles:write"])], 39 | }, 40 | assignRoleTouserHandler 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/modules/users/users.schemas.ts: -------------------------------------------------------------------------------- 1 | import { S } from "drizzle-orm/column.d-8b137277"; 2 | import { z } from "zod"; 3 | import zodToJsonSchema from "zod-to-json-schema"; 4 | 5 | // Create user 6 | const createUserBodySchema = z.object({ 7 | email: z.string().email(), 8 | name: z.string(), 9 | applicationId: z.string().uuid(), 10 | password: z.string().min(6), 11 | initialUser: z.boolean().optional(), 12 | }); 13 | 14 | export type CreateUserBody = z.infer; 15 | 16 | export const createUserJsonSchema = { 17 | body: zodToJsonSchema(createUserBodySchema, "createUserBodySchema"), 18 | }; 19 | 20 | // Login 21 | const loginSchema = z.object({ 22 | email: z.string().email(), 23 | password: z.string(), 24 | applicationId: z.string(), 25 | }); 26 | 27 | export type LoginBody = z.infer; 28 | 29 | export const loginJsonSchema = { 30 | body: zodToJsonSchema(loginSchema, "loginSchema"), 31 | }; 32 | 33 | // Assign role to user 34 | const assignRoleToUserBody = z.object({ 35 | userId: z.string().uuid(), 36 | roleId: z.string().uuid(), 37 | // applicationId: z.string().uuid(), 38 | }); 39 | 40 | export type AssignRoleToUserBody = z.infer; 41 | 42 | export const assignRoleTouserJsonSchema = { 43 | body: zodToJsonSchema(assignRoleToUserBody, "assignRoleToUserBody"), 44 | }; 45 | -------------------------------------------------------------------------------- /src/modules/users/users.services.ts: -------------------------------------------------------------------------------- 1 | import { InferModel, and, eq } from "drizzle-orm"; 2 | import argon2 from "argon2"; 3 | import { applications, roles, users } from "../../db/schema"; 4 | import { db } from "../../db"; 5 | import { usersToRoles } from "../../db/schema"; 6 | import { PgJsonBuilder } from "drizzle-orm/pg-core"; 7 | 8 | export async function createUser(data: InferModel) { 9 | const hashedPassword = await argon2.hash(data.password); 10 | 11 | const result = await db 12 | .insert(users) 13 | .values({ 14 | ...data, 15 | password: hashedPassword, 16 | }) 17 | .returning({ 18 | id: users.id, 19 | email: users.email, 20 | name: users.name, 21 | applicationId: applications.id, 22 | }); 23 | 24 | return result[0]; 25 | } 26 | 27 | export async function getUsersByApplication(applicationId: string) { 28 | const result = await db 29 | .select() 30 | .from(users) 31 | .where(eq(users.applicationId, applicationId)); 32 | 33 | return result; 34 | } 35 | 36 | export async function assignRoleTouser( 37 | data: InferModel 38 | ) { 39 | const result = await db.insert(usersToRoles).values(data).returning(); 40 | 41 | return result[0]; 42 | } 43 | 44 | export async function getUserByEmail({ 45 | email, 46 | applicationId, 47 | }: { 48 | email: string; 49 | applicationId: string; 50 | }) { 51 | const result = await db 52 | .select({ 53 | id: users.id, 54 | email: users.email, 55 | name: users.name, 56 | applicationId: users.applicationId, 57 | roleId: roles.id, 58 | password: users.password, 59 | permissions: roles.permissions, 60 | }) 61 | .from(users) 62 | .where(and(eq(users.email, email), eq(users.applicationId, applicationId))) 63 | // LEFT JOIN 64 | // FROM usersToRoles 65 | // ON usersToRoles.userId = users.id 66 | // AND usersToRoles.applicationId = users.application 67 | .leftJoin( 68 | usersToRoles, 69 | and( 70 | eq(usersToRoles.userId, users.id), 71 | eq(usersToRoles.applicationId, users.applicationId) 72 | ) 73 | ) 74 | // LEFT JOIN 75 | // FROM roles 76 | // ON roles.id = usersToRoles.roleId 77 | .leftJoin(roles, eq(roles.id, usersToRoles.roleId)); 78 | 79 | if (!result.length) { 80 | return null; 81 | } 82 | 83 | const user = result.reduce((acc, curr) => { 84 | if (!acc.id) { 85 | return { 86 | ...curr, 87 | permissions: new Set(curr.permissions), 88 | }; 89 | } 90 | 91 | if (!curr.permissions) { 92 | return acc; 93 | } 94 | 95 | for (const permission of curr.permissions) { 96 | acc.permissions.add(permission); 97 | } 98 | 99 | return acc; 100 | }, {} as Omit<(typeof result)[number], "permissions"> & { permissions: Set }); 101 | 102 | return { 103 | ...user, 104 | permissions: Array.from(user.permissions), 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import pino from "pino"; 2 | 3 | export const logger = pino({ 4 | redact: ["DATABASE_CONNECTION"], 5 | level: "debug", 6 | transport: { 7 | target: "pino-pretty", 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /src/utils/server.ts: -------------------------------------------------------------------------------- 1 | import fastify from "fastify"; 2 | import guard from "fastify-guard"; 3 | import { logger } from "./logger"; 4 | import { applicationRoutes } from "../modules/applications/applications.routes"; 5 | import { usersRoutes } from "../modules/users/users.routes"; 6 | import { roleRoutes } from "../modules/roles/role.routes"; 7 | import jwt from "jsonwebtoken"; 8 | 9 | type User = { 10 | id: string; 11 | applicationId: string; 12 | scopes: Array; 13 | }; 14 | 15 | declare module "fastify" { 16 | interface FastifyRequest { 17 | user: User; 18 | } 19 | } 20 | 21 | export async function buildServer() { 22 | const app = fastify({ 23 | logger, 24 | }); 25 | 26 | app.decorateRequest("user", null); 27 | 28 | app.addHook("onRequest", async function (request, reply) { 29 | const authHeader = request.headers.authorization; 30 | 31 | if (!authHeader) { 32 | return; 33 | } 34 | 35 | try { 36 | const token = authHeader.replace("Bearer ", ""); 37 | const decoded = jwt.verify(token, "secret") as User; 38 | 39 | console.log("user", decoded); 40 | 41 | request.user = decoded; 42 | } catch (e) {} 43 | }); 44 | 45 | // register plugins 46 | app.register(guard, { 47 | requestProperty: "user", 48 | scopeProperty: "scopes", 49 | errorHandler: (result, request, reply) => { 50 | return reply.send("you can not do that"); 51 | }, 52 | }); 53 | 54 | // register routes 55 | app.register(applicationRoutes, { prefix: "/api/applications" }); 56 | app.register(usersRoutes, { prefix: "/api/users" }); 57 | app.register(roleRoutes, { prefix: "/api/roles" }); 58 | 59 | return app; 60 | } 61 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | --------------------------------------------------------------------------------