@qilin-agent/client-connection 0.0.0-stage → 3.1.3

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.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The /api URL prefix — single source for both halves of the web transport.
3
+ * The node half registers this prefix on the web server.
4
+ */
5
+ /** Route prefix owning every api request (`/api` and `/api/<anything>`). */
6
+ export declare const API_PATH = "/api";
7
+ //# sourceMappingURL=api-path.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Browser-trust fence for every /api request. Defends the two confused-deputy
3
+ * paths a browser opens against a local HTTP API — DNS rebinding (Host names
4
+ * the attacker's domain while the socket reaches this server) and cross-site
5
+ * requests fired from a malicious page. The Host fence binds every request,
6
+ * browser-looking or not: over plain HTTP a browser attaches neither Origin
7
+ * nor Fetch-Metadata to reads (images and navigations — those
8
+ * headers go only to trustworthy destinations), so an unmarked request may
9
+ * still be a rebound browser read and Host is the one header rebinding cannot
10
+ * forge. Non-browser and remote clients pass the same fence via loopback,
11
+ * deployment-derived LAN IP literals, or a declared `trustedHosts` authority.
12
+ * Network reachability and authentication stay out of scope: binding policy
13
+ * belongs to the webserver config, and this fence is not an auth layer.
14
+ */
15
+ import type { ConnectionTrustRequest } from './rpc.ts';
16
+ /**
17
+ * Assert one configured `trustedHosts` entry is a bare authority (`host` or
18
+ * `host:port`) in canonical form: it must survive WHATWG parsing unchanged
19
+ * (case aside). Anything parsing would silently rewrite is refused as a typo
20
+ * that must fail the load loudly instead of being ignored until requests 403
21
+ * or quietly changing the grant: URL parts beyond the authority
22
+ * (`harness.internal/path`, `user@harness.internal` — which would authorize
23
+ * the embedded hostname), stripped whitespace, a dangling colon or
24
+ * zero-padded port (which would broaden an intended exact-port grant to every
25
+ * port), and non-canonical host spellings (`0x7f.0.0.1`, percent-encoding,
26
+ * unbracketed IPv6; IDN hosts are declared in punycode, the form the wire
27
+ * carries).
28
+ * @param entry - the configured value, verbatim.
29
+ */
30
+ export declare function assertTrustedAuthority(entry: string): void;
31
+ /**
32
+ * Decide whether one /api request may reach the RPC bridge.
33
+ * @param request - Node HTTP or Fetch request facts (headers).
34
+ * @param trustedHosts - non-loopback authorities this deployment serves: exact `host:port`, or port-less `host` matching any port.
35
+ * @returns true when the Host is ours (loopback or trusted) and any attached browser markers are same-origin.
36
+ */
37
+ export declare function isTrustedApiRequest(request: ConnectionTrustRequest, trustedHosts: readonly string[]): boolean;
38
+ //# sourceMappingURL=api-request-trust.d.ts.map
@@ -0,0 +1,68 @@
1
+ /** Browser-session authentication for the Host Connection carrier. */
2
+ import type { CredentialProvider } from '@qilin-agent/credentials';
3
+ import type { ConnectionIndexRequest, ConnectionIndexResponse, ConnectionTrustRequest } from './rpc.ts';
4
+ /**
5
+ * Process launch-token exchange and persistent signed-cookie verification.
6
+ * Connection loads the credential provider's signing secret during activation
7
+ * and retains it for synchronous request authentication.
8
+ */
9
+ export declare class BrowserAuth {
10
+ private readonly secret;
11
+ private readonly launchToken;
12
+ private readonly maxAgeMilliseconds;
13
+ private constructor();
14
+ /**
15
+ * Initialize browser authentication and create its durable signing secret
16
+ * when this Harness home has none.
17
+ * @param processOwner - root application context retaining one token across Connection reloads.
18
+ * @param credentials - persistent credential provider for the Web profile.
19
+ * @param maxAgeDays - positive absolute browser-cookie lifetime in days.
20
+ * @returns initialized authentication owner with the process owner's launch token.
21
+ */
22
+ static create(processOwner: object, credentials: CredentialProvider, maxAgeDays: number): Promise<BrowserAuth>;
23
+ /**
24
+ * Add this process's launch token to the ordinary application root URL.
25
+ * @param baseUrl - canonical browser origin without credentials.
26
+ * @param displayName - optional operator name the exchange carries into the device cookie for display.
27
+ * @returns root URL carrying the process token as its sole authentication input.
28
+ */
29
+ authenticatedUrl(baseUrl: string, displayName?: string): string;
30
+ /**
31
+ * Authenticate an index request. A valid entry-path query token mints the
32
+ * device cookie and redirects to the clean entry path; a valid cookie lets
33
+ * the caller serve the index; every other request receives the same minimal
34
+ * 401 response.
35
+ * @param req - incoming entry or configured-index request.
36
+ * @param res - response owned when this method returns false.
37
+ * @returns true only when the caller may serve index.html.
38
+ */
39
+ authorizeIndex(req: ConnectionIndexRequest, res: ConnectionIndexResponse): boolean;
40
+ /**
41
+ * Mint the device cookie for one valid launch token and redirect to the clean
42
+ * entry path: the handoff that turns the printed URL into a browser session.
43
+ * @param req - incoming request; its only token input is the query.
44
+ * @param res - response owned when the exchange applies.
45
+ * @returns true when a valid token was exchanged and the redirect written.
46
+ */
47
+ exchangeToken(req: ConnectionIndexRequest, res: ConnectionIndexResponse): boolean;
48
+ /**
49
+ * Verify the authority-bound browser cookie on a Host request.
50
+ * @param request - request headers carrying Host and Cookie.
51
+ * @returns true only for an unexpired cookie signed by this activation's loaded secret.
52
+ */
53
+ isAuthenticated(request: ConnectionTrustRequest): boolean;
54
+ /**
55
+ * Read the device session behind a Host request: its authentication fact and
56
+ * the operator display name the launching host attached, if any. This is the
57
+ * identity channel for deployments without the account gate, and the gate's
58
+ * own status route stays authoritative wherever that is mounted.
59
+ * @param request - request headers carrying Host and Cookie.
60
+ * @returns the session fact and display name of the request's device session.
61
+ */
62
+ identity(request: ConnectionTrustRequest): {
63
+ readonly authenticated: boolean;
64
+ readonly accountName: string | null;
65
+ };
66
+ private writeUnauthorized;
67
+ }
68
+ //# sourceMappingURL=browser-auth.d.ts.map
@@ -0,0 +1,14 @@
1
+ /** Browser-safe Connection protocol and shared application value exports. */
2
+ export type { ClientRequest, RpcMessage, RpcRequest, RpcResponse, RpcResult, ServerResponse, } from '../rpc.ts';
3
+ export { RpcId, transportError } from '../rpc.ts';
4
+ export type { SessionId, SessionEvent } from '@qilin-agent/session/types';
5
+ export type { MessageId } from '@qilin-agent/llm/brand';
6
+ export type { ContentBlock, StreamChunk } from '@qilin-agent/llm/types';
7
+ import type { RpcResponse, RpcResult } from '../rpc.ts';
8
+ /**
9
+ * Return the business result carried by an RPC response.
10
+ * @param response - RPC response to unwrap.
11
+ * @returns the response's business result.
12
+ */
13
+ export declare function resultOf<T>(response: RpcResponse<T>): RpcResult<T>;
14
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1,80 @@
1
+ /** Connection generation readiness, cancellation, and continuous recovery. */
2
+ import { type ConnectionRecoveryConfig } from '../recovery-config.ts';
3
+ export type { ConnectionRecoveryConfig } from '../recovery-config.ts';
4
+ /** Stable Host facts delivered by one established Remote event generation. */
5
+ export interface ConnectionHostInfo {
6
+ /** Host account home used only to abbreviate displayed filesystem paths. */
7
+ readonly home: string;
8
+ }
9
+ /** One successfully established Host generation. */
10
+ export interface ConnectionGeneration {
11
+ /** Monotone generation number within this Client runtime. */
12
+ readonly id: number;
13
+ /** Host facts carried by this generation's opening frame. */
14
+ readonly host: ConnectionHostInfo;
15
+ }
16
+ /** Connection lifecycle state published after the first attempt has an outcome. */
17
+ export type ConnectionState = 'connected' | 'disconnected' | 'connecting';
18
+ /** Connection-generation callbacks owned by API Gateway. */
19
+ export interface ConnectionSinks {
20
+ /** After the generation source reports ready, first connect included. */
21
+ onConnected?: (host: ConnectionHostInfo) => void;
22
+ /** State transitions after the initial attempt has an outcome. Equivalent states are deduplicated. */
23
+ onStateChange?: (state: ConnectionState) => void;
24
+ /** Start one fresh physical-carrier attempt before each logical retry. */
25
+ onReconnectRequested?: () => void;
26
+ }
27
+ /**
28
+ * One long-lived source defining a Connection generation. The source must
29
+ * attach its incremental listeners before calling `ready`, then remain pending
30
+ * until the generation is lost or `signal` aborts. On abort it must stop
31
+ * delivery, release its resources, and settle before a replacement can start.
32
+ * @param signal - cancellation for the current generation.
33
+ * @param ready - one-shot report that incremental delivery is attached.
34
+ * @returns a promise settling only when this generation ends or fails.
35
+ */
36
+ export type ConnectionGenerationSource = (signal: AbortSignal, ready: (host: ConnectionHostInfo) => void) => Promise<void>;
37
+ /**
38
+ * Opens the registered generation source, reconnecting with exponential backoff on loss.
39
+ * State (generation/attempt) is instance-private, never in the store.
40
+ * Sink exceptions do not kill the generation loop.
41
+ */
42
+ export declare class ConnectionController {
43
+ private readonly source;
44
+ private readonly sinks;
45
+ private generation;
46
+ private attempt;
47
+ private current;
48
+ private retryDelay;
49
+ private running;
50
+ private immediateRetry;
51
+ private networkAvailable;
52
+ private lastState;
53
+ private readonly config;
54
+ constructor(source: ConnectionGenerationSource, sinks?: ConnectionSinks, config?: ConnectionRecoveryConfig);
55
+ /** Idempotent: begin the connect/pump/reconnect loop. */
56
+ start(): void;
57
+ /** Stop the loop and abort the current generation source. */
58
+ stop(): void;
59
+ /** Reset the retry sequence and replace the current generation or retry delay immediately. */
60
+ reconnect(): void;
61
+ /**
62
+ * Suspend automatic retries while offline and restart backoff when the network returns.
63
+ * @param available - whether the browser reports network access.
64
+ */
65
+ setNetworkAvailable(available: boolean): void;
66
+ private backoffCap;
67
+ private backoffDelay;
68
+ /** Re-read retry inputs after a potentially reentrant state sink. */
69
+ private isRetryInterrupted;
70
+ /** Read through a method: stop() flips the flag across awaits, so narrowing from the loop condition must not stick. */
71
+ private isRunning;
72
+ /** Re-read both mutable liveness guards after a potentially reentrant sink. */
73
+ private isGenerationActive;
74
+ private loop;
75
+ /** Deduplicated state emission (sink isolation applies). */
76
+ private emitState;
77
+ /** Sink exception isolation: a business-layer throw is logged only, never affecting pump or reconnect semantics. */
78
+ private callSink;
79
+ }
80
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1,136 @@
1
+ /** Browser wire client: Remote transport and connection generations. */
2
+ import type { Context } from '@qilin-agent/kylin';
3
+ import { type ConnectionRecoveryConfig, type ConnectionGeneration, type ConnectionGenerationSource, type ConnectionSinks, type ConnectionState } from './connection.ts';
4
+ import { type RpcFetch, type RpcStreamOpen } from './rpc.ts';
5
+ import type { ClientConnectionRpc } from '../rpc.ts';
6
+ declare module '@qilin-agent/kylin' {
7
+ interface Events {
8
+ /**
9
+ * A connection generation was established. Wire-derived caches must
10
+ * repull; long-lived streams own their own resume and baseline lifecycle.
11
+ * @mode emit
12
+ */
13
+ 'connection/reset'(): void;
14
+ }
15
+ }
16
+ export type { MessageId, RpcRequest, RpcResponse, RpcResult, ClientRequest, ServerResponse, RpcMessage, SessionId, SessionEvent, ContentBlock, StreamChunk, } from './api.ts';
17
+ export { RpcId, transportError, } from './api.ts';
18
+ export type { ConnectionRecoveryConfig, ConnectionGeneration, ConnectionGenerationSource, ConnectionHostInfo, ConnectionSinks, ConnectionState, } from './connection.ts';
19
+ export type { ClientConnectionRpc, ConnectionRpcFailure, ConnectionRpcResult, } from '../rpc.ts';
20
+ export type { RpcFetch } from './rpc.ts';
21
+ /** Observable identity and Host facts for the active connection generation. */
22
+ export interface ConnectionGenerationState {
23
+ /** Active generation, or undefined before readiness and while reconnecting. */
24
+ getSnapshot(): ConnectionGeneration | undefined;
25
+ /** Subscribe to generation establishment, replacement, and loss. */
26
+ subscribe(listener: () => void): () => void;
27
+ }
28
+ /** Observable recovery lifecycle of the owned Connection loop. */
29
+ export interface ConnectionStateSource {
30
+ /** Current state, or undefined before the first connection outcome. */
31
+ getSnapshot(): ConnectionState | undefined;
32
+ /** Subscribe to state changes. */
33
+ subscribe(listener: () => void): () => void;
34
+ }
35
+ /** Required services (none — this is the wire root). */
36
+ export declare const inject: string[];
37
+ /**
38
+ * Physical carrier selected when the Connection service is installed. The
39
+ * served web app omits it and gets HTTP + WebSocket; a shell that owns a
40
+ * different transport (the worker preview's postMessage tunnel) provides both
41
+ * halves instead of forking this plugin.
42
+ */
43
+ export interface ClientTransportHooks {
44
+ /**
45
+ * Already decoded logical RPC carrier. When present it replaces the HTTP
46
+ * caller outright: no envelopes, no `fetch`, no `openStream` (an in-process
47
+ * Host such as a test mock plugs in here).
48
+ */
49
+ rpc?: ClientConnectionRpc;
50
+ /** Transport for generic unary RPC channels (the Typert gateway); unused when `rpc` is present. */
51
+ fetch?: RpcFetch;
52
+ /** Worker-local Gateway stream carrier; absent when the page uses the Gateway WebSocket or `rpc` is present. */
53
+ openStream?: RpcStreamOpen;
54
+ /**
55
+ * Bundle transport for the module system, present when the carrier also owns
56
+ * bundle bytes (the worker tunnel). Absent in the served web app, whose
57
+ * bundles load over HTTP.
58
+ */
59
+ loadBundle?(url: string): Promise<void>;
60
+ /**
61
+ * The transport owner declares the page owns the Host outright: the Host
62
+ * runs inside a worker this page spawned, so no other party can reach it and
63
+ * the loopback stand-in for "the operator's own machine" is vacuous.
64
+ * `ctx.connection.isLoopback` then reports the privileged surface reachable
65
+ * regardless of the page authority. Only a shell that assembles its own
66
+ * transport can set this; served pages never carry the global at all.
67
+ */
68
+ ownsHost?: boolean;
69
+ /** HTTP origin of a shell-owned Host when its WebSocket uses a different page origin. */
70
+ streamBaseUrl?: string;
71
+ }
72
+ /** Browser location fields used to classify loopback authority. */
73
+ export interface ConnectionLocation {
74
+ readonly hostname: string;
75
+ }
76
+ /** Instance-local inputs for installing a Connection service. */
77
+ export interface ConnectionInstallOptions {
78
+ /** Explicit physical carrier; omit for the browser HTTP + WebSocket carrier. */
79
+ readonly transport?: ClientTransportHooks;
80
+ /** Reconnect timing overrides; omitted fields use controller defaults. */
81
+ readonly recovery?: ConnectionRecoveryConfig;
82
+ /** Page location; omit for a non-browser composition. */
83
+ readonly location?: ConnectionLocation;
84
+ }
85
+ /**
86
+ * The ctx.connection service API. API Gateway supplies generation readiness
87
+ * and reset callbacks; Connection stays independent of downstream domain state.
88
+ */
89
+ export interface ConnectionHandle {
90
+ /**
91
+ * Whether the privileged surface is reachable: the page authority is
92
+ * loopback, the transport declares the page owns the Host
93
+ * ({@link ClientTransportHooks.ownsHost}), or the context is not a browser.
94
+ */
95
+ readonly isLoopback: boolean;
96
+ /** Current Remote event generation and the Host facts carried by its opening frame. */
97
+ readonly generation: ConnectionGenerationState;
98
+ /** Current recovery lifecycle for connection-specific consumers. */
99
+ readonly state: ConnectionStateSource;
100
+ /** Generic logical RPC channels over the same Connection transport. */
101
+ readonly rpc: ClientConnectionRpc;
102
+ /** Reset retry progression and replace the current attempt immediately. */
103
+ reconnect(): void;
104
+ /**
105
+ * Register the sole source defining Host generations. The source reports
106
+ * ready only after its incremental listeners are attached.
107
+ * @param source - long-lived generation source owned by the push carrier.
108
+ * @returns disposer withdrawing the source and stopping an active loop.
109
+ */
110
+ registerGenerationSource(source: ConnectionGenerationSource): () => void;
111
+ /**
112
+ * Start the connect/reconnect loop with the consumer's state callbacks.
113
+ * API Gateway owns the loop; a second call throws.
114
+ * @param sinks - connection-state callbacks.
115
+ * @param config - explicit timing overrides; omitted fields use Host bootstrap timing.
116
+ * @returns lifecycle controls for the loop.
117
+ */
118
+ start(sinks: ConnectionSinks, config?: ConnectionRecoveryConfig): ConnectionLoop;
119
+ }
120
+ /** Controls retained by the sole owner of a running connection loop. */
121
+ export interface ConnectionLoop {
122
+ /** Stop the loop and withdraw its active generation. */
123
+ stop(): void;
124
+ }
125
+ /**
126
+ * Install one Context-owned Connection service from explicit composition inputs.
127
+ * @param ctx - client Cordis context.
128
+ * @param options - physical carrier, reconnect timing, and page location.
129
+ */
130
+ export declare function installConnection(ctx: Context, options?: ConnectionInstallOptions): void;
131
+ /**
132
+ * Client plugin body: read the page composition and install its Connection service.
133
+ * @param ctx - client Cordis context.
134
+ */
135
+ export declare function apply(ctx: Context): void;
136
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,7 @@
1
+ /** Browser-safe UUID generation for client-side wire correlation. */
2
+ /**
3
+ * Generate an RFC 4122 version 4 UUID without requiring a secure context.
4
+ * @returns a UUID backed by `crypto.getRandomValues()`, which browsers expose on insecure origins.
5
+ */
6
+ export declare function randomUuid(): string;
7
+ //# sourceMappingURL=random-uuid.d.ts.map
@@ -0,0 +1,14 @@
1
+ /** Browser caller for generic Connection unary RPC channels. */
2
+ import type { ClientConnectionRpc } from '../rpc.ts';
3
+ /** Transport this caller posts through; same signature as the global `fetch`. */
4
+ export type RpcFetch = (input: URL, init: RequestInit) => Promise<Response>;
5
+ /** Worker-local opener for decoded Gateway Remote streams; `uplink` carries the Client's items for the stream. */
6
+ export type RpcStreamOpen = (endpoint: string, payload: unknown, signal: AbortSignal, uplink?: AsyncIterable<unknown>) => AsyncIterable<unknown>;
7
+ /**
8
+ * Create the browser-backed generic RPC caller.
9
+ * @param doFetch - transport override; defaults to the page's global fetch.
10
+ * @param openStream - optional worker-local Gateway stream carrier.
11
+ * @returns caller that owns request correlation and response-envelope validation.
12
+ */
13
+ export declare function createWebConnectionRpc(doFetch?: RpcFetch, openStream?: RpcStreamOpen): ClientConnectionRpc;
14
+ //# sourceMappingURL=rpc.d.ts.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * node:http ↔ WHATWG fetch bridge for the /api transport (host side of the
3
+ * web carrier; the fetch-shaped handler itself is transport-agnostic).
4
+ */
5
+ import type { IncomingMessage, ServerResponse } from 'node:http';
6
+ import type { ConnectionFetchHandler } from './rpc.ts';
7
+ /** Default carrier cap for all HTTP RPC bodies: sized for the default
8
+ * aggregate image limit (200 MiB) after base64 expansion plus envelope
9
+ * headroom (~267.7 MiB required), rounded up for slack. The bridge buffers
10
+ * each body in memory, so this cap is also the per-request resident bound. */
11
+ export declare const DEFAULT_MAX_REQUEST_BODY_BYTES: number;
12
+ /**
13
+ * Bridge one node:http request to the fetch-shaped handler (client close
14
+ * aborts; response bodies stream out chunk by chunk).
15
+ * @param req - incoming node:http request.
16
+ * @param res - node:http response the bridge writes and owns to completion.
17
+ * @param apiHandler - fetch-shaped API carrier the request is dispatched to.
18
+ * @param maxRequestBodyBytes - maximum bytes buffered for a buffered route.
19
+ */
20
+ export declare function bridge(req: IncomingMessage, res: ServerResponse, apiHandler: ConnectionFetchHandler, maxRequestBodyBytes?: number): Promise<void>;
21
+ //# sourceMappingURL=http-bridge.d.ts.map
@@ -0,0 +1,58 @@
1
+ /** Host HTTP bridge for browser-client RPC. */
2
+ import type { Context } from '@qilin-agent/kylin';
3
+ import type { IncomingMessage, ServerResponse } from 'node:http';
4
+ import z from '@qilin-agent/schemastery';
5
+ import { type ConnectionRecoveryConfig } from './recovery-config.ts';
6
+ export type { PeerAdmission, ConnectionFetchMethod, ConnectionFetchHandler, ConnectionFetchRoute, ConnectionIndexRequest, ConnectionIndexResponse, ConnectionSessionAuthority, HostConnectionSession, ConnectionRpcEndpointMatcher, ConnectionRpcFailure, ConnectionRpcHandler, ConnectionRequestRejection, ConnectionRpcResult, ConnectionRequestBodyMode, ConnectionTrustRequest, ClientRequest, HostConnectionHandle, HostConnectionFetch, HostConnectionRpc, RpcMessage, ServerResponse, } from './rpc.ts';
7
+ export type { PeerId, PeerScope, RemoteInvocation } from '@qilin-agent/typert-protocol';
8
+ export { RpcId, transportError } from './rpc.ts';
9
+ export { OperatorPeer } from './operator-peer.ts';
10
+ export { clientRequestSchema, rpcErrorSchema, rpcIdSchema, rpcMessageSchema, rpcResultSchema, serverResponseSchema, } from './rpc-schema.ts';
11
+ export { HostConnectionService } from './rpc-host.ts';
12
+ export { API_PATH } from './api-path.ts';
13
+ export { WEB_ENTRY_PATH } from './web-entry.ts';
14
+ /** Stable Cordis plugin name. */
15
+ export declare const name = "client-connection";
16
+ declare module '@qilin-agent/kylin' {
17
+ interface Events {
18
+ /**
19
+ * Admit or wrap an authenticated shared API request, including body transfer.
20
+ * Existing requests continue when a listener refuses subsequent requests.
21
+ * @param request - Authenticated incoming HTTP request.
22
+ * @param response - Response owned until the delegated bridge settles.
23
+ * @param next - Delegate to the next listener or the shared API bridge.
24
+ * @mode waterfall
25
+ */
26
+ 'connection/request'(request: IncomingMessage, response: ServerResponse, next: () => Promise<void>): Promise<void>;
27
+ }
28
+ }
29
+ /** Services required before providing Connection. */
30
+ export declare const inject: string[];
31
+ /** Browser authentication, request limits, and connection recovery configuration. */
32
+ export interface ConnectionConfig {
33
+ /** Browser recovery timing, injected into each served page. */
34
+ recovery?: ConnectionRecoveryConfig;
35
+ /**
36
+ * Authorities this deployment serves beyond loopback: exact `host:port`, or
37
+ * port-less `host` matching any port. The /api trust fence refuses any
38
+ * request whose Host is neither loopback nor listed here, so a
39
+ * non-loopback (`0.0.0.0`) deployment must declare the names it is reached
40
+ * by; the Web runtime derives LAN IP literals from an active all-interface
41
+ * bind. An entry that is not a bare, canonical authority fails plugin load.
42
+ */
43
+ trustedHosts?: string[];
44
+ /** Absolute browser-session lifetime in days. Default: 30. */
45
+ cookieMaxAgeDays?: number;
46
+ /** Maximum buffered JSON body for every `/api` request. Default: 300 MiB. */
47
+ maxRequestBodyBytes?: number;
48
+ }
49
+ export declare const Config: z<ConnectionConfig>;
50
+ /**
51
+ * Provides carrier-neutral RPC and Fetch registries. When `webServer` is
52
+ * present, the plugin also mounts the `/api` browser transport with Host/Origin
53
+ * checks and persistent browser authentication.
54
+ * @param ctx - Host plugin context.
55
+ * @param config - resolved plugin config (schema defaults applied).
56
+ */
57
+ export declare function apply(ctx: Context, config?: ConnectionConfig): Promise<void>;
58
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Browser-safe, zero-dependency loopback classification shared by the `/api`
3
+ * Host fence and the package's `ctx.connection` state. The predicate stays
4
+ * package-internal; client plugins consume the derived state through Cordis.
5
+ */
6
+ /**
7
+ * Whether a normalized URL hostname names the local loopback authority.
8
+ * @param hostname - WHATWG URL hostname (IPv6 literals retain brackets).
9
+ * @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8.
10
+ */
11
+ export declare function isLoopbackHostname(hostname: string): boolean;
12
+ //# sourceMappingURL=loopback-hostname.d.ts.map
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The operator Peer: the one party this Host answers to. Connection owns it
3
+ * for its own lifetime, admits every request as it, and hands it to each
4
+ * Remote call as `invocation.peer`.
5
+ * @module @qilin-agent/client-connection/src/operator-peer
6
+ */
7
+ import type { Context } from '@qilin-agent/kylin';
8
+ import type { PeerId, PeerScope } from '@qilin-agent/typert-protocol';
9
+ /**
10
+ * The operator's scope. The instance is its own scope key, so `scopeOf(peer.ctx)`
11
+ * returns it and events dispatched with `scopeTarget(subject, peer)` reach
12
+ * listeners registered through `peer.ctx` and nobody else.
13
+ */
14
+ export declare class OperatorPeer implements PeerScope {
15
+ readonly id: PeerId;
16
+ readonly ctx: Context;
17
+ private readonly scope;
18
+ /** @param owner - Connection plugin context the scope fiber hangs under. */
19
+ constructor(owner: Context);
20
+ /** Tear down every connection-lifetime registration; racing calls share one completion. */
21
+ dispose(): Promise<void>;
22
+ }
23
+ //# sourceMappingURL=operator-peer.d.ts.map
@@ -0,0 +1,27 @@
1
+ /** Shared validation for Host-configured and browser-local connection recovery. */
2
+ import z from '@qilin-agent/schemastery';
3
+ /** Timing for generation readiness and automatic reconnection. */
4
+ export interface ConnectionRecoveryConfig {
5
+ /** First-retry delay cap in ms; actual delay is 50–100% of the cap. Default: 500. */
6
+ backoffBaseMs?: number;
7
+ /** Finite growth factor of at least 1 per failed attempt; 1 keeps a fixed cap. Default: 2. */
8
+ backoffFactor?: number;
9
+ /** Maximum retry delay cap in ms; retries continue at this cap. Default: 10000. */
10
+ backoffMaxMs?: number;
11
+ /**
12
+ * Delay before reporting a slow handshake, without cancelling it. Default: 3000.
13
+ * Omitted when readiness, failure, cancellation, or the hard deadline occurs first.
14
+ */
15
+ generationReadyWarnMs?: number;
16
+ /** Deadline in ms for readiness, including physical connection setup. Default: 15000. */
17
+ generationReadyTimeoutMs?: number;
18
+ }
19
+ /** Schema shared by the Host plugin and the Client's recovery input parser. */
20
+ export declare const ConnectionRecoveryConfigSchema: z<ConnectionRecoveryConfig>;
21
+ /**
22
+ * Validate recovery input and supply every timing default before starting work.
23
+ * @param config - Host configuration, page bootstrap data, or direct loop options.
24
+ * @returns validated, complete recovery timing.
25
+ */
26
+ export declare function resolveConnectionConfig(config?: unknown): Required<ConnectionRecoveryConfig>;
27
+ //# sourceMappingURL=recovery-config.d.ts.map
@@ -0,0 +1,70 @@
1
+ /** Host registry and HTTP adapter for generic Connection RPC channels. */
2
+ import { Context, Service } from '@qilin-agent/kylin';
3
+ import type { PeerScope } from '@qilin-agent/typert-protocol';
4
+ import type { BrowserAuth } from './browser-auth.ts';
5
+ import type { PeerAdmission, ConnectionIndexRequest, ConnectionIndexResponse, ConnectionFetchHandler, HostConnectionFetch, HostConnectionSession, ConnectionRequestRejection, ConnectionTrustRequest, HostConnectionHandle, HostConnectionRpc } from './rpc.ts';
6
+ declare module '@qilin-agent/kylin' {
7
+ interface Context {
8
+ /** Host Connection transport and RPC registrations. */
9
+ connection: HostConnectionHandle;
10
+ }
11
+ }
12
+ /** Host Connection service whose channel registrations belong to the caller fiber. */
13
+ export declare class HostConnectionService extends Service implements HostConnectionHandle {
14
+ private readonly trustedHosts;
15
+ private readonly browserAuth;
16
+ /** The operator Peer every admitted request speaks for. */
17
+ readonly operator: PeerScope;
18
+ private readonly interceptors;
19
+ private readonly fetchRoutes;
20
+ private sessionAuthority;
21
+ /**
22
+ * Provide the Host half over the active HTTP server.
23
+ * @param ctx - owning Connection plugin context.
24
+ * @param trustedHosts - deployment authorities accepted by the Host/Origin fence.
25
+ * @param browserAuth - process token and persistent browser-session owner.
26
+ */
27
+ constructor(ctx: Context, trustedHosts: readonly string[], browserAuth: BrowserAuth);
28
+ /** Generic channel registry scoped to the Context reading this service. */
29
+ get rpc(): HostConnectionRpc;
30
+ /** Exact Fetch-route registry scoped to the Context reading this service. */
31
+ get fetch(): HostConnectionFetch;
32
+ /** Request path serving the application document. */
33
+ get entryPath(): string;
34
+ /** Account-session gate seat scoped to the Context reading this service. */
35
+ get session(): HostConnectionSession;
36
+ /**
37
+ * Apply the configured Host/Origin fence, then whichever authentication owns
38
+ * this deployment: an installed account-session authority, or the device
39
+ * cookie minted by the launch-token exchange.
40
+ */
41
+ requestRejection(request: ConnectionTrustRequest): ConnectionRequestRejection;
42
+ /** A request that passes the fence and authentication speaks for the operator. */
43
+ admit(request: ConnectionTrustRequest): PeerAdmission;
44
+ /**
45
+ * Authenticate an index request: the launch-token exchange first, then the
46
+ * installed account-session authority, or the device cookie when no
47
+ * authority claims the seat.
48
+ */
49
+ authorizeIndex(request: ConnectionIndexRequest, response: ConnectionIndexResponse): boolean;
50
+ /** Add this process's launch token, and an optional display name, to the clean application URL. */
51
+ authenticatedUrl(baseUrl: string, displayName?: string): string;
52
+ /**
53
+ * Compose one shared-channel Fetch handler from exact routes and its interceptor.
54
+ * @param channel - shared channel mounted by Connection.
55
+ * @returns Fetch handler that selects one owner or returns 404.
56
+ */
57
+ createSharedFetchHandler(channel: '/api'): ConnectionFetchHandler;
58
+ /**
59
+ * Answer the status read from the device session alone. Exact routes are
60
+ * consulted first, so a mounted account gate keeps owning this path; this
61
+ * fallback exists for the forms that disable it and would otherwise leave
62
+ * the menu without any identity channel.
63
+ */
64
+ private deviceStatusAnswer;
65
+ private installSessionAuthority;
66
+ private registerFetchRoute;
67
+ private register;
68
+ private registerInterceptor;
69
+ }
70
+ //# sourceMappingURL=rpc-host.d.ts.map
@@ -0,0 +1,30 @@
1
+ /** Runtime validation for Connection RPC envelopes. */
2
+ import { z } from 'zod';
3
+ import type { ClientRequest, RpcId, RpcMessage, ServerResponse } from './rpc.ts';
4
+ /** Correlation id after wire validation. */
5
+ export declare const rpcIdSchema: z.ZodType<RpcId>;
6
+ /** Generic endpoint failure carried in a response envelope. */
7
+ export declare const rpcErrorSchema: z.ZodObject<{
8
+ code: z.ZodString;
9
+ message: z.ZodString;
10
+ details: z.ZodRecord<z.ZodString, z.ZodUnknown>;
11
+ }, z.core.$strip>;
12
+ /**
13
+ * Build the result parser for one endpoint value parser.
14
+ * @param value - endpoint-owned success-value parser.
15
+ * @returns parser for either a success value or generic failure.
16
+ */
17
+ export declare function rpcResultSchema<T>(value: z.ZodType<T>): z.ZodType<{
18
+ readonly ok: true;
19
+ readonly value: T;
20
+ } | {
21
+ readonly ok: false;
22
+ readonly error: z.infer<typeof rpcErrorSchema>;
23
+ }>;
24
+ /** Client request envelope; endpoint payload validation belongs to its owner. */
25
+ export declare const clientRequestSchema: z.ZodType<ClientRequest>;
26
+ /** Server response envelope; endpoint value validation belongs to its caller. */
27
+ export declare const serverResponseSchema: z.ZodType<ServerResponse>;
28
+ /** Either Connection RPC envelope direction. */
29
+ export declare const rpcMessageSchema: z.ZodType<RpcMessage>;
30
+ //# sourceMappingURL=rpc-schema.d.ts.map