Declaraciones públicas de zig/server.zig (conduit-zig (SDK consumido)).
apps/docs/generated/zig/conduit.jsonPágina generada desde
conduit@conduit-0.1.0-f7J_7zg5DwCsHBHItwdOz9ZVq8cvH7ceFsk7-m3-T61t (zig/root.zig). No se edita a mano:bun run docs:genla regenera ybun run docs:checkfalla si difiere.
The receiving side of conduit wire v1 (spec §4, §7), transport-agnostic.
An HTTP binding (HTTP/1.1 in http.zig, HTTP/3 in styx's IngestSink)
parses the request head and calls begin; the server authenticates,
routes and admits the request before a single body byte is read:
.reply: done, the response JSON is already in out;.json: read at most max_request_json bytes of body, then finishJson;.chunk: a pinned ChunkWriter; stream the body into write, then
finish (or cancel if the connection drops).Invariants (styx dec-0117):
Authorizer ⇒ it does not compile; no token ⇒ 401
before routing; a session answers only its creator (others get 404);zkit.safety.Budget; one subject never
holds the whole staging), and session memory through a
BudgetAllocator (I4);abortOwner retires every session of a revoked
credential (quotas back, .part unlinked) at once;<uploadId>.part created exclusive, 0600, relative
to the staging root's fd and never through a symlink (I7);zkit.safety.TypedSlab) plus a pin count — an abort while a chunk is
streaming frees the session only when the writer lets go (I9);storage.reserve: ENOSPC → 507,
everything admission counted rolled back); chunk bodies go straight to disk,
hashed on the fly: chunks ≥ storage.Options.direct_min bypass the
page cache (O_DIRECT + io_uring on Linux, F_NOCACHE on macOS,
with runtime fallbacks down to buffered pwrite), the rest with pwrite.
wire v1: the file SHA-256 advances over the in-order prefix through a
zkit.ReorderBuffer whose bound is the admission window (backpressure,
429 window_full), re-reading that prefix from disk. wire v2
(spec/wire-v2.md, negotiated per session by "protocol":2): one
BLAKE3 pass per byte — each chunk is hashed as a subtree at its offset,
group by group, and checked against Conduit-Chunk-Cv; the file root
is the combination of the chunk CVs at complete. No second hash, no
re-read, chunks in any order (the window bounds requests in flight).server.Rootconst · línea 59
pub const Root = zkit.safety.fs.RootStaging directory handle (fd-relative, zkit.safety.fs). Re-exported so a
consumer opens the root with the same type the server takes, whatever
other zkit version it links.
server.Optype · línea 63
pub const Op = enumSin ///.
server.Granttype · línea 65
pub const Grant = structSin ///.
server.Authorizertype · línea 94
pub const Authorizer = structDecides whether token may perform op (on upload_id, when the route
has one). null = deny. Implementations must be thread-safe.
server.Authorizer.authorizefn · línea 106
pub fn authorize(a: Authorizer, token: []const u8, op: Op, upload_id: ?[]const u8) ?GrantSin ///.
server.Authorizer.stillValidfn · línea 110
pub fn stillValid(a: Authorizer, grant: Grant) boolSin ///.
server.StaticTokenstype · línea 118
pub const StaticTokens = structStatic bearer tokens (reference server, CLI serve, tests). Tokens are
kept only as SHA-256 and compared in constant time.
server.StaticTokens.Entrytype · línea 119
pub const Entry = structSin ///.
server.StaticTokens.entryfn · línea 122
pub fn entry(token: []const u8, subject_label: []const u8) EntrySin ///.
server.StaticTokens.authorizerfn · línea 126
pub fn authorizer(self: *const StaticTokens) AuthorizerSin ///.
server.Completedtype · línea 145
pub const Completed = structSin ///.
server.FileDigesttype · línea 162
pub const FileDigest = unionSin ///.
server.FileDigest.bytesfn · línea 166
pub fn bytes(d: FileDigest) [32]u8Sin ///.
server.FileDigest.hexfn · línea 172
pub fn hex(d: FileDigest) [64]u8Sin ///.
server.Finalizertype · línea 180
pub const Finalizer = structMoves a finished upload to its final place and returns its key (the
finalPath of the response, ≤ max_key_len). Called without locks held,
once per session.
server.Finalizer.max_key_lenconst · línea 184
pub const max_key_len = 256Sin ///.
server.rename_to_digestconst · línea 193
pub const rename_to_digest: Finalizer = .{ .finalizeFn = renameToDigest }Default: rename <uploadId>.part → <digest hex> inside the staging root
(content-addressed: the SHA-256 of a v1 upload, the BLAKE3 root of a v2
one; the same content twice under the same protocol lands on the same name).
Durable: the data is synced before the rename and the directory after, so
a crash leaves either the .part or the complete final file, never a
final name over partial data.
server.Limitstype · línea 209
pub const Limits = structSin ///.
server.Limits.max_windowconst · línea 280
pub const max_window = 1024Sin ///.
server.RequestHeadtype · línea 285
pub const RequestHead = structSin ///.
server.Begintype · línea 299
pub const Begin = unionSin ///.
server.JsonRequesttype · línea 308
pub const JsonRequest = structSin ///.
server.Capacitytype · línea 395
pub const Capacity = structOptional room check of the destination, for limits the server does not
see: what finished uploads already occupy, free space on the volume.
Called under the server lock right before a create reserves its staging,
with the size it declares and the staging the open sessions already hold;
false refuses it with 507 insufficient_storage (retryable) and nothing
reserved. Must be cheap (it runs under the lock) and must not call back
into the server. The staging file itself is allocated after the lock is
released (§8.1), so a free-space reading may not yet reflect creates
admitted just before: staging_in_use counts them.
server.Configtype · línea 400
pub const Config = structSin ///.
server.Servertype · línea 442
pub const Server = structSin ///.
server.Server.InitErrorconst · línea 469
pub const InitError = Allocator.Error || error{InvalidLimits}Sin ///.
server.Server.initfn · línea 477
pub fn init(self: *Server, gpa: Allocator, cfg: Config) InitError!voidself must not move after init (the budget allocator is referenced
by the slab). Use create for a heap instance.
Sessions live in memory, so a staging file left under the root by a
previous run can never be completed: init removes them
(removeOrphanStaging) and counts them in orphans_removed.
server.Server.deinitfn · línea 512
pub fn deinit(self: *Server) zkit.safety.LeakReportDrops every session (unfinished staging files are deleted) and
returns the memory report of the session allocator (isClean() in
tests). Callers must have finished or cancelled all chunk writers.
server.Server.storageStatsfn · línea 537
pub fn storageStats(self: *const Server) storage.StatsWhat the storage layer did so far (reservations, direct writes and each fallback taken).
server.Server.stagingInUsefn · línea 541
pub fn stagingInUse(self: *const Server) u64Sin ///.
server.Server.subjectStagingInUsefn · línea 546
pub fn subjectStagingInUse(self: *Server, subject: [32]u8) u64Staging bytes the open sessions of subject hold.
server.Server.ownerUploadsfn · línea 554
pub fn ownerUploads(self: *Server, owner: [32]u8) u32Uploads created so far under owner (grants with max_uploads).
server.Server.sessionCountfn · línea 560
pub fn sessionCount(self: *Server) u32Sin ///.
server.Server.beginfn · línea 568
pub fn begin(self: *Server, head: RequestHead, out: *Writer) BeginSin ///.
server.Server.finishJsonfn · línea 590
pub fn finishJson(self: *Server, req: JsonRequest, body: []const u8, out: *Writer) u16Sin ///.
server.Server.abortOwnerfn · línea 1232
pub fn abortOwner(self: *Server, owner: [32]u8) u32Retire every session created under a grant whose ownerKey() is
owner — the consumer revoked that credential. Its upload count
(Grant.max_uploads) is forgotten: the consumer must not authorize
that credential again. Unfinished staging
files are deleted and quotas released at once; a chunk still
streaming into one gets 404 when it ends. A session in the middle of
finalizing is left to finish (its file is being renamed) and retired
right after. Returns how many were retired now. Idempotent.
server.Server.sweepfn · línea 1264
pub fn sweep(self: *Server) u32Retire sessions idle for longer than idle_ttl_ns (open or finished).
Returns how many were retired. Call periodically.
server.ChunkWritertype · línea 1384
pub const ChunkWriter = structSin ///.
server.ChunkWriter.WriteErrorconst · línea 1427
pub const WriteError = error{ PayloadTooLarge, Io, NoSpace }NoSpace: the filesystem is full (or over quota) → 507, retryable.
server.ChunkWriter.Encodingtype · línea 1428
pub const Encoding = enumSin ///.
server.ChunkWriter.PumpErrorconst · línea 1430
pub const PumpError = error{ /// The connection failed while reading the body: `cancel` and drop it. ReadFailed, /// The writer answered; its status is returned by `failPump`. Answered, }Sin ///.
server.ChunkWriter.Hashtype · línea 1437
pub const Hash = unionSin ///.
server.ChunkWriter.remainingfn · línea 1443
pub fn remaining(w: *const ChunkWriter) u64Bytes still expected; bindings read at most this much.
server.ChunkWriter.writefn · línea 1447
pub fn write(w: *ChunkWriter, bytes: []const u8) WriteError!voidSin ///.
server.ChunkWriter.pumpZstdfn · línea 1471
pub fn pumpZstd(w: *ChunkWriter, in: *std.Io.Reader, out: *Writer) PumpError!voidDecode a Content-Encoding: zstd body from in (exactly the encoded
body) into the chunk, then the caller calls finish. The encoded
bytes are bounded by the range length here, not only by a
Content-Length (a chunked body has none): one byte more is a 400. On
error.Answered the response is already in out with status
w.answered; on error.ReadFailed the caller cancels.
server.ChunkWriter.finishfn · línea 1502
pub fn finish(w: *ChunkWriter, out: *Writer) u16The body ended. Verifies length and digest, stores the chunk and advances the file hash. Writes the response JSON; returns the status.
server.ChunkWriter.cancelfn · línea 1576
pub fn cancel(w: *ChunkWriter) voidConnection dropped or the binding gave up: the chunk is discarded.
server.ChunkWriter.failfn · línea 1595
pub fn fail(w: *ChunkWriter, err: WriteError, out: *Writer) u16write failed: discard the chunk and answer with the matching error.
server.removeOrphanStagingfn · línea 1698
pub fn removeOrphanStaging(root: *const Root) u32Unlink every staging file (<32 lowercase hex>.part) directly under
root, fd-relative: a symlink with that name is unlinked, never
followed, and nothing else is touched (final files are named by their
SHA-256, without .part). Returns how many were removed. Only safe while
no server is using root (Server.init calls it before any session).
server.isStagingNamefn · línea 1715
pub fn isStagingName(name: []const u8) bool<32 lowercase hex>.part, the only name create gives a staging file.