customer-registration 0.0.114 → 0.0.116

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.
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.POST = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const config_1 = require("../../../../../config");
6
+ const complete_registration_token_1 = require("../../shared/complete-registration-token");
7
+ const parse_register_body_1 = require("../../shared/parse-register-body");
8
+ /**
9
+ * Unified registration: emailpass and/or phonepass via `service.register`, depending on
10
+ * plugin `registration.identifier` and JSON body. Response: `{ token }` (Medusa default).
11
+ */
12
+ const POST = async (req, res) => {
13
+ const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
14
+ const options = (0, config_1.resolveCustomerRegistrationOptions)(config);
15
+ const registrationIdentifier = options.registration
16
+ .identifier;
17
+ const parsed = (0, parse_register_body_1.parseCustomerRegisterBody)(req.body, registrationIdentifier);
18
+ const service = req.scope.resolve(utils_1.Modules.AUTH);
19
+ const authData = {
20
+ url: req.url,
21
+ headers: req.headers,
22
+ query: req.query,
23
+ body: req.body,
24
+ protocol: req.protocol,
25
+ };
26
+ const provider = parsed.mode === "email" ? "emailpass" : "phonepass";
27
+ const { success, error, authIdentity } = await service.register(provider, authData);
28
+ if (!success || !authIdentity) {
29
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, error || "Registration failed");
30
+ }
31
+ await (0, complete_registration_token_1.respondWithRegistrationToken)(req, res, authIdentity);
32
+ };
33
+ exports.POST = POST;
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvZW1haWxwYXNzL3JlZ2lzdGVyL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHFEQUlrQztBQUNsQyxrREFHOEI7QUFDOUIsMEZBQXVGO0FBQ3ZGLDBFQUd5QztBQUV6Qzs7O0dBR0c7QUFDSSxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDcEUsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsYUFBYSxDQUFDLENBQUE7SUFDekUsTUFBTSxPQUFPLEdBQUcsSUFBQSwyQ0FBa0MsRUFBQyxNQUEyQixDQUFDLENBQUE7SUFDL0UsTUFBTSxzQkFBc0IsR0FBRyxPQUFPLENBQUMsWUFBWTtTQUNoRCxVQUEwQyxDQUFBO0lBRTdDLE1BQU0sTUFBTSxHQUFHLElBQUEsK0NBQXlCLEVBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxzQkFBc0IsQ0FBQyxDQUFBO0lBRTFFLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUUvQyxNQUFNLFFBQVEsR0FBRztRQUNmLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRztRQUNaLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztRQUNwQixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO1FBQ2QsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO0tBQ0EsQ0FBQTtJQUN4QixNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUE7SUFFcEUsTUFBTSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEdBQUcsTUFBTSxPQUFPLENBQUMsUUFBUSxDQUM3RCxRQUFRLEVBQ1IsUUFBUSxDQUNULENBQUE7SUFFRCxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDOUIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsS0FBSyxJQUFJLHFCQUFxQixDQUMvQixDQUFBO0lBQ0gsQ0FBQztJQUVELE1BQU0sSUFBQSwwREFBNEIsRUFBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLFlBQXVDLENBQUMsQ0FBQTtBQUN2RixDQUFDLENBQUE7QUFoQ1ksUUFBQSxJQUFJLFFBZ0NoQiJ9
@@ -1,132 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.POST = exports.GET = void 0;
4
- const utils_1 = require("@medusajs/framework/utils");
5
- const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
6
- const account_deletion_request_1 = require("../../../../modules/account-deletion-request");
7
- const otp_verification_1 = require("../../../../modules/otp-verification");
8
- const config_1 = require("../../../../config");
9
- const GET = async (req, res) => {
10
- const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
11
- const loginOptions = (0, config_1.resolveCustomerRegistrationOptions)(config);
12
- if (loginOptions.login.identifier === "phone") {
13
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Email login is not enabled. Please log in with your phone number.");
14
- }
15
- const service = req.scope.resolve(utils_1.Modules.AUTH);
16
- const authData = {
17
- url: req.url,
18
- headers: req.headers,
19
- query: req.query,
20
- body: req.body,
21
- protocol: req.protocol,
22
- };
23
- const { success, error, authIdentity, location } = await service.authenticate("emailpass", authData);
24
- if (location) {
25
- return res.status(200).json({ location });
26
- }
27
- if (success && authIdentity) {
28
- const email = authIdentity.provider_identities?.[0]?.entity_id ?? "";
29
- // Ensure authIdentity has customer_id in app_metadata
30
- // The generateJwtTokenForAuthIdentity function requires app_metadata.customer_id
31
- let customerId = authIdentity.app_metadata?.customer_id;
32
- if (!customerId) {
33
- // Try to get customer_id from provider_identity entity_id (email)
34
- // and look up the customer
35
- const customerModule = req.scope.resolve(utils_1.Modules.CUSTOMER);
36
- const customers = await customerModule.listCustomers({
37
- email: email.toLowerCase(),
38
- });
39
- if (customers && customers.length > 0) {
40
- customerId = customers[0].id;
41
- }
42
- }
43
- const resolvedCustomerId = typeof customerId === "string" && customerId.trim().length > 0
44
- ? customerId
45
- : undefined;
46
- if (!resolvedCustomerId) {
47
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Unable to determine customer ID for authentication");
48
- }
49
- await enforceEmailAndPhoneVerification({
50
- customerId: resolvedCustomerId,
51
- email,
52
- req,
53
- });
54
- const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
55
- if (await accountDeletionService.hasPendingRequest(resolvedCustomerId)) {
56
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Customer has an active account deletion request");
57
- }
58
- // Ensure app_metadata has customer_id
59
- const authIdentityWithCustomerId = {
60
- ...authIdentity,
61
- app_metadata: {
62
- ...authIdentity.app_metadata,
63
- customer_id: resolvedCustomerId,
64
- },
65
- };
66
- const { http } = config.projectConfig;
67
- if (!http.jwtSecret) {
68
- console.error("[emailpass-auth] JWT secret is not configured", {
69
- email,
70
- customerId: resolvedCustomerId,
71
- hasJwtSecret: !!http.jwtSecret,
72
- });
73
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
74
- }
75
- let token;
76
- try {
77
- token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
78
- authIdentity: authIdentityWithCustomerId,
79
- actorType: "customer",
80
- }, {
81
- secret: http.jwtSecret,
82
- expiresIn: http.jwtExpiresIn || "7d",
83
- });
84
- }
85
- catch (jwtError) {
86
- console.error("[emailpass-auth] JWT generation threw an exception", {
87
- email,
88
- customerId: resolvedCustomerId,
89
- error: jwtError instanceof Error ? jwtError.message : String(jwtError),
90
- stack: jwtError instanceof Error ? jwtError.stack : undefined,
91
- jwtSecretExists: !!http.jwtSecret,
92
- });
93
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
94
- }
95
- // Validate token was generated successfully
96
- if (!token || typeof token !== "string") {
97
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `Failed to generate authentication token for customer ${resolvedCustomerId}. Token type: ${typeof token}, Token value: ${token}`);
98
- }
99
- return res.status(200).json({ token });
100
- }
101
- console.error("[emailpass-auth] Authentication failed", {
102
- success,
103
- error,
104
- hasAuthIdentity: !!authIdentity,
105
- });
106
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, error || "Authentication failed");
107
- };
108
- exports.GET = GET;
3
+ exports.POST = void 0;
4
+ const customer_login_post_1 = require("../shared/customer-login-post");
5
+ /**
6
+ * Customer login (unified): delegates to `handleCustomerLogin`.
7
+ * - POST + JSON body: `{ email, password }` **or** `{ phone, password }` (exactly one of email/phone), gated by plugin `login.identifier`.
8
+ * - Optional query params can fill missing fields on POST (see `buildUnifiedLoginAuthData`); prefer JSON body for credentials.
9
+ */
109
10
  const POST = async (req, res) => {
110
- await (0, exports.GET)(req, res);
11
+ await (0, customer_login_post_1.handleCustomerLogin)(req, res);
111
12
  };
112
13
  exports.POST = POST;
