Compare commits
9 Commits
4c3688b065
...
dev
Author | SHA1 | Date | |
---|---|---|---|
303ca85e2f | |||
7fc6ca0457 | |||
dd26a3db33 | |||
e2c65425af | |||
4886bc5b1f | |||
f8152c6db8 | |||
3d09199702 | |||
2c2cb819e1 | |||
fc8f26dd0b |
17
.env.example
@ -1,17 +0,0 @@
|
||||
# Since the ".env" file is gitignored, you can use the ".env.example" file to
|
||||
# build a new ".env" file when you clone the repo. Keep this file up-to-date
|
||||
# when you add new variables to `.env`.
|
||||
|
||||
# This file will be committed to version control, so make sure not to have any
|
||||
# secrets in it. If you are cloning this repo, create a copy of this file named
|
||||
# ".env" and populate it with your secrets.
|
||||
|
||||
# When adding additional environment variables, the schema in "/src/env.js"
|
||||
# should be updated accordingly.
|
||||
|
||||
# Drizzle
|
||||
DATABASE_URL="postgresql://postgres:password@localhost:5432/wavelength_server"
|
||||
|
||||
# Example:
|
||||
# SERVERVAR="foo"
|
||||
# NEXT_PUBLIC_CLIENTVAR="bar"
|
0
.eslintrc.cjs
Executable file → Normal file
4
.gitignore
vendored
Executable file → Normal file
@ -1,9 +1,12 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
/public/uploads/*
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
*/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
@ -35,6 +38,7 @@ yarn-error.log*
|
||||
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
|
||||
.env
|
||||
.env*.local
|
||||
*/.env
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
0
drizzle.config.ts
Executable file → Normal file
92
drizzle/0000_warm_edwin_jarvis.sql
Normal file
@ -0,0 +1,92 @@
|
||||
CREATE OR REPLACE FUNCTION notify_new_message()
|
||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify(
|
||||
'new_message',
|
||||
json_build_object(
|
||||
'id', NEW.id,
|
||||
'text', NEW.text,
|
||||
'senderId', NEW.senderId,
|
||||
'receiverId', NEW.receiverId,
|
||||
'createdAt', NEW.createdAt
|
||||
)::text
|
||||
);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER message_insert_trigger
|
||||
AFTER INSERT ON messages
|
||||
FOR EACH ROW EXECUTE FUNCTION notify_new_message();
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_countdown_update()
|
||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify(
|
||||
'countdown_update',
|
||||
json_build_object(
|
||||
'id', NEW.id,
|
||||
'relationshipId', NEW.relationship_id,
|
||||
'title', NEW.title,
|
||||
'date', NEW.date
|
||||
)::text
|
||||
);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER countdown_update_trigger
|
||||
AFTER INSERT OR UPDATE ON countdowns
|
||||
FOR EACH ROW EXECUTE FUNCTION notify_countdown_update();
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_relationship_status_change()
|
||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
|
||||
PERFORM pg_notify(
|
||||
'relationship_status_change',
|
||||
json_build_object(
|
||||
'id', NEW.id,
|
||||
'relationshipId', NEW.id,
|
||||
'status', NEW.is_accepted
|
||||
)::text
|
||||
);
|
||||
ELSIF (TG_OP = 'DELETE') THEN
|
||||
PERFORM pg_notify(
|
||||
'relationship_status_change',
|
||||
json_build_object(
|
||||
'id', OLD.id,
|
||||
'relationshipId', OLD.id,
|
||||
'status', 'deleted'
|
||||
)::text
|
||||
);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER relationship_status_change_trigger
|
||||
AFTER INSERT OR UPDATE OR DELETE ON relationships
|
||||
FOR EACH ROW EXECUTE FUNCTION notify_relationship_status_change();
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_profile_picture_update()
|
||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify(
|
||||
'profile_picture_update',
|
||||
json_build_object(
|
||||
'id', NEW.id,
|
||||
'userId', NEW.id,
|
||||
'pictureUrl', NEW.pfp_url
|
||||
)::text
|
||||
);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER profile_picture_update_trigger
|
||||
AFTER UPDATE OF pfp_url ON users
|
||||
FOR EACH ROW EXECUTE FUNCTION notify_profile_picture_update();
|
15
drizzle/meta/0000_snapshot.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "ba7dd70a-8dd6-41be-b1d2-158ab83ba830",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
13
drizzle/meta/_journal.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1729627211020,
|
||||
"tag": "0000_warm_edwin_jarvis",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
4
next.config.js
Executable file → Normal file
@ -5,6 +5,8 @@
|
||||
await import("./src/env.js");
|
||||
|
||||
/** @type {import("next").NextConfig} */
|
||||
const config = {};
|
||||
const config = {
|
||||
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
8
package.json
Executable file → Normal file
@ -12,24 +12,28 @@
|
||||
"dev": "next dev",
|
||||
"lint": "next lint",
|
||||
"start": "next start",
|
||||
"go": "pnpm dev",
|
||||
"go:prod": "pnpm build && pnpm start"
|
||||
"go": "next dev",
|
||||
"go:prod": "next build && next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@t3-oss/env-nextjs": "^0.10.1",
|
||||
"drizzle-orm": "^0.33.0",
|
||||
"geist": "^1.3.1",
|
||||
"next": "^14.2.15",
|
||||
"pg": "^8.13.0",
|
||||
"postgres": "^3.4.4",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"socket.io": "^4.8.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/eslint": "^8.56.12",
|
||||
"@types/node": "^20.16.13",
|
||||
"@types/pg": "^8.11.10",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/socket.io": "^3.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^8.10.0",
|
||||
"@typescript-eslint/parser": "^8.10.0",
|
||||
"drizzle-kit": "^0.24.2",
|
||||
|
357
pnpm-lock.yaml
generated
Executable file → Normal file
@ -13,13 +13,16 @@ importers:
|
||||
version: 0.10.1(typescript@5.6.3)(zod@3.23.8)
|
||||
drizzle-orm:
|
||||
specifier: ^0.33.0
|
||||
version: 0.33.0(@types/react@18.3.11)(postgres@3.4.4)(react@18.3.1)
|
||||
version: 0.33.0(@types/pg@8.11.10)(@types/react@18.3.11)(pg@8.13.0)(postgres@3.4.4)(react@18.3.1)
|
||||
geist:
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1(next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
next:
|
||||
specifier: ^14.2.15
|
||||
version: 14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
pg:
|
||||
specifier: ^8.13.0
|
||||
version: 8.13.0
|
||||
postgres:
|
||||
specifier: ^3.4.4
|
||||
version: 3.4.4
|
||||
@ -29,6 +32,9 @@ importers:
|
||||
react-dom:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1(react@18.3.1)
|
||||
socket.io:
|
||||
specifier: ^4.8.0
|
||||
version: 4.8.0
|
||||
zod:
|
||||
specifier: ^3.23.8
|
||||
version: 3.23.8
|
||||
@ -39,12 +45,18 @@ importers:
|
||||
'@types/node':
|
||||
specifier: ^20.16.13
|
||||
version: 20.16.13
|
||||
'@types/pg':
|
||||
specifier: ^8.11.10
|
||||
version: 8.11.10
|
||||
'@types/react':
|
||||
specifier: ^18.3.11
|
||||
version: 18.3.11
|
||||
'@types/react-dom':
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1
|
||||
'@types/socket.io':
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^8.10.0
|
||||
version: 8.10.0(@typescript-eslint/parser@8.10.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)
|
||||
@ -505,6 +517,9 @@ packages:
|
||||
'@rushstack/eslint-patch@1.10.4':
|
||||
resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
'@swc/counter@0.1.3':
|
||||
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
|
||||
|
||||
@ -529,6 +544,12 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
'@types/cookie@0.4.1':
|
||||
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
|
||||
|
||||
'@types/cors@2.8.17':
|
||||
resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==}
|
||||
|
||||
'@types/eslint@8.56.12':
|
||||
resolution: {integrity: sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==}
|
||||
|
||||
@ -544,6 +565,9 @@ packages:
|
||||
'@types/node@20.16.13':
|
||||
resolution: {integrity: sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==}
|
||||
|
||||
'@types/pg@8.11.10':
|
||||
resolution: {integrity: sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==}
|
||||
|
||||
'@types/prop-types@15.7.13':
|
||||
resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
|
||||
|
||||
@ -553,6 +577,10 @@ packages:
|
||||
'@types/react@18.3.11':
|
||||
resolution: {integrity: sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==}
|
||||
|
||||
'@types/socket.io@3.0.2':
|
||||
resolution: {integrity: sha512-pu0sN9m5VjCxBZVK8hW37ZcMe8rjn4HHggBN5CbaRTvFwv5jOmuIRZEuddsBPa9Th0ts0SIo3Niukq+95cMBbQ==}
|
||||
deprecated: This is a stub types definition. socket.io provides its own type definitions, so you do not need this installed.
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.10.0':
|
||||
resolution: {integrity: sha512-phuB3hoP7FFKbRXxjl+DRlQDuJqhpOnm5MmtROXyWi3uS/Xg2ZXqiQfcG2BJHiN4QKyzdOJi3NEn/qTnjUlkmQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@ -613,6 +641,10 @@ packages:
|
||||
'@ungap/structured-clone@1.2.0':
|
||||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||
|
||||
accepts@1.3.8:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
acorn-jsx@5.3.2:
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
@ -709,6 +741,10 @@ packages:
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
base64id@2.0.0:
|
||||
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
|
||||
engines: {node: ^4.5.0 || >= 5.9}
|
||||
|
||||
binary-extensions@2.3.0:
|
||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||
engines: {node: '>=8'}
|
||||
@ -770,6 +806,14 @@ packages:
|
||||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
cookie@0.7.2:
|
||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
cors@2.8.5:
|
||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -941,6 +985,14 @@ packages:
|
||||
emoji-regex@9.2.2:
|
||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||
|
||||
engine.io-parser@5.2.3:
|
||||
resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
engine.io@6.6.2:
|
||||
resolution: {integrity: sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==}
|
||||
engines: {node: '>=10.2.0'}
|
||||
|
||||
enhanced-resolve@5.17.1:
|
||||
resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@ -1475,6 +1527,14 @@ packages:
|
||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
mime-db@1.52.0:
|
||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
mime-types@2.1.35:
|
||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
|
||||
@ -1503,6 +1563,10 @@ packages:
|
||||
natural-compare@1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
|
||||
negotiator@0.6.3:
|
||||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
next@14.2.15:
|
||||
resolution: {integrity: sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw==}
|
||||
engines: {node: '>=18.17.0'}
|
||||
@ -1561,6 +1625,9 @@ packages:
|
||||
resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
obuf@1.1.2:
|
||||
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
|
||||
|
||||
once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
|
||||
@ -1602,6 +1669,48 @@ packages:
|
||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
|
||||
pg-cloudflare@1.1.1:
|
||||
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
|
||||
|
||||
pg-connection-string@2.7.0:
|
||||
resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==}
|
||||
|
||||
pg-int8@1.0.1:
|
||||
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
|
||||
pg-numeric@1.0.2:
|
||||
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
pg-pool@3.7.0:
|
||||
resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==}
|
||||
peerDependencies:
|
||||
pg: '>=8.0'
|
||||
|
||||
pg-protocol@1.7.0:
|
||||
resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==}
|
||||
|
||||
pg-types@2.2.0:
|
||||
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
pg-types@4.0.2:
|
||||
resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
pg@8.13.0:
|
||||
resolution: {integrity: sha512-34wkUTh3SxTClfoHB3pQ7bIMvw9dpFU1audQQeZG837fmHfHpr14n/AELVDoOYVDW2h5RDWU78tFjkD+erSBsw==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
pg-native: '>=3.0.1'
|
||||
peerDependenciesMeta:
|
||||
pg-native:
|
||||
optional: true
|
||||
|
||||
pgpass@1.0.5:
|
||||
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
@ -1666,6 +1775,41 @@ packages:
|
||||
resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postgres-array@2.0.0:
|
||||
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postgres-array@3.0.2:
|
||||
resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postgres-bytea@1.0.0:
|
||||
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
postgres-bytea@3.0.0:
|
||||
resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
postgres-date@1.0.7:
|
||||
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
postgres-date@2.1.0:
|
||||
resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postgres-interval@1.2.0:
|
||||
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
postgres-interval@3.0.0:
|
||||
resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postgres-range@1.1.4:
|
||||
resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==}
|
||||
|
||||
postgres@3.4.4:
|
||||
resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==}
|
||||
engines: {node: '>=12'}
|
||||
@ -1842,6 +1986,17 @@ packages:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
socket.io-adapter@2.5.5:
|
||||
resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==}
|
||||
|
||||
socket.io-parser@4.2.4:
|
||||
resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
socket.io@4.8.0:
|
||||
resolution: {integrity: sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==}
|
||||
engines: {node: '>=10.2.0'}
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -1853,6 +2008,10 @@ packages:
|
||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
split2@4.2.0:
|
||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||
engines: {node: '>= 10.x'}
|
||||
|
||||
streamsearch@1.1.0:
|
||||
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@ -2008,6 +2167,10 @@ packages:
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
vary@1.1.2:
|
||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
which-boxed-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||
|
||||
@ -2043,6 +2206,22 @@ packages:
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
ws@8.17.1:
|
||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
xtend@4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
engines: {node: '>=0.4'}
|
||||
|
||||
yaml@2.6.0:
|
||||
resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==}
|
||||
engines: {node: '>= 14'}
|
||||
@ -2321,6 +2500,8 @@ snapshots:
|
||||
|
||||
'@rushstack/eslint-patch@1.10.4': {}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2': {}
|
||||
|
||||
'@swc/counter@0.1.3': {}
|
||||
|
||||
'@swc/helpers@0.5.5':
|
||||
@ -2341,6 +2522,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.6.3
|
||||
|
||||
'@types/cookie@0.4.1': {}
|
||||
|
||||
'@types/cors@2.8.17':
|
||||
dependencies:
|
||||
'@types/node': 20.16.13
|
||||
|
||||
'@types/eslint@8.56.12':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.6
|
||||
@ -2356,6 +2543,12 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.19.8
|
||||
|
||||
'@types/pg@8.11.10':
|
||||
dependencies:
|
||||
'@types/node': 20.16.13
|
||||
pg-protocol: 1.7.0
|
||||
pg-types: 4.0.2
|
||||
|
||||
'@types/prop-types@15.7.13': {}
|
||||
|
||||
'@types/react-dom@18.3.1':
|
||||
@ -2367,6 +2560,14 @@ snapshots:
|
||||
'@types/prop-types': 15.7.13
|
||||
csstype: 3.1.3
|
||||
|
||||
'@types/socket.io@3.0.2':
|
||||
dependencies:
|
||||
socket.io: 4.8.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.10.0(@typescript-eslint/parser@8.10.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.11.1
|
||||
@ -2450,6 +2651,11 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
accepts@1.3.8:
|
||||
dependencies:
|
||||
mime-types: 2.1.35
|
||||
negotiator: 0.6.3
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.13.0):
|
||||
dependencies:
|
||||
acorn: 8.13.0
|
||||
@ -2563,6 +2769,8 @@ snapshots:
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
base64id@2.0.0: {}
|
||||
|
||||
binary-extensions@2.3.0: {}
|
||||
|
||||
brace-expansion@1.1.11:
|
||||
@ -2627,6 +2835,13 @@ snapshots:
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
cookie@0.7.2: {}
|
||||
|
||||
cors@2.8.5:
|
||||
dependencies:
|
||||
object-assign: 4.1.1
|
||||
vary: 1.1.2
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
@ -2700,9 +2915,11 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
drizzle-orm@0.33.0(@types/react@18.3.11)(postgres@3.4.4)(react@18.3.1):
|
||||
drizzle-orm@0.33.0(@types/pg@8.11.10)(@types/react@18.3.11)(pg@8.13.0)(postgres@3.4.4)(react@18.3.1):
|
||||
optionalDependencies:
|
||||
'@types/pg': 8.11.10
|
||||
'@types/react': 18.3.11
|
||||
pg: 8.13.0
|
||||
postgres: 3.4.4
|
||||
react: 18.3.1
|
||||
|
||||
@ -2712,6 +2929,25 @@ snapshots:
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
|
||||
engine.io-parser@5.2.3: {}
|
||||
|
||||
engine.io@6.6.2:
|
||||
dependencies:
|
||||
'@types/cookie': 0.4.1
|
||||
'@types/cors': 2.8.17
|
||||
'@types/node': 20.16.13
|
||||
accepts: 1.3.8
|
||||
base64id: 2.0.0
|
||||
cookie: 0.7.2
|
||||
cors: 2.8.5
|
||||
debug: 4.3.7
|
||||
engine.io-parser: 5.2.3
|
||||
ws: 8.17.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
enhanced-resolve@5.17.1:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@ -3444,6 +3680,12 @@ snapshots:
|
||||
braces: 3.0.3
|
||||
picomatch: 2.3.1
|
||||
|
||||
mime-db@1.52.0: {}
|
||||
|
||||
mime-types@2.1.35:
|
||||
dependencies:
|
||||
mime-db: 1.52.0
|
||||
|
||||
minimatch@3.1.2:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.11
|
||||
@ -3468,6 +3710,8 @@ snapshots:
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
negotiator@0.6.3: {}
|
||||
|
||||
next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@next/env': 14.2.15
|
||||
@ -3535,6 +3779,8 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.0.0
|
||||
|
||||
obuf@1.1.2: {}
|
||||
|
||||
once@1.4.0:
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
@ -3575,6 +3821,53 @@ snapshots:
|
||||
lru-cache: 10.4.3
|
||||
minipass: 7.1.2
|
||||
|
||||
pg-cloudflare@1.1.1:
|
||||
optional: true
|
||||
|
||||
pg-connection-string@2.7.0: {}
|
||||
|
||||
pg-int8@1.0.1: {}
|
||||
|
||||
pg-numeric@1.0.2: {}
|
||||
|
||||
pg-pool@3.7.0(pg@8.13.0):
|
||||
dependencies:
|
||||
pg: 8.13.0
|
||||
|
||||
pg-protocol@1.7.0: {}
|
||||
|
||||
pg-types@2.2.0:
|
||||
dependencies:
|
||||
pg-int8: 1.0.1
|
||||
postgres-array: 2.0.0
|
||||
postgres-bytea: 1.0.0
|
||||
postgres-date: 1.0.7
|
||||
postgres-interval: 1.2.0
|
||||
|
||||
pg-types@4.0.2:
|
||||
dependencies:
|
||||
pg-int8: 1.0.1
|
||||
pg-numeric: 1.0.2
|
||||
postgres-array: 3.0.2
|
||||
postgres-bytea: 3.0.0
|
||||
postgres-date: 2.1.0
|
||||
postgres-interval: 3.0.0
|
||||
postgres-range: 1.1.4
|
||||
|
||||
pg@8.13.0:
|
||||
dependencies:
|
||||
pg-connection-string: 2.7.0
|
||||
pg-pool: 3.7.0(pg@8.13.0)
|
||||
pg-protocol: 1.7.0
|
||||
pg-types: 2.2.0
|
||||
pgpass: 1.0.5
|
||||
optionalDependencies:
|
||||
pg-cloudflare: 1.1.1
|
||||
|
||||
pgpass@1.0.5:
|
||||
dependencies:
|
||||
split2: 4.2.0
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
@ -3628,6 +3921,28 @@ snapshots:
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
postgres-array@2.0.0: {}
|
||||
|
||||
postgres-array@3.0.2: {}
|
||||
|
||||
postgres-bytea@1.0.0: {}
|
||||
|
||||
postgres-bytea@3.0.0:
|
||||
dependencies:
|
||||
obuf: 1.1.2
|
||||
|
||||
postgres-date@1.0.7: {}
|
||||
|
||||
postgres-date@2.1.0: {}
|
||||
|
||||
postgres-interval@1.2.0:
|
||||
dependencies:
|
||||
xtend: 4.0.2
|
||||
|
||||
postgres-interval@3.0.0: {}
|
||||
|
||||
postgres-range@1.1.4: {}
|
||||
|
||||
postgres@3.4.4: {}
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
@ -3763,6 +4078,36 @@ snapshots:
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
socket.io-adapter@2.5.5:
|
||||
dependencies:
|
||||
debug: 4.3.7
|
||||
ws: 8.17.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
socket.io-parser@4.2.4:
|
||||
dependencies:
|
||||
'@socket.io/component-emitter': 3.1.2
|
||||
debug: 4.3.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
socket.io@4.8.0:
|
||||
dependencies:
|
||||
accepts: 1.3.8
|
||||
base64id: 2.0.0
|
||||
cors: 2.8.5
|
||||
debug: 4.3.7
|
||||
engine.io: 6.6.2
|
||||
socket.io-adapter: 2.5.5
|
||||
socket.io-parser: 4.2.4
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
source-map-support@0.5.21:
|
||||
@ -3772,6 +4117,8 @@ snapshots:
|
||||
|
||||
source-map@0.6.1: {}
|
||||
|
||||
split2@4.2.0: {}
|
||||
|
||||
streamsearch@1.1.0: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
@ -3977,6 +4324,8 @@ snapshots:
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vary@1.1.2: {}
|
||||
|
||||
which-boxed-primitive@1.0.2:
|
||||
dependencies:
|
||||
is-bigint: 1.0.4
|
||||
@ -4035,6 +4384,10 @@ snapshots:
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
ws@8.17.1: {}
|
||||
|
||||
xtend@4.0.2: {}
|
||||
|
||||
yaml@2.6.0: {}
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
0
postcss.config.cjs
Executable file → Normal file
0
prettier.config.js
Executable file → Normal file
Before Width: | Height: | Size: 15 KiB |
BIN
public/favicon.png
Normal file
After Width: | Height: | Size: 16 KiB |
0
public/uploads/profile-pictures/2_1729280510919.jpg
Executable file → Normal file
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
BIN
public/uploads/profile-pictures/3_1729898560745.jpg
Normal file
After Width: | Height: | Size: 24 KiB |
0
public/uploads/profile-pictures/madeline.jpg
Executable file → Normal file
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
41
src/app/api/messages/get/route.ts
Normal file
@ -0,0 +1,41 @@
|
||||
'use server';
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { getMessages } from '~/server/functions';
|
||||
import { middleware } from '~/middleware';
|
||||
import type { Message } from '~/server/types';
|
||||
|
||||
export const GET = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const userId = Number.parseInt(url.searchParams.get('userId') ?? '');
|
||||
const limit = Number.parseInt(url.searchParams.get('limit') ?? '');
|
||||
const offset = Number.parseInt(url.searchParams.get('offset') ?? '0');
|
||||
if (!userId || isNaN(userId) || !limit || isNaN(limit) || isNaN(offset)) {
|
||||
console.log('userId: ', userId, 'limit: ', limit, 'offset: ', offset);
|
||||
return NextResponse.json(
|
||||
{ message: 'Missing userId, limit, or offset' }, { status: 400 }
|
||||
);
|
||||
}
|
||||
const messages: Message[] | undefined = await getMessages(userId, limit, offset);
|
||||
if (messages === undefined) {
|
||||
return NextResponse.json(
|
||||
{ message: 'No messages found' }, { status: 404 }
|
||||
);
|
||||
}
|
||||
return NextResponse.json(messages);
|
||||
} catch (error) {
|
||||
console.error('Error getting messages:', error);
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json(
|
||||
{ message: error.message }, { status: 500 }
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ message: 'Unknown error occurred' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
41
src/app/api/messages/send/route.ts
Normal file
@ -0,0 +1,41 @@
|
||||
'use server'
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { sendMessage } from '~/server/functions';
|
||||
import { middleware } from '~/middleware';
|
||||
import type { Message } from '~/server/types';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const body = await request.json() as {
|
||||
message: Message;
|
||||
};
|
||||
const { message } = body;
|
||||
if (!message) {
|
||||
console.log('Message:', message);
|
||||
return NextResponse.json(
|
||||
{ message: 'Missing message' }, { status: 400 }
|
||||
);
|
||||
}
|
||||
const newMessage: Message | null = await sendMessage(message);
|
||||
if (!newMessage) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Error sending message' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
return NextResponse.json(newMessage);
|
||||
} catch (error) {
|
||||
console.error('Error sending message:', error);
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json(
|
||||
{ message: error.message }, { status: 500 }
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ message: 'Unknown error occurred' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
0
src/app/api/relationships/checkRelationshipStatus/route.ts → src/app/api/relationships/checkStatus/route.ts
Executable file → Normal file
37
src/app/api/relationships/countdown/get/route.ts
Normal file
@ -0,0 +1,37 @@
|
||||
'use server';
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { getCountdown } from '~/server/functions';
|
||||
import { middleware } from '~/middleware';
|
||||
import type { Countdown } from '~/server/types';
|
||||
|
||||
export const GET = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const userId = Number.parseInt(url.searchParams.get('userId') ?? '');
|
||||
if (!userId || isNaN(userId))
|
||||
return NextResponse.json(
|
||||
{ message: 'Missing userId' }, { status: 400 }
|
||||
);
|
||||
const countdown: Countdown | null = await getCountdown(userId);
|
||||
if (!countdown) {
|
||||
return NextResponse.json(
|
||||
{ message: 'No countdown found' }, { status: 404 }
|
||||
);
|
||||
}
|
||||
return NextResponse.json(countdown);
|
||||
} catch (error) {
|
||||
console.error('Error getting countdown:', error);
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json(
|
||||
{ message: error.message }, { status: 500 }
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ message: 'Unknown error occurred' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
40
src/app/api/relationships/countdown/set/route.ts
Normal file
@ -0,0 +1,40 @@
|
||||
'use server';
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { setCountdown } from '~/server/functions';
|
||||
import { middleware } from '~/middleware';
|
||||
import type { Countdown } from '~/server/types';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const body = await request.json() as {
|
||||
userId: number;
|
||||
countdown: Countdown;
|
||||
};
|
||||
const { userId, countdown } = body;
|
||||
if (!userId || !countdown || isNaN(userId))
|
||||
return NextResponse.json(
|
||||
{ message: 'Missing userId or countdown' }, { status: 400 }
|
||||
);
|
||||
const newCountdown: Countdown = await setCountdown(userId, countdown);
|
||||
if (!newCountdown) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Error setting countdown' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
return NextResponse.json(newCountdown);
|
||||
} catch (error) {
|
||||
console.error('Error setting countdown:', error);
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json(
|
||||
{ message: error.message }, { status: 500 }
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ message: 'Unknown error occurred' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
15
src/app/api/relationships/createRequest/route.ts
Executable file → Normal file
@ -9,14 +9,17 @@ export const POST = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const userId = Number.parseInt(url.searchParams.get('userId') ?? '');
|
||||
const partnerId = Number.parseInt(url.searchParams.get('partnerId') ?? '');
|
||||
if (!userId || !partnerId || isNaN(userId) || isNaN(partnerId))
|
||||
const body = await request.json() as {
|
||||
userId: number;
|
||||
targetUserId: number;
|
||||
};
|
||||
const { userId, targetUserId } = body;
|
||||
console.log('User ID:', userId, 'Partner ID:', targetUserId);
|
||||
if (!userId || !targetUserId || isNaN(userId) || isNaN(targetUserId))
|
||||
return NextResponse.json(
|
||||
{ message: 'Missing userId or partnerId' }, { status: 400 }
|
||||
{ message: 'Missing userId or targetUserId' }, { status: 400 }
|
||||
);
|
||||
const relationshipData: RelationshipData | null = await createRelationshipRequest(userId, partnerId);
|
||||
const relationshipData: RelationshipData | null = await createRelationshipRequest(userId, targetUserId);
|
||||
if (!relationshipData) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Error creating relationship request' }, { status: 500 }
|
||||
|
11
src/app/api/relationships/updateStatus/route.ts
Executable file → Normal file
@ -9,9 +9,12 @@ export const POST = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const userId = Number.parseInt(url.searchParams.get('userId') ?? '');
|
||||
const status = url.searchParams.get('status');
|
||||
const body = await request.json() as {
|
||||
userId: number;
|
||||
status: string;
|
||||
};
|
||||
const { userId, status } = body;
|
||||
console.log('User ID:', userId, 'Status:', status);
|
||||
if (!userId || !status || isNaN(userId))
|
||||
return NextResponse.json(
|
||||
{ message: 'Missing userId or status' }, { status: 400 }
|
||||
@ -21,7 +24,7 @@ export const POST = async (request: NextRequest) => {
|
||||
await updateRelationshipStatus(userId, theStatus);
|
||||
if (!relationshipData || relationshipData === undefined) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Error updating relationship status' }, { status: 500 }
|
||||
{ message: 'Error updating relationship status.' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
return NextResponse.json(relationshipData);
|
||||
|
0
src/app/api/users/createUser/route.ts
Executable file → Normal file
0
src/app/api/users/getInitialDataByAppleId/route.ts
Executable file → Normal file
0
src/app/api/users/search/route.ts
Executable file → Normal file
0
src/app/api/users/updatePfp/route.ts
Executable file → Normal file
10
src/app/api/users/updatePushToken/route.ts
Executable file → Normal file
@ -1,7 +1,7 @@
|
||||
'use server';
|
||||
import { NextResponse } from 'next/server';
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { updatePushToken } from '~/server/functions';
|
||||
import { addPushToken } from '~/server/functions';
|
||||
import { middleware } from '~/middleware';
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
@ -15,17 +15,17 @@ export const POST = async (request: NextRequest) => {
|
||||
return NextResponse.json(
|
||||
{ message: 'Missing userId or pushToken' }, { status: 400 }
|
||||
);
|
||||
const result = await updatePushToken(userId, pushToken);
|
||||
const result = await addPushToken(userId, pushToken);
|
||||
if (!result) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Error updating push token' }, { status: 500 }
|
||||
{ message: 'Error adding push token' }, { status: 500 }
|
||||
);
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ message: 'Push token updated successfully' }, { status: 200 }
|
||||
{ message: 'Push token added successfully' }, { status: 200 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error updating push token:', error);
|
||||
console.error('Error adding push token:', error);
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json(
|
||||
{ message: error.message }, { status: 500 }
|
||||
|
6
src/app/layout.tsx
Executable file → Normal file
@ -4,9 +4,9 @@ import { GeistSans } from "geist/font/sans";
|
||||
import { type Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create T3 App",
|
||||
description: "Generated by create-t3-app",
|
||||
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
||||
title: "Is Madeline the Cutest?",
|
||||
description: "Answering the easiest question in the world!",
|
||||
icons: [{ rel: "icon", url: "/favicon.png" }],
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
60
src/app/page.tsx
Executable file → Normal file
@ -1,37 +1,35 @@
|
||||
import Link from "next/link";
|
||||
"use client";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const interestingYes = () => {
|
||||
const yesArray = [
|
||||
"Absolutely, yes.",
|
||||
"Without a doubt.",
|
||||
"Of course.",
|
||||
"Definitely.",
|
||||
"Obviously!",
|
||||
"Certainly!",
|
||||
"Positively.",
|
||||
"100%",
|
||||
];
|
||||
return yesArray[Math.floor(Math.random() * yesArray.length)];
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const [currentText, setCurrentText] = useState("");
|
||||
useEffect(() => {
|
||||
setCurrentText(interestingYes() ?? "Absolutely, yes.");
|
||||
}, []);
|
||||
const handleClick = () => {
|
||||
setCurrentText(interestingYes() ?? "Absolutely, yes.");
|
||||
};
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
|
||||
<h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]">
|
||||
Create <span className="text-[hsl(280,100%,70%)]">T3</span> App
|
||||
</h1>
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8">
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/usage/first-steps"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">First Steps →</h3>
|
||||
<div className="text-lg">
|
||||
Just the basics - Everything you need to know to set up your
|
||||
database and authentication.
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/introduction"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">Documentation →</h3>
|
||||
<div className="text-lg">
|
||||
Learn more about Create T3 App, the libraries it uses, and how to
|
||||
deploy it.
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<main className="flex min-h-screen flex-col items-center justify-center
|
||||
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||
<h3 className="text-5xl font-extrabold tracking-tight
|
||||
text-white sm:text-[5rem] text-center" onClick={handleClick}>
|
||||
{currentText}
|
||||
</h3>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
0
src/env.js
Executable file → Normal file
0
src/middleware.ts
Executable file → Normal file
0
src/server/db/index.ts
Executable file → Normal file
18
src/server/db/schema.ts
Executable file → Normal file
@ -1,4 +1,5 @@
|
||||
// https://orm.drizzle.team/docs/sql-schema-declaration
|
||||
import { db } from '~/server/db';
|
||||
import { sql } from "drizzle-orm";
|
||||
import {
|
||||
boolean,
|
||||
@ -22,7 +23,6 @@ export const users = pgTable(
|
||||
email: varchar('email', { length: 100 }).unique().notNull(),
|
||||
fullName: varchar('full_name', { length: 100 }).notNull(),
|
||||
pfpUrl: varchar('pfp_url', { length: 255 }),
|
||||
pushToken: varchar('push_token', { length: 100 }).unique().notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true })
|
||||
.default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
metadata: jsonb('metadata'),
|
||||
@ -34,6 +34,21 @@ export const users = pgTable(
|
||||
})
|
||||
);
|
||||
|
||||
export const pushTokens = pgTable(
|
||||
'push_tokens',
|
||||
{
|
||||
id: serial('id').primaryKey(),
|
||||
userId: integer('user_id').references(() => users.id).notNull(),
|
||||
token: varchar('token', { length: 100 }).unique().notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true })
|
||||
.default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
userIdIndex: index('push_tokens_user_id_idx').on(table.userId),
|
||||
tokenIndex: index('push_tokens_token_idx').on(table.token),
|
||||
})
|
||||
);
|
||||
|
||||
export const relationships = pgTable(
|
||||
'relationships',
|
||||
{
|
||||
@ -161,3 +176,4 @@ export const quickReplyOptions = pgTable(
|
||||
quickReplyIdIndex: index('qr_options_quick_reply_id_idx').on(table.quickReplyId),
|
||||
})
|
||||
);
|
||||
|
||||
|
211
src/server/functions.ts
Executable file → Normal file
@ -1,8 +1,9 @@
|
||||
import 'server-only';
|
||||
import { db } from '~/server/db';
|
||||
import * as schema from '~/server/db/schema';
|
||||
import { eq, and, or, like, not } from 'drizzle-orm';
|
||||
import { User,
|
||||
import { eq, and, or, like, not, desc, sql } from 'drizzle-orm';
|
||||
import type {
|
||||
User,
|
||||
Relationship,
|
||||
UserRelationship,
|
||||
RelationshipData,
|
||||
@ -18,23 +19,70 @@ import { User,
|
||||
export const getUser = async (userId: number) => {
|
||||
try {
|
||||
const users = await db.select().from(schema.users)
|
||||
.where(eq(schema.users.id, userId))
|
||||
return (users.length > 0) ? users[0] as User : null;
|
||||
.where(eq(schema.users.id, userId));
|
||||
|
||||
if (users.length === 0) return null;
|
||||
|
||||
const user = users[0];
|
||||
// Get push tokens for user
|
||||
const tokens = await db.select()
|
||||
.from(schema.pushTokens)
|
||||
.where(eq(schema.pushTokens.userId, userId));
|
||||
|
||||
return {
|
||||
...user,
|
||||
pushTokens: tokens.map(t => t.token)
|
||||
} as User;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const getRelationship = async (userId: number) => {
|
||||
try {
|
||||
const user = await getUser(userId);
|
||||
if (!user) throw new Error("User not found");
|
||||
const userRelationship = await db.select()
|
||||
.from(schema.userRelationships)
|
||||
.where(eq(schema.userRelationships.userId, user.id))
|
||||
.limit(1)
|
||||
.then(results => results[0]);
|
||||
if (!userRelationship) throw new Error('No relationships found for user');
|
||||
const relationship = await db.select()
|
||||
.from(schema.relationships)
|
||||
.where(eq(schema.relationships.id, userRelationship.relationshipId))
|
||||
.limit(1)
|
||||
.then(results => results[0] as Relationship);
|
||||
if (!relationship) throw new Error('Relationship not found');
|
||||
return relationship;
|
||||
} catch (error) {
|
||||
console.error('Error getting relationship:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getInitialDataByAppleId = async (appleId: string) => {
|
||||
try {
|
||||
const users = await db.select().from(schema.users)
|
||||
.where(eq(schema.users.appleId, appleId))
|
||||
.where(eq(schema.users.appleId, appleId));
|
||||
if (users.length === 0) return null;
|
||||
const user = users[0] as User;
|
||||
|
||||
const user = users[0];
|
||||
// Get push tokens for user
|
||||
const tokens = await db.select()
|
||||
.from(schema.pushTokens)
|
||||
.where(eq(schema.pushTokens.userId, user.id));
|
||||
|
||||
const userWithTokens = {
|
||||
...user,
|
||||
pushTokens: tokens.map(t => t.token)
|
||||
};
|
||||
|
||||
// Rest of the function remains the same, but use userWithTokens instead of user
|
||||
const userRelationships = await db.select()
|
||||
.from(schema.userRelationships)
|
||||
.where(eq(schema.userRelationships.userId, user.id))
|
||||
.where(eq(schema.userRelationships.userId, userWithTokens.id));
|
||||
|
||||
let relationshipData: RelationshipData | undefined;
|
||||
let countdown: Countdown | undefined;
|
||||
@ -54,7 +102,7 @@ export const getInitialDataByAppleId = async (appleId: string) => {
|
||||
.where(
|
||||
and(
|
||||
eq(schema.userRelationships.relationshipId, relationship.id),
|
||||
not(eq(schema.userRelationships.userId, user.id))
|
||||
not(eq(schema.userRelationships.userId, userWithTokens.id))
|
||||
)
|
||||
);
|
||||
if (partners.length > 0) {
|
||||
@ -75,7 +123,7 @@ export const getInitialDataByAppleId = async (appleId: string) => {
|
||||
}
|
||||
}
|
||||
const initialData: InitialData = {
|
||||
user,
|
||||
user: userWithTokens,
|
||||
relationshipData,
|
||||
countdown,
|
||||
};
|
||||
@ -91,31 +139,29 @@ export const createUser = async (
|
||||
fullName: string, pushToken: string
|
||||
) => {
|
||||
try {
|
||||
console.log(appleId, email, fullName, pushToken);
|
||||
|
||||
if (!appleId || !email || !fullName || !pushToken) {
|
||||
throw new Error("Error: All required fields must be filled");
|
||||
}
|
||||
// Check if username or email is already taken
|
||||
|
||||
const existingUser = await db.select().from(schema.users)
|
||||
.where(or(eq(schema.users.appleId, appleId), eq(schema.users.email, email)));
|
||||
|
||||
if (existingUser.length > 0) {
|
||||
throw new Error("Username or email is already in use");
|
||||
}
|
||||
console.log('right before we add the user');
|
||||
|
||||
const newUsers: User[] = await db.insert(schema.users).values({
|
||||
appleId, email, fullName, pushToken
|
||||
}).returning() as User[]; // return the newly created user
|
||||
const newUsers = await db.insert(schema.users).values({
|
||||
appleId, email, fullName
|
||||
}).returning();
|
||||
|
||||
const newUser: User | undefined = newUsers[0];
|
||||
const newUser = newUsers[0];
|
||||
|
||||
if (!newUsers.length || !newUsers[0]?.id)
|
||||
throw new Error("Failed to create new user");
|
||||
|
||||
return newUser;
|
||||
await addPushToken(newUser.id, pushToken);
|
||||
|
||||
return newUser;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`Failed to create new user: ${error.message}`);
|
||||
@ -125,25 +171,30 @@ export const createUser = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const updatePushToken = async (userId: number, pushToken: string): Promise<boolean> => {
|
||||
export const addPushToken = async (userId: number, token: string): Promise<boolean> => {
|
||||
try {
|
||||
const result = await db.update(schema.users)
|
||||
.set({ pushToken: pushToken })
|
||||
.where(
|
||||
and(
|
||||
eq(schema.users.id, userId),
|
||||
not(eq(schema.users.pushToken, pushToken))
|
||||
)
|
||||
)
|
||||
.returning({ updatedId: schema.users.id });
|
||||
|
||||
return result.length > 0;
|
||||
await db.insert(schema.pushTokens)
|
||||
.values({ userId, token })
|
||||
.onConflictDoNothing();
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error updating push token:', error);
|
||||
console.error('Error adding push token:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getPushTokens = async (userId: number): Promise<string[]> => {
|
||||
try {
|
||||
const tokens = await db.select()
|
||||
.from(schema.pushTokens)
|
||||
.where(eq(schema.pushTokens.userId, userId));
|
||||
return tokens.map(t => t.token);
|
||||
} catch (error) {
|
||||
console.error('Error getting push tokens:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const getPfpUrl = async (userId: number) => {
|
||||
try {
|
||||
const users = await db.select().from(schema.users)
|
||||
@ -226,6 +277,10 @@ export const updateRelationshipStatus = async (
|
||||
throw new Error('Relationship not found');
|
||||
}
|
||||
const relationship = relationships[0] as Relationship;
|
||||
// Everything above is just getting info
|
||||
if (userId === relationship.requestorId && status === 'accepted') {
|
||||
throw new Error('The requestor cannot accept the relationship they requested.');
|
||||
}
|
||||
if (status === 'accepted') {
|
||||
await db.update(schema.relationships)
|
||||
.set({ isAccepted: true })
|
||||
@ -251,7 +306,9 @@ export const updateRelationshipStatus = async (
|
||||
return relationshipData;
|
||||
} else if (status === 'rejected') {
|
||||
await db.delete(schema.userRelationships)
|
||||
.where(eq(schema.userRelationships.id, userRelationship.id));
|
||||
.where(eq(schema.userRelationships.relationshipId, relationship.id));
|
||||
await db.delete(schema.countdowns)
|
||||
.where(eq(schema.countdowns.relationshipId, relationship.id));
|
||||
await db.delete(schema.relationships)
|
||||
.where(eq(schema.relationships.id, relationship.id));
|
||||
return null;
|
||||
@ -321,3 +378,93 @@ export const createRelationshipRequest = async (userId: number, partnerId: numbe
|
||||
}
|
||||
};
|
||||
|
||||
export const getMessages = async (userId: number, limit: number, offset: number) => {
|
||||
try {
|
||||
const messages = await db.select().from(schema.messages)
|
||||
.where(or(
|
||||
eq(schema.messages.senderId, userId),
|
||||
eq(schema.messages.receiverId, userId)
|
||||
))
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.orderBy(desc(schema.messages.createdAt), desc(schema.messages.id));
|
||||
return messages as Message[];
|
||||
} catch (error) {
|
||||
console.error('Error getting messages:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const sendMessage = async (message: Message) => {
|
||||
try {
|
||||
const [newMessage] = await db.insert(schema.messages).values({
|
||||
senderId: message.senderId,
|
||||
receiverId: message.receiverId,
|
||||
text: message.text,
|
||||
hasLocation: message.hasLocation,
|
||||
hasMedia: message.hasMedia,
|
||||
hasQuickReply: message.hasQuickReply,
|
||||
}).returning();
|
||||
return newMessage as Message;
|
||||
} catch (error) {
|
||||
console.error('Error sending message:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const setCountdown = async (userId: number, countdown: Countdown) => {
|
||||
try {
|
||||
const user = await getUser(userId);
|
||||
if (!user) throw new Error("User not found");
|
||||
const relationship = await getRelationship(userId);
|
||||
if (!relationship) throw new Error("Relationship not found");
|
||||
const existingCountdown: Countdown | null = await getCountdown(userId);
|
||||
|
||||
// Ensure the date is a valid Date object
|
||||
const countdownDate = new Date(countdown.date);
|
||||
if (isNaN(countdownDate.getTime())) {
|
||||
throw new Error("Invalid date provided");
|
||||
}
|
||||
|
||||
let result;
|
||||
if (existingCountdown !== null) {
|
||||
result = await db.update(schema.countdowns)
|
||||
.set({ title: countdown.title, date: countdownDate })
|
||||
.where(eq(schema.countdowns.id, existingCountdown.id))
|
||||
.returning();
|
||||
} else {
|
||||
result = await db.insert(schema.countdowns)
|
||||
.values({
|
||||
relationshipId: relationship.id,
|
||||
title: countdown.title,
|
||||
date: countdownDate,
|
||||
}).returning();
|
||||
}
|
||||
return result[0] as Countdown;
|
||||
} catch (error) {
|
||||
console.error('Error setting countdown:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getCountdown = async (userId: number) => {
|
||||
try {
|
||||
const user = await getUser(userId);
|
||||
if (!user) throw new Error("User not found");
|
||||
const relationship = await getRelationship(userId);
|
||||
if (!relationship) throw new Error("Relationship not found");
|
||||
const countdown = await db.select()
|
||||
.from(schema.countdowns)
|
||||
.where(eq(schema.countdowns.relationshipId, relationship.id))
|
||||
.limit(1)
|
||||
.then(results => results[0] as Countdown);
|
||||
if (!countdown) {
|
||||
console.log('No countdown found');
|
||||
return null;
|
||||
}
|
||||
return countdown;
|
||||
} catch (error) {
|
||||
console.error('Error getting countdown:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
2
src/server/types.ts
Executable file → Normal file
@ -7,9 +7,9 @@ export type User = {
|
||||
email: string;
|
||||
fullName: string;
|
||||
pfpUrl: string | null;
|
||||
pushToken: string;
|
||||
createdAt: Date;
|
||||
metadata?: Record<string, string>;
|
||||
pushTokens?: string[];
|
||||
};
|
||||
// Relationship Table in DB
|
||||
export type Relationship = {
|
||||
|
0
src/styles/globals.css
Executable file → Normal file
0
tailwind.config.ts
Executable file → Normal file
0
tsconfig.json
Executable file → Normal file
102
websocket_server/dist/server.js
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = __importDefault(require("express"));
|
||||
const socket_io_1 = require("socket.io");
|
||||
const http_1 = require("http");
|
||||
const pg_1 = require("pg");
|
||||
const dotenv_1 = __importDefault(require("dotenv"));
|
||||
dotenv_1.default.config();
|
||||
const app = (0, express_1.default)();
|
||||
const httpServer = (0, http_1.createServer)(app);
|
||||
// Create new Socket.IO server
|
||||
const io = new socket_io_1.Server(httpServer);
|
||||
const PORT = process.env.PORT || 3030;
|
||||
const pgClient = new pg_1.Client({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
const handleNotification = (msg) => {
|
||||
var _a;
|
||||
const payload = JSON.parse((_a = msg.payload) !== null && _a !== void 0 ? _a : '{}');
|
||||
switch (msg.channel) {
|
||||
case 'new_message':
|
||||
handleNewMessage(payload);
|
||||
break;
|
||||
case 'countdown_update':
|
||||
handleCountdownUpdate(payload);
|
||||
break;
|
||||
case 'relationship_status_change':
|
||||
handleRelationshipStatusChange(payload);
|
||||
break;
|
||||
case 'profile_picture_update':
|
||||
handleProfilePictureUpdate(payload);
|
||||
break;
|
||||
default:
|
||||
console.log('Unhandled notification:', msg);
|
||||
}
|
||||
};
|
||||
const handleNewMessage = (payload) => {
|
||||
const { receiverId, text, id } = payload;
|
||||
io.to(`user:${receiverId}`).emit('new_message', payload);
|
||||
console.log(`Message sent to room ${receiverId} with text: "${text}"`);
|
||||
};
|
||||
const handleCountdownUpdate = (payload) => {
|
||||
const { relationshipId, countdown } = payload;
|
||||
io.to(`relationship:${relationshipId}`).emit('countdown_update', countdown);
|
||||
console.log(`Countdown update sent to room ${relationshipId}`);
|
||||
};
|
||||
const handleRelationshipStatusChange = (payload) => {
|
||||
const { relationshipId, status } = payload;
|
||||
io.to(`relationship:${relationshipId}`).emit('relationship_status_change', status);
|
||||
console.log(`Relationship status change sent to room ${relationshipId}, status: ${status}`);
|
||||
};
|
||||
const handleProfilePictureUpdate = (payload) => {
|
||||
const { userId, profilePictureUrl } = payload;
|
||||
io.to(`user:${userId}`).emit('profile_picture_update', profilePictureUrl);
|
||||
console.log(`Profile picture update sent to room ${userId}`);
|
||||
};
|
||||
// Connect the PostgreSQL client
|
||||
pgClient.connect()
|
||||
.then(() => {
|
||||
console.log('Connected to PostgreSQL');
|
||||
// Listen for NOTIFY events on the 'new_message' channel
|
||||
pgClient.query('LISTEN new_message');
|
||||
pgClient.query('LISTEN countdown_update');
|
||||
pgClient.query('LISTEN relationship_status_change');
|
||||
pgClient.query('LISTEN profile_picture_update');
|
||||
pgClient.on('notification', handleNotification);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to connect to PostgreSQL:', err);
|
||||
});
|
||||
// Handle WebSocket connections
|
||||
io.on('connection', (socket) => {
|
||||
console.log('WebSocket client connected:', socket.id);
|
||||
socket.on('join', (roomInfo) => {
|
||||
//console.log('Attempting to join room:', roomInfo);
|
||||
if (typeof roomInfo === 'object') {
|
||||
if (roomInfo.userId) {
|
||||
socket.join(`user:${roomInfo.userId}`);
|
||||
console.log(`User ${roomInfo.userId} joined room`);
|
||||
}
|
||||
else if (roomInfo.relationshipId) {
|
||||
socket.join(`relationship:${roomInfo.relationshipId}`);
|
||||
console.log(`Relationship ${roomInfo.relationshipId} joined room`);
|
||||
}
|
||||
}
|
||||
//console.log('Socket object at connection:', socket);
|
||||
});
|
||||
socket.on('error', (error) => {
|
||||
console.error('WebSocket error:', error);
|
||||
});
|
||||
// Handle disconnection of WebSocket clients
|
||||
socket.on('disconnect', () => {
|
||||
console.log('WebSocket client disconnected:', socket.id);
|
||||
});
|
||||
});
|
||||
// Start the WebSocket server
|
||||
httpServer.listen(PORT, () => {
|
||||
console.log(`WebSocket server is running on port ${PORT}`);
|
||||
});
|
1384
websocket_server/package-lock.json
generated
Normal file
32
websocket_server/package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "websocket-server",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "tsc",
|
||||
"start": "node dist/server.js",
|
||||
"dev": "tsc-watch --onSuccess \"node dist/server.js\"",
|
||||
"go": "tsc-watch --onSuccess \"node dist/server.js\""
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.21.1",
|
||||
"pg": "^8.13.0",
|
||||
"socket.io": "^4.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/node": "^22.7.8",
|
||||
"@types/pg": "^8.11.10",
|
||||
"@types/socket.io": "^3.0.2",
|
||||
"tsc-watch": "^6.2.0",
|
||||
"typescript": "^5.6.3"
|
||||
}
|
||||
}
|
1134
websocket_server/pnpm-lock.yaml
generated
Normal file
112
websocket_server/src/server.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import express from 'express';
|
||||
import { Server } from 'socket.io';
|
||||
import { createServer } from 'http';
|
||||
import { Client } from 'pg';
|
||||
import type { Notification } from 'pg';
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
const app = express();
|
||||
const httpServer = createServer(app);
|
||||
|
||||
// Create new Socket.IO server
|
||||
const io = new Server(httpServer);
|
||||
|
||||
const PORT = process.env.PORT ?? 3020;
|
||||
|
||||
const pgClient = new Client({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
|
||||
const handleNotification = (msg: Notification) => {
|
||||
const payload = JSON.parse(msg.payload ?? '{}');
|
||||
switch (msg.channel) {
|
||||
case 'new_message':
|
||||
handleNewMessage(payload);
|
||||
break;
|
||||
case 'countdown_update':
|
||||
handleCountdownUpdate(payload);
|
||||
break;
|
||||
case 'relationship_status_change':
|
||||
handleRelationshipStatusChange(payload);
|
||||
break;
|
||||
case 'profile_picture_update':
|
||||
handleProfilePictureUpdate(payload);
|
||||
break;
|
||||
default:
|
||||
console.log('Unhandled notification:', msg);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNewMessage = (payload: any) => {
|
||||
const {receiverId, text, id} = payload;
|
||||
io.to(`user:${receiverId}`).emit('new_message', payload);
|
||||
console.log(`Message sent to room ${receiverId} with text: "${text}"`);
|
||||
};
|
||||
|
||||
const handleCountdownUpdate = (payload: any) => {
|
||||
const { relationshipId, countdown } = payload;
|
||||
io.to(`relationship:${relationshipId}`).emit('countdown_update', countdown);
|
||||
console.log(`Countdown update sent to room ${relationshipId}`);
|
||||
};
|
||||
|
||||
const handleRelationshipStatusChange = (payload: any) => {
|
||||
const { relationshipId, status } = payload;
|
||||
io.to(`relationship:${relationshipId}`).emit('relationship_status_change', status);
|
||||
console.log(`Relationship status change sent to room ${relationshipId}, status: ${status}`);
|
||||
};
|
||||
|
||||
const handleProfilePictureUpdate = (payload: any) => {
|
||||
const { userId, profilePictureUrl } = payload;
|
||||
io.to(`user:${userId}`).emit('profile_picture_update', profilePictureUrl);
|
||||
console.log(`Profile picture update sent to room ${userId}`);
|
||||
};
|
||||
|
||||
// Connect the PostgreSQL client
|
||||
pgClient.connect()
|
||||
.then(() => {
|
||||
console.log('Connected to PostgreSQL');
|
||||
// Listen for NOTIFY events on the 'new_message' channel
|
||||
pgClient.query('LISTEN new_message');
|
||||
pgClient.query('LISTEN countdown_update');
|
||||
pgClient.query('LISTEN relationship_status_change');
|
||||
pgClient.query('LISTEN profile_picture_update');
|
||||
|
||||
pgClient.on('notification', handleNotification);
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
console.error('Failed to connect to PostgreSQL:', err);
|
||||
});
|
||||
|
||||
// Handle WebSocket connections
|
||||
io.on('connection', (socket) => {
|
||||
console.log('WebSocket client connected:', socket.id);
|
||||
|
||||
socket.on('join', (roomInfo) => {
|
||||
//console.log('Attempting to join room:', roomInfo);
|
||||
if (typeof roomInfo === 'object') {
|
||||
if (roomInfo.userId) {
|
||||
socket.join(`user:${roomInfo.userId}`);
|
||||
console.log(`User ${roomInfo.userId} joined room`);
|
||||
} else if (roomInfo.relationshipId) {
|
||||
socket.join(`relationship:${roomInfo.relationshipId}`);
|
||||
console.log(`Relationship ${roomInfo.relationshipId} joined room`);
|
||||
}
|
||||
}
|
||||
//console.log('Socket object at connection:', socket);
|
||||
});
|
||||
|
||||
socket.on('error', (error) => {
|
||||
console.error('WebSocket error:', error);
|
||||
});
|
||||
|
||||
// Handle disconnection of WebSocket clients
|
||||
socket.on('disconnect', () => {
|
||||
console.log('WebSocket client disconnected:', socket.id);
|
||||
});
|
||||
});
|
||||
|
||||
// Start the WebSocket server
|
||||
httpServer.listen(PORT, () => {
|
||||
console.log(`WebSocket server is running on port ${PORT}`);
|
||||
});
|
110
websocket_server/tsconfig.json
Normal file
@ -0,0 +1,110 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
"rootDir": "./src", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "noUncheckedSideEffectImports": true, /* Check side effect imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "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. */
|
||||
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "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. */
|
||||
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|