import type { TSecretManagementScope } from '../data/secret.js'; /** * Backend-neutral storage vocabulary shared by App Store manifests, control * planes, and fulfillment adapters. Physical providers and runtime attachment * details intentionally do not belong in these contracts. */ export type TStorageResourceKind = 'filesystem' | 'objectStorage'; /** * Compatibility bridge for the existing generic platform capability. New * filesystem requests intentionally have no generic IPlatformBinding mapping. */ export const storageKindPlatformCapabilityIds = { objectStorage: 'objectstorage', } as const; export type TFilesystemStorageAccessMode = | 'ReadWriteOnce' | 'ReadOnlyMany' | 'ReadWriteMany'; export type TObjectStorageAccessMode = 'readOnly' | 'readWrite'; export type TStoragePerformanceTier = 'standard' | 'highIops' | 'capacity'; export type TStorageDurability = 'ephemeral' | 'persistent'; export type TStorageTopology = 'singleNode' | 'multiNode'; export type TStorageSnapshotMode = 'none' | 'portable' | 'native'; export type TStorageReclaimPolicy = 'retain' | 'delete'; /** * A positive base-2 quantity written as an integer followed by KiB, MiB, GiB, * or TiB, for example `20GiB`. Parsers must reject every other representation. */ export type TStorageCapacityQuantity = string; export interface IStorageCapacityRequest { request: TStorageCapacityQuantity; /** * A hard upper bound. A request with a limit can only be fulfilled by a * class whose granted capabilities include hardQuota. */ limit?: TStorageCapacityQuantity; } /** * App-facing requirements describe policy, never a concrete provider class. * Values in a `required` block are hard constraints; values in `preferred` * influence selection but may not weaken required constraints. */ export interface IStorageClassRequirement { performanceTier?: TStoragePerformanceTier; durability?: TStorageDurability; topology?: TStorageTopology; hardQuota?: true; snapshots?: Exclude; backup?: true; encryptedInTransit?: true; } export interface IStorageGrantedCapabilities { performanceTier: TStoragePerformanceTier; durability: TStorageDurability; topology: TStorageTopology; hardQuota: boolean; snapshots: TStorageSnapshotMode; backup: boolean; encryptedInTransit: boolean; } export interface IStorageClassCapabilitiesBase { /** Opaque operator-defined policy class ID, not a physical backend name. */ classId: string; /** Changes whenever matching behavior or guarantees change. */ revision: string; kind: TStorageResourceKind; performanceTiers: TStoragePerformanceTier[]; durabilities: TStorageDurability[]; topologies: TStorageTopology[]; hardQuota: boolean; snapshotModes: TStorageSnapshotMode[]; backup: boolean; encryptedInTransit: boolean; } export interface IFilesystemStorageClassCapabilities extends IStorageClassCapabilitiesBase { kind: 'filesystem'; accessModes: TFilesystemStorageAccessMode[]; } export interface IObjectStorageClassCapabilities extends IStorageClassCapabilitiesBase { kind: 'objectStorage'; accessModes: TObjectStorageAccessMode[]; versioning: boolean; retention: boolean; } export type TStorageClassCapabilities = | IFilesystemStorageClassCapabilities | IObjectStorageClassCapabilities; /** * Fulfillment adapters advertise only portable guarantees. Provider names, * addresses, mount options, principals, and credential values are private. */ export interface IStorageCapabilityAdvertisement { schemaVersion: 2; featureIds: string[]; classes: TStorageClassCapabilities[]; } export interface IObjectStorageLauncherEnvironmentDelivery { type: 'launcher-environment'; /** * Explicit target keys prevent two named bindings from silently overwriting * each other. Every required field must have a distinct environment key. */ keys: { endpoint: string; bucket: string; region: string; accessKeyId: string; secretAccessKey: string; sessionToken?: string; }; } export interface IObjectStorageFileDelivery { type: 'file'; /** Canonical absolute path below /run/secrets/. */ targetPath: string; /** * JSON object with endpoint, bucket, region, accessKeyId, * secretAccessKey, and optional sessionToken fields. */ format: 'servezone-object-storage-v1'; uid: number; gid: number; mode: 0o400 | 0o440; } export type TObjectStorageDelivery = | IObjectStorageLauncherEnvironmentDelivery | IObjectStorageFileDelivery; export type TResolvedStorageBindingStatus = | 'requested' | 'provisioning' | 'ready' | 'degraded' | 'failed' | 'releasing' | 'retained' | 'released'; export type TStorageBindingFailureCode = | 'unsupportedCapability' | 'policyUnavailable' | 'provisionFailed' | 'attachmentFailed' | 'quotaExceeded' | 'credentialsUnavailable' | 'backendUnavailable' | 'migrationRequired'; export interface IStorageBindingFailure { code: TStorageBindingFailureCode; message: string; retryable: boolean; observedAt: number; } export interface IResolvedStoragePolicyRef { /** Opaque operator-defined policy class ID selected for this request. */ classId: string; revision: string; } export interface IResolvedStorageCapacity { requested?: TStorageCapacityQuantity; granted?: TStorageCapacityQuantity; limit?: TStorageCapacityQuantity; } export interface IResolvedStorageBindingBase { schemaVersion: 2; /** Stable binding/allocation identity. */ id: string; serviceId: string; /** Stable App Store storageRequests[].id. */ requestId: string; /** * Canonical digest of the normalized request. Adapters use it to distinguish * an idempotent reconciliation from a migration. */ requestDigest: string; kind: TStorageResourceKind; generation: number; observedGeneration: number; status: TResolvedStorageBindingStatus; policy: IResolvedStoragePolicyRef; capabilities: IStorageGrantedCapabilities; /** Opaque resource identity; never a host path, export, or provider URL. */ resourceRef: string; capacity?: IResolvedStorageCapacity; failure?: IStorageBindingFailure; createdAt?: number; updatedAt?: number; } export interface IResolvedFilesystemStorageBinding extends IResolvedStorageBindingBase { kind: 'filesystem'; mountPath: string; accessMode: TFilesystemStorageAccessMode; } export interface IResolvedObjectStorageConnection { endpoint: string; bucket: string; region: string; } export interface IResolvedObjectStorageBinding extends IResolvedStorageBindingBase { kind: 'objectStorage'; accessMode: TObjectStorageAccessMode; connection: IResolvedObjectStorageConnection; /** Value-free service-owned Secret reconciliation scope. */ credentialManagementScope: Extract; delivery: TObjectStorageDelivery; versioning: boolean; retentionDays?: number; } export type TResolvedStorageBinding = | IResolvedFilesystemStorageBinding | IResolvedObjectStorageBinding;