@byok-sdk/server 0.11.0 → 0.13.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/dist/connections.d.ts +71 -0
- package/dist/device-selection.d.ts +30 -0
- package/dist/event-queue.d.ts +37 -2
- package/dist/index.d.ts +155 -88
- package/dist/index.js +1842 -3045
- package/dist/index.js.map +1 -1
- package/dist/rate-limiter.d.ts +38 -0
- package/dist/relay.d.ts +86 -0
- package/dist/snapshot.d.ts +64 -0
- package/dist/sqlite-support.d.ts +3 -3
- package/dist/stores/sqlite/__tests__/atomic-restart.test.d.ts +1 -0
- package/dist/stores/sqlite/__tests__/conformance.test.d.ts +1 -0
- package/dist/stores/sqlite/index.d.ts +140 -0
- package/dist/stores.d.ts +65 -0
- package/dist/task-handle.d.ts +61 -0
- package/dist/types.d.ts +167 -140
- package/package.json +6 -7
- package/dist/auth.d.ts +0 -218
- package/dist/blob-store.d.ts +0 -77
- package/dist/heartbeat.d.ts +0 -30
- package/dist/http.d.ts +0 -24
- package/dist/hub.d.ts +0 -931
- package/dist/ids.d.ts +0 -3
- package/dist/pairing.d.ts +0 -58
- package/dist/sqlite-blob-store.d.ts +0 -90
- package/dist/sqlite-task-store.d.ts +0 -124
- package/dist/task-store.d.ts +0 -127
- package/dist/ws-server.d.ts +0 -20
package/dist/auth.d.ts
DELETED
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth v2 (docs/protocol.md §6): device identity (Ed25519 keypair, public
|
|
3
|
-
* half registered at pairing time), single-use nonce challenge/response for
|
|
4
|
-
* token renewal, and JWT access tokens. Kept separate from `pairing.ts`
|
|
5
|
-
* (which now only owns the one-time pairing-code lifecycle) because these
|
|
6
|
-
* concerns span every authed surface (WSS upgrade, blob routes, events
|
|
7
|
-
* long-poll), not just `POST /byok/pair`.
|
|
8
|
-
*/
|
|
9
|
-
/** Access tokens are JWTs with a ~1h lifetime (docs/protocol.md §6.1/§6.2). */
|
|
10
|
-
export declare const ACCESS_TOKEN_TTL_SECONDS: number;
|
|
11
|
-
/**
|
|
12
|
-
* S1 (GAP-004): the domain-separation prefix a device signs along with a
|
|
13
|
-
* challenge nonce. The device key is a long-lived identity key that later
|
|
14
|
-
* planes (S6 device proof) will also sign structured messages with; without a
|
|
15
|
-
* domain tag, a signature produced for one purpose is a valid signature for
|
|
16
|
-
* another, and an attacker who can get a device to sign anything shaped like
|
|
17
|
-
* a nonce holds a token-renewal credential.
|
|
18
|
-
*
|
|
19
|
-
* The literal lives in `@byok-sdk/core` (`src/pairing.ts`) and the client signs
|
|
20
|
-
* the same binding (`packages/client/src/daemon/device-keys.ts`) — it used to
|
|
21
|
-
* be three copies, each commented as byte-identical to the other two, which is
|
|
22
|
-
* an agreement that holds only until someone edits one. Re-exported here so
|
|
23
|
-
* this module's public surface is unchanged.
|
|
24
|
-
*
|
|
25
|
-
* There is deliberately no dual mode: a raw, unprefixed nonce signature is
|
|
26
|
-
* simply invalid here, with no flag, fallback, or grace window that would
|
|
27
|
-
* make the old encoding acceptable again. Because the four packages have no
|
|
28
|
-
* published compatibility contract yet, the recovery path for a device on
|
|
29
|
-
* the old encoding is a re-pair, not a server-side shim.
|
|
30
|
-
*/
|
|
31
|
-
export { NONCE_SIGNING_DOMAIN } from '@byok-sdk/core';
|
|
32
|
-
/**
|
|
33
|
-
* S1: server-local tenant identifier. A plain string alias for now — S2 moves
|
|
34
|
-
* the branded/shared form into `@byok-sdk/core`, which does not exist yet, and
|
|
35
|
-
* depending on an unbuilt package would be worse than naming the concept
|
|
36
|
-
* here. What matters at this stage is that every identity-carrying shape in
|
|
37
|
-
* this package names the tenant explicitly and required, never optional.
|
|
38
|
-
*/
|
|
39
|
-
export type TenantId = string;
|
|
40
|
-
/**
|
|
41
|
-
* S1: an access token binds a device to the tenant AND product its row was
|
|
42
|
-
* paired into. All three are required — there is no tenant-less token shape.
|
|
43
|
-
* These are LOOKUP KEYS, not authority: `authenticateBearer` resolves them
|
|
44
|
-
* against the device registry and answers with the ROW's identity (see
|
|
45
|
-
* {@link AuthenticatedDevice}).
|
|
46
|
-
*/
|
|
47
|
-
export interface AccessTokenClaims {
|
|
48
|
-
deviceId: string;
|
|
49
|
-
tenantId: TenantId;
|
|
50
|
-
productId: string;
|
|
51
|
-
}
|
|
52
|
-
export interface TokenSigner {
|
|
53
|
-
sign(claims: AccessTokenClaims, expiresInSeconds: number): Promise<string>;
|
|
54
|
-
/** Returns the claims for a valid, unexpired token, or `undefined` if invalid/expired/malformed. */
|
|
55
|
-
verify(token: string): Promise<AccessTokenClaims | undefined>;
|
|
56
|
-
}
|
|
57
|
-
/** Default {@link TokenSigner}: HS256 over a random 32-byte secret held in memory for this process's lifetime. */
|
|
58
|
-
export declare function createHmacTokenSigner(secret?: Uint8Array): TokenSigner;
|
|
59
|
-
/** Mint a fresh access token + its ISO-8601 expiry, per {@link ACCESS_TOKEN_TTL_SECONDS}. */
|
|
60
|
-
export declare function mintAccessToken(signer: TokenSigner, claims: AccessTokenClaims): Promise<{
|
|
61
|
-
accessToken: string;
|
|
62
|
-
expiresAt: string;
|
|
63
|
-
}>;
|
|
64
|
-
export interface DeviceRecord {
|
|
65
|
-
/** S1: the tenant this device was paired into. Comes from the pairing-code claims and is never client-supplied. */
|
|
66
|
-
tenantId: TenantId;
|
|
67
|
-
/** S1: the product this device was paired into — checked against `conn.hello.productId` and against every token's claims. */
|
|
68
|
-
productId: string;
|
|
69
|
-
deviceId: string;
|
|
70
|
-
deviceName: string;
|
|
71
|
-
/** Ed25519 public key, base64url-encoded (JWK `x` form — see {@link verifyEd25519Signature}). */
|
|
72
|
-
devicePublicKey: string;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Everything `POST /byok/pair` knows at registration time — which is the whole
|
|
76
|
-
* row. Revocation DELETES the registration (§6.3), so there is no lifecycle
|
|
77
|
-
* flag for the registry to own on top of what pairing supplies.
|
|
78
|
-
*/
|
|
79
|
-
export type DeviceRegistration = DeviceRecord;
|
|
80
|
-
export declare class DeviceRegistry {
|
|
81
|
-
/** Keyed by {@link DeviceRegistry.key} — `(tenantId, deviceId)`. */
|
|
82
|
-
private readonly devices;
|
|
83
|
-
/**
|
|
84
|
-
* Secondary index over the SAME record objects, for the two pre-tenant
|
|
85
|
-
* endpoints only (see {@link resolveByDeviceId}). It holds the same record
|
|
86
|
-
* objects rather than copies, and {@link revoke} removes the entry here in
|
|
87
|
-
* the same call that removes the composite-key one — a stale entry left
|
|
88
|
-
* behind would be a deleted device that can still get a token.
|
|
89
|
-
*/
|
|
90
|
-
private readonly byDeviceId;
|
|
91
|
-
private static key;
|
|
92
|
-
/**
|
|
93
|
-
* Write a device row. Every identity field is required by
|
|
94
|
-
* {@link DeviceRegistration}, so a row with no tenant cannot be constructed
|
|
95
|
-
* — which is the whole point of S1.
|
|
96
|
-
*/
|
|
97
|
-
register(device: DeviceRegistration): void;
|
|
98
|
-
/** The row `tenantId` owns under `deviceId`, or `undefined` — including when the device exists under a DIFFERENT tenant. */
|
|
99
|
-
get(tenantId: TenantId, deviceId: string): DeviceRecord | undefined;
|
|
100
|
-
/**
|
|
101
|
-
* Revoke a device (public API via `createByokServer(...).devices.revoke`).
|
|
102
|
-
* Revocation DELETES the registration (docs/protocol.md §6.3): afterwards
|
|
103
|
-
* the device id is byte-for-byte one that was never registered — absent
|
|
104
|
-
* from {@link list}, resolving to nothing on the pre-tenant
|
|
105
|
-
* `/byok/challenge` and `/byok/token` paths, and a 401 on every authed
|
|
106
|
-
* surface. The daemon's only recourse is to re-run `/byok/pair`.
|
|
107
|
-
*
|
|
108
|
-
* There is deliberately no retained `revoked` row: a flag every read path
|
|
109
|
-
* has to remember to exclude is a second way to represent "not a
|
|
110
|
-
* principal", and the first read path that forgets it is a live credential.
|
|
111
|
-
*
|
|
112
|
-
* A tenant can only revoke its own devices: a (tenantId, deviceId) pair it
|
|
113
|
-
* does not own resolves to nothing, deletes nothing, and is silently
|
|
114
|
-
* indistinguishable from revoking one that never existed.
|
|
115
|
-
*
|
|
116
|
-
* Returns whether a row was actually removed — the composition in
|
|
117
|
-
* `index.ts` uses it to delete the device-scoped state that only existed to
|
|
118
|
-
* serve that row (nonces, presence, dedup), so a no-op revoke touches
|
|
119
|
-
* nothing at all.
|
|
120
|
-
*/
|
|
121
|
-
revoke(tenantId: TenantId, deviceId: string): boolean;
|
|
122
|
-
/** Every known device row, across tenants — the in-process read model behind `ByokServer.machines.list()`. */
|
|
123
|
-
list(): DeviceRecord[];
|
|
124
|
-
/**
|
|
125
|
-
* Resolve a device by its globally-unique id alone, WITHOUT a tenant in
|
|
126
|
-
* scope. Exists for exactly two callers — `POST /byok/challenge` and
|
|
127
|
-
* `POST /byok/token` — because those two carry no tenant at all: their
|
|
128
|
-
* request DTOs are the pinned wire contract (docs/protocol.md §6.2), the
|
|
129
|
-
* device authenticates by key possession, and the row itself is what tells
|
|
130
|
-
* the server which tenant to mint the next token for. Everything with a
|
|
131
|
-
* token (and therefore a tenant) in scope goes through {@link get}.
|
|
132
|
-
*
|
|
133
|
-
* Deliberately NOT re-exported from this package's entry point (`index.ts`
|
|
134
|
-
* exports no naked-lookup surface at all), so no embedder can turn it into
|
|
135
|
-
* a cross-tenant device oracle: the only reachable public device surface is
|
|
136
|
-
* tenant-first.
|
|
137
|
-
*/
|
|
138
|
-
resolveByDeviceId(deviceId: string): DeviceRecord | undefined;
|
|
139
|
-
}
|
|
140
|
-
export declare class NonceStore {
|
|
141
|
-
private readonly nonces;
|
|
142
|
-
/** Number of nonce records currently held (post-sweep). Exposed for tests only. */
|
|
143
|
-
get size(): number;
|
|
144
|
-
/**
|
|
145
|
-
* Drop every used or expired record. A long-lived server never calls this
|
|
146
|
-
* on a timer, so `issue()` sweeps inline — a full-Map scan is fine at
|
|
147
|
-
* reference-impl scale (single-digit nonces per device, ~5min TTL).
|
|
148
|
-
*/
|
|
149
|
-
private sweep;
|
|
150
|
-
issue(deviceId: string): string;
|
|
151
|
-
/** `true` iff `nonce` exists, belongs to `deviceId`, is unexpired, and hasn't been consumed yet. Does not mutate. */
|
|
152
|
-
validate(deviceId: string, nonce: string): boolean;
|
|
153
|
-
/**
|
|
154
|
-
* Drop every nonce outstanding for `deviceId` — called when the device's
|
|
155
|
-
* registration is deleted (§6.3 revocation). An unspent challenge is state
|
|
156
|
-
* that only existed to serve a row the directory can no longer name, so it
|
|
157
|
-
* goes with the row rather than sitting until its TTL sweeps it.
|
|
158
|
-
*/
|
|
159
|
-
deleteForDevice(deviceId: string): void;
|
|
160
|
-
/** Mark `nonce` consumed so a replay of the same (deviceId, nonce, signature) is rejected. */
|
|
161
|
-
markUsed(nonce: string): void;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* The ONLY nonce-signature check on this server (§6.2): the signed message is
|
|
165
|
-
* core's `nonceSigningBytes` — the domain followed by the nonce. Applying the
|
|
166
|
-
* domain here rather than at the call site is the point — there is one place
|
|
167
|
-
* that decides what a device signature over a nonce means, so no route can be
|
|
168
|
-
* written that accepts the undomained form.
|
|
169
|
-
*/
|
|
170
|
-
export declare function verifyNonceSignature(devicePublicKey: string, nonce: string, signature: string): boolean;
|
|
171
|
-
export declare function extractBearerToken(header: string | undefined): string | undefined;
|
|
172
|
-
export interface AuthDeps {
|
|
173
|
-
tokenSigner: TokenSigner;
|
|
174
|
-
devices: DeviceRegistry;
|
|
175
|
-
/**
|
|
176
|
-
* The product THIS server instance serves (`createByokServer`'s
|
|
177
|
-
* `productId`). Part of authentication, not of routing: a device row paired
|
|
178
|
-
* into another product is not a principal here at all — see
|
|
179
|
-
* {@link authenticateBearer}.
|
|
180
|
-
*/
|
|
181
|
-
productId: string;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* S1: the authenticated principal every authed surface works with. Built from
|
|
185
|
-
* the DEVICE ROW, never from the token payload — the token's claims are only
|
|
186
|
-
* the keys used to find that row (see {@link authenticateBearer}). A caller
|
|
187
|
-
* holding one of these is holding identity the registry vouched for.
|
|
188
|
-
*/
|
|
189
|
-
export interface AuthenticatedDevice {
|
|
190
|
-
deviceId: string;
|
|
191
|
-
tenantId: TenantId;
|
|
192
|
-
productId: string;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Resolve an `Authorization: Bearer <jwt>` header to an {@link AuthenticatedDevice},
|
|
196
|
-
* or `undefined` — the single check every authed HTTP route and the WSS
|
|
197
|
-
* upgrade share.
|
|
198
|
-
*
|
|
199
|
-
* S1 shape: the token's `(tenantId, deviceId)` are LOOKUP KEYS into the
|
|
200
|
-
* registry, and the row that comes back is the authority. A token for a
|
|
201
|
-
* device that no longer exists, one whose tenant does not own that device,
|
|
202
|
-
* one whose product disagrees with the row, and one whose row belongs to a
|
|
203
|
-
* different product than this instance serves all fail identically here and
|
|
204
|
-
* are indistinguishable to the caller — a revoked device is exactly the first
|
|
205
|
-
* of those, since revocation deleted its row (§6.3) — there
|
|
206
|
-
* is deliberately no "which of those was it" signal to hand back, so no route
|
|
207
|
-
* can turn a 401 into a cross-tenant (or cross-product) existence oracle.
|
|
208
|
-
*
|
|
209
|
-
* The last two checks are different facts and both are needed. Row vs claims
|
|
210
|
-
* says "the token belongs to this row"; row vs instance says "this row
|
|
211
|
-
* belongs to the product this server serves" — a single server can mint
|
|
212
|
-
* pairing codes for any product (`createPairingCode` takes the claims per
|
|
213
|
-
* code), so a row from another product is a real row holding a real token
|
|
214
|
-
* and is still not a principal here. `conn.hello`'s own product checks
|
|
215
|
-
* (`ws-server.ts`) validate the client's ANNOUNCEMENT, which is a third fact
|
|
216
|
-
* and stays where it is.
|
|
217
|
-
*/
|
|
218
|
-
export declare function authenticateBearer(header: string | undefined, deps: AuthDeps): Promise<AuthenticatedDevice | undefined>;
|
package/dist/blob-store.d.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Blob flows (docs/protocol.md §7): `POST /byok/blobs` declares a blob and
|
|
3
|
-
* gets back a presigned upload URL; the caller `PUT`s the bytes there
|
|
4
|
-
* directly (no bearer auth on that URL — the HMAC signature + expiry *is*
|
|
5
|
-
* the auth); `GET /byok/blobs/:id/url` mints a presigned download URL the
|
|
6
|
-
* same way. `BlobRef` itself (`@byok-sdk/protocol`'s `blob.ts`) is unchanged;
|
|
7
|
-
* this module is what produces the URLs a `BlobRef` points at.
|
|
8
|
-
*
|
|
9
|
-
* `BlobStore` is interface-shaped so a SaaS can swap in a real object-store
|
|
10
|
-
* (S3/GCS/R2 presigned URLs) later; {@link LocalDiskBlobStore} is the M1
|
|
11
|
-
* reference implementation (single-process, in-memory metadata + files on
|
|
12
|
-
* disk) — good enough for local dev and the SDK's own tests, not meant to
|
|
13
|
-
* survive a restart or run multi-process.
|
|
14
|
-
*/
|
|
15
|
-
export interface CreateUploadInput {
|
|
16
|
-
size: number;
|
|
17
|
-
contentType: string;
|
|
18
|
-
/** Content-addressed hash the server verifies the uploaded bytes against (§7). Reference impl assumes hex-encoded SHA-256. */
|
|
19
|
-
contentHash: string;
|
|
20
|
-
}
|
|
21
|
-
export type WriteContentResult = {
|
|
22
|
-
ok: true;
|
|
23
|
-
} | {
|
|
24
|
-
ok: false;
|
|
25
|
-
reason: string;
|
|
26
|
-
};
|
|
27
|
-
export interface ReadContentResult {
|
|
28
|
-
data: Buffer;
|
|
29
|
-
contentType: string;
|
|
30
|
-
}
|
|
31
|
-
export declare class BlobDeclarationConflictError extends Error {
|
|
32
|
-
constructor(blobId: string);
|
|
33
|
-
}
|
|
34
|
-
export interface BlobStore {
|
|
35
|
-
/** Declare a blob before upload; an explicit id makes the declaration idempotent across host restart. */
|
|
36
|
-
createUpload(input: CreateUploadInput, blobId?: string): Promise<{
|
|
37
|
-
blobId: string;
|
|
38
|
-
uploadUrl: string;
|
|
39
|
-
}>;
|
|
40
|
-
/** A presigned GET URL for a blob that has finished uploading, or `undefined` if unknown/not yet uploaded. */
|
|
41
|
-
getDownloadUrl(blobId: string): Promise<string | undefined>;
|
|
42
|
-
/** Whether `blobId` is known *and* has finished uploading. */
|
|
43
|
-
exists(blobId: string): Promise<boolean>;
|
|
44
|
-
/** Verify a presigned content URL's `sig`/`exp` query params for `action`. */
|
|
45
|
-
verifySignedUrl(blobId: string, action: 'put' | 'get', sig: string, exp: number): boolean;
|
|
46
|
-
/** Accept uploaded bytes; rejects (without storing) on size/hash mismatch against the `createUpload` declaration. */
|
|
47
|
-
writeContent(blobId: string, data: Buffer): Promise<WriteContentResult>;
|
|
48
|
-
/** Read back previously-uploaded bytes, or `undefined` if unknown/not yet uploaded. */
|
|
49
|
-
readContent(blobId: string): Promise<ReadContentResult | undefined>;
|
|
50
|
-
}
|
|
51
|
-
export interface LocalDiskBlobStoreOptions {
|
|
52
|
-
/** Directory blob content is written under. Defaults to a fresh OS temp dir. */
|
|
53
|
-
directory?: string;
|
|
54
|
-
/** How long a presigned upload/download URL stays valid, ms. Default 15 minutes. */
|
|
55
|
-
urlTtlMs?: number;
|
|
56
|
-
}
|
|
57
|
-
/** Local-disk reference {@link BlobStore}: in-memory metadata, content on disk, HMAC-signed expiring URLs. */
|
|
58
|
-
export declare class LocalDiskBlobStore implements BlobStore {
|
|
59
|
-
private readonly secret;
|
|
60
|
-
private readonly directory;
|
|
61
|
-
private readonly urlTtlMs;
|
|
62
|
-
private readonly blobs;
|
|
63
|
-
private readonly ready;
|
|
64
|
-
constructor(opts?: LocalDiskBlobStoreOptions);
|
|
65
|
-
createUpload(input: CreateUploadInput, requestedBlobId?: string): Promise<{
|
|
66
|
-
blobId: string;
|
|
67
|
-
uploadUrl: string;
|
|
68
|
-
}>;
|
|
69
|
-
getDownloadUrl(blobId: string): Promise<string | undefined>;
|
|
70
|
-
exists(blobId: string): Promise<boolean>;
|
|
71
|
-
verifySignedUrl(blobId: string, action: 'put' | 'get', sig: string, exp: number): boolean;
|
|
72
|
-
writeContent(blobId: string, data: Buffer): Promise<WriteContentResult>;
|
|
73
|
-
readContent(blobId: string): Promise<ReadContentResult | undefined>;
|
|
74
|
-
private pathFor;
|
|
75
|
-
private computeSig;
|
|
76
|
-
private signUrl;
|
|
77
|
-
}
|
package/dist/heartbeat.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WS-native ping/pong liveness check (pinned here per the M1-2 task brief,
|
|
3
|
-
* not in docs/protocol.md — this is a server implementation detail, not a
|
|
4
|
-
* wire message). The server pings every `intervalMs` (default 30s);
|
|
5
|
-
* `ws`'s WebSocket automatically replies to a protocol-level ping with a
|
|
6
|
-
* protocol-level pong on any spec-compliant peer, so a healthy connection
|
|
7
|
-
* just keeps ticking. After `maxMissedPongs` (default 2) consecutive
|
|
8
|
-
* unanswered pings, the connection is terminated.
|
|
9
|
-
*
|
|
10
|
-
* Deliberately decoupled from the real `ws` package's `WebSocket` type (only
|
|
11
|
-
* the four methods below are used) so the scheduling logic can be unit
|
|
12
|
-
* tested with a plain stub + fake timers instead of a real socket — a real
|
|
13
|
-
* peer auto-pongs, so there's no way to exercise "missed pong" through an
|
|
14
|
-
* actual WS round-trip in a test.
|
|
15
|
-
*/
|
|
16
|
-
export interface HeartbeatSocket {
|
|
17
|
-
ping(): void;
|
|
18
|
-
terminate(): void;
|
|
19
|
-
on(event: 'pong', listener: () => void): unknown;
|
|
20
|
-
off(event: 'pong', listener: () => void): unknown;
|
|
21
|
-
}
|
|
22
|
-
export interface HeartbeatOptions {
|
|
23
|
-
intervalMs?: number;
|
|
24
|
-
maxMissedPongs?: number;
|
|
25
|
-
}
|
|
26
|
-
export interface Heartbeat {
|
|
27
|
-
/** Stop the ping timer and detach the pong listener (e.g. on normal connection close). */
|
|
28
|
-
stop(): void;
|
|
29
|
-
}
|
|
30
|
-
export declare function startHeartbeat(ws: HeartbeatSocket, opts?: HeartbeatOptions): Heartbeat;
|
package/dist/http.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Hono } from 'hono';
|
|
2
|
-
import { type AuthDeps, type NonceStore } from './auth';
|
|
3
|
-
import { type BlobStore } from './blob-store';
|
|
4
|
-
import type { ConnectionHub } from './hub';
|
|
5
|
-
import { type PairingManager } from './pairing';
|
|
6
|
-
export interface HttpDeps extends AuthDeps {
|
|
7
|
-
pairing: PairingManager;
|
|
8
|
-
nonces: NonceStore;
|
|
9
|
-
blobStore: BlobStore;
|
|
10
|
-
hub: ConnectionHub;
|
|
11
|
-
/** Per-product blob size ceiling in bytes (§7). */
|
|
12
|
-
maxBlobSizeBytes: number;
|
|
13
|
-
/** How long `GET /byok/events` holds an empty poll open before returning, ms (§8). */
|
|
14
|
-
longPollHoldMs: number;
|
|
15
|
-
/** M4 Phase 4 (part B.2): opt-in `GET /healthz` liveness route — see `CreateByokServerOptions.healthzRoute`'s doc comment (`types.ts`) for the full contract. Default `false` (no route mounted). */
|
|
16
|
-
healthzRoute?: boolean;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* The HTTP half of the pinned wire contract: pairing, token renewal, blob
|
|
20
|
-
* flows, and the long-poll events fallback (docs/protocol.md §6-§8). WS
|
|
21
|
-
* upgrade handling lives in `ws-server.ts` (raw Node `http.Server` upgrade,
|
|
22
|
-
* not routable through Hono's fetch handler).
|
|
23
|
-
*/
|
|
24
|
-
export declare function buildHonoApp(deps: HttpDeps): Hono;
|