@open-mercato/core 0.6.6-develop.6345.2.b236ea3d4b → 0.6.6-develop.6351.1.c140d703c9
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/entities/api/definitions.batch.js +68 -21
- package/dist/modules/entities/api/definitions.batch.js.map +2 -2
- package/dist/modules/entities/api/definitions.js +57 -20
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/api/definitions.restore.js +5 -3
- package/dist/modules/entities/api/definitions.restore.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js +21 -10
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
- package/dist/modules/entities/lib/definition-scope.js +102 -0
- package/dist/modules/entities/lib/definition-scope.js.map +7 -0
- package/package.json +7 -7
- package/src/modules/entities/api/definitions.batch.ts +69 -20
- package/src/modules/entities/api/definitions.restore.ts +5 -3
- package/src/modules/entities/api/definitions.ts +65 -21
- package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +30 -13
- package/src/modules/entities/lib/definition-scope.ts +172 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/entities/api/definitions.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CustomEntity, CustomFieldDef } from '@open-mercato/core/modules/entities/data/entities'\nimport { upsertCustomFieldDefSchema, fieldsetCodeRegex } from '@open-mercato/core/modules/entities/data/validators'\nimport {\n createDefinitionsCacheKey,\n createDefinitionsCacheTags,\n invalidateDefinitionsCache,\n ENTITY_DEFINITIONS_CACHE_TTL_MS,\n} from './definitions.cache'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { filterSelectableSystemEntityIds, isSystemEntitySelectable } from '@open-mercato/shared/lib/entities/system-entities'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { loadEntityFieldsetConfigs, CustomFieldsetDefinition } from '../lib/fieldsets'\nimport { installCustomEntitiesFromModules } from '../lib/install-from-ce'\nimport { normalizeCustomFieldOptions } from '@open-mercato/shared/modules/entities/options'\nimport { CURRENCY_OPTIONS_URL } from '@open-mercato/shared/modules/entities/kinds'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n beginEntitiesMutationGuard,\n FIELD_DEFINITION_RESOURCE_KIND,\n} from './definitions.mutation-guard'\n\n/**\n * Validate defaultValue against the field kind. Returns an error message string\n * if invalid, or null if valid. For dictionary and currency kinds, queries the\n * database to verify the token exists.\n */\nasync function validateDefaultValueByKind(\n value: unknown,\n kind: string,\n cfg: Record<string, unknown>,\n em: EntityManager,\n tenantContext: { tenantId: string | null; organizationId: string | null },\n): Promise<string | null> {\n switch (kind) {\n case 'boolean':\n if (typeof value !== 'boolean') return 'defaultValue for boolean fields must be true or false'\n return null\n case 'integer':\n if (typeof value !== 'number' || !Number.isInteger(value))\n return 'defaultValue for integer fields must be a whole number'\n return null\n case 'float':\n if (typeof value !== 'number' || !isFinite(value))\n return 'defaultValue for float fields must be a finite number'\n return null\n case 'text':\n case 'multiline':\n case 'date':\n case 'datetime':\n if (typeof value !== 'string')\n return `defaultValue for ${kind} fields must be a string`\n return null\n case 'dictionary': {\n if (typeof value !== 'string')\n return 'defaultValue for dictionary fields must be a string'\n const dictionaryId = typeof cfg.dictionaryId === 'string' ? cfg.dictionaryId.trim() : ''\n if (dictionaryId) {\n try {\n const { DictionaryEntry } = await import('@open-mercato/core/modules/dictionaries/data/entities')\n const entry = await em.findOne(DictionaryEntry, {\n dictionary: dictionaryId,\n value: value,\n ...(tenantContext.organizationId ? { organizationId: tenantContext.organizationId } : {}),\n ...(tenantContext.tenantId ? { tenantId: tenantContext.tenantId } : {}),\n })\n if (!entry) return `defaultValue \"${value}\" does not match any entry in the configured dictionary`\n } catch (err) {\n // If the dictionaries module is not available, skip entry validation\n console.debug('[entities.definitions] dictionary validation skipped \u2014 module not available', err)\n }\n }\n return null\n }\n case 'currency': {\n if (typeof value !== 'string')\n return 'defaultValue for currency fields must be a string'\n try {\n const { Currency } = await import('@open-mercato/core/modules/currencies/data/entities')\n const where: Record<string, string> = { code: value as string }\n if (tenantContext.tenantId) where.tenantId = tenantContext.tenantId\n if (tenantContext.organizationId) where.organizationId = tenantContext.organizationId\n const currency = await em.findOne(Currency, where)\n if (!currency) return `defaultValue \"${value}\" does not match any available currency`\n } catch (err) {\n // If the currencies module is not available, skip currency validation\n console.debug('[entities.definitions] currency validation skipped \u2014 module not available', err)\n }\n return null\n }\n case 'select': {\n if (typeof value !== 'string' && typeof value !== 'number')\n return 'defaultValue for select fields must be a string or number'\n const options = normalizeCustomFieldOptions(\n Array.isArray(cfg.options) ? cfg.options : [],\n )\n if (options.length > 0) {\n const match = options.some(\n (o) => o.value === value || String(o.value) === String(value),\n )\n if (!match) return 'defaultValue does not match any of the configured options'\n }\n return null\n }\n case 'relation':\n case 'attachment':\n return `defaultValue is not supported for ${kind} fields`\n default:\n return null\n }\n}\n\n/**\n * Normalize defaultValue to the canonical storage shape for the given kind.\n */\nfunction normalizeDefaultValueByKind(value: unknown, kind: string): unknown {\n switch (kind) {\n case 'boolean':\n return value === true\n case 'integer':\n return Math.round(Number(value))\n case 'float':\n return Number(value)\n default:\n return value\n }\n}\n\nexport const metadata = {\n // Reading definitions is needed by record forms; keep it auth-protected but accessible to all authenticated users\n GET: { requireAuth: true },\n // Mutations remain admin-only\n POST: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n}\n\nfunction parseEntityIds(url: URL): string[] {\n const direct = url.searchParams.getAll('entityId').filter((id) => typeof id === 'string' && id.trim().length > 0)\n const combined = url.searchParams.get('entityIds')\n if (combined) {\n combined\n .split(',')\n .map((id) => id.trim())\n .filter((id) => id.length > 0)\n .forEach((id) => direct.push(id))\n }\n const unique: string[] = []\n const seen = new Set<string>()\n for (const id of direct) {\n if (seen.has(id)) continue\n seen.add(id)\n unique.push(id)\n }\n return unique\n}\n\nasync function resolveEntityDefaultEditor(em: any, entityId: string, tenantId: string | null | undefined): Promise<string | undefined> {\n try {\n const ent = await em.findOne(CustomEntity, {\n entityId,\n $and: [\n { $or: [ { tenantId: tenantId ?? undefined as any }, { tenantId: null } ] },\n ],\n } as any)\n if (ent && typeof (ent as any).defaultEditor === 'string') return (ent as any).defaultEditor\n } catch {}\n return undefined\n}\n\nfunction normalizeFieldGroup(raw: unknown): { code: string; title?: string; hint?: string } | undefined {\n if (!raw) return undefined\n if (typeof raw === 'string') {\n const code = raw.trim()\n return code ? { code } : undefined\n }\n if (typeof raw !== 'object') return undefined\n const entry = raw as Record<string, unknown>\n const code = typeof entry.code === 'string' ? entry.code.trim() : ''\n if (!code) return undefined\n const group: { code: string; title?: string; hint?: string } = { code }\n if (typeof entry.title === 'string' && entry.title.trim()) group.title = entry.title.trim()\n if (typeof entry.hint === 'string' && entry.hint.trim()) group.hint = entry.hint.trim()\n return group\n}\n\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const requestedEntityIds = parseEntityIds(url)\n if (!requestedEntityIds.length) {\n return NextResponse.json({ error: 'entityId is required' }, { status: 400 })\n }\n const requestedFieldset = url.searchParams.get('fieldset')\n const fieldsetFilter = requestedFieldset && requestedFieldset.trim().length ? requestedFieldset.trim() : null\n\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const entityIds = filterSelectableSystemEntityIds(requestedEntityIds)\n if (!entityIds.length) {\n return NextResponse.json({ items: [] })\n }\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const tenantId = scope.tenantId ?? auth.tenantId ?? null\n if (!tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const organizationId = scope.selectedId ?? auth.orgId ?? null\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n\n let canManageDefinitions = false\n if (typeof auth.sub === 'string' && auth.sub.length > 0) {\n try {\n const rbac = resolve('rbacService') as RbacService\n canManageDefinitions = await rbac.userHasAllFeatures(auth.sub, ['entities.definitions.manage'], {\n tenantId,\n organizationId,\n })\n } catch {\n // RBAC service unavailable \u2014 fall back to read-only (no definition sync)\n }\n }\n\n if (canManageDefinitions) {\n try {\n await installCustomEntitiesFromModules(em, cache, {\n tenantIds: [tenantId],\n entityIds,\n includeGlobal: true,\n createOnly: true,\n })\n } catch (err) {\n console.warn('[entities.definitions] Failed to synchronize module-backed definitions', {\n tenantId,\n entityIds,\n err,\n })\n }\n }\n\n let cacheKey: string | null = null\n if (cache && !fieldsetFilter) {\n cacheKey = createDefinitionsCacheKey({\n tenantId,\n organizationId,\n entityIds,\n })\n try {\n const cached = await cache.get(cacheKey)\n if (cached) {\n return NextResponse.json(cached)\n }\n } catch (err) {\n console.warn('[entities.definitions.cache] Failed to read cache', err)\n }\n }\n\n const fieldsetConfigs = await loadEntityFieldsetConfigs(em, {\n entityIds,\n tenantId,\n organizationId,\n mode: 'public',\n })\n\n // Tenant-only scoping: allow global (null) or exact tenant match; do not scope by organization here\n const whereActive = {\n entityId: { $in: entityIds as any },\n deletedAt: null,\n $and: [\n { $or: [ { tenantId: tenantId ?? undefined as any }, { tenantId: null } ] },\n ],\n } as any\n const defs = await em.find(CustomFieldDef, whereActive as any)\n const tombstones = await em.find(CustomFieldDef, {\n entityId: { $in: entityIds as any },\n deletedAt: { $ne: null } as any,\n $and: [\n { $or: [ { tenantId: tenantId ?? undefined as any }, { tenantId: null } ] },\n ],\n } as any)\n\n const tombstonedByEntity = new Map<string, Set<string>>()\n for (const entry of tombstones as any[]) {\n const eid = String(entry.entityId)\n if (!tombstonedByEntity.has(eid)) tombstonedByEntity.set(eid, new Set())\n tombstonedByEntity.get(eid)!.add(entry.key)\n }\n\n const scopeScore = (x: any) => (x.tenantId ? 2 : 0) + (x.organizationId ? 1 : 0)\n\n const definitionsByEntity = new Map<string, any[]>()\n for (const d of defs) {\n const eid = String(d.entityId)\n if (!definitionsByEntity.has(eid)) definitionsByEntity.set(eid, [])\n definitionsByEntity.get(eid)!.push(d)\n }\n\n const entityDefaultEditors = new Map<string, string | undefined>()\n for (const entityId of entityIds) {\n const editor = await resolveEntityDefaultEditor(em, entityId, tenantId ?? null)\n entityDefaultEditors.set(entityId, editor)\n }\n\n const items: any[] = []\n\n const entityOrder = new Map<string, number>()\n entityIds.forEach((id, idx) => entityOrder.set(id, idx))\n\n for (const entityId of entityIds) {\n const defsForEntity = definitionsByEntity.get(entityId) ?? []\n if (!defsForEntity.length) continue\n const tombstonedKeys = tombstonedByEntity.get(entityId) ?? new Set<string>()\n const byKey = new Map<string, any>()\n for (const d of defsForEntity) {\n const existing = byKey.get(d.key)\n if (!existing) { byKey.set(d.key, d); continue }\n const sNew = scopeScore(d)\n const sOld = scopeScore(existing)\n if (sNew > sOld) { byKey.set(d.key, d); continue }\n if (sNew < sOld) continue\n const tNew = (d.updatedAt instanceof Date) ? d.updatedAt.getTime() : new Date(d.updatedAt).getTime()\n const tOld = (existing.updatedAt instanceof Date) ? existing.updatedAt.getTime() : new Date(existing.updatedAt).getTime()\n if (tNew >= tOld) byKey.set(d.key, d)\n }\n\n const defaultEditor = entityDefaultEditors.get(entityId)\n const winning = Array.from(byKey.values()).filter((d: any) => (d.isActive !== false) && !tombstonedKeys.has(d.key))\n winning.sort((a: any, b: any) => ((a.configJson?.priority ?? 0) - (b.configJson?.priority ?? 0)))\n\n for (const d of winning) {\n const rawFieldset = typeof d.configJson?.fieldset === 'string' ? d.configJson.fieldset.trim() : ''\n const normalizedFieldset = rawFieldset.length > 0 ? rawFieldset : undefined\n const normalizedFieldsets = Array.isArray(d.configJson?.fieldsets)\n ? d.configJson.fieldsets\n .filter((entry: unknown): entry is string => typeof entry === 'string')\n .map((entry: string) => entry.trim())\n .filter((entry: string) => entry.length > 0)\n : []\n const effectiveFieldsets = normalizedFieldsets.length > 0\n ? normalizedFieldsets\n : (normalizedFieldset ? [normalizedFieldset] : [])\n if (fieldsetFilter && !effectiveFieldsets.includes(fieldsetFilter)) continue\n const groupInfo = normalizeFieldGroup(d.configJson?.group)\n const keyLower = String(d.key).toLowerCase()\n const candidateBase = {\n key: d.key,\n kind: d.kind,\n label: d.configJson?.label || d.key,\n description: d.configJson?.description || undefined,\n multi: Boolean(d.configJson?.multi),\n options: (() => {\n if (d.kind === 'currency') return undefined\n const normalizedOptions = normalizeCustomFieldOptions(d.configJson?.options)\n return normalizedOptions.length ? normalizedOptions : undefined\n })(),\n optionsUrl: (() => {\n if (d.kind === 'currency') return CURRENCY_OPTIONS_URL\n const dictionaryId = typeof d.configJson?.dictionaryId === 'string' ? d.configJson.dictionaryId : undefined\n if (dictionaryId) return `/api/dictionaries/${dictionaryId}/entries`\n return typeof d.configJson?.optionsUrl === 'string' ? d.configJson.optionsUrl : undefined\n })(),\n filterable: Boolean(d.configJson?.filterable),\n formEditable: d.configJson?.formEditable !== undefined ? Boolean(d.configJson.formEditable) : true,\n listVisible: d.configJson?.listVisible !== undefined ? Boolean(d.configJson.listVisible) : true,\n editor: typeof d.configJson?.editor === 'string'\n ? d.configJson.editor\n : (d.kind === 'multiline' ? defaultEditor : undefined),\n input: typeof d.configJson?.input === 'string' ? d.configJson.input : undefined,\n dictionaryId: typeof d.configJson?.dictionaryId === 'string' ? d.configJson.dictionaryId : undefined,\n dictionaryInlineCreate: d.configJson?.dictionaryInlineCreate !== undefined\n ? Boolean(d.configJson.dictionaryInlineCreate)\n : undefined,\n priority: typeof d.configJson?.priority === 'number' ? d.configJson.priority : 0,\n validation: Array.isArray(d.configJson?.validation) ? d.configJson.validation : undefined,\n defaultValue: d.configJson?.defaultValue !== undefined ? d.configJson.defaultValue : undefined,\n // attachments config passthrough\n maxAttachmentSizeMb: typeof d.configJson?.maxAttachmentSizeMb === 'number' ? d.configJson.maxAttachmentSizeMb : undefined,\n acceptExtensions: Array.isArray(d.configJson?.acceptExtensions) ? d.configJson.acceptExtensions : undefined,\n entityId,\n fieldset: normalizedFieldset ?? effectiveFieldsets[0],\n fieldsets: effectiveFieldsets.length > 0 ? effectiveFieldsets : undefined,\n group: groupInfo,\n } as any\n const metrics = computeDefinitionScore(d, candidateBase, entityOrder.get(entityId) ?? Number.MAX_SAFE_INTEGER)\n const candidate = { ...candidateBase, __score: metrics }\n const existing = (items as any[]).find((entry) => entry.key.toLowerCase() === keyLower)\n if (!existing) {\n items.push(candidate)\n continue\n }\n const existingScore = existing.__score as { base: number; penalty: number; entityIndex: number }\n const candidateScoreInfo = candidate.__score as { base: number; penalty: number; entityIndex: number }\n const better =\n candidateScoreInfo.base > existingScore.base ||\n (candidateScoreInfo.base === existingScore.base && candidateScoreInfo.penalty < existingScore.penalty) ||\n (candidateScoreInfo.base === existingScore.base && candidateScoreInfo.penalty === existingScore.penalty && candidateScoreInfo.entityIndex < existingScore.entityIndex)\n if (better) {\n const index = items.findIndex((entry) => entry.key.toLowerCase() === keyLower)\n if (index >= 0) items[index] = candidate\n }\n }\n }\n\n const sanitized = items.map((item: any) => {\n const { __score, ...rest } = item\n return rest\n })\n sanitized.sort((a: any, b: any) => ((a.priority ?? 0) - (b.priority ?? 0)))\n\n const fieldsetsByEntity: Record<string, CustomFieldsetDefinition[]> = {}\n const entitySettings: Record<string, { singleFieldsetPerRecord: boolean }> = {}\n for (const entityId of entityIds) {\n const cfg = fieldsetConfigs.get(entityId) ?? { fieldsets: [], singleFieldsetPerRecord: true }\n fieldsetsByEntity[entityId] = cfg.fieldsets\n entitySettings[entityId] = { singleFieldsetPerRecord: cfg.singleFieldsetPerRecord }\n }\n\n const responseBody = { items: sanitized, fieldsetsByEntity, entitySettings }\n\n if (cache && cacheKey && !fieldsetFilter) {\n const tags = createDefinitionsCacheTags({\n tenantId,\n organizationId,\n entityIds,\n })\n try {\n await cache.set(cacheKey, responseBody, {\n ttl: ENTITY_DEFINITIONS_CACHE_TTL_MS,\n tags,\n })\n } catch (err) {\n console.warn('[entities.definitions.cache] Failed to store cache entry', err)\n }\n }\n\n return NextResponse.json(responseBody)\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = upsertCustomFieldDefSchema.safeParse(body)\n if (!parsed.success) return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n const input = parsed.data\n\n if (!isSystemEntitySelectable(input.entityId)) {\n return NextResponse.json({ error: 'Custom fields are not supported for this entity' }, { status: 400 })\n }\n\n if (input.kind === 'dictionary') {\n const dictionaryId = input.configJson?.dictionaryId\n if (typeof dictionaryId !== 'string' || dictionaryId.trim().length === 0) {\n return NextResponse.json({ error: 'dictionaryId is required for dictionary custom fields' }, { status: 400 })\n }\n }\n\n const container = await createRequestContainer()\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n\n const where: any = { entityId: input.entityId, key: input.key, organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null }\n let def = await em.findOne(CustomFieldDef, where)\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: FIELD_DEFINITION_RESOURCE_KIND,\n resourceId: def ? def.id : `${input.entityId}:${input.key}`,\n operation: def ? 'update' : 'create',\n mutationPayload: input as unknown as Record<string, unknown>,\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n if (!def) def = em.create(CustomFieldDef, { ...where, createdAt: new Date() })\n def.kind = input.kind\n const inCfg = (input as any).configJson ?? {}\n const cfg: Record<string, any> = { ...inCfg }\n if (cfg.label == null || String(cfg.label).trim() === '') cfg.label = input.key\n if (cfg.formEditable === undefined) cfg.formEditable = true\n if (cfg.listVisible === undefined) cfg.listVisible = true\n if (input.kind === 'dictionary') {\n const dictionaryId = typeof cfg.dictionaryId === 'string' ? cfg.dictionaryId.trim() : ''\n cfg.dictionaryId = dictionaryId\n cfg.dictionaryInlineCreate = cfg.dictionaryInlineCreate !== false\n }\n if (input.kind === 'currency') {\n cfg.optionsUrl = CURRENCY_OPTIONS_URL\n if (Array.isArray(cfg.options)) delete cfg.options\n }\n if (input.kind === 'multiline' && (cfg.editor == null || String(cfg.editor).trim() === '')) {\n cfg.editor = 'markdown'\n }\n // Validate and normalize defaultValue by kind before persisting\n if (cfg.defaultValue !== undefined && cfg.defaultValue !== null) {\n const validationError = await validateDefaultValueByKind(\n cfg.defaultValue, input.kind, cfg, em,\n { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },\n )\n if (validationError) {\n return NextResponse.json({ error: validationError }, { status: 400 })\n }\n cfg.defaultValue = normalizeDefaultValueByKind(cfg.defaultValue, input.kind)\n }\n def.configJson = cfg\n def.isActive = input.isActive ?? true\n def.updatedAt = new Date()\n em.persist(def)\n await em.flush()\n await guard.runAfterSuccess()\n await invalidateDefinitionsCache(cache, {\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n entityIds: [input.entityId],\n })\n // Changing field definitions may impact forms but not sidebar items; no nav cache touch\n return NextResponse.json({ ok: true, item: { id: def.id, key: def.key, kind: def.kind, configJson: def.configJson, isActive: def.isActive } })\n}\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const { entityId, key } = body || {}\n if (!entityId || !key) return NextResponse.json({ error: 'entityId and key are required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n const where: any = { entityId, key, organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null }\n const def = await em.findOne(CustomFieldDef, where)\n if (!def) return NextResponse.json({ error: 'Not found' }, { status: 404 })\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: FIELD_DEFINITION_RESOURCE_KIND,\n resourceId: def.id,\n operation: 'delete',\n mutationPayload: { entityId, key },\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n def.isActive = false\n def.updatedAt = new Date()\n def.deletedAt = def.deletedAt ?? new Date()\n em.persist(def)\n await em.flush()\n await guard.runAfterSuccess()\n await invalidateDefinitionsCache(cache, {\n tenantId: auth.tenantId ?? null,\n organizationId: auth.orgId ?? null,\n entityIds: [entityId],\n })\n // Changing field definitions may impact forms but not sidebar items; no nav cache touch\n return NextResponse.json({ ok: true })\n}\n\nconst definitionsQuerySchema = z\n .object({\n entityId: z.union([z.string(), z.array(z.string())]).optional(),\n entityIds: z.string().optional(),\n fieldset: z.string().regex(fieldsetCodeRegex).optional(),\n })\n .refine(\n (value) => {\n if (value.entityId && typeof value.entityId === 'string' && value.entityId.trim().length > 0) return true\n if (Array.isArray(value.entityId) && value.entityId.length > 0) return true\n return typeof value.entityIds === 'string' && value.entityIds.trim().length > 0\n },\n { message: 'Provide at least one entityId or an entityIds list.' }\n )\n\nconst customFieldOptionValueSchema = z.union([z.string(), z.number()])\n\nconst customFieldDefinitionSchema = z.object({\n key: z.string(),\n kind: z.string(),\n label: z.string(),\n description: z.string().optional(),\n multi: z.boolean().optional(),\n options: z.array(customFieldOptionValueSchema).optional(),\n optionsUrl: z.string().optional(),\n filterable: z.boolean().optional(),\n formEditable: z.boolean().optional(),\n listVisible: z.boolean().optional(),\n editor: z.string().optional(),\n input: z.string().optional(),\n dictionaryId: z.string().optional(),\n dictionaryInlineCreate: z.boolean().optional(),\n priority: z.number().optional(),\n validation: z.array(z.any()).optional(),\n defaultValue: z.union([z.string(), z.number(), z.boolean(), z.null()]).optional(),\n maxAttachmentSizeMb: z.number().optional(),\n acceptExtensions: z.array(z.any()).optional(),\n entityId: z.string(),\n fieldset: z.string().optional(),\n group: z\n .object({\n code: z.string(),\n title: z.string().optional(),\n hint: z.string().optional(),\n })\n .optional(),\n})\n\nconst customFieldsetGroupResponseSchema = z.object({\n code: z.string(),\n title: z.string().optional(),\n hint: z.string().optional(),\n})\n\nconst entityFieldsetResponseSchema = z.object({\n code: z.string(),\n label: z.string(),\n icon: z.string().optional(),\n description: z.string().optional(),\n groups: z.array(customFieldsetGroupResponseSchema).optional(),\n})\n\nconst definitionsResponseSchema = z.object({\n items: z.array(customFieldDefinitionSchema),\n fieldsetsByEntity: z.record(z.string(), z.array(entityFieldsetResponseSchema)).optional(),\n entitySettings: z\n .record(\n z.string(),\n z.object({\n singleFieldsetPerRecord: z.boolean().optional(),\n })\n )\n .optional(),\n})\n\nconst upsertDefinitionResponseSchema = z.object({\n ok: z.literal(true),\n item: z.object({\n id: z.string().uuid(),\n key: z.string(),\n kind: z.string(),\n configJson: z.record(z.string(), z.any()),\n isActive: z.boolean().optional(),\n }),\n})\n\nconst deleteDefinitionRequestSchema = z.object({\n entityId: z.string(),\n key: z.string(),\n})\n\nconst deleteDefinitionResponseSchema = z.object({\n ok: z.literal(true),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Entities',\n summary: 'Manage custom field definitions',\n methods: {\n GET: {\n summary: 'List active custom field definitions',\n description: 'Returns active custom field definitions for the supplied entity ids, respecting tenant scope and tombstones.',\n query: definitionsQuerySchema,\n responses: [\n {\n status: 200,\n description: 'Definition list',\n schema: definitionsResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n POST: {\n summary: 'Upsert custom field definition',\n description: 'Creates or updates a custom field definition for the current tenant/org scope.',\n requestBody: {\n contentType: 'application/json',\n schema: upsertCustomFieldDefSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Definition saved',\n schema: upsertDefinitionResponseSchema,\n },\n {\n status: 400,\n description: 'Validation failed',\n schema: z.object({\n error: z.string(),\n details: z.any().optional(),\n }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n DELETE: {\n summary: 'Soft delete custom field definition',\n description: 'Marks the specified definition inactive and tombstones it for the current scope.',\n requestBody: {\n contentType: 'application/json',\n schema: deleteDefinitionRequestSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Definition deleted',\n schema: deleteDefinitionResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id or key',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 404,\n description: 'Definition not found',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n}\nconst computeDefinitionScore = (def: any, cfg: Record<string, any>, entityIndex: number) => {\n const listVisibleScore = cfg.listVisible === false ? 0 : 1\n const formEditableScore = cfg.formEditable === false ? 0 : 1\n const filterableScore = cfg.filterable ? 1 : 0\n const kindScore = (() => {\n switch (def.kind) {\n case 'dictionary':\n return 8\n case 'relation':\n return 6\n case 'select':\n case 'currency':\n return 4\n case 'multiline':\n return 3\n case 'boolean':\n case 'integer':\n case 'float':\n return 2\n default:\n return 1\n }\n })()\n const optionsBonus = Array.isArray(cfg.options) && cfg.options.length ? 2 : 0\n const dictionaryBonus = typeof cfg.dictionaryId === 'string' && cfg.dictionaryId.trim().length ? 5 : 0\n const base = (listVisibleScore * 16) + (formEditableScore * 8) + (filterableScore * 4) + kindScore + optionsBonus + dictionaryBonus\n const penalty = typeof cfg.priority === 'number' ? cfg.priority : 0\n return { base, penalty, entityIndex }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CustomEntity, CustomFieldDef } from '@open-mercato/core/modules/entities/data/entities'\nimport { upsertCustomFieldDefSchema, fieldsetCodeRegex } from '@open-mercato/core/modules/entities/data/validators'\nimport {\n createDefinitionsCacheKey,\n createDefinitionsCacheTags,\n invalidateDefinitionsCache,\n ENTITY_DEFINITIONS_CACHE_TTL_MS,\n} from './definitions.cache'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { filterSelectableSystemEntityIds, isSystemEntitySelectable } from '@open-mercato/shared/lib/entities/system-entities'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { loadEntityFieldsetConfigs, CustomFieldsetDefinition } from '../lib/fieldsets'\nimport { installCustomEntitiesFromModules } from '../lib/install-from-ce'\nimport { normalizeCustomFieldOptions } from '@open-mercato/shared/modules/entities/options'\nimport { CURRENCY_OPTIONS_URL } from '@open-mercato/shared/modules/entities/kinds'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n beginEntitiesMutationGuard,\n FIELD_DEFINITION_RESOURCE_KIND,\n} from './definitions.mutation-guard'\nimport {\n createExactDefinitionWhere,\n createScopedDefinitionTombstone,\n createVisibleDefinitionWhere,\n markDefinitionTombstoned,\n resolveDefinitionScopeFromOrganizationScope,\n resolveDefinitionMutationScope,\n selectVisibleDefinitionWinner,\n} from '../lib/definition-scope'\n\n/**\n * Validate defaultValue against the field kind. Returns an error message string\n * if invalid, or null if valid. For dictionary and currency kinds, queries the\n * database to verify the token exists.\n */\nasync function validateDefaultValueByKind(\n value: unknown,\n kind: string,\n cfg: Record<string, unknown>,\n em: EntityManager,\n tenantContext: { tenantId: string | null; organizationId: string | null },\n): Promise<string | null> {\n switch (kind) {\n case 'boolean':\n if (typeof value !== 'boolean') return 'defaultValue for boolean fields must be true or false'\n return null\n case 'integer':\n if (typeof value !== 'number' || !Number.isInteger(value))\n return 'defaultValue for integer fields must be a whole number'\n return null\n case 'float':\n if (typeof value !== 'number' || !isFinite(value))\n return 'defaultValue for float fields must be a finite number'\n return null\n case 'text':\n case 'multiline':\n case 'date':\n case 'datetime':\n if (typeof value !== 'string')\n return `defaultValue for ${kind} fields must be a string`\n return null\n case 'dictionary': {\n if (typeof value !== 'string')\n return 'defaultValue for dictionary fields must be a string'\n const dictionaryId = typeof cfg.dictionaryId === 'string' ? cfg.dictionaryId.trim() : ''\n if (dictionaryId) {\n try {\n const { DictionaryEntry } = await import('@open-mercato/core/modules/dictionaries/data/entities')\n const entry = await em.findOne(DictionaryEntry, {\n dictionary: dictionaryId,\n value: value,\n ...(tenantContext.organizationId ? { organizationId: tenantContext.organizationId } : {}),\n ...(tenantContext.tenantId ? { tenantId: tenantContext.tenantId } : {}),\n })\n if (!entry) return `defaultValue \"${value}\" does not match any entry in the configured dictionary`\n } catch (err) {\n // If the dictionaries module is not available, skip entry validation\n console.debug('[entities.definitions] dictionary validation skipped \u2014 module not available', err)\n }\n }\n return null\n }\n case 'currency': {\n if (typeof value !== 'string')\n return 'defaultValue for currency fields must be a string'\n try {\n const { Currency } = await import('@open-mercato/core/modules/currencies/data/entities')\n const where: Record<string, string> = { code: value as string }\n if (tenantContext.tenantId) where.tenantId = tenantContext.tenantId\n if (tenantContext.organizationId) where.organizationId = tenantContext.organizationId\n const currency = await em.findOne(Currency, where)\n if (!currency) return `defaultValue \"${value}\" does not match any available currency`\n } catch (err) {\n // If the currencies module is not available, skip currency validation\n console.debug('[entities.definitions] currency validation skipped \u2014 module not available', err)\n }\n return null\n }\n case 'select': {\n if (typeof value !== 'string' && typeof value !== 'number')\n return 'defaultValue for select fields must be a string or number'\n const options = normalizeCustomFieldOptions(\n Array.isArray(cfg.options) ? cfg.options : [],\n )\n if (options.length > 0) {\n const match = options.some(\n (o) => o.value === value || String(o.value) === String(value),\n )\n if (!match) return 'defaultValue does not match any of the configured options'\n }\n return null\n }\n case 'relation':\n case 'attachment':\n return `defaultValue is not supported for ${kind} fields`\n default:\n return null\n }\n}\n\n/**\n * Normalize defaultValue to the canonical storage shape for the given kind.\n */\nfunction normalizeDefaultValueByKind(value: unknown, kind: string): unknown {\n switch (kind) {\n case 'boolean':\n return value === true\n case 'integer':\n return Math.round(Number(value))\n case 'float':\n return Number(value)\n default:\n return value\n }\n}\n\nexport const metadata = {\n // Reading definitions is needed by record forms; keep it auth-protected but accessible to all authenticated users\n GET: { requireAuth: true },\n // Mutations remain admin-only\n POST: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n}\n\nfunction parseEntityIds(url: URL): string[] {\n const direct = url.searchParams.getAll('entityId').filter((id) => typeof id === 'string' && id.trim().length > 0)\n const combined = url.searchParams.get('entityIds')\n if (combined) {\n combined\n .split(',')\n .map((id) => id.trim())\n .filter((id) => id.length > 0)\n .forEach((id) => direct.push(id))\n }\n const unique: string[] = []\n const seen = new Set<string>()\n for (const id of direct) {\n if (seen.has(id)) continue\n seen.add(id)\n unique.push(id)\n }\n return unique\n}\n\nasync function resolveEntityDefaultEditor(em: any, entityId: string, tenantId: string | null | undefined): Promise<string | undefined> {\n try {\n const ent = await em.findOne(CustomEntity, {\n entityId,\n $and: [\n { $or: [ { tenantId: tenantId ?? undefined as any }, { tenantId: null } ] },\n ],\n } as any)\n if (ent && typeof (ent as any).defaultEditor === 'string') return (ent as any).defaultEditor\n } catch {}\n return undefined\n}\n\nfunction normalizeFieldGroup(raw: unknown): { code: string; title?: string; hint?: string } | undefined {\n if (!raw) return undefined\n if (typeof raw === 'string') {\n const code = raw.trim()\n return code ? { code } : undefined\n }\n if (typeof raw !== 'object') return undefined\n const entry = raw as Record<string, unknown>\n const code = typeof entry.code === 'string' ? entry.code.trim() : ''\n if (!code) return undefined\n const group: { code: string; title?: string; hint?: string } = { code }\n if (typeof entry.title === 'string' && entry.title.trim()) group.title = entry.title.trim()\n if (typeof entry.hint === 'string' && entry.hint.trim()) group.hint = entry.hint.trim()\n return group\n}\n\nfunction definitionMatchesReadScope(\n definition: { tenantId?: string | null; organizationId?: string | null },\n scope: { tenantId: string | null; organizationId: string | null },\n) {\n const definitionTenantId = definition.tenantId ?? null\n const definitionOrganizationId = definition.organizationId ?? null\n const tenantMatches = definitionTenantId === null || definitionTenantId === scope.tenantId\n const organizationMatches =\n definitionOrganizationId === null ||\n (scope.organizationId !== null && definitionOrganizationId === scope.organizationId)\n return tenantMatches && organizationMatches\n}\n\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const requestedEntityIds = parseEntityIds(url)\n if (!requestedEntityIds.length) {\n return NextResponse.json({ error: 'entityId is required' }, { status: 400 })\n }\n const requestedFieldset = url.searchParams.get('fieldset')\n const fieldsetFilter = requestedFieldset && requestedFieldset.trim().length ? requestedFieldset.trim() : null\n\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const entityIds = filterSelectableSystemEntityIds(requestedEntityIds)\n if (!entityIds.length) {\n return NextResponse.json({ items: [] })\n }\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const definitionScope = resolveDefinitionScopeFromOrganizationScope(auth, scope)\n const tenantId = definitionScope.tenantId\n if (!tenantId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n const organizationId = definitionScope.organizationId\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n\n let canManageDefinitions = false\n if (typeof auth.sub === 'string' && auth.sub.length > 0) {\n try {\n const rbac = resolve('rbacService') as RbacService\n canManageDefinitions = await rbac.userHasAllFeatures(auth.sub, ['entities.definitions.manage'], {\n tenantId,\n organizationId,\n })\n } catch {\n // RBAC service unavailable \u2014 fall back to read-only (no definition sync)\n }\n }\n\n if (canManageDefinitions) {\n try {\n await installCustomEntitiesFromModules(em, cache, {\n tenantIds: [tenantId],\n entityIds,\n includeGlobal: true,\n createOnly: true,\n })\n } catch (err) {\n console.warn('[entities.definitions] Failed to synchronize module-backed definitions', {\n tenantId,\n entityIds,\n err,\n })\n }\n }\n\n let cacheKey: string | null = null\n if (cache && !fieldsetFilter) {\n cacheKey = createDefinitionsCacheKey({\n tenantId,\n organizationId,\n entityIds,\n })\n try {\n const cached = await cache.get(cacheKey)\n if (cached) {\n return NextResponse.json(cached)\n }\n } catch (err) {\n console.warn('[entities.definitions.cache] Failed to read cache', err)\n }\n }\n\n const fieldsetConfigs = await loadEntityFieldsetConfigs(em, {\n entityIds,\n tenantId,\n organizationId,\n mode: 'public',\n })\n\n const tenantCandidates = [{ tenantId }, { tenantId: null as string | null }]\n const organizationCandidates = [{ organizationId: null as string | null }]\n if (organizationId) organizationCandidates.unshift({ organizationId })\n const readScope = { tenantId, organizationId }\n\n const whereActive = {\n entityId: { $in: entityIds as any },\n deletedAt: null,\n $and: [\n { $or: tenantCandidates },\n { $or: organizationCandidates },\n ],\n } as any\n const defs = (await em.find(CustomFieldDef, whereActive as any))\n .filter((definition: any) => definitionMatchesReadScope(definition, readScope))\n const tombstones = (await em.find(CustomFieldDef, {\n entityId: { $in: entityIds as any },\n deletedAt: { $ne: null } as any,\n $and: [\n { $or: tenantCandidates },\n { $or: organizationCandidates },\n ],\n } as any)).filter((definition: any) => definitionMatchesReadScope(definition, readScope))\n\n const tombstonedByEntity = new Map<string, Set<string>>()\n for (const entry of tombstones as any[]) {\n const eid = String(entry.entityId)\n if (!tombstonedByEntity.has(eid)) tombstonedByEntity.set(eid, new Set())\n tombstonedByEntity.get(eid)!.add(entry.key)\n }\n\n const scopeScore = (x: any) => (x.tenantId ? 2 : 0) + (x.organizationId ? 1 : 0)\n\n const definitionsByEntity = new Map<string, any[]>()\n for (const d of defs) {\n const eid = String(d.entityId)\n if (!definitionsByEntity.has(eid)) definitionsByEntity.set(eid, [])\n definitionsByEntity.get(eid)!.push(d)\n }\n\n const entityDefaultEditors = new Map<string, string | undefined>()\n for (const entityId of entityIds) {\n const editor = await resolveEntityDefaultEditor(em, entityId, tenantId ?? null)\n entityDefaultEditors.set(entityId, editor)\n }\n\n const items: any[] = []\n\n const entityOrder = new Map<string, number>()\n entityIds.forEach((id, idx) => entityOrder.set(id, idx))\n\n for (const entityId of entityIds) {\n const defsForEntity = definitionsByEntity.get(entityId) ?? []\n if (!defsForEntity.length) continue\n const tombstonedKeys = tombstonedByEntity.get(entityId) ?? new Set<string>()\n const byKey = new Map<string, any>()\n for (const d of defsForEntity) {\n const existing = byKey.get(d.key)\n if (!existing) { byKey.set(d.key, d); continue }\n const sNew = scopeScore(d)\n const sOld = scopeScore(existing)\n if (sNew > sOld) { byKey.set(d.key, d); continue }\n if (sNew < sOld) continue\n const tNew = (d.updatedAt instanceof Date) ? d.updatedAt.getTime() : new Date(d.updatedAt).getTime()\n const tOld = (existing.updatedAt instanceof Date) ? existing.updatedAt.getTime() : new Date(existing.updatedAt).getTime()\n if (tNew >= tOld) byKey.set(d.key, d)\n }\n\n const defaultEditor = entityDefaultEditors.get(entityId)\n const winning = Array.from(byKey.values()).filter((d: any) => (d.isActive !== false) && !tombstonedKeys.has(d.key))\n winning.sort((a: any, b: any) => ((a.configJson?.priority ?? 0) - (b.configJson?.priority ?? 0)))\n\n for (const d of winning) {\n const rawFieldset = typeof d.configJson?.fieldset === 'string' ? d.configJson.fieldset.trim() : ''\n const normalizedFieldset = rawFieldset.length > 0 ? rawFieldset : undefined\n const normalizedFieldsets = Array.isArray(d.configJson?.fieldsets)\n ? d.configJson.fieldsets\n .filter((entry: unknown): entry is string => typeof entry === 'string')\n .map((entry: string) => entry.trim())\n .filter((entry: string) => entry.length > 0)\n : []\n const effectiveFieldsets = normalizedFieldsets.length > 0\n ? normalizedFieldsets\n : (normalizedFieldset ? [normalizedFieldset] : [])\n if (fieldsetFilter && !effectiveFieldsets.includes(fieldsetFilter)) continue\n const groupInfo = normalizeFieldGroup(d.configJson?.group)\n const keyLower = String(d.key).toLowerCase()\n const candidateBase = {\n key: d.key,\n kind: d.kind,\n label: d.configJson?.label || d.key,\n description: d.configJson?.description || undefined,\n multi: Boolean(d.configJson?.multi),\n options: (() => {\n if (d.kind === 'currency') return undefined\n const normalizedOptions = normalizeCustomFieldOptions(d.configJson?.options)\n return normalizedOptions.length ? normalizedOptions : undefined\n })(),\n optionsUrl: (() => {\n if (d.kind === 'currency') return CURRENCY_OPTIONS_URL\n const dictionaryId = typeof d.configJson?.dictionaryId === 'string' ? d.configJson.dictionaryId : undefined\n if (dictionaryId) return `/api/dictionaries/${dictionaryId}/entries`\n return typeof d.configJson?.optionsUrl === 'string' ? d.configJson.optionsUrl : undefined\n })(),\n filterable: Boolean(d.configJson?.filterable),\n formEditable: d.configJson?.formEditable !== undefined ? Boolean(d.configJson.formEditable) : true,\n listVisible: d.configJson?.listVisible !== undefined ? Boolean(d.configJson.listVisible) : true,\n editor: typeof d.configJson?.editor === 'string'\n ? d.configJson.editor\n : (d.kind === 'multiline' ? defaultEditor : undefined),\n input: typeof d.configJson?.input === 'string' ? d.configJson.input : undefined,\n dictionaryId: typeof d.configJson?.dictionaryId === 'string' ? d.configJson.dictionaryId : undefined,\n dictionaryInlineCreate: d.configJson?.dictionaryInlineCreate !== undefined\n ? Boolean(d.configJson.dictionaryInlineCreate)\n : undefined,\n priority: typeof d.configJson?.priority === 'number' ? d.configJson.priority : 0,\n validation: Array.isArray(d.configJson?.validation) ? d.configJson.validation : undefined,\n defaultValue: d.configJson?.defaultValue !== undefined ? d.configJson.defaultValue : undefined,\n // attachments config passthrough\n maxAttachmentSizeMb: typeof d.configJson?.maxAttachmentSizeMb === 'number' ? d.configJson.maxAttachmentSizeMb : undefined,\n acceptExtensions: Array.isArray(d.configJson?.acceptExtensions) ? d.configJson.acceptExtensions : undefined,\n entityId,\n fieldset: normalizedFieldset ?? effectiveFieldsets[0],\n fieldsets: effectiveFieldsets.length > 0 ? effectiveFieldsets : undefined,\n group: groupInfo,\n } as any\n const metrics = computeDefinitionScore(d, candidateBase, entityOrder.get(entityId) ?? Number.MAX_SAFE_INTEGER)\n const candidate = { ...candidateBase, __score: metrics }\n const existing = (items as any[]).find((entry) => entry.key.toLowerCase() === keyLower)\n if (!existing) {\n items.push(candidate)\n continue\n }\n const existingScore = existing.__score as { base: number; penalty: number; entityIndex: number }\n const candidateScoreInfo = candidate.__score as { base: number; penalty: number; entityIndex: number }\n const better =\n candidateScoreInfo.base > existingScore.base ||\n (candidateScoreInfo.base === existingScore.base && candidateScoreInfo.penalty < existingScore.penalty) ||\n (candidateScoreInfo.base === existingScore.base && candidateScoreInfo.penalty === existingScore.penalty && candidateScoreInfo.entityIndex < existingScore.entityIndex)\n if (better) {\n const index = items.findIndex((entry) => entry.key.toLowerCase() === keyLower)\n if (index >= 0) items[index] = candidate\n }\n }\n }\n\n const sanitized = items.map((item: any) => {\n const { __score, ...rest } = item\n return rest\n })\n sanitized.sort((a: any, b: any) => ((a.priority ?? 0) - (b.priority ?? 0)))\n\n const fieldsetsByEntity: Record<string, CustomFieldsetDefinition[]> = {}\n const entitySettings: Record<string, { singleFieldsetPerRecord: boolean }> = {}\n for (const entityId of entityIds) {\n const cfg = fieldsetConfigs.get(entityId) ?? { fieldsets: [], singleFieldsetPerRecord: true }\n fieldsetsByEntity[entityId] = cfg.fieldsets\n entitySettings[entityId] = { singleFieldsetPerRecord: cfg.singleFieldsetPerRecord }\n }\n\n const responseBody = { items: sanitized, fieldsetsByEntity, entitySettings }\n\n if (cache && cacheKey && !fieldsetFilter) {\n const tags = createDefinitionsCacheTags({\n tenantId,\n organizationId,\n entityIds,\n })\n try {\n await cache.set(cacheKey, responseBody, {\n ttl: ENTITY_DEFINITIONS_CACHE_TTL_MS,\n tags,\n })\n } catch (err) {\n console.warn('[entities.definitions.cache] Failed to store cache entry', err)\n }\n }\n\n return NextResponse.json(responseBody)\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = upsertCustomFieldDefSchema.safeParse(body)\n if (!parsed.success) return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n const input = parsed.data\n\n if (!isSystemEntitySelectable(input.entityId)) {\n return NextResponse.json({ error: 'Custom fields are not supported for this entity' }, { status: 400 })\n }\n\n if (input.kind === 'dictionary') {\n const dictionaryId = input.configJson?.dictionaryId\n if (typeof dictionaryId !== 'string' || dictionaryId.trim().length === 0) {\n return NextResponse.json({ error: 'dictionaryId is required for dictionary custom fields' }, { status: 400 })\n }\n }\n\n const container = await createRequestContainer()\n const scope = await resolveDefinitionMutationScope({ auth, container, request: req })\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n\n const where: any = createExactDefinitionWhere(input.entityId, input.key, scope)\n let def = await em.findOne(CustomFieldDef, where)\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: FIELD_DEFINITION_RESOURCE_KIND,\n resourceId: def ? def.id : `${input.entityId}:${input.key}`,\n operation: def ? 'update' : 'create',\n mutationPayload: input as unknown as Record<string, unknown>,\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n if (!def) def = em.create(CustomFieldDef, { ...where, createdAt: new Date() })\n def.kind = input.kind\n const inCfg = (input as any).configJson ?? {}\n const cfg: Record<string, any> = { ...inCfg }\n if (cfg.label == null || String(cfg.label).trim() === '') cfg.label = input.key\n if (cfg.formEditable === undefined) cfg.formEditable = true\n if (cfg.listVisible === undefined) cfg.listVisible = true\n if (input.kind === 'dictionary') {\n const dictionaryId = typeof cfg.dictionaryId === 'string' ? cfg.dictionaryId.trim() : ''\n cfg.dictionaryId = dictionaryId\n cfg.dictionaryInlineCreate = cfg.dictionaryInlineCreate !== false\n }\n if (input.kind === 'currency') {\n cfg.optionsUrl = CURRENCY_OPTIONS_URL\n if (Array.isArray(cfg.options)) delete cfg.options\n }\n if (input.kind === 'multiline' && (cfg.editor == null || String(cfg.editor).trim() === '')) {\n cfg.editor = 'markdown'\n }\n // Validate and normalize defaultValue by kind before persisting\n if (cfg.defaultValue !== undefined && cfg.defaultValue !== null) {\n const validationError = await validateDefaultValueByKind(\n cfg.defaultValue, input.kind, cfg, em,\n { tenantId: scope.tenantId, organizationId: scope.organizationId },\n )\n if (validationError) {\n return NextResponse.json({ error: validationError }, { status: 400 })\n }\n cfg.defaultValue = normalizeDefaultValueByKind(cfg.defaultValue, input.kind)\n }\n def.configJson = cfg\n def.isActive = input.isActive ?? true\n def.deletedAt = def.isActive === false ? (def.deletedAt ?? new Date()) : null\n def.updatedAt = new Date()\n em.persist(def)\n await em.flush()\n await guard.runAfterSuccess()\n await invalidateDefinitionsCache(cache, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n entityIds: [input.entityId],\n })\n // Changing field definitions may impact forms but not sidebar items; no nav cache touch\n return NextResponse.json({ ok: true, item: { id: def.id, key: def.key, kind: def.kind, configJson: def.configJson, isActive: def.isActive } })\n}\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const { entityId, key } = body || {}\n if (!entityId || !key) return NextResponse.json({ error: 'entityId and key are required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const scope = await resolveDefinitionMutationScope({ auth, container, request: req })\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n const where: any = createExactDefinitionWhere(entityId, key, scope)\n let def = await em.findOne(CustomFieldDef, where)\n let inherited: any | null = null\n if (!def) {\n inherited = selectVisibleDefinitionWinner(await em.find(CustomFieldDef, createVisibleDefinitionWhere(\n entityId,\n key,\n scope,\n { deletedAt: null, isActive: true },\n )))\n if (!inherited) return NextResponse.json({ error: 'Not found' }, { status: 404 })\n }\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: FIELD_DEFINITION_RESOURCE_KIND,\n resourceId: def?.id ?? inherited?.id ?? `${entityId}:${key}`,\n operation: 'delete',\n mutationPayload: { entityId, key },\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n if (!def) {\n def = createScopedDefinitionTombstone(em, inherited, scope)\n } else {\n markDefinitionTombstoned(def)\n }\n em.persist(def)\n await em.flush()\n await guard.runAfterSuccess()\n await invalidateDefinitionsCache(cache, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n entityIds: [entityId],\n })\n // Changing field definitions may impact forms but not sidebar items; no nav cache touch\n return NextResponse.json({ ok: true })\n}\n\nconst definitionsQuerySchema = z\n .object({\n entityId: z.union([z.string(), z.array(z.string())]).optional(),\n entityIds: z.string().optional(),\n fieldset: z.string().regex(fieldsetCodeRegex).optional(),\n })\n .refine(\n (value) => {\n if (value.entityId && typeof value.entityId === 'string' && value.entityId.trim().length > 0) return true\n if (Array.isArray(value.entityId) && value.entityId.length > 0) return true\n return typeof value.entityIds === 'string' && value.entityIds.trim().length > 0\n },\n { message: 'Provide at least one entityId or an entityIds list.' }\n )\n\nconst customFieldOptionValueSchema = z.union([z.string(), z.number()])\n\nconst customFieldDefinitionSchema = z.object({\n key: z.string(),\n kind: z.string(),\n label: z.string(),\n description: z.string().optional(),\n multi: z.boolean().optional(),\n options: z.array(customFieldOptionValueSchema).optional(),\n optionsUrl: z.string().optional(),\n filterable: z.boolean().optional(),\n formEditable: z.boolean().optional(),\n listVisible: z.boolean().optional(),\n editor: z.string().optional(),\n input: z.string().optional(),\n dictionaryId: z.string().optional(),\n dictionaryInlineCreate: z.boolean().optional(),\n priority: z.number().optional(),\n validation: z.array(z.any()).optional(),\n defaultValue: z.union([z.string(), z.number(), z.boolean(), z.null()]).optional(),\n maxAttachmentSizeMb: z.number().optional(),\n acceptExtensions: z.array(z.any()).optional(),\n entityId: z.string(),\n fieldset: z.string().optional(),\n group: z\n .object({\n code: z.string(),\n title: z.string().optional(),\n hint: z.string().optional(),\n })\n .optional(),\n})\n\nconst customFieldsetGroupResponseSchema = z.object({\n code: z.string(),\n title: z.string().optional(),\n hint: z.string().optional(),\n})\n\nconst entityFieldsetResponseSchema = z.object({\n code: z.string(),\n label: z.string(),\n icon: z.string().optional(),\n description: z.string().optional(),\n groups: z.array(customFieldsetGroupResponseSchema).optional(),\n})\n\nconst definitionsResponseSchema = z.object({\n items: z.array(customFieldDefinitionSchema),\n fieldsetsByEntity: z.record(z.string(), z.array(entityFieldsetResponseSchema)).optional(),\n entitySettings: z\n .record(\n z.string(),\n z.object({\n singleFieldsetPerRecord: z.boolean().optional(),\n })\n )\n .optional(),\n})\n\nconst upsertDefinitionResponseSchema = z.object({\n ok: z.literal(true),\n item: z.object({\n id: z.string().uuid(),\n key: z.string(),\n kind: z.string(),\n configJson: z.record(z.string(), z.any()),\n isActive: z.boolean().optional(),\n }),\n})\n\nconst deleteDefinitionRequestSchema = z.object({\n entityId: z.string(),\n key: z.string(),\n})\n\nconst deleteDefinitionResponseSchema = z.object({\n ok: z.literal(true),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Entities',\n summary: 'Manage custom field definitions',\n methods: {\n GET: {\n summary: 'List active custom field definitions',\n description: 'Returns active custom field definitions for the supplied entity ids, respecting tenant scope and tombstones.',\n query: definitionsQuerySchema,\n responses: [\n {\n status: 200,\n description: 'Definition list',\n schema: definitionsResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n POST: {\n summary: 'Upsert custom field definition',\n description: 'Creates or updates a custom field definition for the current tenant/org scope.',\n requestBody: {\n contentType: 'application/json',\n schema: upsertCustomFieldDefSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Definition saved',\n schema: upsertDefinitionResponseSchema,\n },\n {\n status: 400,\n description: 'Validation failed',\n schema: z.object({\n error: z.string(),\n details: z.any().optional(),\n }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n DELETE: {\n summary: 'Soft delete custom field definition',\n description: 'Marks the specified definition inactive and tombstones it for the current scope.',\n requestBody: {\n contentType: 'application/json',\n schema: deleteDefinitionRequestSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Definition deleted',\n schema: deleteDefinitionResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id or key',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 404,\n description: 'Definition not found',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n}\nconst computeDefinitionScore = (def: any, cfg: Record<string, any>, entityIndex: number) => {\n const listVisibleScore = cfg.listVisible === false ? 0 : 1\n const formEditableScore = cfg.formEditable === false ? 0 : 1\n const filterableScore = cfg.filterable ? 1 : 0\n const kindScore = (() => {\n switch (def.kind) {\n case 'dictionary':\n return 8\n case 'relation':\n return 6\n case 'select':\n case 'currency':\n return 4\n case 'multiline':\n return 3\n case 'boolean':\n case 'integer':\n case 'float':\n return 2\n default:\n return 1\n }\n })()\n const optionsBonus = Array.isArray(cfg.options) && cfg.options.length ? 2 : 0\n const dictionaryBonus = typeof cfg.dictionaryId === 'string' && cfg.dictionaryId.trim().length ? 5 : 0\n const base = (listVisibleScore * 16) + (formEditableScore * 8) + (filterableScore * 4) + kindScore + optionsBonus + dictionaryBonus\n const penalty = typeof cfg.priority === 'number' ? cfg.priority : 0\n return { base, penalty, entityIndex }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["code"]
|
|
7
7
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
beginEntitiesMutationGuard,
|
|
9
9
|
FIELD_DEFINITION_RESOURCE_KIND
|
|
10
10
|
} from "./definitions.mutation-guard.js";
|
|
11
|
+
import { createExactDefinitionWhere, resolveDefinitionMutationScope } from "../lib/definition-scope.js";
|
|
11
12
|
const metadata = {
|
|
12
13
|
POST: { requireAuth: true, requireFeatures: ["entities.definitions.manage"] }
|
|
13
14
|
};
|
|
@@ -23,6 +24,7 @@ async function POST(req) {
|
|
|
23
24
|
const { entityId, key } = body || {};
|
|
24
25
|
if (!entityId || !key) return NextResponse.json({ error: "entityId and key are required" }, { status: 400 });
|
|
25
26
|
const container = await createRequestContainer();
|
|
27
|
+
const scope = await resolveDefinitionMutationScope({ auth, container, request: req });
|
|
26
28
|
const { resolve } = container;
|
|
27
29
|
const em = resolve("em");
|
|
28
30
|
let cache;
|
|
@@ -30,7 +32,7 @@ async function POST(req) {
|
|
|
30
32
|
cache = resolve("cache");
|
|
31
33
|
} catch {
|
|
32
34
|
}
|
|
33
|
-
const where =
|
|
35
|
+
const where = createExactDefinitionWhere(entityId, key, scope);
|
|
34
36
|
const def = await em.findOne(CustomFieldDef, where);
|
|
35
37
|
if (!def) return NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
36
38
|
const guard = await beginEntitiesMutationGuard({
|
|
@@ -50,8 +52,8 @@ async function POST(req) {
|
|
|
50
52
|
await em.flush();
|
|
51
53
|
await guard.runAfterSuccess();
|
|
52
54
|
await invalidateDefinitionsCache(cache, {
|
|
53
|
-
tenantId:
|
|
54
|
-
organizationId:
|
|
55
|
+
tenantId: scope.tenantId,
|
|
56
|
+
organizationId: scope.organizationId,
|
|
55
57
|
entityIds: [entityId]
|
|
56
58
|
});
|
|
57
59
|
return NextResponse.json({ ok: true });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/entities/api/definitions.restore.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { CustomFieldDef } from '@open-mercato/core/modules/entities/data/entities'\nimport { invalidateDefinitionsCache } from './definitions.cache'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n beginEntitiesMutationGuard,\n FIELD_DEFINITION_RESOURCE_KIND,\n} from './definitions.mutation-guard'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const { entityId, key } = body || {}\n if (!entityId || !key) return NextResponse.json({ error: 'entityId and key are required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n\n const where: any =
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAElB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAE3C;AAAA,EACE;AAAA,EACA;AAAA,OACK;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { CustomFieldDef } from '@open-mercato/core/modules/entities/data/entities'\nimport { invalidateDefinitionsCache } from './definitions.cache'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n beginEntitiesMutationGuard,\n FIELD_DEFINITION_RESOURCE_KIND,\n} from './definitions.mutation-guard'\nimport { createExactDefinitionWhere, resolveDefinitionMutationScope } from '../lib/definition-scope'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const { entityId, key } = body || {}\n if (!entityId || !key) return NextResponse.json({ error: 'entityId and key are required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const scope = await resolveDefinitionMutationScope({ auth, container, request: req })\n const { resolve } = container\n const em = resolve('em') as any\n let cache: CacheStrategy | undefined\n try {\n cache = resolve('cache') as CacheStrategy\n } catch {}\n\n const where: any = createExactDefinitionWhere(entityId, key, scope)\n const def = await em.findOne(CustomFieldDef, where)\n if (!def) return NextResponse.json({ error: 'Not found' }, { status: 404 })\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: FIELD_DEFINITION_RESOURCE_KIND,\n resourceId: def.id,\n operation: 'custom',\n mutationPayload: { entityId, key },\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n ;(def as any).deletedAt = null\n ;(def as any).isActive = true\n ;(def as any).updatedAt = new Date()\n em.persist(def)\n await em.flush()\n await guard.runAfterSuccess()\n await invalidateDefinitionsCache(cache, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n entityIds: [entityId],\n })\n return NextResponse.json({ ok: true })\n}\n\nconst restoreDefinitionRequestSchema = z.object({\n entityId: z.string(),\n key: z.string(),\n})\n\nconst restoreDefinitionResponseSchema = z.object({\n ok: z.literal(true),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Entities',\n summary: 'Restore soft-deleted custom field definitions',\n methods: {\n POST: {\n summary: 'Restore definition',\n description: 'Reactivates a previously soft-deleted definition within the current tenant/org scope.',\n requestBody: {\n contentType: 'application/json',\n schema: restoreDefinitionRequestSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Definition restored',\n schema: restoreDefinitionResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id or key',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 404,\n description: 'Definition not found',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -360,13 +360,15 @@ function EditDefinitionsPage({ params }) {
|
|
|
360
360
|
// Include showInSidebar so CrudForm doesn't strip it on submit
|
|
361
361
|
showInSidebar: z.boolean().optional()
|
|
362
362
|
});
|
|
363
|
+
const metadataFieldsReadOnly = entitySource === "code";
|
|
363
364
|
const fields = [
|
|
364
|
-
{ id: "label", label: "Label", type: "text", required: true },
|
|
365
|
-
{ id: "description", label: "Description", type: "textarea" },
|
|
365
|
+
{ id: "label", label: "Label", type: "text", required: true, readOnly: metadataFieldsReadOnly },
|
|
366
|
+
{ id: "description", label: "Description", type: "textarea", readOnly: metadataFieldsReadOnly },
|
|
366
367
|
{
|
|
367
368
|
id: "defaultEditor",
|
|
368
369
|
label: "Default Editor (multiline)",
|
|
369
370
|
type: "select",
|
|
371
|
+
readOnly: metadataFieldsReadOnly,
|
|
370
372
|
options: [
|
|
371
373
|
{ value: "", label: "Default (Markdown)" },
|
|
372
374
|
{ value: "markdown", label: "Markdown (UIW)" },
|
|
@@ -465,17 +467,12 @@ function EditDefinitionsPage({ params }) {
|
|
|
465
467
|
} catch {
|
|
466
468
|
}
|
|
467
469
|
}
|
|
468
|
-
const defsPayload = {
|
|
470
|
+
const defsPayload = buildDefinitionsBatchPayload({
|
|
469
471
|
entityId,
|
|
470
|
-
|
|
471
|
-
key: d.key,
|
|
472
|
-
kind: d.kind,
|
|
473
|
-
configJson: d.configJson,
|
|
474
|
-
isActive: d.isActive !== false
|
|
475
|
-
})),
|
|
472
|
+
defs,
|
|
476
473
|
fieldsets: buildFieldsetPayload(),
|
|
477
474
|
singleFieldsetPerRecord
|
|
478
|
-
};
|
|
475
|
+
});
|
|
479
476
|
const callDefs = await apiCall("/api/entities/definitions.batch", {
|
|
480
477
|
method: "POST",
|
|
481
478
|
headers: { "content-type": "application/json" },
|
|
@@ -567,6 +564,19 @@ function EditDefinitionsPage({ params }) {
|
|
|
567
564
|
function shouldRegisterEntityMetadata(entitySource) {
|
|
568
565
|
return entitySource === "custom";
|
|
569
566
|
}
|
|
567
|
+
function buildDefinitionsBatchPayload(options) {
|
|
568
|
+
return {
|
|
569
|
+
entityId: options.entityId,
|
|
570
|
+
definitions: options.defs.filter((d) => !!d.key).map((d) => ({
|
|
571
|
+
key: d.key,
|
|
572
|
+
kind: d.kind,
|
|
573
|
+
configJson: d.configJson,
|
|
574
|
+
isActive: d.isActive !== false
|
|
575
|
+
})),
|
|
576
|
+
fieldsets: options.fieldsets,
|
|
577
|
+
singleFieldsetPerRecord: options.singleFieldsetPerRecord
|
|
578
|
+
};
|
|
579
|
+
}
|
|
570
580
|
function buildEntityMetadataPayload(entitySource, vals) {
|
|
571
581
|
const partial = entitySource === "custom" ? upsertCustomEntitySchema.pick({ label: true, description: true, labelField: true, defaultEditor: true }).extend({ showInSidebar: z.boolean().optional() }) : upsertCustomEntitySchema.pick({ label: true, description: true, defaultEditor: true });
|
|
572
582
|
const normalized = {
|
|
@@ -577,6 +587,7 @@ function buildEntityMetadataPayload(entitySource, vals) {
|
|
|
577
587
|
return parsed.success ? parsed.data : null;
|
|
578
588
|
}
|
|
579
589
|
export {
|
|
590
|
+
buildDefinitionsBatchPayload,
|
|
580
591
|
buildEntityMetadataPayload,
|
|
581
592
|
EditDefinitionsPage as default,
|
|
582
593
|
shouldRegisterEntityMetadata
|