diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 4cf30f72..114162e8 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -16,6 +16,9 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 16 + - uses: oven-sh/setup-bun@v1 + with: + bun-version: canary - uses: pnpm/action-setup@v2.2.4 name: Install pnpm id: pnpm-install diff --git a/Dockerfile b/Dockerfile index 2b4beebd..fc3b6987 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,15 @@ -FROM node:current-alpine -# FROM mcr.microsoft.com/playwright:focal +FROM oven/bun:canary WORKDIR /usr/api COPY api/package.json ./ -RUN npm install -g pnpm - -RUN pnpm install +RUN bun install COPY api/ . -RUN npx tsc +RUN bun tsc EXPOSE 3000 -CMD [ "node", "build/index.js" ] +CMD [ "bun", "run", "build/index.js" ] diff --git a/api/package.json b/api/package.json index 7f7d392d..e121f4d7 100644 --- a/api/package.json +++ b/api/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "tsc", "start": "node build/index.js", - "dev": "concurrently --raw \"tsc -w --preserveWatchOutput\" \"node --watch build/index.js\"", + "dev": "concurrently --raw \"tsc -w --preserveWatchOutput\" \"bun --watch build/index.js\"", "db:create": "mikro-orm schema:create --run", "db:update": "mikro-orm schema:update --run", "db:drop": "mikro-orm schema:drop --run", @@ -30,7 +30,6 @@ "@sentry/integrations": "7.77.0", "@sentry/node": "7.77.0", "aws-sdk": "^2.1563.0", - "bcrypt": "^5.1.1", "body-parser": "^1.20.2", "car-info": "^0.1.6", "class-validator": "^0.14.1", @@ -63,6 +62,7 @@ "@types/uuid": "^9.0.8", "@types/ws": "^8.5.10", "concurrently": "^8.2.2", + "@types/bun": "latest", "ts-node": "^10.9.2", "typescript": "^5.3.3" }, diff --git a/api/src/auth/resolver.ts b/api/src/auth/resolver.ts index 2b966af5..55b84430 100644 --- a/api/src/auth/resolver.ts +++ b/api/src/auth/resolver.ts @@ -9,7 +9,7 @@ import { Token } from '../entities/Token'; import { Context } from '../utils/context'; import { s3 } from '../utils/s3'; import { FileUpload } from 'graphql-upload-minimal'; -import { compare, hash } from 'bcrypt'; +import { password as bunPassword } from 'bun'; import { isDevelopment } from '../utils/constants'; @ObjectType() @@ -35,7 +35,7 @@ export class AuthResolver { isPasswordCorrect = sha256(password) === user.password; break; case (PasswordType.BCRYPT): - isPasswordCorrect = await compare(password, user.password); + isPasswordCorrect = await bunPassword.verify(password, user.password, "bcrypt"); break; default: throw new Error(`Unknown password type ${user.passwordType}`); @@ -77,7 +77,7 @@ export class AuthResolver { throw new Error("No result from AWS"); } - const password = await hash(input.password, 10); + const password = await bunPassword.hash(input.password, "bcrypt"); wrap(user).assign({ username: input.username, @@ -185,7 +185,7 @@ export class AuthResolver { throw new Error("Your reset token has expired. You must re-request to reset your password."); } - entry.user.password = await hash(input.password, 10); + entry.user.password = await bunPassword.hash(input.password, "bcrypt"); entry.user.passwordType = PasswordType.BCRYPT; await ctx.em.nativeDelete(Token, { user: entry.user }); diff --git a/api/src/directions/resolver.ts b/api/src/directions/resolver.ts index 6c51cc16..996c53d5 100644 --- a/api/src/directions/resolver.ts +++ b/api/src/directions/resolver.ts @@ -33,4 +33,4 @@ export class DirectionsResolver { return `${etaMinutes} min`; } -} +} \ No newline at end of file diff --git a/api/src/index.ts b/api/src/index.ts index 65060410..4fbb4491 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -3,7 +3,7 @@ import "dotenv/config"; import Redis from 'ioredis'; import express from "express"; import config from './mikro-orm.config'; -import ws from 'ws'; +import { WebSocketServer } from 'ws'; import cors from 'cors'; import * as Sentry from "./utils/sentry"; import * as RealSentry from "@sentry/node"; @@ -99,7 +99,7 @@ async function start() { plugins, }); - const wsServer = new ws.Server({ + const wsServer = new WebSocketServer({ server: httpServer, path: '/subscriptions', }); diff --git a/api/src/payments/resolver.ts b/api/src/payments/resolver.ts index 975bfccf..9106e4c8 100644 --- a/api/src/payments/resolver.ts +++ b/api/src/payments/resolver.ts @@ -71,7 +71,7 @@ export async function syncUserPayments(em: EntityManager, userId: string): Promi const request = await fetch(`https://api.revenuecat.com/v1/subscribers/${userId}`, options); - const response: SubscriberResponse = await request.json(); + const response = await request.json() as SubscriberResponse; const user = await em.findOneOrFail(User, userId, { populate: ['payments.id'] }); diff --git a/api/src/users/resolver.ts b/api/src/users/resolver.ts index 054d1e26..7804722b 100644 --- a/api/src/users/resolver.ts +++ b/api/src/users/resolver.ts @@ -11,7 +11,7 @@ import { S3 } from 'aws-sdk'; import { getOlderObjectsToDelete, getAllObjects, getUserFromObjectKey, deleteObject, s3 } from '../utils/s3'; import { ChangePasswordInput, EditUserInput, NotificationArgs } from './args'; import { createVerifyEmailEntryAndSendEmail } from '../auth/helpers'; -import { hash } from 'bcrypt'; +import { password as bunPassword } from 'bun'; import { VerifyEmail } from '../entities/VerifyEmail'; import { GraphQLUpload } from 'graphql-upload-minimal'; import { setContext } from "@sentry/node"; @@ -109,7 +109,7 @@ export class UserResolver { @Mutation(() => Boolean) @Authorized('No Verification') public async changePassword(@Ctx() ctx: Context, @Arg('input') input: ChangePasswordInput): Promise { - ctx.user.password = await hash(input.password, 10); + ctx.user.password = await bunPassword.hash(input.password, "bcrypt"); ctx.user.passwordType = PasswordType.BCRYPT; await ctx.em.flush(); @@ -164,15 +164,14 @@ export class UserResolver { @Mutation(() => User) @Authorized('No Verification') - public async addProfilePicture(@Ctx() ctx: Context, @Arg("picture", () => GraphQLUpload) { createReadStream, filename }: Upload, @PubSub() pubSub: PubSubEngine): Promise { - + public async addProfilePicture(@Ctx() ctx: Context, @Arg("picture", () => GraphQLUpload) picture: Upload, @PubSub() pubSub: PubSubEngine): Promise { + const { createReadStream, filename } = await picture; + const extention = filename.substring(filename.lastIndexOf("."), filename.length); - filename = ctx.user.id + "-" + Date.now() + extention; - const uploadParams = { Body: createReadStream(), - Key: "images/" + filename, + Key: "images/" + ctx.user.id + "-" + Date.now() + extention, Bucket: "beep", ACL: "public-read" }; diff --git a/api/tsconfig.json b/api/tsconfig.json index 4738067e..aad6b234 100644 --- a/api/tsconfig.json +++ b/api/tsconfig.json @@ -20,7 +20,10 @@ "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "types": [ + "@types/bun" // add Bun global + ] }, "compileOnSave": true, "include": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45524c64..599e5f96 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,9 +39,6 @@ importers: aws-sdk: specifier: ^2.1563.0 version: 2.1563.0 - bcrypt: - specifier: ^5.1.1 - version: 5.1.1 body-parser: specifier: ^1.20.2 version: 1.20.2 @@ -112,6 +109,9 @@ importers: '@types/body-parser': specifier: ^1.19.5 version: 1.19.5 + '@types/bun': + specifier: latest + version: 1.0.4 '@types/cors': specifier: ^2.8.17 version: 2.8.17 @@ -5521,24 +5521,6 @@ packages: resolution: {integrity: sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==} dev: false - /@mapbox/node-pre-gyp@1.0.11: - resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} - hasBin: true - dependencies: - detect-libc: 2.0.2 - https-proxy-agent: 5.0.1 - make-dir: 3.1.0 - node-fetch: 2.7.0 - nopt: 5.0.0 - npmlog: 5.0.1 - rimraf: 3.0.2 - semver: 7.5.4 - tar: 6.1.15 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - /@mapbox/point-geometry@0.1.0: resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} dev: false @@ -8297,6 +8279,12 @@ packages: '@types/connect': 3.4.38 '@types/node': 20.11.19 + /@types/bun@1.0.4: + resolution: {integrity: sha512-2DO7sqwtpko3d3XP2kLpJsOkV12sSRt8cFR955JVB60m1DiXE56T+gJq+DcCczQ5khxgCDQKkyBRlgg5VH33Dw==} + dependencies: + bun-types: 1.0.25 + dev: true + /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: @@ -8576,10 +8564,6 @@ packages: '@zag-js/dom-query': 0.16.0 dev: false - /abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - dev: false - /abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -8700,18 +8684,6 @@ packages: resolution: {integrity: sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==} dev: false - /aproba@2.0.0: - resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} - dev: false - - /are-we-there-yet@2.0.0: - resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} - engines: {node: '>=10'} - dependencies: - delegates: 1.0.0 - readable-stream: 3.6.2 - dev: false - /arg@4.1.0: resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==} dev: false @@ -9022,18 +8994,6 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - /bcrypt@5.1.1: - resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} - engines: {node: '>= 10.0.0'} - requiresBuild: true - dependencies: - '@mapbox/node-pre-gyp': 1.0.11 - node-addon-api: 5.1.0 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - /better-opn@3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} @@ -9224,6 +9184,14 @@ packages: resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} dev: false + /bun-types@1.0.25: + resolution: {integrity: sha512-9lxeUR/OJsvlZH4GOWteiAdx7ikrSxCUX7Rr0JJux+DrR3LejouVLxIZnTeQ3UPAZovvSgKivWeHPJ2wlo7/Kg==} + dependencies: + '@types/node': 20.11.19 + '@types/ws': 8.5.10 + undici-types: 5.26.5 + dev: true + /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -9500,11 +9468,6 @@ packages: simple-swizzle: 0.2.2 dev: false - /color-support@1.1.3: - resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} - hasBin: true - dev: false - /color2k@2.0.2: resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==} dev: false @@ -9620,10 +9583,6 @@ packages: transitivePeerDependencies: - supports-color - /console-control-strings@1.1.0: - resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - dev: false - /content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -9925,10 +9884,6 @@ packages: engines: {node: '>=0.4.0'} dev: false - /delegates@1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - dev: false - /denodeify@1.2.1: resolution: {integrity: sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==} @@ -9959,11 +9914,6 @@ packages: hasBin: true dev: false - /detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} - engines: {node: '>=8'} - dev: false - /detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} dev: false @@ -10920,21 +10870,6 @@ packages: /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - /gauge@3.0.2: - resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} - engines: {node: '>=10'} - dependencies: - aproba: 2.0.0 - color-support: 1.1.3 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - object-assign: 4.1.1 - signal-exit: 3.0.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wide-align: 1.1.5 - dev: false - /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -11232,10 +11167,6 @@ packages: has-symbols: 1.0.3 dev: false - /has-unicode@2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - dev: false - /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -12167,13 +12098,6 @@ packages: pify: 4.0.1 semver: 5.7.2 - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - dependencies: - semver: 6.3.1 - dev: false - /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} dev: true @@ -12678,10 +12602,6 @@ packages: /node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - /node-addon-api@5.1.0: - resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} - dev: false - /node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} @@ -12722,14 +12642,6 @@ packages: engines: {node: '>=6.0.0'} dev: false - /nopt@5.0.0: - resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} - engines: {node: '>=6'} - hasBin: true - dependencies: - abbrev: 1.1.1 - dev: false - /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -12757,15 +12669,6 @@ packages: dependencies: path-key: 3.1.1 - /npmlog@5.0.1: - resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} - dependencies: - are-we-there-yet: 2.0.0 - console-control-strings: 1.1.0 - gauge: 3.0.2 - set-blocking: 2.0.0 - dev: false - /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: @@ -14825,18 +14728,6 @@ packages: - react-dom dev: false - /tar@6.1.15: - resolution: {integrity: sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==} - engines: {node: '>=10'} - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - dev: false - /tar@6.2.0: resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} engines: {node: '>=10'} @@ -15518,12 +15409,6 @@ packages: dependencies: isexe: 2.0.0 - /wide-align@1.1.5: - resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - dependencies: - string-width: 4.2.3 - dev: false - /wkx@0.5.0: resolution: {integrity: sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==} dependencies: