@draftlab/auth 0.12.0 → 0.13.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.
|
@@ -174,22 +174,49 @@ interface PasswordConfig {
|
|
|
174
174
|
* Callback for sending verification codes to users via email.
|
|
175
175
|
* Implement this to integrate with your email service provider.
|
|
176
176
|
*
|
|
177
|
+
* The context parameter indicates why the code is being sent:
|
|
178
|
+
* - "register": User is registering for the first time
|
|
179
|
+
* - "register:resend": User requested to resend registration code
|
|
180
|
+
* - "reset": User is resetting their password
|
|
181
|
+
* - "reset:resend": User requested to resend password reset code
|
|
182
|
+
*
|
|
177
183
|
* @param email - The recipient's email address
|
|
178
184
|
* @param code - The verification code to send
|
|
185
|
+
* @param context - The context of why the code is being sent
|
|
179
186
|
* @returns Promise that resolves when email is sent
|
|
180
187
|
*
|
|
181
188
|
* @example
|
|
182
189
|
* ```ts
|
|
183
|
-
* sendCode: async (email, code) => {
|
|
190
|
+
* sendCode: async (email, code, context) => {
|
|
191
|
+
* const templates = {
|
|
192
|
+
* "register": {
|
|
193
|
+
* subject: "Welcome! Verify your email",
|
|
194
|
+
* body: `Welcome! Your verification code is: ${code}`
|
|
195
|
+
* },
|
|
196
|
+
* "register:resend": {
|
|
197
|
+
* subject: "Your verification code (resent)",
|
|
198
|
+
* body: `Here's your code again: ${code}`
|
|
199
|
+
* },
|
|
200
|
+
* "reset": {
|
|
201
|
+
* subject: "Reset your password",
|
|
202
|
+
* body: `Your password reset code is: ${code}`
|
|
203
|
+
* },
|
|
204
|
+
* "reset:resend": {
|
|
205
|
+
* subject: "Password reset code (resent)",
|
|
206
|
+
* body: `Here's your reset code again: ${code}`
|
|
207
|
+
* }
|
|
208
|
+
* }
|
|
209
|
+
*
|
|
210
|
+
* const template = templates[context]
|
|
184
211
|
* await emailService.send({
|
|
185
212
|
* to: email,
|
|
186
|
-
* subject:
|
|
187
|
-
* text:
|
|
213
|
+
* subject: template.subject,
|
|
214
|
+
* text: template.body
|
|
188
215
|
* })
|
|
189
216
|
* }
|
|
190
217
|
* ```
|
|
191
218
|
*/
|
|
192
|
-
sendCode: (email: string, code: string) => Promise<void>;
|
|
219
|
+
sendCode: (email: string, code: string, context: "register" | "register:resend" | "reset" | "reset:resend") => Promise<void>;
|
|
193
220
|
/**
|
|
194
221
|
* Optional password validation function or schema.
|
|
195
222
|
* Can be either a validation function or a standard-schema validator.
|
|
@@ -129,7 +129,7 @@ const PasswordProvider = (config) => {
|
|
|
129
129
|
"password"
|
|
130
130
|
])) return transition(provider, { type: "email_taken" });
|
|
131
131
|
const code = generateCode();
|
|
132
|
-
await config.sendCode(email, code);
|
|
132
|
+
await config.sendCode(email, code, "register");
|
|
133
133
|
return transition({
|
|
134
134
|
type: "code",
|
|
135
135
|
code,
|
|
@@ -139,7 +139,7 @@ const PasswordProvider = (config) => {
|
|
|
139
139
|
}
|
|
140
140
|
if (action === "register" && provider.type === "code") {
|
|
141
141
|
const code = generateCode();
|
|
142
|
-
await config.sendCode(provider.email, code);
|
|
142
|
+
await config.sendCode(provider.email, code, "register:resend");
|
|
143
143
|
return transition({
|
|
144
144
|
type: "code",
|
|
145
145
|
code,
|
|
@@ -170,7 +170,7 @@ const PasswordProvider = (config) => {
|
|
|
170
170
|
routes.get("/change", async (c) => {
|
|
171
171
|
const state = {
|
|
172
172
|
type: "start",
|
|
173
|
-
redirect: c.query("redirect_uri") || getRelativeUrl(c, "
|
|
173
|
+
redirect: c.query("redirect_uri") || getRelativeUrl(c, "./authorize")
|
|
174
174
|
};
|
|
175
175
|
await ctx.set(c, "provider", 3600 * 24, state);
|
|
176
176
|
return ctx.forward(c, await config.change(c.request, state));
|
|
@@ -194,7 +194,8 @@ const PasswordProvider = (config) => {
|
|
|
194
194
|
redirect: provider.redirect
|
|
195
195
|
}, { type: "invalid_email" });
|
|
196
196
|
const code = generateCode();
|
|
197
|
-
|
|
197
|
+
const context = provider.type === "code" && provider.email === email ? "reset:resend" : "reset";
|
|
198
|
+
await config.sendCode(email, code, context);
|
|
198
199
|
return transition({
|
|
199
200
|
type: "code",
|
|
200
201
|
code,
|
package/dist/ui/password.d.mts
CHANGED
|
@@ -11,7 +11,6 @@ interface PasswordUICopy {
|
|
|
11
11
|
readonly error_invalid_email: string;
|
|
12
12
|
readonly error_invalid_password: string;
|
|
13
13
|
readonly error_password_mismatch: string;
|
|
14
|
-
readonly error_validation_error: string;
|
|
15
14
|
readonly register_title: string;
|
|
16
15
|
readonly register_description: string;
|
|
17
16
|
readonly login_title: string;
|
package/dist/ui/password.mjs
CHANGED
|
@@ -12,7 +12,6 @@ const DEFAULT_COPY = {
|
|
|
12
12
|
error_invalid_email: "Email is not valid.",
|
|
13
13
|
error_invalid_password: "Password is incorrect.",
|
|
14
14
|
error_password_mismatch: "Passwords do not match.",
|
|
15
|
-
error_validation_error: "Password does not meet requirements.",
|
|
16
15
|
register_title: "Welcome to the app",
|
|
17
16
|
register_description: "Sign in with your email",
|
|
18
17
|
login_title: "Welcome to the app",
|
|
@@ -159,7 +158,7 @@ const PasswordUI = (options) => {
|
|
|
159
158
|
] })
|
|
160
159
|
})
|
|
161
160
|
]
|
|
162
|
-
}) : /* @__PURE__ */ jsxs("form", {
|
|
161
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("form", {
|
|
163
162
|
"data-component": "form",
|
|
164
163
|
method: "post",
|
|
165
164
|
children: [
|
|
@@ -188,7 +187,47 @@ const PasswordUI = (options) => {
|
|
|
188
187
|
children: copy.button_continue
|
|
189
188
|
})
|
|
190
189
|
]
|
|
191
|
-
})
|
|
190
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
191
|
+
method: "post",
|
|
192
|
+
children: [
|
|
193
|
+
/* @__PURE__ */ jsx("input", {
|
|
194
|
+
name: "action",
|
|
195
|
+
type: "hidden",
|
|
196
|
+
value: "register"
|
|
197
|
+
}),
|
|
198
|
+
/* @__PURE__ */ jsx("input", {
|
|
199
|
+
name: "email",
|
|
200
|
+
type: "hidden",
|
|
201
|
+
value: state.email
|
|
202
|
+
}),
|
|
203
|
+
/* @__PURE__ */ jsx("input", {
|
|
204
|
+
name: "password",
|
|
205
|
+
type: "hidden",
|
|
206
|
+
value: ""
|
|
207
|
+
}),
|
|
208
|
+
/* @__PURE__ */ jsx("input", {
|
|
209
|
+
name: "repeat",
|
|
210
|
+
type: "hidden",
|
|
211
|
+
value: ""
|
|
212
|
+
}),
|
|
213
|
+
/* @__PURE__ */ jsxs("div", {
|
|
214
|
+
"data-component": "form-footer",
|
|
215
|
+
children: [/* @__PURE__ */ jsxs("span", { children: [
|
|
216
|
+
copy.code_return,
|
|
217
|
+
" ",
|
|
218
|
+
/* @__PURE__ */ jsx("a", {
|
|
219
|
+
"data-component": "link",
|
|
220
|
+
href: "./authorize",
|
|
221
|
+
children: copy.login
|
|
222
|
+
})
|
|
223
|
+
] }), /* @__PURE__ */ jsx("button", {
|
|
224
|
+
type: "submit",
|
|
225
|
+
"data-component": "link",
|
|
226
|
+
children: copy.code_resend
|
|
227
|
+
})]
|
|
228
|
+
})
|
|
229
|
+
]
|
|
230
|
+
})] }) });
|
|
192
231
|
};
|
|
193
232
|
/**
|
|
194
233
|
* Renders the password change form based on current state
|