harn-stdlib 0.10.52

Embedded Harn standard library source catalog
Documentation
/**
 * std/media/asset — content-addressed files produced or consumed by models.
 *
 * An asset has a portable `asset://sha256/...` identity and an optional local
 * materialization path. The digest and MIME declaration are checked against
 * the bytes before a descriptor is returned.
 */
pub type MediaKind = "image" | "audio" | "video" | "document" | "other"

pub type MediaAsset = {
  schema: "harn.media_asset.v1",
  id: string,
  uri: string,
  path: string,
  kind: MediaKind,
  mime_type: string,
  sha256: string,
  size_bytes: int,
  width?: int,
  height?: int,
  duration_ms?: int,
  producing_job?: string,
  metadata?: dict,
}

pub type MediaAssetOptions = {
  mime_type: string,
  root?: string,
  width?: int,
  height?: int,
  duration_ms?: int,
  producing_job?: string,
  metadata?: dict,
}

pub type MediaAssetFailureKind = "invalid" | "mime_mismatch" | "digest_mismatch" | "missing"

pub type MediaAssetFailure = {
  kind: MediaAssetFailureKind,
  message: string,
  path?: string,
  expected?: string,
  actual?: string,
}

fn __media_failure(
  kind: MediaAssetFailureKind,
  message: string,
  details = {},
) -> MediaAssetFailure {
  return {kind: kind, message: message} + (details ?? {})
}

/**
 * Return the broad media family owned by a MIME type.
 *
 * @effects: []
 * @errors: []
 */
pub fn media_kind(mime_type: string) -> MediaKind {
  const mime = lowercase(trim(mime_type))
  if starts_with(mime, "image/") {
    return "image"
  }
  if starts_with(mime, "audio/") {
    return "audio"
  }
  if starts_with(mime, "video/") {
    return "video"
  }
  if mime == "application/pdf" || starts_with(mime, "text/") {
    return "document"
  }
  return "other"
}

fn __media_extension(mime_type: string) -> string? {
  const mime = lowercase(trim(mime_type))
  if mime == "image/png" {
    return "png"
  }
  if mime == "image/jpeg" {
    return "jpg"
  }
  if mime == "image/webp" {
    return "webp"
  }
  if mime == "image/gif" {
    return "gif"
  }
  if mime == "image/svg+xml" {
    return "svg"
  }
  if mime == "audio/wav" {
    return "wav"
  }
  if mime == "audio/mpeg" {
    return "mp3"
  }
  if mime == "video/mp4" {
    return "mp4"
  }
  if mime == "application/pdf" {
    return "pdf"
  }
  return nil
}

fn __media_magic_matches(content: bytes, mime_type: string) -> bool {
  const mime = lowercase(trim(mime_type))
  if mime == "image/png" {
    return bytes_slice(content, 0, 8) == bytes_from_base64("iVBORw0KGgo=")
  }
  if mime == "image/jpeg" {
    return bytes_slice(content, 0, 3) == bytes_from_base64("/9j/")
  }
  if mime == "image/gif" {
    return bytes_slice(content, 0, 4) == bytes_from_string("GIF8")
  }
  if mime == "image/webp" {
    return bytes_slice(content, 0, 4) == bytes_from_string("RIFF")
      && bytes_slice(content, 8, 12)
      == bytes_from_string(
      "WEBP",
    )
  }
  if mime == "image/svg+xml" {
    const prefix = lowercase(trim(bytes_to_string_lossy(bytes_slice(content, 0, 512))))
    return starts_with(prefix, "<svg") || (starts_with(prefix, "<?xml") && contains(prefix, "<svg"))
  }
  if mime == "application/pdf" {
    return bytes_slice(content, 0, 5) == bytes_from_string("%PDF-")
  }
  if mime == "audio/wav" {
    return bytes_slice(content, 0, 4) == bytes_from_string("RIFF")
      && bytes_slice(content, 8, 12)
      == bytes_from_string(
      "WAVE",
    )
  }
  if mime == "video/mp4" {
    return bytes_slice(content, 4, 8) == bytes_from_string("ftyp")
  }
  return false
}

fn __media_positive(value, label: string) -> Result<int?, MediaAssetFailure> {
  if value == nil {
    return Ok(nil)
  }
  const number = to_int(value)
  if number == nil || number <= 0 {
    return Err(__media_failure("invalid", label + " must be a positive integer"))
  }
  return Ok(number)
}

