@open-mercato/core 0.6.1-develop.3260.1.dc719cac84 → 0.6.1-develop.3278.1.a4d26475e4

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 (212) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/domain_mapping/index.js +31 -0
  3. package/dist/generated/entities/domain_mapping/index.js.map +7 -0
  4. package/dist/generated/entities.ids.generated.js +2 -1
  5. package/dist/generated/entities.ids.generated.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +16 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/helpers/integration/salesUi.js +18 -17
  9. package/dist/helpers/integration/salesUi.js.map +2 -2
  10. package/dist/modules/customer_accounts/acl.js +2 -1
  11. package/dist/modules/customer_accounts/acl.js.map +2 -2
  12. package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/health-check.js +110 -0
  13. package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/health-check.js.map +7 -0
  14. package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/verify.js +114 -0
  15. package/dist/modules/customer_accounts/api/admin/domain-mappings/[id]/verify.js.map +7 -0
  16. package/dist/modules/customer_accounts/api/admin/domain-mappings.js +271 -0
  17. package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +7 -0
  18. package/dist/modules/customer_accounts/api/domain-check.js +70 -0
  19. package/dist/modules/customer_accounts/api/domain-check.js.map +7 -0
  20. package/dist/modules/customer_accounts/api/domain-resolve/all.js +128 -0
  21. package/dist/modules/customer_accounts/api/domain-resolve/all.js.map +7 -0
  22. package/dist/modules/customer_accounts/api/domain-resolve.js +84 -0
  23. package/dist/modules/customer_accounts/api/domain-resolve.js.map +7 -0
  24. package/dist/modules/customer_accounts/api/login.js +14 -3
  25. package/dist/modules/customer_accounts/api/login.js.map +2 -2
  26. package/dist/modules/customer_accounts/api/magic-link/request.js +14 -3
  27. package/dist/modules/customer_accounts/api/magic-link/request.js.map +2 -2
  28. package/dist/modules/customer_accounts/api/password/reset-request.js +14 -3
  29. package/dist/modules/customer_accounts/api/password/reset-request.js.map +2 -2
  30. package/dist/modules/customer_accounts/api/signup.js +32 -5
  31. package/dist/modules/customer_accounts/api/signup.js.map +2 -2
  32. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Actions.js +48 -0
  33. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Actions.js.map +7 -0
  34. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js +43 -0
  35. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.js.map +7 -0
  36. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DnsConfig.js +53 -0
  37. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DnsConfig.js.map +7 -0
  38. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DomainPanel.js +69 -0
  39. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DomainPanel.js.map +7 -0
  40. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/OrgSwitcher.js +31 -0
  41. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/OrgSwitcher.js.map +7 -0
  42. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/RegisterDialog.js +147 -0
  43. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/RegisterDialog.js.map +7 -0
  44. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/StatusBadgeSection.js +39 -0
  45. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/StatusBadgeSection.js.map +7 -0
  46. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Stepper.js +60 -0
  47. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Stepper.js.map +7 -0
  48. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/domainStatusMap.js +11 -0
  49. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/domainStatusMap.js.map +7 -0
  50. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/types.js +1 -0
  51. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/components/types.js.map +7 -0
  52. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +361 -0
  53. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +7 -0
  54. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.meta.js +28 -0
  55. package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.meta.js.map +7 -0
  56. package/dist/modules/customer_accounts/data/enrichers.js +78 -12
  57. package/dist/modules/customer_accounts/data/enrichers.js.map +2 -2
  58. package/dist/modules/customer_accounts/data/entities.js +85 -2
  59. package/dist/modules/customer_accounts/data/entities.js.map +2 -2
  60. package/dist/modules/customer_accounts/data/guards.js +130 -0
  61. package/dist/modules/customer_accounts/data/guards.js.map +7 -0
  62. package/dist/modules/customer_accounts/data/validators.js +19 -0
  63. package/dist/modules/customer_accounts/data/validators.js.map +2 -2
  64. package/dist/modules/customer_accounts/di.js +23 -1
  65. package/dist/modules/customer_accounts/di.js.map +2 -2
  66. package/dist/modules/customer_accounts/events.js +9 -2
  67. package/dist/modules/customer_accounts/events.js.map +2 -2
  68. package/dist/modules/customer_accounts/lib/customerAuthServer.js +27 -7
  69. package/dist/modules/customer_accounts/lib/customerAuthServer.js.map +2 -2
  70. package/dist/modules/customer_accounts/lib/customerUrl.js +48 -0
  71. package/dist/modules/customer_accounts/lib/customerUrl.js.map +7 -0
  72. package/dist/modules/customer_accounts/lib/hostname.js +55 -0
  73. package/dist/modules/customer_accounts/lib/hostname.js.map +7 -0
  74. package/dist/modules/customer_accounts/lib/platformDomains.js +7 -0
  75. package/dist/modules/customer_accounts/lib/platformDomains.js.map +7 -0
  76. package/dist/modules/customer_accounts/lib/proxyRanges.js +71 -0
  77. package/dist/modules/customer_accounts/lib/proxyRanges.js.map +7 -0
  78. package/dist/modules/customer_accounts/lib/rateLimiter.js +7 -0
  79. package/dist/modules/customer_accounts/lib/rateLimiter.js.map +2 -2
  80. package/dist/modules/customer_accounts/lib/resolveTenantContext.js +63 -0
  81. package/dist/modules/customer_accounts/lib/resolveTenantContext.js.map +7 -0
  82. package/dist/modules/customer_accounts/lib/secretCompare.js +13 -0
  83. package/dist/modules/customer_accounts/lib/secretCompare.js.map +7 -0
  84. package/dist/modules/customer_accounts/migrations/Migration20260430120000_customer_accounts.js +37 -0
  85. package/dist/modules/customer_accounts/migrations/Migration20260430120000_customer_accounts.js.map +7 -0
  86. package/dist/modules/customer_accounts/notifications.client.js +76 -0
  87. package/dist/modules/customer_accounts/notifications.client.js.map +2 -2
  88. package/dist/modules/customer_accounts/notifications.js +76 -0
  89. package/dist/modules/customer_accounts/notifications.js.map +2 -2
  90. package/dist/modules/customer_accounts/services/domainMappingService.js +497 -0
  91. package/dist/modules/customer_accounts/services/domainMappingService.js.map +7 -0
  92. package/dist/modules/customer_accounts/setup.js +48 -1
  93. package/dist/modules/customer_accounts/setup.js.map +2 -2
  94. package/dist/modules/customer_accounts/subscribers/invalidateDomainCache.js +29 -0
  95. package/dist/modules/customer_accounts/subscribers/invalidateDomainCache.js.map +7 -0
  96. package/dist/modules/customer_accounts/subscribers/notifyDomainActivated.js +29 -0
  97. package/dist/modules/customer_accounts/subscribers/notifyDomainActivated.js.map +7 -0
  98. package/dist/modules/customer_accounts/subscribers/notifyDomainDnsFailed.js +30 -0
  99. package/dist/modules/customer_accounts/subscribers/notifyDomainDnsFailed.js.map +7 -0
  100. package/dist/modules/customer_accounts/subscribers/notifyDomainTlsFailed.js +31 -0
  101. package/dist/modules/customer_accounts/subscribers/notifyDomainTlsFailed.js.map +7 -0
  102. package/dist/modules/customer_accounts/subscribers/notifyDomainVerified.js +29 -0
  103. package/dist/modules/customer_accounts/subscribers/notifyDomainVerified.js.map +7 -0
  104. package/dist/modules/customer_accounts/workers/domainTlsRetryWorker.js +67 -0
  105. package/dist/modules/customer_accounts/workers/domainTlsRetryWorker.js.map +7 -0
  106. package/dist/modules/customer_accounts/workers/domainVerificationWorker.js +34 -0
  107. package/dist/modules/customer_accounts/workers/domainVerificationWorker.js.map +7 -0
  108. package/dist/modules/customers/api/companies/route.js +4 -9
  109. package/dist/modules/customers/api/companies/route.js.map +2 -2
  110. package/dist/modules/customers/api/deals/route.js +4 -9
  111. package/dist/modules/customers/api/deals/route.js.map +2 -2
  112. package/dist/modules/customers/api/people/route.js +4 -9
  113. package/dist/modules/customers/api/people/route.js.map +2 -2
  114. package/dist/modules/customers/api/utils.js +0 -12
  115. package/dist/modules/customers/api/utils.js.map +2 -2
  116. package/dist/modules/customers/backend/customers/companies/page.js +361 -284
  117. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  118. package/dist/modules/customers/backend/customers/deals/page.js +378 -473
  119. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  120. package/dist/modules/customers/backend/customers/people/page.js +368 -286
  121. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  122. package/dist/modules/customers/components/detail/assignableStaff.js +15 -1
  123. package/dist/modules/customers/components/detail/assignableStaff.js.map +2 -2
  124. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +188 -36
  125. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +2 -2
  126. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +2 -2
  127. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +2 -2
  128. package/dist/modules/customers/widgets/injection-table.js +6 -0
  129. package/dist/modules/customers/widgets/injection-table.js.map +2 -2
  130. package/dist/modules/perspectives/services/perspectiveService.js +16 -2
  131. package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
  132. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +1 -0
  133. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
  134. package/dist/modules/query_index/lib/engine.js +31 -8
  135. package/dist/modules/query_index/lib/engine.js.map +2 -2
  136. package/generated/entities/domain_mapping/index.ts +14 -0
  137. package/generated/entities.ids.generated.ts +2 -1
  138. package/generated/entity-fields-registry.ts +16 -0
  139. package/package.json +5 -5
  140. package/src/helpers/integration/salesUi.ts +27 -23
  141. package/src/modules/customer_accounts/acl.ts +1 -0
  142. package/src/modules/customer_accounts/api/admin/domain-mappings/[id]/health-check.ts +119 -0
  143. package/src/modules/customer_accounts/api/admin/domain-mappings/[id]/verify.ts +123 -0
  144. package/src/modules/customer_accounts/api/admin/domain-mappings.ts +303 -0
  145. package/src/modules/customer_accounts/api/domain-check.ts +83 -0
  146. package/src/modules/customer_accounts/api/domain-resolve/all.ts +139 -0
  147. package/src/modules/customer_accounts/api/domain-resolve.ts +91 -0
  148. package/src/modules/customer_accounts/api/login.ts +14 -3
  149. package/src/modules/customer_accounts/api/magic-link/request.ts +14 -3
  150. package/src/modules/customer_accounts/api/password/reset-request.ts +15 -3
  151. package/src/modules/customer_accounts/api/signup.ts +36 -5
  152. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Actions.tsx +70 -0
  153. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.tsx +66 -0
  154. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DnsConfig.tsx +78 -0
  155. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DomainPanel.tsx +90 -0
  156. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/OrgSwitcher.tsx +43 -0
  157. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/RegisterDialog.tsx +178 -0
  158. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/StatusBadgeSection.tsx +56 -0
  159. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Stepper.tsx +69 -0
  160. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/domainStatusMap.ts +10 -0
  161. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/types.ts +31 -0
  162. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.meta.ts +26 -0
  163. package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +411 -0
  164. package/src/modules/customer_accounts/data/enrichers.ts +95 -12
  165. package/src/modules/customer_accounts/data/entities.ts +80 -1
  166. package/src/modules/customer_accounts/data/guards.ts +155 -0
  167. package/src/modules/customer_accounts/data/validators.ts +26 -0
  168. package/src/modules/customer_accounts/di.ts +35 -1
  169. package/src/modules/customer_accounts/events.ts +8 -1
  170. package/src/modules/customer_accounts/i18n/de.json +78 -0
  171. package/src/modules/customer_accounts/i18n/en.json +78 -0
  172. package/src/modules/customer_accounts/i18n/es.json +78 -0
  173. package/src/modules/customer_accounts/i18n/pl.json +78 -0
  174. package/src/modules/customer_accounts/lib/customerAuthServer.ts +44 -8
  175. package/src/modules/customer_accounts/lib/customerUrl.ts +72 -0
  176. package/src/modules/customer_accounts/lib/hostname.ts +76 -0
  177. package/src/modules/customer_accounts/lib/platformDomains.ts +14 -0
  178. package/src/modules/customer_accounts/lib/proxyRanges.ts +85 -0
  179. package/src/modules/customer_accounts/lib/rateLimiter.ts +10 -0
  180. package/src/modules/customer_accounts/lib/resolveTenantContext.ts +96 -0
  181. package/src/modules/customer_accounts/lib/secretCompare.ts +20 -0
  182. package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +341 -0
  183. package/src/modules/customer_accounts/migrations/Migration20260430120000_customer_accounts.ts +38 -0
  184. package/src/modules/customer_accounts/notifications.client.ts +76 -0
  185. package/src/modules/customer_accounts/notifications.ts +76 -0
  186. package/src/modules/customer_accounts/services/domainMappingService.ts +632 -0
  187. package/src/modules/customer_accounts/setup.ts +81 -1
  188. package/src/modules/customer_accounts/subscribers/invalidateDomainCache.ts +35 -0
  189. package/src/modules/customer_accounts/subscribers/notifyDomainActivated.ts +32 -0
  190. package/src/modules/customer_accounts/subscribers/notifyDomainDnsFailed.ts +33 -0
  191. package/src/modules/customer_accounts/subscribers/notifyDomainTlsFailed.ts +34 -0
  192. package/src/modules/customer_accounts/subscribers/notifyDomainVerified.ts +32 -0
  193. package/src/modules/customer_accounts/workers/domainTlsRetryWorker.ts +84 -0
  194. package/src/modules/customer_accounts/workers/domainVerificationWorker.ts +45 -0
  195. package/src/modules/customers/api/companies/route.ts +4 -9
  196. package/src/modules/customers/api/deals/route.ts +4 -9
  197. package/src/modules/customers/api/people/route.ts +4 -9
  198. package/src/modules/customers/api/utils.ts +0 -14
  199. package/src/modules/customers/backend/customers/companies/page.tsx +321 -237
  200. package/src/modules/customers/backend/customers/deals/page.tsx +321 -455
  201. package/src/modules/customers/backend/customers/people/page.tsx +331 -240
  202. package/src/modules/customers/components/detail/assignableStaff.ts +21 -0
  203. package/src/modules/customers/i18n/de.json +31 -0
  204. package/src/modules/customers/i18n/en.json +31 -0
  205. package/src/modules/customers/i18n/es.json +31 -0
  206. package/src/modules/customers/i18n/pl.json +31 -0
  207. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +197 -40
  208. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +13 -7
  209. package/src/modules/customers/widgets/injection-table.ts +6 -0
  210. package/src/modules/perspectives/services/perspectiveService.ts +30 -2
  211. package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +1 -0
  212. package/src/modules/query_index/lib/engine.ts +46 -8
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customer_accounts/api/signup.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { compare as bcryptCompare } from 'bcryptjs'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc, OpenApiMethodDoc } from '@open-mercato/shared/lib/openapi'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { sendEmail } from '@open-mercato/shared/lib/email/send'\nimport { signupSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { CustomerUserService } from '@open-mercato/core/modules/customer_accounts/services/customerUserService'\nimport { CustomerTokenService } from '@open-mercato/core/modules/customer_accounts/services/customerTokenService'\nimport { CustomerRole, CustomerUserRole } from '@open-mercato/core/modules/customer_accounts/data/entities'\nimport { emitCustomerAccountsEvent } from '@open-mercato/core/modules/customer_accounts/events'\nimport CustomerSignupVerificationEmail from '@open-mercato/core/modules/customer_accounts/emails/CustomerSignupVerificationEmail'\nimport CustomerExistingAccountEmail from '@open-mercato/core/modules/customer_accounts/emails/CustomerExistingAccountEmail'\nimport { rateLimitErrorSchema } from '@open-mercato/shared/lib/ratelimit/helpers'\nimport {\n checkAuthRateLimit,\n customerSignupRateLimitConfig,\n customerSignupIpRateLimitConfig,\n} from '@open-mercato/core/modules/customer_accounts/lib/rateLimiter'\nimport { readNormalizedEmailFromJsonRequest } from '@open-mercato/core/modules/customer_accounts/lib/rateLimitIdentifier'\nimport { findOrganizationInTenant } from '@open-mercato/core/modules/customer_accounts/lib/organizationLookup'\nimport { getSecurityEmailBaseUrl, mapSecurityEmailUrlError } from '@open-mercato/shared/lib/url'\n\nexport const metadata: { path?: string; requireAuth?: boolean } = { requireAuth: false }\n\n// Precomputed bcrypt cost-10 hash of an unknowable random 32-byte input; used to equalize\n// response latency between the existing-user and new-user signup branches so the endpoint's\n// 202-for-both contract is not undone by a timing side channel.\nconst TIMING_EQUALIZATION_HASH = '$2b$10$.F2A6UHFzk.d8trNdfqt4OLz05Nf3IOuMmN6VJKflhD4.rz.prR8i'\nfunction resolvePortalLoginUrl(baseUrl: string, organizationSlug?: string | null): string {\n return organizationSlug\n ? `${baseUrl}/${organizationSlug}/portal/login`\n : `${baseUrl}/portal/login`\n}\n\nfunction resolvePortalVerifyUrl(baseUrl: string, token: string, organizationSlug?: string | null): string {\n const route = organizationSlug\n ? `${baseUrl}/${organizationSlug}/portal/verify`\n : `${baseUrl}/portal/verify`\n return `${route}?token=${encodeURIComponent(token)}`\n}\n\nexport async function POST(req: Request) {\n const rateLimitEmail = await readNormalizedEmailFromJsonRequest(req)\n const { error: rateLimitError } = await checkAuthRateLimit({\n req,\n ipConfig: customerSignupIpRateLimitConfig,\n compoundConfig: customerSignupRateLimitConfig,\n compoundIdentifier: rateLimitEmail,\n })\n if (rateLimitError) return rateLimitError\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ ok: false, error: 'Invalid request body' }, { status: 400 })\n }\n\n const parsed = signupSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ ok: false, error: 'Validation failed', details: parsed.error.flatten().fieldErrors }, { status: 400 })\n }\n\n const { email, password, displayName, tenantId, organizationId } = parsed.data\n if (!tenantId || !organizationId) {\n return NextResponse.json({ ok: false, error: 'tenantId and organizationId are required' }, { status: 400 })\n }\n\n let baseUrl: string\n try {\n baseUrl = getSecurityEmailBaseUrl(req)\n } catch (error) {\n const mapped = mapSecurityEmailUrlError(error, {\n scope: 'customer_accounts.signup',\n configMessage: 'Customer signup is not configured',\n })\n if (mapped) return NextResponse.json(mapped.body, { status: mapped.status })\n throw error\n }\n\n const container = await createRequestContainer()\n const customerUserService = container.resolve('customerUserService') as CustomerUserService\n const customerTokenService = container.resolve('customerTokenService') as CustomerTokenService\n const em = container.resolve('em') as import('@mikro-orm/postgresql').EntityManager\n const { translate } = await resolveTranslations()\n\n const orgRow = await findOrganizationInTenant(em, organizationId, tenantId)\n if (!orgRow) {\n return NextResponse.json({ ok: false, error: 'Registration could not be completed' }, { status: 400 })\n }\n\n const existing = await customerUserService.findByEmail(email, tenantId)\n if (existing) {\n await bcryptCompare(password, TIMING_EQUALIZATION_HASH)\n const existingOrg = await findOrganizationInTenant(em, existing.organizationId, tenantId)\n const loginUrl = resolvePortalLoginUrl(baseUrl, existingOrg?.slug ?? null)\n const subject = translate('customer_accounts.signup.existing.subject', 'You already have a portal account')\n const copy = {\n preview: translate('customer_accounts.signup.existing.preview', 'A sign-up attempt was made for an email that already has a portal account.'),\n title: translate('customer_accounts.signup.existing.title', 'You already have a portal account'),\n body: translate(\n 'customer_accounts.signup.existing.body',\n 'A sign-up request was made for this email address. You can sign in with your existing account. If you forgot your password, use the password reset option on the sign-in page.',\n ),\n cta: translate('customer_accounts.signup.existing.cta', 'Open sign-in page'),\n hint: translate(\n 'customer_accounts.signup.existing.hint',\n 'If this was not you, you can ignore this message. No new portal account was created.',\n ),\n }\n\n void sendEmail({\n to: existing.email,\n subject,\n react: CustomerExistingAccountEmail({ loginUrl, copy }),\n }).catch((error) => {\n console.error('[customer_accounts.signup] existing-account email failed', error)\n })\n\n return NextResponse.json({ ok: true }, { status: 202 })\n }\n\n const user = await customerUserService.createUser(email, password, displayName, { tenantId, organizationId })\n\n const defaultRole = await em.findOne(CustomerRole, {\n tenantId,\n isDefault: true,\n deletedAt: null,\n })\n if (defaultRole) {\n const userRole = em.create(CustomerUserRole, {\n user,\n role: defaultRole,\n createdAt: new Date(),\n } as any)\n em.persist(userRole)\n }\n\n await em.persist(user).flush()\n\n const verificationToken = await customerTokenService.createEmailVerification(user.id, tenantId)\n const verifyUrl = resolvePortalVerifyUrl(baseUrl, verificationToken, orgRow.slug)\n const subject = translate('customer_accounts.signup.created.subject', 'Verify your portal account')\n const copy = {\n preview: translate('customer_accounts.signup.created.preview', 'Verify your portal account to finish sign-up.'),\n title: translate('customer_accounts.signup.created.title', 'Verify your portal account'),\n body: translate(\n 'customer_accounts.signup.created.body',\n 'Your account request was accepted. Confirm your email address to finish setting up portal access.',\n ),\n cta: translate('customer_accounts.signup.created.cta', 'Verify email address'),\n hint: translate(\n 'customer_accounts.signup.created.hint',\n 'This verification link expires in 24 hours. If you did not request this, you can ignore this email.',\n ),\n }\n\n void sendEmail({\n to: user.email,\n subject,\n react: CustomerSignupVerificationEmail({ verifyUrl, copy }),\n }).catch((error) => {\n console.error('[customer_accounts.signup] verification email failed', error)\n })\n\n void emitCustomerAccountsEvent('customer_accounts.user.created', {\n id: user.id,\n email: user.email,\n tenantId,\n organizationId,\n }).catch(() => undefined)\n\n return NextResponse.json({ ok: true }, { status: 202 })\n}\n\nconst signupAcceptedSchema = z.object({ ok: z.literal(true) })\n\nconst errorSchema = z.object({\n ok: z.literal(false),\n error: z.string(),\n})\n\nconst methodDoc: OpenApiMethodDoc = {\n summary: 'Register a new customer account',\n description: 'Accepts a signup request and always returns 202 to prevent account enumeration.',\n tags: ['Customer Authentication'],\n requestBody: {\n schema: signupSchema,\n description: 'Signup payload with email, password, and display name.',\n },\n responses: [\n { status: 202, description: 'Signup accepted', schema: signupAcceptedSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed or invalid request origin', schema: errorSchema },\n { status: 429, description: 'Too many signup attempts', schema: rateLimitErrorSchema },\n { status: 500, description: 'Signup email origin is not configured', schema: errorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Customer account registration',\n description: 'Handles customer self-registration without revealing whether the email already exists.',\n methods: { POST: methodDoc },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { compare as bcryptCompare } from 'bcryptjs'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc, OpenApiMethodDoc } from '@open-mercato/shared/lib/openapi'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { sendEmail } from '@open-mercato/shared/lib/email/send'\nimport { signupSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { CustomerUserService } from '@open-mercato/core/modules/customer_accounts/services/customerUserService'\nimport { CustomerTokenService } from '@open-mercato/core/modules/customer_accounts/services/customerTokenService'\nimport { CustomerRole, CustomerUserRole } from '@open-mercato/core/modules/customer_accounts/data/entities'\nimport { emitCustomerAccountsEvent } from '@open-mercato/core/modules/customer_accounts/events'\nimport CustomerSignupVerificationEmail from '@open-mercato/core/modules/customer_accounts/emails/CustomerSignupVerificationEmail'\nimport CustomerExistingAccountEmail from '@open-mercato/core/modules/customer_accounts/emails/CustomerExistingAccountEmail'\nimport { rateLimitErrorSchema } from '@open-mercato/shared/lib/ratelimit/helpers'\nimport {\n checkAuthRateLimit,\n customerSignupRateLimitConfig,\n customerSignupIpRateLimitConfig,\n} from '@open-mercato/core/modules/customer_accounts/lib/rateLimiter'\nimport { readNormalizedEmailFromJsonRequest } from '@open-mercato/core/modules/customer_accounts/lib/rateLimitIdentifier'\nimport { findOrganizationInTenant } from '@open-mercato/core/modules/customer_accounts/lib/organizationLookup'\nimport { getSecurityEmailBaseUrl, mapSecurityEmailUrlError } from '@open-mercato/shared/lib/url'\nimport {\n resolveTenantContext,\n TenantResolutionError,\n} from '@open-mercato/core/modules/customer_accounts/lib/resolveTenantContext'\nimport { urlForCustomerOrg } from '@open-mercato/core/modules/customer_accounts/lib/customerUrl'\n\nexport const metadata: { path?: string; requireAuth?: boolean } = { requireAuth: false }\n\n// Precomputed bcrypt cost-10 hash of an unknowable random 32-byte input; used to equalize\n// response latency between the existing-user and new-user signup branches so the endpoint's\n// 202-for-both contract is not undone by a timing side channel.\nconst TIMING_EQUALIZATION_HASH = '$2b$10$.F2A6UHFzk.d8trNdfqt4OLz05Nf3IOuMmN6VJKflhD4.rz.prR8i'\nfunction resolvePortalLoginUrl(baseUrl: string, organizationSlug?: string | null): string {\n return organizationSlug\n ? `${baseUrl}/${organizationSlug}/portal/login`\n : `${baseUrl}/portal/login`\n}\n\nfunction resolvePortalVerifyUrl(baseUrl: string, token: string, organizationSlug?: string | null): string {\n const route = organizationSlug\n ? `${baseUrl}/${organizationSlug}/portal/verify`\n : `${baseUrl}/portal/verify`\n return `${route}?token=${encodeURIComponent(token)}`\n}\n\nexport async function POST(req: Request) {\n const rateLimitEmail = await readNormalizedEmailFromJsonRequest(req)\n const { error: rateLimitError } = await checkAuthRateLimit({\n req,\n ipConfig: customerSignupIpRateLimitConfig,\n compoundConfig: customerSignupRateLimitConfig,\n compoundIdentifier: rateLimitEmail,\n })\n if (rateLimitError) return rateLimitError\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ ok: false, error: 'Invalid request body' }, { status: 400 })\n }\n\n const parsed = signupSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ ok: false, error: 'Validation failed', details: parsed.error.flatten().fieldErrors }, { status: 400 })\n }\n\n const { email, password, displayName } = parsed.data\n let tenantId: string\n let organizationId: string | null\n try {\n const context = await resolveTenantContext(req, parsed.data.tenantId)\n tenantId = context.tenantId\n organizationId = context.organizationId ?? parsed.data.organizationId ?? null\n } catch (err) {\n if (err instanceof TenantResolutionError) {\n return NextResponse.json({ ok: false, error: err.message }, { status: err.status })\n }\n throw err\n }\n if (!organizationId) {\n return NextResponse.json({ ok: false, error: 'organizationId is required' }, { status: 400 })\n }\n\n let baseUrl: string\n try {\n baseUrl = getSecurityEmailBaseUrl(req)\n } catch (error) {\n const mapped = mapSecurityEmailUrlError(error, {\n scope: 'customer_accounts.signup',\n configMessage: 'Customer signup is not configured',\n })\n if (mapped) return NextResponse.json(mapped.body, { status: mapped.status })\n throw error\n }\n\n const container = await createRequestContainer()\n const customerUserService = container.resolve('customerUserService') as CustomerUserService\n const customerTokenService = container.resolve('customerTokenService') as CustomerTokenService\n const em = container.resolve('em') as import('@mikro-orm/postgresql').EntityManager\n const { translate } = await resolveTranslations()\n\n const orgRow = await findOrganizationInTenant(em, organizationId, tenantId)\n if (!orgRow) {\n return NextResponse.json({ ok: false, error: 'Registration could not be completed' }, { status: 400 })\n }\n\n const existing = await customerUserService.findByEmail(email, tenantId)\n if (existing) {\n await bcryptCompare(password, TIMING_EQUALIZATION_HASH)\n const existingOrg = await findOrganizationInTenant(em, existing.organizationId, tenantId)\n // Prefer the org's active custom domain when available; fall back to the\n // platform login URL preserved by `resolvePortalLoginUrl`.\n let loginUrl = resolvePortalLoginUrl(baseUrl, existingOrg?.slug ?? null)\n try {\n loginUrl = await urlForCustomerOrg(existing.organizationId, '/login', { container })\n } catch {\n // Fall back to platform URL on any resolution issue.\n }\n const subject = translate('customer_accounts.signup.existing.subject', 'You already have a portal account')\n const copy = {\n preview: translate('customer_accounts.signup.existing.preview', 'A sign-up attempt was made for an email that already has a portal account.'),\n title: translate('customer_accounts.signup.existing.title', 'You already have a portal account'),\n body: translate(\n 'customer_accounts.signup.existing.body',\n 'A sign-up request was made for this email address. You can sign in with your existing account. If you forgot your password, use the password reset option on the sign-in page.',\n ),\n cta: translate('customer_accounts.signup.existing.cta', 'Open sign-in page'),\n hint: translate(\n 'customer_accounts.signup.existing.hint',\n 'If this was not you, you can ignore this message. No new portal account was created.',\n ),\n }\n\n void sendEmail({\n to: existing.email,\n subject,\n react: CustomerExistingAccountEmail({ loginUrl, copy }),\n }).catch((error) => {\n console.error('[customer_accounts.signup] existing-account email failed', error)\n })\n\n return NextResponse.json({ ok: true }, { status: 202 })\n }\n\n const user = await customerUserService.createUser(email, password, displayName, { tenantId, organizationId })\n\n const defaultRole = await em.findOne(CustomerRole, {\n tenantId,\n isDefault: true,\n deletedAt: null,\n })\n if (defaultRole) {\n const userRole = em.create(CustomerUserRole, {\n user,\n role: defaultRole,\n createdAt: new Date(),\n } as any)\n em.persist(userRole)\n }\n\n await em.persist(user).flush()\n\n const verificationToken = await customerTokenService.createEmailVerification(user.id, tenantId)\n let verifyUrl = resolvePortalVerifyUrl(baseUrl, verificationToken, orgRow.slug)\n try {\n verifyUrl = await urlForCustomerOrg(organizationId, `/verify?token=${encodeURIComponent(verificationToken)}`, {\n container,\n })\n } catch {\n // Fall back to the platform-derived URL on any resolution issue.\n }\n const subject = translate('customer_accounts.signup.created.subject', 'Verify your portal account')\n const copy = {\n preview: translate('customer_accounts.signup.created.preview', 'Verify your portal account to finish sign-up.'),\n title: translate('customer_accounts.signup.created.title', 'Verify your portal account'),\n body: translate(\n 'customer_accounts.signup.created.body',\n 'Your account request was accepted. Confirm your email address to finish setting up portal access.',\n ),\n cta: translate('customer_accounts.signup.created.cta', 'Verify email address'),\n hint: translate(\n 'customer_accounts.signup.created.hint',\n 'This verification link expires in 24 hours. If you did not request this, you can ignore this email.',\n ),\n }\n\n void sendEmail({\n to: user.email,\n subject,\n react: CustomerSignupVerificationEmail({ verifyUrl, copy }),\n }).catch((error) => {\n console.error('[customer_accounts.signup] verification email failed', error)\n })\n\n void emitCustomerAccountsEvent('customer_accounts.user.created', {\n id: user.id,\n email: user.email,\n tenantId,\n organizationId,\n }).catch(() => undefined)\n\n return NextResponse.json({ ok: true }, { status: 202 })\n}\n\nconst signupAcceptedSchema = z.object({ ok: z.literal(true) })\n\nconst errorSchema = z.object({\n ok: z.literal(false),\n error: z.string(),\n})\n\nconst methodDoc: OpenApiMethodDoc = {\n summary: 'Register a new customer account',\n description: 'Accepts a signup request and always returns 202 to prevent account enumeration.',\n tags: ['Customer Authentication'],\n requestBody: {\n schema: signupSchema,\n description: 'Signup payload with email, password, and display name.',\n },\n responses: [\n { status: 202, description: 'Signup accepted', schema: signupAcceptedSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed or invalid request origin', schema: errorSchema },\n { status: 429, description: 'Too many signup attempts', schema: rateLimitErrorSchema },\n { status: 500, description: 'Signup email origin is not configured', schema: errorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Customer account registration',\n description: 'Handles customer self-registration without revealing whether the email already exists.',\n methods: { POST: methodDoc },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["subject", "copy"]
7
7
  }
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { ExternalLink, RefreshCw, Replace, Trash2 } from "lucide-react";
4
+ import { Button } from "@open-mercato/ui/primitives/button";
5
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
+ function DefaultActions({
7
+ mapping,
8
+ isReplacement,
9
+ onCheckNow,
10
+ onRetryTls,
11
+ onChangeDomain,
12
+ onRemove,
13
+ busy
14
+ }) {
15
+ const t = useT();
16
+ const showCheckNow = mapping.status === "pending" || mapping.status === "dns_failed";
17
+ const showRetryTls = mapping.status === "tls_failed" || mapping.status === "verified";
18
+ const showTestDomain = mapping.status === "active";
19
+ const showChangeDomain = mapping.status === "active" && !isReplacement;
20
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
21
+ showCheckNow ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onCheckNow, disabled: busy, children: [
22
+ /* @__PURE__ */ jsx(RefreshCw, { className: "mr-1.5 h-4 w-4", "aria-hidden": true }),
23
+ t("customer_accounts.domainMapping.verifyNow", "Check Now")
24
+ ] }) : null,
25
+ showRetryTls ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onRetryTls, disabled: busy, children: [
26
+ /* @__PURE__ */ jsx(RefreshCw, { className: "mr-1.5 h-4 w-4", "aria-hidden": true }),
27
+ t("customer_accounts.domainMapping.tls.retryButton", "Retry SSL")
28
+ ] }) : null,
29
+ showTestDomain ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", asChild: true, children: /* @__PURE__ */ jsxs("a", { href: `https://${mapping.hostname}`, target: "_blank", rel: "noopener noreferrer", children: [
30
+ /* @__PURE__ */ jsx(ExternalLink, { className: "mr-1.5 h-4 w-4", "aria-hidden": true }),
31
+ t("customer_accounts.domainMapping.preview", "Test Domain")
32
+ ] }) }) : null,
33
+ showChangeDomain ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onChangeDomain, disabled: busy, children: [
34
+ /* @__PURE__ */ jsx(Replace, { className: "mr-1.5 h-4 w-4", "aria-hidden": true }),
35
+ t("customer_accounts.domainMapping.changeDomain", "Change Domain")
36
+ ] }) : null,
37
+ /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onRemove, disabled: busy, children: [
38
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 h-4 w-4", "aria-hidden": true }),
39
+ t("customer_accounts.domainMapping.removeDomain", "Remove Domain")
40
+ ] })
41
+ ] });
42
+ }
43
+ var Actions_default = DefaultActions;
44
+ export {
45
+ DefaultActions,
46
+ Actions_default as default
47
+ };
48
+ //# sourceMappingURL=Actions.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Actions.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { ExternalLink, RefreshCw, Replace, Trash2 } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { DomainMappingRow } from './types'\n\nexport type ActionsProps = {\n mapping: DomainMappingRow\n isReplacement: boolean\n onCheckNow: () => void\n onRetryTls: () => void\n onChangeDomain: () => void\n onRemove: () => void\n busy?: boolean\n}\n\nexport function DefaultActions({\n mapping,\n isReplacement,\n onCheckNow,\n onRetryTls,\n onChangeDomain,\n onRemove,\n busy,\n}: ActionsProps) {\n const t = useT()\n const showCheckNow = mapping.status === 'pending' || mapping.status === 'dns_failed'\n const showRetryTls = mapping.status === 'tls_failed' || mapping.status === 'verified'\n const showTestDomain = mapping.status === 'active'\n const showChangeDomain = mapping.status === 'active' && !isReplacement\n\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n {showCheckNow ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onCheckNow} disabled={busy}>\n <RefreshCw className=\"mr-1.5 h-4 w-4\" aria-hidden />\n {t('customer_accounts.domainMapping.verifyNow', 'Check Now')}\n </Button>\n ) : null}\n {showRetryTls ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onRetryTls} disabled={busy}>\n <RefreshCw className=\"mr-1.5 h-4 w-4\" aria-hidden />\n {t('customer_accounts.domainMapping.tls.retryButton', 'Retry SSL')}\n </Button>\n ) : null}\n {showTestDomain ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" asChild>\n <a href={`https://${mapping.hostname}`} target=\"_blank\" rel=\"noopener noreferrer\">\n <ExternalLink className=\"mr-1.5 h-4 w-4\" aria-hidden />\n {t('customer_accounts.domainMapping.preview', 'Test Domain')}\n </a>\n </Button>\n ) : null}\n {showChangeDomain ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onChangeDomain} disabled={busy}>\n <Replace className=\"mr-1.5 h-4 w-4\" aria-hidden />\n {t('customer_accounts.domainMapping.changeDomain', 'Change Domain')}\n </Button>\n ) : null}\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onRemove} disabled={busy}>\n <Trash2 className=\"mr-1.5 h-4 w-4\" aria-hidden />\n {t('customer_accounts.domainMapping.removeDomain', 'Remove Domain')}\n </Button>\n </div>\n )\n}\n\nexport default DefaultActions\n"],
5
+ "mappings": ";AAoCQ,SACE,KADF;AAjCR,SAAS,cAAc,WAAW,SAAS,cAAc;AACzD,SAAS,cAAc;AACvB,SAAS,YAAY;AAad,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiB;AACf,QAAM,IAAI,KAAK;AACf,QAAM,eAAe,QAAQ,WAAW,aAAa,QAAQ,WAAW;AACxE,QAAM,eAAe,QAAQ,WAAW,gBAAgB,QAAQ,WAAW;AAC3E,QAAM,iBAAiB,QAAQ,WAAW;AAC1C,QAAM,mBAAmB,QAAQ,WAAW,YAAY,CAAC;AAEzD,SACE,qBAAC,SAAI,WAAU,qCACZ;AAAA,mBACC,qBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,YAAY,UAAU,MAC/E;AAAA,0BAAC,aAAU,WAAU,kBAAiB,eAAW,MAAC;AAAA,MACjD,EAAE,6CAA6C,WAAW;AAAA,OAC7D,IACE;AAAA,IACH,eACC,qBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,YAAY,UAAU,MAC/E;AAAA,0BAAC,aAAU,WAAU,kBAAiB,eAAW,MAAC;AAAA,MACjD,EAAE,mDAAmD,WAAW;AAAA,OACnE,IACE;AAAA,IACH,iBACC,oBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAO,MACvD,+BAAC,OAAE,MAAM,WAAW,QAAQ,QAAQ,IAAI,QAAO,UAAS,KAAI,uBAC1D;AAAA,0BAAC,gBAAa,WAAU,kBAAiB,eAAW,MAAC;AAAA,MACpD,EAAE,2CAA2C,aAAa;AAAA,OAC7D,GACF,IACE;AAAA,IACH,mBACC,qBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,gBAAgB,UAAU,MACnF;AAAA,0BAAC,WAAQ,WAAU,kBAAiB,eAAW,MAAC;AAAA,MAC/C,EAAE,gDAAgD,eAAe;AAAA,OACpE,IACE;AAAA,IACJ,qBAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,UAAU,UAAU,MAC7E;AAAA,0BAAC,UAAO,WAAU,kBAAiB,eAAW,MAAC;AAAA,MAC9C,EAAE,gDAAgD,eAAe;AAAA,OACpE;AAAA,KACF;AAEJ;AAEA,IAAO,kBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { AlertTriangle } from "lucide-react";
4
+ import { Alert, AlertTitle, AlertDescription } from "@open-mercato/ui/primitives/alert";
5
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
+ function DnsDiagnostics({ mapping }) {
7
+ const t = useT();
8
+ if (mapping.status !== "dns_failed") return null;
9
+ return /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
10
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4", "aria-hidden": true }),
11
+ /* @__PURE__ */ jsx(AlertTitle, { children: t("customer_accounts.domainMapping.dns.diagnostics.title", "DNS configuration issue") }),
12
+ /* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
13
+ mapping.dnsFailureReason ? /* @__PURE__ */ jsx("p", { children: mapping.dnsFailureReason }) : null,
14
+ mapping.cnameTarget ? /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-xs", children: [
15
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: t("customer_accounts.domainMapping.dns.diagnostics.expected", "Expected target") }),
16
+ /* @__PURE__ */ jsx("dd", { className: "font-mono", children: mapping.cnameTarget })
17
+ ] }) : null
18
+ ] }) })
19
+ ] });
20
+ }
21
+ function TlsDiagnostics({ mapping }) {
22
+ const t = useT();
23
+ if (mapping.status !== "tls_failed") return null;
24
+ return /* @__PURE__ */ jsxs(Alert, { variant: "warning", children: [
25
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4", "aria-hidden": true }),
26
+ /* @__PURE__ */ jsx(AlertTitle, { children: t("customer_accounts.domainMapping.tls.diagnostics.title", "SSL certificate issue") }),
27
+ /* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
28
+ mapping.tlsFailureReason ? /* @__PURE__ */ jsx("p", { children: mapping.tlsFailureReason }) : null,
29
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("customer_accounts.domainMapping.tls.diagnostics.retryCount", "Retry attempts: {count}", {
30
+ count: String(mapping.tlsRetryCount)
31
+ }) }),
32
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t(
33
+ "customer_accounts.domainMapping.tls.diagnostics.operatorNote",
34
+ "We are retrying automatically. If this persists, contact platform support \u2014 your DNS is fine, this is on our side."
35
+ ) })
36
+ ] }) })
37
+ ] });
38
+ }
39
+ export {
40
+ DnsDiagnostics,
41
+ TlsDiagnostics
42
+ };
43
+ //# sourceMappingURL=Diagnostics.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/Diagnostics.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertTriangle } from 'lucide-react'\nimport { Alert, AlertTitle, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { DomainMappingRow } from './types'\n\nexport type DiagnosticsProps = {\n mapping: DomainMappingRow\n}\n\nexport function DnsDiagnostics({ mapping }: DiagnosticsProps) {\n const t = useT()\n if (mapping.status !== 'dns_failed') return null\n return (\n <Alert variant=\"destructive\">\n <AlertTriangle className=\"h-4 w-4\" aria-hidden />\n <AlertTitle>\n {t('customer_accounts.domainMapping.dns.diagnostics.title', 'DNS configuration issue')}\n </AlertTitle>\n <AlertDescription>\n <div className=\"space-y-2\">\n {mapping.dnsFailureReason ? <p>{mapping.dnsFailureReason}</p> : null}\n {mapping.cnameTarget ? (\n <dl className=\"grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-xs\">\n <dt className=\"text-muted-foreground\">\n {t('customer_accounts.domainMapping.dns.diagnostics.expected', 'Expected target')}\n </dt>\n <dd className=\"font-mono\">{mapping.cnameTarget}</dd>\n </dl>\n ) : null}\n </div>\n </AlertDescription>\n </Alert>\n )\n}\n\nexport function TlsDiagnostics({ mapping }: DiagnosticsProps) {\n const t = useT()\n if (mapping.status !== 'tls_failed') return null\n return (\n <Alert variant=\"warning\">\n <AlertTriangle className=\"h-4 w-4\" aria-hidden />\n <AlertTitle>\n {t('customer_accounts.domainMapping.tls.diagnostics.title', 'SSL certificate issue')}\n </AlertTitle>\n <AlertDescription>\n <div className=\"space-y-2\">\n {mapping.tlsFailureReason ? <p>{mapping.tlsFailureReason}</p> : null}\n <p className=\"text-xs text-muted-foreground\">\n {t('customer_accounts.domainMapping.tls.diagnostics.retryCount', 'Retry attempts: {count}', {\n count: String(mapping.tlsRetryCount),\n })}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {t(\n 'customer_accounts.domainMapping.tls.diagnostics.operatorNote',\n 'We are retrying automatically. If this persists, contact platform support \u2014 your DNS is fine, this is on our side.',\n )}\n </p>\n </div>\n </AlertDescription>\n </Alert>\n )\n}\n"],
5
+ "mappings": ";AAiBM,cAQM,YARN;AAdN,SAAS,qBAAqB;AAC9B,SAAS,OAAO,YAAY,wBAAwB;AACpD,SAAS,YAAY;AAOd,SAAS,eAAe,EAAE,QAAQ,GAAqB;AAC5D,QAAM,IAAI,KAAK;AACf,MAAI,QAAQ,WAAW,aAAc,QAAO;AAC5C,SACE,qBAAC,SAAM,SAAQ,eACb;AAAA,wBAAC,iBAAc,WAAU,WAAU,eAAW,MAAC;AAAA,IAC/C,oBAAC,cACE,YAAE,yDAAyD,yBAAyB,GACvF;AAAA,IACA,oBAAC,oBACC,+BAAC,SAAI,WAAU,aACZ;AAAA,cAAQ,mBAAmB,oBAAC,OAAG,kBAAQ,kBAAiB,IAAO;AAAA,MAC/D,QAAQ,cACP,qBAAC,QAAG,WAAU,4DACZ;AAAA,4BAAC,QAAG,WAAU,yBACX,YAAE,4DAA4D,iBAAiB,GAClF;AAAA,QACA,oBAAC,QAAG,WAAU,aAAa,kBAAQ,aAAY;AAAA,SACjD,IACE;AAAA,OACN,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,eAAe,EAAE,QAAQ,GAAqB;AAC5D,QAAM,IAAI,KAAK;AACf,MAAI,QAAQ,WAAW,aAAc,QAAO;AAC5C,SACE,qBAAC,SAAM,SAAQ,WACb;AAAA,wBAAC,iBAAc,WAAU,WAAU,eAAW,MAAC;AAAA,IAC/C,oBAAC,cACE,YAAE,yDAAyD,uBAAuB,GACrF;AAAA,IACA,oBAAC,oBACC,+BAAC,SAAI,WAAU,aACZ;AAAA,cAAQ,mBAAmB,oBAAC,OAAG,kBAAQ,kBAAiB,IAAO;AAAA,MAChE,oBAAC,OAAE,WAAU,iCACV,YAAE,8DAA8D,2BAA2B;AAAA,QAC1F,OAAO,OAAO,QAAQ,aAAa;AAAA,MACrC,CAAC,GACH;AAAA,MACA,oBAAC,OAAE,WAAU,iCACV;AAAA,QACC;AAAA,QACA;AAAA,MACF,GACF;AAAA,OACF,GACF;AAAA,KACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Copy, Check } from "lucide-react";
5
+ import { Button } from "@open-mercato/ui/primitives/button";
6
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
7
+ function CopyButton({ value, label }) {
8
+ const t = useT();
9
+ const [copied, setCopied] = React.useState(false);
10
+ const handleCopy = React.useCallback(async () => {
11
+ if (typeof navigator === "undefined" || !navigator.clipboard) return;
12
+ await navigator.clipboard.writeText(value);
13
+ setCopied(true);
14
+ window.setTimeout(() => setCopied(false), 1500);
15
+ }, [value]);
16
+ return /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: handleCopy, "aria-label": label, children: [
17
+ copied ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4", "aria-hidden": true }),
18
+ /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-xs", children: copied ? t("customer_accounts.domainMapping.copyTarget.copied", "Copied") : t("customer_accounts.domainMapping.copyTarget", "Copy") })
19
+ ] });
20
+ }
21
+ function DefaultDnsConfig({ hostname, cnameTarget, aRecordTarget }) {
22
+ const t = useT();
23
+ const exampleHost = hostname ?? t("customer_accounts.domainMapping.hostname.placeholder", "e.g., shop.yourdomain.com");
24
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4 rounded-lg border bg-muted/20 p-4", children: [
25
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
26
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: t("customer_accounts.domainMapping.cnameInstruction", "Add a CNAME record for {hostname} pointing to {target} in your DNS provider", {
27
+ hostname: exampleHost,
28
+ target: cnameTarget ?? "\u2014"
29
+ }) }),
30
+ cnameTarget ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-md border bg-background px-3 py-2", children: [
31
+ /* @__PURE__ */ jsx("code", { className: "flex-1 truncate font-mono text-sm", children: cnameTarget }),
32
+ /* @__PURE__ */ jsx(CopyButton, { value: cnameTarget, label: t("customer_accounts.domainMapping.copyTarget", "Copy") })
33
+ ] }) : null
34
+ ] }),
35
+ aRecordTarget ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
36
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("customer_accounts.domainMapping.aRecordInstruction", "For an apex domain, add an A record for {hostname} pointing to {target}", {
37
+ hostname: exampleHost,
38
+ target: aRecordTarget
39
+ }) }),
40
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-md border bg-background px-3 py-2", children: [
41
+ /* @__PURE__ */ jsx("code", { className: "flex-1 truncate font-mono text-sm", children: aRecordTarget }),
42
+ /* @__PURE__ */ jsx(CopyButton, { value: aRecordTarget, label: t("customer_accounts.domainMapping.copyTarget", "Copy") })
43
+ ] })
44
+ ] }) : null,
45
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("customer_accounts.domainMapping.propagationNote", "DNS changes can take up to 48 hours to propagate. The system checks automatically \u2014 you'll be notified when it's ready.") })
46
+ ] });
47
+ }
48
+ var DnsConfig_default = DefaultDnsConfig;
49
+ export {
50
+ DefaultDnsConfig,
51
+ DnsConfig_default as default
52
+ };
53
+ //# sourceMappingURL=DnsConfig.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DnsConfig.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Copy, Check } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type DnsConfigProps = {\n hostname: string | null\n cnameTarget: string | null\n aRecordTarget: string | null\n}\n\nfunction CopyButton({ value, label }: { value: string; label: string }) {\n const t = useT()\n const [copied, setCopied] = React.useState(false)\n\n const handleCopy = React.useCallback(async () => {\n if (typeof navigator === 'undefined' || !navigator.clipboard) return\n await navigator.clipboard.writeText(value)\n setCopied(true)\n window.setTimeout(() => setCopied(false), 1500)\n }, [value])\n\n return (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={handleCopy} aria-label={label}>\n {copied ? <Check className=\"h-4 w-4\" aria-hidden /> : <Copy className=\"h-4 w-4\" aria-hidden />}\n <span className=\"ml-1.5 text-xs\">\n {copied\n ? t('customer_accounts.domainMapping.copyTarget.copied', 'Copied')\n : t('customer_accounts.domainMapping.copyTarget', 'Copy')}\n </span>\n </Button>\n )\n}\n\nexport function DefaultDnsConfig({ hostname, cnameTarget, aRecordTarget }: DnsConfigProps) {\n const t = useT()\n const exampleHost = hostname ?? t('customer_accounts.domainMapping.hostname.placeholder', 'e.g., shop.yourdomain.com')\n\n return (\n <div className=\"space-y-4 rounded-lg border bg-muted/20 p-4\">\n <div className=\"space-y-2\">\n <p className=\"text-sm font-medium text-foreground\">\n {t('customer_accounts.domainMapping.cnameInstruction', 'Add a CNAME record for {hostname} pointing to {target} in your DNS provider', {\n hostname: exampleHost,\n target: cnameTarget ?? '\u2014',\n })}\n </p>\n {cnameTarget ? (\n <div className=\"flex items-center gap-2 rounded-md border bg-background px-3 py-2\">\n <code className=\"flex-1 truncate font-mono text-sm\">{cnameTarget}</code>\n <CopyButton value={cnameTarget} label={t('customer_accounts.domainMapping.copyTarget', 'Copy')} />\n </div>\n ) : null}\n </div>\n {aRecordTarget ? (\n <div className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">\n {t('customer_accounts.domainMapping.aRecordInstruction', 'For an apex domain, add an A record for {hostname} pointing to {target}', {\n hostname: exampleHost,\n target: aRecordTarget,\n })}\n </p>\n <div className=\"flex items-center gap-2 rounded-md border bg-background px-3 py-2\">\n <code className=\"flex-1 truncate font-mono text-sm\">{aRecordTarget}</code>\n <CopyButton value={aRecordTarget} label={t('customer_accounts.domainMapping.copyTarget', 'Copy')} />\n </div>\n </div>\n ) : null}\n <p className=\"text-xs text-muted-foreground\">\n {t('customer_accounts.domainMapping.propagationNote', 'DNS changes can take up to 48 hours to propagate. The system checks automatically \u2014 you\\'ll be notified when it\\'s ready.')}\n </p>\n </div>\n )\n}\n\nexport default DefaultDnsConfig\n"],
5
+ "mappings": ";AAyBI,SACY,KADZ;AAvBJ,YAAY,WAAW;AACvB,SAAS,MAAM,aAAa;AAC5B,SAAS,cAAc;AACvB,SAAS,YAAY;AAQrB,SAAS,WAAW,EAAE,OAAO,MAAM,GAAqC;AACtE,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,KAAK;AAEhD,QAAM,aAAa,MAAM,YAAY,YAAY;AAC/C,QAAI,OAAO,cAAc,eAAe,CAAC,UAAU,UAAW;AAC9D,UAAM,UAAU,UAAU,UAAU,KAAK;AACzC,cAAU,IAAI;AACd,WAAO,WAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,EAChD,GAAG,CAAC,KAAK,CAAC;AAEV,SACE,qBAAC,UAAO,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,SAAS,YAAY,cAAY,OAC9E;AAAA,aAAS,oBAAC,SAAM,WAAU,WAAU,eAAW,MAAC,IAAK,oBAAC,QAAK,WAAU,WAAU,eAAW,MAAC;AAAA,IAC5F,oBAAC,UAAK,WAAU,kBACb,mBACG,EAAE,qDAAqD,QAAQ,IAC/D,EAAE,8CAA8C,MAAM,GAC5D;AAAA,KACF;AAEJ;AAEO,SAAS,iBAAiB,EAAE,UAAU,aAAa,cAAc,GAAmB;AACzF,QAAM,IAAI,KAAK;AACf,QAAM,cAAc,YAAY,EAAE,wDAAwD,2BAA2B;AAErH,SACE,qBAAC,SAAI,WAAU,+CACb;AAAA,yBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,OAAE,WAAU,uCACV,YAAE,oDAAoD,+EAA+E;AAAA,QACpI,UAAU;AAAA,QACV,QAAQ,eAAe;AAAA,MACzB,CAAC,GACH;AAAA,MACC,cACC,qBAAC,SAAI,WAAU,qEACb;AAAA,4BAAC,UAAK,WAAU,qCAAqC,uBAAY;AAAA,QACjE,oBAAC,cAAW,OAAO,aAAa,OAAO,EAAE,8CAA8C,MAAM,GAAG;AAAA,SAClG,IACE;AAAA,OACN;AAAA,IACC,gBACC,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,OAAE,WAAU,iCACV,YAAE,sDAAsD,2EAA2E;AAAA,QAClI,UAAU;AAAA,QACV,QAAQ;AAAA,MACV,CAAC,GACH;AAAA,MACA,qBAAC,SAAI,WAAU,qEACb;AAAA,4BAAC,UAAK,WAAU,qCAAqC,yBAAc;AAAA,QACnE,oBAAC,cAAW,OAAO,eAAe,OAAO,EAAE,8CAA8C,MAAM,GAAG;AAAA,SACpG;AAAA,OACF,IACE;AAAA,IACJ,oBAAC,OAAE,WAAU,iCACV,YAAE,mDAAmD,8HAA2H,GACnL;AAAA,KACF;AAEJ;AAEA,IAAO,oBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useRegisteredComponent } from "@open-mercato/ui/backend/injection/useRegisteredComponent";
4
+ import { Tag } from "@open-mercato/ui/primitives/tag";
5
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
+ import { DefaultStepper } from "./Stepper.js";
7
+ import { DefaultStatusBadge } from "./StatusBadgeSection.js";
8
+ import { DefaultDnsConfig } from "./DnsConfig.js";
9
+ import { DefaultActions } from "./Actions.js";
10
+ import { DnsDiagnostics, TlsDiagnostics } from "./Diagnostics.js";
11
+ function DomainPanel(props) {
12
+ const t = useT();
13
+ const Stepper = useRegisteredComponent(
14
+ "section:customer_accounts.domain-settings:stepper",
15
+ DefaultStepper
16
+ );
17
+ const StatusBadgeSection = useRegisteredComponent(
18
+ "section:customer_accounts.domain-settings:status",
19
+ DefaultStatusBadge
20
+ );
21
+ const DnsConfig = useRegisteredComponent(
22
+ "section:customer_accounts.domain-settings:dns-config",
23
+ DefaultDnsConfig
24
+ );
25
+ const Actions = useRegisteredComponent(
26
+ "section:customer_accounts.domain-settings:actions",
27
+ DefaultActions
28
+ );
29
+ const { mapping, isReplacement, cnameTarget, aRecordTarget } = props;
30
+ const showDnsConfig = mapping.status !== "active";
31
+ return /* @__PURE__ */ jsxs("section", { className: "space-y-4 rounded-xl border bg-card p-6 shadow-sm", children: [
32
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-start justify-between gap-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
33
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
34
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold tracking-tight", children: mapping.hostname }),
35
+ isReplacement ? /* @__PURE__ */ jsx(Tag, { variant: "info", dot: true, children: t("customer_accounts.domainMapping.replacement.label", "Replacement (waiting to activate)") }) : null
36
+ ] }),
37
+ /* @__PURE__ */ jsx(StatusBadgeSection, { mapping })
38
+ ] }) }),
39
+ /* @__PURE__ */ jsx(Stepper, { status: mapping.status }),
40
+ /* @__PURE__ */ jsx(DnsDiagnostics, { mapping }),
41
+ /* @__PURE__ */ jsx(TlsDiagnostics, { mapping }),
42
+ showDnsConfig ? /* @__PURE__ */ jsx(
43
+ DnsConfig,
44
+ {
45
+ hostname: mapping.hostname,
46
+ cnameTarget: mapping.cnameTarget ?? cnameTarget,
47
+ aRecordTarget: mapping.aRecordTarget ?? aRecordTarget
48
+ }
49
+ ) : null,
50
+ /* @__PURE__ */ jsx(
51
+ Actions,
52
+ {
53
+ mapping,
54
+ isReplacement,
55
+ busy: props.busy,
56
+ onCheckNow: props.onCheckNow,
57
+ onRetryTls: props.onRetryTls,
58
+ onChangeDomain: props.onChangeDomain,
59
+ onRemove: props.onRemove
60
+ }
61
+ )
62
+ ] });
63
+ }
64
+ var DomainPanel_default = DomainPanel;
65
+ export {
66
+ DomainPanel,
67
+ DomainPanel_default as default
68
+ };
69
+ //# sourceMappingURL=DomainPanel.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/DomainPanel.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRegisteredComponent } from '@open-mercato/ui/backend/injection/useRegisteredComponent'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DefaultStepper, type StepperProps } from './Stepper'\nimport { DefaultStatusBadge, type StatusBadgeSectionProps } from './StatusBadgeSection'\nimport { DefaultDnsConfig, type DnsConfigProps } from './DnsConfig'\nimport { DefaultActions, type ActionsProps } from './Actions'\nimport { DnsDiagnostics, TlsDiagnostics } from './Diagnostics'\nimport type { DomainMappingRow } from './types'\n\nexport type DomainPanelProps = {\n mapping: DomainMappingRow\n isReplacement: boolean\n cnameTarget: string | null\n aRecordTarget: string | null\n busy?: boolean\n onCheckNow: () => void\n onRetryTls: () => void\n onChangeDomain: () => void\n onRemove: () => void\n}\n\nexport function DomainPanel(props: DomainPanelProps) {\n const t = useT()\n const Stepper = useRegisteredComponent<StepperProps>(\n 'section:customer_accounts.domain-settings:stepper',\n DefaultStepper,\n )\n const StatusBadgeSection = useRegisteredComponent<StatusBadgeSectionProps>(\n 'section:customer_accounts.domain-settings:status',\n DefaultStatusBadge,\n )\n const DnsConfig = useRegisteredComponent<DnsConfigProps>(\n 'section:customer_accounts.domain-settings:dns-config',\n DefaultDnsConfig,\n )\n const Actions = useRegisteredComponent<ActionsProps>(\n 'section:customer_accounts.domain-settings:actions',\n DefaultActions,\n )\n\n const { mapping, isReplacement, cnameTarget, aRecordTarget } = props\n const showDnsConfig = mapping.status !== 'active'\n\n return (\n <section className=\"space-y-4 rounded-xl border bg-card p-6 shadow-sm\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"text-lg font-semibold tracking-tight\">{mapping.hostname}</h3>\n {isReplacement ? (\n <Tag variant=\"info\" dot>\n {t('customer_accounts.domainMapping.replacement.label', 'Replacement (waiting to activate)')}\n </Tag>\n ) : null}\n </div>\n <StatusBadgeSection mapping={mapping} />\n </div>\n </div>\n\n <Stepper status={mapping.status} />\n\n <DnsDiagnostics mapping={mapping} />\n <TlsDiagnostics mapping={mapping} />\n\n {showDnsConfig ? (\n <DnsConfig\n hostname={mapping.hostname}\n cnameTarget={mapping.cnameTarget ?? cnameTarget}\n aRecordTarget={mapping.aRecordTarget ?? aRecordTarget}\n />\n ) : null}\n\n <Actions\n mapping={mapping}\n isReplacement={isReplacement}\n busy={props.busy}\n onCheckNow={props.onCheckNow}\n onRetryTls={props.onRetryTls}\n onChangeDomain={props.onChangeDomain}\n onRemove={props.onRemove}\n />\n </section>\n )\n}\n\nexport default DomainPanel\n"],
5
+ "mappings": ";AAmDU,SACE,KADF;AAhDV,SAAS,8BAA8B;AACvC,SAAS,WAAW;AACpB,SAAS,YAAY;AACrB,SAAS,sBAAyC;AAClD,SAAS,0BAAwD;AACjE,SAAS,wBAA6C;AACtD,SAAS,sBAAyC;AAClD,SAAS,gBAAgB,sBAAsB;AAexC,SAAS,YAAY,OAAyB;AACnD,QAAM,IAAI,KAAK;AACf,QAAM,UAAU;AAAA,IACd;AAAA,IACA;AAAA,EACF;AACA,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACA,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU;AAAA,IACd;AAAA,IACA;AAAA,EACF;AAEA,QAAM,EAAE,SAAS,eAAe,aAAa,cAAc,IAAI;AAC/D,QAAM,gBAAgB,QAAQ,WAAW;AAEzC,SACE,qBAAC,aAAQ,WAAU,qDACjB;AAAA,wBAAC,SAAI,WAAU,oDACb,+BAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,QAAG,WAAU,wCAAwC,kBAAQ,UAAS;AAAA,QACtE,gBACC,oBAAC,OAAI,SAAQ,QAAO,KAAG,MACpB,YAAE,qDAAqD,mCAAmC,GAC7F,IACE;AAAA,SACN;AAAA,MACA,oBAAC,sBAAmB,SAAkB;AAAA,OACxC,GACF;AAAA,IAEA,oBAAC,WAAQ,QAAQ,QAAQ,QAAQ;AAAA,IAEjC,oBAAC,kBAAe,SAAkB;AAAA,IAClC,oBAAC,kBAAe,SAAkB;AAAA,IAEjC,gBACC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,QAAQ;AAAA,QAClB,aAAa,QAAQ,eAAe;AAAA,QACpC,eAAe,QAAQ,iBAAiB;AAAA;AAAA,IAC1C,IACE;AAAA,IAEJ;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,MAAM,MAAM;AAAA,QACZ,YAAY,MAAM;AAAA,QAClB,YAAY,MAAM;AAAA,QAClB,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA;AAAA,IAClB;AAAA,KACF;AAEJ;AAEA,IAAO,sBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
4
+ function OrgSwitcher({ options, selectedId, onChange }) {
5
+ const t = useT();
6
+ if (options.length <= 1) return null;
7
+ return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
8
+ /* @__PURE__ */ jsx("span", { children: t("customer_accounts.domainMapping.orgSwitcher.label", "Organization") }),
9
+ /* @__PURE__ */ jsx(
10
+ "select",
11
+ {
12
+ className: "h-9 rounded-md border border-input bg-background px-3 text-sm text-foreground shadow-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40",
13
+ value: selectedId ?? "",
14
+ onChange: (event) => onChange(event.target.value),
15
+ children: options.map((opt) => {
16
+ const indent = opt.depth > 0 ? "\xA0\xA0".repeat(opt.depth) : "";
17
+ return /* @__PURE__ */ jsxs("option", { value: opt.id, children: [
18
+ indent,
19
+ opt.label
20
+ ] }, opt.id);
21
+ })
22
+ }
23
+ )
24
+ ] });
25
+ }
26
+ var OrgSwitcher_default = OrgSwitcher;
27
+ export {
28
+ OrgSwitcher,
29
+ OrgSwitcher_default as default
30
+ };
31
+ //# sourceMappingURL=OrgSwitcher.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/OrgSwitcher.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type OrgOption = {\n id: string\n label: string\n depth: number\n}\n\nexport type OrgSwitcherProps = {\n options: OrgOption[]\n selectedId: string | null\n onChange: (next: string) => void\n}\n\nexport function OrgSwitcher({ options, selectedId, onChange }: OrgSwitcherProps) {\n const t = useT()\n if (options.length <= 1) return null\n return (\n <label className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <span>{t('customer_accounts.domainMapping.orgSwitcher.label', 'Organization')}</span>\n <select\n className=\"h-9 rounded-md border border-input bg-background px-3 text-sm text-foreground shadow-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40\"\n value={selectedId ?? ''}\n onChange={(event) => onChange(event.target.value)}\n >\n {options.map((opt) => {\n const indent = opt.depth > 0 ? '\u00A0\u00A0'.repeat(opt.depth) : ''\n return (\n <option key={opt.id} value={opt.id}>\n {indent}\n {opt.label}\n </option>\n )\n })}\n </select>\n </label>\n )\n}\n\nexport default OrgSwitcher\n"],
5
+ "mappings": ";AAsBM,cASM,YATN;AAnBN,SAAS,YAAY;AAcd,SAAS,YAAY,EAAE,SAAS,YAAY,SAAS,GAAqB;AAC/E,QAAM,IAAI,KAAK;AACf,MAAI,QAAQ,UAAU,EAAG,QAAO;AAChC,SACE,qBAAC,WAAM,WAAU,yDACf;AAAA,wBAAC,UAAM,YAAE,qDAAqD,cAAc,GAAE;AAAA,IAC9E;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,cAAc;AAAA,QACrB,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QAE/C,kBAAQ,IAAI,CAAC,QAAQ;AACpB,gBAAM,SAAS,IAAI,QAAQ,IAAI,WAAK,OAAO,IAAI,KAAK,IAAI;AACxD,iBACE,qBAAC,YAAoB,OAAO,IAAI,IAC7B;AAAA;AAAA,YACA,IAAI;AAAA,eAFM,IAAI,EAGjB;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAEA,IAAO,sBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,147 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import {
5
+ Dialog,
6
+ DialogContent,
7
+ DialogDescription,
8
+ DialogFooter,
9
+ DialogHeader,
10
+ DialogTitle
11
+ } from "@open-mercato/ui/primitives/dialog";
12
+ import { Button } from "@open-mercato/ui/primitives/button";
13
+ import { Input } from "@open-mercato/ui/primitives/input";
14
+ import { Label } from "@open-mercato/ui/primitives/label";
15
+ import { KbdShortcut } from "@open-mercato/ui/primitives/kbd";
16
+ import { Spinner } from "@open-mercato/ui/primitives/spinner";
17
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
18
+ const HOSTNAME_BASIC = /^[a-z0-9.-]+$/i;
19
+ function RegisterDialog({
20
+ open,
21
+ onOpenChange,
22
+ mode,
23
+ currentHostname,
24
+ onSubmit,
25
+ initialError
26
+ }) {
27
+ const t = useT();
28
+ const [hostname, setHostname] = React.useState("");
29
+ const [error, setError] = React.useState(initialError ?? null);
30
+ const [submitting, setSubmitting] = React.useState(false);
31
+ const inputRef = React.useRef(null);
32
+ React.useEffect(() => {
33
+ if (!open) {
34
+ setHostname("");
35
+ setError(null);
36
+ setSubmitting(false);
37
+ return;
38
+ }
39
+ setError(initialError ?? null);
40
+ window.setTimeout(() => inputRef.current?.focus(), 0);
41
+ }, [open, initialError]);
42
+ const validate = React.useCallback(
43
+ (value) => {
44
+ const trimmed = value.trim();
45
+ if (!trimmed) return t("customer_accounts.domainMapping.errors.required", "Domain is required");
46
+ if (trimmed.length > 253) return t("customer_accounts.domainMapping.hostname.validation.invalid", "Enter a valid domain name (no protocol, path, or port)");
47
+ if (trimmed.includes("://") || trimmed.includes("/") || trimmed.includes(":")) {
48
+ return t("customer_accounts.domainMapping.hostname.validation.invalid", "Enter a valid domain name (no protocol, path, or port)");
49
+ }
50
+ if (!HOSTNAME_BASIC.test(trimmed) && !/^xn--/i.test(trimmed)) {
51
+ return t("customer_accounts.domainMapping.hostname.validation.invalid", "Enter a valid domain name (no protocol, path, or port)");
52
+ }
53
+ return null;
54
+ },
55
+ [t]
56
+ );
57
+ const handleSubmit = React.useCallback(
58
+ async (event) => {
59
+ event.preventDefault();
60
+ const validation = validate(hostname);
61
+ if (validation) {
62
+ setError(validation);
63
+ return;
64
+ }
65
+ setSubmitting(true);
66
+ setError(null);
67
+ try {
68
+ await onSubmit(hostname.trim());
69
+ } catch (err) {
70
+ const message = err instanceof Error ? err.message : "Submission failed";
71
+ setError(message);
72
+ } finally {
73
+ setSubmitting(false);
74
+ }
75
+ },
76
+ [hostname, onSubmit, validate]
77
+ );
78
+ const handleKeyDown = React.useCallback(
79
+ (event) => {
80
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
81
+ event.preventDefault();
82
+ handleSubmit(event);
83
+ }
84
+ },
85
+ [handleSubmit]
86
+ );
87
+ const title = mode === "change" ? t("customer_accounts.domainMapping.dialog.change.title", "Change custom domain") : t("customer_accounts.domainMapping.dialog.register.title", "Register custom domain");
88
+ const description = mode === "change" && currentHostname ? t(
89
+ "customer_accounts.domainMapping.changeDomain.description",
90
+ "Your current domain ({hostname}) will stay active until the new domain is fully set up. No downtime for your customers.",
91
+ { hostname: currentHostname }
92
+ ) : t("customer_accounts.domainMapping.description", "Map your own domain to the customer portal");
93
+ const submitLabel = mode === "change" ? t("customer_accounts.domainMapping.dialog.change.submit", "Start replacement") : t("customer_accounts.domainMapping.dialog.register.submit", "Register");
94
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { children: [
95
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
96
+ /* @__PURE__ */ jsx(DialogTitle, { children: title }),
97
+ /* @__PURE__ */ jsx(DialogDescription, { children: description })
98
+ ] }),
99
+ /* @__PURE__ */ jsxs("form", { className: "space-y-4", onSubmit: handleSubmit, onKeyDown: handleKeyDown, children: [
100
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
101
+ /* @__PURE__ */ jsx(Label, { htmlFor: "custom-domain-hostname", children: t("customer_accounts.domainMapping.hostname.label", "Domain") }),
102
+ /* @__PURE__ */ jsx(
103
+ Input,
104
+ {
105
+ id: "custom-domain-hostname",
106
+ ref: inputRef,
107
+ value: hostname,
108
+ autoComplete: "off",
109
+ spellCheck: false,
110
+ placeholder: t("customer_accounts.domainMapping.hostname.placeholder", "e.g., shop.yourdomain.com"),
111
+ onChange: (event) => {
112
+ setHostname(event.target.value);
113
+ if (error) setError(null);
114
+ },
115
+ "aria-invalid": error ? true : void 0,
116
+ disabled: submitting
117
+ }
118
+ ),
119
+ error ? /* @__PURE__ */ jsx("p", { className: "text-sm text-status-error-text", role: "alert", children: error }) : null
120
+ ] }),
121
+ /* @__PURE__ */ jsxs(DialogFooter, { className: "items-center", children: [
122
+ /* @__PURE__ */ jsx("span", { className: "hidden text-xs text-muted-foreground sm:inline-flex sm:items-center sm:gap-1", children: /* @__PURE__ */ jsx(KbdShortcut, { keys: ["\u2318", "Enter"] }) }),
123
+ /* @__PURE__ */ jsx(
124
+ Button,
125
+ {
126
+ type: "button",
127
+ variant: "ghost",
128
+ size: "default",
129
+ onClick: () => onOpenChange(false),
130
+ disabled: submitting,
131
+ children: t("customer_accounts.domainMapping.dialog.cancel", "Cancel")
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsxs(Button, { type: "submit", size: "default", disabled: submitting, children: [
135
+ submitting ? /* @__PURE__ */ jsx(Spinner, { className: "mr-2 h-4 w-4" }) : null,
136
+ submitLabel
137
+ ] })
138
+ ] })
139
+ ] })
140
+ ] }) });
141
+ }
142
+ var RegisterDialog_default = RegisterDialog;
143
+ export {
144
+ RegisterDialog,
145
+ RegisterDialog_default as default
146
+ };
147
+ //# sourceMappingURL=RegisterDialog.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../src/modules/customer_accounts/backend/customer_accounts/settings/domain/components/RegisterDialog.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { KbdShortcut } from '@open-mercato/ui/primitives/kbd'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type RegisterDialogProps = {\n open: boolean\n onOpenChange: (next: boolean) => void\n mode: 'register' | 'change'\n currentHostname?: string | null\n onSubmit: (hostname: string) => Promise<void>\n initialError?: string | null\n}\n\nconst HOSTNAME_BASIC = /^[a-z0-9.-]+$/i\n\nexport function RegisterDialog({\n open,\n onOpenChange,\n mode,\n currentHostname,\n onSubmit,\n initialError,\n}: RegisterDialogProps) {\n const t = useT()\n const [hostname, setHostname] = React.useState('')\n const [error, setError] = React.useState<string | null>(initialError ?? null)\n const [submitting, setSubmitting] = React.useState(false)\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n React.useEffect(() => {\n if (!open) {\n setHostname('')\n setError(null)\n setSubmitting(false)\n return\n }\n setError(initialError ?? null)\n window.setTimeout(() => inputRef.current?.focus(), 0)\n }, [open, initialError])\n\n const validate = React.useCallback(\n (value: string): string | null => {\n const trimmed = value.trim()\n if (!trimmed) return t('customer_accounts.domainMapping.errors.required', 'Domain is required')\n if (trimmed.length > 253) return t('customer_accounts.domainMapping.hostname.validation.invalid', 'Enter a valid domain name (no protocol, path, or port)')\n if (trimmed.includes('://') || trimmed.includes('/') || trimmed.includes(':')) {\n return t('customer_accounts.domainMapping.hostname.validation.invalid', 'Enter a valid domain name (no protocol, path, or port)')\n }\n if (!HOSTNAME_BASIC.test(trimmed) && !/^xn--/i.test(trimmed)) {\n return t('customer_accounts.domainMapping.hostname.validation.invalid', 'Enter a valid domain name (no protocol, path, or port)')\n }\n return null\n },\n [t],\n )\n\n const handleSubmit = React.useCallback(\n async (event: React.FormEvent) => {\n event.preventDefault()\n const validation = validate(hostname)\n if (validation) {\n setError(validation)\n return\n }\n setSubmitting(true)\n setError(null)\n try {\n await onSubmit(hostname.trim())\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Submission failed'\n setError(message)\n } finally {\n setSubmitting(false)\n }\n },\n [hostname, onSubmit, validate],\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLFormElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n handleSubmit(event)\n }\n },\n [handleSubmit],\n )\n\n const title =\n mode === 'change'\n ? t('customer_accounts.domainMapping.dialog.change.title', 'Change custom domain')\n : t('customer_accounts.domainMapping.dialog.register.title', 'Register custom domain')\n\n const description =\n mode === 'change' && currentHostname\n ? t(\n 'customer_accounts.domainMapping.changeDomain.description',\n 'Your current domain ({hostname}) will stay active until the new domain is fully set up. No downtime for your customers.',\n { hostname: currentHostname },\n )\n : t('customer_accounts.domainMapping.description', 'Map your own domain to the customer portal')\n\n const submitLabel =\n mode === 'change'\n ? t('customer_accounts.domainMapping.dialog.change.submit', 'Start replacement')\n : t('customer_accounts.domainMapping.dialog.register.submit', 'Register')\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <form className=\"space-y-4\" onSubmit={handleSubmit} onKeyDown={handleKeyDown}>\n <div className=\"space-y-2\">\n <Label htmlFor=\"custom-domain-hostname\">\n {t('customer_accounts.domainMapping.hostname.label', 'Domain')}\n </Label>\n <Input\n id=\"custom-domain-hostname\"\n ref={inputRef}\n value={hostname}\n autoComplete=\"off\"\n spellCheck={false}\n placeholder={t('customer_accounts.domainMapping.hostname.placeholder', 'e.g., shop.yourdomain.com')}\n onChange={(event) => {\n setHostname(event.target.value)\n if (error) setError(null)\n }}\n aria-invalid={error ? true : undefined}\n disabled={submitting}\n />\n {error ? (\n <p className=\"text-sm text-status-error-text\" role=\"alert\">\n {error}\n </p>\n ) : null}\n </div>\n <DialogFooter className=\"items-center\">\n <span className=\"hidden text-xs text-muted-foreground sm:inline-flex sm:items-center sm:gap-1\">\n <KbdShortcut keys={['\u2318', 'Enter']} />\n </span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"default\"\n onClick={() => onOpenChange(false)}\n disabled={submitting}\n >\n {t('customer_accounts.domainMapping.dialog.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" size=\"default\" disabled={submitting}>\n {submitting ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {submitLabel}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n\nexport default RegisterDialog\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }