customer-registration 0.0.111 → 0.0.113

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.
Files changed (50) hide show
  1. package/.medusa/server/src/admin/index.js +3249 -2
  2. package/.medusa/server/src/admin/index.mjs +3232 -2
  3. package/.medusa/server/src/api/admin/account-deletion-requests/route.js +30 -0
  4. package/.medusa/server/src/api/admin/account-deletion-requests/validators.js +12 -0
  5. package/.medusa/server/src/api/auth/customer/emailpass/reset-password/route.js +1 -26
  6. package/.medusa/server/src/api/auth/customer/emailpass/route.js +24 -97
  7. package/.medusa/server/src/api/auth/customer/phonepass/register/route.js +50 -0
  8. package/.medusa/server/src/api/auth/customer/phonepass/route.js +105 -0
  9. package/.medusa/server/src/api/middlewares/guard-account-deletion.js +29 -0
  10. package/.medusa/server/src/api/middlewares/ip-rate-limit.js +48 -0
  11. package/.medusa/server/src/api/middlewares/validate-customer-registration.js +60 -0
  12. package/.medusa/server/src/api/middlewares.js +30 -0
  13. package/.medusa/server/src/api/store/customers/account-deletion/cancel-confirm/route.js +36 -0
  14. package/.medusa/server/src/api/store/customers/account-deletion/cancel-request/route.js +55 -0
  15. package/.medusa/server/src/api/store/customers/account-deletion/confirm/route.js +43 -0
  16. package/.medusa/server/src/api/store/customers/account-deletion/request/route.js +40 -0
  17. package/.medusa/server/src/api/store/customers/account-deletion/validators.js +27 -0
  18. package/.medusa/server/src/api/store/customers/me/contact/route.js +95 -0
  19. package/.medusa/server/src/api/store/customers/me/contact/verify/route.js +83 -0
  20. package/.medusa/server/src/api/store/customers/me/route.js +53 -0
  21. package/.medusa/server/src/api/store/customers/otp/send/route.js +1 -6
  22. package/.medusa/server/src/api/store/customers/otp/verify/route.js +95 -3
  23. package/.medusa/server/src/api/store/customers/route.js +89 -0
  24. package/.medusa/server/src/config.js +44 -13
  25. package/.medusa/server/src/jobs/process-account-deletions.js +69 -0
  26. package/.medusa/server/src/modules/account-deletion-request/index.js +17 -0
  27. package/.medusa/server/src/modules/account-deletion-request/migrations/Migration20250221000000CreateAccountDeletionRequestTable.js +42 -0
  28. package/.medusa/server/src/modules/account-deletion-request/migrations/Migration20250221100000AddCompletedStatusToAccountDeletionRequest.js +30 -0
  29. package/.medusa/server/src/modules/account-deletion-request/models/account-deletion-request.js +26 -0
  30. package/.medusa/server/src/modules/account-deletion-request/service.js +90 -0
  31. package/.medusa/server/src/modules/otp-verification/migrations/Migration20250221000000AddAccountDeletionOtpPurposes.js +35 -0
  32. package/.medusa/server/src/modules/otp-verification/models/otp-verification.js +9 -2
  33. package/.medusa/server/src/modules/otp-verification/service.js +79 -1
  34. package/.medusa/server/src/providers/phonepass/index.js +9 -0
  35. package/.medusa/server/src/providers/phonepass/service.js +133 -0
  36. package/.medusa/server/src/subscribers/password-reset.js +1 -42
  37. package/.medusa/server/src/workflows/change-password.js +40 -64
  38. package/.medusa/server/src/workflows/send-contact-change-otp-workflow.js +41 -0
  39. package/.medusa/server/src/workflows/steps/determine-contact-method-step.js +8 -2
  40. package/.medusa/server/src/workflows/steps/generate-contact-change-otp-step.js +24 -0
  41. package/.medusa/server/src/workflows/steps/index.js +6 -2
  42. package/.medusa/server/src/workflows/steps/resolve-channel-config-step.js +10 -1
  43. package/.medusa/server/src/workflows/steps/send-notification-step.js +1 -11
  44. package/.medusa/server/src/workflows/steps/sync-phonepass-entity-id-step.js +63 -0
  45. package/.medusa/server/src/workflows/steps/update-password-step.js +21 -29
  46. package/.medusa/server/src/workflows/update-contact-workflow.js +100 -0
  47. package/.medusa/server/src/workflows/verify-phone.js +11 -4
  48. package/README.md +389 -147
  49. package/package.json +12 -3
  50. package/.medusa/server/src/subscribers/customer-updated.js +0 -100
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateCustomerRegistration = validateCustomerRegistration;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const config_1 = require("../../config");
6
+ const VALID_IDENTIFIERS = ["email", "phone", "both"];
7
+ const EMAIL_REGEX = /^\S+@\S+\.\S+$/;
8
+ const PHONE_REGEX = /^\+?[0-9]{8,15}$/;
9
+ /**
10
+ * Validates registration fields on `POST /store/customers` based on the
11
+ * plugin's `registration.identifier` config:
12
+ *
13
+ * - "email" → email required, format checked
14
+ * - "phone" → phone required, format checked
15
+ * - "both" → email and phone both required, both format-checked
16
+ *
17
+ * Format validation applies to any field that is present, regardless of
18
+ * whether it was required, so bad data is always rejected early.
19
+ */
20
+ async function validateCustomerRegistration(req, res, next) {
21
+ // Defensive guard — the matcher in middlewares.ts already limits to POST,
22
+ // but protect against accidental broader mounting.
23
+ if (req.method !== "POST") {
24
+ return next();
25
+ }
26
+ const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
27
+ const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
28
+ const identifier = options.registration.identifier;
29
+ // Fail fast if the config value is somehow outside the known set
30
+ if (!VALID_IDENTIFIERS.includes(identifier)) {
31
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Invalid registration identifier configuration: "${identifier}". Must be one of: ${VALID_IDENTIFIERS.join(", ")}`);
32
+ }
33
+ const { email, phone } = (req.body ?? {});
34
+ const emailNormalized = email?.trim() || undefined;
35
+ const phoneNormalized = phone?.trim() || undefined;
36
+ // --- Presence checks (identifier-specific) ---
37
+ if (identifier === "email" && !emailNormalized) {
38
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Email is required for registration");
39
+ }
40
+ if (identifier === "phone" && !phoneNormalized) {
41
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Phone is required for registration");
42
+ }
43
+ if (identifier === "both") {
44
+ if (!emailNormalized) {
45
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Email is required for registration");
46
+ }
47
+ if (!phoneNormalized) {
48
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Phone is required for registration");
49
+ }
50
+ }
51
+ // --- Format checks (applied to any field that is present) ---
52
+ if (emailNormalized && !EMAIL_REGEX.test(emailNormalized)) {
53
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid email format");
54
+ }
55
+ if (phoneNormalized && !PHONE_REGEX.test(phoneNormalized)) {
56
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid phone number format. Must be 8–15 digits, optionally prefixed with +");
57
+ }
58
+ next();
59
+ }
60
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUtY3VzdG9tZXItcmVnaXN0cmF0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9taWRkbGV3YXJlcy92YWxpZGF0ZS1jdXN0b21lci1yZWdpc3RyYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUEyQkEsb0VBaUZDO0FBdkdELHFEQUFrRjtBQUNsRix5Q0FHcUI7QUFFckIsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFVLENBQUE7QUFFN0QsTUFBTSxXQUFXLEdBQUcsZ0JBQWdCLENBQUE7QUFDcEMsTUFBTSxXQUFXLEdBQUcsa0JBQWtCLENBQUE7QUFFdEM7Ozs7Ozs7Ozs7R0FVRztBQUNJLEtBQUssVUFBVSw0QkFBNEIsQ0FDaEQsR0FBa0IsRUFDbEIsR0FBbUIsRUFDbkIsSUFBd0I7SUFFeEIsMEVBQTBFO0lBQzFFLG1EQUFtRDtJQUNuRCxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssTUFBTSxFQUFFLENBQUM7UUFDMUIsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUNmLENBQUM7SUFFRCxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDcEMsaUNBQXlCLENBQUMsYUFBYSxDQUN4QyxDQUFBO0lBQ0QsTUFBTSxPQUFPLEdBQUcsSUFBQSwyQ0FBa0MsRUFBQyxZQUFZLENBQUMsQ0FBQTtJQUNoRSxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQTtJQUVsRCxpRUFBaUU7SUFDakUsSUFBSSxDQUFFLGlCQUF1QyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ25FLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG1EQUFtRCxVQUFVLHNCQUFzQixpQkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDbEgsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBR3ZDLENBQUE7SUFFRCxNQUFNLGVBQWUsR0FBRyxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksU0FBUyxDQUFBO0lBQ2xELE1BQU0sZUFBZSxHQUFHLEtBQUssRUFBRSxJQUFJLEVBQUUsSUFBSSxTQUFTLENBQUE7SUFFbEQsZ0RBQWdEO0lBRWhELElBQUksVUFBVSxLQUFLLE9BQU8sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQy9DLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG9DQUFvQyxDQUNyQyxDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksVUFBVSxLQUFLLE9BQU8sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQy9DLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG9DQUFvQyxDQUNyQyxDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksVUFBVSxLQUFLLE1BQU0sRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNyQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixvQ0FBb0MsQ0FDckMsQ0FBQTtRQUNILENBQUM7UUFDRCxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDckIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsb0NBQW9DLENBQ3JDLENBQUE7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELCtEQUErRDtJQUUvRCxJQUFJLGVBQWUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUMxRCxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixzQkFBc0IsQ0FDdkIsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLGVBQWUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUMxRCxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw4RUFBOEUsQ0FDL0UsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLEVBQUUsQ0FBQTtBQUNSLENBQUMifQ==
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const http_1 = require("@medusajs/framework/http");
4
+ const guard_account_deletion_1 = require("./middlewares/guard-account-deletion");
5
+ const validate_customer_registration_1 = require("./middlewares/validate-customer-registration");
6
+ const ip_rate_limit_1 = require("./middlewares/ip-rate-limit");
7
+ exports.default = (0, http_1.defineMiddlewares)({
8
+ routes: [
9
+ {
10
+ matcher: "/auth/customer/*",
11
+ middlewares: [guard_account_deletion_1.guardAccountDeletion],
12
+ },
13
+ {
14
+ matcher: "/store/*",
15
+ middlewares: [guard_account_deletion_1.guardAccountDeletion],
16
+ },
17
+ {
18
+ matcher: "/store/customers",
19
+ method: ["POST"],
20
+ middlewares: [validate_customer_registration_1.validateCustomerRegistration],
21
+ },
22
+ {
23
+ // Unauthenticated endpoint — rate-limit per IP to prevent OTP spam
24
+ matcher: "/store/customers/account-deletion/cancel-request",
25
+ method: ["POST"],
26
+ middlewares: [(0, ip_rate_limit_1.ipRateLimit)({ max: 5, windowMs: 60_000 })],
27
+ },
28
+ ],
29
+ });
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXBpL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbURBQTREO0FBQzVELGlGQUEyRTtBQUMzRSxpR0FBMkY7QUFDM0YsK0RBQXlEO0FBRXpELGtCQUFlLElBQUEsd0JBQWlCLEVBQUM7SUFDL0IsTUFBTSxFQUFFO1FBQ047WUFDRSxPQUFPLEVBQUUsa0JBQWtCO1lBQzNCLFdBQVcsRUFBRSxDQUFDLDZDQUFvQixDQUFDO1NBQ3BDO1FBQ0Q7WUFDRSxPQUFPLEVBQUUsVUFBVTtZQUNuQixXQUFXLEVBQUUsQ0FBQyw2Q0FBb0IsQ0FBQztTQUNwQztRQUNEO1lBQ0UsT0FBTyxFQUFFLGtCQUFrQjtZQUMzQixNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUM7WUFDaEIsV0FBVyxFQUFFLENBQUMsNkRBQTRCLENBQUM7U0FDNUM7UUFDRDtZQUNFLG1FQUFtRTtZQUNuRSxPQUFPLEVBQUUsa0RBQWtEO1lBQzNELE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQztZQUNoQixXQUFXLEVBQUUsQ0FBQyxJQUFBLDJCQUFXLEVBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1NBQ3pEO0tBQ0Y7Q0FDRixDQUFDLENBQUEifQ==
@@ -0,0 +1,36 @@
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 otp_verification_1 = require("../../../../../modules/otp-verification");
6
+ const otp_verification_2 = require("../../../../../modules/otp-verification/models/otp-verification");
7
+ const account_deletion_request_1 = require("../../../../../modules/account-deletion-request");
8
+ const validators_1 = require("../validators");
9
+ const POST = async (req, res) => {
10
+ const parsed = validators_1.ConfirmCancelSchema.safeParse(req.body ?? {});
11
+ if (!parsed.success) {
12
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, parsed.error.errors.map((e) => e.message).join("; ") || "Invalid input");
13
+ }
14
+ const { token, code } = parsed.data;
15
+ const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
16
+ const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
17
+ const jwtSecret = config?.projectConfig?.http
18
+ ?.jwtSecret || "supersecret";
19
+ const verifyResult = await otpService.verifyOtp({ token, code }, jwtSecret);
20
+ if (verifyResult.type !== otp_verification_2.OtpPurpose.ACCOUNT_DELETION_CANCEL) {
21
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid verification type for cancel confirmation");
22
+ }
23
+ const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
24
+ const request = await accountDeletionService.cancelRequest(verifyResult.customer_id);
25
+ return res.status(200).json({
26
+ cancelled: true,
27
+ request: {
28
+ id: request.id,
29
+ customer_id: request.customer_id,
30
+ status: request.status,
31
+ cancelled_at: request.cancelled_at,
32
+ },
33
+ });
34
+ };
35
+ exports.POST = POST;
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9hY2NvdW50LWRlbGV0aW9uL2NhbmNlbC1jb25maXJtL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUdrQztBQUNsQyw4RUFBaUY7QUFFakYsc0dBQTRGO0FBQzVGLDhGQUFpRztBQUVqRyw4Q0FBbUQ7QUFFNUMsTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLGdDQUFtQixDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQzVELElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLGVBQWUsQ0FDeEUsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUE7SUFFbkMsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ2xDLDBDQUF1QixDQUN4QixDQUFBO0lBQ0QsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsYUFBYSxDQUFDLENBQUE7SUFDekUsTUFBTSxTQUFTLEdBQ1osTUFBTSxFQUFFLGFBQW1ELEVBQUUsSUFBSTtRQUNoRSxFQUFFLFNBQVMsSUFBSSxhQUFhLENBQUE7SUFFaEMsTUFBTSxZQUFZLEdBQUcsTUFBTSxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLFNBQVMsQ0FBQyxDQUFBO0lBRTNFLElBQUksWUFBWSxDQUFDLElBQUksS0FBSyw2QkFBVSxDQUFDLHVCQUF1QixFQUFFLENBQUM7UUFDN0QsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsbURBQW1ELENBQ3BELENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDOUMsMERBQStCLENBQ2hDLENBQUE7SUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLHNCQUFzQixDQUFDLGFBQWEsQ0FDeEQsWUFBWSxDQUFDLFdBQVcsQ0FDekIsQ0FBQTtJQUVELE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDMUIsU0FBUyxFQUFFLElBQUk7UUFDZixPQUFPLEVBQUU7WUFDUCxFQUFFLEVBQUUsT0FBTyxDQUFDLEVBQUU7WUFDZCxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVc7WUFDaEMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1lBQ3RCLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtTQUNuQztLQUNGLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQTtBQTdDWSxRQUFBLElBQUksUUE2Q2hCIn0=
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.POST = void 0;
7
+ const utils_1 = require("@medusajs/framework/utils");
8
+ const account_deletion_request_1 = require("../../../../../modules/account-deletion-request");
9
+ const otp_verification_1 = require("../../../../../modules/otp-verification/models/otp-verification");
10
+ const send_otp_workflow_1 = __importDefault(require("../../../../../workflows/send-otp-workflow"));
11
+ const validators_1 = require("../validators");
12
+ const POST = async (req, res) => {
13
+ const parsed = validators_1.CancelRequestSchema.safeParse(req.body ?? {});
14
+ if (!parsed.success) {
15
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, parsed.error.errors.map((e) => e.message).join("; ") || "Invalid input");
16
+ }
17
+ const { email, phone } = parsed.data;
18
+ const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
19
+ if (!knex) {
20
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Database connection not available");
21
+ }
22
+ let customerId;
23
+ if (email) {
24
+ const result = await knex.raw(`SELECT id FROM customer WHERE email = ? LIMIT 1`, [email.toLowerCase().trim()]);
25
+ const row = result.rows?.[0] ?? result[0]?.[0];
26
+ customerId = row?.id;
27
+ }
28
+ else if (phone) {
29
+ const result = await knex.raw(`SELECT id FROM customer WHERE phone = ? LIMIT 1`, [phone.trim()]);
30
+ const row = result.rows?.[0] ?? result[0]?.[0];
31
+ customerId = row?.id;
32
+ }
33
+ if (!customerId) {
34
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, email
35
+ ? "Customer not found with this email"
36
+ : "Customer not found with this phone number");
37
+ }
38
+ const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
39
+ const active = await accountDeletionService.getActiveByCustomerId(customerId);
40
+ if (!active) {
41
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "No active deletion request found for this customer");
42
+ }
43
+ const { result: workflowResult } = await (0, send_otp_workflow_1.default)(req.scope).run({
44
+ input: {
45
+ customer_id: customerId,
46
+ type: otp_verification_1.OtpPurpose.ACCOUNT_DELETION_CANCEL,
47
+ },
48
+ });
49
+ return res.status(200).json({
50
+ token: workflowResult.token,
51
+ expires_at: workflowResult.expires_at,
52
+ });
53
+ };
54
+ exports.POST = POST;
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9hY2NvdW50LWRlbGV0aW9uL2NhbmNlbC1yZXF1ZXN0L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUNBLHFEQUdrQztBQUNsQyw4RkFBaUc7QUFFakcsc0dBQTRGO0FBQzVGLG1HQUF3RTtBQUN4RSw4Q0FBbUQ7QUFFNUMsTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLGdDQUFtQixDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQzVELElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLGVBQWUsQ0FDeEUsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUE7SUFFcEMsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsYUFBYSxDQUFDLENBQUE7SUFDdkUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLGdCQUFnQixFQUNsQyxtQ0FBbUMsQ0FDcEMsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLFVBQThCLENBQUE7SUFFbEMsSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUNWLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FDM0IsaURBQWlELEVBQ2pELENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLENBQzdCLENBQUE7UUFDRCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDOUMsVUFBVSxHQUFHLEdBQUcsRUFBRSxFQUFFLENBQUE7SUFDdEIsQ0FBQztTQUFNLElBQUksS0FBSyxFQUFFLENBQUM7UUFDakIsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsR0FBRyxDQUMzQixpREFBaUQsRUFDakQsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FDZixDQUFBO1FBQ0QsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQzlDLFVBQVUsR0FBRyxHQUFHLEVBQUUsRUFBRSxDQUFBO0lBQ3RCLENBQUM7SUFFRCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFDM0IsS0FBSztZQUNILENBQUMsQ0FBQyxvQ0FBb0M7WUFDdEMsQ0FBQyxDQUFDLDJDQUEyQyxDQUNoRCxDQUFBO0lBQ0gsQ0FBQztJQUVELE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQzlDLDBEQUErQixDQUNoQyxDQUFBO0lBRUQsTUFBTSxNQUFNLEdBQUcsTUFBTSxzQkFBc0IsQ0FBQyxxQkFBcUIsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUM3RSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUMzQixvREFBb0QsQ0FDckQsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRSxHQUFHLE1BQU0sSUFBQSwyQkFBZSxFQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7UUFDdEUsS0FBSyxFQUFFO1lBQ0wsV0FBVyxFQUFFLFVBQVU7WUFDdkIsSUFBSSxFQUFFLDZCQUFVLENBQUMsdUJBQXVCO1NBQ3pDO0tBQ0YsQ0FBQyxDQUFBO0lBRUYsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUMxQixLQUFLLEVBQUUsY0FBYyxDQUFDLEtBQUs7UUFDM0IsVUFBVSxFQUFFLGNBQWMsQ0FBQyxVQUFVO0tBQ3RDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQTtBQXJFWSxRQUFBLElBQUksUUFxRWhCIn0=
@@ -0,0 +1,43 @@
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 otp_verification_1 = require("../../../../../modules/otp-verification");
6
+ const otp_verification_2 = require("../../../../../modules/otp-verification/models/otp-verification");
7
+ const account_deletion_request_1 = require("../../../../../modules/account-deletion-request");
8
+ const config_1 = require("../../../../../config");
9
+ const validators_1 = require("../validators");
10
+ const DEFAULT_SCHEDULED_DAYS = 7;
11
+ const POST = async (req, res) => {
12
+ const parsed = validators_1.ConfirmDeletionSchema.safeParse(req.body ?? {});
13
+ if (!parsed.success) {
14
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, parsed.error.errors.map((e) => e.message).join("; ") || "Invalid input");
15
+ }
16
+ const { token, code } = parsed.data;
17
+ const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
18
+ const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
19
+ const jwtSecret = config?.projectConfig?.http
20
+ ?.jwtSecret || "supersecret";
21
+ const verifyResult = await otpService.verifyOtp({ token, code }, jwtSecret);
22
+ if (verifyResult.type !== otp_verification_2.OtpPurpose.ACCOUNT_DELETION_REQUEST) {
23
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid verification type for account deletion confirmation");
24
+ }
25
+ const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
26
+ const pluginOptions = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
27
+ const scheduledDays = pluginOptions?.account_deletion_request?.scheduled_days ??
28
+ DEFAULT_SCHEDULED_DAYS;
29
+ const deletion_scheduled_at = new Date(Date.now() + scheduledDays * 24 * 60 * 60 * 1000);
30
+ const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
31
+ const request = await accountDeletionService.createConfirmed(verifyResult.customer_id, deletion_scheduled_at);
32
+ return res.status(200).json({
33
+ request: {
34
+ id: request.id,
35
+ customer_id: request.customer_id,
36
+ reason: request.reason,
37
+ deletion_scheduled_at: request.deletion_scheduled_at,
38
+ status: request.status,
39
+ },
40
+ });
41
+ };
42
+ exports.POST = POST;
43
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9hY2NvdW50LWRlbGV0aW9uL2NvbmZpcm0vcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EscURBR2tDO0FBQ2xDLDhFQUFpRjtBQUVqRixzR0FBNEY7QUFDNUYsOEZBQWlHO0FBRWpHLGtEQUEwRTtBQUUxRSw4Q0FBcUQ7QUFFckQsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLENBQUE7QUFFekIsTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLGtDQUFxQixDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQzlELElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLGVBQWUsQ0FDeEUsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUE7SUFFbkMsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ2xDLDBDQUF1QixDQUN4QixDQUFBO0lBQ0QsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsYUFBYSxDQUFDLENBQUE7SUFDekUsTUFBTSxTQUFTLEdBQ1osTUFBTSxFQUFFLGFBQW1ELEVBQUUsSUFBSTtRQUNoRSxFQUFFLFNBQVMsSUFBSSxhQUFhLENBQUE7SUFFaEMsTUFBTSxZQUFZLEdBQUcsTUFBTSxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLFNBQVMsQ0FBQyxDQUFBO0lBRTNFLElBQUksWUFBWSxDQUFDLElBQUksS0FBSyw2QkFBVSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDOUQsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFlBQVksRUFDOUIsNkRBQTZELENBQzlELENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxZQUFZLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQ3BDLGlDQUF5QixDQUFDLGFBQWEsQ0FDbkIsQ0FBQTtJQUN0QixNQUFNLGFBQWEsR0FBRyxJQUFBLDJDQUFrQyxFQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ3RFLE1BQU0sYUFBYSxHQUNqQixhQUFhLEVBQUUsd0JBQXdCLEVBQUUsY0FBYztRQUN2RCxzQkFBc0IsQ0FBQTtJQUN4QixNQUFNLHFCQUFxQixHQUFHLElBQUksSUFBSSxDQUNwQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsYUFBYSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FDakQsQ0FBQTtJQUVELE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQzlDLDBEQUErQixDQUNoQyxDQUFBO0lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxzQkFBc0IsQ0FBQyxlQUFlLENBQzFELFlBQVksQ0FBQyxXQUFXLEVBQ3hCLHFCQUFxQixDQUN0QixDQUFBO0lBRUQsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUMxQixPQUFPLEVBQUU7WUFDUCxFQUFFLEVBQUUsT0FBTyxDQUFDLEVBQUU7WUFDZCxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVc7WUFDaEMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1lBQ3RCLHFCQUFxQixFQUFFLE9BQU8sQ0FBQyxxQkFBcUI7WUFDcEQsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1NBQ3ZCO0tBQ0YsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBekRZLFFBQUEsSUFBSSxRQXlEaEIifQ==
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.POST = void 0;
7
+ const utils_1 = require("@medusajs/framework/utils");
8
+ const account_deletion_request_1 = require("../../../../../modules/account-deletion-request");
9
+ const otp_verification_1 = require("../../../../../modules/otp-verification/models/otp-verification");
10
+ const send_otp_workflow_1 = __importDefault(require("../../../../../workflows/send-otp-workflow"));
11
+ const validators_1 = require("../validators");
12
+ const POST = async (req, res) => {
13
+ const authContext = req
14
+ .auth_context;
15
+ const customerId = authContext?.actor_id ?? authContext?.user_id;
16
+ if (!customerId) {
17
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Authentication required");
18
+ }
19
+ const parsed = validators_1.RequestDeletionSchema.safeParse(req.body ?? {});
20
+ if (!parsed.success) {
21
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, parsed.error.errors.map((e) => e.message).join("; ") || "Invalid input");
22
+ }
23
+ const accountDeletionService = req.scope.resolve(account_deletion_request_1.ACCOUNT_DELETION_REQUEST_MODULE);
24
+ const active = await accountDeletionService.getActiveByCustomerId(customerId);
25
+ if (active) {
26
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "An active deletion request already exists. Cancel it first.");
27
+ }
28
+ const { result } = await (0, send_otp_workflow_1.default)(req.scope).run({
29
+ input: {
30
+ customer_id: customerId,
31
+ type: otp_verification_1.OtpPurpose.ACCOUNT_DELETION_REQUEST,
32
+ },
33
+ });
34
+ return res.status(200).json({
35
+ token: result.token,
36
+ expires_at: result.expires_at,
37
+ });
38
+ };
39
+ exports.POST = POST;
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9hY2NvdW50LWRlbGV0aW9uL3JlcXVlc3Qvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EscURBQXVEO0FBQ3ZELDhGQUFpRztBQUVqRyxzR0FBNEY7QUFDNUYsbUdBQXdFO0FBQ3hFLDhDQUFxRDtBQUU5QyxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDcEUsTUFBTSxXQUFXLEdBQUksR0FBa0U7U0FDcEYsWUFBWSxDQUFBO0lBQ2YsTUFBTSxVQUFVLEdBQUcsV0FBVyxFQUFFLFFBQVEsSUFBSSxXQUFXLEVBQUUsT0FBTyxDQUFBO0lBRWhFLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNoQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qix5QkFBeUIsQ0FDMUIsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLE1BQU0sR0FBRyxrQ0FBcUIsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUM5RCxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3BCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxlQUFlLENBQ3hFLENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDOUMsMERBQStCLENBQ2hDLENBQUE7SUFFRCxNQUFNLE1BQU0sR0FBRyxNQUFNLHNCQUFzQixDQUFDLHFCQUFxQixDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQzdFLElBQUksTUFBTSxFQUFFLENBQUM7UUFDWCxNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw2REFBNkQsQ0FDOUQsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLDJCQUFlLEVBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQztRQUN0RCxLQUFLLEVBQUU7WUFDTCxXQUFXLEVBQUUsVUFBVTtZQUN2QixJQUFJLEVBQUUsNkJBQVUsQ0FBQyx3QkFBd0I7U0FDMUM7S0FDRixDQUFDLENBQUE7SUFFRixPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQzFCLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSztRQUNuQixVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVU7S0FDOUIsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBM0NZLFFBQUEsSUFBSSxRQTJDaEIifQ==
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfirmCancelSchema = exports.CancelRequestSchema = exports.ConfirmDeletionSchema = exports.RequestDeletionSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.RequestDeletionSchema = zod_1.z.object({
6
+ reason: zod_1.z.string().max(2000).optional().nullable(),
7
+ });
8
+ exports.ConfirmDeletionSchema = zod_1.z.object({
9
+ token: zod_1.z.string().min(1, "Token is required"),
10
+ code: zod_1.z.string().min(1, "OTP code is required"),
11
+ });
12
+ exports.CancelRequestSchema = zod_1.z
13
+ .object({
14
+ email: zod_1.z.string().email("Valid email address").optional(),
15
+ phone: zod_1.z
16
+ .string()
17
+ .regex(/^\+?[0-9]{8,15}$/, "Invalid phone number format")
18
+ .optional(),
19
+ })
20
+ .refine((data) => data.email || data.phone, {
21
+ message: "Either email or phone is required",
22
+ });
23
+ exports.ConfirmCancelSchema = zod_1.z.object({
24
+ token: zod_1.z.string().min(1, "Token is required"),
25
+ code: zod_1.z.string().min(1, "OTP code is required"),
26
+ });
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvc3RvcmUvY3VzdG9tZXJzL2FjY291bnQtZGVsZXRpb24vdmFsaWRhdG9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2QkFBdUI7QUFFVixRQUFBLHFCQUFxQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDNUMsTUFBTSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0NBQ25ELENBQUMsQ0FBQTtBQUVXLFFBQUEscUJBQXFCLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUM1QyxLQUFLLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsbUJBQW1CLENBQUM7SUFDN0MsSUFBSSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLHNCQUFzQixDQUFDO0NBQ2hELENBQUMsQ0FBQTtBQUVXLFFBQUEsbUJBQW1CLEdBQUcsT0FBQztLQUNqQyxNQUFNLENBQUM7SUFDTixLQUFLLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLFFBQVEsRUFBRTtJQUN6RCxLQUFLLEVBQUUsT0FBQztTQUNMLE1BQU0sRUFBRTtTQUNSLEtBQUssQ0FBQyxrQkFBa0IsRUFBRSw2QkFBNkIsQ0FBQztTQUN4RCxRQUFRLEVBQUU7Q0FDZCxDQUFDO0tBQ0QsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUU7SUFDMUMsT0FBTyxFQUFFLG1DQUFtQztDQUM3QyxDQUFDLENBQUE7QUFFUyxRQUFBLG1CQUFtQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDMUMsS0FBSyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLG1CQUFtQixDQUFDO0lBQzdDLElBQUksRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxzQkFBc0IsQ0FBQztDQUNoRCxDQUFDLENBQUEifQ==
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.POST = void 0;
7
+ const utils_1 = require("@medusajs/framework/utils");
8
+ const otp_verification_1 = require("../../../../../modules/otp-verification/models/otp-verification");
9
+ const config_1 = require("../../../../../config");
10
+ const send_contact_change_otp_workflow_1 = __importDefault(require("../../../../../workflows/send-contact-change-otp-workflow"));
11
+ const EMAIL_REGEX = /^\S+@\S+\.\S+$/;
12
+ const PHONE_REGEX = /^\+?[0-9]{8,15}$/;
13
+ /**
14
+ * POST /store/customers/me/contact
15
+ *
16
+ * Authenticated endpoint for requesting a phone or email change.
17
+ * Validates the new value, checks for duplicates, generates an OTP with the
18
+ * new_value embedded in the signed JWT (no metadata staging), sends the OTP
19
+ * to the new contact, and returns the token + expiry for use at /verify.
20
+ *
21
+ * Request body (exactly one field required):
22
+ * { phone: string } | { email: string }
23
+ */
24
+ const POST = async (req, res) => {
25
+ const customerId = req.auth_context.actor_id;
26
+ const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
27
+ const options = (0, config_1.resolveCustomerRegistrationOptions)(configModule);
28
+ const { phone: rawPhone, email: rawEmail } = (req.body ?? {});
29
+ const phone = rawPhone?.trim() || undefined;
30
+ const email = rawEmail?.trim() || undefined;
31
+ if (!phone && !email) {
32
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Either phone or email is required");
33
+ }
34
+ if (phone && email) {
35
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Only one of phone or email can be changed at a time");
36
+ }
37
+ const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
38
+ const customerService = req.scope.resolve(utils_1.Modules.CUSTOMER);
39
+ const customer = await customerService.retrieveCustomer(customerId);
40
+ if (phone) {
41
+ if (!PHONE_REGEX.test(phone)) {
42
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid phone number format. Must be 8–15 digits, optionally prefixed with +");
43
+ }
44
+ if (phone === customer.phone) {
45
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "New phone number is the same as the current one");
46
+ }
47
+ // Reject if login.identifier doesn't support phone
48
+ if (options.login.identifier !== "phone" &&
49
+ options.login.identifier !== "both") {
50
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Phone-based login is not enabled for this store");
51
+ }
52
+ // Duplicate check
53
+ const existing = await knex.raw(`SELECT id FROM customer WHERE phone = ? AND has_account = true LIMIT 1`, [phone]);
54
+ if (existing.rows?.[0] ?? existing[0]?.[0]) {
55
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.DUPLICATE_ERROR, "A customer with this phone number already exists");
56
+ }
57
+ const { result } = await (0, send_contact_change_otp_workflow_1.default)(req.scope).run({
58
+ input: {
59
+ customer_id: customerId,
60
+ new_value: phone,
61
+ contact_type: "phone",
62
+ otp_type: otp_verification_1.OtpPurpose.PHONE_VERIFICATION,
63
+ },
64
+ });
65
+ return res.status(200).json({ token: result.token, expires_at: result.expires_at });
66
+ }
67
+ // email branch
68
+ if (!EMAIL_REGEX.test(email)) {
69
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Invalid email format");
70
+ }
71
+ if (email === customer.email) {
72
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "New email is the same as the current one");
73
+ }
74
+ // Reject if login.identifier doesn't support email
75
+ if (options.login.identifier !== "email" &&
76
+ options.login.identifier !== "both") {
77
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Email-based login is not enabled for this store");
78
+ }
79
+ // Duplicate check
80
+ const existingEmail = await knex.raw(`SELECT id FROM customer WHERE email = ? AND has_account = true LIMIT 1`, [email]);
81
+ if (existingEmail.rows?.[0] ?? existingEmail[0]?.[0]) {
82
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.DUPLICATE_ERROR, "A customer with this email already exists");
83
+ }
84
+ const { result } = await (0, send_contact_change_otp_workflow_1.default)(req.scope).run({
85
+ input: {
86
+ customer_id: customerId,
87
+ new_value: email,
88
+ contact_type: "email",
89
+ otp_type: otp_verification_1.OtpPurpose.EMAIL_VERIFICATION,
90
+ },
91
+ });
92
+ return res.status(200).json({ token: result.token, expires_at: result.expires_at });
93
+ };
94
+ exports.POST = POST;
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9tZS9jb250YWN0L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUNBLHFEQUlrQztBQUVsQyxzR0FBNEY7QUFDNUYsa0RBRzhCO0FBQzlCLGlJQUFvRztBQUVwRyxNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQTtBQUNwQyxNQUFNLFdBQVcsR0FBRyxrQkFBa0IsQ0FBQTtBQUV0Qzs7Ozs7Ozs7OztHQVVHO0FBQ0ksTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUN2QixHQUErQixFQUMvQixHQUFtQixFQUNuQixFQUFFO0lBQ0YsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUE7SUFFNUMsTUFBTSxZQUFZLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsYUFBYSxDQUFDLENBQUE7SUFDL0UsTUFBTSxPQUFPLEdBQUcsSUFBQSwyQ0FBa0MsRUFBQyxZQUFpQyxDQUFDLENBQUE7SUFFckYsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBRzNELENBQUE7SUFFRCxNQUFNLEtBQUssR0FBRyxRQUFRLEVBQUUsSUFBSSxFQUFFLElBQUksU0FBUyxDQUFBO0lBQzNDLE1BQU0sS0FBSyxHQUFHLFFBQVEsRUFBRSxJQUFJLEVBQUUsSUFBSSxTQUFTLENBQUE7SUFFM0MsSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3JCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG1DQUFtQyxDQUNwQyxDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksS0FBSyxJ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
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.POST = void 0;
7
+ const utils_1 = require("@medusajs/framework/utils");
8
+ const generate_jwt_token_1 = require("@medusajs/medusa/api/auth/utils/generate-jwt-token");
9
+ const otp_verification_1 = require("../../../../../../modules/otp-verification");
10
+ const config_1 = require("../../../../../../config");
11
+ const update_contact_workflow_1 = __importDefault(require("../../../../../../workflows/update-contact-workflow"));
12
+ /**
13
+ * POST /store/customers/me/contact/verify
14
+ *
15
+ * Authenticated endpoint for confirming a phone or email change.
16
+ *
17
+ * 1. Decodes the JWT from /store/customers/me/contact — extracts new_value
18
+ * and contact_type without any database lookup.
19
+ * 2. Validates the OTP code against the stored hashed record.
20
+ * 3. Runs updateContactWorkflow which atomically:
21
+ * - Writes new_value to customer.phone / customer.email
22
+ * - Sets phone_verified / email_verified = true
23
+ * - Updates provider_identity.entity_id (phonepass / emailpass) when the
24
+ * changed field is the active login identifier.
25
+ * 4. Returns the updated customer + a fresh JWT so the caller is immediately
26
+ * re-authenticated with the new identity.
27
+ *
28
+ * Request body: { token: string; code: string }
29
+ */
30
+ const POST = async (req, res) => {
31
+ const customerId = req.auth_context.actor_id;
32
+ const { token, code } = (req.body ?? {});
33
+ if (!token) {
34
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "token is required");
35
+ }
36
+ if (!code) {
37
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "code is required");
38
+ }
39
+ const config = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
40
+ const { http } = config.projectConfig;
41
+ const jwtSecret = http?.jwtSecret || "supersecret";
42
+ const otpService = req.scope.resolve(otp_verification_1.OTP_VERIFICATION_MODULE);
43
+ // Decode the contact-change JWT — new_value lives here, not in metadata
44
+ const decoded = otpService.decodeContactChangeToken(token, jwtSecret);
45
+ // Ensure the token belongs to the authenticated customer
46
+ if (decoded.customer_id !== customerId) {
47
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNAUTHORIZED, "Token does not match the authenticated customer");
48
+ }
49
+ // Validate the OTP record (expiry, attempts, already-used)
50
+ // and verify the submitted code against the stored hash.
51
+ // These are the same private-method-backed operations used by verifyOtp().
52
+ await otpService.verifyOtp({ token, code }, jwtSecret);
53
+ const options = (0, config_1.resolveCustomerRegistrationOptions)(config);
54
+ const { result } = await (0, update_contact_workflow_1.default)(req.scope).run({
55
+ input: {
56
+ customer_id: customerId,
57
+ new_value: decoded.new_value,
58
+ contact_type: decoded.contact_type,
59
+ login_identifier: options.login.identifier,
60
+ },
61
+ });
62
+ // Generate a fresh login token so the caller stays authenticated
63
+ let loginToken;
64
+ try {
65
+ const knex = req.scope.resolve(utils_1.ContainerRegistrationKeys.PG_CONNECTION);
66
+ const authRow = await knex.raw(`SELECT id FROM auth_identity WHERE app_metadata->>'customer_id' = ? LIMIT 1`, [customerId]);
67
+ const authIdentityId = (authRow.rows?.[0] ?? authRow[0]?.[0])?.id;
68
+ if (authIdentityId) {
69
+ const authService = req.scope.resolve(utils_1.Modules.AUTH);
70
+ const authIdentity = await authService.retrieveAuthIdentity(authIdentityId);
71
+ loginToken = await (0, generate_jwt_token_1.generateJwtTokenForAuthIdentity)({ authIdentity, actorType: "customer" }, { secret: jwtSecret, expiresIn: http.jwtExpiresIn || "7d" });
72
+ }
73
+ }
74
+ catch {
75
+ // Token generation is best-effort; the contact update already succeeded
76
+ }
77
+ return res.status(200).json({
78
+ customer: result.customer,
79
+ token: loginToken ?? null,
80
+ });
81
+ };
82
+ exports.POST = POST;
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9tZS9jb250YWN0L3ZlcmlmeS9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxxREFJa0M7QUFDbEMsMkZBQW9HO0FBQ3BHLGlGQUFvRjtBQUVwRixxREFHaUM7QUFDakMsa0hBQXVGO0FBRXZGOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUNJLE1BQU0sSUFBSSxHQUFHLEtBQUssRUFDdkIsR0FBK0IsRUFDL0IsR0FBbUIsRUFDbkIsRUFBRTtJQUNGLE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFBO0lBRTVDLE1BQU0sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBc0MsQ0FBQTtJQUU3RSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDWCxNQUFNLElBQUksbUJBQVcsQ0FBQyxtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQUUsbUJBQW1CLENBQUMsQ0FBQTtJQUM1RSxDQUFDO0lBQ0QsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLG1CQUFXLENBQUMsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUFFLGtCQUFrQixDQUFDLENBQUE7SUFDM0UsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBQ3pFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFBO0lBQ3JDLE1BQU0sU0FBUyxHQUFJLElBQUksRUFBRSxTQUFnQyxJQUFJLGFBQWEsQ0FBQTtJQUUxRSxNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsS0FBSyxD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
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PATCH = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ /**
6
+ * Override of Medusa's built-in PATCH /store/customers/me.
7
+ *
8
+ * Phone and email changes require OTP verification and must go through the
9
+ * dedicated endpoint:
10
+ * POST /store/customers/me/contact — request the change + receive OTP token
11
+ * POST /store/customers/me/contact/verify — submit OTP code to apply the change
12
+ *
13
+ * All other profile fields (first_name, last_name, etc.) are applied directly
14
+ * via the customer service, matching Medusa's default behaviour.
15
+ */
16
+ const PATCH = async (req, res) => {
17
+ const customerId = req.auth_context.actor_id;
18
+ const body = (req.body ?? {});
19
+ if (body.phone !== undefined) {
20
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Phone changes require OTP verification. Use POST /store/customers/me/contact to request a change.");
21
+ }
22
+ if (body.email !== undefined) {
23
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Email changes require OTP verification. Use POST /store/customers/me/contact to request a change.");
24
+ }
25
+ const customerService = req.scope.resolve(utils_1.Modules.CUSTOMER);
26
+ if (Object.keys(body).length > 0) {
27
+ await customerService.updateCustomers(customerId, body);
28
+ }
29
+ const updated = await refetchCustomer(customerId, req.scope);
30
+ return res.status(200).json({ customer: updated });
31
+ };
32
+ exports.PATCH = PATCH;
33
+ async function refetchCustomer(customerId, scope) {
34
+ const remoteQuery = scope.resolve(utils_1.ContainerRegistrationKeys.REMOTE_QUERY);
35
+ const queryObject = (0, utils_1.remoteQueryObjectFromString)({
36
+ entryPoint: "customer",
37
+ variables: { filters: { id: customerId } },
38
+ fields: [
39
+ "id",
40
+ "email",
41
+ "first_name",
42
+ "last_name",
43
+ "phone",
44
+ "has_account",
45
+ "metadata",
46
+ "created_at",
47
+ "updated_at",
48
+ ],
49
+ });
50
+ const customers = await remoteQuery(queryObject);
51
+ return customers[0];
52
+ }
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9tZS9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFQSxxREFLa0M7QUFHbEM7Ozs7Ozs7Ozs7R0FVRztBQUNJLE1BQU0sS0FBSyxHQUFHLEtBQUssRUFDeEIsR0FBK0IsRUFDL0IsR0FBbUIsRUFDbkIsRUFBRTtJQUNGLE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFBO0lBQzVDLE1BQU0sSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBQTRCLENBQUE7SUFFeEQsSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzdCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQzdCLG1HQUFtRyxDQUNwRyxDQUFBO0lBQ0gsQ0FBQztJQUVELElBQUksSUFBSSxDQUFDLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM3QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUM3QixtR0FBbUcsQ0FDcEcsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLGVBQWUsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBeUIsZUFBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBRW5GLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDakMsTUFBTSxlQUFlLENBQUMsZUFBZSxDQUNuQyxVQUFVLEVBQ1YsSUFBNkQsQ0FDOUQsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLGVBQWUsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQzVELE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQTtBQUNwRCxDQUFDLENBQUE7QUFoQ1ksUUFBQSxLQUFLLFNBZ0NqQjtBQUVELEtBQUssVUFBVSxlQUFlLENBQUMsVUFBa0IsRUFBRSxLQUFzQjtJQUN2RSxNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ3pFLE1BQU0sV0FBVyxHQUFHLElBQUEsbUNBQTJCLEVBQUM7UUFDOUMsVUFBVSxFQUFFLFVBQVU7UUFDdEIsU0FBUyxFQUFFLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxFQUFFO1FBQzFDLE1BQU0sRUFBRTtZQUNOLElBQUk7WUFDSixPQUFPO1lBQ1AsWUFBWTtZQUNaLFdBQVc7WUFDWCxPQUFPO1lBQ1AsYUFBYTtZQUNiLFVBQVU7WUFDVixZQUFZO1lBQ1osWUFBWTtTQUNiO0tBQ0YsQ0FBQyxDQUFBO0lBQ0YsTUFBTSxTQUFTLEdBQUcsTUFBTSxXQUFXLENBQUMsV0FBVyxDQUFDLENBQUE7SUFDaEQsT0FBTyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDckIsQ0FBQyJ9
@@ -9,15 +9,12 @@ const otp_verification_1 = require("../../../../../modules/otp-verification/mode
9
9
  const send_otp_workflow_1 = __importDefault(require("../../../../../workflows/send-otp-workflow"));
10
10
  const POST = async (req, res) => {
11
11
  const { customer_id, type } = req.body;
12
- console.log("=== [otp/send] Route Called ===");
13
- console.log("Request body:", { customer_id, type });
14
12
  if (!customer_id) {
15
13
  throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "customer_id is required");
16
14
  }
17
15
  if (!type || !Object.values(otp_verification_1.OtpPurpose).includes(type)) {
18
16
  throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Type must be one of: ${Object.values(otp_verification_1.OtpPurpose).join(", ")}`);
19
17
  }
