@byok-sdk/client 0.11.0 → 0.12.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 +15 -3
- package/dist/agent-home.d.ts +33 -0
- package/dist/agent-memory/index.js +8 -5
- package/dist/agent-memory/index.js.map +1 -1
- package/dist/bin/byok-agent.js +832 -177
- package/dist/bin/byok-agent.js.map +1 -1
- package/dist/daemon/agent-egress-controller.d.ts +4 -0
- package/dist/daemon/auth-manager.d.ts +20 -0
- package/dist/daemon/blob-client.d.ts +24 -6
- package/dist/daemon/connection-manager.d.ts +7 -0
- package/dist/daemon/create-daemon.d.ts +2 -0
- package/dist/daemon/device-credential-store.d.ts +16 -0
- package/dist/daemon/long-poll-transport.d.ts +3 -0
- package/dist/daemon/replay-cursor.d.ts +9 -0
- package/dist/daemon/task-runner.d.ts +4 -0
- package/dist/daemon/url.d.ts +7 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +832 -177
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -46,6 +46,8 @@ export declare class AgentEgressController {
|
|
|
46
46
|
private readonly options;
|
|
47
47
|
private readonly latest;
|
|
48
48
|
private readonly spools;
|
|
49
|
+
private readonly spoolOpens;
|
|
50
|
+
private reliableAppendTail;
|
|
49
51
|
private readonly latestStatus;
|
|
50
52
|
private readonly reliableStatus;
|
|
51
53
|
private readonly drops;
|
|
@@ -74,6 +76,8 @@ export declare class AgentEgressController {
|
|
|
74
76
|
/** Missing ack capability holds records in their reliable lane; it never makes them lossy. */
|
|
75
77
|
retryableReliableRecords(serverCapabilities: readonly string[]): readonly AgentReliableEgressRecord[];
|
|
76
78
|
private spoolFor;
|
|
79
|
+
private bindSpool;
|
|
77
80
|
private tenantPendingBytes;
|
|
81
|
+
private withAppendTail;
|
|
78
82
|
private noteDrop;
|
|
79
83
|
}
|
|
@@ -9,6 +9,15 @@ import type { DeviceCredentialStore, InMemoryDeviceCredentialStore } from './dev
|
|
|
9
9
|
export declare class DeviceRevokedError extends Error {
|
|
10
10
|
constructor(message?: string);
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Thrown when the local AuthManager deadline or shutdown cancels its own
|
|
14
|
+
* in-flight request. This is deliberately distinct from `DeviceRevokedError`:
|
|
15
|
+
* only an actual challenge/token HTTP 401 is server authority for revocation.
|
|
16
|
+
*/
|
|
17
|
+
export declare class AuthRequestAbortedError extends Error {
|
|
18
|
+
readonly reason: 'deadline' | 'stopped';
|
|
19
|
+
constructor(reason: 'deadline' | 'stopped');
|
|
20
|
+
}
|
|
12
21
|
export interface AuthManagerOptions {
|
|
13
22
|
serverUrl: string;
|
|
14
23
|
store: DeviceStore;
|
|
@@ -23,6 +32,8 @@ export interface AuthManagerOptions {
|
|
|
23
32
|
* permission to supersede this machine's prior active device rows.
|
|
24
33
|
*/
|
|
25
34
|
machineId?: () => Promise<string | undefined>;
|
|
35
|
+
/** Upper bound for one pair/challenge/token fetch plus its response-body read. */
|
|
36
|
+
authRequestDeadlineMs?: number;
|
|
26
37
|
/** Called once revocation is detected, so a caller (ConnectionManager) can stop retrying and surface the state instead of looping. */
|
|
27
38
|
onRevoked?: () => void;
|
|
28
39
|
}
|
|
@@ -42,7 +53,10 @@ export declare class AuthManager {
|
|
|
42
53
|
private stopped;
|
|
43
54
|
private pairing;
|
|
44
55
|
private credentialMutationTail;
|
|
56
|
+
/** The sole cancellation authority for the request currently inside the serialized credential mutation. */
|
|
57
|
+
private activeRequest;
|
|
45
58
|
private readonly credentials;
|
|
59
|
+
private readonly requestDeadlineMs;
|
|
46
60
|
constructor(opts: AuthManagerOptions);
|
|
47
61
|
get deviceId(): string | undefined;
|
|
48
62
|
isRevoked(): boolean;
|
|
@@ -62,6 +76,12 @@ export declare class AuthManager {
|
|
|
62
76
|
/** Always throws — `never` return type lets call sites use `if (x === 401) this.markRevoked();` without an explicit `return`/`throw` of their own. */
|
|
63
77
|
private markRevoked;
|
|
64
78
|
private scheduleProactiveRenewal;
|
|
79
|
+
/**
|
|
80
|
+
* Bounds one complete auth exchange rather than fetch alone. Keeping the
|
|
81
|
+
* controller active through `json()`/`text()` makes a non-cooperative or
|
|
82
|
+
* partial response body cancellable by the same authority that owns fetch.
|
|
83
|
+
*/
|
|
84
|
+
private runRequest;
|
|
65
85
|
private runCredentialMutation;
|
|
66
86
|
/** Read the current paired authority afresh; metadata without its OS secret is re-pair required. */
|
|
67
87
|
private loadRecord;
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import type { BlobRef } from '@byok-sdk/protocol';
|
|
2
2
|
import type { AuthManager } from './auth-manager';
|
|
3
|
+
export type BlobRequestAbortReason = 'deadline' | 'cancelled';
|
|
4
|
+
/** A blob request/body read did not complete before its deadline or its owner cancelled it. */
|
|
5
|
+
export declare class BlobRequestAbortedError extends Error {
|
|
6
|
+
readonly reason: BlobRequestAbortReason;
|
|
7
|
+
constructor(reason: BlobRequestAbortReason);
|
|
8
|
+
}
|
|
9
|
+
export interface BlobClientOptions {
|
|
10
|
+
/** Bound for each individual HTTP request and response-body read. Default: 15 seconds. */
|
|
11
|
+
requestDeadlineMs?: number;
|
|
12
|
+
/** Daemon lifecycle authority; aborting it stops all in-flight blob I/O. */
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}
|
|
15
|
+
export interface BlobRequestOptions {
|
|
16
|
+
/** Task lifecycle authority; aborting it stops this transfer before finalization. */
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}
|
|
3
19
|
/** Seam `TaskRunner` depends on, so tests can substitute a fake without spinning up real HTTP endpoints. */
|
|
4
20
|
export interface BlobResolver {
|
|
5
|
-
resolveInstruction(blobRef: BlobRef): Promise<string>;
|
|
6
|
-
uploadArtifact(content: string | Uint8Array, contentType: string, options?: {
|
|
21
|
+
resolveInstruction(blobRef: BlobRef, options?: BlobRequestOptions): Promise<string>;
|
|
22
|
+
uploadArtifact(content: string | Uint8Array, contentType: string, options?: BlobRequestOptions & {
|
|
7
23
|
readonly idempotencyKey?: string;
|
|
8
24
|
}): Promise<BlobRef>;
|
|
9
25
|
}
|
|
@@ -16,11 +32,13 @@ export declare class BlobClient implements BlobResolver {
|
|
|
16
32
|
#private;
|
|
17
33
|
private readonly serverUrl;
|
|
18
34
|
private readonly auth;
|
|
19
|
-
|
|
35
|
+
private readonly options;
|
|
36
|
+
private readonly requestDeadlineMs;
|
|
37
|
+
constructor(serverUrl: string, auth: AuthManager, options?: BlobClientOptions);
|
|
20
38
|
/** `blobRef` -> `GET /byok/blobs/:id/url` -> fetch the presigned download URL -> text content. Always resolves fresh rather than trusting any inlined `BlobRef.url`, per docs/protocol.md §7. */
|
|
21
|
-
resolveInstruction(blobRef: BlobRef): Promise<string>;
|
|
22
|
-
/** `POST /byok/blobs`
|
|
23
|
-
uploadArtifact(content: string | Uint8Array, contentType: string, options?: {
|
|
39
|
+
resolveInstruction(blobRef: BlobRef, options?: BlobRequestOptions): Promise<string>;
|
|
40
|
+
/** `POST /byok/blobs` -> PUT the bytes to the presigned URL -> finalize into a `BlobRef`. */
|
|
41
|
+
uploadArtifact(content: string | Uint8Array, contentType: string, options?: BlobRequestOptions & {
|
|
24
42
|
readonly idempotencyKey?: string;
|
|
25
43
|
}): Promise<BlobRef>;
|
|
26
44
|
}
|
|
@@ -2,8 +2,10 @@ import { type CapabilityFlag, type Envelope, type RuntimeInfo, type ToolsetId }
|
|
|
2
2
|
import { AuthManager } from './auth-manager';
|
|
3
3
|
import type { CursorStore } from './cursor-store';
|
|
4
4
|
import { type FleetJitter } from './deterministic-jitter';
|
|
5
|
+
import { ReplayCursorTooOldError } from './replay-cursor';
|
|
5
6
|
import { type BackoffOptions, type ConnectionState, type LivenessOptions } from './ws-transport';
|
|
6
7
|
export type { ConnectionState } from './ws-transport';
|
|
8
|
+
export { ReplayCursorTooOldError } from './replay-cursor';
|
|
7
9
|
export interface ConnectionManagerOptions {
|
|
8
10
|
serverUrl: string;
|
|
9
11
|
deviceId: string;
|
|
@@ -35,6 +37,7 @@ export interface ConnectionManagerOptions {
|
|
|
35
37
|
longPollIdleDelayMs?: number;
|
|
36
38
|
fleetJitter?: FleetJitter;
|
|
37
39
|
onOperationalOutcome?: (outcome: 'success' | 'failure', source: 'reconnect' | 'upload') => void;
|
|
40
|
+
onTerminalError?: (error: ReplayCursorTooOldError) => void;
|
|
38
41
|
}
|
|
39
42
|
/**
|
|
40
43
|
* Owns the daemon's one logical connection to the server, which may be
|
|
@@ -119,6 +122,7 @@ export declare class ConnectionManager {
|
|
|
119
122
|
private draining;
|
|
120
123
|
private stopped;
|
|
121
124
|
private revoked;
|
|
125
|
+
private terminalError;
|
|
122
126
|
private settledWaiters;
|
|
123
127
|
private pendingCursorSave;
|
|
124
128
|
/**
|
|
@@ -249,6 +253,8 @@ export declare class ConnectionManager {
|
|
|
249
253
|
* advertisement, and cleared across disconnect/switch boundaries.
|
|
250
254
|
*/
|
|
251
255
|
getServerCapabilities(): readonly string[];
|
|
256
|
+
getTerminalError(): ReplayCursorTooOldError | undefined;
|
|
257
|
+
getMode(): 'ws' | 'long-poll';
|
|
252
258
|
isConnected(): boolean;
|
|
253
259
|
isRevoked(): boolean;
|
|
254
260
|
/**
|
|
@@ -496,6 +502,7 @@ export declare class ConnectionManager {
|
|
|
496
502
|
private onWsOutcome;
|
|
497
503
|
private notifySettled;
|
|
498
504
|
private enterLongPoll;
|
|
505
|
+
private enterReplayCursorTooOld;
|
|
499
506
|
private exitLongPoll;
|
|
500
507
|
private scheduleWsProbe;
|
|
501
508
|
private enterRevoked;
|
|
@@ -91,6 +91,8 @@ export interface DaemonConfig {
|
|
|
91
91
|
productName: string;
|
|
92
92
|
productId: string;
|
|
93
93
|
serverUrl: string;
|
|
94
|
+
/** Bounds one AuthManager pair/challenge/token exchange, including response-body reads. */
|
|
95
|
+
authRequestDeadlineMs?: number;
|
|
94
96
|
deviceName?: string;
|
|
95
97
|
/**
|
|
96
98
|
* Optional override for the client-hashed physical machine identity sent
|
|
@@ -16,6 +16,18 @@ export interface DeviceMetadata {
|
|
|
16
16
|
* from one pairing response with metadata from another.
|
|
17
17
|
*/
|
|
18
18
|
export type DeviceRecord = DeviceMetadata & DeviceCredentials;
|
|
19
|
+
/**
|
|
20
|
+
* The one durable authority allowed before a first pairing response is
|
|
21
|
+
* received. It keeps the generated key immutable across a lost response, so
|
|
22
|
+
* an exact server-side retry can prove the same public-key binding.
|
|
23
|
+
*/
|
|
24
|
+
export interface FirstPairingAttempt {
|
|
25
|
+
readonly kind: 'first-pairing-attempt-v1';
|
|
26
|
+
readonly deviceName: string;
|
|
27
|
+
readonly devicePublicKey: string;
|
|
28
|
+
readonly devicePrivateKeyPem: string;
|
|
29
|
+
readonly machineId?: string;
|
|
30
|
+
}
|
|
19
31
|
export interface DeviceCommandResult {
|
|
20
32
|
readonly exitCode: number;
|
|
21
33
|
readonly stdout: string;
|
|
@@ -44,6 +56,8 @@ export declare class DeviceCredentialStore {
|
|
|
44
56
|
#private;
|
|
45
57
|
constructor(options: DeviceCredentialStoreOptions);
|
|
46
58
|
read(): Promise<DeviceRecord | undefined>;
|
|
59
|
+
readFirstPairingAttempt(): Promise<FirstPairingAttempt | undefined>;
|
|
60
|
+
saveFirstPairingAttempt(attempt: FirstPairingAttempt): Promise<void>;
|
|
47
61
|
replace(record: DeviceRecord): Promise<void>;
|
|
48
62
|
/** Returns true only after the sole secret authority is confirmed absent. */
|
|
49
63
|
clear(): Promise<boolean>;
|
|
@@ -52,6 +66,8 @@ export declare class DeviceCredentialStore {
|
|
|
52
66
|
export declare class InMemoryDeviceCredentialStore {
|
|
53
67
|
#private;
|
|
54
68
|
read(): Promise<DeviceRecord | undefined>;
|
|
69
|
+
readFirstPairingAttempt(): Promise<FirstPairingAttempt | undefined>;
|
|
70
|
+
saveFirstPairingAttempt(attempt: FirstPairingAttempt): Promise<void>;
|
|
55
71
|
replace(record: DeviceRecord): Promise<void>;
|
|
56
72
|
clear(): Promise<boolean>;
|
|
57
73
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Envelope } from '@byok-sdk/protocol';
|
|
2
2
|
import { AuthManager } from './auth-manager';
|
|
3
|
+
import { ReplayCursorTooOldError } from './replay-cursor';
|
|
3
4
|
import { type TransportEndpoint } from './url';
|
|
4
5
|
/**
|
|
5
6
|
* A long-poll request failed in a way that today told the caller only
|
|
@@ -41,6 +42,8 @@ export interface LongPollClientOptions {
|
|
|
41
42
|
onServerCapabilities?: (capabilities: string[]) => void;
|
|
42
43
|
/** Called once the device is found to be revoked (401 surfaced through {@link AuthManager}) — the loop stops itself rather than retrying. */
|
|
43
44
|
onRevoked?: () => void;
|
|
45
|
+
/** Called when the server cannot replay the durable cursor supplied to this poll. */
|
|
46
|
+
onReplayCursorTooOld?: (error: ReplayCursorTooOldError) => void;
|
|
44
47
|
/**
|
|
45
48
|
* M4 Phase 4 (version-negotiation drill fix), scope narrowed by finding F1:
|
|
46
49
|
* called ONLY for a batch entry that failed to parse because its `type`
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server retained no contiguous replay history after the cursor the
|
|
3
|
+
* daemon acknowledged. This is terminal for the current device enrollment:
|
|
4
|
+
* retrying the same cursor can only repeat the loss condition.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ReplayCursorTooOldError extends Error {
|
|
7
|
+
readonly recoverableFrom?: number | undefined;
|
|
8
|
+
constructor(recoverableFrom?: number | undefined);
|
|
9
|
+
}
|
|
@@ -421,6 +421,7 @@ export declare class TaskRunner {
|
|
|
421
421
|
private readonly deps;
|
|
422
422
|
private readonly tasks;
|
|
423
423
|
private readonly pendingMessageTasks;
|
|
424
|
+
private readonly messageOutboxesByHome;
|
|
424
425
|
private readonly messageContextByToken;
|
|
425
426
|
private readonly messageContextByTask;
|
|
426
427
|
private readonly memoryContextByToken;
|
|
@@ -481,6 +482,8 @@ export declare class TaskRunner {
|
|
|
481
482
|
* costs nothing.
|
|
482
483
|
*/
|
|
483
484
|
private readonly inFlightOffers;
|
|
485
|
+
/** Blob I/O before an offer becomes an active task still belongs to that offer's cancellation authority. */
|
|
486
|
+
private readonly inFlightBlobAborts;
|
|
484
487
|
/**
|
|
485
488
|
* Finding P2 (Fix 2c): taskIds that have reached a terminal outcome
|
|
486
489
|
* (Complete/Failed/Cancelled) this session — populated in `finish()`.
|
|
@@ -592,6 +595,7 @@ export declare class TaskRunner {
|
|
|
592
595
|
}>;
|
|
593
596
|
/** Restore activated, unaccepted message drafts before transport admission on daemon restart. */
|
|
594
597
|
recoverAgentMessageOutboxes(agentsRoot: string): Promise<void>;
|
|
598
|
+
private agentMessageOutbox;
|
|
595
599
|
/** Retry stable recovered records after a transport handshake/re-handshake. */
|
|
596
600
|
retryRecoveredAgentMessages(): void;
|
|
597
601
|
private sendAgentMessageRecord;
|
package/dist/daemon/url.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export interface TransportEndpoint {
|
|
|
23
23
|
}
|
|
24
24
|
/** The single construction site for {@link TransportEndpoint} — see that interface's own doc comment for why it is the only one. */
|
|
25
25
|
export declare function describeEndpoint(transport: TransportEndpoint['transport'], url: string | URL): TransportEndpoint;
|
|
26
|
+
/**
|
|
27
|
+
* The only URL projection used by validation errors. Reading from the parsed
|
|
28
|
+
* structure means userinfo, query, and fragment never enter the diagnostic.
|
|
29
|
+
*/
|
|
30
|
+
/** The sole secret-safe projection for a configured server URL diagnostic. */
|
|
31
|
+
export declare function formatServerUrl(value: string | URL): string;
|
|
26
32
|
/**
|
|
27
33
|
* M5: thrown by {@link assertServerUrlAllowed} — see that function's own doc
|
|
28
34
|
* comment for the full allow/deny rule this names. Deliberately ONE error
|
|
@@ -68,7 +74,7 @@ export interface AssertServerUrlAllowedOptions {
|
|
|
68
74
|
* `localhost` or any `*.localhost` subdomain, an IPv4 literal in
|
|
69
75
|
* `127.0.0.0/8`, or the IPv6 loopback `::1` — see {@link isLoopbackHostname}.
|
|
70
76
|
* - `http:`/`ws:` to any other host — refused with a clear, typed
|
|
71
|
-
* {@link InsecureServerUrlError} naming the
|
|
77
|
+
* {@link InsecureServerUrlError} naming the redacted scheme/host/path and the fix
|
|
72
78
|
* (use `wss:`/`https:`, or pass `dangerouslyAllowInsecureRemote: true` if
|
|
73
79
|
* this is a deliberate, understood exception) — UNLESS
|
|
74
80
|
* `opts.dangerouslyAllowInsecureRemote` is `true`.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { AgentRef } from './agent-home';
|
|
|
3
3
|
export { AgentHomeError, AgentRefValidationError, AgentHomeResolutionError, AgentHomeCollisionError, AgentHomeBusyError, AgentHomeLeaseCorruptError, AgentHomeLayout, AgentHomeLeaseManager, AgentHomeManager, createAgentHomeProjection, createAgentHomeProjectionConsumer, AGENT_HOME_PROJECTION_STATE_FILE, stableAgentHomeOwnerId, validateAgentRef, } from './agent-home';
|
|
4
4
|
export { AgentSessionHandoffStore, AgentSessionHandoffStoreError, AgentSessionHandoffCorruptError, AgentSessionHandoffMismatchError, } from './daemon/agent-session-handoff-store';
|
|
5
5
|
export type { AgentSessionHandoff, AgentSessionHandoffMatch, AgentTaskTerminalEvidence, AgentTaskTerminalMatch, AgentTerminalCause, } from './daemon/agent-session-handoff-store';
|
|
6
|
-
export type { AgentHomeResolution, AgentHomeProjection, AgentHomeProjectionInput, AgentHomeProjectionApplyInput, AgentHomeProjectionFunction, AgentHomeProjectionApplyFunction, AgentHomeLease, AgentHomeBinding, } from './agent-home';
|
|
6
|
+
export type { AgentHomeResolution, AgentHomeProjection, AgentHomeProjectionInput, AgentHomeProjectionApplyInput, AgentHomeProjectionFunction, AgentHomeProjectionApplyFunction, AgentHomeLease, AgentHomeBinding, AgentHomeExecutionLease, AgentHomeExecutionBinding, } from './agent-home';
|
|
7
7
|
export { localStateRelocation, LocalStateRelocationError, LocalStateRelocationBusyError, LocalStateRelocationIntegrityError, } from './local-state-relocation';
|
|
8
8
|
export type { LocalStateRelocationInput, LocalStateRelocationLease, } from './local-state-relocation';
|
|
9
9
|
export { PolicyUnsupportedError, SteerUnsupportedError, freezeRuntimeAdapterDescriptor, sealRuntimeOperationManifest } from './types';
|
|
@@ -62,8 +62,9 @@ export type { InstallSkillPacksOptions, InstalledSkillPack, ProjectedSkillPack,
|
|
|
62
62
|
export { TruthMemoryClient, TruthMemoryClientError } from './daemon/truth-memory-client';
|
|
63
63
|
export type { LocalMemoryFilter, MemorySelector, TruthManifestQueryInput, TruthManifestRecord, TruthMemoryClientErrorCode, TruthMemoryClientOptions, TruthMemoryMetric, TruthSnapshotCandidateInput, TruthSnapshotWriteInput, TruthTerminalWriteInput, TruthWriteBody, TruthWriteResult, VerifiedTruthRecord, } from './daemon/truth-memory-client';
|
|
64
64
|
export type { ConnectionState } from './daemon/ws-transport';
|
|
65
|
-
export {
|
|
66
|
-
export
|
|
65
|
+
export { ReplayCursorTooOldError } from './daemon/replay-cursor';
|
|
66
|
+
export { BlobClient, BlobRequestAbortedError } from './daemon/blob-client';
|
|
67
|
+
export type { BlobClientOptions, BlobRequestAbortReason, BlobRequestOptions, BlobResolver } from './daemon/blob-client';
|
|
67
68
|
export { DaemonObserver } from './daemon/observer';
|
|
68
69
|
export type { DaemonEvent, DaemonEventKind, DaemonEventListener, DaemonTaskInfo, Unsubscribe } from './daemon/observer';
|
|
69
70
|
export { createServiceLifecycle, UnsupportedServicePlatformError } from './lifecycle/create-service-lifecycle';
|