feat: type-safe CRUD sensitive field definitions (AEG-V16-021)
Constrain sensitive fields to row keys and preserve generic resource-definition contracts.
This commit is contained in:
@@ -2,6 +2,7 @@ import type { ZodType } from 'zod'
|
||||
import type { UiGridColumn } from '../ui/adapter/contracts'
|
||||
export type CrudConcurrencyMode = 'NONE' | 'ETAG_IF_MATCH'
|
||||
export type CrudIdempotencyMode = 'NONE' | 'IDEMPOTENCY_KEY'
|
||||
export type CrudRowField<TRow> = Extract<keyof TRow, string>
|
||||
export interface CrudResourceDefinition<TQuery, TRow, TForm> {
|
||||
resourceId: string
|
||||
querySchemaVersion: string
|
||||
@@ -10,12 +11,12 @@ export interface CrudResourceDefinition<TQuery, TRow, TForm> {
|
||||
rowSchema: ZodType<TRow>
|
||||
formSchema: ZodType<TForm>
|
||||
columns: readonly UiGridColumn[]
|
||||
sensitiveFields: readonly string[]
|
||||
sensitiveFields: readonly CrudRowField<TRow>[]
|
||||
permissionPolicy: string
|
||||
concurrencyMode: CrudConcurrencyMode
|
||||
idempotencyMode: CrudIdempotencyMode
|
||||
}
|
||||
export function assertCrudResourceDefinition(definition: CrudResourceDefinition<unknown, unknown, unknown>): void {
|
||||
export function assertCrudResourceDefinition<TQuery, TRow, TForm>(definition: CrudResourceDefinition<TQuery, TRow, TForm>): void {
|
||||
if (!definition.resourceId.trim()) throw new Error('resourceId is required')
|
||||
if (!definition.querySchemaVersion.trim() || !definition.responseSchemaVersion.trim()) throw new Error('schema versions are required')
|
||||
if (!definition.permissionPolicy.trim()) throw new Error('permissionPolicy is required')
|
||||
|
||||
@@ -2,9 +2,11 @@ import { z } from 'zod'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { assertCrudResourceDefinition, type CrudResourceDefinition } from '../resourceDefinition'
|
||||
|
||||
const definition: CrudResourceDefinition<unknown, unknown, unknown> = {
|
||||
interface ClientRow { email: string }
|
||||
|
||||
const definition: CrudResourceDefinition<unknown, ClientRow, unknown> = {
|
||||
resourceId: 'client-advisory', querySchemaVersion: '1', responseSchemaVersion: '1',
|
||||
querySchema: z.unknown(), rowSchema: z.unknown(), formSchema: z.unknown(),
|
||||
querySchema: z.unknown(), rowSchema: z.object({ email: z.string() }), formSchema: z.unknown(),
|
||||
columns: [{ field: 'email', header: 'Email', sensitive: true }], sensitiveFields: ['email'],
|
||||
permissionPolicy: 'ClientAdvisory.Read', concurrencyMode: 'ETAG_IF_MATCH', idempotencyMode: 'IDEMPOTENCY_KEY'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user