customer-registration 0.0.114 → 0.0.115

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,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=
@@ -3,15 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.POST = void 0;
4
4
  const utils_1 = require("@medusajs/framework/utils");
5
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");
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
+ */
9
13
  const POST = async (req, res) => {
10
14
  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
15
  const service = req.scope.resolve(utils_1.Modules.AUTH);
16
16
  const authData = {
17
17
  url: req.url,
@@ -20,86 +20,31 @@ const POST = async (req, res) => {
20
20
  body: req.body,
21
21
  protocol: req.protocol,
22
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 });
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");
73
26
  }
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;
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");
83
30
  }
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.");
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
+ });
92
40
  }
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.");
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"}`);
103
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 });
104
48
  };
105
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvcGhvbmVwYXNzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUtBLHFEQUlrQztBQUNsQywyRkFBb0c7QUFDcEcsMkZBQThGO0FBRTlGLDJFQUE4RTtBQUc5RSwrQ0FHMkI7QUFFcEIsTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBRXpFLE1BQU0sWUFBWSxHQUFHLElBQUEsMkNBQWtDLEVBQUMsTUFBMkIsQ0FBQyxDQUFBO0lBQ3BGLElBQUksWUFBWSxDQUFDLEtBQUssQ0FBQyxVQUFVLEtBQUssT0FBTyxFQUFFLENBQUM7UUFDOUMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsNERBQTRELENBQzdELENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLElBQUksQ0FBQyxDQUFBO0lBRS9DLE1BQU0sUUFBUSxHQUFHO1FBQ2YsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHO1FBQ1osT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO1FBQ3BCLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSztRQUNoQixJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUk7UUFDZCxRQUFRLEVBQUUsR0FBRyxDQUFDLFFBQVE7S0FDQSxDQUFBO0lBRXhCLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxHQUNwQyxNQUFNLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FB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
49
+ exports.POST = POST;
50
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2F1dGgvY3VzdG9tZXIvcGhvbmVwYXNzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHFEQUlrQztBQUNsQywyRkFBb0c7QUFFcEc7Ozs7OztHQU1HO0FBQ0ksTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBQ3pFLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUUvQyxNQUFNLFFBQVEsR0FBRztRQUNmLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRztRQUNaLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTztRQUNwQixLQUFLLEVBQUUsR0FBRyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO1FBQ2QsUUFBUSxFQUFFLEdBQUcsQ0FBQyxRQUFRO0tBQ0EsQ0FBQTtJQUV4QixNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxRQUFRLENBQzdELFdBQVcsRUFDWCxRQUFRLENBQ1QsQ0FBQTtJQUVELElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixLQUFLLElBQUkscUJBQXFCLENBQy9CLENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUE7SUFFckMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNwQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw4QkFBOEIsQ0FDL0IsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLEtBQXlCLENBQUE7SUFDN0IsSUFBSSxDQUFDO1FBQ0gsS0FBSyxHQUFHLE1BQU0sSUFBQSxvREFBK0IsRUFDM0M7WUFDRSxZQUFZO1lBQ1osU0FBUyxFQUFFLFVBQVU7U0FDdEIsRUFDRDtZQUNFLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUztZQUN0QixTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJO1NBQ3JDLENBQ0YsQ0FBQTtJQUNILENBQUM7SUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFDbEMsMEJBQTBCLFFBQVEsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUMzRixDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDeEMsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLGdCQUFnQixFQUNsQyx1Q0FBdUMsQ0FDeEMsQ0FBQTtJQUNILENBQUM7SUFFRCxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQTtBQUN4QyxDQUFDLENBQUE7QUE1RFksUUFBQSxJQUFJLFFBNERoQiJ9
@@ -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,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,140 @@
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
+ });
61
+ await (0, complete_customer_login_1.completeCustomerLogin)(req, res, config, authIdentity, resolvedCustomerId, {
62
+ kind: "email",
63
+ email,
64
+ });
65
+ return;
66
+ }
67
+ console.error("[customer-auth] Email authentication failed", {
68
+ success,
69
+ error,
70
+ hasAuthIdentity: !!authIdentity,
71
+ });
72
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, error || "Authentication failed");
73
+ }
74
+ /**
75
+ * Phone-only login (phonepass provider).
76
+ */
77
+ async function runPhonePassAuthFlow(req, res, config, authData) {
78
+ const service = req.scope.resolve(utils_1.Modules.AUTH);
79
+ const { success, error, authIdentity } = await service.authenticate("phonepass", authData);
80
+ if (!success || !authIdentity) {
81
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, error || "Authentication failed");
82
+ }
83
+ const phone = authIdentity.provider_identities?.[0]
84
+ ?.entity_id ?? "";
85
+ const appMetaPhone = authIdentity.app_metadata;
86
+ let customerId = typeof appMetaPhone?.customer_id === "string"
87
+ ? appMetaPhone.customer_id
88
+ : undefined;
89
+ if (!customerId) {
90
+ const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
91
+ if (knex) {
92
+ const result = await knex.raw(`SELECT id FROM customer WHERE phone = ? LIMIT 1`, [phone]);
93
+ const row = firstKnexRow(result);
94
+ if (row?.id) {
95
+ customerId = row.id;
96
+ }
97
+ }
98
+ }
99
+ if (!customerId) {
100
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Unable to determine customer ID for authentication");
101
+ }
102
+ let logLabel = phone;
103
+ const knexEmail = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
104
+ if (knexEmail) {
105
+ const rowResult = await knexEmail.raw(`SELECT email FROM customer WHERE id = ? LIMIT 1`, [customerId]);
106
+ const row = firstKnexRow(rowResult);
107
+ const e = row?.email;
108
+ if (typeof e === "string" && e.trim()) {
109
+ logLabel = e.trim();
110
+ }
111
+ }
112
+ await (0, enforce_registration_verification_1.enforceRegistrationVerification)({
113
+ customerId,
114
+ req,
115
+ logLabel,
116
+ });
117
+ await (0, complete_customer_login_1.completeCustomerLogin)(req, res, config, authIdentity, customerId, {
118
+ kind: "phone",
119
+ phone,
120
+ });
121
+ }
122
+ /**
123
+ * Unified customer login: POST (JSON body) or GET (query `email`|`phone` + `password`).
124
+ * Credentials are merged with body taking precedence over query (see `buildUnifiedLoginAuthData`).
125
+ */
126
+ async function handleCustomerLogin(req, res) {
127
+ const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
128
+ const loginOptions = (0, config_1.resolveCustomerRegistrationOptions)(config);
129
+ const loginIdentifier = loginOptions.login.identifier;
130
+ const authData = (0, build_unified_login_auth_data_1.buildUnifiedLoginAuthData)(req);
131
+ const parseSource = authData.body !== null && typeof authData.body === "object" && !Array.isArray(authData.body)
132
+ ? authData.body
133
+ : {};
134
+ const parsed = (0, parse_login_body_1.parseCustomerLoginBody)(parseSource, loginIdentifier);
135
+ if (parsed.mode === "email") {
136
+ return runEmailPassAuthFlow(req, res, config, authData);
137
+ }
138
+ return runPhonePassAuthFlow(req, res, config, authData);
139
+ }
140
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXItbG9naW4tcG9zdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYXV0aC9jdXN0b21lci9zaGFyZWQvY3VzdG9tZXItbG9naW4tcG9zdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWlEQSxvREEyRUM7QUFLRCxvREF1RkM7QUFNRCxrREF3QkM7QUFwUEQscURBSWtDO0FBRWxDLCtDQUF1RTtBQUN2RSx1RUFBMEY7QUFDMUYsMkZBQXFGO0FBQ3JGLG1GQUEyRTtBQUMzRSx5REFHMkI7QUFFM0IsU0FBUyxZQUFZLENBQ25CLE1BQW1DO0lBRW5DLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUNqQyxJQUFJLFFBQVEsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDekUsT0FBTyxRQUFRLENBQUE7SUFDakIsQ0FBQztJQUNELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN2QixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN6QixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDdEIsSUFBSSxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2hFLE9BQU8sS0FBVSxDQUFBO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUE7QUFDbEIsQ0FBQztBQWNEOztHQUVHO0FBQ0ksS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxHQUFrQixFQUNsQixHQUFtQixFQUNuQixNQUE4QyxFQUM5QyxRQUE2QjtJQUU3QixNQUFNLE9B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
@@ -0,0 +1,38 @@
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 email / phone OTP verification according to `registration.identifier` and `require_verification`.
9
+ * When phone is required but unverified, includes `pending_phone` UX (same as legacy phonepass route).
10
+ */
11
+ async function enforceRegistrationVerification({ customerId, req, logLabel, }) {
12
+ const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
13
+ const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
14
+ const { identifier, require_verification } = options.registration;
15
+ if (!require_verification) {
16
+ return;
17
+ }
18
+ const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
19
+ const verificationStatus = await otpService.getCustomerVerificationByCustomerId(req.scope, customerId);
20
+ if ((identifier === "email" || identifier === "both") &&
21
+ !verificationStatus.email_verified) {
22
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Email not verified.");
23
+ }
24
+ if ((identifier === "phone" || identifier === "both") &&
25
+ !verificationStatus.phone_verified) {
26
+ const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
27
+ const row = await knex.raw(`SELECT metadata->>'pending_phone' AS pending_phone FROM customer WHERE id = ? LIMIT 1`, [customerId]);
28
+ const pendingPhone = (row.rows?.[0] ?? row[0]?.[0])?.pending_phone ?? null;
29
+ console.error("[customer-auth] Phone not verified", {
30
+ logLabel,
31
+ customerId,
32
+ });
33
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, pendingPhone
34
+ ? "Your new phone number is pending verification. Please verify it to continue."
35
+ : "Phone not verified.");
36
+ }
37
+ }
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5mb3JjZS1yZWdpc3RyYXRpb24tdmVyaWZpY2F0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9hdXRoL2N1c3RvbWVyL3NoYXJlZC9lbmZvcmNlLXJlZ2lzdHJhdGlvbi12ZXJpZmljYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFrQkEsMEVBK0RDO0FBaEZELHFEQUdrQztBQUdsQywyRUFBOEU7QUFFOUUsK0NBRzJCO0FBRTNCOzs7R0FHRztBQUNJLEtBQUssVUFBVSwrQkFBK0IsQ0FBQyxFQUNwRCxVQUFVLEVBQ1YsR0FBRyxFQUNILFFBQVEsR0FNVDtJQUNDLE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUNwQyxpQ0FBeUIsQ0FBQyxhQUFhLENBQ3hDLENBQUE7SUFDRCxNQUFNLE9BQU8sR0FBRyxJQUFBLDJDQUFrQyxFQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ2hFLE1BQU0sRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQUUsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFBO0lBRWpFLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzFCLE9BQU07SUFDUixDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ2xDLDBDQUF1QixDQUN4QixDQUFBO0lBRUQsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLFVBQVUsQ0FBQyxtQ0FBbUMsQ0FDN0UsR0FBRyxDQUFDLEtBQStCLEVBQ25DLFVBQVUsQ0FDWCxDQUFBO0lBRUQsSUFDRSxDQUFDLFVBQVUsS0FBSyxPQUFPLElBQUksVUFBVSxLQUFLLE1BQU0sQ0FBQztRQUNqRCxDQUFDLGtCQUFrQixDQUFDLGNBQWMsRUFDbEMsQ0FBQztRQUNELE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHFCQUFxQixDQUN0QixDQUFBO0lBQ0gsQ0FBQztJQUVELElBQ0UsQ0FBQyxVQUFVLEtBQUssT0FBTyxJQUFJLFVBQVUsS0FBSyxNQUFNLENBQUM7UUFDakQsQ0FBQyxrQkFBa0IsQ0FBQyxjQUFjLEVBQ2xDLENBQUM7UUFDRCxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxhQUFhLENBQUMsQ0FBQTtRQUN2RSxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQ3hCLHVGQUF1RixFQUN2RixDQUFDLFVBQVUsQ0FBQyxDQUNiLENBQUE7UUFDRCxNQUFNLFlBQVksR0FDaEIsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxhQUFhLElBQUksSUFBSSxDQUFBO1FBRXZELE9BQU8sQ0FBQyxLQUFLLENBQUMsb0NBQW9DLEVBQUU7WUFDbEQsUUFBUTtZQUNSLFVBQVU7U0FDWCxDQUFDLENBQUE7UUFFRixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixZQUFZO1lBQ1YsQ0FBQyxDQUFDLDhFQUE4RTtZQUNoRixDQUFDLENBQUMscUJBQXFCLENBQzFCLENBQUE7SUFDSCxDQUFDO0FBQ0gsQ0FBQyJ9
@@ -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
package/README.md CHANGED
@@ -13,7 +13,7 @@ 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
+ - **Phone + unified login**: `phonepass` provider for **registering** with phone + password (`POST /auth/customer/phonepass`); **login** is always `POST /auth/customer/emailpass` with `{ phone, password }` or `{ email, password }` depending on `login.identifier`
17
17
  - **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
18
 
19
19
  ## Quick Start
@@ -131,9 +131,11 @@ Controls which auth providers are accepted at login. Defaults to `registration.i
131
131
 
132
132
  | Value | Accepted login methods |
133
133
  |---|---|
134
- | `"email"` | `POST /auth/customer/emailpass` only |
135
- | `"phone"` | `POST /auth/customer/phonepass` only |
136
- | `"both"` | Both emailpass and phonepass accepted |
134
+ | `"email"` | `POST /auth/customer/emailpass` with `{ "email", "password" }` only |
135
+ | `"phone"` | Same endpoint with `{ "phone", "password" }` only |
136
+ | `"both"` | Same endpoint; **either** email **or** phone (not both) plus `password` in the JSON body |
137
+
138
+ All of the above use the **same URL**; there is no separate `/auth/customer/phonepass` **login** route in this plugin.
137
139
 
138
140
  ### Full options reference
139
141
 
@@ -223,14 +225,17 @@ POST /store/customers/otp/verify
223
225
 
224
226
  ---
225
227
 
226
- ### Login
228
+ ### Login & registration (customer auth)
229
+
230
+ Implementation lives under [`src/api/auth/customer/`](src/api/auth/customer/): **`emailpass/`** (login + password reset), **`phonepass/`** (phone **registration** only), **`shared/`** (unified login: parse body, merge body/query for `AuthenticationInput`, verification, JWT).
227
231
 
228
232
  | Endpoint | Method | Description |
229
233
  |---|---|---|
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 |
234
+ | `/auth/customer/emailpass` | POST | **Login.** JSON: `password` plus **exactly one** of `email` or `phone` (XOR), validated against `login.identifier`. Handler: [`emailpass/route.ts`](src/api/auth/customer/emailpass/route.ts) → [`handleCustomerLogin`](src/api/auth/customer/shared/customer-login-post.ts). |
235
+ | `/auth/customer/emailpass/register` | POST | Create **emailpass** identity (standard Medusa auth route; use when registering with email). |
236
+ | `/auth/customer/phonepass` | POST | Create **phonepass** identity only — [`phonepass/route.ts`](src/api/auth/customer/phonepass/route.ts). Returns a short-lived JWT for `POST /store/customers`. **Not** used for login. |
237
+
238
+ Password reset URLs are unchanged; see [Password Reset](#password-reset).
234
239
 
235
240
  ---
236
241
 
@@ -412,7 +417,7 @@ export default defineConfig({
412
417
 
413
418
  ```bash
414
419
  # Step 1 — create phonepass auth identity
415
- POST /auth/customer/phonepass/register
420
+ POST /auth/customer/phonepass
416
421
  { "phone": "+15551234567", "password": "SecretPass1!" }
417
422
  # Response: { "token": "<pre-customer jwt>" }
418
423
 
@@ -435,7 +440,7 @@ POST /store/customers/otp/verify
435
440
  ### 3. Login flow
436
441
 
437
442
  ```bash
438
- POST /auth/customer/phonepass
443
+ POST /auth/customer/emailpass
439
444
  { "phone": "+15551234567", "password": "SecretPass1!" }
440
445
  # Response: { "token": "<jwt>" }
441
446
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "customer-registration",
3
- "version": "0.0.114",
3
+ "version": "0.0.115",
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