@open-mercato/core 0.6.6-develop.6088.1.e6193c2018 → 0.6.6-develop.6094.1.28b081ea16

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.
@@ -10,7 +10,7 @@ import { invalidateCustomFieldDefs } from "@open-mercato/ui/backend/utils/custom
10
10
  import { upsertCustomEntitySchema, upsertCustomFieldDefSchema } from "@open-mercato/core/modules/entities/data/validators";
11
11
  import { z } from "zod";
12
12
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
13
- import { ErrorNotice } from "@open-mercato/ui/primitives/ErrorNotice";
13
+ import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
14
14
  import Link from "next/link";
15
15
  import { Button } from "@open-mercato/ui/primitives/button";
16
16
  import { loadGeneratedFieldRegistrations } from "@open-mercato/ui/backend/fields/registry";
@@ -492,7 +492,10 @@ function EditDefinitionsPage({ params }) {
492
492
  flash("Definitions saved", "success");
493
493
  }, [buildFieldsetPayload, defs, entityId, entitySource, queryClient, singleFieldsetPerRecord, validateAll]);
494
494
  if (!entityId) {
495
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx("div", { className: "p-6", children: /* @__PURE__ */ jsx(ErrorNotice, { title: "Invalid entity", message: "The requested entity ID is missing or invalid." }) }) }) });
495
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
496
+ /* @__PURE__ */ jsx(AlertTitle, { children: "Invalid entity" }),
497
+ /* @__PURE__ */ jsx(AlertDescription, { children: "The requested entity ID is missing or invalid." })
498
+ ] }) }) }) });
496
499
  }
