|
| 1 | +/** |
| 2 | + * Artifact storage contract + requirements (backend-agnostic). |
| 3 | + * |
| 4 | + * Concrete backends (S3, Supabase) implement `ArtifactStorage`. |
| 5 | + * Prefer `@bitcode/artifacts` for the default S3→Supabase implementation. |
| 6 | + */ |
| 7 | + |
| 8 | +import type { ArtifactBytes, ArtifactInfo } from './types'; |
| 9 | + |
| 10 | +/** Declared requirements every Artifact storage backend must satisfy. */ |
| 11 | +export interface ArtifactStorageRequirements { |
| 12 | + /** |
| 13 | + * At least one durable backend must be configured at runtime |
| 14 | + * (e.g. S3 bucket + region, or Supabase URL + key). |
| 15 | + */ |
| 16 | + requiresConfiguredBackend: true; |
| 17 | + /** |
| 18 | + * Keys must be unique; timestamp + UUID + name is the admitted generation law |
| 19 | + * when the caller does not supply an explicit key. |
| 20 | + */ |
| 21 | + keyGeneration: 'timestamp-uuid-name' | 'explicit-key'; |
| 22 | + /** Content-type is always required (default application/octet-stream). */ |
| 23 | + contentTypeRequired: true; |
| 24 | + /** Both binary and text payloads are admitted. */ |
| 25 | + acceptsBinaryAndText: true; |
| 26 | + /** |
| 27 | + * Raw product source (AssetPack protected blobs) must never be stored under |
| 28 | + * artifact APIs without an explicit product policy — storage is content-opaque. |
| 29 | + */ |
| 30 | + contentOpaque: true; |
| 31 | +} |
| 32 | + |
| 33 | +export const DEFAULT_ARTIFACT_STORAGE_REQUIREMENTS: ArtifactStorageRequirements = { |
| 34 | + requiresConfiguredBackend: true, |
| 35 | + keyGeneration: 'timestamp-uuid-name', |
| 36 | + contentTypeRequired: true, |
| 37 | + acceptsBinaryAndText: true, |
| 38 | + contentOpaque: true, |
| 39 | +}; |
| 40 | + |
| 41 | +export const DEFAULT_ARTIFACT_CONTENT_TYPE = 'application/octet-stream'; |
| 42 | + |
| 43 | +/** |
| 44 | + * Backend-agnostic storage port. |
| 45 | + * Implementations: `@bitcode/artifacts` (S3 primary, Supabase fallback). |
| 46 | + */ |
| 47 | +export interface ArtifactStorage { |
| 48 | + /** |
| 49 | + * Store bytes under an auto-generated key derived from `name`. |
| 50 | + * Returns public URL + size metadata. |
| 51 | + */ |
| 52 | + save( |
| 53 | + buffer: ArtifactBytes, |
| 54 | + name: string, |
| 55 | + contentType?: string, |
| 56 | + ): Promise<ArtifactInfo>; |
| 57 | + |
| 58 | + /** |
| 59 | + * Store bytes at an explicit key (stable paths, logs, upserts). |
| 60 | + */ |
| 61 | + putAtKey( |
| 62 | + key: string, |
| 63 | + buffer: ArtifactBytes, |
| 64 | + contentType?: string, |
| 65 | + ): Promise<ArtifactInfo>; |
| 66 | +} |
| 67 | + |
| 68 | +export type SaveArtifact = ArtifactStorage['save']; |
| 69 | +export type PutArtifactAtKey = ArtifactStorage['putAtKey']; |
0 commit comments