113
- const enforceEmailAndPhoneVerification = async ({ customerId, email, req, }) => {
114
- // Read identifier + require_verification from plugin config
115
- const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
116
- const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
117
- const { identifier, require_verification } = options.registration;
118
- // If verification is disabled entirely, skip all checks
119
- if (!require_verification) {
120
- return;
121
- }
122
- const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
123
- const verificationStatus = await otpService.getCustomerVerificationByCustomerId(req.scope, customerId);
124
- if ((identifier === "email" || identifier === "both") && !verificationStatus.email_verified) {
125
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Email not verified.");
126
- }
127
- if ((identifier === "phone" || identifier === "both") && !verificationStatus.phone_verified) {
128
- console.error("[emailpass-auth] Phone not verified", { email });
129
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Phone not verified.");
130
- }
131
- };
132
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvZW1haWxwYXNzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQU1BLHFEQUlrQztBQUNsQywyRkFBb0c7QUFDcEcsMkZBQThGO0FBRTlGLDJFQUE4RTtBQUk5RSwrQ0FHMkI7QUFFcEIsTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ25FLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUM5QixpQ0FBeUIsQ0FBQyxhQUFhLENBQ3hDLENBQUE7SUFFRCxNQUFNLFlBQVksR0FBRyxJQUFBLDJDQUFrQyxFQUFDLE1BQTJCLENBQUMsQ0FBQTtJQUNwRixJQUFJLFlBQVksQ0FBQyxLQUFLLENBQUMsVUFBVSxLQUFLLE9BQU8sRUFBRSxDQUFDO1FBQzlDLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG1FQUFtRSxDQUNwRSxDQUFBO0lBQ0gsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUUvQyxNQUFNLFFBQVEsR0FBRztRQUNmLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRztRQUNaLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztRQUNwQixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO1FBQ2QsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO0tBQ0EsQ0FBQTtJQUV4QixNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLEdBQzlDLE1BQU0sT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVB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
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvZW1haWxwYXNzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHVFQUFtRTtBQUVuRTs7OztHQUlHO0FBRUksTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sSUFBQSx5Q0FBbUIsRUFBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUE7QUFDckMsQ0FBQyxDQUFBO0FBRlksUUFBQSxJQUFJLFFBRWhCIn0=
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const build_unified_login_auth_data_1 = require("../build-unified-login-auth-data");
5
+ function makeReq(partial) {
6
+ return {
7
+ url: "/auth/customer/emailpass",
8
+ headers: {},
9
+ query: partial.query ?? {},
10
+ body: partial.body,
11
+ protocol: "http",
12
+ };
13
+ }
14
+ (0, vitest_1.describe)("buildUnifiedLoginAuthData", () => {
15
+ const cases = [
16
+ {
17
+ name: "POST body only",
18
+ req: makeReq({
19
+ body: { email: "a@b.co", password: "x" },
20
+ }),
21
+ wantBody: { email: "a@b.co", password: "x" },
22
+ },
23
+ {
24
+ name: "GET query fills missing body fields",
25
+ req: makeReq({
26
+ body: {},
27
+ query: { phone: "+1555", password: "secret" },
28
+ }),
29
+ wantBody: { phone: "+1555", password: "secret" },
30
+ },
31
+ {
32
+ name: "body overrides query for same key",
33
+ req: makeReq({
34
+ body: { email: "primary@x.com", password: "p1" },
35
+ query: { email: "ignored@x.com", password: "p2" },
36
+ }),
37
+ wantBody: { email: "primary@x.com", password: "p1" },
38
+ },
39
+ {
40
+ name: "array query param takes first string",
41
+ req: makeReq({
42
+ body: {},
43
+ query: { email: ["x@y.com", "z@y.com"], password: "pw" },
44
+ }),
45
+ wantBody: { email: "x@y.com", password: "pw" },
46
+ },
47
+ ];
48
+ vitest_1.it.each(cases)("$name", ({ req, wantBody }) => {
49
+ const auth = (0, build_unified_login_auth_data_1.buildUnifiedLoginAuthData)(req);
50
+ (0, vitest_1.expect)(auth.body).toEqual(wantBody);
51
+ (0, vitest_1.expect)(auth.query).toBe(req.query);
52
+ });
53
+ });
54
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtdW5pZmllZC1sb2dpbi1hdXRoLWRhdGEudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYXV0aC9jdXN0b21lci9zaGFyZWQvX190ZXN0c19fL2J1aWxkLXVuaWZpZWQtbG9naW4tYXV0aC1kYXRhLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxtQ0FBNkM7QUFFN0Msb0ZBQTRFO0FBRTVFLFNBQVMsT0FBTyxDQUFDLE9BR2hCO0lBQ0MsT0FBTztRQUNMLEdBQUcsRUFBRSwwQkFBMEI7UUFDL0IsT0FBTyxFQUFFLEVBQUU7UUFDWCxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQzFCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtRQUNsQixRQUFRLEVBQUUsTUFBTTtLQUNBLENBQUE7QUFDcEIsQ0FBQztBQUVELElBQUEsaUJBQVEsRUFBQywyQkFBMkIsRUFBRSxHQUFHLEVBQUU7SUFDekMsTUFBTSxLQUFLLEdBSU47UUFDSDtZQUNFLElBQUksRUFBRSxnQkFBZ0I7WUFDdEIsR0FBRyxFQUFFLE9BQU8sQ0FBQztnQkFDWCxJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7YUFDekMsQ0FBQztZQUNGLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRTtTQUM3QztRQUNEO1lBQ0UsSUFBSSxFQUFFLHFDQUFxQztZQUMzQyxHQUFHLEVBQUUsT0FBTyxDQUFDO2dCQUNYLElBQUksRUFBRSxFQUFFO2dCQUNSLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRTthQUM5QyxDQUFDO1lBQ0YsUUFBUSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFO1NBQ2pEO1FBQ0Q7WUFDRSxJQUFJLEVBQUUsbUNBQW1DO1lBQ3pDLEdBQUcsRUFBRSxPQUFPLENBQUM7Z0JBQ1gsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNoRCxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUU7YUFDbEQsQ0FBQztZQUNGLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRTtTQUNyRDtRQUNEO1lBQ0UsSUFBSSxFQUFFLHNDQUFzQztZQUM1QyxHQUFHLEVBQUUsT0FBTyxDQUFDO2dCQUNYLElBQUksRUFBRSxFQUFFO2dCQUNSLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2FBQ3pELENBQUM7WUFDRixRQUFRLEVBQUUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUU7U0FDL0M7S0FDRixDQUFBO0lBRUQsV0FBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFO1FBQzVDLE1BQU0sSUFBSSxHQUFHLElBQUEseURBQXlCLEVBQUMsR0FBRyxDQUFDLENBQUE7UUFDM0MsSUFBQSxlQUFNLEVBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUNuQyxJQUFBLGVBQU0sRUFBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUNwQyxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQyxDQUFBIn0=
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const parse_login_body_1 = require("../parse-login-body");
6
+ (0, vitest_1.describe)("parseCustomerLoginBody", () => {
7
+ const cases = [
8
+ {
9
+ name: "both config + email only",
10
+ body: { email: "a@b.co", password: "x" },
11
+ loginIdentifier: "both",
12
+ want: { mode: "email" },
13
+ },
14
+ {
15
+ name: "both config + phone only",
16
+ body: { phone: "+15550001", password: "x" },
17
+ loginIdentifier: "both",
18
+ want: { mode: "phone" },
19
+ },
20
+ {
21
+ name: "email config + email (trim)",
22
+ body: { email: " u@v.com ", password: "x" },
23
+ loginIdentifier: "email",
24
+ want: { mode: "email" },
25
+ },
26
+ {
27
+ name: "phone config + phone",
28
+ body: { phone: "7428730894", password: "x" },
29
+ loginIdentifier: "phone",
30
+ want: { mode: "phone" },
31
+ },
32
+ ];
33
+ vitest_1.it.each(cases)("$name", ({ body, loginIdentifier, want }) => {
34
+ (0, vitest_1.expect)((0, parse_login_body_1.parseCustomerLoginBody)(body, loginIdentifier)).toEqual(want);
35
+ });
36
+ const errorCases = [
37
+ {
38
+ name: "both present",
39
+ body: { email: "a@b.co", phone: "+1", password: "x" },
40
+ loginIdentifier: "both",
41
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
42
+ wantMessageSubstring: "not both",
43
+ },
44
+ {
45
+ name: "neither present",
46
+ body: { password: "x" },
47
+ loginIdentifier: "both",
48
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
49
+ wantMessageSubstring: "Either email or phone",
50
+ },
51
+ {
52
+ name: "email config rejects phone-only body",
53
+ body: { phone: "+1555", password: "x" },
54
+ loginIdentifier: "email",
55
+ wantType: utils_1.MedusaError.Types.UNAUTHORIZED,
56
+ wantMessageSubstring: "Email login is not enabled",
57
+ },
58
+ {
59
+ name: "phone config rejects email-only body",
60
+ body: { email: "a@b.co", password: "x" },
61
+ loginIdentifier: "phone",
62
+ wantType: utils_1.MedusaError.Types.UNAUTHORIZED,
63
+ wantMessageSubstring: "Phone login is not enabled",
64
+ },
65
+ ];
66
+ vitest_1.it.each(errorCases)("$name", ({ body, loginIdentifier, wantType, wantMessageSubstring }) => {
67
+ try {
68
+ (0, parse_login_body_1.parseCustomerLoginBody)(body, loginIdentifier);
69
+ vitest_1.expect.fail("expected MedusaError");
70
+ }
71
+ catch (e) {
72
+ (0, vitest_1.expect)(e).toBeInstanceOf(utils_1.MedusaError);
73
+ const err = e;
74
+ (0, vitest_1.expect)(err.type).toBe(wantType);
75
+ (0, vitest_1.expect)(err.message).toContain(wantMessageSubstring);
76
+ }
77
+ });
78
+ });
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2UtbG9naW4tYm9keS50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9hdXRoL2N1c3RvbWVyL3NoYXJlZC9fX3Rlc3RzX18vcGFyc2UtbG9naW4tYm9keS50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbUNBQTZDO0FBQzdDLHFEQUF1RDtBQUN2RCwwREFHNEI7QUFFNUIsSUFBQSxpQkFBUSxFQUFDLHdCQUF3QixFQUFFLEdBQUcsRUFBRTtJQUN0QyxNQUFNLEtBQUssR0FLTjtRQUNIO1lBQ0UsSUFBSSxFQUFFLDBCQUEwQjtZQUNoQyxJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDeEMsZUFBZSxFQUFFLE1BQU07WUFDdkIsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRTtTQUN4QjtRQUNEO1lBQ0UsSUFBSSxFQUFFLDBCQUEwQjtZQUNoQyxJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDM0MsZUFBZSxFQUFFLE1BQU07WUFDdkIsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRTtTQUN4QjtRQUNEO1lBQ0UsSUFBSSxFQUFFLDZCQUE2QjtZQUNuQyxJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDN0MsZUFBZSxFQUFFLE9BQU87WUFDeEIsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRTtTQUN4QjtRQUNEO1lBQ0UsSUFBSSxFQUFFLHNCQUFzQjtZQUM1QixJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDNUMsZUFBZSxFQUFFLE9BQU87WUFDeEIsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFF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
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const parse_register_body_1 = require("../parse-register-body");
6
+ (0, vitest_1.describe)("parseCustomerRegisterBody", () => {
7
+ const okCases = [
8
+ {
9
+ name: "email config",
10
+ body: { email: "a@b.co", password: "x" },
11
+ registrationIdentifier: "email",
12
+ want: { mode: "email" },
13
+ },
14
+ {
15
+ name: "phone config",
16
+ body: { phone: "+15551", password: "x" },
17
+ registrationIdentifier: "phone",
18
+ want: { mode: "phone" },
19
+ },
20
+ {
21
+ name: "both config email only",
22
+ body: { email: "u@v.com", password: "Secret1!" },
23
+ registrationIdentifier: "both",
24
+ want: { mode: "email" },
25
+ },
26
+ ];
27
+ vitest_1.it.each(okCases)("$name", ({ body, registrationIdentifier, want }) => {
28
+ (0, vitest_1.expect)((0, parse_register_body_1.parseCustomerRegisterBody)(body, registrationIdentifier)).toEqual(want);
29
+ });
30
+ const errCases = [
31
+ {
32
+ name: "missing password",
33
+ body: { email: "a@b.co" },
34
+ registrationIdentifier: "email",
35
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
36
+ wantSubstring: "Password is required",
37
+ },
38
+ {
39
+ name: "both rejects phone-only",
40
+ body: { phone: "+1", password: "x" },
41
+ registrationIdentifier: "both",
42
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
43
+ wantSubstring: "email and password is required first",
44
+ },
45
+ {
46
+ name: "both rejects email+phone",
47
+ body: { email: "a@b.co", phone: "+1", password: "x" },
48
+ registrationIdentifier: "both",
49
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
50
+ wantSubstring: "only email and password",
51
+ },
52
+ {
53
+ name: "email rejects phone-only",
54
+ body: { phone: "+1", password: "x" },
55
+ registrationIdentifier: "email",
56
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
57
+ wantSubstring: "Register with your email",
58
+ },
59
+ {
60
+ name: "phone rejects email-only",
61
+ body: { email: "a@b.co", password: "x" },
62
+ registrationIdentifier: "phone",
63
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
64
+ wantSubstring: "Register with your phone",
65
+ },
66
+ {
67
+ name: "email XOR violated",
68
+ body: { email: "a@b.co", phone: "+1", password: "x" },
69
+ registrationIdentifier: "email",
70
+ wantType: utils_1.MedusaError.Types.INVALID_DATA,
71
+ wantSubstring: "not both",
72
+ },
73
+ ];
74
+ vitest_1.it.each(errCases)("$name", ({ body, registrationIdentifier, wantType, wantSubstring }) => {
75
+ try {
76
+ (0, parse_register_body_1.parseCustomerRegisterBody)(body, registrationIdentifier);
77
+ vitest_1.expect.fail("expected MedusaError");
78
+ }
79
+ catch (e) {
80
+ (0, vitest_1.expect)(e).toBeInstanceOf(utils_1.MedusaError);
81
+ const err = e;
82
+ (0, vitest_1.expect)(err.type).toBe(wantType);
83
+ (0, vitest_1.expect)(err.message).toContain(wantSubstring);
84
+ }
85
+ });
86
+ });
87
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2UtcmVnaXN0ZXItYm9keS50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9hdXRoL2N1c3RvbWVyL3NoYXJlZC9fX3Rlc3RzX18vcGFyc2UtcmVnaXN0ZXItYm9keS50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbUNBQTZDO0FBQzdDLHFEQUF1RDtBQUN2RCxnRUFHK0I7QUFFL0IsSUFBQSxpQkFBUSxFQUFDLDJCQUEyQixFQUFFLEdBQUcsRUFBRTtJQUN6QyxNQUFNLE9BQU8sR0FLUjtRQUNIO1lBQ0UsSUFBSSxFQUFFLGNBQWM7WUFDcEIsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFO1lBQ3hDLHNCQUFzQixFQUFFLE9BQU87WUFDL0IsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRTtTQUN4QjtRQUNEO1lBQ0UsSUFBSSxFQUFFLGNBQWM7WUFDcEIsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFO1lBQ3hDLHNCQUFzQixFQUFFLE9BQU87WUFDL0IsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRTtTQUN4QjtRQUNEO1lBQ0UsSUFBSSxFQUFFLHdCQUF3QjtZQUM5QixJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUU7WUFDaEQsc0JBQXNCLEVBQUUsTUFBTTtZQUM5QixJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFO1NBQ3hCO0tBQ0YsQ0FBQTtJQUVELFdBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsc0JBQXNCLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtRQUNuRSxJQUFBLGVBQU0sRUFB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
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildUnifiedLoginAuthData = buildUnifiedLoginAuthData;
4
+ function firstQueryValue(value) {
5
+ if (typeof value === "string") {
6
+ return value;
7
+ }
8
+ if (Array.isArray(value) && typeof value[0] === "string") {
9
+ return value[0];
10
+ }
11
+ return undefined;
12
+ }
13
+ /**
14
+ * Builds `AuthenticationInput` for customer login with credentials from the JSON body
15
+ * and, for missing fields, from query string (supports GET with `?email&password` or `?phone&password`).
16
+ * Body keys take precedence over query when both are present.
17
+ */
18
+ function buildUnifiedLoginAuthData(req) {
19
+ const bodyRaw = req.body;
20
+ const body = bodyRaw !== null && typeof bodyRaw === "object" && !Array.isArray(bodyRaw)
21
+ ? { ...bodyRaw }
22
+ : {};
23
+ const q = req.query !== null && typeof req.query === "object" && !Array.isArray(req.query)
24
+ ? req.query
25
+ : {};
26
+ const merged = { ...body };
27
+ const qEmail = firstQueryValue(q.email);
28
+ const qPhone = firstQueryValue(q.phone);
29
+ const qPassword = firstQueryValue(q.password);
30
+ if (merged.email === undefined && qEmail !== undefined) {
31
+ merged.email = qEmail;
32
+ }
33
+ if (merged.phone === undefined && qPhone !== undefined) {
34
+ merged.phone = qPhone;
35
+ }
36
+ if (merged.password === undefined && qPassword !== undefined) {
37
+ merged.password = qPassword;
38
+ }
39
+ return {
40
+ url: req.url,
41
+ headers: req.headers,
42
+ query: req.query,
43
+ body: merged,
44
+ protocol: req.protocol,
45
+ };
46
+ }
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtdW5pZmllZC1sb2dpbi1hdXRoLWRhdGEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvc2hhcmVkL2J1aWxkLXVuaWZpZWQtbG9naW4tYXV0aC1kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBa0JBLDhEQW1DQztBQWxERCxTQUFTLGVBQWUsQ0FBQyxLQUFjO0lBQ3JDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDOUIsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3pELE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ2pCLENBQUM7SUFDRCxPQUFPLFNBQVMsQ0FBQTtBQUNsQixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLHlCQUF5QixDQUFDLEdBQWtCO0lBQzFELE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUE7SUFDeEIsTUFBTSxJQUFJLEdBQ1IsT0FBTyxLQUFLLElBQUksSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxDQUFDLENBQUMsRUFBRSxHQUFJLE9BQW1DLEVBQUU7UUFDN0MsQ0FBQyxDQUFDLEVBQUUsQ0FBQTtJQUVSLE1BQU0sQ0FBQyxHQUNMLEdBQUcsQ0FBQyxLQUFLLEtBQUssSUFBSSxJQUFJLE9BQU8sR0FBRyxDQUFDLEtBQUssS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUM7UUFDOUUsQ0FBQyxDQUFFLEdBQUcsQ0FBQyxLQUFpQztRQUN4QyxDQUFDLENBQUMsRUFBRSxDQUFBO0lBRVIsTUFBTSxNQUFNLEdBQTRCLEVBQUUsR0FBRyxJQUFJLEVBQUUsQ0FBQTtJQUVuRCxNQUFNLE1BQU0sR0FBRyxlQUFlLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQ3ZDLE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDdkMsTUFBTSxTQUFTLEdBQUcsZUFBZSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQTtJQUU3QyxJQUFJLE1BQU0sQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLE1BQU0sS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN2RCxNQUFNLENBQUMsS0FBSyxHQUFHLE1BQU0sQ0FBQTtJQUN2QixDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsS0FBSyxLQUFLLFNBQVMsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDdkQsTUFBTSxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUE7SUFDdkIsQ0FBQztJQUNELElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxTQUFTLElBQUksU0FBUyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzdELE1BQU0sQ0FBQyxRQUFRLEdBQUcsU0FBUyxDQUFBO0lBQzdCLENBQUM7SUFFRCxPQUFPO1FBQ0wsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHO1FBQ1osT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO1FBQ3BCLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSztRQUNoQixJQUFJLEVBQUUsTUFBTTtRQUNaLFFBQVEsRUFBRSxHQUFHLENBQUMsUUFBUTtLQUNBLENBQUE7QUFDMUIsQ0FBQyJ9
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.completeCustomerLogin = completeCustomerLogin;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
6
+ const account_deletion_request_1 = require("../../../../modules/account-deletion-request");
7
+ /**
8
+ * Pending deletion check, merge customer_id into app_metadata, issue JWT, respond 200 `{ token }`.
9
+ */
10
+ async function completeCustomerLogin(req, res, config, authIdentity, customerId, logContext) {
11
+ const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
12
+ if (await accountDeletionService.hasPendingRequest(customerId)) {
13
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Customer has an active account deletion request");
14
+ }
15
+ const authIdentityWithCustomerId = {
16
+ ...authIdentity,
17
+ app_metadata: {
18
+ ...authIdentity.app_metadata,
19
+ customer_id: customerId,
20
+ },
21
+ };
22
+ const { http } = config.projectConfig ?? {};
23
+ if (!http?.jwtSecret) {
24
+ if (logContext.kind === "email") {
25
+ console.error("[customer-auth] JWT secret is not configured", {
26
+ email: logContext.email,
27
+ customerId,
28
+ hasJwtSecret: !!http?.jwtSecret,
29
+ });
30
+ }
31
+ else {
32
+ console.error("[customer-auth] JWT secret is not configured", {
33
+ phone: logContext.phone,
34
+ customerId,
35
+ hasJwtSecret: !!http?.jwtSecret,
36
+ });
37
+ }
38
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
39
+ }
40
+ let token;
41
+ try {
42
+ token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
43
+ authIdentity: authIdentityWithCustomerId,
44
+ actorType: "customer",
45
+ }, {
46
+ secret: http.jwtSecret,
47
+ expiresIn: http.jwtExpiresIn || "7d",
48
+ });
49
+ }
50
+ catch (jwtError) {
51
+ if (logContext.kind === "email") {
52
+ console.error("[customer-auth] JWT generation threw an exception", {
53
+ email: logContext.email,
54
+ customerId,
55
+ error: jwtError instanceof Error ? jwtError.message : String(jwtError),
56
+ stack: jwtError instanceof Error ? jwtError.stack : undefined,
57
+ jwtSecretExists: !!http.jwtSecret,
58
+ });
59
+ }
60
+ else {
61
+ console.error("[customer-auth] JWT generation threw an exception", {
62
+ phone: logContext.phone,
63
+ customerId,
64
+ error: jwtError instanceof Error ? jwtError.message : String(jwtError),
65
+ stack: jwtError instanceof Error ? jwtError.stack : undefined,
66
+ jwtSecretExists: !!http.jwtSecret,
67
+ });
68
+ }
69
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
70
+ }
71
+ if (!token || typeof token !== "string") {
72
+ if (logContext.kind === "email") {
73
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `Failed to generate authentication token for customer ${customerId}. Token type: ${typeof token}, Token value: ${token}`);
74
+ }
75
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to generate authentication token");
76
+ }
77
+ res.status(200).json({ token });
78
+ }
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxldGUtY3VzdG9tZXItbG9naW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvc2hhcmVkL2NvbXBsZXRlLWN1c3RvbWVyLWxvZ2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBcUJBLHNEQW1HQztBQXRIRCxxREFBdUQ7QUFDdkQsMkZBQW9HO0FBQ3BHLDJGQUE4RjtBQWM5Rjs7R0FFRztBQUNJLEtBQUssVUFBVSxxQkFBcUIsQ0FDekMsR0FBa0IsRUFDbEIsR0FBbUIsRUFDbkIsTUFBMEIsRUFDMUIsWUFBK0IsRUFDL0IsVUFBa0IsRUFDbEIsVUFBK0U7SUFFL0UsTUFBTSxzQkFBc0IsR0FDMUIsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ2YsMERBQStCLENBQ2hDLENBQUE7SUFDSCxJQUFJLE1BQU0sc0JBQXNCLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMvRCxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixpREFBaUQsQ0FDbEQsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLDBCQUEwQixHQUFHO1FBQ2pDLEdBQUcsWUFBWTtRQUNmLFlBQVksRUFBRTtZQUNaLEdBQUcsWUFBWSxDQUFDLFlBQVk7WUFDNUIsV0FBVyxFQUFFLFVBQVU7U0FDeEI7S0FDRixDQUFBO0lBRUQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxhQUFhLElBQUksRUFBRSxDQUFBO0lBRTNDLElBQUksQ0FBQyxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7UUFDckIsSUFBSSxVQUFVLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQ2hDLE9BQU8sQ0FBQyxLQUFLLENBQUMsOENBQThDLEVBQUU7Z0JBQzVELEtBQUssRUFBRSxVQUFVLENBQUMsS0FBSztnQkFDdkIsVUFB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
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.respondWithRegistrationToken = respondWithRegistrationToken;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
6
+ /**
7
+ * After a successful `authModuleService.register(...)`, issues the standard
8
+ * Medusa registration JWT and responds with `{ token }`.
9
+ */
10
+ async function respondWithRegistrationToken(req, res, authIdentity) {
11
+ const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
12
+ const { http } = config.projectConfig ?? {};
13
+ if (!http?.jwtSecret) {
14
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
15
+ }
16
+ let token;
17
+ try {
18
+ token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
19
+ authIdentity: authIdentity,
20
+ actorType: "customer",
21
+ }, {
22
+ secret: http.jwtSecret,
23
+ expiresIn: http.jwtExpiresIn || "7d",
24
+ });
25
+ }
26
+ catch (jwtError) {
27
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
28
+ }
29
+ if (!token || typeof token !== "string") {
30
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to generate registration token");
31
+ }
32
+ res.status(200).json({ token });
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxldGUtcmVnaXN0cmF0aW9uLXRva2VuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9hdXRoL2N1c3RvbWVyL3NoYXJlZC9jb21wbGV0ZS1yZWdpc3RyYXRpb24tdG9rZW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFjQSxvRUE2Q0M7QUF6REQscURBR2tDO0FBQ2xDLDJGQUFvRztBQUlwRzs7O0dBR0c7QUFDSSxLQUFLLFVBQVUsNEJBQTRCLENBQ2hELEdBQWtCLEVBQ2xCLEdBQW1CLEVBQ25CLFlBQXFDO0lBRXJDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FFcEQsQ0FBQTtJQUVwQixNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsTUFBTSxDQUFDLGFBQWEsSUFBSSxFQUFFLENBQUE7SUFFM0MsSUFBSSxDQUFDLElBQUksRUFBRSxTQUFTLEVBQUUsQ0FBQztRQUNyQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw4QkFBOEIsQ0FDL0IsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLEtBQXlCLENBQUE7SUFDN0IsSUFBSSxDQUFDO1FBQ0gsS0FBSyxHQUFHLE1BQU0sSUFBQSxvREFBK0IsRUFDM0M7WUFDRSxZQUFZLEVBQUUsWUFBMEM7WUFDeEQsU0FBUyxFQUFFLFVBQVU7U0FDdEIsRUFDRDtZQUNFLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUztZQUN0QixTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJO1NBQ3JDLENBQ0YsQ0FBQTtJQUNILENBQUM7SUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMsMEJBQTBCLFFBQVEsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUMzRixDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDeEMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLGdCQUFnQixFQUNsQyx1Q0FBdUMsQ0FDeEMsQ0FBQTtJQUNILENBQUM7SUFFRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7QUFDakMsQ0FBQyJ9
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runEmailPassAuthFlow = runEmailPassAuthFlow;
4
+ exports.runPhonePassAuthFlow = runPhonePassAuthFlow;
5
+ exports.handleCustomerLogin = handleCustomerLogin;
6
+ const utils_1 = require("@medusajs/framework/utils");
7
+ const config_1 = require("../../../../config");
8
+ const complete_customer_login_1 = require("./complete-customer-login");
9
+ const enforce_registration_verification_1 = require("./enforce-registration-verification");
10
+ const build_unified_login_auth_data_1 = require("./build-unified-login-auth-data");
11
+ const parse_login_body_1 = require("./parse-login-body");
12
+ function firstKnexRow(result) {
13
+ const fromRows = result.rows?.[0];
14
+ if (fromRows && typeof fromRows === "object" && !Array.isArray(fromRows)) {
15
+ return fromRows;
16
+ }
17
+ const batch = result[0];
18
+ if (Array.isArray(batch)) {
19
+ const first = batch[0];
20
+ if (first && typeof first === "object" && !Array.isArray(first)) {
21
+ return first;
22
+ }
23
+ }
24
+ return undefined;
25
+ }
26
+ /**
27
+ * Email-only login (used when unified parse selects email).
28
+ */
29
+ async function runEmailPassAuthFlow(req, res, config, authData) {
30
+ const service = req.scope.resolve(utils_1.Modules.AUTH);
31
+ const { success, error, authIdentity, location } = await service.authenticate("emailpass", authData);
32
+ if (location) {
33
+ res.status(200).json({ location });
34
+ return;
35
+ }
36
+ if (success && authIdentity) {
37
+ const email = authIdentity.provider_identities?.[0]
38
+ ?.entity_id ?? "";
39
+ const appMeta = authIdentity.app_metadata;
40
+ let customerId = typeof appMeta?.customer_id === "string" ? appMeta.customer_id : undefined;
41
+ if (!customerId) {
42
+ const customerModule = req.scope.resolve(utils_1.Modules.CUSTOMER);
43
+ const customers = await customerModule.listCustomers({
44
+ email: email.toLowerCase(),
45
+ });
46
+ if (customers && customers.length > 0) {
47
+ customerId = customers[0].id;
48
+ }
49
+ }
50
+ const resolvedCustomerId = typeof customerId === "string" && customerId.trim().length > 0
51
+ ? customerId
52
+ : undefined;
53
+ if (!resolvedCustomerId) {
54
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Unable to determine customer ID for authentication");
55
+ }
56
+ await (0, enforce_registration_verification_1.enforceRegistrationVerification)({
57
+ customerId: resolvedCustomerId,
58
+ req,
59
+ logLabel: email,
60
+ loginChannel: "email",
61
+ });
62
+ await (0, complete_customer_login_1.completeCustomerLogin)(req, res, config, authIdentity, resolvedCustomerId, {
63
+ kind: "email",
64
+ email,
65
+ });
66
+ return;
67
+ }
68
+ console.error("[customer-auth] Email authentication failed", {
69
+ success,
70
+ error,
71
+ hasAuthIdentity: !!authIdentity,
72
+ });
73
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, error || "Authentication failed");
74
+ }
75
+ /**
76
+ * Phone-only login (phonepass provider).
77
+ */
78
+ async function runPhonePassAuthFlow(req, res, config, authData) {
79
+ const service = req.scope.resolve(utils_1.Modules.AUTH);
80
+ const { success, error, authIdentity } = await service.authenticate("phonepass", authData);
81
+ if (!success || !authIdentity) {
82
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, error || "Authentication failed");
83
+ }
84
+ const phone = authIdentity.provider_identities?.[0]
85
+ ?.entity_id ?? "";
86
+ const appMetaPhone = authIdentity.app_metadata;
87
+ let customerId = typeof appMetaPhone?.customer_id === "string"
88
+ ? appMetaPhone.customer_id
89
+ : undefined;
90
+ if (!customerId) {
91
+ const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
92
+ if (knex) {
93
+ const result = await knex.raw(`SELECT id FROM customer WHERE phone = ? LIMIT 1`, [phone]);
94
+ const row = firstKnexRow(result);
95
+ if (row?.id) {
96
+ customerId = row.id;
97
+ }
98
+ }
99
+ }
100
+ if (!customerId) {
101
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Unable to determine customer ID for authentication");
102
+ }
103
+ let logLabel = phone;
104
+ const knexEmail = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
105
+ if (knexEmail) {
106
+ const rowResult = await knexEmail.raw(`SELECT email FROM customer WHERE id = ? LIMIT 1`, [customerId]);
107
+ const row = firstKnexRow(rowResult);
108
+ const e = row?.email;
109
+ if (typeof e === "string" && e.trim()) {
110
+ logLabel = e.trim();
111
+ }
112
+ }
113
+ await (0, enforce_registration_verification_1.enforceRegistrationVerification)({
114
+ customerId,
115
+ req,
116
+ logLabel,
117
+ loginChannel: "phone",
118
+ });
119
+ await (0, complete_customer_login_1.completeCustomerLogin)(req, res, config, authIdentity, customerId, {
120
+ kind: "phone",
121
+ phone,
122
+ });
123
+ }
124
+ /**
125
+ * Unified customer login: POST (JSON body) or GET (query `email`|`phone` + `password`).
126
+ * Credentials are merged with body taking precedence over query (see `buildUnifiedLoginAuthData`).
127
+ */
128
+ async function handleCustomerLogin(req, res) {
129
+ const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
130
+ const loginOptions = (0, config_1.resolveCustomerRegistrationOptions)(config);
131
+ const loginIdentifier = loginOptions.login.identifier;
132
+ const authData = (0, build_unified_login_auth_data_1.buildUnifiedLoginAuthData)(req);
133
+ const parseSource = authData.body !== null && typeof authData.body === "object" && !Array.isArray(authData.body)
134
+ ? authData.body
135
+ : {};
136
+ const parsed = (0, parse_login_body_1.parseCustomerLoginBody)(parseSource, loginIdentifier);
137
+ if (parsed.mode === "email") {
138
+ return runEmailPassAuthFlow(req, res, config, authData);
139
+ }
140
+ return runPhonePassAuthFlow(req, res, config, authData);
141
+ }
142
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXItbG9naW4tcG9zdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYXV0aC9jdXN0b21lci9zaGFyZWQvY3VzdG9tZXItbG9naW4tcG9zdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWlEQSxvREE0RUM7QUFLRCxvREF3RkM7QUFNRCxrREF3QkM7QUF0UEQscURBSWtDO0FBRWxDLCtDQUF1RTtBQUN2RSx1RUFBMEY7QUFDMUYsMkZBQXFGO0FBQ3JGLG1GQUEyRTtBQUMzRSx5REFHMkI7QUFFM0IsU0FBUyxZQUFZLENBQ25CLE1BQW1DO0lBRW5DLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUNqQyxJQUFJLFFBQVEsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDekUsT0FBTyxRQUFRLENBQUE7SUFDakIsQ0FBQztJQUNELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN2QixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN6QixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDdEIsSUFBSSxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2hFLE9BQU8sS0FBVSxDQUFBO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUE7QUFDbEIsQ0FBQztBQWNEOztHQUVHO0FBQ0ksS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxHQUFrQixFQUNsQixHQUFtQixFQUNuQixNQUE4QyxFQUM5QyxRQUE2QjtJQUU3QixNQUFNLE9B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
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enforceRegistrationVerification = enforceRegistrationVerification;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const otp_verification_1 = require("../../../../modules/otp-verification");
6
+ const config_1 = require("../../../../config");
7
+ /**
8
+ * Enforces OTP verification for login according to `registration.identifier` and `require_verification`.
9
+ *
10
+ * - `email` / `phone`: only that channel must be verified.
11
+ * - `both`: only the channel used to log in must be verified (`loginChannel`).
12
+ *
13
+ * When phone is enforced but unverified, includes `pending_phone` UX for pending number changes.
14
+ */
15
+ async function enforceRegistrationVerification({ customerId, req, logLabel, loginChannel, }) {
16
+ const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
17
+ const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
18
+ const { identifier, require_verification } = options.registration;
19
+ if (!require_verification) {
20
+ return;
21
+ }
22
+ const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
23
+ const verificationStatus = await otpService.getCustomerVerificationByCustomerId(req.scope, customerId);
24
+ const enforceEmail = identifier === "email" ||
25
+ (identifier === "both" && loginChannel === "email");
26
+ const enforcePhone = identifier === "phone" ||
27
+ (identifier === "both" && loginChannel === "phone");
28
+ if (enforceEmail && !verificationStatus.email_verified) {
29
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Email not verified.");
30
+ }
31
+ if (enforcePhone && !verificationStatus.phone_verified) {
32
+ const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
33
+ const row = await knex.raw(`SELECT metadata->>'pending_phone' AS pending_phone FROM customer WHERE id = ? LIMIT 1`, [customerId]);
34
+ const pendingPhone = (row.rows?.[0] ?? row[0]?.[0])?.pending_phone ?? null;
35
+ console.error("[customer-auth] Phone not verified", {
36
+ logLabel,
37
+ customerId,
38
+ });
39
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, pendingPhone
40
+ ? "Your new phone number is pending verification. Please verify it to continue."
41
+ : "Phone not verified.");
42
+ }
43
+ }
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5mb3JjZS1yZWdpc3RyYXRpb24tdmVyaWZpY2F0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9hdXRoL2N1c3RvbWVyL3NoYXJlZC9lbmZvcmNlLXJlZ2lzdHJhdGlvbi12ZXJpZmljYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFzQkEsMEVBb0VDO0FBekZELHFEQUdrQztBQUdsQywyRUFBOEU7QUFFOUUsK0NBRzJCO0FBRTNCOzs7Ozs7O0dBT0c7QUFDSSxLQUFLLFVBQVUsK0JBQStCLENBQUMsRUFDcEQsVUFBVSxFQUNWLEdBQUcsRUFDSCxRQUFRLEVBQ1IsWUFBWSxHQVFiO0lBQ0MsTUFBTSxZQUFZLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ3BDLGlDQUF5QixDQUFDLGFBQWEsQ0FDeEMsQ0FBQTtJQUNELE1BQU0sT0FBTyxHQUFHLElBQUEsMkNBQWtDLEVBQUMsWUFBWSxDQUFDLENBQUE7SUFDaEUsTUFBTSxFQUFFLFVBQVUsRUFBRSxvQkFBb0IsRUFBRSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUE7SUFFakUsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDMUIsT0FBTTtJQUNSLENBQUM7SUFFRCxNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDbEMsMENBQXVCLENBQ3hCLENBQUE7SUFFRCxNQUFNLGtCQUFrQixHQUFHLE1BQU0sVUFBVSxDQUFDLG1DQUFtQyxDQUM3RSxHQUFHLENBQUMsS0FBK0IsRUFDbkMsVUFBVSxDQUNYLENBQUE7SUFFRCxNQUFNLFlBQVksR0FDaEIsVUFBVSxLQUFLLE9BQU87UUFDdEIsQ0FBQyxVQUFVLEtBQUssTUFBTSxJQUFJLFlBQVksS0FBSyxPQUFPLENBQUMsQ0FBQTtJQUVyRCxNQUFNLFlBQVksR0FDaEIsVUFBVSxLQUFLLE9BQU87UUFDdEIsQ0FBQyxVQUFVLEtBQUssTUFBTSxJQUFJLFlBQVksS0FBSyxPQUFPLENBQUMsQ0FBQTtJQUVyRCxJQUFJLFlBQVksSUFBSSxDQUFDLGtCQUFrQixDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZELE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHFCQUFxQixDQUN0QixDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksWUFBWSxJQUFJLENBQUMsa0JBQWtCLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkQsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsYUFBYSxDQUFDLENBQUE7UUFDdkUsTUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsR0FBRyxDQUN4Qix1RkFBdUYsRUFDdkYsQ0FBQyxVQUFVLENBQUMsQ0FDYixDQUFBO1FBQ0QsTUFBTSxZQUFZLEdBQ2hCLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsYUFBYSxJQUFJLElBQUksQ0FBQTtRQUV2RCxPQUFPLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxFQUFFO1lBQ2xELFFBQVE7WUFDUixVQUFVO1NBQ1gsQ0FBQyxDQUFBO1FBRUYsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsWUFBWTtZQUNWLENBQUMsQ0FBQyw4RUFBOEU7WUFDaEYsQ0FBQyxDQUFDLHFCQUFxQixDQUMxQixDQUFBO0lBQ0gsQ0FBQztBQUNILENBQUMifQ==
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCustomerLoginBody = parseCustomerLoginBody;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ function nonEmptyString(value) {
6
+ if (typeof value !== "string") {
7
+ return undefined;
8
+ }
9
+ const t = value.trim();
10
+ return t.length > 0 ? t : undefined;
11
+ }
12
+ /**
13
+ * Determines email vs phone login from the request body and enforces `login.identifier` from plugin config.
14
+ * Requires exactly one identifier: XOR on non-empty `email` / `phone` (plus `password` for auth).
15
+ */
16
+ function parseCustomerLoginBody(body, loginIdentifier) {
17
+ const record = body !== null && typeof body === "object"
18
+ ? body
19
+ : {};
20
+ const email = nonEmptyString(record.email);
21
+ const phone = nonEmptyString(record.phone);
22
+ if (email && phone) {
23
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Provide either email or phone, not both.");
24
+ }
25
+ if (!email && !phone) {
26
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Either email or phone is required.");
27
+ }
28
+ if (loginIdentifier === "email") {
29
+ if (phone && !email) {
30
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Email login is not enabled. Please log in with your email.");
31
+ }
32
+ return { mode: "email" };
33
+ }
34
+ if (loginIdentifier === "phone") {
35
+ if (email && !phone) {
36
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Phone login is not enabled. Please log in with your phone number.");
37
+ }
38
+ return { mode: "phone" };
39
+ }
40
+ return email ? { mode: "email" } : { mode: "phone" };
41
+ }
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2UtbG9naW4tYm9keS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYXV0aC9jdXN0b21lci9zaGFyZWQvcGFyc2UtbG9naW4tYm9keS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQW9CQSx3REErQ0M7QUFuRUQscURBQXVEO0FBUXZELFNBQVMsY0FBYyxDQUFDLEtBQWM7SUFDcEMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM5QixPQUFPLFNBQVMsQ0FBQTtJQUNsQixDQUFDO0lBQ0QsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFBO0lBQ3RCLE9BQU8sQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0FBQ3JDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixzQkFBc0IsQ0FDcEMsSUFBYSxFQUNiLGVBQXNDO0lBRXRDLE1BQU0sTUFBTSxHQUNWLElBQUksS0FBSyxJQUFJLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUTtRQUN2QyxDQUFDLENBQUUsSUFBZ0M7UUFDbkMsQ0FBQyxDQUFDLEVBQUUsQ0FBQTtJQUVSLE1BQU0sS0FBSyxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDMUMsTUFBTSxLQUFLLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUUxQyxJQUFJLEtBQUssSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUNuQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QiwwQ0FBMEMsQ0FDM0MsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDckIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsb0NBQW9DLENBQ3JDLENBQUE7SUFDSCxDQUFDO0lBRUQsSUFBSSxlQUFlLEtBQUssT0FBTyxFQUFFLENBQUM7UUFDaEMsSUFBSSxLQUFLLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNwQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw0REFBNEQsQ0FDN0QsQ0FBQTtRQUNILENBQUM7UUFDRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFBO0lBQzFCLENBQUM7SUFFRCxJQUFJLGVBQWUsS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUNoQyxJQUFJLEtBQUssSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG1FQUFtRSxDQUNwRSxDQUFBO1FBQ0gsQ0FBQztRQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUE7SUFDMUIsQ0FBQztJQUVELE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUE7QUFDdEQsQ0FBQyJ9
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCustomerRegisterBody = parseCustomerRegisterBody;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ function nonEmptyString(value) {
6
+ if (typeof value !== "string") {
7
+ return undefined;
8
+ }
9
+ const t = value.trim();
10
+ return t.length > 0 ? t : undefined;
11
+ }
12
+ /**
13
+ * Chooses email vs phone registration from the JSON body and enforces `registration.identifier`.
14
+ * Requires `password` (non-empty string). For `"both"`, only `email` + `password` is allowed (no phone-only; no extra phone field).
15
+ */
16
+ function parseCustomerRegisterBody(body, registrationIdentifier) {
17
+ const record = body !== null && typeof body === "object"
18
+ ? body
19
+ : {};
20
+ const password = nonEmptyString(record.password);
21
+ if (!password) {
22
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Password is required.");
23
+ }
24
+ const email = nonEmptyString(record.email);
25
+ const phone = nonEmptyString(record.phone);
26
+ if (registrationIdentifier === "both") {
27
+ if (phone && !email) {
28
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Registration with email and password is required first. Use email and password only on this step.");
29
+ }
30
+ if (!email) {
31
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Email and password are required.");
32
+ }
33
+ if (phone) {
34
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Provide only email and password. Add your phone when creating the customer.");
35
+ }
36
+ return { mode: "email" };
37
+ }
38
+ if (email && phone) {
39
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Provide either email or phone, not both.");
40
+ }
41
+ if (!email && !phone) {
42
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Either email or phone is required.");
43
+ }
44
+ if (registrationIdentifier === "email") {
45
+ if (phone && !email) {
46
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Phone registration is not enabled for this store. Register with your email.");
47
+ }
48
+ return { mode: "email" };
49
+ }
50
+ if (registrationIdentifier === "phone") {
51
+ if (email && !phone) {
52
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Email registration is not enabled for this store. Register with your phone number.");
53
+ }
54
+ return { mode: "phone" };
55
+ }
56
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid registration configuration.");
57
+ }
58
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2UtcmVnaXN0ZXItYm9keS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYXV0aC9jdXN0b21lci9zaGFyZWQvcGFyc2UtcmVnaXN0ZXItYm9keS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQW9CQSw4REFnRkM7QUFwR0QscURBQXVEO0FBUXZELFNBQVMsY0FBYyxDQUFDLEtBQWM7SUFDcEMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM5QixPQUFPLFNBQVMsQ0FBQTtJQUNsQixDQUFDO0lBQ0QsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFBO0lBQ3RCLE9BQU8sQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0FBQ3JDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQix5QkFBeUIsQ0FDdkMsSUFBYSxFQUNiLHNCQUFvRDtJQUVwRCxNQUFNLE1BQU0sR0FDVixJQUFJLEtBQUssSUFBSSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVE7UUFDdkMsQ0FBQyxDQUFFLElBQWdDO1FBQ25DLENBQUMsQ0FBQyxFQUFFLENBQUE7SUFFUixNQUFNLFFBQVEsR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBQ2hELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHVCQUF1QixDQUN4QixDQUFBO0lBQ0gsQ0FBQztJQUVELE1BQU0sS0FBSyxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDMUMsTUFBTSxLQUFLLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUUxQyxJQUFJLHNCQUFzQixLQUFLLE1BQU0sRUFBRSxDQUFDO1FBQ3RDLElBQUksS0FBSyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDcEIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsbUdBQW1HLENBQ3BHLENBQUE7UUFDSCxDQUFDO1FBQ0QsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ1gsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsa0NBQWtDLENBQ25DLENBQUE7UUFDSCxDQUFDO1FBQ0QsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNWLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLDZFQUE2RSxDQUM5RSxDQUFBO1FBQ0gsQ0FBQztRQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUE7SUFDMUIsQ0FBQztJQUVELElBQUksS0FBSyxJQUFJLEtBQUssRUFBRSxDQUFDO1FBQ25CLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLDBDQUEwQyxDQUMzQyxDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNyQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixvQ0FBb0MsQ0FDckMsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLHNCQUFzQixLQUFLLE9BQU8sRUFBRSxDQUFDO1FBQ3ZDLElBQUksS0FBSyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDcEIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsNkVBQTZFLENBQzlFLENBQUE7UUFDSCxDQUFDO1FBQ0QsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQTtJQUMxQixDQUFDO0lBRUQsSUFBSSxzQkFBc0IsS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUN2QyxJQUFJLEtBQUssSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG9GQUFvRixDQUNyRixDQUFBO1FBQ0gsQ0FBQztRQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUE7SUFDMUIsQ0FBQztJQUVELE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHFDQUFxQyxDQUN0QyxDQUFBO0FBQ0gsQ0FBQyJ9
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "vitest/config";
2
+ export default defineConfig({
3
+ test: {
4
+ include: ["src/**/*.test.ts"],
5
+ exclude: ["node_modules", ".medusa/**", ".medusa/server/**"],
6
+ },
7
+ });
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidml0ZXN0LmNvbmZpZy5tanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi92aXRlc3QuY29uZmlnLm10cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBRTVDLGVBQWUsWUFBWSxDQUFDO0lBQzFCLElBQUksRUFBRTtRQUNKLE9BQU8sRUFBRSxDQUFDLGtCQUFrQixDQUFDO1FBQzdCLE9BQU8sRUFBRSxDQUFDLGNBQWMsRUFBRSxZQUFZLEVBQUUsbUJBQW1CLENBQUM7S0FDN0Q7Q0FDRixDQUFDLENBQUEifQ==
package/README.md CHANGED
@@ -13,7 +13,8 @@ A comprehensive Medusa v2 plugin that provides OTP-based verification for email
13
13
  - **Throttling & Rate Limiting**: Built-in protection against OTP spam