497
500
  if (embedFieldsetView) {
498
501
  return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/entities/backend/entities/user/%5BentityId%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport React, { useEffect, useMemo, useState } from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { invalidateCustomFieldDefs } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport { upsertCustomEntitySchema, upsertCustomFieldDefSchema } from '@open-mercato/core/modules/entities/data/validators'\nimport { z } from 'zod'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorNotice } from '@open-mercato/ui/primitives/ErrorNotice'\nimport Link from 'next/link'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { loadGeneratedFieldRegistrations } from '@open-mercato/ui/backend/fields/registry'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { createCrudFormError, raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { FieldDefinitionsEditor, type FieldDefinition, type FieldDefinitionError } from '@open-mercato/ui/backend/custom-fields/FieldDefinitionsEditor'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { normalizeCustomFieldOptions } from '@open-mercato/shared/modules/entities/options'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Def = FieldDefinition\ntype EntitiesListResponse = { items?: Array<Record<string, unknown>> }\ntype FieldsetGroup = { code: string; title?: string; hint?: string }\ntype FieldsetDefinition = { code: string; label: string; icon?: string; description?: string; groups?: FieldsetGroup[] }\ntype DefinitionsManageResponse = { items?: any[]; deletedKeys?: string[]; fieldsets?: FieldsetDefinition[]; settings?: { singleFieldsetPerRecord?: boolean } }\n\ntype DefErrors = FieldDefinitionError\n\n\nexport default function EditDefinitionsPage({ params }: { params?: { entityId?: string } }) {\n React.useEffect(() => { loadGeneratedFieldRegistrations().catch(() => {}) }, [])\n const router = useRouter()\n const searchParams = useSearchParams()\n const t = useT()\n const queryClient = useQueryClient()\n const entityId = useMemo(() => decodeURIComponent((params?.entityId as any) || ''), [params])\n const [label, setLabel] = useState('')\n const [entitySource, setEntitySource] = useState<'code'|'custom'>('custom')\n const [entityFormLoading, setEntityFormLoading] = useState(true)\n const [entityInitial, setEntityInitial] = useState<{ label?: string; description?: string; labelField?: string; defaultEditor?: string; showInSidebar?: boolean; updatedAt?: string }>({})\n const [defs, setDefs] = useState<Def[]>([])\n const [orderDirty, setOrderDirty] = useState(false)\n const [orderSaving, setOrderSaving] = useState(false)\n const listRef = React.useRef<HTMLDivElement | null>(null)\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [deletedKeys, setDeletedKeys] = useState<string[]>([])\n const [defErrors, setDefErrors] = useState<Record<number, DefErrors>>({})\n const [fieldsets, setFieldsets] = useState<FieldsetDefinition[]>([])\n const [activeFieldset, setActiveFieldset] = useState<string | null>(null)\n const [singleFieldsetPerRecord, setSingleFieldsetPerRecord] = useState(true)\n const [translateDef, setTranslateDef] = useState<{ def: Def; entityId: string } | null>(null)\n\n const translateFields = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const fields: string[] = ['label', 'description']\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value) fields.push(`options.${opt.value}.label`)\n }\n return fields\n }, [translateDef])\n\n const translateBaseValues = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const base: Record<string, string> = {}\n if (typeof def.configJson?.label === 'string') base.label = def.configJson.label\n if (typeof def.configJson?.description === 'string') base.description = def.configJson.description\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value && opt.label) base[`options.${opt.value}.label`] = opt.label\n }\n return base\n }, [translateDef])\n\n const requestedFieldset = React.useMemo(() => {\n const raw = searchParams?.get('fieldset')\n return raw && raw.trim().length ? raw.trim() : null\n }, [searchParams])\n const embedFieldsetView = React.useMemo(() => searchParams?.get('view') === 'fieldset', [searchParams])\n const normalizeGroupPayload = React.useCallback((value: unknown) => {\n if (!value) return null\n if (typeof value === 'string') {\n const code = value.trim()\n return code ? { code } : null\n }\n if (typeof value !== 'object') return null\n const entry = value as Record<string, unknown>\n const code = typeof entry.code === 'string' ? entry.code.trim() : ''\n if (!code) return null\n const group: FieldsetGroup = { 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\n const buildFieldsetPayload = React.useCallback(() => {\n const groupMap = new Map<string, FieldsetGroup[]>()\n defs.forEach((definition) => {\n const code = typeof definition.configJson?.fieldset === 'string' ? definition.configJson.fieldset : null\n if (!code) return\n const normalized = normalizeGroupPayload(definition.configJson?.group)\n if (!normalized) return\n const list = groupMap.get(code) ?? []\n if (!list.some((entry) => entry.code === normalized.code)) {\n list.push(normalized)\n groupMap.set(code, list)\n }\n })\n return fieldsets.map((fs) => ({\n ...fs,\n groups: groupMap.get(fs.code) ?? [],\n }))\n }, [defs, fieldsets, normalizeGroupPayload])\n\n const validateDef = React.useCallback((d: Def): DefErrors => {\n const parsed = upsertCustomFieldDefSchema.safeParse({ entityId, key: d.key, kind: d.kind, configJson: d.configJson, isActive: d.isActive })\n if (parsed.success) return {}\n const errs: DefErrors = {}\n for (const issue of parsed.error.issues) {\n if ((issue.path || []).includes('key')) errs.key = issue.message\n if ((issue.path || []).includes('kind')) errs.kind = issue.message\n }\n return errs\n }, [entityId, requestedFieldset])\n\n const validateAndSetErrorAt = (index: number, d: Def) => {\n const errs = validateDef(d)\n setDefErrors((prev) => ({ ...prev, [index]: errs }))\n return !errs.key && !errs.kind\n }\n\n const validateAll = () => {\n const nextErrors: Record<number, DefErrors> = {}\n defs.forEach((d, i) => {\n nextErrors[i] = validateDef(d)\n })\n setDefErrors(nextErrors)\n return Object.values(nextErrors).every(e => !e.key && !e.kind)\n }\n\n useEffect(() => {\n let mounted = true\n async function load() {\n setLoading(true)\n try {\n const entJson = await readApiResultOrThrow<EntitiesListResponse>(\n '/api/entities/entities',\n undefined,\n { errorMessage: 'Failed to load entity metadata', fallback: { items: [] } },\n )\n const ent = (entJson.items || []).find((x: any) => x.entityId === entityId)\n if (mounted) {\n const record = ent as Record<string, unknown> | undefined\n const labelValue =\n typeof record?.label === 'string' && record.label.trim().length > 0 ? record.label : entityId\n const descriptionValue = typeof record?.description === 'string' ? record.description : ''\n const labelFieldValue =\n typeof record?.labelField === 'string' && record.labelField.length > 0 ? record.labelField : 'name'\n const defaultEditorValue =\n typeof record?.defaultEditor === 'string' ? record.defaultEditor : ''\n const showInSidebarValue = record?.showInSidebar === true\n const updatedAtValue =\n typeof record?.updatedAt === 'string' && record.updatedAt.length > 0 ? record.updatedAt : undefined\n setLabel(labelValue)\n if (record?.source === 'code' || record?.source === 'custom') setEntitySource(record.source)\n setEntityInitial({\n label: labelValue,\n description: descriptionValue,\n labelField: labelFieldValue,\n defaultEditor: defaultEditorValue,\n showInSidebar: showInSidebarValue,\n updatedAt: updatedAtValue,\n })\n setEntityFormLoading(false)\n }\n const json = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: 'Failed to load entity definitions', fallback: { items: [], deletedKeys: [] } },\n )\n if (mounted) {\n const loaded: Def[] = (json.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDefErrors({})\n setDeletedKeys(Array.isArray(json.deletedKeys) ? json.deletedKeys : [])\n const loadedFieldsets = Array.isArray(json.fieldsets) ? json.fieldsets : []\n setFieldsets(loadedFieldsets)\n setActiveFieldset((prev) => {\n if (requestedFieldset && loadedFieldsets.some((fs) => fs.code === requestedFieldset)) {\n return requestedFieldset\n }\n if (prev && loadedFieldsets.some((fs) => fs.code === prev)) return prev\n return loadedFieldsets[0]?.code ?? null\n })\n setSingleFieldsetPerRecord(json.settings?.singleFieldsetPerRecord !== false)\n }\n } catch (e: any) {\n if (mounted) setError(e.message || 'Failed to load')\n } finally {\n if (mounted) setLoading(false)\n }\n }\n if (entityId) load()\n return () => { mounted = false }\n }, [entityId])\n\n function addField() {\n setDefs((arr) => [\n ...arr,\n {\n key: '',\n kind: 'text',\n configJson: activeFieldset ? { fieldset: activeFieldset } : {},\n isActive: true,\n },\n ])\n }\n\n async function restoreField(key: string) {\n try {\n const call = await apiCall('/api/entities/definitions.restore', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to restore field')\n }\n // Reload definitions & deleted keys\n const j2 = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: 'Failed to reload field definitions', fallback: { items: [], deletedKeys: [] } },\n )\n const loaded: Def[] = (j2.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDeletedKeys(Array.isArray(j2.deletedKeys) ? j2.deletedKeys : [])\n flash(`Restored ${key}`, 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || 'Failed to restore field', 'error')\n }\n }\n\n async function saveAll() {\n setSaving(true)\n setError(null)\n try {\n if (!validateAll()) {\n flash('Please fix validation errors in field definitions', 'error')\n throw new Error('Validation failed')\n }\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await apiCall('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to save definitions')\n }\n await invalidateCustomFieldDefs(queryClient, entityId)\n router.push(`/backend/entities/user?flash=Definitions%20saved&type=success`)\n } catch (e: any) {\n setError(e.message || 'Failed to save')\n } finally {\n setSaving(false)\n }\n }\n\n async function removeField(idx: number) {\n const def = defs[idx]\n if (!def) return\n if (def.key) {\n try {\n const call = await apiCall('/api/entities/definitions', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key: def.key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to delete field')\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to delete field'\n flash(message, 'error')\n return\n }\n }\n setDefs((arr) => arr.filter((_, i) => i !== idx))\n setOrderDirty(true)\n if (def.key) {\n await invalidateCustomFieldDefs(queryClient, entityId)\n }\n }\n\n const handleFieldsetCodeChange = React.useCallback((previousCode: string, nextCode: string) => {\n if (!previousCode || !nextCode || previousCode === nextCode) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== previousCode) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n nextConfig.fieldset = nextCode\n return { ...entry, configJson: nextConfig }\n })\n )\n setActiveFieldset((current) => (current === previousCode ? nextCode : current))\n }, [])\n\n const handleFieldsetRemoved = React.useCallback((code: string) => {\n if (!code) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== code) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n delete nextConfig.fieldset\n delete nextConfig.group\n return { ...entry, configJson: nextConfig }\n })\n )\n }, [])\n\n async function saveOrderIfDirty() {\n if (!orderDirty) return\n setOrderSaving(true)\n try {\n // Do not save order when there are invalid keys/kinds\n if (!validateAll()) throw new Error('Validation failed')\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await apiCall('/api/entities/definitions.batch', {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload)\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to save order')\n }\n setOrderDirty(false)\n flash('Order saved', 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || 'Failed to save order', 'error')\n } finally {\n setOrderSaving(false)\n }\n }\n\n // Unify loader via CrudForm isLoading; do not return early here\n\n // Schema for inline field-level validation in CrudForm\n const entityFormSchema = upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any })\n .extend({\n // Allow empty string in the UI select, treat as undefined later\n defaultEditor: z.union([z.enum(['markdown','simpleMarkdown','htmlRichText']).optional(), z.literal('')]).optional(),\n // Include showInSidebar so CrudForm doesn't strip it on submit\n showInSidebar: z.boolean().optional(),\n }) as z.ZodType<Record<string, unknown>>\n\n const fields: CrudField[] = [\n { id: 'label', label: 'Label', type: 'text', required: true },\n { id: 'description', label: 'Description', type: 'textarea' },\n {\n id: 'defaultEditor',\n label: 'Default Editor (multiline)',\n type: 'select',\n options: [\n { value: '', label: 'Default (Markdown)' },\n { value: 'markdown', label: 'Markdown (UIW)' },\n { value: 'simpleMarkdown', label: 'Simple Markdown' },\n { value: 'htmlRichText', label: 'HTML Rich Text' },\n ],\n } as any,\n ...(entitySource === 'custom' ? [{ id: 'showInSidebar', label: 'Show in sidebar', type: 'checkbox' }] : []),\n ]\n const renderFieldDefinitions = React.useCallback(() => (\n <FieldDefinitionsEditor\n definitions={defs}\n errors={defErrors}\n deletedKeys={deletedKeys}\n fieldsets={fieldsets}\n activeFieldset={activeFieldset}\n onActiveFieldsetChange={setActiveFieldset}\n onFieldsetsChange={(next) => {\n setFieldsets(next)\n if (!next.some((fs) => fs.code === activeFieldset)) {\n setActiveFieldset(next[0]?.code ?? null)\n }\n }}\n onFieldsetCodeChange={handleFieldsetCodeChange}\n onFieldsetRemoved={handleFieldsetRemoved}\n singleFieldsetPerRecord={singleFieldsetPerRecord}\n onSingleFieldsetPerRecordChange={setSingleFieldsetPerRecord}\n onAddField={addField}\n onRemoveField={(index) => { void removeField(index) }}\n onDefinitionChange={(index, nextDef) => {\n setDefs((arr) => arr.map((entry, idx) => (idx === index ? nextDef : entry)))\n validateAndSetErrorAt(index, nextDef)\n }}\n onTranslate={(def) => setTranslateDef({ def, entityId })}\n onRestoreField={(key) => { void restoreField(key) }}\n onReorder={(from, to) => {\n setDefs((arr) => {\n const next = [...arr]\n const [moved] = next.splice(from, 1)\n next.splice(to, 0, moved)\n return next\n })\n setOrderDirty(true)\n }}\n orderNotice={orderDirty ? { dirty: true, saving: orderSaving, message: 'Reordered \u2014 will auto-save on blur' } : undefined}\n addButtonLabel=\"Add Field\"\n translate={t}\n listRef={listRef}\n listProps={{\n tabIndex: -1,\n onBlur: (event) => {\n const current = listRef.current\n const next = event.relatedTarget as Node | null\n if (!current) return\n if (!next || !current.contains(next)) {\n void saveOrderIfDirty()\n }\n },\n }}\n />\n ),\n [defs, defErrors, deletedKeys, fieldsets, activeFieldset, singleFieldsetPerRecord, orderDirty, orderSaving, addField, removeField, restoreField, saveOrderIfDirty])\n\n const definitionsGroup: CrudFormGroup = { id: 'definitions', title: 'Field Definitions', column: 1, component: renderFieldDefinitions }\n\n const groups: CrudFormGroup[] = [\n { id: 'settings', title: 'Entity Settings', column: 1, fields: entitySource === 'custom' ? ['label','description','defaultEditor','showInSidebar'] : ['label','description','defaultEditor'] },\n definitionsGroup,\n ]\n\n const handleCrudFormSubmit = React.useCallback(async (vals: Record<string, unknown>) => {\n if (!entityId) {\n throw createCrudFormError('Invalid entity ID')\n }\n if (!validateAll()) {\n flash('Please fix validation errors in field definitions', 'error')\n throw createCrudFormError('Please fix validation errors in field definitions')\n }\n // Code-declared system entities are not registered as custom entities \u2014 their\n // metadata is owned by code and `POST /api/entities/entities` is fail-closed for\n // ORM-backed system ids (#3115). Only their field definitions are user-editable, so\n // skip the registration call and persist definitions below.\n if (shouldRegisterEntityMetadata(entitySource)) {\n const entityPayload = buildEntityMetadataPayload(entitySource, vals)\n if (!entityPayload) throw createCrudFormError('Validation failed')\n const callEntity = await apiCall('/api/entities/entities', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, ...entityPayload }),\n })\n if (!callEntity.ok) {\n await raiseCrudError(callEntity.response, 'Failed to save entity')\n }\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }\n const defsPayload = {\n entityId,\n definitions: defs.filter((d) => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n fieldsets: buildFieldsetPayload(),\n singleFieldsetPerRecord,\n }\n const callDefs = await apiCall('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(defsPayload),\n })\n if (!callDefs.ok) {\n await raiseCrudError(callDefs.response, 'Failed to save definitions')\n }\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n await invalidateCustomFieldDefs(queryClient, entityId)\n flash('Definitions saved', 'success')\n }, [buildFieldsetPayload, defs, entityId, entitySource, queryClient, singleFieldsetPerRecord, validateAll])\n\n if (!entityId) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-6\">\n <ErrorNotice title=\"Invalid entity\" message=\"The requested entity ID is missing or invalid.\" />\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (embedFieldsetView) {\n return (\n <div className=\"p-4\">\n <CrudForm\n schema={entityFormSchema}\n title={`Edit fieldset: ${requestedFieldset ?? entityId}`}\n fields={[]}\n groups={[definitionsGroup]}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel=\"Save\"\n deleteVisible={false}\n backHref={undefined}\n cancelHref={undefined}\n embedded\n onSubmit={handleCrudFormSubmit}\n />\n </div>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n schema={entityFormSchema}\n title={`Edit Entity: ${entityId}`}\n backHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n fields={fields}\n groups={groups}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel=\"Save\"\n deleteVisible={entitySource === 'custom'}\n extraActions={entitySource === 'custom' ? (\n <Button variant=\"outline\" asChild>\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}/records`}>\n Show Records\n </Link>\n </Button>\n ) : null}\n cancelHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n successRedirect={entitySource === 'code' ? \"/backend/entities/system?flash=Definitions%20saved&type=success\" : \"/backend/entities/user?flash=Definitions%20saved&type=success\"}\n onSubmit={handleCrudFormSubmit}\n onDelete={entitySource === 'custom' ? async () => {\n const callDelete = await apiCall('/api/entities/entities', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ entityId }) })\n if (!callDelete.ok) {\n await raiseCrudError(callDelete.response, 'Failed to delete entity')\n }\n flash('Entity deleted', 'success')\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n } : undefined}\n />\n </PageBody>\n <Dialog open={!!translateDef} onOpenChange={(open) => { if (!open) setTranslateDef(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateField', 'Translate field: {{key}}', { key: translateDef?.def.key ?? '' })}</DialogTitle>\n </DialogHeader>\n {translateDef && (\n <TranslationManager\n mode=\"embedded\"\n compact\n entityType=\"entities:custom_field_def\"\n recordId={`${translateDef.entityId}:${translateDef.def.key}`}\n baseValues={translateBaseValues}\n translatableFields={translateFields}\n />\n )}\n </DialogContent>\n </Dialog>\n </Page>\n )\n}\n\nexport function shouldRegisterEntityMetadata(entitySource: 'code' | 'custom'): boolean {\n return entitySource === 'custom'\n}\n\nexport function buildEntityMetadataPayload(\n entitySource: 'code' | 'custom',\n vals: Record<string, unknown>,\n): Record<string, unknown> | null {\n const partial = entitySource === 'custom'\n ? upsertCustomEntitySchema\n .pick({ label: true, description: true, labelField: true as any, defaultEditor: true as any })\n .extend({ showInSidebar: z.boolean().optional() }) as unknown as z.ZodTypeAny\n : upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any }) as unknown as z.ZodTypeAny\n const normalized = {\n ...vals,\n defaultEditor: typeof vals.defaultEditor === 'string' && vals.defaultEditor ? vals.defaultEditor : undefined,\n }\n const parsed = partial.safeParse(normalized)\n return parsed.success ? (parsed.data as Record<string, unknown>) : null\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport React, { useEffect, useMemo, useState } from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { invalidateCustomFieldDefs } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport { upsertCustomEntitySchema, upsertCustomFieldDefSchema } from '@open-mercato/core/modules/entities/data/validators'\nimport { z } from 'zod'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport Link from 'next/link'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { loadGeneratedFieldRegistrations } from '@open-mercato/ui/backend/fields/registry'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { createCrudFormError, raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { FieldDefinitionsEditor, type FieldDefinition, type FieldDefinitionError } from '@open-mercato/ui/backend/custom-fields/FieldDefinitionsEditor'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { normalizeCustomFieldOptions } from '@open-mercato/shared/modules/entities/options'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Def = FieldDefinition\ntype EntitiesListResponse = { items?: Array<Record<string, unknown>> }\ntype FieldsetGroup = { code: string; title?: string; hint?: string }\ntype FieldsetDefinition = { code: string; label: string; icon?: string; description?: string; groups?: FieldsetGroup[] }\ntype DefinitionsManageResponse = { items?: any[]; deletedKeys?: string[]; fieldsets?: FieldsetDefinition[]; settings?: { singleFieldsetPerRecord?: boolean } }\n\ntype DefErrors = FieldDefinitionError\n\n\nexport default function EditDefinitionsPage({ params }: { params?: { entityId?: string } }) {\n React.useEffect(() => { loadGeneratedFieldRegistrations().catch(() => {}) }, [])\n const router = useRouter()\n const searchParams = useSearchParams()\n const t = useT()\n const queryClient = useQueryClient()\n const entityId = useMemo(() => decodeURIComponent((params?.entityId as any) || ''), [params])\n const [label, setLabel] = useState('')\n const [entitySource, setEntitySource] = useState<'code'|'custom'>('custom')\n const [entityFormLoading, setEntityFormLoading] = useState(true)\n const [entityInitial, setEntityInitial] = useState<{ label?: string; description?: string; labelField?: string; defaultEditor?: string; showInSidebar?: boolean; updatedAt?: string }>({})\n const [defs, setDefs] = useState<Def[]>([])\n const [orderDirty, setOrderDirty] = useState(false)\n const [orderSaving, setOrderSaving] = useState(false)\n const listRef = React.useRef<HTMLDivElement | null>(null)\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [deletedKeys, setDeletedKeys] = useState<string[]>([])\n const [defErrors, setDefErrors] = useState<Record<number, DefErrors>>({})\n const [fieldsets, setFieldsets] = useState<FieldsetDefinition[]>([])\n const [activeFieldset, setActiveFieldset] = useState<string | null>(null)\n const [singleFieldsetPerRecord, setSingleFieldsetPerRecord] = useState(true)\n const [translateDef, setTranslateDef] = useState<{ def: Def; entityId: string } | null>(null)\n\n const translateFields = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const fields: string[] = ['label', 'description']\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value) fields.push(`options.${opt.value}.label`)\n }\n return fields\n }, [translateDef])\n\n const translateBaseValues = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const base: Record<string, string> = {}\n if (typeof def.configJson?.label === 'string') base.label = def.configJson.label\n if (typeof def.configJson?.description === 'string') base.description = def.configJson.description\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value && opt.label) base[`options.${opt.value}.label`] = opt.label\n }\n return base\n }, [translateDef])\n\n const requestedFieldset = React.useMemo(() => {\n const raw = searchParams?.get('fieldset')\n return raw && raw.trim().length ? raw.trim() : null\n }, [searchParams])\n const embedFieldsetView = React.useMemo(() => searchParams?.get('view') === 'fieldset', [searchParams])\n const normalizeGroupPayload = React.useCallback((value: unknown) => {\n if (!value) return null\n if (typeof value === 'string') {\n const code = value.trim()\n return code ? { code } : null\n }\n if (typeof value !== 'object') return null\n const entry = value as Record<string, unknown>\n const code = typeof entry.code === 'string' ? entry.code.trim() : ''\n if (!code) return null\n const group: FieldsetGroup = { 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\n const buildFieldsetPayload = React.useCallback(() => {\n const groupMap = new Map<string, FieldsetGroup[]>()\n defs.forEach((definition) => {\n const code = typeof definition.configJson?.fieldset === 'string' ? definition.configJson.fieldset : null\n if (!code) return\n const normalized = normalizeGroupPayload(definition.configJson?.group)\n if (!normalized) return\n const list = groupMap.get(code) ?? []\n if (!list.some((entry) => entry.code === normalized.code)) {\n list.push(normalized)\n groupMap.set(code, list)\n }\n })\n return fieldsets.map((fs) => ({\n ...fs,\n groups: groupMap.get(fs.code) ?? [],\n }))\n }, [defs, fieldsets, normalizeGroupPayload])\n\n const validateDef = React.useCallback((d: Def): DefErrors => {\n const parsed = upsertCustomFieldDefSchema.safeParse({ entityId, key: d.key, kind: d.kind, configJson: d.configJson, isActive: d.isActive })\n if (parsed.success) return {}\n const errs: DefErrors = {}\n for (const issue of parsed.error.issues) {\n if ((issue.path || []).includes('key')) errs.key = issue.message\n if ((issue.path || []).includes('kind')) errs.kind = issue.message\n }\n return errs\n }, [entityId, requestedFieldset])\n\n const validateAndSetErrorAt = (index: number, d: Def) => {\n const errs = validateDef(d)\n setDefErrors((prev) => ({ ...prev, [index]: errs }))\n return !errs.key && !errs.kind\n }\n\n const validateAll = () => {\n const nextErrors: Record<number, DefErrors> = {}\n defs.forEach((d, i) => {\n nextErrors[i] = validateDef(d)\n })\n setDefErrors(nextErrors)\n return Object.values(nextErrors).every(e => !e.key && !e.kind)\n }\n\n useEffect(() => {\n let mounted = true\n async function load() {\n setLoading(true)\n try {\n const entJson = await readApiResultOrThrow<EntitiesListResponse>(\n '/api/entities/entities',\n undefined,\n { errorMessage: 'Failed to load entity metadata', fallback: { items: [] } },\n )\n const ent = (entJson.items || []).find((x: any) => x.entityId === entityId)\n if (mounted) {\n const record = ent as Record<string, unknown> | undefined\n const labelValue =\n typeof record?.label === 'string' && record.label.trim().length > 0 ? record.label : entityId\n const descriptionValue = typeof record?.description === 'string' ? record.description : ''\n const labelFieldValue =\n typeof record?.labelField === 'string' && record.labelField.length > 0 ? record.labelField : 'name'\n const defaultEditorValue =\n typeof record?.defaultEditor === 'string' ? record.defaultEditor : ''\n const showInSidebarValue = record?.showInSidebar === true\n const updatedAtValue =\n typeof record?.updatedAt === 'string' && record.updatedAt.length > 0 ? record.updatedAt : undefined\n setLabel(labelValue)\n if (record?.source === 'code' || record?.source === 'custom') setEntitySource(record.source)\n setEntityInitial({\n label: labelValue,\n description: descriptionValue,\n labelField: labelFieldValue,\n defaultEditor: defaultEditorValue,\n showInSidebar: showInSidebarValue,\n updatedAt: updatedAtValue,\n })\n setEntityFormLoading(false)\n }\n const json = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: 'Failed to load entity definitions', fallback: { items: [], deletedKeys: [] } },\n )\n if (mounted) {\n const loaded: Def[] = (json.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDefErrors({})\n setDeletedKeys(Array.isArray(json.deletedKeys) ? json.deletedKeys : [])\n const loadedFieldsets = Array.isArray(json.fieldsets) ? json.fieldsets : []\n setFieldsets(loadedFieldsets)\n setActiveFieldset((prev) => {\n if (requestedFieldset && loadedFieldsets.some((fs) => fs.code === requestedFieldset)) {\n return requestedFieldset\n }\n if (prev && loadedFieldsets.some((fs) => fs.code === prev)) return prev\n return loadedFieldsets[0]?.code ?? null\n })\n setSingleFieldsetPerRecord(json.settings?.singleFieldsetPerRecord !== false)\n }\n } catch (e: any) {\n if (mounted) setError(e.message || 'Failed to load')\n } finally {\n if (mounted) setLoading(false)\n }\n }\n if (entityId) load()\n return () => { mounted = false }\n }, [entityId])\n\n function addField() {\n setDefs((arr) => [\n ...arr,\n {\n key: '',\n kind: 'text',\n configJson: activeFieldset ? { fieldset: activeFieldset } : {},\n isActive: true,\n },\n ])\n }\n\n async function restoreField(key: string) {\n try {\n const call = await apiCall('/api/entities/definitions.restore', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to restore field')\n }\n // Reload definitions & deleted keys\n const j2 = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: 'Failed to reload field definitions', fallback: { items: [], deletedKeys: [] } },\n )\n const loaded: Def[] = (j2.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDeletedKeys(Array.isArray(j2.deletedKeys) ? j2.deletedKeys : [])\n flash(`Restored ${key}`, 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || 'Failed to restore field', 'error')\n }\n }\n\n async function saveAll() {\n setSaving(true)\n setError(null)\n try {\n if (!validateAll()) {\n flash('Please fix validation errors in field definitions', 'error')\n throw new Error('Validation failed')\n }\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await apiCall('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to save definitions')\n }\n await invalidateCustomFieldDefs(queryClient, entityId)\n router.push(`/backend/entities/user?flash=Definitions%20saved&type=success`)\n } catch (e: any) {\n setError(e.message || 'Failed to save')\n } finally {\n setSaving(false)\n }\n }\n\n async function removeField(idx: number) {\n const def = defs[idx]\n if (!def) return\n if (def.key) {\n try {\n const call = await apiCall('/api/entities/definitions', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key: def.key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to delete field')\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to delete field'\n flash(message, 'error')\n return\n }\n }\n setDefs((arr) => arr.filter((_, i) => i !== idx))\n setOrderDirty(true)\n if (def.key) {\n await invalidateCustomFieldDefs(queryClient, entityId)\n }\n }\n\n const handleFieldsetCodeChange = React.useCallback((previousCode: string, nextCode: string) => {\n if (!previousCode || !nextCode || previousCode === nextCode) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== previousCode) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n nextConfig.fieldset = nextCode\n return { ...entry, configJson: nextConfig }\n })\n )\n setActiveFieldset((current) => (current === previousCode ? nextCode : current))\n }, [])\n\n const handleFieldsetRemoved = React.useCallback((code: string) => {\n if (!code) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== code) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n delete nextConfig.fieldset\n delete nextConfig.group\n return { ...entry, configJson: nextConfig }\n })\n )\n }, [])\n\n async function saveOrderIfDirty() {\n if (!orderDirty) return\n setOrderSaving(true)\n try {\n // Do not save order when there are invalid keys/kinds\n if (!validateAll()) throw new Error('Validation failed')\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await apiCall('/api/entities/definitions.batch', {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload)\n })\n if (!call.ok) {\n await raiseCrudError(call.response, 'Failed to save order')\n }\n setOrderDirty(false)\n flash('Order saved', 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || 'Failed to save order', 'error')\n } finally {\n setOrderSaving(false)\n }\n }\n\n // Unify loader via CrudForm isLoading; do not return early here\n\n // Schema for inline field-level validation in CrudForm\n const entityFormSchema = upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any })\n .extend({\n // Allow empty string in the UI select, treat as undefined later\n defaultEditor: z.union([z.enum(['markdown','simpleMarkdown','htmlRichText']).optional(), z.literal('')]).optional(),\n // Include showInSidebar so CrudForm doesn't strip it on submit\n showInSidebar: z.boolean().optional(),\n }) as z.ZodType<Record<string, unknown>>\n\n const fields: CrudField[] = [\n { id: 'label', label: 'Label', type: 'text', required: true },\n { id: 'description', label: 'Description', type: 'textarea' },\n {\n id: 'defaultEditor',\n label: 'Default Editor (multiline)',\n type: 'select',\n options: [\n { value: '', label: 'Default (Markdown)' },\n { value: 'markdown', label: 'Markdown (UIW)' },\n { value: 'simpleMarkdown', label: 'Simple Markdown' },\n { value: 'htmlRichText', label: 'HTML Rich Text' },\n ],\n } as any,\n ...(entitySource === 'custom' ? [{ id: 'showInSidebar', label: 'Show in sidebar', type: 'checkbox' }] : []),\n ]\n const renderFieldDefinitions = React.useCallback(() => (\n <FieldDefinitionsEditor\n definitions={defs}\n errors={defErrors}\n deletedKeys={deletedKeys}\n fieldsets={fieldsets}\n activeFieldset={activeFieldset}\n onActiveFieldsetChange={setActiveFieldset}\n onFieldsetsChange={(next) => {\n setFieldsets(next)\n if (!next.some((fs) => fs.code === activeFieldset)) {\n setActiveFieldset(next[0]?.code ?? null)\n }\n }}\n onFieldsetCodeChange={handleFieldsetCodeChange}\n onFieldsetRemoved={handleFieldsetRemoved}\n singleFieldsetPerRecord={singleFieldsetPerRecord}\n onSingleFieldsetPerRecordChange={setSingleFieldsetPerRecord}\n onAddField={addField}\n onRemoveField={(index) => { void removeField(index) }}\n onDefinitionChange={(index, nextDef) => {\n setDefs((arr) => arr.map((entry, idx) => (idx === index ? nextDef : entry)))\n validateAndSetErrorAt(index, nextDef)\n }}\n onTranslate={(def) => setTranslateDef({ def, entityId })}\n onRestoreField={(key) => { void restoreField(key) }}\n onReorder={(from, to) => {\n setDefs((arr) => {\n const next = [...arr]\n const [moved] = next.splice(from, 1)\n next.splice(to, 0, moved)\n return next\n })\n setOrderDirty(true)\n }}\n orderNotice={orderDirty ? { dirty: true, saving: orderSaving, message: 'Reordered \u2014 will auto-save on blur' } : undefined}\n addButtonLabel=\"Add Field\"\n translate={t}\n listRef={listRef}\n listProps={{\n tabIndex: -1,\n onBlur: (event) => {\n const current = listRef.current\n const next = event.relatedTarget as Node | null\n if (!current) return\n if (!next || !current.contains(next)) {\n void saveOrderIfDirty()\n }\n },\n }}\n />\n ),\n [defs, defErrors, deletedKeys, fieldsets, activeFieldset, singleFieldsetPerRecord, orderDirty, orderSaving, addField, removeField, restoreField, saveOrderIfDirty])\n\n const definitionsGroup: CrudFormGroup = { id: 'definitions', title: 'Field Definitions', column: 1, component: renderFieldDefinitions }\n\n const groups: CrudFormGroup[] = [\n { id: 'settings', title: 'Entity Settings', column: 1, fields: entitySource === 'custom' ? ['label','description','defaultEditor','showInSidebar'] : ['label','description','defaultEditor'] },\n definitionsGroup,\n ]\n\n const handleCrudFormSubmit = React.useCallback(async (vals: Record<string, unknown>) => {\n if (!entityId) {\n throw createCrudFormError('Invalid entity ID')\n }\n if (!validateAll()) {\n flash('Please fix validation errors in field definitions', 'error')\n throw createCrudFormError('Please fix validation errors in field definitions')\n }\n // Code-declared system entities are not registered as custom entities \u2014 their\n // metadata is owned by code and `POST /api/entities/entities` is fail-closed for\n // ORM-backed system ids (#3115). Only their field definitions are user-editable, so\n // skip the registration call and persist definitions below.\n if (shouldRegisterEntityMetadata(entitySource)) {\n const entityPayload = buildEntityMetadataPayload(entitySource, vals)\n if (!entityPayload) throw createCrudFormError('Validation failed')\n const callEntity = await apiCall('/api/entities/entities', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, ...entityPayload }),\n })\n if (!callEntity.ok) {\n await raiseCrudError(callEntity.response, 'Failed to save entity')\n }\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }\n const defsPayload = {\n entityId,\n definitions: defs.filter((d) => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n fieldsets: buildFieldsetPayload(),\n singleFieldsetPerRecord,\n }\n const callDefs = await apiCall('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(defsPayload),\n })\n if (!callDefs.ok) {\n await raiseCrudError(callDefs.response, 'Failed to save definitions')\n }\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n await invalidateCustomFieldDefs(queryClient, entityId)\n flash('Definitions saved', 'success')\n }, [buildFieldsetPayload, defs, entityId, entitySource, queryClient, singleFieldsetPerRecord, validateAll])\n\n if (!entityId) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-6\">\n <Alert variant=\"destructive\">\n <AlertTitle>Invalid entity</AlertTitle>\n <AlertDescription>The requested entity ID is missing or invalid.</AlertDescription>\n </Alert>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (embedFieldsetView) {\n return (\n <div className=\"p-4\">\n <CrudForm\n schema={entityFormSchema}\n title={`Edit fieldset: ${requestedFieldset ?? entityId}`}\n fields={[]}\n groups={[definitionsGroup]}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel=\"Save\"\n deleteVisible={false}\n backHref={undefined}\n cancelHref={undefined}\n embedded\n onSubmit={handleCrudFormSubmit}\n />\n </div>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n schema={entityFormSchema}\n title={`Edit Entity: ${entityId}`}\n backHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n fields={fields}\n groups={groups}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel=\"Save\"\n deleteVisible={entitySource === 'custom'}\n extraActions={entitySource === 'custom' ? (\n <Button variant=\"outline\" asChild>\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}/records`}>\n Show Records\n </Link>\n </Button>\n ) : null}\n cancelHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n successRedirect={entitySource === 'code' ? \"/backend/entities/system?flash=Definitions%20saved&type=success\" : \"/backend/entities/user?flash=Definitions%20saved&type=success\"}\n onSubmit={handleCrudFormSubmit}\n onDelete={entitySource === 'custom' ? async () => {\n const callDelete = await apiCall('/api/entities/entities', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ entityId }) })\n if (!callDelete.ok) {\n await raiseCrudError(callDelete.response, 'Failed to delete entity')\n }\n flash('Entity deleted', 'success')\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n } : undefined}\n />\n </PageBody>\n <Dialog open={!!translateDef} onOpenChange={(open) => { if (!open) setTranslateDef(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateField', 'Translate field: {{key}}', { key: translateDef?.def.key ?? '' })}</DialogTitle>\n </DialogHeader>\n {translateDef && (\n <TranslationManager\n mode=\"embedded\"\n compact\n entityType=\"entities:custom_field_def\"\n recordId={`${translateDef.entityId}:${translateDef.def.key}`}\n baseValues={translateBaseValues}\n translatableFields={translateFields}\n />\n )}\n </DialogContent>\n </Dialog>\n </Page>\n )\n}\n\nexport function shouldRegisterEntityMetadata(entitySource: 'code' | 'custom'): boolean {\n return entitySource === 'custom'\n}\n\nexport function buildEntityMetadataPayload(\n entitySource: 'code' | 'custom',\n vals: Record<string, unknown>,\n): Record<string, unknown> | null {\n const partial = entitySource === 'custom'\n ? upsertCustomEntitySchema\n .pick({ label: true, description: true, labelField: true as any, defaultEditor: true as any })\n .extend({ showInSidebar: z.boolean().optional() }) as unknown as z.ZodTypeAny\n : upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any }) as unknown as z.ZodTypeAny\n const normalized = {\n ...vals,\n defaultEditor: typeof vals.defaultEditor === 'string' && vals.defaultEditor ? vals.defaultEditor : undefined,\n }\n const parsed = partial.safeParse(normalized)\n return parsed.success ? (parsed.data as Record<string, unknown>) : null\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["fields", "code", "error"]
