moonbagit

    BagIt 1.0 archive package creation and validation for MoonBit

    bagit
    rfc8493
    preservation
    integrity
    Download zip
    Author
    Version
    0.4.1
    License
    MIT
    Last updated
    5 days ago
    Downloads
    106

    No dependencies

    #MoonBagIt

    CI

    BagIt 1.0 archive-directory creation and validation for MoonBit, based on RFC 8493.

    The input is a directory of opaque files, such as a research dataset or a digital-library export. The output is a standard BagIt directory, not a custom JSON evidence pack, backup database, ZIP file, or network transfer service.

    #Quick Start

    Install the MoonBit toolchain and Node.js 22 or later. Use MoonBit moon 0.1.20261012 or later. This release was tested with moonc v0.10.15 and Node.js 24.14.1.

    npm ci --ignore-scripts moon check --target js moon test --target js moon build --target js node bin/moonbagit.mjs create examples/payload example-bag --both --metadata examples/metadata.json node bin/moonbagit.mjs validate example-bag

    example-bag must not already exist. Creation leaves the source unchanged. Default creation uses SHA-512; --sha256 and --both select other supported manifest sets. Metadata is an ordered JSON array of { "label", "value" } objects, allowing repeated labels and multi-line values. Payload-Oxum is computed by MoonBagIt and cannot be supplied by the caller. Metadata preserves labels, repetitions, ordering and non-linebreaking characters as required by the format; JSON output escapes control characters. Continuation indentation is syntax in BagIt: the writer rejects values with leading spaces/tabs after LF rather than silently losing those characters when read back. Normalize such values explicitly.

    example-bag/ bagit.txt bag-info.txt manifest-sha256.txt manifest-sha512.txt tagmanifest-sha256.txt tagmanifest-sha512.txt data/ readme.txt nested/measurement.csv

    Validation returns JSON with complete, valid, payload counts, verified checksum counts and diagnostics containing code, path, message and severity. Int64 counts use decimal strings to preserve integer precision. Exit codes: 0 valid/success, 1 a negative validation/comparison/acceptance decision, 2 I/O or CLI failure. Invalid UTF-8 is an I/O decoding failure, not silently replaced text.

    Changing payload bytes without changing its length leaves the structure complete but makes it invalid. Adding an unlisted payload file makes the bag incomplete. SHA digests detect corruption; they do not authenticate the sender or protect against an attacker who can rewrite files and manifests together.

    #Library

    The root MoonBit package exports typed models, parse_declaration, parse_manifest, parse_metadata, parse_fetch, render_fetch, encode_path, decode_path, create_tags, create_tag_manifests, payload_oxum, and validate. It also exports parse_profile, validate_profile, plan_upgrade, and lint_portability.

    Add the published library to an independent MoonBit project:

    moon add zbhzs1/moonbagit@0.4.0

    Add "zbhzs1/moonbagit" @bag to the consumer package's import block. Then call @bag.parse_declaration(...), @bag.create_tags(...) or @bag.validate(...). The registry library does not install a global CLI: clone this repository and build the JS target for real-filesystem commands.

    BagView separates the rules engine from its filesystem. It contains file records with relative paths, Int64 sizes and raw-byte digests, directory names, and strictly decoded text tags. Callers must supply accurate records and hashes. The directory list must include every parent directory, including empty directories. Duplicate/unsafe directory names, file/directory collisions and standard tag filenames used as directories are rejected rather than trusted. Every decoded-text entry must refer to an inventory file; a phantom metadata entry cannot satisfy a receiving profile. Text bytes and digests still remain the host's responsibility and cannot be authenticated by these structural checks. validate does not read files or compute hashes itself. The CLI supplies these through a small Node.js adapter using streaming node:crypto hashes; there is no custom cryptographic implementation. The pure core also runs on WASM-GC.

    The 0.4.0 preservation APIs add incremental manifest input with source-line diagnostics, per-file checksum evidence, local snapshots and periodic revalidation, snapshot differences, receiving resource/security policy, offline transfer batching, exact-copy/fetch-completion handoff checks and collection acceptance. These extend the BagIt workflows, not the BagIt format. See preservation and receiving for the public contracts, wire schemas, runnable commands and trust boundaries. Saved JSON snapshots are optional local audit records; interoperable BagIt directories remain the primary output and no custom JSON document is required to read a bag.

    Creation uses two stages: create_tags generates the declaration, metadata and payload manifests; after the caller encodes standard tags using the declaration (the declaration itself is always UTF-8) and hashes those exact bytes, create_tag_manifests generates tag manifests. See the runnable CLI and generated interface for the full signatures.

    Run the in-memory library example without Node filesystem integration:

    moon run examples/core --target wasm-gc

    #Supported Scope

    AreaCurrent behavior
    DeclarationBagIt 1.0; declaration always UTF-8 without BOM; remaining standard tags use its declared encoding
    Payload manifestsSHA-256, SHA-512 and legacy MD5/SHA-1; every manifest covers every payload file exactly once
    Tag manifestsRequired payload-manifest coverage; forbid payload and tag-manifest references; check listed arbitrary tags
    MetadataOrdered/repeated fields, continuations; unique and numeric Payload-Oxum
    Paths/ separators, normative %25, %0D, %0A; reject traversal, absolute, NUL and drive-qualified paths; ordinary POSIX colons/backslashes are not format errors
    ChecksumsVerify every supported manifest, including all tag manifests
    FetchComplete RFC 3986 absolute-URI grammar, coverage/length checks and explicit HTTP(S) retrieval into a new staged output; no automatic URI execution during validation
    Additional tagsOpaque content; verify if listed; unprotected tags produce warnings
    Host safetyReject symlinks and special files; no source overwrite; new output only
    Receiving profilesBagIt Profiles 1.4.0 rules for metadata, algorithms, fetch, files/directories and directory serialization constraints
    Digest upgradeAdd supported manifests to a new output; retain payload, metadata and existing payload manifests; regenerate every tag manifest
    Portability lintAdvisory device-name, trailing-character, case-collision and path-length diagnostics

    #Receiving and Upgrading

    See three reproducible workflows for research handoff, digital-library receiving checks and archive checksum migration.

    The included research-data scenario supplies receiving requirements, rather than generic JSON schema validation. Profile JSON is read from a caller-selected local file; profile identifiers and fetch URLs are never executed or fetched.

    node bin/moonbagit.mjs create examples/payload research-bag --both --metadata examples/research-metadata.json --profile examples/research-profile.json node bin/moonbagit.mjs validate research-bag --profile examples/research-profile.json node bin/moonbagit.mjs lint research-bag node bin/moonbagit.mjs create examples/payload sha256-bag --sha256 node bin/moonbagit.mjs upgrade sha256-bag upgraded-bag --sha512 node bin/moonbagit.mjs validate upgraded-bag

    Profile results expose conforms, the separate base bag report, and profile diagnostics. Creation with --profile validates the staged bag before publishing the output. A mismatch exits with code 1, returns published: false and a staging path for inspection, and leaves the requested output absent. Profile identifiers and required metadata must be explicitly supplied; creation never invents them. Invalid profile configuration and unsafe metadata fail before staging is created. A checksum-valid bag can fail a receiving profile. Unknown profile keys and older profile specifications are rejected, not ignored. Only * is a wildcard and matches zero or more characters, including /. Serialized input is currently not opened: a profile requiring serialization rejects a directory bag. optional permits this directory input; its accepted MIME types describe serialized input, not the directory. See profiles.

    Upgrade checks the original bag, copies it to sibling staging, rechecks the copy, adds missing manifests and regenerates all old/new tag manifests so that they cover every payload manifest. Existing corrupt bags are refused; upgrade is not a repair or authenticity service. The original bag is never modified. Existing valid manifests are preserved byte-for-byte; repeating an upgrade produces the same manifest content when tag coverage was already complete. Previously unprotected arbitrary tags are included in regenerated tag manifests. The pure plan_upgrade API only prepares payload manifests: the host must hash their exact bytes before calling create_tag_manifests.

    #Delivery Endpoint and Safety

    The 0.3.0 delivery target is the BagIt 1.0 format's mandatory creation and validation behavior, including optional elements when present. See the requirement-by-requirement audit, not just a feature list. MD5/SHA-1 are accepted for legacy verification with warnings, not recommended for new content. Standard tags are decoded according to the declaration using maintained codecs (UTF-8, UTF-16, ISO-8859 variants, Shift_JIS, GB18030 and other iconv-lite encodings); unknown host codecs cause an explicit unsupported-codec error, not a false statement that the bag violates the RFC. Digests always use raw file bytes, not decoded text. Creation defaults to UTF-8 and SHA-512; create --encoding NAME chooses another representable tag encoding and --all explicitly includes both legacy algorithms in addition to SHA-256/SHA-512.

    URI grammar validation covers scheme, all hier-part/path forms, userinfo, reg-name, IPv4/IPv6/IPvFuture literals, decimal port, query and percent escapes. The RFC 3986 absolute-URI production used by fetch.txt excludes fragments. Scheme-specific semantics and authorization belong to transport, not syntax. Payload paths use BagIt's separate percent-encoding rules.

    node bin/moonbagit.mjs fetch incoming-bag received-bag --allow-origin https://data.example.org --max-bytes 1073741824 --timeout-ms 30000 --profile examples/research-profile.json

    Only missing payload explicitly listed in a structurally checked fetch plan is retrieved. All requested HTTP(S) origins must be explicitly authorized before any staging or request. Redirects, credentials in URLs, non-200/partial responses and compressed HTTP bodies are refused. Defaults are a 1 GiB total byte budget and 30 seconds per file; both can be configured. The receiver checks actual streamed sizes, every payload/tag digest and the optional profile before publishing a new directory. Failed staging is retained, never published. Existing corrupt payload is not silently replaced. URNs and other syntactically valid schemes remain valid fetch entries but require a separately authorized transport adapter; validation never runs them. Trusting an origin includes its DNS and network endpoint; this is not an SSRF-resistant arbitrary-URL proxy.

    Case-only collisions produce warnings. POSIX-specific names remain usable on POSIX filesystems; host OS restrictions are not additional BagIt format rules. Unicode normalization is not silently applied where it could merge names. Manifest writing rejects root-relative tag paths starting with a space or TAB: the reader cannot distinguish them from the separator without losing characters. Whitespace inside paths (for example data/ notes.txt) is preserved. A manifest writer call must use one digest length consistently, not mix algorithms.

    The CLI supports 100,000 files and 100,000 directories, 16 MiB per standard text tag and 64 MiB total standard text. Payload hashing is streaming. File sizes must fit the Node.js safe-integer range; the core uses Int64. File mutation is checked while reading, but this is not a hostile-filesystem sandbox or lock service. Keep the source, destination and scanned bag quiescent during an operation. Creation uses a sibling staging directory and renames it only after validation; failed staging directories are retained for inspection. It does not promise crash durability or race-free publication against another writer. Existing output entries, including dangling symlinks, are refused.

    #Verification

    For direction-by-direction reproduction, independent validator results and CI downloads of the actual bags and reports, see bidirectional bagit-python verification.

    moon test --target js moon test --target wasm-gc python -m pip install bagit==1.9.0 python scripts/interop.py git -c core.autocrlf=false clone https://github.com/LibraryOfCongress/bagit-conformance-suite.git ../bagit-conformance-suite git -C ../bagit-conformance-suite checkout 9ab48705c06664f9f419ca740c728c9f89a61e7c python scripts/conformance.py ../bagit-conformance-suite python scripts/benchmark.py --files 10000 --bytes 1024 python scripts/consumer.py

    scripts/rfc8493.py --bagit-path .interop/upstream exercises declared encodings, legacy algorithms, no-optional-tag bags and real local HTTP receipt failures. Set up the pinned native producer as described in the bidirectional guide first.

    The independent Library of Congress bagit-python tool validates generated bags, and MoonBagIt validates bags generated by it. The released tool creates BagIt 0.97, so the reverse test upgrades the declaration to 1.0 and asks that independent tool to regenerate tag manifests. No MoonBagIt creation or hashing is used to regenerate those independent manifests. The same suite was also run against the pinned upstream snapshot listed in the support document, which natively creates 1.0 bags and needs no such upgrade.

    Known upstream compatibility issue: bagit-python does not decode %25 in manifest filenames. The percent-filename test records this limitation explicitly; it is not counted as successful cross-tool interoperability. The normative MoonBagIt encoding is retained. Newline-filename and symlink tests are skipped where Windows permissions or filesystem restrictions prevent them; Linux CI also runs the suite. See support details.

    #Competition Status

    The public repository contains the implementation, CI workflow, executable examples and independently reproducible tests. The current delivered scope is BagIt 1.0 format processing and explicitly authorized receiving/upgrade workflows, not a backup, evidence-ledger or network-transfer service. Verification details separate observed checks from future work. Competition acceptance is decided by the organizers, not by test count or a configured workflow. The architecture and review map links each declared capability to its implementation and checks, and explains the difference from generic manifest, evidence-pack and backup tools.

    #License

    MIT. The implementation is written against RFC 8493, not copied from adjacent MoonBit archive/evidence projects. bagit-python is a test-only independent dependency distributed under CC0; its source is not part of this package. The independently maintained conformance fixtures and BagIt Profiles specification are also CC0. See third-party references.

    FormatError

    pub(all) suberror FormatError {
    Invalid(String)
    } derive(Eq,
    Debug
    )

    FormatError::equal

    fn FormatError::equal(FormatError, FormatError) -> Bool

    FormatError::not_equal

    fn FormatError::not_equal(x : FormatError, y : FormatError) -> Bool

    AcceptanceReport

    pub(all) struct AcceptanceReport {
    accepted : Bool
    policy : String
    bag : Report
    diagnostics : Array[Diagnostic]
    } derive(ToJson)

    AcceptanceReport::to_json

    Algorithm

    pub(all) enum Algorithm {
    Md5
    Sha1
    Sha256
    Sha512
    } derive(Eq,
    Debug
    )

    Algorithm::equal

    fn Algorithm::equal(Algorithm, Algorithm) -> Bool

    Algorithm::hex_length

    fn Algorithm::hex_length(self : Algorithm) -> Int

    Algorithm::name

    fn Algorithm::name(self : Algorithm) -> String

    Algorithm::not_equal

    fn Algorithm::not_equal(x : Algorithm, y : Algorithm) -> Bool

    AuditSummary

    pub(all) struct AuditSummary {
    manifest_count : Int
    expected_files : Int
    missing_files : Int
    mismatched_checksums : Int
    unavailable_checksums : Int
    unprotected_tags : Int
    pending_fetches : Int
    verified_algorithms : Array[String]
    } derive(ToJson)

    AuditSummary::to_json

    BagAudit

    pub(all) struct BagAudit {
    report : Report
    summary : AuditSummary
    files : Array[FileAudit]
    located_diagnostics : Array[LocatedDiagnostic]
    } derive(ToJson)

    BagAudit::to_json

    fn BagAudit::to_json(BagAudit) -> Json

    BagSnapshot

    pub(all) struct BagSnapshot {
    label : String
    bag_version : String
    encoding : String
    directories : Array[String]
    files : Array[FileRecord]
    metadata : Array[Metadata]
    }

    A local preservation record, not a signed proof or a BagIt standard tag.

    BagView

    pub(all) struct BagView {
    files : Array[FileRecord]
    directories : Array[String]
    texts : Map[String, String]
    } derive(
    Debug
    ,
    FromJson
    )

    ChecksumEvidence

    pub(all) struct ChecksumEvidence {
    manifest : String
    algorithm : String
    expected : String
    observed : String?
    status : String
    } derive(ToJson)

    ChecksumEvidence::to_json

    CollectionItem

    pub(all) struct CollectionItem {
    identifier : String
    view : BagView
    }

    CollectionReport

    pub(all) struct CollectionReport {
    accepted : Bool
    accepted_bags : Int
    rejected_bags : Int
    payload_files : Int64
    payload_bytes : Int64
    items : Array[CollectionResult]
    } derive(ToJson)

    CollectionReport::to_json

    CollectionResult

    pub(all) struct CollectionResult {
    identifier : String
    acceptance : AcceptanceReport
    } derive(ToJson)

    CollectionResult::to_json

    Declaration

    pub(all) struct Declaration {
    version : String
    encoding : String
    } derive(Eq,
    Debug
    )

    Declaration::equal

    fn Declaration::equal(Declaration, Declaration) -> Bool

    Declaration::not_equal

    fn Declaration::not_equal(x : Declaration, y : Declaration) -> Bool

    DeliveryMode

    pub(all) enum DeliveryMode {
    ExactCopy
    CompleteFetch
    } derive(Eq)

    DeliveryMode::equal

    DeliveryMode::not_equal

    fn DeliveryMode::not_equal(x : DeliveryMode, y : DeliveryMode) -> Bool

    DeliveryReport

    pub(all) struct DeliveryReport {
    accepted : Bool
    mode : String
    source : Report
    received : Report
    preserved_files : Int
    completed_files : Int
    diagnostics : Array[Diagnostic]
    } derive(ToJson)

    DeliveryReport::to_json

    Diagnostic

    pub(all) struct Diagnostic {
    severity : Severity
    code : String
    path : String
    message : String
    } derive(ToJson,
    Debug
    )

    Diagnostic::to_json

    fn Diagnostic::to_json(Diagnostic) -> Json

    DiagnosticGroup

    pub(all) struct DiagnosticGroup {
    code : String
    errors : Int
    warnings : Int
    paths : Array[String]
    } derive(ToJson)

    DiagnosticGroup::to_json

    Entry

    pub(all) struct Entry {
    path : String
    checksum : String
    } derive(Eq,
    Debug
    )

    Entry::equal

    fn Entry::equal(Entry, Entry) -> Bool

    Entry::not_equal

    fn Entry::not_equal(x : Entry, y : Entry) -> Bool

    Entry::to_repr

    FetchEntry

    pub(all) struct FetchEntry {
    url : String
    size : Int64?
    path : String
    } derive(Eq, ToJson,
    Debug
    )

    FetchEntry::equal

    fn FetchEntry::equal(FetchEntry, FetchEntry) -> Bool

    FetchEntry::not_equal

    fn FetchEntry::not_equal(x : FetchEntry, y : FetchEntry) -> Bool

    FetchEntry::to_json

    fn FetchEntry::to_json(FetchEntry) -> Json

    FileAudit

    pub(all) struct FileAudit {
    path : String
    payload : Bool
    present : Bool
    size : Int64?
    checksums : Array[ChecksumEvidence]
    integrity_verified : Bool
    } derive(ToJson)

    FileAudit::to_json

    fn FileAudit::to_json(FileAudit) -> Json

    FileChange

    pub(all) struct FileChange {
    path : String
    kind : String
    payload : Bool
    before_size : Int64?
    after_size : Int64?
    compared_algorithms : Array[String]
    added_algorithms : Array[String]
    removed_algorithms : Array[String]
    } derive(ToJson)

    FileChange::to_json

    fn FileChange::to_json(FileChange) -> Json

    FileRecord

    pub(all) struct FileRecord {
    path : String
    size : Int64
    digests : Map[String, String]
    } derive(ToJson,
    Debug
    ,
    FromJson
    )

    The host supplies hashes of raw file bytes, not hashes of decoded text.

    FileRecord::to_json

    fn FileRecord::to_json(FileRecord) -> Json

    LocatedDiagnostic

    pub(all) struct LocatedDiagnostic {
    path : String
    line : Int
    code : String
    message : String
    } derive(ToJson)

    LocatedDiagnostic::to_json

    Manifest

    pub(all) struct Manifest {
    name : String
    algorithm : Algorithm
    tag : Bool
    entries : Array[Entry]
    } derive(Eq,
    Debug
    )

    Manifest::equal

    fn Manifest::equal(Manifest, Manifest) -> Bool

    Manifest::not_equal

    fn Manifest::not_equal(x : Manifest, y : Manifest) -> Bool

    Manifest::to_repr

    ManifestInspection

    pub(all) struct ManifestInspection {
    name : String
    parsed_entries : Array[Entry]
    diagnostics : Array[LocatedDiagnostic]
    }

    ManifestReader

    pub struct ManifestReader {
    name : String
    alg : Algorithm
    tag : Bool
    max_line_units : Int?
    max_entries : Int?
    entries : Array[Entry]
    seen : Map[String, Bool]
    buffer : StringBuilder
    buffer_units : Int
    line : Int
    after_cr : Bool
    finished : Bool
    failure : String?
    }

    Incremental decoded-text input. Limits are caller policy, not BagIt rules.

    ManifestReader::feed

    fn ManifestReader::feed(self : ManifestReader, chunk : String) -> Unit raise FormatError

    Feed well-formed decoded chunks; a CRLF may straddle two chunks.

    ManifestReader::finish

    Metadata

    pub(all) struct Metadata {
    label : String
    value : String
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Metadata::equal

    fn Metadata::equal(Metadata, Metadata) -> Bool

    Metadata::not_equal

    fn Metadata::not_equal(x : Metadata, y : Metadata) -> Bool

    Metadata::to_json

    fn Metadata::to_json(Metadata) -> Json

    Metadata::to_repr

    MetadataChange

    pub(all) struct MetadataChange {
    label : String
    before_values : Array[String]
    after_values : Array[String]
    } derive(ToJson)

    MetadataChange::to_json

    MetadataRule

    pub(all) struct MetadataRule {
    label : String
    required : Bool
    repeatable : Bool
    values : Array[String]
    } derive(
    Debug
    )

    PathBudget

    pub(all) struct PathBudget {
    pattern : String
    max_files : Int64?
    max_bytes : Int64?
    }

    PreservationReport

    pub(all) struct PreservationReport {
    preserved : Bool
    bag : Report
    inventory : SnapshotVerification
    metadata : Array[MetadataChange]
    declaration_matches : Bool
    } derive(ToJson)

    PreservationReport::to_json

    Profile

    pub(all) struct Profile {
    identifier : String
    version : String
    metadata : Array[MetadataRule]
    manifests_required : Array[String]
    manifests_allowed : Array[String]?
    tag_manifests_required : Array[String]
    tag_manifests_allowed : Array[String]?
    allow_fetch : Bool
    require_fetch : Bool
    data_empty : Bool
    serialization : String
    accepted_serializations : Array[String]
    bag_versions : Array[String]
    tags_required : Array[String]
    tags_allowed : Array[String]
    payload_required : Array[String]
    payload_allowed : Array[String]
    } derive(
    Debug
    )

    Profile::to_repr

    ProfileReport

    pub(all) struct ProfileReport {
    conforms : Bool
    bag : Report
    diagnostics : Array[Diagnostic]
    } derive(ToJson,
    Debug
    )

    ProfileReport::to_json

    ReceivingPolicy

    pub(all) struct ReceivingPolicy {
    name : String
    payload_algorithms : Array[String]
    tag_algorithms : Array[String]
    forbid_legacy : Bool
    require_tag_protection : Bool
    require_portable : Bool
    allow_empty : Bool
    allow_fetch : Bool
    max_payload_files : Int64?
    max_payload_bytes : Int64?
    max_file_bytes : Int64?
    max_tag_bytes : Int64?
    max_path_depth : Int64?
    max_manifest_entries : Int64?
    path_budgets : Array[PathBudget]
    }

    Operational receiving policy, deliberately distinct from RFC validity.

    Report

    pub(all) struct Report {
    complete : Bool
    valid : Bool
    payload_files : Int
    payload_bytes : Int64
    verified_checksums : Int
    diagnostics : Array[Diagnostic]
    } derive(ToJson,
    Debug
    )

    Report::has_code

    fn Report::has_code(self : Report, code : String) -> Bool

    Report::to_json

    fn Report::to_json(Report) -> Json

    Report::to_repr

    Severity

    pub(all) enum Severity {
    Error
    Warning
    } derive(Eq, ToJson,
    Debug
    )

    Severity::equal

    fn Severity::equal(Severity, Severity) -> Bool

    Severity::not_equal

    fn Severity::not_equal(x : Severity, y : Severity) -> Bool

    Severity::to_json

    fn Severity::to_json(Severity) -> Json

    Severity::to_repr

    SnapshotDelta

    pub(all) struct SnapshotDelta {
    byte_identical : Bool
    payload_identical : Bool
    comparable : Bool
    unchanged_files : Int
    files : Array[FileChange]
    directories_added : Array[String]
    directories_removed : Array[String]
    metadata : Array[MetadataChange]
    declaration_changed : Bool
    } derive(ToJson)

    SnapshotDelta::to_json

    SnapshotVerification

    pub(all) struct SnapshotVerification {
    matches : Bool
    checked_files : Int
    verified_checksums : Int
    diagnostics : Array[Diagnostic]
    } derive(ToJson)

    SnapshotVerification::to_json

    TransferBatch

    pub(all) struct TransferBatch {
    number : Int
    reserved_bytes : Int64
    tasks : Array[TransferTask]
    } derive(ToJson)

    TransferBatch::to_json

    TransferOptions

    pub(all) struct TransferOptions {
    allowed_schemes : Array[String]
    max_total_bytes : Int64
    max_file_bytes : Int64
    max_batch_bytes : Int64
    max_batch_files : Int
    unknown_size_reservation : Int64?
    }

    TransferPlan

    pub(all) struct TransferPlan {
    pending_files : Int
    known_bytes : Int64
    reserved_bytes : Int64
    unknown_sizes : Int
    directories_to_create : Array[String]
    batches : Array[TransferBatch]
    } derive(ToJson)

    TransferPlan::to_json

    TransferTask

    pub(all) struct TransferTask {
    path : String
    url : String
    scheme : String
    declared_bytes : Int64?
    reserved_bytes : Int64
    checksums : Map[String, String]
    } derive(ToJson)

    TransferTask::to_json

    UpgradePlan

    pub(all) struct UpgradePlan {
    payload_manifests : Map[String, String]
    tag_algorithms : Array[Algorithm]
    } derive(
    Debug
    )

    algorithm

    fn algorithm(name : String) -> Algorithm raise FormatError

    audit_bag

    fn audit_bag(view : BagView) -> BagAudit

    A deterministic per-file explanation in addition to the authoritative report.

    capture_snapshot

    fn capture_snapshot(view : BagView, label? : String) -> BagSnapshot raise FormatError

    Full validation always runs first; timestamps are not used as hash substitutes.

    check_fetch_url

    fn check_fetch_url(url : String) -> Unit raise FormatError

    RFC 3986 section 4.3 absolute-URI: unlike URI-reference, no fragment is allowed.

    check_path

    fn check_path(path : String) -> Unit raise FormatError

    Format paths are POSIX-relative; portability is a separate advisory check.

    compare_snapshots

    fn compare_snapshots(before : BagSnapshot, after : BagSnapshot) -> SnapshotDelta raise FormatError

    Matching size without a common digest is explicitly not proof of equality.

    create_tag_manifests

    fn create_tag_manifests(tags : Array[FileRecord], algorithms? : Array[Algorithm]) -> Map[String, String] raise FormatError

    create_tags

    fn create_tags(payload : Array[FileRecord], metadata? : Array[Metadata], algorithms? : Array[Algorithm], encoding? : String) -> Map[String, String] raise FormatError

    Returns initial tag text; callers then hash these bytes to build tag manifests.

    decode_path

    fn decode_path(path : String) -> String raise FormatError

    encode_path

    fn encode_path(path : String) -> String

    evaluate_collection

    fn evaluate_collection(collection : Array[CollectionItem], policy : ReceivingPolicy) -> CollectionReport raise FormatError

    Every bag gets an independent report; one bad bag cannot hide another result.

    evaluate_receiving_policy

    fn evaluate_receiving_policy(view : BagView, policy : ReceivingPolicy) -> AcceptanceReport raise FormatError

    Policy failure does not rewrite the RFC-validity result to 'invalid'.

    group_diagnostics

    fn group_diagnostics(items : Array[Diagnostic]) -> Array[DiagnosticGroup]

    inspect_manifest

    fn inspect_manifest(name : String, text : String) -> ManifestInspection

    Recovery is for diagnostics only; its partial entries never imply validity.

    lint_portability

    fn lint_portability(view : BagView) -> Array[Diagnostic]

    Advisory destination portability checks, distinct from BagIt validity.

    manifest_reader

    fn manifest_reader(name : String, max_line_units? : Int, max_entries? : Int) -> ManifestReader raise FormatError

    parse_declaration

    fn parse_declaration(text : String) -> Declaration raise FormatError

    parse_fetch

    fn parse_fetch(text : String) -> Array[FetchEntry] raise FormatError

    parse_manifest

    fn parse_manifest(name : String, text : String) -> Manifest raise FormatError

    parse_metadata

    fn parse_metadata(text : String) -> Array[Metadata] raise FormatError

    parse_profile

    fn parse_profile(json : Json) -> Profile raise FormatError

    Strict BagIt Profiles 1.4 JSON. Older versions and unknown constraints fail closed.

    parse_receiving_policy

    fn parse_receiving_policy(document : Json) -> ReceivingPolicy raise FormatError

    parse_snapshot

    fn parse_snapshot(document : Json) -> BagSnapshot raise FormatError

    parse_transfer_options

    fn parse_transfer_options(document : Json) -> TransferOptions raise FormatError

    payload_oxum

    fn payload_oxum(files : Array[FileRecord]) -> String raise FormatError

    plan_fetch

    fn plan_fetch(view : BagView) -> Array[FetchEntry] raise FormatError

    Preflight an incomplete transfer before an explicitly authorized host retrieves holes. Existing bytes and all present tag manifests must already verify.

    plan_transfer

    fn plan_transfer(view : BagView, options : TransferOptions) -> TransferPlan raise FormatError

    Planning never authorizes origins or executes a URI. The host enforces real bytes.

    plan_upgrade

    fn plan_upgrade(view : BagView, algorithms : Array[Algorithm]) -> UpgradePlan raise FormatError

    Refuses invalid sources. The caller must rehash all tags after writing the plan.

    profile_path_matches

    fn profile_path_matches(pattern : String, path : String) -> Bool

    Only '*' is special. It matches zero or more code units, including '/'.

    receiving_policy

    fn receiving_policy(name : String) -> ReceivingPolicy

    receiving_policy_document

    fn receiving_policy_document(policy : ReceivingPolicy) -> Json raise FormatError

    render_fetch

    fn render_fetch(entries : Array[FetchEntry]) -> String raise FormatError

    Serialize an offline fetch plan; this function never downloads its URIs.

    render_manifest

    fn render_manifest(entries : Array[Entry]) -> String raise FormatError

    render_metadata

    fn render_metadata(fields : Array[Metadata]) -> String raise FormatError

    revalidate_snapshot

    fn revalidate_snapshot(expected : BagSnapshot, current : BagView) -> PreservationReport raise FormatError

    Combine independent preservation evidence with a fresh full BagIt validation.

    snapshot_document

    fn snapshot_document(value : BagSnapshot) -> Json raise FormatError

    The versioned wire schema has exact Int64 decimal strings and ordered arrays.

    transfer_options

    fn transfer_options() -> TransferOptions

    validate

    fn validate(view : BagView) -> Report

    validate_profile

    fn validate_profile(view : BagView, profile : Profile) -> ProfileReport

    Validates a directory bag and receiving rules; no profile URL or payload is fetched.

    verify_delivery

    fn verify_delivery(source : BagView, received : BagView, mode : DeliveryMode) -> DeliveryReport

    Verify a read-only handoff. This does not authenticate the sender or sign a receipt.

    verify_snapshot_inventory

    fn verify_snapshot_inventory(expected : BagSnapshot, observed : Array[FileRecord], directories : Array[String]) -> SnapshotVerification raise FormatError

    Recheck every recorded digest, without treating unchanged timestamps as evidence. This checks preservation against a trusted local snapshot, not RFC conformance.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io