import type { TRegistryProtocol } from './interfaces.core.js'; /** * Actor information from request context */ export interface IStorageActor { userId?: string; tokenId?: string; ip?: string; userAgent?: string; orgId?: string; sessionId?: string; } /** * Metadata about the storage operation */ export interface IStorageMetadata { /** Content type of the object */ contentType?: string; /** Size in bytes */ size?: number; /** Content digest (e.g., sha256:abc123) */ digest?: string; /** Package/artifact name */ packageName?: string; /** Version */ version?: string; } /** * Context passed to storage hooks */ export interface IStorageHookContext { /** Type of operation */ operation: 'put' | 'delete' | 'get'; /** Storage key/path */ key: string; /** Protocol that triggered this operation */ protocol: TRegistryProtocol; /** Actor who performed the operation (if known) */ actor?: IStorageActor; /** Metadata about the object */ metadata?: IStorageMetadata; /** Timestamp of the operation */ timestamp: Date; } /** * Result from a beforePut hook that can modify the operation */ export interface IBeforePutResult { /** Whether to allow the operation */ allowed: boolean; /** Optional reason for rejection */ reason?: string; /** Optional modified metadata */ metadata?: IStorageMetadata; } /** * Result from a beforeDelete hook */ export interface IBeforeDeleteResult { /** Whether to allow the operation */ allowed: boolean; /** Optional reason for rejection */ reason?: string; } /** * Storage event hooks for quota tracking, audit logging, cache invalidation, etc. * * @example * ```typescript * const quotaHooks: IStorageHooks = { * async beforePut(context) { * const quota = await getQuota(context.actor?.orgId); * const currentUsage = await getUsage(context.actor?.orgId); * if (currentUsage + (context.metadata?.size || 0) > quota) { * return { allowed: false, reason: 'Quota exceeded' }; * } * return { allowed: true }; * }, * * async afterPut(context) { * await updateUsage(context.actor?.orgId, context.metadata?.size || 0); * await auditLog('storage.put', context); * }, * * async afterDelete(context) { * await invalidateCache(context.key); * } * }; * ``` */ export interface IStorageHooks { /** * Called before storing an object. * Return { allowed: false } to reject the operation. * Use for quota checks, virus scanning, validation, etc. */ beforePut?(context: IStorageHookContext): Promise; /** * Called after successfully storing an object. * Use for quota tracking, audit logging, notifications, etc. */ afterPut?(context: IStorageHookContext): Promise; /** * Called before deleting an object. * Return { allowed: false } to reject the operation. * Use for preventing deletion of protected resources. */ beforeDelete?(context: IStorageHookContext): Promise; /** * Called after successfully deleting an object. * Use for quota updates, audit logging, cache invalidation, etc. */ afterDelete?(context: IStorageHookContext): Promise; /** * Called after reading an object. * Use for access logging, analytics, etc. * Note: This is called even for cache hits. */ afterGet?(context: IStorageHookContext): Promise; }