7
7
  }
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@open-mercato/ui/primitives/card";
4
- import { DataLoader, ErrorNotice } from "@open-mercato/ui";
4
+ import { DataLoader } from "@open-mercato/ui";
5
+ import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
5
6
  import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
6
7
  import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
7
8
  import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
@@ -57,7 +58,10 @@ function FeatureToggleOverrideCard({ toggleId }) {
57
58
  if (error) {
58
59
  return /* @__PURE__ */ jsxs(Card, { children: [
59
60
  /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: t("feature_toggles.override.title", "Override") }) }),
60
- /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(ErrorNotice, { message: error.message }) })
61
+ /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
62
+ /* @__PURE__ */ jsx(AlertTitle, { children: t("ui.errors.defaultTitle", "Something went wrong") }),
63
+ /* @__PURE__ */ jsx(AlertDescription, { children: error.message })
64
+ ] }) })
61
65
  ] });
62
66
  }
63
67
  const fieldDefinitions = createOverrideFieldDefinitions(t);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'\nimport { DataLoader, ErrorNotice } from \"@open-mercato/ui\";\nimport { useQuery, useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { apiCall, withScopedApiRequestHeaders } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { buildOptimisticLockHeader } from \"@open-mercato/ui/backend/utils/optimisticLock\";\nimport { surfaceRecordConflict } from \"@open-mercato/ui/backend/conflicts\";\nimport { raiseCrudError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { CrudForm } from \"@open-mercato/ui/backend/CrudForm\";\nimport { createOverrideFieldDefinitions, createOverrideFormGroups } from \"./overrideFormConfig\";\nimport { FeatureToggleOverrideResponse } from \"../data/validators\";\n\n\nexport function FeatureToggleOverrideCard({ toggleId }: { toggleId: string }) {\n const t = useT()\n const queryClient = useQueryClient()\n \n const { data: overrideData, isLoading, error } = useQuery({\n queryKey: ['feature_toggle_override', toggleId],\n queryFn: async () => {\n const call = await apiCall<FeatureToggleOverrideResponse>(`/api/feature_toggles/global/${toggleId}/override`)\n if (!call.ok) {\n await raiseCrudError(call.response, t('feature_toggles.override.error.load', 'Failed to load override'))\n }\n return call.result\n },\n enabled: !!toggleId\n })\n\n const mutation = useMutation({\n mutationFn: async (input: { toggleId: string; isOverride: boolean; overrideValue?: any; tenantId: string }) => {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(overrideData?.updatedAt ?? null),\n () => apiCall<{ ok: boolean }>(\n `/api/feature_toggles/overrides`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n toggleId: input.toggleId,\n isOverride: input.isOverride,\n overrideValue: input.overrideValue,\n }),\n },\n ),\n )\n if (!call.ok) {\n await raiseCrudError(call.response, t('feature_toggles.overrides.error.update', 'Failed to update override'))\n }\n return call.result\n },\n onError: (err: unknown) => {\n // Route an optimistic-lock 409 to the unified conflict bar; other errors\n // already surfaced via raiseCrudError inside mutationFn.\n surfaceRecordConflict(err, t)\n },\n onSettled: async () => {\n await queryClient.invalidateQueries({ queryKey: ['feature_toggle_override', toggleId] })\n await queryClient.invalidateQueries({ queryKey: ['feature_toggle_overrides'] })\n },\n })\n\n if (error) {\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t('feature_toggles.override.title', 'Override')}</CardTitle>\n </CardHeader>\n <CardContent>\n <ErrorNotice message={error.message} />\n </CardContent>\n </Card>\n )\n }\n\n const fieldDefinitions = createOverrideFieldDefinitions(t)\n const formGroups = createOverrideFormGroups(t)\n const initialValues = overrideData ? {\n isOverride: overrideData.id === '' ? false : true,\n overrideValue: overrideData.value,\n toggleType: overrideData.toggleType,\n tenantId: overrideData.tenantId,\n tenantName: overrideData.tenantName,\n } : {}\n\n const handleSubmit = async (values: any) => {\n if (!overrideData) return\n await mutation.mutateAsync({\n toggleId,\n isOverride: values.isOverride,\n overrideValue: values.overrideValue,\n tenantId: overrideData.tenantId\n })\n }\n\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t('feature_toggles.override.title', 'Override')}</CardTitle>\n {overrideData ? (\n <CardDescription>{t('feature_toggles.override.tenant', 'Tenant: {{name}}', { name: overrideData.tenantName })}</CardDescription>\n ) : <CardDescription className=\"h-5 w-48 animate-pulse bg-zinc-100 dark:bg-zinc-800 rounded-md\" />}\n </CardHeader>\n <CardContent>\n <DataLoader\n isLoading={isLoading}\n showSkeleton\n skeletonComponent={\n <div className=\"space-y-4\">\n <div className=\"h-9 w-full animate-pulse rounded-md bg-zinc-100 dark:bg-zinc-800\" />\n <div className=\"h-20 w-full animate-pulse rounded-md bg-zinc-100 dark:bg-zinc-800\" />\n </div>\n }\n >\n {overrideData && (\n <CrudForm\n fields={fieldDefinitions}\n groups={formGroups}\n initialValues={initialValues}\n onSubmit={handleSubmit}\n submitLabel={t('feature_toggles.override.save', 'Save Override')}\n embedded={true}\n isLoading={false}\n />\n )}\n </DataLoader>\n </CardContent>\n </Card>\n )\n}\n"],
