From ef921537517a798421a00f0c5b60e450c4b74f2b Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Mon, 3 Apr 2023 13:17:31 +0000 Subject: [PATCH 01/32] Docs: auth.js --- src/routes/docs/auth.js | 47 ++++++++++++++++++++++++++++++++++ src/routes/docs/errors.js | 15 +++++++++++ src/routes/docs/reports.js | 26 +++---------------- src/routes/docs/swaggerDocs.js | 6 +++++ 4 files changed, 72 insertions(+), 22 deletions(-) create mode 100644 src/routes/docs/auth.js create mode 100644 src/routes/docs/errors.js diff --git a/src/routes/docs/auth.js b/src/routes/docs/auth.js new file mode 100644 index 00000000..b4cf1ab5 --- /dev/null +++ b/src/routes/docs/auth.js @@ -0,0 +1,47 @@ +const errorsDocs = require("./errors"); + +const authDocs = { + "/auth/sparcssso": { + get: { + tags: ["auth"], + summary: "로그인 페이지로 리다이렉트", + description: "SPARCS SSO 로그인 페이지로 리다이렉트", + responses: {}, + }, + }, + "/auth/sparcssso/callback": { + get: { + tags: ["auth"], + summary: "리다이렉트 되었을 때 다시 로그인 시도", + description: + "SPARCS SSO 로그인 페이지로부터 다시 리다이렉트되었을 때 로그인을 시도", + parameters: [], + responses: {}, + }, + }, + "/auth/logout": { + get: { + tags: ["auth"], + summary: "세션 삭제 및 사용자 로그아웃", + description: "세션 삭제 및 사용자 로그아웃", + responses: { + 200: { + content: { + schema: { + type: "object", + properties: { + ssoLogoutUrl: { + type: "string", + description: "SSO 로그아웃 URL", + }, + }, + }, + }, + }, + 500: errorsDocs["500"], + }, + }, + }, +}; + +module.exports = authDocs; diff --git a/src/routes/docs/errors.js b/src/routes/docs/errors.js new file mode 100644 index 00000000..cb7be6d6 --- /dev/null +++ b/src/routes/docs/errors.js @@ -0,0 +1,15 @@ +const errorsDocs = { + 500: { + description: "internal server error", + content: { + "text/plain": { + schema: { + type: "string", + example: "internal server error", + }, + }, + }, + }, +}; + +module.exports = errorsDocs; diff --git a/src/routes/docs/reports.js b/src/routes/docs/reports.js index 0210197e..cbbb105a 100644 --- a/src/routes/docs/reports.js +++ b/src/routes/docs/reports.js @@ -1,3 +1,5 @@ +const errorsDocs = require("./errors"); + const reportsDocs = { "/reports/create": { post: { @@ -26,17 +28,7 @@ const reportsDocs = { }, }, }, - 500: { - description: "internal server error", - content: { - "text/plain": { - schema: { - type: "string", - example: "internal server error", - }, - }, - }, - }, + 500: errorsDocs["500"], }, }, }, @@ -65,17 +57,7 @@ const reportsDocs = { }, }, }, - 500: { - description: "internal server error", - content: { - "text/plain": { - schema: { - type: "string", - example: "internal server error", - }, - }, - }, - }, + 500: errorsDocs["500"], }, }, }, diff --git a/src/routes/docs/swaggerDocs.js b/src/routes/docs/swaggerDocs.js index cf52ff2a..605031b8 100644 --- a/src/routes/docs/swaggerDocs.js +++ b/src/routes/docs/swaggerDocs.js @@ -2,6 +2,7 @@ const reportsSchema = require("./reportsSchema"); const reportsDocs = require("./reports"); const logininfoDocs = require("./logininfo"); const locationsDocs = require("./locations"); +const authDocs = require("./auth"); const swaggerDocs = { openapi: "3.0.3", @@ -23,6 +24,10 @@ const swaggerDocs = { name: "reports", description: "사용자 신고 및 신고 기록 조회", }, + { + name: "auth", + description: "사용자 상태 관리 지원", + }, ], consumes: ["application/json"], produces: ["application/json"], @@ -30,6 +35,7 @@ const swaggerDocs = { ...reportsDocs, ...logininfoDocs, ...locationsDocs, + ...authDocs, }, components: { schemas: { From fa3c2c63fb008ec6caed9b6d3a1c2ea1c6c10780 Mon Sep 17 00:00:00 2001 From: chlehdwon Date: Tue, 4 Apr 2023 12:06:25 +0000 Subject: [PATCH 02/32] Docs: add format --- src/routes/docs/auth.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/routes/docs/auth.js b/src/routes/docs/auth.js index b4cf1ab5..d000995d 100644 --- a/src/routes/docs/auth.js +++ b/src/routes/docs/auth.js @@ -42,6 +42,29 @@ const authDocs = { }, }, }, + "/auth/app/token/login": { + get: { + tags: ["auth"], + }, + }, + "/auth/app/token/refresh": { + get: { + tags: ["auth"], + }, + }, + "/auth/app/device": { + post: { + tags: ["auth"], + }, + delete: { + tags: ["auth"], + }, + }, + "/auth/app/token/generate": { + get: { + tags: ["auth"], + }, + }, }; module.exports = authDocs; From 3028de05ef955a6e3d5f738a7c73eb3f730f9ef7 Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Mon, 18 Sep 2023 16:48:00 +0000 Subject: [PATCH 03/32] Docs: add /auth/spacssso/* --- src/routes/docs/auth.js | 67 ++++++++++++++++++++++++++++++++++ src/routes/docs/locations.js | 2 +- src/routes/docs/logininfo.js | 2 +- src/routes/docs/reports.js | 4 +- src/routes/docs/swaggerDocs.js | 12 ++++-- 5 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 src/routes/docs/auth.js diff --git a/src/routes/docs/auth.js b/src/routes/docs/auth.js new file mode 100644 index 00000000..5f2813c3 --- /dev/null +++ b/src/routes/docs/auth.js @@ -0,0 +1,67 @@ +const authDocs = { + "/auth/sparcssso": { + get: { + tags: ["/auth"], + summary: "SPARCS SSO 로그인 페이지로 리다이렉트", + description: + "Prod의 경우 SSO 로그인 페이지로, Dev의 경우 replace 페이지로 리다이렉트함.", + parameters: [ + { + in: "query", + name: "redirect", + schema: { + type: "string", + }, + description: "리다이렉트 URI", + }, + { + in: "query", + name: "isApp", + schema: { + type: "boolean", + }, + description: "앱인지 여부", + }, + ], + response: { + 302: { + description: "SPARCS SSO 로그인 페이지로 리다이렉트", + }, + }, + }, + }, + "/auth/sparcssso/callback": { + get: { + tags: ["/auth"], + summary: "SPARCS SSO 로그인 페이지에서 다시 리다이렉트를 처리", + description: + "SPARCS SSO 로그인 페이지로부터 프론트로 다시 리다이렉트되었을 때 로그인을 시도함.", + parameters: [ + { + in: "query", + name: "code", + schema: { + type: "string", + }, + description: "SSO server에서 부여한 유저 정보를 위한 code", + }, + { + in: "query", + name: "state", + schema: { + type: "string", + }, + description: "login 성공 여부 확인을 위한 state", + }, + ], + response: { + 302: { + description: + "로그인 성공 후 페이지, 혹은 로그인 실패 URI로 리다이렉트", + }, + }, + }, + }, +}; + +module.exports = authDocs; diff --git a/src/routes/docs/locations.js b/src/routes/docs/locations.js index 530788eb..6f7d3847 100644 --- a/src/routes/docs/locations.js +++ b/src/routes/docs/locations.js @@ -1,7 +1,7 @@ const locationsDocs = { "/locations": { get: { - tags: ["locations"], + tags: ["/locations"], summary: "출발지/도착지 정보 반환", description: "출발지/도착지로 사용 가능한 장소 목록 조회 및 요청 처리 당시 서버 시각 반환
\n (로그인된 상태에서만 접근 가능)", diff --git a/src/routes/docs/logininfo.js b/src/routes/docs/logininfo.js index b24c5fe6..d878427c 100644 --- a/src/routes/docs/logininfo.js +++ b/src/routes/docs/logininfo.js @@ -1,7 +1,7 @@ const logininfoDocs = { "/logininfo": { get: { - tags: ["logininfo"], + tags: ["/logininfo"], summary: "사용자 정보 반환", description: "로그인되어 있는 사용자의 정보를 반환", responses: { diff --git a/src/routes/docs/reports.js b/src/routes/docs/reports.js index 0210197e..62842f68 100644 --- a/src/routes/docs/reports.js +++ b/src/routes/docs/reports.js @@ -1,7 +1,7 @@ const reportsDocs = { "/reports/create": { post: { - tags: ["reports"], + tags: ["/reports"], summary: "신고 작성", description: "주어진 유저를 전달된 사유로 신고함", requestBody: { @@ -42,7 +42,7 @@ const reportsDocs = { }, "/reports/searchByUser": { get: { - tags: ["reports"], + tags: ["/reports"], summary: "신고 내역 반환", description: "로그인된 사용자의 신고한 내역과, 신고받은 내역을 반환한다
1000개의 limit이 있다.", diff --git a/src/routes/docs/swaggerDocs.js b/src/routes/docs/swaggerDocs.js index cf52ff2a..b6028ca4 100644 --- a/src/routes/docs/swaggerDocs.js +++ b/src/routes/docs/swaggerDocs.js @@ -2,6 +2,7 @@ const reportsSchema = require("./reportsSchema"); const reportsDocs = require("./reports"); const logininfoDocs = require("./logininfo"); const locationsDocs = require("./locations"); +const authDocs = require("./auth"); const swaggerDocs = { openapi: "3.0.3", @@ -12,17 +13,21 @@ const swaggerDocs = { basePath: "/", tags: [ { - name: "locations", + name: "/locations", description: "출발지/도착지 정보 제공", }, { - name: "logininfo", + name: "/logininfo", description: "로그인 정보 제공", }, { - name: "reports", + name: "/reports", description: "사용자 신고 및 신고 기록 조회", }, + { + name: "/auth", + description: "사용자 생성, 로그인, 로그아웃 등 사용자 상태 관리 지원", + }, ], consumes: ["application/json"], produces: ["application/json"], @@ -30,6 +35,7 @@ const swaggerDocs = { ...reportsDocs, ...logininfoDocs, ...locationsDocs, + ...authDocs, }, components: { schemas: { From 065827e1b8af510c76a2168957b22213edf2e8ce Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Tue, 19 Sep 2023 15:13:56 +0000 Subject: [PATCH 04/32] Docs: auth.js basic format done --- src/routes/docs/auth.js | 204 +++++++++++++++++++++++++++++++++++--- src/routes/docs/errors.js | 33 ++++++ 2 files changed, 223 insertions(+), 14 deletions(-) diff --git a/src/routes/docs/auth.js b/src/routes/docs/auth.js index f3facdf0..172dd11c 100644 --- a/src/routes/docs/auth.js +++ b/src/routes/docs/auth.js @@ -25,9 +25,16 @@ const authDocs = { description: "앱인지 여부", }, ], - response: { + responses: { 302: { description: "SPARCS SSO 로그인 페이지로 리다이렉트", + headers: { + Location: { + type: "string", + description: "SPARCS SSO 로그인 페이지", + format: "uri", + }, + }, }, }, }, @@ -56,11 +63,19 @@ const authDocs = { description: "login 성공 여부 확인을 위한 state", }, ], - response: { + responses: { 302: { description: - "로그인 성공 후 페이지, 혹은 로그인 실패 URI로 리다이렉트", + "로그인 성공 후 페이지 URI로, 혹은 로그인 실패 URI로 리다이렉트", + headers: { + Location: { + type: "string", + description: "로그인 성공 후 페이지 URI, 혹은 로그인 실패 URI", + format: "uri", + }, + }, }, + 400: errorsDocs["400"], }, }, }, @@ -69,15 +84,27 @@ const authDocs = { tags: ["/auth"], summary: "세션 삭제 및 사용자 로그아웃", description: "세션 삭제 및 사용자 로그아웃", + parameters: [ + { + in: "query", + name: "redirect", + schema: { + type: "string", + }, + description: "로그아웃 후 리다이렉트 URI", + }, + ], responses: { 200: { content: { - schema: { - type: "object", - properties: { - ssoLogoutUrl: { - type: "string", - description: "SSO 로그아웃 URL", + "application/json": { + schema: { + type: "object", + properties: { + ssoLogoutUrl: { + type: "string", + description: "SSO 로그아웃 URL", + }, }, }, }, @@ -90,24 +117,173 @@ const authDocs = { "/auth/app/token/login": { get: { tags: ["/auth"], + summary: "Access token을 사용하여 로그인", + description: "앱에서 Access Token을 사용하여 로그인 시도", + parameters: [ + { + in: "query", + name: "accessToken", + schema: { + type: "string", + }, + description: "만료 되지 않은 유효한 JWT Access Token", + }, + { + in: "query", + name: "deviceToken", + schema: { + type: "string", + }, + description: "Device Token", + }, + ], + responses: { + 200: { + description: "성공 메세지", + content: { + "text/plain": { + schema: { + type: "string", + example: "success", + }, + }, + }, + }, + 401: errorsDocs["401"], + 500: errorsDocs["500"], + }, }, }, "/auth/app/token/refresh": { get: { tags: ["/auth"], + summary: "만료된 Access Token 갱신", + description: "앱에서 Access Token을 Refresh Token을 활용하여 갱신", + parameters: [ + { + in: "query", + name: "accessToken", + schema: { + type: "string", + }, + description: "만료된 유효한 JWT Access Token", + }, + { + in: "query", + name: "refreshToken", + schema: { + type: "string", + }, + description: "만료되지 않은 유효한 JWT Refresh Token", + }, + ], + responses: { + 200: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + accessToken: { + type: "string", + description: "새로운 JWT Access Token", + }, + refreshToken: { + type: "string", + description: "새로운 Refresh Token", + }, + }, + }, + }, + }, + }, + 400: errorsDocs["400"], + 401: errorsDocs["401"], + 501: errorsDocs["501"], + }, }, }, "/auth/app/device": { post: { tags: ["/auth"], + summary: "기기의 Device Token을 데이터베이스에 등록", + description: "App 기기의 Device Token을 데이터베이스에 등록", + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + accessToken: { + type: "string", + description: "만료 되지 않은 유효한 JWT Access Token", + }, + deviceToken: { + type: "string", + description: + "Firebase 라이브러리에서 제공해주는 Device Token", + }, + }, + }, + }, + }, + }, + responses: { + 200: { + description: "성공 메세지", + content: { + "text/plain": { + schema: { + type: "string", + exapmle: "success", + }, + }, + }, + }, + 400: errorsDocs["400"], + 401: errorsDocs["401"], + 500: errorsDocs["500"], + }, }, delete: { tags: ["/auth"], - }, - }, - "/auth/app/token/generate": { - get: { - tags: ["/auth"], + summary: "기기의 Device Token을 데이터베이스에서 삭제", + description: "App 기기의 Device Token을 데이터베이스에 삭제", + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + accessToken: { + type: "string", + description: "만료 되지 않은 유효한 JWT accessToken", + }, + deviceToken: { + type: "string", + description: "Firebase 라이브러리에서 제공해주는 DeviceToken", + }, + }, + }, + }, + }, + }, + responses: { + 200: { + description: "성공 메세지", + content: { + "text/plain": { + schema: { + type: "string", + exapmle: "success", + }, + }, + }, + }, + 400: errorsDocs["400"], + 401: errorsDocs["401"], + 500: errorsDocs["500"], + }, }, }, }; diff --git a/src/routes/docs/errors.js b/src/routes/docs/errors.js index cb7be6d6..e6569813 100644 --- a/src/routes/docs/errors.js +++ b/src/routes/docs/errors.js @@ -1,4 +1,26 @@ const errorsDocs = { + 400: { + description: "invalid request", + content: { + "text/plain": { + schema: { + type: "string", + example: "invalid request", + }, + }, + }, + }, + 401: { + description: "invalid request", + content: { + "text/plain": { + schema: { + type: "string", + example: "Invalid token", + }, + }, + }, + }, 500: { description: "internal server error", content: { @@ -10,6 +32,17 @@ const errorsDocs = { }, }, }, + 501: { + description: "server error", + content: { + "text/plain": { + schema: { + type: "string", + example: "server error", + }, + }, + }, + }, }; module.exports = errorsDocs; From 0ca21b6fc881f75e6ceac8f954681f2a8a5129d2 Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Tue, 19 Sep 2023 15:15:12 +0000 Subject: [PATCH 05/32] Remove: auth.md --- src/routes/docs/auth.md | 180 ---------------------------------------- 1 file changed, 180 deletions(-) delete mode 100644 src/routes/docs/auth.md diff --git a/src/routes/docs/auth.md b/src/routes/docs/auth.md deleted file mode 100644 index 799ddd01..00000000 --- a/src/routes/docs/auth.md +++ /dev/null @@ -1,180 +0,0 @@ -## `/auth` **(for production)** - -- 사용자 생성, 로그인, 로그아웃 등 사용자 상태 관리를 지원하는 API. -- SPARCS SSO를 사용하는 프로덕션 용 API. - -### `/sparcssso` **(GET)** - -- SPARCS SSO 로그인 페이지로 리다이렉트. - -#### URL Parameters - -- 없음 - -#### Response - -- SPARCS SSO 로그인 페이지로 리다이렉트. - -#### Errors - -- 없음 - -### `/sparcssso/callback` **(GET)** - -- SPARCS SSO 로그인 페이지로부터 다시 리다이렉트되었을 때 로그인을 시도함 - -#### URL Parameters - -- state -- code - -#### Response - -- DB에 존재하는 id면 로그인 진행 후 프론트엔드의 첫 페이지로 리다이렉트 -- DB에 존재하지 않는 id면 새로운 사용자를 만들고 로그인을 진행한 후 프론트엔드의 첫 페이지로 리다이렉트 - -#### Errors - -- 없음 - -### `/logout` **(GET)** - -- 세션을 삭제하여 사용자를 로그아웃시킴 - -#### URL Parameters - -- 없음 - -#### Response - -```javascript -{ - ssoLogoutUrl: String, // sso 로그아웃 url -} -``` - -#### Errors - -- 500 / "internal server error" - -### `/getToken` **(GET)** - -- 세션의 로그인 정보를 토큰으로 만들어 반환 - -#### URL Parameters - -- 없음 - -#### Response - -```javascript -{ - status: 200, - data: String, //JSON Web Token -} -``` - -#### Errors - -- 403 "not logged in" - -### `/app/token/generate` **(GET)** - -- SPARCSSSO로 로그인을 진행하고 로그인 정보를 담아 ACCESSTOKEN, REFRESHTOKEN을 반환 - -#### URL Parameters - -- None - -#### Response - -app's deep link -형식 APP_URI_SCHEME + ://login?accessToken=[ACCESSTOKEN]&refreshToken=[REFRESHTOKEN] - -#### Errors - -- 없음 - -### `/app/token/refresh` **(GET)** - -- 만료된 access token을 refresh token을 활용하여 갱신 - -#### URL Parameters - -- accessToken / 만료된 유효한 JWT Access Token이어야 함 -- refreshToken / 만료되지 않은 유효한 JWT Refresh Token 이어야 함. - -#### Response - -```javascript -{ - accessToken: [newAccessToken], // JSON Web Token - refreshToken: [newRefreshToken], //JSON Web Token -} -``` - -#### Errors - -- 401 / Invalid Access Token -- 401 / Invalid Token -- 401 / Expired Token -- 401 / Not Refresh Token -- 501 / Server Error - -### `/app/token/login` **(GET)** - -- access token을 사용하여 로그인 - -#### URL Parameters - -- accessToken / 만료 되지 않은 유효한 JWT accessToken 이어야 함 - -#### Response - -None / 세션 기록 - -#### Errors - -- 401 / Invalid Access Token -- 401 / Invalid Token -- 401 / Expired Token -- 401 / Not Refresh Token -- 501 / Server Error - -### `/app/device` **(POST)** - -- 기기의 deviceToken을 데이터베이스에 등록 - -#### URL Parameters - -- accessToken / 만료 되지 않은 유효한 JWT accessToken 이어야 함 -- deviceToken / Firebase 라이브러리에서 제공해주는 DeviceToken 이어야 함 - -#### Response - -None - -#### Errors - -- 400 / invalid request ( URL Parameters가 누락되어 있음 ) -- 401 / unauthorized ( 토큰이 유효하지 않음 ) -- 500 / server error - -### `/app/device` **(DELETE)** - -- 기기의 deviceToken을 데이터베이스에서 삭제 - -#### URL Parameters - -- accessToken / 만료 되지 않은 유효한 JWT accessToken 이어야 함 -- deviceToken / Firebase 라이브러리에서 제공해주는 DeviceToken 이어야 함 - -#### Response - -None - -#### Errors - -- 400 / invalid request ( URL Parameters가 누락되어 있음 ) -- 401 / unauthorized ( 토큰이 유효하지 않음 ) -- 500 / server error From b936c658825b3e8f571395814fdfa65560dcf1cd Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Sun, 24 Sep 2023 17:11:53 +0000 Subject: [PATCH 06/32] Remove: error messages --- src/routes/docs/auth.js | 15 ------------ src/routes/docs/errors.js | 48 --------------------------------------- 2 files changed, 63 deletions(-) delete mode 100644 src/routes/docs/errors.js diff --git a/src/routes/docs/auth.js b/src/routes/docs/auth.js index 172dd11c..801e8a01 100644 --- a/src/routes/docs/auth.js +++ b/src/routes/docs/auth.js @@ -1,5 +1,3 @@ -const errorsDocs = require("./errors"); - const authDocs = { "/auth/sparcssso": { get: { @@ -75,7 +73,6 @@ const authDocs = { }, }, }, - 400: errorsDocs["400"], }, }, }, @@ -110,7 +107,6 @@ const authDocs = { }, }, }, - 500: errorsDocs["500"], }, }, }, @@ -149,8 +145,6 @@ const authDocs = { }, }, }, - 401: errorsDocs["401"], - 500: errorsDocs["500"], }, }, }, @@ -197,9 +191,6 @@ const authDocs = { }, }, }, - 400: errorsDocs["400"], - 401: errorsDocs["401"], - 501: errorsDocs["501"], }, }, }, @@ -240,9 +231,6 @@ const authDocs = { }, }, }, - 400: errorsDocs["400"], - 401: errorsDocs["401"], - 500: errorsDocs["500"], }, }, delete: { @@ -280,9 +268,6 @@ const authDocs = { }, }, }, - 400: errorsDocs["400"], - 401: errorsDocs["401"], - 500: errorsDocs["500"], }, }, }, diff --git a/src/routes/docs/errors.js b/src/routes/docs/errors.js deleted file mode 100644 index e6569813..00000000 --- a/src/routes/docs/errors.js +++ /dev/null @@ -1,48 +0,0 @@ -const errorsDocs = { - 400: { - description: "invalid request", - content: { - "text/plain": { - schema: { - type: "string", - example: "invalid request", - }, - }, - }, - }, - 401: { - description: "invalid request", - content: { - "text/plain": { - schema: { - type: "string", - example: "Invalid token", - }, - }, - }, - }, - 500: { - description: "internal server error", - content: { - "text/plain": { - schema: { - type: "string", - example: "internal server error", - }, - }, - }, - }, - 501: { - description: "server error", - content: { - "text/plain": { - schema: { - type: "string", - example: "server error", - }, - }, - }, - }, -}; - -module.exports = errorsDocs; From 33a11717d35b1376c41e5e3fae0e06611909a9cf Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Sun, 24 Sep 2023 17:15:48 +0000 Subject: [PATCH 07/32] Docs: remove reports.js errors --- src/routes/docs/reports.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/routes/docs/reports.js b/src/routes/docs/reports.js index f94488fc..22eab8f0 100644 --- a/src/routes/docs/reports.js +++ b/src/routes/docs/reports.js @@ -1,5 +1,3 @@ -const errorsDocs = require("./errors"); - const reportsDocs = { "/reports/create": { post: { @@ -28,7 +26,6 @@ const reportsDocs = { }, }, }, - 500: errorsDocs["500"], }, }, }, @@ -57,7 +54,6 @@ const reportsDocs = { }, }, }, - 500: errorsDocs["500"], }, }, }, From 77123ed6fcf41169036f63e9d3ac85bde6d8b0dc Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 18:57:58 +0900 Subject: [PATCH 08/32] Fix: skip validation for trust proxy setting in rate-limit middleware --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- src/middlewares/limitRate.js | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index cdb57f4f..20ec12eb 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "eslint-config-prettier": "^8.3.0", "express": "^4.17.1", "express-formidable": "^1.2.0", - "express-rate-limit": "^6.6.0", + "express-rate-limit": "^7.1.0", "express-session": "^1.17.3", "express-validator": "^6.14.0", "firebase-admin": "^11.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2249f8ac..8e1b598e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -60,8 +60,8 @@ dependencies: specifier: ^1.2.0 version: 1.2.0 express-rate-limit: - specifier: ^6.6.0 - version: 6.8.1(express@4.18.2) + specifier: ^7.1.0 + version: 7.1.0(express@4.18.2) express-session: specifier: ^1.17.3 version: 1.17.3 @@ -5088,9 +5088,9 @@ packages: formidable: 1.2.6 dev: false - /express-rate-limit@6.8.1(express@4.18.2): - resolution: {integrity: sha512-xJyudsE60CsDShK74Ni1MxsldYaIoivmG3ieK2tAckMsYCBewEuGalss6p/jHmFFnqM9xd5ojE0W2VlanxcOKg==} - engines: {node: '>= 14.0.0'} + /express-rate-limit@7.1.0(express@4.18.2): + resolution: {integrity: sha512-pwKOMedrpJJeINON/9jhAa18udV2qwxPZSoklPZK8pmXxUyE5uXaptiwjGw8bZILbxqfUZ/p8pQA99ODjSgA5Q==} + engines: {node: '>= 16'} peerDependencies: express: ^4 || ^5 dependencies: diff --git a/src/middlewares/limitRate.js b/src/middlewares/limitRate.js index 4cba6af3..c5069c8f 100644 --- a/src/middlewares/limitRate.js +++ b/src/middlewares/limitRate.js @@ -5,6 +5,10 @@ const limiter = rateLimit({ max: 1500, // Limit each IP to 1500 requests per `window` (here, per 15 minutes) standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers legacyHeaders: false, // Disable the `X-RateLimit-*` headers + validate: { + default: true, + trustProxy: false, // Disable the validation error caused by 'trust proxy' set to true + }, }); module.exports = limiter; From 73e3c0005b15169bf2895a080e6bbe287ca61ffe Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 19:00:12 +0900 Subject: [PATCH 09/32] Refactor: force node.js >= 18 --- .npmrc | 2 ++ .nvmrc | 1 + package.json | 32 ++++++++++++++++++-------------- pnpm-lock.yaml | 4 ++-- 4 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 .npmrc create mode 100644 .nvmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..be7e0b34 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +# Force Node.js and pnpm versions according to package.json +engine-strict=true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..7950a445 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v18.17.0 diff --git a/package.json b/package.json index 20ec12eb..1882cbbf 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,22 @@ "name": "taxi-back", "version": "1.0.0", "description": "KAIST Taxi Party Matching Web Service", + "author": "sparcs/taxi", + "license": "MIT", "main": "app.js", + "scripts": { + "preinstall": "npx only-allow pnpm", + "start": "cross-env TZ='Asia/Seoul' npx nodemon app.js", + "test": "npm run sample && cross-env TZ='Asia/Seoul' npm run mocha", + "mocha": "cross-env TZ='Asia/Seoul' NODE_ENV=test mocha --recursive --reporter spec --exit", + "serve": "cross-env TZ='Asia/Seoul' NODE_ENV=production node app.js", + "lint": "npx eslint --fix .", + "sample": "cd sampleGenerator && npm start && cd .." + }, + "engines": { + "node": ">=18.0.0", + "pnpm": ">=8.0.0" + }, "dependencies": { "@adminjs/express": "^5.1.0", "@adminjs/mongoose": "^3.0.3", @@ -40,22 +55,11 @@ "winston-daily-rotate-file": "^4.7.1" }, "devDependencies": { - "chai": "*", + "chai": "^4.3.7", "eslint": "^8.22.0", "eslint-plugin-mocha": "^10.1.0", - "mocha": "*", + "mocha": "^10.2.0", "nodemon": "^2.0.14", "supertest": "^6.2.4" - }, - "scripts": { - "preinstall": "npx only-allow pnpm", - "start": "cross-env TZ='Asia/Seoul' npx nodemon app.js", - "test": "npm run sample && cross-env TZ='Asia/Seoul' npm run mocha", - "mocha": "cross-env TZ='Asia/Seoul' NODE_ENV=test mocha --recursive --reporter spec --exit", - "serve": "cross-env TZ='Asia/Seoul' NODE_ENV=production node app.js", - "lint": "npx eslint --fix .", - "sample": "cd sampleGenerator && npm start && cd .." - }, - "author": "sparcs/taxi", - "license": "MIT" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e1b598e..77d40850 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -110,7 +110,7 @@ dependencies: devDependencies: chai: - specifier: '*' + specifier: ^4.3.7 version: 4.3.7 eslint: specifier: ^8.22.0 @@ -119,7 +119,7 @@ devDependencies: specifier: ^10.1.0 version: 10.1.0(eslint@8.22.0) mocha: - specifier: '*' + specifier: ^10.2.0 version: 10.2.0 nodemon: specifier: ^2.0.14 From 02d8127d08c36cdc10cebc42e4ca102f201002de Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 19:00:48 +0900 Subject: [PATCH 10/32] Fix: specify strictQuery to Mongoose --- src/modules/stores/mongo.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/stores/mongo.js b/src/modules/stores/mongo.js index 119e0c0d..f05f266a 100755 --- a/src/modules/stores/mongo.js +++ b/src/modules/stores/mongo.js @@ -173,6 +173,8 @@ const adminLogSchema = Schema({ }, // 수행 업무 }); +mongoose.set("strictQuery", true); + const database = mongoose.connection; database.on("error", console.error.bind(console, "mongoose connection error.")); database.on("open", () => { From c5058248b39b1a0dfc6fa4999c89dcfd937d3654 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 19:14:49 +0900 Subject: [PATCH 11/32] Refactor: update Node.js version of Dockerfile & Actions --- .github/workflows/test_ci.yml | 7 ++++--- Dockerfile | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml index 3c8885b2..f3aed1ef 100644 --- a/.github/workflows/test_ci.yml +++ b/.github/workflows/test_ci.yml @@ -12,7 +12,8 @@ jobs: strategy: matrix: # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - node-version: [16.x] + node-version: ['18.x'] + pnpm-version: ['8'] mongodb-version: ['5.0'] steps: - name: Start MongoDB @@ -24,12 +25,12 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: ${{ matrix.node-version }} - uses: pnpm/action-setup@v2 name: Install pnpm with: - version: 8 + version: ${{ matrix.pnpm-version }} - id: submodule-local name: Save local version of submodule run: echo "ver=`cd sampleGenerator && git log --pretty="%h" -1 && cd ..`" >> $GITHUB_OUTPUT diff --git a/Dockerfile b/Dockerfile index 78ab302f..12ee05fd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine +FROM node:18-alpine # Copy repository WORKDIR /usr/src/app @@ -6,7 +6,7 @@ COPY . . # Install curl (for taxi-docker) RUN apk update && apk add curl -RUN npm install --global pnpm@8.6.6 serve@14.1.2 +RUN npm install --global pnpm@8.8.0 # Install requirements RUN pnpm i --force --frozen-lockfile From 2b558807b65c63a0600c6cd581b08e10f9f12422 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 19:42:03 +0900 Subject: [PATCH 12/32] Add: add pnpm cache for CI workflow --- .github/workflows/test_ci.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml index f3aed1ef..dab9f5a0 100644 --- a/.github/workflows/test_ci.yml +++ b/.github/workflows/test_ci.yml @@ -13,7 +13,6 @@ jobs: matrix: # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ node-version: ['18.x'] - pnpm-version: ['8'] mongodb-version: ['5.0'] steps: - name: Start MongoDB @@ -22,15 +21,15 @@ jobs: uses: actions/checkout@v3 with: submodules: true + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 - name: Install Node.js uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - - uses: pnpm/action-setup@v2 - name: Install pnpm - with: - version: ${{ matrix.pnpm-version }} + cache: 'pnpm' - id: submodule-local name: Save local version of submodule run: echo "ver=`cd sampleGenerator && git log --pretty="%h" -1 && cd ..`" >> $GITHUB_OUTPUT From bd26b54c8b3e870b1bb0abaa15553133ef602a21 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 20:07:35 +0900 Subject: [PATCH 13/32] Refactor: use pnpm fetch for better caching --- Dockerfile | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 12ee05fd..0873829c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,21 @@ FROM node:18-alpine -# Copy repository WORKDIR /usr/src/app -COPY . . -# Install curl (for taxi-docker) -RUN apk update && apk add curl -RUN npm install --global pnpm@8.8.0 +# Install curl(for taxi-watchtower) and pnpm +RUN apk update && apk add curl && npm install --global pnpm@8.8.0 -# Install requirements -RUN pnpm i --force --frozen-lockfile +# pnpm fetch does require only lockfile +COPY pnpm-lock.yaml . + +# Note: devDependencies are not fetched +RUN pnpm fetch --prod + +# Copy repository and install dependencies +ADD . ./ +RUN pnpm install --offline --prod # Run container EXPOSE 80 ENV PORT 80 CMD ["pnpm", "run", "serve"] - From 68165897be34d9584bb27d2520457dc5e176ff82 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 20:32:32 +0900 Subject: [PATCH 14/32] Refactor: cache github actions to build image --- .github/workflows/push_image_ecr.yml | 37 +++++++++++++++++++++--- .github/workflows/push_image_ecr_dev.yml | 36 +++++++++++++++++++---- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/.github/workflows/push_image_ecr.yml b/.github/workflows/push_image_ecr.yml index 17e172f7..232535a1 100644 --- a/.github/workflows/push_image_ecr.yml +++ b/.github/workflows/push_image_ecr.yml @@ -22,6 +22,17 @@ jobs: with: fetch-depth: 0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Get previous tag-version id: previous_tag uses: WyriHaximus/github-action-get-previous-tag@v1 @@ -47,15 +58,33 @@ jobs: id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - - name: Build and Push to AWS ECR + - name: Build Image id: build_image + uses: docker/build-push-action@v5 + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + IMAGE_TAG: ${{ steps.tag.outputs.tag }} + ECR_REPOSITORY: taxi-back + with: + tags: | + "${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}" + "${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest" + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + + - name: Push to AWS ECR + id: push_image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ steps.tag.outputs.tag }} ECR_REPOSITORY: taxi-back run: | - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:latest . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest - echo "Push iamge : $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG and latest" + echo "Push image : $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG and latest" + + - name: Remove old cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + \ No newline at end of file diff --git a/.github/workflows/push_image_ecr_dev.yml b/.github/workflows/push_image_ecr_dev.yml index ef917f5b..701bfa7d 100644 --- a/.github/workflows/push_image_ecr_dev.yml +++ b/.github/workflows/push_image_ecr_dev.yml @@ -20,7 +20,18 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: @@ -31,13 +42,28 @@ jobs: - name: Login to AWS ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - - - name: Build and Push to AWS ECR + + - name: Build Image id: build_image + uses: docker/build-push-action@v5 + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + ECR_REPOSITORY: taxi-back + with: + tags: "${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:dev" + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + + - name: Push to AWS ECR + id: push_image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY: taxi-back run: | - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:dev . docker push $ECR_REGISTRY/$ECR_REPOSITORY:dev - echo "Push iamge : $ECR_REGISTRY/$ECR_REPOSITORY:dev" + echo "Push image : $ECR_REGISTRY/$ECR_REPOSITORY:dev" + + - name: Remove old cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache \ No newline at end of file From a839177632aa80093155afcf0ee0f8b345860136 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 20:55:41 +0900 Subject: [PATCH 15/32] Fix: bump dependencies --- package.json | 6 +- pnpm-lock.yaml | 1017 ++++++++++++++++++++++++++---------------------- 2 files changed, 559 insertions(+), 464 deletions(-) diff --git a/package.json b/package.json index 1882cbbf..10e08d1f 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "express-validator": "^6.14.0", "firebase-admin": "^11.4.1", "jsonwebtoken": "^8.5.1", - "mongoose": "^6.11.3", + "mongoose": "^6.12.0", "node-cron": "3.0.2", "node-mocks-http": "^1.12.1", "querystring": "^0.2.1", @@ -55,11 +55,11 @@ "winston-daily-rotate-file": "^4.7.1" }, "devDependencies": { - "chai": "^4.3.7", + "chai": "^4.3.10", "eslint": "^8.22.0", "eslint-plugin-mocha": "^10.1.0", "mocha": "^10.2.0", - "nodemon": "^2.0.14", + "nodemon": "^3.0.1", "supertest": "^6.2.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 77d40850..44ff861f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,10 +7,10 @@ settings: dependencies: '@adminjs/express': specifier: ^5.1.0 - version: 5.1.0(adminjs@6.8.7)(express-formidable@1.2.0)(express-session@1.17.3)(express@4.18.2)(tslib@2.6.1) + version: 5.1.0(adminjs@6.8.7)(express-formidable@1.2.0)(express-session@1.17.3)(express@4.18.2)(tslib@2.6.2) '@adminjs/mongoose': specifier: ^3.0.3 - version: 3.0.3(adminjs@6.8.7)(mongoose@6.11.5) + version: 3.0.3(adminjs@6.8.7)(mongoose@6.12.0) adminjs: specifier: ^6.8.7 version: 6.8.7 @@ -34,7 +34,7 @@ dependencies: version: 2.2.0 connect-mongo: specifier: ^4.6.0 - version: 4.6.0(express-session@1.17.3)(mongodb@4.16.0) + version: 4.6.0(express-session@1.17.3)(mongodb@4.17.1) connect-redis: specifier: ^6.1.3 version: 6.1.3 @@ -75,8 +75,8 @@ dependencies: specifier: ^8.5.1 version: 8.5.1 mongoose: - specifier: ^6.11.3 - version: 6.11.5 + specifier: ^6.12.0 + version: 6.12.0 node-cron: specifier: 3.0.2 version: 3.0.2 @@ -110,8 +110,8 @@ dependencies: devDependencies: chai: - specifier: ^4.3.7 - version: 4.3.7 + specifier: ^4.3.10 + version: 4.3.10 eslint: specifier: ^8.22.0 version: 8.22.0 @@ -122,8 +122,8 @@ devDependencies: specifier: ^10.2.0 version: 10.2.0 nodemon: - specifier: ^2.0.14 - version: 2.0.22 + specifier: ^3.0.1 + version: 3.0.1 supertest: specifier: ^6.2.4 version: 6.3.3 @@ -181,7 +181,7 @@ packages: - prop-types dev: false - /@adminjs/express@5.1.0(adminjs@6.8.7)(express-formidable@1.2.0)(express-session@1.17.3)(express@4.18.2)(tslib@2.6.1): + /@adminjs/express@5.1.0(adminjs@6.8.7)(express-formidable@1.2.0)(express-session@1.17.3)(express@4.18.2)(tslib@2.6.2): resolution: {integrity: sha512-+mrtDmoAYA9R+/FTYWOLL48g005yrgcAWC2phdwqGzznIxGKSp2YERcfzdTI7Svtnlaal72/QW8Q3OhzJjVLzQ==} peerDependencies: adminjs: '>=6.0.0' @@ -195,10 +195,10 @@ packages: express-formidable: 1.2.0 express-session: 1.17.3 path-to-regexp: 6.2.1 - tslib: 2.6.1 + tslib: 2.6.2 dev: false - /@adminjs/mongoose@3.0.3(adminjs@6.8.7)(mongoose@6.11.5): + /@adminjs/mongoose@3.0.3(adminjs@6.8.7)(mongoose@6.12.0): resolution: {integrity: sha512-J/Ogz3oJ2ytOsbeqBpjgIFtiAmGk3MVVfJq2cUidXJ1phrvNHhb7AjiaKd+pcdFcT84COUHaoo6uPYvrLhZEQg==} peerDependencies: adminjs: '>=6.0.0' @@ -207,7 +207,7 @@ packages: adminjs: 6.8.7 escape-regexp: 0.0.1 lodash: 4.17.21 - mongoose: 6.11.5 + mongoose: 6.12.0 dev: false /@ampproject/remapping@2.2.1: @@ -223,7 +223,7 @@ packages: requiresBuild: true dependencies: '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.378.0 + '@aws-sdk/types': 3.425.0 tslib: 1.14.1 dev: false optional: true @@ -244,7 +244,7 @@ packages: '@aws-crypto/sha256-js': 3.0.0 '@aws-crypto/supports-web-crypto': 3.0.0 '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.378.0 + '@aws-sdk/types': 3.425.0 '@aws-sdk/util-locate-window': 3.310.0 '@aws-sdk/util-utf8-browser': 3.259.0 tslib: 1.14.1 @@ -256,7 +256,7 @@ packages: requiresBuild: true dependencies: '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.378.0 + '@aws-sdk/types': 3.425.0 tslib: 1.14.1 dev: false optional: true @@ -273,388 +273,453 @@ packages: resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 + '@aws-sdk/types': 3.425.0 '@aws-sdk/util-utf8-browser': 3.259.0 tslib: 1.14.1 dev: false optional: true - /@aws-sdk/client-cognito-identity@3.385.0: - resolution: {integrity: sha512-fRXZhxvBBeK/Jxb+sLPhyQmcduNSugSKJDz474A/wLK5UIuDOnKhDTjsa0OXMpY5DkqwdYLwDcGZtxUbEZ8DCQ==} + /@aws-sdk/client-cognito-identity@3.427.0: + resolution: {integrity: sha512-9brRaNnl6haE7R3R43A5CSNw0k1YtB3xjuArbMg/p6NDUpvRSRgOVNWu2R02Yjh/j2ZuaLOCPLuCipb+PHQPKQ==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.385.0 - '@aws-sdk/credential-provider-node': 3.385.0 - '@aws-sdk/middleware-host-header': 3.379.1 - '@aws-sdk/middleware-logger': 3.378.0 - '@aws-sdk/middleware-recursion-detection': 3.378.0 - '@aws-sdk/middleware-signing': 3.379.1 - '@aws-sdk/middleware-user-agent': 3.382.0 - '@aws-sdk/types': 3.378.0 - '@aws-sdk/util-endpoints': 3.382.0 - '@aws-sdk/util-user-agent-browser': 3.378.0 - '@aws-sdk/util-user-agent-node': 3.378.0 - '@smithy/config-resolver': 2.0.1 - '@smithy/fetch-http-handler': 2.0.1 - '@smithy/hash-node': 2.0.1 - '@smithy/invalid-dependency': 2.0.1 - '@smithy/middleware-content-length': 2.0.1 - '@smithy/middleware-endpoint': 2.0.1 - '@smithy/middleware-retry': 2.0.1 - '@smithy/middleware-serde': 2.0.1 - '@smithy/middleware-stack': 2.0.0 - '@smithy/node-config-provider': 2.0.1 - '@smithy/node-http-handler': 2.0.1 - '@smithy/protocol-http': 2.0.1 - '@smithy/smithy-client': 2.0.1 - '@smithy/types': 2.0.2 - '@smithy/url-parser': 2.0.1 + '@aws-sdk/client-sts': 3.427.0 + '@aws-sdk/credential-provider-node': 3.427.0 + '@aws-sdk/middleware-host-header': 3.425.0 + '@aws-sdk/middleware-logger': 3.425.0 + '@aws-sdk/middleware-recursion-detection': 3.425.0 + '@aws-sdk/middleware-signing': 3.425.0 + '@aws-sdk/middleware-user-agent': 3.427.0 + '@aws-sdk/region-config-resolver': 3.425.0 + '@aws-sdk/types': 3.425.0 + '@aws-sdk/util-endpoints': 3.427.0 + '@aws-sdk/util-user-agent-browser': 3.425.0 + '@aws-sdk/util-user-agent-node': 3.425.0 + '@smithy/config-resolver': 2.0.14 + '@smithy/fetch-http-handler': 2.2.2 + '@smithy/hash-node': 2.0.11 + '@smithy/invalid-dependency': 2.0.11 + '@smithy/middleware-content-length': 2.0.13 + '@smithy/middleware-endpoint': 2.0.11 + '@smithy/middleware-retry': 2.0.16 + '@smithy/middleware-serde': 2.0.11 + '@smithy/middleware-stack': 2.0.5 + '@smithy/node-config-provider': 2.1.1 + '@smithy/node-http-handler': 2.1.7 + '@smithy/protocol-http': 3.0.7 + '@smithy/smithy-client': 2.1.10 + '@smithy/types': 2.3.5 + '@smithy/url-parser': 2.0.11 '@smithy/util-base64': 2.0.0 '@smithy/util-body-length-browser': 2.0.0 - '@smithy/util-body-length-node': 2.0.0 - '@smithy/util-defaults-mode-browser': 2.0.1 - '@smithy/util-defaults-mode-node': 2.0.1 - '@smithy/util-retry': 2.0.0 + '@smithy/util-body-length-node': 2.1.0 + '@smithy/util-defaults-mode-browser': 2.0.14 + '@smithy/util-defaults-mode-node': 2.0.18 + '@smithy/util-retry': 2.0.4 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/client-sso@3.382.0: - resolution: {integrity: sha512-ge11t4hJllOF8pBNF0p1X52lLqUsLGAoey24fvk3fyvvczeLpegGYh2kdLG0iwFTDgRxaUqK+kboH5Wy9ux/pw==} + /@aws-sdk/client-sso@3.427.0: + resolution: {integrity: sha512-sFVFEmsQ1rmgYO1SgrOTxE/MTKpeE4hpOkm1WqhLQK7Ij136vXpjCxjH1JYZiHiUzO1wr9t4ex4dlB5J3VS/Xg==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/middleware-host-header': 3.379.1 - '@aws-sdk/middleware-logger': 3.378.0 - '@aws-sdk/middleware-recursion-detection': 3.378.0 - '@aws-sdk/middleware-user-agent': 3.382.0 - '@aws-sdk/types': 3.378.0 - '@aws-sdk/util-endpoints': 3.382.0 - '@aws-sdk/util-user-agent-browser': 3.378.0 - '@aws-sdk/util-user-agent-node': 3.378.0 - '@smithy/config-resolver': 2.0.1 - '@smithy/fetch-http-handler': 2.0.1 - '@smithy/hash-node': 2.0.1 - '@smithy/invalid-dependency': 2.0.1 - '@smithy/middleware-content-length': 2.0.1 - '@smithy/middleware-endpoint': 2.0.1 - '@smithy/middleware-retry': 2.0.1 - '@smithy/middleware-serde': 2.0.1 - '@smithy/middleware-stack': 2.0.0 - '@smithy/node-config-provider': 2.0.1 - '@smithy/node-http-handler': 2.0.1 - '@smithy/protocol-http': 2.0.1 - '@smithy/smithy-client': 2.0.1 - '@smithy/types': 2.0.2 - '@smithy/url-parser': 2.0.1 + '@aws-sdk/middleware-host-header': 3.425.0 + '@aws-sdk/middleware-logger': 3.425.0 + '@aws-sdk/middleware-recursion-detection': 3.425.0 + '@aws-sdk/middleware-user-agent': 3.427.0 + '@aws-sdk/region-config-resolver': 3.425.0 + '@aws-sdk/types': 3.425.0 + '@aws-sdk/util-endpoints': 3.427.0 + '@aws-sdk/util-user-agent-browser': 3.425.0 + '@aws-sdk/util-user-agent-node': 3.425.0 + '@smithy/config-resolver': 2.0.14 + '@smithy/fetch-http-handler': 2.2.2 + '@smithy/hash-node': 2.0.11 + '@smithy/invalid-dependency': 2.0.11 + '@smithy/middleware-content-length': 2.0.13 + '@smithy/middleware-endpoint': 2.0.11 + '@smithy/middleware-retry': 2.0.16 + '@smithy/middleware-serde': 2.0.11 + '@smithy/middleware-stack': 2.0.5 + '@smithy/node-config-provider': 2.1.1 + '@smithy/node-http-handler': 2.1.7 + '@smithy/protocol-http': 3.0.7 + '@smithy/smithy-client': 2.1.10 + '@smithy/types': 2.3.5 + '@smithy/url-parser': 2.0.11 '@smithy/util-base64': 2.0.0 '@smithy/util-body-length-browser': 2.0.0 - '@smithy/util-body-length-node': 2.0.0 - '@smithy/util-defaults-mode-browser': 2.0.1 - '@smithy/util-defaults-mode-node': 2.0.1 - '@smithy/util-retry': 2.0.0 + '@smithy/util-body-length-node': 2.1.0 + '@smithy/util-defaults-mode-browser': 2.0.14 + '@smithy/util-defaults-mode-node': 2.0.18 + '@smithy/util-retry': 2.0.4 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/client-sts@3.385.0: - resolution: {integrity: sha512-VdSDwICW2cBttbdj1izu6VYflJbZZKu3/FSaJGuGu8SgTvRsa56g6E5xfbUfR/SCstuETObKLusSfQZ6yxUnzA==} + /@aws-sdk/client-sts@3.427.0: + resolution: {integrity: sha512-le2wLJKILyWuRfPz2HbyaNtu5kEki+ojUkTqCU6FPDRrqUvEkaaCBH9Awo/2AtrCfRkiobop8RuTTj6cAnpiJg==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/credential-provider-node': 3.385.0 - '@aws-sdk/middleware-host-header': 3.379.1 - '@aws-sdk/middleware-logger': 3.378.0 - '@aws-sdk/middleware-recursion-detection': 3.378.0 - '@aws-sdk/middleware-sdk-sts': 3.379.1 - '@aws-sdk/middleware-signing': 3.379.1 - '@aws-sdk/middleware-user-agent': 3.382.0 - '@aws-sdk/types': 3.378.0 - '@aws-sdk/util-endpoints': 3.382.0 - '@aws-sdk/util-user-agent-browser': 3.378.0 - '@aws-sdk/util-user-agent-node': 3.378.0 - '@smithy/config-resolver': 2.0.1 - '@smithy/fetch-http-handler': 2.0.1 - '@smithy/hash-node': 2.0.1 - '@smithy/invalid-dependency': 2.0.1 - '@smithy/middleware-content-length': 2.0.1 - '@smithy/middleware-endpoint': 2.0.1 - '@smithy/middleware-retry': 2.0.1 - '@smithy/middleware-serde': 2.0.1 - '@smithy/middleware-stack': 2.0.0 - '@smithy/node-config-provider': 2.0.1 - '@smithy/node-http-handler': 2.0.1 - '@smithy/protocol-http': 2.0.1 - '@smithy/smithy-client': 2.0.1 - '@smithy/types': 2.0.2 - '@smithy/url-parser': 2.0.1 + '@aws-sdk/credential-provider-node': 3.427.0 + '@aws-sdk/middleware-host-header': 3.425.0 + '@aws-sdk/middleware-logger': 3.425.0 + '@aws-sdk/middleware-recursion-detection': 3.425.0 + '@aws-sdk/middleware-sdk-sts': 3.425.0 + '@aws-sdk/middleware-signing': 3.425.0 + '@aws-sdk/middleware-user-agent': 3.427.0 + '@aws-sdk/region-config-resolver': 3.425.0 + '@aws-sdk/types': 3.425.0 + '@aws-sdk/util-endpoints': 3.427.0 + '@aws-sdk/util-user-agent-browser': 3.425.0 + '@aws-sdk/util-user-agent-node': 3.425.0 + '@smithy/config-resolver': 2.0.14 + '@smithy/fetch-http-handler': 2.2.2 + '@smithy/hash-node': 2.0.11 + '@smithy/invalid-dependency': 2.0.11 + '@smithy/middleware-content-length': 2.0.13 + '@smithy/middleware-endpoint': 2.0.11 + '@smithy/middleware-retry': 2.0.16 + '@smithy/middleware-serde': 2.0.11 + '@smithy/middleware-stack': 2.0.5 + '@smithy/node-config-provider': 2.1.1 + '@smithy/node-http-handler': 2.1.7 + '@smithy/protocol-http': 3.0.7 + '@smithy/smithy-client': 2.1.10 + '@smithy/types': 2.3.5 + '@smithy/url-parser': 2.0.11 '@smithy/util-base64': 2.0.0 '@smithy/util-body-length-browser': 2.0.0 - '@smithy/util-body-length-node': 2.0.0 - '@smithy/util-defaults-mode-browser': 2.0.1 - '@smithy/util-defaults-mode-node': 2.0.1 - '@smithy/util-retry': 2.0.0 + '@smithy/util-body-length-node': 2.1.0 + '@smithy/util-defaults-mode-browser': 2.0.14 + '@smithy/util-defaults-mode-node': 2.0.18 + '@smithy/util-retry': 2.0.4 '@smithy/util-utf8': 2.0.0 fast-xml-parser: 4.2.5 - tslib: 2.6.1 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/credential-provider-cognito-identity@3.385.0: - resolution: {integrity: sha512-NeWJgI2XdfO0ZM25KsfNx9CDmLByY3ymVc0ae4Os+bd8pJsFeo1rX3NSkyw8XGryEbOlVJ3Jz5W5huhjo4LvqQ==} + /@aws-sdk/credential-provider-cognito-identity@3.427.0: + resolution: {integrity: sha512-BQNzNrMJlBAfXhYNdAUqaVASpT9Aho5swj7glZKxx4Uds1w5Pih2e14JWgnl8XgUWAZ36pchTrV1aA4JT7N8vw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/client-cognito-identity': 3.385.0 - '@aws-sdk/types': 3.378.0 - '@smithy/property-provider': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/client-cognito-identity': 3.427.0 + '@aws-sdk/types': 3.425.0 + '@smithy/property-provider': 2.0.12 + '@smithy/types': 2.3.5 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/credential-provider-env@3.378.0: - resolution: {integrity: sha512-B2OVdO9kBClDwGgWTBLAQwFV8qYTYGyVujg++1FZFSFMt8ORFdZ5fNpErvJtiSjYiOOQMzyBeSNhKyYNXCiJjQ==} + /@aws-sdk/credential-provider-env@3.425.0: + resolution: {integrity: sha512-J20etnLvMKXRVi5FK4F8yOCNm2RTaQn5psQTGdDEPWJNGxohcSpzzls8U2KcMyUJ+vItlrThr4qwgpHG3i/N0w==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/property-provider': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/property-provider': 2.0.12 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/credential-provider-ini@3.385.0: - resolution: {integrity: sha512-WBIR5GdfUzCGzynQYX/TuCXw3KJCkHBk6bVAsO1YmfR68XKVAxWmJPKovlK/rR6LIuV+iwUMNludO+SkmG0efg==} + /@aws-sdk/credential-provider-http@3.425.0: + resolution: {integrity: sha512-aP9nkoVWf+OlNMecrUqe4+RuQrX13nucVbty0HTvuwfwJJj0T6ByWZzle+fo1D+5OxvJmtzTflBWt6jUERdHWA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/credential-provider-env': 3.378.0 - '@aws-sdk/credential-provider-process': 3.378.0 - '@aws-sdk/credential-provider-sso': 3.385.0 - '@aws-sdk/credential-provider-web-identity': 3.378.0 - '@aws-sdk/types': 3.378.0 - '@smithy/credential-provider-imds': 2.0.1 - '@smithy/property-provider': 2.0.1 - '@smithy/shared-ini-file-loader': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/fetch-http-handler': 2.2.2 + '@smithy/node-http-handler': 2.1.7 + '@smithy/property-provider': 2.0.12 + '@smithy/protocol-http': 3.0.7 + '@smithy/types': 2.3.5 + tslib: 2.6.2 + dev: false + optional: true + + /@aws-sdk/credential-provider-ini@3.427.0: + resolution: {integrity: sha512-NmH1cO/w98CKMltYec3IrJIIco19wRjATFNiw83c+FGXZ+InJwReqBnruxIOmKTx2KDzd6fwU1HOewS7UjaaaQ==} + engines: {node: '>=14.0.0'} + requiresBuild: true + dependencies: + '@aws-sdk/credential-provider-env': 3.425.0 + '@aws-sdk/credential-provider-process': 3.425.0 + '@aws-sdk/credential-provider-sso': 3.427.0 + '@aws-sdk/credential-provider-web-identity': 3.425.0 + '@aws-sdk/types': 3.425.0 + '@smithy/credential-provider-imds': 2.0.16 + '@smithy/property-provider': 2.0.12 + '@smithy/shared-ini-file-loader': 2.2.0 + '@smithy/types': 2.3.5 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/credential-provider-node@3.385.0: - resolution: {integrity: sha512-Lk8uu6jm/8OkbLX4Qnss8o5bnt0yQa0Tb7Azbh5/5otju5kStVAD2E+zMGrMP++NriGyZV87crduh0J8l4JUTA==} + /@aws-sdk/credential-provider-node@3.427.0: + resolution: {integrity: sha512-wYYbQ57nKL8OfgRbl8k6uXcdnYml+p3LSSfDUAuUEp1HKlQ8lOXFJ3BdLr5qrk7LhpyppSRnWBmh2c3kWa7ANQ==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/credential-provider-env': 3.378.0 - '@aws-sdk/credential-provider-ini': 3.385.0 - '@aws-sdk/credential-provider-process': 3.378.0 - '@aws-sdk/credential-provider-sso': 3.385.0 - '@aws-sdk/credential-provider-web-identity': 3.378.0 - '@aws-sdk/types': 3.378.0 - '@smithy/credential-provider-imds': 2.0.1 - '@smithy/property-provider': 2.0.1 - '@smithy/shared-ini-file-loader': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/credential-provider-env': 3.425.0 + '@aws-sdk/credential-provider-ini': 3.427.0 + '@aws-sdk/credential-provider-process': 3.425.0 + '@aws-sdk/credential-provider-sso': 3.427.0 + '@aws-sdk/credential-provider-web-identity': 3.425.0 + '@aws-sdk/types': 3.425.0 + '@smithy/credential-provider-imds': 2.0.16 + '@smithy/property-provider': 2.0.12 + '@smithy/shared-ini-file-loader': 2.2.0 + '@smithy/types': 2.3.5 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/credential-provider-process@3.378.0: - resolution: {integrity: sha512-KFTIy7u+wXj3eDua4rgS0tODzMnXtXhAm1RxzCW9FL5JLBBrd82ymCj1Dp72217Sw5Do6NjCnDTTNkCHZMA77w==} + /@aws-sdk/credential-provider-process@3.425.0: + resolution: {integrity: sha512-YY6tkLdvtb1Fgofp3b1UWO+5vwS14LJ/smGmuGpSba0V7gFJRdcrJ9bcb9vVgAGuMdjzRJ+bUKlLLtqXkaykEw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/property-provider': 2.0.1 - '@smithy/shared-ini-file-loader': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/property-provider': 2.0.12 + '@smithy/shared-ini-file-loader': 2.2.0 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/credential-provider-sso@3.385.0: - resolution: {integrity: sha512-ETFnS+4ZKTAgT8boVpIpRuXA9wWGpNqOcI1RXtjsaIgQ9s8uNn2JPa8l71gZh861mzBC8Hadp1EpNu+43w4lkg==} + /@aws-sdk/credential-provider-sso@3.427.0: + resolution: {integrity: sha512-c+tXyS/i49erHs4bAp6vKNYeYlyQ0VNMBgoco0LCn1rL0REtHbfhWMnqDLF6c2n3yIWDOTrQu0D73Idnpy16eA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/client-sso': 3.382.0 - '@aws-sdk/token-providers': 3.385.0 - '@aws-sdk/types': 3.378.0 - '@smithy/property-provider': 2.0.1 - '@smithy/shared-ini-file-loader': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/client-sso': 3.427.0 + '@aws-sdk/token-providers': 3.427.0 + '@aws-sdk/types': 3.425.0 + '@smithy/property-provider': 2.0.12 + '@smithy/shared-ini-file-loader': 2.2.0 + '@smithy/types': 2.3.5 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/credential-provider-web-identity@3.378.0: - resolution: {integrity: sha512-GWjydOszhc4xDF8xuPtBvboglXQr0gwCW1oHAvmLcOT38+Hd6qnKywnMSeoXYRPgoKfF9TkWQgW1jxplzCG0UA==} + /@aws-sdk/credential-provider-web-identity@3.425.0: + resolution: {integrity: sha512-/0R65TgRzL01JU3SzloivWNwdkbIhr06uY/F5pBHf/DynQqaspKNfdHn6AiozgSVDfwRHFjKBTUy6wvf3QFkuA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/property-provider': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/property-provider': 2.0.12 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/credential-providers@3.385.0: - resolution: {integrity: sha512-II4WAFMk061Ud6n1Pux+5T3FQe6gLIwmpF+QgMH97TxJZWFiKyhmJ1Z0VArjo1wwcEPMyIN21Ij91ayop8agwQ==} + /@aws-sdk/credential-providers@3.427.0: + resolution: {integrity: sha512-rKKohSHju462vo+uQnPjcEZPBAfAMgGH6K1XyyCNpuOC0yYLkG87PYpvAQeb8riTrkHPX0dYUHuTHZ6zQgMGjA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/client-cognito-identity': 3.385.0 - '@aws-sdk/client-sso': 3.382.0 - '@aws-sdk/client-sts': 3.385.0 - '@aws-sdk/credential-provider-cognito-identity': 3.385.0 - '@aws-sdk/credential-provider-env': 3.378.0 - '@aws-sdk/credential-provider-ini': 3.385.0 - '@aws-sdk/credential-provider-node': 3.385.0 - '@aws-sdk/credential-provider-process': 3.378.0 - '@aws-sdk/credential-provider-sso': 3.385.0 - '@aws-sdk/credential-provider-web-identity': 3.378.0 - '@aws-sdk/types': 3.378.0 - '@smithy/credential-provider-imds': 2.0.1 - '@smithy/property-provider': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/client-cognito-identity': 3.427.0 + '@aws-sdk/client-sso': 3.427.0 + '@aws-sdk/client-sts': 3.427.0 + '@aws-sdk/credential-provider-cognito-identity': 3.427.0 + '@aws-sdk/credential-provider-env': 3.425.0 + '@aws-sdk/credential-provider-http': 3.425.0 + '@aws-sdk/credential-provider-ini': 3.427.0 + '@aws-sdk/credential-provider-node': 3.427.0 + '@aws-sdk/credential-provider-process': 3.425.0 + '@aws-sdk/credential-provider-sso': 3.427.0 + '@aws-sdk/credential-provider-web-identity': 3.425.0 + '@aws-sdk/types': 3.425.0 + '@smithy/credential-provider-imds': 2.0.16 + '@smithy/property-provider': 2.0.12 + '@smithy/types': 2.3.5 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false optional: true - /@aws-sdk/middleware-host-header@3.379.1: - resolution: {integrity: sha512-LI4KpAFWNWVr2aH2vRVblr0Y8tvDz23lj8LOmbDmCrzd5M21nxuocI/8nEAQj55LiTIf9Zs+dHCdsyegnFXdrA==} + /@aws-sdk/middleware-host-header@3.425.0: + resolution: {integrity: sha512-E5Gt41LObQ+cr8QnLthwsH3MtVSNXy1AKJMowDr85h0vzqA/FHUkgHyOGntgozzjXT5M0MaSRYxS0xwTR5D4Ew==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/protocol-http': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/protocol-http': 3.0.7 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/middleware-logger@3.378.0: - resolution: {integrity: sha512-l1DyaDLm3KeBMNMuANI3scWh8Xvu248x+vw6Z7ExWOhGXFmQ1MW7YvASg/SdxWkhlF9HmkkTif1LdMB22x6QDA==} + /@aws-sdk/middleware-logger@3.425.0: + resolution: {integrity: sha512-INE9XWRXx2f4a/r2vOU0tAmgctVp7nEaEasemNtVBYhqbKLZvr9ndLBSgKGgJ8LIcXAoISipaMuFiqIGkFsm7A==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/middleware-recursion-detection@3.378.0: - resolution: {integrity: sha512-mUMfHAz0oGNIWiTZHTVJb+I515Hqs2zx1j36Le4MMiiaMkPW1SRUF1FIwGuc1wh6E8jB5q+XfEMriDjRi4TZRA==} + /@aws-sdk/middleware-recursion-detection@3.425.0: + resolution: {integrity: sha512-77gnzJ5b91bgD75L/ugpOyerx6lR3oyS4080X1YI58EzdyBMkDrHM4FbMcY2RynETi3lwXCFzLRyZjWXY1mRlw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/protocol-http': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/protocol-http': 3.0.7 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/middleware-sdk-sts@3.379.1: - resolution: {integrity: sha512-SK3gSyT0XbLiY12+AjLFYL9YngxOXHnZF3Z33Cdd4a+AUYrVBV7JBEEGD1Nlwrcmko+3XgaKlmgUaR5s91MYvg==} + /@aws-sdk/middleware-sdk-sts@3.425.0: + resolution: {integrity: sha512-JFojrg76oKAoBknnr9EL5N2aJ1mRCtBqXoZYST58GSx8uYdFQ89qS65VNQ8JviBXzsrCNAn4vDhZ5Ch5E6TxGQ==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/middleware-signing': 3.379.1 - '@aws-sdk/types': 3.378.0 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/middleware-signing': 3.425.0 + '@aws-sdk/types': 3.425.0 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/middleware-signing@3.379.1: - resolution: {integrity: sha512-kBk2ZUvR84EM4fICjr8K+Ykpf8SI1UzzPp2/UVYZ0X+4H/ZCjfSqohGRwHykMqeplne9qHSL7/rGJs1H3l3gPg==} + /@aws-sdk/middleware-signing@3.425.0: + resolution: {integrity: sha512-ZpOfgJHk7ovQ0sSwg3tU4NxFOnz53lJlkJRf7S+wxQALHM0P2MJ6LYBrZaFMVsKiJxNIdZBXD6jclgHg72ZW6Q==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/property-provider': 2.0.1 - '@smithy/protocol-http': 2.0.1 - '@smithy/signature-v4': 2.0.1 - '@smithy/types': 2.0.2 - '@smithy/util-middleware': 2.0.0 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/property-provider': 2.0.12 + '@smithy/protocol-http': 3.0.7 + '@smithy/signature-v4': 2.0.11 + '@smithy/types': 2.3.5 + '@smithy/util-middleware': 2.0.4 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/middleware-user-agent@3.382.0: - resolution: {integrity: sha512-LFRW1jmXOrOAd3911ktn6oaYmuurNnulbdRMOUdwz99GGdLVFipQhOi9idKswb8IOhPa4jEVQt25Kcv7ctvu0A==} + /@aws-sdk/middleware-user-agent@3.427.0: + resolution: {integrity: sha512-y9HxYsNvnA3KqDl8w1jHeCwz4P9CuBEtu/G+KYffLeAMBsMZmh4SIkFFCO9wE/dyYg6+yo07rYcnnIfy7WA0bw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@aws-sdk/util-endpoints': 3.382.0 - '@smithy/protocol-http': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@aws-sdk/util-endpoints': 3.427.0 + '@smithy/protocol-http': 3.0.7 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/token-providers@3.385.0: - resolution: {integrity: sha512-2A2Y7/bU5EaxQwLwLy7ojs+Wy5VOBkIlGPH7ZcpPaoQ1Hscwn3Wvx/DZmOvbyYfZ1CbIFutoHJlVxh6KZldUDw==} + /@aws-sdk/region-config-resolver@3.425.0: + resolution: {integrity: sha512-u7uv/iUOapIJdRgRkO3wnpYsUgV6ponsZJQgVg/8L+n+Vo5PQL5gAcIuAOwcYSKQPFaeK+KbmByI4SyOK203Vw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/property-provider': 2.0.1 - '@smithy/shared-ini-file-loader': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/node-config-provider': 2.1.1 + '@smithy/types': 2.3.5 + '@smithy/util-config-provider': 2.0.0 + '@smithy/util-middleware': 2.0.4 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/types@3.378.0: - resolution: {integrity: sha512-qP0CvR/ItgktmN8YXpGQglzzR/6s0nrsQ4zIfx3HMwpsBTwuouYahcCtF1Vr82P4NFcoDA412EJahJ2pIqEd+w==} + /@aws-sdk/token-providers@3.427.0: + resolution: {integrity: sha512-4E5E+4p8lJ69PBY400dJXF06LUHYx5lkKzBEsYqWWhoZcoftrvi24ltIhUDoGVLkrLcTHZIWSdFAWSos4hXqeg==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/middleware-host-header': 3.425.0 + '@aws-sdk/middleware-logger': 3.425.0 + '@aws-sdk/middleware-recursion-detection': 3.425.0 + '@aws-sdk/middleware-user-agent': 3.427.0 + '@aws-sdk/types': 3.425.0 + '@aws-sdk/util-endpoints': 3.427.0 + '@aws-sdk/util-user-agent-browser': 3.425.0 + '@aws-sdk/util-user-agent-node': 3.425.0 + '@smithy/config-resolver': 2.0.14 + '@smithy/fetch-http-handler': 2.2.2 + '@smithy/hash-node': 2.0.11 + '@smithy/invalid-dependency': 2.0.11 + '@smithy/middleware-content-length': 2.0.13 + '@smithy/middleware-endpoint': 2.0.11 + '@smithy/middleware-retry': 2.0.16 + '@smithy/middleware-serde': 2.0.11 + '@smithy/middleware-stack': 2.0.5 + '@smithy/node-config-provider': 2.1.1 + '@smithy/node-http-handler': 2.1.7 + '@smithy/property-provider': 2.0.12 + '@smithy/protocol-http': 3.0.7 + '@smithy/shared-ini-file-loader': 2.2.0 + '@smithy/smithy-client': 2.1.10 + '@smithy/types': 2.3.5 + '@smithy/url-parser': 2.0.11 + '@smithy/util-base64': 2.0.0 + '@smithy/util-body-length-browser': 2.0.0 + '@smithy/util-body-length-node': 2.1.0 + '@smithy/util-defaults-mode-browser': 2.0.14 + '@smithy/util-defaults-mode-node': 2.0.18 + '@smithy/util-retry': 2.0.4 + '@smithy/util-utf8': 2.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt dev: false optional: true - /@aws-sdk/util-endpoints@3.382.0: - resolution: {integrity: sha512-flajPyjmjNG67fXk7l4GoTB/7J11VBqtFZXuuAZKhKU07Ia3IQupsFqNf5lV8D44ZgjnKH0fTGnv3dUALjW7Wg==} + /@aws-sdk/types@3.425.0: + resolution: {integrity: sha512-6lqbmorwerN4v+J5dqbHPAsjynI0mkEF+blf+69QTaKKGaxBBVaXgqoqul9RXYcK5MMrrYRbQIMd0zYOoy90kA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 + dev: false + optional: true + + /@aws-sdk/util-endpoints@3.427.0: + resolution: {integrity: sha512-rSyiAIFF/EVvity/+LWUqoTMJ0a25RAc9iqx0WZ4tf1UjuEXRRXxZEb+jEZg1bk+pY84gdLdx9z5E+MSJCZxNQ==} + engines: {node: '>=14.0.0'} + requiresBuild: true + dependencies: + '@aws-sdk/types': 3.425.0 + '@smithy/node-config-provider': 2.1.1 + tslib: 2.6.2 dev: false optional: true @@ -663,23 +728,23 @@ packages: engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/util-user-agent-browser@3.378.0: - resolution: {integrity: sha512-FSCpagzftK1W+m7Ar6lpX7/Gr9y5P56nhFYz8U4EYQ4PkufS6czWX9YW+/FA5OYV0vlQ/SvPqMnzoHIPUNhZrQ==} + /@aws-sdk/util-user-agent-browser@3.425.0: + resolution: {integrity: sha512-22Y9iMtjGcFjGILR6/xdp1qRezlHVLyXtnpEsbuPTiernRCPk6zfAnK/ATH77r02MUjU057tdxVkd5umUBTn9Q==} requiresBuild: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/types': 2.0.2 + '@aws-sdk/types': 3.425.0 + '@smithy/types': 2.3.5 bowser: 2.11.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@aws-sdk/util-user-agent-node@3.378.0: - resolution: {integrity: sha512-IdwVJV0E96MkJeFte4dlWqvB+oiqCiZ5lOlheY3W9NynTuuX0GGYNC8Y9yIsV8Oava1+ujpJq0ww6qXdYxmO4A==} + /@aws-sdk/util-user-agent-node@3.425.0: + resolution: {integrity: sha512-SIR4F5uQeeVAi8lv4OgRirtdtNi5zeyogTuQgGi9su8F/WP1N6JqxofcwpUY5f8/oJ2UlXr/tx1f09UHfJJzvA==} engines: {node: '>=14.0.0'} requiresBuild: true peerDependencies: @@ -688,10 +753,10 @@ packages: aws-crt: optional: true dependencies: - '@aws-sdk/types': 3.378.0 - '@smithy/node-config-provider': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@aws-sdk/types': 3.425.0 + '@smithy/node-config-provider': 2.1.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true @@ -699,7 +764,7 @@ packages: resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true @@ -2269,15 +2334,15 @@ packages: resolution: {integrity: sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==} dev: false - /@google-cloud/firestore@6.7.0: - resolution: {integrity: sha512-bkH2jb5KkQSUa+NAvpip9HQ+rpYhi77IaqHovWuN07adVmvNXX08gPpvPWEzoXYa/wDjEVI7LiAtCWkJJEYTNg==} + /@google-cloud/firestore@6.8.0: + resolution: {integrity: sha512-JRpk06SmZXLGz0pNx1x7yU3YhkUXheKgH5hbDZ4kMsdhtfV5qPLJLRI4wv69K0cZorIk+zTMOwptue7hizo0eA==} engines: {node: '>=12.0.0'} requiresBuild: true dependencies: fast-deep-equal: 3.1.3 functional-red-black-tree: 1.0.1 google-gax: 3.6.1 - protobufjs: 7.2.4 + protobufjs: 7.2.5 transitivePeerDependencies: - encoding - supports-color @@ -2356,7 +2421,7 @@ packages: '@types/long': 4.0.2 lodash.camelcase: 4.3.0 long: 4.0.0 - protobufjs: 7.2.4 + protobufjs: 7.2.5 yargs: 17.7.2 dev: false optional: true @@ -2460,6 +2525,14 @@ packages: dev: false optional: true + /@mongodb-js/saslprep@1.1.0: + resolution: {integrity: sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==} + requiresBuild: true + dependencies: + sparse-bitfield: 3.0.3 + dev: false + optional: true + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2706,82 +2779,83 @@ packages: rollup: 2.79.1 dev: false - /@smithy/abort-controller@2.0.1: - resolution: {integrity: sha512-0s7XjIbsTwZyUW9OwXQ8J6x1UiA1TNCh60Vaw56nHahL7kUZsLhmTlWiaxfLkFtO2Utkj8YewcpHTYpxaTzO+w==} + /@smithy/abort-controller@2.0.11: + resolution: {integrity: sha512-MSzE1qR2JNyb7ot3blIOT3O3H0Jn06iNDEgHRaqZUwBgx5EG+VIx24Y21tlKofzYryIOcWpIohLrIIyocD6LMA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/config-resolver@2.0.1: - resolution: {integrity: sha512-l83Pm7hV+8CBQOCmBRopWDtF+CURUJol7NsuPYvimiDhkC2F8Ba9T1imSFE+pD1UIJ9jlsDPAnZfPJT5cjnuEw==} + /@smithy/config-resolver@2.0.14: + resolution: {integrity: sha512-K1K+FuWQoy8j/G7lAmK85o03O89s2Vvh6kMFmzEmiHUoQCRH1rzbDtMnGNiaMHeSeYJ6y79IyTusdRG+LuWwtg==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 + '@smithy/node-config-provider': 2.1.1 + '@smithy/types': 2.3.5 '@smithy/util-config-provider': 2.0.0 - '@smithy/util-middleware': 2.0.0 - tslib: 2.6.1 + '@smithy/util-middleware': 2.0.4 + tslib: 2.6.2 dev: false optional: true - /@smithy/credential-provider-imds@2.0.1: - resolution: {integrity: sha512-8VxriuRINNEfVZjEFKBY75y9ZWAx73DZ5K/u+3LmB6r8WR2h3NaFxFKMlwlq0uzNdGhD1ouKBn9XWEGYHKiPLw==} + /@smithy/credential-provider-imds@2.0.16: + resolution: {integrity: sha512-tKa2xF+69TvGxJT+lnJpGrKxUuAZDLYXFhqnPEgnHz+psTpkpcB4QRjHj63+uj83KaeFJdTfW201eLZeRn6FfA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/node-config-provider': 2.0.1 - '@smithy/property-provider': 2.0.1 - '@smithy/types': 2.0.2 - '@smithy/url-parser': 2.0.1 - tslib: 2.6.1 + '@smithy/node-config-provider': 2.1.1 + '@smithy/property-provider': 2.0.12 + '@smithy/types': 2.3.5 + '@smithy/url-parser': 2.0.11 + tslib: 2.6.2 dev: false optional: true - /@smithy/eventstream-codec@2.0.1: - resolution: {integrity: sha512-/IiNB7gQM2y2ZC/GAWOWDa8+iXfhr1g9Xe5979cQEOdCWDISvrAiv18cn3OtIQUhbYOR3gm7QtCpkq1to2takQ==} + /@smithy/eventstream-codec@2.0.11: + resolution: {integrity: sha512-BQCTjxhCYRZIfXapa2LmZSaH8QUBGwMZw7XRN83hrdixbLjIcj+o549zjkedFS07Ve2TlvWUI6BTzP+nv7snBA==} requiresBuild: true dependencies: '@aws-crypto/crc32': 3.0.0 - '@smithy/types': 2.0.2 + '@smithy/types': 2.3.5 '@smithy/util-hex-encoding': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/fetch-http-handler@2.0.1: - resolution: {integrity: sha512-/SoU/ClazgcdOxgE4zA7RX8euiELwpsrKCSvulVQvu9zpmqJRyEJn8ZTWYFV17/eHOBdHTs9kqodhNhsNT+cUw==} + /@smithy/fetch-http-handler@2.2.2: + resolution: {integrity: sha512-K7aRtRuaBjzlk+jWWeyfDTLAmRRvmA4fU8eHUXtjsuEDgi3f356ZE32VD2ssxIH13RCLVZbXMt5h7wHzYiSuVA==} requiresBuild: true dependencies: - '@smithy/protocol-http': 2.0.1 - '@smithy/querystring-builder': 2.0.1 - '@smithy/types': 2.0.2 + '@smithy/protocol-http': 3.0.7 + '@smithy/querystring-builder': 2.0.11 + '@smithy/types': 2.3.5 '@smithy/util-base64': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/hash-node@2.0.1: - resolution: {integrity: sha512-oTKYimQdF4psX54ZonpcIE+MXjMUWFxLCNosjPkJPFQ9whRX0K/PFX/+JZGRQh3zO9RlEOEUIbhy9NO+Wha6hw==} + /@smithy/hash-node@2.0.11: + resolution: {integrity: sha512-PbleVugN2tbhl1ZoNWVrZ1oTFFas/Hq+s6zGO8B9bv4w/StTriTKA9W+xZJACOj9X7zwfoTLbscM+avCB1KqOQ==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 + '@smithy/types': 2.3.5 '@smithy/util-buffer-from': 2.0.0 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/invalid-dependency@2.0.1: - resolution: {integrity: sha512-2q/Eb0AE662zwyMV+z+TL7deBwcHCgaZZGc0RItamBE8kak3MzCi/EZCNoFWoBfxgQ4jfR12wm8KKsSXhJzJtQ==} + /@smithy/invalid-dependency@2.0.11: + resolution: {integrity: sha512-zazq99ujxYv/NOf9zh7xXbNgzoVLsqE0wle8P/1zU/XdhPi/0zohTPKWUzIxjGdqb5hkkwfBkNkl5H+LE0mvgw==} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true @@ -2790,195 +2864,199 @@ packages: engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/middleware-content-length@2.0.1: - resolution: {integrity: sha512-IZhRSk5GkVBcrKaqPXddBS2uKhaqwBgaSgbBb1OJyGsKe7SxRFbclWS0LqOR9fKUkDl+3lL8E2ffpo6EQg0igw==} + /@smithy/middleware-content-length@2.0.13: + resolution: {integrity: sha512-Md2kxWpaec3bXp1oERFPQPBhOXCkGSAF7uc1E+4rkwjgw3/tqAXRtbjbggu67HJdwaif76As8AV6XxbD1HzqTQ==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/protocol-http': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/protocol-http': 3.0.7 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/middleware-endpoint@2.0.1: - resolution: {integrity: sha512-uz/KI1MBd9WHrrkVFZO4L4Wyv24raf0oR4EsOYEeG5jPJO5U+C7MZGLcMxX8gWERDn1sycBDqmGv8fjUMLxT6w==} + /@smithy/middleware-endpoint@2.0.11: + resolution: {integrity: sha512-mCugsvB15up6fqpzUEpMT4CuJmFkEI+KcozA7QMzYguXCaIilyMKsyxgamwmr+o7lo3QdjN0//XLQ9bWFL129g==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/middleware-serde': 2.0.1 - '@smithy/types': 2.0.2 - '@smithy/url-parser': 2.0.1 - '@smithy/util-middleware': 2.0.0 - tslib: 2.6.1 + '@smithy/middleware-serde': 2.0.11 + '@smithy/types': 2.3.5 + '@smithy/url-parser': 2.0.11 + '@smithy/util-middleware': 2.0.4 + tslib: 2.6.2 dev: false optional: true - /@smithy/middleware-retry@2.0.1: - resolution: {integrity: sha512-NKHF4i0gjSyjO6C0ZyjEpNqzGgIu7s8HOK6oT/1Jqws2Q1GynR1xV8XTUs1gKXeaNRzbzKQRewHHmfPwZjOtHA==} + /@smithy/middleware-retry@2.0.16: + resolution: {integrity: sha512-Br5+0yoiMS0ugiOAfJxregzMMGIRCbX4PYo1kDHtLgvkA/d++aHbnHB819m5zOIAMPvPE7AThZgcsoK+WOsUTA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/protocol-http': 2.0.1 - '@smithy/service-error-classification': 2.0.0 - '@smithy/types': 2.0.2 - '@smithy/util-middleware': 2.0.0 - '@smithy/util-retry': 2.0.0 - tslib: 2.6.1 + '@smithy/node-config-provider': 2.1.1 + '@smithy/protocol-http': 3.0.7 + '@smithy/service-error-classification': 2.0.4 + '@smithy/types': 2.3.5 + '@smithy/util-middleware': 2.0.4 + '@smithy/util-retry': 2.0.4 + tslib: 2.6.2 uuid: 8.3.2 dev: false optional: true - /@smithy/middleware-serde@2.0.1: - resolution: {integrity: sha512-uKxPaC6ItH9ZXdpdqNtf8sda7GcU4SPMp0tomq/5lUg9oiMa/Q7+kD35MUrpKaX3IVXVrwEtkjCU9dogZ/RAUA==} + /@smithy/middleware-serde@2.0.11: + resolution: {integrity: sha512-NuxnjMyf4zQqhwwdh0OTj5RqpnuT6HcH5Xg5GrPijPcKzc2REXVEVK4Yyk8ckj8ez1XSj/bCmJ+oNjmqB02GWA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/middleware-stack@2.0.0: - resolution: {integrity: sha512-31XC1xNF65nlbc16yuh3wwTudmqs6qy4EseQUGF8A/p2m/5wdd/cnXJqpniy/XvXVwkHPz/GwV36HqzHtIKATQ==} + /@smithy/middleware-stack@2.0.5: + resolution: {integrity: sha512-bVQU/rZzBY7CbSxIrDTGZYnBWKtIw+PL/cRc9B7etZk1IKSOe0NvKMJyWllfhfhrTeMF6eleCzOihIQympAvPw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/node-config-provider@2.0.1: - resolution: {integrity: sha512-Zoel4CPkKRTQ2XxmozZUfqBYqjPKL53/SvTDhJHj+VBSiJy6MXRav1iDCyFPS92t40Uh+Yi+Km5Ch3hQ+c/zSA==} + /@smithy/node-config-provider@2.1.1: + resolution: {integrity: sha512-1lF6s1YWBi1LBu2O30tD3jyTgMtuvk/Z1twzXM4GPYe4dmZix4nNREPJIPOcfFikNU2o0eTYP80+izx5F2jIJA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/property-provider': 2.0.1 - '@smithy/shared-ini-file-loader': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/property-provider': 2.0.12 + '@smithy/shared-ini-file-loader': 2.2.0 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/node-http-handler@2.0.1: - resolution: {integrity: sha512-Zv3fxk3p9tsmPT2CKMsbuwbbxnq2gzLDIulxv+yI6aE+02WPYorObbbe9gh7SW3weadMODL1vTfOoJ9yFypDzg==} + /@smithy/node-http-handler@2.1.7: + resolution: {integrity: sha512-PQIKZXlp3awCDn/xNlCSTFE7aYG/5Tx33M05NfQmWYeB5yV1GZZOSz4dXpwiNJYTXb9jPqjl+ueXXkwtEluFFA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/abort-controller': 2.0.1 - '@smithy/protocol-http': 2.0.1 - '@smithy/querystring-builder': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/abort-controller': 2.0.11 + '@smithy/protocol-http': 3.0.7 + '@smithy/querystring-builder': 2.0.11 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/property-provider@2.0.1: - resolution: {integrity: sha512-pmJRyY9SF6sutWIktIhe+bUdSQDxv/qZ4mYr3/u+u45riTPN7nmRxPo+e4sjWVoM0caKFjRSlj3tf5teRFy0Vg==} + /@smithy/property-provider@2.0.12: + resolution: {integrity: sha512-Un/OvvuQ1Kg8WYtoMCicfsFFuHb/TKL3pCA6ZIo/WvNTJTR94RtoRnL7mY4XkkUAoFMyf6KjcQJ76y1FX7S5rw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/protocol-http@2.0.1: - resolution: {integrity: sha512-mrkMAp0wtaDEIkgRObWYxI1Kun1tm6Iu6rK+X4utb6Ah7Uc3Kk4VIWwK/rBHdYGReiLIrxFCB1rq4a2gyZnSgg==} + /@smithy/protocol-http@3.0.7: + resolution: {integrity: sha512-HnZW8y+r66ntYueCDbLqKwWcMNWW8o3eVpSrHNluwtBJ/EUWfQHRKSiu6vZZtc6PGfPQWgVfucoCE/C3QufMAA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/querystring-builder@2.0.1: - resolution: {integrity: sha512-bp+93WFzx1FojVEIeFPtG0A1pKsFdCUcZvVdZdRlmNooOUrz9Mm9bneRd8hDwAQ37pxiZkCOxopSXXRQN10mYw==} + /@smithy/querystring-builder@2.0.11: + resolution: {integrity: sha512-b4kEbVMxpmfv2VWUITn2otckTi7GlMteZQxi+jlwedoATOGEyrCJPfRcYQJjbCi3fZ2QTfh3PcORvB27+j38Yg==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 + '@smithy/types': 2.3.5 '@smithy/util-uri-escape': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/querystring-parser@2.0.1: - resolution: {integrity: sha512-h+e7k1z+IvI2sSbUBG9Aq46JsgLl4UqIUl6aigAlRBj+P6ocNXpM6Yn1vMBw5ijtXeZbYpd1YvCxwDgdw3jhmg==} + /@smithy/querystring-parser@2.0.11: + resolution: {integrity: sha512-YXe7jhi7s3dQ0Fu9dLoY/gLu6NCyy8tBWJL/v2c9i7/RLpHgKT+uT96/OqZkHizCJ4kr0ZD46tzMjql/o60KLg==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/service-error-classification@2.0.0: - resolution: {integrity: sha512-2z5Nafy1O0cTf69wKyNjGW/sNVMiqDnb4jgwfMG8ye8KnFJ5qmJpDccwIbJNhXIfbsxTg9SEec2oe1cexhMJvw==} + /@smithy/service-error-classification@2.0.4: + resolution: {integrity: sha512-77506l12I5gxTZqBkx3Wb0RqMG81bMYLaVQ+EqIWFwQDJRs5UFeXogKxSKojCmz1wLUziHZQXm03MBzPQiumQw==} engines: {node: '>=14.0.0'} requiresBuild: true + dependencies: + '@smithy/types': 2.3.5 dev: false optional: true - /@smithy/shared-ini-file-loader@2.0.1: - resolution: {integrity: sha512-a463YiZrPGvM+F336rIF8pLfQsHAdCRAn/BiI/EWzg5xLoxbC7GSxIgliDDXrOu0z8gT3nhVsif85eU6jyct3A==} + /@smithy/shared-ini-file-loader@2.2.0: + resolution: {integrity: sha512-xFXqs4vAb5BdkzHSRrTapFoaqS4/3m/CGZzdw46fBjYZ0paYuLAoMY60ICCn1FfGirG+PiJ3eWcqJNe4/SkfyA==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/signature-v4@2.0.1: - resolution: {integrity: sha512-jztv5Mirca42ilxmMDjzLdXcoAmRhZskGafGL49sRo5u7swEZcToEFrq6vtX5YMbSyTVrE9Teog5EFexY5Ff2Q==} + /@smithy/signature-v4@2.0.11: + resolution: {integrity: sha512-EFVU1dT+2s8xi227l1A9O27edT/GNKvyAK6lZnIZ0zhIHq/jSLznvkk15aonGAM1kmhmZBVGpI7Tt0odueZK9A==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/eventstream-codec': 2.0.1 + '@smithy/eventstream-codec': 2.0.11 '@smithy/is-array-buffer': 2.0.0 - '@smithy/types': 2.0.2 + '@smithy/types': 2.3.5 '@smithy/util-hex-encoding': 2.0.0 - '@smithy/util-middleware': 2.0.0 + '@smithy/util-middleware': 2.0.4 '@smithy/util-uri-escape': 2.0.0 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/smithy-client@2.0.1: - resolution: {integrity: sha512-LHC5m6tYpEu1iNbONfvMbwtErboyTZJfEIPoD78Ei5MVr36vZQCaCla5mvo36+q/a2NAk2//fA5Rx3I1Kf7+lQ==} + /@smithy/smithy-client@2.1.10: + resolution: {integrity: sha512-2OEmZDiW1Z196QHuQZ5M6cBE8FCSG0H2HADP1G+DY8P3agsvb0YJyfhyKuJbxIQy15tr3eDAK6FOrlbxgKOOew==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/middleware-stack': 2.0.0 - '@smithy/types': 2.0.2 - '@smithy/util-stream': 2.0.1 - tslib: 2.6.1 + '@smithy/middleware-stack': 2.0.5 + '@smithy/types': 2.3.5 + '@smithy/util-stream': 2.0.15 + tslib: 2.6.2 dev: false optional: true - /@smithy/types@2.0.2: - resolution: {integrity: sha512-wcymEjIXQ9+NEfE5Yt5TInAqe1o4n+Nh+rh00AwoazppmUt8tdo6URhc5gkDcOYrcvlDVAZE7uG69nDpEGUKxw==} + /@smithy/types@2.3.5: + resolution: {integrity: sha512-ehyDt8M9hehyxrLQGoA1BGPou8Js1Ocoh5M0ngDhJMqbFmNK5N6Xhr9/ZExWkyIW8XcGkiMPq3ZUEE0ScrhbuQ==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/url-parser@2.0.1: - resolution: {integrity: sha512-NpHVOAwddo+OyyIoujDL9zGL96piHWrTNXqltWmBvlUoWgt1HPyBuKs6oHjioyFnNZXUqveTOkEEq0U5w6Uv8A==} + /@smithy/url-parser@2.0.11: + resolution: {integrity: sha512-h89yXMCCF+S5k9XIoKltMIWTYj+FcEkU/IIFZ6RtE222fskOTL4Iak6ZRG+ehSvZDt8yKEcxqheTDq7JvvtK3g==} requiresBuild: true dependencies: - '@smithy/querystring-parser': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/querystring-parser': 2.0.11 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true @@ -2988,7 +3066,7 @@ packages: requiresBuild: true dependencies: '@smithy/util-buffer-from': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true @@ -2996,16 +3074,16 @@ packages: resolution: {integrity: sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/util-body-length-node@2.0.0: - resolution: {integrity: sha512-ZV7Z/WHTMxHJe/xL/56qZwSUcl63/5aaPAGjkfynJm4poILjdD4GmFI+V+YWabh2WJIjwTKZ5PNsuvPQKt93Mg==} + /@smithy/util-body-length-node@2.1.0: + resolution: {integrity: sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true @@ -3015,7 +3093,7 @@ packages: requiresBuild: true dependencies: '@smithy/is-array-buffer': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true @@ -3024,33 +3102,35 @@ packages: engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/util-defaults-mode-browser@2.0.1: - resolution: {integrity: sha512-w72Qwsb+IaEYEFtYICn0Do42eFju78hTaBzzJfT107lFOPdbjWjKnFutV+6GL/nZd5HWXY7ccAKka++C3NrjHw==} + /@smithy/util-defaults-mode-browser@2.0.14: + resolution: {integrity: sha512-NupG7SWUucm3vJrvlpt9jG1XeoPJphjcivgcUUXhDJbUPy4F04LhlTiAhWSzwlCNcF8OJsMvZ/DWbpYD3pselw==} engines: {node: '>= 10.0.0'} requiresBuild: true dependencies: - '@smithy/property-provider': 2.0.1 - '@smithy/types': 2.0.2 + '@smithy/property-provider': 2.0.12 + '@smithy/smithy-client': 2.1.10 + '@smithy/types': 2.3.5 bowser: 2.11.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/util-defaults-mode-node@2.0.1: - resolution: {integrity: sha512-dNF45caelEBambo0SgkzQ0v76m4YM+aFKZNTtSafy7P5dVF8TbjZuR2UX1A5gJABD9XK6lzN+v/9Yfzj/EDgGg==} + /@smithy/util-defaults-mode-node@2.0.18: + resolution: {integrity: sha512-+3jMom/b/Cdp21tDnY4vKu249Al+G/P0HbRbct7/aSZDlROzv1tksaYukon6UUv7uoHn+/McqnsvqZHLlqvQ0g==} engines: {node: '>= 10.0.0'} requiresBuild: true dependencies: - '@smithy/config-resolver': 2.0.1 - '@smithy/credential-provider-imds': 2.0.1 - '@smithy/node-config-provider': 2.0.1 - '@smithy/property-provider': 2.0.1 - '@smithy/types': 2.0.2 - tslib: 2.6.1 + '@smithy/config-resolver': 2.0.14 + '@smithy/credential-provider-imds': 2.0.16 + '@smithy/node-config-provider': 2.1.1 + '@smithy/property-provider': 2.0.12 + '@smithy/smithy-client': 2.1.10 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true @@ -3059,42 +3139,44 @@ packages: engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true - /@smithy/util-middleware@2.0.0: - resolution: {integrity: sha512-eCWX4ECuDHn1wuyyDdGdUWnT4OGyIzV0LN1xRttBFMPI9Ff/4heSHVxneyiMtOB//zpXWCha1/SWHJOZstG7kA==} + /@smithy/util-middleware@2.0.4: + resolution: {integrity: sha512-Pbu6P4MBwRcjrLgdTR1O4Y3c0sTZn2JdOiJNcgL7EcIStcQodj+6ZTXtbyU/WTEU3MV2NMA10LxFc3AWHZ3+4A==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/util-retry@2.0.0: - resolution: {integrity: sha512-/dvJ8afrElasuiiIttRJeoS2sy8YXpksQwiM/TcepqdRVp7u4ejd9C4IQURHNjlfPUT7Y6lCDSa2zQJbdHhVTg==} + /@smithy/util-retry@2.0.4: + resolution: {integrity: sha512-b+n1jBBKc77C1E/zfBe1Zo7S9OXGBiGn55N0apfhZHxPUP/fMH5AhFUUcWaJh7NAnah284M5lGkBKuhnr3yK5w==} engines: {node: '>= 14.0.0'} requiresBuild: true dependencies: - '@smithy/service-error-classification': 2.0.0 - tslib: 2.6.1 + '@smithy/service-error-classification': 2.0.4 + '@smithy/types': 2.3.5 + tslib: 2.6.2 dev: false optional: true - /@smithy/util-stream@2.0.1: - resolution: {integrity: sha512-2a0IOtwIKC46EEo7E7cxDN8u2jwOiYYJqcFKA6rd5rdXqKakHT2Gc+AqHWngr0IEHUfW92zX12wRQKwyoqZf2Q==} + /@smithy/util-stream@2.0.15: + resolution: {integrity: sha512-A/hkYJPH2N5MCWYvky4tTpQihpYAEzqnUfxDyG3L/yMndy/2sLvxnyQal9Opuj1e9FiKSTeMyjnU9xxZGs0mRw==} engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - '@smithy/fetch-http-handler': 2.0.1 - '@smithy/node-http-handler': 2.0.1 - '@smithy/types': 2.0.2 + '@smithy/fetch-http-handler': 2.2.2 + '@smithy/node-http-handler': 2.1.7 + '@smithy/types': 2.3.5 '@smithy/util-base64': 2.0.0 '@smithy/util-buffer-from': 2.0.0 '@smithy/util-hex-encoding': 2.0.0 '@smithy/util-utf8': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true @@ -3103,7 +3185,7 @@ packages: engines: {node: '>=14.0.0'} requiresBuild: true dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true @@ -3113,7 +3195,7 @@ packages: requiresBuild: true dependencies: '@smithy/util-buffer-from': 2.0.0 - tslib: 2.6.1 + tslib: 2.6.2 dev: false optional: true @@ -4302,14 +4384,14 @@ packages: dev: false optional: true - /chai@4.3.7: - resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} + /chai@4.3.10: + resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} engines: {node: '>=4'} dependencies: assertion-error: 1.1.0 - check-error: 1.0.2 + check-error: 1.0.3 deep-eql: 4.1.3 - get-func-name: 2.0.0 + get-func-name: 2.0.2 loupe: 2.3.6 pathval: 1.1.1 type-detect: 4.0.8 @@ -4331,8 +4413,10 @@ packages: ansi-styles: 4.3.0 supports-color: 7.2.0 - /check-error@1.0.2: - resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + dependencies: + get-func-name: 2.0.2 dev: true /chokidar@3.5.3: @@ -4347,7 +4431,7 @@ packages: normalize-path: 3.0.0 readdirp: 3.6.0 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /ci@2.2.0: @@ -4484,7 +4568,7 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - /connect-mongo@4.6.0(express-session@1.17.3)(mongodb@4.16.0): + /connect-mongo@4.6.0(express-session@1.17.3)(mongodb@4.17.1): resolution: {integrity: sha512-8new4Z7NLP3CGP65Aw6ls3xDBeKVvHRSh39CXuDZTQsvpeeU9oNMzfFgvqmHqZ6gWpxIl663RyoVEmCAGf1yOg==} engines: {node: '>=10'} peerDependencies: @@ -4494,7 +4578,7 @@ packages: debug: 4.3.4 express-session: 1.17.3 kruptein: 3.0.6 - mongodb: 4.16.0 + mongodb: 4.17.1 transitivePeerDependencies: - supports-color dev: false @@ -5302,7 +5386,7 @@ packages: node-forge: 1.3.1 uuid: 9.0.0 optionalDependencies: - '@google-cloud/firestore': 6.7.0 + '@google-cloud/firestore': 6.8.0 '@google-cloud/storage': 6.12.0 transitivePeerDependencies: - encoding @@ -5378,8 +5462,8 @@ packages: /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true @@ -5433,8 +5517,8 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - /get-func-name@2.0.0: - resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + /get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true /get-intrinsic@1.2.1: @@ -6246,7 +6330,7 @@ packages: /loupe@2.3.6: resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} dependencies: - get-func-name: 2.0.0 + get-func-name: 2.0.2 dev: true /lru-cache@4.0.2: @@ -6492,27 +6576,27 @@ packages: whatwg-url: 11.0.0 dev: false - /mongodb@4.16.0: - resolution: {integrity: sha512-0EB113Fsucaq1wsY0dOhi1fmZOwFtLOtteQkiqOXGklvWMnSH3g2QS53f0KTP+/6qOkuoXE2JksubSZNmxeI+g==} + /mongodb@4.17.1: + resolution: {integrity: sha512-MBuyYiPUPRTqfH2dV0ya4dcr2E5N52ocBuZ8Sgg/M030nGF78v855B3Z27mZJnp8PxjnUquEnAtjOsphgMZOlQ==} engines: {node: '>=12.9.0'} dependencies: bson: 4.7.2 mongodb-connection-string-url: 2.6.0 socks: 2.7.1 optionalDependencies: - '@aws-sdk/credential-providers': 3.385.0 - saslprep: 1.0.3 + '@aws-sdk/credential-providers': 3.427.0 + '@mongodb-js/saslprep': 1.1.0 transitivePeerDependencies: - aws-crt dev: false - /mongoose@6.11.5: - resolution: {integrity: sha512-ZarPe1rCHG4aVb78xLuok4BBIm0HMz/Y/CjxYXCk3Qz1mEhS7bPMy6ZhSX2/Dng//R7ei8719j6K87UVM/1b3g==} + /mongoose@6.12.0: + resolution: {integrity: sha512-sd/q83C6TBRPBrrD2A/POSbA/exbCFM2WOuY7Lf2JuIJFlHFG39zYSDTTAEiYlzIfahNOLmXPxBGFxdAch41Mw==} engines: {node: '>=12.0.0'} dependencies: bson: 4.7.2 kareem: 2.5.1 - mongodb: 4.16.0 + mongodb: 4.17.1 mpath: 0.9.0 mquery: 4.0.3 ms: 2.1.3 @@ -6606,9 +6690,9 @@ packages: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} dev: false - /nodemon@2.0.22: - resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} - engines: {node: '>=8.10.0'} + /nodemon@3.0.1: + resolution: {integrity: sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==} + engines: {node: '>=10'} hasBin: true dependencies: chokidar: 3.5.3 @@ -6616,8 +6700,8 @@ packages: ignore-by-default: 1.0.1 minimatch: 3.1.2 pstree.remy: 1.1.8 - semver: 5.7.2 - simple-update-notifier: 1.1.0 + semver: 7.5.4 + simple-update-notifier: 2.0.0 supports-color: 5.5.0 touch: 3.1.0 undefsafe: 2.0.5 @@ -7035,7 +7119,7 @@ packages: engines: {node: '>=12.0.0'} requiresBuild: true dependencies: - protobufjs: 7.2.4 + protobufjs: 7.2.5 dev: false optional: true @@ -7081,6 +7165,26 @@ packages: dev: false optional: true + /protobufjs@7.2.5: + resolution: {integrity: sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==} + engines: {node: '>=12.0.0'} + requiresBuild: true + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 20.4.7 + long: 5.2.3 + dev: false + optional: true + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -7542,7 +7646,7 @@ packages: engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: false /rope-sequence@1.3.4: @@ -7566,15 +7670,6 @@ packages: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: false - /saslprep@1.0.3: - resolution: {integrity: sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==} - engines: {node: '>=6'} - requiresBuild: true - dependencies: - sparse-bitfield: 3.0.3 - dev: false - optional: true - /sax@1.2.1: resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} dev: false @@ -7588,17 +7683,13 @@ packages: /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true + dev: false /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true dev: false - /semver@7.0.0: - resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} - hasBin: true - dev: true - /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} @@ -7697,11 +7788,11 @@ packages: is-arrayish: 0.3.2 dev: false - /simple-update-notifier@1.1.0: - resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} - engines: {node: '>=8.10.0'} + /simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} dependencies: - semver: 7.0.0 + semver: 7.5.4 dev: true /slash@3.0.0: @@ -8074,6 +8165,10 @@ packages: resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} dev: false + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: false + /type-check@0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} From 8367363f0b635ac8aac5171a313286555f17b58e Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 21:10:21 +0900 Subject: [PATCH 16/32] Fix: remove FRONT_URL in CI workflow --- .github/workflows/test_ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml index dab9f5a0..83d4c2e7 100644 --- a/.github/workflows/test_ci.yml +++ b/.github/workflows/test_ci.yml @@ -53,6 +53,5 @@ jobs: AWS_S3_BUCKET_NAME: ${{ secrets.AWS_S3_BUCKET_NAME }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} DB_PATH: ${{ secrets.DB_PATH }} - FRONT_URL: ${{ secrets.FRONT_URL }} PORT: ${{ secrets.PORT }} SESSION_KEY: ${{ secrets.SESSION_KEY }} From 8da001336239493bb3825ca2af5a10f08a8941c4 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 21:31:10 +0900 Subject: [PATCH 17/32] Refactor: move test codes into /test/services --- test/{ => services}/auth.replace.js | 4 +- test/{ => services}/locations.js | 30 +- test/{ => services}/logininfo.js | 4 +- test/{ => services}/reports.js | 8 +- test/{ => services}/rooms.js | 406 ++++++++++++++-------------- test/{ => services}/users.js | 280 +++++++++---------- 6 files changed, 366 insertions(+), 366 deletions(-) rename test/{ => services}/auth.replace.js (82%) rename test/{ => services}/locations.js (87%) rename test/{ => services}/logininfo.js (94%) rename test/{ => services}/reports.js (92%) rename test/{ => services}/rooms.js (95%) rename test/{ => services}/users.js (94%) diff --git a/test/auth.replace.js b/test/services/auth.replace.js similarity index 82% rename from test/auth.replace.js rename to test/services/auth.replace.js index 322d13ef..643eddf7 100644 --- a/test/auth.replace.js +++ b/test/services/auth.replace.js @@ -1,7 +1,7 @@ const request = require("supertest"); -const authHandlers = require("../src/services/auth.replace"); -const { userModel } = require("../src/modules/stores/mongo"); +const authHandlers = require("../../src/services/auth.replace"); +const { userModel } = require("../../src/modules/stores/mongo"); // auth.replace.js 관련 1개의 handler을 테스트 // 1. dev 환경에서 로그인이 성공적으로 이루어지는지 확인 diff --git a/test/locations.js b/test/services/locations.js similarity index 87% rename from test/locations.js rename to test/services/locations.js index 19308e51..7df01482 100644 --- a/test/locations.js +++ b/test/services/locations.js @@ -1,15 +1,15 @@ -const expect = require("chai").expect; -const locationHandlers = require("../src/services/locations"); -const httpMocks = require("node-mocks-http"); - -// locations.js 관련 1개의 handler을 테스트 -// 1. 모든 location 정보를 잘 가져오는지 확인 -describe("[locations] 1.getAllLocationsHandler", () => { - it("should return information of locations correctly", async () => { - let req = httpMocks.createRequest({}); - let res = httpMocks.createResponse(); - await locationHandlers.getAllLocationsHandler(req, res); - - expect(res._getJSONData().locations).not.to.have.lengthOf(0); - }); -}); +const expect = require("chai").expect; +const locationHandlers = require("../../src/services/locations"); +const httpMocks = require("node-mocks-http"); + +// locations.js 관련 1개의 handler을 테스트 +// 1. 모든 location 정보를 잘 가져오는지 확인 +describe("[locations] 1.getAllLocationsHandler", () => { + it("should return information of locations correctly", async () => { + let req = httpMocks.createRequest({}); + let res = httpMocks.createResponse(); + await locationHandlers.getAllLocationsHandler(req, res); + + expect(res._getJSONData().locations).not.to.have.lengthOf(0); + }); +}); diff --git a/test/logininfo.js b/test/services/logininfo.js similarity index 94% rename from test/logininfo.js rename to test/services/logininfo.js index 64e492f7..30204643 100644 --- a/test/logininfo.js +++ b/test/services/logininfo.js @@ -1,6 +1,6 @@ const expect = require("chai").expect; -const logininfoHandlers = require("../src/services/logininfo"); -const { userModel } = require("../src/modules/stores/mongo"); +const logininfoHandlers = require("../../src/services/logininfo"); +const { userModel } = require("../../src/modules/stores/mongo"); // 1-1. 로그인 한 유저가 없을 시 undefined를 return 하는지 확인 // 1-2. login 정보를 잘 return 하는지 확인 diff --git a/test/reports.js b/test/services/reports.js similarity index 92% rename from test/reports.js rename to test/services/reports.js index 67bf4001..86347d4a 100644 --- a/test/reports.js +++ b/test/services/reports.js @@ -1,7 +1,7 @@ const expect = require("chai").expect; -const reportHandlers = require("../src/services/reports"); -const { userModel } = require("../src/modules/stores/mongo"); -const { userGenerator, roomGenerator, testRemover } = require("./utils"); +const reportHandlers = require("../../src/services/reports"); +const { userModel } = require("../../src/modules/stores/mongo"); +const { userGenerator, roomGenerator, testRemover } = require("../utils"); const httpMocks = require("node-mocks-http"); let testData = { rooms: [], users: [], chat: [], location: [], report: [] }; @@ -24,7 +24,7 @@ describe("[reports] 1.createHandler", () => { type: "etc-reason", etcDetail: "etc-detail", time: Date.now(), - roomId: testRoom._id + roomId: testRoom._id, }, }); let res = httpMocks.createResponse(); diff --git a/test/rooms.js b/test/services/rooms.js similarity index 95% rename from test/rooms.js rename to test/services/rooms.js index 6ba0c232..e17ae6af 100644 --- a/test/rooms.js +++ b/test/services/rooms.js @@ -1,203 +1,203 @@ -const expect = require("chai").expect; -const express = require("express"); -const roomsHandlers = require("../src/services/rooms"); -const { - userModel, - roomModel, - locationModel, -} = require("../src/modules/stores/mongo"); -const { userGenerator, testRemover } = require("./utils"); -const app = express(); -const httpMocks = require("node-mocks-http"); - -let testData = { rooms: [], users: [], chat: [], location: [], report: [] }; -const removeTestData = async () => { - // drop all testData - await testRemover(testData); -}; - -// rooms.js 관련 9개의 handler을 테스트 -// 1. test1이 1분 뒤에 출발하는 test-room 방을 생성, 제대로 생성 되었는지 확인 -describe("[rooms] 1.createHandler", () => { - it("should create room which departs after 1 minute", async () => { - const testUser1 = await userGenerator("test1", testData); - const testFrom = await locationModel.findOne({ koName: "대전역" }); - const testTo = await locationModel.findOne({ koName: "택시승강장" }); - let req = httpMocks.createRequest({ - body: { - name: "test-room", - from: testFrom._id, - to: testTo._id, - time: Date.now() + 60 * 1000, - maxPartLength: 4, - }, - userId: testUser1.id, - app, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.createHandler(req, res); - - const testRoom = await roomModel.findOne({ name: "test-room" }); - testData["rooms"].push(testRoom); - const resData = res._getData(); - expect(resData).to.has.property("name", "test-room"); - }); -}); - -// 2. test1을 통하여 방의 정보를 제대로 가져오는지 확인 -describe("[rooms] 2.infoHandler", () => { - it("should return information of room", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - const testRoom = await roomModel.findOne({ name: "test-room" }); - let req = httpMocks.createRequest({ - query: { id: testRoom._id }, - userId: testUser1.id, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.infoHandler(req, res); - - const resData = res._getData(); - expect(resData).to.has.property("name", "test-room"); - expect(resData).to.has.property("isOver"); - }); -}); - -// 3. 로그인되지 않은 유저가 방의 정보를 제대로 가져오는지 확인 -describe("[rooms] 3.publicInfoHandler", () => { - it("should return information of room", async () => { - const testRoom = await roomModel.findOne({ name: "test-room" }); - let req = httpMocks.createRequest({ - query: { id: testRoom._id }, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.publicInfoHandler(req, res); - - const resData = res._getData(); - expect(resData).to.has.property("name", "test-room"); - expect(resData).to.has.property("isOver", undefined); - }); -}); - -// 4. test2가 test-room에 join, 방에 잘 join 했는지 확인 -describe("[rooms] 4.joinHandler", () => { - it("should return information of room and join", async () => { - const testUser2 = await userGenerator("test2", testData); - const testRoom = await roomModel.findOne({ name: "test-room" }); - let req = httpMocks.createRequest({ - body: { - roomId: testRoom._id, - }, - userId: testUser2.id, - app, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.joinHandler(req, res); - - const resData = res._getData(); - expect(resData).to.has.property("name", "test-room"); - expect(resData.part).to.have.lengthOf(2); - }); -}); - -// 5. 방의 정보를 통해 검색, 검색 정보가 예상과 일치하는지 확인 -describe("[rooms] 5.searchHandler", () => { - it("should return information of searching room", async () => { - const testFrom = await locationModel.findOne({ koName: "대전역" }); - const testTo = await locationModel.findOne({ koName: "택시승강장" }); - let req = httpMocks.createRequest({ - query: { - name: "test-room", - from: testFrom._id, - to: testTo._id, - time: Date.now(), - withTime: true, - maxPartLength: 4, - }, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.searchHandler(req, res); - - const resJson = res._getJSONData(); - expect(resJson[0]).to.has.property("name", "test-room"); - expect(resJson[0].settlementTotal).to.be.undefined; - }); -}); - -// 6. 방에 속한 유저를 통해 검색 -// ongoing은 test-room이 검색되고, done은 아무것도 검색되지 않아야함 -describe("[rooms] 6.searchByUserHandler", () => { - it("should return information of searching room", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - let req = httpMocks.createRequest({ - userId: testUser1.id, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.searchByUserHandler(req, res); - - const resJson = res._getJSONData(); - expect(resJson["ongoing"][0]).to.has.property("name", "test-room"); - expect(resJson["done"][0]).to.be.undefined; - }); -}); - -// 7. 1분이 지난 후, 정산 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 -describe("[rooms] 7.commitPaymentHandler", () => { - it("should return information of room and commit payment", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - const testRoom = await roomModel.findOne({ name: "test-room" }); - let req = httpMocks.createRequest({ - body: { roomId: testRoom._id }, - userId: testUser1.id, - timestamp: Date.now() + 60 * 1000, - app, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.commitPaymentHandler(req, res); - - const resData = res._getData(); - expect(resData).to.has.property("name", "test-room"); - expect(resData).to.has.property("isOver", true); - expect(resData).to.has.property("settlementTotal", 1); - }); -}); - -// 8. 도착 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 -describe("[rooms] 8.settlementHandler", () => { - it("should return information of room and set settlement", async () => { - const testUser2 = await userModel.findOne({ id: "test2" }); - const testRoom = await roomModel.findOne({ name: "test-room" }); - let req = httpMocks.createRequest({ - body: { roomId: testRoom._id }, - userId: testUser2.id, - app, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.settlementHandler(req, res); - - const resData = res._getData(); - expect(resData).to.has.property("name", "test-room"); - expect(resData).to.has.property("isOver", true); - expect(resData).to.has.property("settlementTotal", 2); - }); -}); - -// 9. test2 방에서 퇴장, 제대로 방에서 나갔는지 확인하고 생성해준 data 모두 삭제 -describe("[rooms] 9.abortHandler", () => { - it("should return information of room and abort user", async () => { - const testUser2 = await userModel.findOne({ id: "test2" }); - const testRoom = await roomModel.findOne({ name: "test-room" }); - let req = httpMocks.createRequest({ - body: { roomId: testRoom._id }, - userId: testUser2.id, - session: {}, - app, - }); - let res = httpMocks.createResponse(); - await roomsHandlers.abortHandler(req, res); - afterEach(removeTestData); - - const resData = res._getData(); - expect(resData).to.has.property("name", "test-room"); - expect(resData.part).to.have.lengthOf(1); - }); -}); +const expect = require("chai").expect; +const express = require("express"); +const roomsHandlers = require("../../src/services/rooms"); +const { + userModel, + roomModel, + locationModel, +} = require("../../src/modules/stores/mongo"); +const { userGenerator, testRemover } = require("../utils"); +const app = express(); +const httpMocks = require("node-mocks-http"); + +let testData = { rooms: [], users: [], chat: [], location: [], report: [] }; +const removeTestData = async () => { + // drop all testData + await testRemover(testData); +}; + +// rooms.js 관련 9개의 handler을 테스트 +// 1. test1이 1분 뒤에 출발하는 test-room 방을 생성, 제대로 생성 되었는지 확인 +describe("[rooms] 1.createHandler", () => { + it("should create room which departs after 1 minute", async () => { + const testUser1 = await userGenerator("test1", testData); + const testFrom = await locationModel.findOne({ koName: "대전역" }); + const testTo = await locationModel.findOne({ koName: "택시승강장" }); + let req = httpMocks.createRequest({ + body: { + name: "test-room", + from: testFrom._id, + to: testTo._id, + time: Date.now() + 60 * 1000, + maxPartLength: 4, + }, + userId: testUser1.id, + app, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.createHandler(req, res); + + const testRoom = await roomModel.findOne({ name: "test-room" }); + testData["rooms"].push(testRoom); + const resData = res._getData(); + expect(resData).to.has.property("name", "test-room"); + }); +}); + +// 2. test1을 통하여 방의 정보를 제대로 가져오는지 확인 +describe("[rooms] 2.infoHandler", () => { + it("should return information of room", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + const testRoom = await roomModel.findOne({ name: "test-room" }); + let req = httpMocks.createRequest({ + query: { id: testRoom._id }, + userId: testUser1.id, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.infoHandler(req, res); + + const resData = res._getData(); + expect(resData).to.has.property("name", "test-room"); + expect(resData).to.has.property("isOver"); + }); +}); + +// 3. 로그인되지 않은 유저가 방의 정보를 제대로 가져오는지 확인 +describe("[rooms] 3.publicInfoHandler", () => { + it("should return information of room", async () => { + const testRoom = await roomModel.findOne({ name: "test-room" }); + let req = httpMocks.createRequest({ + query: { id: testRoom._id }, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.publicInfoHandler(req, res); + + const resData = res._getData(); + expect(resData).to.has.property("name", "test-room"); + expect(resData).to.has.property("isOver", undefined); + }); +}); + +// 4. test2가 test-room에 join, 방에 잘 join 했는지 확인 +describe("[rooms] 4.joinHandler", () => { + it("should return information of room and join", async () => { + const testUser2 = await userGenerator("test2", testData); + const testRoom = await roomModel.findOne({ name: "test-room" }); + let req = httpMocks.createRequest({ + body: { + roomId: testRoom._id, + }, + userId: testUser2.id, + app, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.joinHandler(req, res); + + const resData = res._getData(); + expect(resData).to.has.property("name", "test-room"); + expect(resData.part).to.have.lengthOf(2); + }); +}); + +// 5. 방의 정보를 통해 검색, 검색 정보가 예상과 일치하는지 확인 +describe("[rooms] 5.searchHandler", () => { + it("should return information of searching room", async () => { + const testFrom = await locationModel.findOne({ koName: "대전역" }); + const testTo = await locationModel.findOne({ koName: "택시승강장" }); + let req = httpMocks.createRequest({ + query: { + name: "test-room", + from: testFrom._id, + to: testTo._id, + time: Date.now(), + withTime: true, + maxPartLength: 4, + }, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.searchHandler(req, res); + + const resJson = res._getJSONData(); + expect(resJson[0]).to.has.property("name", "test-room"); + expect(resJson[0].settlementTotal).to.be.undefined; + }); +}); + +// 6. 방에 속한 유저를 통해 검색 +// ongoing은 test-room이 검색되고, done은 아무것도 검색되지 않아야함 +describe("[rooms] 6.searchByUserHandler", () => { + it("should return information of searching room", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + let req = httpMocks.createRequest({ + userId: testUser1.id, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.searchByUserHandler(req, res); + + const resJson = res._getJSONData(); + expect(resJson["ongoing"][0]).to.has.property("name", "test-room"); + expect(resJson["done"][0]).to.be.undefined; + }); +}); + +// 7. 1분이 지난 후, 정산 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 +describe("[rooms] 7.commitPaymentHandler", () => { + it("should return information of room and commit payment", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + const testRoom = await roomModel.findOne({ name: "test-room" }); + let req = httpMocks.createRequest({ + body: { roomId: testRoom._id }, + userId: testUser1.id, + timestamp: Date.now() + 60 * 1000, + app, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.commitPaymentHandler(req, res); + + const resData = res._getData(); + expect(resData).to.has.property("name", "test-room"); + expect(resData).to.has.property("isOver", true); + expect(resData).to.has.property("settlementTotal", 1); + }); +}); + +// 8. 도착 정보를 불러옴. 예상과 같은 정보를 불러오는지 확인 +describe("[rooms] 8.settlementHandler", () => { + it("should return information of room and set settlement", async () => { + const testUser2 = await userModel.findOne({ id: "test2" }); + const testRoom = await roomModel.findOne({ name: "test-room" }); + let req = httpMocks.createRequest({ + body: { roomId: testRoom._id }, + userId: testUser2.id, + app, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.settlementHandler(req, res); + + const resData = res._getData(); + expect(resData).to.has.property("name", "test-room"); + expect(resData).to.has.property("isOver", true); + expect(resData).to.has.property("settlementTotal", 2); + }); +}); + +// 9. test2 방에서 퇴장, 제대로 방에서 나갔는지 확인하고 생성해준 data 모두 삭제 +describe("[rooms] 9.abortHandler", () => { + it("should return information of room and abort user", async () => { + const testUser2 = await userModel.findOne({ id: "test2" }); + const testRoom = await roomModel.findOne({ name: "test-room" }); + let req = httpMocks.createRequest({ + body: { roomId: testRoom._id }, + userId: testUser2.id, + session: {}, + app, + }); + let res = httpMocks.createResponse(); + await roomsHandlers.abortHandler(req, res); + afterEach(removeTestData); + + const resData = res._getData(); + expect(resData).to.has.property("name", "test-room"); + expect(resData.part).to.have.lengthOf(1); + }); +}); diff --git a/test/users.js b/test/services/users.js similarity index 94% rename from test/users.js rename to test/services/users.js index 1efa0d86..1bb2f586 100644 --- a/test/users.js +++ b/test/services/users.js @@ -1,140 +1,140 @@ -const expect = require("chai").expect; -const usersHandlers = require("../src/services/users"); -const { userModel } = require("../src/modules/stores/mongo"); -const { userGenerator, testRemover } = require("./utils"); -const httpMocks = require("node-mocks-http"); - -let testData = { rooms: [], users: [], chat: [], location: [], report: [] }; -const removeTestData = async () => { - await testRemover(testData); -}; - -// users.js 관련 5개의 handler을 테스트 -// 1. test1 유저를 생성 후, agreeOnTermsOfServiceHandler가 제대로 msg를 send 하는지 확인 -describe("[users] 1.agreeOnTermsOfServiceHandler", () => { - it("should return correct response from handler", async () => { - const testUser1 = await userGenerator("test1", testData); - const msg = - "User/agreeOnTermsOfService : agree on Terms of Service successful"; - let req = httpMocks.createRequest({ - userId: testUser1.id, - }); - let res = httpMocks.createResponse(); - await usersHandlers.agreeOnTermsOfServiceHandler(req, res); - - const resData = res._getData(); - expect(res).to.has.property("statusCode", 200); - expect(resData).to.equal(msg); - }); -}); - -// 2. test1 유저의 agreeOnTermsOfService 정보를 가져와서 true인지 확인 -describe("[users] 2.getAgreeOnTermsOfServiceHandler", () => { - it("should return AgreeOnTermsOfService of user", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - let req = httpMocks.createRequest({ - userId: testUser1.id, - }); - let res = httpMocks.createResponse(); - await usersHandlers.getAgreeOnTermsOfServiceHandler(req, res); - - const resJson = res._getJSONData(); - expect(res).to.has.property("statusCode", 200); - expect(resJson).to.has.property("agreeOnTermsOfService", true); - }); -}); - -// 3. test1 유저의 nickname을 test-nickname으로 변경, 성공 메세지가 제대로 오는지 확인 -describe("[users] 3.editNicknameHandler", () => { - const testNickname = "test-nickname"; - - it("should return correct response from handler", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - const msg = "User/editNickname : edit user nickname successful"; - let req = httpMocks.createRequest({ - userId: testUser1.id, - body: { - nickname: testNickname, - }, - }); - let res = httpMocks.createResponse(); - await usersHandlers.editNicknameHandler(req, res); - - const resData = res._getData(); - expect(res).to.has.property("statusCode", 200); - expect(resData).to.equal(msg); - }); - - it("should be changed to new nickname", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - expect(testUser1).to.have.property("nickname", testNickname); - }); -}); - -// 3. test1 유저의 계좌번호를 testAccount으로 변경, 성공 메세지가 제대로 오는지 확인 -describe("[users] 4.editAccountHandler", () => { - const testAccount = "신한 0123456789012"; - - it("should return correct response from handler", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - const msg = "User/editAccount : edit user account successful"; - let req = httpMocks.createRequest({ - userId: testUser1.id, - body: { - account: testAccount, - }, - }); - let res = httpMocks.createResponse(); - await usersHandlers.editAccountHandler(req, res); - - const resData = res._getData(); - expect(res).to.has.property("statusCode", 200); - expect(resData).to.equal(msg); - }); - - it("should be changed to new account", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - expect(testUser1).to.have.property("account", testAccount); - }); -}); - -// 5. test1 유저의 프로필 업로드를 위한 PUrl을 제대로 받았는지 확인 -// 추가 검증을 위해, key와 Content-Type이 일치하는지 확인 -describe("[users] 5.editProfileImgGetPUrlHandler", () => { - it("should return url and fields of data", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - const testImgType = "image/jpg"; - let req = httpMocks.createRequest({ - userId: testUser1.id, - body: { - type: testImgType, - }, - }); - let res = httpMocks.createResponse(); - await usersHandlers.editProfileImgGetPUrlHandler(req, res); - - const resJson = res._getJSONData(); - expect(res).to.has.property("statusCode", 200); - expect(resJson).to.has.property("url"); - expect(resJson.fields).to.has.property( - "key", - `profile-img/${testUser1._id}` - ); - expect(resJson.fields).to.has.property("Content-Type", testImgType); - }); -}); - -// 6. test1 유저의 프로필 업로드가 정상적으로 완료되었는지 확인 -describe("[users] 6.editProfileImgDoneHandler", () => { - it("should return correct result and new profileImageUrl", async () => { - const testUser1 = await userModel.findOne({ id: "test1" }); - let req = httpMocks.createRequest({ - userId: testUser1.id, - }); - let res = httpMocks.createResponse(); - await usersHandlers.editProfileImgDoneHandler(req, res); - afterEach(removeTestData); - - expect(res).to.has.property("statusCode", 200); - }); -}); +const expect = require("chai").expect; +const usersHandlers = require("../../src/services/users"); +const { userModel } = require("../../src/modules/stores/mongo"); +const { userGenerator, testRemover } = require("../utils"); +const httpMocks = require("node-mocks-http"); + +let testData = { rooms: [], users: [], chat: [], location: [], report: [] }; +const removeTestData = async () => { + await testRemover(testData); +}; + +// users.js 관련 5개의 handler을 테스트 +// 1. test1 유저를 생성 후, agreeOnTermsOfServiceHandler가 제대로 msg를 send 하는지 확인 +describe("[users] 1.agreeOnTermsOfServiceHandler", () => { + it("should return correct response from handler", async () => { + const testUser1 = await userGenerator("test1", testData); + const msg = + "User/agreeOnTermsOfService : agree on Terms of Service successful"; + let req = httpMocks.createRequest({ + userId: testUser1.id, + }); + let res = httpMocks.createResponse(); + await usersHandlers.agreeOnTermsOfServiceHandler(req, res); + + const resData = res._getData(); + expect(res).to.has.property("statusCode", 200); + expect(resData).to.equal(msg); + }); +}); + +// 2. test1 유저의 agreeOnTermsOfService 정보를 가져와서 true인지 확인 +describe("[users] 2.getAgreeOnTermsOfServiceHandler", () => { + it("should return AgreeOnTermsOfService of user", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + let req = httpMocks.createRequest({ + userId: testUser1.id, + }); + let res = httpMocks.createResponse(); + await usersHandlers.getAgreeOnTermsOfServiceHandler(req, res); + + const resJson = res._getJSONData(); + expect(res).to.has.property("statusCode", 200); + expect(resJson).to.has.property("agreeOnTermsOfService", true); + }); +}); + +// 3. test1 유저의 nickname을 test-nickname으로 변경, 성공 메세지가 제대로 오는지 확인 +describe("[users] 3.editNicknameHandler", () => { + const testNickname = "test-nickname"; + + it("should return correct response from handler", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + const msg = "User/editNickname : edit user nickname successful"; + let req = httpMocks.createRequest({ + userId: testUser1.id, + body: { + nickname: testNickname, + }, + }); + let res = httpMocks.createResponse(); + await usersHandlers.editNicknameHandler(req, res); + + const resData = res._getData(); + expect(res).to.has.property("statusCode", 200); + expect(resData).to.equal(msg); + }); + + it("should be changed to new nickname", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + expect(testUser1).to.have.property("nickname", testNickname); + }); +}); + +// 3. test1 유저의 계좌번호를 testAccount으로 변경, 성공 메세지가 제대로 오는지 확인 +describe("[users] 4.editAccountHandler", () => { + const testAccount = "신한 0123456789012"; + + it("should return correct response from handler", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + const msg = "User/editAccount : edit user account successful"; + let req = httpMocks.createRequest({ + userId: testUser1.id, + body: { + account: testAccount, + }, + }); + let res = httpMocks.createResponse(); + await usersHandlers.editAccountHandler(req, res); + + const resData = res._getData(); + expect(res).to.has.property("statusCode", 200); + expect(resData).to.equal(msg); + }); + + it("should be changed to new account", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + expect(testUser1).to.have.property("account", testAccount); + }); +}); + +// 5. test1 유저의 프로필 업로드를 위한 PUrl을 제대로 받았는지 확인 +// 추가 검증을 위해, key와 Content-Type이 일치하는지 확인 +describe("[users] 5.editProfileImgGetPUrlHandler", () => { + it("should return url and fields of data", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + const testImgType = "image/jpg"; + let req = httpMocks.createRequest({ + userId: testUser1.id, + body: { + type: testImgType, + }, + }); + let res = httpMocks.createResponse(); + await usersHandlers.editProfileImgGetPUrlHandler(req, res); + + const resJson = res._getJSONData(); + expect(res).to.has.property("statusCode", 200); + expect(resJson).to.has.property("url"); + expect(resJson.fields).to.has.property( + "key", + `profile-img/${testUser1._id}` + ); + expect(resJson.fields).to.has.property("Content-Type", testImgType); + }); +}); + +// 6. test1 유저의 프로필 업로드가 정상적으로 완료되었는지 확인 +describe("[users] 6.editProfileImgDoneHandler", () => { + it("should return correct result and new profileImageUrl", async () => { + const testUser1 = await userModel.findOne({ id: "test1" }); + let req = httpMocks.createRequest({ + userId: testUser1.id, + }); + let res = httpMocks.createResponse(); + await usersHandlers.editProfileImgDoneHandler(req, res); + afterEach(removeTestData); + + expect(res).to.has.property("statusCode", 200); + }); +}); From 660a23251477e92c7f9e93546074adb61e58e858 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 22:21:59 +0900 Subject: [PATCH 18/32] Refactor: bump jsonwebtoken version to ^9.0.2 --- loadenv.js | 1 + package.json | 2 +- pnpm-lock.yaml | 22 ++++++---------------- test/modules/auths/jwt.js | 29 +++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 test/modules/auths/jwt.js diff --git a/loadenv.js b/loadenv.js index 3dfc5be6..12634228 100644 --- a/loadenv.js +++ b/loadenv.js @@ -25,6 +25,7 @@ module.exports = { secretKey: process.env.JWT_SECRET_KEY || "TAXI_JWT_KEY", option: { algorithm: "HS256", + // FIXME: remove FRONT_URL from issuer. 단, issuer를 변경하면 이전에 발급했던 모든 JWT가 무효화됩니다. issuer: process.env.FRONT_URL || "http://localhost:3000", // optional (default = "http://localhost:3000") }, TOKEN_EXPIRED: -3, diff --git a/package.json b/package.json index 10e08d1f..fecc4769 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "express-session": "^1.17.3", "express-validator": "^6.14.0", "firebase-admin": "^11.4.1", - "jsonwebtoken": "^8.5.1", + "jsonwebtoken": "^9.0.2", "mongoose": "^6.12.0", "node-cron": "3.0.2", "node-mocks-http": "^1.12.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44ff861f..d197fbe1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,8 +72,8 @@ dependencies: specifier: ^11.4.1 version: 11.10.1 jsonwebtoken: - specifier: ^8.5.1 - version: 8.5.1 + specifier: ^9.0.2 + version: 9.0.2 mongoose: specifier: ^6.12.0 version: 6.12.0 @@ -5381,7 +5381,7 @@ packages: '@firebase/database-compat': 0.3.4 '@firebase/database-types': 0.10.4 '@types/node': 20.4.7 - jsonwebtoken: 9.0.1 + jsonwebtoken: 9.0.2 jwks-rsa: 3.0.1 node-forge: 1.3.1 uuid: 9.0.0 @@ -6065,9 +6065,9 @@ packages: hasBin: true dev: false - /jsonwebtoken@8.5.1: - resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==} - engines: {node: '>=4', npm: '>=1.4.28'} + /jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} dependencies: jws: 3.2.2 lodash.includes: 4.3.0 @@ -6078,16 +6078,6 @@ packages: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 5.7.2 - dev: false - - /jsonwebtoken@9.0.1: - resolution: {integrity: sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==} - engines: {node: '>=12', npm: '>=6'} - dependencies: - jws: 3.2.2 - lodash: 4.17.21 - ms: 2.1.3 semver: 7.5.4 dev: false diff --git a/test/modules/auths/jwt.js b/test/modules/auths/jwt.js new file mode 100644 index 00000000..bac7edfa --- /dev/null +++ b/test/modules/auths/jwt.js @@ -0,0 +1,29 @@ +const { expect } = require("chai"); +const { sign, verify } = require("../../../src/modules/auths/jwt"); + +// jwt.js 관련 2개의 함수를 테스트 +// 1. jwt 서명과 검증이 성공적으로 되는지 테스트 +describe("[jwt] 1.sign & verify", () => { + it("should sign and verify jwt correctly", async () => { + // JWT 서명에 사용되는 사용자 + const user = { + _id: "507f191e810c19729de860ea", + }; + + // 토큰 생성이 성공적으로 되는지 테스트 + const { token: accessToken } = await sign({ + id: user._id, + type: "access", + }); + const { token: refreshToken } = await sign({ + id: user._id, + type: "refresh", + }); + + // 토큰 검증이 성공적으로 되는지 테스트 + const accessTokenStatus = await verify(accessToken); + expect(accessTokenStatus).to.has.property("id", user._id); + const refreshTokenStatus = await verify(refreshToken); + expect(refreshTokenStatus).to.has.property("id", user._id); + }); +}); From b9fa44315e80ca0e3e7b1f894b07ac08817aeba1 Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 23:04:14 +0900 Subject: [PATCH 19/32] Docs: add issue link to fixme --- loadenv.js | 1 + 1 file changed, 1 insertion(+) diff --git a/loadenv.js b/loadenv.js index 12634228..a0954d4d 100644 --- a/loadenv.js +++ b/loadenv.js @@ -26,6 +26,7 @@ module.exports = { option: { algorithm: "HS256", // FIXME: remove FRONT_URL from issuer. 단, issuer를 변경하면 이전에 발급했던 모든 JWT가 무효화됩니다. + // See https://github.com/sparcs-kaist/taxi-back/issues/415 issuer: process.env.FRONT_URL || "http://localhost:3000", // optional (default = "http://localhost:3000") }, TOKEN_EXPIRED: -3, From 8bda357273d40fea0abb7f24a760f6b8d8d43c6e Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 23:25:11 +0900 Subject: [PATCH 20/32] Fix: remove wrong step name in CI workflow --- .github/workflows/test_ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml index 83d4c2e7..29f7f21b 100644 --- a/.github/workflows/test_ci.yml +++ b/.github/workflows/test_ci.yml @@ -17,15 +17,14 @@ jobs: steps: - name: Start MongoDB run: sudo docker run --name mongodb -d -p 27017:27017 mongo:${{ matrix.mongodb-version }} - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: submodules: true - name: Install pnpm uses: pnpm/action-setup@v2 with: version: 8 - - name: Install Node.js + - name: Install Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} From e55481cb8c830411b96add7239ce230757dc8bbe Mon Sep 17 00:00:00 2001 From: withsang Date: Sat, 7 Oct 2023 23:49:05 +0900 Subject: [PATCH 21/32] Docs: update Node.js version in README --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fbd01b8a..26cda418 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,11 @@ Taxi는 KAIST 구성원들의 택시 동승 인원 모집을 위한 서비스입 - Notion : [Sparcs Notion Taxi page](https://www.notion.so/sparcs/Taxi-9d371e8ac5ac4f0c9b9c35869682a0eb) (Only SPARCS members can access it) - Slack : #taxi-main, #taxi-notice, #taxi-bug-report, #taxi-github-bot, #taxi-notion-bot (Only SPARCS members can access it) -## Prerequisites -- Recommended npm version : 8.5.5 (with node v.16.15.0) -- Recommended mognoDB version : 5.0.8 -- [Issue with node version](https://github.com/sparcs-kaist/taxi-front/issues/76) +## Prerequisite + +- Recommended node version : >=18.0.0 (Node v18.18.0, for example) +- Recommended pnpm version : >=8.0.0 (pmpm v8.8.0, for example) +- Recommended mongoDB version : 5.0.8 ## Project Setup @@ -24,7 +25,7 @@ $ git clone https://github.com/sparcs-kaist/taxi-back ### Install Requirements ```bash -$ npm install --save +$ pnpm install ``` ### Set Environment Configuration @@ -32,7 +33,9 @@ See [notion page](https://www.notion.so/sparcs/Environment-Variables-1b404bd385f Refer to [.env.example](.env.example) and write your own `.env`. ## Backend Route Information -See [Backend Route Documentation](src/routes/docs/README.md) +API specification is defined on Swagger. +Start development server and visit `/docs` to see the specification of each endpoint. +Some endpoints are not documented in Swagger yet. For those endpoints, refer to [routes/docs/README.md](./src/routes/docs/README.md). ## License This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details From 916856c471931f41d3d79f5c95197a6c1edc8527 Mon Sep 17 00:00:00 2001 From: static Date: Mon, 9 Oct 2023 20:39:20 +0900 Subject: [PATCH 22/32] Fix: loadenv.js --- loadenv.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loadenv.js b/loadenv.js index 3dfc5be6..d8a3be78 100644 --- a/loadenv.js +++ b/loadenv.js @@ -42,6 +42,6 @@ module.exports = { JSON.parse(process.env.EVENT_CONFIG)) || { mode: "2023fall", startAt: "2023-09-25T00:00:00+09:00", - endAt: "2023-10-10T00:00:00+09:00", + endAt: "2023-10-12T00:00:00+09:00", }, }; From 7a59b033965c4e0270ac110391cd20c5ec25f56f Mon Sep 17 00:00:00 2001 From: withsang Date: Mon, 9 Oct 2023 21:38:38 +0900 Subject: [PATCH 23/32] Fix: specify push: true in Docker Action --- .github/workflows/push_image_ecr.yml | 16 +++------------- .github/workflows/push_image_ecr_dev.yml | 14 +++----------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/.github/workflows/push_image_ecr.yml b/.github/workflows/push_image_ecr.yml index 232535a1..6b3ce161 100644 --- a/.github/workflows/push_image_ecr.yml +++ b/.github/workflows/push_image_ecr.yml @@ -58,31 +58,21 @@ jobs: id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - - name: Build Image - id: build_image + - name: Build Image and Push to AWS ECR + id: build_image_and_push uses: docker/build-push-action@v5 env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ steps.tag.outputs.tag }} ECR_REPOSITORY: taxi-back with: + push: true tags: | "${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}" "${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest" cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new - - name: Push to AWS ECR - id: push_image - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - IMAGE_TAG: ${{ steps.tag.outputs.tag }} - ECR_REPOSITORY: taxi-back - run: | - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest - echo "Push image : $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG and latest" - - name: Remove old cache run: | rm -rf /tmp/.buildx-cache diff --git a/.github/workflows/push_image_ecr_dev.yml b/.github/workflows/push_image_ecr_dev.yml index 701bfa7d..d1c1dae4 100644 --- a/.github/workflows/push_image_ecr_dev.yml +++ b/.github/workflows/push_image_ecr_dev.yml @@ -43,25 +43,17 @@ jobs: id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - - name: Build Image - id: build_image + - name: Build Image and Push to AWS ECR + id: build_image_and_push uses: docker/build-push-action@v5 env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY: taxi-back with: + push: true tags: "${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:dev" cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new - - - name: Push to AWS ECR - id: push_image - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - ECR_REPOSITORY: taxi-back - run: | - docker push $ECR_REGISTRY/$ECR_REPOSITORY:dev - echo "Push image : $ECR_REGISTRY/$ECR_REPOSITORY:dev" - name: Remove old cache run: | From fd3c8235e571f43025fb4eac3ed29829ef68ed85 Mon Sep 17 00:00:00 2001 From: static Date: Tue, 24 Oct 2023 21:27:55 +0900 Subject: [PATCH 24/32] Remove: default eventConfig value --- loadenv.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/loadenv.js b/loadenv.js index 02843dc5..ce0d9dc4 100644 --- a/loadenv.js +++ b/loadenv.js @@ -40,10 +40,5 @@ module.exports = { slackWebhookUrl: { report: process.env.SLACK_REPORT_WEBHOOK_URL || "", // optional }, - eventConfig: (process.env.EVENT_CONFIG && - JSON.parse(process.env.EVENT_CONFIG)) || { - mode: "2023fall", - startAt: "2023-09-25T00:00:00+09:00", - endAt: "2023-10-12T00:00:00+09:00", - }, + eventConfig: (process.env.EVENT_CONFIG && JSON.parse(process.env.EVENT_CONFIG)) }; From 3f56ed023a07b2e92b91006740d5e3522c422de5 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Thu, 26 Oct 2023 23:57:25 +0900 Subject: [PATCH 25/32] Add: reset user nickname and reset user profile image --- src/routes/users.js | 6 ++++++ src/services/auth.js | 2 +- src/services/users.js | 45 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/routes/users.js b/src/routes/users.js index f7736cd6..81ff7f03 100755 --- a/src/routes/users.js +++ b/src/routes/users.js @@ -31,6 +31,9 @@ router.post( userHandlers.editNicknameHandler ); +// 넥네임을 기본값으로 재설정합니다. +router.get("/resetNickname", userHandlers.resetNicknameHandler); + // 새 계좌번호를 받아 로그인된 유저의 계좌번호를 변경합니다. router.post( "/editAccount", @@ -50,4 +53,7 @@ router.post( // 프로필 이미지가 S3에 정상적으로 업로드가 되었는지 확인합니다. router.get("/editProfileImg/done", userHandlers.editProfileImgDoneHandler); +// 프로필 이미지를 기본값으로 재설정합니다. +router.get("/resetProfileImg", userHandlers.resetProfileImg); + module.exports = router; diff --git a/src/services/auth.js b/src/services/auth.js index 83b598de..740a7aab 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -43,7 +43,7 @@ const joinus = async (req, userData) => { const newUser = new userModel({ id: userData.id, name: userData.name, - nickname: generateNickname(userData.id), + nickname: userData.id, profileImageUrl: generateProfileImageUrl(), joinat: req.timestamp, subinfo: { diff --git a/src/services/users.js b/src/services/users.js index f4a00d6a..82eb6129 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -4,6 +4,10 @@ const aws = require("../modules/stores/aws"); // 이벤트 코드입니다. const { contracts } = require("../lottery"); +const { + generateNickname, + generateProfileImageUrl, +} = require("../modules/modifyProfile"); const agreeOnTermsOfServiceHandler = async (req, res) => { try { @@ -151,6 +155,45 @@ const editProfileImgDoneHandler = async (req, res) => { } }; +const resetNicknameHandler = async (req, res) => { + try { + const result = await userModel.findOneAndUpdate( + { id: req.userId }, + { nickname: generateNickname(req.body.id) }, + { new: true } + ); + if (result) { + res + .status(200) + .send("User/resetNickname : reset user nickname successful"); + } else { + res.status(400).send("User/resetNickname : such user does not exist"); + } + } catch (err) { + logger.error(err); + res.status(500).send("User/resetNickname : internal server error"); + } +}; + +const resetProfileImg = async (req, res) => { + try { + const result = await userModel.findOneAndUpdate( + { id: req.userId }, + { profileImageUrl: generateProfileImageUrl() }, + { new: true } + ); + if (result) { + res + .status(200) + .send("User/resetProfileImg : reset user profile image successful"); + } else { + res.status(400).send("User/resetProfileImg : such user does not exist"); + } + } catch (err) { + res.status(500).send("User/resetProfileImg : internal server error"); + } +}; + module.exports = { agreeOnTermsOfServiceHandler, getAgreeOnTermsOfServiceHandler, @@ -158,4 +201,6 @@ module.exports = { editAccountHandler, editProfileImgGetPUrlHandler, editProfileImgDoneHandler, + resetNicknameHandler, + resetProfileImg, }; From e1aefcb48201c99527bad748778aa040bb2505c3 Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Fri, 27 Oct 2023 01:39:39 +0900 Subject: [PATCH 26/32] Add: swagger docs users --- src/routes/docs/swaggerDocs.js | 6 +++ src/routes/docs/users.js | 68 ++++++++++++++++++++++++++++++++++ src/routes/users.js | 2 +- src/services/users.js | 4 +- 4 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/routes/docs/users.js diff --git a/src/routes/docs/swaggerDocs.js b/src/routes/docs/swaggerDocs.js index cf52ff2a..c6c13060 100644 --- a/src/routes/docs/swaggerDocs.js +++ b/src/routes/docs/swaggerDocs.js @@ -2,6 +2,7 @@ const reportsSchema = require("./reportsSchema"); const reportsDocs = require("./reports"); const logininfoDocs = require("./logininfo"); const locationsDocs = require("./locations"); +const usersDocs = require("./users"); const swaggerDocs = { openapi: "3.0.3", @@ -23,6 +24,10 @@ const swaggerDocs = { name: "reports", description: "사용자 신고 및 신고 기록 조회", }, + { + name: "users", + description: "유저 계정 정보 수정 및 조회", + }, ], consumes: ["application/json"], produces: ["application/json"], @@ -30,6 +35,7 @@ const swaggerDocs = { ...reportsDocs, ...logininfoDocs, ...locationsDocs, + ...usersDocs, }, components: { schemas: { diff --git a/src/routes/docs/users.js b/src/routes/docs/users.js new file mode 100644 index 00000000..c40e08f2 --- /dev/null +++ b/src/routes/docs/users.js @@ -0,0 +1,68 @@ +const tag = "users"; +const apiPrefix = "/users"; + +const usersDocs = {}; +usersDocs[`${apiPrefix}/resetNickname`] = { + get: { + tags: [`${tag}`], + summary: "유저 닉네임 기본값으로 재설정", + description: "유저의 별명을 기본값(랜덤한 닉네임)으로 초기화합니다", + responses: { + 200: { + content: { + "text/html": { + example: "User/resetNickname : reset user nickname successful", + }, + }, + }, + 400: { + content: { + "text/html": { + example: "User/resetNickname : such user does not exist", + }, + }, + }, + 500: { + content: { + "text/html": { + example: "User/resetNickname : internal server error", + }, + }, + }, + }, + }, +}; + +usersDocs[`${apiPrefix}/resetProfileImg`] = { + get: { + tags: [`${tag}`], + summary: "유저 프로필 사진 기본값으로 재설정", + description: "유저의 프로필 사진을 기본값(랜덤한 사진)으로 초기화합니다", + responses: { + 200: { + content: { + "text/html": { + example: + "User/resetProfileImg : reset user profile image successful", + }, + }, + }, + 400: { + content: { + "text/html": { + example: "User/resetProfileImg : such user does not exist", + }, + }, + }, + 500: { + content: { + "text/html": { + example: "User/resetProfileImg : internal server error", + }, + }, + }, + }, + }, +}; + +module.exports = usersDocs; diff --git a/src/routes/users.js b/src/routes/users.js index 81ff7f03..31bde597 100755 --- a/src/routes/users.js +++ b/src/routes/users.js @@ -54,6 +54,6 @@ router.post( router.get("/editProfileImg/done", userHandlers.editProfileImgDoneHandler); // 프로필 이미지를 기본값으로 재설정합니다. -router.get("/resetProfileImg", userHandlers.resetProfileImg); +router.get("/resetProfileImg", userHandlers.resetProfileImgHandler); module.exports = router; diff --git a/src/services/users.js b/src/services/users.js index 82eb6129..06c580c4 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -175,7 +175,7 @@ const resetNicknameHandler = async (req, res) => { } }; -const resetProfileImg = async (req, res) => { +const resetProfileImgHandler = async (req, res) => { try { const result = await userModel.findOneAndUpdate( { id: req.userId }, @@ -202,5 +202,5 @@ module.exports = { editProfileImgGetPUrlHandler, editProfileImgDoneHandler, resetNicknameHandler, - resetProfileImg, + resetProfileImgHandler, }; From 7ba86763ccbbdc6a634080a038e173da2cf248fa Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Fri, 27 Oct 2023 01:52:28 +0900 Subject: [PATCH 27/32] Fix: auth nickname generation --- src/services/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/auth.js b/src/services/auth.js index 740a7aab..83b598de 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -43,7 +43,7 @@ const joinus = async (req, userData) => { const newUser = new userModel({ id: userData.id, name: userData.name, - nickname: userData.id, + nickname: generateNickname(userData.id), profileImageUrl: generateProfileImageUrl(), joinat: req.timestamp, subinfo: { From c234823fe70e54b3cd7ab61b2434f739f1d2fc6a Mon Sep 17 00:00:00 2001 From: TaehyeonPark Date: Fri, 27 Oct 2023 02:46:04 +0900 Subject: [PATCH 28/32] Refactor: early return pattern --- src/routes/docs/users.js | 4 ++-- src/services/users.js | 26 ++++++++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/routes/docs/users.js b/src/routes/docs/users.js index c40e08f2..e76cd2b4 100644 --- a/src/routes/docs/users.js +++ b/src/routes/docs/users.js @@ -4,7 +4,7 @@ const apiPrefix = "/users"; const usersDocs = {}; usersDocs[`${apiPrefix}/resetNickname`] = { get: { - tags: [`${tag}`], + tags: [tag], summary: "유저 닉네임 기본값으로 재설정", description: "유저의 별명을 기본값(랜덤한 닉네임)으로 초기화합니다", responses: { @@ -35,7 +35,7 @@ usersDocs[`${apiPrefix}/resetNickname`] = { usersDocs[`${apiPrefix}/resetProfileImg`] = { get: { - tags: [`${tag}`], + tags: [tag], summary: "유저 프로필 사진 기본값으로 재설정", description: "유저의 프로필 사진을 기본값(랜덤한 사진)으로 초기화합니다", responses: { diff --git a/src/services/users.js b/src/services/users.js index 06c580c4..3c26b164 100644 --- a/src/services/users.js +++ b/src/services/users.js @@ -162,13 +162,11 @@ const resetNicknameHandler = async (req, res) => { { nickname: generateNickname(req.body.id) }, { new: true } ); - if (result) { - res - .status(200) - .send("User/resetNickname : reset user nickname successful"); - } else { - res.status(400).send("User/resetNickname : such user does not exist"); - } + if (!result) + return res + .status(400) + .send("User/resetNickname : such user does not exist"); + res.status(200).send("User/resetNickname : reset user nickname successful"); } catch (err) { logger.error(err); res.status(500).send("User/resetNickname : internal server error"); @@ -182,13 +180,13 @@ const resetProfileImgHandler = async (req, res) => { { profileImageUrl: generateProfileImageUrl() }, { new: true } ); - if (result) { - res - .status(200) - .send("User/resetProfileImg : reset user profile image successful"); - } else { - res.status(400).send("User/resetProfileImg : such user does not exist"); - } + if (!result) + return res + .status(400) + .send("User/resetProfileImg : such user does not exist"); + res + .status(200) + .send("User/resetProfileImg : reset user profile image successful"); } catch (err) { res.status(500).send("User/resetProfileImg : internal server error"); } From dd6d4fe7b9bbc18fd57e9406f056dd21f3ef6c98 Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Thu, 2 Nov 2023 16:26:07 +0000 Subject: [PATCH 29/32] Docs: add error examples in the auth document --- src/routes/docs/auth.js | 549 +++++++++++++++++++++++++--------------- 1 file changed, 350 insertions(+), 199 deletions(-) diff --git a/src/routes/docs/auth.js b/src/routes/docs/auth.js index 801e8a01..a5d6eae6 100644 --- a/src/routes/docs/auth.js +++ b/src/routes/docs/auth.js @@ -1,205 +1,246 @@ -const authDocs = { - "/auth/sparcssso": { - get: { - tags: ["/auth"], - summary: "SPARCS SSO 로그인 페이지로 리다이렉트", - description: - "Prod의 경우 SSO 로그인 페이지로, Dev의 경우 replace 페이지로 리다이렉트함.", - parameters: [ - { - in: "query", - name: "redirect", - schema: { - type: "string", - }, - description: "리다이렉트 URI", +const tag = "auth"; +const apiPrefix = "/auth"; + +const authDocs = {}; +authDocs[`${apiPrefix}/sparcssso`] = { + get: { + tags: [tag], + summary: "SPARCS SSO 로그인 페이지로 리다이렉트", + description: + "Prod의 경우 SSO 로그인 페이지로, Dev의 경우 replace 페이지로 리다이렉트함.", + parameters: [ + { + in: "query", + name: "redirect", + schema: { + type: "string", }, - { - in: "query", - name: "isApp", - schema: { - type: "boolean", - }, - description: "앱인지 여부", - }, - ], - responses: { - 302: { - description: "SPARCS SSO 로그인 페이지로 리다이렉트", - headers: { - Location: { - type: "string", - description: "SPARCS SSO 로그인 페이지", - format: "uri", - }, + description: "리다이렉트 URI", + }, + { + in: "query", + name: "isApp", + schema: { + type: "boolean", + }, + description: "앱인지 여부", + }, + ], + responses: { + 302: { + description: "SPARCS SSO 로그인 페이지로 리다이렉트", + headers: { + Location: { + type: "string", + description: "SPARCS SSO 로그인 페이지", + format: "uri", }, }, }, }, }, - "/auth/sparcssso/callback": { - get: { - tags: ["/auth"], - summary: "SPARCS SSO 로그인 페이지에서 다시 리다이렉트를 처리", - description: - "SPARCS SSO 로그인 페이지로부터 프론트로 다시 리다이렉트되었을 때 로그인을 시도함.", - parameters: [ - { - in: "query", - name: "code", - schema: { - type: "string", - }, - description: "SSO server에서 부여한 유저 정보를 위한 code", +}; + +authDocs[`${apiPrefix}/sparcssso/callback`] = { + get: { + tags: [tag], + summary: "SPARCS SSO 로그인 페이지에서 다시 리다이렉트를 처리", + description: + "SPARCS SSO 로그인 페이지로부터 프론트로 다시 리다이렉트되었을 때 로그인을 시도함.", + parameters: [ + { + in: "query", + name: "code", + schema: { + type: "string", }, - { - in: "query", - name: "state", - schema: { + description: "SSO server에서 부여한 유저 정보를 위한 code", + }, + { + in: "query", + name: "state", + schema: { + type: "string", + }, + description: "login 성공 여부 확인을 위한 state", + }, + ], + responses: { + 302: { + description: + "로그인 성공 후 페이지 URI로, 혹은 로그인 실패 URI로 리다이렉트", + headers: { + Location: { type: "string", + description: "로그인 성공 후 페이지 URI, 혹은 로그인 실패 URI", + format: "uri", }, - description: "login 성공 여부 확인을 위한 state", - }, - ], - responses: { - 302: { - description: - "로그인 성공 후 페이지 URI로, 혹은 로그인 실패 URI로 리다이렉트", - headers: { - Location: { - type: "string", - description: "로그인 성공 후 페이지 URI, 혹은 로그인 실패 URI", - format: "uri", - }, + }, + }, + 400: { + content: { + "text/html": { + example: "SparcsssoCallbackHandler : invalid request", }, }, }, }, }, - "/auth/logout": { - get: { - tags: ["/auth"], - summary: "세션 삭제 및 사용자 로그아웃", - description: "세션 삭제 및 사용자 로그아웃", - parameters: [ - { - in: "query", - name: "redirect", - schema: { - type: "string", - }, - description: "로그아웃 후 리다이렉트 URI", - }, - ], - responses: { - 200: { - content: { - "application/json": { - schema: { - type: "object", - properties: { - ssoLogoutUrl: { - type: "string", - description: "SSO 로그아웃 URL", - }, +}; + +authDocs[`${apiPrefix}/logout`] = { + get: { + tags: [tag], + summary: "세션 삭제 및 사용자 로그아웃", + description: "세션 삭제 및 사용자 로그아웃", + parameters: [ + { + in: "query", + name: "redirect", + schema: { + type: "string", + }, + description: "로그아웃 후 리다이렉트 URI", + }, + ], + responses: { + 200: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + ssoLogoutUrl: { + type: "string", + description: "SSO 로그아웃 URL", }, }, }, }, }, }, - }, - }, - "/auth/app/token/login": { - get: { - tags: ["/auth"], - summary: "Access token을 사용하여 로그인", - description: "앱에서 Access Token을 사용하여 로그인 시도", - parameters: [ - { - in: "query", - name: "accessToken", - schema: { - type: "string", - }, - description: "만료 되지 않은 유효한 JWT Access Token", - }, - { - in: "query", - name: "deviceToken", - schema: { - type: "string", - }, - description: "Device Token", - }, - ], - responses: { - 200: { - description: "성공 메세지", - content: { - "text/plain": { - schema: { - type: "string", - example: "success", - }, - }, + 500: { + content: { + "text/html": { + example: "Auth/logout : internal server error", }, }, }, }, }, - "/auth/app/token/refresh": { - get: { - tags: ["/auth"], - summary: "만료된 Access Token 갱신", - description: "앱에서 Access Token을 Refresh Token을 활용하여 갱신", - parameters: [ - { - in: "query", - name: "accessToken", - schema: { - type: "string", +}; + +authDocs[`${apiPrefix}/app/token/login`] = { + get: { + tags: [tag], + summary: "Access token을 사용하여 로그인", + description: "앱에서 Access Token을 사용하여 로그인 시도", + parameters: [ + { + in: "query", + name: "accessToken", + schema: { + type: "string", + }, + description: "만료 되지 않은 유효한 JWT Access Token", + }, + { + in: "query", + name: "deviceToken", + schema: { + type: "string", + }, + description: "Device Token", + }, + ], + responses: { + 200: { + description: "성공 메세지", + content: { + "text/html": { + example: "success", }, - description: "만료된 유효한 JWT Access Token", }, - { - in: "query", - name: "refreshToken", - schema: { - type: "string", + }, + 400: { + content: { + "text/html": { + example: "invalid request", }, - description: "만료되지 않은 유효한 JWT Refresh Token", - }, - ], - responses: { - 200: { - content: { - "application/json": { - schema: { - type: "object", - properties: { - accessToken: { - type: "string", - description: "새로운 JWT Access Token", - }, - refreshToken: { - type: "string", - description: "새로운 Refresh Token", - }, + }, + }, + 401: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + message: { + type: "string", + }, + }, + }, + examples: { + "Invalid token": { + value: { + message: "Invalid token", + }, + }, + "Expired token": { + value: { + message: "Expired token", + }, + }, + "Not Access token": { + value: { + message: "Not Access token", + }, + }, + "No corresponding user": { + value: { + message: "No corresponding user", }, }, }, }, }, }, + 500: { + content: { + "text/html": { + example: "server error", + }, + }, + }, }, }, - "/auth/app/device": { - post: { - tags: ["/auth"], - summary: "기기의 Device Token을 데이터베이스에 등록", - description: "App 기기의 Device Token을 데이터베이스에 등록", - requestBody: { +}; + +authDocs[`${apiPrefix}/app/token/refresh`] = { + get: { + tags: [tag], + summary: "만료된 Access Token 갱신", + description: "앱에서 Access Token을 Refresh Token을 활용하여 갱신", + parameters: [ + { + in: "query", + name: "accessToken", + schema: { + type: "string", + }, + description: "만료된 유효한 JWT Access Token", + }, + { + in: "query", + name: "refreshToken", + schema: { + type: "string", + }, + description: "만료되지 않은 유효한 JWT Refresh Token", + }, + ], + responses: { + 200: { content: { "application/json": { schema: { @@ -207,69 +248,179 @@ const authDocs = { properties: { accessToken: { type: "string", - description: "만료 되지 않은 유효한 JWT Access Token", + description: "새로운 JWT Access Token", }, - deviceToken: { + refreshToken: { type: "string", - description: - "Firebase 라이브러리에서 제공해주는 Device Token", + description: "새로운 Refresh Token", }, }, }, }, }, }, - responses: { - 200: { - description: "성공 메세지", - content: { - "text/plain": { - schema: { - type: "string", - exapmle: "success", - }, - }, - }, + 400: { + "text/html": { + example: "invalid request", }, }, - }, - delete: { - tags: ["/auth"], - summary: "기기의 Device Token을 데이터베이스에서 삭제", - description: "App 기기의 Device Token을 데이터베이스에 삭제", - requestBody: { + 401: { content: { "application/json": { schema: { type: "object", properties: { - accessToken: { + message: { type: "string", - description: "만료 되지 않은 유효한 JWT accessToken", }, - deviceToken: { - type: "string", - description: "Firebase 라이브러리에서 제공해주는 DeviceToken", + }, + }, + examples: { + "Invalid access token": { + value: { + message: "Invalid access token", + }, + }, + "Invalid token": { + value: { + message: "Invalid token", }, }, + "Expired token": { + value: { + message: "Expired token", + }, + }, + "Not Refresh token": { + value: { + message: "Not Refresh token", + }, + }, + }, + }, + }, + }, + 501: { + content: { + "text/html": { + example: "server error", + }, + }, + }, + }, + }, +}; + +authDocs[`${apiPrefix}/app/device`] = { + post: { + tags: [tag], + summary: "기기의 Device Token을 데이터베이스에 등록", + description: "App 기기의 Device Token을 데이터베이스에 등록", + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + accessToken: { + type: "string", + description: "만료 되지 않은 유효한 JWT Access Token", + }, + deviceToken: { + type: "string", + description: "Firebase 라이브러리에서 제공해주는 Device Token", + }, }, }, }, }, - responses: { - 200: { - description: "성공 메세지", - content: { - "text/plain": { - schema: { + }, + responses: { + 200: { + description: "성공 메세지", + content: { + "text/html": { + example: "success", + }, + }, + }, + 400: { + content: { + "text/html": { + example: "invalid request", + }, + }, + }, + 401: { + content: { + "text/html": { + example: "unauthorized", + }, + }, + }, + 500: { + content: { + "text/html": { + example: "server error", + }, + }, + }, + }, + }, + delete: { + tags: [tag], + summary: "기기의 Device Token을 데이터베이스에서 삭제", + description: "App 기기의 Device Token을 데이터베이스에 삭제", + requestBody: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + accessToken: { + type: "string", + description: "만료 되지 않은 유효한 JWT accessToken", + }, + deviceToken: { type: "string", - exapmle: "success", + description: "Firebase 라이브러리에서 제공해주는 DeviceToken", }, }, }, }, }, }, + responses: { + 200: { + description: "성공 메세지", + content: { + "text/html": { + example: "success", + }, + }, + }, + 400: { + content: { + "text/html": { + example: "invalid request", + }, + }, + }, + 401: { + content: { + "text/html": { + example: "unauthorized", + }, + }, + }, + 500: { + content: { + "text/html": { + example: "server error", + }, + }, + }, + }, }, }; From b4fbb4296407146aedc9eff707aabff64240f6a0 Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Thu, 2 Nov 2023 16:26:41 +0000 Subject: [PATCH 30/32] Docs: rollback name --- src/routes/docs/swaggerDocs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/docs/swaggerDocs.js b/src/routes/docs/swaggerDocs.js index 5f00d08e..796a71f6 100644 --- a/src/routes/docs/swaggerDocs.js +++ b/src/routes/docs/swaggerDocs.js @@ -14,19 +14,19 @@ const swaggerDocs = { basePath: "/", tags: [ { - name: "/locations", + name: "locations", description: "출발지/도착지 정보 제공", }, { - name: "/logininfo", + name: "logininfo", description: "로그인 정보 제공", }, { - name: "/reports", + name: "reports", description: "사용자 신고 및 신고 기록 조회", }, { - name: "/auth", + name: "auth", description: "사용자 생성, 로그인, 로그아웃 등 사용자 상태 관리 지원", }, { From e7d1e3c808976de1d19c4a4ba26f73dcae92a073 Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Thu, 2 Nov 2023 16:27:06 +0000 Subject: [PATCH 31/32] Docs: align docs style with the recent documents --- src/routes/docs/locations.js | 93 +++++++++---------- src/routes/docs/logininfo.js | 170 ++++++++++++++++++----------------- src/routes/docs/reports.js | 87 +++++++++--------- 3 files changed, 178 insertions(+), 172 deletions(-) diff --git a/src/routes/docs/locations.js b/src/routes/docs/locations.js index 6f7d3847..1fb445b9 100644 --- a/src/routes/docs/locations.js +++ b/src/routes/docs/locations.js @@ -1,52 +1,53 @@ -const locationsDocs = { - "/locations": { - get: { - tags: ["/locations"], - summary: "출발지/도착지 정보 반환", - description: - "출발지/도착지로 사용 가능한 장소 목록 조회 및 요청 처리 당시 서버 시각 반환
\n (로그인된 상태에서만 접근 가능)", - responses: { - 200: { - description: - "서버에 저장된 location이 없을 경우, locations은 빈 배열", - content: { - "application/json": { - schema: { - type: "object", - properties: { - locations: { - type: "array", - description: "출발지/도착지로 사용 가능한 장소 목록", - items: { - type: "object", - properties: { - priority: { - type: "number", - }, - isValid: { - type: "boolean", - }, - _id: { - type: "string", - }, - koName: { - type: "string", - description: "장소의 한국어 명칭", - example: "택시승강장", - }, - enName: { - type: "string", - description: "장소의 영어 명칭", - example: "Taxi Stand", - }, +const tag = "locations"; +const apiPrefix = "/locations"; + +const locationsDocs = {}; +locationsDocs[`${apiPrefix}`] = { + get: { + tags: [tag], + summary: "출발지/도착지 정보 반환", + description: + "출발지/도착지로 사용 가능한 장소 목록 조회 및 요청 처리 당시 서버 시각 반환
\n (로그인된 상태에서만 접근 가능)", + responses: { + 200: { + description: "서버에 저장된 location이 없을 경우, locations은 빈 배열", + content: { + "application/json": { + schema: { + type: "object", + properties: { + locations: { + type: "array", + description: "출발지/도착지로 사용 가능한 장소 목록", + items: { + type: "object", + properties: { + priority: { + type: "number", + }, + isValid: { + type: "boolean", + }, + _id: { + type: "string", + }, + koName: { + type: "string", + description: "장소의 한국어 명칭", + example: "택시승강장", + }, + enName: { + type: "string", + description: "장소의 영어 명칭", + example: "Taxi Stand", }, }, }, - serverTime: { - type: "string", - format: "date-time", - description: "요청 처리 당시 서버 시각", - }, + }, + serverTime: { + type: "string", + format: "date-time", + description: "요청 처리 당시 서버 시각", }, }, }, diff --git a/src/routes/docs/logininfo.js b/src/routes/docs/logininfo.js index 95df5967..e752d3b0 100644 --- a/src/routes/docs/logininfo.js +++ b/src/routes/docs/logininfo.js @@ -1,89 +1,91 @@ -const logininfoDocs = { - "/logininfo": { - get: { - tags: ["/logininfo"], - summary: "사용자 정보 반환", - description: "로그인되어 있는 사용자의 정보를 반환", - responses: { - 200: { - description: - "사용자의 로그인 세션이 유효한 경우, 현재 로그인된 사용자의 정보를 반환,
\n 세션이 유효하지 않은 경우, 빈 오브젝트를 반환", - content: { - "application/json": { - schema: { - type: "object", - properties: { - oid: { - type: "string", - }, - id: { - type: "string", - description: "사용자 id", - }, - name: { - type: "string", - description: "사용자 이름", - }, - nickname: { - type: "string", - }, - withdraw: { - type: "boolean", - }, - phoneNumber: { - type: "string", - description: "사용자 전화번호", - }, - ban: { - type: "boolean", - }, - joinat: { - type: "string", - format: "date-time", - }, - agreeOnTermsOfService: { - type: "boolean", - }, - subinfo: { - type: "object", - properties: { - kaist: { - type: "string", - description: "KAIST 학번(8자리)", - minLength: 8, - maxLength: 8, - example: "20190052", - }, - sparcs: { - type: "string", - }, - facebook: { - type: "string", - }, - twitter: { - type: "string", - }, +const tag = "logininfo"; +const apiPrefix = "/logininfo"; + +const logininfoDocs = {}; +logininfoDocs[`${apiPrefix}`] = { + get: { + tags: [tag], + summary: "사용자 정보 반환", + description: "로그인되어 있는 사용자의 정보를 반환", + responses: { + 200: { + description: + "사용자의 로그인 세션이 유효한 경우, 현재 로그인된 사용자의 정보를 반환,
\n 세션이 유효하지 않은 경우, 빈 오브젝트를 반환", + content: { + "application/json": { + schema: { + type: "object", + properties: { + oid: { + type: "string", + }, + id: { + type: "string", + description: "사용자 id", + }, + name: { + type: "string", + description: "사용자 이름", + }, + nickname: { + type: "string", + }, + withdraw: { + type: "boolean", + }, + phoneNumber: { + type: "string", + description: "사용자 전화번호", + }, + ban: { + type: "boolean", + }, + joinat: { + type: "string", + format: "date-time", + }, + agreeOnTermsOfService: { + type: "boolean", + }, + subinfo: { + type: "object", + properties: { + kaist: { + type: "string", + description: "KAIST 학번(8자리)", + minLength: 8, + maxLength: 8, + example: "20190052", + }, + sparcs: { + type: "string", + }, + facebook: { + type: "string", + }, + twitter: { + type: "string", }, }, - email: { - type: "string", - example: "geon6757@kaist.ac.kr", - }, - profileImgUrl: { - type: "string", - }, - account: { - type: "string", - }, - deviceToken: { - type: "string", - description: - "클라이언트의 디바이스 토큰, 세션에 저장되어 있지 않은 경우 undefined", - }, - deviceType: { - type: "string", - enum: ["web", "app"], - }, + }, + email: { + type: "string", + example: "geon6757@kaist.ac.kr", + }, + profileImgUrl: { + type: "string", + }, + account: { + type: "string", + }, + deviceToken: { + type: "string", + description: + "클라이언트의 디바이스 토큰, 세션에 저장되어 있지 않은 경우 undefined", + }, + deviceType: { + type: "string", + enum: ["web", "app"], }, }, }, diff --git a/src/routes/docs/reports.js b/src/routes/docs/reports.js index 22eab8f0..b2e3b035 100644 --- a/src/routes/docs/reports.js +++ b/src/routes/docs/reports.js @@ -1,54 +1,57 @@ -const reportsDocs = { - "/reports/create": { - post: { - tags: ["/reports"], - summary: "신고 작성", - description: "주어진 유저를 전달된 사유로 신고함", - requestBody: { - description: "Update an existent user in the store", - content: { - "application/json": { - schema: { - $ref: "#/components/schemas/createHandler", - }, +const tag = "reports"; +const apiPrefix = "/reports"; + +const reportsDocs = {}; +reportsDocs[`${apiPrefix}/create`] = { + post: { + tags: [tag], + summary: "신고 작성", + description: "주어진 유저를 전달된 사유로 신고함", + requestBody: { + description: "Update an existent user in the store", + content: { + "application/json": { + schema: { + $ref: "#/components/schemas/createHandler", }, }, }, - responses: { - 200: { - description: "report successful", - content: { - "text/plain": { - schema: { - type: "string", - example: "report successful", - }, + }, + responses: { + 200: { + description: "report successful", + content: { + "text/plain": { + schema: { + type: "string", + example: "report successful", }, }, }, }, }, }, - "/reports/searchByUser": { - get: { - tags: ["/reports"], - summary: "신고 내역 반환", - description: - "로그인된 사용자의 신고한 내역과, 신고받은 내역을 반환한다
1000개의 limit이 있다.", - responses: { - 200: { - description: "신고된 내역과 신고 받은 내역", - content: { - "application/json": { - schema: { - type: "object", - properties: { - reporting: { - type: "array", - }, - reported: { - type: "array", - }, +}; + +reportsDocs[`${apiPrefix}/searchByUser`] = { + get: { + tags: [tag], + summary: "신고 내역 반환", + description: + "로그인된 사용자의 신고한 내역과, 신고받은 내역을 반환한다
1000개의 limit이 있다.", + responses: { + 200: { + description: "신고된 내역과 신고 받은 내역", + content: { + "application/json": { + schema: { + type: "object", + properties: { + reporting: { + type: "array", + }, + reported: { + type: "array", }, }, }, From 2301c54b1e42e223a642c0197cb624c1d450e919 Mon Sep 17 00:00:00 2001 From: Dongwon Choi Date: Thu, 2 Nov 2023 16:31:50 +0000 Subject: [PATCH 32/32] Docs: update error message --- src/routes/docs/reports.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/routes/docs/reports.js b/src/routes/docs/reports.js index b2e3b035..0f5b8e76 100644 --- a/src/routes/docs/reports.js +++ b/src/routes/docs/reports.js @@ -29,6 +29,14 @@ reportsDocs[`${apiPrefix}/create`] = { }, }, }, + 500: { + description: "internal server error", + content: { + "text/html": { + example: "User/report : internal server error", + }, + }, + }, }, }, }; @@ -58,6 +66,14 @@ reportsDocs[`${apiPrefix}/searchByUser`] = { }, }, }, + 500: { + description: "internal server error", + content: { + "text/html": { + example: "report/searchByUser : internal server error", + }, + }, + }, }, }, };