@open-mercato/core 0.10.1-develop.7762.1.657bb7236b → 0.10.1-develop.7764.1.7505d7340b
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/modules/auth/api/profile/route.js +16 -2
- package/dist/modules/auth/api/profile/route.js.map +2 -2
- package/dist/modules/auth/lib/userDataSubject.js +26 -0
- package/dist/modules/auth/lib/userDataSubject.js.map +7 -0
- package/dist/modules/customers/api/companies/route.js +2 -1
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +2 -1
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +21 -3
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/listSorting.js +2 -1
- package/dist/modules/customers/backend/customers/listSorting.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +17 -1
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/lib/createdAtDayFilter.js +64 -0
- package/dist/modules/customers/lib/createdAtDayFilter.js.map +7 -0
- package/dist/modules/dashboards/api/layout/[itemId]/route.js +11 -4
- package/dist/modules/dashboards/api/layout/[itemId]/route.js.map +2 -2
- package/dist/modules/dashboards/api/layout/route.js +25 -13
- package/dist/modules/dashboards/api/layout/route.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/api/profile/route.ts +15 -1
- package/src/modules/auth/lib/userDataSubject.ts +30 -0
- package/src/modules/customers/api/companies/route.ts +2 -1
- package/src/modules/customers/api/people/route.ts +2 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +26 -3
- package/src/modules/customers/backend/customers/listSorting.ts +1 -0
- package/src/modules/customers/backend/customers/people/page.tsx +22 -1
- package/src/modules/customers/i18n/de.json +2 -0
- package/src/modules/customers/i18n/en.json +2 -0
- package/src/modules/customers/i18n/es.json +2 -0
- package/src/modules/customers/i18n/ko.json +2 -0
- package/src/modules/customers/i18n/pl.json +2 -0
- package/src/modules/customers/lib/createdAtDayFilter.ts +68 -0
- package/src/modules/dashboards/api/layout/[itemId]/route.ts +12 -4
- package/src/modules/dashboards/api/layout/route.ts +25 -12
package/.turbo/turbo-build.log
CHANGED
|
@@ -10,6 +10,7 @@ import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find"
|
|
|
10
10
|
import { buildPasswordSchema } from "@open-mercato/shared/lib/auth/passwordPolicy";
|
|
11
11
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
12
12
|
import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
|
|
13
|
+
import { resolveUserDataSubject } from "@open-mercato/core/modules/auth/lib/userDataSubject";
|
|
13
14
|
const logger = createLogger("auth").child({ component: "profile" });
|
|
14
15
|
const profileResponseSchema = z.object({
|
|
15
16
|
email: z.string().email(),
|
|
@@ -84,10 +85,18 @@ async function GET(req) {
|
|
|
84
85
|
try {
|
|
85
86
|
const container = await createRequestContainer();
|
|
86
87
|
const em = container.resolve("em");
|
|
88
|
+
const userId = await resolveUserDataSubject(em, auth);
|
|
89
|
+
if (!userId) {
|
|
90
|
+
return NextResponse.json({ error: translate("api.errors.forbidden", "Forbidden") }, { status: 403 });
|
|
91
|
+
}
|
|
87
92
|
const user = await findOneWithDecryption(
|
|
88
93
|
em,
|
|
89
94
|
User,
|
|
90
|
-
{
|
|
95
|
+
{
|
|
96
|
+
id: userId,
|
|
97
|
+
deletedAt: null,
|
|
98
|
+
...auth.isApiKey ? { tenantId: auth.tenantId, ...auth.orgId ? { organizationId: auth.orgId } : {} } : {}
|
|
99
|
+
},
|
|
91
100
|
void 0,
|
|
92
101
|
{ tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null }
|
|
93
102
|
);
|
|
@@ -111,6 +120,9 @@ async function PUT(req) {
|
|
|
111
120
|
if (!auth?.sub) {
|
|
112
121
|
return NextResponse.json({ error: translate("api.errors.unauthorized", "Unauthorized") }, { status: 401 });
|
|
113
122
|
}
|
|
123
|
+
if (auth.isApiKey) {
|
|
124
|
+
return NextResponse.json({ error: translate("api.errors.forbidden", "Forbidden") }, { status: 403 });
|
|
125
|
+
}
|
|
114
126
|
try {
|
|
115
127
|
const body = await req.json().catch(() => ({}));
|
|
116
128
|
const parsed = buildUpdateSchema(translate).safeParse(body);
|
|
@@ -206,6 +218,7 @@ const openApi = {
|
|
|
206
218
|
responses: [
|
|
207
219
|
{ status: 200, description: "Profile payload", schema: profileResponseSchema },
|
|
208
220
|
{ status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) },
|
|
221
|
+
{ status: 403, description: "No user binding in the authenticated scope", schema: z.object({ error: z.string() }) },
|
|
209
222
|
{ status: 404, description: "User not found", schema: z.object({ error: z.string() }) }
|
|
210
223
|
]
|
|
211
224
|
},
|
|
@@ -219,7 +232,8 @@ const openApi = {
|
|
|
219
232
|
responses: [
|
|
220
233
|
{ status: 200, description: "Profile updated", schema: profileUpdateResponseSchema },
|
|
221
234
|
{ status: 400, description: "Invalid payload", schema: z.object({ error: z.string() }) },
|
|
222
|
-
{ status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) }
|
|
235
|
+
{ status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) },
|
|
236
|
+
{ status: 403, description: "Interactive session required", schema: z.object({ error: z.string() }) }
|
|
223
237
|
]
|
|
224
238
|
}
|
|
225
239
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/auth/api/profile/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { signJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildPasswordSchema } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\n\nconst logger = createLogger('auth').child({ component: 'profile' })\n\nconst profileResponseSchema = z.object({\n email: z.string().email(),\n name: z.string().nullable().optional(),\n roles: z.array(z.string()),\n})\n\nconst passwordSchema = buildPasswordSchema()\n\nconst updateSchemaBase = z.object({\n email: z.string().email().optional(),\n currentPassword: z.string().trim().min(1).optional(),\n password: passwordSchema.optional(),\n})\n\nfunction buildUpdateSchema(translate: (key: string, fallback: string) => string) {\n return updateSchemaBase.superRefine((data, ctx) => {\n if (!data.email && !data.password) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: translate(\n 'auth.profile.form.errors.emailOrPasswordRequired',\n 'Provide an email or password.',\n ),\n path: ['email'],\n })\n }\n if (data.password && !data.currentPassword) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: translate(\n 'auth.profile.form.errors.currentPasswordRequired',\n 'Current password is required.',\n ),\n path: ['currentPassword'],\n })\n }\n if (data.currentPassword && !data.password) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: translate(\n 'auth.profile.form.errors.newPasswordRequired',\n 'New password is required.',\n ),\n path: ['password'],\n })\n }\n })\n}\n\nconst updateSchema = buildUpdateSchema((_key, fallback) => fallback)\n\nconst profileUpdateResponseSchema = z.object({\n ok: z.literal(true),\n email: z.string().email(),\n})\n\nexport const metadata = {\n GET: { requireAuth: true },\n PUT: { requireAuth: true },\n}\n\nfunction buildCommandContext(container: Awaited<ReturnType<typeof createRequestContainer>>, auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>, req: Request): CommandRuntimeContext {\n return {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId: auth.orgId ?? null,\n organizationIds: auth.orgId ? [auth.orgId] : null,\n request: req,\n }\n}\n\nexport async function GET(req: Request) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) {\n return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n }\n try {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const user = await findOneWithDecryption(\n em,\n User,\n { id: auth.sub, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },\n )\n if (!user) {\n return NextResponse.json({ error: translate('auth.users.form.errors.notFound', 'User not found') }, { status: 404 })\n }\n const displayName = typeof user.name === 'string' ? user.name.trim() : ''\n return NextResponse.json({\n email: String(user.email),\n name: displayName.length > 0 ? displayName : null,\n roles: auth.roles ?? [],\n })\n } catch (err) {\n logger.error('Profile load failed', { err })\n return NextResponse.json({ error: translate('auth.profile.form.errors.load', 'Failed to load profile.') }, { status: 400 })\n }\n}\n\nexport async function PUT(req: Request) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) {\n return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n }\n try {\n const body = await req.json().catch(() => ({}))\n const parsed = buildUpdateSchema(translate).safeParse(body)\n if (!parsed.success) {\n return NextResponse.json(\n {\n error: translate('auth.profile.form.errors.invalid', 'Invalid profile update.'),\n issues: parsed.error.issues,\n },\n { status: 400 },\n )\n }\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const authService = container.resolve('authService') as AuthService\n if (parsed.data.password) {\n const user = await findOneWithDecryption(\n em,\n User,\n { id: auth.sub, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },\n )\n if (!user) {\n return NextResponse.json({ error: translate('auth.users.form.errors.notFound', 'User not found') }, { status: 404 })\n }\n const currentPassword = parsed.data.currentPassword?.trim() ?? ''\n const isCurrentPasswordValid = await authService.verifyPassword(user, currentPassword)\n if (!isCurrentPasswordValid) {\n const message = translate(\n 'auth.profile.form.errors.currentPasswordInvalid',\n 'Current password is incorrect.',\n )\n return NextResponse.json(\n {\n error: message,\n issues: [{ path: ['currentPassword'], message }],\n },\n { status: 400 },\n )\n }\n }\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const ctx = buildCommandContext(container, auth, req)\n const { result } = await commandBus.execute<{ id: string; email?: string; password?: string }, User>(\n 'auth.users.update',\n {\n input: {\n id: auth.sub,\n email: parsed.data.email,\n password: parsed.data.password,\n },\n ctx,\n },\n )\n const roles = await authService.getUserRoles(result, result.tenantId ? String(result.tenantId) : null)\n const jwt = signJwt({\n sub: String(result.id),\n sid: typeof auth.sid === 'string' ? auth.sid : undefined,\n tenantId: result.tenantId ? String(result.tenantId) : null,\n orgId: result.organizationId ? String(result.organizationId) : null,\n email: result.email,\n roles,\n })\n const res = NextResponse.json({ ok: true, email: String(result.email) })\n res.cookies.set('auth_token', jwt, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge: 60 * 60 * 8,\n })\n return res\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n logger.error('Profile update failed', { err })\n return NextResponse.json({ error: translate('auth.profile.form.errors.save', 'Failed to update profile.') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'Profile settings',\n methods: {\n GET: {\n summary: 'Get current profile',\n description: 'Returns the email address, display name, and roles for the signed-in user. The display name is null when unset.',\n responses: [\n { status: 200, description: 'Profile payload', schema: profileResponseSchema },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 404, description: 'User not found', schema: z.object({ error: z.string() }) },\n ],\n },\n PUT: {\n summary: 'Update current profile',\n description: 'Updates the email address or password for the signed-in user.',\n requestBody: {\n contentType: 'application/json',\n schema: updateSchema,\n },\n responses: [\n { status: 200, description: 'Profile updated', schema: profileUpdateResponseSchema },\n { status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAGlB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,eAAe;AACxB,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAEhC,SAAS,YAAY;AAErB,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,oBAAoB;AAC7B,SAAS,0CAA0C;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { signJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildPasswordSchema } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\nimport { resolveUserDataSubject } from '@open-mercato/core/modules/auth/lib/userDataSubject'\n\nconst logger = createLogger('auth').child({ component: 'profile' })\n\nconst profileResponseSchema = z.object({\n email: z.string().email(),\n name: z.string().nullable().optional(),\n roles: z.array(z.string()),\n})\n\nconst passwordSchema = buildPasswordSchema()\n\nconst updateSchemaBase = z.object({\n email: z.string().email().optional(),\n currentPassword: z.string().trim().min(1).optional(),\n password: passwordSchema.optional(),\n})\n\nfunction buildUpdateSchema(translate: (key: string, fallback: string) => string) {\n return updateSchemaBase.superRefine((data, ctx) => {\n if (!data.email && !data.password) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: translate(\n 'auth.profile.form.errors.emailOrPasswordRequired',\n 'Provide an email or password.',\n ),\n path: ['email'],\n })\n }\n if (data.password && !data.currentPassword) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: translate(\n 'auth.profile.form.errors.currentPasswordRequired',\n 'Current password is required.',\n ),\n path: ['currentPassword'],\n })\n }\n if (data.currentPassword && !data.password) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: translate(\n 'auth.profile.form.errors.newPasswordRequired',\n 'New password is required.',\n ),\n path: ['password'],\n })\n }\n })\n}\n\nconst updateSchema = buildUpdateSchema((_key, fallback) => fallback)\n\nconst profileUpdateResponseSchema = z.object({\n ok: z.literal(true),\n email: z.string().email(),\n})\n\nexport const metadata = {\n GET: { requireAuth: true },\n PUT: { requireAuth: true },\n}\n\nfunction buildCommandContext(container: Awaited<ReturnType<typeof createRequestContainer>>, auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>, req: Request): CommandRuntimeContext {\n return {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId: auth.orgId ?? null,\n organizationIds: auth.orgId ? [auth.orgId] : null,\n request: req,\n }\n}\n\nexport async function GET(req: Request) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) {\n return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n }\n try {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const userId = await resolveUserDataSubject(em, auth)\n if (!userId) {\n return NextResponse.json({ error: translate('api.errors.forbidden', 'Forbidden') }, { status: 403 })\n }\n const user = await findOneWithDecryption(\n em,\n User,\n {\n id: userId,\n deletedAt: null,\n ...(auth.isApiKey ? { tenantId: auth.tenantId, ...(auth.orgId ? { organizationId: auth.orgId } : {}) } : {}),\n },\n undefined,\n { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },\n )\n if (!user) {\n return NextResponse.json({ error: translate('auth.users.form.errors.notFound', 'User not found') }, { status: 404 })\n }\n const displayName = typeof user.name === 'string' ? user.name.trim() : ''\n return NextResponse.json({\n email: String(user.email),\n name: displayName.length > 0 ? displayName : null,\n roles: auth.roles ?? [],\n })\n } catch (err) {\n logger.error('Profile load failed', { err })\n return NextResponse.json({ error: translate('auth.profile.form.errors.load', 'Failed to load profile.') }, { status: 400 })\n }\n}\n\nexport async function PUT(req: Request) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) {\n return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n }\n if (auth.isApiKey) {\n return NextResponse.json({ error: translate('api.errors.forbidden', 'Forbidden') }, { status: 403 })\n }\n try {\n const body = await req.json().catch(() => ({}))\n const parsed = buildUpdateSchema(translate).safeParse(body)\n if (!parsed.success) {\n return NextResponse.json(\n {\n error: translate('auth.profile.form.errors.invalid', 'Invalid profile update.'),\n issues: parsed.error.issues,\n },\n { status: 400 },\n )\n }\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const authService = container.resolve('authService') as AuthService\n if (parsed.data.password) {\n const user = await findOneWithDecryption(\n em,\n User,\n { id: auth.sub, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },\n )\n if (!user) {\n return NextResponse.json({ error: translate('auth.users.form.errors.notFound', 'User not found') }, { status: 404 })\n }\n const currentPassword = parsed.data.currentPassword?.trim() ?? ''\n const isCurrentPasswordValid = await authService.verifyPassword(user, currentPassword)\n if (!isCurrentPasswordValid) {\n const message = translate(\n 'auth.profile.form.errors.currentPasswordInvalid',\n 'Current password is incorrect.',\n )\n return NextResponse.json(\n {\n error: message,\n issues: [{ path: ['currentPassword'], message }],\n },\n { status: 400 },\n )\n }\n }\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const ctx = buildCommandContext(container, auth, req)\n const { result } = await commandBus.execute<{ id: string; email?: string; password?: string }, User>(\n 'auth.users.update',\n {\n input: {\n id: auth.sub,\n email: parsed.data.email,\n password: parsed.data.password,\n },\n ctx,\n },\n )\n const roles = await authService.getUserRoles(result, result.tenantId ? String(result.tenantId) : null)\n const jwt = signJwt({\n sub: String(result.id),\n sid: typeof auth.sid === 'string' ? auth.sid : undefined,\n tenantId: result.tenantId ? String(result.tenantId) : null,\n orgId: result.organizationId ? String(result.organizationId) : null,\n email: result.email,\n roles,\n })\n const res = NextResponse.json({ ok: true, email: String(result.email) })\n res.cookies.set('auth_token', jwt, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge: 60 * 60 * 8,\n })\n return res\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n logger.error('Profile update failed', { err })\n return NextResponse.json({ error: translate('auth.profile.form.errors.save', 'Failed to update profile.') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'Profile settings',\n methods: {\n GET: {\n summary: 'Get current profile',\n description: 'Returns the email address, display name, and roles for the signed-in user. The display name is null when unset.',\n responses: [\n { status: 200, description: 'Profile payload', schema: profileResponseSchema },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'No user binding in the authenticated scope', schema: z.object({ error: z.string() }) },\n { status: 404, description: 'User not found', schema: z.object({ error: z.string() }) },\n ],\n },\n PUT: {\n summary: 'Update current profile',\n description: 'Updates the email address or password for the signed-in user.',\n requestBody: {\n contentType: 'application/json',\n schema: updateSchema,\n },\n responses: [\n { status: 200, description: 'Profile updated', schema: profileUpdateResponseSchema },\n { status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Interactive session required', schema: z.object({ error: z.string() }) },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
3
|
+
import { User } from "../data/entities.js";
|
|
4
|
+
const uuidSchema = z.string().uuid();
|
|
5
|
+
async function resolveUserDataSubject(em, auth) {
|
|
6
|
+
if (!auth.isApiKey) return auth.sub;
|
|
7
|
+
if (!uuidSchema.safeParse(auth.userId).success || !uuidSchema.safeParse(auth.tenantId).success) return null;
|
|
8
|
+
if (auth.orgId !== null && !uuidSchema.safeParse(auth.orgId).success) return null;
|
|
9
|
+
const user = await findOneWithDecryption(
|
|
10
|
+
em,
|
|
11
|
+
User,
|
|
12
|
+
{
|
|
13
|
+
id: auth.userId,
|
|
14
|
+
tenantId: auth.tenantId,
|
|
15
|
+
...auth.orgId ? { organizationId: auth.orgId } : {},
|
|
16
|
+
deletedAt: null
|
|
17
|
+
},
|
|
18
|
+
void 0,
|
|
19
|
+
{ tenantId: auth.tenantId, organizationId: auth.orgId }
|
|
20
|
+
);
|
|
21
|
+
return user?.id ?? null;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
resolveUserDataSubject
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=userDataSubject.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/auth/lib/userDataSubject.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { User } from '../data/entities'\n\nconst uuidSchema = z.string().uuid()\n\nexport async function resolveUserDataSubject(\n em: EntityManager,\n auth: NonNullable<AuthContext>,\n): Promise<string | null> {\n if (!auth.isApiKey) return auth.sub\n if (!uuidSchema.safeParse(auth.userId).success || !uuidSchema.safeParse(auth.tenantId).success) return null\n if (auth.orgId !== null && !uuidSchema.safeParse(auth.orgId).success) return null\n\n const user = await findOneWithDecryption(\n em,\n User,\n {\n id: auth.userId,\n tenantId: auth.tenantId,\n ...(auth.orgId ? { organizationId: auth.orgId } : {}),\n deletedAt: null,\n },\n undefined,\n { tenantId: auth.tenantId, organizationId: auth.orgId },\n )\n return user?.id ?? null\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAGlB,SAAS,6BAA6B;AACtC,SAAS,YAAY;AAErB,MAAM,aAAa,EAAE,OAAO,EAAE,KAAK;AAEnC,eAAsB,uBACpB,IACA,MACwB;AACxB,MAAI,CAAC,KAAK,SAAU,QAAO,KAAK;AAChC,MAAI,CAAC,WAAW,UAAU,KAAK,MAAM,EAAE,WAAW,CAAC,WAAW,UAAU,KAAK,QAAQ,EAAE,QAAS,QAAO;AACvG,MAAI,KAAK,UAAU,QAAQ,CAAC,WAAW,UAAU,KAAK,KAAK,EAAE,QAAS,QAAO;AAE7E,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,MACE,IAAI,KAAK;AAAA,MACT,UAAU,KAAK;AAAA,MACf,GAAI,KAAK,QAAQ,EAAE,gBAAgB,KAAK,MAAM,IAAI,CAAC;AAAA,MACnD,WAAW;AAAA,IACb;AAAA,IACA;AAAA,IACA,EAAE,UAAU,KAAK,UAAU,gBAAgB,KAAK,MAAM;AAAA,EACxD;AACA,SAAO,MAAM,MAAM;AACrB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -27,6 +27,7 @@ import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
|
|
|
27
27
|
import { isUuidListParam, splitIdListParam } from "@open-mercato/shared/lib/crud/ids";
|
|
28
28
|
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
29
29
|
import { consumeAdvancedFilterState, mergeAdvancedFilterTree } from "@open-mercato/shared/lib/crud/advanced-filter-integration";
|
|
30
|
+
import { expandCreatedAtDayRules } from "../../lib/createdAtDayFilter.js";
|
|
30
31
|
import {
|
|
31
32
|
createCustomersCrudOpenApi,
|
|
32
33
|
createPagedListResponseSchema,
|
|
@@ -123,7 +124,7 @@ const crud = makeCrudRoute({
|
|
|
123
124
|
updatedAt: "updated_at"
|
|
124
125
|
},
|
|
125
126
|
buildFilters: async (query, ctx) => {
|
|
126
|
-
const advancedFilterTree = consumeAdvancedFilterState(query);
|
|
127
|
+
const advancedFilterTree = expandCreatedAtDayRules(consumeAdvancedFilterState(query), "UTC");
|
|
127
128
|
const filters = { kind: { $eq: "company" } };
|
|
128
129
|
if (query.id) filters.id = { $eq: query.id };
|
|
129
130
|
if (query.search) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/api/companies/route.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n CustomerCompanyProfile,\n CustomerDealCompanyLink,\n CustomerEntity,\n CustomerPersonCompanyLink,\n} from '../../data/entities'\nimport { E } from '#generated/entities.ids.generated'\nimport { companyCreateSchema, companyUpdateSchema } from '../../data/validators'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n applyEntityIdExclusion,\n applyEntityIdRestriction,\n findMatchingEntityIdsWithQueryEngine,\n findMatchingEntityIdsBySearchTokensAcrossSources,\n withScopedPayload,\n} from '../utils'\nimport {\n buildCustomFieldFiltersFromQuery,\n extractAllCustomFieldEntries,\n splitCustomFieldPayload,\n} from '@open-mercato/shared/lib/crud/custom-fields'\nimport { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { isUuidListParam, splitIdListParam } from '@open-mercato/shared/lib/crud/ids'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'\nimport {\n createCustomersCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n withCustomerPersonCompanyLinkScope,\n withScopedCustomerDealLinkWhere,\n} from '../../lib/personCompanyLinkTable'\nimport { normalizeCompanyProfilePayload } from './payload'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n email: z.string().optional(),\n emailStartsWith: z.string().optional(),\n emailContains: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n status: z.string().optional(),\n lifecycleStage: z.string().optional(),\n source: z.string().optional(),\n hasEmail: z.string().optional(),\n hasPhone: z.string().optional(),\n hasNextInteraction: z.string().optional(),\n createdFrom: z.string().optional(),\n createdTo: z.string().optional(),\n id: z.string().uuid().optional(),\n tagIds: z\n .string()\n .optional()\n .refine(isUuidListParam, { message: 'tagIds must be a comma-separated list of UUIDs' }),\n tagIdsEmpty: z.string().optional(),\n excludeIds: z.string().optional(),\n excludeLinkedPersonId: z.string().uuid().optional(),\n excludeLinkedCompanyId: z.string().uuid().optional(),\n excludeLinkedDealId: z.string().uuid().optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.companies.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.companies.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.companies.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerEntity,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.company' },\n indexer: {\n entityType: E.customers.customer_entity,\n },\n list: {\n schema: listSchema,\n entityId: E.customers.customer_entity,\n fields: [\n 'id',\n 'display_name',\n 'description',\n 'owner_user_id',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_at',\n 'next_interaction_name',\n 'next_interaction_ref_id',\n 'next_interaction_icon',\n 'next_interaction_color',\n 'organization_id',\n 'tenant_id',\n 'kind',\n 'created_at',\n 'updated_at',\n ],\n sortFieldMap: {\n name: 'display_name',\n email: 'primary_email',\n primaryEmail: 'primary_email',\n status: 'status',\n lifecycleStage: 'lifecycle_stage',\n source: 'source',\n nextInteractionAt: 'next_interaction_at',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n buildFilters: async (query, ctx) => {\n const advancedFilterTree = consumeAdvancedFilterState(query)\n const filters: Record<string, unknown> = { kind: { $eq: 'company' } }\n if (query.id) filters.id = { $eq: query.id }\n if (query.search) {\n const matchingIds = ctx\n ? await findMatchingEntityIdsBySearchTokensAcrossSources({\n ctx,\n query: query.search,\n sources: [\n {\n entityType: E.customers.customer_entity,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_name',\n ],\n },\n {\n entityType: E.customers.customer_company_profile,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'legal_name',\n 'brand_name',\n 'domain',\n 'website_url',\n 'industry',\n 'size_bucket',\n 'annual_revenue',\n ],\n mapToEntityIds: {\n table: 'customer_companies',\n targetColumn: 'entity_id',\n },\n },\n ],\n })\n : null\n if (matchingIds !== null && matchingIds.length > 0) {\n applyEntityIdRestriction(filters, matchingIds)\n } else {\n const searchPattern = buildIlikeTerm(query.search)\n filters.$or = [\n { display_name: { $ilike: searchPattern } },\n { primary_email: { $ilike: searchPattern } },\n { primary_phone: { $ilike: searchPattern } },\n { description: { $ilike: searchPattern } },\n { next_interaction_name: { $ilike: searchPattern } },\n ]\n }\n }\n if (query.status) {\n filters.status = { $eq: query.status }\n }\n if (query.lifecycleStage) {\n filters.lifecycle_stage = { $eq: query.lifecycleStage }\n }\n if (query.source) {\n filters.source = { $eq: query.source }\n }\n const tagIds = splitIdListParam(query.tagIds)\n const tagIdsEmpty = parseBooleanToken(query.tagIdsEmpty) === true\n if (tagIdsEmpty) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length > 0) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n }\n const excludedIds = new Set<string>()\n const excludeIdsRaw = typeof query.excludeIds === 'string' ? query.excludeIds : ''\n excludeIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n .forEach((value: string) => excludedIds.add(value))\n if (ctx && query.excludeLinkedPersonId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n withCustomerPersonCompanyLinkScope({ person: query.excludeLinkedPersonId }, decryptionScope),\n 'customers.companies.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['company'] },\n decryptionScope,\n ),\n )\n links.forEach((link) => {\n const companyId = link.company?.id\n if (typeof companyId === 'string' && companyId.length > 0) excludedIds.add(companyId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'companies.list', err })\n }\n }\n if (typeof query.excludeLinkedCompanyId === 'string' && query.excludeLinkedCompanyId.length > 0) {\n excludedIds.add(query.excludeLinkedCompanyId)\n }\n if (ctx && query.excludeLinkedDealId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const links = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n withScopedCustomerDealLinkWhere(query.excludeLinkedDealId, decryptionScope),\n { populate: ['company'] },\n decryptionScope,\n )\n links.forEach((link) => {\n const companyId = link.company?.id\n if (typeof companyId === 'string' && companyId.length > 0) excludedIds.add(companyId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'companies.list', err })\n }\n }\n applyEntityIdExclusion(filters, Array.from(excludedIds))\n const email = typeof query.email === 'string' ? query.email.trim().toLowerCase() : ''\n const emailStartsWith = typeof query.emailStartsWith === 'string' ? query.emailStartsWith.trim().toLowerCase() : ''\n const emailContains = typeof query.emailContains === 'string' ? query.emailContains.trim().toLowerCase() : ''\n if (email) {\n filters.primary_email = { $eq: email }\n } else if (emailStartsWith) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailStartsWith, 'startsWith') }\n } else if (emailContains) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailContains) }\n }\n const hasEmail = parseBooleanToken(query.hasEmail)\n if (!email && !emailStartsWith && !emailContains && hasEmail !== null) {\n filters.primary_email = { $exists: hasEmail }\n }\n const hasPhone = parseBooleanToken(query.hasPhone)\n if (hasPhone !== null) {\n filters.primary_phone = { $exists: hasPhone }\n }\n const hasNextInteraction = parseBooleanToken(query.hasNextInteraction)\n if (hasNextInteraction !== null) {\n filters.next_interaction_at = { $exists: hasNextInteraction }\n }\n const createdRange: Record<string, Date> = {}\n if (query.createdFrom) {\n const from = new Date(query.createdFrom)\n if (!Number.isNaN(from.getTime())) createdRange.$gte = from\n }\n if (query.createdTo) {\n const to = new Date(query.createdTo)\n if (!Number.isNaN(to.getTime())) createdRange.$lte = to\n }\n if (Object.keys(createdRange).length) {\n filters.created_at = createdRange\n }\n if (ctx) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.customers.customer_entity, E.customers.customer_company_profile],\n query,\n em,\n tenantId: ctx.auth?.tenantId ?? null,\n })\n Object.assign(filters, cfFilters)\n } catch (err) {\n logger.warn('custom field filter resolution failed; falling back to base filters', { component: 'companies.list', err })\n }\n }\n if (ctx && advancedFilterTree) {\n const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)\n const matchedIds = await findMatchingEntityIdsWithQueryEngine({\n ctx,\n entityId: E.customers.customer_entity,\n filters: advancedFilters,\n customFieldSources: [\n {\n entityId: E.customers.customer_company_profile,\n table: 'customer_companies',\n alias: 'company_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n })\n applyEntityIdRestriction(filters, matchedIds)\n }\n return filters\n },\n customFieldSources: [\n {\n entityId: E.customers.customer_company_profile,\n table: 'customer_companies',\n alias: 'company_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n transformItem: (item) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const normalized: Record<string, unknown> = { ...record }\n delete normalized.kind\n const cfEntries = extractAllCustomFieldEntries(record)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) {\n delete normalized[key]\n }\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'customers.companies.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const { base, custom } = splitCustomFieldPayload(scoped)\n const parsed = companyCreateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: ({ result }) => ({\n id: result?.entityId ?? result?.id ?? null,\n companyId: result?.companyId ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: 'customers.companies.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const normalized = normalizeCompanyProfilePayload(scoped, translate)\n const { base, custom } = splitCustomFieldPayload(normalized)\n const parsed = companyUpdateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n // Return the freshly-bumped updatedAt so inline-edit detail pages can refresh\n // their optimistic-lock token between sequential saves (avoids a false 409 on\n // the 2nd inline edit now that locking is default-ON). #2055. The factory hands\n // the updated entity here; read defensively in case a `{ result }` wrapper arrives.\n response: (arg: { result?: unknown; updatedAt?: Date | string | null }) => {\n const raw = arg?.updatedAt\n ?? (arg?.result as { updatedAt?: Date | string | null } | null | undefined)?.updatedAt\n ?? null\n return {\n ok: true,\n updatedAt: raw instanceof Date ? raw.toISOString() : (typeof raw === 'string' ? raw : null),\n }\n },\n },\n delete: {\n commandId: 'customers.companies.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) throw new CrudHttpError(400, { error: translate('customers.errors.company_required', 'Company id is required') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n const ids = items\n .map((item: unknown) => (item && typeof item === 'object' && typeof (item as Record<string, unknown>).id === 'string'\n ? (item as Record<string, unknown>).id as string\n : null))\n .filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)\n if (!ids.length) return\n\n const where: Record<string, unknown> = {\n entity: { $in: ids },\n tenantId: ctx.auth?.tenantId ?? null,\n }\n if (ctx.selectedOrganizationId) {\n where.organizationId = ctx.selectedOrganizationId\n }\n\n const profiles = await findWithDecryption(\n ctx.container.resolve('em') as EntityManager,\n CustomerCompanyProfile,\n where as FilterQuery<CustomerCompanyProfile>,\n { populate: ['entity'] },\n {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n },\n )\n\n const profilesByEntityId = new Map<string, CustomerCompanyProfile>()\n for (const profile of profiles) {\n const profileEntity = (profile as { entity?: { id?: unknown } }).entity\n const entityId = typeof profileEntity?.id === 'string' ? profileEntity.id : null\n if (entityId) profilesByEntityId.set(entityId, profile)\n }\n\n payload.items = items.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const profile = typeof record.id === 'string' ? profilesByEntityId.get(record.id) : undefined\n if (!profile) return item\n return {\n ...record,\n legal_name: profile.legalName ?? null,\n brand_name: profile.brandName ?? null,\n domain: profile.domain ?? null,\n website_url: profile.websiteUrl ?? null,\n industry: profile.industry ?? null,\n size_bucket: profile.sizeBucket ?? null,\n annual_revenue: profile.annualRevenue ?? null,\n }\n })\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\nexport const GET = crud.GET\n\nconst companyListItemSchema = z.object({\n id: z.string().uuid(),\n display_name: z.string().optional(),\n description: z.string().nullable().optional(),\n owner_user_id: z.string().uuid().nullable().optional(),\n primary_email: z.string().nullable().optional(),\n primary_phone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycle_stage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n next_interaction_at: z.string().nullable().optional(),\n next_interaction_name: z.string().nullable().optional(),\n next_interaction_ref_id: z.string().nullable().optional(),\n next_interaction_icon: z.string().nullable().optional(),\n next_interaction_color: z.string().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n})\n\nconst companyCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n companyId: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Company',\n pluralName: 'Companies',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(companyListItemSchema),\n create: {\n schema: companyCreateSchema,\n responseSchema: companyCreateResponseSchema,\n description: 'Creates a company record and associated profile data.',\n },\n update: {\n schema: companyUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates company profile fields, tags, or custom attributes.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a company by id. The identifier can be provided via body or query.',\n errors: [\n {\n status: 422,\n description: 'Company has dependent records (people, deals, or direct staff); unlink or reassign before delete.',\n schema: z.object({\n error: z.string(),\n code: z.literal('COMPANY_HAS_DEPENDENTS'),\n }),\n },\n ],\n },\n})\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n CustomerCompanyProfile,\n CustomerDealCompanyLink,\n CustomerEntity,\n CustomerPersonCompanyLink,\n} from '../../data/entities'\nimport { E } from '#generated/entities.ids.generated'\nimport { companyCreateSchema, companyUpdateSchema } from '../../data/validators'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n applyEntityIdExclusion,\n applyEntityIdRestriction,\n findMatchingEntityIdsWithQueryEngine,\n findMatchingEntityIdsBySearchTokensAcrossSources,\n withScopedPayload,\n} from '../utils'\nimport {\n buildCustomFieldFiltersFromQuery,\n extractAllCustomFieldEntries,\n splitCustomFieldPayload,\n} from '@open-mercato/shared/lib/crud/custom-fields'\nimport { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { isUuidListParam, splitIdListParam } from '@open-mercato/shared/lib/crud/ids'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'\nimport { expandCreatedAtDayRules } from '../../lib/createdAtDayFilter'\nimport {\n createCustomersCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n withCustomerPersonCompanyLinkScope,\n withScopedCustomerDealLinkWhere,\n} from '../../lib/personCompanyLinkTable'\nimport { normalizeCompanyProfilePayload } from './payload'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n email: z.string().optional(),\n emailStartsWith: z.string().optional(),\n emailContains: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n status: z.string().optional(),\n lifecycleStage: z.string().optional(),\n source: z.string().optional(),\n hasEmail: z.string().optional(),\n hasPhone: z.string().optional(),\n hasNextInteraction: z.string().optional(),\n createdFrom: z.string().optional(),\n createdTo: z.string().optional(),\n id: z.string().uuid().optional(),\n tagIds: z\n .string()\n .optional()\n .refine(isUuidListParam, { message: 'tagIds must be a comma-separated list of UUIDs' }),\n tagIdsEmpty: z.string().optional(),\n excludeIds: z.string().optional(),\n excludeLinkedPersonId: z.string().uuid().optional(),\n excludeLinkedCompanyId: z.string().uuid().optional(),\n excludeLinkedDealId: z.string().uuid().optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.companies.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.companies.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.companies.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerEntity,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.company' },\n indexer: {\n entityType: E.customers.customer_entity,\n },\n list: {\n schema: listSchema,\n entityId: E.customers.customer_entity,\n fields: [\n 'id',\n 'display_name',\n 'description',\n 'owner_user_id',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_at',\n 'next_interaction_name',\n 'next_interaction_ref_id',\n 'next_interaction_icon',\n 'next_interaction_color',\n 'organization_id',\n 'tenant_id',\n 'kind',\n 'created_at',\n 'updated_at',\n ],\n sortFieldMap: {\n name: 'display_name',\n email: 'primary_email',\n primaryEmail: 'primary_email',\n status: 'status',\n lifecycleStage: 'lifecycle_stage',\n source: 'source',\n nextInteractionAt: 'next_interaction_at',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n buildFilters: async (query, ctx) => {\n const advancedFilterTree = expandCreatedAtDayRules(consumeAdvancedFilterState(query), 'UTC')\n const filters: Record<string, unknown> = { kind: { $eq: 'company' } }\n if (query.id) filters.id = { $eq: query.id }\n if (query.search) {\n const matchingIds = ctx\n ? await findMatchingEntityIdsBySearchTokensAcrossSources({\n ctx,\n query: query.search,\n sources: [\n {\n entityType: E.customers.customer_entity,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_name',\n ],\n },\n {\n entityType: E.customers.customer_company_profile,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'legal_name',\n 'brand_name',\n 'domain',\n 'website_url',\n 'industry',\n 'size_bucket',\n 'annual_revenue',\n ],\n mapToEntityIds: {\n table: 'customer_companies',\n targetColumn: 'entity_id',\n },\n },\n ],\n })\n : null\n if (matchingIds !== null && matchingIds.length > 0) {\n applyEntityIdRestriction(filters, matchingIds)\n } else {\n const searchPattern = buildIlikeTerm(query.search)\n filters.$or = [\n { display_name: { $ilike: searchPattern } },\n { primary_email: { $ilike: searchPattern } },\n { primary_phone: { $ilike: searchPattern } },\n { description: { $ilike: searchPattern } },\n { next_interaction_name: { $ilike: searchPattern } },\n ]\n }\n }\n if (query.status) {\n filters.status = { $eq: query.status }\n }\n if (query.lifecycleStage) {\n filters.lifecycle_stage = { $eq: query.lifecycleStage }\n }\n if (query.source) {\n filters.source = { $eq: query.source }\n }\n const tagIds = splitIdListParam(query.tagIds)\n const tagIdsEmpty = parseBooleanToken(query.tagIdsEmpty) === true\n if (tagIdsEmpty) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length > 0) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n }\n const excludedIds = new Set<string>()\n const excludeIdsRaw = typeof query.excludeIds === 'string' ? query.excludeIds : ''\n excludeIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n .forEach((value: string) => excludedIds.add(value))\n if (ctx && query.excludeLinkedPersonId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n withCustomerPersonCompanyLinkScope({ person: query.excludeLinkedPersonId }, decryptionScope),\n 'customers.companies.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['company'] },\n decryptionScope,\n ),\n )\n links.forEach((link) => {\n const companyId = link.company?.id\n if (typeof companyId === 'string' && companyId.length > 0) excludedIds.add(companyId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'companies.list', err })\n }\n }\n if (typeof query.excludeLinkedCompanyId === 'string' && query.excludeLinkedCompanyId.length > 0) {\n excludedIds.add(query.excludeLinkedCompanyId)\n }\n if (ctx && query.excludeLinkedDealId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const links = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n withScopedCustomerDealLinkWhere(query.excludeLinkedDealId, decryptionScope),\n { populate: ['company'] },\n decryptionScope,\n )\n links.forEach((link) => {\n const companyId = link.company?.id\n if (typeof companyId === 'string' && companyId.length > 0) excludedIds.add(companyId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'companies.list', err })\n }\n }\n applyEntityIdExclusion(filters, Array.from(excludedIds))\n const email = typeof query.email === 'string' ? query.email.trim().toLowerCase() : ''\n const emailStartsWith = typeof query.emailStartsWith === 'string' ? query.emailStartsWith.trim().toLowerCase() : ''\n const emailContains = typeof query.emailContains === 'string' ? query.emailContains.trim().toLowerCase() : ''\n if (email) {\n filters.primary_email = { $eq: email }\n } else if (emailStartsWith) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailStartsWith, 'startsWith') }\n } else if (emailContains) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailContains) }\n }\n const hasEmail = parseBooleanToken(query.hasEmail)\n if (!email && !emailStartsWith && !emailContains && hasEmail !== null) {\n filters.primary_email = { $exists: hasEmail }\n }\n const hasPhone = parseBooleanToken(query.hasPhone)\n if (hasPhone !== null) {\n filters.primary_phone = { $exists: hasPhone }\n }\n const hasNextInteraction = parseBooleanToken(query.hasNextInteraction)\n if (hasNextInteraction !== null) {\n filters.next_interaction_at = { $exists: hasNextInteraction }\n }\n const createdRange: Record<string, Date> = {}\n if (query.createdFrom) {\n const from = new Date(query.createdFrom)\n if (!Number.isNaN(from.getTime())) createdRange.$gte = from\n }\n if (query.createdTo) {\n const to = new Date(query.createdTo)\n if (!Number.isNaN(to.getTime())) createdRange.$lte = to\n }\n if (Object.keys(createdRange).length) {\n filters.created_at = createdRange\n }\n if (ctx) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.customers.customer_entity, E.customers.customer_company_profile],\n query,\n em,\n tenantId: ctx.auth?.tenantId ?? null,\n })\n Object.assign(filters, cfFilters)\n } catch (err) {\n logger.warn('custom field filter resolution failed; falling back to base filters', { component: 'companies.list', err })\n }\n }\n if (ctx && advancedFilterTree) {\n const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)\n const matchedIds = await findMatchingEntityIdsWithQueryEngine({\n ctx,\n entityId: E.customers.customer_entity,\n filters: advancedFilters,\n customFieldSources: [\n {\n entityId: E.customers.customer_company_profile,\n table: 'customer_companies',\n alias: 'company_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n })\n applyEntityIdRestriction(filters, matchedIds)\n }\n return filters\n },\n customFieldSources: [\n {\n entityId: E.customers.customer_company_profile,\n table: 'customer_companies',\n alias: 'company_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n transformItem: (item) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const normalized: Record<string, unknown> = { ...record }\n delete normalized.kind\n const cfEntries = extractAllCustomFieldEntries(record)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) {\n delete normalized[key]\n }\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'customers.companies.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const { base, custom } = splitCustomFieldPayload(scoped)\n const parsed = companyCreateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: ({ result }) => ({\n id: result?.entityId ?? result?.id ?? null,\n companyId: result?.companyId ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: 'customers.companies.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const normalized = normalizeCompanyProfilePayload(scoped, translate)\n const { base, custom } = splitCustomFieldPayload(normalized)\n const parsed = companyUpdateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n // Return the freshly-bumped updatedAt so inline-edit detail pages can refresh\n // their optimistic-lock token between sequential saves (avoids a false 409 on\n // the 2nd inline edit now that locking is default-ON). #2055. The factory hands\n // the updated entity here; read defensively in case a `{ result }` wrapper arrives.\n response: (arg: { result?: unknown; updatedAt?: Date | string | null }) => {\n const raw = arg?.updatedAt\n ?? (arg?.result as { updatedAt?: Date | string | null } | null | undefined)?.updatedAt\n ?? null\n return {\n ok: true,\n updatedAt: raw instanceof Date ? raw.toISOString() : (typeof raw === 'string' ? raw : null),\n }\n },\n },\n delete: {\n commandId: 'customers.companies.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) throw new CrudHttpError(400, { error: translate('customers.errors.company_required', 'Company id is required') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n const ids = items\n .map((item: unknown) => (item && typeof item === 'object' && typeof (item as Record<string, unknown>).id === 'string'\n ? (item as Record<string, unknown>).id as string\n : null))\n .filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)\n if (!ids.length) return\n\n const where: Record<string, unknown> = {\n entity: { $in: ids },\n tenantId: ctx.auth?.tenantId ?? null,\n }\n if (ctx.selectedOrganizationId) {\n where.organizationId = ctx.selectedOrganizationId\n }\n\n const profiles = await findWithDecryption(\n ctx.container.resolve('em') as EntityManager,\n CustomerCompanyProfile,\n where as FilterQuery<CustomerCompanyProfile>,\n { populate: ['entity'] },\n {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n },\n )\n\n const profilesByEntityId = new Map<string, CustomerCompanyProfile>()\n for (const profile of profiles) {\n const profileEntity = (profile as { entity?: { id?: unknown } }).entity\n const entityId = typeof profileEntity?.id === 'string' ? profileEntity.id : null\n if (entityId) profilesByEntityId.set(entityId, profile)\n }\n\n payload.items = items.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const profile = typeof record.id === 'string' ? profilesByEntityId.get(record.id) : undefined\n if (!profile) return item\n return {\n ...record,\n legal_name: profile.legalName ?? null,\n brand_name: profile.brandName ?? null,\n domain: profile.domain ?? null,\n website_url: profile.websiteUrl ?? null,\n industry: profile.industry ?? null,\n size_bucket: profile.sizeBucket ?? null,\n annual_revenue: profile.annualRevenue ?? null,\n }\n })\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\nexport const GET = crud.GET\n\nconst companyListItemSchema = z.object({\n id: z.string().uuid(),\n display_name: z.string().optional(),\n description: z.string().nullable().optional(),\n owner_user_id: z.string().uuid().nullable().optional(),\n primary_email: z.string().nullable().optional(),\n primary_phone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycle_stage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n next_interaction_at: z.string().nullable().optional(),\n next_interaction_name: z.string().nullable().optional(),\n next_interaction_ref_id: z.string().nullable().optional(),\n next_interaction_icon: z.string().nullable().optional(),\n next_interaction_color: z.string().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n})\n\nconst companyCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n companyId: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Company',\n pluralName: 'Companies',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(companyListItemSchema),\n create: {\n schema: companyCreateSchema,\n responseSchema: companyCreateResponseSchema,\n description: 'Creates a company record and associated profile data.',\n },\n update: {\n schema: companyUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates company profile fields, tags, or custom attributes.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a company by id. The identifier can be provided via body or query.',\n errors: [\n {\n status: 422,\n description: 'Company has dependent records (people, deals, or direct staff); unlink or reassign before delete.',\n schema: z.object({\n error: z.string(),\n code: z.literal('COMPANY_HAS_DEPENDENTS'),\n }),\n },\n ],\n },\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -23,6 +23,7 @@ import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
|
|
|
23
23
|
import { isUuidListParam, splitIdListParam } from "@open-mercato/shared/lib/crud/ids";
|
|
24
24
|
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
25
25
|
import { consumeAdvancedFilterState, mergeAdvancedFilterTree } from "@open-mercato/shared/lib/crud/advanced-filter-integration";
|
|
26
|
+
import { expandCreatedAtDayRules } from "../../lib/createdAtDayFilter.js";
|
|
26
27
|
import {
|
|
27
28
|
createCustomersCrudOpenApi,
|
|
28
29
|
createPagedListResponseSchema,
|
|
@@ -116,7 +117,7 @@ const crud = makeCrudRoute({
|
|
|
116
117
|
updatedAt: "updated_at"
|
|
117
118
|
},
|
|
118
119
|
buildFilters: async (query, ctx) => {
|
|
119
|
-
const advancedFilterTree = consumeAdvancedFilterState(query);
|
|
120
|
+
const advancedFilterTree = expandCreatedAtDayRules(consumeAdvancedFilterState(query), "UTC");
|
|
120
121
|
const filters = { kind: { $eq: "person" } };
|
|
121
122
|
if (query.id) filters.id = { $eq: query.id };
|
|
122
123
|
if (query.search) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/api/people/route.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n CustomerDealPersonLink,\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../../data/entities'\nimport { E } from '#generated/entities.ids.generated'\nimport { personCreateSchema, personUpdateSchema } from '../../data/validators'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n applyEntityIdExclusion,\n applyEntityIdRestriction,\n findMatchingEntityIdsWithQueryEngine,\n findMatchingEntityIdsBySearchTokensAcrossSources,\n withScopedPayload,\n} from '../utils'\nimport { buildCustomFieldFiltersFromQuery, extractAllCustomFieldEntries, splitCustomFieldPayload } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { isUuidListParam, splitIdListParam } from '@open-mercato/shared/lib/crud/ids'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'\nimport {\n createCustomersCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n withCustomerPersonCompanyLinkScope,\n withScopedCustomerDealLinkWhere,\n} from '../../lib/personCompanyLinkTable'\nimport { normalizeProfilePayload } from './payload'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n email: z.string().optional(),\n emailStartsWith: z.string().optional(),\n emailContains: z.string().optional(),\n status: z.string().optional(),\n lifecycleStage: z.string().optional(),\n source: z.string().optional(),\n hasEmail: z.string().optional(),\n hasPhone: z.string().optional(),\n hasNextInteraction: z.string().optional(),\n createdFrom: z.string().optional(),\n createdTo: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n id: z.string().uuid().optional(),\n tagIds: z\n .string()\n .optional()\n .refine(isUuidListParam, { message: 'tagIds must be a comma-separated list of UUIDs' }),\n tagIdsEmpty: z.string().optional(),\n excludeIds: z.string().optional(),\n excludeLinkedCompanyId: z.string().uuid().optional(),\n excludeLinkedDealId: z.string().uuid().optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerEntity,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.person' },\n indexer: { entityType: E.customers.customer_entity },\n list: {\n schema: listSchema,\n entityId: E.customers.customer_entity,\n fields: [\n 'id',\n 'display_name',\n 'description',\n 'owner_user_id',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_at',\n 'next_interaction_name',\n 'next_interaction_ref_id',\n 'next_interaction_icon',\n 'next_interaction_color',\n 'organization_id',\n 'tenant_id',\n 'kind',\n 'created_at',\n 'updated_at',\n ],\n sortFieldMap: {\n name: 'display_name',\n email: 'primary_email',\n primaryEmail: 'primary_email',\n status: 'status',\n lifecycleStage: 'lifecycle_stage',\n source: 'source',\n nextInteractionAt: 'next_interaction_at',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n buildFilters: async (query, ctx) => {\n const advancedFilterTree = consumeAdvancedFilterState(query)\n const filters: Record<string, unknown> = { kind: { $eq: 'person' } }\n if (query.id) filters.id = { $eq: query.id }\n if (query.search) {\n const matchingIds = ctx\n ? await findMatchingEntityIdsBySearchTokensAcrossSources({\n ctx,\n query: query.search,\n sources: [\n {\n entityType: E.customers.customer_entity,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_name',\n ],\n },\n {\n entityType: E.customers.customer_person_profile,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'first_name',\n 'last_name',\n 'preferred_name',\n 'job_title',\n 'department',\n 'seniority',\n 'timezone',\n 'linked_in_url',\n 'twitter_url',\n ],\n mapToEntityIds: {\n table: 'customer_people',\n targetColumn: 'entity_id',\n },\n },\n ],\n })\n : null\n if (matchingIds !== null && matchingIds.length > 0) {\n applyEntityIdRestriction(filters, matchingIds)\n } else {\n const searchPattern = buildIlikeTerm(query.search)\n filters.$or = [\n { display_name: { $ilike: searchPattern } },\n { primary_email: { $ilike: searchPattern } },\n { primary_phone: { $ilike: searchPattern } },\n { description: { $ilike: searchPattern } },\n { next_interaction_name: { $ilike: searchPattern } },\n ]\n }\n }\n const email = typeof query.email === 'string' ? query.email.trim().toLowerCase() : ''\n const emailStartsWith = typeof query.emailStartsWith === 'string' ? query.emailStartsWith.trim().toLowerCase() : ''\n const emailContains = typeof query.emailContains === 'string' ? query.emailContains.trim().toLowerCase() : ''\n if (email) {\n filters.primary_email = { $eq: email }\n } else if (emailStartsWith) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailStartsWith, 'startsWith') }\n } else if (emailContains) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailContains) }\n }\n if (query.status) {\n filters.status = { $eq: query.status }\n }\n if (query.lifecycleStage) {\n filters.lifecycle_stage = { $eq: query.lifecycleStage }\n }\n if (query.source) {\n filters.source = { $eq: query.source }\n }\n const tagIds = splitIdListParam(query.tagIds)\n const tagIdsEmpty = parseBooleanToken(query.tagIdsEmpty) === true\n if (tagIdsEmpty) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length > 0) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n }\n const excludedIds = new Set<string>()\n const excludeIdsRaw = typeof query.excludeIds === 'string' ? query.excludeIds : ''\n excludeIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n .forEach((value: string) => excludedIds.add(value))\n if (ctx && query.excludeLinkedCompanyId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n withCustomerPersonCompanyLinkScope({ company: query.excludeLinkedCompanyId }, decryptionScope),\n 'customers.people.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['person'] },\n decryptionScope,\n ),\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'people.list', err })\n }\n }\n if (ctx && query.excludeLinkedDealId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const links = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n withScopedCustomerDealLinkWhere(query.excludeLinkedDealId, decryptionScope),\n { populate: ['person'] },\n decryptionScope,\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'people.list', err })\n }\n }\n applyEntityIdExclusion(filters, Array.from(excludedIds))\n const hasEmail = parseBooleanToken(query.hasEmail)\n if (!email && !emailStartsWith && !emailContains && hasEmail !== null) {\n filters.primary_email = { $exists: hasEmail }\n }\n const hasPhone = parseBooleanToken(query.hasPhone)\n if (hasPhone !== null) {\n filters.primary_phone = { $exists: hasPhone }\n }\n const hasNextInteraction = parseBooleanToken(query.hasNextInteraction)\n if (hasNextInteraction !== null) {\n filters.next_interaction_at = { $exists: hasNextInteraction }\n }\n const createdRange: Record<string, Date> = {}\n if (query.createdFrom) {\n const from = new Date(query.createdFrom)\n if (!Number.isNaN(from.getTime())) createdRange.$gte = from\n }\n if (query.createdTo) {\n const to = new Date(query.createdTo)\n if (!Number.isNaN(to.getTime())) createdRange.$lte = to\n }\n if (Object.keys(createdRange).length) {\n filters.created_at = createdRange\n }\n if (ctx) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.customers.customer_entity, E.customers.customer_person_profile],\n query,\n em,\n tenantId: ctx.auth?.tenantId ?? null,\n })\n Object.assign(filters, cfFilters)\n } catch (err) {\n logger.warn('custom field filter resolution failed; falling back to base filters', { component: 'people.list', err })\n }\n }\n if (ctx && advancedFilterTree) {\n const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)\n const matchedIds = await findMatchingEntityIdsWithQueryEngine({\n ctx,\n entityId: E.customers.customer_entity,\n filters: advancedFilters,\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n })\n applyEntityIdRestriction(filters, matchedIds)\n }\n return filters\n },\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n transformItem: (item) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const normalized: Record<string, unknown> = { ...record }\n delete normalized.kind\n const cfEntries = extractAllCustomFieldEntries(record)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) {\n delete normalized[key]\n }\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'customers.people.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const { base, custom } = splitCustomFieldPayload(scoped)\n const parsed = personCreateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: ({ result }) => ({\n id: result?.entityId ?? result?.id ?? null,\n personId: result?.personId ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: 'customers.people.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const normalized = normalizeProfilePayload(scoped, translate)\n const { base, custom } = splitCustomFieldPayload(normalized)\n const parsed = personUpdateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n // Return the freshly-bumped updatedAt so inline-edit detail pages can refresh\n // their optimistic-lock token between sequential saves (#2055).\n response: (arg: { result?: unknown; updatedAt?: Date | string | null }) => {\n const raw = arg?.updatedAt\n ?? (arg?.result as { updatedAt?: Date | string | null } | null | undefined)?.updatedAt\n ?? null\n return {\n ok: true,\n updatedAt: raw instanceof Date ? raw.toISOString() : (typeof raw === 'string' ? raw : null),\n }\n },\n },\n delete: {\n commandId: 'customers.people.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) throw new CrudHttpError(400, { error: translate('customers.errors.person_required', 'Person id is required') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n const ids = items\n .map((item: unknown) => (\n item && typeof item === 'object' && typeof (item as Record<string, unknown>).id === 'string'\n ? (item as Record<string, unknown>).id as string\n : null\n ))\n .filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)\n if (!ids.length) return\n\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const profileWhere: Record<string, unknown> = {\n entity: { $in: ids },\n tenantId: ctx.auth?.tenantId ?? null,\n }\n if (ctx.selectedOrganizationId) {\n profileWhere.organizationId = ctx.selectedOrganizationId\n }\n\n const [entities, profiles] = await Promise.all([\n findWithDecryption(\n em,\n CustomerEntity,\n {\n id: { $in: ids },\n deletedAt: null,\n kind: 'person',\n } as FilterQuery<CustomerEntity>,\n undefined,\n decryptionScope,\n ),\n findWithDecryption(\n em,\n CustomerPersonProfile,\n profileWhere as FilterQuery<CustomerPersonProfile>,\n { populate: ['entity', 'company'] },\n decryptionScope,\n ),\n ])\n\n const entitiesById = new Map<string, CustomerEntity>()\n for (const entity of entities) {\n entitiesById.set(entity.id, entity)\n }\n\n const profilesByEntityId = new Map<string, CustomerPersonProfile>()\n for (const profile of profiles) {\n const profileEntity = (profile as { entity?: { id?: unknown } }).entity\n const entityId = typeof profileEntity?.id === 'string' ? profileEntity.id : null\n if (entityId) profilesByEntityId.set(entityId, profile)\n }\n\n payload.items = items.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const entity = typeof record.id === 'string' ? entitiesById.get(record.id) : undefined\n const profile = typeof record.id === 'string' ? profilesByEntityId.get(record.id) : undefined\n if (!entity && !profile) return item\n return {\n ...record,\n display_name: entity?.displayName ?? record.display_name ?? null,\n description: entity?.description ?? record.description ?? null,\n owner_user_id: entity?.ownerUserId ?? record.owner_user_id ?? null,\n primary_email: entity?.primaryEmail ?? record.primary_email ?? null,\n primary_phone: entity?.primaryPhone ?? record.primary_phone ?? null,\n status: entity?.status ?? record.status ?? null,\n lifecycle_stage: entity?.lifecycleStage ?? record.lifecycle_stage ?? null,\n source: entity?.source ?? record.source ?? null,\n next_interaction_at: entity?.nextInteractionAt ? entity.nextInteractionAt.toISOString() : record.next_interaction_at ?? null,\n next_interaction_name: entity?.nextInteractionName ?? record.next_interaction_name ?? null,\n next_interaction_ref_id: entity?.nextInteractionRefId ?? record.next_interaction_ref_id ?? null,\n next_interaction_icon: entity?.nextInteractionIcon ?? record.next_interaction_icon ?? null,\n next_interaction_color: entity?.nextInteractionColor ?? record.next_interaction_color ?? null,\n first_name: profile?.firstName ?? null,\n last_name: profile?.lastName ?? null,\n preferred_name: profile?.preferredName ?? null,\n job_title: profile?.jobTitle ?? null,\n department: profile?.department ?? null,\n seniority: profile?.seniority ?? null,\n timezone: profile?.timezone ?? null,\n linked_in_url: profile?.linkedInUrl ?? null,\n twitter_url: profile?.twitterUrl ?? null,\n company_entity_id:\n profile?.company && typeof profile.company === 'object'\n ? profile.company.id\n : profile?.company ?? null,\n }\n })\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\nexport const GET = crud.GET\n\nconst personListItemSchema = z.object({\n id: z.string().uuid(),\n display_name: z.string().optional(),\n description: z.string().nullable().optional(),\n owner_user_id: z.string().uuid().nullable().optional(),\n primary_email: z.string().nullable().optional(),\n primary_phone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycle_stage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n next_interaction_at: z.string().nullable().optional(),\n next_interaction_name: z.string().nullable().optional(),\n next_interaction_ref_id: z.string().nullable().optional(),\n next_interaction_icon: z.string().nullable().optional(),\n next_interaction_color: z.string().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n})\n\nconst personCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n personId: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Person',\n pluralName: 'People',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(personListItemSchema),\n create: {\n schema: personCreateSchema,\n responseSchema: personCreateResponseSchema,\n description: 'Creates a person contact using scoped organization and tenant identifiers.',\n },\n update: {\n schema: personUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates contact details or custom fields for a person.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a person by id. Request body or query may provide the identifier.',\n errors: [\n {\n status: 422,\n description: 'Person has dependent records (e.g. linked deals); unlink or reassign before delete.',\n schema: z.object({\n error: z.string(),\n code: z.literal('PERSON_HAS_DEPENDENTS'),\n }),\n },\n ],\n },\n})\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n CustomerDealPersonLink,\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../../data/entities'\nimport { E } from '#generated/entities.ids.generated'\nimport { personCreateSchema, personUpdateSchema } from '../../data/validators'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n applyEntityIdExclusion,\n applyEntityIdRestriction,\n findMatchingEntityIdsWithQueryEngine,\n findMatchingEntityIdsBySearchTokensAcrossSources,\n withScopedPayload,\n} from '../utils'\nimport { buildCustomFieldFiltersFromQuery, extractAllCustomFieldEntries, splitCustomFieldPayload } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { isUuidListParam, splitIdListParam } from '@open-mercato/shared/lib/crud/ids'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'\nimport { expandCreatedAtDayRules } from '../../lib/createdAtDayFilter'\nimport {\n createCustomersCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n withCustomerPersonCompanyLinkScope,\n withScopedCustomerDealLinkWhere,\n} from '../../lib/personCompanyLinkTable'\nimport { normalizeProfilePayload } from './payload'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n email: z.string().optional(),\n emailStartsWith: z.string().optional(),\n emailContains: z.string().optional(),\n status: z.string().optional(),\n lifecycleStage: z.string().optional(),\n source: z.string().optional(),\n hasEmail: z.string().optional(),\n hasPhone: z.string().optional(),\n hasNextInteraction: z.string().optional(),\n createdFrom: z.string().optional(),\n createdTo: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n id: z.string().uuid().optional(),\n tagIds: z\n .string()\n .optional()\n .refine(isUuidListParam, { message: 'tagIds must be a comma-separated list of UUIDs' }),\n tagIdsEmpty: z.string().optional(),\n excludeIds: z.string().optional(),\n excludeLinkedCompanyId: z.string().uuid().optional(),\n excludeLinkedDealId: z.string().uuid().optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerEntity,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.person' },\n indexer: { entityType: E.customers.customer_entity },\n list: {\n schema: listSchema,\n entityId: E.customers.customer_entity,\n fields: [\n 'id',\n 'display_name',\n 'description',\n 'owner_user_id',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_at',\n 'next_interaction_name',\n 'next_interaction_ref_id',\n 'next_interaction_icon',\n 'next_interaction_color',\n 'organization_id',\n 'tenant_id',\n 'kind',\n 'created_at',\n 'updated_at',\n ],\n sortFieldMap: {\n name: 'display_name',\n email: 'primary_email',\n primaryEmail: 'primary_email',\n status: 'status',\n lifecycleStage: 'lifecycle_stage',\n source: 'source',\n nextInteractionAt: 'next_interaction_at',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n buildFilters: async (query, ctx) => {\n const advancedFilterTree = expandCreatedAtDayRules(consumeAdvancedFilterState(query), 'UTC')\n const filters: Record<string, unknown> = { kind: { $eq: 'person' } }\n if (query.id) filters.id = { $eq: query.id }\n if (query.search) {\n const matchingIds = ctx\n ? await findMatchingEntityIdsBySearchTokensAcrossSources({\n ctx,\n query: query.search,\n sources: [\n {\n entityType: E.customers.customer_entity,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_name',\n ],\n },\n {\n entityType: E.customers.customer_person_profile,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'first_name',\n 'last_name',\n 'preferred_name',\n 'job_title',\n 'department',\n 'seniority',\n 'timezone',\n 'linked_in_url',\n 'twitter_url',\n ],\n mapToEntityIds: {\n table: 'customer_people',\n targetColumn: 'entity_id',\n },\n },\n ],\n })\n : null\n if (matchingIds !== null && matchingIds.length > 0) {\n applyEntityIdRestriction(filters, matchingIds)\n } else {\n const searchPattern = buildIlikeTerm(query.search)\n filters.$or = [\n { display_name: { $ilike: searchPattern } },\n { primary_email: { $ilike: searchPattern } },\n { primary_phone: { $ilike: searchPattern } },\n { description: { $ilike: searchPattern } },\n { next_interaction_name: { $ilike: searchPattern } },\n ]\n }\n }\n const email = typeof query.email === 'string' ? query.email.trim().toLowerCase() : ''\n const emailStartsWith = typeof query.emailStartsWith === 'string' ? query.emailStartsWith.trim().toLowerCase() : ''\n const emailContains = typeof query.emailContains === 'string' ? query.emailContains.trim().toLowerCase() : ''\n if (email) {\n filters.primary_email = { $eq: email }\n } else if (emailStartsWith) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailStartsWith, 'startsWith') }\n } else if (emailContains) {\n filters.primary_email = { $ilike: buildIlikeTerm(emailContains) }\n }\n if (query.status) {\n filters.status = { $eq: query.status }\n }\n if (query.lifecycleStage) {\n filters.lifecycle_stage = { $eq: query.lifecycleStage }\n }\n if (query.source) {\n filters.source = { $eq: query.source }\n }\n const tagIds = splitIdListParam(query.tagIds)\n const tagIdsEmpty = parseBooleanToken(query.tagIdsEmpty) === true\n if (tagIdsEmpty) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length > 0) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n }\n const excludedIds = new Set<string>()\n const excludeIdsRaw = typeof query.excludeIds === 'string' ? query.excludeIds : ''\n excludeIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n .forEach((value: string) => excludedIds.add(value))\n if (ctx && query.excludeLinkedCompanyId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n withCustomerPersonCompanyLinkScope({ company: query.excludeLinkedCompanyId }, decryptionScope),\n 'customers.people.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['person'] },\n decryptionScope,\n ),\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'people.list', err })\n }\n }\n if (ctx && query.excludeLinkedDealId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const links = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n withScopedCustomerDealLinkWhere(query.excludeLinkedDealId, decryptionScope),\n { populate: ['person'] },\n decryptionScope,\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n logger.warn('exclusion lookup failed; falling back to base result set', { component: 'people.list', err })\n }\n }\n applyEntityIdExclusion(filters, Array.from(excludedIds))\n const hasEmail = parseBooleanToken(query.hasEmail)\n if (!email && !emailStartsWith && !emailContains && hasEmail !== null) {\n filters.primary_email = { $exists: hasEmail }\n }\n const hasPhone = parseBooleanToken(query.hasPhone)\n if (hasPhone !== null) {\n filters.primary_phone = { $exists: hasPhone }\n }\n const hasNextInteraction = parseBooleanToken(query.hasNextInteraction)\n if (hasNextInteraction !== null) {\n filters.next_interaction_at = { $exists: hasNextInteraction }\n }\n const createdRange: Record<string, Date> = {}\n if (query.createdFrom) {\n const from = new Date(query.createdFrom)\n if (!Number.isNaN(from.getTime())) createdRange.$gte = from\n }\n if (query.createdTo) {\n const to = new Date(query.createdTo)\n if (!Number.isNaN(to.getTime())) createdRange.$lte = to\n }\n if (Object.keys(createdRange).length) {\n filters.created_at = createdRange\n }\n if (ctx) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.customers.customer_entity, E.customers.customer_person_profile],\n query,\n em,\n tenantId: ctx.auth?.tenantId ?? null,\n })\n Object.assign(filters, cfFilters)\n } catch (err) {\n logger.warn('custom field filter resolution failed; falling back to base filters', { component: 'people.list', err })\n }\n }\n if (ctx && advancedFilterTree) {\n const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)\n const matchedIds = await findMatchingEntityIdsWithQueryEngine({\n ctx,\n entityId: E.customers.customer_entity,\n filters: advancedFilters,\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n })\n applyEntityIdRestriction(filters, matchedIds)\n }\n return filters\n },\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n transformItem: (item) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const normalized: Record<string, unknown> = { ...record }\n delete normalized.kind\n const cfEntries = extractAllCustomFieldEntries(record)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) {\n delete normalized[key]\n }\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'customers.people.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const { base, custom } = splitCustomFieldPayload(scoped)\n const parsed = personCreateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: ({ result }) => ({\n id: result?.entityId ?? result?.id ?? null,\n personId: result?.personId ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: 'customers.people.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const normalized = normalizeProfilePayload(scoped, translate)\n const { base, custom } = splitCustomFieldPayload(normalized)\n const parsed = personUpdateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n // Return the freshly-bumped updatedAt so inline-edit detail pages can refresh\n // their optimistic-lock token between sequential saves (#2055).\n response: (arg: { result?: unknown; updatedAt?: Date | string | null }) => {\n const raw = arg?.updatedAt\n ?? (arg?.result as { updatedAt?: Date | string | null } | null | undefined)?.updatedAt\n ?? null\n return {\n ok: true,\n updatedAt: raw instanceof Date ? raw.toISOString() : (typeof raw === 'string' ? raw : null),\n }\n },\n },\n delete: {\n commandId: 'customers.people.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) throw new CrudHttpError(400, { error: translate('customers.errors.person_required', 'Person id is required') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n const ids = items\n .map((item: unknown) => (\n item && typeof item === 'object' && typeof (item as Record<string, unknown>).id === 'string'\n ? (item as Record<string, unknown>).id as string\n : null\n ))\n .filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)\n if (!ids.length) return\n\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const profileWhere: Record<string, unknown> = {\n entity: { $in: ids },\n tenantId: ctx.auth?.tenantId ?? null,\n }\n if (ctx.selectedOrganizationId) {\n profileWhere.organizationId = ctx.selectedOrganizationId\n }\n\n const [entities, profiles] = await Promise.all([\n findWithDecryption(\n em,\n CustomerEntity,\n {\n id: { $in: ids },\n deletedAt: null,\n kind: 'person',\n } as FilterQuery<CustomerEntity>,\n undefined,\n decryptionScope,\n ),\n findWithDecryption(\n em,\n CustomerPersonProfile,\n profileWhere as FilterQuery<CustomerPersonProfile>,\n { populate: ['entity', 'company'] },\n decryptionScope,\n ),\n ])\n\n const entitiesById = new Map<string, CustomerEntity>()\n for (const entity of entities) {\n entitiesById.set(entity.id, entity)\n }\n\n const profilesByEntityId = new Map<string, CustomerPersonProfile>()\n for (const profile of profiles) {\n const profileEntity = (profile as { entity?: { id?: unknown } }).entity\n const entityId = typeof profileEntity?.id === 'string' ? profileEntity.id : null\n if (entityId) profilesByEntityId.set(entityId, profile)\n }\n\n payload.items = items.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const entity = typeof record.id === 'string' ? entitiesById.get(record.id) : undefined\n const profile = typeof record.id === 'string' ? profilesByEntityId.get(record.id) : undefined\n if (!entity && !profile) return item\n return {\n ...record,\n display_name: entity?.displayName ?? record.display_name ?? null,\n description: entity?.description ?? record.description ?? null,\n owner_user_id: entity?.ownerUserId ?? record.owner_user_id ?? null,\n primary_email: entity?.primaryEmail ?? record.primary_email ?? null,\n primary_phone: entity?.primaryPhone ?? record.primary_phone ?? null,\n status: entity?.status ?? record.status ?? null,\n lifecycle_stage: entity?.lifecycleStage ?? record.lifecycle_stage ?? null,\n source: entity?.source ?? record.source ?? null,\n next_interaction_at: entity?.nextInteractionAt ? entity.nextInteractionAt.toISOString() : record.next_interaction_at ?? null,\n next_interaction_name: entity?.nextInteractionName ?? record.next_interaction_name ?? null,\n next_interaction_ref_id: entity?.nextInteractionRefId ?? record.next_interaction_ref_id ?? null,\n next_interaction_icon: entity?.nextInteractionIcon ?? record.next_interaction_icon ?? null,\n next_interaction_color: entity?.nextInteractionColor ?? record.next_interaction_color ?? null,\n first_name: profile?.firstName ?? null,\n last_name: profile?.lastName ?? null,\n preferred_name: profile?.preferredName ?? null,\n job_title: profile?.jobTitle ?? null,\n department: profile?.department ?? null,\n seniority: profile?.seniority ?? null,\n timezone: profile?.timezone ?? null,\n linked_in_url: profile?.linkedInUrl ?? null,\n twitter_url: profile?.twitterUrl ?? null,\n company_entity_id:\n profile?.company && typeof profile.company === 'object'\n ? profile.company.id\n : profile?.company ?? null,\n }\n })\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\nexport const GET = crud.GET\n\nconst personListItemSchema = z.object({\n id: z.string().uuid(),\n display_name: z.string().optional(),\n description: z.string().nullable().optional(),\n owner_user_id: z.string().uuid().nullable().optional(),\n primary_email: z.string().nullable().optional(),\n primary_phone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycle_stage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n next_interaction_at: z.string().nullable().optional(),\n next_interaction_name: z.string().nullable().optional(),\n next_interaction_ref_id: z.string().nullable().optional(),\n next_interaction_icon: z.string().nullable().optional(),\n next_interaction_color: z.string().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n})\n\nconst personCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n personId: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Person',\n pluralName: 'People',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(personListItemSchema),\n create: {\n schema: personCreateSchema,\n responseSchema: personCreateResponseSchema,\n description: 'Creates a person contact using scoped organization and tenant identifiers.',\n },\n update: {\n schema: personUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates contact details or custom fields for a person.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a person by id. Request body or query may provide the identifier.',\n errors: [\n {\n status: 422,\n description: 'Person has dependent records (e.g. linked deals); unlink or reassign before delete.',\n schema: z.object({\n error: z.string(),\n code: z.literal('PERSON_HAS_DEPENDENTS'),\n }),\n },\n ],\n },\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|