@open-mercato/core 0.4.2-canary-19353c5970 → 0.4.2-canary-ad4e7882e9

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 (37) hide show
  1. package/dist/modules/auth/api/login.js +25 -6
  2. package/dist/modules/auth/api/login.js.map +2 -2
  3. package/dist/modules/auth/data/validators.js +2 -1
  4. package/dist/modules/auth/data/validators.js.map +2 -2
  5. package/dist/modules/auth/frontend/login.js +85 -1
  6. package/dist/modules/auth/frontend/login.js.map +2 -2
  7. package/dist/modules/auth/lib/setup-app.js +25 -12
  8. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  9. package/dist/modules/auth/services/authService.js +21 -0
  10. package/dist/modules/auth/services/authService.js.map +2 -2
  11. package/dist/modules/business_rules/cli.js +2 -1
  12. package/dist/modules/business_rules/cli.js.map +2 -2
  13. package/dist/modules/directory/api/get/tenants/lookup.js +70 -0
  14. package/dist/modules/directory/api/get/tenants/lookup.js.map +7 -0
  15. package/dist/modules/notifications/migrations/Migration20260129082610.js +13 -0
  16. package/dist/modules/notifications/migrations/Migration20260129082610.js.map +7 -0
  17. package/dist/modules/query_index/cli.js +63 -7
  18. package/dist/modules/query_index/cli.js.map +2 -2
  19. package/dist/modules/workflows/cli.js +12 -12
  20. package/dist/modules/workflows/cli.js.map +2 -2
  21. package/package.json +2 -2
  22. package/src/modules/auth/api/__tests__/login.test.ts +2 -0
  23. package/src/modules/auth/api/login.ts +26 -7
  24. package/src/modules/auth/data/validators.ts +1 -0
  25. package/src/modules/auth/frontend/login.tsx +106 -2
  26. package/src/modules/auth/i18n/de.json +5 -0
  27. package/src/modules/auth/i18n/en.json +5 -0
  28. package/src/modules/auth/i18n/es.json +5 -0
  29. package/src/modules/auth/i18n/pl.json +5 -0
  30. package/src/modules/auth/lib/setup-app.ts +37 -15
  31. package/src/modules/auth/services/authService.ts +23 -0
  32. package/src/modules/business_rules/cli.ts +2 -1
  33. package/src/modules/directory/api/get/tenants/lookup.ts +75 -0
  34. package/src/modules/notifications/migrations/.snapshot-open-mercato.json +36 -0
  35. package/src/modules/notifications/migrations/Migration20260129082610.ts +13 -0
  36. package/src/modules/query_index/cli.ts +82 -13
  37. package/src/modules/workflows/cli.ts +12 -12
