dn-react-router-toolkit 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,15 @@
1
1
  interface AuthRepository<TFile = unknown> {
2
2
  findCredentialById(id: string): Promise<{
3
+ id: string;
3
4
  password: string;
4
5
  userId: string;
5
6
  } | undefined>;
7
+ createCredential(params: {
8
+ id: string;
9
+ password: string;
10
+ userId: string;
11
+ }): Promise<void>;
12
+ updatePassword(id: string, hashedPassword: string): Promise<void>;
6
13
  findUserById(userId: string): Promise<{
7
14
  id: string;
8
15
  role: string;
@@ -29,11 +36,6 @@ interface AuthRepository<TFile = unknown> {
29
36
  provider: string;
30
37
  userId: string;
31
38
  }): Promise<void>;
32
- createCredential(params: {
33
- id: string;
34
- password: string;
35
- userId: string;
36
- }): Promise<void>;
37
39
  }
38
40
 
39
41
  export type { AuthRepository };
@@ -1,8 +1,15 @@
1
1
  interface AuthRepository<TFile = unknown> {
2
2
  findCredentialById(id: string): Promise<{
3
+ id: string;
3
4
  password: string;
4
5
  userId: string;
5
6
  } | undefined>;
7
+ createCredential(params: {
8
+ id: string;
9
+ password: string;
10
+ userId: string;
11
+ }): Promise<void>;
12
+ updatePassword(id: string, hashedPassword: string): Promise<void>;
6
13
  findUserById(userId: string): Promise<{
7
14
  id: string;
8
15
  role: string;
@@ -29,11 +36,6 @@ interface AuthRepository<TFile = unknown> {
29
36
  provider: string;
30
37
  userId: string;
31
38
  }): Promise<void>;
32
- createCredential(params: {
33
- id: string;
34
- password: string;
35
- userId: string;
36
- }): Promise<void>;
37
39
  }
38
40
 
39
41
  export type { AuthRepository };