5
- "mappings": ";AAiEY,SAEQ,KAFR;AAhEZ,SAAS,MAAM,aAAa,YAAY,WAAW,uBAAuB;AAC1E,SAAS,YAAY,mBAAmB;AACxC,SAAS,UAAU,aAAa,sBAAsB;AACtD,SAAS,SAAS,mCAAmC;AACrD,SAAS,iCAAiC;AAC1C,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,YAAY;AACrB,SAAS,gBAAgB;AACzB,SAAS,gCAAgC,gCAAgC;AAIlE,SAAS,0BAA0B,EAAE,SAAS,GAAyB;AAC1E,QAAM,IAAI,KAAK;AACf,QAAM,cAAc,eAAe;AAEnC,QAAM,EAAE,MAAM,cAAc,WAAW,MAAM,IAAI,SAAS;AAAA,IACtD,UAAU,CAAC,2BAA2B,QAAQ;AAAA,IAC9C,SAAS,YAAY;AACjB,YAAM,OAAO,MAAM,QAAuC,+BAA+B,QAAQ,WAAW;AAC5G,UAAI,CAAC,KAAK,IAAI;AACV,cAAM,eAAe,KAAK,UAAU,EAAE,uCAAuC,yBAAyB,CAAC;AAAA,MAC3G;AACA,aAAO,KAAK;AAAA,IAChB;AAAA,IACA,SAAS,CAAC,CAAC;AAAA,EACf,CAAC;AAED,QAAM,WAAW,YAAY;AAAA,IACzB,YAAY,OAAO,UAA4F;AAC3G,YAAM,OAAO,MAAM;AAAA,QACf,0BAA0B,cAAc,aAAa,IAAI;AAAA,QACzD,MAAM;AAAA,UACF;AAAA,UACA;AAAA,YACI,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU;AAAA,cACjB,UAAU,MAAM;AAAA,cAChB,YAAY,MAAM;AAAA,cAClB,eAAe,MAAM;AAAA,YACzB,CAAC;AAAA,UACL;AAAA,QACJ;AAAA,MACJ;AACA,UAAI,CAAC,KAAK,IAAI;AACV,cAAM,eAAe,KAAK,UAAU,EAAE,0CAA0C,2BAA2B,CAAC;AAAA,MAChH;AACA,aAAO,KAAK;AAAA,IAChB;AAAA,IACA,SAAS,CAAC,QAAiB;AAGvB,4BAAsB,KAAK,CAAC;AAAA,IAChC;AAAA,IACA,WAAW,YAAY;AACnB,YAAM,YAAY,kBAAkB,EAAE,UAAU,CAAC,2BAA2B,QAAQ,EAAE,CAAC;AACvF,YAAM,YAAY,kBAAkB,EAAE,UAAU,CAAC,0BAA0B,EAAE,CAAC;AAAA,IAClF;AAAA,EACJ,CAAC;AAED,MAAI,OAAO;AACP,WACI,qBAAC,QACG;AAAA,0BAAC,cACG,8BAAC,aAAW,YAAE,kCAAkC,UAAU,GAAE,GAChE;AAAA,MACA,oBAAC,eACG,8BAAC,eAAY,SAAS,MAAM,SAAS,GACzC;AAAA,OACJ;AAAA,EAER;AAEA,QAAM,mBAAmB,+BAA+B,CAAC;AACzD,QAAM,aAAa,yBAAyB,CAAC;AAC7C,QAAM,gBAAgB,eAAe;AAAA,IACjC,YAAY,aAAa,OAAO,KAAK,QAAQ;AAAA,IAC7C,eAAe,aAAa;AAAA,IAC5B,YAAY,aAAa;AAAA,IACzB,UAAU,aAAa;AAAA,IACvB,YAAY,aAAa;AAAA,EAC7B,IAAI,CAAC;AAEL,QAAM,eAAe,OAAO,WAAgB;AACxC,QAAI,CAAC,aAAc;AACnB,UAAM,SAAS,YAAY;AAAA,MACvB;AAAA,MACA,YAAY,OAAO;AAAA,MACnB,eAAe,OAAO;AAAA,MACtB,UAAU,aAAa;AAAA,IAC3B,CAAC;AAAA,EACL;AAEA,SACI,qBAAC,QACG;AAAA,yBAAC,cACG;AAAA,0BAAC,aAAW,YAAE,kCAAkC,UAAU,GAAE;AAAA,MAC3D,eACG,oBAAC,mBAAiB,YAAE,mCAAmC,oBAAoB,EAAE,MAAM,aAAa,WAAW,CAAC,GAAE,IAC9G,oBAAC,mBAAgB,WAAU,kEAAiE;AAAA,OACpG;AAAA,IACA,oBAAC,eACG;AAAA,MAAC;AAAA;AAAA,QACG;AAAA,QACA,cAAY;AAAA,QACZ,mBACI,qBAAC,SAAI,WAAU,aACX;AAAA,8BAAC,SAAI,WAAU,oEAAmE;AAAA,UAClF,oBAAC,SAAI,WAAU,qEAAoE;AAAA,WACvF;AAAA,QAGH,0BACG;AAAA,UAAC;AAAA;AAAA,YACG,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR;AAAA,YACA,UAAU;AAAA,YACV,aAAa,EAAE,iCAAiC,eAAe;AAAA,YAC/D,UAAU;AAAA,YACV,WAAW;AAAA;AAAA,QACf;AAAA;AAAA,IAER,GACJ;AAAA,KACJ;AAER;",
4
+ "sourcesContent": ["\"use client\"\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@open-mercato/ui/primitives/card'\nimport { DataLoader } from \"@open-mercato/ui\";\nimport { Alert, AlertDescription, AlertTitle } from \"@open-mercato/ui/primitives/alert\";\nimport { useQuery, useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { apiCall, withScopedApiRequestHeaders } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { buildOptimisticLockHeader } from \"@open-mercato/ui/backend/utils/optimisticLock\";\nimport { surfaceRecordConflict } from \"@open-mercato/ui/backend/conflicts\";\nimport { raiseCrudError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { CrudForm } from \"@open-mercato/ui/backend/CrudForm\";\nimport { createOverrideFieldDefinitions, createOverrideFormGroups } from \"./overrideFormConfig\";\nimport { FeatureToggleOverrideResponse } from \"../data/validators\";\n\n\nexport function FeatureToggleOverrideCard({ toggleId }: { toggleId: string }) {\n const t = useT()\n const queryClient = useQueryClient()\n \n const { data: overrideData, isLoading, error } = useQuery({\n queryKey: ['feature_toggle_override', toggleId],\n queryFn: async () => {\n const call = await apiCall<FeatureToggleOverrideResponse>(`/api/feature_toggles/global/${toggleId}/override`)\n if (!call.ok) {\n await raiseCrudError(call.response, t('feature_toggles.override.error.load', 'Failed to load override'))\n }\n return call.result\n },\n enabled: !!toggleId\n })\n\n const mutation = useMutation({\n mutationFn: async (input: { toggleId: string; isOverride: boolean; overrideValue?: any; tenantId: string }) => {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(overrideData?.updatedAt ?? null),\n () => apiCall<{ ok: boolean }>(\n `/api/feature_toggles/overrides`,\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n toggleId: input.toggleId,\n isOverride: input.isOverride,\n overrideValue: input.overrideValue,\n }),\n },\n ),\n )\n if (!call.ok) {\n await raiseCrudError(call.response, t('feature_toggles.overrides.error.update', 'Failed to update override'))\n }\n return call.result\n },\n onError: (err: unknown) => {\n // Route an optimistic-lock 409 to the unified conflict bar; other errors\n // already surfaced via raiseCrudError inside mutationFn.\n surfaceRecordConflict(err, t)\n },\n onSettled: async () => {\n await queryClient.invalidateQueries({ queryKey: ['feature_toggle_override', toggleId] })\n await queryClient.invalidateQueries({ queryKey: ['feature_toggle_overrides'] })\n },\n })\n\n if (error) {\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t('feature_toggles.override.title', 'Override')}</CardTitle>\n </CardHeader>\n <CardContent>\n <Alert variant=\"destructive\">\n <AlertTitle>{t('ui.errors.defaultTitle', 'Something went wrong')}</AlertTitle>\n <AlertDescription>{error.message}</AlertDescription>\n </Alert>\n </CardContent>\n </Card>\n )\n }\n\n const fieldDefinitions = createOverrideFieldDefinitions(t)\n const formGroups = createOverrideFormGroups(t)\n const initialValues = overrideData ? {\n isOverride: overrideData.id === '' ? false : true,\n overrideValue: overrideData.value,\n toggleType: overrideData.toggleType,\n tenantId: overrideData.tenantId,\n tenantName: overrideData.tenantName,\n } : {}\n\n const handleSubmit = async (values: any) => {\n if (!overrideData) return\n await mutation.mutateAsync({\n toggleId,\n isOverride: values.isOverride,\n overrideValue: values.overrideValue,\n tenantId: overrideData.tenantId\n })\n }\n\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t('feature_toggles.override.title', 'Override')}</CardTitle>\n {overrideData ? (\n <CardDescription>{t('feature_toggles.override.tenant', 'Tenant: {{name}}', { name: overrideData.tenantName })}</CardDescription>\n ) : <CardDescription className=\"h-5 w-48 animate-pulse bg-zinc-100 dark:bg-zinc-800 rounded-md\" />}\n </CardHeader>\n <CardContent>\n <DataLoader\n isLoading={isLoading}\n showSkeleton\n skeletonComponent={\n <div className=\"space-y-4\">\n <div className=\"h-9 w-full animate-pulse rounded-md bg-zinc-100 dark:bg-zinc-800\" />\n <div className=\"h-20 w-full animate-pulse rounded-md bg-zinc-100 dark:bg-zinc-800\" />\n </div>\n }\n >\n {overrideData && (\n <CrudForm\n fields={fieldDefinitions}\n groups={formGroups}\n initialValues={initialValues}\n onSubmit={handleSubmit}\n submitLabel={t('feature_toggles.override.save', 'Save Override')}\n embedded={true}\n isLoading={false}\n />\n )}\n </DataLoader>\n </CardContent>\n </Card>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -13,13 +13,23 @@ import {
13
13
  } from "../lib/actions.js";