fn __media_validate_options(options: MediaAssetOptions) -> Result<dict, MediaAssetFailure> {
  const mime = lowercase(trim(options.mime_type))
  if __media_extension(mime) == nil {
    return Err(__media_failure("invalid", "unsupported media MIME type: " + mime))
  }
  const width = __media_positive(options.width, "width")
  if !is_ok(width) {
    return Err(unwrap_err(width))
  }
  const height = __media_positive(options.height, "height")
  if !is_ok(height) {
    return Err(unwrap_err(height))
  }
  const duration = __media_positive(options.duration_ms, "duration_ms")
  if !is_ok(duration) {
    return Err(unwrap_err(duration))
  }
  if media_kind(mime) == "image" && options.width == nil != (options.height == nil) {
    return Err(__media_failure("invalid", "image width and height must be declared together"))
  }
  return Ok(
    {mime_type: mime, width: unwrap(width), height: unwrap(height), duration_ms: unwrap(duration)},
  )
}

/**
 * Validate bytes and place them in the shared media store.
 *
 * @effects: [fs.read, fs.write]
 * @errors: []
 */
pub fn media_asset_store_result(
  fs: HarnessFs,
  content: bytes,
  options: MediaAssetOptions,
) -> Result<MediaAsset, MediaAssetFailure> {
  const checked = __media_validate_options(options)
  if !is_ok(checked) {
    return Err(unwrap_err(checked))
  }
  const resolved = unwrap(checked)
  if !__media_magic_matches(content, resolved.mime_type) {
    return Err(
      __media_failure(
        "mime_mismatch",
        "content does not match declared MIME type " + resolved.mime_type,
        {expected: resolved.mime_type},
      ),
    )
  }
  const digest = sha256(content)
  const root = path_normalize(
    options.root ?? path_join(fs.runtime_paths().asset_root, "media", "sha256"),
  )
  const path = path_join(
    root,
    substring(digest, 0, 2),
    digest + "." + to_string(__media_extension(resolved.mime_type)),
  )
  fs.mkdir(dirname(path))
  if fs.exists(path) {
    const found = fs.read_bytes(path)
    if sha256(found) != digest {
      return Err(
        __media_failure(
          "digest_mismatch",
          "content-addressed destination contains different bytes",
          {path: path, expected: digest, actual: sha256(found)},
        ),
      )
    }
  } else {
    fs.write_bytes(path, content)
  }
  let asset: MediaAsset = {
    schema: "harn.media_asset.v1",
    id: "sha256:" + digest,
    uri: "asset://sha256/" + digest,
    path: path,
    kind: media_kind(resolved.mime_type),
    mime_type: resolved.mime_type,
    sha256: digest,
    size_bytes: bytes_len(content),
  }
  if resolved.width != nil {
    asset.width = resolved.width
    asset.height = resolved.height
  }
  if resolved.duration_ms != nil {
    asset.duration_ms = resolved.duration_ms
  }
  if options.producing_job != nil {
    asset.producing_job = options.producing_job
  }
  if options.metadata != nil {
    asset.metadata = options.metadata
  }
  return Ok(asset)
}

/**
 * Throwing convenience form of `media_asset_store_result`.
 *
 * @effects: [fs.read, fs.write]
 * @errors: [invalid, mime_mismatch, digest_mismatch]
 */
pub fn media_asset_store(fs: HarnessFs, content: bytes, options: MediaAssetOptions) -> MediaAsset {
  return unwrap(media_asset_store_result(fs, content, options))
}

/**
 * Re-read and verify a materialized asset descriptor.
 *
 * @effects: [fs.read]
 * @errors: []
 */
pub fn media_asset_verify_result(
  fs: HarnessFs,
  asset: MediaAsset,
) -> Result<MediaAsset, MediaAssetFailure> {
  if !fs.exists(asset.path) {
    return Err(__media_failure("missing", "media asset is missing", {path: asset.path}))
  }
  const content = fs.read_bytes(asset.path)
  const digest = sha256(content)
  if digest != asset.sha256 || asset.id != "sha256:" + digest
    || asset.uri
    != "asset://sha256/"
    + digest {
    return Err(
      __media_failure(
        "digest_mismatch",
        "media asset digest or identity does not match its bytes",
        {path: asset.path, expected: asset.sha256, actual: digest},
      ),
    )
  }
  if bytes_len(content) != asset.size_bytes {
    return Err(
      __media_failure(
        "digest_mismatch",
        "media asset size does not match its descriptor",
        {
          path: asset.path,
          expected: to_string(asset.size_bytes),
          actual: to_string(bytes_len(content)),
        },
      ),
    )
  }
  if !__media_magic_matches(content, asset.mime_type) {
    return Err(
      __media_failure(
        "mime_mismatch",
        "media asset bytes do not match " + asset.mime_type,
        {path: asset.path, expected: asset.mime_type},
      ),
    )
  }
  return Ok(asset)
}