@yannelli/zoomies 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/cli/client.d.ts +77 -0
- package/dist/cli/client.d.ts.map +1 -0
- package/dist/cli/client.js +300 -0
- package/dist/cli/client.js.map +1 -0
- package/dist/cli/commands/certs.d.ts +11 -0
- package/dist/cli/commands/certs.d.ts.map +1 -0
- package/dist/cli/commands/certs.js +110 -0
- package/dist/cli/commands/certs.js.map +1 -0
- package/dist/cli/commands/flags.d.ts +29 -0
- package/dist/cli/commands/flags.d.ts.map +1 -0
- package/dist/cli/commands/flags.js +104 -0
- package/dist/cli/commands/flags.js.map +1 -0
- package/dist/cli/commands/reload.d.ts +11 -0
- package/dist/cli/commands/reload.d.ts.map +1 -0
- package/dist/cli/commands/reload.js +35 -0
- package/dist/cli/commands/reload.js.map +1 -0
- package/dist/cli/commands/sites.d.ts +11 -0
- package/dist/cli/commands/sites.d.ts.map +1 -0
- package/dist/cli/commands/sites.js +221 -0
- package/dist/cli/commands/sites.js.map +1 -0
- package/dist/cli/commands/status.d.ts +10 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +41 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/upstreams.d.ts +21 -0
- package/dist/cli/commands/upstreams.d.ts.map +1 -0
- package/dist/cli/commands/upstreams.js +248 -0
- package/dist/cli/commands/upstreams.js.map +1 -0
- package/dist/cli/dispatcher.d.ts +45 -0
- package/dist/cli/dispatcher.d.ts.map +1 -0
- package/dist/cli/dispatcher.js +192 -0
- package/dist/cli/dispatcher.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/server/api/db-context.d.ts +50 -0
- package/dist/server/api/db-context.d.ts.map +1 -0
- package/dist/server/api/db-context.js +76 -0
- package/dist/server/api/db-context.js.map +1 -0
- package/dist/server/api/error-mapping.d.ts +19 -0
- package/dist/server/api/error-mapping.d.ts.map +1 -0
- package/dist/server/api/error-mapping.js +56 -0
- package/dist/server/api/error-mapping.js.map +1 -0
- package/dist/server/api/handlers/site-cert.d.ts +49 -0
- package/dist/server/api/handlers/site-cert.d.ts.map +1 -0
- package/dist/server/api/handlers/site-cert.js +54 -0
- package/dist/server/api/handlers/site-cert.js.map +1 -0
- package/dist/server/api/handlers/sites.d.ts +67 -0
- package/dist/server/api/handlers/sites.d.ts.map +1 -0
- package/dist/server/api/handlers/sites.js +78 -0
- package/dist/server/api/handlers/sites.js.map +1 -0
- package/dist/server/api/handlers/upstreams.d.ts +64 -0
- package/dist/server/api/handlers/upstreams.d.ts.map +1 -0
- package/dist/server/api/handlers/upstreams.js +97 -0
- package/dist/server/api/handlers/upstreams.js.map +1 -0
- package/dist/server/auth/require-token.d.ts +24 -0
- package/dist/server/auth/require-token.d.ts.map +1 -0
- package/dist/server/auth/require-token.js +98 -0
- package/dist/server/auth/require-token.js.map +1 -0
- package/dist/server/certs/acme-account.d.ts +37 -0
- package/dist/server/certs/acme-account.d.ts.map +1 -0
- package/dist/server/certs/acme-account.js +49 -0
- package/dist/server/certs/acme-account.js.map +1 -0
- package/dist/server/certs/challenge-store.d.ts +53 -0
- package/dist/server/certs/challenge-store.d.ts.map +1 -0
- package/dist/server/certs/challenge-store.js +66 -0
- package/dist/server/certs/challenge-store.js.map +1 -0
- package/dist/server/certs/issue.d.ts +106 -0
- package/dist/server/certs/issue.d.ts.map +1 -0
- package/dist/server/certs/issue.js +107 -0
- package/dist/server/certs/issue.js.map +1 -0
- package/dist/server/certs/renew.d.ts +34 -0
- package/dist/server/certs/renew.d.ts.map +1 -0
- package/dist/server/certs/renew.js +36 -0
- package/dist/server/certs/renew.js.map +1 -0
- package/dist/server/certs/scheduler.d.ts +68 -0
- package/dist/server/certs/scheduler.d.ts.map +1 -0
- package/dist/server/certs/scheduler.js +76 -0
- package/dist/server/certs/scheduler.js.map +1 -0
- package/dist/server/db/connection.d.ts +10 -0
- package/dist/server/db/connection.d.ts.map +1 -0
- package/dist/server/db/connection.js +16 -0
- package/dist/server/db/connection.js.map +1 -0
- package/dist/server/db/migrate.d.ts +12 -0
- package/dist/server/db/migrate.d.ts.map +1 -0
- package/dist/server/db/migrate.js +37 -0
- package/dist/server/db/migrate.js.map +1 -0
- package/dist/server/db/migrations/0001_init.sql +42 -0
- package/dist/server/domain/cert.d.ts +17 -0
- package/dist/server/domain/cert.d.ts.map +1 -0
- package/dist/server/domain/cert.js +22 -0
- package/dist/server/domain/cert.js.map +1 -0
- package/dist/server/domain/errors.d.ts +36 -0
- package/dist/server/domain/errors.d.ts.map +1 -0
- package/dist/server/domain/errors.js +37 -0
- package/dist/server/domain/errors.js.map +1 -0
- package/dist/server/domain/site.d.ts +15 -0
- package/dist/server/domain/site.d.ts.map +1 -0
- package/dist/server/domain/site.js +25 -0
- package/dist/server/domain/site.js.map +1 -0
- package/dist/server/domain/upstream.d.ts +25 -0
- package/dist/server/domain/upstream.d.ts.map +1 -0
- package/dist/server/domain/upstream.js +24 -0
- package/dist/server/domain/upstream.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +4 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/reload/atomic-write.d.ts +44 -0
- package/dist/server/reload/atomic-write.d.ts.map +1 -0
- package/dist/server/reload/atomic-write.js +151 -0
- package/dist/server/reload/atomic-write.js.map +1 -0
- package/dist/server/reload/health-probe.d.ts +62 -0
- package/dist/server/reload/health-probe.d.ts.map +1 -0
- package/dist/server/reload/health-probe.js +105 -0
- package/dist/server/reload/health-probe.js.map +1 -0
- package/dist/server/reload/reload.d.ts +118 -0
- package/dist/server/reload/reload.d.ts.map +1 -0
- package/dist/server/reload/reload.js +232 -0
- package/dist/server/reload/reload.js.map +1 -0
- package/dist/server/renderer/render-bundle.d.ts +18 -0
- package/dist/server/renderer/render-bundle.d.ts.map +1 -0
- package/dist/server/renderer/render-bundle.js +32 -0
- package/dist/server/renderer/render-bundle.js.map +1 -0
- package/dist/server/renderer/render-site.d.ts +5 -0
- package/dist/server/renderer/render-site.d.ts.map +1 -0
- package/dist/server/renderer/render-site.js +144 -0
- package/dist/server/renderer/render-site.js.map +1 -0
- package/dist/server/repositories/cert-repository.d.ts +19 -0
- package/dist/server/repositories/cert-repository.d.ts.map +1 -0
- package/dist/server/repositories/cert-repository.js +112 -0
- package/dist/server/repositories/cert-repository.js.map +1 -0
- package/dist/server/repositories/site-repository.d.ts +17 -0
- package/dist/server/repositories/site-repository.d.ts.map +1 -0
- package/dist/server/repositories/site-repository.js +122 -0
- package/dist/server/repositories/site-repository.js.map +1 -0
- package/dist/server/repositories/upstream-repository.d.ts +22 -0
- package/dist/server/repositories/upstream-repository.d.ts.map +1 -0
- package/dist/server/repositories/upstream-repository.js +142 -0
- package/dist/server/repositories/upstream-repository.js.map +1 -0
- package/dist/server/validator/nginx-binary.d.ts +9 -0
- package/dist/server/validator/nginx-binary.d.ts.map +1 -0
- package/dist/server/validator/nginx-binary.js +11 -0
- package/dist/server/validator/nginx-binary.js.map +1 -0
- package/dist/server/validator/validate.d.ts +29 -0
- package/dist/server/validator/validate.d.ts.map +1 -0
- package/dist/server/validator/validate.js +69 -0
- package/dist/server/validator/validate.js.map +1 -0
- package/dist/server/worker/main.d.ts +43 -0
- package/dist/server/worker/main.d.ts.map +1 -0
- package/dist/server/worker/main.js +181 -0
- package/dist/server/worker/main.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryan Yannelli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Zoomies
|
|
2
|
+
|
|
3
|
+
> A control plane for NGINX. Zoomies renders, validates, and reloads NGINX
|
|
4
|
+
> configuration from a typed model so you can manage reverse-proxied sites
|
|
5
|
+
> without hand-editing config files.
|
|
6
|
+
|
|
7
|
+
[](https://github.com/yannelli/zoomies/actions/workflows/ci.yml)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
**Status:** Alpha. The v1 surface is complete and runnable, but the API,
|
|
12
|
+
CLI, and config schema may still see breaking changes before 1.0.
|
|
13
|
+
|
|
14
|
+
## What it is (and isn't)
|
|
15
|
+
|
|
16
|
+
Zoomies is the **control plane**. NGINX is the **data plane**: it handles
|
|
17
|
+
every byte of proxied traffic, and that's where the performance comes from.
|
|
18
|
+
Zoomies' job is to:
|
|
19
|
+
|
|
20
|
+
- Model sites, upstreams, and certificates as typed records.
|
|
21
|
+
- Render NGINX config from those records.
|
|
22
|
+
- Validate the rendered config with `nginx -t` before swapping it in.
|
|
23
|
+
- Atomically swap files, trigger a reload, probe health, and roll back on
|
|
24
|
+
any failure.
|
|
25
|
+
- Automate Let's Encrypt certificate issuance and renewal.
|
|
26
|
+
|
|
27
|
+
It is **not** a new proxy, a new HTTP server, or a replacement for NGINX.
|
|
28
|
+
|
|
29
|
+
See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the component sketch.
|
|
30
|
+
|
|
31
|
+
## What's in v1
|
|
32
|
+
|
|
33
|
+
- **Web UI** at `/login`, `/sites`, `/upstreams` — cookie-gated CRUD with
|
|
34
|
+
shadcn-style primitives.
|
|
35
|
+
- **HTTP API** under `/api/v1/{sites,upstreams,sites/[id]/cert}` — bearer-
|
|
36
|
+
token-guarded; `DomainError` and `ZodError` map to clean HTTP statuses.
|
|
37
|
+
- **CLI** — `zoomies sites|upstreams|certs|reload|status`. Runs in
|
|
38
|
+
`--local` mode (direct SQLite access) or HTTP mode against a running
|
|
39
|
+
control plane.
|
|
40
|
+
- **ACME worker** (`zoomies-worker`) — long-running process that polls
|
|
41
|
+
for certs nearing expiry and renews them serially. HTTP-01 challenges
|
|
42
|
+
served from a directory NGINX exposes.
|
|
43
|
+
- **Reload orchestrator** — validate → atomic write → SIGHUP → health
|
|
44
|
+
probe → rollback on any failure step.
|
|
45
|
+
- **SQLite persistence** with idempotent migrations and Zod-on-read.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
Two supported paths, both covered in [`docs/INSTALL.md`](docs/INSTALL.md):
|
|
50
|
+
|
|
51
|
+
- **Docker Compose** — the shipped `docker-compose.yml` runs the control
|
|
52
|
+
plane (`app`), an NGINX edge sidecar (`nginx`), and optionally the ACME
|
|
53
|
+
renewal worker (`worker`).
|
|
54
|
+
- **Ubuntu native** — `scripts/install-ubuntu.sh` installs Node 22 if
|
|
55
|
+
needed, builds into `/opt/zoomies`, and registers `zoomies.service` and
|
|
56
|
+
`zoomies-worker.service` systemd units.
|
|
57
|
+
|
|
58
|
+
For the ops side — NGINX permission strategies, the `include` contract,
|
|
59
|
+
ACME challenge directory layout — see
|
|
60
|
+
[`docs/OPERATIONS.md`](docs/OPERATIONS.md).
|
|
61
|
+
|
|
62
|
+
## Development
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/yannelli/zoomies.git
|
|
66
|
+
cd zoomies
|
|
67
|
+
nvm use # .nvmrc → Node 22 LTS
|
|
68
|
+
pnpm install
|
|
69
|
+
pnpm typecheck
|
|
70
|
+
pnpm test
|
|
71
|
+
pnpm dev # next dev on http://localhost:3000
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Other scripts:
|
|
75
|
+
|
|
76
|
+
| Command | What it does |
|
|
77
|
+
| ---------------- | --------------------------------------------------------------------- |
|
|
78
|
+
| `pnpm typecheck` | `tsc --noEmit` for both the Next app and the CLI tsconfig |
|
|
79
|
+
| `pnpm lint` | `eslint .` |
|
|
80
|
+
| `pnpm format` | `prettier --write .` |
|
|
81
|
+
| `pnpm test` | `vitest run` (NGINX-dependent e2e gated on `ZOOMIES_E2E=1`) |
|
|
82
|
+
| `pnpm build` | `next build` (web) + `tsc -p tsconfig.cli.json` + copy SQL migrations |
|
|
83
|
+
| `pnpm start` | `next start` against the standalone bundle |
|
|
84
|
+
| `pnpm cli` | Run the CLI through `tsx` for fast iteration |
|
|
85
|
+
|
|
86
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the conventions: ESM only,
|
|
87
|
+
strict TypeScript, validate-at-boundary with Zod, never write NGINX
|
|
88
|
+
config without validating first, no shell-string `execa`.
|
|
89
|
+
|
|
90
|
+
## Why "Zoomies"?
|
|
91
|
+
|
|
92
|
+
It's what cats do when they sprint in circles for no apparent reason.
|
|
93
|
+
NGINX already runs fast; Zoomies just points it where to go.
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
[MIT](LICENSE) © Ryan Yannelli
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI client abstraction — single interface, two implementations.
|
|
3
|
+
*
|
|
4
|
+
* The CLI commands speak {@link CliClient}. `createLocalClient` wraps the
|
|
5
|
+
* in-process repositories + framework-agnostic handlers; `createHttpClient`
|
|
6
|
+
* hits the running Next.js HTTP API. Commands never branch on mode — the
|
|
7
|
+
* dispatcher picks one client and hands it to every command.
|
|
8
|
+
*
|
|
9
|
+
* Failures bubble as plain `Error`s with a `code` discriminator where the
|
|
10
|
+
* structured server response provided one, so command modules can pretty-
|
|
11
|
+
* print without re-deriving HTTP details.
|
|
12
|
+
*/
|
|
13
|
+
import { type CreateSiteInput, type UpdateSiteInput } from '../server/api/handlers/sites.js';
|
|
14
|
+
import { type CreateUpstreamInput, type UpdateUpstreamInput } from '../server/api/handlers/upstreams.js';
|
|
15
|
+
import type { Cert } from '../server/domain/cert.js';
|
|
16
|
+
import type { Site } from '../server/domain/site.js';
|
|
17
|
+
import type { Upstream } from '../server/domain/upstream.js';
|
|
18
|
+
import { type ApplyStep } from '../server/reload/reload.js';
|
|
19
|
+
export type { CreateSiteInput, UpdateSiteInput, CreateUpstreamInput, UpdateUpstreamInput };
|
|
20
|
+
export interface SitesClient {
|
|
21
|
+
list(): Promise<Site[]>;
|
|
22
|
+
get(id: string): Promise<Site>;
|
|
23
|
+
create(input: CreateSiteInput): Promise<Site>;
|
|
24
|
+
update(id: string, patch: UpdateSiteInput): Promise<Site>;
|
|
25
|
+
delete(id: string): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export interface UpstreamsClient {
|
|
28
|
+
list(): Promise<Upstream[]>;
|
|
29
|
+
get(id: string): Promise<Upstream>;
|
|
30
|
+
create(input: CreateUpstreamInput): Promise<Upstream>;
|
|
31
|
+
update(id: string, patch: UpdateUpstreamInput): Promise<Upstream>;
|
|
32
|
+
delete(id: string): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export interface CertsClient {
|
|
35
|
+
issueForSite(siteId: string): Promise<Cert>;
|
|
36
|
+
list(): Promise<Cert[]>;
|
|
37
|
+
}
|
|
38
|
+
export interface ReloadResult {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
step: ApplyStep | 'config' | 'unsupported';
|
|
41
|
+
message?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface ReloadClient {
|
|
44
|
+
apply(): Promise<ReloadResult>;
|
|
45
|
+
}
|
|
46
|
+
export interface HealthResult {
|
|
47
|
+
ok: boolean;
|
|
48
|
+
status: number | null;
|
|
49
|
+
body?: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface StatusClient {
|
|
52
|
+
health(): Promise<HealthResult>;
|
|
53
|
+
}
|
|
54
|
+
export interface CliClient {
|
|
55
|
+
sites: SitesClient;
|
|
56
|
+
upstreams: UpstreamsClient;
|
|
57
|
+
certs: CertsClient;
|
|
58
|
+
reload: ReloadClient;
|
|
59
|
+
status: StatusClient;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Structured client error. Mirrors the shape of `mapErrorToResponse`'s
|
|
63
|
+
* body so commands can pretty-print uniformly across local and http modes.
|
|
64
|
+
*/
|
|
65
|
+
export declare class CliClientError extends Error {
|
|
66
|
+
readonly status: number | null;
|
|
67
|
+
readonly code: string;
|
|
68
|
+
readonly details?: unknown;
|
|
69
|
+
constructor(message: string, opts?: {
|
|
70
|
+
status?: number | null;
|
|
71
|
+
code?: string;
|
|
72
|
+
details?: unknown;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export declare function createLocalClient(): CliClient;
|
|
76
|
+
export declare function createHttpClient(baseUrl: string, token: string | undefined): CliClient;
|
|
77
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/cli/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI client abstraction — single interface, two implementations.
|
|
3
|
+
*
|
|
4
|
+
* The CLI commands speak {@link CliClient}. `createLocalClient` wraps the
|
|
5
|
+
* in-process repositories + framework-agnostic handlers; `createHttpClient`
|
|
6
|
+
* hits the running Next.js HTTP API. Commands never branch on mode — the
|
|
7
|
+
* dispatcher picks one client and hands it to every command.
|
|
8
|
+
*
|
|
9
|
+
* Failures bubble as plain `Error`s with a `code` discriminator where the
|
|
10
|
+
* structured server response provided one, so command modules can pretty-
|
|
11
|
+
* print without re-deriving HTTP details.
|
|
12
|
+
*/
|
|
13
|
+
import { mkdir } from 'node:fs/promises';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { createSite, deleteSite, getSite, listSites, updateSite, } from '../server/api/handlers/sites.js';
|
|
16
|
+
import { createUpstream, deleteUpstream, getUpstream, listUpstreams, updateUpstream, } from '../server/api/handlers/upstreams.js';
|
|
17
|
+
import { issueCertForSite } from '../server/api/handlers/site-cert.js';
|
|
18
|
+
import { getDb, getRepositories } from '../server/api/db-context.js';
|
|
19
|
+
import { loadOrCreateAccount } from '../server/certs/acme-account.js';
|
|
20
|
+
import { createChallengeStore } from '../server/certs/challenge-store.js';
|
|
21
|
+
import { issueCertificate } from '../server/certs/issue.js';
|
|
22
|
+
import { applyDesiredState } from '../server/reload/reload.js';
|
|
23
|
+
import { renderBundle } from '../server/renderer/render-bundle.js';
|
|
24
|
+
/**
|
|
25
|
+
* Structured client error. Mirrors the shape of `mapErrorToResponse`'s
|
|
26
|
+
* body so commands can pretty-print uniformly across local and http modes.
|
|
27
|
+
*/
|
|
28
|
+
export class CliClientError extends Error {
|
|
29
|
+
status;
|
|
30
|
+
code;
|
|
31
|
+
details;
|
|
32
|
+
constructor(message, opts = {}) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = 'CliClientError';
|
|
35
|
+
this.status = opts.status ?? null;
|
|
36
|
+
this.code = opts.code ?? 'error';
|
|
37
|
+
if (opts.details !== undefined) {
|
|
38
|
+
this.details = opts.details;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Wrap a synchronous handler call in `Promise.resolve` so the interface is
|
|
44
|
+
* uniformly async. The handlers themselves are sync because `better-sqlite3`
|
|
45
|
+
* is sync, but the HTTP client is necessarily async and we don't want the
|
|
46
|
+
* command code branching on which one it has.
|
|
47
|
+
*/
|
|
48
|
+
async function syncAsync(fn) {
|
|
49
|
+
return Promise.resolve(fn());
|
|
50
|
+
}
|
|
51
|
+
export function createLocalClient() {
|
|
52
|
+
const repos = () => getRepositories();
|
|
53
|
+
return {
|
|
54
|
+
sites: {
|
|
55
|
+
async list() {
|
|
56
|
+
return syncAsync(() => listSites({ siteRepo: repos().sites }));
|
|
57
|
+
},
|
|
58
|
+
async get(id) {
|
|
59
|
+
return syncAsync(() => getSite(id, { siteRepo: repos().sites }));
|
|
60
|
+
},
|
|
61
|
+
async create(input) {
|
|
62
|
+
return syncAsync(() => createSite(input, { siteRepo: repos().sites }));
|
|
63
|
+
},
|
|
64
|
+
async update(id, patch) {
|
|
65
|
+
return syncAsync(() => updateSite(id, patch, { siteRepo: repos().sites }));
|
|
66
|
+
},
|
|
67
|
+
async delete(id) {
|
|
68
|
+
return syncAsync(() => {
|
|
69
|
+
deleteSite(id, { siteRepo: repos().sites });
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
upstreams: {
|
|
74
|
+
async list() {
|
|
75
|
+
return syncAsync(() => listUpstreams({ upstreamRepo: repos().upstreams }));
|
|
76
|
+
},
|
|
77
|
+
async get(id) {
|
|
78
|
+
return syncAsync(() => getUpstream(id, { upstreamRepo: repos().upstreams }));
|
|
79
|
+
},
|
|
80
|
+
async create(input) {
|
|
81
|
+
return syncAsync(() => createUpstream(input, { upstreamRepo: repos().upstreams }));
|
|
82
|
+
},
|
|
83
|
+
async update(id, patch) {
|
|
84
|
+
return syncAsync(() => updateUpstream(id, patch, { upstreamRepo: repos().upstreams }));
|
|
85
|
+
},
|
|
86
|
+
async delete(id) {
|
|
87
|
+
return syncAsync(() => {
|
|
88
|
+
deleteUpstream(id, { upstreamRepo: repos().upstreams });
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
certs: {
|
|
93
|
+
async issueForSite(siteId) {
|
|
94
|
+
const contactEmail = process.env.ZOOMIES_ACME_EMAIL;
|
|
95
|
+
if (contactEmail === undefined || contactEmail === '') {
|
|
96
|
+
throw new CliClientError('ACME email not configured: set ZOOMIES_ACME_EMAIL', {
|
|
97
|
+
code: 'config_missing',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const directoryUrl = process.env.ZOOMIES_ACME_DIRECTORY_URL ??
|
|
101
|
+
'https://acme-v02.api.letsencrypt.org/directory';
|
|
102
|
+
const stateDir = process.env.ZOOMIES_STATE_DIR ?? join(process.cwd(), '.zoomies');
|
|
103
|
+
const certDir = process.env.ZOOMIES_CERT_DIR ?? join(stateDir, 'certs');
|
|
104
|
+
await mkdir(certDir, { recursive: true });
|
|
105
|
+
const challengeStore = createChallengeStore({ stateDir });
|
|
106
|
+
await mkdir(challengeStore.basePath, { recursive: true });
|
|
107
|
+
const account = await loadOrCreateAccount({
|
|
108
|
+
accountKeyPath: join(stateDir, 'acme-account.key'),
|
|
109
|
+
contactEmail,
|
|
110
|
+
directoryUrl,
|
|
111
|
+
});
|
|
112
|
+
const { sites, certs } = repos();
|
|
113
|
+
return issueCertForSite(siteId, {
|
|
114
|
+
siteRepo: sites,
|
|
115
|
+
certRepo: certs,
|
|
116
|
+
account,
|
|
117
|
+
challengeStore,
|
|
118
|
+
certDir,
|
|
119
|
+
issue: issueCertificate,
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
async list() {
|
|
123
|
+
return syncAsync(() => repos().certs.list());
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
reload: {
|
|
127
|
+
async apply() {
|
|
128
|
+
const sitesDir = process.env.ZOOMIES_NGINX_SITES_DIR;
|
|
129
|
+
const healthCheckUrl = process.env.ZOOMIES_HEALTH_CHECK_URL;
|
|
130
|
+
if (sitesDir === undefined || sitesDir === '') {
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
step: 'config',
|
|
134
|
+
message: 'ZOOMIES_NGINX_SITES_DIR is not set',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (healthCheckUrl === undefined || healthCheckUrl === '') {
|
|
138
|
+
return {
|
|
139
|
+
ok: false,
|
|
140
|
+
step: 'config',
|
|
141
|
+
message: 'ZOOMIES_HEALTH_CHECK_URL is not set',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const { sites, upstreams, certs } = repos();
|
|
145
|
+
const rendered = renderBundle(sites.list(), upstreams.list(), certs.list());
|
|
146
|
+
const result = await applyDesiredState(rendered, { sitesDir, healthCheckUrl });
|
|
147
|
+
return {
|
|
148
|
+
ok: result.ok,
|
|
149
|
+
step: result.step,
|
|
150
|
+
...(result.message !== undefined ? { message: result.message } : {}),
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
status: {
|
|
155
|
+
async health() {
|
|
156
|
+
try {
|
|
157
|
+
const db = getDb();
|
|
158
|
+
const row = db.prepare('SELECT 1 AS ok').get();
|
|
159
|
+
if (row?.ok === 1) {
|
|
160
|
+
return { ok: true, status: null, body: { status: 'ok', db: 'reachable' } };
|
|
161
|
+
}
|
|
162
|
+
return { ok: false, status: null, body: { status: 'degraded', db: 'no rows' } };
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
166
|
+
return { ok: false, status: null, body: { status: 'error', message } };
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function isErrorBody(value) {
|
|
173
|
+
return typeof value === 'object' && value !== null;
|
|
174
|
+
}
|
|
175
|
+
async function parseJsonOrNull(response) {
|
|
176
|
+
const text = await response.text();
|
|
177
|
+
if (text === '') {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
return JSON.parse(text);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return text;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Throw a {@link CliClientError} carrying the server-provided code + details
|
|
189
|
+
* when the response is non-2xx; otherwise return the parsed JSON body.
|
|
190
|
+
*/
|
|
191
|
+
async function unwrapResponse(response) {
|
|
192
|
+
const body = await parseJsonOrNull(response);
|
|
193
|
+
if (response.ok) {
|
|
194
|
+
return body;
|
|
195
|
+
}
|
|
196
|
+
const message = isErrorBody(body) && typeof body.error === 'string' ? body.error : `HTTP ${response.status}`;
|
|
197
|
+
const code = isErrorBody(body) && typeof body.code === 'string' ? body.code : 'http_error';
|
|
198
|
+
const details = isErrorBody(body) ? body.details : undefined;
|
|
199
|
+
const opts = {
|
|
200
|
+
status: response.status,
|
|
201
|
+
code,
|
|
202
|
+
};
|
|
203
|
+
if (details !== undefined) {
|
|
204
|
+
opts.details = details;
|
|
205
|
+
}
|
|
206
|
+
throw new CliClientError(message, opts);
|
|
207
|
+
}
|
|
208
|
+
export function createHttpClient(baseUrl, token) {
|
|
209
|
+
const headers = { 'content-type': 'application/json' };
|
|
210
|
+
if (token !== undefined && token !== '') {
|
|
211
|
+
headers.authorization = `Bearer ${token}`;
|
|
212
|
+
}
|
|
213
|
+
const url = (path) => {
|
|
214
|
+
const trimmed = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
215
|
+
return `${trimmed}${path}`;
|
|
216
|
+
};
|
|
217
|
+
async function request(path, init = {}) {
|
|
218
|
+
const response = await fetch(url(path), {
|
|
219
|
+
...init,
|
|
220
|
+
headers: { ...headers, ...init.headers },
|
|
221
|
+
});
|
|
222
|
+
return unwrapResponse(response);
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
sites: {
|
|
226
|
+
list: () => request('/api/v1/sites'),
|
|
227
|
+
get: (id) => request(`/api/v1/sites/${encodeURIComponent(id)}`),
|
|
228
|
+
create: (input) => request('/api/v1/sites', { method: 'POST', body: JSON.stringify(input) }),
|
|
229
|
+
update: (id, patch) => request(`/api/v1/sites/${encodeURIComponent(id)}`, {
|
|
230
|
+
method: 'PATCH',
|
|
231
|
+
body: JSON.stringify(patch),
|
|
232
|
+
}),
|
|
233
|
+
async delete(id) {
|
|
234
|
+
const response = await fetch(url(`/api/v1/sites/${encodeURIComponent(id)}`), {
|
|
235
|
+
method: 'DELETE',
|
|
236
|
+
headers,
|
|
237
|
+
});
|
|
238
|
+
if (response.ok) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
await unwrapResponse(response);
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
upstreams: {
|
|
245
|
+
list: () => request('/api/v1/upstreams'),
|
|
246
|
+
get: (id) => request(`/api/v1/upstreams/${encodeURIComponent(id)}`),
|
|
247
|
+
create: (input) => request('/api/v1/upstreams', {
|
|
248
|
+
method: 'POST',
|
|
249
|
+
body: JSON.stringify(input),
|
|
250
|
+
}),
|
|
251
|
+
update: (id, patch) => request(`/api/v1/upstreams/${encodeURIComponent(id)}`, {
|
|
252
|
+
method: 'PATCH',
|
|
253
|
+
body: JSON.stringify(patch),
|
|
254
|
+
}),
|
|
255
|
+
async delete(id) {
|
|
256
|
+
const response = await fetch(url(`/api/v1/upstreams/${encodeURIComponent(id)}`), {
|
|
257
|
+
method: 'DELETE',
|
|
258
|
+
headers,
|
|
259
|
+
});
|
|
260
|
+
if (response.ok) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
await unwrapResponse(response);
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
certs: {
|
|
267
|
+
issueForSite: (siteId) => request(`/api/v1/sites/${encodeURIComponent(siteId)}/cert`, {
|
|
268
|
+
method: 'POST',
|
|
269
|
+
}),
|
|
270
|
+
list: () => {
|
|
271
|
+
throw new CliClientError('listing certs over HTTP is not yet implemented; use --local', {
|
|
272
|
+
code: 'unsupported',
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
reload: {
|
|
277
|
+
async apply() {
|
|
278
|
+
return {
|
|
279
|
+
ok: false,
|
|
280
|
+
step: 'unsupported',
|
|
281
|
+
message: 'reload via HTTP not yet implemented; use --local',
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
status: {
|
|
286
|
+
async health() {
|
|
287
|
+
try {
|
|
288
|
+
const response = await fetch(url('/api/healthz'), { headers });
|
|
289
|
+
const body = await parseJsonOrNull(response);
|
|
290
|
+
return { ok: response.ok, status: response.status, body };
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
294
|
+
return { ok: false, status: null, body: { error: message } };
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/cli/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `zoomies certs <subcommand>` — issue / list cert rows.
|
|
3
|
+
*
|
|
4
|
+
* `issue` blocks until the ACME order completes (10–60 s in production
|
|
5
|
+
* against Let's Encrypt). The HTTP API does not yet expose a list-certs
|
|
6
|
+
* endpoint, so `list` is local-only for now.
|
|
7
|
+
*/
|
|
8
|
+
import type { Command } from '../dispatcher.js';
|
|
9
|
+
export declare const CERTS_USAGE = "Usage: zoomies certs <subcommand> [args]\n\nSubcommands:\n issue --site-id <id> Issue (or re-issue) a Let's Encrypt cert for a site.\n Blocks until the ACME order completes (10-60 seconds\n against the production Let's Encrypt API).\n Local mode requires ZOOMIES_ACME_EMAIL to be set.\n list Tabular listing of all certs (local mode only).\n";
|
|
10
|
+
export declare const certsCommand: Command;
|
|
11
|
+
//# sourceMappingURL=certs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/certs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,kBAAkB,CAAC;AAGhE,eAAO,MAAM,WAAW,wbAQvB,CAAC;AAgFF,eAAO,MAAM,YAAY,EAAE,OAoB1B,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `zoomies certs <subcommand>` — issue / list cert rows.
|
|
3
|
+
*
|
|
4
|
+
* `issue` blocks until the ACME order completes (10–60 s in production
|
|
5
|
+
* against Let's Encrypt). The HTTP API does not yet expose a list-certs
|
|
6
|
+
* endpoint, so `list` is local-only for now.
|
|
7
|
+
*/
|
|
8
|
+
import { CliClientError } from '../client.js';
|
|
9
|
+
import { FlagParseError, parseFlags } from './flags.js';
|
|
10
|
+
export const CERTS_USAGE = `Usage: zoomies certs <subcommand> [args]
|
|
11
|
+
|
|
12
|
+
Subcommands:
|
|
13
|
+
issue --site-id <id> Issue (or re-issue) a Let's Encrypt cert for a site.
|
|
14
|
+
Blocks until the ACME order completes (10-60 seconds
|
|
15
|
+
against the production Let's Encrypt API).
|
|
16
|
+
Local mode requires ZOOMIES_ACME_EMAIL to be set.
|
|
17
|
+
list Tabular listing of all certs (local mode only).
|
|
18
|
+
`;
|
|
19
|
+
function shortId(id) {
|
|
20
|
+
return id.slice(0, 8);
|
|
21
|
+
}
|
|
22
|
+
function printUsage(ctx) {
|
|
23
|
+
ctx.stdout.write(CERTS_USAGE);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
function writeUsageErr(ctx, msg) {
|
|
27
|
+
ctx.stderr.write(`zoomies certs: ${msg}\n`);
|
|
28
|
+
ctx.stderr.write(CERTS_USAGE);
|
|
29
|
+
return 2;
|
|
30
|
+
}
|
|
31
|
+
function handleClientError(ctx, err) {
|
|
32
|
+
if (err instanceof CliClientError) {
|
|
33
|
+
ctx.stderr.write(`zoomies certs: ${err.message} (${err.code})\n`);
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
37
|
+
ctx.stderr.write(`zoomies certs: ${message}\n`);
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
async function runIssue(args, ctx) {
|
|
41
|
+
let parsed;
|
|
42
|
+
try {
|
|
43
|
+
parsed = parseFlags(args, { valueFlags: new Set(['site-id']) });
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
if (err instanceof FlagParseError) {
|
|
47
|
+
return writeUsageErr(ctx, err.message);
|
|
48
|
+
}
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
const siteId = parsed.flags['site-id'];
|
|
52
|
+
if (siteId === undefined) {
|
|
53
|
+
return writeUsageErr(ctx, 'issue requires --site-id <id>');
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const cert = await ctx.client.certs.issueForSite(siteId);
|
|
57
|
+
ctx.stdout.write(JSON.stringify(cert, null, 2) + '\n');
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
return handleClientError(ctx, err);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function runList(ctx) {
|
|
65
|
+
if (ctx.mode === 'http') {
|
|
66
|
+
ctx.stderr.write('zoomies certs: listing certs over HTTP is not yet supported; rerun with --local\n');
|
|
67
|
+
return 2;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const certs = await ctx.client.certs.list();
|
|
71
|
+
if (certs.length === 0) {
|
|
72
|
+
ctx.stdout.write('(no certs)\n');
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
const header = ['id', 'domain', 'provider', 'not_after'];
|
|
76
|
+
const rows = certs.map((c) => [shortId(c.id), c.domain, c.provider, c.notAfter]);
|
|
77
|
+
const widths = header.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)));
|
|
78
|
+
const fmt = (cols) => cols.map((c, i) => c.padEnd(widths[i] ?? 0)).join(' ');
|
|
79
|
+
ctx.stdout.write(fmt(header) + '\n');
|
|
80
|
+
for (const row of rows) {
|
|
81
|
+
ctx.stdout.write(fmt(row) + '\n');
|
|
82
|
+
}
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return handleClientError(ctx, err);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export const certsCommand = {
|
|
90
|
+
name: 'certs',
|
|
91
|
+
describe: 'Issue / list ACME certificates',
|
|
92
|
+
usage: CERTS_USAGE,
|
|
93
|
+
async run(args, ctx) {
|
|
94
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
95
|
+
return printUsage(ctx);
|
|
96
|
+
}
|
|
97
|
+
const [sub, ...rest] = args;
|
|
98
|
+
switch (sub) {
|
|
99
|
+
case undefined:
|
|
100
|
+
return printUsage(ctx);
|
|
101
|
+
case 'issue':
|
|
102
|
+
return runIssue(rest, ctx);
|
|
103
|
+
case 'list':
|
|
104
|
+
return runList(ctx);
|
|
105
|
+
default:
|
|
106
|
+
return writeUsageErr(ctx, `unknown subcommand '${sub}'`);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=certs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certs.js","sourceRoot":"","sources":["../../../src/cli/commands/certs.ts"],"names":[],"mappings":"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"}
|