Document every exported property and target variant, enrich function JSDoc, gate releases with deno doc lint, and prepare the immutable registry update as v0.3.1.
- commit
- 890b49b482be9f441510ae26e5a551d7b8b19194
- parent
- ba5c7eb542dc4346825d301be7df450f9140a14c
- author
- Dami <dami.etoile@gmail.com>
| M | .github/ | 1 | + |
| M | cli/ | 2 | +- |
| M | deno.json | 1 | + |
| M | shared/ | 72 | ++++++++++++++++++++++++++---- |
| M | shared/ | 2 | +- |
| M | shared/ | 7 | +++- |
| M | shared/ | 13 | +++++- |
| M | shared/ | bin | |
| M | shared/ | 8 | +++- |
| M | shared/ | 47 | +++++++++++++++++++- |
| M | shared/ | 7 | ++- |
| M | worker/ | 2 | +- |
@@ -9,12 +9,23 @@ export const SITES_PER_VAULT = 0x1000;
99 const ADDR_RE = /^[0-9a-f]{4}$/;1010 const NAME_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;1111 12-/** True if `s` is a well-formed 4-hex address like `"2a3f"`. */12+/**13+ * Tests whether a string is a canonical four-character site address.14+ *15+ * @param s Candidate address such as `"2a3f"`.16+ * @returns `true` only for four lowercase hexadecimal characters.17+ */1318 export function isAddressString(s: string): boolean {1419 return ADDR_RE.test(s);1520 }1621 17-/** "2a3f" → 0x2a3f. Throws on malformed input. */22+/**23+ * Converts a canonical address string to its numeric representation.24+ *25+ * @param s Four-character lowercase hexadecimal address.26+ * @returns Integer in the inclusive range `0x0000`–`0xffff`.27+ * @throws {Error} If `s` is not a canonical address.28+ */1829 export function parseAddress(s: string): number {1930 if (!ADDR_RE.test(s)) {2031 throw new Error(`invalid address: ${JSON.stringify(s)}`);@@ -22,7 +33,13 @@ export function parseAddress(s: string): number {
2233 return parseInt(s, 16);2334 }2435 25-/** 0x2a3f → "2a3f" */36+/**37+ * Formats a numeric site address as four lowercase hexadecimal characters.38+ *39+ * @param addr Integer site address.40+ * @returns Canonical address string such as `"2a3f"`.41+ * @throws {Error} If `addr` is not an integer from `0x0000` through `0xffff`.42+ */2643 export function formatAddress(addr: number): string {2744 if (2845 !Number.isInteger(addr) || addr < 0 || addr >= VAULT_SLOTS * SITES_PER_VAULT@@ -32,23 +49,60 @@ export function formatAddress(addr: number): string {
3249 return addr.toString(16).padStart(4, "0");3350 }3451 35-/** Extract the vault slot (0–15) from an address integer. */52+/**53+ * Extracts the high-nibble vault slot from a numeric site address.54+ *55+ * @param addr Numeric site address.56+ * @returns Vault slot from `0` through `15`.57+ */3658 export function vaultSlotOf(addr: number): number {3759 return addr >> 12;3860 }3961 40-/** Valid vault or alias name: lowercase alnum + hyphen, 1-32 chars, must not look like an address. */62+/**63+ * Tests whether a string is a valid vault or alias name.64+ *65+ * Names contain 1–32 lowercase alphanumeric or hyphen characters, start with66+ * an alphanumeric character, and cannot look like a four-hex address.67+ *68+ * @param name Candidate vault or alias name.69+ * @returns Whether the candidate satisfies the shared naming contract.70+ */4171 export function isValidName(name: string): boolean {4272 return NAME_RE.test(name) && !ADDR_RE.test(name);4373 }4474 4575 /** A parsed target: a raw address, a `vault:alias` pair, or a bare alias in the default vault. */4676 export type ParsedTarget =47- | { kind: "address"; address: number }48- | { kind: "vaultAlias"; vault: string; alias: string }49- | { kind: "alias"; alias: string };77+ | {78+ /** Discriminator for a direct four-hex address. */79+ kind: "address";80+ /** Parsed numeric site address. */81+ address: number;82+ }83+ | {84+ /** Discriminator for an explicitly named vault and alias. */85+ kind: "vaultAlias";86+ /** Valid registered-vault name from the input. */87+ vault: string;88+ /** Valid site alias from the input. */89+ alias: string;90+ }91+ | {92+ /** Discriminator for an alias that requires the caller's default vault. */93+ kind: "alias";94+ /** Valid site alias from the input. */95+ alias: string;96+ };5097 51-/** Parse a CLI/API target: "2a3f" | "work:demo" | "demo". */98+/**99+ * Parses a CLI or API target into a discriminated union.100+ *101+ * @param s Direct address (`"2a3f"`), vault alias (`"work:demo"`), or bare102+ * alias (`"demo"`).103+ * @returns Structured target for address or vault resolution.104+ * @throws {Error} If the target or either name component is malformed.105+ */52106 export function parseTarget(s: string): ParsedTarget {53107 if (ADDR_RE.test(s)) return { kind: "address", address: parseInt(s, 16) };54108 const colon = s.indexOf(":");@@ -1,4 +1,9 @@
1-/** sha256 of bytes as lowercase hex. Web Crypto only — works in Deno and Workers. */1+/**2+ * Computes the SHA-256 digest of bytes using the Web Crypto API.3+ *4+ * @param bytes Bytes to hash.5+ * @returns The 32-byte digest encoded as 64 lowercase hexadecimal characters.6+ */27 export async function sha256hex(bytes: Uint8Array): Promise<string> {38 const digest = await crypto.subtle.digest("SHA-256", bytes as BufferSource);49 return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0"))@@ -1,5 +1,14 @@
1-/** Maximum number of distinct R2 blobs a manifest may reference. */1+/**2+ * Maximum number of distinct R2 blobs a manifest may reference.3+ *4+ * The ceiling leaves headroom beneath the Workers Free internal-subrequest5+ * limit for manifest storage and D1 operations during prepare and commit.6+ */27 export const MAX_UNIQUE_BLOBS = 900;38 4-/** Maximum size of one uploaded blob (50 MiB). */9+/**10+ * Maximum size of one uploaded blob, in bytes (`50 MiB`).11+ *12+ * Both the CLI and Worker enforce this before retaining or buffering a body.13+ */514 export const MAX_BLOB_BYTES = 50 * 1024 * 1024;Binary file.
@@ -35,7 +35,13 @@ const TYPES: Record<string, string> = {
3535 webmanifest: "application/manifest+json",3636 };3737 38-/** Resolve a content-type from a path's file extension, defaulting to `application/octet-stream`. */38+/**39+ * Resolves the media type stored in a manifest from a file path's extension.40+ *41+ * @param path File path whose final extension should be inspected.42+ * @returns A known media type, or `application/octet-stream` for unknown and43+ * extensionless paths.44+ */3945 export function contentTypeFor(path: string): string {4046 const dot = path.lastIndexOf(".");4147 const ext = dot === -1 ? "" : path.slice(dot + 1).toLowerCase();@@ -21,16 +21,26 @@ export interface Manifest {
2121 2222 /** A push destination: a raw address, or a vault (optionally with an alias). */2323 export type Target =24- | { address: number }25- | { vault: string; alias?: string | null };24+ | {25+ /** Numeric site address in the inclusive range `0x0000`–`0xffff`. */26+ address: number;27+ }28+ | {29+ /** Registered vault name that owns the destination address. */30+ vault: string;31+ /** Optional site alias within the vault; `null` requests an unaliased site. */32+ alias?: string | null;33+ };2634 2735 /** Body of `POST /api/push/prepare`: the manifest the client wants to push. */2836 export interface PrepareRequest {37+ /** Complete manifest whose referenced blob availability should be checked. */2938 manifest: Manifest;3039 }3140 3241 /** Reply to `prepare`: the manifest's hash and which blobs the server still needs. */3342 export interface PrepareResponse {43+ /** Lowercase SHA-256 of the canonical manifest bytes. */3444 manifestHash: string;3545 /** blob hashes the server does not have yet */3646 missing: string[];@@ -38,7 +48,9 @@ export interface PrepareResponse {
3848 3949 /** Body of `POST /api/push/commit`: atomically publish content and its access policy. */4050 export interface CommitRequest {51+ /** Complete manifest to publish as the site's current version. */4152 manifest: Manifest;53+ /** Address or vault destination that should receive the new version. */4254 target: Target;4355 /** days until expiry; "forever" = no expiry; omitted = server default (14) */4456 ttl?: number | "forever";@@ -50,8 +62,11 @@ export interface CommitRequest {
5062 export interface CommitResponse {5163 /** 4-hex address, e.g. "2a3f" */5264 address: string;65+ /** Absolute public URL of the committed site. */5366 url: string;67+ /** Resolved site alias, or `null` for an unaliased address. */5468 alias: string | null;69+ /** Lowercase SHA-256 of the committed canonical manifest. */5570 manifestHash: string;5671 /** unix seconds, null = permanent */5772 expiresAt: number | null;@@ -61,50 +76,75 @@ export interface CommitResponse {
6176 6277 /** Summary of a single site, as returned by list/status endpoints. */6378 export interface SiteInfo {79+ /** Four-character lowercase hexadecimal site address. */6480 address: string;81+ /** Name of the vault containing the site. */6582 vault: string;83+ /** Site alias within its vault, or `null` when unaliased. */6684 alias: string | null;85+ /** Lowercase SHA-256 of the site's current canonical manifest. */6786 manifestHash: string;87+ /** Unix timestamp, in seconds, when the site was created. */6888 createdAt: number;89+ /** Unix timestamp, in seconds, of the most recent site update. */6990 updatedAt: number;91+ /** Unix expiry timestamp in seconds, or `null` for a permanent site. */7092 expiresAt: number | null;93+ /** Absolute public URL of the site. */7194 url: string;95+ /** Whether visitors must unlock the site with a password. */7296 protected: boolean;7397 }7498 7599 /** One entry in a site's push history. */76100 export interface PushInfo {101+ /** Monotonically increasing push sequence number within the site. */77102 seq: number;103+ /** Lowercase SHA-256 of the manifest published by this push. */78104 manifestHash: string;105+ /** Unix timestamp, in seconds, when the push was committed. */79106 pushedAt: number;107+ /** Optional audit note, such as the source sequence of a revert. */80108 note: string | null;81109 }82110 83111 /** A site plus its retained push history (powers `nzip revert`). */84112 export interface SiteDetail extends SiteInfo {113+ /** Retained push history ordered from newest to oldest. */85114 history: PushInfo[];86115 }87116 88117 /** Current uploaded bundle for a site, returned only by the authenticated recovery API. */89118 export interface SourceResponse {119+ /** Four-character lowercase hexadecimal address of the recovered site. */90120 address: string;121+ /** Lowercase SHA-256 of the returned canonical manifest. */91122 manifestHash: string;123+ /** Current manifest used to reconstruct and verify the hosted bundle. */92124 manifest: Manifest;93125 }94126 95127 /** A registered vault: its slot, name, and current site count. */96128 export interface VaultInfo {129+ /** Numeric vault slot in the inclusive range `0x0`–`0xf`. */97130 slot: number;131+ /** Registered lowercase vault name. */98132 name: string;133+ /** Unix timestamp, in seconds, when the vault was registered. */99134 createdAt: number;135+ /** Number of currently live sites assigned to this vault. */100136 siteCount: number;101137 }102138 103139 /** Reply to `GET /api/status`: server version and a snapshot of vaults and sites. */104140 export interface StatusResponse {141+ /** Literal success marker for a healthy authenticated status response. */105142 ok: true;143+ /** Semantic version reported by the running nzip Worker. */106144 version: string;145+ /** All registered vaults and their current site counts. */107146 vaults: VaultInfo[];147+ /** Total number of currently registered sites across every vault. */108148 siteCount: number;109149 /** sites expiring within 48h */110150 expiringSoon: number;@@ -112,11 +152,13 @@ export interface StatusResponse {
112152 113153 /** Body of a revert request: the push sequence number to repoint to (defaults to previous). */114154 export interface RevertRequest {155+ /** Push sequence to restore; omission selects the newest differing version. */115156 toSeq?: number;116157 }117158 118159 /** Body of a site PATCH: change TTL and/or password. Omitted fields are left unchanged. */119160 export interface PatchSiteRequest {161+ /** New lifetime in days, or `"forever"`; omission preserves the current expiry. */120162 ttl?: number | "forever";121163 /** set a password (string), clear it (null), or leave unchanged (undefined) */122164 password?: string | null;@@ -124,5 +166,6 @@ export interface PatchSiteRequest {
124166 125167 /** Standard error envelope returned by the API on failure. */126168 export interface ApiError {169+ /** Human-readable error message safe to show to the authenticated client. */127170 error: string;128171 }@@ -38,7 +38,7 @@ describe("Worker runtime", () => {
3838 });3939 4040 expect(response.status).toBe(200);41- expect((await response.json<{ version: string }>()).version).toBe("0.3.0");41+ expect((await response.json<{ version: string }>()).version).toBe("0.3.1");4242 });4343 4444 it("evaluates a real D1 probe window through the scheduled handler", async () => {