@claxedo/workspace-relay 0.1.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/README.md +135 -0
- package/dist/auth.d.ts +107 -0
- package/dist/bun.d.ts +107 -0
- package/dist/directory.d.ts +55 -0
- package/dist/http.d.ts +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +1563 -0
- package/dist/main.d.ts +160 -0
- package/dist/main.mjs +1933 -0
- package/dist/server.d.ts +226 -0
- package/dist/synthetic.d.ts +60 -0
- package/package.json +36 -0
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { type WorkspaceRelayBunDrainController } from "./bun";
|
|
2
|
+
import { type WorkspaceRelayDirectory } from "./directory";
|
|
3
|
+
import type { RelayHostPublicKey, RuntimeAccessTokenActiveResult } from "./server";
|
|
4
|
+
import type { RelayKey } from "./auth";
|
|
5
|
+
/**
|
|
6
|
+
* Production fail-closed gate for the relay → claxedo-server resolver channel.
|
|
7
|
+
*
|
|
8
|
+
* If `CLAXEDO_RELAY_RESOLVER_TOKEN` is missing/empty in production the relay
|
|
9
|
+
* would otherwise call the resolver unauthenticated. Refuse to boot.
|
|
10
|
+
*
|
|
11
|
+
* Allowed in dev/test for ergonomics — the resolver itself falls back to a
|
|
12
|
+
* loopback-only check when no token is configured.
|
|
13
|
+
*/
|
|
14
|
+
export type ValidateProductionEnvInput = {
|
|
15
|
+
NODE_ENV?: string | undefined;
|
|
16
|
+
CLAXEDO_RELAY_RESOLVER_TOKEN?: string | undefined;
|
|
17
|
+
};
|
|
18
|
+
export type ValidateProductionEnvResult = {
|
|
19
|
+
ok: true;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
exitCode: 2;
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function validateProductionEnv(env: ValidateProductionEnvInput): ValidateProductionEnvResult;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the verification key (or keyset resolver) for Runtime Access Tokens.
|
|
28
|
+
*
|
|
29
|
+
* Precedence: `CLAXEDO_CONTROL_PLANE_JWKS_URL` > `CLAXEDO_RUNTIME_ACCESS_TOKEN_PUBLIC_KEY_PEM`.
|
|
30
|
+
* The PEM env var is kept as a fallback so JWKS rollouts can ship gradually.
|
|
31
|
+
*
|
|
32
|
+
* Exported for tests.
|
|
33
|
+
*/
|
|
34
|
+
export type LoadRuntimeAccessKeyEnv = {
|
|
35
|
+
CLAXEDO_CONTROL_PLANE_JWKS_URL?: string | undefined;
|
|
36
|
+
CLAXEDO_RUNTIME_ACCESS_TOKEN_PUBLIC_KEY_PEM?: string | undefined;
|
|
37
|
+
};
|
|
38
|
+
export declare function loadRuntimeAccessKeyOrJwks(env: LoadRuntimeAccessKeyEnv): Promise<RelayKey>;
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the RHT key material — both the private key used to sign RHTs and
|
|
41
|
+
* the public key(s) we publish at `/.well-known/jwks.json`.
|
|
42
|
+
*
|
|
43
|
+
* Precedence for the public counterpart:
|
|
44
|
+
* 1. `CLAXEDO_RELAY_HOST_PUBLIC_KEY_PEM` (explicit override; useful when
|
|
45
|
+
* the private key is held in an HSM-style import that strips public bits).
|
|
46
|
+
* 2. Derived from the private key via `exportJWK` (works because we now
|
|
47
|
+
* load the private key with `extractable: true`).
|
|
48
|
+
*
|
|
49
|
+
* `kid` is the explicit `CLAXEDO_RELAY_HOST_KID` env var if set, otherwise
|
|
50
|
+
* SHA-256(public-key-x).slice(0, 16). Mint and JWKS use the same derivation
|
|
51
|
+
* so they always agree.
|
|
52
|
+
*
|
|
53
|
+
* `next` is optional and is included in JWKS only — never used to mint. It
|
|
54
|
+
* exists to support rolling rotation: publish the next key, drain the
|
|
55
|
+
* current one, swap signing key, retire the old.
|
|
56
|
+
*
|
|
57
|
+
* Exported for tests.
|
|
58
|
+
*/
|
|
59
|
+
export type LoadRelayHostKeyMaterialEnv = {
|
|
60
|
+
/**
|
|
61
|
+
* Used to gate the production fail-closed check for the RHT signing key.
|
|
62
|
+
* If `production` and no signing key PEM is configured, the loader exits
|
|
63
|
+
* with code 2 rather than silently generating an ephemeral key (which
|
|
64
|
+
* would be different on every instance and break verification across a
|
|
65
|
+
* multi-instance deploy).
|
|
66
|
+
*
|
|
67
|
+
* Note: T2's `validateProductionEnv` is the canonical home for top-level
|
|
68
|
+
* env validation, but this check lives here because the loader already
|
|
69
|
+
* inspects the signing-key env var and the failure mode is local. The
|
|
70
|
+
* boot path could optionally re-route through `validateProductionEnv` in
|
|
71
|
+
* a future refactor.
|
|
72
|
+
*/
|
|
73
|
+
NODE_ENV?: string | undefined;
|
|
74
|
+
CLAXEDO_RELAY_HOST_SIGNING_KEY_PEM?: string | undefined;
|
|
75
|
+
CLAXEDO_RELAY_HOST_PUBLIC_KEY_PEM?: string | undefined;
|
|
76
|
+
CLAXEDO_RELAY_HOST_NEXT_PUBLIC_KEY_PEM?: string | undefined;
|
|
77
|
+
CLAXEDO_RELAY_HOST_KID?: string | undefined;
|
|
78
|
+
CLAXEDO_RELAY_HOST_NEXT_KID?: string | undefined;
|
|
79
|
+
};
|
|
80
|
+
export type RelayHostKeyMaterial = {
|
|
81
|
+
privateKey: CryptoKey;
|
|
82
|
+
current: RelayHostPublicKey;
|
|
83
|
+
next?: RelayHostPublicKey;
|
|
84
|
+
};
|
|
85
|
+
export declare function loadRelayHostKeyMaterial(env: LoadRelayHostKeyMaterialEnv): Promise<RelayHostKeyMaterial>;
|
|
86
|
+
/**
|
|
87
|
+
* T16: parse `CLAXEDO_RELAY_AUDIT_ACCEPT_SAMPLE_RATE` into a number in [0, 1].
|
|
88
|
+
* Falls back to a NODE_ENV-gated default (production: 0.1, dev/test: 1.0) if
|
|
89
|
+
* unset, empty, or out of range. Exported for tests.
|
|
90
|
+
*/
|
|
91
|
+
export type ParseAuditAcceptSampleRateEnv = {
|
|
92
|
+
CLAXEDO_RELAY_AUDIT_ACCEPT_SAMPLE_RATE?: string | undefined;
|
|
93
|
+
NODE_ENV?: string | undefined;
|
|
94
|
+
};
|
|
95
|
+
export declare function parseAuditAcceptSampleRate(env: ParseAuditAcceptSampleRateEnv): number;
|
|
96
|
+
/**
|
|
97
|
+
* T31: parse the `CLAXEDO_RELAY_METRICS_TOKEN` env var. Returns `undefined`
|
|
98
|
+
* for missing/empty/whitespace-only values so the relay can fall back to its
|
|
99
|
+
* loopback-only `/metrics` access policy.
|
|
100
|
+
*/
|
|
101
|
+
export type ParseMetricsTokenEnv = {
|
|
102
|
+
CLAXEDO_RELAY_METRICS_TOKEN?: string | undefined;
|
|
103
|
+
};
|
|
104
|
+
export declare function parseMetricsToken(env: ParseMetricsTokenEnv): string | undefined;
|
|
105
|
+
export type RevocationLookupArgs = {
|
|
106
|
+
jti: string;
|
|
107
|
+
workspaceId: string;
|
|
108
|
+
hostId: string;
|
|
109
|
+
};
|
|
110
|
+
export type RevocationLookup = (args: RevocationLookupArgs) => Promise<RuntimeAccessTokenActiveResult>;
|
|
111
|
+
export type CachedRevocationOptions = {
|
|
112
|
+
/** TTL in milliseconds for cached revocation responses. Defaults to 10_000. */
|
|
113
|
+
ttlMs?: number;
|
|
114
|
+
/** Clock injection for tests. Defaults to `Date.now`. */
|
|
115
|
+
now?: () => number;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Wraps a revocation lookup with a small in-memory cache keyed by `jti`.
|
|
119
|
+
* Both positive and negative results are cached for the full TTL — this is
|
|
120
|
+
* safe because RAT revocation lag is bounded by the same TTL by design.
|
|
121
|
+
*/
|
|
122
|
+
export declare function createCachedRevocationClient(inner: RevocationLookup, options?: CachedRevocationOptions): RevocationLookup;
|
|
123
|
+
/**
|
|
124
|
+
* T9: graceful SIGTERM drain wiring.
|
|
125
|
+
*
|
|
126
|
+
* On `SIGTERM` (or `SIGINT` for local dev) the relay must:
|
|
127
|
+
* 1. Flip the drain flag so `/health` reports 503 and Fly removes the
|
|
128
|
+
* machine from routing, and so new HTTP requests + tunnel registrations
|
|
129
|
+
* fast-path to 503 before doing any auth or upstream work.
|
|
130
|
+
* 2. Wait up to `drainTimeoutMs` (default 30 s, override via
|
|
131
|
+
* `CLAXEDO_RELAY_DRAIN_TIMEOUT_MS`) for the in-flight tunnel HTTP
|
|
132
|
+
* response map to empty across every connected host tunnel.
|
|
133
|
+
* 3. Release the directory's TTL sweep timer (T18 added `dispose()`) so
|
|
134
|
+
* the process can exit cleanly without a dangling `setInterval`.
|
|
135
|
+
* 4. Exit with code 0.
|
|
136
|
+
*
|
|
137
|
+
* Exposed for tests so the trigger logic can be exercised without actually
|
|
138
|
+
* raising signals or stopping the process. Pass `register: false` in tests
|
|
139
|
+
* to skip the real `process.on(...)` registration.
|
|
140
|
+
*/
|
|
141
|
+
export type ShutdownDrainHandlerOptions = {
|
|
142
|
+
drain: WorkspaceRelayBunDrainController;
|
|
143
|
+
directory: Pick<WorkspaceRelayDirectory, "dispose">;
|
|
144
|
+
drainTimeoutMs: number;
|
|
145
|
+
/** Defaults to `process.exit`. Override for tests. */
|
|
146
|
+
exit?: (code?: number) => void;
|
|
147
|
+
/** Defaults to a no-op log. */
|
|
148
|
+
log?: (message: string) => void;
|
|
149
|
+
/** When true (default), register `SIGTERM` and `SIGINT` handlers on `process`. */
|
|
150
|
+
register?: boolean;
|
|
151
|
+
/** Signals to listen for. Defaults to `["SIGTERM", "SIGINT"]`. */
|
|
152
|
+
signals?: NodeJS.Signals[];
|
|
153
|
+
/** Defaults to a no-op (we let Bun.serve get GC'd as part of process exit). */
|
|
154
|
+
stopServer?: () => Promise<void> | void;
|
|
155
|
+
};
|
|
156
|
+
export type ShutdownDrainHandle = {
|
|
157
|
+
trigger(): Promise<void>;
|
|
158
|
+
isShuttingDown(): boolean;
|
|
159
|
+
};
|
|
160
|
+
export declare function installShutdownDrainHandler(options: ShutdownDrainHandlerOptions): ShutdownDrainHandle;
|