@happyvertical/smrt-content 0.57.32 → 0.57.33

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.
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":["workflow"],"sources":["../src/server/content-list-actions.ts","../src/server/content-list-data-surface.ts","../src/server/content-list-lifecycle.ts","../src/server.ts"],"sourcesContent":["/**\n * Principal-bound ContentList bulk workflows (#2453).\n *\n * The generic action adapter owns confirmation tokens, idempotency, principal\n * execution, permission checks, per-row outcomes, and background acceptance.\n * This module supplies the content-specific half: declarative workflows,\n * canonical query resolution, row-revision binding, governance eligibility,\n * and domain mutations.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHash } from 'node:crypto';\n// Publication and automated-review permissions include facts operations. The\n// catalog is registration-driven, so ensure those definitions exist even when\n// a host imports only the content server entry point.\nimport '@happyvertical/smrt-facts';\nimport {\n type PrincipalRun,\n PrincipalToolNotAllowedError,\n} from '@happyvertical/smrt-agents';\nimport {\n createDataSurfaceActionAdapter,\n type DataSurfaceActionAdapter,\n type DataSurfaceActionStateStore,\n type DataSurfaceBackgroundQueue,\n type DataSurfaceServerActionContext,\n type DataSurfaceServerActionDefinition,\n type DataSurfaceServerActionRequest,\n isBoundedDataSurfaceJsonValue,\n} from '@happyvertical/smrt-agents/server';\nimport {\n createDataQueryFingerprint,\n MAX_DATA_QUERY_PAGE_LIMIT,\n normalizeDataQueryRequest,\n} from '@happyvertical/smrt-core';\nimport type {\n DataQueryRequest,\n DataSurfaceActionResult,\n DataSurfaceDescriptor,\n DataSurfaceIdentity,\n DataSurfaceJsonObject,\n DataSurfaceJsonValue,\n DataSurfaceRowId,\n} from '@happyvertical/smrt-types';\nimport type { ContentBodyFormat } from '../body-format.js';\nimport type { Content } from '../content.js';\nimport {\n buildContentQuerySchema,\n CONTENT_QUERY_MAX_PAGE_LIMIT,\n type ContentQueryCollection,\n type ContentQueryScope,\n executeContentQuery,\n} from '../content-query.js';\n\nexport const CONTENT_LIST_WORKFLOW_IDS = [\n 'move-to-trash',\n 'mark-draft',\n 'submit-review',\n 'publish',\n 'archive',\n 'restore',\n 'automated-review',\n 'format-body',\n 'categorize',\n 'optimize',\n] as const;\n\nexport type ContentListWorkflowId = (typeof CONTENT_LIST_WORKFLOW_IDS)[number];\nexport const CONTENT_LIST_LIFECYCLE_ACTION_IDS = [\n 'move-to-trash',\n 'restore',\n 'permanent-delete',\n] as const;\nexport type ContentListLifecycleActionId =\n (typeof CONTENT_LIST_LIFECYCLE_ACTION_IDS)[number];\nexport type ContentListServerActionId =\n | ContentListWorkflowId\n | ContentListLifecycleActionId;\nexport type ContentListWorkflowExecution = 'foreground' | 'background';\nexport type ContentListWorkflowConfirmation = 'required' | 'none';\n\nexport interface ContentListWorkflowDescriptor {\n id: ContentListServerActionId;\n label: string;\n description: string;\n selectionScopes: Array<'current-page' | 'explicit-ids' | 'all-matching'>;\n sensitivity: 'public' | 'sensitive';\n confirmation: ContentListWorkflowConfirmation;\n execution: ContentListWorkflowExecution;\n inputSchema: DataSurfaceJsonObject | null;\n eligibility: string[];\n permissionRequirements: {\n tool: string;\n operations: Array<{ id: string; collection: string; action: string }>;\n };\n consequences: string[];\n partialResult: {\n statuses: Array<'accepted' | 'skipped' | 'failed'>;\n preservesFailedSelection: true;\n };\n}\n\nconst ALL_SELECTION_SCOPES: ContentListWorkflowDescriptor['selectionScopes'] = [\n 'current-page',\n 'explicit-ids',\n 'all-matching',\n];\n\nconst NO_INPUT: DataSurfaceJsonObject = {\n type: 'object',\n additionalProperties: false,\n};\n\nconst OPTIONAL_REVIEW_INPUT: DataSurfaceJsonObject = {\n type: 'object',\n additionalProperties: false,\n properties: {\n kind: { type: 'string', enum: ['facts', 'safety', 'custom'] },\n policyKey: { type: 'string', maxLength: 128 },\n },\n};\n\nconst CONTENT_UPDATE_OPERATION = {\n id: 'contents:update',\n collection: 'contents',\n action: 'update',\n};\n\nconst CONTENT_READ_OPERATION = {\n id: 'contents:read',\n collection: 'contents',\n action: 'read',\n};\n\nconst GOVERNANCE_READ_OPERATIONS = [\n {\n id: 'content-governance-assignments:read',\n collection: 'contentgovernanceassignments',\n action: 'read',\n },\n {\n id: 'content-governance-policies:read',\n collection: 'contentgovernancepolicies',\n action: 'read',\n },\n {\n id: 'content-governance-profiles:read',\n collection: 'contentgovernanceprofiles',\n action: 'read',\n },\n] as const;\n\nconst PUBLICATION_OPERATIONS = [\n CONTENT_READ_OPERATION,\n CONTENT_UPDATE_OPERATION,\n ...GOVERNANCE_READ_OPERATIONS,\n {\n id: 'content-references:read',\n collection: 'contentreferences',\n action: 'read',\n },\n {\n id: 'content-assets:read',\n collection: 'contentassets',\n action: 'read',\n },\n { id: 'assets:read', collection: 'assets', action: 'read' },\n { id: 'facts:read', collection: 'facts', action: 'read' },\n { id: 'fact-contents:read', collection: 'factcontents', action: 'read' },\n { id: 'fact-sources:read', collection: 'factsources', action: 'read' },\n { id: 'content-reviews:read', collection: 'contentreviews', action: 'read' },\n {\n id: 'content-corrections:read',\n collection: 'contentcorrections',\n action: 'read',\n },\n {\n id: 'content-versions:read',\n collection: 'contentversions',\n action: 'read',\n },\n {\n id: 'content-versions:create',\n collection: 'contentversions',\n action: 'create',\n },\n] as const;\n\nconst AUTOMATED_REVIEW_OPERATIONS = [\n ...PUBLICATION_OPERATIONS,\n {\n id: 'prompt-overrides:read',\n collection: 'promptoverrides',\n action: 'read',\n },\n {\n id: 'content-reviews:create',\n collection: 'contentreviews',\n action: 'create',\n },\n] as const;\n\nexport const CONTENT_LIST_WORKFLOWS: readonly ContentListWorkflowDescriptor[] =\n Object.freeze([\n workflow('move-to-trash', 'Move to trash', {\n description: 'Soft-delete eligible content into the trash lifecycle.',\n sensitivity: 'sensitive',\n eligibility: ['content is not already deleted'],\n consequences: [\n 'Content leaves active views and becomes restorable from trash.',\n ],\n }),\n workflow('mark-draft', 'Mark draft', {\n description: 'Return eligible active content to draft.',\n eligibility: ['content is not deleted', 'content is not already draft'],\n consequences: ['Published content is no longer public.'],\n }),\n workflow('submit-review', 'Submit for review', {\n description: 'Move eligible draft content into editorial review.',\n eligibility: ['content is draft'],\n consequences: ['Content enters the review queue.'],\n }),\n workflow('publish', 'Publish', {\n description: 'Publish content that passes current governance readiness.',\n sensitivity: 'sensitive',\n eligibility: [\n 'content is draft, review, or archived',\n 'publication readiness passes',\n ],\n consequences: [\n 'Content becomes public and may create a publication snapshot.',\n ],\n permissionRequirements: {\n tool: 'content.workflow.publish',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('archive', 'Archive', {\n description: 'Remove eligible content from active publication workflows.',\n eligibility: [\n 'content is not deleted',\n 'content is not already archived',\n ],\n consequences: ['Published content is no longer public.'],\n }),\n workflow('restore', 'Restore', {\n description: 'Restore deleted content to an explicit eligible status.',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['status'],\n properties: {\n status: { enum: ['draft', 'review', 'published'] },\n },\n },\n eligibility: [\n 'content is deleted',\n 'requested destination is valid',\n 'publish readiness passes when publishing',\n ],\n consequences: [\n 'Content leaves trash.',\n 'Publishing makes content public.',\n ],\n permissionRequirements: {\n tool: 'content.workflow.restore',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('automated-review', 'Automated review', {\n description: 'Run the configured content governance review.',\n execution: 'background',\n inputSchema: OPTIONAL_REVIEW_INPUT,\n eligibility: [\n 'content is not deleted',\n 'content governance is configured',\n ],\n consequences: [\n 'Creates a review result and may create a review version.',\n ],\n permissionRequirements: {\n tool: 'content.workflow.automated-review',\n operations: [...AUTOMATED_REVIEW_OPERATIONS],\n },\n }),\n workflow('format-body', 'Format body', {\n description: 'Run the application-owned body-formatting workflow.',\n execution: 'background',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n properties: { format: { enum: ['markdown', 'html'] } },\n },\n eligibility: [\n 'content is not deleted',\n 'a formatting handler is configured',\n ],\n consequences: ['The persisted content body may change.'],\n permissionRequirements: {\n tool: 'content.workflow.format-body',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('categorize', 'Categorize', {\n description: 'Assign one required hierarchical category path.',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['category'],\n properties: {\n category: { type: 'string', minLength: 1, maxLength: 256 },\n },\n },\n eligibility: ['content is not deleted', 'category is non-empty'],\n consequences: ['The content category changes.'],\n permissionRequirements: {\n tool: 'content.workflow.categorize',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('optimize', 'Optimize / complete', {\n description: 'Run the application-owned content optimization workflow.',\n execution: 'background',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n properties: { instructions: { type: 'string', maxLength: 4096 } },\n },\n eligibility: [\n 'content is draft or review',\n 'an optimization handler is configured',\n ],\n consequences: ['Content fields may be revised or completed.'],\n }),\n ]);\n\nconst PERMANENT_DELETE_ACTION: ContentListWorkflowDescriptor = workflow(\n 'permanent-delete',\n 'Delete permanently',\n {\n description: 'Permanently delete content that is already in trash.',\n sensitivity: 'sensitive',\n eligibility: ['content is deleted'],\n consequences: [\n 'Content and its owned lifecycle data are irreversibly deleted.',\n ],\n permissionRequirements: {\n tool: 'content.lifecycle.permanent-delete',\n operations: [\n CONTENT_READ_OPERATION,\n {\n id: 'contents:delete',\n collection: 'contents',\n action: 'delete',\n },\n ],\n },\n },\n);\n\n/** The lifecycle-only catalog exposed by the dedicated route/service. */\nexport const CONTENT_LIST_LIFECYCLE_ACTIONS: readonly ContentListWorkflowDescriptor[] =\n Object.freeze([\n contentListWorkflow('move-to-trash'),\n contentListWorkflow('restore'),\n PERMANENT_DELETE_ACTION,\n ]);\n\nconst CONTENT_LIST_SERVER_ACTIONS: readonly ContentListWorkflowDescriptor[] =\n Object.freeze([...CONTENT_LIST_WORKFLOWS, PERMANENT_DELETE_ACTION]);\n\nfunction contentListWorkflow(\n id: ContentListWorkflowId,\n): ContentListWorkflowDescriptor {\n const descriptor = CONTENT_LIST_WORKFLOWS.find((entry) => entry.id === id);\n if (!descriptor) throw new Error(`Missing ContentList workflow: ${id}`);\n return descriptor;\n}\n\nfunction workflow(\n id: ContentListServerActionId,\n label: string,\n options: Partial<ContentListWorkflowDescriptor> &\n Pick<\n ContentListWorkflowDescriptor,\n 'description' | 'eligibility' | 'consequences'\n >,\n): ContentListWorkflowDescriptor {\n return {\n id,\n label,\n description: options.description,\n selectionScopes: options.selectionScopes ?? [...ALL_SELECTION_SCOPES],\n sensitivity: options.sensitivity ?? 'public',\n confirmation: options.confirmation ?? 'required',\n execution: options.execution ?? 'foreground',\n inputSchema: options.inputSchema ?? NO_INPUT,\n eligibility: options.eligibility,\n permissionRequirements: options.permissionRequirements ?? {\n tool: `content.workflow.${id}`,\n operations: [CONTENT_READ_OPERATION, CONTENT_UPDATE_OPERATION],\n },\n consequences: options.consequences,\n partialResult: {\n statuses: ['accepted', 'skipped', 'failed'],\n preservesFailedSelection: true,\n },\n };\n}\n\nexport interface ContentListActionTarget {\n /** Canonical query sent to the content query endpoint. Required except for explicit IDs. */\n query?: DataQueryRequest;\n /** Count visible at selection time; drift fails the preview/apply. */\n expectedCount: number;\n /** Operator-entered preview count, required only for permanent-delete apply. */\n confirmedCount?: number;\n}\n\nexport interface ContentListActionRequest\n extends DataSurfaceServerActionRequest {\n actionId: ContentListServerActionId;\n target: ContentListActionTarget;\n}\n\nexport interface ContentListActionCollection extends ContentQueryCollection {\n get(filter: string | Record<string, unknown>): Promise<Content | null>;\n}\n\n/**\n * Persistence-free copy supplied to host format/optimize handlers.\n *\n * Only the explicitly copied mutable fields are applied back to Content before\n * the adapter's revision-guarded save. Identity, tenancy, lifecycle state,\n * relationship IDs, database handles, and Content persistence methods are\n * deliberately absent.\n */\nexport interface ContentListWorkflowDraft {\n readonly contentId: string;\n readonly tenantId: string | null;\n readonly type: string | null;\n readonly variant: string | null;\n readonly status: Content['status'];\n readonly state: Content['state'];\n fileKey: string | null;\n author: string | null;\n name: string;\n title: string;\n description: string | null;\n body: string;\n bodyFormat: ContentBodyFormat | null;\n publish_date: Date | null;\n url: string | null;\n source: string | null;\n original_url: string | null;\n language: string | null;\n tags: string[];\n category: string | null;\n metadata: Record<string, unknown>;\n thumbnailAssetId: string | null;\n}\n\nexport interface ContentListWorkflowHandlers {\n /** Mutate a persistence-free draft; the adapter applies it by revision CAS. */\n formatBody?: (\n content: ContentListWorkflowDraft,\n payload: DataSurfaceJsonValue | undefined,\n run: PrincipalRun,\n ) => Promise<void>;\n /** Mutate a persistence-free draft; the adapter applies it by revision CAS. */\n optimize?: (\n content: ContentListWorkflowDraft,\n payload: DataSurfaceJsonValue | undefined,\n run: PrincipalRun,\n ) => Promise<void>;\n}\n\nexport interface ContentListWorkflowStorage {\n adapterType: 'sqlite' | 'postgres' | 'duckdb' | 'json';\n writeStrategy?: 'immediate' | 'manual' | 'none';\n}\n\nexport class UnsupportedContentListWorkflowStorageError extends Error {\n readonly code = 'UNSUPPORTED_CONTENT_LIST_WORKFLOW_STORAGE';\n\n constructor(storage: ContentListWorkflowStorage) {\n super(\n `ContentList workflows do not support ${storage.adapterType} with ` +\n 'immediate write-back because exported files are not transactionally ' +\n 'rolled back. Use PostgreSQL, SQLite, ordinary DuckDB, or a ' +\n 'non-immediate write strategy.',\n );\n this.name = 'UnsupportedContentListWorkflowStorageError';\n }\n}\n\nexport function assertContentListWorkflowStorageSupported(\n storage: ContentListWorkflowStorage,\n): void {\n const adapterType: unknown = storage?.adapterType;\n const writeStrategy: unknown = storage?.writeStrategy;\n if (\n adapterType !== 'sqlite' &&\n adapterType !== 'postgres' &&\n adapterType !== 'duckdb' &&\n adapterType !== 'json'\n ) {\n throw new TypeError(\n 'ContentList workflow storage adapterType must be sqlite, postgres, duckdb, or json.',\n );\n }\n if (\n writeStrategy !== undefined &&\n writeStrategy !== 'immediate' &&\n writeStrategy !== 'manual' &&\n writeStrategy !== 'none'\n ) {\n throw new TypeError(\n 'ContentList workflow storage writeStrategy must be immediate, manual, or none.',\n );\n }\n const effectiveStrategy =\n adapterType === 'json' ? (writeStrategy ?? 'immediate') : writeStrategy;\n if (\n (adapterType === 'json' || adapterType === 'duckdb') &&\n effectiveStrategy === 'immediate'\n ) {\n throw new UnsupportedContentListWorkflowStorageError({\n adapterType,\n writeStrategy: effectiveStrategy,\n });\n }\n}\n\nexport interface ContentListActionAdapterOptions {\n /** Public adapter capability contract; validated before any workflow state is created. */\n workflowStorage: ContentListWorkflowStorage;\n state: DataSurfaceActionStateStore;\n collection(\n run: PrincipalRun,\n ): ContentListActionCollection | Promise<ContentListActionCollection>;\n /** Trusted site/organization narrowing, applied in addition to tenant context. */\n scope?: (\n run: PrincipalRun,\n ) => ContentQueryScope | undefined | Promise<ContentQueryScope | undefined>;\n /** Server-owned mounted/catalog revision. Defaults to zero for standalone endpoints. */\n revision?: (\n run: PrincipalRun,\n identity: DataSurfaceIdentity,\n ) => number | Promise<number>;\n authorize?: (\n workflow: ContentListServerActionId,\n run: PrincipalRun,\n ) => boolean | Promise<boolean>;\n handlers?: ContentListWorkflowHandlers;\n backgroundQueue?: DataSurfaceBackgroundQueue;\n backgroundHandlerId?: string;\n /** In-process secret used to authenticate the durable background envelope. */\n deferredEnvelopeSigningKey?: string | Uint8Array;\n descriptor?: DataSurfaceDescriptor;\n maxSelectionSize?: number;\n representativeLimit?: number;\n tokenTtlMs?: number;\n /** Test/host seam for principal execution; production defaults to executeAsPrincipal. */\n runAsPrincipal?: typeof import('@happyvertical/smrt-agents').executeAsPrincipal;\n /** Resolve the live persona/TenantAgent binding before a queued mutation. */\n resolveDeferredPrincipal?: Parameters<\n typeof createDataSurfaceActionAdapter\n >[0]['resolveDeferredPrincipal'];\n}\n\ninterface ResolvedContentSelection {\n revision: number;\n queryFingerprint: string;\n rowIds: DataSurfaceRowId[];\n rows: Array<Record<string, unknown>>;\n representativeLabels: string[];\n scope: ContentListActionRequest['selection']['scope'];\n}\n\nconst REQUIRED_QUERY_FIELDS = ['id', 'title', 'status', 'updated_at'] as const;\nconst DEFAULT_MAX_SELECTION_SIZE = 200;\nconst DEFAULT_REPRESENTATIVE_LIMIT = 5;\n\nclass ContentListActionError extends Error {\n constructor(readonly reason: string) {\n super(reason);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isPermissionDenied(error: unknown): boolean {\n if (!(error instanceof Error) || error.name !== 'OperationPermissionError')\n return false;\n const decision = (error as Error & { decision?: unknown }).decision;\n return isRecord(decision) && decision.reason === 'permission_denied';\n}\n\nfunction isServerActionId(value: unknown): value is ContentListServerActionId {\n return CONTENT_LIST_SERVER_ACTIONS.some(({ id }) => id === value);\n}\n\nfunction payloadRecord(\n value: DataSurfaceJsonValue | undefined,\n): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction validPayload(\n workflowId: ContentListServerActionId,\n payload: DataSurfaceJsonValue | undefined,\n): boolean {\n if (payload !== undefined && !isRecord(payload)) return false;\n const value = payloadRecord(payload);\n const keys = Object.keys(value);\n switch (workflowId) {\n case 'restore':\n return (\n keys.length === 1 &&\n typeof value.status === 'string' &&\n ['draft', 'review', 'published'].includes(value.status)\n );\n case 'categorize':\n return (\n keys.length === 1 &&\n typeof value.category === 'string' &&\n value.category.trim().length > 0 &&\n value.category.length <= 256\n );\n case 'automated-review':\n return (\n keys.every((key) => ['kind', 'policyKey'].includes(key)) &&\n (value.kind === undefined ||\n (typeof value.kind === 'string' &&\n ['facts', 'safety', 'custom'].includes(value.kind) &&\n value.kind.length > 0 &&\n value.kind.length <= 64)) &&\n (value.policyKey === undefined ||\n (typeof value.policyKey === 'string' &&\n value.policyKey.length > 0 &&\n value.policyKey.length <= 128))\n );\n case 'format-body':\n return (\n keys.every((key) => key === 'format') &&\n (value.format === undefined ||\n value.format === 'markdown' ||\n value.format === 'html')\n );\n case 'optimize':\n return (\n keys.every((key) => key === 'instructions') &&\n (value.instructions === undefined ||\n (typeof value.instructions === 'string' &&\n value.instructions.length <= 4096))\n );\n default:\n return keys.length === 0;\n }\n}\n\nfunction actionResult(\n request: unknown,\n ok: boolean,\n reason?: string,\n): DataSurfaceActionResult {\n const candidate = isRecord(request) ? request : {};\n const identityCandidate = isRecord(candidate.identity)\n ? candidate.identity\n : {};\n const identity: DataSurfaceIdentity =\n typeof identityCandidate.surfaceId === 'string' &&\n ['table', 'list', 'report', 'custom'].includes(\n String(identityCandidate.kind),\n )\n ? (identityCandidate as unknown as DataSurfaceIdentity)\n : { surfaceId: 'content-list', kind: 'table' };\n return {\n version: 1,\n requestId:\n typeof candidate.requestId === 'string'\n ? candidate.requestId\n : 'invalid-request',\n identity,\n actionId:\n typeof candidate.actionId === 'string' ? candidate.actionId : 'invalid',\n phase: candidate.phase === 'apply' ? 'apply' : 'preview',\n ok,\n ...(reason ? { reason } : {}),\n };\n}\n\nfunction validateTarget(request: unknown): string | undefined {\n if (\n !isRecord(request) ||\n !isServerActionId(request.actionId) ||\n !isRecord(request.target) ||\n !isRecord(request.selection)\n )\n return 'invalid_request';\n const keys = Object.keys(request.target);\n if (\n keys.some(\n (key) =>\n key !== 'query' && key !== 'expectedCount' && key !== 'confirmedCount',\n )\n )\n return 'invalid_request';\n const expectedCount = request.target.expectedCount;\n if (\n typeof expectedCount !== 'number' ||\n !Number.isSafeInteger(expectedCount) ||\n expectedCount < 0\n ) {\n return 'invalid_request';\n }\n const requiresCountAffirmation =\n request.actionId === 'permanent-delete' && request.phase === 'apply';\n if (\n (requiresCountAffirmation &&\n (request.target.confirmedCount !== expectedCount ||\n !Number.isSafeInteger(request.target.confirmedCount))) ||\n (!requiresCountAffirmation && request.target.confirmedCount !== undefined)\n ) {\n return 'confirmation_count_mismatch';\n }\n if (\n request.selection.scope !== 'explicit-ids' &&\n !isRecord(request.target.query)\n ) {\n return 'invalid_request';\n }\n if (\n request.target.query !== undefined &&\n !isBoundedDataSurfaceJsonValue(request.target.query)\n ) {\n return 'invalid_request';\n }\n return undefined;\n}\n\nfunction statusOf(content: Content): string {\n return String(content.status ?? '').toLowerCase();\n}\n\nasync function publishReady(content: Content): Promise<boolean> {\n const governance = await content.resolveGovernance();\n if (!governance.isGoverned || !governance.enforcePublishReadiness)\n return true;\n if (!governance.publicationProfileKey) return false;\n return (await content.evaluateReviewProfile(governance.publicationProfileKey))\n .ready;\n}\n\nasync function eligibility(\n workflowId: ContentListServerActionId,\n content: Content,\n payload: DataSurfaceJsonValue | undefined,\n handlers: ContentListWorkflowHandlers,\n): Promise<{ eligible: boolean; reason?: string }> {\n const status = statusOf(content);\n if (workflowId === 'restore') {\n if (status !== 'deleted') return { eligible: false, reason: 'not_deleted' };\n if (\n payloadRecord(payload).status === 'published' &&\n !(await publishReady(content))\n ) {\n return { eligible: false, reason: 'publish_readiness_failed' };\n }\n return { eligible: true };\n }\n if (workflowId === 'permanent-delete') {\n return status === 'deleted'\n ? { eligible: true }\n : { eligible: false, reason: 'not_deleted' };\n }\n if (status === 'deleted') return { eligible: false, reason: 'deleted' };\n switch (workflowId) {\n case 'move-to-trash':\n return { eligible: true };\n case 'mark-draft':\n return status === 'draft'\n ? { eligible: false, reason: 'already_draft' }\n : { eligible: true };\n case 'submit-review':\n return status === 'draft'\n ? { eligible: true }\n : { eligible: false, reason: 'requires_draft' };\n case 'publish':\n if (!['draft', 'review', 'archived'].includes(status))\n return { eligible: false, reason: 'invalid_status' };\n return (await publishReady(content))\n ? { eligible: true }\n : { eligible: false, reason: 'publish_readiness_failed' };\n case 'archive':\n return status === 'archived'\n ? { eligible: false, reason: 'already_archived' }\n : { eligible: true };\n case 'automated-review': {\n const governance = await content.resolveGovernance();\n if (!governance.isGoverned)\n return { eligible: false, reason: 'governance_unavailable' };\n const input = payloadRecord(payload);\n const policy =\n typeof input.policyKey === 'string'\n ? governance.reviewPolicies.find(\n (entry) => entry.key === input.policyKey,\n )\n : undefined;\n if (typeof input.policyKey === 'string' && !policy)\n return { eligible: false, reason: 'review_policy_unavailable' };\n if (\n typeof input.kind === 'string' &&\n policy &&\n policy.kind !== input.kind\n )\n return { eligible: false, reason: 'review_kind_mismatch' };\n return { eligible: true };\n }\n case 'format-body':\n return handlers.formatBody\n ? { eligible: true }\n : { eligible: false, reason: 'handler_unavailable' };\n case 'categorize':\n return { eligible: true };\n case 'optimize':\n if (!handlers.optimize)\n return { eligible: false, reason: 'handler_unavailable' };\n return ['draft', 'review'].includes(status)\n ? { eligible: true }\n : { eligible: false, reason: 'requires_draft_or_review' };\n }\n}\n\nasync function applyWorkflow(\n workflowId: ContentListServerActionId,\n content: Content,\n expectedUpdatedAt: Date | string,\n payload: DataSurfaceJsonValue | undefined,\n run: PrincipalRun,\n handlers: ContentListWorkflowHandlers,\n): Promise<void> {\n const input = payloadRecord(payload);\n const save = async () => {\n await content.withTransaction((bound) => bound.save({ expectedUpdatedAt }));\n };\n const mutationDraft = (): ContentListWorkflowDraft => ({\n contentId: String(content.id),\n tenantId: content.tenantId,\n type: content.type,\n variant: content.variant,\n status: content.status,\n state: content.state,\n fileKey: content.fileKey,\n author: content.author,\n name: content.name,\n title: content.title,\n description: content.description,\n body: content.body,\n bodyFormat: content.bodyFormat,\n publish_date: content.publish_date,\n url: content.url,\n source: content.source,\n original_url: content.original_url,\n language: content.language,\n tags: [...(content.tags ?? [])],\n category: content.category,\n metadata: structuredClone(content.metadata ?? {}),\n thumbnailAssetId: content.thumbnailAssetId,\n });\n const applyDraft = (draft: ContentListWorkflowDraft) => {\n content.fileKey = draft.fileKey;\n content.author = draft.author;\n content.name = draft.name;\n content.title = draft.title;\n content.description = draft.description;\n content.body = draft.body;\n content.bodyFormat = draft.bodyFormat;\n content.publish_date = draft.publish_date;\n content.url = draft.url;\n content.source = draft.source;\n content.original_url = draft.original_url;\n content.language = draft.language;\n content.tags = [...draft.tags];\n content.category = draft.category;\n content.metadata = structuredClone(draft.metadata);\n content.thumbnailAssetId = draft.thumbnailAssetId;\n };\n const runHandler = async (\n handler: NonNullable<ContentListWorkflowHandlers['formatBody']>,\n ) => {\n const draft = mutationDraft();\n await handler(draft, payload, run);\n applyDraft(draft);\n await save();\n };\n switch (workflowId) {\n case 'move-to-trash':\n content.status = 'deleted';\n await save();\n return;\n case 'mark-draft':\n content.status = 'draft';\n await save();\n return;\n case 'submit-review':\n content.status = 'review';\n await save();\n return;\n case 'publish':\n content.status = 'published';\n await save();\n return;\n case 'archive':\n content.status = 'archived';\n await save();\n return;\n case 'restore':\n content.status = input.status as Content['status'];\n await save();\n return;\n case 'permanent-delete':\n // Content owns cascading references, so a revision-guarded destructive\n // delete must never use the core's documented non-transaction fallback.\n // Probe through the public object API before any cascade can begin.\n await content.withTransaction(async () => undefined);\n await content.delete({ expectedUpdatedAt });\n return;\n case 'automated-review':\n await content.runReviewAction({\n expectedUpdatedAt,\n ...(typeof input.kind === 'string'\n ? { kind: input.kind as never }\n : {}),\n ...(typeof input.policyKey === 'string'\n ? { policyKey: input.policyKey }\n : {}),\n });\n return;\n case 'format-body':\n if (!handlers.formatBody) throw new Error('format handler unavailable');\n await runHandler(handlers.formatBody);\n return;\n case 'categorize':\n content.category = String(input.category).trim();\n await save();\n return;\n case 'optimize':\n if (!handlers.optimize) throw new Error('optimize handler unavailable');\n await runHandler(handlers.optimize);\n return;\n }\n}\n\nfunction revisionFingerprint(rows: readonly Record<string, unknown>[]): string {\n const canonical = rows\n .map((row) => `${String(row.id)}\\u0000${String(row.updated_at ?? '')}`)\n .sort();\n return createHash('sha256')\n .update(canonical.join('\\u0001'))\n .digest('base64url');\n}\n\nfunction representativeLabels(\n rows: readonly Record<string, unknown>[],\n limit: number,\n): string[] {\n return rows.slice(0, limit).map((row) => {\n const title = typeof row.title === 'string' ? row.title.trim() : '';\n return title || String(row.id);\n });\n}\n\nasync function resolveQuerySelection(\n request: ContentListActionRequest,\n collection: ContentListActionCollection,\n scope: ContentQueryScope | undefined,\n maxSelectionSize: number,\n representativeLimit: number,\n revision: number,\n): Promise<ResolvedContentSelection> {\n const schema = await buildContentQuerySchema();\n const selection = request.selection;\n const rows: Array<Record<string, unknown>> = [];\n let queryFingerprint: string;\n\n if (selection.scope === 'explicit-ids') {\n const ids = [...new Set(selection.rowIds.map((rowId) => String(rowId)))];\n if (ids.length > maxSelectionSize)\n throw new ContentListActionError('limit_exceeded');\n queryFingerprint = `explicit:${revisionFingerprint(ids.map((id) => ({ id })))}`;\n for (let start = 0; start < ids.length; start += 100) {\n const chunk = ids.slice(start, start + 100);\n const query: DataQueryRequest = {\n version: 1,\n requestId: `content-action-explicit-${start}`,\n mode: 'rows',\n projection: [...REQUIRED_QUERY_FIELDS],\n filter: {\n kind: 'condition',\n field: 'id',\n operator: 'in',\n value: chunk,\n },\n sort: [{ field: 'id', direction: 'asc' }],\n page: { kind: 'offset', offset: 0, limit: Math.max(1, chunk.length) },\n };\n const result = await executeContentQuery(collection, query, { scope });\n rows.push(...result.rows);\n }\n queryFingerprint = `${queryFingerprint}:${revisionFingerprint(rows)}`;\n } else {\n const input = request.target.query;\n if (!input) throw new ContentListActionError('invalid_target');\n const normalized = normalizeDataQueryRequest(input, schema);\n const allMatchingPageLimit = Math.min(\n maxSelectionSize,\n MAX_DATA_QUERY_PAGE_LIMIT,\n );\n const querySchema =\n selection.scope === 'all-matching'\n ? {\n ...schema,\n defaultPageLimit: Math.min(\n schema.defaultPageLimit ?? CONTENT_QUERY_MAX_PAGE_LIMIT,\n allMatchingPageLimit,\n ),\n maxPageLimit: allMatchingPageLimit,\n }\n : schema;\n if (normalized.mode !== 'rows')\n throw new ContentListActionError('invalid_target');\n for (const field of REQUIRED_QUERY_FIELDS) {\n if (!normalized.projection?.includes(field))\n throw new ContentListActionError('missing_action_projection');\n }\n const baseFingerprint = createDataQueryFingerprint(normalized, schema);\n if (\n selection.scope === 'all-matching' &&\n selection.queryFingerprint !== baseFingerprint\n ) {\n throw new ContentListActionError('stale_query_fingerprint');\n }\n const pageLimit =\n selection.scope === 'current-page'\n ? (normalized.page?.limit ?? CONTENT_QUERY_MAX_PAGE_LIMIT)\n : allMatchingPageLimit;\n const offset =\n selection.scope === 'current-page' && normalized.page?.kind === 'offset'\n ? normalized.page.offset\n : 0;\n const pageRequest: DataQueryRequest = {\n ...normalized,\n requestId: `${normalized.requestId}-action-${offset}`.slice(0, 128),\n page: { kind: 'offset', offset, limit: Math.max(1, pageLimit) },\n };\n const result = await executeContentQuery(collection, pageRequest, {\n scope,\n schema: querySchema,\n });\n if (result.total.kind !== 'exact')\n throw new ContentListActionError('count_unavailable');\n if (selection.scope === 'all-matching' && result.total.value > pageLimit) {\n throw new ContentListActionError('limit_exceeded');\n }\n rows.push(...result.rows);\n if (\n selection.scope === 'all-matching' &&\n rows.length !== result.total.value\n ) {\n throw new ContentListActionError('matching_count_drifted');\n }\n if (selection.scope === 'all-matching') {\n const distinctIds = new Set(rows.map((row) => String(row.id)));\n if (distinctIds.size !== rows.length) {\n throw new ContentListActionError('matching_count_drifted');\n }\n }\n queryFingerprint = `${baseFingerprint}:${revisionFingerprint(rows)}`;\n }\n\n if (request.target.expectedCount !== rows.length) {\n throw new ContentListActionError('matching_count_drifted');\n }\n return {\n revision,\n queryFingerprint,\n rowIds: rows.map((row) => row.id as DataSurfaceRowId),\n rows,\n representativeLabels: representativeLabels(rows, representativeLimit),\n scope: selection.scope,\n };\n}\n\nfunction defaultDescriptor(maxSelectionSize: number): DataSurfaceDescriptor {\n return {\n version: 1,\n identity: { surfaceId: 'content-list', kind: 'table' },\n schemaVersion: 2,\n label: 'Contents',\n rowKey: 'id',\n columns: [\n {\n id: 'id',\n label: 'Content id',\n fieldName: 'id',\n role: 'row-key',\n capabilities: ['read', 'project'],\n },\n {\n id: 'title',\n label: 'Title',\n fieldName: 'title',\n capabilities: ['read', 'project'],\n },\n {\n id: 'status',\n label: 'Status',\n fieldName: 'status',\n role: 'status',\n capabilities: ['read', 'project'],\n },\n ],\n query: {\n modes: ['rows', 'count'],\n projectableColumnIds: ['id', 'title', 'status'],\n },\n controls: [],\n actions: CONTENT_LIST_SERVER_ACTIONS.map((entry) => ({\n id: entry.id,\n label: entry.label,\n description: entry.description,\n sensitivity: entry.sensitivity,\n selectionScopes: [...entry.selectionScopes],\n requiresConfirmation: entry.confirmation === 'required',\n })),\n limits: {\n maxQueryRows: CONTENT_QUERY_MAX_PAGE_LIMIT,\n maxQueryBytes: 1_000_000,\n maxSelectionSize,\n },\n };\n}\n\nexport interface ContentListActionAdapter extends DataSurfaceActionAdapter {\n preview(\n request: ContentListActionRequest,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult>;\n apply(\n request: ContentListActionRequest,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult>;\n}\n\nexport function createContentListActionAdapter(\n options: ContentListActionAdapterOptions,\n): ContentListActionAdapter {\n assertContentListWorkflowStorageSupported(options.workflowStorage);\n const handlers = options.handlers ?? {};\n const maxSelectionSize =\n options.maxSelectionSize ??\n options.descriptor?.limits.maxSelectionSize ??\n DEFAULT_MAX_SELECTION_SIZE;\n if (\n !Number.isSafeInteger(maxSelectionSize) ||\n maxSelectionSize < 1 ||\n maxSelectionSize > MAX_DATA_QUERY_PAGE_LIMIT\n ) {\n throw new Error(\n `ContentList maxSelectionSize must be an integer between 1 and ${MAX_DATA_QUERY_PAGE_LIMIT} so all-matching membership resolves in one bounded query`,\n );\n }\n const representativeLimit =\n options.representativeLimit ?? DEFAULT_REPRESENTATIVE_LIMIT;\n const descriptor = options.descriptor ?? defaultDescriptor(maxSelectionSize);\n if (descriptor.limits.maxSelectionSize !== maxSelectionSize) {\n throw new Error(\n 'ContentList descriptor maxSelectionSize must match the server selection cap',\n );\n }\n const resolvedByRequest = new WeakMap<object, ResolvedContentSelection>();\n const contentByRequest = new WeakMap<\n object,\n Map<string, Promise<Content | null>>\n >();\n // Request ids are client input and may collide across concurrent calls.\n const invocationResources = new AsyncLocalStorage<\n Map<string, { resourceId: string; resourceType: string }>\n >();\n async function loadContent(\n invocation: { run: PrincipalRun; request: DataSurfaceServerActionRequest },\n rowId: DataSurfaceRowId,\n ): Promise<Content | null> {\n const key = String(rowId);\n let byRow = contentByRequest.get(invocation.request);\n if (!byRow) {\n byRow = new Map();\n contentByRequest.set(invocation.request, byRow);\n }\n let pending = byRow.get(key);\n if (!pending) {\n pending = (async () => {\n const collection = await options.collection(invocation.run);\n const content = await collection.get({ id: key });\n if (!content) return null;\n const serialized = content.toJSON() as Record<string, unknown>;\n invocationResources.getStore()?.set(key, {\n resourceId: String(content.id),\n resourceType:\n typeof serialized._meta_type === 'string'\n ? serialized._meta_type\n : content.constructor.name,\n });\n const resolved = resolvedByRequest.get(invocation.request);\n const expected = resolved?.rows.find((row) => String(row.id) === key);\n const revisionValue = (value: unknown) =>\n value instanceof Date ? value.toISOString() : String(value ?? '');\n if (\n !expected ||\n revisionValue(content.updated_at) !==\n revisionValue(expected.updated_at)\n ) {\n throw new ContentListActionError('row_revision_drifted');\n }\n return content;\n })();\n byRow.set(key, pending);\n }\n return pending;\n }\n\n const mapActionError = (error: unknown) =>\n error instanceof ContentListActionError\n ? error.reason\n : isRecord(error) && error.code === 'RUNTIME_REVISION_CONFLICT'\n ? 'row_revision_drifted'\n : isPermissionDenied(error) ||\n error instanceof PrincipalToolNotAllowedError\n ? 'denied'\n : undefined;\n\n const definitions = Object.fromEntries(\n CONTENT_LIST_SERVER_ACTIONS.map(\n (entry): [string, DataSurfaceServerActionDefinition] => [\n entry.id,\n {\n descriptor: {\n id: entry.id,\n label: entry.label,\n description: entry.description,\n sensitivity: entry.sensitivity,\n selectionScopes: [...entry.selectionScopes],\n requiresConfirmation: entry.confirmation === 'required',\n },\n inputSchema: entry.inputSchema,\n validatePayload: (payload) =>\n validPayload(entry.id, payload)\n ? { valid: true }\n : { valid: false, reason: 'invalid_payload' },\n confirmation: entry.confirmation,\n execution: entry.execution,\n tool: entry.permissionRequirements.tool,\n operation:\n entry.permissionRequirements.operations[0] ??\n CONTENT_READ_OPERATION,\n authorize: async (invocation) => {\n const operations =\n entry.id === 'restore' &&\n payloadRecord(invocation.request.payload).status !== 'published'\n ? entry.permissionRequirements.operations.slice(0, 2)\n : entry.permissionRequirements.operations;\n for (const operation of operations.slice(1)) {\n try {\n await invocation.run.assertOperation(\n operation.collection,\n operation.action,\n );\n } catch (error) {\n if (isPermissionDenied(error)) return false;\n throw error;\n }\n }\n return options.authorize?.(entry.id, invocation.run) ?? true;\n },\n eligible: async (invocation, rowId) => {\n const content = await loadContent(invocation, rowId);\n if (!content)\n return { eligible: false, reason: 'not_found_or_denied' };\n return eligibility(\n entry.id,\n content,\n invocation.request.payload,\n handlers,\n );\n },\n apply: async (invocation, rowId) => {\n const content = await loadContent(invocation, rowId);\n if (!content) throw new Error('content not found');\n const expectedUpdatedAt = content.updated_at;\n if (\n !(expectedUpdatedAt instanceof Date) &&\n typeof expectedUpdatedAt !== 'string'\n ) {\n throw new ContentListActionError('row_revision_drifted');\n }\n const resource = invocationResources.getStore()?.get(String(rowId));\n try {\n await applyWorkflow(\n entry.id,\n content,\n expectedUpdatedAt,\n invocation.request.payload,\n invocation.run,\n handlers,\n );\n } catch (error) {\n if (entry.id !== 'permanent-delete') throw error;\n // delete() commits before its post-delete hooks. If one of those\n // hooks fails, confirm the authoritative row state so an\n // irreversible success is never reported as retryable failure.\n const collection = await options.collection(invocation.run);\n if (await collection.get({ id: String(rowId) })) throw error;\n }\n return resource ?? null;\n },\n },\n ],\n ),\n );\n\n const state: DataSurfaceActionStateStore = {\n putToken: (...args) => options.state.putToken(...args),\n getToken: (...args) => options.state.getToken(...args),\n markTokenConsumed: (...args) => options.state.markTokenConsumed(...args),\n consumeTokenAndReserveIdempotency: (...args) =>\n options.state.consumeTokenAndReserveIdempotency(...args),\n getIdempotency: (...args) => options.state.getIdempotency(...args),\n reserveIdempotency: (...args) => options.state.reserveIdempotency(...args),\n completeIdempotency: (key, ownerToken, result) => {\n if (result.details) {\n result.details = {\n ...result.details,\n auditReference: result.requestId,\n };\n }\n return options.state.completeIdempotency(key, ownerToken, result);\n },\n releaseIdempotency: (...args) => options.state.releaseIdempotency(...args),\n };\n\n const generic = createDataSurfaceActionAdapter({\n state,\n backgroundQueue: options.backgroundQueue,\n backgroundHandlerId: options.backgroundHandlerId,\n deferredEnvelopeSigningKey: options.deferredEnvelopeSigningKey,\n tokenTtlMs: options.tokenTtlMs,\n runAsPrincipal: options.runAsPrincipal,\n resolveDeferredPrincipal: options.resolveDeferredPrincipal,\n requestFingerprintExtension: (request) =>\n (() => {\n const target = (request as ContentListActionRequest).target;\n // The operator-entered count exists only on apply. Bind the preview's\n // server-checked expected count/query into the token while validating\n // the separate affirmation above before the generic adapter runs.\n return {\n expectedCount: target.expectedCount,\n ...(target.query ? { query: target.query } : {}),\n } as unknown as DataSurfaceJsonValue;\n })(),\n mapError: mapActionError,\n resolveSurface: async (run) => ({\n descriptor,\n revision: await (options.revision?.(run, descriptor.identity) ?? 0),\n actions: definitions,\n }),\n resolveSelection: async (invocation, selection) => {\n const request = invocation.request as ContentListActionRequest;\n const collection = await options.collection(invocation.run);\n const scope = await options.scope?.(invocation.run);\n const revision = await (options.revision?.(\n invocation.run,\n descriptor.identity,\n ) ?? 0);\n const resolved = await resolveQuerySelection(\n { ...request, selection },\n collection,\n scope,\n maxSelectionSize,\n representativeLimit,\n revision,\n );\n resolvedByRequest.set(request, resolved);\n return resolved;\n },\n });\n\n async function invoke(\n phase: 'preview' | 'apply',\n request: ContentListActionRequest,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult> {\n const invalid = validateTarget(request);\n if (invalid) return actionResult(request, false, invalid);\n try {\n const resources = new Map<\n string,\n { resourceId: string; resourceType: string }\n >();\n const result = await invocationResources.run(resources, () =>\n generic[phase](request, context),\n );\n const resolved = resolvedByRequest.get(request);\n const workflow = CONTENT_LIST_SERVER_ACTIONS.find(\n (entry) => entry.id === request.actionId,\n );\n const outcomes = Array.isArray(result.details?.outcomes)\n ? result.details.outcomes.map((outcome) => {\n if (!isRecord(outcome)) return outcome;\n const resource =\n resources?.get(String(outcome.rowId)) ??\n (typeof outcome.resourceId === 'string' &&\n typeof outcome.resourceType === 'string'\n ? {\n resourceId: outcome.resourceId,\n resourceType: outcome.resourceType,\n }\n : undefined);\n return resource ? { ...outcome, ...resource } : outcome;\n })\n : undefined;\n if (phase !== 'preview' || !result.ok) {\n return {\n ...result,\n ...(result.details\n ? {\n details: {\n ...result.details,\n ...(outcomes ? { outcomes } : {}),\n auditReference:\n typeof result.details.auditReference === 'string'\n ? result.details.auditReference\n : request.requestId,\n },\n }\n : {}),\n };\n }\n return {\n ...result,\n details: {\n ...(result.details ?? {}),\n ...(outcomes ? { outcomes } : {}),\n resolvedScope: resolved?.scope ?? request.selection.scope,\n representativeLabels: resolved?.representativeLabels ?? [],\n ineligible: Array.isArray(result.details?.outcomes)\n ? result.details.outcomes.filter(\n (entry) => isRecord(entry) && entry.status === 'skipped',\n )\n : [],\n consequences: workflow?.consequences ?? [],\n sensitivity: workflow?.sensitivity ?? 'public',\n execution: workflow?.execution ?? 'foreground',\n auditReference: request.requestId,\n },\n };\n } catch (error) {\n return actionResult(\n request,\n false,\n mapActionError(error) ?? 'execution_failed',\n );\n } finally {\n resolvedByRequest.delete(request);\n }\n }\n\n return {\n preview: (request, context) => invoke('preview', request, context),\n apply: (request, context) => invoke('apply', request, context),\n executeDeferred: (envelope) => generic.executeDeferred(envelope),\n };\n}\n","/** Principal-bound, silent ContentList query discovery and execution (#2456). */\n\nimport {\n assertIdFieldConditions,\n type DataSurfaceDefinition,\n type DataSurfaceExecutionContext,\n type DataSurfaceSchema,\n uuidColumnFieldIds,\n} from '@happyvertical/smrt-agents';\nimport { normalizeDataQueryRequest } from '@happyvertical/smrt-core';\nimport type { DataQuerySchema } from '@happyvertical/smrt-types';\nimport {\n assertContentQuerySchema,\n buildContentQuerySchema,\n CONTENT_QUERY_CLASS_NAME,\n type ContentQueryCollection,\n type ContentQueryScope,\n executeContentQuery,\n} from '../content-query.js';\n\nexport const CONTENT_LIST_DATA_SURFACE_ID = 'content-list';\nexport const CONTENT_LIST_DATA_SURFACE_COLLECTION = 'contents';\n\nexport interface ContentListDataSurfaceOptions {\n /** Stable catalog id. Defaults to the mounted ContentList surface id. */\n id?: string;\n /** Permission-catalog collection checked by the generic agent tools. */\n collectionName?: string;\n label?: string;\n description?: string;\n metadata?: NonNullable<DataSurfaceDefinition['metadata']>;\n /** Resolve a collection from the live principal context, never model input. */\n collection:\n | ContentQueryCollection\n | ((\n context: DataSurfaceExecutionContext,\n ) => ContentQueryCollection | Promise<ContentQueryCollection>);\n /** Trusted application narrowing applied in addition to tenant isolation. */\n scope?:\n | ContentQueryScope\n | ((\n context: DataSurfaceExecutionContext,\n ) =>\n | ContentQueryScope\n | undefined\n | Promise<ContentQueryScope | undefined>);\n /** Trusted policy override; defaults to the canonical Content query schema. */\n schema?: DataSurfaceSchema;\n}\n\nfunction requiredName(\n value: string | undefined,\n fallback: string,\n label: string,\n) {\n const resolved = value ?? fallback;\n if (resolved.trim().length === 0) {\n throw new Error(`${label} must be a non-empty string`);\n }\n return resolved;\n}\n\nfunction querySchema(schema: DataSurfaceSchema): DataQuerySchema {\n return {\n ...schema,\n // A host descriptor is untrusted at this boundary. Discovery redacts\n // protected fields, and execution uses the same principal-aware field set\n // so a direct data.query request cannot bypass that policy.\n fields: schema.fields\n .filter(({ sensitive, readPermission }) => {\n if (sensitive) return false;\n return !readPermission;\n })\n .map(\n ({\n sensitive: _sensitive,\n readPermission: _readPermission,\n metadata: _metadata,\n ...field\n }) => field,\n ),\n };\n}\n\nasync function resolveCollection(\n options: ContentListDataSurfaceOptions,\n context: DataSurfaceExecutionContext,\n): Promise<ContentQueryCollection> {\n return typeof options.collection === 'function'\n ? options.collection(context)\n : options.collection;\n}\n\nasync function resolveScope(\n options: ContentListDataSurfaceOptions,\n context: DataSurfaceExecutionContext,\n): Promise<ContentQueryScope | undefined> {\n return typeof options.scope === 'function'\n ? options.scope(context)\n : options.scope;\n}\n\n/**\n * Build one server-owned ContentList surface for `data.discover`,\n * `data.inspect`, and silent/background `data.query` calls.\n *\n * The returned executor resolves its collection and application scope from the\n * live principal context. The request can only narrow that trusted scope, and\n * every projection/count/facet/page still passes through `executeContentQuery`.\n */\nexport async function createContentListDataSurfaceDefinition(\n options: ContentListDataSurfaceOptions,\n): Promise<DataSurfaceDefinition> {\n const schema = options.schema ?? (await buildContentQuerySchema());\n // `SmrtCollection.list({ select })` intentionally refuses model fields with\n // readPermission because that projection primitive has no permission\n // context. Publishing one here would let discovery promise a query that the\n // real collection cannot execute. Keep the server data surface fail-closed:\n // only universally executable, non-sensitive fields are advertised.\n const executableSchema = querySchema(schema);\n assertContentQuerySchema(executableSchema);\n\n return {\n id: requiredName(\n options.id,\n CONTENT_LIST_DATA_SURFACE_ID,\n 'ContentList data surface id',\n ),\n collection: requiredName(\n options.collectionName,\n CONTENT_LIST_DATA_SURFACE_COLLECTION,\n 'ContentList permission collection',\n ),\n className: CONTENT_QUERY_CLASS_NAME,\n label: options.label ?? 'Contents',\n description:\n options.description ??\n 'Bounded, tenant-safe content rows, counts, facets, and continuations.',\n metadata: {\n domain: 'content',\n adapter: 'ContentList',\n views: ['grid', 'detailed', 'compact'],\n queryModes: ['rows', 'count', 'facets'],\n ...options.metadata,\n },\n schema: executableSchema,\n execute: async (_surface, request, context) => {\n // Validate before resolving the host collection. This makes a rejected\n // protected projection a zero-I/O failure, even for hostile descriptors.\n const normalized = normalizeDataQueryRequest(request, executableSchema);\n // A non-UUID value for an id column is refused here, as the caller's\n // error, instead of reaching PostgreSQL as `invalid input syntax for\n // type uuid` (an opaque query failure to the agent).\n assertIdFieldConditions(\n normalized.filter,\n uuidColumnFieldIds(\n CONTENT_QUERY_CLASS_NAME,\n executableSchema.fields.map((field) => field.id),\n ),\n );\n return executeContentQuery(\n await resolveCollection(options, context),\n request,\n {\n schema: executableSchema,\n scope: await resolveScope(options, context),\n },\n );\n },\n };\n}\n","/**\n * Principal-bound HTTP boundary for ContentList lifecycle actions (#2454).\n *\n * Hosts supply authentication by resolving a DataSurface server context from\n * the incoming Request. The service gates this dedicated endpoint to lifecycle\n * actions, then delegates to the same content action adapter used by agents and\n * bulk workflows so authorization, selection resolution, confirmation,\n * idempotency, and audit metadata cannot diverge by caller.\n */\n\nimport type { DataSurfaceServerActionContext } from '@happyvertical/smrt-agents/server';\nimport type {\n DataSurfaceActionResult,\n DataSurfaceIdentity,\n} from '@happyvertical/smrt-types';\nimport {\n CONTENT_LIST_LIFECYCLE_ACTION_IDS,\n type ContentListActionAdapter,\n type ContentListActionRequest,\n type ContentListLifecycleActionId,\n} from './content-list-actions.js';\n\nexport interface ContentListLifecycleService {\n invoke(\n request: unknown,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult>;\n}\n\nexport interface ContentListLifecycleRouteOptions {\n adapter: ContentListActionAdapter;\n /** Authenticate and bind the request to its current principal/tenant. */\n context(\n request: Request,\n ): DataSurfaceServerActionContext | Promise<DataSurfaceServerActionContext>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isLifecycleActionId(\n value: unknown,\n): value is ContentListLifecycleActionId {\n return (CONTENT_LIST_LIFECYCLE_ACTION_IDS as readonly unknown[]).includes(\n value,\n );\n}\n\nfunction safeIdentity(value: unknown): DataSurfaceIdentity {\n if (!isRecord(value)) return { surfaceId: 'content-list', kind: 'table' };\n if (\n typeof value.surfaceId !== 'string' ||\n !['table', 'list', 'report', 'custom'].includes(String(value.kind))\n ) {\n return { surfaceId: 'content-list', kind: 'table' };\n }\n return value as unknown as DataSurfaceIdentity;\n}\n\nfunction rejected(\n request: unknown,\n reason: 'invalid_request' | 'unsupported',\n): DataSurfaceActionResult {\n const candidate = isRecord(request) ? request : {};\n return {\n version: 1,\n requestId:\n typeof candidate.requestId === 'string'\n ? candidate.requestId\n : 'invalid-request',\n identity: safeIdentity(candidate.identity),\n actionId:\n typeof candidate.actionId === 'string' ? candidate.actionId : 'invalid',\n phase: candidate.phase === 'apply' ? 'apply' : 'preview',\n ok: false,\n reason,\n };\n}\n\n/** Create the transport-neutral lifecycle service used by HTTP and agent hosts. */\nexport function createContentListLifecycleService(\n adapter: ContentListActionAdapter,\n): ContentListLifecycleService {\n return {\n async invoke(request, context) {\n if (!isRecord(request)) return rejected(request, 'invalid_request');\n if (!isLifecycleActionId(request.actionId)) {\n return rejected(request, 'unsupported');\n }\n if (request.phase !== 'preview' && request.phase !== 'apply') {\n return rejected(request, 'invalid_request');\n }\n return adapter[request.phase](\n request as unknown as ContentListActionRequest,\n context,\n );\n },\n };\n}\n\n/**\n * Create a native Request/Response handler for `POST /api/v1/contents/lifecycle`.\n * SvelteKit hosts can call it with `event.request`; other runtimes can mount it\n * directly anywhere that implements the standard Fetch API.\n */\nexport function createContentListLifecycleRoute(\n options: ContentListLifecycleRouteOptions,\n): (request: Request) => Promise<Response> {\n const service = createContentListLifecycleService(options.adapter);\n return async (request) => {\n if (request.method !== 'POST') {\n return Response.json(\n { error: { message: 'Method not allowed.' } },\n { status: 405, headers: { allow: 'POST' } },\n );\n }\n let input: unknown;\n try {\n input = await request.json();\n } catch {\n return Response.json(\n { error: { message: 'The lifecycle request body must be JSON.' } },\n { status: 400 },\n );\n }\n let context: DataSurfaceServerActionContext;\n try {\n context = await options.context(request);\n } catch {\n return Response.json(\n { error: { message: 'Authentication is required.' } },\n { status: 401 },\n );\n }\n try {\n return Response.json({ result: await service.invoke(input, context) });\n } catch {\n return Response.json(\n { error: { message: 'The lifecycle request could not be completed.' } },\n { status: 500 },\n );\n }\n };\n}\n","/**\n * SMRT Content Service Server\n *\n * Demonstrates auto-generated REST API from SMRT Content objects.\n * No manual route definitions needed - everything is generated from @smrt() decorated classes.\n */\n\nimport { startRestServer } from '@happyvertical/smrt-core';\nimport './__smrt-register__.js';\nimport { Content } from './content';\n\nasync function startServer() {\n console.log('🚀 Starting SMRT Content Server...');\n\n // Start server with registered SMRT objects\n const shutdown = await startRestServer(\n [Content], // SMRT objects to generate API for\n {}, // context\n {\n port: 3100,\n hostname: 'localhost',\n basePath: '/api/v1',\n enableCors: true,\n },\n );\n\n console.log('✅ Server ready!');\n console.log('📡 REST API: http://localhost:3100/api/v1');\n console.log('📚 Endpoints:');\n console.log(' GET /api/v1/contents - List contents');\n console.log(' POST /api/v1/contents - Create content');\n console.log(' GET /api/v1/contents/:id - Get content');\n console.log(' PUT /api/v1/contents/:id - Update content');\n console.log(' DELETE /api/v1/contents/:id - Delete content');\n\n console.log('\\n💡 Try these endpoints:');\n console.log(' curl http://localhost:3100/api/v1/contents');\n console.log(\n ' curl -X POST http://localhost:3100/api/v1/contents -H \"Content-Type: application/json\" -d \\'{\"title\":\"Test Content\",\"body\":\"Test body content\"}\\'',\n );\n\n return { shutdown };\n}\n\n// Start if running directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n startServer().catch(console.error);\n}\n\nexport * from './server/content-list-actions.js';\nexport * from './server/content-list-data-surface.js';\nexport * from './server/content-list-lifecycle.js';\nexport { startServer };\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.js","names":["workflow"],"sources":["../src/server/content-list-actions.ts","../src/server/content-list-data-surface.ts","../src/server/content-list-lifecycle.ts","../src/server.ts"],"sourcesContent":["/**\n * Principal-bound ContentList bulk workflows (#2453).\n *\n * The generic action adapter owns confirmation tokens, idempotency, principal\n * execution, permission checks, per-row outcomes, and background acceptance.\n * This module supplies the content-specific half: declarative workflows,\n * canonical query resolution, row-revision binding, governance eligibility,\n * and domain mutations.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHash } from 'node:crypto';\n// Publication and automated-review permissions include facts operations. The\n// catalog is registration-driven, so ensure those definitions exist even when\n// a host imports only the content server entry point.\nimport '@happyvertical/smrt-facts';\nimport {\n type PrincipalRun,\n PrincipalToolNotAllowedError,\n} from '@happyvertical/smrt-agents';\nimport {\n createDataSurfaceActionAdapter,\n type DataSurfaceActionAdapter,\n type DataSurfaceActionStateStore,\n type DataSurfaceBackgroundQueue,\n type DataSurfaceServerActionContext,\n type DataSurfaceServerActionDefinition,\n type DataSurfaceServerActionRequest,\n isBoundedDataSurfaceJsonValue,\n} from '@happyvertical/smrt-agents/server';\nimport {\n createDataQueryFingerprint,\n MAX_DATA_QUERY_PAGE_LIMIT,\n normalizeDataQueryRequest,\n} from '@happyvertical/smrt-core';\nimport type {\n DataQueryRequest,\n DataSurfaceActionResult,\n DataSurfaceDescriptor,\n DataSurfaceIdentity,\n DataSurfaceJsonObject,\n DataSurfaceJsonValue,\n DataSurfaceRowId,\n} from '@happyvertical/smrt-types';\nimport type { ContentBodyFormat } from '../body-format.js';\nimport type { Content } from '../content.js';\nimport {\n buildContentQuerySchema,\n CONTENT_QUERY_MAX_PAGE_LIMIT,\n type ContentQueryCollection,\n type ContentQueryScope,\n executeContentQuery,\n} from '../content-query.js';\n\nexport const CONTENT_LIST_WORKFLOW_IDS = [\n 'move-to-trash',\n 'mark-draft',\n 'submit-review',\n 'publish',\n 'archive',\n 'restore',\n 'automated-review',\n 'format-body',\n 'categorize',\n 'optimize',\n] as const;\n\nexport type ContentListWorkflowId = (typeof CONTENT_LIST_WORKFLOW_IDS)[number];\nexport const CONTENT_LIST_LIFECYCLE_ACTION_IDS = [\n 'move-to-trash',\n 'restore',\n 'permanent-delete',\n] as const;\nexport type ContentListLifecycleActionId =\n (typeof CONTENT_LIST_LIFECYCLE_ACTION_IDS)[number];\nexport type ContentListServerActionId =\n | ContentListWorkflowId\n | ContentListLifecycleActionId;\nexport type ContentListWorkflowExecution = 'foreground' | 'background';\nexport type ContentListWorkflowConfirmation = 'required' | 'none';\n\nexport interface ContentListWorkflowDescriptor {\n id: ContentListServerActionId;\n label: string;\n description: string;\n selectionScopes: Array<'current-page' | 'explicit-ids' | 'all-matching'>;\n sensitivity: 'public' | 'sensitive';\n confirmation: ContentListWorkflowConfirmation;\n execution: ContentListWorkflowExecution;\n inputSchema: DataSurfaceJsonObject | null;\n eligibility: string[];\n permissionRequirements: {\n tool: string;\n operations: Array<{ id: string; collection: string; action: string }>;\n };\n consequences: string[];\n partialResult: {\n statuses: Array<'accepted' | 'skipped' | 'failed'>;\n preservesFailedSelection: true;\n };\n}\n\nconst ALL_SELECTION_SCOPES: ContentListWorkflowDescriptor['selectionScopes'] = [\n 'current-page',\n 'explicit-ids',\n 'all-matching',\n];\n\nconst NO_INPUT: DataSurfaceJsonObject = {\n type: 'object',\n additionalProperties: false,\n};\n\nconst OPTIONAL_REVIEW_INPUT: DataSurfaceJsonObject = {\n type: 'object',\n additionalProperties: false,\n properties: {\n kind: { type: 'string', enum: ['facts', 'safety', 'custom'] },\n policyKey: { type: 'string', maxLength: 128 },\n },\n};\n\nconst CONTENT_UPDATE_OPERATION = {\n id: 'contents:update',\n collection: 'contents',\n action: 'update',\n};\n\nconst CONTENT_READ_OPERATION = {\n id: 'contents:read',\n collection: 'contents',\n action: 'read',\n};\n\nconst GOVERNANCE_READ_OPERATIONS = [\n {\n id: 'content-governance-assignments:read',\n collection: 'contentgovernanceassignments',\n action: 'read',\n },\n {\n id: 'content-governance-policies:read',\n collection: 'contentgovernancepolicies',\n action: 'read',\n },\n {\n id: 'content-governance-profiles:read',\n collection: 'contentgovernanceprofiles',\n action: 'read',\n },\n] as const;\n\nconst PUBLICATION_OPERATIONS = [\n CONTENT_READ_OPERATION,\n CONTENT_UPDATE_OPERATION,\n ...GOVERNANCE_READ_OPERATIONS,\n {\n id: 'content-references:read',\n collection: 'contentreferences',\n action: 'read',\n },\n {\n id: 'content-assets:read',\n collection: 'contentassets',\n action: 'read',\n },\n { id: 'assets:read', collection: 'assets', action: 'read' },\n { id: 'facts:read', collection: 'facts', action: 'read' },\n { id: 'fact-contents:read', collection: 'factcontents', action: 'read' },\n { id: 'fact-sources:read', collection: 'factsources', action: 'read' },\n { id: 'content-reviews:read', collection: 'contentreviews', action: 'read' },\n {\n id: 'content-corrections:read',\n collection: 'contentcorrections',\n action: 'read',\n },\n {\n id: 'content-versions:read',\n collection: 'contentversions',\n action: 'read',\n },\n {\n id: 'content-versions:create',\n collection: 'contentversions',\n action: 'create',\n },\n] as const;\n\nconst AUTOMATED_REVIEW_OPERATIONS = [\n ...PUBLICATION_OPERATIONS,\n {\n id: 'prompt-overrides:read',\n collection: 'promptoverrides',\n action: 'read',\n },\n {\n id: 'content-reviews:create',\n collection: 'contentreviews',\n action: 'create',\n },\n] as const;\n\nexport const CONTENT_LIST_WORKFLOWS: readonly ContentListWorkflowDescriptor[] =\n Object.freeze([\n workflow('move-to-trash', 'Move to trash', {\n description: 'Soft-delete eligible content into the trash lifecycle.',\n sensitivity: 'sensitive',\n eligibility: ['content is not already deleted'],\n consequences: [\n 'Content leaves active views and becomes restorable from trash.',\n ],\n }),\n workflow('mark-draft', 'Mark draft', {\n description: 'Return eligible active content to draft.',\n eligibility: ['content is not deleted', 'content is not already draft'],\n consequences: ['Published content is no longer public.'],\n }),\n workflow('submit-review', 'Submit for review', {\n description: 'Move eligible draft content into editorial review.',\n eligibility: ['content is draft'],\n consequences: ['Content enters the review queue.'],\n }),\n workflow('publish', 'Publish', {\n description: 'Publish content that passes current governance readiness.',\n sensitivity: 'sensitive',\n eligibility: [\n 'content is draft, review, or archived',\n 'publication readiness passes',\n ],\n consequences: [\n 'Content becomes public and may create a publication snapshot.',\n ],\n permissionRequirements: {\n tool: 'content.workflow.publish',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('archive', 'Archive', {\n description: 'Remove eligible content from active publication workflows.',\n eligibility: [\n 'content is not deleted',\n 'content is not already archived',\n ],\n consequences: ['Published content is no longer public.'],\n }),\n workflow('restore', 'Restore', {\n description: 'Restore deleted content to an explicit eligible status.',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['status'],\n properties: {\n status: { enum: ['draft', 'review', 'published'] },\n },\n },\n eligibility: [\n 'content is deleted',\n 'requested destination is valid',\n 'publish readiness passes when publishing',\n ],\n consequences: [\n 'Content leaves trash.',\n 'Publishing makes content public.',\n ],\n permissionRequirements: {\n tool: 'content.workflow.restore',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('automated-review', 'Automated review', {\n description: 'Run the configured content governance review.',\n execution: 'background',\n inputSchema: OPTIONAL_REVIEW_INPUT,\n eligibility: [\n 'content is not deleted',\n 'content governance is configured',\n ],\n consequences: [\n 'Creates a review result and may create a review version.',\n ],\n permissionRequirements: {\n tool: 'content.workflow.automated-review',\n operations: [...AUTOMATED_REVIEW_OPERATIONS],\n },\n }),\n workflow('format-body', 'Format body', {\n description: 'Run the application-owned body-formatting workflow.',\n execution: 'background',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n properties: { format: { enum: ['markdown', 'html'] } },\n },\n eligibility: [\n 'content is not deleted',\n 'a formatting handler is configured',\n ],\n consequences: ['The persisted content body may change.'],\n permissionRequirements: {\n tool: 'content.workflow.format-body',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('categorize', 'Categorize', {\n description: 'Assign one required hierarchical category path.',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['category'],\n properties: {\n category: { type: 'string', minLength: 1, maxLength: 256 },\n },\n },\n eligibility: ['content is not deleted', 'category is non-empty'],\n consequences: ['The content category changes.'],\n permissionRequirements: {\n tool: 'content.workflow.categorize',\n operations: [...PUBLICATION_OPERATIONS],\n },\n }),\n workflow('optimize', 'Optimize / complete', {\n description: 'Run the application-owned content optimization workflow.',\n execution: 'background',\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n properties: { instructions: { type: 'string', maxLength: 4096 } },\n },\n eligibility: [\n 'content is draft or review',\n 'an optimization handler is configured',\n ],\n consequences: ['Content fields may be revised or completed.'],\n }),\n ]);\n\nconst PERMANENT_DELETE_ACTION: ContentListWorkflowDescriptor = workflow(\n 'permanent-delete',\n 'Delete permanently',\n {\n description: 'Permanently delete content that is already in trash.',\n sensitivity: 'sensitive',\n eligibility: ['content is deleted'],\n consequences: [\n 'Content and its owned lifecycle data are irreversibly deleted.',\n ],\n permissionRequirements: {\n tool: 'content.lifecycle.permanent-delete',\n operations: [\n CONTENT_READ_OPERATION,\n {\n id: 'contents:delete',\n collection: 'contents',\n action: 'delete',\n },\n ],\n },\n },\n);\n\n/** The lifecycle-only catalog exposed by the dedicated route/service. */\nexport const CONTENT_LIST_LIFECYCLE_ACTIONS: readonly ContentListWorkflowDescriptor[] =\n Object.freeze([\n contentListWorkflow('move-to-trash'),\n contentListWorkflow('restore'),\n PERMANENT_DELETE_ACTION,\n ]);\n\nconst CONTENT_LIST_SERVER_ACTIONS: readonly ContentListWorkflowDescriptor[] =\n Object.freeze([...CONTENT_LIST_WORKFLOWS, PERMANENT_DELETE_ACTION]);\n\nfunction contentListWorkflow(\n id: ContentListWorkflowId,\n): ContentListWorkflowDescriptor {\n const descriptor = CONTENT_LIST_WORKFLOWS.find((entry) => entry.id === id);\n if (!descriptor) throw new Error(`Missing ContentList workflow: ${id}`);\n return descriptor;\n}\n\nfunction workflow(\n id: ContentListServerActionId,\n label: string,\n options: Partial<ContentListWorkflowDescriptor> &\n Pick<\n ContentListWorkflowDescriptor,\n 'description' | 'eligibility' | 'consequences'\n >,\n): ContentListWorkflowDescriptor {\n return {\n id,\n label,\n description: options.description,\n selectionScopes: options.selectionScopes ?? [...ALL_SELECTION_SCOPES],\n sensitivity: options.sensitivity ?? 'public',\n confirmation: options.confirmation ?? 'required',\n execution: options.execution ?? 'foreground',\n inputSchema: options.inputSchema ?? NO_INPUT,\n eligibility: options.eligibility,\n permissionRequirements: options.permissionRequirements ?? {\n tool: `content.workflow.${id}`,\n operations: [CONTENT_READ_OPERATION, CONTENT_UPDATE_OPERATION],\n },\n consequences: options.consequences,\n partialResult: {\n statuses: ['accepted', 'skipped', 'failed'],\n preservesFailedSelection: true,\n },\n };\n}\n\nexport interface ContentListActionTarget {\n /** Canonical query sent to the content query endpoint. Required except for explicit IDs. */\n query?: DataQueryRequest;\n /** Count visible at selection time; drift fails the preview/apply. */\n expectedCount: number;\n /** Operator-entered preview count, required only for permanent-delete apply. */\n confirmedCount?: number;\n}\n\nexport interface ContentListActionRequest\n extends DataSurfaceServerActionRequest {\n actionId: ContentListServerActionId;\n target: ContentListActionTarget;\n}\n\nexport interface ContentListActionCollection extends ContentQueryCollection {\n get(filter: string | Record<string, unknown>): Promise<Content | null>;\n}\n\n/**\n * Persistence-free copy supplied to host format/optimize handlers.\n *\n * Only the explicitly copied mutable fields are applied back to Content before\n * the adapter's revision-guarded save. Identity, tenancy, lifecycle state,\n * relationship IDs, database handles, and Content persistence methods are\n * deliberately absent.\n */\nexport interface ContentListWorkflowDraft {\n readonly contentId: string;\n readonly tenantId: string | null;\n readonly type: string | null;\n readonly variant: string | null;\n readonly status: Content['status'];\n readonly state: Content['state'];\n fileKey: string | null;\n author: string | null;\n name: string;\n title: string;\n description: string | null;\n body: string;\n bodyFormat: ContentBodyFormat | null;\n publish_date: Date | null;\n url: string | null;\n source: string | null;\n original_url: string | null;\n language: string | null;\n tags: string[];\n category: string | null;\n metadata: Record<string, unknown>;\n thumbnailAssetId: string | null;\n}\n\nexport interface ContentListWorkflowHandlers {\n /** Mutate a persistence-free draft; the adapter applies it by revision CAS. */\n formatBody?: (\n content: ContentListWorkflowDraft,\n payload: DataSurfaceJsonValue | undefined,\n run: PrincipalRun,\n ) => Promise<void>;\n /** Mutate a persistence-free draft; the adapter applies it by revision CAS. */\n optimize?: (\n content: ContentListWorkflowDraft,\n payload: DataSurfaceJsonValue | undefined,\n run: PrincipalRun,\n ) => Promise<void>;\n}\n\nexport interface ContentListWorkflowStorage {\n adapterType: 'sqlite' | 'postgres' | 'duckdb' | 'json';\n writeStrategy?: 'immediate' | 'manual' | 'none';\n}\n\nexport class UnsupportedContentListWorkflowStorageError extends Error {\n readonly code = 'UNSUPPORTED_CONTENT_LIST_WORKFLOW_STORAGE';\n\n constructor(storage: ContentListWorkflowStorage) {\n super(\n `ContentList workflows do not support ${storage.adapterType} with ` +\n 'immediate write-back because exported files are not transactionally ' +\n 'rolled back. Use PostgreSQL, SQLite, ordinary DuckDB, or a ' +\n 'non-immediate write strategy.',\n );\n this.name = 'UnsupportedContentListWorkflowStorageError';\n }\n}\n\nexport function assertContentListWorkflowStorageSupported(\n storage: ContentListWorkflowStorage,\n): void {\n const adapterType: unknown = storage?.adapterType;\n const writeStrategy: unknown = storage?.writeStrategy;\n if (\n adapterType !== 'sqlite' &&\n adapterType !== 'postgres' &&\n adapterType !== 'duckdb' &&\n adapterType !== 'json'\n ) {\n throw new TypeError(\n 'ContentList workflow storage adapterType must be sqlite, postgres, duckdb, or json.',\n );\n }\n if (\n writeStrategy !== undefined &&\n writeStrategy !== 'immediate' &&\n writeStrategy !== 'manual' &&\n writeStrategy !== 'none'\n ) {\n throw new TypeError(\n 'ContentList workflow storage writeStrategy must be immediate, manual, or none.',\n );\n }\n const effectiveStrategy =\n adapterType === 'json' ? (writeStrategy ?? 'immediate') : writeStrategy;\n if (\n (adapterType === 'json' || adapterType === 'duckdb') &&\n effectiveStrategy === 'immediate'\n ) {\n throw new UnsupportedContentListWorkflowStorageError({\n adapterType,\n writeStrategy: effectiveStrategy,\n });\n }\n}\n\nexport interface ContentListActionAdapterOptions {\n /** Public adapter capability contract; validated before any workflow state is created. */\n workflowStorage: ContentListWorkflowStorage;\n state: DataSurfaceActionStateStore;\n collection(\n run: PrincipalRun,\n ): ContentListActionCollection | Promise<ContentListActionCollection>;\n /** Trusted site/organization narrowing, applied in addition to tenant context. */\n scope?: (\n run: PrincipalRun,\n ) => ContentQueryScope | undefined | Promise<ContentQueryScope | undefined>;\n /** Server-owned mounted/catalog revision. Defaults to zero for standalone endpoints. */\n revision?: (\n run: PrincipalRun,\n identity: DataSurfaceIdentity,\n ) => number | Promise<number>;\n authorize?: (\n workflow: ContentListServerActionId,\n run: PrincipalRun,\n ) => boolean | Promise<boolean>;\n handlers?: ContentListWorkflowHandlers;\n backgroundQueue?: DataSurfaceBackgroundQueue;\n backgroundHandlerId?: string;\n /** In-process secret used to authenticate the durable background envelope. */\n deferredEnvelopeSigningKey?: string | Uint8Array;\n descriptor?: DataSurfaceDescriptor;\n maxSelectionSize?: number;\n representativeLimit?: number;\n tokenTtlMs?: number;\n /** Test/host seam for principal execution; production defaults to executeAsPrincipal. */\n runAsPrincipal?: typeof import('@happyvertical/smrt-agents').executeAsPrincipal;\n /** Resolve the live persona/TenantAgent binding before a queued mutation. */\n resolveDeferredPrincipal?: Parameters<\n typeof createDataSurfaceActionAdapter\n >[0]['resolveDeferredPrincipal'];\n}\n\ninterface ResolvedContentSelection {\n revision: number;\n queryFingerprint: string;\n rowIds: DataSurfaceRowId[];\n rows: Array<Record<string, unknown>>;\n representativeLabels: string[];\n scope: ContentListActionRequest['selection']['scope'];\n}\n\nconst REQUIRED_QUERY_FIELDS = ['id', 'title', 'status', 'updated_at'] as const;\nconst DEFAULT_MAX_SELECTION_SIZE = 200;\nconst DEFAULT_REPRESENTATIVE_LIMIT = 5;\n\nclass ContentListActionError extends Error {\n constructor(readonly reason: string) {\n super(reason);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isPermissionDenied(error: unknown): boolean {\n if (!(error instanceof Error) || error.name !== 'OperationPermissionError')\n return false;\n const decision = (error as Error & { decision?: unknown }).decision;\n return isRecord(decision) && decision.reason === 'permission_denied';\n}\n\nfunction isServerActionId(value: unknown): value is ContentListServerActionId {\n return CONTENT_LIST_SERVER_ACTIONS.some(({ id }) => id === value);\n}\n\nfunction payloadRecord(\n value: DataSurfaceJsonValue | undefined,\n): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction validPayload(\n workflowId: ContentListServerActionId,\n payload: DataSurfaceJsonValue | undefined,\n): boolean {\n if (payload !== undefined && !isRecord(payload)) return false;\n const value = payloadRecord(payload);\n const keys = Object.keys(value);\n switch (workflowId) {\n case 'restore':\n return (\n keys.length === 1 &&\n typeof value.status === 'string' &&\n ['draft', 'review', 'published'].includes(value.status)\n );\n case 'categorize':\n return (\n keys.length === 1 &&\n typeof value.category === 'string' &&\n value.category.trim().length > 0 &&\n value.category.length <= 256\n );\n case 'automated-review':\n return (\n keys.every((key) => ['kind', 'policyKey'].includes(key)) &&\n (value.kind === undefined ||\n (typeof value.kind === 'string' &&\n ['facts', 'safety', 'custom'].includes(value.kind) &&\n value.kind.length > 0 &&\n value.kind.length <= 64)) &&\n (value.policyKey === undefined ||\n (typeof value.policyKey === 'string' &&\n value.policyKey.length > 0 &&\n value.policyKey.length <= 128))\n );\n case 'format-body':\n return (\n keys.every((key) => key === 'format') &&\n (value.format === undefined ||\n value.format === 'markdown' ||\n value.format === 'html')\n );\n case 'optimize':\n return (\n keys.every((key) => key === 'instructions') &&\n (value.instructions === undefined ||\n (typeof value.instructions === 'string' &&\n value.instructions.length <= 4096))\n );\n default:\n return keys.length === 0;\n }\n}\n\nfunction actionResult(\n request: unknown,\n ok: boolean,\n reason?: string,\n): DataSurfaceActionResult {\n const candidate = isRecord(request) ? request : {};\n const identityCandidate = isRecord(candidate.identity)\n ? candidate.identity\n : {};\n const identity: DataSurfaceIdentity =\n typeof identityCandidate.surfaceId === 'string' &&\n ['table', 'list', 'report', 'custom'].includes(\n String(identityCandidate.kind),\n )\n ? (identityCandidate as unknown as DataSurfaceIdentity)\n : { surfaceId: 'content-list', kind: 'table' };\n return {\n version: 1,\n requestId:\n typeof candidate.requestId === 'string'\n ? candidate.requestId\n : 'invalid-request',\n identity,\n actionId:\n typeof candidate.actionId === 'string' ? candidate.actionId : 'invalid',\n phase: candidate.phase === 'apply' ? 'apply' : 'preview',\n ok,\n ...(reason ? { reason } : {}),\n };\n}\n\nfunction validateTarget(request: unknown): string | undefined {\n if (\n !isRecord(request) ||\n !isServerActionId(request.actionId) ||\n !isRecord(request.target) ||\n !isRecord(request.selection)\n )\n return 'invalid_request';\n const keys = Object.keys(request.target);\n if (\n keys.some(\n (key) =>\n key !== 'query' && key !== 'expectedCount' && key !== 'confirmedCount',\n )\n )\n return 'invalid_request';\n const expectedCount = request.target.expectedCount;\n if (\n typeof expectedCount !== 'number' ||\n !Number.isSafeInteger(expectedCount) ||\n expectedCount < 0\n ) {\n return 'invalid_request';\n }\n const requiresCountAffirmation =\n request.actionId === 'permanent-delete' && request.phase === 'apply';\n if (\n (requiresCountAffirmation &&\n (request.target.confirmedCount !== expectedCount ||\n !Number.isSafeInteger(request.target.confirmedCount))) ||\n (!requiresCountAffirmation && request.target.confirmedCount !== undefined)\n ) {\n return 'confirmation_count_mismatch';\n }\n if (\n request.selection.scope !== 'explicit-ids' &&\n !isRecord(request.target.query)\n ) {\n return 'invalid_request';\n }\n if (\n request.target.query !== undefined &&\n !isBoundedDataSurfaceJsonValue(request.target.query)\n ) {\n return 'invalid_request';\n }\n return undefined;\n}\n\nfunction statusOf(content: Content): string {\n return String(content.status ?? '').toLowerCase();\n}\n\nasync function publishReady(content: Content): Promise<boolean> {\n const governance = await content.resolveGovernance();\n if (!governance.isGoverned || !governance.enforcePublishReadiness)\n return true;\n if (!governance.publicationProfileKey) return false;\n return (await content.evaluateReviewProfile(governance.publicationProfileKey))\n .ready;\n}\n\nasync function eligibility(\n workflowId: ContentListServerActionId,\n content: Content,\n payload: DataSurfaceJsonValue | undefined,\n handlers: ContentListWorkflowHandlers,\n): Promise<{ eligible: boolean; reason?: string }> {\n const status = statusOf(content);\n if (workflowId === 'restore') {\n if (status !== 'deleted') return { eligible: false, reason: 'not_deleted' };\n if (\n payloadRecord(payload).status === 'published' &&\n !(await publishReady(content))\n ) {\n return { eligible: false, reason: 'publish_readiness_failed' };\n }\n return { eligible: true };\n }\n if (workflowId === 'permanent-delete') {\n return status === 'deleted'\n ? { eligible: true }\n : { eligible: false, reason: 'not_deleted' };\n }\n if (status === 'deleted') return { eligible: false, reason: 'deleted' };\n switch (workflowId) {\n case 'move-to-trash':\n return { eligible: true };\n case 'mark-draft':\n return status === 'draft'\n ? { eligible: false, reason: 'already_draft' }\n : { eligible: true };\n case 'submit-review':\n return status === 'draft'\n ? { eligible: true }\n : { eligible: false, reason: 'requires_draft' };\n case 'publish':\n if (!['draft', 'review', 'archived'].includes(status))\n return { eligible: false, reason: 'invalid_status' };\n return (await publishReady(content))\n ? { eligible: true }\n : { eligible: false, reason: 'publish_readiness_failed' };\n case 'archive':\n return status === 'archived'\n ? { eligible: false, reason: 'already_archived' }\n : { eligible: true };\n case 'automated-review': {\n const governance = await content.resolveGovernance();\n if (!governance.isGoverned)\n return { eligible: false, reason: 'governance_unavailable' };\n const input = payloadRecord(payload);\n const policy =\n typeof input.policyKey === 'string'\n ? governance.reviewPolicies.find(\n (entry) => entry.key === input.policyKey,\n )\n : undefined;\n if (typeof input.policyKey === 'string' && !policy)\n return { eligible: false, reason: 'review_policy_unavailable' };\n if (\n typeof input.kind === 'string' &&\n policy &&\n policy.kind !== input.kind\n )\n return { eligible: false, reason: 'review_kind_mismatch' };\n return { eligible: true };\n }\n case 'format-body':\n return handlers.formatBody\n ? { eligible: true }\n : { eligible: false, reason: 'handler_unavailable' };\n case 'categorize':\n return { eligible: true };\n case 'optimize':\n if (!handlers.optimize)\n return { eligible: false, reason: 'handler_unavailable' };\n return ['draft', 'review'].includes(status)\n ? { eligible: true }\n : { eligible: false, reason: 'requires_draft_or_review' };\n }\n}\n\nasync function applyWorkflow(\n workflowId: ContentListServerActionId,\n content: Content,\n expectedUpdatedAt: Date | string,\n payload: DataSurfaceJsonValue | undefined,\n run: PrincipalRun,\n handlers: ContentListWorkflowHandlers,\n): Promise<void> {\n const input = payloadRecord(payload);\n const save = async () => {\n await content.withTransaction((bound) => bound.save({ expectedUpdatedAt }));\n };\n const mutationDraft = (): ContentListWorkflowDraft => ({\n contentId: String(content.id),\n tenantId: content.tenantId,\n type: content.type,\n variant: content.variant,\n status: content.status,\n state: content.state,\n fileKey: content.fileKey,\n author: content.author,\n name: content.name,\n title: content.title,\n description: content.description,\n body: content.body,\n bodyFormat: content.bodyFormat,\n publish_date: content.publish_date,\n url: content.url,\n source: content.source,\n original_url: content.original_url,\n language: content.language,\n tags: [...(content.tags ?? [])],\n category: content.category,\n metadata: structuredClone(content.metadata ?? {}),\n thumbnailAssetId: content.thumbnailAssetId,\n });\n const applyDraft = (draft: ContentListWorkflowDraft) => {\n content.fileKey = draft.fileKey;\n content.author = draft.author;\n content.name = draft.name;\n content.title = draft.title;\n content.description = draft.description;\n content.body = draft.body;\n content.bodyFormat = draft.bodyFormat;\n content.publish_date = draft.publish_date;\n content.url = draft.url;\n content.source = draft.source;\n content.original_url = draft.original_url;\n content.language = draft.language;\n content.tags = [...draft.tags];\n content.category = draft.category;\n content.metadata = structuredClone(draft.metadata);\n content.thumbnailAssetId = draft.thumbnailAssetId;\n };\n const runHandler = async (\n handler: NonNullable<ContentListWorkflowHandlers['formatBody']>,\n ) => {\n const draft = mutationDraft();\n await handler(draft, payload, run);\n applyDraft(draft);\n await save();\n };\n switch (workflowId) {\n case 'move-to-trash':\n content.status = 'deleted';\n await save();\n return;\n case 'mark-draft':\n content.status = 'draft';\n await save();\n return;\n case 'submit-review':\n content.status = 'review';\n await save();\n return;\n case 'publish':\n content.status = 'published';\n await save();\n return;\n case 'archive':\n content.status = 'archived';\n await save();\n return;\n case 'restore':\n content.status = input.status as Content['status'];\n await save();\n return;\n case 'permanent-delete':\n // Content owns cascading references, so a revision-guarded destructive\n // delete must never use the core's documented non-transaction fallback.\n // Probe through the public object API before any cascade can begin.\n await content.withTransaction(async () => undefined);\n await content.delete({ expectedUpdatedAt });\n return;\n case 'automated-review':\n await content.runReviewAction({\n expectedUpdatedAt,\n ...(typeof input.kind === 'string'\n ? { kind: input.kind as never }\n : {}),\n ...(typeof input.policyKey === 'string'\n ? { policyKey: input.policyKey }\n : {}),\n });\n return;\n case 'format-body':\n if (!handlers.formatBody) throw new Error('format handler unavailable');\n await runHandler(handlers.formatBody);\n return;\n case 'categorize':\n content.category = String(input.category).trim();\n await save();\n return;\n case 'optimize':\n if (!handlers.optimize) throw new Error('optimize handler unavailable');\n await runHandler(handlers.optimize);\n return;\n }\n}\n\nfunction revisionFingerprint(rows: readonly Record<string, unknown>[]): string {\n const canonical = rows\n .map((row) => `${String(row.id)}\\u0000${String(row.updated_at ?? '')}`)\n .sort();\n return createHash('sha256')\n .update(canonical.join('\\u0001'))\n .digest('base64url');\n}\n\nfunction representativeLabels(\n rows: readonly Record<string, unknown>[],\n limit: number,\n): string[] {\n return rows.slice(0, limit).map((row) => {\n const title = typeof row.title === 'string' ? row.title.trim() : '';\n return title || String(row.id);\n });\n}\n\nasync function resolveQuerySelection(\n request: ContentListActionRequest,\n collection: ContentListActionCollection,\n scope: ContentQueryScope | undefined,\n maxSelectionSize: number,\n representativeLimit: number,\n revision: number,\n): Promise<ResolvedContentSelection> {\n const schema = await buildContentQuerySchema();\n const selection = request.selection;\n const rows: Array<Record<string, unknown>> = [];\n let queryFingerprint: string;\n\n if (selection.scope === 'explicit-ids') {\n const ids = [...new Set(selection.rowIds.map((rowId) => String(rowId)))];\n if (ids.length > maxSelectionSize)\n throw new ContentListActionError('limit_exceeded');\n queryFingerprint = `explicit:${revisionFingerprint(ids.map((id) => ({ id })))}`;\n for (let start = 0; start < ids.length; start += 100) {\n const chunk = ids.slice(start, start + 100);\n const query: DataQueryRequest = {\n version: 1,\n requestId: `content-action-explicit-${start}`,\n mode: 'rows',\n projection: [...REQUIRED_QUERY_FIELDS],\n filter: {\n kind: 'condition',\n field: 'id',\n operator: 'in',\n value: chunk,\n },\n sort: [{ field: 'id', direction: 'asc' }],\n page: { kind: 'offset', offset: 0, limit: Math.max(1, chunk.length) },\n };\n const result = await executeContentQuery(collection, query, { scope });\n rows.push(...result.rows);\n }\n queryFingerprint = `${queryFingerprint}:${revisionFingerprint(rows)}`;\n } else {\n const input = request.target.query;\n if (!input) throw new ContentListActionError('invalid_target');\n const normalized = normalizeDataQueryRequest(input, schema);\n const allMatchingPageLimit = Math.min(\n maxSelectionSize,\n MAX_DATA_QUERY_PAGE_LIMIT,\n );\n const querySchema =\n selection.scope === 'all-matching'\n ? {\n ...schema,\n defaultPageLimit: Math.min(\n schema.defaultPageLimit ?? CONTENT_QUERY_MAX_PAGE_LIMIT,\n allMatchingPageLimit,\n ),\n maxPageLimit: allMatchingPageLimit,\n }\n : schema;\n if (normalized.mode !== 'rows')\n throw new ContentListActionError('invalid_target');\n for (const field of REQUIRED_QUERY_FIELDS) {\n if (!normalized.projection?.includes(field))\n throw new ContentListActionError('missing_action_projection');\n }\n const baseFingerprint = createDataQueryFingerprint(normalized, schema);\n if (\n selection.scope === 'all-matching' &&\n selection.queryFingerprint !== baseFingerprint\n ) {\n throw new ContentListActionError('stale_query_fingerprint');\n }\n const pageLimit =\n selection.scope === 'current-page'\n ? (normalized.page?.limit ?? CONTENT_QUERY_MAX_PAGE_LIMIT)\n : allMatchingPageLimit;\n const offset =\n selection.scope === 'current-page' && normalized.page?.kind === 'offset'\n ? normalized.page.offset\n : 0;\n const pageRequest: DataQueryRequest = {\n ...normalized,\n requestId: `${normalized.requestId}-action-${offset}`.slice(0, 128),\n page: { kind: 'offset', offset, limit: Math.max(1, pageLimit) },\n };\n const result = await executeContentQuery(collection, pageRequest, {\n scope,\n schema: querySchema,\n });\n if (result.total.kind !== 'exact')\n throw new ContentListActionError('count_unavailable');\n if (selection.scope === 'all-matching' && result.total.value > pageLimit) {\n throw new ContentListActionError('limit_exceeded');\n }\n rows.push(...result.rows);\n if (\n selection.scope === 'all-matching' &&\n rows.length !== result.total.value\n ) {\n throw new ContentListActionError('matching_count_drifted');\n }\n if (selection.scope === 'all-matching') {\n const distinctIds = new Set(rows.map((row) => String(row.id)));\n if (distinctIds.size !== rows.length) {\n throw new ContentListActionError('matching_count_drifted');\n }\n }\n queryFingerprint = `${baseFingerprint}:${revisionFingerprint(rows)}`;\n }\n\n if (request.target.expectedCount !== rows.length) {\n throw new ContentListActionError('matching_count_drifted');\n }\n return {\n revision,\n queryFingerprint,\n rowIds: rows.map((row) => row.id as DataSurfaceRowId),\n rows,\n representativeLabels: representativeLabels(rows, representativeLimit),\n scope: selection.scope,\n };\n}\n\nfunction defaultDescriptor(maxSelectionSize: number): DataSurfaceDescriptor {\n return {\n version: 1,\n identity: { surfaceId: 'content-list', kind: 'table' },\n schemaVersion: 2,\n label: 'Contents',\n rowKey: 'id',\n columns: [\n {\n id: 'id',\n label: 'Content id',\n fieldName: 'id',\n role: 'row-key',\n capabilities: ['read', 'project'],\n },\n {\n id: 'title',\n label: 'Title',\n fieldName: 'title',\n capabilities: ['read', 'project'],\n },\n {\n id: 'status',\n label: 'Status',\n fieldName: 'status',\n role: 'status',\n capabilities: ['read', 'project'],\n },\n ],\n query: {\n modes: ['rows', 'count'],\n projectableColumnIds: ['id', 'title', 'status'],\n },\n controls: [],\n actions: CONTENT_LIST_SERVER_ACTIONS.map((entry) => ({\n id: entry.id,\n label: entry.label,\n description: entry.description,\n sensitivity: entry.sensitivity,\n selectionScopes: [...entry.selectionScopes],\n requiresConfirmation: entry.confirmation === 'required',\n })),\n limits: {\n maxQueryRows: CONTENT_QUERY_MAX_PAGE_LIMIT,\n maxQueryBytes: 1_000_000,\n maxSelectionSize,\n },\n };\n}\n\nexport interface ContentListActionAdapter extends DataSurfaceActionAdapter {\n preview(\n request: ContentListActionRequest,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult>;\n apply(\n request: ContentListActionRequest,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult>;\n}\n\nexport function createContentListActionAdapter(\n options: ContentListActionAdapterOptions,\n): ContentListActionAdapter {\n assertContentListWorkflowStorageSupported(options.workflowStorage);\n const handlers = options.handlers ?? {};\n const maxSelectionSize =\n options.maxSelectionSize ??\n options.descriptor?.limits.maxSelectionSize ??\n DEFAULT_MAX_SELECTION_SIZE;\n if (\n !Number.isSafeInteger(maxSelectionSize) ||\n maxSelectionSize < 1 ||\n maxSelectionSize > MAX_DATA_QUERY_PAGE_LIMIT\n ) {\n throw new Error(\n `ContentList maxSelectionSize must be an integer between 1 and ${MAX_DATA_QUERY_PAGE_LIMIT} so all-matching membership resolves in one bounded query`,\n );\n }\n const representativeLimit =\n options.representativeLimit ?? DEFAULT_REPRESENTATIVE_LIMIT;\n const descriptor = options.descriptor ?? defaultDescriptor(maxSelectionSize);\n if (descriptor.limits.maxSelectionSize !== maxSelectionSize) {\n throw new Error(\n 'ContentList descriptor maxSelectionSize must match the server selection cap',\n );\n }\n const resolvedByRequest = new WeakMap<object, ResolvedContentSelection>();\n const contentByRequest = new WeakMap<\n object,\n Map<string, Promise<Content | null>>\n >();\n // Request ids are client input and may collide across concurrent calls.\n const invocationResources = new AsyncLocalStorage<\n Map<string, { resourceId: string; resourceType: string }>\n >();\n async function loadContent(\n invocation: { run: PrincipalRun; request: DataSurfaceServerActionRequest },\n rowId: DataSurfaceRowId,\n ): Promise<Content | null> {\n const key = String(rowId);\n let byRow = contentByRequest.get(invocation.request);\n if (!byRow) {\n byRow = new Map();\n contentByRequest.set(invocation.request, byRow);\n }\n let pending = byRow.get(key);\n if (!pending) {\n pending = (async () => {\n const collection = await options.collection(invocation.run);\n const content = await collection.get({ id: key });\n if (!content) return null;\n const serialized = content.toJSON() as Record<string, unknown>;\n invocationResources.getStore()?.set(key, {\n resourceId: String(content.id),\n resourceType:\n typeof serialized._meta_type === 'string'\n ? serialized._meta_type\n : content.constructor.name,\n });\n const resolved = resolvedByRequest.get(invocation.request);\n const expected = resolved?.rows.find((row) => String(row.id) === key);\n const revisionValue = (value: unknown) =>\n value instanceof Date ? value.toISOString() : String(value ?? '');\n if (\n !expected ||\n revisionValue(content.updated_at) !==\n revisionValue(expected.updated_at)\n ) {\n throw new ContentListActionError('row_revision_drifted');\n }\n return content;\n })();\n byRow.set(key, pending);\n }\n return pending;\n }\n\n const mapActionError = (error: unknown) =>\n error instanceof ContentListActionError\n ? error.reason\n : isRecord(error) && error.code === 'RUNTIME_REVISION_CONFLICT'\n ? 'row_revision_drifted'\n : isPermissionDenied(error) ||\n error instanceof PrincipalToolNotAllowedError\n ? 'denied'\n : undefined;\n\n const definitions = Object.fromEntries(\n CONTENT_LIST_SERVER_ACTIONS.map(\n (entry): [string, DataSurfaceServerActionDefinition] => [\n entry.id,\n {\n descriptor: {\n id: entry.id,\n label: entry.label,\n description: entry.description,\n sensitivity: entry.sensitivity,\n selectionScopes: [...entry.selectionScopes],\n requiresConfirmation: entry.confirmation === 'required',\n },\n inputSchema: entry.inputSchema,\n validatePayload: (payload) =>\n validPayload(entry.id, payload)\n ? { valid: true }\n : { valid: false, reason: 'invalid_payload' },\n confirmation: entry.confirmation,\n execution: entry.execution,\n tool: entry.permissionRequirements.tool,\n operation:\n entry.permissionRequirements.operations[0] ??\n CONTENT_READ_OPERATION,\n authorize: async (invocation) => {\n const operations =\n entry.id === 'restore' &&\n payloadRecord(invocation.request.payload).status !== 'published'\n ? entry.permissionRequirements.operations.slice(0, 2)\n : entry.permissionRequirements.operations;\n for (const operation of operations.slice(1)) {\n try {\n await invocation.run.assertOperation(\n operation.collection,\n operation.action,\n );\n } catch (error) {\n if (isPermissionDenied(error)) return false;\n throw error;\n }\n }\n return options.authorize?.(entry.id, invocation.run) ?? true;\n },\n eligible: async (invocation, rowId) => {\n const content = await loadContent(invocation, rowId);\n if (!content)\n return { eligible: false, reason: 'not_found_or_denied' };\n return eligibility(\n entry.id,\n content,\n invocation.request.payload,\n handlers,\n );\n },\n apply: async (invocation, rowId) => {\n const content = await loadContent(invocation, rowId);\n if (!content) throw new Error('content not found');\n const expectedUpdatedAt = content.updated_at;\n if (\n !(expectedUpdatedAt instanceof Date) &&\n typeof expectedUpdatedAt !== 'string'\n ) {\n throw new ContentListActionError('row_revision_drifted');\n }\n const resource = invocationResources.getStore()?.get(String(rowId));\n try {\n await applyWorkflow(\n entry.id,\n content,\n expectedUpdatedAt,\n invocation.request.payload,\n invocation.run,\n handlers,\n );\n } catch (error) {\n if (entry.id !== 'permanent-delete') throw error;\n // delete() commits before its post-delete hooks. If one of those\n // hooks fails, confirm the authoritative row state so an\n // irreversible success is never reported as retryable failure.\n const collection = await options.collection(invocation.run);\n if (await collection.get({ id: String(rowId) })) throw error;\n }\n return resource ?? null;\n },\n },\n ],\n ),\n );\n\n const state: DataSurfaceActionStateStore = {\n putToken: (...args) => options.state.putToken(...args),\n getToken: (...args) => options.state.getToken(...args),\n markTokenConsumed: (...args) => options.state.markTokenConsumed(...args),\n consumeTokenAndReserveIdempotency: (...args) =>\n options.state.consumeTokenAndReserveIdempotency(...args),\n getIdempotency: (...args) => options.state.getIdempotency(...args),\n reserveIdempotency: (...args) => options.state.reserveIdempotency(...args),\n completeIdempotency: (key, ownerToken, result) => {\n if (result.details) {\n result.details = {\n ...result.details,\n auditReference: result.requestId,\n };\n }\n return options.state.completeIdempotency(key, ownerToken, result);\n },\n releaseIdempotency: (...args) => options.state.releaseIdempotency(...args),\n };\n\n const generic = createDataSurfaceActionAdapter({\n state,\n backgroundQueue: options.backgroundQueue,\n backgroundHandlerId: options.backgroundHandlerId,\n deferredEnvelopeSigningKey: options.deferredEnvelopeSigningKey,\n tokenTtlMs: options.tokenTtlMs,\n runAsPrincipal: options.runAsPrincipal,\n resolveDeferredPrincipal: options.resolveDeferredPrincipal,\n requestFingerprintExtension: (request) =>\n (() => {\n const target = (request as ContentListActionRequest).target;\n // The operator-entered count exists only on apply. Bind the preview's\n // server-checked expected count/query into the token while validating\n // the separate affirmation above before the generic adapter runs.\n return {\n expectedCount: target.expectedCount,\n ...(target.query ? { query: target.query } : {}),\n } as unknown as DataSurfaceJsonValue;\n })(),\n mapError: mapActionError,\n resolveSurface: async (run) => ({\n descriptor,\n revision: await (options.revision?.(run, descriptor.identity) ?? 0),\n actions: definitions,\n }),\n resolveSelection: async (invocation, selection) => {\n const request = invocation.request as ContentListActionRequest;\n const collection = await options.collection(invocation.run);\n const scope = await options.scope?.(invocation.run);\n const revision = await (options.revision?.(\n invocation.run,\n descriptor.identity,\n ) ?? 0);\n const resolved = await resolveQuerySelection(\n { ...request, selection },\n collection,\n scope,\n maxSelectionSize,\n representativeLimit,\n revision,\n );\n resolvedByRequest.set(request, resolved);\n return resolved;\n },\n });\n\n async function invoke(\n phase: 'preview' | 'apply',\n request: ContentListActionRequest,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult> {\n const invalid = validateTarget(request);\n if (invalid) return actionResult(request, false, invalid);\n try {\n const resources = new Map<\n string,\n { resourceId: string; resourceType: string }\n >();\n const result = await invocationResources.run(resources, () =>\n generic[phase](request, context),\n );\n const resolved = resolvedByRequest.get(request);\n const workflow = CONTENT_LIST_SERVER_ACTIONS.find(\n (entry) => entry.id === request.actionId,\n );\n const outcomes = Array.isArray(result.details?.outcomes)\n ? result.details.outcomes.map((outcome) => {\n if (!isRecord(outcome)) return outcome;\n const resource =\n resources?.get(String(outcome.rowId)) ??\n (typeof outcome.resourceId === 'string' &&\n typeof outcome.resourceType === 'string'\n ? {\n resourceId: outcome.resourceId,\n resourceType: outcome.resourceType,\n }\n : undefined);\n return resource ? { ...outcome, ...resource } : outcome;\n })\n : undefined;\n if (phase !== 'preview' || !result.ok) {\n return {\n ...result,\n ...(result.details\n ? {\n details: {\n ...result.details,\n ...(outcomes ? { outcomes } : {}),\n auditReference:\n typeof result.details.auditReference === 'string'\n ? result.details.auditReference\n : request.requestId,\n },\n }\n : {}),\n };\n }\n return {\n ...result,\n details: {\n ...(result.details ?? {}),\n ...(outcomes ? { outcomes } : {}),\n resolvedScope: resolved?.scope ?? request.selection.scope,\n representativeLabels: resolved?.representativeLabels ?? [],\n ineligible: Array.isArray(result.details?.outcomes)\n ? result.details.outcomes.filter(\n (entry) => isRecord(entry) && entry.status === 'skipped',\n )\n : [],\n consequences: workflow?.consequences ?? [],\n sensitivity: workflow?.sensitivity ?? 'public',\n execution: workflow?.execution ?? 'foreground',\n auditReference: request.requestId,\n },\n };\n } catch (error) {\n return actionResult(\n request,\n false,\n mapActionError(error) ?? 'execution_failed',\n );\n } finally {\n resolvedByRequest.delete(request);\n }\n }\n\n return {\n preview: (request, context) => invoke('preview', request, context),\n apply: (request, context) => invoke('apply', request, context),\n executeDeferred: (envelope) => generic.executeDeferred(envelope),\n };\n}\n","/** Principal-bound, silent ContentList query discovery and execution (#2456). */\n\nimport {\n assertIdFieldConditions,\n type DataSurfaceDefinition,\n type DataSurfaceExecutionContext,\n type DataSurfaceSchema,\n uuidColumnFieldIds,\n} from '@happyvertical/smrt-agents';\nimport { normalizeDataQueryRequest } from '@happyvertical/smrt-core';\nimport type { DataQuerySchema } from '@happyvertical/smrt-types';\nimport {\n assertContentQuerySchema,\n buildContentQuerySchema,\n CONTENT_QUERY_CLASS_NAME,\n type ContentQueryCollection,\n type ContentQueryScope,\n executeContentQuery,\n} from '../content-query.js';\n\nexport const CONTENT_LIST_DATA_SURFACE_ID = 'content-list';\nexport const CONTENT_LIST_DATA_SURFACE_COLLECTION = 'contents';\n\nexport interface ContentListDataSurfaceOptions {\n /** Stable catalog id. Defaults to the mounted ContentList surface id. */\n id?: string;\n /** Permission-catalog collection checked by the generic agent tools. */\n collectionName?: string;\n label?: string;\n description?: string;\n metadata?: NonNullable<DataSurfaceDefinition['metadata']>;\n /** Host-supplied discovery size hint; never computed by querying. */\n rowCountHint?: DataSurfaceDefinition['rowCountHint'];\n /** Resolve a collection from the live principal context, never model input. */\n collection:\n | ContentQueryCollection\n | ((\n context: DataSurfaceExecutionContext,\n ) => ContentQueryCollection | Promise<ContentQueryCollection>);\n /** Trusted application narrowing applied in addition to tenant isolation. */\n scope?:\n | ContentQueryScope\n | ((\n context: DataSurfaceExecutionContext,\n ) =>\n | ContentQueryScope\n | undefined\n | Promise<ContentQueryScope | undefined>);\n /** Trusted policy override; defaults to the canonical Content query schema. */\n schema?: DataSurfaceSchema;\n}\n\nfunction requiredName(\n value: string | undefined,\n fallback: string,\n label: string,\n) {\n const resolved = value ?? fallback;\n if (resolved.trim().length === 0) {\n throw new Error(`${label} must be a non-empty string`);\n }\n return resolved;\n}\n\nfunction querySchema(schema: DataSurfaceSchema): DataQuerySchema {\n return {\n ...schema,\n // A host descriptor is untrusted at this boundary. Discovery redacts\n // protected fields, and execution uses the same principal-aware field set\n // so a direct data.query request cannot bypass that policy.\n fields: schema.fields\n .filter(({ sensitive, readPermission }) => {\n if (sensitive) return false;\n return !readPermission;\n })\n .map(\n ({\n sensitive: _sensitive,\n readPermission: _readPermission,\n metadata: _metadata,\n ...field\n }) => field,\n ),\n };\n}\n\nasync function resolveCollection(\n options: ContentListDataSurfaceOptions,\n context: DataSurfaceExecutionContext,\n): Promise<ContentQueryCollection> {\n return typeof options.collection === 'function'\n ? options.collection(context)\n : options.collection;\n}\n\nasync function resolveScope(\n options: ContentListDataSurfaceOptions,\n context: DataSurfaceExecutionContext,\n): Promise<ContentQueryScope | undefined> {\n return typeof options.scope === 'function'\n ? options.scope(context)\n : options.scope;\n}\n\n/**\n * Build one server-owned ContentList surface for `data.discover`,\n * `data.inspect`, and silent/background `data.query` calls.\n *\n * The returned executor resolves its collection and application scope from the\n * live principal context. The request can only narrow that trusted scope, and\n * every projection/count/facet/page still passes through `executeContentQuery`.\n */\nexport async function createContentListDataSurfaceDefinition(\n options: ContentListDataSurfaceOptions,\n): Promise<DataSurfaceDefinition> {\n const schema = options.schema ?? (await buildContentQuerySchema());\n // `SmrtCollection.list({ select })` intentionally refuses model fields with\n // readPermission because that projection primitive has no permission\n // context. Publishing one here would let discovery promise a query that the\n // real collection cannot execute. Keep the server data surface fail-closed:\n // only universally executable, non-sensitive fields are advertised.\n const executableSchema = querySchema(schema);\n assertContentQuerySchema(executableSchema);\n\n return {\n id: requiredName(\n options.id,\n CONTENT_LIST_DATA_SURFACE_ID,\n 'ContentList data surface id',\n ),\n collection: requiredName(\n options.collectionName,\n CONTENT_LIST_DATA_SURFACE_COLLECTION,\n 'ContentList permission collection',\n ),\n className: CONTENT_QUERY_CLASS_NAME,\n label: options.label ?? 'Contents',\n description:\n options.description ??\n 'Bounded, tenant-safe content rows, counts, facets, and continuations.',\n ...(options.rowCountHint !== undefined\n ? { rowCountHint: options.rowCountHint }\n : {}),\n metadata: {\n domain: 'content',\n adapter: 'ContentList',\n views: ['grid', 'detailed', 'compact'],\n queryModes: ['rows', 'count', 'facets'],\n ...options.metadata,\n },\n schema: executableSchema,\n execute: async (_surface, request, context) => {\n // Validate before resolving the host collection. This makes a rejected\n // protected projection a zero-I/O failure, even for hostile descriptors.\n const normalized = normalizeDataQueryRequest(request, executableSchema);\n // A non-UUID value for an id column is refused here, as the caller's\n // error, instead of reaching PostgreSQL as `invalid input syntax for\n // type uuid` (an opaque query failure to the agent).\n assertIdFieldConditions(\n normalized.filter,\n uuidColumnFieldIds(\n CONTENT_QUERY_CLASS_NAME,\n executableSchema.fields.map((field) => field.id),\n ),\n );\n return executeContentQuery(\n await resolveCollection(options, context),\n request,\n {\n schema: executableSchema,\n scope: await resolveScope(options, context),\n },\n );\n },\n };\n}\n","/**\n * Principal-bound HTTP boundary for ContentList lifecycle actions (#2454).\n *\n * Hosts supply authentication by resolving a DataSurface server context from\n * the incoming Request. The service gates this dedicated endpoint to lifecycle\n * actions, then delegates to the same content action adapter used by agents and\n * bulk workflows so authorization, selection resolution, confirmation,\n * idempotency, and audit metadata cannot diverge by caller.\n */\n\nimport type { DataSurfaceServerActionContext } from '@happyvertical/smrt-agents/server';\nimport type {\n DataSurfaceActionResult,\n DataSurfaceIdentity,\n} from '@happyvertical/smrt-types';\nimport {\n CONTENT_LIST_LIFECYCLE_ACTION_IDS,\n type ContentListActionAdapter,\n type ContentListActionRequest,\n type ContentListLifecycleActionId,\n} from './content-list-actions.js';\n\nexport interface ContentListLifecycleService {\n invoke(\n request: unknown,\n context: DataSurfaceServerActionContext,\n ): Promise<DataSurfaceActionResult>;\n}\n\nexport interface ContentListLifecycleRouteOptions {\n adapter: ContentListActionAdapter;\n /** Authenticate and bind the request to its current principal/tenant. */\n context(\n request: Request,\n ): DataSurfaceServerActionContext | Promise<DataSurfaceServerActionContext>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isLifecycleActionId(\n value: unknown,\n): value is ContentListLifecycleActionId {\n return (CONTENT_LIST_LIFECYCLE_ACTION_IDS as readonly unknown[]).includes(\n value,\n );\n}\n\nfunction safeIdentity(value: unknown): DataSurfaceIdentity {\n if (!isRecord(value)) return { surfaceId: 'content-list', kind: 'table' };\n if (\n typeof value.surfaceId !== 'string' ||\n !['table', 'list', 'report', 'custom'].includes(String(value.kind))\n ) {\n return { surfaceId: 'content-list', kind: 'table' };\n }\n return value as unknown as DataSurfaceIdentity;\n}\n\nfunction rejected(\n request: unknown,\n reason: 'invalid_request' | 'unsupported',\n): DataSurfaceActionResult {\n const candidate = isRecord(request) ? request : {};\n return {\n version: 1,\n requestId:\n typeof candidate.requestId === 'string'\n ? candidate.requestId\n : 'invalid-request',\n identity: safeIdentity(candidate.identity),\n actionId:\n typeof candidate.actionId === 'string' ? candidate.actionId : 'invalid',\n phase: candidate.phase === 'apply' ? 'apply' : 'preview',\n ok: false,\n reason,\n };\n}\n\n/** Create the transport-neutral lifecycle service used by HTTP and agent hosts. */\nexport function createContentListLifecycleService(\n adapter: ContentListActionAdapter,\n): ContentListLifecycleService {\n return {\n async invoke(request, context) {\n if (!isRecord(request)) return rejected(request, 'invalid_request');\n if (!isLifecycleActionId(request.actionId)) {\n return rejected(request, 'unsupported');\n }\n if (request.phase !== 'preview' && request.phase !== 'apply') {\n return rejected(request, 'invalid_request');\n }\n return adapter[request.phase](\n request as unknown as ContentListActionRequest,\n context,\n );\n },\n };\n}\n\n/**\n * Create a native Request/Response handler for `POST /api/v1/contents/lifecycle`.\n * SvelteKit hosts can call it with `event.request`; other runtimes can mount it\n * directly anywhere that implements the standard Fetch API.\n */\nexport function createContentListLifecycleRoute(\n options: ContentListLifecycleRouteOptions,\n): (request: Request) => Promise<Response> {\n const service = createContentListLifecycleService(options.adapter);\n return async (request) => {\n if (request.method !== 'POST') {\n return Response.json(\n { error: { message: 'Method not allowed.' } },\n { status: 405, headers: { allow: 'POST' } },\n );\n }\n let input: unknown;\n try {\n input = await request.json();\n } catch {\n return Response.json(\n { error: { message: 'The lifecycle request body must be JSON.' } },\n { status: 400 },\n );\n }\n let context: DataSurfaceServerActionContext;\n try {\n context = await options.context(request);\n } catch {\n return Response.json(\n { error: { message: 'Authentication is required.' } },\n { status: 401 },\n );\n }\n try {\n return Response.json({ result: await service.invoke(input, context) });\n } catch {\n return Response.json(\n { error: { message: 'The lifecycle request could not be completed.' } },\n { status: 500 },\n );\n }\n };\n}\n","/**\n * SMRT Content Service Server\n *\n * Demonstrates auto-generated REST API from SMRT Content objects.\n * No manual route definitions needed - everything is generated from @smrt() decorated classes.\n */\n\nimport { startRestServer } from '@happyvertical/smrt-core';\nimport './__smrt-register__.js';\nimport { Content } from './content';\n\nasync function startServer() {\n console.log('🚀 Starting SMRT Content Server...');\n\n // Start server with registered SMRT objects\n const shutdown = await startRestServer(\n [Content], // SMRT objects to generate API for\n {}, // context\n {\n port: 3100,\n hostname: 'localhost',\n basePath: '/api/v1',\n enableCors: true,\n },\n );\n\n console.log('✅ Server ready!');\n console.log('📡 REST API: http://localhost:3100/api/v1');\n console.log('📚 Endpoints:');\n console.log(' GET /api/v1/contents - List contents');\n console.log(' POST /api/v1/contents - Create content');\n console.log(' GET /api/v1/contents/:id - Get content');\n console.log(' PUT /api/v1/contents/:id - Update content');\n console.log(' DELETE /api/v1/contents/:id - Delete content');\n\n console.log('\\n💡 Try these endpoints:');\n console.log(' curl http://localhost:3100/api/v1/contents');\n console.log(\n ' curl -X POST http://localhost:3100/api/v1/contents -H \"Content-Type: application/json\" -d \\'{\"title\":\"Test Content\",\"body\":\"Test body content\"}\\'',\n );\n\n return { shutdown };\n}\n\n// Start if running directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n startServer().catch(console.error);\n}\n\nexport * from './server/content-list-actions.js';\nexport * from './server/content-list-data-surface.js';\nexport * from './server/content-list-lifecycle.js';\nexport { startServer };\n"],"mappings":"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"}
@@ -3,14 +3,14 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-content",
6
- "packageVersion": "0.57.32",
6
+ "packageVersion": "0.57.33",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "26aefa87b47f751ecc6521202c755cb65de6ca9036c6cffacbf45bbfd7b0c0f9",
11
- "packageJson": "a011f1579b87ddcce7725b024a8e92f5a7633d6834f6e6a2084013ae7ef050dd",
10
+ "manifest": "d5abc285422f8a63e9959f41dcbb7b9474f5cc8ccaa8faa04d03f74623fe1044",
11
+ "packageJson": "f6c309c41ec24a283c462abbb707ccbaea5472525f49a703cd89f6336cebdb78",
12
12
  "agents": "dffe54f5b13fa274d24056c6dc48179bd3bb4ef93c4e47670651f27b67523826",
13
- "moduleDoc:agents/content-list.md": "f616b006826d48af3e16e4f3e0693a7b656e9228b7aa987a791c31660a58da0f"
13
+ "moduleDoc:agents/content-list.md": "76052be17883252011f074d1988df0c0353c352a18d33e2ba3c28c37e363af01"
14
14
  },
15
15
  "exports": [
16
16
  ".",
@@ -13780,7 +13780,7 @@
13780
13780
  {
13781
13781
  "path": "agents/content-list.md",
13782
13782
  "module": "content-list",
13783
- "content": "<!-- Module doc for packages/content/AGENTS.md. -->\n\n# ContentList contracts\n\nRead for changes to `src/svelte/content-list-*.ts`, `ContentList.svelte`, or the\nserver content-query/action adapters. Browser exports come from `/svelte`;\nprincipal-bound query/action factories come from `/server`.\n\n## Ownership and integration\n\n- `content-list-controller.ts` is the shared adapter over `DataTableController`.\n Search, filters, sort, paging, selection, columns, and action eligibility have\n one implementation across grid, detailed, and compact presentations. Controller\n modes are manual. Local arrays use `toContentListRows`, `selectContentListRows`,\n then `paginateContentListRows`; server rows must never be transformed again.\n- `query`, `urlState`, `savedViews`, `lifecycle`, `jobs`, and `dataSurface` are\n optional bindings. Without query, rows come from `contents`; with it, contents\n is ignored. `type` locks/hides the type filter; `defaultViewMode` seeds once.\n Existing callbacks (`onEdit`, `onDelete`, `onAdd`, `getViewHref`) remain usable.\n- `query.bind()` runs once during component initialization so a structural\n `remoteQuery(collection, transport)` binding registers teardown in that scope.\n Do not import smrt-svelte/web or its browser data runtime into the content\n Svelte barrel: public content pages depend on that code-split boundary.\n- The default query transport targets `POST /api/v1/contents/query`.\n `CONTENT_LIST_QUERY_FIELDS` maps column IDs to server fields;\n `ROW_FIELD_TO_CONTENT_KEY` maps response fields to ContentData. For example,\n column `updated`, client `updatedAt`, and server `updated_at` differ.\n `publish` maps to `publish_date`. Derived `site` comes from url/source and has\n no server field; server filtering/sorting on it is dropped and reported.\n- Missing/duplicate durable IDs still render with positional keys but are\n `identified: false`. Disable and explain their selection controls. Page select\n all and normalization exclude synthetic IDs; server selection must survive\n page changes, so current-page membership is not a durability test.\n- Compact uses content-owned `select` and `actions` columns, included in\n `CONTENT_LIST_TABLE_COLUMN_IDS`. DataTable's generic selection cannot enforce\n per-row eligibility. Resolve links/actions through the shared adapter.\n\n## Paging and freshness\n\nContentList owns the pager in every presentation and passes no `totalRows` to\nDataTable, whose independent clamp would mutate the shared controller without\nknowing which query produced a count.\n\n- Clamp on the local full-array count or an exact total for the active settled\n server query only. Never clamp on an estimate, unavailable total, page length,\n previous-query response, or before the current response arrives. An estimate\n may still drive the displayed pager. Test paging in grid and compact modes.\n- Resolve one page-size ceiling with `resolveContentListMaxPageSize`: the minimum\n of configured limits and schema limit (default 200). Use it for controller\n seed, URL/saved-view sanitizers, translator, and live state. Server seed defaults\n to 50; null page size becomes the seed and oversized values become the ceiling,\n with reported drops. Local mode may remain unpaginated. Omitted URL size must\n restore the server seed. `setPageSize` resets page.\n- Offset only; maximum offset is 1,000,000. Report capping and update the marker\n to `effectivePage`; retain the notice until the operator leaves that page.\n Pager maximum is `floor(MAX_OFFSET / pageSize) + 1`, while clamp uses the true\n total so crafted out-of-range pages receive the explanatory notice.\n- Subscribe after the first request; query changes rebind the exact subscription.\n Offline retains usable stale rows. Online calls live `reconnect()` (refresh\n before resubscription), otherwise `refresh()`. Refresh errors are inline over\n retained rows. Show loading, retry, refreshing, last update, offline, truncation,\n and warnings across presentations. Read completeness flags from retry envelopes\n as well as execute envelopes; a successful retry replaces old flags.\n\n## Query authority and protocol\n\n`executeContentQuery()` applies tenancy, failing closed to global rows. Host\napplication scope comes from authenticated context, never request body; caller\nfilters only narrow it. Omitted scope means no extra application restriction;\n`scope: []` means no permitted rows (`id IS NULL`). AND scope into every query\nbranch alongside tenancy. Empty object conditions are configuration errors.\n\nKeep field maps, projectable fields, operator/search vocabulary, and mirrored\nlimits asserted against `buildContentQuerySchema()` and core constants or their\nobservable acceptance boundaries.\n\n- No cursor paging, body queries, metadata-path filters, or ETag/version slot.\n Read body through GET by ID; use queryFingerprint/freshness.asOf for freshness.\n- Search emits an `any` of `like` over title/description/author, escaping caller\n `%`/`_`. Drop and report unsupported `notContains`, datetime LIKE operators,\n invalid datetime inputs, unknown projection fields, and derived site queries.\n- Bound normalized request bytes, including default sort. Always emit sort\n (fall back to `CONTENT_LIST_QUERY_DEFAULT_SORT`) so client accounting is not\n smaller than the normalizer's. Limits: 100 list values, 50 filter nodes\n (containers count; search costs four), 128 DNF branches, 50 projection fields\n with 1–256-character IDs, 128-character request ID, 4096 UTF-16 units per scalar,\n 100,000 serialized request bytes. Count escapes and surrogate pairs without\n splitting code points. DNF costs include null unions and De Morgan negation.\n- Preserve comparands exactly or omit/report the filter. Oversized/unusable `in`\n entries may be removed as a reported subset (`out-of-range`/`unsupported-value`).\n Never partially apply `notIn`: drop/report `filter-widened`. Shed conjuncts for\n node/branch/byte budgets with that same report. Shortened LIKE/search patterns\n report widening; retain leading code points for contains/startsWith and trailing\n ones for endsWith. Never shorten scalar eq/ne/ordered comparands into a value\n the caller did not name. Every change is either exact, a reported superset,\n a reported subset, or a reported omitted predicate.\n- Datetimes require a real calendar day, four-digit year, T separator and an\n offset when time is present. Date-only means midnight UTC; minutes without\n seconds and lowercase t/z are accepted. Trim and uppercase before parsing,\n validate that same string, and calendar-round-trip to reject rolled dates.\n\n### Comparison semantics and dialect limits\n\nFold token filter values (type/status/state); preserve free-text case. Local\ntext comparison is case-insensitive; server free-text matching follows its SQL\noperator/dialect. PostgreSQL/DuckDB LIKE is case-sensitive; SQLite LIKE is ASCII\ncase-insensitive. Do not promise uniform free-text matching.\n\nSQLite's LIKE lacks the default backslash escape used by PostgreSQL/DuckDB;\nescaped wildcards can fail closed there. Fixing portability needs SQL-boundary\nESCAPE support. Null placement is likewise dialect-dependent: local sorts absent\nlast ascending/first descending, matching PostgreSQL/DuckDB; SQLite defaults\noppositely. The query sort grammar cannot express NULLS FIRST/LAST.\n\n- Read absence from original ContentData, not flattened display text. Type's\n `content` and title's `Untitled content` fallbacks are presentation only; missing\n values compare/search as null, genuinely blank strings remain present.\n- eq/in/LIKE exclude absent values unless null is explicitly listed. ne of a\n non-null value and notIn without null include absence. notIn containing null\n excludes absence. eq/ne null lower to IS NULL/IS NOT NULL. Direct ordered\n comparisons exclude absence; their negations include it. Every supported\n predicate and its negation must partition rows without gaps or overlap,\n including nested all/any and double negation. Negated LIKE is refused.\n- Preserve literal null through sanitization, saved views, translation and local\n evaluation; only undefined denotes unusable input. Test null, false, zero and\n empty strings. Blank scalar clears a filter; an empty entry within a list is\n real text, but a wholly empty list parameter is refused/reported.\n\n## Result budgets\n\nCall `assertContentQuerySchema(schema)` at configuration time. Every executor\nmode, including count, rejects maxResultBytes below\n`CONTENT_QUERY_MIN_RESULT_BYTES`; this is a host error, not caller validation.\n\n- Never drop rows to fit bytes: offset advances by requested limit, so omitted\n rows would become unreachable. Seat every row's irreducible floor first, then\n distribute surplus max-min fairly by appetite (cost minus floor).\n `allocateRowBytes` guarantees a page whenever floors fit; otherwise fail loudly.\n Preserve `floor <= cost` and refund the final unused array separator at exact\n byte boundaries.\n- Within rows use one sorted water-filling walk. Strings may shorten; datetime\n and JSON values are all-or-nothing (null only if smaller). Numbers, booleans,\n null, and identity never shrink. Prefer shortening free text before losing a\n format-constrained value; new constrained types are all-or-nothing by default.\n Report shortening with truncated/warnings.\n- Bound JSON documents before result normalization: strings 65,536 characters,\n containers 1,000 items, depth 16; finite numbers, no cycles, plain values only.\n Drop forbidden __proto__/constructor/prototype keys and build with null\n prototypes. Report truncation rather than allowing one stored document to\n invalidate an entire page.\n- Facets share the result byte budget; drop excess facet values and flag both\n facet and result. Per-value caps alone do not bound the envelope.\n\n## URL state and saved views\n\nRead urlState.params once; later onChange(params, state) preserves foreign\nparameters and lets the host own routing. `applyContentListViewState` is the\npublic application boundary: sanitize every patch, including raw saved snapshots,\nthen merge over current state without resetting restored page. Sanitize the patch,\nnot the merged result, because selection is intentionally absent from sanitizer\noutput. Keep raw saved-view payloads so stale-field drops remain reportable.\n\n- Escape list separators and double literal backslashes. List null uses the\n collision-free `\\0` token; a literal backslash-zero string is doubled. Scalar\n null serializes through isNull/isNotNull. Preserve foreign parameters by base\n name, even when they have a known operator suffix; unknown suffixed columns\n may still be reported as refused without being deleted.\n- The type lock applies to live state, including agent reset/filter commands.\n Fold it into restored patches to preserve paging. Clear it only on an actual\n lock-removal transition, not every unlocked render.\n- Toolbar selects must state the live predicate honestly. Unlisted equals values\n render as extra options and produce a notice. Lists, non-equals operators, and\n multiple predicates render a disabled summary and notice. Use operator-aware\n `readContentListSelectFilter`, not value-only `readContentListFilter`.\n Choosing a real option replaces all filters on that column. Summary sentinel\n uses U+001F; NUL changes during HTML parsing and breaks hydration.\n- Review is an ordinary status; deleted belongs exclusively to opt-in trash\n mode. Type options are display vocabulary, not the freeform model domain.\n Restore/translation refusals appear in one dismissible notice; stale state\n should still open with the refused parts omitted.\n\n## Shared mutations and lifecycle\n\nHuman transports and agent/bulk callers terminate at the same\n`createContentListActionAdapter()` instance. Preview/apply is principal-bound;\nrendered rows are never mutation authority.\n\n- Supported workflows: trash, draft, review submission, publish, archive, restore,\n automated review, formatting, categorization, optimization. Applications inject\n formatting/optimization handlers; handlers mutate supplied objects but must\n not save them because the adapter owns guarded writes.\n- Explicit/current-page/all-matching selections share a default 200-row cap.\n Match server and browser maxSelectionSize. All-matching is canonical query,\n fingerprint and exact count, never browser-page expansion. Above-cap requests\n fail closed, including forged/agent requests; UI asks the operator to narrow.\n- Read-only preview returns resolved scope/count/labels/eligibility/consequences.\n Apply uses opaque token and idempotency key, re-resolves query under live\n principal/tenant, rechecks tool/operation permissions and eligibility, and\n compares aggregate updated_at revision. Query/count/membership/row drift fails\n before mutation. Each save also guards updated_at atomically at UPDATE.\n Required projection: id, title, status, updated_at, even under host overrides.\n- Publication workflows require every snapshot read permission, explicitly\n including contentassets:read and assets:read. Keep assertions aligned with\n `ContentVersion.createSnapshot()`; embedded adapters rely on them without RLS.\n- Declare workflowStorage capability. PostgreSQL, SQLite, ordinary DuckDB and\n non-immediate exported-file modes are supported. JSON default/immediate and\n DuckDB immediate writes are rejected at setup because exports cannot roll back.\n- Partial results separate accepted/skipped/failed rows; clear only accepted IDs.\n Failures retain selection. Refresh the exact query and expose progress,\n exceptions, representative labels, resourceType/resourceId and auditReference.\n\nLifecycle binding enables trash controls; trash mode locks deleted and hides\nordinary status/edit/delete controls. Without it legacy onDelete remains.\n`createContentListLifecycleRoute()` mounts POST /api/v1/contents/lifecycle;\nits host authenticates every native Request and supplies current action context.\nOnly move-to-trash, restore, permanent-delete are accepted; malformed/auth/internal\nfailures use bounded envelopes without private error text.\n\n| Action | Eligible state | Contract |\n|---|---|---|\n| move-to-trash | not deleted | soft deletion |\n| restore | deleted | draft/review/published; recheck permissions and publication readiness |\n| permanent-delete | deleted | type exact server count; irreversible |\n\nPermanent DELETE binds updated_at in PostgreSQL's predicate with transactional\ncascade; embedded adapters compare under the shared write queue before cascade.\nRaces return row_revision_drifted. Empty-trash requires exact server count plus\ncanonical query. Query/selection changes invalidate previews; expiry, stale\nrevision, row/query/count drift or token failures require new preview. Preview,\ninitial apply and replay each get distinct attempt request IDs; apply/replay keep\nconfirmation/idempotency authority, and auditReference identifies original execution.\n\n## Jobs and agent surfaces\n\n- Automated review/formatting/optimization return job IDs. Queue callbacks repeat\n guarded apply with idempotency. Hosts must provide resolveDeferredPrincipal to\n re-resolve the complete live persona/TenantAgent binding; absent, mismatched or\n incomplete bindings fail closed. Authenticated jobStatusPath or client.status\n keeps identical intents locked while running, reconciles terminal outcomes,\n and allows failed/cancelled retry. Disable selection during status requests and\n recheck captured intent before reconciling responses.\n- `createContentListJobController().submit({ actionId, submissionKey, target },\n start)` coalesces duplicate active keys; rejected submissions stay failed until\n retry. update(job) cannot regress terminal state. Pending row work disables\n selection/edit/delete. Only succeeded transitions refresh: row targets require\n an affected visible row; query targets require the active request key. Failed\n jobs show error/retry and never masquerade as success.\n- Register dataSurface once at ContentList boundary across presentations and\n loading/empty/error states. Publish rendered columns plus required id (hidden\n description stays search-only), explicit fieldName mapping, available operators,\n query fingerprint/total, normalized selection, presentation and freshness.\n Derived site becomes read-only in server mode. Expose only mounted executable\n workflow/lifecycle actions. Context changes advance the same revision stream;\n stale revisions and disconnected registry commands are refused. set-view\n acknowledgements describe accepted state before renderer changes.\n- Silent reads use server `createContentListDataSurfaceDefinition({ collection,\n scope })` in createDataSurfaceTools. Resolve collection/scope from live principal;\n executeContentQuery owns rows/counts/facets/offset continuation. Exclude tenant,\n hidden and sensitive fields from discovery/projection. Durable agent mutations\n use the action adapter, never browser registry authority.\n\n## Validation\n\nUse package `pnpm test` (which generates routes through SvelteKit sync), never\nbare Vitest. Narrow with `-- <test-file>` to the affected content-list, query,\naction, lifecycle or component tests; include both grid and compact paging\nscenarios for reachability changes. Run package `pnpm typecheck` for Svelte\nchanges and root knowledge checks for this module documentation.\n\n### Hydrated result values\n\nThe query boundary normalizes values against their declared descriptors before\nbyte budgeting. Objects hydrated from text columns become JSON strings and use\nthe existing scalar shortening/warning path; JSON columns retain their document\nlimits. Date-only and timezone-less datetime strings mean UTC, including facet\nbuckets. Bigint values must remain safely representable as JavaScript numbers.\n"
13783
+ "content": "<!-- Module doc for packages/content/AGENTS.md. -->\n\n# ContentList contracts\n\nRead for changes to `src/svelte/content-list-*.ts`, `ContentList.svelte`, or the\nserver content-query/action adapters. Browser exports come from `/svelte`;\nprincipal-bound query/action factories come from `/server`.\n\n## Ownership and integration\n\n- `content-list-controller.ts` is the shared adapter over `DataTableController`.\n Search, filters, sort, paging, selection, columns, and action eligibility have\n one implementation across grid, detailed, and compact presentations. Controller\n modes are manual. Local arrays use `toContentListRows`, `selectContentListRows`,\n then `paginateContentListRows`; server rows must never be transformed again.\n- `query`, `urlState`, `savedViews`, `lifecycle`, `jobs`, and `dataSurface` are\n optional bindings. Without query, rows come from `contents`; with it, contents\n is ignored. `type` locks/hides the type filter; `defaultViewMode` seeds once.\n Existing callbacks (`onEdit`, `onDelete`, `onAdd`, `getViewHref`) remain usable.\n- `query.bind()` runs once during component initialization so a structural\n `remoteQuery(collection, transport)` binding registers teardown in that scope.\n Do not import smrt-svelte/web or its browser data runtime into the content\n Svelte barrel: public content pages depend on that code-split boundary.\n- The default query transport targets `POST /api/v1/contents/query`.\n `CONTENT_LIST_QUERY_FIELDS` maps column IDs to server fields;\n `ROW_FIELD_TO_CONTENT_KEY` maps response fields to ContentData. For example,\n column `updated`, client `updatedAt`, and server `updated_at` differ.\n `publish` maps to `publish_date`. Derived `site` comes from url/source and has\n no server field; server filtering/sorting on it is dropped and reported.\n- Missing/duplicate durable IDs still render with positional keys but are\n `identified: false`. Disable and explain their selection controls. Page select\n all and normalization exclude synthetic IDs; server selection must survive\n page changes, so current-page membership is not a durability test.\n- Compact uses content-owned `select` and `actions` columns, included in\n `CONTENT_LIST_TABLE_COLUMN_IDS`. DataTable's generic selection cannot enforce\n per-row eligibility. Resolve links/actions through the shared adapter.\n\n## Paging and freshness\n\nContentList owns the pager in every presentation and passes no `totalRows` to\nDataTable, whose independent clamp would mutate the shared controller without\nknowing which query produced a count.\n\n- Clamp on the local full-array count or an exact total for the active settled\n server query only. Never clamp on an estimate, unavailable total, page length,\n previous-query response, or before the current response arrives. An estimate\n may still drive the displayed pager. Test paging in grid and compact modes.\n- Resolve one page-size ceiling with `resolveContentListMaxPageSize`: the minimum\n of configured limits and schema limit (default 200). Use it for controller\n seed, URL/saved-view sanitizers, translator, and live state. Server seed defaults\n to 50; null page size becomes the seed and oversized values become the ceiling,\n with reported drops. Local mode may remain unpaginated. Omitted URL size must\n restore the server seed. `setPageSize` resets page.\n- Offset only; maximum offset is 1,000,000. Report capping and update the marker\n to `effectivePage`; retain the notice until the operator leaves that page.\n Pager maximum is `floor(MAX_OFFSET / pageSize) + 1`, while clamp uses the true\n total so crafted out-of-range pages receive the explanatory notice.\n- Subscribe after the first request; query changes rebind the exact subscription.\n Offline retains usable stale rows. Online calls live `reconnect()` (refresh\n before resubscription), otherwise `refresh()`. Refresh errors are inline over\n retained rows. Show loading, retry, refreshing, last update, offline, truncation,\n and warnings across presentations. Read completeness flags from retry envelopes\n as well as execute envelopes; a successful retry replaces old flags.\n\n## Query authority and protocol\n\n`executeContentQuery()` applies tenancy, failing closed to global rows. Host\napplication scope comes from authenticated context, never request body; caller\nfilters only narrow it. Omitted scope means no extra application restriction;\n`scope: []` means no permitted rows (`id IS NULL`). AND scope into every query\nbranch alongside tenancy. Empty object conditions are configuration errors.\n\nKeep field maps, projectable fields, operator/search vocabulary, and mirrored\nlimits asserted against `buildContentQuerySchema()` and core constants or their\nobservable acceptance boundaries.\n\n- No cursor paging, body queries, metadata-path filters, or ETag/version slot.\n Read body through GET by ID; use queryFingerprint/freshness.asOf for freshness.\n- Search emits an `any` of `like` over title/description/author, escaping caller\n `%`/`_`. Drop and report unsupported `notContains`, datetime LIKE operators,\n invalid datetime inputs, unknown projection fields, and derived site queries.\n- Bound normalized request bytes, including default sort. Always emit sort\n (fall back to `CONTENT_LIST_QUERY_DEFAULT_SORT`) so client accounting is not\n smaller than the normalizer's. Limits: 100 list values, 50 filter nodes\n (containers count; search costs four), 128 DNF branches, 50 projection fields\n with 1–256-character IDs, 128-character request ID, 4096 UTF-16 units per scalar,\n 100,000 serialized request bytes. Count escapes and surrogate pairs without\n splitting code points. DNF costs include null unions and De Morgan negation.\n- Preserve comparands exactly or omit/report the filter. Oversized/unusable `in`\n entries may be removed as a reported subset (`out-of-range`/`unsupported-value`).\n Never partially apply `notIn`: drop/report `filter-widened`. Shed conjuncts for\n node/branch/byte budgets with that same report. Shortened LIKE/search patterns\n report widening; retain leading code points for contains/startsWith and trailing\n ones for endsWith. Never shorten scalar eq/ne/ordered comparands into a value\n the caller did not name. Every change is either exact, a reported superset,\n a reported subset, or a reported omitted predicate.\n- Datetimes require a real calendar day, four-digit year, T separator and an\n offset when time is present. Date-only means midnight UTC; minutes without\n seconds and lowercase t/z are accepted. Trim and uppercase before parsing,\n validate that same string, and calendar-round-trip to reject rolled dates.\n\n### Comparison semantics and dialect limits\n\nFold token filter values (type/status/state); preserve free-text case. Local\ntext comparison is case-insensitive; server free-text matching follows its SQL\noperator/dialect. PostgreSQL/DuckDB LIKE is case-sensitive; SQLite LIKE is ASCII\ncase-insensitive. Do not promise uniform free-text matching.\n\nSQLite's LIKE lacks the default backslash escape used by PostgreSQL/DuckDB;\nescaped wildcards can fail closed there. Fixing portability needs SQL-boundary\nESCAPE support. Null placement is likewise dialect-dependent: local sorts absent\nlast ascending/first descending, matching PostgreSQL/DuckDB; SQLite defaults\noppositely. The query sort grammar cannot express NULLS FIRST/LAST.\n\n- Read absence from original ContentData, not flattened display text. Type's\n `content` and title's `Untitled content` fallbacks are presentation only; missing\n values compare/search as null, genuinely blank strings remain present.\n- eq/in/LIKE exclude absent values unless null is explicitly listed. ne of a\n non-null value and notIn without null include absence. notIn containing null\n excludes absence. eq/ne null lower to IS NULL/IS NOT NULL. Direct ordered\n comparisons exclude absence; their negations include it. Every supported\n predicate and its negation must partition rows without gaps or overlap,\n including nested all/any and double negation. Negated LIKE is refused.\n- Preserve literal null through sanitization, saved views, translation and local\n evaluation; only undefined denotes unusable input. Test null, false, zero and\n empty strings. Blank scalar clears a filter; an empty entry within a list is\n real text, but a wholly empty list parameter is refused/reported.\n\n## Result budgets\n\nCall `assertContentQuerySchema(schema)` at configuration time. Every executor\nmode, including count, rejects maxResultBytes below\n`CONTENT_QUERY_MIN_RESULT_BYTES`; this is a host error, not caller validation.\n\n- Never drop rows to fit bytes: offset advances by requested limit, so omitted\n rows would become unreachable. Seat every row's irreducible floor first, then\n distribute surplus max-min fairly by appetite (cost minus floor).\n `allocateRowBytes` guarantees a page whenever floors fit; otherwise fail loudly.\n Preserve `floor <= cost` and refund the final unused array separator at exact\n byte boundaries.\n- Within rows use one sorted water-filling walk. Strings may shorten; datetime\n and JSON values are all-or-nothing (null only if smaller). Numbers, booleans,\n null, and identity never shrink. Prefer shortening free text before losing a\n format-constrained value; new constrained types are all-or-nothing by default.\n Report shortening with truncated/warnings.\n- Bound JSON documents before result normalization: strings 65,536 characters,\n containers 1,000 items, depth 16; finite numbers, no cycles, plain values only.\n Drop forbidden __proto__/constructor/prototype keys and build with null\n prototypes. Report truncation rather than allowing one stored document to\n invalidate an entire page.\n- Facets share the result byte budget; drop excess facet values and flag both\n facet and result. Per-value caps alone do not bound the envelope.\n\n## URL state and saved views\n\nRead urlState.params once; later onChange(params, state) preserves foreign\nparameters and lets the host own routing. `applyContentListViewState` is the\npublic application boundary: sanitize every patch, including raw saved snapshots,\nthen merge over current state without resetting restored page. Sanitize the patch,\nnot the merged result, because selection is intentionally absent from sanitizer\noutput. Keep raw saved-view payloads so stale-field drops remain reportable.\n\n- Escape list separators and double literal backslashes. List null uses the\n collision-free `\\0` token; a literal backslash-zero string is doubled. Scalar\n null serializes through isNull/isNotNull. Preserve foreign parameters by base\n name, even when they have a known operator suffix; unknown suffixed columns\n may still be reported as refused without being deleted.\n- The type lock applies to live state, including agent reset/filter commands.\n Fold it into restored patches to preserve paging. Clear it only on an actual\n lock-removal transition, not every unlocked render.\n- Toolbar selects must state the live predicate honestly. Unlisted equals values\n render as extra options and produce a notice. Lists, non-equals operators, and\n multiple predicates render a disabled summary and notice. Use operator-aware\n `readContentListSelectFilter`, not value-only `readContentListFilter`.\n Choosing a real option replaces all filters on that column. Summary sentinel\n uses U+001F; NUL changes during HTML parsing and breaks hydration.\n- Review is an ordinary status; deleted belongs exclusively to opt-in trash\n mode. Type options are display vocabulary, not the freeform model domain.\n Restore/translation refusals appear in one dismissible notice; stale state\n should still open with the refused parts omitted.\n\n## Shared mutations and lifecycle\n\nHuman transports and agent/bulk callers terminate at the same\n`createContentListActionAdapter()` instance. Preview/apply is principal-bound;\nrendered rows are never mutation authority.\n\n- Supported workflows: trash, draft, review submission, publish, archive, restore,\n automated review, formatting, categorization, optimization. Applications inject\n formatting/optimization handlers; handlers mutate supplied objects but must\n not save them because the adapter owns guarded writes.\n- Explicit/current-page/all-matching selections share a default 200-row cap.\n Match server and browser maxSelectionSize. All-matching is canonical query,\n fingerprint and exact count, never browser-page expansion. Above-cap requests\n fail closed, including forged/agent requests; UI asks the operator to narrow.\n- Read-only preview returns resolved scope/count/labels/eligibility/consequences.\n Apply uses opaque token and idempotency key, re-resolves query under live\n principal/tenant, rechecks tool/operation permissions and eligibility, and\n compares aggregate updated_at revision. Query/count/membership/row drift fails\n before mutation. Each save also guards updated_at atomically at UPDATE.\n Required projection: id, title, status, updated_at, even under host overrides.\n- Publication workflows require every snapshot read permission, explicitly\n including contentassets:read and assets:read. Keep assertions aligned with\n `ContentVersion.createSnapshot()`; embedded adapters rely on them without RLS.\n- Declare workflowStorage capability. PostgreSQL, SQLite, ordinary DuckDB and\n non-immediate exported-file modes are supported. JSON default/immediate and\n DuckDB immediate writes are rejected at setup because exports cannot roll back.\n- Partial results separate accepted/skipped/failed rows; clear only accepted IDs.\n Failures retain selection. Refresh the exact query and expose progress,\n exceptions, representative labels, resourceType/resourceId and auditReference.\n\nLifecycle binding enables trash controls; trash mode locks deleted and hides\nordinary status/edit/delete controls. Without it legacy onDelete remains.\n`createContentListLifecycleRoute()` mounts POST /api/v1/contents/lifecycle;\nits host authenticates every native Request and supplies current action context.\nOnly move-to-trash, restore, permanent-delete are accepted; malformed/auth/internal\nfailures use bounded envelopes without private error text.\n\n| Action | Eligible state | Contract |\n|---|---|---|\n| move-to-trash | not deleted | soft deletion |\n| restore | deleted | draft/review/published; recheck permissions and publication readiness |\n| permanent-delete | deleted | type exact server count; irreversible |\n\nPermanent DELETE binds updated_at in PostgreSQL's predicate with transactional\ncascade; embedded adapters compare under the shared write queue before cascade.\nRaces return row_revision_drifted. Empty-trash requires exact server count plus\ncanonical query. Query/selection changes invalidate previews; expiry, stale\nrevision, row/query/count drift or token failures require new preview. Preview,\ninitial apply and replay each get distinct attempt request IDs; apply/replay keep\nconfirmation/idempotency authority, and auditReference identifies original execution.\n\n## Jobs and agent surfaces\n\n- Automated review/formatting/optimization return job IDs. Queue callbacks repeat\n guarded apply with idempotency. Hosts must provide resolveDeferredPrincipal to\n re-resolve the complete live persona/TenantAgent binding; absent, mismatched or\n incomplete bindings fail closed. Authenticated jobStatusPath or client.status\n keeps identical intents locked while running, reconciles terminal outcomes,\n and allows failed/cancelled retry. Disable selection during status requests and\n recheck captured intent before reconciling responses.\n- `createContentListJobController().submit({ actionId, submissionKey, target },\n start)` coalesces duplicate active keys; rejected submissions stay failed until\n retry. update(job) cannot regress terminal state. Pending row work disables\n selection/edit/delete. Only succeeded transitions refresh: row targets require\n an affected visible row; query targets require the active request key. Failed\n jobs show error/retry and never masquerade as success.\n- Register dataSurface once at ContentList boundary across presentations and\n loading/empty/error states. Publish rendered columns plus required id (hidden\n description stays search-only), explicit fieldName mapping, available operators,\n query fingerprint/total, normalized selection, presentation and freshness.\n Derived site becomes read-only in server mode. Expose only mounted executable\n workflow/lifecycle actions. Context changes advance the same revision stream;\n stale revisions and disconnected registry commands are refused. set-view\n acknowledgements describe accepted state before renderer changes.\n- Silent reads use server `createContentListDataSurfaceDefinition({ collection,\n scope })` in createDataSurfaceTools. Resolve collection/scope from live principal;\n executeContentQuery owns rows/counts/facets/offset continuation. Exclude tenant,\n hidden and sensitive fields from discovery/projection. Durable agent mutations\n use the action adapter, never browser registry authority.\n An optional `rowCountHint` passes through for `data.discover`; it is shown\n to every reader, so use a coarse static label, never a per-tenant count.\n\n## Validation\n\nUse package `pnpm test` (which generates routes through SvelteKit sync), never\nbare Vitest. Narrow with `-- <test-file>` to the affected content-list, query,\naction, lifecycle or component tests; include both grid and compact paging\nscenarios for reachability changes. Run package `pnpm typecheck` for Svelte\nchanges and root knowledge checks for this module documentation.\n\n### Hydrated result values\n\nThe query boundary normalizes values against their declared descriptors before\nbyte budgeting. Objects hydrated from text columns become JSON strings and use\nthe existing scalar shortening/warning path; JSON columns retain their document\nlimits. Date-only and timezone-less datetime strings mean UTC, including facet\nbuckets. Bigint values must remain safely representable as JavaScript numbers.\n"
13784
13784
  }
13785
13785
  ],
13786
13786
  "browser": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-content",
3
- "version": "0.57.32",
3
+ "version": "0.57.33",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Content processing module for SMRT framework - handles documents, web content, and media",
6
6
  "type": "module",
@@ -56,18 +56,18 @@
56
56
  "@happyvertical/logger": "^0.108.0",
57
57
  "@happyvertical/ocr": "^0.62.1",
58
58
  "@happyvertical/pdf": "^0.65.9",
59
- "@happyvertical/smrt-assets": "0.57.32",
60
- "@happyvertical/smrt-agents": "0.57.32",
61
- "@happyvertical/smrt-chat": "0.57.32",
62
- "@happyvertical/smrt-core": "0.57.32",
63
- "@happyvertical/smrt-facts": "0.57.32",
64
- "@happyvertical/smrt-images": "0.57.32",
65
- "@happyvertical/smrt-messages": "0.57.32",
66
- "@happyvertical/smrt-prompts": "0.57.32",
67
- "@happyvertical/smrt-profiles": "0.57.32",
68
- "@happyvertical/smrt-tenancy": "0.57.32",
69
- "@happyvertical/smrt-types": "0.57.32",
70
- "@happyvertical/smrt-ui": "0.57.32",
59
+ "@happyvertical/smrt-assets": "0.57.33",
60
+ "@happyvertical/smrt-agents": "0.57.33",
61
+ "@happyvertical/smrt-chat": "0.57.33",
62
+ "@happyvertical/smrt-core": "0.57.33",
63
+ "@happyvertical/smrt-facts": "0.57.33",
64
+ "@happyvertical/smrt-images": "0.57.33",
65
+ "@happyvertical/smrt-messages": "0.57.33",
66
+ "@happyvertical/smrt-prompts": "0.57.33",
67
+ "@happyvertical/smrt-profiles": "0.57.33",
68
+ "@happyvertical/smrt-tenancy": "0.57.33",
69
+ "@happyvertical/smrt-types": "0.57.33",
70
+ "@happyvertical/smrt-ui": "0.57.33",
71
71
  "@happyvertical/spider": "^1.1.13",
72
72
  "@happyvertical/sql": "^0.108.0",
73
73
  "@happyvertical/utils": "^0.108.0",
@@ -86,9 +86,9 @@
86
86
  },
87
87
  "devDependencies": {
88
88
  "@faker-js/faker": "^10.6.0",
89
- "@happyvertical/smrt-playground": "0.57.32",
90
- "@happyvertical/smrt-users": "0.57.32",
91
- "@happyvertical/smrt-vitest": "0.57.32",
89
+ "@happyvertical/smrt-playground": "0.57.33",
90
+ "@happyvertical/smrt-users": "0.57.33",
91
+ "@happyvertical/smrt-vitest": "0.57.33",
92
92
  "@sveltejs/kit": "2.69.1",
93
93
  "@sveltejs/package": "^2.5.8",
94
94
  "@sveltejs/vite-plugin-svelte": "^7.3.0",