clone

push a directory of html from the terminal and get a four-character url back. a deno cli on cloudflare

feat/source-stable-push
nzip / cli / README.md
README.md 6.1K rendered
1# `@nzip/cli`23**Push a directory of HTML from the terminal. Get a four-character URL back.**45The command-line client for [nzip](https://github.com/FelineStateMachine/nzip), a personal,6self-hosted share tool. The CLI bundles a directory, uploads only the blobs your server hasn't seen,7and prints a tiny URL. The backend is your own Cloudflare Worker (R2 + D1); there is no public8service.910## Install1112Requires [Deno](https://docs.deno.com/runtime/) on your `PATH`.1314```sh15deno install -g -A -f -n nzip jsr:@nzip/cli16nzip --version17```1819Try it without installing:2021```sh22deno run -A jsr:@nzip/cli --help23```2425## Use2627```sh28nzip auth --server https://share.demo.dev # authenticate (prompts for the token)29nzip vault add work # register a named vault30nzip site push ./site work:demo --ttl 30d --password secret31 # → https://12d8.demo.dev/32```3334Config is saved to `~/.config/nzip/config.json` (mode 0600), so later commands just work. On a35second machine, install from JSR and re-run `nzip auth` with the same server and token; every vault36and site is already there.3738`nzip --version` prints the installed release without reading saved configuration. Use39`nzip --version --json` to receive a single JSON object with a `version` field for scripts and40agents.4142## Commands4344```text45nzip46├─ --version [--json] show the installed CLI version47├─ auth [--server URL] [--token T] authenticate and save config48├─ status show server and vault status49├─ app50│ ├─ init <alias|vault:alias> reserve a stable app URL51│ └─ deploy build and deploy the configured lofi app52├─ vault53│ ├─ add <name> [--slot N] [--default-ttl 14d|forever|inherit]54│ ├─ update <name> [--default-ttl 14d|forever|inherit]55│ ├─ ls list vaults56│ └─ default <temporary|permanent> <name>57├─ site58│ ├─ push <dir|file> [target] [--new] [--ttl …] [--password PW | --no-password]59│ ├─ cp <target> [dir] [--overwrite] copy a hosted bundle60│ ├─ show <target> show site details61│ ├─ policy <target> [--ttl …] [--password PW | --no-password]62│ ├─ ls [vault] list sites63│ ├─ where <target> print this machine's source directory64│ ├─ rm <target> [--yes] delete a site65│ └─ revert <target> [--to N] [--list] inspect or restore push history66└─ notify67 ├─ send <body> [--title TEXT] [--open TARGET] [--tag TEXT]68 ├─ test send a diagnostic notification69 ├─ pair allow device pairing for 10 minutes70 ├─ approve <code> --name NAME [--yes]71 ├─ devices [--all] list current notification devices72 └─ revoke <device-id> [--yes] revoke a notification device73```7475Vault descriptions, lifecycle roles, configured TTLs, and effective TTLs are included in76`vault ls --json`. Use `nzip vault update <name> --no-description` to clear a description,77`--default-ttl inherit` to restore the global fallback, and78`nzip vault default <temporary|permanent> <name>` to select lifecycle defaults.7980Password and TTL are committed with the content. TTL precedence is explicit flag, existing-site81expiry, vault default, then the global 14-day fallback. Fresh servers create `personal` in slot `0`82as the temporary 14-day default and `public` in slot `f` as the permanent forever default, without83overwriting occupied slots on upgrade. `public` does not mean unprotected. Pass `--no-password` to84clear protection explicitly. Push JSON includes the resolved `ttl` and `ttlSource`.8586Use `site push` for content revisions and `site policy` for TTL or password changes. An untargeted87push reuses a unique unexpired local breadcrumb for the same logical source; a directory and its88`index.html` are treated as one source. Multiple matches stop with candidate targets instead of89guessing; an explicit targeted push rebinds the source for later untargeted revisions. Pass `--new`90only when a separate URL is intended.9192For a lofi PWA, run `nzip app init <alias>` before editing its deployed credential origins. The93command reserves the permanent default vault's final URL and writes a token-free `nzip.app.json`.94After adding the printed origin to `src/app.ts` `credentialOrigins`, run `nzip app deploy`. It95builds at `/`, validates the lofi output and stable identity settings, mirrors the generated CSP,96and pushes to the reservation. The address remains reserved after content deletion or expiry and is97never returned to ordinary site allocation.9899`nzip site cp work:demo ./recovered-demo` reconstructs the current hosted bundle into an empty100directory. It uses the configured bearer token, verifies file hashes, and never exposes source via101the public page URL. Only uploaded files can be restored; ignored dotfiles and local metadata were102never stored.103104## Notifications105106Pairing is closed by default. Open a 10-minute pairing window from the authenticated CLI, then open107the deployment root on the phone. The `pair` action appears only while that window is open. After108the phone shows a code, approve it from the CLI:109110```sh111nzip notify pair112nzip notify approve ABCD-1234 --name "Personal phone"113nzip notify devices114nzip notify devices --all # include disabled, revoked, and expired tombstones115nzip notify send "Report ready" --title "nzip" --open work:report116```117118`--open` accepts an existing nzip target and applies the same local vault guardrails as other119target-aware commands. It never accepts an arbitrary URL. `nzip notify test` uses the ordinary120notification delivery path. Use `nzip notify revoke <device-id> --yes` to remove a device.121122Notification content may appear on a lock screen. Never include passwords, tokens, private URLs, or123sensitive personal data in a title or body.124125See the [project README](../README.md) for how addresses work, the126[deployment runbook](../worker/setup.md) for self-hosting, and [ARCHITECTURE.md](../ARCHITECTURE.md)127for internals. MIT licensed.