@@ -24,7 +24,7 @@ declare class AuthService<TFile = unknown> {
24
24
  getAccessTokenFromCookies(request: Request): Promise<any>;
25
25
  getRefreshTokenFromCookies(request: Request): Promise<any>;
26
26
  refresh(request: Request): Promise<jose.JWTPayload | undefined>;
27
- signIn({ id, password }: {
27
+ login({ id, password }: {
28
28
  id: string;
29
29
  password: string;
30
30
  }): Promise<{
@@ -24,7 +24,7 @@ declare class AuthService<TFile = unknown> {
24
24
  getAccessTokenFromCookies(request: Request): Promise<any>;
25
25
  getRefreshTokenFromCookies(request: Request): Promise<any>;
26
26
  refresh(request: Request): Promise<jose.JWTPayload | undefined>;
27
- signIn({ id, password }: {
27
+ login({ id, password }: {
28
28
  id: string;
29
29
  password: string;
30
30
  }): Promise<{
@@ -117,7 +117,7 @@ var AuthService = class {
117
117
  }
118
118
  }
119
119
  }
120
- async signIn({ id, password }) {
120
+ async login({ id, password }) {
121
121
  const credential = await this.authRepository.findCredentialById(id);
122
122
  if (!credential) {
123
123
  throw Error("\uC544\uC774\uB514 \uB610\uB294 \uBE44\uBC00\uBC88\uD638\uAC00 \uD2C0\uB838\uC2B5\uB2C8\uB2E4.");
@@ -79,7 +79,7 @@ var AuthService = class {
79
79
  }
80
80
  }
81
81
  }
82
- async signIn({ id, password }) {
82
+ async login({ id, password }) {
83
83
  const credential = await this.authRepository.findCredentialById(id);
84
84
  if (!credential) {
85
85
  throw Error("\uC544\uC774\uB514 \uB610\uB294 \uBE44\uBC00\uBC88\uD638\uAC00 \uD2C0\uB838\uC2B5\uB2C8\uB2E4.");
@@ -7,6 +7,9 @@ type AuthContextValue = {
7
7
  login: (id: string, password: string) => Promise<void>;
8
8
  loginWithGoogle: (redirectUrl?: string) => Promise<void>;
9
9
  logout: () => Promise<void>;
10
+ signup: (email: string, password: string, passwordConfirm: string) => Promise<{
11
+ userId: string;
12
+ }>;
10
13
  requestResetPassword: (email: string) => Promise<boolean>;
11
14
  resetPassword: (token: string, password: string, passwordConfirm: string) => Promise<boolean>;
12
15
  };
@@ -7,6 +7,9 @@ type AuthContextValue = {
7
7
  login: (id: string, password: string) => Promise<void>;
8
8
  loginWithGoogle: (redirectUrl?: string) => Promise<void>;
9
9
  logout: () => Promise<void>;
10
+ signup: (email: string, password: string, passwordConfirm: string) => Promise<{
11
+ userId: string;
12
+ }>;
10
13
  requestResetPassword: (email: string) => Promise<boolean>;
11
14
  resetPassword: (token: string, password: string, passwordConfirm: string) => Promise<boolean>;
12
15
  };
@@ -90,8 +90,22 @@ function AuthProvider({ children, googleAuth }) {
90
90
  alert(message);
91
91
  }
92
92
  };
93
+ const signup = async (email, password, passwordConfirm) => {
94
+ const response = await fetch("/api/auth/signup", {
95
+ method: "POST",
96
+ headers: {
97
+ "Content-Type": "application/json"
98
+ },
99
+ body: JSON.stringify({ email, password, passwordConfirm })
100
+ });
101
+ if (!response.ok) {
102
+ const { message } = await response.json();
103
+ throw new Error(message);
104
+ }
105
+ return response.json();
106
+ };
93
107
  const requestResetPassword = async (email) => {
94
- const response = await fetch("/api/find-password", {
108
+ const response = await fetch("/api/auth/request-password-reset", {
95
109
  method: "POST",
96
110
  headers: {
97
111
  "Content-Type": "application/json"
@@ -106,7 +120,7 @@ function AuthProvider({ children, googleAuth }) {
106
120
  return true;
107
121
  };
108
122
  const resetPassword = async (token, password, passwordConfirm) => {
109
- const response = await fetch("/api/reset-password", {
123
+ const response = await fetch("/api/auth/reset-password", {
110
124
  method: "POST",
111
125
  headers: {
112
126
  "Content-Type": "application/json"
@@ -125,6 +139,7 @@ function AuthProvider({ children, googleAuth }) {
125
139
  login,
126
140
  logout,
127
141
  loginWithGoogle,
142
+ signup,
128
143
  requestResetPassword,
129
144
  resetPassword
130
145
  };
@@ -54,8 +54,22 @@ function AuthProvider({ children, googleAuth }) {
54
54
  alert(message);
55
55
  }
56
56
  };
57
+ const signup = async (email, password, passwordConfirm) => {
58
+ const response = await fetch("/api/auth/signup", {
59
+ method: "POST",
60
+ headers: {
61
+ "Content-Type": "application/json"
62
+ },
63
+ body: JSON.stringify({ email, password, passwordConfirm })
64
+ });
65
+ if (!response.ok) {
66
+ const { message } = await response.json();
67
+ throw new Error(message);
68
+ }
69
+ return response.json();
70
+ };
57
71
  const requestResetPassword = async (email) => {
58
- const response = await fetch("/api/find-password", {
72
+ const response = await fetch("/api/auth/request-password-reset", {
59
73
  method: "POST",
60
74
  headers: {
61
75
  "Content-Type": "application/json"
@@ -70,7 +84,7 @@ function AuthProvider({ children, googleAuth }) {
70
84
  return true;
71
85
  };
72
86
  const resetPassword = async (token, password, passwordConfirm) => {
73
- const response = await fetch("/api/reset-password", {
87
+ const response = await fetch("/api/auth/reset-password", {
74
88
  method: "POST",
75
89
  headers: {
76
90
  "Content-Type": "application/json"
@@ -89,6 +103,7 @@ function AuthProvider({ children, googleAuth }) {
89
103
  login,
90
104
  logout,
91
105
  loginWithGoogle,
106
+ signup,
92
107
  requestResetPassword,
93
108
  resetPassword
94
109
  };
@@ -74,7 +74,7 @@ var loginHandler = async (request, {
74
74
  }) => {
75
75
  const { id, password } = await request.json();
76
76
  try {
77
- const { accessToken, refreshToken } = await authService.signIn({
77
+ const { accessToken, refreshToken } = await authService.login({
78
78
  id,
79
79
  password
80
80
  });
@@ -48,7 +48,7 @@ var loginHandler = async (request, {
48
48
  }) => {
49
49
  const { id, password } = await request.json();
50
50
  try {
51
- const { accessToken, refreshToken } = await authService.signIn({
51
+ const { accessToken, refreshToken } = await authService.login({
52
52
  id,
53
53
  password
54
54
  });
@@ -0,0 +1,10 @@
1
+ import { PasswordRecoveryService } from '../password_recovery.mjs';
2
+ import '../auth_repository.mjs';
3
+ import '../jwt_manager.mjs';
4
+ import 'jose';
5
+
6
+ declare const requestPasswordResetHandler: (request: Request, { passwordRecoveryService, }: {
7
+ passwordRecoveryService: PasswordRecoveryService;
8
+ }) => Promise<Response>;
9
+
10
+ export { requestPasswordResetHandler };
@@ -0,0 +1,10 @@
1
+ import { PasswordRecoveryService } from '../password_recovery.js';
2
+ import '../auth_repository.js';
3
+ import '../jwt_manager.js';
4
+ import 'jose';
5
+
6
+ declare const requestPasswordResetHandler: (request: Request, { passwordRecoveryService, }: {
7
+ passwordRecoveryService: PasswordRecoveryService;
8
+ }) => Promise<Response>;
9
+
10
+ export { requestPasswordResetHandler };
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/auth/handlers/request_password_reset.ts
21
+ var request_password_reset_exports = {};
22
+ __export(request_password_reset_exports, {
23
+ requestPasswordResetHandler: () => requestPasswordResetHandler
24
+ });
25
+ module.exports = __toCommonJS(request_password_reset_exports);
26
+
27
+ // src/http/response.ts
28
+ var createJsonResponse = (status) => {
29
+ return (data = {}, init) => {
30
+ return Response.json(data, { status, ...init });
31
+ };
32
+ };
33
+ var OK = createJsonResponse(200);
34
+ var CREATED = createJsonResponse(201);
35
+ var ACCEPTED = createJsonResponse(202);
36
+ var createException = (status, defaultMessage = "\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.") => {
37
+ return (message = defaultMessage, init) => {
38
+ return createJsonResponse(status)({ message }, init);
39
+ };
40
+ };
41
+ var BAD_REQUEST = createException(400, "\uC694\uCCAD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
42
+ var UNAUTHORIZED = createException(401, "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
43
+ var FORBIDDEN = createException(403, "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
44
+ var NOT_FOUND = createException(
45
+ 404,
46
+ "\uC694\uCCAD\uD55C \uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
47
+ );
48
+ var METHOD_NOT_ALLOWED = createException(
49
+ 405,
50
+ "\uBA54\uC11C\uB4DC\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
51
+ );
52
+ var NOT_ACCEPTABLE = createException(
53
+ 406,
54
+ "\uC694\uCCAD\uD55C \uD615\uC2DD\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
55
+ );
56
+ var REQUEST_TIMEOUT = createException(
57
+ 408,
58
+ "\uC694\uCCAD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."
59
+ );
60
+ var CONFLICT = createException(409, "\uC694\uCCAD\uC774 \uCDA9\uB3CC\uD588\uC2B5\uB2C8\uB2E4.");
61
+ var UNPROCESSABLE_ENTITY = createException(
62
+ 422,
63
+ "\uCC98\uB9AC\uD560 \uC218 \uC5C6\uB294 \uC5D4\uD2F0\uD2F0\uC785\uB2C8\uB2E4."
64
+ );
65
+ var TOO_MANY_REQUESTS = createException(429, "\uC694\uCCAD\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4.");
66
+ var INTERNAL_SERVER_ERROR = createException(
67
+ 500,
68
+ "\uC608\uAE30\uCE58 \uBABB\uD55C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4."
69
+ );
70
+
71
+ // src/auth/handlers/request_password_reset.ts
72
+ var requestPasswordResetHandler = async (request, {
73
+ passwordRecoveryService
74
+ }) => {
75
+ const { email } = await request.json();
76
+ try {
77
+ await passwordRecoveryService.requestPasswordReset(email);
78
+ return CREATED({ message: "\uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815 \uC774\uBA54\uC77C\uC744 \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4." });
79
+ } catch (error) {
80
+ console.error(error);
81
+ return INTERNAL_SERVER_ERROR("\uC774\uBA54\uC77C \uC804\uC1A1\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
82
+ }
83
+ };
84
+ // Annotate the CommonJS export names for ESM import in node:
85
+ 0 && (module.exports = {
86
+ requestPasswordResetHandler
87
+ });
@@ -0,0 +1,60 @@
1
+ // src/http/response.ts
2
+ var createJsonResponse = (status) => {
3
+ return (data = {}, init) => {
4
+ return Response.json(data, { status, ...init });
5
+ };
6
+ };
7
+ var OK = createJsonResponse(200);
8
+ var CREATED = createJsonResponse(201);
9
+ var ACCEPTED = createJsonResponse(202);
10
+ var createException = (status, defaultMessage = "\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.") => {
11
+ return (message = defaultMessage, init) => {
12
+ return createJsonResponse(status)({ message }, init);
13
+ };
14
+ };
15
+ var BAD_REQUEST = createException(400, "\uC694\uCCAD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
16
+ var UNAUTHORIZED = createException(401, "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
17
+ var FORBIDDEN = createException(403, "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
18
+ var NOT_FOUND = createException(
19
+ 404,
20
+ "\uC694\uCCAD\uD55C \uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
21
+ );
22
+ var METHOD_NOT_ALLOWED = createException(
23
+ 405,
24
+ "\uBA54\uC11C\uB4DC\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
25
+ );
26
+ var NOT_ACCEPTABLE = createException(
27
+ 406,
28
+ "\uC694\uCCAD\uD55C \uD615\uC2DD\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
29
+ );
30
+ var REQUEST_TIMEOUT = createException(
31
+ 408,
32
+ "\uC694\uCCAD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."
33
+ );
34
+ var CONFLICT = createException(409, "\uC694\uCCAD\uC774 \uCDA9\uB3CC\uD588\uC2B5\uB2C8\uB2E4.");
35
+ var UNPROCESSABLE_ENTITY = createException(
36
+ 422,
37
+ "\uCC98\uB9AC\uD560 \uC218 \uC5C6\uB294 \uC5D4\uD2F0\uD2F0\uC785\uB2C8\uB2E4."
38
+ );
39
+ var TOO_MANY_REQUESTS = createException(429, "\uC694\uCCAD\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4.");
40
+ var INTERNAL_SERVER_ERROR = createException(
41
+ 500,
42
+ "\uC608\uAE30\uCE58 \uBABB\uD55C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4."
43
+ );
44
+
45
+ // src/auth/handlers/request_password_reset.ts
46
+ var requestPasswordResetHandler = async (request, {
47
+ passwordRecoveryService
48
+ }) => {
49
+ const { email } = await request.json();
50
+ try {
51
+ await passwordRecoveryService.requestPasswordReset(email);
52
+ return CREATED({ message: "\uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815 \uC774\uBA54\uC77C\uC744 \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4." });
53
+ } catch (error) {
54
+ console.error(error);
55
+ return INTERNAL_SERVER_ERROR("\uC774\uBA54\uC77C \uC804\uC1A1\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
56
+ }
57
+ };
58
+ export {
59
+ requestPasswordResetHandler
60
+ };
@@ -0,0 +1,10 @@
1
+ import { PasswordRecoveryService } from '../password_recovery.mjs';
2
+ import '../auth_repository.mjs';
3
+ import '../jwt_manager.mjs';
4
+ import 'jose';
5
+
6
+ declare const resetPasswordHandler: (request: Request, { passwordRecoveryService, }: {
7
+ passwordRecoveryService: PasswordRecoveryService;
8
+ }) => Promise<Response>;
9
+
10
+ export { resetPasswordHandler };
@@ -0,0 +1,10 @@
1
+ import { PasswordRecoveryService } from '../password_recovery.js';
2
+ import '../auth_repository.js';
3
+ import '../jwt_manager.js';
4
+ import 'jose';
5
+
6
+ declare const resetPasswordHandler: (request: Request, { passwordRecoveryService, }: {
7
+ passwordRecoveryService: PasswordRecoveryService;
8
+ }) => Promise<Response>;
9
+
10
+ export { resetPasswordHandler };
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/auth/handlers/reset_password.ts
21
+ var reset_password_exports = {};
22
+ __export(reset_password_exports, {
23
+ resetPasswordHandler: () => resetPasswordHandler
24
+ });
25
+ module.exports = __toCommonJS(reset_password_exports);
26
+
27
+ // src/http/response.ts
28
+ var createJsonResponse = (status) => {
29
+ return (data = {}, init) => {
30
+ return Response.json(data, { status, ...init });
31
+ };
32
+ };
33
+ var OK = createJsonResponse(200);
34
+ var CREATED = createJsonResponse(201);
35
+ var ACCEPTED = createJsonResponse(202);
36
+ var NO_CONTENT = (init) => {
37
+ return new Response(null, {
38
+ ...init,
39
+ status: 204
40
+ });
41
+ };
42
+ var createException = (status, defaultMessage = "\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.") => {
43
+ return (message = defaultMessage, init) => {
44
+ return createJsonResponse(status)({ message }, init);
45
+ };
46
+ };
47
+ var BAD_REQUEST = createException(400, "\uC694\uCCAD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
48
+ var UNAUTHORIZED = createException(401, "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
49
+ var FORBIDDEN = createException(403, "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
50
+ var NOT_FOUND = createException(
51
+ 404,
52
+ "\uC694\uCCAD\uD55C \uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
53
+ );
54
+ var METHOD_NOT_ALLOWED = createException(
55
+ 405,
56
+ "\uBA54\uC11C\uB4DC\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
57
+ );
58
+ var NOT_ACCEPTABLE = createException(
59
+ 406,
60
+ "\uC694\uCCAD\uD55C \uD615\uC2DD\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
61
+ );
62
+ var REQUEST_TIMEOUT = createException(
63
+ 408,
64
+ "\uC694\uCCAD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."
65
+ );
66
+ var CONFLICT = createException(409, "\uC694\uCCAD\uC774 \uCDA9\uB3CC\uD588\uC2B5\uB2C8\uB2E4.");
67
+ var UNPROCESSABLE_ENTITY = createException(
68
+ 422,
69
+ "\uCC98\uB9AC\uD560 \uC218 \uC5C6\uB294 \uC5D4\uD2F0\uD2F0\uC785\uB2C8\uB2E4."
70
+ );
71
+ var TOO_MANY_REQUESTS = createException(429, "\uC694\uCCAD\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4.");
72
+ var INTERNAL_SERVER_ERROR = createException(
73
+ 500,
74
+ "\uC608\uAE30\uCE58 \uBABB\uD55C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4."
75
+ );
76
+
77
+ // src/auth/handlers/reset_password.ts
78
+ var resetPasswordHandler = async (request, {
79
+ passwordRecoveryService
80
+ }) => {
81
+ const { token, password, passwordConfirm } = await request.json();
82
+ await passwordRecoveryService.resetPassword(token, password, passwordConfirm);
83
+ return NO_CONTENT();
84
+ };
85
+ // Annotate the CommonJS export names for ESM import in node:
86
+ 0 && (module.exports = {
87
+ resetPasswordHandler
88
+ });
@@ -0,0 +1,61 @@
1
+ // src/http/response.ts
2
+ var createJsonResponse = (status) => {
3
+ return (data = {}, init) => {
4
+ return Response.json(data, { status, ...init });
5
+ };
6
+ };
7
+ var OK = createJsonResponse(200);
8
+ var CREATED = createJsonResponse(201);
9
+ var ACCEPTED = createJsonResponse(202);
10
+ var NO_CONTENT = (init) => {
11
+ return new Response(null, {
12
+ ...init,
13
+ status: 204
14
+ });
15
+ };
16
+ var createException = (status, defaultMessage = "\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.") => {
17
+ return (message = defaultMessage, init) => {
18
+ return createJsonResponse(status)({ message }, init);
19
+ };
20
+ };
21
+ var BAD_REQUEST = createException(400, "\uC694\uCCAD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
22
+ var UNAUTHORIZED = createException(401, "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
23
+ var FORBIDDEN = createException(403, "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
24
+ var NOT_FOUND = createException(
25
+ 404,
26
+ "\uC694\uCCAD\uD55C \uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
27
+ );
28
+ var METHOD_NOT_ALLOWED = createException(
29
+ 405,
30
+ "\uBA54\uC11C\uB4DC\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
31
+ );
32
+ var NOT_ACCEPTABLE = createException(
33
+ 406,
34
+ "\uC694\uCCAD\uD55C \uD615\uC2DD\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
35
+ );
36
+ var REQUEST_TIMEOUT = createException(
37
+ 408,
38
+ "\uC694\uCCAD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."
39
+ );
40
+ var CONFLICT = createException(409, "\uC694\uCCAD\uC774 \uCDA9\uB3CC\uD588\uC2B5\uB2C8\uB2E4.");
41
+ var UNPROCESSABLE_ENTITY = createException(
42
+ 422,
43
+ "\uCC98\uB9AC\uD560 \uC218 \uC5C6\uB294 \uC5D4\uD2F0\uD2F0\uC785\uB2C8\uB2E4."
44
+ );
45
+ var TOO_MANY_REQUESTS = createException(429, "\uC694\uCCAD\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4.");
46
+ var INTERNAL_SERVER_ERROR = createException(
47
+ 500,
48
+ "\uC608\uAE30\uCE58 \uBABB\uD55C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4."
49
+ );
50
+
51
+ // src/auth/handlers/reset_password.ts
52
+ var resetPasswordHandler = async (request, {
53
+ passwordRecoveryService
54
+ }) => {
55
+ const { token, password, passwordConfirm } = await request.json();
56
+ await passwordRecoveryService.resetPassword(token, password, passwordConfirm);
57
+ return NO_CONTENT();
58
+ };
59
+ export {
60
+ resetPasswordHandler
61
+ };
@@ -102,12 +102,9 @@ var signupHandler = async (request, {
102
102
  if (!passwordConfirm) {
103
103
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638 \uD655\uC778\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
104
104
  }
105
- if (!name) {
106
- return BAD_REQUEST("\uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
107
- }
108
105
  const existing = await authService.authRepository.findCredentialById(email);
109
106
  if (existing) {
110
- return CONFLICT("\uC774\uBA54\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.");
107
+ return CONFLICT("\uC774\uBBF8 \uAC00\uC785\uD55C \uC774\uBA54\uC77C\uC785\uB2C8\uB2E4.");
111
108
  }
112
109
  if (password !== passwordConfirm) {
113
110
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
@@ -127,7 +124,22 @@ var signupHandler = async (request, {
127
124
  password: bcrypt.hashSync(password, 10)
128
125
  });
129
126
  const { accessToken, refreshToken } = await authService.issueTokenPair(user);
130
- return CREATED({ accessToken, refreshToken });
127
+ const searchParams = new URL(request.url).searchParams;
128
+ const type = searchParams.get("type");
129
+ if (type === "json") {
130
+ return CREATED({ accessToken, refreshToken });
131
+ }
132
+ const [accessTokenSetCookie, refreshTokenSetCookie] = await Promise.all([
133
+ authService.getAccessTokenSetCookie(accessToken),
134
+ authService.getRefreshTokenSetCookie(refreshToken)
135
+ ]);
136
+ const payload = authService.jwtManager.decode(accessToken);
137
+ const headers = new Headers();
138
+ headers.append("Set-Cookie", accessTokenSetCookie);
139
+ headers.append("Set-Cookie", refreshTokenSetCookie);
140
+ return CREATED(payload, {
141
+ headers
142
+ });
131
143
  };
132
144
  // Annotate the CommonJS export names for ESM import in node:
133
145
  0 && (module.exports = {
@@ -68,12 +68,9 @@ var signupHandler = async (request, {
68
68
  if (!passwordConfirm) {
69
69
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638 \uD655\uC778\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
70
70
  }
71
- if (!name) {
72
- return BAD_REQUEST("\uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
73
- }
74
71
  const existing = await authService.authRepository.findCredentialById(email);
75
72
  if (existing) {
76
- return CONFLICT("\uC774\uBA54\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.");
73
+ return CONFLICT("\uC774\uBBF8 \uAC00\uC785\uD55C \uC774\uBA54\uC77C\uC785\uB2C8\uB2E4.");
77
74
  }
78
75
  if (password !== passwordConfirm) {
79
76
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
@@ -93,7 +90,22 @@ var signupHandler = async (request, {
93
90
  password: bcrypt.hashSync(password, 10)
94
91
  });
95
92
  const { accessToken, refreshToken } = await authService.issueTokenPair(user);
96
- return CREATED({ accessToken, refreshToken });
93
+ const searchParams = new URL(request.url).searchParams;
94
+ const type = searchParams.get("type");
95
+ if (type === "json") {
96
+ return CREATED({ accessToken, refreshToken });
97
+ }
98
+ const [accessTokenSetCookie, refreshTokenSetCookie] = await Promise.all([
99
+ authService.getAccessTokenSetCookie(accessToken),
100
+ authService.getRefreshTokenSetCookie(refreshToken)
101
+ ]);
102
+ const payload = authService.jwtManager.decode(accessToken);
103
+ const headers = new Headers();
104
+ headers.append("Set-Cookie", accessTokenSetCookie);
105
+ headers.append("Set-Cookie", refreshTokenSetCookie);
106
+ return CREATED(payload, {
107
+ headers
108
+ });
97
109
  };
98
110
  export {
99
111
  signupHandler
@@ -0,0 +1,34 @@
1
+ import { AuthRepository } from './auth_repository.mjs';
2
+ import { JWTManager } from './jwt_manager.mjs';
3
+ import 'jose';
4
+
5
+ declare class PasswordRecoveryService {
6
+ siteOrigin: string;
7
+ siteName: string;
8
+ jwtManager: JWTManager;
9
+ authRepository: AuthRepository;
10
+ emailCredentials: {
11
+ service: string;
12
+ user: string;
13
+ pass: string;
14
+ };
15
+ resetPasswordTokenSecret: string;
16
+ resetPasswordTokenExpiresIn: string;
17
+ constructor({ siteOrigin, siteName, jwtManager, authRepository, emailCredentials, resetPasswordTokenSecret, resetPasswordTokenExpiresIn, }: {
18
+ siteOrigin: string;
19
+ siteName: string;
20
+ jwtManager: JWTManager;
21
+ authRepository: AuthRepository;
22
+ emailCredentials: {
23
+ service: string;
24
+ user: string;
25
+ pass: string;
26
+ };
27
+ resetPasswordTokenSecret: string;
28
+ resetPasswordTokenExpiresIn?: string;
29
+ });
30
+ requestPasswordReset(email: string): Promise<void>;
31
+ resetPassword(token: string, password: string, passwordConfirm: string): Promise<void>;
32
+ }
33
+
34
+ export { PasswordRecoveryService };
@@ -0,0 +1,34 @@
1
+ import { AuthRepository } from './auth_repository.js';
2
+ import { JWTManager } from './jwt_manager.js';
3
+ import 'jose';
4
+
5
+ declare class PasswordRecoveryService {
6
+ siteOrigin: string;
7
+ siteName: string;
8
+ jwtManager: JWTManager;
9
+ authRepository: AuthRepository;
10
+ emailCredentials: {
11
+ service: string;
12
+ user: string;
13
+ pass: string;
14
+ };
15
+ resetPasswordTokenSecret: string;
16
+ resetPasswordTokenExpiresIn: string;
17
+ constructor({ siteOrigin, siteName, jwtManager, authRepository, emailCredentials, resetPasswordTokenSecret, resetPasswordTokenExpiresIn, }: {
18
+ siteOrigin: string;
19
+ siteName: string;
20
+ jwtManager: JWTManager;
21
+ authRepository: AuthRepository;
22
+ emailCredentials: {
23
+ service: string;
24
+ user: string;
25
+ pass: string;
26
+ };
27
+ resetPasswordTokenSecret: string;
28
+ resetPasswordTokenExpiresIn?: string;
29
+ });
30
+ requestPasswordReset(email: string): Promise<void>;
31
+ resetPassword(token: string, password: string, passwordConfirm: string): Promise<void>;
32
+ }
33
+
34
+ export { PasswordRecoveryService };
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/auth/password_recovery.ts
31
+ var password_recovery_exports = {};
32
+ __export(password_recovery_exports, {
33
+ PasswordRecoveryService: () => PasswordRecoveryService
34
+ });
35
+ module.exports = __toCommonJS(password_recovery_exports);
36
+ var import_nodemailer = __toESM(require("nodemailer"));
37
+
38
+ // src/http/response.ts
39
+ var createJsonResponse = (status) => {
40
+ return (data = {}, init) => {
41
+ return Response.json(data, { status, ...init });
42
+ };
43
+ };
44
+ var OK = createJsonResponse(200);
45
+ var CREATED = createJsonResponse(201);
46
+ var ACCEPTED = createJsonResponse(202);
47
+ var createException = (status, defaultMessage = "\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.") => {
48
+ return (message = defaultMessage, init) => {
49
+ return createJsonResponse(status)({ message }, init);
50
+ };
51
+ };
52
+ var BAD_REQUEST = createException(400, "\uC694\uCCAD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
53
+ var UNAUTHORIZED = createException(401, "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
54
+ var FORBIDDEN = createException(403, "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
55
+ var NOT_FOUND = createException(
56
+ 404,
57
+ "\uC694\uCCAD\uD55C \uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
58
+ );
59
+ var METHOD_NOT_ALLOWED = createException(
60
+ 405,
61
+ "\uBA54\uC11C\uB4DC\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
62
+ );
63
+ var NOT_ACCEPTABLE = createException(
64
+ 406,
65
+ "\uC694\uCCAD\uD55C \uD615\uC2DD\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
66
+ );
67
+ var REQUEST_TIMEOUT = createException(
68
+ 408,
69
+ "\uC694\uCCAD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."
70
+ );
71
+ var CONFLICT = createException(409, "\uC694\uCCAD\uC774 \uCDA9\uB3CC\uD588\uC2B5\uB2C8\uB2E4.");
72
+ var UNPROCESSABLE_ENTITY = createException(
73
+ 422,
74
+ "\uCC98\uB9AC\uD560 \uC218 \uC5C6\uB294 \uC5D4\uD2F0\uD2F0\uC785\uB2C8\uB2E4."
75
+ );
76
+ var TOO_MANY_REQUESTS = createException(429, "\uC694\uCCAD\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4.");
77
+ var INTERNAL_SERVER_ERROR = createException(
78
+ 500,
79
+ "\uC608\uAE30\uCE58 \uBABB\uD55C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4."
80
+ );
81
+
82
+ // src/auth/password_recovery.ts
83
+ var import_bcryptjs = __toESM(require("bcryptjs"));
84
+ var PasswordRecoveryService = class {
85
+ siteOrigin;
86
+ siteName;
87
+ jwtManager;
88
+ authRepository;
89
+ emailCredentials;
90
+ resetPasswordTokenSecret;
91
+ resetPasswordTokenExpiresIn;
92
+ constructor({
93
+ siteOrigin,
94
+ siteName,
95
+ jwtManager,
96
+ authRepository,
97
+ emailCredentials,
98
+ resetPasswordTokenSecret,
99
+ resetPasswordTokenExpiresIn = "1h"
100
+ }) {
101
+ this.siteOrigin = siteOrigin;
102
+ this.siteName = siteName;
103
+ this.jwtManager = jwtManager;
104
+ this.authRepository = authRepository;
105
+ this.emailCredentials = emailCredentials;
106
+ this.resetPasswordTokenSecret = resetPasswordTokenSecret;
107
+ this.resetPasswordTokenExpiresIn = resetPasswordTokenExpiresIn;
108
+ }
109
+ async requestPasswordReset(email) {
110
+ const credential = await this.authRepository.findCredentialById(email);
111
+ if (!credential) {
112
+ throw NOT_FOUND("\uAC00\uC785\uB418\uC9C0 \uC54A\uC740 \uC774\uBA54\uC77C\uC785\uB2C8\uB2E4.");
113
+ }
114
+ const transporter = import_nodemailer.default.createTransport({
115
+ service: this.emailCredentials.service,
116
+ auth: {
117
+ user: this.emailCredentials.user,
118
+ pass: this.emailCredentials.pass
119
+ }
120
+ });
121
+ const token = await this.jwtManager.sign(
122
+ {
123
+ id: credential.id
124
+ },
125
+ this.resetPasswordTokenSecret,
126
+ {
127
+ expiresIn: this.resetPasswordTokenExpiresIn
128
+ }
129
+ );
130
+ const link = `${this.siteOrigin}/reset-password?token=${token}`;
131
+ const mailOptions = {
132
+ from: process.env.EMAIL_USER,
133
+ to: email,
134
+ subject: `${this.siteName} \uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815`,
135
+ html: `<main>
136
+ <p>\uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815\uC744 \uC704\uD574 \uC544\uB798 \uB9C1\uD06C\uB97C \uD074\uB9AD\uD574 \uC8FC\uC138\uC694. \uB9C1\uD06C\uB294 \uD55C \uC2DC\uAC04 \uB3D9\uC548 \uC720\uD6A8\uD569\uB2C8\uB2E4. \uB2E4\uB978 \uC0AC\uB78C\uC5D0\uAC8C \uACF5\uC720\uD558\uC9C0 \uB9C8\uC138\uC694.</p>
137
+ <a href="${link}" target="_blank">${link}</a>
138
+ </main>`
139
+ };
140
+ await transporter.sendMail(mailOptions);
141
+ }
142
+ async resetPassword(token, password, passwordConfirm) {
143
+ const payload = await this.jwtManager.verify(
144
+ token,
145
+ this.resetPasswordTokenSecret
146
+ );
147
+ if (!payload) {
148
+ throw UNAUTHORIZED("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD1A0\uD070\uC785\uB2C8\uB2E4.");
149
+ }
150
+ if (typeof payload.id !== "string") {
151
+ throw UNAUTHORIZED("\uD1A0\uD070\uC774 \uC704\uC870\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
152
+ }
153
+ const credential = await this.authRepository.findCredentialById(payload.id);
154
+ if (!credential) {
155
+ throw NOT_FOUND("\uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uACC4\uC815\uC785\uB2C8\uB2E4.");
156
+ }
157
+ if (typeof password !== "string" || !password.trim()) {
158
+ throw BAD_REQUEST("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uBE44\uBC00\uBC88\uD638\uC785\uB2C8\uB2E4.");
159
+ }
160
+ if (password !== passwordConfirm) {
161
+ throw BAD_REQUEST("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
162
+ }
163
+ await this.authRepository.updatePassword(credential.id, import_bcryptjs.default.hashSync(password, 10));
164
+ }
165
+ };
166
+ // Annotate the CommonJS export names for ESM import in node:
167
+ 0 && (module.exports = {
168
+ PasswordRecoveryService
169
+ });
@@ -0,0 +1,134 @@
1
+ // src/auth/password_recovery.ts
2
+ import nodemailer from "nodemailer";
3
+
4
+ // src/http/response.ts
5
+ var createJsonResponse = (status) => {
6
+ return (data = {}, init) => {
7
+ return Response.json(data, { status, ...init });
8
+ };
9
+ };
10
+ var OK = createJsonResponse(200);
11
+ var CREATED = createJsonResponse(201);
12
+ var ACCEPTED = createJsonResponse(202);
13
+ var createException = (status, defaultMessage = "\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.") => {
14
+ return (message = defaultMessage, init) => {
15
+ return createJsonResponse(status)({ message }, init);
16
+ };
17
+ };
18
+ var BAD_REQUEST = createException(400, "\uC694\uCCAD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
19
+ var UNAUTHORIZED = createException(401, "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
20
+ var FORBIDDEN = createException(403, "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
21
+ var NOT_FOUND = createException(
22
+ 404,
23
+ "\uC694\uCCAD\uD55C \uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
24
+ );
25
+ var METHOD_NOT_ALLOWED = createException(
26
+ 405,
27
+ "\uBA54\uC11C\uB4DC\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
28
+ );
29
+ var NOT_ACCEPTABLE = createException(
30
+ 406,
31
+ "\uC694\uCCAD\uD55C \uD615\uC2DD\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
32
+ );
33
+ var REQUEST_TIMEOUT = createException(
34
+ 408,
35
+ "\uC694\uCCAD \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."
36
+ );
37
+ var CONFLICT = createException(409, "\uC694\uCCAD\uC774 \uCDA9\uB3CC\uD588\uC2B5\uB2C8\uB2E4.");
38
+ var UNPROCESSABLE_ENTITY = createException(
39
+ 422,
40
+ "\uCC98\uB9AC\uD560 \uC218 \uC5C6\uB294 \uC5D4\uD2F0\uD2F0\uC785\uB2C8\uB2E4."
41
+ );
42
+ var TOO_MANY_REQUESTS = createException(429, "\uC694\uCCAD\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4.");
43
+ var INTERNAL_SERVER_ERROR = createException(
44
+ 500,
45
+ "\uC608\uAE30\uCE58 \uBABB\uD55C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4."
46
+ );
47
+
48
+ // src/auth/password_recovery.ts
49
+ import bcrypt from "bcryptjs";
50
+ var PasswordRecoveryService = class {
51
+ siteOrigin;
52
+ siteName;
53
+ jwtManager;
54
+ authRepository;
55
+ emailCredentials;
56
+ resetPasswordTokenSecret;
57
+ resetPasswordTokenExpiresIn;
58
+ constructor({
59
+ siteOrigin,
60
+ siteName,
61
+ jwtManager,
62
+ authRepository,
63
+ emailCredentials,
64
+ resetPasswordTokenSecret,
65
+ resetPasswordTokenExpiresIn = "1h"
66
+ }) {
67
+ this.siteOrigin = siteOrigin;
68
+ this.siteName = siteName;
69
+ this.jwtManager = jwtManager;
70
+ this.authRepository = authRepository;
71
+ this.emailCredentials = emailCredentials;
72
+ this.resetPasswordTokenSecret = resetPasswordTokenSecret;
73
+ this.resetPasswordTokenExpiresIn = resetPasswordTokenExpiresIn;
74
+ }
75
+ async requestPasswordReset(email) {
76
+ const credential = await this.authRepository.findCredentialById(email);
77
+ if (!credential) {
78
+ throw NOT_FOUND("\uAC00\uC785\uB418\uC9C0 \uC54A\uC740 \uC774\uBA54\uC77C\uC785\uB2C8\uB2E4.");
79
+ }
80
+ const transporter = nodemailer.createTransport({
81
+ service: this.emailCredentials.service,
82
+ auth: {
83
+ user: this.emailCredentials.user,
84
+ pass: this.emailCredentials.pass
85
+ }
86
+ });
87
+ const token = await this.jwtManager.sign(
88
+ {
89
+ id: credential.id
90
+ },
91
+ this.resetPasswordTokenSecret,
92
+ {
93
+ expiresIn: this.resetPasswordTokenExpiresIn
94
+ }
95
+ );
96
+ const link = `${this.siteOrigin}/reset-password?token=${token}`;
97
+ const mailOptions = {
98
+ from: process.env.EMAIL_USER,
99
+ to: email,
100
+ subject: `${this.siteName} \uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815`,
101
+ html: `<main>
102
+ <p>\uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815\uC744 \uC704\uD574 \uC544\uB798 \uB9C1\uD06C\uB97C \uD074\uB9AD\uD574 \uC8FC\uC138\uC694. \uB9C1\uD06C\uB294 \uD55C \uC2DC\uAC04 \uB3D9\uC548 \uC720\uD6A8\uD569\uB2C8\uB2E4. \uB2E4\uB978 \uC0AC\uB78C\uC5D0\uAC8C \uACF5\uC720\uD558\uC9C0 \uB9C8\uC138\uC694.</p>
103
+ <a href="${link}" target="_blank">${link}</a>
104
+ </main>`
105
+ };
106
+ await transporter.sendMail(mailOptions);
107
+ }
108
+ async resetPassword(token, password, passwordConfirm) {
109
+ const payload = await this.jwtManager.verify(
110
+ token,
111
+ this.resetPasswordTokenSecret
112
+ );
113
+ if (!payload) {
114
+ throw UNAUTHORIZED("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD1A0\uD070\uC785\uB2C8\uB2E4.");
115
+ }
116
+ if (typeof payload.id !== "string") {
117
+ throw UNAUTHORIZED("\uD1A0\uD070\uC774 \uC704\uC870\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
118
+ }
119
+ const credential = await this.authRepository.findCredentialById(payload.id);
120
+ if (!credential) {
121
+ throw NOT_FOUND("\uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uACC4\uC815\uC785\uB2C8\uB2E4.");
122
+ }
123
+ if (typeof password !== "string" || !password.trim()) {
124
+ throw BAD_REQUEST("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uBE44\uBC00\uBC88\uD638\uC785\uB2C8\uB2E4.");
125
+ }
126
+ if (password !== passwordConfirm) {
127
+ throw BAD_REQUEST("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
128
+ }
129
+ await this.authRepository.updatePassword(credential.id, bcrypt.hashSync(password, 10));
130
+ }
131
+ };
132
+ export {
133
+ PasswordRecoveryService
134
+ };
@@ -2,6 +2,7 @@ import { AuthService } from '../auth/auth_service.mjs';
2
2
  import { FileService } from '../file/file_service.mjs';
3
3
  import { ThirdpartyAuth } from '../auth/thirdparty_auth.mjs';
4
4
  import { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router';
5
+ import { PasswordRecoveryService } from '../auth/password_recovery.mjs';
5
6
  import 'jose';
6
7
  import '../auth/jwt_manager.mjs';
7
8
  import '../file/object_storage.mjs';
@@ -9,9 +10,10 @@ import '@aws-sdk/client-s3';
9
10
  import '../auth/auth_repository.mjs';
10
11
  import '../file/file_repository.mjs';
11
12
 
12
- declare const createAPIHandler: <TFile>({ authService, fileService, getThirdPartyAuth, signupTokenSecret, }: {
13
+ declare const createAPIHandler: <TFile>({ authService, fileService, passwordRecoveryService, getThirdPartyAuth, signupTokenSecret, }: {
13
14
  authService: AuthService<TFile>;
14
15
  fileService: FileService<TFile>;
16
+ passwordRecoveryService: PasswordRecoveryService;
15
17
  getThirdPartyAuth: (provider: string) => ThirdpartyAuth;
16
18
  signupTokenSecret: string;
17
19
  }) => ({ request, params }: LoaderFunctionArgs | ActionFunctionArgs) => Promise<Response>;
@@ -2,6 +2,7 @@ import { AuthService } from '../auth/auth_service.js';
2
2
  import { FileService } from '../file/file_service.js';
3
3
  import { ThirdpartyAuth } from '../auth/thirdparty_auth.js';
4
4
  import { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router';
5
+ import { PasswordRecoveryService } from '../auth/password_recovery.js';
5
6
  import 'jose';
6
7
  import '../auth/jwt_manager.js';
7
8
  import '../file/object_storage.js';
@@ -9,9 +10,10 @@ import '@aws-sdk/client-s3';
9
10
  import '../auth/auth_repository.js';
10
11
  import '../file/file_repository.js';
11
12
 
12
- declare const createAPIHandler: <TFile>({ authService, fileService, getThirdPartyAuth, signupTokenSecret, }: {
13
+ declare const createAPIHandler: <TFile>({ authService, fileService, passwordRecoveryService, getThirdPartyAuth, signupTokenSecret, }: {
13
14
  authService: AuthService<TFile>;
14
15
  fileService: FileService<TFile>;
16
+ passwordRecoveryService: PasswordRecoveryService;
15
17
  getThirdPartyAuth: (provider: string) => ThirdpartyAuth;
16
18
  signupTokenSecret: string;
17
19
  }) => ({ request, params }: LoaderFunctionArgs | ActionFunctionArgs) => Promise<Response>;
package/dist/route/api.js CHANGED
@@ -233,7 +233,7 @@ var loginHandler = async (request, {
233
233
  }) => {
234
234
  const { id, password } = await request.json();
235
235
  try {
236
- const { accessToken, refreshToken } = await authService.signIn({
236
+ const { accessToken, refreshToken } = await authService.login({
237
237
  id,
238
238
  password
239
239
  });
@@ -327,12 +327,9 @@ var signupHandler = async (request, {
327
327
  if (!passwordConfirm) {
328
328
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638 \uD655\uC778\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
329
329
  }
330
- if (!name) {
331
- return BAD_REQUEST("\uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
332
- }
333
330
  const existing = await authService.authRepository.findCredentialById(email);
334
331
  if (existing) {
335
- return CONFLICT("\uC774\uBA54\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.");
332
+ return CONFLICT("\uC774\uBBF8 \uAC00\uC785\uD55C \uC774\uBA54\uC77C\uC785\uB2C8\uB2E4.");
336
333
  }
337
334
  if (password !== passwordConfirm) {
338
335
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
@@ -352,7 +349,22 @@ var signupHandler = async (request, {
352
349
  password: bcrypt.hashSync(password, 10)
353
350
  });
354
351
  const { accessToken, refreshToken } = await authService.issueTokenPair(user);
355
- return CREATED({ accessToken, refreshToken });
352
+ const searchParams = new URL(request.url).searchParams;
353
+ const type = searchParams.get("type");
354
+ if (type === "json") {
355
+ return CREATED({ accessToken, refreshToken });
356
+ }
357
+ const [accessTokenSetCookie, refreshTokenSetCookie] = await Promise.all([
358
+ authService.getAccessTokenSetCookie(accessToken),
359
+ authService.getRefreshTokenSetCookie(refreshToken)
360
+ ]);
361
+ const payload = authService.jwtManager.decode(accessToken);
362
+ const headers = new Headers();
363
+ headers.append("Set-Cookie", accessTokenSetCookie);
364
+ headers.append("Set-Cookie", refreshTokenSetCookie);
365
+ return CREATED(payload, {
366
+ headers
367
+ });
356
368
  };
357
369
 
358
370
  // src/auth/handlers/signup_with_thirdparty.ts
@@ -405,10 +417,34 @@ var signUpWithThirdpartyHandler = async (request, {
405
417
  return CREATED({ accessToken, refreshToken });
406
418
  };
407
419
 
420
+ // src/auth/handlers/request_password_reset.ts
421
+ var requestPasswordResetHandler = async (request, {
422
+ passwordRecoveryService
423
+ }) => {
424
+ const { email } = await request.json();
425
+ try {
426
+ await passwordRecoveryService.requestPasswordReset(email);
427
+ return CREATED({ message: "\uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815 \uC774\uBA54\uC77C\uC744 \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4." });
428
+ } catch (error) {
429
+ console.error(error);
430
+ return INTERNAL_SERVER_ERROR("\uC774\uBA54\uC77C \uC804\uC1A1\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
431
+ }
432
+ };
433
+
434
+ // src/auth/handlers/reset_password.ts
435
+ var resetPasswordHandler = async (request, {
436
+ passwordRecoveryService
437
+ }) => {
438
+ const { token, password, passwordConfirm } = await request.json();
439
+ await passwordRecoveryService.resetPassword(token, password, passwordConfirm);
440
+ return NO_CONTENT();
441
+ };
442
+
408
443
  // src/route/api.ts
409
444
  var createAPIHandler = ({
410
445
  authService,
411
446
  fileService,
447
+ passwordRecoveryService,
412
448
  getThirdPartyAuth,
413
449
  signupTokenSecret
414
450
  }) => {
@@ -504,6 +540,12 @@ var createAPIHandler = ({
504
540
  }
505
541
  }
506
542
  }
543
+ case "request-password-reset": {
544
+ return requestPasswordResetHandler(request, { passwordRecoveryService });
545
+ }
546
+ case "reset-password": {
547
+ return resetPasswordHandler(request, { passwordRecoveryService });
548
+ }
507
549
  }
508
550
  }
509
551
  case "files": {
@@ -197,7 +197,7 @@ var loginHandler = async (request, {
197
197
  }) => {
198
198
  const { id, password } = await request.json();
199
199
  try {
200
- const { accessToken, refreshToken } = await authService.signIn({
200
+ const { accessToken, refreshToken } = await authService.login({
201
201
  id,
202
202
  password
203
203
  });
@@ -291,12 +291,9 @@ var signupHandler = async (request, {
291
291
  if (!passwordConfirm) {
292
292
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638 \uD655\uC778\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
293
293
  }
294
- if (!name) {
295
- return BAD_REQUEST("\uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
296
- }
297
294
  const existing = await authService.authRepository.findCredentialById(email);
298
295
  if (existing) {
299
- return CONFLICT("\uC774\uBA54\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.");
296
+ return CONFLICT("\uC774\uBBF8 \uAC00\uC785\uD55C \uC774\uBA54\uC77C\uC785\uB2C8\uB2E4.");
300
297
  }
301
298
  if (password !== passwordConfirm) {
302
299
  return BAD_REQUEST("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
@@ -316,7 +313,22 @@ var signupHandler = async (request, {
316
313
  password: bcrypt.hashSync(password, 10)
317
314
  });
318
315
  const { accessToken, refreshToken } = await authService.issueTokenPair(user);
319
- return CREATED({ accessToken, refreshToken });
316
+ const searchParams = new URL(request.url).searchParams;
317
+ const type = searchParams.get("type");
318
+ if (type === "json") {
319
+ return CREATED({ accessToken, refreshToken });
320
+ }
321
+ const [accessTokenSetCookie, refreshTokenSetCookie] = await Promise.all([
322
+ authService.getAccessTokenSetCookie(accessToken),
323
+ authService.getRefreshTokenSetCookie(refreshToken)
324
+ ]);
325
+ const payload = authService.jwtManager.decode(accessToken);
326
+ const headers = new Headers();
327
+ headers.append("Set-Cookie", accessTokenSetCookie);
328
+ headers.append("Set-Cookie", refreshTokenSetCookie);
329
+ return CREATED(payload, {
330
+ headers
331
+ });
320
332
  };
321
333
 
322
334
  // src/auth/handlers/signup_with_thirdparty.ts
@@ -369,10 +381,34 @@ var signUpWithThirdpartyHandler = async (request, {
369
381
  return CREATED({ accessToken, refreshToken });
370
382
  };
371
383
 
384
+ // src/auth/handlers/request_password_reset.ts
385
+ var requestPasswordResetHandler = async (request, {
386
+ passwordRecoveryService
387
+ }) => {
388
+ const { email } = await request.json();
389
+ try {
390
+ await passwordRecoveryService.requestPasswordReset(email);
391
+ return CREATED({ message: "\uBE44\uBC00\uBC88\uD638 \uC7AC\uC124\uC815 \uC774\uBA54\uC77C\uC744 \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4." });
392
+ } catch (error) {
393
+ console.error(error);
394
+ return INTERNAL_SERVER_ERROR("\uC774\uBA54\uC77C \uC804\uC1A1\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
395
+ }
396
+ };
397
+
398
+ // src/auth/handlers/reset_password.ts
399
+ var resetPasswordHandler = async (request, {
400
+ passwordRecoveryService
401
+ }) => {
402
+ const { token, password, passwordConfirm } = await request.json();
403
+ await passwordRecoveryService.resetPassword(token, password, passwordConfirm);
404
+ return NO_CONTENT();
405
+ };
406
+
372
407
  // src/route/api.ts
373
408
  var createAPIHandler = ({
374
409
  authService,
375
410
  fileService,
411
+ passwordRecoveryService,
376
412
  getThirdPartyAuth,
377
413
  signupTokenSecret
378
414
  }) => {
@@ -468,6 +504,12 @@ var createAPIHandler = ({
468
504
  }
469
505
  }
470
506
  }
507
+ case "request-password-reset": {
508
+ return requestPasswordResetHandler(request, { passwordRecoveryService });
509
+ }
510
+ case "reset-password": {
511
+ return resetPasswordHandler(request, { passwordRecoveryService });
512
+ }
471
513
  }
472
514
  }
473
515
  case "files": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dn-react-router-toolkit",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "types": "./dist/index.d.ts",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.js",
@@ -58,6 +58,7 @@
58
58
  "description": "",
59
59
  "devDependencies": {
60
60
  "@types/node": "^24.10.1",
61
+ "@types/nodemailer": "^7.0.4",
61
62
  "@types/react": "^19",
62
63
  "@types/react-dom": "^19",
63
64
  "rimraf": "^6.0.1",
@@ -71,6 +72,7 @@
71
72
  "bcryptjs": "^3.0.3",
72
73
  "jose": "^6.1.2",
73
74
  "moment-timezone": "^0.6.0",
75
+ "nodemailer": "^7.0.11",
74
76
  "react-icons": "^5.5.0",
75
77
  "uuid": "^13.0.0"
76
78
  },