@@ -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 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 { SalesSettings, SalesDocumentSequence } from '@open-mercato/core/modules/sales/data/entities'\nimport {\n DEFAULT_ORDER_NUMBER_FORMAT,\n DEFAULT_QUOTE_NUMBER_FORMAT,\n} from '@open-mercato/core/modules/sales/lib/documentNumberTokens'\nimport { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { EncryptionMap } from '@open-mercato/core/modules/entities/data/entities'\nimport { DEFAULT_ENCRYPTION_MAPS } from '@open-mercato/core/modules/entities/lib/encryptionDefaults'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nconst DEFAULT_ROLE_NAMES = ['employee', 'admin', 'superadmin'] as const\nconst DEMO_SUPERADMIN_EMAIL = 'superadmin@acme.com'\n\nexport type EnsureRolesOptions = {\n roleNames?: string[]\n tenantId?: string | null\n}\n\nasync function ensureRolesInContext(\n em: EntityManager,\n roleNames: string[],\n tenantId: string | null,\n) {\n for (const name of roleNames) {\n const existing = await em.findOne(Role, { name, tenantId })\n if (existing) continue\n if (tenantId !== null) {\n const globalRole = await em.findOne(Role, { name, tenantId: null })\n if (globalRole) {\n globalRole.tenantId = tenantId\n em.persist(globalRole)\n continue\n }\n }\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) ?? null\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 let role = await em.findOne(Role, { name, tenantId: normalizedTenant })\n if (!role && normalizedTenant !== null) {\n role = await em.findOne(Role, { name, tenantId: null })\n }\n return role\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 SetupInitialTenantOptions = {\n orgName: string\n primaryUser: PrimaryUserInput\n roleNames?: string[]\n includeDerivedUsers?: boolean\n failIfUserExists?: boolean\n primaryUserRoles?: string[]\n includeSuperadminRole?: boolean\n}\n\nexport type SetupInitialTenantResult = {\n tenantId: string\n organizationId: string\n users: Array<{ user: User; roles: string[]; created: boolean }>\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\n const mainEmail = primaryUser.email\n const existingUser = await em.findOne(User, { email: mainEmail })\n if (existingUser && failIfUserExists) {\n throw new Error('USER_EXISTS')\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 }> = []\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\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<{ email: string; roles: string[]; name?: string | null }> = [\n { email: primaryUser.email, roles: primaryRoles, name: resolvePrimaryName(primaryUser) },\n ]\n if (includeDerivedUsers) {\n const [local, domain] = String(primaryUser.email).split('@')\n const isSuperadminLocal = (local || '').toLowerCase() === 'superadmin' && !!domain\n if (isSuperadminLocal) {\n const adminOverride = readEnvValue(DERIVED_EMAIL_ENV.admin)\n const employeeOverride = readEnvValue(DERIVED_EMAIL_ENV.employee)\n const adminEmail = adminOverride ?? `admin@${domain}`\n const employeeEmail = employeeOverride ?? `employee@${domain}`\n addUniqueBaseUser(baseUsers, { email: adminEmail, roles: ['admin'] })\n addUniqueBaseUser(baseUsers, { email: employeeEmail, roles: ['employee'] })\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} Tenant`,\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 tenant,\n isActive: true,\n depth: 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\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 console.info('\uD83D\uDD11 [encryption][setup] provisioning tenant DEK', { tenantId: String(tenant.id) })\n }\n await kms.createTenantDek(String(tenant.id))\n if (isEncryptionDebugEnabled()) {\n console.info('\uD83D\uDD11 [encryption][setup] created tenant DEK during setup', { tenantId: String(tenant.id) })\n }\n } else {\n if (isEncryptionDebugEnabled()) {\n console.warn('\u26A0\uFE0F [encryption][setup] KMS not healthy, skipping tenant DEK creation', { tenantId: String(tenant.id) })\n }\n }\n } catch (err) {\n if (isEncryptionDebugEnabled()) {\n console.warn('\u26A0\uFE0F [encryption][setup] 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 for (const spec of DEFAULT_ENCRYPTION_MAPS) {\n const existing = await tem.findOne(EncryptionMap, { entityId: spec.entityId, tenantId: tenant.id, organizationId: organization.id, deletedAt: null })\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 let user = await tem.findOne(User, { email: base.email })\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 = passwordHash\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 })\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,\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 })\n }\n await tem.flush()\n for (const roleName of base.roles) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n const existingLink = await tem.findOne(UserRole, { user, role })\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, { includeSuperadminRole })\n await deactivateDemoSuperAdminIfSelfOnboardingEnabled(em)\n await ensureSalesNumberingDefaults(em, { tenantId, organizationId })\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 }>,\n entry: { email: string; roles: string[]; name?: 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\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\nasync function ensureDefaultRoleAcls(\n em: EntityManager,\n tenantId: string,\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 if (includeSuperadminRole && superadminRole) {\n await ensureRoleAclFor(em, superadminRole, tenantId, ['directory.tenants.*'], { isSuperAdmin: true })\n }\n if (adminRole) {\n const adminFeatures = [\n 'auth.*',\n 'entities.*',\n 'attachments.*',\n 'attachments.view',\n 'attachments.manage',\n 'query_index.*',\n 'search.*',\n 'vector.*',\n 'feature_toggles.*',\n 'configs.system_status.view',\n 'configs.cache.view',\n 'configs.cache.manage',\n 'configs.manage',\n 'catalog.*',\n 'catalog.variants.manage',\n 'catalog.pricing.manage',\n 'sales.*',\n 'audit_logs.*',\n 'directory.organizations.view',\n 'directory.organizations.manage',\n 'customers.*',\n 'customers.people.view',\n 'customers.people.manage',\n 'customers.companies.view',\n 'customers.companies.manage',\n 'customers.deals.view',\n 'customers.deals.manage',\n 'dictionaries.view',\n 'dictionaries.manage',\n 'example.*',\n 'dashboards.*',\n 'dashboards.admin.assign-widgets',\n 'analytics.view',\n 'api_keys.*',\n 'notifications.manage',\n 'perspectives.use',\n 'perspectives.role_defaults',\n 'business_rules.*',\n 'workflows.*',\n 'currencies.*',\n 'staff.*',\n 'staff.leave_requests.manage',\n 'resources.*',\n 'planner.*',\n ]\n await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures, { remove: ['directory.organizations.*', 'directory.tenants.*'] })\n }\n if (employeeRole) {\n await ensureRoleAclFor(em, employeeRole, tenantId, [\n 'customers.*',\n 'customers.people.view',\n 'customers.people.manage',\n 'customers.companies.view',\n 'customers.companies.manage',\n 'vector.*',\n 'catalog.*',\n 'catalog.variants.manage',\n 'catalog.pricing.manage',\n 'sales.*',\n 'dictionaries.view',\n 'example.*',\n 'example.widgets.*',\n 'dashboards.view',\n 'dashboards.configure',\n 'analytics.view',\n 'audit_logs.undo_self',\n 'perspectives.use',\n 'staff.leave_requests.send',\n 'staff.my_availability.view',\n 'staff.my_availability.manage',\n 'staff.my_leave_requests.view',\n 'staff.my_leave_requests.send',\n 'planner.view',\n ])\n }\n}\n\nasync function ensureRoleAclFor(\n em: EntityManager,\n role: Role,\n tenantId: string,\n features: string[],\n options: { isSuperAdmin?: boolean; remove?: string[] } = {},\n) {\n const existing = await em.findOne(RoleAcl, { role, tenantId })\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.persistAndFlush(acl)\n return\n }\n const currentFeatures = Array.isArray(existing.featuresJson) ? existing.featuresJson : []\n const merged = Array.from(new Set([...currentFeatures, ...features]))\n const removeSet = new Set(options.remove ?? [])\n const sanitized =\n removeSet.size\n ? merged.filter((value) => {\n if (removeSet.has(value)) return false\n for (const entry of removeSet) {\n if (entry.endsWith('.*')) {\n const prefix = entry.slice(0, -1) // keep trailing dot\n if (value === entry || value.startsWith(prefix)) return false\n }\n }\n return true\n })\n : merged\n const changed =\n sanitized.length !== currentFeatures.length ||\n sanitized.some((value, index) => value !== currentFeatures[index])\n if (changed) existing.featuresJson = sanitized\n if (options.isSuperAdmin && !existing.isSuperAdmin) {\n existing.isSuperAdmin = true\n }\n if (changed || options.isSuperAdmin) {\n await em.persistAndFlush(existing)\n }\n}\n\nasync function deactivateDemoSuperAdminIfSelfOnboardingEnabled(em: EntityManager) {\n if (process.env.SELF_SERVICE_ONBOARDING_ENABLED !== 'true') return\n try {\n const user = await em.findOne(User, { email: DEMO_SUPERADMIN_EMAIL })\n if (!user) return\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.persistAndFlush(user)\n }\n } catch (error) {\n console.error('[auth.setup] failed to deactivate demo superadmin user', error)\n }\n}\n\nasync function ensureSalesNumberingDefaults(\n em: EntityManager,\n scope: { tenantId: string; organizationId: string },\n) {\n const repo = (em as any).getRepository?.(SalesSettings)\n const findSettings = async () =>\n repo?.findOne({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }) ??\n (em as any).findOne?.(SalesSettings, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n\n const exists = await findSettings()\n if (!exists) {\n const settings =\n repo?.create?.({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n orderNumberFormat: DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: DEFAULT_QUOTE_NUMBER_FORMAT,\n createdAt: new Date(),\n updatedAt: new Date(),\n }) ??\n (em as any).create?.(SalesSettings, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n orderNumberFormat: DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: DEFAULT_QUOTE_NUMBER_FORMAT,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n if (settings && (em as any).persist) {\n em.persist(settings)\n }\n }\n\n const sequenceRepo = (em as any).getRepository?.(SalesDocumentSequence)\n const kinds: Array<'order' | 'quote'> = ['order', 'quote']\n for (const kind of kinds) {\n const seq =\n sequenceRepo?.findOne({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n }) ??\n (em as any).findOne?.(SalesDocumentSequence, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n })\n if (!seq) {\n const entry =\n sequenceRepo?.create?.({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n currentValue: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n }) ??\n (em as any).create?.(SalesDocumentSequence, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n currentValue: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n if (entry && (em as any).persist) {\n em.persist(entry)\n }\n }\n }\n\n if ((em as any).flush) {\n await em.flush()\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { hash } from 'bcryptjs'\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 { SalesSettings, SalesDocumentSequence } from '@open-mercato/core/modules/sales/data/entities'\nimport {\n DEFAULT_ORDER_NUMBER_FORMAT,\n DEFAULT_QUOTE_NUMBER_FORMAT,\n} from '@open-mercato/core/modules/sales/lib/documentNumberTokens'\nimport { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { isEncryptionDebugEnabled, isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { EncryptionMap } from '@open-mercato/core/modules/entities/data/entities'\nimport { DEFAULT_ENCRYPTION_MAPS } from '@open-mercato/core/modules/entities/lib/encryptionDefaults'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\nconst DEFAULT_ROLE_NAMES = ['employee', 'admin', 'superadmin'] as const\nconst DEMO_SUPERADMIN_EMAIL = 'superadmin@acme.com'\n\nexport type EnsureRolesOptions = {\n roleNames?: string[]\n tenantId?: string | null\n}\n\nasync function ensureRolesInContext(\n em: EntityManager,\n roleNames: string[],\n tenantId: string | null,\n) {\n for (const name of roleNames) {\n const existing = await em.findOne(Role, { name, tenantId })\n if (existing) continue\n if (tenantId !== null) {\n const globalRole = await em.findOne(Role, { name, tenantId: null })\n if (globalRole) {\n globalRole.tenantId = tenantId\n em.persist(globalRole)\n continue\n }\n }\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) ?? null\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 let role = await em.findOne(Role, { name, tenantId: normalizedTenant })\n if (!role && normalizedTenant !== null) {\n role = await em.findOne(Role, { name, tenantId: null })\n }\n return role\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 SetupInitialTenantOptions = {\n orgName: string\n primaryUser: PrimaryUserInput\n roleNames?: string[]\n includeDerivedUsers?: boolean\n failIfUserExists?: boolean\n primaryUserRoles?: string[]\n includeSuperadminRole?: boolean\n}\n\nexport type SetupInitialTenantResult = {\n tenantId: string\n organizationId: string\n users: Array<{ user: User; roles: string[]; created: boolean }>\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\n const mainEmail = primaryUser.email\n const existingUser = await em.findOne(User, { email: mainEmail })\n if (existingUser && failIfUserExists) {\n throw new Error('USER_EXISTS')\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 }> = []\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\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 }> = [\n { email: primaryUser.email, roles: primaryRoles, name: resolvePrimaryName(primaryUser) },\n ]\n if (includeDerivedUsers) {\n const [, domain] = String(primaryUser.email).split('@')\n const adminOverride = readEnvValue(DERIVED_EMAIL_ENV.admin)\n const employeeOverride = readEnvValue(DERIVED_EMAIL_ENV.employee)\n const adminEmail = adminOverride ?? (domain ? `admin@${domain}` : '')\n const employeeEmail = employeeOverride ?? (domain ? `employee@${domain}` : '')\n const adminPassword = readEnvValue('OM_INIT_ADMIN_PASSWORD')\n const employeePassword = readEnvValue('OM_INIT_EMPLOYEE_PASSWORD')\n const adminPasswordHash = adminPassword ? await resolvePasswordHash({ email: adminEmail, password: adminPassword }) : null\n const employeePasswordHash = employeePassword\n ? await resolvePasswordHash({ email: employeeEmail, password: employeePassword })\n : null\n addUniqueBaseUser(baseUsers, { email: adminEmail, roles: ['admin'], passwordHash: adminPasswordHash })\n addUniqueBaseUser(baseUsers, { email: employeeEmail, roles: ['employee'], passwordHash: employeePasswordHash })\n }\n const passwordHash = await resolvePasswordHash(primaryUser)\n\n await em.transactional(async (tem) => {\n const tenant = tem.create(Tenant, {\n name: `${options.orgName} Tenant`,\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 tenant,\n isActive: true,\n depth: 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\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 console.info('\uD83D\uDD11 [encryption][setup] provisioning tenant DEK', { tenantId: String(tenant.id) })\n }\n await kms.createTenantDek(String(tenant.id))\n if (isEncryptionDebugEnabled()) {\n console.info('\uD83D\uDD11 [encryption][setup] created tenant DEK during setup', { tenantId: String(tenant.id) })\n }\n } else {\n if (isEncryptionDebugEnabled()) {\n console.warn('\u26A0\uFE0F [encryption][setup] KMS not healthy, skipping tenant DEK creation', { tenantId: String(tenant.id) })\n }\n }\n } catch (err) {\n if (isEncryptionDebugEnabled()) {\n console.warn('\u26A0\uFE0F [encryption][setup] 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 for (const spec of DEFAULT_ENCRYPTION_MAPS) {\n const existing = await tem.findOne(EncryptionMap, { entityId: spec.entityId, tenantId: tenant.id, organizationId: organization.id, deletedAt: null })\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 tem.findOne(User, { email: base.email })\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 })\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 })\n }\n await tem.flush()\n for (const roleName of base.roles) {\n const role = await findRoleByNameOrFail(tem, roleName, roleTenantId)\n const existingLink = await tem.findOne(UserRole, { user, role })\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, { includeSuperadminRole })\n await deactivateDemoSuperAdminIfSelfOnboardingEnabled(em)\n await ensureSalesNumberingDefaults(em, { tenantId, organizationId })\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 }>,\n entry: { email: string; roles: string[]; name?: string | null; passwordHash?: 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\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\nasync function ensureDefaultRoleAcls(\n em: EntityManager,\n tenantId: string,\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 if (includeSuperadminRole && superadminRole) {\n await ensureRoleAclFor(em, superadminRole, tenantId, ['directory.tenants.*'], { isSuperAdmin: true })\n }\n if (adminRole) {\n const adminFeatures = [\n 'auth.*',\n 'entities.*',\n 'attachments.*',\n 'attachments.view',\n 'attachments.manage',\n 'query_index.*',\n 'search.*',\n 'vector.*',\n 'feature_toggles.*',\n 'configs.system_status.view',\n 'configs.cache.view',\n 'configs.cache.manage',\n 'configs.manage',\n 'catalog.*',\n 'catalog.variants.manage',\n 'catalog.pricing.manage',\n 'sales.*',\n 'audit_logs.*',\n 'directory.organizations.view',\n 'directory.organizations.manage',\n 'customers.*',\n 'customers.people.view',\n 'customers.people.manage',\n 'customers.companies.view',\n 'customers.companies.manage',\n 'customers.deals.view',\n 'customers.deals.manage',\n 'dictionaries.view',\n 'dictionaries.manage',\n 'example.*',\n 'dashboards.*',\n 'dashboards.admin.assign-widgets',\n 'analytics.view',\n 'api_keys.*',\n 'notifications.manage',\n 'perspectives.use',\n 'perspectives.role_defaults',\n 'business_rules.*',\n 'workflows.*',\n 'currencies.*',\n 'staff.*',\n 'staff.leave_requests.manage',\n 'resources.*',\n 'planner.*',\n ]\n await ensureRoleAclFor(em, adminRole, tenantId, adminFeatures, { remove: ['directory.organizations.*', 'directory.tenants.*'] })\n }\n if (employeeRole) {\n await ensureRoleAclFor(em, employeeRole, tenantId, [\n 'customers.*',\n 'customers.people.view',\n 'customers.people.manage',\n 'customers.companies.view',\n 'customers.companies.manage',\n 'vector.*',\n 'catalog.*',\n 'catalog.variants.manage',\n 'catalog.pricing.manage',\n 'sales.*',\n 'dictionaries.view',\n 'example.*',\n 'example.widgets.*',\n 'dashboards.view',\n 'dashboards.configure',\n 'analytics.view',\n 'audit_logs.undo_self',\n 'perspectives.use',\n 'staff.leave_requests.send',\n 'staff.my_availability.view',\n 'staff.my_availability.manage',\n 'staff.my_leave_requests.view',\n 'staff.my_leave_requests.send',\n 'planner.view',\n ])\n }\n}\n\nasync function ensureRoleAclFor(\n em: EntityManager,\n role: Role,\n tenantId: string,\n features: string[],\n options: { isSuperAdmin?: boolean; remove?: string[] } = {},\n) {\n const existing = await em.findOne(RoleAcl, { role, tenantId })\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.persistAndFlush(acl)\n return\n }\n const currentFeatures = Array.isArray(existing.featuresJson) ? existing.featuresJson : []\n const merged = Array.from(new Set([...currentFeatures, ...features]))\n const removeSet = new Set(options.remove ?? [])\n const sanitized =\n removeSet.size\n ? merged.filter((value) => {\n if (removeSet.has(value)) return false\n for (const entry of removeSet) {\n if (entry.endsWith('.*')) {\n const prefix = entry.slice(0, -1) // keep trailing dot\n if (value === entry || value.startsWith(prefix)) return false\n }\n }\n return true\n })\n : merged\n const changed =\n sanitized.length !== currentFeatures.length ||\n sanitized.some((value, index) => value !== currentFeatures[index])\n if (changed) existing.featuresJson = sanitized\n if (options.isSuperAdmin && !existing.isSuperAdmin) {\n existing.isSuperAdmin = true\n }\n if (changed || options.isSuperAdmin) {\n await em.persistAndFlush(existing)\n }\n}\n\nasync function deactivateDemoSuperAdminIfSelfOnboardingEnabled(em: EntityManager) {\n if (process.env.SELF_SERVICE_ONBOARDING_ENABLED !== 'true') return\n if (shouldKeepDemoSuperadminDuringInit()) return\n try {\n const user = await em.findOne(User, { email: DEMO_SUPERADMIN_EMAIL })\n if (!user) return\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.persistAndFlush(user)\n }\n } catch (error) {\n console.error('[auth.setup] failed to deactivate demo superadmin user', error)\n }\n}\n\nasync function ensureSalesNumberingDefaults(\n em: EntityManager,\n scope: { tenantId: string; organizationId: string },\n) {\n const repo = (em as any).getRepository?.(SalesSettings)\n const findSettings = async () =>\n repo?.findOne({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }) ??\n (em as any).findOne?.(SalesSettings, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n\n const exists = await findSettings()\n if (!exists) {\n const settings =\n repo?.create?.({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n orderNumberFormat: DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: DEFAULT_QUOTE_NUMBER_FORMAT,\n createdAt: new Date(),\n updatedAt: new Date(),\n }) ??\n (em as any).create?.(SalesSettings, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n orderNumberFormat: DEFAULT_ORDER_NUMBER_FORMAT,\n quoteNumberFormat: DEFAULT_QUOTE_NUMBER_FORMAT,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n if (settings && (em as any).persist) {\n em.persist(settings)\n }\n }\n\n const sequenceRepo = (em as any).getRepository?.(SalesDocumentSequence)\n const kinds: Array<'order' | 'quote'> = ['order', 'quote']\n for (const kind of kinds) {\n const seq =\n sequenceRepo?.findOne({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n }) ??\n (em as any).findOne?.(SalesDocumentSequence, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n })\n if (!seq) {\n const entry =\n sequenceRepo?.create?.({\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n currentValue: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n }) ??\n (em as any).create?.(SalesDocumentSequence, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n documentKind: kind,\n currentValue: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n if (entry && (em as any).persist) {\n em.persist(entry)\n }\n }\n }\n\n if ((em as any).flush) {\n await em.flush()\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -16,6 +16,27 @@ class AuthService {
16
16
  ]
17
17
  });
18
18
  }
19
+ async findUsersByEmail(email) {
20
+ const emailHash = computeEmailHash(email);
21
+ return this.em.find(User, {
22
+ deletedAt: null,
23
+ $or: [
24
+ { email },
25
+ { emailHash }
26
+ ]
27
+ });
28
+ }
29
+ async findUserByEmailAndTenant(email, tenantId) {
30
+ const emailHash = computeEmailHash(email);
31
+ return this.em.findOne(User, {
32
+ tenantId,
33
+ deletedAt: null,
34
+ $or: [
35
+ { email },
36
+ { emailHash }
37
+ ]
38
+ });
39
+ }
19
40
  async verifyPassword(user, password) {
20
41
  if (!user.passwordHash) return false;
21
42
  return compare(password, user.passwordHash);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/services/authService.ts"],
4
- "sourcesContent": ["import { EntityManager } from '@mikro-orm/postgresql'\nimport { compare, hash } from 'bcryptjs'\nimport { User, Role, UserRole, Session, PasswordReset } from '@open-mercato/core/modules/auth/data/entities'\nimport crypto from 'node:crypto'\nimport { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nexport class AuthService {\n constructor(private em: EntityManager) {}\n\n async findUserByEmail(email: string) {\n const emailHash = computeEmailHash(email)\n return this.em.findOne(User, {\n $or: [\n { email },\n { emailHash },\n ],\n } as any)\n }\n\n async verifyPassword(user: User, password: string) {\n if (!user.passwordHash) return false\n return compare(password, user.passwordHash)\n }\n\n async updateLastLoginAt(user: User) {\n const now = new Date()\n // Use native update to avoid flushing unrelated entities that might be pending in this EM\n await this.em.nativeUpdate(User, { id: user.id }, { lastLoginAt: now })\n user.lastLoginAt = now\n }\n\n async getUserRoles(user: User, tenantId?: string | null): Promise<string[]> {\n const resolvedTenantId = tenantId ?? user.tenantId ?? null\n if (!resolvedTenantId) return []\n const links = await findWithDecryption(\n this.em,\n UserRole,\n { user, role: { tenantId: resolvedTenantId } as any },\n { populate: ['role'] },\n { tenantId: resolvedTenantId, organizationId: user.organizationId ?? null },\n )\n return links.map((l) => l.role.name)\n }\n\n\n async createSession(user: User, expiresAt: Date): Promise<Session> {\n const token = crypto.randomBytes(32).toString('hex')\n const sess = this.em.create(Session as any, { user, token, expiresAt, createdAt: new Date() } as any)\n await this.em.persistAndFlush(sess)\n return sess as Session\n }\n\n async deleteSessionByToken(token: string) {\n await this.em.nativeDelete(Session, { token })\n }\n\n async refreshFromSessionToken(token: string) {\n const now = new Date()\n const sess = await this.em.findOne(Session, { token })\n if (!sess || sess.expiresAt <= now) return null\n const user = await this.em.findOne(User, { id: sess.user.id })\n if (!user) return null\n const roles = await this.getUserRoles(user, user.tenantId ?? null)\n return { user, roles }\n }\n\n async requestPasswordReset(email: string) {\n const user = await this.findUserByEmail(email)\n if (!user) return null\n const token = crypto.randomBytes(32).toString('hex')\n const expiresAt = new Date(Date.now() + 60 * 60 * 1000)\n const row = this.em.create(PasswordReset as any, { user, token, expiresAt, createdAt: new Date() } as any)\n await this.em.persistAndFlush(row)\n return { user, token }\n }\n\n async confirmPasswordReset(token: string, newPassword: string): Promise<User | null> {\n const now = new Date()\n const row = await this.em.findOne(PasswordReset, { token })\n if (!row || (row.usedAt && row.usedAt <= now) || row.expiresAt <= now) return null\n const user = await this.em.findOne(User, { id: row.user.id })\n if (!user) return null\n user.passwordHash = await hash(newPassword, 10)\n row.usedAt = new Date()\n await this.em.flush()\n return user\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { EntityManager } from '@mikro-orm/postgresql'\nimport { compare, hash } from 'bcryptjs'\nimport { User, Role, UserRole, Session, PasswordReset } from '@open-mercato/core/modules/auth/data/entities'\nimport crypto from 'node:crypto'\nimport { computeEmailHash } from '@open-mercato/core/modules/auth/lib/emailHash'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nexport class AuthService {\n constructor(private em: EntityManager) {}\n\n async findUserByEmail(email: string) {\n const emailHash = computeEmailHash(email)\n return this.em.findOne(User, {\n $or: [\n { email },\n { emailHash },\n ],\n } as any)\n }\n\n async findUsersByEmail(email: string) {\n const emailHash = computeEmailHash(email)\n return this.em.find(User, {\n deletedAt: null,\n $or: [\n { email },\n { emailHash },\n ],\n } as any)\n }\n\n async findUserByEmailAndTenant(email: string, tenantId: string) {\n const emailHash = computeEmailHash(email)\n return this.em.findOne(User, {\n tenantId,\n deletedAt: null,\n $or: [\n { email },\n { emailHash },\n ],\n } as any)\n }\n\n async verifyPassword(user: User, password: string) {\n if (!user.passwordHash) return false\n return compare(password, user.passwordHash)\n }\n\n async updateLastLoginAt(user: User) {\n const now = new Date()\n // Use native update to avoid flushing unrelated entities that might be pending in this EM\n await this.em.nativeUpdate(User, { id: user.id }, { lastLoginAt: now })\n user.lastLoginAt = now\n }\n\n async getUserRoles(user: User, tenantId?: string | null): Promise<string[]> {\n const resolvedTenantId = tenantId ?? user.tenantId ?? null\n if (!resolvedTenantId) return []\n const links = await findWithDecryption(\n this.em,\n UserRole,\n { user, role: { tenantId: resolvedTenantId } as any },\n { populate: ['role'] },\n { tenantId: resolvedTenantId, organizationId: user.organizationId ?? null },\n )\n return links.map((l) => l.role.name)\n }\n\n\n async createSession(user: User, expiresAt: Date): Promise<Session> {\n const token = crypto.randomBytes(32).toString('hex')\n const sess = this.em.create(Session as any, { user, token, expiresAt, createdAt: new Date() } as any)\n await this.em.persistAndFlush(sess)\n return sess as Session\n }\n\n async deleteSessionByToken(token: string) {\n await this.em.nativeDelete(Session, { token })\n }\n\n async refreshFromSessionToken(token: string) {\n const now = new Date()\n const sess = await this.em.findOne(Session, { token })\n if (!sess || sess.expiresAt <= now) return null\n const user = await this.em.findOne(User, { id: sess.user.id })\n if (!user) return null\n const roles = await this.getUserRoles(user, user.tenantId ?? null)\n return { user, roles }\n }\n\n async requestPasswordReset(email: string) {\n const user = await this.findUserByEmail(email)\n if (!user) return null\n const token = crypto.randomBytes(32).toString('hex')\n const expiresAt = new Date(Date.now() + 60 * 60 * 1000)\n const row = this.em.create(PasswordReset as any, { user, token, expiresAt, createdAt: new Date() } as any)\n await this.em.persistAndFlush(row)\n return { user, token }\n }\n\n async confirmPasswordReset(token: string, newPassword: string): Promise<User | null> {\n const now = new Date()\n const row = await this.em.findOne(PasswordReset, { token })\n if (!row || (row.usedAt && row.usedAt <= now) || row.expiresAt <= now) return null\n const user = await this.em.findOne(User, { id: row.user.id })\n if (!user) return null\n user.passwordHash = await hash(newPassword, 10)\n row.usedAt = new Date()\n await this.em.flush()\n return user\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,SAAS,YAAY;AAC9B,SAAS,MAAY,UAAU,SAAS,qBAAqB;AAC7D,OAAO,YAAY;AACnB,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAE5B,MAAM,YAAY;AAAA,EACvB,YAAoB,IAAmB;AAAnB;AAAA,EAAoB;AAAA,EAExC,MAAM,gBAAgB,OAAe;AACnC,UAAM,YAAY,iBAAiB,KAAK;AACxC,WAAO,KAAK,GAAG,QAAQ,MAAM;AAAA,MAC3B,KAAK;AAAA,QACH,EAAE,MAAM;AAAA,QACR,EAAE,UAAU;AAAA,MACd;AAAA,IACF,CAAQ;AAAA,EACV;AAAA,EAEA,MAAM,iBAAiB,OAAe;AACpC,UAAM,YAAY,iBAAiB,KAAK;AACxC,WAAO,KAAK,GAAG,KAAK,MAAM;AAAA,MACxB,WAAW;AAAA,MACX,KAAK;AAAA,QACH,EAAE,MAAM;AAAA,QACR,EAAE,UAAU;AAAA,MACd;AAAA,IACF,CAAQ;AAAA,EACV;AAAA,EAEA,MAAM,yBAAyB,OAAe,UAAkB;AAC9D,UAAM,YAAY,iBAAiB,KAAK;AACxC,WAAO,KAAK,GAAG,QAAQ,MAAM;AAAA,MAC3B;AAAA,MACA,WAAW;AAAA,MACX,KAAK;AAAA,QACH,EAAE,MAAM;AAAA,QACR,EAAE,UAAU;AAAA,MACd;AAAA,IACF,CAAQ;AAAA,EACV;AAAA,EAEA,MAAM,eAAe,MAAY,UAAkB;AACjD,QAAI,CAAC,KAAK,aAAc,QAAO;AAC/B,WAAO,QAAQ,UAAU,KAAK,YAAY;AAAA,EAC5C;AAAA,EAEA,MAAM,kBAAkB,MAAY;AAClC,UAAM,MAAM,oBAAI,KAAK;AAErB,UAAM,KAAK,GAAG,aAAa,MAAM,EAAE,IAAI,KAAK,GAAG,GAAG,EAAE,aAAa,IAAI,CAAC;AACtE,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAM,aAAa,MAAY,UAA6C;AAC1E,UAAM,mBAAmB,YAAY,KAAK,YAAY;AACtD,QAAI,CAAC,iBAAkB,QAAO,CAAC;AAC/B,UAAM,QAAQ,MAAM;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,MACA,EAAE,MAAM,MAAM,EAAE,UAAU,iBAAiB,EAAS;AAAA,MACpD,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,MACrB,EAAE,UAAU,kBAAkB,gBAAgB,KAAK,kBAAkB,KAAK;AAAA,IAC5E;AACA,WAAO,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI;AAAA,EACrC;AAAA,EAGA,MAAM,cAAc,MAAY,WAAmC;AACjE,UAAM,QAAQ,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACnD,UAAM,OAAO,KAAK,GAAG,OAAO,SAAgB,EAAE,MAAM,OAAO,WAAW,WAAW,oBAAI,KAAK,EAAE,CAAQ;AACpG,UAAM,KAAK,GAAG,gBAAgB,IAAI;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,qBAAqB,OAAe;AACxC,UAAM,KAAK,GAAG,aAAa,SAAS,EAAE,MAAM,CAAC;AAAA,EAC/C;AAAA,EAEA,MAAM,wBAAwB,OAAe;AAC3C,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,OAAO,MAAM,KAAK,GAAG,QAAQ,SAAS,EAAE,MAAM,CAAC;AACrD,QAAI,CAAC,QAAQ,KAAK,aAAa,IAAK,QAAO;AAC3C,UAAM,OAAO,MAAM,KAAK,GAAG,QAAQ,MAAM,EAAE,IAAI,KAAK,KAAK,GAAG,CAAC;AAC7D,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,QAAQ,MAAM,KAAK,aAAa,MAAM,KAAK,YAAY,IAAI;AACjE,WAAO,EAAE,MAAM,MAAM;AAAA,EACvB;AAAA,EAEA,MAAM,qBAAqB,OAAe;AACxC,UAAM,OAAO,MAAM,KAAK,gBAAgB,KAAK;AAC7C,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,QAAQ,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACnD,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,GAAI;AACtD,UAAM,MAAM,KAAK,GAAG,OAAO,eAAsB,EAAE,MAAM,OAAO,WAAW,WAAW,oBAAI,KAAK,EAAE,CAAQ;AACzG,UAAM,KAAK,GAAG,gBAAgB,GAAG;AACjC,WAAO,EAAE,MAAM,MAAM;AAAA,EACvB;AAAA,EAEA,MAAM,qBAAqB,OAAe,aAA2C;AACnF,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,MAAM,MAAM,KAAK,GAAG,QAAQ,eAAe,EAAE,MAAM,CAAC;AAC1D,QAAI,CAAC,OAAQ,IAAI,UAAU,IAAI,UAAU,OAAQ,IAAI,aAAa,IAAK,QAAO;AAC9E,UAAM,OAAO,MAAM,KAAK,GAAG,QAAQ,MAAM,EAAE,IAAI,IAAI,KAAK,GAAG,CAAC;AAC5D,QAAI,CAAC,KAAM,QAAO;AAClB,SAAK,eAAe,MAAM,KAAK,aAAa,EAAE;AAC9C,QAAI,SAAS,oBAAI,KAAK;AACtB,UAAM,KAAK,GAAG,MAAM;AACpB,WAAO;AAAA,EACT;AACF;",
6
6
  "names": []
7
7
  }
@@ -29,6 +29,7 @@ const seedGuardRules = {
29
29
  const em = resolve("em");
30
30
  const rulesPath = path.join(__dirname, "../workflows/examples", "guard-rules-example.json");
31
31
  const rulesData = JSON.parse(fs.readFileSync(rulesPath, "utf8"));
32
+ console.log("\u{1F9E0} Seeding guard rules...");
32
33
  let seededCount = 0;
33
34
  let skippedCount = 0;
34
35
  for (const ruleData of rulesData) {
@@ -52,7 +53,7 @@ const seedGuardRules = {
52
53
  seededCount++;
53
54
  }
54
55
  console.log(`
55
- \u2713 Guard rules seeding complete:`);
56
+ \u2705 Guard rules seeding complete:`);
56
57
  console.log(` - Seeded: ${seededCount}`);
57
58
  console.log(` - Skipped (existing): ${skippedCount}`);
58
59
  console.log(` - Total: ${rulesData.length}`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/business_rules/cli.ts"],
4
- "sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { BusinessRule } from './data/entities'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\n/**\n * Parse CLI arguments\n */\nfunction parseArgs(args: string[]) {\n const result: Record<string, string> = {}\n for (let i = 0; i < args.length; i += 2) {\n const key = args[i]?.replace(/^-+/, '')\n const value = args[i + 1]\n if (key && value) {\n result[key] = value\n }\n }\n return result\n}\n\n/**\n * Seed guard rules for workflow checkout demo\n */\nconst seedGuardRules: ModuleCli = {\n command: 'seed-guard-rules',\n async run(rest: string[]) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? args.t ?? '')\n const organizationId = String(args.organizationId ?? args.orgId ?? args.org ?? args.o ?? '')\n\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato business_rules seed-guard-rules --tenant <tenantId> --org <organizationId>')\n console.error(' or: mercato business_rules seed-guard-rules -t <tenantId> -o <organizationId>')\n return\n }\n\n try {\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n\n // Read guard rules from workflows examples\n const rulesPath = path.join(__dirname, '../workflows/examples', 'guard-rules-example.json')\n const rulesData = JSON.parse(fs.readFileSync(rulesPath, 'utf8'))\n\n let seededCount = 0\n let skippedCount = 0\n\n for (const ruleData of rulesData) {\n // Check if rule already exists\n const existing = await em.findOne(BusinessRule, {\n ruleId: ruleData.ruleId,\n tenantId,\n organizationId,\n })\n\n if (existing) {\n console.log(` \u2298 Guard rule '${ruleData.ruleId}' already exists`)\n skippedCount++\n continue\n }\n\n // Create the business rule\n const rule = em.create(BusinessRule, {\n ...ruleData,\n tenantId,\n organizationId,\n })\n\n await em.persistAndFlush(rule)\n console.log(` \u2713 Seeded guard rule: ${rule.ruleName}`)\n seededCount++\n }\n\n console.log(`\\n\u2713 Guard rules seeding complete:`)\n console.log(` - Seeded: ${seededCount}`)\n console.log(` - Skipped (existing): ${skippedCount}`)\n console.log(` - Total: ${rulesData.length}`)\n } catch (error) {\n console.error('Error seeding guard rules:', error)\n throw error\n }\n },\n}\n\nconst businessRulesCliCommands = [\n seedGuardRules,\n]\n\nexport default businessRulesCliCommands\n"],
5
- "mappings": "AACA,SAAS,8BAA8B;AAEvC,SAAS,oBAAoB;AAC7B,YAAY,QAAQ;AACpB,YAAY,UAAU;AAKtB,SAAS,UAAU,MAAgB;AACjC,QAAM,SAAiC,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAM,MAAM,KAAK,CAAC,GAAG,QAAQ,OAAO,EAAE;AACtC,UAAM,QAAQ,KAAK,IAAI,CAAC;AACxB,QAAI,OAAO,OAAO;AAChB,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAKA,MAAM,iBAA4B;AAAA,EAChC,SAAS;AAAA,EACT,MAAM,IAAI,MAAgB;AACxB,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,WAAW,OAAO,KAAK,YAAY,KAAK,UAAU,KAAK,KAAK,EAAE;AACpE,UAAM,iBAAiB,OAAO,KAAK,kBAAkB,KAAK,SAAS,KAAK,OAAO,KAAK,KAAK,EAAE;AAE3F,QAAI,CAAC,YAAY,CAAC,gBAAgB;AAChC,cAAQ,MAAM,2FAA2F;AACzG,cAAQ,MAAM,kFAAkF;AAChG;AAAA,IACF;AAEA,QAAI;AACF,YAAM,EAAE,QAAQ,IAAI,MAAM,uBAAuB;AACjD,YAAM,KAAK,QAAuB,IAAI;AAGtC,YAAM,YAAY,KAAK,KAAK,WAAW,yBAAyB,0BAA0B;AAC1F,YAAM,YAAY,KAAK,MAAM,GAAG,aAAa,WAAW,MAAM,CAAC;AAE/D,UAAI,cAAc;AAClB,UAAI,eAAe;AAEnB,iBAAW,YAAY,WAAW;AAEhC,cAAM,WAAW,MAAM,GAAG,QAAQ,cAAc;AAAA,UAC9C,QAAQ,SAAS;AAAA,UACjB;AAAA,UACA;AAAA,QACF,CAAC;AAED,YAAI,UAAU;AACZ,kBAAQ,IAAI,wBAAmB,SAAS,MAAM,kBAAkB;AAChE;AACA;AAAA,QACF;AAGA,cAAM,OAAO,GAAG,OAAO,cAAc;AAAA,UACnC,GAAG;AAAA,UACH;AAAA,UACA;AAAA,QACF,CAAC;AAED,cAAM,GAAG,gBAAgB,IAAI;AAC7B,gBAAQ,IAAI,+BAA0B,KAAK,QAAQ,EAAE;AACrD;AAAA,MACF;AAEA,cAAQ,IAAI;AAAA,qCAAmC;AAC/C,cAAQ,IAAI,eAAe,WAAW,EAAE;AACxC,cAAQ,IAAI,2BAA2B,YAAY,EAAE;AACrD,cAAQ,IAAI,cAAc,UAAU,MAAM,EAAE;AAAA,IAC9C,SAAS,OAAO;AACd,cAAQ,MAAM,8BAA8B,KAAK;AACjD,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,MAAM,2BAA2B;AAAA,EAC/B;AACF;AAEA,IAAO,cAAQ;",
4
+ "sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { BusinessRule } from './data/entities'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\n/**\n * Parse CLI arguments\n */\nfunction parseArgs(args: string[]) {\n const result: Record<string, string> = {}\n for (let i = 0; i < args.length; i += 2) {\n const key = args[i]?.replace(/^-+/, '')\n const value = args[i + 1]\n if (key && value) {\n result[key] = value\n }\n }\n return result\n}\n\n/**\n * Seed guard rules for workflow checkout demo\n */\nconst seedGuardRules: ModuleCli = {\n command: 'seed-guard-rules',\n async run(rest: string[]) {\n const args = parseArgs(rest)\n const tenantId = String(args.tenantId ?? args.tenant ?? args.t ?? '')\n const organizationId = String(args.organizationId ?? args.orgId ?? args.org ?? args.o ?? '')\n\n if (!tenantId || !organizationId) {\n console.error('Usage: mercato business_rules seed-guard-rules --tenant <tenantId> --org <organizationId>')\n console.error(' or: mercato business_rules seed-guard-rules -t <tenantId> -o <organizationId>')\n return\n }\n\n try {\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n\n // Read guard rules from workflows examples\n const rulesPath = path.join(__dirname, '../workflows/examples', 'guard-rules-example.json')\n const rulesData = JSON.parse(fs.readFileSync(rulesPath, 'utf8'))\n\n console.log('\uD83E\uDDE0 Seeding guard rules...')\n let seededCount = 0\n let skippedCount = 0\n\n for (const ruleData of rulesData) {\n // Check if rule already exists\n const existing = await em.findOne(BusinessRule, {\n ruleId: ruleData.ruleId,\n tenantId,\n organizationId,\n })\n\n if (existing) {\n console.log(` \u2298 Guard rule '${ruleData.ruleId}' already exists`)\n skippedCount++\n continue\n }\n\n // Create the business rule\n const rule = em.create(BusinessRule, {\n ...ruleData,\n tenantId,\n organizationId,\n })\n\n await em.persistAndFlush(rule)\n console.log(` \u2713 Seeded guard rule: ${rule.ruleName}`)\n seededCount++\n }\n\n console.log(`\\n\u2705 Guard rules seeding complete:`)\n console.log(` - Seeded: ${seededCount}`)\n console.log(` - Skipped (existing): ${skippedCount}`)\n console.log(` - Total: ${rulesData.length}`)\n } catch (error) {\n console.error('Error seeding guard rules:', error)\n throw error\n }\n },\n}\n\nconst businessRulesCliCommands = [\n seedGuardRules,\n]\n\nexport default businessRulesCliCommands\n"],
5
+ "mappings": "AACA,SAAS,8BAA8B;AAEvC,SAAS,oBAAoB;AAC7B,YAAY,QAAQ;AACpB,YAAY,UAAU;AAKtB,SAAS,UAAU,MAAgB;AACjC,QAAM,SAAiC,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAM,MAAM,KAAK,CAAC,GAAG,QAAQ,OAAO,EAAE;AACtC,UAAM,QAAQ,KAAK,IAAI,CAAC;AACxB,QAAI,OAAO,OAAO;AAChB,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAKA,MAAM,iBAA4B;AAAA,EAChC,SAAS;AAAA,EACT,MAAM,IAAI,MAAgB;AACxB,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,WAAW,OAAO,KAAK,YAAY,KAAK,UAAU,KAAK,KAAK,EAAE;AACpE,UAAM,iBAAiB,OAAO,KAAK,kBAAkB,KAAK,SAAS,KAAK,OAAO,KAAK,KAAK,EAAE;AAE3F,QAAI,CAAC,YAAY,CAAC,gBAAgB;AAChC,cAAQ,MAAM,2FAA2F;AACzG,cAAQ,MAAM,kFAAkF;AAChG;AAAA,IACF;AAEA,QAAI;AACF,YAAM,EAAE,QAAQ,IAAI,MAAM,uBAAuB;AACjD,YAAM,KAAK,QAAuB,IAAI;AAGtC,YAAM,YAAY,KAAK,KAAK,WAAW,yBAAyB,0BAA0B;AAC1F,YAAM,YAAY,KAAK,MAAM,GAAG,aAAa,WAAW,MAAM,CAAC;AAE/D,cAAQ,IAAI,kCAA2B;AACvC,UAAI,cAAc;AAClB,UAAI,eAAe;AAEnB,iBAAW,YAAY,WAAW;AAEhC,cAAM,WAAW,MAAM,GAAG,QAAQ,cAAc;AAAA,UAC9C,QAAQ,SAAS;AAAA,UACjB;AAAA,UACA;AAAA,QACF,CAAC;AAED,YAAI,UAAU;AACZ,kBAAQ,IAAI,wBAAmB,SAAS,MAAM,kBAAkB;AAChE;AACA;AAAA,QACF;AAGA,cAAM,OAAO,GAAG,OAAO,cAAc;AAAA,UACnC,GAAG;AAAA,UACH;AAAA,UACA;AAAA,QACF,CAAC;AAED,cAAM,GAAG,gBAAgB,IAAI;AAC7B,gBAAQ,IAAI,+BAA0B,KAAK,QAAQ,EAAE;AACrD;AAAA,MACF;AAEA,cAAQ,IAAI;AAAA,qCAAmC;AAC/C,cAAQ,IAAI,eAAe,WAAW,EAAE;AACxC,cAAQ,IAAI,2BAA2B,YAAY,EAAE;AACrD,cAAQ,IAAI,cAAc,UAAU,MAAM,EAAE;AAAA,IAC9C,SAAS,OAAO;AACd,cAAQ,MAAM,8BAA8B,KAAK;AACjD,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,MAAM,2BAA2B;AAAA,EAC/B;AACF;AAEA,IAAO,cAAQ;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,70 @@
1
+ import { NextResponse } from "next/server";
2
+ import { z } from "zod";
3
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
+ import { Tenant } from "@open-mercato/core/modules/directory/data/entities";
5
+ const metadata = {
6
+ GET: {
7
+ requireAuth: false
8
+ }
9
+ };
10
+ const tenantLookupQuerySchema = z.object({
11
+ tenantId: z.string().uuid()
12
+ });
13
+ async function GET(req) {
14
+ const url = new URL(req.url);
15
+ const tenantId = url.searchParams.get("tenantId") || url.searchParams.get("tenant") || "";
16
+ const parsed = tenantLookupQuerySchema.safeParse({ tenantId });
17
+ if (!parsed.success) {
18
+ return NextResponse.json({ ok: false, error: "Invalid tenant id." }, { status: 400 });
19
+ }
20
+ const container = await createRequestContainer();
21
+ const em = container.resolve("em");
22
+ const tenant = await em.findOne(Tenant, { id: parsed.data.tenantId, deletedAt: null });
23
+ if (!tenant) {
24
+ return NextResponse.json({ ok: false, error: "Tenant not found." }, { status: 404 });
25
+ }
26
+ return NextResponse.json({
27
+ ok: true,
28
+ tenant: { id: String(tenant.id), name: tenant.name }
29
+ });
30
+ }
31
+ const lookupTag = "Directory";
32
+ const tenantLookupSuccessSchema = z.object({
33
+ ok: z.literal(true),
34
+ tenant: z.object({
35
+ id: z.string().uuid(),
36
+ name: z.string()
37
+ })
38
+ });
39
+ const tenantLookupErrorSchema = z.object({
40
+ ok: z.literal(false),
41
+ error: z.string()
42
+ });
43
+ const tenantLookupDoc = {
44
+ summary: "Public tenant lookup",
45
+ description: "Resolves tenant metadata for login/activation flows.",
46
+ tags: [lookupTag],
47
+ query: tenantLookupQuerySchema,
48
+ responses: [
49
+ { status: 200, description: "Tenant resolved.", schema: tenantLookupSuccessSchema }
50
+ ],
51
+ errors: [
52
+ { status: 400, description: "Invalid tenant id", schema: tenantLookupErrorSchema },
53
+ { status: 404, description: "Tenant not found", schema: tenantLookupErrorSchema }
54
+ ]
55
+ };
56
+ const openApi = {
57
+ tag: lookupTag,
58
+ summary: "Public tenant lookup",
59
+ methods: {
60
+ GET: tenantLookupDoc
61
+ }
62
+ };
63
+ var lookup_default = GET;
64
+ export {
65
+ GET,
66
+ lookup_default as default,
67
+ metadata,
68
+ openApi
69
+ };
70
+ //# sourceMappingURL=lookup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/directory/api/get/tenants/lookup.ts"],
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { Tenant } from '@open-mercato/core/modules/directory/data/entities'\nimport type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\n\nexport const metadata = {\n GET: {\n requireAuth: false,\n },\n}\n\nconst tenantLookupQuerySchema = z.object({\n tenantId: z.string().uuid(),\n})\n\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const tenantId = url.searchParams.get('tenantId') || url.searchParams.get('tenant') || ''\n const parsed = tenantLookupQuerySchema.safeParse({ tenantId })\n if (!parsed.success) {\n return NextResponse.json({ ok: false, error: 'Invalid tenant id.' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const tenant = await em.findOne(Tenant, { id: parsed.data.tenantId, deletedAt: null })\n if (!tenant) {\n return NextResponse.json({ ok: false, error: 'Tenant not found.' }, { status: 404 })\n }\n return NextResponse.json({\n ok: true,\n tenant: { id: String(tenant.id), name: tenant.name },\n })\n}\n\nconst lookupTag = 'Directory'\n\nconst tenantLookupSuccessSchema = z.object({\n ok: z.literal(true),\n tenant: z.object({\n id: z.string().uuid(),\n name: z.string(),\n }),\n})\n\nconst tenantLookupErrorSchema = z.object({\n ok: z.literal(false),\n error: z.string(),\n})\n\nconst tenantLookupDoc: OpenApiMethodDoc = {\n summary: 'Public tenant lookup',\n description: 'Resolves tenant metadata for login/activation flows.',\n tags: [lookupTag],\n query: tenantLookupQuerySchema,\n responses: [\n { status: 200, description: 'Tenant resolved.', schema: tenantLookupSuccessSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid tenant id', schema: tenantLookupErrorSchema },\n { status: 404, description: 'Tenant not found', schema: tenantLookupErrorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: lookupTag,\n summary: 'Public tenant lookup',\n methods: {\n GET: tenantLookupDoc,\n },\n}\n\nexport default GET\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAElB,SAAS,8BAA8B;AACvC,SAAS,cAAc;AAGhB,MAAM,WAAW;AAAA,EACtB,KAAK;AAAA,IACH,aAAa;AAAA,EACf;AACF;AAEA,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,UAAU,EAAE,OAAO,EAAE,KAAK;AAC5B,CAAC;AAED,eAAsB,IAAI,KAAc;AACtC,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,QAAM,WAAW,IAAI,aAAa,IAAI,UAAU,KAAK,IAAI,aAAa,IAAI,QAAQ,KAAK;AACvF,QAAM,SAAS,wBAAwB,UAAU,EAAE,SAAS,CAAC;AAC7D,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACtF;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,KAAM,UAAU,QAAQ,IAAI;AAClC,QAAM,SAAS,MAAM,GAAG,QAAQ,QAAQ,EAAE,IAAI,OAAO,KAAK,UAAU,WAAW,KAAK,CAAC;AACrF,MAAI,CAAC,QAAQ;AACX,WAAO,aAAa,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrF;AACA,SAAO,aAAa,KAAK;AAAA,IACvB,IAAI;AAAA,IACJ,QAAQ,EAAE,IAAI,OAAO,OAAO,EAAE,GAAG,MAAM,OAAO,KAAK;AAAA,EACrD,CAAC;AACH;AAEA,MAAM,YAAY;AAElB,MAAM,4BAA4B,EAAE,OAAO;AAAA,EACzC,IAAI,EAAE,QAAQ,IAAI;AAAA,EAClB,QAAQ,EAAE,OAAO;AAAA,IACf,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,IACpB,MAAM,EAAE,OAAO;AAAA,EACjB,CAAC;AACH,CAAC;AAED,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,IAAI,EAAE,QAAQ,KAAK;AAAA,EACnB,OAAO,EAAE,OAAO;AAClB,CAAC;AAED,MAAM,kBAAoC;AAAA,EACxC,SAAS;AAAA,EACT,aAAa;AAAA,EACb,MAAM,CAAC,SAAS;AAAA,EAChB,OAAO;AAAA,EACP,WAAW;AAAA,IACT,EAAE,QAAQ,KAAK,aAAa,oBAAoB,QAAQ,0BAA0B;AAAA,EACpF;AAAA,EACA,QAAQ;AAAA,IACN,EAAE,QAAQ,KAAK,aAAa,qBAAqB,QAAQ,wBAAwB;AAAA,IACjF,EAAE,QAAQ,KAAK,aAAa,oBAAoB,QAAQ,wBAAwB;AAAA,EAClF;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,EACP;AACF;AAEA,IAAO,iBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ import { Migration } from "@mikro-orm/migrations";
2
+ class Migration20260129082610 extends Migration {
3
+ async up() {
4
+ this.addSql(`alter table "notifications" add column if not exists "title_key" text null, add column if not exists "body_key" text null, add column if not exists "title_variables" jsonb null, add column if not exists "body_variables" jsonb null;`);
5
+ }
6
+ async down() {
7
+ this.addSql(`alter table "notifications" drop column if exists "title_key", drop column if exists "body_key", drop column if exists "title_variables", drop column if exists "body_variables";`);
8
+ }
9
+ }
10
+ export {
11
+ Migration20260129082610
12
+ };
13
+ //# sourceMappingURL=Migration20260129082610.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/notifications/migrations/Migration20260129082610.ts"],
4
+ "sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260129082610 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`alter table \"notifications\" add column if not exists \"title_key\" text null, add column if not exists \"body_key\" text null, add column if not exists \"title_variables\" jsonb null, add column if not exists \"body_variables\" jsonb null;`);\n }\n\n override async down(): Promise<void> {\n this.addSql(`alter table \"notifications\" drop column if exists \"title_key\", drop column if exists \"body_key\", drop column if exists \"title_variables\", drop column if exists \"body_variables\";`);\n }\n\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,yOAAyO;AAAA,EACvP;AAAA,EAEA,MAAe,OAAsB;AACnC,SAAK,OAAO,mLAAmL;AAAA,EACjM;AAEF;",
6
+ "names": []
7
+ }
@@ -10,6 +10,43 @@ import { upsertIndexBatch } from "./lib/batch.js";
10
10
  import { reindexEntity, DEFAULT_REINDEX_PARTITIONS } from "./lib/reindexer.js";
11
11
  import { purgeIndexScope } from "./lib/purge.js";
12
12
  import { flattenSystemEntityIds } from "@open-mercato/shared/lib/entities/system-entities";
13
+ function isIndexerVerbose() {
14
+ const parsed = parseBooleanToken(process.env.OM_INDEXER_VERBOSE ?? "");
15
+ return parsed === true;
16
+ }
17
+ function createGroupedProgress(label, partitionTargets) {
18
+ const totals = /* @__PURE__ */ new Map();
19
+ const processed = /* @__PURE__ */ new Map();
20
+ let bar = null;
21
+ const getTotals = () => {
22
+ let total = 0;
23
+ let done = 0;
24
+ for (const value of totals.values()) total += value;
25
+ for (const value of processed.values()) done += value;
26
+ return { total, done };
27
+ };
28
+ const tryInitBar = () => {
29
+ if (bar) return;
30
+ if (totals.size < partitionTargets.length) return;
31
+ const { total } = getTotals();
32
+ if (total <= 0) return;
33
+ bar = createProgressBar(label, total);
34
+ };
35
+ return {
36
+ onProgress(partition, info) {
37
+ processed.set(partition, info.processed);
38
+ if (!totals.has(partition)) totals.set(partition, info.total);
39
+ tryInitBar();
40
+ if (!bar) return;
41
+ const { done } = getTotals();
42
+ bar.update(done);
43
+ },
44
+ complete() {
45
+ if (bar) bar.complete();
46
+ },
47
+ getTotals
48
+ };
49
+ }
13
50
  function parseArgs(rest) {
14
51
  const args = {};
15
52
  for (let i = 0; i < rest.length; i += 1) {
@@ -444,8 +481,11 @@ const reindex = {
444
481
  await purgeIndexScope(baseEm, { entityType: entity, organizationId: orgId, tenantId });
445
482
  }
446
483
  console.log(`Reindexing ${entity}${force ? " (forced)" : ""} in ${partitionTargets.length} partition(s)...`);
447
- const progressState = /* @__PURE__ */ new Map();
484
+ const verbose = isIndexerVerbose();
485
+ const progressState = verbose ? /* @__PURE__ */ new Map() : null;
486
+ const groupedProgress = !verbose && partitionTargets.length > 1 ? createGroupedProgress(`Reindexing ${entity}`, partitionTargets) : null;
448
487
  const renderProgress = (part, entityId, info) => {
488
+ if (!progressState) return;
449
489
  const state = progressState.get(part) ?? { last: 0 };
450
490
  const now = Date.now();
451
491
  if (now - state.last < 1e3 && info.processed < info.total) return;
@@ -461,7 +501,7 @@ const reindex = {
461
501
  const label = partitionTargets.length > 1 ? ` [partition ${part + 1}/${partitionCount}]` : "";
462
502
  if (partitionTargets.length === 1) {
463
503
  console.log(` -> processing${label}`);
464
- } else if (idx === 0) {
504
+ } else if (verbose && idx === 0) {
465
505
  console.log(` -> processing partitions in parallel (count=${partitionTargets.length})`);
466
506
  }
467
507
  const partitionContainer = await createRequestContainer();
@@ -489,9 +529,14 @@ const reindex = {
489
529
  onProgress(info) {
490
530
  if (useBar) {
491
531
  if (info.total > 0 && !progressBar) {
492
- progressBar = createProgressBar(`Reindexing ${entity}${label}`, info.total);
532
+ progressBar = createProgressBar(
533
+ `Reindexing ${entity}${label}`,
534
+ info.total
535
+ );
493
536
  }
494
537
  progressBar?.update(info.processed);
538
+ } else if (groupedProgress) {
539
+ groupedProgress.onProgress(part, info);
495
540
  } else {
496
541
  renderProgress(part, entity, info);
497
542
  }
@@ -500,7 +545,9 @@ const reindex = {
500
545
  if (progressBar) {
501
546
  progressBar.complete();
502
547
  }
503
- if (!useBar) {
548
+ if (!useBar && groupedProgress) {
549
+ groupedProgress.onProgress(part, { processed: partitionStats.processed, total: partitionStats.total });
550
+ } else if (!useBar) {
504
551
  renderProgress(part, entity, { processed: partitionStats.processed, total: partitionStats.total });
505
552
  } else {
506
553
  console.log(
@@ -515,6 +562,7 @@ const reindex = {
515
562
  }
516
563
  })
517
564
  );
565
+ groupedProgress?.complete();
518
566
  const totalProcessed = stats.reduce((acc, value) => acc + value, 0);
519
567
  console.log(`Finished ${entity}: processed ${totalProcessed} row(s) across ${partitionTargets.length} partition(s)`);
520
568
  await recordIndexerLog(
@@ -569,8 +617,11 @@ const reindex = {
569
617
  console.log(
570
618
  `[${idx + 1}/${entityIds.length}] Reindexing ${id}${force ? " (forced)" : ""} in ${partitionTargets.length} partition(s)...`
571
619
  );
572
- const progressState = /* @__PURE__ */ new Map();
620
+ const verbose = isIndexerVerbose();
621
+ const progressState = verbose ? /* @__PURE__ */ new Map() : null;
622
+ const groupedProgress = !verbose && partitionTargets.length > 1 ? createGroupedProgress(`Reindexing ${id}`, partitionTargets) : null;
573
623
  const renderProgress = (part, entityId, info) => {
624
+ if (!progressState) return;
574
625
  const state = progressState.get(part) ?? { last: 0 };
575
626
  const now = Date.now();
576
627
  if (now - state.last < 1e3 && info.processed < info.total) return;
@@ -586,7 +637,7 @@ const reindex = {
586
637
  const label = partitionTargets.length > 1 ? ` [partition ${part + 1}/${partitionCount}]` : "";
587
638
  if (partitionTargets.length === 1) {
588
639
  console.log(` -> processing${label}`);
589
- } else if (partitionIdx === 0) {
640
+ } else if (verbose && partitionIdx === 0) {
590
641
  console.log(` -> processing partitions in parallel (count=${partitionTargets.length})`);
591
642
  }
592
643
  const partitionContainer = await createRequestContainer();
@@ -617,6 +668,8 @@ const reindex = {
617
668
  progressBar = createProgressBar(`Reindexing ${id}${label}`, info.total);
618
669
  }
619
670
  progressBar?.update(info.processed);
671
+ } else if (groupedProgress) {
672
+ groupedProgress.onProgress(part, info);
620
673
  } else {
621
674
  renderProgress(part, id, info);
622
675
  }
@@ -625,7 +678,9 @@ const reindex = {
625
678
  if (progressBar) {
626
679
  progressBar.complete();
627
680
  }
628
- if (!useBar) {
681
+ if (!useBar && groupedProgress) {
682
+ groupedProgress.onProgress(part, { processed: result.processed, total: result.total });
683
+ } else if (!useBar) {
629
684
  renderProgress(part, id, { processed: result.processed, total: result.total });
630
685
  } else {
631
686
  console.log(
@@ -640,6 +695,7 @@ const reindex = {
640
695
  }
641
696
  })
642
697
  );
698
+ groupedProgress?.complete();
643
699
  const totalProcessed = partitionResults.reduce((acc, value) => acc + value, 0);
644
700
  console.log(` -> ${id} complete: processed ${totalProcessed} row(s) across ${partitionTargets.length} partition(s)`);
645
701
  await recordIndexerLog(