@open-mercato/core 0.5.1-develop.2800.bfe2178a4f → 0.5.1-develop.2851.2854b4507f
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/generated/entities/action_log/index.js +4 -0
- package/dist/generated/entities/action_log/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/audit_logs/data/entities.js +10 -1
- package/dist/modules/audit_logs/data/entities.js.map +2 -2
- package/dist/modules/audit_logs/data/validators.js +2 -0
- package/dist/modules/audit_logs/data/validators.js.map +2 -2
- package/dist/modules/audit_logs/migrations/Migration20260423202109.js +15 -0
- package/dist/modules/audit_logs/migrations/Migration20260423202109.js.map +7 -0
- package/dist/modules/audit_logs/services/accessLogService.js +3 -2
- package/dist/modules/audit_logs/services/accessLogService.js.map +3 -3
- package/dist/modules/audit_logs/services/actionLogService.js +13 -2
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +3 -18
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/cancel/route.js +7 -2
- package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/complete/route.js +7 -2
- package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +45 -44
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/commands/comments.js +6 -0
- package/dist/modules/customers/commands/comments.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +41 -13
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js +30 -0
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/DealDetailHeader.js +32 -0
- package/dist/modules/customers/components/detail/DealDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/DealWonPopup.js +2 -2
- package/dist/modules/customers/components/detail/DealWonPopup.js.map +2 -2
- package/dist/modules/customers/components/detail/InlineActivityComposer.js +62 -6
- package/dist/modules/customers/components/detail/InlineActivityComposer.js.map +2 -2
- package/dist/modules/customers/components/detail/ObjectHistoryButton.js +39 -0
- package/dist/modules/customers/components/detail/ObjectHistoryButton.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonDetailHeader.js +30 -0
- package/dist/modules/customers/components/detail/PersonDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/RolesSection.js +14 -4
- package/dist/modules/customers/components/detail/RolesSection.js.map +3 -3
- package/dist/modules/customers/components/formConfig.js +16 -2
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/lib/displayName.js +15 -0
- package/dist/modules/customers/lib/displayName.js.map +7 -0
- package/dist/modules/customers/lib/interactionReadModel.js +1 -2
- package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
- package/dist/modules/customers/lib/operationMetadata.js +21 -0
- package/dist/modules/customers/lib/operationMetadata.js.map +7 -0
- package/dist/modules/messages/components/MessagesInboxPageClient.js +106 -107
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/useMessagesInboxBulkActions.js +235 -0
- package/dist/modules/messages/components/useMessagesInboxBulkActions.js.map +7 -0
- package/generated/entities/action_log/index.ts +2 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +3 -3
- package/src/modules/audit_logs/data/entities.ts +7 -0
- package/src/modules/audit_logs/data/validators.ts +2 -0
- package/src/modules/audit_logs/migrations/.snapshot-open-mercato.json +51 -5
- package/src/modules/audit_logs/migrations/Migration20260423202109.ts +15 -0
- package/src/modules/audit_logs/services/accessLogService.ts +1 -3
- package/src/modules/audit_logs/services/actionLogService.ts +11 -6
- package/src/modules/auth/cli.ts +1 -1
- package/src/modules/customers/api/entity-roles-factory.ts +3 -23
- package/src/modules/customers/api/interactions/cancel/route.ts +7 -2
- package/src/modules/customers/api/interactions/complete/route.ts +7 -2
- package/src/modules/customers/backend/customers/deals/page.tsx +48 -44
- package/src/modules/customers/commands/comments.ts +6 -0
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +37 -9
- package/src/modules/customers/components/detail/CompanyDetailHeader.tsx +25 -0
- package/src/modules/customers/components/detail/DealDetailHeader.tsx +29 -0
- package/src/modules/customers/components/detail/DealWonPopup.tsx +2 -2
- package/src/modules/customers/components/detail/InlineActivityComposer.tsx +65 -6
- package/src/modules/customers/components/detail/ObjectHistoryButton.tsx +47 -0
- package/src/modules/customers/components/detail/PersonDetailHeader.tsx +25 -0
- package/src/modules/customers/components/detail/RolesSection.tsx +20 -1
- package/src/modules/customers/components/formConfig.tsx +14 -2
- package/src/modules/customers/i18n/de.json +12 -0
- package/src/modules/customers/i18n/en.json +12 -0
- package/src/modules/customers/i18n/es.json +13 -1
- package/src/modules/customers/i18n/pl.json +13 -1
- package/src/modules/customers/lib/displayName.ts +16 -0
- package/src/modules/customers/lib/interactionReadModel.ts +1 -7
- package/src/modules/customers/lib/operationMetadata.ts +38 -0
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +17 -29
- package/src/modules/messages/components/useMessagesInboxBulkActions.ts +324 -0
- package/src/modules/messages/i18n/de.json +8 -0
- package/src/modules/messages/i18n/en.json +8 -0
- package/src/modules/messages/i18n/es.json +8 -0
- package/src/modules/messages/i18n/pl.json +8 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/auth/cli.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { hash } from 'bcryptjs'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { User, Role, 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 { ensureRoles, setupInitialTenant, ensureDefaultRoleAcls, ensureCustomRoleAcls } from './lib/setup-app'\nimport { normalizeTenantId } from './lib/tenantAccess'\nimport { computeEmailHash } from './lib/emailHash'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { decryptWithAesGcm } from '@open-mercato/shared/lib/encryption/aes'\nimport { env } from 'process'\nimport type { KmsService, TenantDek } from '@open-mercato/shared/lib/encryption/kms'\nimport crypto from 'node:crypto'\nimport { formatPasswordRequirements, getPasswordPolicy, validatePassword } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { getCliModules } from '@open-mercato/shared/modules/registry'\n\nconst addUser: ModuleCli = {\n command: 'add-user',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n const email = args.email\n const password = args.password\n const organizationId = String(args.organizationId ?? args.orgId ?? args.org)\n const rolesCsv = (args.roles ?? '').trim()\n if (!email || !password || !organizationId) {\n console.error('Usage: mercato auth add-user --email <email> --password <password> --organizationId <id> [--roles customer,employee]')\n return\n }\n if (!ensurePasswordPolicy(password)) return\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const org =\n (await findOneWithDecryption(\n em,\n Organization,\n { id: organizationId },\n { populate: ['tenant'] },\n { tenantId: null, organizationId },\n )) ?? null\n if (!org) throw new Error('Organization not found')\n const orgTenantId = org.tenant?.id ? String(org.tenant.id) : null\n const normalizedTenantId = normalizeTenantId(orgTenantId ?? null) ?? null\n const u = em.create(User, {\n email,\n emailHash: computeEmailHash(email),\n passwordHash: await hash(password, 10),\n isConfirmed: true,\n organizationId: org.id,\n tenantId: org.tenant.id,\n })\n await em.persist(u).flush()\n if (rolesCsv) {\n const names = rolesCsv.split(',').map(s => s.trim()).filter(Boolean)\n for (const name of names) {\n let role = await em.findOne(Role, { name, tenantId: normalizedTenantId })\n if (!role && normalizedTenantId !== null) {\n role = await em.findOne(Role, { name, tenantId: null })\n }\n if (!role) {\n role = em.create(Role, { name, tenantId: normalizedTenantId, createdAt: new Date() })\n await em.persist(role).flush()\n } else if (normalizedTenantId !== null && role.tenantId !== normalizedTenantId) {\n role.tenantId = normalizedTenantId\n await em.persist(role).flush()\n }\n const link = em.create(UserRole, { user: u, role })\n await em.persist(link).flush()\n }\n }\n console.log('User created with id', u.id)\n },\n}\n\nfunction parseArgs(rest: string[]) {\n const args: Record<string, string | boolean> = {}\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i]\n if (!a) continue\n if (a.startsWith('--')) {\n const [k, v] = a.replace(/^--/, '').split('=')\n if (v !== undefined) args[k] = v\n else if (rest[i + 1] && !rest[i + 1]!.startsWith('--')) { args[k] = rest[i + 1]!; i++ }\n else args[k] = true\n }\n }\n return args\n}\n\nfunction normalizeKeyInput(value: string): string {\n return value.trim().replace(/(?:^['\"]|['\"]$)/g, '')\n}\n\nfunction hashSecret(value: string | null | undefined): string | null {\n if (!value) return null\n return crypto.createHash('sha256').update(normalizeKeyInput(value)).digest('hex').slice(0, 12)\n}\n\nfunction ensurePasswordPolicy(password: string): boolean {\n const policy = getPasswordPolicy()\n const result = validatePassword(password, policy)\n if (result.ok) return true\n const requirements = formatPasswordRequirements(policy, (_key, fallback) => fallback)\n const suffix = requirements ? `: ${requirements}` : ''\n console.error(`Password does not meet the requirements${suffix}.`)\n return false\n}\n\nasync function withEncryptionDebugDisabled<T>(fn: () => Promise<T>): Promise<T> {\n const previous = process.env.TENANT_DATA_ENCRYPTION_DEBUG\n process.env.TENANT_DATA_ENCRYPTION_DEBUG = 'no'\n try {\n return await fn()\n } finally {\n if (previous === undefined) {\n delete process.env.TENANT_DATA_ENCRYPTION_DEBUG\n } else {\n process.env.TENANT_DATA_ENCRYPTION_DEBUG = previous\n }\n }\n}\n\nclass DerivedKeyKmsService implements KmsService {\n private root: Buffer\n constructor(secret: string) {\n this.root = crypto.createHash('sha256').update(normalizeKeyInput(secret)).digest()\n }\n\n isHealthy(): boolean {\n return true\n }\n\n private deriveKey(tenantId: string): string {\n const iterations = 310_000\n const keyLength = 32\n const derived = crypto.pbkdf2Sync(this.root, tenantId, iterations, keyLength, 'sha512')\n return derived.toString('base64')\n }\n\n async getTenantDek(tenantId: string): Promise<TenantDek | null> {\n if (!tenantId) return null\n return { tenantId, key: this.deriveKey(tenantId), fetchedAt: Date.now() }\n }\n\n async createTenantDek(tenantId: string): Promise<TenantDek | null> {\n return this.getTenantDek(tenantId)\n }\n}\n\nfunction fingerprintDek(dek: TenantDek | null): string | null {\n if (!dek?.key) return null\n return crypto.createHash('sha256').update(dek.key).digest('hex').slice(0, 12)\n}\n\nfunction decryptWithOldKey(\n payload: string,\n dek: TenantDek | null,\n): string | null {\n if (!dek?.key) return null\n return decryptWithAesGcm(payload, dek.key)\n}\n\nconst seedRoles: ModuleCli = {\n command: 'seed-roles',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const key = rest[i]?.replace(/^--/, '')\n if (!key) continue\n const value = rest[i + 1]\n if (value) args[key] = value\n }\n const tenantId = args.tenantId ?? args.tenant ?? args.tenant_id ?? null\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n if (tenantId) {\n await ensureRoles(em, { tenantId })\n console.log('\uD83D\uDEE1\uFE0F Roles ensured for tenant', tenantId)\n return\n }\n const tenants = await em.find(Tenant, {})\n if (!tenants.length) {\n console.log('No tenants found; nothing to seed.')\n return\n }\n for (const tenant of tenants) {\n const id = tenant.id ? String(tenant.id) : null\n if (!id) continue\n await ensureRoles(em, { tenantId: id })\n console.log('\uD83D\uDEE1\uFE0F Roles ensured for tenant', id)\n }\n },\n}\n\nconst rotateEncryptionKey: ModuleCli = {\n command: 'rotate-encryption-key',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = (args.tenantId as string) ?? (args.tenant as string) ?? (args.tenant_id as string) ?? null\n const organizationId = (args.organizationId as string) ?? (args.orgId as string) ?? (args.org as string) ?? null\n const oldKey = (args['old-key'] as string) ?? (args.oldKey as string) ?? null\n const dryRun = Boolean(args['dry-run'] || args.dry)\n const debug = Boolean(args.debug)\n const rotate = Boolean(oldKey)\n if (rotate && !tenantId) {\n console.warn(\n '\u26A0\uFE0F Rotating with --old-key across all tenants. A single old key should normally target one tenant; consider --tenant.',\n )\n }\n if (!isTenantDataEncryptionEnabled()) {\n console.error('TENANT_DATA_ENCRYPTION is disabled; aborting.')\n return\n }\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n const encryptionService = new TenantDataEncryptionService(em as any, { kms: createKmsService() })\n const oldKms = rotate && oldKey ? new DerivedKeyKmsService(oldKey) : null\n if (debug) {\n console.log('[rotate-encryption-key]', {\n hasOldKey: Boolean(oldKey),\n rotate,\n tenantId: tenantId ?? null,\n organizationId: organizationId ?? null,\n })\n console.log('[rotate-encryption-key] key fingerprints', {\n oldKey: hashSecret(oldKey),\n currentKey: hashSecret(process.env.TENANT_DATA_ENCRYPTION_FALLBACK_KEY),\n })\n }\n if (!encryptionService.isEnabled()) {\n console.error('Encryption service is not enabled (KMS unhealthy or no DEK). Aborting.')\n return\n }\n const conn: any = (em as any).getConnection?.()\n if (!conn || typeof conn.execute !== 'function') {\n console.error('Unable to access raw connection; aborting.')\n return\n }\n const meta = (em as any)?.getMetadata?.()?.get?.(User)\n const tableName = meta?.tableName || 'users'\n const schema = meta?.schema\n const qualifiedTable = schema ? `\"${schema}\".\"${tableName}\"` : `\"${tableName}\"`\n const isEncryptedPayload = (value: unknown): boolean => {\n if (typeof value !== 'string') return false\n const parts = value.split(':')\n return parts.length === 4 && parts[3] === 'v1'\n }\n const printedDek = new Set<string>()\n const oldDekCache = new Map<string, TenantDek | null>()\n const processScope = async (scopeTenantId: string, scopeOrganizationId: string): Promise<number> => {\n if (debug && !printedDek.has(scopeTenantId)) {\n printedDek.add(scopeTenantId)\n const [oldDek, newDek] = await Promise.all([\n oldKms?.getTenantDek(scopeTenantId) ?? Promise.resolve(null),\n encryptionService.getDek(scopeTenantId),\n ])\n console.log('[rotate-encryption-key] dek fingerprints', {\n tenantId: scopeTenantId,\n oldKey: fingerprintDek(oldDek),\n currentKey: fingerprintDek(newDek),\n })\n }\n const rawRows = await conn.execute(\n `select id, email, email_hash from ${qualifiedTable} where tenant_id = ? and organization_id = ?`,\n [scopeTenantId, scopeOrganizationId],\n )\n const rows = Array.isArray(rawRows) ? rawRows : []\n const pending = rotate\n ? rows\n : rows.filter((row: any) => !isEncryptedPayload(row?.email))\n if (!pending.length) return 0\n console.log(\n `Found ${pending.length} auth user records to process for org=${scopeOrganizationId}${dryRun ? ' (dry-run)' : ''}.`\n )\n if (dryRun) return 0\n const ids = pending.map((row: any) => String(row.id))\n const users = rotate\n ? await em.find(\n User,\n { id: { $in: ids }, tenantId: scopeTenantId, organizationId: scopeOrganizationId },\n )\n : await findWithDecryption(\n em,\n User,\n { id: { $in: ids }, tenantId: scopeTenantId, organizationId: scopeOrganizationId },\n {},\n { tenantId: scopeTenantId, organizationId: scopeOrganizationId, encryptionService },\n )\n const usersById = new Map(users.map((user) => [String(user.id), user]))\n let updated = 0\n for (const row of pending) {\n const user = usersById.get(String(row.id))\n if (!user) continue\n const rawEmail = typeof row.email === 'string' ? row.email : String(row.email ?? '')\n if (!rawEmail) continue\n if (rotate && (!isEncryptedPayload(rawEmail) || !oldKms)) {\n continue\n }\n let plainEmail = rawEmail\n if (rotate && isEncryptedPayload(rawEmail) && oldKms) {\n if (debug) {\n console.log('[rotate-encryption-key] decrypting', {\n userId: row.id,\n tenantId: scopeTenantId,\n organizationId: scopeOrganizationId,\n })\n }\n let oldDek = oldDekCache.get(scopeTenantId) ?? null\n if (!oldDekCache.has(scopeTenantId)) {\n oldDek = await oldKms.getTenantDek(scopeTenantId)\n oldDekCache.set(scopeTenantId, oldDek)\n }\n const maybeEmail = decryptWithOldKey(rawEmail, oldDek)\n if (typeof maybeEmail !== 'string' || isEncryptedPayload(maybeEmail)) continue\n plainEmail = maybeEmail\n }\n if (!plainEmail) continue\n const encrypted = await encryptionService.encryptEntityPayload(\n 'auth:user',\n { email: plainEmail },\n scopeTenantId,\n scopeOrganizationId,\n )\n const nextEmail = encrypted.email as string | undefined\n if (nextEmail && nextEmail !== user.email) {\n user.email = nextEmail as any\n user.emailHash = (encrypted as any).emailHash ?? computeEmailHash(plainEmail)\n em.persist(user)\n updated += 1\n }\n }\n if (updated > 0) {\n await em.flush()\n }\n return updated\n }\n\n if (tenantId && organizationId) {\n const updated = await processScope(String(tenantId), String(organizationId))\n if (!updated) {\n console.log('All auth user emails already encrypted for the selected scope.')\n } else {\n console.log(`Encrypted ${updated} auth user email(s).`)\n }\n return\n }\n\n const organizations = await em.find(Organization, {})\n if (!organizations.length) {\n console.log('No organizations found; nothing to encrypt.')\n return\n }\n let total = 0\n for (const org of organizations) {\n const scopeTenantId = org.tenant?.id ? String(org.tenant.id) : org.tenant.id ? String(org.tenant.id) : null\n const scopeOrganizationId = org.id ? String(org.id) : null\n if (!scopeTenantId || !scopeOrganizationId) continue\n total += await processScope(scopeTenantId, scopeOrganizationId)\n }\n if (total > 0) {\n console.log(`Encrypted ${total} auth user email(s) across all organizations.`)\n } else {\n console.log('All auth user emails already encrypted across all organizations.')\n }\n },\n}\n\n// will be exported at the bottom with all commands\n\nconst addOrganization: ModuleCli = {\n command: 'add-org',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n const name = args.name || args.orgName\n if (!name) {\n console.error('Usage: mercato auth add-org --name <organization name>')\n return\n }\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n // Create tenant implicitly for simplicity\n const tenant = em.create(Tenant, { name: `${name} Tenant` })\n await em.persist(tenant).flush()\n const org = em.create(Organization, { name, tenant })\n await em.persist(org).flush()\n await rebuildHierarchyForTenant(em, String(tenant.id))\n console.log('Organization created with id', org.id, 'in tenant', tenant.id)\n },\n}\n\nconst setupApp: ModuleCli = {\n command: 'setup',\n async run(rest) {\n const args = parseArgs(rest)\n const orgName = typeof args.orgName === 'string'\n ? args.orgName\n : typeof args.name === 'string'\n ? args.name\n : undefined\n const email = typeof args.email === 'string' ? args.email : undefined\n const password = typeof args.password === 'string' ? args.password : undefined\n const rolesCsv = typeof args.roles === 'string'\n ? args.roles.trim()\n : 'superadmin,admin,employee'\n const skipPasswordPolicyRaw =\n args['skip-password-policy'] ??\n args.skipPasswordPolicy ??\n args['allow-weak-password'] ??\n args.allowWeakPassword\n const skipPasswordPolicy = typeof skipPasswordPolicyRaw === 'boolean'\n ? skipPasswordPolicyRaw\n : parseBooleanToken(typeof skipPasswordPolicyRaw === 'string' ? skipPasswordPolicyRaw : null) ?? false\n if (!orgName || !email || !password) {\n console.error('Usage: mercato auth setup --orgName <name> --email <email> --password <password> [--roles superadmin,admin,employee] [--skip-password-policy]')\n return\n }\n if (!skipPasswordPolicy && !ensurePasswordPolicy(password)) return\n if (skipPasswordPolicy) {\n console.warn('\u26A0\uFE0F Password policy validation skipped for setup.')\n }\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n const roleNames = rolesCsv\n ? rolesCsv.split(',').map((s) => s.trim()).filter(Boolean)\n : undefined\n\n try {\n const result = await setupInitialTenant(em, {\n orgName,\n roleNames,\n primaryUser: { email, password, confirm: true },\n includeDerivedUsers: true,\n modules: getCliModules(),\n })\n\n if (result.reusedExistingUser) {\n console.log('\u26A0\uFE0F Existing initial user detected during setup.')\n console.log(`\u26A0\uFE0F Email: ${email}`)\n console.log('\u26A0\uFE0F Updated roles if missing and reused tenant/organization.')\n }\n\n if (env.NODE_ENV !== 'test') {\n for (const snapshot of result.users) {\n if (snapshot.created) {\n if (snapshot.user.email === email && password) {\n console.log('\uD83C\uDF89 Created user', snapshot.user.email, 'password:', password)\n } else {\n console.log('\uD83C\uDF89 Created user', snapshot.user.email)\n }\n } else {\n console.log(`Updated user ${snapshot.user.email}`)\n }\n }\n }\n\n if (env.NODE_ENV !== 'test') console.log('\u2705 Setup complete:', { tenantId: result.tenantId, organizationId: result.organizationId })\n } catch (err) {\n if (err instanceof Error && err.message === 'USER_EXISTS') {\n console.error('Setup aborted: user already exists with the provided email.')\n return\n }\n throw err\n }\n },\n}\n\nconst listOrganizations: ModuleCli = {\n command: 'list-orgs',\n async run() {\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const orgs = await findWithDecryption(\n em,\n Organization,\n {},\n { populate: ['tenant'] },\n { tenantId: null, organizationId: null },\n )\n\n if (orgs.length === 0) {\n console.log('No organizations found')\n return\n }\n\n console.log(`Found ${orgs.length} organization(s):`)\n console.log('')\n console.log('ID | Name | Tenant ID | Created')\n console.log('-------------------------------------|-------------------------|-------------------------------------|-------------------')\n\n for (const org of orgs) {\n const created = org.createdAt ? new Date(org.createdAt).toLocaleDateString() : 'N/A'\n const id = org.id || 'N/A'\n const tenantId = org.tenant?.id || 'N/A'\n const name = (org.name || 'Unnamed').padEnd(23)\n console.log(`${id.padEnd(35)} | ${name} | ${tenantId.padEnd(35)} | ${created}`)\n }\n },\n}\n\nconst listTenants: ModuleCli = {\n command: 'list-tenants',\n async run() {\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const tenants = await em.find(Tenant, {})\n\n if (tenants.length === 0) {\n console.log('No tenants found')\n return\n }\n\n console.log(`Found ${tenants.length} tenant(s):`)\n console.log('')\n console.log('ID | Name | Created')\n console.log('-------------------------------------|-------------------------|-------------------')\n\n for (const tenant of tenants) {\n const created = tenant.createdAt ? new Date(tenant.createdAt).toLocaleDateString() : 'N/A'\n const id = tenant.id || 'N/A'\n const name = (tenant.name || 'Unnamed').padEnd(23)\n console.log(`${id.padEnd(35)} | ${name} | ${created}`)\n }\n },\n}\n\nconst listUsers: ModuleCli = {\n command: 'list-users',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n\n // Build query with optional filters\n const where: any = {}\n if (args.organizationId || args.orgId || args.org) {\n where.organizationId = args.organizationId || args.orgId || args.org\n }\n if (args.tenantId || args.tenant) {\n where.tenantId = args.tenantId || args.tenant\n }\n\n const users = await em.find(User, where)\n\n if (users.length === 0) {\n console.log('No users found')\n return\n }\n\n console.log(`Found ${users.length} user(s):`)\n console.log('')\n console.log('ID | Email | Name | Organization ID | Tenant ID | Roles')\n console.log('-------------------------------------|-------------------------|-------------------------|---------------------|---------------------|-------------------')\n\n for (const user of users) {\n // Get user roles separately\n const userRoles = await findWithDecryption(\n em,\n UserRole,\n { user: user.id },\n { populate: ['role'] },\n { tenantId: user.tenantId ?? null, organizationId: user.organizationId ?? null },\n )\n const roles = userRoles.map((ur: any) => ur.role?.name).filter(Boolean).join(', ') || 'None'\n\n // Get organization and tenant names if IDs exist\n let orgName = 'N/A'\n let tenantName = 'N/A'\n\n if (user.organizationId) {\n const org = await em.findOne(Organization, { id: user.organizationId })\n orgName = org?.name?.substring(0, 19) + '...' || user.organizationId.substring(0, 8) + '...'\n }\n\n if (user.tenantId) {\n const tenant = await em.findOne(Tenant, { id: user.tenantId })\n tenantName = tenant?.name?.substring(0, 19) + '...' || user.tenantId.substring(0, 8) + '...'\n }\n\n const id = user.id || 'N/A'\n const email = (user.email || 'N/A').padEnd(23)\n const name = (user.name || 'Unnamed').padEnd(23)\n\n console.log(`${id.padEnd(35)} | ${email} | ${name} | ${orgName.padEnd(19)} | ${tenantName.padEnd(19)} | ${roles}`)\n }\n },\n}\n\nconst setPassword: ModuleCli = {\n command: 'set-password',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n\n const email = args.email\n const password = args.password\n\n if (!email || !password) {\n console.error('Usage: mercato auth set-password --email <email> --password <newPassword>')\n return\n }\n if (!ensurePasswordPolicy(password)) return\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const emailHash = computeEmailHash(email)\n const user = await em.findOne(User, { $or: [{ email }, { emailHash }] })\n\n if (!user) {\n console.error(`User with email \"${email}\" not found`)\n return\n }\n\n user.passwordHash = await hash(password, 10)\n await em.persist(user).flush()\n\n console.log(`\u2705 Password updated successfully for user: ${email}`)\n },\n}\n\n// Export the full CLI list\nconst syncRoleAcls: ModuleCli = {\n command: 'sync-role-acls',\n async run(rest) {\n const args: Record<string, string> = {}\n const flags = new Set<string>()\n for (let i = 0; i < rest.length; i++) {\n const token = rest[i]\n if (!token?.startsWith('--')) continue\n const key = token.replace(/^--/, '')\n const next = rest[i + 1]\n if (next && !next.startsWith('--')) {\n args[key] = next\n i++\n } else {\n flags.add(key)\n }\n }\n const tenantArg = args.tenantId ?? args.tenant ?? args.tenant_id ?? null\n const includeSuperadminRole = !flags.has('no-superadmin')\n\n const modules = getCliModules()\n if (!modules.length) {\n console.error('\u274C No CLI modules registered. Run `yarn generate` first.')\n return\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n\n const targetTenantIds: string[] = []\n if (tenantArg) {\n const normalized = normalizeTenantId(tenantArg)\n if (!normalized) {\n console.error(`\u274C Invalid --tenant value: ${tenantArg}`)\n return\n }\n const tenant = await em.findOne(Tenant, { id: normalized })\n if (!tenant) {\n console.error(`\u274C Tenant not found: ${normalized}`)\n return\n }\n targetTenantIds.push(normalized)\n } else {\n const tenants = await em.find(Tenant, {})\n if (!tenants.length) {\n console.log('No tenants found; nothing to sync.')\n return\n }\n for (const tenant of tenants) {\n const id = tenant.id ? String(tenant.id) : null\n if (id) targetTenantIds.push(id)\n }\n }\n\n for (const tenantId of targetTenantIds) {\n await ensureDefaultRoleAcls(em, tenantId, modules, { includeSuperadminRole })\n await ensureCustomRoleAcls(em, tenantId, modules)\n console.log(`\u2705 Synced role ACLs for tenant ${tenantId}`)\n }\n },\n}\n\nexport default [addUser, seedRoles, syncRoleAcls, rotateEncryptionKey, addOrganization, setupApp, listOrganizations, listTenants, listUsers, setPassword]\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { ModuleCli } from '@open-mercato/shared/modules/registry'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { hash } from 'bcryptjs'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { User, Role, 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 { ensureRoles, setupInitialTenant, ensureDefaultRoleAcls, ensureCustomRoleAcls } from './lib/setup-app'\nimport { normalizeTenantId } from './lib/tenantAccess'\nimport { computeEmailHash } from './lib/emailHash'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { createKmsService } from '@open-mercato/shared/lib/encryption/kms'\nimport { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { decryptWithAesGcm } from '@open-mercato/shared/lib/encryption/aes'\nimport { env } from 'process'\nimport type { KmsService, TenantDek } from '@open-mercato/shared/lib/encryption/kms'\nimport crypto from 'node:crypto'\nimport { formatPasswordRequirements, getPasswordPolicy, validatePassword } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { getCliModules } from '@open-mercato/shared/modules/registry'\n\nconst addUser: ModuleCli = {\n command: 'add-user',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n const email = args.email\n const password = args.password\n const organizationId = String(args.organizationId ?? args.orgId ?? args.org)\n const rolesCsv = (args.roles ?? '').trim()\n if (!email || !password || !organizationId) {\n console.error('Usage: mercato auth add-user --email <email> --password <password> --organizationId <id> [--roles customer,employee]')\n return\n }\n if (!ensurePasswordPolicy(password)) return\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const org =\n (await findOneWithDecryption(\n em,\n Organization,\n { id: organizationId },\n { populate: ['tenant'] },\n { tenantId: null, organizationId },\n )) ?? null\n if (!org) throw new Error('Organization not found')\n const orgTenantId = org.tenant?.id ? String(org.tenant.id) : null\n const normalizedTenantId = normalizeTenantId(orgTenantId ?? null) ?? null\n const u = em.create(User, {\n email,\n emailHash: computeEmailHash(email),\n passwordHash: await hash(password, 10),\n isConfirmed: true,\n organizationId: org.id,\n tenantId: org.tenant.id,\n })\n await em.persist(u).flush()\n if (rolesCsv) {\n const names = rolesCsv.split(',').map(s => s.trim()).filter(Boolean)\n for (const name of names) {\n let role = await em.findOne(Role, { name, tenantId: normalizedTenantId })\n if (!role && normalizedTenantId !== null) {\n role = await em.findOne(Role, { name, tenantId: null })\n }\n if (!role) {\n role = em.create(Role, { name, tenantId: normalizedTenantId, createdAt: new Date() })\n await em.persist(role).flush()\n } else if (normalizedTenantId !== null && role.tenantId !== normalizedTenantId) {\n role.tenantId = normalizedTenantId\n await em.persist(role).flush()\n }\n const link = em.create(UserRole, { user: u, role })\n await em.persist(link).flush()\n }\n }\n console.log('User created with id', u.id)\n },\n}\n\nfunction parseArgs(rest: string[]) {\n const args: Record<string, string | boolean> = {}\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i]\n if (!a) continue\n if (a.startsWith('--')) {\n const [k, v] = a.replace(/^--/, '').split('=')\n if (v !== undefined) args[k] = v\n else if (rest[i + 1] && !rest[i + 1]!.startsWith('--')) { args[k] = rest[i + 1]!; i++ }\n else args[k] = true\n }\n }\n return args\n}\n\nfunction normalizeKeyInput(value: string): string {\n return value.trim().replace(/(?:^['\"]|['\"]$)/g, '')\n}\n\nfunction hashSecret(value: string | null | undefined): string | null {\n if (!value) return null\n return crypto.createHash('sha256').update(normalizeKeyInput(value)).digest('hex').slice(0, 12)\n}\n\nfunction ensurePasswordPolicy(password: string): boolean {\n const policy = getPasswordPolicy()\n const result = validatePassword(password, policy)\n if (result.ok) return true\n const requirements = formatPasswordRequirements(policy, (_key, fallback) => fallback)\n const suffix = requirements ? `: ${requirements}` : ''\n console.error(`Password does not meet the requirements${suffix}.`)\n return false\n}\n\nasync function withEncryptionDebugDisabled<T>(fn: () => Promise<T>): Promise<T> {\n const previous = process.env.TENANT_DATA_ENCRYPTION_DEBUG\n process.env.TENANT_DATA_ENCRYPTION_DEBUG = 'no'\n try {\n return await fn()\n } finally {\n if (previous === undefined) {\n delete process.env.TENANT_DATA_ENCRYPTION_DEBUG\n } else {\n process.env.TENANT_DATA_ENCRYPTION_DEBUG = previous\n }\n }\n}\n\nclass DerivedKeyKmsService implements KmsService {\n private root: Buffer\n constructor(secret: string) {\n this.root = crypto.createHash('sha256').update(normalizeKeyInput(secret)).digest()\n }\n\n isHealthy(): boolean {\n return true\n }\n\n private deriveKey(tenantId: string): string {\n const iterations = 310_000\n const keyLength = 32\n const derived = crypto.pbkdf2Sync(this.root, tenantId, iterations, keyLength, 'sha512')\n return derived.toString('base64')\n }\n\n async getTenantDek(tenantId: string): Promise<TenantDek | null> {\n if (!tenantId) return null\n return { tenantId, key: this.deriveKey(tenantId), fetchedAt: Date.now() }\n }\n\n async createTenantDek(tenantId: string): Promise<TenantDek | null> {\n return this.getTenantDek(tenantId)\n }\n}\n\nfunction fingerprintDek(dek: TenantDek | null): string | null {\n if (!dek?.key) return null\n return crypto.createHash('sha256').update(dek.key).digest('hex').slice(0, 12)\n}\n\nfunction decryptWithOldKey(\n payload: string,\n dek: TenantDek | null,\n): string | null {\n if (!dek?.key) return null\n return decryptWithAesGcm(payload, dek.key)\n}\n\nconst seedRoles: ModuleCli = {\n command: 'seed-roles',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const key = rest[i]?.replace(/^--/, '')\n if (!key) continue\n const value = rest[i + 1]\n if (value) args[key] = value\n }\n const tenantId = args.tenantId ?? args.tenant ?? args.tenant_id ?? null\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n if (tenantId) {\n await ensureRoles(em, { tenantId })\n console.log('\uD83D\uDEE1\uFE0F Roles ensured for tenant', tenantId)\n return\n }\n const tenants = await em.find(Tenant, {})\n if (!tenants.length) {\n console.log('No tenants found; nothing to seed.')\n return\n }\n for (const tenant of tenants) {\n const id = tenant.id ? String(tenant.id) : null\n if (!id) continue\n await ensureRoles(em, { tenantId: id })\n console.log('\uD83D\uDEE1\uFE0F Roles ensured for tenant', id)\n }\n },\n}\n\nconst rotateEncryptionKey: ModuleCli = {\n command: 'rotate-encryption-key',\n async run(rest) {\n const args = parseArgs(rest)\n const tenantId = (args.tenantId as string) ?? (args.tenant as string) ?? (args.tenant_id as string) ?? null\n const organizationId = (args.organizationId as string) ?? (args.orgId as string) ?? (args.org as string) ?? null\n const oldKey = (args['old-key'] as string) ?? (args.oldKey as string) ?? null\n const dryRun = Boolean(args['dry-run'] || args.dry)\n const debug = Boolean(args.debug)\n const rotate = Boolean(oldKey)\n if (rotate && !tenantId) {\n console.warn(\n '\u26A0\uFE0F Rotating with --old-key across all tenants. A single old key should normally target one tenant; consider --tenant.',\n )\n }\n if (!isTenantDataEncryptionEnabled()) {\n console.error('TENANT_DATA_ENCRYPTION is disabled; aborting.')\n return\n }\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n const encryptionService = new TenantDataEncryptionService(em as any, { kms: createKmsService() })\n const oldKms = rotate && oldKey ? new DerivedKeyKmsService(oldKey) : null\n if (debug) {\n console.log('[rotate-encryption-key]', {\n hasOldKey: Boolean(oldKey),\n rotate,\n tenantId: tenantId ?? null,\n organizationId: organizationId ?? null,\n })\n console.log('[rotate-encryption-key] key fingerprints', {\n oldKey: hashSecret(oldKey),\n currentKey: hashSecret(process.env.TENANT_DATA_ENCRYPTION_FALLBACK_KEY),\n })\n }\n if (!encryptionService.isEnabled()) {\n console.error('Encryption service is not enabled (KMS unhealthy or no DEK). Aborting.')\n return\n }\n const conn: any = (em as any).getConnection?.()\n if (!conn || typeof conn.execute !== 'function') {\n console.error('Unable to access raw connection; aborting.')\n return\n }\n const meta = (em as any)?.getMetadata?.()?.get?.(User)\n const tableName = meta?.tableName || 'users'\n const schema = meta?.schema\n const qualifiedTable = schema ? `\"${schema}\".\"${tableName}\"` : `\"${tableName}\"`\n const isEncryptedPayload = (value: unknown): boolean => {\n if (typeof value !== 'string') return false\n const parts = value.split(':')\n return parts.length === 4 && parts[3] === 'v1'\n }\n const printedDek = new Set<string>()\n const oldDekCache = new Map<string, TenantDek | null>()\n const processScope = async (scopeTenantId: string, scopeOrganizationId: string): Promise<number> => {\n if (debug && !printedDek.has(scopeTenantId)) {\n printedDek.add(scopeTenantId)\n const [oldDek, newDek] = await Promise.all([\n oldKms?.getTenantDek(scopeTenantId) ?? Promise.resolve(null),\n encryptionService.getDek(scopeTenantId),\n ])\n console.log('[rotate-encryption-key] dek fingerprints', {\n tenantId: scopeTenantId,\n oldKey: fingerprintDek(oldDek),\n currentKey: fingerprintDek(newDek),\n })\n }\n const rawRows = await conn.execute(\n `select id, email, email_hash from ${qualifiedTable} where tenant_id = ? and organization_id = ?`,\n [scopeTenantId, scopeOrganizationId],\n )\n const rows = Array.isArray(rawRows) ? rawRows : []\n const pending = rotate\n ? rows\n : rows.filter((row: any) => !isEncryptedPayload(row?.email))\n if (!pending.length) return 0\n console.log(\n `Found ${pending.length} auth user records to process for org=${scopeOrganizationId}${dryRun ? ' (dry-run)' : ''}.`\n )\n if (dryRun) return 0\n const ids = pending.map((row: any) => String(row.id))\n const users = rotate\n ? await em.find(\n User,\n { id: { $in: ids }, tenantId: scopeTenantId, organizationId: scopeOrganizationId },\n )\n : await findWithDecryption(\n em,\n User,\n { id: { $in: ids }, tenantId: scopeTenantId, organizationId: scopeOrganizationId },\n {},\n { tenantId: scopeTenantId, organizationId: scopeOrganizationId, encryptionService },\n )\n const usersById = new Map(users.map((user) => [String(user.id), user]))\n let updated = 0\n for (const row of pending) {\n const user = usersById.get(String(row.id))\n if (!user) continue\n const rawEmail = typeof row.email === 'string' ? row.email : String(row.email ?? '')\n if (!rawEmail) continue\n if (rotate && (!isEncryptedPayload(rawEmail) || !oldKms)) {\n continue\n }\n let plainEmail = rawEmail\n if (rotate && isEncryptedPayload(rawEmail) && oldKms) {\n if (debug) {\n console.log('[rotate-encryption-key] decrypting', {\n userId: row.id,\n tenantId: scopeTenantId,\n organizationId: scopeOrganizationId,\n })\n }\n let oldDek = oldDekCache.get(scopeTenantId) ?? null\n if (!oldDekCache.has(scopeTenantId)) {\n oldDek = await oldKms.getTenantDek(scopeTenantId)\n oldDekCache.set(scopeTenantId, oldDek)\n }\n const maybeEmail = decryptWithOldKey(rawEmail, oldDek)\n if (typeof maybeEmail !== 'string' || isEncryptedPayload(maybeEmail)) continue\n plainEmail = maybeEmail\n }\n if (!plainEmail) continue\n const encrypted = await encryptionService.encryptEntityPayload(\n 'auth:user',\n { email: plainEmail },\n scopeTenantId,\n scopeOrganizationId,\n )\n const nextEmail = encrypted.email as string | undefined\n if (nextEmail && nextEmail !== user.email) {\n user.email = nextEmail as any\n user.emailHash = (encrypted as any).emailHash ?? computeEmailHash(plainEmail)\n em.persist(user)\n updated += 1\n }\n }\n if (updated > 0) {\n await em.flush()\n }\n return updated\n }\n\n if (tenantId && organizationId) {\n const updated = await processScope(String(tenantId), String(organizationId))\n if (!updated) {\n console.log('All auth user emails already encrypted for the selected scope.')\n } else {\n console.log(`Encrypted ${updated} auth user email(s).`)\n }\n return\n }\n\n const organizations = await em.find(Organization, {})\n if (!organizations.length) {\n console.log('No organizations found; nothing to encrypt.')\n return\n }\n let total = 0\n for (const org of organizations) {\n const scopeTenantId = org.tenant?.id ? String(org.tenant.id) : org.tenant.id ? String(org.tenant.id) : null\n const scopeOrganizationId = org.id ? String(org.id) : null\n if (!scopeTenantId || !scopeOrganizationId) continue\n total += await processScope(scopeTenantId, scopeOrganizationId)\n }\n if (total > 0) {\n console.log(`Encrypted ${total} auth user email(s) across all organizations.`)\n } else {\n console.log('All auth user emails already encrypted across all organizations.')\n }\n },\n}\n\n// will be exported at the bottom with all commands\n\nconst addOrganization: ModuleCli = {\n command: 'add-org',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n const name = args.name || args.orgName\n if (!name) {\n console.error('Usage: mercato auth add-org --name <organization name>')\n return\n }\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n // Create tenant implicitly for simplicity\n const tenant = em.create(Tenant, { name: `${name} Tenant` })\n await em.persist(tenant).flush()\n const org = em.create(Organization, { name, tenant })\n await em.persist(org).flush()\n await rebuildHierarchyForTenant(em, String(tenant.id))\n console.log('Organization created with id', org.id, 'in tenant', tenant.id)\n },\n}\n\nconst setupApp: ModuleCli = {\n command: 'setup',\n async run(rest) {\n const args = parseArgs(rest)\n const orgName = typeof args.orgName === 'string'\n ? args.orgName\n : typeof args.name === 'string'\n ? args.name\n : undefined\n const email = typeof args.email === 'string' ? args.email : undefined\n const password = typeof args.password === 'string' ? args.password : undefined\n const rolesCsv = typeof args.roles === 'string'\n ? args.roles.trim()\n : 'superadmin,admin,employee'\n const skipPasswordPolicyRaw =\n args['skip-password-policy'] ??\n args.skipPasswordPolicy ??\n args['allow-weak-password'] ??\n args.allowWeakPassword\n const skipPasswordPolicy = typeof skipPasswordPolicyRaw === 'boolean'\n ? skipPasswordPolicyRaw\n : parseBooleanToken(typeof skipPasswordPolicyRaw === 'string' ? skipPasswordPolicyRaw : null) ?? false\n if (!orgName || !email || !password) {\n console.error('Usage: mercato auth setup --orgName <name> --email <email> --password <password> [--roles superadmin,admin,employee] [--skip-password-policy]')\n return\n }\n if (!skipPasswordPolicy && !ensurePasswordPolicy(password)) return\n if (skipPasswordPolicy) {\n console.warn('\u26A0\uFE0F Password policy validation skipped for setup.')\n }\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n const roleNames = rolesCsv\n ? rolesCsv.split(',').map((s) => s.trim()).filter(Boolean)\n : undefined\n\n try {\n const result = await setupInitialTenant(em, {\n orgName,\n roleNames,\n primaryUser: { email, password, confirm: true },\n includeDerivedUsers: true,\n modules: getCliModules(),\n })\n\n if (result.reusedExistingUser) {\n console.log('\u26A0\uFE0F Existing initial user detected during setup.')\n console.log(`\u26A0\uFE0F Email: ${email}`)\n console.log('\u26A0\uFE0F Updated roles if missing and reused tenant/organization.')\n }\n\n if (env.NODE_ENV !== 'test') {\n for (const snapshot of result.users) {\n if (snapshot.created) {\n if (snapshot.user.email === email && password) {\n console.log('\uD83C\uDF89 Created user', snapshot.user.email, 'password:', password)\n } else {\n console.log('\uD83C\uDF89 Created user', snapshot.user.email)\n }\n } else {\n console.log(`Updated user ${snapshot.user.email}`)\n }\n }\n }\n\n if (env.NODE_ENV !== 'test') console.log('\u2705 Setup complete:', { tenantId: result.tenantId, organizationId: result.organizationId })\n } catch (err) {\n if (err instanceof Error && err.message === 'USER_EXISTS') {\n console.error('Setup aborted: user already exists with the provided email.')\n return\n }\n throw err\n }\n },\n}\n\nconst listOrganizations: ModuleCli = {\n command: 'list-orgs',\n async run() {\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const orgs = await findWithDecryption(\n em,\n Organization,\n {},\n { populate: ['tenant'] },\n { tenantId: null, organizationId: null },\n )\n\n if (orgs.length === 0) {\n console.log('No organizations found')\n return\n }\n\n console.log(`Found ${orgs.length} organization(s):`)\n console.log('')\n console.log('ID | Name | Tenant ID | Created')\n console.log('-------------------------------------|-------------------------|-------------------------------------|-------------------')\n\n for (const org of orgs) {\n const created = org.createdAt ? new Date(org.createdAt).toLocaleDateString() : 'N/A'\n const id = org.id || 'N/A'\n const tenantId = org.tenant?.id || 'N/A'\n const name = (org.name || 'Unnamed').padEnd(23)\n console.log(`${id.padEnd(35)} | ${name} | ${tenantId.padEnd(35)} | ${created}`)\n }\n },\n}\n\nconst listTenants: ModuleCli = {\n command: 'list-tenants',\n async run() {\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const tenants = await em.find(Tenant, {})\n\n if (tenants.length === 0) {\n console.log('No tenants found')\n return\n }\n\n console.log(`Found ${tenants.length} tenant(s):`)\n console.log('')\n console.log('ID | Name | Created')\n console.log('-------------------------------------|-------------------------|-------------------')\n\n for (const tenant of tenants) {\n const created = tenant.createdAt ? new Date(tenant.createdAt).toLocaleDateString() : 'N/A'\n const id = tenant.id || 'N/A'\n const name = (tenant.name || 'Unnamed').padEnd(23)\n console.log(`${id.padEnd(35)} | ${name} | ${created}`)\n }\n },\n}\n\nconst listUsers: ModuleCli = {\n command: 'list-users',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n\n // Build query with optional filters\n const where: any = {}\n if (args.organizationId || args.orgId || args.org) {\n where.organizationId = args.organizationId || args.orgId || args.org\n }\n if (args.tenantId || args.tenant) {\n where.tenantId = args.tenantId || args.tenant\n }\n\n const users = await em.find(User, where)\n\n if (users.length === 0) {\n console.log('No users found')\n return\n }\n\n console.log(`Found ${users.length} user(s):`)\n console.log('')\n console.log('ID | Email | Name | Organization ID | Tenant ID | Roles')\n console.log('-------------------------------------|-------------------------|-------------------------|---------------------|---------------------|-------------------')\n\n for (const user of users) {\n // Get user roles separately\n const userRoles = await findWithDecryption(\n em,\n UserRole,\n { user: user.id },\n { populate: ['role'] },\n { tenantId: user.tenantId ?? null, organizationId: user.organizationId ?? null },\n )\n const roles = userRoles.map((ur: any) => ur.role?.name).filter(Boolean).join(', ') || 'None'\n\n // Get organization and tenant names if IDs exist\n let orgName = 'N/A'\n let tenantName = 'N/A'\n\n if (user.organizationId) {\n const org = await em.findOne(Organization, { id: user.organizationId })\n orgName = org?.name?.substring(0, 19) + '...' || user.organizationId.substring(0, 8) + '...'\n }\n\n if (user.tenantId) {\n const tenant = await em.findOne(Tenant, { id: user.tenantId })\n tenantName = tenant?.name?.substring(0, 19) + '...' || user.tenantId.substring(0, 8) + '...'\n }\n\n const id = user.id || 'N/A'\n const email = (user.email || 'N/A').padEnd(23)\n const name = (user.name || 'Unnamed').padEnd(23)\n\n console.log(`${id.padEnd(35)} | ${email} | ${name} | ${orgName.padEnd(19)} | ${tenantName.padEnd(19)} | ${roles}`)\n }\n },\n}\n\nconst setPassword: ModuleCli = {\n command: 'set-password',\n async run(rest) {\n const args: Record<string, string> = {}\n for (let i = 0; i < rest.length; i += 2) {\n const k = rest[i]?.replace(/^--/, '')\n const v = rest[i + 1]\n if (k) args[k] = v\n }\n\n const email = args.email\n const password = args.password\n\n if (!email || !password) {\n console.error('Usage: mercato auth set-password --email <email> --password <newPassword>')\n return\n }\n if (!ensurePasswordPolicy(password)) return\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n const emailHash = computeEmailHash(email)\n const user = await em.findOne(User, { $or: [{ email }, { emailHash }] })\n\n if (!user) {\n console.error(`User with email \"${email}\" not found`)\n return\n }\n\n user.passwordHash = await hash(password, 10)\n await em.persist(user).flush()\n\n console.log(`\u2705 Password updated successfully for user: ${email}`)\n },\n}\n\nconst syncRoleAcls: ModuleCli = {\n command: 'sync-role-acls',\n async run(rest) {\n const args: Record<string, string> = {}\n const flags = new Set<string>()\n for (let i = 0; i < rest.length; i++) {\n const token = rest[i]\n if (!token?.startsWith('--')) continue\n const key = token.replace(/^--/, '')\n const next = rest[i + 1]\n if (next && !next.startsWith('--')) {\n args[key] = next\n i++\n } else {\n flags.add(key)\n }\n }\n const tenantArg = args.tenantId ?? args.tenant ?? args.tenant_id ?? null\n const includeSuperadminRole = !flags.has('no-superadmin')\n\n const modules = getCliModules()\n if (!modules.length) {\n console.error('\u274C No CLI modules registered. Run `yarn generate` first.')\n return\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve<EntityManager>('em')\n\n const targetTenantIds: string[] = []\n if (tenantArg) {\n const normalized = normalizeTenantId(tenantArg)\n if (!normalized) {\n console.error(`\u274C Invalid --tenant value: ${tenantArg}`)\n return\n }\n const tenant = await em.findOne(Tenant, { id: normalized })\n if (!tenant) {\n console.error(`\u274C Tenant not found: ${normalized}`)\n return\n }\n targetTenantIds.push(normalized)\n } else {\n const tenants = await em.find(Tenant, {})\n if (!tenants.length) {\n console.log('No tenants found; nothing to sync.')\n return\n }\n for (const tenant of tenants) {\n const id = tenant.id ? String(tenant.id) : null\n if (id) targetTenantIds.push(id)\n }\n }\n\n for (const tenantId of targetTenantIds) {\n await ensureDefaultRoleAcls(em, tenantId, modules, { includeSuperadminRole })\n await ensureCustomRoleAcls(em, tenantId, modules)\n console.log(`\u2705 Synced role ACLs for tenant ${tenantId}`)\n }\n },\n}\n\n// Export the full CLI list\nexport default [addUser, seedRoles, syncRoleAcls, rotateEncryptionKey, addOrganization, setupApp, listOrganizations, listTenants, listUsers, setPassword]\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { serializeOperationMetadata } from "@open-mercato/shared/lib/commands/operationMetadata";
|
|
4
3
|
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
5
4
|
import { validateCrudMutationGuard, runCrudMutationGuardAfterSuccess } from "@open-mercato/shared/lib/crud/mutation-guard";
|
|
6
5
|
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
@@ -11,6 +10,8 @@ import { CustomerEntity, CustomerEntityRole } from "../data/entities.js";
|
|
|
11
10
|
import { entityRoleCreateSchema, entityRoleUpdateSchema, entityRoleDeleteSchema } from "../data/validators.js";
|
|
12
11
|
import { withScopedPayload } from "./utils.js";
|
|
13
12
|
import { resolveCustomersRequestContext, resolveAuthActorId } from "../lib/interactionRequestContext.js";
|
|
13
|
+
import { deriveDisplayNameFromEmail } from "../lib/displayName.js";
|
|
14
|
+
import { withOperationMetadata } from "../lib/operationMetadata.js";
|
|
14
15
|
const paramsSchema = z.object({ id: z.string().uuid() });
|
|
15
16
|
const roleIdQuerySchema = z.object({ roleId: z.string().uuid() });
|
|
16
17
|
const createBodySchema = z.object({
|
|
@@ -46,22 +47,6 @@ function buildValidationErrorResponse(error, translate) {
|
|
|
46
47
|
{ status: 400 }
|
|
47
48
|
);
|
|
48
49
|
}
|
|
49
|
-
function withOperationMetadata(response, logEntry, fallback) {
|
|
50
|
-
if (!logEntry?.undoToken || !logEntry.id || !logEntry.commandId) return response;
|
|
51
|
-
response.headers.set(
|
|
52
|
-
"x-om-operation",
|
|
53
|
-
serializeOperationMetadata({
|
|
54
|
-
id: logEntry.id,
|
|
55
|
-
undoToken: logEntry.undoToken,
|
|
56
|
-
commandId: logEntry.commandId,
|
|
57
|
-
actionLabel: logEntry.actionLabel ?? null,
|
|
58
|
-
resourceKind: logEntry.resourceKind ?? fallback.resourceKind,
|
|
59
|
-
resourceId: logEntry.resourceId ?? fallback.resourceId,
|
|
60
|
-
executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
61
|
-
})
|
|
62
|
-
);
|
|
63
|
-
return response;
|
|
64
|
-
}
|
|
65
50
|
async function buildContext(request) {
|
|
66
51
|
const context = await resolveCustomersRequestContext(request);
|
|
67
52
|
return {
|
|
@@ -244,7 +229,7 @@ function createEntityRolesHandlers(entityType) {
|
|
|
244
229
|
}
|
|
245
230
|
) : [];
|
|
246
231
|
const userMap = new Map(users.map((user) => [user.id, {
|
|
247
|
-
name: user.name ?? null,
|
|
232
|
+
name: user.name ?? deriveDisplayNameFromEmail(user.email) ?? null,
|
|
248
233
|
email: user.email ?? null,
|
|
249
234
|
phone: null
|
|
250
235
|
}]));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/api/entity-roles-factory.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { validateCrudMutationGuard, runCrudMutationGuardAfterSuccess } from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CustomerEntity, CustomerEntityRole } from '../data/entities'\nimport { entityRoleCreateSchema, entityRoleUpdateSchema, entityRoleDeleteSchema, type EntityRoleCreateInput, type EntityRoleUpdateInput, type EntityRoleDeleteInput } from '../data/validators'\nimport { withScopedPayload } from './utils'\nimport { resolveCustomersRequestContext, resolveAuthActorId } from '../lib/interactionRequestContext'\n\nconst paramsSchema = z.object({ id: z.string().uuid() })\nconst roleIdQuerySchema = z.object({ roleId: z.string().uuid() })\n\nconst createBodySchema = z.object({\n roleType: z.string().trim().min(1).max(100),\n userId: z.string().uuid(),\n})\nconst updateBodySchema = z.object({\n userId: z.string().uuid(),\n})\n\nconst listItemSchema = z.object({\n id: z.string().uuid(),\n entityType: z.enum(['company', 'person']),\n entityId: z.string().uuid(),\n userId: z.string().uuid(),\n userName: z.string().nullable().optional(),\n userEmail: z.string().nullable().optional(),\n userPhone: z.string().nullable().optional(),\n roleType: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n})\n\nconst listResponseSchema = z.object({ items: z.array(listItemSchema) })\nconst okResponseSchema = z.object({ ok: z.boolean() })\nconst createResponseSchema = z.object({ id: z.string().uuid() })\nconst errorSchema = z.object({ error: z.string() })\n\ntype EntityType = 'company' | 'person'\n\ntype Translator = Awaited<ReturnType<typeof resolveTranslations>>['translate']\n\nfunction getRoleContext(entityType: EntityType, entityId: string) {\n const resourceKind = entityType === 'company' ? 'customers.company' : 'customers.person'\n return { entityType, entityId, resourceKind, resourceId: entityId }\n}\n\nfunction buildValidationErrorResponse(error: z.ZodError, translate: Translator) {\n return NextResponse.json(\n { error: translate('customers.errors.validationFailed', 'Validation failed'), fieldErrors: error.flatten().fieldErrors },\n { status: 400 },\n )\n}\n\nfunction withOperationMetadata(\n response: NextResponse,\n logEntry: { undoToken?: string | null; id?: string | null; commandId?: string | null; actionLabel?: string | null; resourceKind?: string | null; resourceId?: string | null; createdAt?: Date | null } | null | undefined,\n fallback: { resourceKind: string; resourceId: string | null },\n) {\n if (!logEntry?.undoToken || !logEntry.id || !logEntry.commandId) return response\n response.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? fallback.resourceKind,\n resourceId: logEntry.resourceId ?? fallback.resourceId,\n executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : new Date().toISOString(),\n }),\n )\n return response\n}\n\nasync function buildContext(request: Request) {\n const context = await resolveCustomersRequestContext(request)\n return {\n ...context,\n ctx: context.commandContext,\n }\n}\n\nfunction collectAllowedOrganizationIds(\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n) {\n const allowedOrgIds = new Set<string>()\n if (scope?.filterIds?.length) scope.filterIds.forEach((id) => allowedOrgIds.add(id))\n else if (auth.orgId) allowedOrgIds.add(auth.orgId)\n return allowedOrgIds\n}\n\nfunction ensureRouteOrganizationAccess(\n organizationId: string,\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n translate: Translator,\n) {\n const allowedOrgIds = collectAllowedOrganizationIds(scope, auth)\n if (allowedOrgIds.size > 0 && !allowedOrgIds.has(organizationId)) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n}\n\nasync function ensureFeatureOnOrganization(\n container: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['container'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n feature: string,\n organizationId: string,\n translate: Translator,\n) {\n const actorId = resolveAuthActorId(auth)\n if (!actorId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n let rbac: RbacService | undefined\n try {\n rbac = container.resolve('rbacService') as RbacService | undefined\n } catch (err) {\n console.error('[customers.entity-roles-factory] rbacService resolve failed', err)\n rbac = undefined\n }\n if (!rbac) {\n throw new CrudHttpError(500, { error: translate('customers.errors.internal', 'Internal error') })\n }\n const hasFeature = await rbac.userHasAllFeatures(actorId, [feature], {\n tenantId: auth.tenantId,\n organizationId,\n })\n if (!hasFeature) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n}\n\nasync function resolveEntityRouteScope(\n em: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['em'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n entityType: EntityType,\n entityId: string,\n translate: Translator,\n) {\n const entity = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id: entityId, kind: entityType, tenantId: auth.tenantId, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId, organizationId: scope?.selectedId ?? auth.orgId ?? null },\n )\n if (!entity || entity.tenantId !== auth.tenantId) {\n throw new CrudHttpError(404, { error: translate('customers.errors.customer_not_found', 'Customer not found') })\n }\n ensureRouteOrganizationAccess(entity.organizationId, scope, auth, translate)\n return {\n entity,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n }\n}\n\nasync function resolveRoleRouteScope(\n em: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['em'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n entityType: EntityType,\n entityId: string,\n roleId: string,\n translate: Translator,\n) {\n const role = await findOneWithDecryption(\n em,\n CustomerEntityRole,\n { id: roleId, tenantId: auth.tenantId, entityType, entityId, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId, organizationId: scope?.selectedId ?? auth.orgId ?? null },\n )\n if (\n !role ||\n role.tenantId !== auth.tenantId ||\n role.entityType !== entityType ||\n role.entityId !== entityId\n ) {\n throw new CrudHttpError(404, { error: translate('customers.errors.role_not_found', 'Role not found') })\n }\n ensureRouteOrganizationAccess(role.organizationId, scope, auth, translate)\n return {\n role,\n organizationId: role.organizationId,\n tenantId: role.tenantId,\n }\n}\n\nfunction createScopedCommandContext(\n ctx: Awaited<ReturnType<typeof buildContext>>['ctx'],\n organizationId: string,\n) {\n return {\n ...ctx,\n selectedOrganizationId: organizationId,\n organizationIds: [organizationId],\n }\n}\n\nexport const entityRolesMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.roles.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.roles.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.roles.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.roles.manage'] },\n}\n\nexport function buildEntityRolesOpenApi(entityType: EntityType): OpenApiRouteDoc {\n const label = entityType === 'company' ? 'company' : 'person'\n return {\n tag: 'Customers',\n summary: `${label.charAt(0).toUpperCase() + label.slice(1)} role assignments`,\n pathParams: paramsSchema,\n methods: {\n GET: {\n summary: `List roles for a ${label}`,\n responses: [{ status: 200, description: 'Role assignments', schema: listResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n POST: {\n summary: `Assign a role to a ${label}`,\n requestBody: { contentType: 'application/json', schema: createBodySchema },\n responses: [{ status: 201, description: 'Role created', schema: createResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 409, description: 'Role already assigned', schema: errorSchema },\n ],\n },\n PUT: {\n summary: `Update a ${label} role assignment`,\n query: roleIdQuerySchema,\n requestBody: { contentType: 'application/json', schema: updateBodySchema },\n responses: [{ status: 200, description: 'Role updated', schema: okResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Role not found', schema: errorSchema },\n ],\n },\n DELETE: {\n summary: `Remove a ${label} role assignment`,\n query: roleIdQuerySchema,\n responses: [{ status: 200, description: 'Role deleted', schema: okResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Role not found', schema: errorSchema },\n ],\n },\n },\n }\n}\n\nexport function createEntityRolesHandlers(entityType: EntityType) {\n const resourceKind = entityType === 'company' ? 'customers.company' : 'customers.person'\n const logPrefix = entityType === 'company' ? 'customers.company.roles' : 'customers.person.roles'\n\n async function GET(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { container, em, auth, scope } = await buildContext(request)\n const targetScope = await resolveEntityRouteScope(em, auth, scope, entityType, entityId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.view', targetScope.organizationId, translate)\n\n const roles = await findWithDecryption(\n em,\n CustomerEntityRole,\n {\n entityType,\n entityId,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n deletedAt: null,\n },\n { orderBy: { roleType: 'asc' } },\n {\n tenantId: targetScope.tenantId,\n organizationId: targetScope.organizationId,\n },\n )\n\n const userIds = Array.from(new Set(roles.map((role) => role.userId).filter((value): value is string => typeof value === 'string' && value.length > 0)))\n const users = userIds.length\n ? await findWithDecryption(\n em,\n User,\n {\n id: { $in: userIds },\n deletedAt: null,\n ...(targetScope.tenantId ? { tenantId: targetScope.tenantId } : {}),\n },\n undefined,\n {\n tenantId: targetScope.tenantId,\n organizationId: targetScope.organizationId,\n },\n )\n : []\n const userMap = new Map(users.map((user) => [user.id, {\n name: user.name ?? null,\n email: user.email ?? null,\n phone: null,\n }]))\n\n return NextResponse.json({\n items: roles.map((role) => ({\n ...(userMap.has(role.userId)\n ? {\n userName: userMap.get(role.userId)?.name ?? null,\n userEmail: userMap.get(role.userId)?.email ?? null,\n userPhone: userMap.get(role.userId)?.phone ?? null,\n }\n : {}),\n id: role.id,\n entityType: role.entityType,\n entityId: role.entityId,\n userId: role.userId,\n roleType: role.roleType,\n createdAt: role.createdAt.toISOString(),\n updatedAt: role.updatedAt.toISOString(),\n })),\n })\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.get failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_load_roles', 'Failed to load roles') }, { status: 500 })\n }\n }\n\n async function POST(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { container, em, auth, scope, ctx } = await buildContext(request)\n const targetScope = await resolveEntityRouteScope(em, auth, scope, entityType, entityId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.manage', targetScope.organizationId, translate)\n const commandCtx = createScopedCommandContext(ctx, targetScope.organizationId)\n\n const rawBody = await readJsonSafe<Record<string, unknown>>(request, {})\n const scoped = withScopedPayload(\n {\n ...rawBody,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n ...getRoleContext(entityType, entityId),\n },\n commandCtx,\n translate,\n )\n const parsed = entityRoleCreateSchema.parse(scoped)\n\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, mutationPayload: rawBody,\n })\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<EntityRoleCreateInput, { roleId: string }>(\n 'customers.entityRoles.create',\n { input: parsed, ctx: commandCtx },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, metadata: guardResult.metadata ?? null,\n })\n }\n\n return withOperationMetadata(\n NextResponse.json({ id: result?.roleId ?? null }, { status: 201 }),\n logEntry,\n { resourceKind, resourceId: entityId },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.post failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_assign_role', 'Failed to assign role') }, { status: 500 })\n }\n }\n\n async function PUT(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { roleId } = roleIdQuerySchema.parse(Object.fromEntries(new URL(request.url).searchParams))\n const { container, em, auth, scope, ctx } = await buildContext(request)\n const targetScope = await resolveRoleRouteScope(em, auth, scope, entityType, entityId, roleId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.manage', targetScope.organizationId, translate)\n const commandCtx = createScopedCommandContext(ctx, targetScope.organizationId)\n\n const rawBody = await readJsonSafe<Record<string, unknown>>(request, {})\n const scoped = withScopedPayload(\n {\n ...rawBody,\n id: roleId,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n },\n commandCtx,\n translate,\n )\n const parsed = entityRoleUpdateSchema.parse(scoped)\n\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, mutationPayload: { roleId, ...rawBody },\n })\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<EntityRoleUpdateInput, { roleId: string }>(\n 'customers.entityRoles.update',\n { input: parsed, ctx: commandCtx },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, metadata: guardResult.metadata ?? null,\n })\n }\n\n return withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind, resourceId: entityId },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.put failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_update_role', 'Failed to update role') }, { status: 500 })\n }\n }\n\n async function DELETE(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { roleId } = roleIdQuerySchema.parse(Object.fromEntries(new URL(request.url).searchParams))\n const { container, em, auth, scope, ctx } = await buildContext(request)\n const targetScope = await resolveRoleRouteScope(em, auth, scope, entityType, entityId, roleId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.manage', targetScope.organizationId, translate)\n const commandCtx = createScopedCommandContext(ctx, targetScope.organizationId)\n\n const parsed = entityRoleDeleteSchema.parse(\n withScopedPayload(\n {\n id: roleId,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n },\n commandCtx,\n translate,\n ),\n )\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, mutationPayload: { roleId },\n })\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<EntityRoleDeleteInput, { roleId: string }>(\n 'customers.entityRoles.delete',\n { input: parsed, ctx: commandCtx },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, metadata: guardResult.metadata ?? null,\n })\n }\n\n return withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind, resourceId: entityId },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.delete failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_delete_role', 'Failed to delete role') }, { status: 500 })\n }\n }\n\n return { GET, POST, PUT, DELETE }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { validateCrudMutationGuard, runCrudMutationGuardAfterSuccess } from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CustomerEntity, CustomerEntityRole } from '../data/entities'\nimport { entityRoleCreateSchema, entityRoleUpdateSchema, entityRoleDeleteSchema, type EntityRoleCreateInput, type EntityRoleUpdateInput, type EntityRoleDeleteInput } from '../data/validators'\nimport { withScopedPayload } from './utils'\nimport { resolveCustomersRequestContext, resolveAuthActorId } from '../lib/interactionRequestContext'\nimport { deriveDisplayNameFromEmail } from '../lib/displayName'\nimport { withOperationMetadata } from '../lib/operationMetadata'\n\nconst paramsSchema = z.object({ id: z.string().uuid() })\nconst roleIdQuerySchema = z.object({ roleId: z.string().uuid() })\n\nconst createBodySchema = z.object({\n roleType: z.string().trim().min(1).max(100),\n userId: z.string().uuid(),\n})\nconst updateBodySchema = z.object({\n userId: z.string().uuid(),\n})\n\nconst listItemSchema = z.object({\n id: z.string().uuid(),\n entityType: z.enum(['company', 'person']),\n entityId: z.string().uuid(),\n userId: z.string().uuid(),\n userName: z.string().nullable().optional(),\n userEmail: z.string().nullable().optional(),\n userPhone: z.string().nullable().optional(),\n roleType: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n})\n\nconst listResponseSchema = z.object({ items: z.array(listItemSchema) })\nconst okResponseSchema = z.object({ ok: z.boolean() })\nconst createResponseSchema = z.object({ id: z.string().uuid() })\nconst errorSchema = z.object({ error: z.string() })\n\ntype EntityType = 'company' | 'person'\n\ntype Translator = Awaited<ReturnType<typeof resolveTranslations>>['translate']\n\nfunction getRoleContext(entityType: EntityType, entityId: string) {\n const resourceKind = entityType === 'company' ? 'customers.company' : 'customers.person'\n return { entityType, entityId, resourceKind, resourceId: entityId }\n}\n\nfunction buildValidationErrorResponse(error: z.ZodError, translate: Translator) {\n return NextResponse.json(\n { error: translate('customers.errors.validationFailed', 'Validation failed'), fieldErrors: error.flatten().fieldErrors },\n { status: 400 },\n )\n}\n\nasync function buildContext(request: Request) {\n const context = await resolveCustomersRequestContext(request)\n return {\n ...context,\n ctx: context.commandContext,\n }\n}\n\nfunction collectAllowedOrganizationIds(\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n) {\n const allowedOrgIds = new Set<string>()\n if (scope?.filterIds?.length) scope.filterIds.forEach((id) => allowedOrgIds.add(id))\n else if (auth.orgId) allowedOrgIds.add(auth.orgId)\n return allowedOrgIds\n}\n\nfunction ensureRouteOrganizationAccess(\n organizationId: string,\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n translate: Translator,\n) {\n const allowedOrgIds = collectAllowedOrganizationIds(scope, auth)\n if (allowedOrgIds.size > 0 && !allowedOrgIds.has(organizationId)) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n}\n\nasync function ensureFeatureOnOrganization(\n container: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['container'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n feature: string,\n organizationId: string,\n translate: Translator,\n) {\n const actorId = resolveAuthActorId(auth)\n if (!actorId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n let rbac: RbacService | undefined\n try {\n rbac = container.resolve('rbacService') as RbacService | undefined\n } catch (err) {\n console.error('[customers.entity-roles-factory] rbacService resolve failed', err)\n rbac = undefined\n }\n if (!rbac) {\n throw new CrudHttpError(500, { error: translate('customers.errors.internal', 'Internal error') })\n }\n const hasFeature = await rbac.userHasAllFeatures(actorId, [feature], {\n tenantId: auth.tenantId,\n organizationId,\n })\n if (!hasFeature) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n}\n\nasync function resolveEntityRouteScope(\n em: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['em'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n entityType: EntityType,\n entityId: string,\n translate: Translator,\n) {\n const entity = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id: entityId, kind: entityType, tenantId: auth.tenantId, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId, organizationId: scope?.selectedId ?? auth.orgId ?? null },\n )\n if (!entity || entity.tenantId !== auth.tenantId) {\n throw new CrudHttpError(404, { error: translate('customers.errors.customer_not_found', 'Customer not found') })\n }\n ensureRouteOrganizationAccess(entity.organizationId, scope, auth, translate)\n return {\n entity,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n }\n}\n\nasync function resolveRoleRouteScope(\n em: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['em'],\n auth: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['auth'],\n scope: Awaited<ReturnType<typeof resolveCustomersRequestContext>>['scope'],\n entityType: EntityType,\n entityId: string,\n roleId: string,\n translate: Translator,\n) {\n const role = await findOneWithDecryption(\n em,\n CustomerEntityRole,\n { id: roleId, tenantId: auth.tenantId, entityType, entityId, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId, organizationId: scope?.selectedId ?? auth.orgId ?? null },\n )\n if (\n !role ||\n role.tenantId !== auth.tenantId ||\n role.entityType !== entityType ||\n role.entityId !== entityId\n ) {\n throw new CrudHttpError(404, { error: translate('customers.errors.role_not_found', 'Role not found') })\n }\n ensureRouteOrganizationAccess(role.organizationId, scope, auth, translate)\n return {\n role,\n organizationId: role.organizationId,\n tenantId: role.tenantId,\n }\n}\n\nfunction createScopedCommandContext(\n ctx: Awaited<ReturnType<typeof buildContext>>['ctx'],\n organizationId: string,\n) {\n return {\n ...ctx,\n selectedOrganizationId: organizationId,\n organizationIds: [organizationId],\n }\n}\n\nexport const entityRolesMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.roles.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.roles.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.roles.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.roles.manage'] },\n}\n\nexport function buildEntityRolesOpenApi(entityType: EntityType): OpenApiRouteDoc {\n const label = entityType === 'company' ? 'company' : 'person'\n return {\n tag: 'Customers',\n summary: `${label.charAt(0).toUpperCase() + label.slice(1)} role assignments`,\n pathParams: paramsSchema,\n methods: {\n GET: {\n summary: `List roles for a ${label}`,\n responses: [{ status: 200, description: 'Role assignments', schema: listResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n ],\n },\n POST: {\n summary: `Assign a role to a ${label}`,\n requestBody: { contentType: 'application/json', schema: createBodySchema },\n responses: [{ status: 201, description: 'Role created', schema: createResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 409, description: 'Role already assigned', schema: errorSchema },\n ],\n },\n PUT: {\n summary: `Update a ${label} role assignment`,\n query: roleIdQuerySchema,\n requestBody: { contentType: 'application/json', schema: updateBodySchema },\n responses: [{ status: 200, description: 'Role updated', schema: okResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Role not found', schema: errorSchema },\n ],\n },\n DELETE: {\n summary: `Remove a ${label} role assignment`,\n query: roleIdQuerySchema,\n responses: [{ status: 200, description: 'Role deleted', schema: okResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Role not found', schema: errorSchema },\n ],\n },\n },\n }\n}\n\nexport function createEntityRolesHandlers(entityType: EntityType) {\n const resourceKind = entityType === 'company' ? 'customers.company' : 'customers.person'\n const logPrefix = entityType === 'company' ? 'customers.company.roles' : 'customers.person.roles'\n\n async function GET(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { container, em, auth, scope } = await buildContext(request)\n const targetScope = await resolveEntityRouteScope(em, auth, scope, entityType, entityId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.view', targetScope.organizationId, translate)\n\n const roles = await findWithDecryption(\n em,\n CustomerEntityRole,\n {\n entityType,\n entityId,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n deletedAt: null,\n },\n { orderBy: { roleType: 'asc' } },\n {\n tenantId: targetScope.tenantId,\n organizationId: targetScope.organizationId,\n },\n )\n\n const userIds = Array.from(new Set(roles.map((role) => role.userId).filter((value): value is string => typeof value === 'string' && value.length > 0)))\n const users = userIds.length\n ? await findWithDecryption(\n em,\n User,\n {\n id: { $in: userIds },\n deletedAt: null,\n ...(targetScope.tenantId ? { tenantId: targetScope.tenantId } : {}),\n },\n undefined,\n {\n tenantId: targetScope.tenantId,\n organizationId: targetScope.organizationId,\n },\n )\n : []\n const userMap = new Map(users.map((user) => [user.id, {\n name: user.name ?? deriveDisplayNameFromEmail(user.email) ?? null,\n email: user.email ?? null,\n phone: null,\n }]))\n\n return NextResponse.json({\n items: roles.map((role) => ({\n ...(userMap.has(role.userId)\n ? {\n userName: userMap.get(role.userId)?.name ?? null,\n userEmail: userMap.get(role.userId)?.email ?? null,\n userPhone: userMap.get(role.userId)?.phone ?? null,\n }\n : {}),\n id: role.id,\n entityType: role.entityType,\n entityId: role.entityId,\n userId: role.userId,\n roleType: role.roleType,\n createdAt: role.createdAt.toISOString(),\n updatedAt: role.updatedAt.toISOString(),\n })),\n })\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.get failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_load_roles', 'Failed to load roles') }, { status: 500 })\n }\n }\n\n async function POST(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { container, em, auth, scope, ctx } = await buildContext(request)\n const targetScope = await resolveEntityRouteScope(em, auth, scope, entityType, entityId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.manage', targetScope.organizationId, translate)\n const commandCtx = createScopedCommandContext(ctx, targetScope.organizationId)\n\n const rawBody = await readJsonSafe<Record<string, unknown>>(request, {})\n const scoped = withScopedPayload(\n {\n ...rawBody,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n ...getRoleContext(entityType, entityId),\n },\n commandCtx,\n translate,\n )\n const parsed = entityRoleCreateSchema.parse(scoped)\n\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, mutationPayload: rawBody,\n })\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<EntityRoleCreateInput, { roleId: string }>(\n 'customers.entityRoles.create',\n { input: parsed, ctx: commandCtx },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, metadata: guardResult.metadata ?? null,\n })\n }\n\n return withOperationMetadata(\n NextResponse.json({ id: result?.roleId ?? null }, { status: 201 }),\n logEntry,\n { resourceKind, resourceId: entityId },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.post failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_assign_role', 'Failed to assign role') }, { status: 500 })\n }\n }\n\n async function PUT(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { roleId } = roleIdQuerySchema.parse(Object.fromEntries(new URL(request.url).searchParams))\n const { container, em, auth, scope, ctx } = await buildContext(request)\n const targetScope = await resolveRoleRouteScope(em, auth, scope, entityType, entityId, roleId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.manage', targetScope.organizationId, translate)\n const commandCtx = createScopedCommandContext(ctx, targetScope.organizationId)\n\n const rawBody = await readJsonSafe<Record<string, unknown>>(request, {})\n const scoped = withScopedPayload(\n {\n ...rawBody,\n id: roleId,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n },\n commandCtx,\n translate,\n )\n const parsed = entityRoleUpdateSchema.parse(scoped)\n\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, mutationPayload: { roleId, ...rawBody },\n })\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<EntityRoleUpdateInput, { roleId: string }>(\n 'customers.entityRoles.update',\n { input: parsed, ctx: commandCtx },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, metadata: guardResult.metadata ?? null,\n })\n }\n\n return withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind, resourceId: entityId },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.put failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_update_role', 'Failed to update role') }, { status: 500 })\n }\n }\n\n async function DELETE(request: Request, { params }: { params: { id: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id: entityId } = paramsSchema.parse(params)\n const { roleId } = roleIdQuerySchema.parse(Object.fromEntries(new URL(request.url).searchParams))\n const { container, em, auth, scope, ctx } = await buildContext(request)\n const targetScope = await resolveRoleRouteScope(em, auth, scope, entityType, entityId, roleId, translate)\n await ensureFeatureOnOrganization(container, auth, 'customers.roles.manage', targetScope.organizationId, translate)\n const commandCtx = createScopedCommandContext(ctx, targetScope.organizationId)\n\n const parsed = entityRoleDeleteSchema.parse(\n withScopedPayload(\n {\n id: roleId,\n organizationId: targetScope.organizationId,\n tenantId: targetScope.tenantId,\n },\n commandCtx,\n translate,\n ),\n )\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, mutationPayload: { roleId },\n })\n if (guardResult && !guardResult.ok) return NextResponse.json(guardResult.body, { status: guardResult.status })\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<EntityRoleDeleteInput, { roleId: string }>(\n 'customers.entityRoles.delete',\n { input: parsed, ctx: commandCtx },\n )\n\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: targetScope.tenantId, organizationId: targetScope.organizationId, userId: guardUserId,\n resourceKind, resourceId: entityId, operation: 'custom',\n requestMethod: request.method, requestHeaders: request.headers, metadata: guardResult.metadata ?? null,\n })\n }\n\n return withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind, resourceId: entityId },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) return NextResponse.json(err.body, { status: err.status })\n if (err instanceof z.ZodError) return buildValidationErrorResponse(err, translate)\n console.error(`${logPrefix}.delete failed`, err)\n return NextResponse.json({ error: translate('customers.errors.failed_to_delete_role', 'Failed to delete role') }, { status: 500 })\n }\n }\n\n return { GET, POST, PUT, DELETE }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
validateCrudMutationGuard
|
|
13
13
|
} from "@open-mercato/shared/lib/crud/mutation-guard";
|
|
14
14
|
import { resolveAuthActorId } from "../../../lib/interactionRequestContext.js";
|
|
15
|
+
import { withOperationMetadata } from "../../../lib/operationMetadata.js";
|
|
15
16
|
const metadata = {
|
|
16
17
|
POST: { requireAuth: true, requireFeatures: ["customers.interactions.manage"] }
|
|
17
18
|
};
|
|
@@ -50,7 +51,7 @@ async function POST(req) {
|
|
|
50
51
|
return NextResponse.json(guardResult.body, { status: guardResult.status });
|
|
51
52
|
}
|
|
52
53
|
const commandBus = ctx.container.resolve("commandBus");
|
|
53
|
-
await commandBus.execute(
|
|
54
|
+
const { logEntry } = await commandBus.execute(
|
|
54
55
|
"customers.interactions.cancel",
|
|
55
56
|
{ input: parsed, ctx }
|
|
56
57
|
);
|
|
@@ -67,7 +68,11 @@ async function POST(req) {
|
|
|
67
68
|
metadata: guardResult.metadata ?? null
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
|
-
return
|
|
71
|
+
return withOperationMetadata(
|
|
72
|
+
NextResponse.json({ ok: true }),
|
|
73
|
+
logEntry,
|
|
74
|
+
{ resourceKind: "customers.interaction", resourceId: parsed.id }
|
|
75
|
+
);
|
|
71
76
|
} catch (err) {
|
|
72
77
|
if (err instanceof CrudHttpError) {
|
|
73
78
|
return NextResponse.json(err.body, { status: err.status });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/api/interactions/cancel/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandRuntimeContext, CommandBus } from '@open-mercato/shared/lib/commands'\nimport { interactionCancelSchema, type InteractionCancelInput } from '../../../data/validators'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { resolveAuthActorId } from '../../../lib/interactionRequestContext'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n}\n\nexport async function POST(req: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const body = await readJsonSafe<Record<string, unknown>>(req, {})\n const parsed = interactionCancelSchema.parse(body)\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n await commandBus.execute<InteractionCancelInput, { interactionId: string }>(\n 'customers.interactions.cancel',\n { input: parsed, ctx },\n )\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return NextResponse.json({ ok: true })\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return NextResponse.json(err.body, { status: err.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 })\n }\n console.error('customers.interactions.cancel failed', err)\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst okResponseSchema = z.object({ ok: z.boolean() })\nconst errorSchema = z.object({ error: z.string() })\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Cancel an interaction',\n methods: {\n POST: {\n summary: 'Cancel an interaction',\n description: 'Marks an interaction as canceled.',\n requestBody: { contentType: 'application/json', schema: interactionCancelSchema },\n responses: [\n { status: 200, description: 'Interaction canceled', schema: okResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Interaction not found', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AAEnD,SAAS,+BAA4D;AACrE,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AAEpC,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandRuntimeContext, CommandBus } from '@open-mercato/shared/lib/commands'\nimport { interactionCancelSchema, type InteractionCancelInput } from '../../../data/validators'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { resolveAuthActorId } from '../../../lib/interactionRequestContext'\nimport { withOperationMetadata } from '../../../lib/operationMetadata'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n}\n\nexport async function POST(req: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const body = await readJsonSafe<Record<string, unknown>>(req, {})\n const parsed = interactionCancelSchema.parse(body)\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<InteractionCancelInput, { interactionId: string }>(\n 'customers.interactions.cancel',\n { input: parsed, ctx },\n )\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind: 'customers.interaction', resourceId: parsed.id },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return NextResponse.json(err.body, { status: err.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 })\n }\n console.error('customers.interactions.cancel failed', err)\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst okResponseSchema = z.object({ ok: z.boolean() })\nconst errorSchema = z.object({ error: z.string() })\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Cancel an interaction',\n methods: {\n POST: {\n summary: 'Cancel an interaction',\n description: 'Marks an interaction as canceled.',\n requestBody: { contentType: 'application/json', schema: interactionCancelSchema },\n responses: [\n { status: 200, description: 'Interaction canceled', schema: okResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Interaction not found', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
validateCrudMutationGuard
|
|
13
13
|
} from "@open-mercato/shared/lib/crud/mutation-guard";
|
|
14
14
|
import { resolveAuthActorId } from "../../../lib/interactionRequestContext.js";
|
|
15
|
+
import { withOperationMetadata } from "../../../lib/operationMetadata.js";
|
|
15
16
|
const metadata = {
|
|
16
17
|
POST: { requireAuth: true, requireFeatures: ["customers.interactions.manage"] }
|
|
17
18
|
};
|
|
@@ -50,7 +51,7 @@ async function POST(req) {
|
|
|
50
51
|
return NextResponse.json(guardResult.body, { status: guardResult.status });
|
|
51
52
|
}
|
|
52
53
|
const commandBus = ctx.container.resolve("commandBus");
|
|
53
|
-
await commandBus.execute(
|
|
54
|
+
const { logEntry } = await commandBus.execute(
|
|
54
55
|
"customers.interactions.complete",
|
|
55
56
|
{ input: parsed, ctx }
|
|
56
57
|
);
|
|
@@ -67,7 +68,11 @@ async function POST(req) {
|
|
|
67
68
|
metadata: guardResult.metadata ?? null
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
|
-
return
|
|
71
|
+
return withOperationMetadata(
|
|
72
|
+
NextResponse.json({ ok: true }),
|
|
73
|
+
logEntry,
|
|
74
|
+
{ resourceKind: "customers.interaction", resourceId: parsed.id }
|
|
75
|
+
);
|
|
71
76
|
} catch (err) {
|
|
72
77
|
if (err instanceof CrudHttpError) {
|
|
73
78
|
return NextResponse.json(err.body, { status: err.status });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/api/interactions/complete/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandRuntimeContext, CommandBus } from '@open-mercato/shared/lib/commands'\nimport { interactionCompleteSchema, type InteractionCompleteInput } from '../../../data/validators'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { resolveAuthActorId } from '../../../lib/interactionRequestContext'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n}\n\nexport async function POST(req: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const body = await readJsonSafe<Record<string, unknown>>(req, {})\n const parsed = interactionCompleteSchema.parse(body)\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n await commandBus.execute<InteractionCompleteInput, { interactionId: string }>(\n 'customers.interactions.complete',\n { input: parsed, ctx },\n )\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return NextResponse.json({ ok: true })\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return NextResponse.json(err.body, { status: err.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 })\n }\n console.error('customers.interactions.complete failed', err)\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst okResponseSchema = z.object({ ok: z.boolean() })\nconst errorSchema = z.object({ error: z.string() })\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Complete an interaction',\n methods: {\n POST: {\n summary: 'Complete an interaction',\n description: 'Marks an interaction as done and sets occurredAt to current time (or a provided timestamp).',\n requestBody: { contentType: 'application/json', schema: interactionCompleteSchema },\n responses: [\n { status: 200, description: 'Interaction completed', schema: okResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Interaction not found', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AAEnD,SAAS,iCAAgE;AACzE,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AAEpC,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandRuntimeContext, CommandBus } from '@open-mercato/shared/lib/commands'\nimport { interactionCompleteSchema, type InteractionCompleteInput } from '../../../data/validators'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { resolveAuthActorId } from '../../../lib/interactionRequestContext'\nimport { withOperationMetadata } from '../../../lib/operationMetadata'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n}\n\nexport async function POST(req: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n const body = await readJsonSafe<Record<string, unknown>>(req, {})\n const parsed = interactionCompleteSchema.parse(body)\n const guardUserId = resolveAuthActorId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return NextResponse.json(guardResult.body, { status: guardResult.status })\n }\n\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const { logEntry } = await commandBus.execute<InteractionCompleteInput, { interactionId: string }>(\n 'customers.interactions.complete',\n { input: parsed, ctx },\n )\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: ctx.selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.interaction',\n resourceId: parsed.id,\n operation: 'custom',\n requestMethod: req.method,\n requestHeaders: req.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind: 'customers.interaction', resourceId: parsed.id },\n )\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return NextResponse.json(err.body, { status: err.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 })\n }\n console.error('customers.interactions.complete failed', err)\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst okResponseSchema = z.object({ ok: z.boolean() })\nconst errorSchema = z.object({ error: z.string() })\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Complete an interaction',\n methods: {\n POST: {\n summary: 'Complete an interaction',\n description: 'Marks an interaction as done and sets occurredAt to current time (or a provided timestamp).',\n requestBody: { contentType: 'application/json', schema: interactionCompleteSchema },\n responses: [\n { status: 200, description: 'Interaction completed', schema: okResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Interaction not found', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AAEnD,SAAS,iCAAgE;AACzE,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AAEpC,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AAE/B,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,+BAA+B,EAAE;AAChF;AAEA,eAAsB,KAAK,KAAc;AACvC,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,QAAI,CAAC,QAAQ,CAAC,KAAK,UAAU;AAC3B,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,iCAAiC,cAAc,EAAE,CAAC;AAAA,IACpG;AACA,UAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,SAAS,IAAI,CAAC;AACxF,UAAM,MAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,wBAAwB,OAAO,cAAc,KAAK,SAAS;AAAA,MAC3D,iBAAiB,OAAO,cAAc,KAAK,QAAQ,CAAC,KAAK,KAAK,IAAI;AAAA,MAClE,SAAS;AAAA,IACX;AAEA,UAAM,OAAO,MAAM,aAAsC,KAAK,CAAC,CAAC;AAChE,UAAM,SAAS,0BAA0B,MAAM,IAAI;AACnD,UAAM,cAAc,mBAAmB,IAAI;AAC3C,UAAM,cAAc,MAAM,0BAA0B,WAAW;AAAA,MAC7D,UAAU,KAAK;AAAA,MACf,gBAAgB,IAAI;AAAA,MACpB,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,WAAW;AAAA,MACX,eAAe,IAAI;AAAA,MACnB,gBAAgB,IAAI;AAAA,MACpB,iBAAiB;AAAA,IACnB,CAAC;AACD,QAAI,eAAe,CAAC,YAAY,IAAI;AAClC,aAAO,aAAa,KAAK,YAAY,MAAM,EAAE,QAAQ,YAAY,OAAO,CAAC;AAAA,IAC3E;AAEA,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,UAAM,EAAE,SAAS,IAAI,MAAM,WAAW;AAAA,MACpC;AAAA,MACA,EAAE,OAAO,QAAQ,IAAI;AAAA,IACvB;AACA,QAAI,aAAa,MAAM,YAAY,uBAAuB;AACxD,YAAM,iCAAiC,WAAW;AAAA,QAChD,UAAU,KAAK;AAAA,QACf,gBAAgB,IAAI;AAAA,QACpB,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,YAAY,OAAO;AAAA,QACnB,WAAW;AAAA,QACX,eAAe,IAAI;AAAA,QACnB,gBAAgB,IAAI;AAAA,QACpB,UAAU,YAAY,YAAY;AAAA,MACpC,CAAC;AAAA,IACH;AACA,WAAO;AAAA,MACL,aAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,MAC9B;AAAA,MACA,EAAE,cAAc,yBAAyB,YAAY,OAAO,GAAG;AAAA,IACjE;AAAA,EACF,SAAS,KAAK;AACZ,QAAI,eAAe,eAAe;AAChC,aAAO,aAAa,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,IAC3D;AACA,QAAI,eAAe,EAAE,UAAU;AAC7B,aAAO,aAAa,KAAK,EAAE,OAAO,qBAAqB,SAAS,IAAI,OAAO,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC/F;AACA,YAAQ,MAAM,0CAA0C,GAAG;AAC3D,WAAO,aAAa,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9E;AACF;AAEA,MAAM,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACrD,MAAM,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAE3C,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,MACb,aAAa,EAAE,aAAa,oBAAoB,QAAQ,0BAA0B;AAAA,MAClF,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,yBAAyB,QAAQ,iBAAiB;AAAA,MAChF;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,qBAAqB,QAAQ,YAAY;AAAA,QACrE,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,YAAY;AAAA,QAChE,EAAE,QAAQ,KAAK,aAAa,yBAAyB,QAAQ,YAAY;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|