14
14
  import { getMessageType } from "../lib/message-types-registry.js";
15
15
  import { assertOrganizationAccess } from "./shared.js";
16
+ const actionStateSnapshotSchema = z.object({
17
+ actionTaken: z.string().nullable(),
18
+ actionTakenByUserId: z.string().nullable(),
19
+ actionTakenAt: z.string().nullable(),
20
+ actionResult: z.record(z.string(), z.unknown()).nullable()
21
+ });
16
22
  const recordTerminalActionSchema = z.object({
17
23
  messageId: z.string().uuid(),
18
24
  actionId: z.string().min(1),
19
25
  result: z.record(z.string(), z.unknown()),
20
26
  tenantId: z.string().uuid(),
21
27
  organizationId: z.string().uuid().nullable(),
22
- userId: z.string().uuid()
28
+ userId: z.string().uuid(),
29
+ // Optional pre-claim snapshot supplied by `messages.actions.execute` so the
30
+ // undo log records the true (un-taken) state even though the terminal action
31
+ // was atomically claimed before this finalizer runs.
32
+ previousState: actionStateSnapshotSchema.optional()
23
33
  });
24
34
  const executeActionSchema = z.object({
25
35
  messageId: z.string().uuid(),
@@ -100,12 +110,29 @@ const recordTerminalActionCommand = {
100
110
  const input = recordTerminalActionSchema.parse(rawInput);
101
111
  const em = ctx.container.resolve("em").fork();
102
112
  const message = await requireActionTarget(em, input);
103
- if (message.actionTaken) {
104
- throw new Error("Action already taken");
113
+ const claimedByCaller = message.actionTaken === input.actionId && message.actionTakenByUserId === input.userId;
114
+ if (!claimedByCaller) {
115
+ if (message.actionTaken) {
116
+ throw new Error("Action already taken");
117
+ }
118
+ const claimedRows = await em.nativeUpdate(
119
+ Message,
120
+ { id: input.messageId, tenantId: input.tenantId, actionTaken: null, deletedAt: null },
121
+ {
122
+ actionTaken: input.actionId,
123
+ actionTakenByUserId: input.userId,
124
+ actionTakenAt: /* @__PURE__ */ new Date()
125
+ }
126
+ );
127
+ if (claimedRows === 0) {
128
+ throw new Error("Action already taken");
129
+ }
130
+ message.actionTaken = input.actionId;
131
+ message.actionTakenByUserId = input.userId;
132
+ }
133
+ if (!message.actionTakenAt) {
134
+ message.actionTakenAt = /* @__PURE__ */ new Date();
105
135
  }
106
- message.actionTaken = input.actionId;
107
- message.actionTakenByUserId = input.userId;
108
- message.actionTakenAt = /* @__PURE__ */ new Date();
109
136
  message.actionResult = input.result;
110
137
  await em.flush();
111
138
  return { ok: true };
@@ -118,6 +145,7 @@ const recordTerminalActionCommand = {
118
145
  },
119
146
  buildLog: async ({ input, snapshots }) => {
120
147
  const parsed = recordTerminalActionSchema.parse(input);
148
+ const before = parsed.previousState ?? snapshots.before ?? null;
121
149
  return {
122
150
  actionLabel: "Execute message terminal action",
123
151
  resourceKind: "messages.message",
@@ -126,11 +154,11 @@ const recordTerminalActionCommand = {
126
154
  organizationId: parsed.organizationId,
127
155
  payload: {
128
156
  undo: {
129
- before: snapshots.before ?? null,
157
+ before,
130
158
  after: snapshots.after ?? null
131
159
  }
132
160
  },
133
- snapshotBefore: snapshots.before ?? null,
161
+ snapshotBefore: before,
134
162
  snapshotAfter: snapshots.after ?? null
135
163
  };
136
164
  },
@@ -179,6 +207,46 @@ const executeActionCommand = {
179
207
  }
180
208
  }
181
209
  }
210
+ const previousState = snapshotActionState(message);
211
+ let claimedTerminal = false;
212
+ const releaseTerminalClaim = async () => {
213
+ if (!claimedTerminal) return;
214
+ claimedTerminal = false;
215
+ await em.nativeUpdate(
216
+ Message,
217
+ {
218
+ id: message.id,
219
+ tenantId: input.tenantId,
220
+ actionTaken: action.id,
221
+ actionTakenByUserId: input.userId
222
+ },
223
+ { actionTaken: null, actionTakenByUserId: null, actionTakenAt: null }
224
+ );
225
+ };
226
+ if (shouldRecordActionTaken) {
227
+ const claimedRows = await em.nativeUpdate(
228
+ Message,
229
+ { id: message.id, tenantId: input.tenantId, actionTaken: null, deletedAt: null },
230
+ {
231
+ actionTaken: action.id,
232
+ actionTakenByUserId: input.userId,
233
+ actionTakenAt: /* @__PURE__ */ new Date()
234
+ }
235
+ );
236
+ if (claimedRows === 0) {
237
+ const current = await findOneWithDecryption(
238
+ em,
239
+ Message,
240
+ { id: message.id, tenantId: input.tenantId, deletedAt: null },
241
+ void 0,
242
+ { tenantId: input.tenantId, organizationId: input.organizationId }
243
+ );
244
+ throw Object.assign(new Error("Action already taken"), {
245
+ actionTaken: current?.actionTaken ?? message.actionTaken ?? action.id
246
+ });
247
+ }
248
+ claimedTerminal = true;
249
+ }
182
250
  const commandBus = ctx.container.resolve("commandBus");
183
251
  let result = {};
184
252
  let operationLogEntry = null;
@@ -223,6 +291,7 @@ const executeActionCommand = {
223
291
  operationLogEntry = commandResult.logEntry ?? null;
224
292
  } catch (err) {
225
293
  console.error("[messages] executeActionCommand sub-command failed", err);
294
+ await releaseTerminalClaim();
226
295
  throw new Error("Action failed");
227
296
  }
228
297
  } else if (action.href) {
@@ -232,10 +301,12 @@ const executeActionCommand = {
232
301
  userId: input.userId
233
302
  });
234
303
  if (!safeRedirect) {
304
+ await releaseTerminalClaim();
235
305
  throw new Error("Action has an unsafe redirect target");
236
306
  }
237
307
  result = { redirect: safeRedirect };
238
308
  } else {
309
+ await releaseTerminalClaim();
239
310
  throw new Error("Action has no executable target");
240
311
  }
241
312
  if (shouldRecordActionTaken) {
@@ -246,7 +317,8 @@ const executeActionCommand = {
246
317
  result,
247
318
  tenantId: input.tenantId,
248
319
  organizationId: input.organizationId,
249
- userId: input.userId
320
+ userId: input.userId,
321
+ previousState
250
322
  },
251
323
  ctx: {
252
324
  container: ctx.container,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/messages/commands/actions.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { Message, MessageObject, MessageRecipient } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n findResolvedMessageActionById,\n isTerminalMessageAction,\n resolveActionCommandInput,\n resolveActionHref,\n resolveMessageActionData,\n} from '../lib/actions'\nimport { getMessageType } from '../lib/message-types-registry'\nimport { assertOrganizationAccess, type MessageScopeInput } from './shared'\n\nconst recordTerminalActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n result: z.record(z.string(), z.unknown()),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\ntype RecordTerminalActionInput = z.infer<typeof recordTerminalActionSchema>\n\nconst executeActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n payload: z.record(z.string(), z.unknown()).optional(),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\ntype ExecuteActionInput = z.infer<typeof executeActionSchema>\n\ntype ActionStateSnapshot = {\n actionTaken: string | null\n actionTakenByUserId: string | null\n actionTakenAt: string | null\n actionResult: Record<string, unknown> | null\n}\n\nfunction toIso(value: Date | null | undefined): string | null {\n return value ? value.toISOString() : null\n}\n\nfunction toDate(value: string | null | undefined): Date | null {\n if (!value) return null\n return new Date(value)\n}\n\nasync function requireActionTarget(em: EntityManager, input: RecordTerminalActionInput) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nasync function requireActionMessage(em: EntityManager, input: ExecuteActionInput) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nfunction snapshotActionState(message: Message): ActionStateSnapshot {\n return {\n actionTaken: message.actionTaken ?? null,\n actionTakenByUserId: message.actionTakenByUserId ?? null,\n actionTakenAt: toIso(message.actionTakenAt),\n actionResult: message.actionResult ?? null,\n }\n}\n\nconst recordTerminalActionCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.actions.record_terminal',\n async prepare(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return { before: snapshotActionState(message) }\n },\n async execute(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n if (message.actionTaken) {\n throw new Error('Action already taken')\n }\n message.actionTaken = input.actionId\n message.actionTakenByUserId = input.userId\n message.actionTakenAt = new Date()\n message.actionResult = input.result\n await em.flush()\n return { ok: true }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return snapshotActionState(message)\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = recordTerminalActionSchema.parse(input)\n return {\n actionLabel: 'Execute message terminal action',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before: (snapshots.before as ActionStateSnapshot | undefined) ?? null,\n after: (snapshots.after as ActionStateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<ActionStateSnapshot>,\n },\n snapshotBefore: snapshots.before ?? null,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<ActionStateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const messageId = logEntry?.resourceId as string | null\n if (!messageId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await findOneWithDecryption(em, Message, { id: messageId })\n if (!message) return\n message.actionTaken = before.actionTaken\n message.actionTakenByUserId = before.actionTakenByUserId\n message.actionTakenAt = toDate(before.actionTakenAt)\n message.actionResult = before.actionResult\n await em.flush()\n },\n}\n\nconst executeActionCommand: CommandHandler<\n unknown,\n { ok: true; actionId: string; result: Record<string, unknown>; operationLogEntry: unknown | null }\n> = {\n id: 'messages.actions.execute',\n async execute(rawInput, ctx) {\n const input = executeActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionMessage(em, input)\n const objects = await em.find(MessageObject, { messageId: message.id })\n const action = findResolvedMessageActionById(message, objects, input.actionId)\n\n if (!action) {\n throw new Error('Action not found')\n }\n\n if (message.actionTaken) {\n throw Object.assign(new Error('Action already taken'), { actionTaken: message.actionTaken })\n }\n\n const shouldRecordActionTaken = isTerminalMessageAction(action)\n\n const actionData = resolveMessageActionData(message)\n if (actionData?.expiresAt) {\n if (new Date(actionData.expiresAt) < new Date()) {\n throw new Error('Actions have expired')\n }\n } else {\n const messageType = getMessageType(message.type)\n if (messageType?.actionsExpireAfterHours && message.sentAt) {\n const expiry = new Date(message.sentAt.getTime() + messageType.actionsExpireAfterHours * 60 * 60 * 1000)\n if (expiry < new Date()) {\n throw new Error('Actions have expired')\n }\n }\n }\n\n const commandBus = ctx.container.resolve('commandBus') as {\n execute: (\n commandId: string,\n options: { input: unknown; ctx: unknown; metadata?: unknown }\n ) => Promise<{ result: unknown; logEntry?: unknown }>\n }\n\n let result: Record<string, unknown> = {}\n let operationLogEntry: unknown | null = null\n\n if (action.commandId) {\n try {\n const actionInput = resolveActionCommandInput(\n action,\n message,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n },\n input.payload ?? {},\n )\n\n if (actionInput.id == null) {\n const fallbackId = action.objectRef?.entityId ?? message.sourceEntityId ?? null\n if (typeof fallbackId === 'string' && fallbackId.trim().length > 0) {\n actionInput.id = fallbackId\n }\n }\n\n const commandResult = await commandBus.execute(action.commandId, {\n input: actionInput,\n ctx: {\n container: ctx.container,\n auth: {\n sub: input.userId,\n tenantId: input.tenantId,\n orgId: input.organizationId,\n },\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n metadata: {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n resourceKind: 'messages',\n },\n })\n\n result = (commandResult.result as Record<string, unknown>) ?? {}\n operationLogEntry = commandResult.logEntry ?? null\n } catch (err) {\n console.error('[messages] executeActionCommand sub-command failed', err)\n throw new Error('Action failed')\n }\n } else if (action.href) {\n const safeRedirect = resolveActionHref(action, message, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n })\n if (!safeRedirect) {\n throw new Error('Action has an unsafe redirect target')\n }\n result = { redirect: safeRedirect }\n } else {\n throw new Error('Action has no executable target')\n }\n\n if (shouldRecordActionTaken) {\n const terminalResult = await commandBus.execute('messages.actions.record_terminal', {\n input: {\n messageId: message.id,\n actionId: action.id,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n },\n ctx: {\n container: ctx.container,\n auth: ctx.auth ?? null,\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n })\n if (!operationLogEntry) {\n operationLogEntry = terminalResult.logEntry ?? null\n }\n await emitMessagesEvent(\n 'messages.message.action_taken',\n {\n messageId: message.id,\n actionId: action.id,\n userId: input.userId,\n recipientUserId: input.userId,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n { persistent: true }\n )\n }\n\n return {\n ok: true,\n actionId: action.id,\n result,\n operationLogEntry,\n }\n },\n}\n\nregisterCommand(recordTerminalActionCommand)\nregisterCommand(executeActionCommand)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { registerCommand, type CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { Message, MessageObject, MessageRecipient } from '../data/entities'\nimport { emitMessagesEvent } from '../events'\nimport {\n findResolvedMessageActionById,\n isTerminalMessageAction,\n resolveActionCommandInput,\n resolveActionHref,\n resolveMessageActionData,\n} from '../lib/actions'\nimport { getMessageType } from '../lib/message-types-registry'\nimport { assertOrganizationAccess, type MessageScopeInput } from './shared'\n\nconst actionStateSnapshotSchema = z.object({\n actionTaken: z.string().nullable(),\n actionTakenByUserId: z.string().nullable(),\n actionTakenAt: z.string().nullable(),\n actionResult: z.record(z.string(), z.unknown()).nullable(),\n})\n\nconst recordTerminalActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n result: z.record(z.string(), z.unknown()),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n // Optional pre-claim snapshot supplied by `messages.actions.execute` so the\n // undo log records the true (un-taken) state even though the terminal action\n // was atomically claimed before this finalizer runs.\n previousState: actionStateSnapshotSchema.optional(),\n})\n\ntype RecordTerminalActionInput = z.infer<typeof recordTerminalActionSchema>\n\nconst executeActionSchema = z.object({\n messageId: z.string().uuid(),\n actionId: z.string().min(1),\n payload: z.record(z.string(), z.unknown()).optional(),\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid().nullable(),\n userId: z.string().uuid(),\n})\n\ntype ExecuteActionInput = z.infer<typeof executeActionSchema>\n\ntype ActionStateSnapshot = {\n actionTaken: string | null\n actionTakenByUserId: string | null\n actionTakenAt: string | null\n actionResult: Record<string, unknown> | null\n}\n\nfunction toIso(value: Date | null | undefined): string | null {\n return value ? value.toISOString() : null\n}\n\nfunction toDate(value: string | null | undefined): Date | null {\n if (!value) return null\n return new Date(value)\n}\n\nasync function requireActionTarget(em: EntityManager, input: RecordTerminalActionInput) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nasync function requireActionMessage(em: EntityManager, input: ExecuteActionInput) {\n const message = await findOneWithDecryption(\n em,\n Message,\n {\n id: input.messageId,\n tenantId: input.tenantId,\n deletedAt: null,\n },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n if (!message) throw new Error('Message not found')\n assertOrganizationAccess(input as MessageScopeInput, message)\n const recipient = await em.findOne(MessageRecipient, {\n messageId: input.messageId,\n recipientUserId: input.userId,\n deletedAt: null,\n })\n if (!recipient) throw new Error('Access denied')\n return message\n}\n\nfunction snapshotActionState(message: Message): ActionStateSnapshot {\n return {\n actionTaken: message.actionTaken ?? null,\n actionTakenByUserId: message.actionTakenByUserId ?? null,\n actionTakenAt: toIso(message.actionTakenAt),\n actionResult: message.actionResult ?? null,\n }\n}\n\nconst recordTerminalActionCommand: CommandHandler<unknown, { ok: true }> = {\n id: 'messages.actions.record_terminal',\n async prepare(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return { before: snapshotActionState(message) }\n },\n async execute(rawInput, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n const claimedByCaller =\n message.actionTaken === input.actionId && message.actionTakenByUserId === input.userId\n if (!claimedByCaller) {\n if (message.actionTaken) {\n throw new Error('Action already taken')\n }\n // Atomic compare-and-set: only one concurrent request transitions the\n // message out of the un-taken state. nativeUpdate runs as a single\n // `UPDATE ... WHERE action_taken IS NULL` so the loser matches 0 rows.\n const claimedRows = await em.nativeUpdate(\n Message,\n { id: input.messageId, tenantId: input.tenantId, actionTaken: null, deletedAt: null },\n {\n actionTaken: input.actionId,\n actionTakenByUserId: input.userId,\n actionTakenAt: new Date(),\n },\n )\n if (claimedRows === 0) {\n throw new Error('Action already taken')\n }\n message.actionTaken = input.actionId\n message.actionTakenByUserId = input.userId\n }\n if (!message.actionTakenAt) {\n message.actionTakenAt = new Date()\n }\n // action_result is an encrypted column, so it must be written through the\n // flush path (the encryption subscriber) rather than nativeUpdate.\n message.actionResult = input.result\n await em.flush()\n return { ok: true }\n },\n async captureAfter(rawInput, _result, ctx) {\n const input = recordTerminalActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionTarget(em, input)\n return snapshotActionState(message)\n },\n buildLog: async ({ input, snapshots }) => {\n const parsed = recordTerminalActionSchema.parse(input)\n // When the action was pre-claimed by `messages.actions.execute`, the\n // prepare-captured snapshot already reflects the claimed state, so prefer\n // the explicit pre-claim snapshot for the undo baseline.\n const before =\n (parsed.previousState as ActionStateSnapshot | undefined) ??\n (snapshots.before as ActionStateSnapshot | undefined) ??\n null\n return {\n actionLabel: 'Execute message terminal action',\n resourceKind: 'messages.message',\n resourceId: parsed.messageId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n payload: {\n undo: {\n before,\n after: (snapshots.after as ActionStateSnapshot | undefined) ?? null,\n } satisfies UndoPayload<ActionStateSnapshot>,\n },\n snapshotBefore: before,\n snapshotAfter: snapshots.after ?? null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<UndoPayload<ActionStateSnapshot>>(logEntry)\n const before = undo?.before\n if (!before) return\n const messageId = logEntry?.resourceId as string | null\n if (!messageId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await findOneWithDecryption(em, Message, { id: messageId })\n if (!message) return\n message.actionTaken = before.actionTaken\n message.actionTakenByUserId = before.actionTakenByUserId\n message.actionTakenAt = toDate(before.actionTakenAt)\n message.actionResult = before.actionResult\n await em.flush()\n },\n}\n\nconst executeActionCommand: CommandHandler<\n unknown,\n { ok: true; actionId: string; result: Record<string, unknown>; operationLogEntry: unknown | null }\n> = {\n id: 'messages.actions.execute',\n async execute(rawInput, ctx) {\n const input = executeActionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const message = await requireActionMessage(em, input)\n const objects = await em.find(MessageObject, { messageId: message.id })\n const action = findResolvedMessageActionById(message, objects, input.actionId)\n\n if (!action) {\n throw new Error('Action not found')\n }\n\n if (message.actionTaken) {\n throw Object.assign(new Error('Action already taken'), { actionTaken: message.actionTaken })\n }\n\n const shouldRecordActionTaken = isTerminalMessageAction(action)\n\n const actionData = resolveMessageActionData(message)\n if (actionData?.expiresAt) {\n if (new Date(actionData.expiresAt) < new Date()) {\n throw new Error('Actions have expired')\n }\n } else {\n const messageType = getMessageType(message.type)\n if (messageType?.actionsExpireAfterHours && message.sentAt) {\n const expiry = new Date(message.sentAt.getTime() + messageType.actionsExpireAfterHours * 60 * 60 * 1000)\n if (expiry < new Date()) {\n throw new Error('Actions have expired')\n }\n }\n }\n\n // Capture the un-taken state for the undo log before reserving the action.\n const previousState = snapshotActionState(message)\n let claimedTerminal = false\n const releaseTerminalClaim = async () => {\n if (!claimedTerminal) return\n claimedTerminal = false\n await em.nativeUpdate(\n Message,\n {\n id: message.id,\n tenantId: input.tenantId,\n actionTaken: action.id,\n actionTakenByUserId: input.userId,\n },\n { actionTaken: null, actionTakenByUserId: null, actionTakenAt: null },\n )\n }\n\n if (shouldRecordActionTaken) {\n // Atomically reserve the terminal action BEFORE running the target\n // command so concurrent requests cannot both execute it. The losing\n // request matches 0 rows and surfaces the existing 409 response.\n const claimedRows = await em.nativeUpdate(\n Message,\n { id: message.id, tenantId: input.tenantId, actionTaken: null, deletedAt: null },\n {\n actionTaken: action.id,\n actionTakenByUserId: input.userId,\n actionTakenAt: new Date(),\n },\n )\n if (claimedRows === 0) {\n const current = await findOneWithDecryption(\n em,\n Message,\n { id: message.id, tenantId: input.tenantId, deletedAt: null },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n throw Object.assign(new Error('Action already taken'), {\n actionTaken: current?.actionTaken ?? message.actionTaken ?? action.id,\n })\n }\n claimedTerminal = true\n }\n\n const commandBus = ctx.container.resolve('commandBus') as {\n execute: (\n commandId: string,\n options: { input: unknown; ctx: unknown; metadata?: unknown }\n ) => Promise<{ result: unknown; logEntry?: unknown }>\n }\n\n let result: Record<string, unknown> = {}\n let operationLogEntry: unknown | null = null\n\n if (action.commandId) {\n try {\n const actionInput = resolveActionCommandInput(\n action,\n message,\n {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n },\n input.payload ?? {},\n )\n\n if (actionInput.id == null) {\n const fallbackId = action.objectRef?.entityId ?? message.sourceEntityId ?? null\n if (typeof fallbackId === 'string' && fallbackId.trim().length > 0) {\n actionInput.id = fallbackId\n }\n }\n\n const commandResult = await commandBus.execute(action.commandId, {\n input: actionInput,\n ctx: {\n container: ctx.container,\n auth: {\n sub: input.userId,\n tenantId: input.tenantId,\n orgId: input.organizationId,\n },\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n metadata: {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n resourceKind: 'messages',\n },\n })\n\n result = (commandResult.result as Record<string, unknown>) ?? {}\n operationLogEntry = commandResult.logEntry ?? null\n } catch (err) {\n console.error('[messages] executeActionCommand sub-command failed', err)\n // The target command never completed \u2014 release the reservation so the\n // action stays retryable, matching the pre-claim failure semantics.\n await releaseTerminalClaim()\n throw new Error('Action failed')\n }\n } else if (action.href) {\n const safeRedirect = resolveActionHref(action, message, {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n })\n if (!safeRedirect) {\n await releaseTerminalClaim()\n throw new Error('Action has an unsafe redirect target')\n }\n result = { redirect: safeRedirect }\n } else {\n await releaseTerminalClaim()\n throw new Error('Action has no executable target')\n }\n\n if (shouldRecordActionTaken) {\n const terminalResult = await commandBus.execute('messages.actions.record_terminal', {\n input: {\n messageId: message.id,\n actionId: action.id,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n userId: input.userId,\n previousState,\n },\n ctx: {\n container: ctx.container,\n auth: ctx.auth ?? null,\n organizationScope: null,\n selectedOrganizationId: input.organizationId,\n organizationIds: input.organizationId ? [input.organizationId] : null,\n },\n })\n if (!operationLogEntry) {\n operationLogEntry = terminalResult.logEntry ?? null\n }\n await emitMessagesEvent(\n 'messages.message.action_taken',\n {\n messageId: message.id,\n actionId: action.id,\n userId: input.userId,\n recipientUserId: input.userId,\n result,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n { persistent: true }\n )\n }\n\n return {\n ok: true,\n actionId: action.id,\n result,\n operationLogEntry,\n }\n },\n}\n\nregisterCommand(recordTerminalActionCommand)\nregisterCommand(executeActionCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6088.1.e6193c2018",
3
+ "version": "0.6.6-develop.6094.1.28b081ea16",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -246,16 +246,16 @@
246
246
  "zod": "^4.4.3"
247
247
  },
248
248
  "peerDependencies": {
249
- "@open-mercato/ai-assistant": "0.6.6-develop.6088.1.e6193c2018",
250
- "@open-mercato/shared": "0.6.6-develop.6088.1.e6193c2018",
251
- "@open-mercato/ui": "0.6.6-develop.6088.1.e6193c2018",
249
+ "@open-mercato/ai-assistant": "0.6.6-develop.6094.1.28b081ea16",
250
+ "@open-mercato/shared": "0.6.6-develop.6094.1.28b081ea16",
251
+ "@open-mercato/ui": "0.6.6-develop.6094.1.28b081ea16",
252
252
  "react": "^19.0.0",
253
253
  "react-dom": "^19.0.0"
254
254
  },
255
255
  "devDependencies": {
256
- "@open-mercato/ai-assistant": "0.6.6-develop.6088.1.e6193c2018",
257
- "@open-mercato/shared": "0.6.6-develop.6088.1.e6193c2018",
258
- "@open-mercato/ui": "0.6.6-develop.6088.1.e6193c2018",
256
+ "@open-mercato/ai-assistant": "0.6.6-develop.6094.1.28b081ea16",
257
+ "@open-mercato/shared": "0.6.6-develop.6094.1.28b081ea16",
258
+ "@open-mercato/ui": "0.6.6-develop.6094.1.28b081ea16",
259
259
  "@testing-library/dom": "^10.4.1",
260
260
  "@testing-library/jest-dom": "^6.9.1",
261
261
  "@testing-library/react": "^16.3.1",