14
14
  - **Database Migrations**: Automatic schema updates for verification columns
15
15
  - **Account Deletion Request Flow**: Two-step OTP flow to request and confirm account deletion with optional cancel flow
16
- - **Phone-only Authentication**: `phonepass` auth provider for registering and logging in with phone + password (no email required)
16
+ - **Unified registration & login**: **`POST /auth/customer/emailpass/register`** creates an **emailpass** or **phonepass** identity (from JSON body + `registration.identifier`); **`POST /auth/customer/emailpass`** logs in with `{ email, password }` or `{ phone, password }` per `login.identifier`
17
+ - **Per-channel OTP at login**: When `registration.identifier` is **`"both"`** and `require_verification` is on, **email login** only requires **email** verified; **phone login** only requires **phone** verified — you can use either method after completing that channel’s OTP
17
18
  - **Authenticated Contact Change**: Dedicated OTP-verified routes for updating phone or email — new value is embedded in the signed JWT, no metadata staging required
18
19
 
19
20
  ## Quick Start
@@ -77,8 +78,6 @@ npx medusa db:migrate
77
78
 
78
79
  4. **Use the API** — see [API Endpoints](#api-endpoints) below.
79
80
 
80
- 📖 **For complete documentation, see [USAGE.md](./USAGE.md)**
81
-
82
81
  ---
83
82
 
84
83
  ## Installation
@@ -131,9 +130,25 @@ Controls which auth providers are accepted at login. Defaults to `registration.i
131
130
 
132
131
  | Value | Accepted login methods |
133
132
  |---|---|
134
- | `"email"` | `POST /auth/customer/emailpass` only |
135
- | `"phone"` | `POST /auth/customer/phonepass` only |
136
- | `"both"` | Both emailpass and phonepass accepted |
133
+ | `"email"` | `POST /auth/customer/emailpass` with `{ "email", "password" }` only |
134
+ | `"phone"` | Same endpoint with `{ "phone", "password" }` only |
135
+ | `"both"` | Same endpoint; **either** email **or** phone (not both) plus `password` in the JSON body |
136
+
137
+ Login always uses **`POST /auth/customer/emailpass`** (single URL). There is **no** `/auth/customer/phonepass` route; phone registration uses the same **`POST /auth/customer/emailpass/register`** as email registration.
138
+
139
+ Credentials are normally sent in the **JSON body**; the same keys can be supplied on the **query string** for missing fields (see `buildUnifiedLoginAuthData`) — prefer **body** for passwords.
140
+
141
+ ### `require_verification` and login
142
+
143
+ When **`registration.require_verification`** is **`true`** (default), login checks OTP flags **for the credential you use** (see [`enforce-registration-verification.ts`](src/api/auth/customer/shared/enforce-registration-verification.ts)):
144
+
145
+ - **`registration.identifier: "email"`** — signing in with **email** requires **`email_verified`**.
146
+ - **`registration.identifier: "phone"`** — signing in with **phone** requires **`phone_verified`**.
147
+ - **`registration.identifier: "both"`** — signing in with **email** requires **`email_verified`** only (phone may still be unverified). Signing in with **phone** requires **`phone_verified`** only (email may still be unverified).
148
+
149
+ So with **`both`**, a customer can **log in with email** after email OTP even if **phone** OTP is still pending, and the reverse for phone login.
150
+
151
+ When **`require_verification`** is **`false`**, these checks are skipped.
137
152
 
138
153
  ### Full options reference
139
154
 
@@ -223,14 +238,16 @@ POST /store/customers/otp/verify
223
238
 
224
239
  ---
225
240
 
226
- ### Login
241
+ ### Login & registration (customer auth)
242
+
243
+ Implementation lives under [`src/api/auth/customer/`](src/api/auth/customer/): **`emailpass/`** (login, **register**, password reset), **`shared/`** (credential parsing, verification, JWT helpers).
227
244
 
228
245
  | Endpoint | Method | Description |
229
246
  |---|---|---|
230
- | `/auth/customer/emailpass` | POST | Login with email + password |
231
- | `/auth/customer/phonepass` | POST | Login with phone + password |
232
- | `/auth/customer/emailpass/register` | POST | Create emailpass auth identity |
233
- | `/auth/customer/phonepass/register` | POST | Create phonepass auth identity |
247
+ | `/auth/customer/emailpass/register` | POST | **Register.** JSON: `password` plus identifier per `registration.identifier` — **`email`** only for `"email"` and `"both"` (for `"both"`, phone is added on `POST /store/customers`); **`phone`** only for `"phone"`. Dispatches to `register("emailpass")` or `register("phonepass")`. Response: `{ "token" }` (pre-customer JWT). See [`emailpass/register/route.ts`](src/api/auth/customer/emailpass/register/route.ts), [`parse-register-body.ts`](src/api/auth/customer/shared/parse-register-body.ts), [`complete-registration-token.ts`](src/api/auth/customer/shared/complete-registration-token.ts). |
248
+ | `/auth/customer/emailpass` | POST | **Login.** JSON: `password` plus **exactly one** of `email` or `phone` (XOR), validated against `login.identifier`. Optional query params can fill missing keys (body wins). [`emailpass/route.ts`](src/api/auth/customer/emailpass/route.ts) → [`handleCustomerLogin`](src/api/auth/customer/shared/customer-login-post.ts). |
249
+
250
+ Password reset URLs are unchanged; see [Password Reset](#password-reset).
234
251
 
235
252
  ---
236
253
 
@@ -411,8 +428,8 @@ export default defineConfig({
411
428
  ### 2. Registration flow
412
429
 
413
430
  ```bash
414
- # Step 1 — create phonepass auth identity
415
- POST /auth/customer/phonepass/register
431
+ # Step 1 — create phonepass auth identity (unified register URL)
432
+ POST /auth/customer/emailpass/register
416
433
  { "phone": "+15551234567", "password": "SecretPass1!" }
417
434
  # Response: { "token": "<pre-customer jwt>" }
418
435
 
@@ -435,7 +452,7 @@ POST /store/customers/otp/verify
435
452
  ### 3. Login flow
436
453
 
437
454
  ```bash
438
- POST /auth/customer/phonepass
455
+ POST /auth/customer/emailpass
439
456
  { "phone": "+15551234567", "password": "SecretPass1!" }
440
457
  # Response: { "token": "<jwt>" }
441
458
  ```
@@ -519,12 +536,11 @@ await completePasswordReset(
519
536
  - Node.js >= 20
520
537
  - Notification module configured with at least one provider (email/SMS)
521
538
  - Database migrations applied (`npx medusa db:migrate`)
522
- - `phonepass` provider registered in auth module (required when `registration.identifier` is `"phone"` or `"both"`)
539
+ - **`phonepass`** auth provider registered in `medusa-config` (required when customers can **register** or **log in** with phone — i.e. `registration.identifier` and/or `login.identifier` is `"phone"` or `"both"`)
523
540
 
524
541
  ## Documentation
525
542
 
526
- - **[USAGE.md](./USAGE.md)** Complete usage guide with examples
527
- - **[README.md](./README.md)** — This file (overview and quick start)
543
+ This **README** is the main overview: configuration, auth routes, OTP behaviour, and API tables.
528
544
 
529
545
  ## Development
530
546
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "customer-registration",
3
- "version": "0.0.114",
3
+ "version": "0.0.116",
4
4
  "description": "Medusa plugin that overrides store customer registration, enforces email/phone verification flags, and provides OTP management module.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",
@@ -1,50 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.POST = void 0;
4
- const utils_1 = require("@medusajs/framework/utils");
5
- const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
6
- /**
7
- * Register a new customer with phone + password.
8
- *
9
- * On success the caller receives a short-lived JWT token. Use it as the
10
- * Bearer token when calling `POST /store/customers` to create the customer
11
- * record and link it to this auth identity.
12
- */
13
- const POST = async (req, res) => {
14
- const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
15
- const service = req.scope.resolve(utils_1.Modules.AUTH);
16
- const authData = {
17
- url: req.url,
18
- headers: req.headers,
19
- query: req.query,
20
- body: req.body,
21
- protocol: req.protocol,
22
- };
23
- const { success, error, authIdentity } = await service.register("phonepass", authData);
24
- if (!success || !authIdentity) {
25
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, error || "Registration failed");
26
- }
27
- const { http } = config.projectConfig;
28
- if (!http.jwtSecret) {
29
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
30
- }
31
- let token;
32
- try {
33
- token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
34
- authIdentity,
35
- actorType: "customer",
36
- }, {
37
- secret: http.jwtSecret,
38
- expiresIn: http.jwtExpiresIn || "7d",
39
- });
40
- }
41
- catch (jwtError) {
42
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
43
- }
44
- if (!token || typeof token !== "string") {
45
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to generate registration token");
46
- }
47
- return res.status(200).json({ token });
48
- };
49
- exports.POST = POST;
50
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvcGhvbmVwYXNzL3JlZ2lzdGVyL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHFEQUlrQztBQUNsQywyRkFBb0c7QUFFcEc7Ozs7OztHQU1HO0FBQ0ksTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBQ3pFLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUUvQyxNQUFNLFFBQVEsR0FBRztRQUNmLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRztRQUNaLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztRQUNwQixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO1FBQ2QsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO0tBQ0EsQ0FBQTtJQUV4QixNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxRQUFRLENBQzdELFdBQVcsRUFDWCxRQUFRLENBQ1QsQ0FBQTtJQUVELElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixLQUFLLElBQUkscUJBQXFCLENBQy9CLENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUE7SUFFckMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNwQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw4QkFBOEIsQ0FDL0IsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLEtBQXlCLENBQUE7SUFDN0IsSUFBSSxDQUFDO1FBQ0gsS0FBSyxHQUFHLE1BQU0sSUFBQSxvREFBK0IsRUFDM0M7WUFDRSxZQUFZO1lBQ1osU0FBUyxFQUFFLFVBQVU7U0FDdEIsRUFDRDtZQUNFLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUztZQUN0QixTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJO1NBQ3JDLENBQ0YsQ0FBQTtJQUNILENBQUM7SUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMsMEJBQTBCLFFBQVEsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUMzRixDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDeEMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLGdCQUFnQixFQUNsQyx1Q0FBdUMsQ0FDeEMsQ0FBQTtJQUNILENBQUM7SUFFRCxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQTtBQUN4QyxDQUFDLENBQUE7QUE1RFksUUFBQSxJQUFJLFFBNERoQiJ9
@@ -1,105 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.POST = void 0;
4
- const utils_1 = require("@medusajs/framework/utils");
5
- const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
6
- const account_deletion_request_1 = require("../../../../modules/account-deletion-request");
7
- const otp_verification_1 = require("../../../../modules/otp-verification");
8
- const config_1 = require("../../../../config");
9
- const POST = async (req, res) => {
10
- const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
11
- const loginOptions = (0, config_1.resolveCustomerRegistrationOptions)(config);
12
- if (loginOptions.login.identifier === "email") {
13
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Phone login is not enabled. Please log in with your email.");
14
- }
15
- const service = req.scope.resolve(utils_1.Modules.AUTH);
16
- const authData = {
17
- url: req.url,
18
- headers: req.headers,
19
- query: req.query,
20
- body: req.body,
21
- protocol: req.protocol,
22
- };
23
- const { success, error, authIdentity } = await service.authenticate("phonepass", authData);
24
- if (success && authIdentity) {
25
- const phone = authIdentity.provider_identities?.[0]?.entity_id ?? "";
26
- await enforcePhoneVerification({ authIdentity, req });
27
- let customerId = authIdentity.app_metadata?.customer_id;
28
- if (!customerId) {
29
- const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
30
- if (knex) {
31
- const result = await knex.raw(`SELECT id FROM customer WHERE phone = ? LIMIT 1`, [phone]);
32
- const row = result.rows?.[0] ?? result[0]?.[0];
33
- if (row?.id) {
34
- customerId = row.id;
35
- }
36
- }
37
- }
38
- if (!customerId) {
39
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Unable to determine customer ID for authentication");
40
- }
41
- const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
42
- if (await accountDeletionService.hasPendingRequest(customerId)) {
43
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Customer has an active account deletion request");
44
- }
45
- const authIdentityWithCustomerId = {
46
- ...authIdentity,
47
- app_metadata: {
48
- ...authIdentity.app_metadata,
49
- customer_id: customerId,
50
- },
51
- };
52
- const { http } = config.projectConfig;
53
- if (!http.jwtSecret) {
54
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "JWT secret is not configured");
55
- }
56
- let token;
57
- try {
58
- token = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({
59
- authIdentity: authIdentityWithCustomerId,
60
- actorType: "customer",
61
- }, {
62
- secret: http.jwtSecret,
63
- expiresIn: http.jwtExpiresIn || "7d",
64
- });
65
- }
66
- catch (jwtError) {
67
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, `JWT generation failed: ${jwtError instanceof Error ? jwtError.message : "Unknown error"}`);
68
- }
69
- if (!token || typeof token !== "string") {
70
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Failed to generate authentication token");
71
- }
72
- return res.status(200).json({ token });
73
- }
74
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, error || "Authentication failed");
75
- };
76
- exports.POST = POST;
77
- const enforcePhoneVerification = async ({ authIdentity, req, }) => {
78
- const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
79
- const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
80
- const { require_verification } = options.registration;
81
- if (!require_verification) {
82
- return;
83
- }
84
- // Use customer_id — not phone — for the verification lookup.
85
- // Phone is mutable: after a phone update customer.phone becomes the NEW number
86
- // while provider_identity.entity_id still holds the OLD one. Querying
87
- // WHERE phone = entity_id would find no row and return phone_verified = false
88
- // even when the customer's actual record is marked verified.
89
- const customerId = authIdentity.app_metadata?.customer_id;
90
- if (!customerId) {
91
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Phone not verified.");
92
- }
93
- const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
94
- const verificationStatus = await otpService.getCustomerVerificationByCustomerId(req.scope, customerId);
95
- if (!verificationStatus.phone_verified) {
96
- // Surface a helpful message when a phone change is pending verification
97
- const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
98
- const row = await knex.raw(`SELECT metadata->>'pending_phone' AS pending_phone FROM customer WHERE id = ? LIMIT 1`, [customerId]);
99
- const pendingPhone = (row.rows?.[0] ?? row[0]?.[0])?.pending_phone ?? null;
100
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, pendingPhone
101
- ? "Your new phone number is pending verification. Please verify it to continue."
102
- : "Phone not verified.");
103
- }
104
- };
105
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvcGhvbmVwYXNzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUtBLHFEQUlrQztBQUNsQywyRkFBb0c7QUFDcEcsMkZBQThGO0FBRTlGLDJFQUE4RTtBQUc5RSwrQ0FHMkI7QUFFcEIsTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBRXpFLE1BQU0sWUFBWSxHQUFHLElBQUEsMkNBQWtDLEVBQUMsTUFBMkIsQ0FBQyxDQUFBO0lBQ3BGLElBQUksWUFBWSxDQUFDLEtBQUssQ0FBQyxVQUFVLEtBQUssT0FBTyxFQUFFLENBQUM7UUFDOUMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsNERBQTRELENBQzdELENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLElBQUksQ0FBQyxDQUFBO0lBRS9DLE1BQU0sUUFBUSxHQUFHO1FBQ2YsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHO1FBQ1osT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO1FBQ3BCLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSztRQUNoQixJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUk7UUFDZCxRQUFRLEVBQUUsR0FBRyxDQUFDLFFBQVE7S0FDQSxDQUFBO0lBRXhCLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxHQUNwQyxNQUFNLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FB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