@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.
Files changed (160) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/cli/client.d.ts +77 -0
  4. package/dist/cli/client.d.ts.map +1 -0
  5. package/dist/cli/client.js +300 -0
  6. package/dist/cli/client.js.map +1 -0
  7. package/dist/cli/commands/certs.d.ts +11 -0
  8. package/dist/cli/commands/certs.d.ts.map +1 -0
  9. package/dist/cli/commands/certs.js +110 -0
  10. package/dist/cli/commands/certs.js.map +1 -0
  11. package/dist/cli/commands/flags.d.ts +29 -0
  12. package/dist/cli/commands/flags.d.ts.map +1 -0
  13. package/dist/cli/commands/flags.js +104 -0
  14. package/dist/cli/commands/flags.js.map +1 -0
  15. package/dist/cli/commands/reload.d.ts +11 -0
  16. package/dist/cli/commands/reload.d.ts.map +1 -0
  17. package/dist/cli/commands/reload.js +35 -0
  18. package/dist/cli/commands/reload.js.map +1 -0
  19. package/dist/cli/commands/sites.d.ts +11 -0
  20. package/dist/cli/commands/sites.d.ts.map +1 -0
  21. package/dist/cli/commands/sites.js +221 -0
  22. package/dist/cli/commands/sites.js.map +1 -0
  23. package/dist/cli/commands/status.d.ts +10 -0
  24. package/dist/cli/commands/status.d.ts.map +1 -0
  25. package/dist/cli/commands/status.js +41 -0
  26. package/dist/cli/commands/status.js.map +1 -0
  27. package/dist/cli/commands/upstreams.d.ts +21 -0
  28. package/dist/cli/commands/upstreams.d.ts.map +1 -0
  29. package/dist/cli/commands/upstreams.js +248 -0
  30. package/dist/cli/commands/upstreams.js.map +1 -0
  31. package/dist/cli/dispatcher.d.ts +45 -0
  32. package/dist/cli/dispatcher.d.ts.map +1 -0
  33. package/dist/cli/dispatcher.js +192 -0
  34. package/dist/cli/dispatcher.js.map +1 -0
  35. package/dist/index.d.ts +12 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +42 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/server/api/db-context.d.ts +50 -0
  40. package/dist/server/api/db-context.d.ts.map +1 -0
  41. package/dist/server/api/db-context.js +76 -0
  42. package/dist/server/api/db-context.js.map +1 -0
  43. package/dist/server/api/error-mapping.d.ts +19 -0
  44. package/dist/server/api/error-mapping.d.ts.map +1 -0
  45. package/dist/server/api/error-mapping.js +56 -0
  46. package/dist/server/api/error-mapping.js.map +1 -0
  47. package/dist/server/api/handlers/site-cert.d.ts +49 -0
  48. package/dist/server/api/handlers/site-cert.d.ts.map +1 -0
  49. package/dist/server/api/handlers/site-cert.js +54 -0
  50. package/dist/server/api/handlers/site-cert.js.map +1 -0
  51. package/dist/server/api/handlers/sites.d.ts +67 -0
  52. package/dist/server/api/handlers/sites.d.ts.map +1 -0
  53. package/dist/server/api/handlers/sites.js +78 -0
  54. package/dist/server/api/handlers/sites.js.map +1 -0
  55. package/dist/server/api/handlers/upstreams.d.ts +64 -0
  56. package/dist/server/api/handlers/upstreams.d.ts.map +1 -0
  57. package/dist/server/api/handlers/upstreams.js +97 -0
  58. package/dist/server/api/handlers/upstreams.js.map +1 -0
  59. package/dist/server/auth/require-token.d.ts +24 -0
  60. package/dist/server/auth/require-token.d.ts.map +1 -0
  61. package/dist/server/auth/require-token.js +98 -0
  62. package/dist/server/auth/require-token.js.map +1 -0
  63. package/dist/server/certs/acme-account.d.ts +37 -0
  64. package/dist/server/certs/acme-account.d.ts.map +1 -0
  65. package/dist/server/certs/acme-account.js +49 -0
  66. package/dist/server/certs/acme-account.js.map +1 -0
  67. package/dist/server/certs/challenge-store.d.ts +53 -0
  68. package/dist/server/certs/challenge-store.d.ts.map +1 -0
  69. package/dist/server/certs/challenge-store.js +66 -0
  70. package/dist/server/certs/challenge-store.js.map +1 -0
  71. package/dist/server/certs/issue.d.ts +106 -0
  72. package/dist/server/certs/issue.d.ts.map +1 -0
  73. package/dist/server/certs/issue.js +107 -0
  74. package/dist/server/certs/issue.js.map +1 -0
  75. package/dist/server/certs/renew.d.ts +34 -0
  76. package/dist/server/certs/renew.d.ts.map +1 -0
  77. package/dist/server/certs/renew.js +36 -0
  78. package/dist/server/certs/renew.js.map +1 -0
  79. package/dist/server/certs/scheduler.d.ts +68 -0
  80. package/dist/server/certs/scheduler.d.ts.map +1 -0
  81. package/dist/server/certs/scheduler.js +76 -0
  82. package/dist/server/certs/scheduler.js.map +1 -0
  83. package/dist/server/db/connection.d.ts +10 -0
  84. package/dist/server/db/connection.d.ts.map +1 -0
  85. package/dist/server/db/connection.js +16 -0
  86. package/dist/server/db/connection.js.map +1 -0
  87. package/dist/server/db/migrate.d.ts +12 -0
  88. package/dist/server/db/migrate.d.ts.map +1 -0
  89. package/dist/server/db/migrate.js +37 -0
  90. package/dist/server/db/migrate.js.map +1 -0
  91. package/dist/server/db/migrations/0001_init.sql +42 -0
  92. package/dist/server/domain/cert.d.ts +17 -0
  93. package/dist/server/domain/cert.d.ts.map +1 -0
  94. package/dist/server/domain/cert.js +22 -0
  95. package/dist/server/domain/cert.js.map +1 -0
  96. package/dist/server/domain/errors.d.ts +36 -0
  97. package/dist/server/domain/errors.d.ts.map +1 -0
  98. package/dist/server/domain/errors.js +37 -0
  99. package/dist/server/domain/errors.js.map +1 -0
  100. package/dist/server/domain/site.d.ts +15 -0
  101. package/dist/server/domain/site.d.ts.map +1 -0
  102. package/dist/server/domain/site.js +25 -0
  103. package/dist/server/domain/site.js.map +1 -0
  104. package/dist/server/domain/upstream.d.ts +25 -0
  105. package/dist/server/domain/upstream.d.ts.map +1 -0
  106. package/dist/server/domain/upstream.js +24 -0
  107. package/dist/server/domain/upstream.js.map +1 -0
  108. package/dist/server/index.d.ts +2 -0
  109. package/dist/server/index.d.ts.map +1 -0
  110. package/dist/server/index.js +4 -0
  111. package/dist/server/index.js.map +1 -0
  112. package/dist/server/reload/atomic-write.d.ts +44 -0
  113. package/dist/server/reload/atomic-write.d.ts.map +1 -0
  114. package/dist/server/reload/atomic-write.js +151 -0
  115. package/dist/server/reload/atomic-write.js.map +1 -0
  116. package/dist/server/reload/health-probe.d.ts +62 -0
  117. package/dist/server/reload/health-probe.d.ts.map +1 -0
  118. package/dist/server/reload/health-probe.js +105 -0
  119. package/dist/server/reload/health-probe.js.map +1 -0
  120. package/dist/server/reload/reload.d.ts +118 -0
  121. package/dist/server/reload/reload.d.ts.map +1 -0
  122. package/dist/server/reload/reload.js +232 -0
  123. package/dist/server/reload/reload.js.map +1 -0
  124. package/dist/server/renderer/render-bundle.d.ts +18 -0
  125. package/dist/server/renderer/render-bundle.d.ts.map +1 -0
  126. package/dist/server/renderer/render-bundle.js +32 -0
  127. package/dist/server/renderer/render-bundle.js.map +1 -0
  128. package/dist/server/renderer/render-site.d.ts +5 -0
  129. package/dist/server/renderer/render-site.d.ts.map +1 -0
  130. package/dist/server/renderer/render-site.js +144 -0
  131. package/dist/server/renderer/render-site.js.map +1 -0
  132. package/dist/server/repositories/cert-repository.d.ts +19 -0
  133. package/dist/server/repositories/cert-repository.d.ts.map +1 -0
  134. package/dist/server/repositories/cert-repository.js +112 -0
  135. package/dist/server/repositories/cert-repository.js.map +1 -0
  136. package/dist/server/repositories/site-repository.d.ts +17 -0
  137. package/dist/server/repositories/site-repository.d.ts.map +1 -0
  138. package/dist/server/repositories/site-repository.js +122 -0
  139. package/dist/server/repositories/site-repository.js.map +1 -0
  140. package/dist/server/repositories/upstream-repository.d.ts +22 -0
  141. package/dist/server/repositories/upstream-repository.d.ts.map +1 -0
  142. package/dist/server/repositories/upstream-repository.js +142 -0
  143. package/dist/server/repositories/upstream-repository.js.map +1 -0
  144. package/dist/server/validator/nginx-binary.d.ts +9 -0
  145. package/dist/server/validator/nginx-binary.d.ts.map +1 -0
  146. package/dist/server/validator/nginx-binary.js +11 -0
  147. package/dist/server/validator/nginx-binary.js.map +1 -0
  148. package/dist/server/validator/validate.d.ts +29 -0
  149. package/dist/server/validator/validate.d.ts.map +1 -0
  150. package/dist/server/validator/validate.js +69 -0
  151. package/dist/server/validator/validate.js.map +1 -0
  152. package/dist/server/worker/main.d.ts +43 -0
  153. package/dist/server/worker/main.d.ts.map +1 -0
  154. package/dist/server/worker/main.js +181 -0
  155. package/dist/server/worker/main.js.map +1 -0
  156. package/dist/version.d.ts +2 -0
  157. package/dist/version.d.ts.map +1 -0
  158. package/dist/version.js +2 -0
  159. package/dist/version.js.map +1 -0
  160. package/package.json +84 -0
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Long-running renewal worker entrypoint.
4
+ *
5
+ * `main()` runs an outer loop that calls {@link runRenewalCheck} every
6
+ * {@link WorkerOptions.intervalMs} (default 6 hours), resolves the production
7
+ * dependencies from the environment once on startup, and races the wait
8
+ * between iterations against a SIGTERM/SIGINT-driven abort promise so the
9
+ * worker shuts down promptly on signal.
10
+ *
11
+ * Shutdown semantics: we never interrupt a renewal mid-flight. The signal
12
+ * handlers flip a flag and resolve the abort promise — the loop reads it
13
+ * **after** the current `runRenewalCheck` returns, then exits cleanly. Let's
14
+ * Encrypt orders are stateful and a half-completed order tends to consume
15
+ * rate limit without producing a usable cert, so the cost of a clean wait
16
+ * is worth more than a few seconds of shutdown latency.
17
+ *
18
+ * Importable + runnable: the bottom of this file uses the same
19
+ * `import.meta.url === pathToFileURL(process.argv[1]).href` shim as
20
+ * `src/index.ts`, so it works both as `node dist/server/worker/main.js` and
21
+ * as an imported module from tests.
22
+ *
23
+ * The leading `#!/usr/bin/env node` shebang must stay on line 1 for the
24
+ * `zoomies-worker` bin entry to be directly executable; TypeScript happily
25
+ * carries the line through to the emitted JS as a comment-shaped no-op.
26
+ */
27
+ import { mkdir } from 'node:fs/promises';
28
+ import { resolve, join } from 'node:path';
29
+ import { pathToFileURL } from 'node:url';
30
+ import { getDb } from '../api/db-context.js';
31
+ import { CertRepository } from '../repositories/cert-repository.js';
32
+ import { loadOrCreateAccount } from '../certs/acme-account.js';
33
+ import { createChallengeStore } from '../certs/challenge-store.js';
34
+ import { renewCertificate } from '../certs/renew.js';
35
+ import { runRenewalCheck } from '../certs/scheduler.js';
36
+ const DEFAULT_INTERVAL_MS = 6 * 60 * 60 * 1000;
37
+ const DEFAULT_DIRECTORY_URL = 'https://acme-v02.api.letsencrypt.org/directory';
38
+ function readConfigFromEnv() {
39
+ const contactEmail = process.env.ZOOMIES_ACME_EMAIL;
40
+ if (contactEmail === undefined || contactEmail === '') {
41
+ throw new Error('ZOOMIES_ACME_EMAIL is required — set it to a contact email registered with the ACME directory');
42
+ }
43
+ const directoryUrl = process.env.ZOOMIES_ACME_DIRECTORY_URL ?? DEFAULT_DIRECTORY_URL;
44
+ const stateDir = process.env.ZOOMIES_STATE_DIR ?? join(process.cwd(), '.zoomies');
45
+ const certDir = process.env.ZOOMIES_CERT_DIR ?? join(stateDir, 'certs');
46
+ return { contactEmail, directoryUrl, stateDir, certDir };
47
+ }
48
+ /**
49
+ * Resolve a SIGTERM/SIGINT-driven abort promise. Returns an object the
50
+ * caller can `await` and an `attach` that wires the handlers so signal
51
+ * delivery resolves the promise.
52
+ *
53
+ * Calling `dispose()` removes the handlers; tests don't use this (smoke
54
+ * test runs with `once: true`) but the production loop does after exit.
55
+ */
56
+ function createAbortSignal() {
57
+ let resolveWait;
58
+ const wait = new Promise((r) => {
59
+ resolveWait = r;
60
+ });
61
+ const onSignal = (signal) => {
62
+ console.info(`zoomies: received ${signal}, shutting down after current renewal check`);
63
+ resolveWait();
64
+ };
65
+ const onTerm = () => onSignal('SIGTERM');
66
+ const onInt = () => onSignal('SIGINT');
67
+ process.once('SIGTERM', onTerm);
68
+ process.once('SIGINT', onInt);
69
+ return {
70
+ wait,
71
+ dispose: () => {
72
+ process.off('SIGTERM', onTerm);
73
+ process.off('SIGINT', onInt);
74
+ },
75
+ };
76
+ }
77
+ /**
78
+ * Wait for `ms` milliseconds OR for the abort promise to resolve, whichever
79
+ * happens first. The `setTimeout` is `unref`'d so it never holds the event
80
+ * loop open past a shutdown signal.
81
+ */
82
+ async function waitOrAbort(ms, abort) {
83
+ let timer;
84
+ const sleep = new Promise((resolveSleep) => {
85
+ timer = setTimeout(resolveSleep, ms);
86
+ timer.unref();
87
+ });
88
+ try {
89
+ await Promise.race([sleep, abort]);
90
+ }
91
+ finally {
92
+ if (timer !== undefined) {
93
+ clearTimeout(timer);
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Build a `renew(cert)` closure pre-bound to the production dependencies.
99
+ *
100
+ * The scheduler only knows about `Cert -> Promise<Cert>`, so the worker
101
+ * owns the responsibility of capturing the ACME account, challenge store,
102
+ * cert directory, and cert repository.
103
+ */
104
+ function bindRenew(args) {
105
+ return (cert) => renewCertificate({
106
+ cert,
107
+ certRepo: args.certRepo,
108
+ domain: cert.domain,
109
+ account: args.account,
110
+ challengeStore: args.challengeStore,
111
+ certDir: args.certDir,
112
+ });
113
+ }
114
+ /**
115
+ * Worker entrypoint. Resolves the production deps from the environment,
116
+ * then loops `runRenewalCheck` on the configured cadence until a shutdown
117
+ * signal is received (or `opts.once` is true).
118
+ */
119
+ export async function main(opts) {
120
+ const intervalMs = opts?.intervalMs ?? DEFAULT_INTERVAL_MS;
121
+ const once = opts?.once ?? false;
122
+ const config = readConfigFromEnv();
123
+ // Make sure the state, cert, and ACME challenge directories exist before
124
+ // any code reaches for them. `recursive: true` makes this idempotent.
125
+ await mkdir(config.certDir, { recursive: true });
126
+ const challengeStore = createChallengeStore({ stateDir: config.stateDir });
127
+ await mkdir(challengeStore.basePath, { recursive: true });
128
+ const account = await loadOrCreateAccount({
129
+ accountKeyPath: join(config.stateDir, 'acme-account.key'),
130
+ contactEmail: config.contactEmail,
131
+ directoryUrl: config.directoryUrl,
132
+ });
133
+ const certRepo = new CertRepository(getDb());
134
+ const renew = bindRenew({
135
+ account,
136
+ challengeStore,
137
+ certDir: config.certDir,
138
+ certRepo,
139
+ });
140
+ // TODO: signal handling smoke test — currently exercised manually with
141
+ // `kill -TERM <pid>`. Hard to automate without a child-process harness.
142
+ const abort = once ? null : createAbortSignal();
143
+ console.info('zoomies-worker: starting', {
144
+ directoryUrl: config.directoryUrl,
145
+ certDir: config.certDir,
146
+ intervalMs,
147
+ once,
148
+ });
149
+ try {
150
+ while (true) {
151
+ const result = await runRenewalCheck({ deps: { certRepo, renew } });
152
+ console.info('zoomies-worker: renewal check complete', result);
153
+ if (once || abort === null) {
154
+ return;
155
+ }
156
+ // Race the sleep against the abort promise. If a signal was already
157
+ // delivered while the renewal check was running, this resolves on the
158
+ // next microtask and the loop exits.
159
+ await waitOrAbort(intervalMs, abort.wait);
160
+ const aborted = await Promise.race([abort.wait.then(() => true), Promise.resolve(false)]);
161
+ if (aborted) {
162
+ return;
163
+ }
164
+ }
165
+ }
166
+ finally {
167
+ abort?.dispose();
168
+ }
169
+ }
170
+ // Entrypoint shim — mirrors src/index.ts so the patterns stay consistent.
171
+ // `pathToFileURL` normalises the argv path so Windows + POSIX both match.
172
+ const entryArg = process.argv[1];
173
+ const entryUrl = entryArg ? pathToFileURL(resolve(entryArg)).href : undefined;
174
+ const isEntrypoint = entryUrl !== undefined && import.meta.url === entryUrl;
175
+ if (isEntrypoint) {
176
+ main().catch((err) => {
177
+ console.error('zoomies-worker: fatal error', err);
178
+ process.exit(1);
179
+ });
180
+ }
181
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/server/worker/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const version = "0.0.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const version = '0.0.0';
2
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@yannelli/zoomies",
3
+ "version": "0.0.0",
4
+ "description": "Control plane for NGINX reverse proxy: config rendering, validation, and reload orchestration.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "zoomies": "dist/index.js",
9
+ "zoomies-worker": "dist/server/worker/main.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "dist/server/db/migrations/*.sql",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "packageManager": "pnpm@10.33.0",
21
+ "scripts": {
22
+ "dev": "next dev",
23
+ "build": "pnpm run build:web && pnpm run build:cli",
24
+ "build:web": "next build",
25
+ "build:cli": "tsc -p tsconfig.cli.json && node scripts/copy-migrations.mjs",
26
+ "start": "next start",
27
+ "cli": "tsx src/index.ts",
28
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.cli.json --noEmit",
29
+ "lint": "eslint .",
30
+ "format": "prettier --write .",
31
+ "format:check": "prettier --check .",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest"
34
+ },
35
+ "keywords": [
36
+ "nginx",
37
+ "reverse-proxy",
38
+ "proxy-manager",
39
+ "control-plane"
40
+ ],
41
+ "author": "Ryan Yannelli",
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/yannelli/zoomies.git"
46
+ },
47
+ "dependencies": {
48
+ "acme-client": "^5.4.0",
49
+ "better-sqlite3": "^12.10.0",
50
+ "class-variance-authority": "^0.7.1",
51
+ "clsx": "^2.1.1",
52
+ "execa": "^9.6.1",
53
+ "next": "^15.0.0",
54
+ "react": "^19.0.0",
55
+ "react-dom": "^19.0.0",
56
+ "tailwind-merge": "^2.5.5",
57
+ "zod": "^4.4.3"
58
+ },
59
+ "pnpm": {
60
+ "onlyBuiltDependencies": [
61
+ "better-sqlite3"
62
+ ]
63
+ },
64
+ "devDependencies": {
65
+ "@eslint/eslintrc": "^3.2.0",
66
+ "@eslint/js": "^9.18.0",
67
+ "@tailwindcss/postcss": "^4.0.0",
68
+ "@types/better-sqlite3": "^7.6.13",
69
+ "@types/node": "^22.10.5",
70
+ "@types/react": "^19.0.0",
71
+ "@types/react-dom": "^19.0.0",
72
+ "@typescript-eslint/eslint-plugin": "^8.20.0",
73
+ "@typescript-eslint/parser": "^8.20.0",
74
+ "eslint": "^9.18.0",
75
+ "eslint-config-next": "^15.0.0",
76
+ "postcss": "^8.4.49",
77
+ "prettier": "^3.4.2",
78
+ "tailwindcss": "^4.0.0",
79
+ "tsx": "^4.19.2",
80
+ "typescript": "^5.7.3",
81
+ "typescript-eslint": "^8.20.0",
82
+ "vitest": "^2.1.8"
83
+ }
84
+ }