import type { CtxPath } from './context/authz-context'; /** Placeholder $ctx nei template scope. Sostituito a build-time snapshot dal builder skillID. */ export type CtxPlaceholder = { $ctx: CtxPath; }; export type DeepPartial = { [K in keyof T]?: T[K] extends object ? DeepPartial : T[K]; }; /** * Template Prisma WhereInput con segnaposti `{ $ctx: 'path' }` al posto dei valori. * Esempio: * { juridicalId: { $ctx: 'tenantId' } } * → al snapshot build diventa { juridicalId: '' } */ export type WhereTemplate = DeepPartial; /** * 5 kind di tenancy (Step 1 DEC-6/7/8/9/10 con scope ristretto): * - single: standard `juridicalId` required (es. JuridicalIndividual) * - multiRef: N FK juridical OR-uniti (es. Planning, JuridicalAccreditation) * - transitive: ereditata via single relation (es. Certificate via IndividualDocument) * - inheritFrom: ereditata via relation chain multi-hop (junction, PlanningResult deep) * - global: nessuna tenancy (catalog, top-level masters) */ export type TenancyDecl = { kind: 'single'; field: string; } | { kind: 'multiRef'; fields: string[]; relation: 'AND' | 'OR'; } | { kind: 'transitive'; via: string; through: string; field: string; } | { kind: 'inheritFrom'; relation: string; field?: string; } | { kind: 'global'; }; /** Ownership: which context field identifies an "owner" of the row (free-form, app-defined). */ export type OwnershipDecl = { field: string; /** The `$ctx` claim that identifies the actor (e.g. 'userId') — consumer-defined. */ actor: string; /** Optional role label for the ownership edge (free-form). */ role?: string; }; /** Step 1 DEC-15/DEC-S3.21: lifecycle state machine inline nel manifest. */ export type LifecycleDecl = { field: string; initial: S; states: readonly S[]; transitions: Record; }; /** Step 1 DEC-21 + Step 5: autoquery allowlist whitelist tassativa. */ export type AutoqueryDecl = { filterable: Record; sortable: readonly string[]; includable: readonly string[]; pagination: { default: number; max: number; cursorRequiredOver?: number; /** Step 5 DEC-S5.10: opt-in per autorizzare paginazione unbounded. Default false. */ allowUnbounded?: boolean; }; /** Step 5 DEC-S5.31: default sort se client non passa orderBy. Fallback {id:'desc'}. */ defaultSort?: { field: string; order: 'asc' | 'desc'; }; }; export type AuditDecl = { create?: 'always' | 'never'; update?: 'always' | 'never' | 'fields'; delete?: 'always'; custom?: string[]; /** Step 7 DEC-S7.7: campi che richiedono PII redaction nei log. */ piiFields?: string[]; /** Step 7 EDGE-S7.8: cattura diff before/after nei mutate. Default false. */ captureDiff?: boolean; }; export interface ResourceManifest { /** CASL Subject literal — es. 'JuridicalIndividual' */ subject: S; /** Prisma model name camelCase — es. 'juridicalIndividual' */ prismaModel: string; /** * Owning microservice name — free-form metadata (tooling/codegen only; NOT read by the * scoping engine). Kept agnostic: the SDK never enumerates service names, so onboarding * a new service requires zero SDK changes. */ service: string; tenancy: TenancyDecl; ownership?: OwnershipDecl[]; /** Cross-tenant link (JuridicalAccreditation) — provider/customer field names */ external?: { providerField: string; customerField: string; }; /** * Cross-service "soft-FK" includes per la federazione genquery. Ogni voce mappa una * chiave include (es. 'customer') → il SUBJECT proprietario (+ colonna FK opzionale, * default `Id`). Co-locati qui col model che possiede la soft-FK così il gateway * li raccoglie nell'indice di federazione invece di hardcodare una alias-map centrale. * Metadato di sola codegen: NON letto dallo scoping engine. * links: { customer: { subject: 'Juridical' }, submitter: { subject: 'JuridicalIndividual' } } */ links?: Record; /** * Step 1 DEC-25a / DEC-S5.16 (codegen): polymorphic dispatch (e.g. ApprovalRequest). * Values are OTHER subjects (the target resources), not this resource's own subject, * so they are plain subject strings — validated against the registry by `authz:check`. */ polymorphicMap?: Record; /** * Step 1 DEC-12/27: nested children — standalone findMany BLOCKED. `parent`/`rootSubject` * reference OTHER subjects (the ancestor resources), hence subject strings (not `S`). */ nested?: { parent: string; via: string; rootSubject?: string; }; /** Step 1 DEC-23: default attivo {field:'deletedAt', restoreAction:'restore'} */ softDelete?: false | { field?: 'deletedAt'; restoreAction?: string; }; lifecycle?: LifecycleDecl; /** Lista actions consentite. Step 1 DEC-17: lifecycle verbs auto-aggiunti da framework. */ actions: readonly string[]; /** Scope templates per i 6 scope CASL. Sostituiti a build-time snapshot. */ scopes: Partial>>; autoquery: AutoqueryDecl; audit?: AuditDecl; documentation?: { description: string; owner: string; }; } /** * Identity function generica. Type inference vincola scope templates a essere * strutturalmente compatibili con `Prisma.WhereInput`. * * Esempio: * export const CourseResource = defineResource({ * subject: 'Course', * prismaModel: 'course', * service: 'skillID', * tenancy: { kind: 'single', field: 'juridicalId' }, * // ... * }); */ export declare function defineResource(manifest: ResourceManifest): ResourceManifest; //# sourceMappingURL=define-resource.d.ts.map