public/Get-BucketObjectStats.ps1

function Get-BucketObjectStats {
    <#
    .SYNOPSIS
    Returns detailed per-object statistics for objects in a bucket.
    .DESCRIPTION
    Enumerates objects and reads lightweight metadata (format, size, type, timestamps,
    compression status) without full deserialization. Peeks at file content to determine
    object type (Object, Array, or Value) from the first bytes.
    .PARAMETER Bucket
    Bucket name to scan. If omitted, scans all buckets under -Path. Supports wildcards.
    .PARAMETER Key
    Exact object key to look up. When specified, returns stats for a single object only.
    .PARAMETER Path
    Root directory for bucket storage. Default: $HOME/.buckets.
    .PARAMETER Match
    Filter keys by pattern (wildcard). Case-insensitive.
    .OUTPUTS
    PSCustomObject with Bucket, Key, Format, Type, Size, LastWriteTime, and IsCompressed
    properties. Path is included as a hidden property.
    .EXAMPLE
    Get-BucketObjectStats -Bucket users
    .EXAMPLE
    Get-BucketObjectStats -Bucket users -Match "*admin*"
    .EXAMPLE
    Get-BucketObjectStats -Bucket users -Key "alice"
    #>

    [CmdletBinding()]
    param(
        [Parameter(Position = 0)][string]$Bucket,
        [Parameter(Position = 1)][string]$Key,
        [string]$Path,
        [string]$Match
    )

    if ([string]::IsNullOrWhiteSpace($Path)) { $Path = Get-DefaultPath }
    $Path = Resolve-SafePath -Path $Path

    $bucketPaths = @()
    if (-not [string]::IsNullOrWhiteSpace($Bucket)) {
        if ($Bucket -match '[\*\?]') {
            $cachedBuckets = Get-Bucket -Path $Path -Recurse
            $matched = $cachedBuckets | Where-Object { $_.Name -like $Bucket }
            $bucketPaths += $matched | ForEach-Object { $_.Path }
        }
        else {
            $bucketPaths += Get-BucketPath -Name $Bucket -Path $Path
        }
    }
    else {
        if ([System.IO.Directory]::Exists($Path)) {
            $bucketPaths += [System.IO.DirectoryInfo]::new($Path).GetDirectories() | ForEach-Object { $_.FullName }
        }
    }

    $results = [System.Collections.ArrayList]::new()

    foreach ($bucketPath in $bucketPaths) {
        if (-not [System.IO.Directory]::Exists($bucketPath)) { continue }
        $bucketName = $bucketPath.Substring($Path.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar).Replace([System.IO.Path]::DirectorySeparatorChar, '/')
        $di = [System.IO.DirectoryInfo]::new($bucketPath)

        if (-not [string]::IsNullOrWhiteSpace($Key)) {
            $jsonFile = [System.IO.Path]::Combine($bucketPath, "$Key.json")
            $datFile = [System.IO.Path]::Combine($bucketPath, "$Key.dat")
            $found = $false
            foreach ($filePath in @($datFile, $jsonFile)) {
                if ([System.IO.File]::Exists($filePath)) {
                    $f = [System.IO.FileInfo]::new($filePath)
                    $info = Resolve-ObjectType -FileInfo $f
                    $entry = [PSCustomObject]@{
                        Bucket        = $bucketName
                        Key           = $Key
                        Format        = if ($f.Extension -eq ".json") { "JSON" } else { "Binary" }
                        Type          = $info.Type
                        Size          = $f.Length
                        LastWriteTime = $f.LastWriteTime
                        IsCompressed  = $info.IsCompressed
                    }
                    Add-HiddenProperty -Target $entry -Name 'Path' -Value $f.FullName
                    $null = $results.Add($entry)
                    $found = $true
                    break
                }
            }
            if (-not $found) {
                Write-Warning "Key '$Key' not found in bucket '$bucketName'"
            }
            continue
        }

        $files = @($di.GetFiles("*.json")) + @($di.GetFiles("*.dat"))
        foreach ($f in $files) {
            $fKey = [System.IO.Path]::GetFileNameWithoutExtension($f.Name)
            if (-not [string]::IsNullOrWhiteSpace($Match) -and $fKey -notlike $Match) { continue }
            $info = Resolve-ObjectType -FileInfo $f
            $entry = [PSCustomObject]@{
                Bucket        = $bucketName
                Key           = $fKey
                Format        = if ($f.Extension -eq ".json") { "JSON" } else { "Binary" }
                Type          = $info.Type
                Size          = $f.Length
                LastWriteTime = $f.LastWriteTime
                IsCompressed  = $info.IsCompressed
            }
            Add-HiddenProperty -Target $entry -Name 'Path' -Value $f.FullName
            $null = $results.Add($entry)
        }
    }

    $results
}