@open-mercato/core 0.6.8-develop.6918.1.7b3f32b0c8 → 0.6.8-develop.6925.1.cefa200fa4

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 (95) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/bootstrap.js +2 -1
  3. package/dist/bootstrap.js.map +2 -2
  4. package/dist/generated/entities/role/index.js +2 -0
  5. package/dist/generated/entities/role/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +1 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/helpers/integration/api.js +4 -0
  9. package/dist/helpers/integration/api.js.map +2 -2
  10. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +5 -0
  11. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
  12. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js +5 -0
  13. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js.map +2 -2
  14. package/dist/modules/audit_logs/backend/audit-logs/page.js +4 -4
  15. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  16. package/dist/modules/audit_logs/components/AuditLogsActions.js +9 -2
  17. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  18. package/dist/modules/auth/api/login.js +5 -2
  19. package/dist/modules/auth/api/login.js.map +2 -2
  20. package/dist/modules/auth/api/users/route.js +8 -5
  21. package/dist/modules/auth/api/users/route.js.map +2 -2
  22. package/dist/modules/auth/backend/users/[id]/edit/page.js +15 -1
  23. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  24. package/dist/modules/auth/backend/users/page.js +7 -1
  25. package/dist/modules/auth/backend/users/page.js.map +2 -2
  26. package/dist/modules/auth/commands/users.js +175 -76
  27. package/dist/modules/auth/commands/users.js.map +2 -2
  28. package/dist/modules/auth/data/entities.js +4 -0
  29. package/dist/modules/auth/data/entities.js.map +2 -2
  30. package/dist/modules/auth/lib/sessionIntegrity.js +1 -1
  31. package/dist/modules/auth/lib/sessionIntegrity.js.map +2 -2
  32. package/dist/modules/auth/lib/setup-app.js +1 -1
  33. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  34. package/dist/modules/auth/migrations/Migration20260728134212_auth.js +14 -0
  35. package/dist/modules/auth/migrations/Migration20260728134212_auth.js.map +7 -0
  36. package/dist/modules/catalog/search.js +8 -0
  37. package/dist/modules/catalog/search.js.map +2 -2
  38. package/dist/modules/customer_accounts/search.js +2 -0
  39. package/dist/modules/customer_accounts/search.js.map +2 -2
  40. package/dist/modules/customers/commands/deals.js +55 -8
  41. package/dist/modules/customers/commands/deals.js.map +2 -2
  42. package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js +1 -1
  43. package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js.map +2 -2
  44. package/dist/modules/customers/components/formConfig.js +2 -0
  45. package/dist/modules/customers/components/formConfig.js.map +2 -2
  46. package/dist/modules/inbox_ops/search.js +1 -0
  47. package/dist/modules/inbox_ops/search.js.map +2 -2
  48. package/dist/modules/messages/search.js +2 -1
  49. package/dist/modules/messages/search.js.map +2 -2
  50. package/dist/modules/planner/search.js +1 -0
  51. package/dist/modules/planner/search.js.map +2 -2
  52. package/dist/modules/resources/search.js +2 -0
  53. package/dist/modules/resources/search.js.map +2 -2
  54. package/dist/modules/sales/search.js +24 -2
  55. package/dist/modules/sales/search.js.map +2 -2
  56. package/dist/modules/staff/search.js +4 -0
  57. package/dist/modules/staff/search.js.map +2 -2
  58. package/dist/modules/wms/search.js +4 -0
  59. package/dist/modules/wms/search.js.map +2 -2
  60. package/generated/entities/role/index.ts +1 -0
  61. package/generated/entity-fields-registry.ts +1 -0
  62. package/package.json +7 -7
  63. package/src/bootstrap.ts +9 -2
  64. package/src/helpers/integration/api.ts +13 -0
  65. package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +7 -0
  66. package/src/modules/audit_logs/api/audit-logs/actions/undo/route.ts +9 -0
  67. package/src/modules/audit_logs/backend/audit-logs/page.tsx +4 -4
  68. package/src/modules/audit_logs/components/AuditLogsActions.tsx +20 -4
  69. package/src/modules/auth/api/login.ts +9 -2
  70. package/src/modules/auth/api/users/route.ts +8 -4
  71. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -1
  72. package/src/modules/auth/backend/users/page.tsx +11 -0
  73. package/src/modules/auth/commands/users.ts +251 -85
  74. package/src/modules/auth/data/entities.ts +3 -0
  75. package/src/modules/auth/i18n/de.json +6 -0
  76. package/src/modules/auth/i18n/en.json +6 -0
  77. package/src/modules/auth/i18n/es.json +6 -0
  78. package/src/modules/auth/i18n/ko.json +6 -0
  79. package/src/modules/auth/i18n/pl.json +6 -0
  80. package/src/modules/auth/lib/sessionIntegrity.ts +1 -1
  81. package/src/modules/auth/lib/setup-app.ts +1 -1
  82. package/src/modules/auth/migrations/.snapshot-open-mercato.json +16 -0
  83. package/src/modules/auth/migrations/Migration20260728134212_auth.ts +14 -0
  84. package/src/modules/catalog/search.ts +8 -0
  85. package/src/modules/customer_accounts/search.ts +2 -0
  86. package/src/modules/customers/commands/deals.ts +86 -14
  87. package/src/modules/customers/components/detail/create/dealCustomFieldControl.tsx +1 -1
  88. package/src/modules/customers/components/formConfig.tsx +2 -0
  89. package/src/modules/inbox_ops/search.ts +1 -0
  90. package/src/modules/messages/search.ts +2 -1
  91. package/src/modules/planner/search.ts +1 -0
  92. package/src/modules/resources/search.ts +2 -0
  93. package/src/modules/sales/search.ts +24 -2
  94. package/src/modules/staff/search.ts +4 -0
  95. package/src/modules/wms/search.ts +4 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/lib/setup-app.ts"],