20
- console.log("=== [otp/send] Starting Workflow ===");
21
18
  // Execute workflow
22
19
  const { result } = await (0, send_otp_workflow_1.default)(req.scope).run({
23
20
  input: {
@@ -25,12 +22,10 @@ const POST = async (req, res) => {
25
22
  type: type,
26
23
  },
27
24
  });
28
- console.log("=== [otp/send] Workflow Completed ===");
29
- console.log("Result:", { token: result.token, expires_at: result.expires_at });
30
25
  return res.status(200).json({
31
26
  token: result.token,
32
27
  expires_at: result.expires_at,
33
28
  });
34
29
  };
35
30
  exports.POST = POST;
36
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9vdHAvc2VuZC9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxxREFBdUQ7QUFDdkQsc0dBQTRGO0FBQzVGLG1HQUF3RTtBQUVqRSxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDcEUsTUFBTSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsR0FBRyxHQUFHLENBQUMsSUFHakMsQ0FBQTtJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQTtJQUM5QyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBRW5ELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNqQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qix5QkFBeUIsQ0FDMUIsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyw2QkFBVSxDQUFDLENBQUMsUUFBUSxDQUFDLElBQWtCLENBQUMsRUFBRSxDQUFDO1FBQ3JFLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHdCQUF3QixNQUFNLENBQUMsTUFBTSxDQUFDLDZCQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDL0QsQ0FBQTtJQUNILENBQUM7SUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLHNDQUFzQyxDQUFDLENBQUE7SUFFbkQsbUJBQW1CO0lBQ25CLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxNQUFNLElBQUEsMkJBQWUsRUFBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDO1FBQ3RELEtBQUssRUFBRTtZQUNMLFdBQVc7WUFDWCxJQUFJLEVBQUUsSUFBa0I7U0FDekI7S0FDRixDQUFDLENBQUE7SUFFRixPQUFPLENBQUMsR0FBRyxDQUFDLHVDQUF1QyxDQUFDLENBQUE7SUFDcEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUE7SUFFOUUsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUMxQixLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUs7UUFDbkIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO0tBQzlCLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQTtBQXhDWSxRQUFBLElBQUksUUF3Q2hCIn0=
31
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2N1c3RvbWVycy9vdHAvc2VuZC9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxxREFBdUQ7QUFDdkQsc0dBQTRGO0FBQzVGLG1HQUF3RTtBQUVqRSxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDcEUsTUFBTSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsR0FBRyxHQUFHLENBQUMsSUFHakMsQ0FBQTtJQUVELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNqQixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qix5QkFBeUIsQ0FDMUIsQ0FBQTtJQUNILENBQUM7SUFFRCxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyw2QkFBVSxDQUFDLENBQUMsUUFBUSxDQUFDLElBQWtCLENBQUMsRUFBRSxDQUFDO1FBQ3JFLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLHdCQUF3QixNQUFNLENBQUMsTUFBTSxDQUFDLDZCQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDL0QsQ0FBQTtJQUNILENBQUM7SUFHRCxtQkFBbUI7SUFDbkIsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sSUFBQSwyQkFBZSxFQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7UUFDdEQsS0FBSyxFQUFFO1lBQ0wsV0FBVztZQUNYLElBQUksRUFBRSxJQUFrQjtTQUN6QjtLQUNGLENBQUMsQ0FBQTtJQUVGLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDMUIsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLO1FBQ25CLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVTtLQUM5QixDQUFDLENBQUE7QUFDSixDQUFDLENBQUE7QUFqQ1ksUUFBQSxJQUFJLFFBaUNoQiJ9