4
- "sourcesContent": ["import { hash } from 'bcryptjs'\nimport { randomBytes } from 'node:crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { Role, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { Tenant, Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'\nimport { normalizeTenantId } from './tenantAccess'\nimport { computeEmailHash, emailHashLookupValues } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { getDefaultEncryptionMaps, type Module } from '@open-mercato/shared/modules/registry'\nimport { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { EncryptionMap } from '@open-mercato/core/modules/entities/data/entities'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'setup' })\n\nconst DEFAULT_ROLE_NAMES = ['employee', 'admin', 'superadmin'] as const\nconst DEMO_SUPERADMIN_EMAIL = 'superadmin@acme.com'\nconst DEFAULT_DERIVED_EMAIL_DOMAIN = DEMO_SUPERADMIN_EMAIL.split('@')[1] ?? 'acme.com'\n\nexport type EnsureRolesOptions = {\n roleNames?: string[]\n tenantId?: string\n}\n\nasync function ensureRolesInContext(\n em: EntityManager,\n roleNames: string[],\n tenantId: string,\n) {\n for (const name of roleNames) {\n const existing = await findOneWithDecryption(em, Role, { name, tenantId }, {}, { tenantId, organizationId: null })\n if (existing) continue\n em.persist(em.create(Role, { name, tenantId, createdAt: new Date() }))\n }\n}\n\nexport async function ensureRoles(em: EntityManager, options: EnsureRolesOptions = {}) {\n const roleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const tenantId = normalizeTenantId(options.tenantId ?? null)\n if (!tenantId) {\n throw new Error('ensureRoles requires a tenantId \u2014 global roles are not supported')\n }\n await em.transactional(async (tem) => {\n await ensureRolesInContext(tem, roleNames, tenantId)\n await tem.flush()\n })\n}\n\nasync function findRoleByName(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role | null> {\n const normalizedTenant = normalizeTenantId(tenantId ?? null) ?? null\n return findOneWithDecryption(em, Role, { name, tenantId: normalizedTenant }, {}, { tenantId: normalizedTenant, organizationId: null })\n}\n\nasync function findRoleByNameOrFail(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role> {\n const role = await findRoleByName(em, name, tenantId)\n if (!role) throw new Error(`ROLE_NOT_FOUND:${name}`)\n return role\n}\n\ntype PrimaryUserInput = {\n email: string\n password?: string\n hashedPassword?: string | null\n firstName?: string | null\n lastName?: string | null\n displayName?: string | null\n confirm?: boolean\n}\n\nconst DERIVED_EMAIL_ENV = {\n admin: 'OM_INIT_ADMIN_EMAIL',\n employee: 'OM_INIT_EMPLOYEE_EMAIL',\n} as const\n\nexport type DemoUserRole = 'superadmin' | 'admin' | 'employee'\nexport type DemoUserEmail = { role: DemoUserRole; email: string }\n\n/**\n * Returns the canonical list of demo user emails the setup path may have\n * seeded. Honors OM_INIT_ADMIN_EMAIL / OM_INIT_EMPLOYEE_EMAIL exactly the\n * same way the derived-user seeding branch does, so the deactivation loop\n * never drifts from the seeding loop.\n *\n * Pure function \u2014 no side effects, safe to unit-test in isolation.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport function resolveDemoUserEmails(): DemoUserEmail[] {\n const adminEmail = readEnvValue(DERIVED_EMAIL_ENV.admin) ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = readEnvValue(DERIVED_EMAIL_ENV.employee) ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n return [\n { role: 'superadmin', email: DEMO_SUPERADMIN_EMAIL },\n { role: 'admin', email: adminEmail },\n { role: 'employee', email: employeeEmail },\n ]\n}\n\nexport type SetupInitialTenantOptions = {\n orgName: string\n primaryUser: PrimaryUserInput\n roleNames?: string[]\n includeDerivedUsers?: boolean\n failIfUserExists?: boolean\n primaryUserRoles?: string[]\n includeSuperadminRole?: boolean\n /** Optional list of enabled modules. When provided, module setup hooks are called. */\n modules?: Module[]\n /**\n * Optional global slug to persist on the new Organization. When set, a\n * pre-flight uniqueness check across all tenants throws OrgSlugExistsError\n * on collision so scriptable callers can fail loudly instead of silently\n * reusing or clobbering an existing organization.\n */\n orgSlug?: string\n /**\n * Opt-in flag that allows seeding the derived admin/employee accounts when\n * the OM_INIT_ADMIN_PASSWORD / OM_INIT_EMPLOYEE_PASSWORD env vars are unset.\n *\n * - In non-production (`NODE_ENV !== 'production'`): the demo accounts are\n * seeded with the well-known `'secret'` password so local dev workflows\n * (e.g. `mercato init`) stay predictable for developers.\n * - In production: the fallback uses a randomly generated 96-bit password\n * (printed once by the CLI) so an operator who deliberately opts in still\n * avoids the historical hardcoded credential. When this flag is false/unset\n * in production and the env vars are missing, `DerivedUserPasswordRequiredError`\n * is thrown instead of silently seeding any account.\n */\n allowDemoDerivedPasswords?: boolean\n}\n\nexport class OrgSlugExistsError extends Error {\n constructor(public readonly slug: string) {\n super(`ORG_SLUG_EXISTS: an organization with slug \"${slug}\" already exists`)\n this.name = 'OrgSlugExistsError'\n }\n}\n\nexport class DerivedUserPasswordRequiredError extends Error {\n constructor(public readonly missing: string[]) {\n super(\n `DERIVED_USER_PASSWORD_REQUIRED: missing ${missing.join(', ')} (set the env vars, pass allowDemoDerivedPasswords: true / --include-demo-users in non-production, or disable derived user seeding)`,\n )\n this.name = 'DerivedUserPasswordRequiredError'\n }\n}\n\nexport type SetupInitialTenantResult = {\n tenantId: string\n organizationId: string\n users: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }>\n reusedExistingUser: boolean\n}\n\nexport async function setupInitialTenant(\n em: EntityManager,\n options: SetupInitialTenantOptions,\n): Promise<SetupInitialTenantResult> {\n const {\n primaryUser,\n includeDerivedUsers = true,\n failIfUserExists = false,\n primaryUserRoles,\n includeSuperadminRole = true,\n } = options\n const primaryRolesInput = primaryUserRoles && primaryUserRoles.length ? primaryUserRoles : ['superadmin']\n const primaryRoles = includeSuperadminRole\n ? primaryRolesInput\n : primaryRolesInput.filter((role) => role !== 'superadmin')\n if (primaryRoles.length === 0) {\n throw new Error('PRIMARY_ROLES_REQUIRED')\n }\n const defaultRoleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const resolvedRoleNames = includeSuperadminRole\n ? defaultRoleNames\n : defaultRoleNames.filter((role) => role !== 'superadmin')\n const roleNames = Array.from(new Set([...resolvedRoleNames, ...primaryRoles]))\n const resolvedModules = options.modules ?? tryGetModules()\n const defaultEncryptionMaps = getDefaultEncryptionMaps(resolvedModules)\n\n const mainEmail = primaryUser.email\n const existingUserByHash = await findOneWithDecryption(\n em,\n User,\n { emailHash: { $in: emailHashLookupValues(mainEmail) }, deletedAt: null },\n {},\n { tenantId: null, organizationId: null },\n )\n const existingUser = existingUserByHash ?? await findOneWithDecryption(\n em,\n User,\n { email: mainEmail, deletedAt: null },\n {},\n { tenantId: null, organizationId: null },\n )\n if (existingUser && failIfUserExists) {\n throw new Error('USER_EXISTS')\n }\n\n if (options.orgSlug) {\n const slugConflict = await findOneWithDecryption(\n em,\n Organization,\n { slug: options.orgSlug },\n {},\n { tenantId: null, organizationId: null },\n )\n if (slugConflict) {\n throw new OrgSlugExistsError(options.orgSlug)\n }\n }\n\n let tenantId: string | undefined\n let organizationId: string | undefined\n let reusedExistingUser = false\n const userSnapshots: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }> = []\n\n await em.transactional(async (tem) => {\n if (!existingUser) return\n reusedExistingUser = true\n tenantId = existingUser.tenantId ? String(existingUser.tenantId) : undefined\n organizationId = existingUser.organizationId ? String(existingUser.organizationId) : undefined\n const roleTenantId = normalizeTenantId(existingUser.tenantId ?? null) ?? null\n if (!roleTenantId) {\n throw new Error('Cannot reuse a user without a tenantId \u2014 global roles are not supported')\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n const requiredRoleSet = new Set([...roleNames, ...primaryRoles])\n const links = await findWithDecryption(\n tem,\n UserRole,\n { user: existingUser },\n { populate: ['role'] },\n { tenantId: roleTenantId, organizationId: null },\n )\n const currentRoles = new Set(links.map((link) => link.role.name))\n for (const roleName of requiredRoleSet) {\n if (!currentRoles.has(roleName)) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n tem.persist(tem.create(UserRole, { user: existingUser, role, createdAt: new Date() }))\n }\n }\n await tem.flush()\n const roles = Array.from(new Set([...currentRoles, ...roleNames]))\n userSnapshots.push({ user: existingUser, roles, created: false })\n })\n\n if (!existingUser) {\n const baseUsers: Array<{\n email: string\n roles: string[]\n name?: string | null\n passwordHash?: string | null\n generatedPassword?: string | null\n }> = [\n { email: primaryUser.email, roles: primaryRoles, name: resolvePrimaryName(primaryUser) },\n ]\n if (includeDerivedUsers) {\n const adminOverride = readEnvValue(DERIVED_EMAIL_ENV.admin)\n const employeeOverride = readEnvValue(DERIVED_EMAIL_ENV.employee)\n const adminEmail = adminOverride ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = employeeOverride ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const envAdminPwd = readEnvValue('OM_INIT_ADMIN_PASSWORD')\n const envEmployeePwd = readEnvValue('OM_INIT_EMPLOYEE_PASSWORD')\n const isProduction = process.env.NODE_ENV === 'production'\n const allowDemo = options.allowDemoDerivedPasswords === true\n if (isProduction && !allowDemo) {\n const missing: string[] = []\n if (!envAdminPwd) missing.push('OM_INIT_ADMIN_PASSWORD')\n if (!envEmployeePwd) missing.push('OM_INIT_EMPLOYEE_PASSWORD')\n if (missing.length) {\n throw new DerivedUserPasswordRequiredError(missing)\n }\n }\n // In non-production, fall back to the well-known DEMO_DERIVED_PASSWORD so\n // local dev workflows stay predictable (admin@/employee@ login with the\n // documented demo password). In production we either have env-supplied\n // values, or \u2014 for opt-in --include-demo-users flows \u2014 we generate a\n // random one-time password and surface it via `generatedPassword` so the\n // operator can capture it. Production callers without env vars and\n // without the opt-in already threw above.\n const fallbackAdminPwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const fallbackEmployeePwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const adminPasswordPlain = envAdminPwd ?? fallbackAdminPwd\n const employeePasswordPlain = envEmployeePwd ?? fallbackEmployeePwd\n const adminPasswordHash = await hash(adminPasswordPlain, 10)\n const employeePasswordHash = await hash(employeePasswordPlain, 10)\n addUniqueBaseUser(baseUsers, {\n email: adminEmail,\n roles: ['admin'],\n passwordHash: adminPasswordHash,\n generatedPassword: envAdminPwd ? null : adminPasswordPlain,\n })\n addUniqueBaseUser(baseUsers, {\n email: employeeEmail,\n roles: ['employee'],\n passwordHash: employeePasswordHash,\n generatedPassword: envEmployeePwd ? null : employeePasswordPlain,\n })\n }\n const passwordHash = await resolvePasswordHash(primaryUser)\n\n await em.transactional(async (tem) => {\n const tenant = tem.create(Tenant, {\n name: options.orgName,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(tenant)\n await tem.flush()\n\n const organization = tem.create(Organization, {\n name: options.orgName,\n slug: options.orgSlug ?? null,\n tenant,\n isActive: true,\n depth: 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n logoPreserveAspectRatio: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(organization)\n await tem.flush()\n\n tenantId = String(tenant.id)\n organizationId = String(organization.id)\n const roleTenantId = tenantId\n\n if (isTenantDataEncryptionEnabled()) {\n try {\n const kms = createKmsService()\n if (kms.isHealthy()) {\n if (isEncryptionDebugEnabled()) {\n logger.info('Provisioning tenant DEK', { tenantId: String(tenant.id) })\n }\n await kms.createTenantDek(String(tenant.id))\n if (isEncryptionDebugEnabled()) {\n logger.info('Created tenant DEK during setup', { tenantId: String(tenant.id) })\n }\n } else {\n if (isEncryptionDebugEnabled()) {\n logger.warn('KMS not healthy, skipping tenant DEK creation', { tenantId: String(tenant.id) })\n }\n }\n } catch (err) {\n if (isEncryptionDebugEnabled()) {\n logger.warn('Failed to create tenant DEK', { err })\n }\n }\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n if (isTenantDataEncryptionEnabled()) {\n // System-scoped maps are resolved from module code, never from a tenant row.\n // Persisting one here would make the tenant-scoped encryption CLIs believe they\n // own that entity and re-wrap its `system:<entityId>` ciphertext under the tenant\n // DEK, which runtime decryption can no longer read.\n for (const spec of defaultEncryptionMaps) {\n if (spec.keyScope === 'system') continue\n const existing = await findOneWithDecryption(tem, EncryptionMap, { entityId: spec.entityId, tenantId: tenant.id, organizationId: organization.id, deletedAt: null }, {}, { tenantId: String(tenant.id), organizationId: String(organization.id) })\n if (!existing) {\n tem.persist(tem.create(EncryptionMap, {\n entityId: spec.entityId,\n tenantId: tenant.id,\n organizationId: organization.id,\n fieldsJson: spec.fields,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n }))\n } else {\n existing.fieldsJson = spec.fields\n existing.isActive = true\n }\n }\n await tem.flush()\n }\n })\n\n await em.transactional(async (tem) => {\n if (!tenantId || !organizationId) return\n const roleTenantId = tenantId\n const encryptionService = isTenantDataEncryptionEnabled()\n ? new TenantDataEncryptionService(tem as any, { kms: createKmsService() })\n : null\n if (encryptionService) {\n await encryptionService.invalidateMap('auth:user', String(tenantId), String(organizationId))\n await encryptionService.invalidateMap('auth:user', String(tenantId), null)\n }\n\n for (const base of baseUsers) {\n const resolvedPasswordHash = base.passwordHash ?? passwordHash\n let user = await findOneWithDecryption(tem, User, { email: base.email }, {}, { tenantId: tenantId ?? null, organizationId: organizationId ?? null })\n const confirm = primaryUser.confirm ?? true\n const encryptedPayload = encryptionService\n ? await encryptionService.encryptEntityPayload('auth:user', { email: base.email }, tenantId, organizationId)\n : { email: base.email, emailHash: computeEmailHash(base.email) }\n if (user) {\n user.passwordHash = resolvedPasswordHash\n user.organizationId = organizationId\n user.tenantId = tenantId\n if (isTenantDataEncryptionEnabled()) {\n user.email = encryptedPayload.email as any\n user.emailHash = (encryptedPayload as any).emailHash ?? computeEmailHash(base.email)\n }\n if (base.name) user.name = base.name\n if (confirm) user.isConfirmed = true\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: false, generatedPassword: base.generatedPassword ?? null })\n } else {\n user = tem.create(User, {\n email: (encryptedPayload as any).email ?? base.email,\n emailHash: isTenantDataEncryptionEnabled() ? (encryptedPayload as any).emailHash ?? computeEmailHash(base.email) : undefined,\n passwordHash: resolvedPasswordHash,\n organizationId,\n tenantId,\n name: base.name ?? undefined,\n isConfirmed: confirm,\n createdAt: new Date(),\n })\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: true, generatedPassword: base.generatedPassword ?? null })\n }\n await tem.flush()\n for (const roleName of base.roles) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n const existingLink = await findOneWithDecryption(tem, UserRole, { user, role }, {}, { tenantId: tenantId ?? null, organizationId: null })\n if (!existingLink) tem.persist(tem.create(UserRole, { user, role, createdAt: new Date() }))\n }\n await tem.flush()\n }\n })\n }\n\n if (!tenantId || !organizationId) {\n throw new Error('SETUP_FAILED')\n }\n\n if (!reusedExistingUser) {\n await rebuildHierarchyForTenant(em, tenantId)\n }\n\n await ensureDefaultRoleAcls(em, tenantId, resolvedModules, { includeSuperadminRole })\n await deactivateDemoUsersIfSelfOnboardingEnabled(em)\n\n // Call module onTenantCreated hooks\n for (const mod of resolvedModules) {\n if (mod.setup?.onTenantCreated) {\n await mod.setup.onTenantCreated({ em, tenantId, organizationId })\n }\n }\n\n return {\n tenantId,\n organizationId,\n users: userSnapshots,\n reusedExistingUser,\n }\n}\n\nfunction resolvePrimaryName(input: PrimaryUserInput): string | null {\n if (input.displayName && input.displayName.trim()) return input.displayName.trim()\n const parts = [input.firstName, input.lastName].map((value) => value?.trim()).filter(Boolean)\n if (parts.length) return parts.join(' ')\n return null\n}\n\nfunction readEnvValue(key: string): string | undefined {\n const value = process.env[key]\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction addUniqueBaseUser(\n baseUsers: Array<{ email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null }>,\n entry: { email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null },\n) {\n if (!entry.email) return\n const normalized = entry.email.toLowerCase()\n if (baseUsers.some((user) => user.email.toLowerCase() === normalized)) return\n baseUsers.push(entry)\n}\n\n/**\n * Well-known demo password seeded for derived admin@/employee@ accounts in\n * non-production (`NODE_ENV !== 'production'`) when no env override is set.\n * Keeps the documented `yarn dev` / `mercato init` DX predictable. Never used\n * in production: the production branch either consumes env-supplied values or\n * falls back to `generateDerivedPassword()` so credentials remain non-guessable.\n */\nconst DEMO_DERIVED_PASSWORD = 'secret'\n\n/**\n * Generate a 16-character base64url password (96 bits of entropy) for a derived\n * demo user in production when no env override is provided AND the caller\n * explicitly opted in via `allowDemoDerivedPasswords`. Surfaced via the\n * `users[].generatedPassword` snapshot so CLI callers can print it to the\n * operator \u2014 there is no other recovery path for these credentials.\n */\nfunction generateDerivedPassword(): string {\n return randomBytes(12).toString('base64url')\n}\n\nfunction isDemoModeEnabled(): boolean {\n const parsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n return parsed === false ? false : true\n}\n\nfunction shouldKeepDemoSuperadminDuringInit(): boolean {\n if (process.env.OM_INIT_FLOW !== 'true') return false\n if (!readEnvValue('OM_INIT_SUPERADMIN_EMAIL')) return false\n return isDemoModeEnabled()\n}\n\nasync function resolvePasswordHash(input: PrimaryUserInput): Promise<string | null> {\n if (typeof input.hashedPassword === 'string') return input.hashedPassword\n if (input.password) return hash(input.password, 10)\n return null\n}\n\nexport async function ensureDefaultRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules: Module[],\n options: { includeSuperadminRole?: boolean } = {},\n) {\n const includeSuperadminRole = options.includeSuperadminRole ?? true\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const superadminRole = includeSuperadminRole ? await findRoleByName(em, 'superadmin', roleTenantId) : null\n const adminRole = await findRoleByName(em, 'admin', roleTenantId)\n const employeeRole = await findRoleByName(em, 'employee', roleTenantId)\n\n // Merge features from all enabled modules' setup configs\n const builtInRoles = ['superadmin', 'admin', 'employee'] as const\n const superadminFeatures: string[] = []\n const adminFeatures: string[] = []\n const employeeFeatures: string[] = []\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of modules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n if (roleFeatures.superadmin) superadminFeatures.push(...roleFeatures.superadmin)\n if (roleFeatures.admin) adminFeatures.push(...roleFeatures.admin)\n if (roleFeatures.employee) employeeFeatures.push(...roleFeatures.employee)\n\n // Collect features for custom roles (any key not in builtInRoles)\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if ((builtInRoles as readonly string[]).includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n logger.info('Seeded default role features', {\n superadmin: superadminFeatures,\n admin: adminFeatures,\n employee: employeeFeatures,\n ...(customRoleFeatures.size > 0\n ? Object.fromEntries(customRoleFeatures)\n : {}),\n })\n\n if (includeSuperadminRole && superadminRole) {\n await ensureRoleAclFor(em, superadminRole, tenantId, superadminFeatures, { isSuperAdmin: true })\n }\n if (adminRole) {\n await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures)\n }\n if (employeeRole) {\n await ensureRoleAclFor(em, employeeRole, tenantId, employeeFeatures)\n }\n\n // Seed ACLs for custom roles defined by app modules.\n // NOTE: Custom roles may not exist yet if they are created in seedDefaults\n // (which runs after this function). In that case, use ensureCustomRoleAcls()\n // after seedDefaults to pick them up.\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n }\n }\n}\n\n/**\n * Seed ACLs for custom roles defined in module defaultRoleFeatures.\n * Call this AFTER seedDefaults to pick up roles created by app modules.\n * Safe to call multiple times \u2014 ensureRoleAclFor merges features idempotently.\n */\nexport async function ensureCustomRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules?: Module[],\n): Promise<void> {\n const resolvedModules = modules ?? tryGetModules()\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const builtInRoles = ['superadmin', 'admin', 'employee']\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of resolvedModules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if (builtInRoles.includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n if (customRoleFeatures.size === 0) return\n\n let seeded = 0\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n seeded++\n }\n }\n if (seeded > 0) {\n logger.info('Seeded custom role ACLs', { seeded })\n }\n}\n\nasync function ensureRoleAclFor(\n em: EntityManager,\n role: Role,\n tenantId: string,\n features: string[],\n options: { isSuperAdmin?: boolean } = {},\n) {\n const existing = await findOneWithDecryption(em, RoleAcl, { role, tenantId }, {}, { tenantId, organizationId: null })\n if (!existing) {\n const acl = em.create(RoleAcl, {\n role,\n tenantId,\n featuresJson: features,\n isSuperAdmin: !!options.isSuperAdmin,\n createdAt: new Date(),\n })\n await em.persist(acl).flush()\n return\n }\n const currentFeatures = Array.isArray(existing.featuresJson) ? existing.featuresJson : []\n const merged = Array.from(new Set([...currentFeatures, ...features]))\n const changed =\n merged.length !== currentFeatures.length ||\n merged.some((value, index) => value !== currentFeatures[index])\n if (changed) existing.featuresJson = merged\n if (options.isSuperAdmin && !existing.isSuperAdmin) {\n existing.isSuperAdmin = true\n }\n if (changed || options.isSuperAdmin) {\n await em.persist(existing).flush()\n }\n}\n\n/**\n * Neutralizes every demo account the setup path may have seeded\n * (superadmin, admin, employee \u2014 honoring OM_INIT_*_EMAIL overrides)\n * when SELF_SERVICE_ONBOARDING_ENABLED is on and the operator did not\n * opt in to keeping demo credentials via shouldKeepDemoSuperadminDuringInit.\n *\n * Each user is processed in its own try/catch so a single failure (e.g.\n * decryption error on a legacy row) does not skip the remaining accounts.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport async function deactivateDemoUsersIfSelfOnboardingEnabled(em: EntityManager) {\n if (process.env.SELF_SERVICE_ONBOARDING_ENABLED !== 'true') return\n if (shouldKeepDemoSuperadminDuringInit()) return\n for (const { role, email } of resolveDemoUserEmails()) {\n try {\n const user = await findOneWithDecryption(\n em,\n User,\n { email },\n {},\n { tenantId: null, organizationId: null },\n )\n if (!user) continue\n let dirty = false\n if (user.passwordHash) {\n user.passwordHash = null\n dirty = true\n }\n if (user.isConfirmed !== false) {\n user.isConfirmed = false\n dirty = true\n }\n if (dirty) {\n await em.persist(user).flush()\n }\n } catch (error) {\n logger.error('Failed to deactivate demo user', { role, email, err: error })\n }\n }\n}\n\n/**\n * @deprecated Renamed to {@link deactivateDemoUsersIfSelfOnboardingEnabled}\n * because the helper now neutralizes admin/employee demo accounts in addition\n * to superadmin (security tracker finding #5). Kept as an internal alias to\n * avoid breaking any out-of-tree caller that imported the old name; will be\n * removed in a future major.\n */\nconst deactivateDemoSuperAdminIfSelfOnboardingEnabled = deactivateDemoUsersIfSelfOnboardingEnabled\n\n/** Try to get modules from runtime registry; returns empty array if not yet registered. */\nfunction tryGetModules(): Module[] {\n try {\n const { getModules } = require('@open-mercato/shared/lib/modules/registry')\n return getModules()\n } catch {\n return []\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { hash } from 'bcryptjs'\nimport { randomBytes } from 'node:crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { Role, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { Tenant, Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'\nimport { normalizeTenantId } from './tenantAccess'\nimport { computeEmailHash, emailHashLookupValues } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { getDefaultEncryptionMaps, type Module } from '@open-mercato/shared/modules/registry'\nimport { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { EncryptionMap } from '@open-mercato/core/modules/entities/data/entities'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'setup' })\n\nconst DEFAULT_ROLE_NAMES = ['employee', 'admin', 'superadmin'] as const\nconst DEMO_SUPERADMIN_EMAIL = 'superadmin@acme.com'\nconst DEFAULT_DERIVED_EMAIL_DOMAIN = DEMO_SUPERADMIN_EMAIL.split('@')[1] ?? 'acme.com'\n\nexport type EnsureRolesOptions = {\n roleNames?: string[]\n tenantId?: string\n}\n\nasync function ensureRolesInContext(\n em: EntityManager,\n roleNames: string[],\n tenantId: string,\n) {\n for (const name of roleNames) {\n const existing = await findOneWithDecryption(em, Role, { name, tenantId }, {}, { tenantId, organizationId: null })\n if (existing) continue\n em.persist(em.create(Role, { name, tenantId, minActiveHolders: name === 'admin' ? 1 : 0, createdAt: new Date() }))\n }\n}\n\nexport async function ensureRoles(em: EntityManager, options: EnsureRolesOptions = {}) {\n const roleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const tenantId = normalizeTenantId(options.tenantId ?? null)\n if (!tenantId) {\n throw new Error('ensureRoles requires a tenantId \u2014 global roles are not supported')\n }\n await em.transactional(async (tem) => {\n await ensureRolesInContext(tem, roleNames, tenantId)\n await tem.flush()\n })\n}\n\nasync function findRoleByName(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role | null> {\n const normalizedTenant = normalizeTenantId(tenantId ?? null) ?? null\n return findOneWithDecryption(em, Role, { name, tenantId: normalizedTenant }, {}, { tenantId: normalizedTenant, organizationId: null })\n}\n\nasync function findRoleByNameOrFail(\n em: EntityManager,\n name: string,\n tenantId: string | null,\n): Promise<Role> {\n const role = await findRoleByName(em, name, tenantId)\n if (!role) throw new Error(`ROLE_NOT_FOUND:${name}`)\n return role\n}\n\ntype PrimaryUserInput = {\n email: string\n password?: string\n hashedPassword?: string | null\n firstName?: string | null\n lastName?: string | null\n displayName?: string | null\n confirm?: boolean\n}\n\nconst DERIVED_EMAIL_ENV = {\n admin: 'OM_INIT_ADMIN_EMAIL',\n employee: 'OM_INIT_EMPLOYEE_EMAIL',\n} as const\n\nexport type DemoUserRole = 'superadmin' | 'admin' | 'employee'\nexport type DemoUserEmail = { role: DemoUserRole; email: string }\n\n/**\n * Returns the canonical list of demo user emails the setup path may have\n * seeded. Honors OM_INIT_ADMIN_EMAIL / OM_INIT_EMPLOYEE_EMAIL exactly the\n * same way the derived-user seeding branch does, so the deactivation loop\n * never drifts from the seeding loop.\n *\n * Pure function \u2014 no side effects, safe to unit-test in isolation.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport function resolveDemoUserEmails(): DemoUserEmail[] {\n const adminEmail = readEnvValue(DERIVED_EMAIL_ENV.admin) ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = readEnvValue(DERIVED_EMAIL_ENV.employee) ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n return [\n { role: 'superadmin', email: DEMO_SUPERADMIN_EMAIL },\n { role: 'admin', email: adminEmail },\n { role: 'employee', email: employeeEmail },\n ]\n}\n\nexport type SetupInitialTenantOptions = {\n orgName: string\n primaryUser: PrimaryUserInput\n roleNames?: string[]\n includeDerivedUsers?: boolean\n failIfUserExists?: boolean\n primaryUserRoles?: string[]\n includeSuperadminRole?: boolean\n /** Optional list of enabled modules. When provided, module setup hooks are called. */\n modules?: Module[]\n /**\n * Optional global slug to persist on the new Organization. When set, a\n * pre-flight uniqueness check across all tenants throws OrgSlugExistsError\n * on collision so scriptable callers can fail loudly instead of silently\n * reusing or clobbering an existing organization.\n */\n orgSlug?: string\n /**\n * Opt-in flag that allows seeding the derived admin/employee accounts when\n * the OM_INIT_ADMIN_PASSWORD / OM_INIT_EMPLOYEE_PASSWORD env vars are unset.\n *\n * - In non-production (`NODE_ENV !== 'production'`): the demo accounts are\n * seeded with the well-known `'secret'` password so local dev workflows\n * (e.g. `mercato init`) stay predictable for developers.\n * - In production: the fallback uses a randomly generated 96-bit password\n * (printed once by the CLI) so an operator who deliberately opts in still\n * avoids the historical hardcoded credential. When this flag is false/unset\n * in production and the env vars are missing, `DerivedUserPasswordRequiredError`\n * is thrown instead of silently seeding any account.\n */\n allowDemoDerivedPasswords?: boolean\n}\n\nexport class OrgSlugExistsError extends Error {\n constructor(public readonly slug: string) {\n super(`ORG_SLUG_EXISTS: an organization with slug \"${slug}\" already exists`)\n this.name = 'OrgSlugExistsError'\n }\n}\n\nexport class DerivedUserPasswordRequiredError extends Error {\n constructor(public readonly missing: string[]) {\n super(\n `DERIVED_USER_PASSWORD_REQUIRED: missing ${missing.join(', ')} (set the env vars, pass allowDemoDerivedPasswords: true / --include-demo-users in non-production, or disable derived user seeding)`,\n )\n this.name = 'DerivedUserPasswordRequiredError'\n }\n}\n\nexport type SetupInitialTenantResult = {\n tenantId: string\n organizationId: string\n users: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }>\n reusedExistingUser: boolean\n}\n\nexport async function setupInitialTenant(\n em: EntityManager,\n options: SetupInitialTenantOptions,\n): Promise<SetupInitialTenantResult> {\n const {\n primaryUser,\n includeDerivedUsers = true,\n failIfUserExists = false,\n primaryUserRoles,\n includeSuperadminRole = true,\n } = options\n const primaryRolesInput = primaryUserRoles && primaryUserRoles.length ? primaryUserRoles : ['superadmin']\n const primaryRoles = includeSuperadminRole\n ? primaryRolesInput\n : primaryRolesInput.filter((role) => role !== 'superadmin')\n if (primaryRoles.length === 0) {\n throw new Error('PRIMARY_ROLES_REQUIRED')\n }\n const defaultRoleNames = options.roleNames ?? [...DEFAULT_ROLE_NAMES]\n const resolvedRoleNames = includeSuperadminRole\n ? defaultRoleNames\n : defaultRoleNames.filter((role) => role !== 'superadmin')\n const roleNames = Array.from(new Set([...resolvedRoleNames, ...primaryRoles]))\n const resolvedModules = options.modules ?? tryGetModules()\n const defaultEncryptionMaps = getDefaultEncryptionMaps(resolvedModules)\n\n const mainEmail = primaryUser.email\n const existingUserByHash = await findOneWithDecryption(\n em,\n User,\n { emailHash: { $in: emailHashLookupValues(mainEmail) }, deletedAt: null },\n {},\n { tenantId: null, organizationId: null },\n )\n const existingUser = existingUserByHash ?? await findOneWithDecryption(\n em,\n User,\n { email: mainEmail, deletedAt: null },\n {},\n { tenantId: null, organizationId: null },\n )\n if (existingUser && failIfUserExists) {\n throw new Error('USER_EXISTS')\n }\n\n if (options.orgSlug) {\n const slugConflict = await findOneWithDecryption(\n em,\n Organization,\n { slug: options.orgSlug },\n {},\n { tenantId: null, organizationId: null },\n )\n if (slugConflict) {\n throw new OrgSlugExistsError(options.orgSlug)\n }\n }\n\n let tenantId: string | undefined\n let organizationId: string | undefined\n let reusedExistingUser = false\n const userSnapshots: Array<{ user: User; roles: string[]; created: boolean; generatedPassword?: string | null }> = []\n\n await em.transactional(async (tem) => {\n if (!existingUser) return\n reusedExistingUser = true\n tenantId = existingUser.tenantId ? String(existingUser.tenantId) : undefined\n organizationId = existingUser.organizationId ? String(existingUser.organizationId) : undefined\n const roleTenantId = normalizeTenantId(existingUser.tenantId ?? null) ?? null\n if (!roleTenantId) {\n throw new Error('Cannot reuse a user without a tenantId \u2014 global roles are not supported')\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n const requiredRoleSet = new Set([...roleNames, ...primaryRoles])\n const links = await findWithDecryption(\n tem,\n UserRole,\n { user: existingUser },\n { populate: ['role'] },\n { tenantId: roleTenantId, organizationId: null },\n )\n const currentRoles = new Set(links.map((link) => link.role.name))\n for (const roleName of requiredRoleSet) {\n if (!currentRoles.has(roleName)) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n tem.persist(tem.create(UserRole, { user: existingUser, role, createdAt: new Date() }))\n }\n }\n await tem.flush()\n const roles = Array.from(new Set([...currentRoles, ...roleNames]))\n userSnapshots.push({ user: existingUser, roles, created: false })\n })\n\n if (!existingUser) {\n const baseUsers: Array<{\n email: string\n roles: string[]\n name?: string | null\n passwordHash?: string | null\n generatedPassword?: string | null\n }> = [\n { email: primaryUser.email, roles: primaryRoles, name: resolvePrimaryName(primaryUser) },\n ]\n if (includeDerivedUsers) {\n const adminOverride = readEnvValue(DERIVED_EMAIL_ENV.admin)\n const employeeOverride = readEnvValue(DERIVED_EMAIL_ENV.employee)\n const adminEmail = adminOverride ?? `admin@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const employeeEmail = employeeOverride ?? `employee@${DEFAULT_DERIVED_EMAIL_DOMAIN}`\n const envAdminPwd = readEnvValue('OM_INIT_ADMIN_PASSWORD')\n const envEmployeePwd = readEnvValue('OM_INIT_EMPLOYEE_PASSWORD')\n const isProduction = process.env.NODE_ENV === 'production'\n const allowDemo = options.allowDemoDerivedPasswords === true\n if (isProduction && !allowDemo) {\n const missing: string[] = []\n if (!envAdminPwd) missing.push('OM_INIT_ADMIN_PASSWORD')\n if (!envEmployeePwd) missing.push('OM_INIT_EMPLOYEE_PASSWORD')\n if (missing.length) {\n throw new DerivedUserPasswordRequiredError(missing)\n }\n }\n // In non-production, fall back to the well-known DEMO_DERIVED_PASSWORD so\n // local dev workflows stay predictable (admin@/employee@ login with the\n // documented demo password). In production we either have env-supplied\n // values, or \u2014 for opt-in --include-demo-users flows \u2014 we generate a\n // random one-time password and surface it via `generatedPassword` so the\n // operator can capture it. Production callers without env vars and\n // without the opt-in already threw above.\n const fallbackAdminPwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const fallbackEmployeePwd = isProduction ? generateDerivedPassword() : DEMO_DERIVED_PASSWORD\n const adminPasswordPlain = envAdminPwd ?? fallbackAdminPwd\n const employeePasswordPlain = envEmployeePwd ?? fallbackEmployeePwd\n const adminPasswordHash = await hash(adminPasswordPlain, 10)\n const employeePasswordHash = await hash(employeePasswordPlain, 10)\n addUniqueBaseUser(baseUsers, {\n email: adminEmail,\n roles: ['admin'],\n passwordHash: adminPasswordHash,\n generatedPassword: envAdminPwd ? null : adminPasswordPlain,\n })\n addUniqueBaseUser(baseUsers, {\n email: employeeEmail,\n roles: ['employee'],\n passwordHash: employeePasswordHash,\n generatedPassword: envEmployeePwd ? null : employeePasswordPlain,\n })\n }\n const passwordHash = await resolvePasswordHash(primaryUser)\n\n await em.transactional(async (tem) => {\n const tenant = tem.create(Tenant, {\n name: options.orgName,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(tenant)\n await tem.flush()\n\n const organization = tem.create(Organization, {\n name: options.orgName,\n slug: options.orgSlug ?? null,\n tenant,\n isActive: true,\n depth: 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n logoPreserveAspectRatio: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n tem.persist(organization)\n await tem.flush()\n\n tenantId = String(tenant.id)\n organizationId = String(organization.id)\n const roleTenantId = tenantId\n\n if (isTenantDataEncryptionEnabled()) {\n try {\n const kms = createKmsService()\n if (kms.isHealthy()) {\n if (isEncryptionDebugEnabled()) {\n logger.info('Provisioning tenant DEK', { tenantId: String(tenant.id) })\n }\n await kms.createTenantDek(String(tenant.id))\n if (isEncryptionDebugEnabled()) {\n logger.info('Created tenant DEK during setup', { tenantId: String(tenant.id) })\n }\n } else {\n if (isEncryptionDebugEnabled()) {\n logger.warn('KMS not healthy, skipping tenant DEK creation', { tenantId: String(tenant.id) })\n }\n }\n } catch (err) {\n if (isEncryptionDebugEnabled()) {\n logger.warn('Failed to create tenant DEK', { err })\n }\n }\n }\n\n await ensureRolesInContext(tem, roleNames, roleTenantId)\n await tem.flush()\n\n if (isTenantDataEncryptionEnabled()) {\n // System-scoped maps are resolved from module code, never from a tenant row.\n // Persisting one here would make the tenant-scoped encryption CLIs believe they\n // own that entity and re-wrap its `system:<entityId>` ciphertext under the tenant\n // DEK, which runtime decryption can no longer read.\n for (const spec of defaultEncryptionMaps) {\n if (spec.keyScope === 'system') continue\n const existing = await findOneWithDecryption(tem, EncryptionMap, { entityId: spec.entityId, tenantId: tenant.id, organizationId: organization.id, deletedAt: null }, {}, { tenantId: String(tenant.id), organizationId: String(organization.id) })\n if (!existing) {\n tem.persist(tem.create(EncryptionMap, {\n entityId: spec.entityId,\n tenantId: tenant.id,\n organizationId: organization.id,\n fieldsJson: spec.fields,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n }))\n } else {\n existing.fieldsJson = spec.fields\n existing.isActive = true\n }\n }\n await tem.flush()\n }\n })\n\n await em.transactional(async (tem) => {\n if (!tenantId || !organizationId) return\n const roleTenantId = tenantId\n const encryptionService = isTenantDataEncryptionEnabled()\n ? new TenantDataEncryptionService(tem as any, { kms: createKmsService() })\n : null\n if (encryptionService) {\n await encryptionService.invalidateMap('auth:user', String(tenantId), String(organizationId))\n await encryptionService.invalidateMap('auth:user', String(tenantId), null)\n }\n\n for (const base of baseUsers) {\n const resolvedPasswordHash = base.passwordHash ?? passwordHash\n let user = await findOneWithDecryption(tem, User, { email: base.email }, {}, { tenantId: tenantId ?? null, organizationId: organizationId ?? null })\n const confirm = primaryUser.confirm ?? true\n const encryptedPayload = encryptionService\n ? await encryptionService.encryptEntityPayload('auth:user', { email: base.email }, tenantId, organizationId)\n : { email: base.email, emailHash: computeEmailHash(base.email) }\n if (user) {\n user.passwordHash = resolvedPasswordHash\n user.organizationId = organizationId\n user.tenantId = tenantId\n if (isTenantDataEncryptionEnabled()) {\n user.email = encryptedPayload.email as any\n user.emailHash = (encryptedPayload as any).emailHash ?? computeEmailHash(base.email)\n }\n if (base.name) user.name = base.name\n if (confirm) user.isConfirmed = true\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: false, generatedPassword: base.generatedPassword ?? null })\n } else {\n user = tem.create(User, {\n email: (encryptedPayload as any).email ?? base.email,\n emailHash: isTenantDataEncryptionEnabled() ? (encryptedPayload as any).emailHash ?? computeEmailHash(base.email) : undefined,\n passwordHash: resolvedPasswordHash,\n organizationId,\n tenantId,\n name: base.name ?? undefined,\n isConfirmed: confirm,\n createdAt: new Date(),\n })\n tem.persist(user)\n userSnapshots.push({ user, roles: base.roles, created: true, generatedPassword: base.generatedPassword ?? null })\n }\n await tem.flush()\n for (const roleName of base.roles) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n const existingLink = await findOneWithDecryption(tem, UserRole, { user, role }, {}, { tenantId: tenantId ?? null, organizationId: null })\n if (!existingLink) tem.persist(tem.create(UserRole, { user, role, createdAt: new Date() }))\n }\n await tem.flush()\n }\n })\n }\n\n if (!tenantId || !organizationId) {\n throw new Error('SETUP_FAILED')\n }\n\n if (!reusedExistingUser) {\n await rebuildHierarchyForTenant(em, tenantId)\n }\n\n await ensureDefaultRoleAcls(em, tenantId, resolvedModules, { includeSuperadminRole })\n await deactivateDemoUsersIfSelfOnboardingEnabled(em)\n\n // Call module onTenantCreated hooks\n for (const mod of resolvedModules) {\n if (mod.setup?.onTenantCreated) {\n await mod.setup.onTenantCreated({ em, tenantId, organizationId })\n }\n }\n\n return {\n tenantId,\n organizationId,\n users: userSnapshots,\n reusedExistingUser,\n }\n}\n\nfunction resolvePrimaryName(input: PrimaryUserInput): string | null {\n if (input.displayName && input.displayName.trim()) return input.displayName.trim()\n const parts = [input.firstName, input.lastName].map((value) => value?.trim()).filter(Boolean)\n if (parts.length) return parts.join(' ')\n return null\n}\n\nfunction readEnvValue(key: string): string | undefined {\n const value = process.env[key]\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction addUniqueBaseUser(\n baseUsers: Array<{ email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null }>,\n entry: { email: string; roles: string[]; name?: string | null; passwordHash?: string | null; generatedPassword?: string | null },\n) {\n if (!entry.email) return\n const normalized = entry.email.toLowerCase()\n if (baseUsers.some((user) => user.email.toLowerCase() === normalized)) return\n baseUsers.push(entry)\n}\n\n/**\n * Well-known demo password seeded for derived admin@/employee@ accounts in\n * non-production (`NODE_ENV !== 'production'`) when no env override is set.\n * Keeps the documented `yarn dev` / `mercato init` DX predictable. Never used\n * in production: the production branch either consumes env-supplied values or\n * falls back to `generateDerivedPassword()` so credentials remain non-guessable.\n */\nconst DEMO_DERIVED_PASSWORD = 'secret'\n\n/**\n * Generate a 16-character base64url password (96 bits of entropy) for a derived\n * demo user in production when no env override is provided AND the caller\n * explicitly opted in via `allowDemoDerivedPasswords`. Surfaced via the\n * `users[].generatedPassword` snapshot so CLI callers can print it to the\n * operator \u2014 there is no other recovery path for these credentials.\n */\nfunction generateDerivedPassword(): string {\n return randomBytes(12).toString('base64url')\n}\n\nfunction isDemoModeEnabled(): boolean {\n const parsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n return parsed === false ? false : true\n}\n\nfunction shouldKeepDemoSuperadminDuringInit(): boolean {\n if (process.env.OM_INIT_FLOW !== 'true') return false\n if (!readEnvValue('OM_INIT_SUPERADMIN_EMAIL')) return false\n return isDemoModeEnabled()\n}\n\nasync function resolvePasswordHash(input: PrimaryUserInput): Promise<string | null> {\n if (typeof input.hashedPassword === 'string') return input.hashedPassword\n if (input.password) return hash(input.password, 10)\n return null\n}\n\nexport async function ensureDefaultRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules: Module[],\n options: { includeSuperadminRole?: boolean } = {},\n) {\n const includeSuperadminRole = options.includeSuperadminRole ?? true\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const superadminRole = includeSuperadminRole ? await findRoleByName(em, 'superadmin', roleTenantId) : null\n const adminRole = await findRoleByName(em, 'admin', roleTenantId)\n const employeeRole = await findRoleByName(em, 'employee', roleTenantId)\n\n // Merge features from all enabled modules' setup configs\n const builtInRoles = ['superadmin', 'admin', 'employee'] as const\n const superadminFeatures: string[] = []\n const adminFeatures: string[] = []\n const employeeFeatures: string[] = []\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of modules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n if (roleFeatures.superadmin) superadminFeatures.push(...roleFeatures.superadmin)\n if (roleFeatures.admin) adminFeatures.push(...roleFeatures.admin)\n if (roleFeatures.employee) employeeFeatures.push(...roleFeatures.employee)\n\n // Collect features for custom roles (any key not in builtInRoles)\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if ((builtInRoles as readonly string[]).includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n logger.info('Seeded default role features', {\n superadmin: superadminFeatures,\n admin: adminFeatures,\n employee: employeeFeatures,\n ...(customRoleFeatures.size > 0\n ? Object.fromEntries(customRoleFeatures)\n : {}),\n })\n\n if (includeSuperadminRole && superadminRole) {\n await ensureRoleAclFor(em, superadminRole, tenantId, superadminFeatures, { isSuperAdmin: true })\n }\n if (adminRole) {\n await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures)\n }\n if (employeeRole) {\n await ensureRoleAclFor(em, employeeRole, tenantId, employeeFeatures)\n }\n\n // Seed ACLs for custom roles defined by app modules.\n // NOTE: Custom roles may not exist yet if they are created in seedDefaults\n // (which runs after this function). In that case, use ensureCustomRoleAcls()\n // after seedDefaults to pick them up.\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n }\n }\n}\n\n/**\n * Seed ACLs for custom roles defined in module defaultRoleFeatures.\n * Call this AFTER seedDefaults to pick up roles created by app modules.\n * Safe to call multiple times \u2014 ensureRoleAclFor merges features idempotently.\n */\nexport async function ensureCustomRoleAcls(\n em: EntityManager,\n tenantId: string,\n modules?: Module[],\n): Promise<void> {\n const resolvedModules = modules ?? tryGetModules()\n const roleTenantId = normalizeTenantId(tenantId) ?? null\n const builtInRoles = ['superadmin', 'admin', 'employee']\n const customRoleFeatures = new Map<string, string[]>()\n\n for (const mod of resolvedModules) {\n const roleFeatures = mod.setup?.defaultRoleFeatures\n if (!roleFeatures) continue\n for (const [roleName, features] of Object.entries(roleFeatures)) {\n if (builtInRoles.includes(roleName)) continue\n if (!Array.isArray(features)) continue\n const existing = customRoleFeatures.get(roleName) ?? []\n existing.push(...features)\n customRoleFeatures.set(roleName, existing)\n }\n }\n\n if (customRoleFeatures.size === 0) return\n\n let seeded = 0\n for (const [roleName, features] of customRoleFeatures) {\n const role = await findRoleByName(em, roleName, roleTenantId)\n if (role) {\n await ensureRoleAclFor(em, role, tenantId, features)\n seeded++\n }\n }\n if (seeded > 0) {\n logger.info('Seeded custom role ACLs', { seeded })\n }\n}\n\nasync function ensureRoleAclFor(\n em: EntityManager,\n role: Role,\n tenantId: string,\n features: string[],\n options: { isSuperAdmin?: boolean } = {},\n) {\n const existing = await findOneWithDecryption(em, RoleAcl, { role, tenantId }, {}, { tenantId, organizationId: null })\n if (!existing) {\n const acl = em.create(RoleAcl, {\n role,\n tenantId,\n featuresJson: features,\n isSuperAdmin: !!options.isSuperAdmin,\n createdAt: new Date(),\n })\n await em.persist(acl).flush()\n return\n }\n const currentFeatures = Array.isArray(existing.featuresJson) ? existing.featuresJson : []\n const merged = Array.from(new Set([...currentFeatures, ...features]))\n const changed =\n merged.length !== currentFeatures.length ||\n merged.some((value, index) => value !== currentFeatures[index])\n if (changed) existing.featuresJson = merged\n if (options.isSuperAdmin && !existing.isSuperAdmin) {\n existing.isSuperAdmin = true\n }\n if (changed || options.isSuperAdmin) {\n await em.persist(existing).flush()\n }\n}\n\n/**\n * Neutralizes every demo account the setup path may have seeded\n * (superadmin, admin, employee \u2014 honoring OM_INIT_*_EMAIL overrides)\n * when SELF_SERVICE_ONBOARDING_ENABLED is on and the operator did not\n * opt in to keeping demo credentials via shouldKeepDemoSuperadminDuringInit.\n *\n * Each user is processed in its own try/catch so a single failure (e.g.\n * decryption error on a legacy row) does not skip the remaining accounts.\n *\n * @internal Exported for tests; not part of the public auth API.\n */\nexport async function deactivateDemoUsersIfSelfOnboardingEnabled(em: EntityManager) {\n if (process.env.SELF_SERVICE_ONBOARDING_ENABLED !== 'true') return\n if (shouldKeepDemoSuperadminDuringInit()) return\n for (const { role, email } of resolveDemoUserEmails()) {\n try {\n const user = await findOneWithDecryption(\n em,\n User,\n { email },\n {},\n { tenantId: null, organizationId: null },\n )\n if (!user) continue\n let dirty = false\n if (user.passwordHash) {\n user.passwordHash = null\n dirty = true\n }\n if (user.isConfirmed !== false) {\n user.isConfirmed = false\n dirty = true\n }\n if (dirty) {\n await em.persist(user).flush()\n }\n } catch (error) {\n logger.error('Failed to deactivate demo user', { role, email, err: error })\n }\n }\n}\n\n/**\n * @deprecated Renamed to {@link deactivateDemoUsersIfSelfOnboardingEnabled}\n * because the helper now neutralizes admin/employee demo accounts in addition\n * to superadmin (security tracker finding #5). Kept as an internal alias to\n * avoid breaking any out-of-tree caller that imported the old name; will be\n * removed in a future major.\n */\nconst deactivateDemoSuperAdminIfSelfOnboardingEnabled = deactivateDemoUsersIfSelfOnboardingEnabled\n\n/** Try to get modules from runtime registry; returns empty array if not yet registered. */\nfunction tryGetModules(): Module[] {\n try {\n const { getModules } = require('@open-mercato/shared/lib/modules/registry')\n return getModules()\n } catch {\n return []\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,14 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260728134212_auth extends Migration {
3
+ up() {
4
+ this.addSql(`alter table "roles" add "min_active_holders" int not null default 0;`);
5
+ this.addSql(`update "roles" set "min_active_holders" = 1 where "name" = 'admin' and "deleted_at" is null;`);
6
+ }
7
+ down() {
8
+ this.addSql(`alter table "roles" drop column "min_active_holders";`);
9
+ }
10
+ }
11
+ export {
12
+ Migration20260728134212_auth
13
+ };
14
+ //# sourceMappingURL=Migration20260728134212_auth.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/auth/migrations/Migration20260728134212_auth.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260728134212_auth extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"roles\" add \"min_active_holders\" int not null default 0;`);\n this.addSql(`update \"roles\" set \"min_active_holders\" = 1 where \"name\" = 'admin' and \"deleted_at\" is null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"roles\" drop column \"min_active_holders\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,qCAAqC,UAAU;AAAA,EAEjD,KAA2B;AAClC,SAAK,OAAO,sEAAsE;AAClF,SAAK,OAAO,8FAA8F;AAAA,EAC5G;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,uDAAuD;AAAA,EACrE;AAEF;",
6
+ "names": []
7
+ }
@@ -208,6 +208,7 @@ const searchConfig = {
208
208
  entities: [
209
209
  {
210
210
  entityId: "catalog:catalog_product",
211
+ aclFeatures: ["catalog.products.view"],
211
212
  enabled: true,
212
213
  priority: 10,
213
214
  buildSource: async (ctx) => {
@@ -264,6 +265,7 @@ const searchConfig = {
264
265
  },
265
266
  {
266
267
  entityId: "catalog:catalog_product_variant",
268
+ aclFeatures: ["catalog.products.view"],
267
269
  enabled: true,
268
270
  priority: 8,
269
271
  buildSource: async (ctx) => {
@@ -292,6 +294,7 @@ const searchConfig = {
292
294
  },
293
295
  {
294
296
  entityId: "catalog:catalog_product_category",
297
+ aclFeatures: ["catalog.categories.view"],
295
298
  enabled: true,
296
299
  priority: 7,
297
300
  buildSource: async (ctx) => {
@@ -316,6 +319,7 @@ const searchConfig = {
316
319
  },
317
320
  {
318
321
  entityId: "catalog:catalog_offer",
322
+ aclFeatures: ["sales.channels.manage"],
319
323
  enabled: true,
320
324
  priority: 7,
321
325
  buildSource: async (ctx) => {
@@ -342,6 +346,7 @@ const searchConfig = {
342
346
  },
343
347
  {
344
348
  entityId: "catalog:catalog_product_tag",
349
+ aclFeatures: ["catalog.products.view"],
345
350
  enabled: true,
346
351
  priority: 5,
347
352
  buildSource: async (ctx) => {
@@ -363,6 +368,7 @@ const searchConfig = {
363
368
  },
364
369
  {
365
370
  entityId: "catalog:catalog_price_kind",
371
+ aclFeatures: ["catalog.settings.manage"],
366
372
  enabled: true,
367
373
  priority: 4,
368
374
  buildSource: async (ctx) => {
@@ -386,6 +392,7 @@ const searchConfig = {
386
392
  },
387
393
  {
388
394
  entityId: "catalog:catalog_product_unit_conversion",
395
+ aclFeatures: ["catalog.products.view"],
389
396
  enabled: true,
390
397
  priority: 3,
391
398
  buildSource: async (ctx) => {
@@ -414,6 +421,7 @@ const searchConfig = {
414
421
  },
415
422
  {
416
423
  entityId: "catalog:catalog_option_schema_template",
424
+ aclFeatures: ["catalog.products.view"],
417
425
  enabled: true,
418
426
  priority: 4,
419
427
  buildSource: async (ctx) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/catalog/search.ts"],
4
- "sourcesContent": ["import type { SearchBuildContext, SearchIndexSource, SearchModuleConfig, SearchResultPresenter } from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nconst CATALOG_PRODUCTS_URL = '/backend/catalog/products'\nconst CATALOG_CATEGORIES_URL = '/backend/catalog/categories'\nconst CATALOG_CONFIG_URL = '/backend/config/catalog'\n\nfunction normalizeText(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n }\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n return null\n}\n\nfunction pickText(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n const text = normalizeText(candidate)\n if (text) return text\n }\n return null\n}\n\nfunction readRecordText(record: Record<string, unknown>, ...keys: string[]): string | null {\n for (const key of keys) {\n const text = normalizeText(record[key])\n if (text) return text\n }\n return null\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => normalizeText(part))\n .filter((value): value is string => Boolean(value))\n if (!text.length) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction snippet(value: unknown, maxLength = 140): string | undefined {\n const text = normalizeText(value)\n if (!text) return undefined\n if (text.length <= maxLength) return text\n return `${text.slice(0, maxLength - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => normalizeText(item)).filter(Boolean).join(', ')\n : typeof value === 'object'\n ? JSON.stringify(value)\n : String(value)\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction friendlyLabel(input: string): string {\n return input\n .replace(/^cf:/, '')\n .replace(/_/g, ' ')\n .replace(/([a-z])([A-Z])/g, (_match, firstChar, secondChar) => `${firstChar} ${secondChar}`)\n .replace(/\\b\\w/g, (character) => character.toUpperCase())\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, friendlyLabel(key), value)\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nfunction buildProductUrl(productId: string | null): string | null {\n if (!productId) return null\n return `${CATALOG_PRODUCTS_URL}/${encodeURIComponent(productId)}`\n}\n\nfunction buildVariantUrl(productId: string | null, variantId: string | null): string | null {\n if (!productId || !variantId) return null\n return `${CATALOG_PRODUCTS_URL}/${encodeURIComponent(productId)}/variants/${encodeURIComponent(variantId)}`\n}\n\nfunction buildCategoryUrl(categoryId: string | null): string | null {\n if (!categoryId) return null\n return `${CATALOG_CATEGORIES_URL}/${encodeURIComponent(categoryId)}/edit`\n}\n\nfunction resolveProductId(record: Record<string, unknown>): string | null {\n // Check direct FK fields first\n const directId = readRecordText(record, 'product_id', 'productId')\n if (directId) return directId\n // Check if product is a string (FK value)\n const product = record.product\n if (typeof product === 'string') return product\n // Check if product is an object with id\n if (product && typeof product === 'object') {\n const productObj = product as Record<string, unknown>\n return readRecordText(productObj, 'id')\n }\n return null\n}\n\nfunction buildProductPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.product', 'Product')\n const title = pickText(\n readRecordText(record, 'title'),\n readRecordText(record, 'sku'),\n readRecordText(record, 'handle'),\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'subtitle'),\n readRecordText(record, 'sku'),\n readRecordText(record, 'product_type', 'productType'),\n statusText,\n ) ?? snippet(readRecordText(record, 'description'))\n return { title, subtitle, icon: 'package', badge: label }\n}\n\nfunction buildVariantPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.variant', 'Variant')\n const isDefault = record.is_default ?? record.isDefault\n const defaultLabel = isDefault ? translate('catalog.search.variant.default', 'Default') : null\n const title = pickText(\n readRecordText(record, 'name'),\n readRecordText(record, 'sku'),\n defaultLabel,\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'sku'),\n readRecordText(record, 'barcode'),\n defaultLabel,\n statusText,\n )\n return { title, subtitle, icon: 'box', badge: label }\n}\n\nfunction buildCategoryPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.category', 'Category')\n const title = pickText(\n readRecordText(record, 'name'),\n readRecordText(record, 'slug'),\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'tree_path', 'treePath'),\n readRecordText(record, 'slug'),\n statusText,\n ) ?? snippet(readRecordText(record, 'description'))\n return { title, subtitle, icon: 'folder-tree', badge: label }\n}\n\nfunction buildOfferPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n channelName?: string | null,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.offer', 'Channel Offer')\n const channelLabel = channelName ?? readRecordText(record, 'channel_name', 'channelName')\n const title = pickText(\n readRecordText(record, 'title'),\n readRecordText(record, 'id'),\n ) ?? label\n const titleWithChannel = channelLabel ? `${title} \u00B7 ${channelLabel}` : title\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(statusText) ?? snippet(readRecordText(record, 'description'))\n return { title: titleWithChannel, subtitle, icon: 'store', badge: label }\n}\n\nfunction buildTagPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.tag', 'Tag')\n const title = pickText(\n readRecordText(record, 'label'),\n readRecordText(record, 'slug'),\n readRecordText(record, 'id'),\n ) ?? label\n const subtitle = formatSubtitle(readRecordText(record, 'slug'))\n return { title, subtitle, icon: 'tag', badge: label }\n}\n\nfunction buildPriceKindPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.priceKind', 'Price Kind')\n const title = pickText(\n readRecordText(record, 'title'),\n readRecordText(record, 'code'),\n readRecordText(record, 'id'),\n ) ?? label\n const displayMode = readRecordText(record, 'display_mode', 'displayMode')\n const isPromotion = record.is_promotion ?? record.isPromotion\n const promotionLabel = isPromotion ? translate('catalog.search.priceKind.promotion', 'Promotion') : null\n const displayModeLabel = displayMode === 'including-tax'\n ? translate('catalog.search.priceKind.includingTax', 'Incl. tax')\n : displayMode === 'excluding-tax'\n ? translate('catalog.search.priceKind.excludingTax', 'Excl. tax')\n : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'code'),\n displayModeLabel,\n promotionLabel,\n )\n return { title, subtitle, icon: 'dollar-sign', badge: label }\n}\n\nfunction buildUnitConversionPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.unitConversion', 'Unit Conversion')\n const unitCode = readRecordText(record, 'unit_code', 'unitCode')\n const factor = readRecordText(record, 'to_base_factor', 'toBaseFactor')\n const title = unitCode ? `${unitCode} (\u00D7${factor ?? '?'})` : label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(unitCode, statusText)\n return { title, subtitle, icon: 'ruler', badge: label }\n}\n\nfunction buildOptionSchemaPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.optionSchema', 'Option Schema')\n const title = pickText(\n readRecordText(record, 'name'),\n readRecordText(record, 'code'),\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'code'),\n statusText,\n ) ?? snippet(readRecordText(record, 'description'))\n return { title, subtitle, icon: 'settings', badge: label }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'catalog:catalog_product',\n enabled: true,\n priority: 10,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Title', record.title)\n appendLine(lines, 'Subtitle', record.subtitle)\n appendLine(lines, 'Description', record.description)\n appendLine(lines, 'SKU', record.sku)\n appendLine(lines, 'Handle', record.handle)\n appendLine(lines, 'Product type', record.product_type ?? record.productType)\n appendLine(lines, 'Base unit', record.default_unit ?? record.defaultUnit)\n appendLine(lines, 'Default sales unit', record.default_sales_unit ?? record.defaultSalesUnit)\n appendLine(\n lines,\n 'Default sales quantity',\n record.default_sales_unit_quantity ?? record.defaultSalesUnitQuantity,\n )\n appendLine(lines, 'UoM rounding mode', record.uom_rounding_mode ?? record.uomRoundingMode)\n appendLine(lines, 'UoM rounding scale', record.uom_rounding_scale ?? record.uomRoundingScale)\n appendLine(lines, 'Unit price enabled', record.unit_price_enabled ?? record.unitPriceEnabled)\n appendLine(\n lines,\n 'Unit price reference unit',\n record.unit_price_reference_unit ?? record.unitPriceReferenceUnit,\n )\n appendLine(\n lines,\n 'Unit price base quantity',\n record.unit_price_base_quantity ?? record.unitPriceBaseQuantity,\n )\n return buildIndexSource(ctx, buildProductPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildProductPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => buildProductUrl(readRecordText(ctx.record, 'id')),\n fieldPolicy: {\n searchable: [\n 'title',\n 'subtitle',\n 'description',\n 'sku',\n 'handle',\n 'product_type',\n 'default_unit',\n 'default_sales_unit',\n 'unit_price_reference_unit',\n ],\n excluded: ['metadata', 'dimensions', 'tax_rate_id'],\n },\n },\n {\n entityId: 'catalog:catalog_product_variant',\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'SKU', record.sku)\n appendLine(lines, 'Barcode', record.barcode)\n appendLine(lines, 'Option values', record.option_values ?? record.optionValues)\n return buildIndexSource(ctx, buildVariantPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildVariantPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const productId = resolveProductId(ctx.record)\n const variantId = readRecordText(ctx.record, 'id')\n return buildVariantUrl(productId, variantId)\n },\n fieldPolicy: {\n searchable: ['name', 'sku', 'barcode'],\n excluded: ['metadata', 'dimensions', 'option_values', 'tax_rate_id'],\n },\n },\n {\n entityId: 'catalog:catalog_product_category',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Slug', record.slug)\n appendLine(lines, 'Description', record.description)\n appendLine(lines, 'Path', record.tree_path ?? record.treePath)\n return buildIndexSource(ctx, buildCategoryPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildCategoryPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => buildCategoryUrl(readRecordText(ctx.record, 'id')),\n fieldPolicy: {\n searchable: ['name', 'slug', 'description', 'tree_path'],\n excluded: ['metadata', 'ancestor_ids', 'child_ids', 'descendant_ids'],\n },\n },\n {\n entityId: 'catalog:catalog_offer',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Title', record.title)\n appendLine(lines, 'Description', record.description)\n appendLine(lines, 'Channel', record.channel_id ?? record.channelId)\n return buildIndexSource(ctx, buildOfferPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildOfferPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const productId = resolveProductId(ctx.record)\n return buildProductUrl(productId)\n },\n fieldPolicy: {\n searchable: ['title', 'description'],\n excluded: ['metadata'],\n },\n },\n {\n entityId: 'catalog:catalog_product_tag',\n enabled: true,\n priority: 5,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Label', record.label)\n appendLine(lines, 'Slug', record.slug)\n return buildIndexSource(ctx, buildTagPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildTagPresenter(translate, ctx.record)\n },\n resolveUrl: async () => CATALOG_PRODUCTS_URL,\n fieldPolicy: {\n searchable: ['label', 'slug'],\n },\n },\n {\n entityId: 'catalog:catalog_price_kind',\n enabled: true,\n priority: 4,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Title', record.title)\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'Display mode', record.display_mode ?? record.displayMode)\n appendLine(lines, 'Currency', record.currency_code ?? record.currencyCode)\n return buildIndexSource(ctx, buildPriceKindPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildPriceKindPresenter(translate, ctx.record)\n },\n resolveUrl: async () => CATALOG_CONFIG_URL,\n fieldPolicy: {\n searchable: ['title', 'code'],\n },\n },\n {\n entityId: 'catalog:catalog_product_unit_conversion',\n enabled: true,\n priority: 3,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Unit code', record.unit_code ?? record.unitCode)\n appendLine(lines, 'To base factor', record.to_base_factor ?? record.toBaseFactor)\n appendLine(lines, 'Sort order', record.sort_order ?? record.sortOrder)\n const isActive = record.is_active ?? record.isActive\n appendLine(lines, 'Active', isActive)\n return buildIndexSource(ctx, buildUnitConversionPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildUnitConversionPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const productId = resolveProductId(ctx.record)\n return buildProductUrl(productId)\n },\n fieldPolicy: {\n searchable: ['unit_code'],\n excluded: ['metadata'],\n },\n },\n {\n entityId: 'catalog:catalog_option_schema_template',\n enabled: true,\n priority: 4,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'Description', record.description)\n return buildIndexSource(ctx, buildOptionSchemaPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildOptionSchemaPresenter(translate, ctx.record)\n },\n resolveUrl: async () => CATALOG_CONFIG_URL,\n fieldPolicy: {\n searchable: ['name', 'code', 'description'],\n excluded: ['schema', 'metadata'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { SearchBuildContext, SearchIndexSource, SearchModuleConfig, SearchResultPresenter } from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nconst CATALOG_PRODUCTS_URL = '/backend/catalog/products'\nconst CATALOG_CATEGORIES_URL = '/backend/catalog/categories'\nconst CATALOG_CONFIG_URL = '/backend/config/catalog'\n\nfunction normalizeText(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n }\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n return null\n}\n\nfunction pickText(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n const text = normalizeText(candidate)\n if (text) return text\n }\n return null\n}\n\nfunction readRecordText(record: Record<string, unknown>, ...keys: string[]): string | null {\n for (const key of keys) {\n const text = normalizeText(record[key])\n if (text) return text\n }\n return null\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => normalizeText(part))\n .filter((value): value is string => Boolean(value))\n if (!text.length) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction snippet(value: unknown, maxLength = 140): string | undefined {\n const text = normalizeText(value)\n if (!text) return undefined\n if (text.length <= maxLength) return text\n return `${text.slice(0, maxLength - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => normalizeText(item)).filter(Boolean).join(', ')\n : typeof value === 'object'\n ? JSON.stringify(value)\n : String(value)\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction friendlyLabel(input: string): string {\n return input\n .replace(/^cf:/, '')\n .replace(/_/g, ' ')\n .replace(/([a-z])([A-Z])/g, (_match, firstChar, secondChar) => `${firstChar} ${secondChar}`)\n .replace(/\\b\\w/g, (character) => character.toUpperCase())\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, friendlyLabel(key), value)\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nfunction buildProductUrl(productId: string | null): string | null {\n if (!productId) return null\n return `${CATALOG_PRODUCTS_URL}/${encodeURIComponent(productId)}`\n}\n\nfunction buildVariantUrl(productId: string | null, variantId: string | null): string | null {\n if (!productId || !variantId) return null\n return `${CATALOG_PRODUCTS_URL}/${encodeURIComponent(productId)}/variants/${encodeURIComponent(variantId)}`\n}\n\nfunction buildCategoryUrl(categoryId: string | null): string | null {\n if (!categoryId) return null\n return `${CATALOG_CATEGORIES_URL}/${encodeURIComponent(categoryId)}/edit`\n}\n\nfunction resolveProductId(record: Record<string, unknown>): string | null {\n // Check direct FK fields first\n const directId = readRecordText(record, 'product_id', 'productId')\n if (directId) return directId\n // Check if product is a string (FK value)\n const product = record.product\n if (typeof product === 'string') return product\n // Check if product is an object with id\n if (product && typeof product === 'object') {\n const productObj = product as Record<string, unknown>\n return readRecordText(productObj, 'id')\n }\n return null\n}\n\nfunction buildProductPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.product', 'Product')\n const title = pickText(\n readRecordText(record, 'title'),\n readRecordText(record, 'sku'),\n readRecordText(record, 'handle'),\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'subtitle'),\n readRecordText(record, 'sku'),\n readRecordText(record, 'product_type', 'productType'),\n statusText,\n ) ?? snippet(readRecordText(record, 'description'))\n return { title, subtitle, icon: 'package', badge: label }\n}\n\nfunction buildVariantPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.variant', 'Variant')\n const isDefault = record.is_default ?? record.isDefault\n const defaultLabel = isDefault ? translate('catalog.search.variant.default', 'Default') : null\n const title = pickText(\n readRecordText(record, 'name'),\n readRecordText(record, 'sku'),\n defaultLabel,\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'sku'),\n readRecordText(record, 'barcode'),\n defaultLabel,\n statusText,\n )\n return { title, subtitle, icon: 'box', badge: label }\n}\n\nfunction buildCategoryPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.category', 'Category')\n const title = pickText(\n readRecordText(record, 'name'),\n readRecordText(record, 'slug'),\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'tree_path', 'treePath'),\n readRecordText(record, 'slug'),\n statusText,\n ) ?? snippet(readRecordText(record, 'description'))\n return { title, subtitle, icon: 'folder-tree', badge: label }\n}\n\nfunction buildOfferPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n channelName?: string | null,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.offer', 'Channel Offer')\n const channelLabel = channelName ?? readRecordText(record, 'channel_name', 'channelName')\n const title = pickText(\n readRecordText(record, 'title'),\n readRecordText(record, 'id'),\n ) ?? label\n const titleWithChannel = channelLabel ? `${title} \u00B7 ${channelLabel}` : title\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(statusText) ?? snippet(readRecordText(record, 'description'))\n return { title: titleWithChannel, subtitle, icon: 'store', badge: label }\n}\n\nfunction buildTagPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.tag', 'Tag')\n const title = pickText(\n readRecordText(record, 'label'),\n readRecordText(record, 'slug'),\n readRecordText(record, 'id'),\n ) ?? label\n const subtitle = formatSubtitle(readRecordText(record, 'slug'))\n return { title, subtitle, icon: 'tag', badge: label }\n}\n\nfunction buildPriceKindPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.priceKind', 'Price Kind')\n const title = pickText(\n readRecordText(record, 'title'),\n readRecordText(record, 'code'),\n readRecordText(record, 'id'),\n ) ?? label\n const displayMode = readRecordText(record, 'display_mode', 'displayMode')\n const isPromotion = record.is_promotion ?? record.isPromotion\n const promotionLabel = isPromotion ? translate('catalog.search.priceKind.promotion', 'Promotion') : null\n const displayModeLabel = displayMode === 'including-tax'\n ? translate('catalog.search.priceKind.includingTax', 'Incl. tax')\n : displayMode === 'excluding-tax'\n ? translate('catalog.search.priceKind.excludingTax', 'Excl. tax')\n : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'code'),\n displayModeLabel,\n promotionLabel,\n )\n return { title, subtitle, icon: 'dollar-sign', badge: label }\n}\n\nfunction buildUnitConversionPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.unitConversion', 'Unit Conversion')\n const unitCode = readRecordText(record, 'unit_code', 'unitCode')\n const factor = readRecordText(record, 'to_base_factor', 'toBaseFactor')\n const title = unitCode ? `${unitCode} (\u00D7${factor ?? '?'})` : label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(unitCode, statusText)\n return { title, subtitle, icon: 'ruler', badge: label }\n}\n\nfunction buildOptionSchemaPresenter(\n translate: TranslateFn,\n record: Record<string, unknown>,\n): SearchResultPresenter {\n const label = translate('catalog.search.badge.optionSchema', 'Option Schema')\n const title = pickText(\n readRecordText(record, 'name'),\n readRecordText(record, 'code'),\n readRecordText(record, 'id'),\n ) ?? label\n const isActive = record.is_active ?? record.isActive\n const statusText = isActive === false ? translate('catalog.search.status.inactive', 'Inactive') : null\n const subtitle = formatSubtitle(\n readRecordText(record, 'code'),\n statusText,\n ) ?? snippet(readRecordText(record, 'description'))\n return { title, subtitle, icon: 'settings', badge: label }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'catalog:catalog_product',\n aclFeatures: ['catalog.products.view'],\n enabled: true,\n priority: 10,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Title', record.title)\n appendLine(lines, 'Subtitle', record.subtitle)\n appendLine(lines, 'Description', record.description)\n appendLine(lines, 'SKU', record.sku)\n appendLine(lines, 'Handle', record.handle)\n appendLine(lines, 'Product type', record.product_type ?? record.productType)\n appendLine(lines, 'Base unit', record.default_unit ?? record.defaultUnit)\n appendLine(lines, 'Default sales unit', record.default_sales_unit ?? record.defaultSalesUnit)\n appendLine(\n lines,\n 'Default sales quantity',\n record.default_sales_unit_quantity ?? record.defaultSalesUnitQuantity,\n )\n appendLine(lines, 'UoM rounding mode', record.uom_rounding_mode ?? record.uomRoundingMode)\n appendLine(lines, 'UoM rounding scale', record.uom_rounding_scale ?? record.uomRoundingScale)\n appendLine(lines, 'Unit price enabled', record.unit_price_enabled ?? record.unitPriceEnabled)\n appendLine(\n lines,\n 'Unit price reference unit',\n record.unit_price_reference_unit ?? record.unitPriceReferenceUnit,\n )\n appendLine(\n lines,\n 'Unit price base quantity',\n record.unit_price_base_quantity ?? record.unitPriceBaseQuantity,\n )\n return buildIndexSource(ctx, buildProductPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildProductPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => buildProductUrl(readRecordText(ctx.record, 'id')),\n fieldPolicy: {\n searchable: [\n 'title',\n 'subtitle',\n 'description',\n 'sku',\n 'handle',\n 'product_type',\n 'default_unit',\n 'default_sales_unit',\n 'unit_price_reference_unit',\n ],\n excluded: ['metadata', 'dimensions', 'tax_rate_id'],\n },\n },\n {\n entityId: 'catalog:catalog_product_variant',\n aclFeatures: ['catalog.products.view'],\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'SKU', record.sku)\n appendLine(lines, 'Barcode', record.barcode)\n appendLine(lines, 'Option values', record.option_values ?? record.optionValues)\n return buildIndexSource(ctx, buildVariantPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildVariantPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const productId = resolveProductId(ctx.record)\n const variantId = readRecordText(ctx.record, 'id')\n return buildVariantUrl(productId, variantId)\n },\n fieldPolicy: {\n searchable: ['name', 'sku', 'barcode'],\n excluded: ['metadata', 'dimensions', 'option_values', 'tax_rate_id'],\n },\n },\n {\n entityId: 'catalog:catalog_product_category',\n aclFeatures: ['catalog.categories.view'],\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Slug', record.slug)\n appendLine(lines, 'Description', record.description)\n appendLine(lines, 'Path', record.tree_path ?? record.treePath)\n return buildIndexSource(ctx, buildCategoryPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildCategoryPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => buildCategoryUrl(readRecordText(ctx.record, 'id')),\n fieldPolicy: {\n searchable: ['name', 'slug', 'description', 'tree_path'],\n excluded: ['metadata', 'ancestor_ids', 'child_ids', 'descendant_ids'],\n },\n },\n {\n entityId: 'catalog:catalog_offer',\n aclFeatures: ['sales.channels.manage'],\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Title', record.title)\n appendLine(lines, 'Description', record.description)\n appendLine(lines, 'Channel', record.channel_id ?? record.channelId)\n return buildIndexSource(ctx, buildOfferPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildOfferPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const productId = resolveProductId(ctx.record)\n return buildProductUrl(productId)\n },\n fieldPolicy: {\n searchable: ['title', 'description'],\n excluded: ['metadata'],\n },\n },\n {\n entityId: 'catalog:catalog_product_tag',\n aclFeatures: ['catalog.products.view'],\n enabled: true,\n priority: 5,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Label', record.label)\n appendLine(lines, 'Slug', record.slug)\n return buildIndexSource(ctx, buildTagPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildTagPresenter(translate, ctx.record)\n },\n resolveUrl: async () => CATALOG_PRODUCTS_URL,\n fieldPolicy: {\n searchable: ['label', 'slug'],\n },\n },\n {\n entityId: 'catalog:catalog_price_kind',\n aclFeatures: ['catalog.settings.manage'],\n enabled: true,\n priority: 4,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Title', record.title)\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'Display mode', record.display_mode ?? record.displayMode)\n appendLine(lines, 'Currency', record.currency_code ?? record.currencyCode)\n return buildIndexSource(ctx, buildPriceKindPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildPriceKindPresenter(translate, ctx.record)\n },\n resolveUrl: async () => CATALOG_CONFIG_URL,\n fieldPolicy: {\n searchable: ['title', 'code'],\n },\n },\n {\n entityId: 'catalog:catalog_product_unit_conversion',\n aclFeatures: ['catalog.products.view'],\n enabled: true,\n priority: 3,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Unit code', record.unit_code ?? record.unitCode)\n appendLine(lines, 'To base factor', record.to_base_factor ?? record.toBaseFactor)\n appendLine(lines, 'Sort order', record.sort_order ?? record.sortOrder)\n const isActive = record.is_active ?? record.isActive\n appendLine(lines, 'Active', isActive)\n return buildIndexSource(ctx, buildUnitConversionPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildUnitConversionPresenter(translate, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const productId = resolveProductId(ctx.record)\n return buildProductUrl(productId)\n },\n fieldPolicy: {\n searchable: ['unit_code'],\n excluded: ['metadata'],\n },\n },\n {\n entityId: 'catalog:catalog_option_schema_template',\n aclFeatures: ['catalog.products.view'],\n enabled: true,\n priority: 4,\n buildSource: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'Description', record.description)\n return buildIndexSource(ctx, buildOptionSchemaPresenter(translate, record), lines)\n },\n formatResult: async (ctx) => {\n const { t: translate } = await resolveTranslations()\n return buildOptionSchemaPresenter(translate, ctx.record)\n },\n resolveUrl: async () => CATALOG_CONFIG_URL,\n fieldPolicy: {\n searchable: ['name', 'code', 'description'],\n excluded: ['schema', 'metadata'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -37,6 +37,7 @@ const searchConfig = {
37
37
  entities: [
38
38
  {
39
39
  entityId: "customer_accounts:customer_user",
40
+ aclFeatures: ["customer_accounts.view"],
40
41
  enabled: true,
41
42
  priority: 6,
42
43
  buildSource: async (ctx) => {
@@ -74,6 +75,7 @@ const searchConfig = {
74
75
  },
75
76
  {
76
77
  entityId: "customer_accounts:customer_role",
78
+ aclFeatures: ["customer_accounts.view"],
77
79
  enabled: true,
78
80
  priority: 6,
79
81
  buildSource: async (ctx) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/customer_accounts/search.ts"],
4
- "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = typeof value === 'object' ? JSON.stringify(value) : String(value)\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'customer_accounts:customer_user',\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.display_name ?? record.displayName)\n appendLine(lines, 'Email', record.email)\n return buildIndexSource(\n ctx,\n {\n title: pickString(record.display_name, record.displayName) ?? String(record.id),\n subtitle: formatSubtitle(record.email),\n icon: 'user',\n badge: t('customer_accounts.search.badge.customerUser', 'Customer User'),\n },\n lines,\n )\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n return {\n title: pickString(record.display_name, record.displayName) ?? String(record.id),\n subtitle: formatSubtitle(record.email),\n icon: 'user',\n badge: t('customer_accounts.search.badge.customerUser', 'Customer User'),\n }\n },\n resolveUrl: async (ctx) => `/backend/customer-accounts/users/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['display_name', 'email'],\n excluded: ['password_hash', 'email_hash'],\n },\n },\n {\n entityId: 'customer_accounts:customer_role',\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Description', record.description)\n return buildIndexSource(\n ctx,\n {\n title: pickString(record.name) ?? String(record.id),\n subtitle: formatSubtitle(snippet(record.description)),\n icon: 'shield',\n badge: t('customer_accounts.search.badge.customerRole', 'Customer Role'),\n },\n lines,\n )\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n return {\n title: pickString(record.name) ?? String(record.id),\n subtitle: formatSubtitle(snippet(record.description)),\n icon: 'shield',\n badge: t('customer_accounts.search.badge.customerRole', 'Customer Role'),\n }\n },\n resolveUrl: async (ctx) => `/backend/customer-accounts/roles/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = typeof value === 'object' ? JSON.stringify(value) : String(value)\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'customer_accounts:customer_user',\n aclFeatures: ['customer_accounts.view'],\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.display_name ?? record.displayName)\n appendLine(lines, 'Email', record.email)\n return buildIndexSource(\n ctx,\n {\n title: pickString(record.display_name, record.displayName) ?? String(record.id),\n subtitle: formatSubtitle(record.email),\n icon: 'user',\n badge: t('customer_accounts.search.badge.customerUser', 'Customer User'),\n },\n lines,\n )\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n return {\n title: pickString(record.display_name, record.displayName) ?? String(record.id),\n subtitle: formatSubtitle(record.email),\n icon: 'user',\n badge: t('customer_accounts.search.badge.customerUser', 'Customer User'),\n }\n },\n resolveUrl: async (ctx) => `/backend/customer-accounts/users/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['display_name', 'email'],\n excluded: ['password_hash', 'email_hash'],\n },\n },\n {\n entityId: 'customer_accounts:customer_role',\n aclFeatures: ['customer_accounts.view'],\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Description', record.description)\n return buildIndexSource(\n ctx,\n {\n title: pickString(record.name) ?? String(record.id),\n subtitle: formatSubtitle(snippet(record.description)),\n icon: 'shield',\n badge: t('customer_accounts.search.badge.customerRole', 'Customer Role'),\n },\n lines,\n )\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n return {\n title: pickString(record.name) ?? String(record.id),\n subtitle: formatSubtitle(snippet(record.description)),\n icon: 'shield',\n badge: t('customer_accounts.search.badge.customerRole', 'Customer Role'),\n }\n },\n resolveUrl: async (ctx) => `/backend/customer-accounts/roles/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }